From 07334b057dbed58cc7319fa9328efa7c0010e63a Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Thu, 28 Dec 2023 16:41:17 +0700 Subject: [PATCH 001/102] desktop (gradle): support specifying more versions in Gradle (#3614) --- apps/multiplatform/desktop/build.gradle.kts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/multiplatform/desktop/build.gradle.kts b/apps/multiplatform/desktop/build.gradle.kts index a784d5c5fe..4f5536a25b 100644 --- a/apps/multiplatform/desktop/build.gradle.kts +++ b/apps/multiplatform/desktop/build.gradle.kts @@ -102,9 +102,8 @@ compose { // Packaging requires to have version like MAJOR.MINOR.PATCH var adjustedVersion = rootProject.extra["desktop.version_name"] as String adjustedVersion = adjustedVersion.replace(Regex("[^0-9.]"), "") - if (adjustedVersion.split(".").size != 3) { - adjustedVersion += ".0" - } + val split = adjustedVersion.split(".") + adjustedVersion = split[0] + "." + (split.getOrNull(1) ?: "0") + "." + (split.getOrNull(2) ?: "0") version = adjustedVersion } } From b4dd6941d75b09d5c4fbedd484069b60f089c8f6 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Thu, 28 Dec 2023 10:06:49 +0000 Subject: [PATCH 002/102] core: allow quoted strings (with spaces) in network interface of remote hosts (#3592) --- .../commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt | 2 +- src/Simplex/Chat.hs | 2 +- tests/RemoteTests.hs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt index 4af3e3f2ed..e3f565b77c 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt @@ -2385,7 +2385,7 @@ sealed class CC { is CancelFile -> "/fcancel $fileId" is SetLocalDeviceName -> "/set device name $displayName" is ListRemoteHosts -> "/list remote hosts" - is StartRemoteHost -> "/start remote host " + (if (remoteHostId == null) "new" else "$remoteHostId multicast=${onOff(multicast)}") + (if (address != null) " addr=${address.address} iface=${address.`interface`}" else "") + (if (port != null) " port=$port" else "") + is StartRemoteHost -> "/start remote host " + (if (remoteHostId == null) "new" else "$remoteHostId multicast=${onOff(multicast)}") + (if (address != null) " addr=${address.address} iface=${json.encodeToString(address.`interface`)}" else "") + (if (port != null) " port=$port" else "") is SwitchRemoteHost -> "/switch remote host " + if (remoteHostId == null) "local" else "$remoteHostId" is StopRemoteHost -> "/stop remote host " + if (remoteHostKey == null) "new" else "$remoteHostKey" is DeleteRemoteHost -> "/delete remote host $remoteHostId" diff --git a/src/Simplex/Chat.hs b/src/Simplex/Chat.hs index eb16a492ee..1b61fb7487 100644 --- a/src/Simplex/Chat.hs +++ b/src/Simplex/Chat.hs @@ -6543,7 +6543,7 @@ chatCommandP = (pure Nothing) srvCfgP = strP >>= \case AProtocolType p -> APSC p <$> (A.space *> jsonP) toServerCfg server = ServerCfg {server, preset = False, tested = Nothing, enabled = True} - rcCtrlAddressP = RCCtrlAddress <$> ("addr=" *> strP) <*> (" iface=" *> text1P) + rcCtrlAddressP = RCCtrlAddress <$> ("addr=" *> strP) <*> (" iface=" *> (jsonP <|> text1P)) text1P = safeDecodeUtf8 <$> A.takeTill (== ' ') char_ = optional . A.char diff --git a/tests/RemoteTests.hs b/tests/RemoteTests.hs index ff0e5cb2d1..1622ce175c 100644 --- a/tests/RemoteTests.hs +++ b/tests/RemoteTests.hs @@ -142,7 +142,7 @@ storedBindingsTest = testChat2 aliceProfile aliceDesktopProfile $ \mobile deskto mobile ##> "/set device name Mobile" mobile <## "ok" - desktop ##> "/start remote host new addr=127.0.0.1 iface=lo port=52230" + desktop ##> "/start remote host new addr=127.0.0.1 iface=\"lo\" port=52230" desktop <##. "new remote host started on 127.0.0.1:52230" -- TODO: show ip? desktop <## "Remote session invitation:" inv <- getTermLine desktop From 5b52d0e173c29741075f0f36b70ddc8a885ea7e0 Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Thu, 28 Dec 2023 22:53:37 +0700 Subject: [PATCH 003/102] android, desktop: localization script enchancement (#3616) --- apps/multiplatform/common/build.gradle.kts | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/apps/multiplatform/common/build.gradle.kts b/apps/multiplatform/common/build.gradle.kts index 4d2eeca2ee..3b6975638a 100644 --- a/apps/multiplatform/common/build.gradle.kts +++ b/apps/multiplatform/common/build.gradle.kts @@ -154,8 +154,10 @@ afterEvaluate { val endStringRegex = Regex("[ ]*") val endTagRegex = Regex("]*>.*(<|>).*|[^>]*>.*(<|>).*") + val fontLtGtRegex = Regex("[^>]*>.*<font[^>]*>.*</font>.*") + val unbracketedColorRegex = Regex("color=#[abcdefABCDEF0-9]{3,6}") val correctHtmlRegex = Regex("[^>]*>.*.*.*|[^>]*>.*.*.*|[^>]*>.*.*.*|[^>]*>.*]*>.*.*") - val possibleFormat = listOf("s", "d", "1\$s", "1\$d", "2s", "f") + val possibleFormat = listOf("s", "d", "1\$s", "2\$s", "3\$s", "4\$s", "1\$d", "2\$d", "3\$d", "4\$d", "2s", "f") fun String.id(): String = replace("' } - if (countOfStartTag != countOfEndTag || countOfStartTag != endTagRegex.findAll(this).count() * 2 || !correctHtmlRegex.matches(this)) { + val prepared = if (fontLtGtRegex.matches(this) || unbracketedColorRegex.containsMatchIn(this)) { + replace("<", "<").replace(">", ">").replace(unbracketedColorRegex) { it.value.replace("color=#", "color=\"#") + "\"" } + } else this + val countOfStartTag = prepared.count { it == '<' } + val countOfEndTag = prepared.count { it == '>' } + if (countOfStartTag != countOfEndTag || countOfStartTag != endTagRegex.findAll(prepared).count() * 2 || !correctHtmlRegex.matches(prepared)) { if (debug) { println("Wrong string:") println(this) @@ -206,7 +215,7 @@ afterEvaluate { throw Exception("Wrong string: $this \nin $filepath") } } - val res = replace(startStringRegex) { it.value + "" + it.value } + val res = prepared.replace(startStringRegex) { it.value + "" + it.value } if (debug) { println("Changed string:") println(this) From 5ff6bd15f6716cdec2ed381adbff84f71367dfc6 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Thu, 28 Dec 2023 17:31:40 +0000 Subject: [PATCH 004/102] ui: translations (#3615) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Translated using Weblate (Italian) Currently translated at 100.0% (1500 of 1500 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/ * Translated using Weblate (Italian) Currently translated at 100.0% (1346 of 1346 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/it/ * Translated using Weblate (Chinese (Traditional)) Currently translated at 82.9% (1116 of 1346 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/zh_Hant/ * Translated using Weblate (Turkish) Currently translated at 9.2% (125 of 1346 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/tr/ * Translated using Weblate (Turkish) Currently translated at 80.1% (1202 of 1500 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/tr/ * Translated using Weblate (Hungarian) Currently translated at 38.0% (571 of 1500 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/ * Update translation files Updated by "Remove blank strings" hook in Weblate. Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ * Translated using Weblate (Ukrainian) Currently translated at 100.0% (1500 of 1500 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/uk/ * Translated using Weblate (Ukrainian) Currently translated at 100.0% (1500 of 1500 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/uk/ * Translated using Weblate (Ukrainian) Currently translated at 93.0% (1252 of 1346 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/uk/ * Translated using Weblate (Arabic) Currently translated at 94.4% (1416 of 1500 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/ * Translated using Weblate (Hungarian) Currently translated at 41.2% (619 of 1500 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/ * Translated using Weblate (Italian) Currently translated at 100.0% (1500 of 1500 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/ * Translated using Weblate (Italian) Currently translated at 100.0% (1346 of 1346 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/it/ * Translated using Weblate (Arabic) Currently translated at 99.7% (1496 of 1500 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/ * Translated using Weblate (Italian) Currently translated at 100.0% (1500 of 1500 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/ * Translated using Weblate (Italian) Currently translated at 100.0% (1346 of 1346 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/it/ * Translated using Weblate (Japanese) Currently translated at 90.9% (1224 of 1346 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ja/ * Translated using Weblate (Czech) Currently translated at 93.8% (1407 of 1500 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/cs/ * Translated using Weblate (French) Currently translated at 100.0% (1503 of 1503 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fr/ * Translated using Weblate (Italian) Currently translated at 100.0% (1503 of 1503 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/ * Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (1503 of 1503 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/ * Translated using Weblate (German) Currently translated at 100.0% (1504 of 1504 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/ * Translated using Weblate (Czech) Currently translated at 93.8% (1411 of 1504 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/cs/ * Translated using Weblate (Czech) Currently translated at 93.8% (1411 of 1504 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/cs/ * Translated using Weblate (Czech) Currently translated at 93.8% (1411 of 1504 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/cs/ * Translated using Weblate (Czech) Currently translated at 93.8% (1411 of 1504 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/cs/ * Translated using Weblate (French) Currently translated at 100.0% (1504 of 1504 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fr/ * Translated using Weblate (Italian) Currently translated at 100.0% (1504 of 1504 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/ * Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (1504 of 1504 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/ * Translated using Weblate (Czech) Currently translated at 93.8% (1412 of 1504 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/cs/ * Translated using Weblate (Czech) Currently translated at 93.8% (1412 of 1504 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/cs/ * Translated using Weblate (Turkish) Currently translated at 81.7% (1230 of 1504 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/tr/ * Translated using Weblate (Dutch) Currently translated at 100.0% (1504 of 1504 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/ * Translated using Weblate (Dutch) Currently translated at 100.0% (1346 of 1346 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/ * Translated using Weblate (Turkish) Currently translated at 83.2% (1252 of 1504 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/tr/ * Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ * Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (1507 of 1507 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% (1507 of 1507 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/es/ * Translated using Weblate (German) Currently translated at 100.0% (1507 of 1507 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/ * Translated using Weblate (Italian) Currently translated at 100.0% (1508 of 1508 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/ * Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (1508 of 1508 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/ * Translated using Weblate (German) Currently translated at 100.0% (1508 of 1508 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/ * Translated using Weblate (Dutch) Currently translated at 100.0% (1508 of 1508 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/ * Translated using Weblate (Dutch) Currently translated at 100.0% (1346 of 1346 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/ * Translated using Weblate (Hungarian) Currently translated at 42.4% (640 of 1508 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/ * Translated using Weblate (Hungarian) Currently translated at 55.0% (830 of 1508 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/ * Translated using Weblate (Russian) Currently translated at 99.8% (1506 of 1508 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ru/ * Translated using Weblate (Arabic) Currently translated at 99.7% (1504 of 1508 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/ * Translated using Weblate (French) Currently translated at 100.0% (1508 of 1508 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fr/ * Translated using Weblate (Spanish) Currently translated at 99.9% (1507 of 1508 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 98.5% (1326 of 1346 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/ * Translated using Weblate (Dutch) Currently translated at 100.0% (1508 of 1508 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/ * Translated using Weblate (Dutch) Currently translated at 100.0% (1346 of 1346 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/ * Translated using Weblate (Hungarian) Currently translated at 80.4% (1213 of 1508 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/ * Translated using Weblate (Spanish) Currently translated at 100.0% (1508 of 1508 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% (1346 of 1346 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/ * Translated using Weblate (Hungarian) Currently translated at 80.6% (1216 of 1508 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/ * Translated using Weblate (Bulgarian) Currently translated at 100.0% (1508 of 1508 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/bg/ * Translated using Weblate (Hungarian) Currently translated at 82.4% (1244 of 1508 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/ * Translated using Weblate (Hungarian) Currently translated at 86.4% (1304 of 1508 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/ * Update translation files Updated by "Remove blank strings" hook in Weblate. Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ * Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (1508 of 1508 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/ * Translated using Weblate (Russian) Currently translated at 99.9% (1507 of 1508 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ru/ * Translated using Weblate (Greek) Currently translated at 6.2% (94 of 1508 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/el/ * Translated using Weblate (Hungarian) Currently translated at 97.6% (1473 of 1508 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/ * Translated using Weblate (Hungarian) Currently translated at 97.6% (1473 of 1508 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/ * Update translation files Updated by "Remove blank strings" hook in Weblate. Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ * Translated using Weblate (Greek) Currently translated at 9.3% (141 of 1508 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/el/ * Update translation files Updated by "Remove blank strings" hook in Weblate. Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ * Translated using Weblate (Greek) Currently translated at 13.3% (201 of 1508 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/el/ * Translated using Weblate (Hungarian) Currently translated at 100.0% (1508 of 1508 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/ * Translated using Weblate (French) Currently translated at 100.0% (1510 of 1510 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fr/ * Translated using Weblate (Arabic) Currently translated at 99.7% (1506 of 1510 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/ * Translated using Weblate (Greek) Currently translated at 14.2% (215 of 1510 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/el/ * Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (1510 of 1510 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/ * Translated using Weblate (Hungarian) Currently translated at 100.0% (1510 of 1510 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/ * Translated using Weblate (Greek) Currently translated at 14.8% (224 of 1510 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/el/ * Translated using Weblate (Greek) Currently translated at 1.1% (16 of 1346 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/el/ * Translated using Weblate (Italian) Currently translated at 100.0% (1510 of 1510 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/ * Translated using Weblate (Italian) Currently translated at 100.0% (1346 of 1346 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/it/ * Translated using Weblate (Dutch) Currently translated at 100.0% (1510 of 1510 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/ * Translated using Weblate (Spanish) Currently translated at 100.0% (1510 of 1510 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/es/ * Translated using Weblate (French) Currently translated at 100.0% (1510 of 1510 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fr/ * Translated using Weblate (French) Currently translated at 100.0% (1346 of 1346 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/fr/ * Translated using Weblate (Spanish) Currently translated at 100.0% (1510 of 1510 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% (1346 of 1346 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/ * Translated using Weblate (Hungarian) Currently translated at 100.0% (1510 of 1510 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/ * Translated using Weblate (German) Currently translated at 100.0% (1510 of 1510 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/ * Translated using Weblate (Dutch) Currently translated at 100.0% (1346 of 1346 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/ * fix kotlin strings, import/export ios --------- Co-authored-by: Random Co-authored-by: Corey Lin Co-authored-by: xe1st Co-authored-by: Istvan Novak Co-authored-by: Hosted Weblate Co-authored-by: Maksym Lukashenko Co-authored-by: jonnysemon Co-authored-by: 小林照幸 Co-authored-by: inson1 Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com> Co-authored-by: Eric Co-authored-by: mlanp Co-authored-by: zenobit Co-authored-by: M1K4 Co-authored-by: No name Co-authored-by: summoner001 Co-authored-by: v1s7 Co-authored-by: elgratea Co-authored-by: diodepon --- .../bg.xcloc/Localized Contents/bg.xliff | 60 +- .../cs.xcloc/Localized Contents/cs.xliff | 60 +- .../de.xcloc/Localized Contents/de.xliff | 60 +- .../el.xcloc/Localized Contents/el.xliff | 66 +- .../en.xcloc/Localized Contents/en.xliff | 70 +- .../es.xcloc/Localized Contents/es.xliff | 186 +- .../fi.xcloc/Localized Contents/fi.xliff | 60 +- .../fr.xcloc/Localized Contents/fr.xliff | 64 +- .../it.xcloc/Localized Contents/it.xliff | 78 +- .../ja.xcloc/Localized Contents/ja.xliff | 63 +- .../nl.xcloc/Localized Contents/nl.xliff | 70 +- .../pl.xcloc/Localized Contents/pl.xliff | 60 +- .../ru.xcloc/Localized Contents/ru.xliff | 60 +- .../th.xcloc/Localized Contents/th.xliff | 60 +- .../tr.xcloc/Localized Contents/tr.xliff | 138 +- .../uk.xcloc/Localized Contents/uk.xliff | 98 +- .../Localized Contents/zh-Hans.xliff | 60 +- .../Localized Contents/zh-Hant.xliff | 30 + apps/ios/bg.lproj/Localizable.strings | 15 +- apps/ios/cs.lproj/Localizable.strings | 15 +- apps/ios/de.lproj/Localizable.strings | 15 +- apps/ios/es.lproj/Localizable.strings | 346 ++- .../es.lproj/SimpleX--iOS--InfoPlist.strings | 3 + apps/ios/fi.lproj/Localizable.strings | 15 +- apps/ios/fr.lproj/Localizable.strings | 21 +- apps/ios/it.lproj/Localizable.strings | 45 +- apps/ios/ja.lproj/Localizable.strings | 24 +- apps/ios/nl.lproj/Localizable.strings | 25 +- apps/ios/pl.lproj/Localizable.strings | 15 +- apps/ios/ru.lproj/Localizable.strings | 15 +- apps/ios/th.lproj/Localizable.strings | 15 +- apps/ios/uk.lproj/Localizable.strings | 111 +- apps/ios/zh-Hans.lproj/Localizable.strings | 15 +- .../commonMain/resources/MR/ar/strings.xml | 143 +- .../commonMain/resources/MR/bg/strings.xml | 146 +- .../commonMain/resources/MR/cs/strings.xml | 180 +- .../commonMain/resources/MR/de/strings.xml | 12 +- .../commonMain/resources/MR/el/strings.xml | 164 ++ .../commonMain/resources/MR/es/strings.xml | 166 +- .../commonMain/resources/MR/fr/strings.xml | 14 +- .../commonMain/resources/MR/hu/strings.xml | 1125 +++++++++- .../commonMain/resources/MR/it/strings.xml | 33 +- .../commonMain/resources/MR/nl/strings.xml | 20 +- .../commonMain/resources/MR/ru/strings.xml | 7 + .../commonMain/resources/MR/tr/strings.xml | 240 ++- .../commonMain/resources/MR/uk/strings.xml | 1878 +++++++++-------- .../resources/MR/zh-rCN/strings.xml | 11 + 47 files changed, 4514 insertions(+), 1663 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 7a2afea082..44f2d878e6 100644 --- a/apps/ios/SimpleX Localizations/bg.xcloc/Localized Contents/bg.xliff +++ b/apps/ios/SimpleX Localizations/bg.xcloc/Localized Contents/bg.xliff @@ -1072,6 +1072,10 @@ Чатът е спрян No comment provided by engineer. + + Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat. + No comment provided by engineer. + Chat preferences Чат настройки @@ -2015,6 +2019,10 @@ This cannot be undone! Криптирано съобщение или друго събитие notification + + Encrypted message: app is stopped + notification + Encrypted message: database error Криптирано съобщение: грешка в базата данни @@ -2240,6 +2248,10 @@ This cannot be undone! Грешка при зареждане на %@ сървъри No comment provided by engineer. + + Error opening chat + No comment provided by engineer. + Error receiving file Грешка при получаване на файл @@ -2918,6 +2930,10 @@ This cannot be undone! Invalid name! No comment provided by engineer. + + Invalid response + No comment provided by engineer. + Invalid server address! Невалиден адрес на сървъра! @@ -3118,6 +3134,11 @@ This is your link for group %@! Съобщения на живо No comment provided by engineer. + + Local + Локално + No comment provided by engineer. + Local name Локално име @@ -3485,11 +3506,6 @@ This is your link for group %@! Изключено No comment provided by engineer. - - Off (Local) - Изключено (Локално) - No comment provided by engineer. - Ok Ок @@ -3629,9 +3645,8 @@ This is your link for group %@! Протокол и код с отворен код – всеки може да оперира собствени сървъри. No comment provided by engineer. - - Opening database… - Отваряне на база данни… + + Opening app… No comment provided by engineer. @@ -3733,6 +3748,11 @@ This is your link for group %@! Моля, проверете вашите настройки и тези вашия за контакт. No comment provided by engineer. + + Please contact developers. +Error: %@ + No comment provided by engineer. + Please contact group admin. Моля, свържете се с груповия администартор. @@ -4707,6 +4727,10 @@ This is your link for group %@! Започни чат No comment provided by engineer. + + Start chat? + No comment provided by engineer. + Start migration Започни миграция @@ -5106,11 +5130,6 @@ You will be prompted to complete authentication before this feature is enabled.< Изключи No comment provided by engineer. - - Turn off notifications? - Изключи известията? - No comment provided by engineer. - Turn on Включи @@ -5307,6 +5326,10 @@ To connect, please ask your contact to create another connection link and check Използвай нов инкогнито профил No comment provided by engineer. + + Use only local notifications? + No comment provided by engineer. + Use server Използвай сървър @@ -5581,6 +5604,10 @@ Repeat join request? Можете да скриете или заглушите известията за потребителски профил - плъзнете надясно. No comment provided by engineer. + + You can make it visible to your SimpleX contacts via Settings. + No comment provided by engineer. + You can now send messages to %@ Вече можете да изпращате съобщения до %@ @@ -5805,13 +5832,6 @@ You can cancel this connection and remove the contact (and try later with a new Вашите контакти могат да позволят пълното изтриване на съобщението. No comment provided by engineer. - - Your contacts in SimpleX will see it. -You can change it in Settings. - Вашите контакти в SimpleX ще го видят. -Можете да го промените в Настройки. - No comment provided by engineer. - Your contacts will remain connected. Вашите контакти ще останат свързани. 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 be8b23658b..f0abba7bb2 100644 --- a/apps/ios/SimpleX Localizations/cs.xcloc/Localized Contents/cs.xliff +++ b/apps/ios/SimpleX Localizations/cs.xcloc/Localized Contents/cs.xliff @@ -1072,6 +1072,10 @@ Chat je zastaven No comment provided by engineer. + + Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat. + No comment provided by engineer. + Chat preferences Předvolby chatu @@ -2015,6 +2019,10 @@ This cannot be undone! Šifrovaná zpráva nebo jiná událost notification + + Encrypted message: app is stopped + notification + Encrypted message: database error Šifrovaná zpráva: chyba databáze @@ -2240,6 +2248,10 @@ This cannot be undone! Chyba načítání %@ serverů No comment provided by engineer. + + Error opening chat + No comment provided by engineer. + Error receiving file Chyba při příjmu souboru @@ -2918,6 +2930,10 @@ This cannot be undone! Invalid name! No comment provided by engineer. + + Invalid response + No comment provided by engineer. + Invalid server address! Neplatná adresa serveru! @@ -3118,6 +3134,11 @@ This is your link for group %@! Živé zprávy No comment provided by engineer. + + Local + Místní + No comment provided by engineer. + Local name Místní název @@ -3485,11 +3506,6 @@ This is your link for group %@! Vypnout No comment provided by engineer. - - Off (Local) - Vypnuto (místní) - No comment provided by engineer. - Ok Ok @@ -3629,9 +3645,8 @@ This is your link for group %@! Protokol a kód s otevřeným zdrojovým kódem - servery může provozovat kdokoli. No comment provided by engineer. - - Opening database… - Otvírání databáze… + + Opening app… No comment provided by engineer. @@ -3733,6 +3748,11 @@ This is your link for group %@! Zkontrolujte prosím nastavení své i svého kontaktu. No comment provided by engineer. + + Please contact developers. +Error: %@ + No comment provided by engineer. + Please contact group admin. Kontaktujte prosím správce skupiny. @@ -4707,6 +4727,10 @@ This is your link for group %@! Začít chat No comment provided by engineer. + + Start chat? + No comment provided by engineer. + Start migration Zahájit přenesení @@ -5106,11 +5130,6 @@ Před zapnutím této funkce budete vyzváni k dokončení ověření. Vypnout No comment provided by engineer. - - Turn off notifications? - Vypnout upozornění? - No comment provided by engineer. - Turn on Zapnout @@ -5307,6 +5326,10 @@ Chcete-li se připojit, požádejte svůj kontakt o vytvoření dalšího odkazu Použít nový inkognito profil No comment provided by engineer. + + Use only local notifications? + No comment provided by engineer. + Use server Použít server @@ -5581,6 +5604,10 @@ Repeat join request? Profil uživatele můžete skrýt nebo ztlumit - přejeďte prstem doprava. No comment provided by engineer. + + You can make it visible to your SimpleX contacts via Settings. + No comment provided by engineer. + You can now send messages to %@ Nyní můžete posílat zprávy %@ @@ -5805,13 +5832,6 @@ Toto připojení můžete zrušit a kontakt odebrat (a zkusit to později s nov Vaše kontakty mohou povolit úplné mazání zpráv. No comment provided by engineer. - - Your contacts in SimpleX will see it. -You can change it in Settings. - Vaše kontakty v SimpleX ji uvidí. -Můžete ji změnit v Nastavení. - No comment provided by engineer. - Your contacts will remain connected. Vaše kontakty zůstanou připojeny. 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 75f70f7ad1..dda89f5c0c 100644 --- a/apps/ios/SimpleX Localizations/de.xcloc/Localized Contents/de.xliff +++ b/apps/ios/SimpleX Localizations/de.xcloc/Localized Contents/de.xliff @@ -1094,6 +1094,10 @@ Der Chat ist beendet No comment provided by engineer. + + Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat. + No comment provided by engineer. + Chat preferences Chat-Präferenzen @@ -2063,6 +2067,10 @@ Das kann nicht rückgängig gemacht werden! Verschlüsselte Nachricht oder ein anderes Ereignis notification + + Encrypted message: app is stopped + notification + Encrypted message: database error Verschlüsselte Nachricht: Datenbankfehler @@ -2293,6 +2301,10 @@ Das kann nicht rückgängig gemacht werden! Fehler beim Laden von %@ Servern No comment provided by engineer. + + Error opening chat + No comment provided by engineer. + Error receiving file Fehler beim Empfangen der Datei @@ -2980,6 +2992,10 @@ Das kann nicht rückgängig gemacht werden! Ungültiger Name! No comment provided by engineer. + + Invalid response + No comment provided by engineer. + Invalid server address! Ungültige Serveradresse! @@ -3188,6 +3204,11 @@ Das ist Ihr Link für die Gruppe %@! Live Nachrichten No comment provided by engineer. + + Local + Lokal + No comment provided by engineer. + Local name Lokaler Name @@ -3557,11 +3578,6 @@ Das ist Ihr Link für die Gruppe %@! Aus No comment provided by engineer. - - Off (Local) - Aus (Lokal) - No comment provided by engineer. - Ok Ok @@ -3702,9 +3718,8 @@ Das ist Ihr Link für die Gruppe %@! Open-Source-Protokoll und -Code – Jede Person kann ihre eigenen Server aufsetzen und nutzen. No comment provided by engineer. - - Opening database… - Öffne Datenbank … + + Opening app… No comment provided by engineer. @@ -3807,6 +3822,11 @@ Das ist Ihr Link für die Gruppe %@! Bitte überprüfen sie sowohl Ihre, als auch die Präferenzen Ihres Kontakts. No comment provided by engineer. + + Please contact developers. +Error: %@ + No comment provided by engineer. + Please contact group admin. Bitte kontaktieren Sie den Gruppen-Administrator. @@ -4787,6 +4807,10 @@ Das ist Ihr Link für die Gruppe %@! Starten Sie den Chat No comment provided by engineer. + + Start chat? + No comment provided by engineer. + Start migration Starten Sie die Migration @@ -5191,11 +5215,6 @@ Sie werden aufgefordert, die Authentifizierung abzuschließen, bevor diese Funkt Abschalten No comment provided by engineer. - - Turn off notifications? - Benachrichtigungen abschalten? - No comment provided by engineer. - Turn on Einschalten @@ -5398,6 +5417,10 @@ Bitten Sie Ihren Kontakt darum einen weiteren Verbindungs-Link zu erzeugen, um s Nutzen Sie das neue Inkognito-Profil No comment provided by engineer. + + Use only local notifications? + No comment provided by engineer. + Use server Server nutzen @@ -5685,6 +5708,10 @@ Verbindungsanfrage wiederholen? Sie können ein Benutzerprofil verbergen oder stummschalten - wischen Sie es nach rechts. No comment provided by engineer. + + You can make it visible to your SimpleX contacts via Settings. + No comment provided by engineer. + You can now send messages to %@ Sie können nun Nachrichten an %@ versenden @@ -5914,13 +5941,6 @@ Sie können diese Verbindung abbrechen und den Kontakt entfernen (und es später Ihre Kontakte können die unwiederbringliche Löschung von Nachrichten erlauben. No comment provided by engineer. - - Your contacts in SimpleX will see it. -You can change it in Settings. - Ihre Kontakte in SimpleX werden es sehen. -Sie können es in den Einstellungen ändern. - No comment provided by engineer. - Your contacts will remain connected. Ihre Kontakte bleiben verbunden. diff --git a/apps/ios/SimpleX Localizations/el.xcloc/Localized Contents/el.xliff b/apps/ios/SimpleX Localizations/el.xcloc/Localized Contents/el.xliff index 7649b595cd..c6dcc84e99 100644 --- a/apps/ios/SimpleX Localizations/el.xcloc/Localized Contents/el.xliff +++ b/apps/ios/SimpleX Localizations/el.xcloc/Localized Contents/el.xliff @@ -31,32 +31,39 @@ Available in v5.1 ( No comment provided by engineer. - + (can be copied) + (μπορεί να αντιγραφή) No comment provided by engineer. - + !1 colored! + !1 έγχρωμο! No comment provided by engineer. - + #secret# + #μυστικό# No comment provided by engineer. - + %@ + %@ No comment provided by engineer. - + %@ %@ + %@ %@ No comment provided by engineer. - + %@ / %@ + %@ / %@ No comment provided by engineer. - + %@ is connected! + %@ είναι συνδεδεμένο! notification title @@ -4162,6 +4169,51 @@ SimpleX servers cannot see your profile. \~strike~ No comment provided by engineer. + + %@ connected + %@ συνδεδεμένο + No comment provided by engineer. + + + # %@ + # %@ + copied message info title, # <title> + + + %@ and %@ + %@ και %@ + No comment provided by engineer. + + + %1$@ at %2$@: + %1$@ στις %2$@: + copied message info, <sender> at <time> + + + ## History + ## Ιστορικό + copied message info + + + ## In reply to + ## Ως απαντηση σε + copied message info + + + %@ (current) + %@ (τωρινό) + No comment provided by engineer. + + + %@ (current): + %@ (τωρινό): + copied message info + + + %@ and %@ connected + %@ και %@ συνδεδεμένο + No comment provided by engineer. + 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 23498b2128..4544b823f7 100644 --- a/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff +++ b/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff @@ -1094,6 +1094,11 @@ Chat is stopped No comment provided by engineer. + + Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat. + Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat. + No comment provided by engineer. + Chat preferences Chat preferences @@ -2063,6 +2068,11 @@ This cannot be undone! Encrypted message or another event notification + + Encrypted message: app is stopped + Encrypted message: app is stopped + notification + Encrypted message: database error Encrypted message: database error @@ -2293,6 +2303,11 @@ This cannot be undone! Error loading %@ servers No comment provided by engineer. + + Error opening chat + Error opening chat + No comment provided by engineer. + Error receiving file Error receiving file @@ -2980,6 +2995,11 @@ This cannot be undone! Invalid name! No comment provided by engineer. + + Invalid response + Invalid response + No comment provided by engineer. + Invalid server address! Invalid server address! @@ -3188,6 +3208,11 @@ This is your link for group %@! Live messages No comment provided by engineer. + + Local + Local + No comment provided by engineer. + Local name Local name @@ -3557,11 +3582,6 @@ This is your link for group %@! Off No comment provided by engineer. - - Off (Local) - Off (Local) - No comment provided by engineer. - Ok Ok @@ -3702,9 +3722,9 @@ This is your link for group %@! Open-source protocol and code – anybody can run the servers. No comment provided by engineer. - - Opening database… - Opening database… + + Opening app… + Opening app… No comment provided by engineer. @@ -3807,6 +3827,13 @@ This is your link for group %@! Please check yours and your contact preferences. No comment provided by engineer. + + Please contact developers. +Error: %@ + Please contact developers. +Error: %@ + No comment provided by engineer. + Please contact group admin. Please contact group admin. @@ -4787,6 +4814,11 @@ This is your link for group %@! Start chat No comment provided by engineer. + + Start chat? + Start chat? + No comment provided by engineer. + Start migration Start migration @@ -5191,11 +5223,6 @@ You will be prompted to complete authentication before this feature is enabled.< Turn off No comment provided by engineer. - - Turn off notifications? - Turn off notifications? - No comment provided by engineer. - Turn on Turn on @@ -5398,6 +5425,11 @@ To connect, please ask your contact to create another connection link and check Use new incognito profile No comment provided by engineer. + + Use only local notifications? + Use only local notifications? + No comment provided by engineer. + Use server Use server @@ -5685,6 +5717,11 @@ Repeat join request? You can hide or mute a user profile - swipe it to the right. No comment provided by engineer. + + You can make it visible to your SimpleX contacts via Settings. + You can make it visible to your SimpleX contacts via Settings. + No comment provided by engineer. + You can now send messages to %@ You can now send messages to %@ @@ -5914,13 +5951,6 @@ You can cancel this connection and remove the contact (and try later with a new Your contacts can allow full message deletion. No comment provided by engineer. - - Your contacts in SimpleX will see it. -You can change it in Settings. - Your contacts in SimpleX will see it. -You can change it in Settings. - No comment provided by engineer. - Your contacts will remain connected. Your contacts will remain connected. 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 ccc7ee3446..5b3d820d6f 100644 --- a/apps/ios/SimpleX Localizations/es.xcloc/Localized Contents/es.xliff +++ b/apps/ios/SimpleX Localizations/es.xcloc/Localized Contents/es.xliff @@ -89,6 +89,7 @@ %@ and %@ + %@ y %@ No comment provided by engineer. @@ -103,6 +104,7 @@ %@ connected + %@ conectado No comment provided by engineer. @@ -132,6 +134,7 @@ %@, %@ and %lld members + %@, %@ y %lld miembro(s) más No comment provided by engineer. @@ -201,6 +204,7 @@ %lld group events + %lld evento(s) de grupo No comment provided by engineer. @@ -210,14 +214,17 @@ %lld messages blocked + %lld mensaje(s) bloqueado(s) No comment provided by engineer. %lld messages marked deleted + %lld mensaje(s) marcado(s) eliminado(s) No comment provided by engineer. %lld messages moderated by %@ + %lld mensaje(s) moderado(s) por %@ No comment provided by engineer. @@ -292,10 +299,12 @@ (new) + (nuevo) No comment provided by engineer. (this device v%@) + (este dispositivo v%@) No comment provided by engineer. @@ -390,6 +399,9 @@ - optionally notify deleted contacts. - profile names with spaces. - and more! + - notificar opcionalmente a los contactos eliminados. +- nombres de perfil con espacios. +- ¡...y más! No comment provided by engineer. @@ -408,6 +420,7 @@ 0 sec + 0 seg time to disappear @@ -637,6 +650,7 @@ All new messages from %@ will be hidden! + ¡Los mensajes nuevos de %@ estarán ocultos! No comment provided by engineer. @@ -746,10 +760,12 @@ Already connecting! + ¡Ya en proceso de conexión! No comment provided by engineer. Already joining the group! + ¡Ya en proceso de unirse al grupo! No comment provided by engineer. @@ -874,6 +890,7 @@ Bad desktop address + Dirección ordenador incorrecta No comment provided by engineer. @@ -888,6 +905,7 @@ Better groups + Grupos mejorados No comment provided by engineer. @@ -897,18 +915,22 @@ Block + Bloquear No comment provided by engineer. Block group members + Bloquear miembros del grupo No comment provided by engineer. Block member + Bloquear miembro No comment provided by engineer. Block member? + ¿Bloquear miembro? No comment provided by engineer. @@ -1072,6 +1094,10 @@ Chat está detenido No comment provided by engineer. + + Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat. + No comment provided by engineer. + Chat preferences Preferencias de Chat @@ -1174,6 +1200,7 @@ Connect automatically + Conectar automáticamente No comment provided by engineer. @@ -1183,24 +1210,31 @@ Connect to desktop + Conectar con ordenador No comment provided by engineer. Connect to yourself? + ¿Conectarte a tí mismo? No comment provided by engineer. Connect to yourself? This is your own SimpleX address! + ¿Conectarte a tí mismo? +¡Esta es tu propia dirección SimpleX! No comment provided by engineer. Connect to yourself? This is your own one-time link! + ¿Conectarte a tí mismo? +¡Este es tu propio enlace de un solo uso! No comment provided by engineer. Connect via contact address + Conectar mediante dirección de contacto No comment provided by engineer. @@ -1220,14 +1254,17 @@ This is your own one-time link! Connect with %@ + Conectar con %@ No comment provided by engineer. Connected desktop + Ordenador conectado No comment provided by engineer. Connected to desktop + Conectado con ordenador No comment provided by engineer. @@ -1242,6 +1279,7 @@ This is your own one-time link! Connecting to desktop + Conectando con ordenador No comment provided by engineer. @@ -1266,6 +1304,7 @@ This is your own one-time link! Connection terminated + Conexión finalizada No comment provided by engineer. @@ -1335,6 +1374,7 @@ This is your own one-time link! Correct name to %@? + ¿Corregir el nombre a %@? No comment provided by engineer. @@ -1344,11 +1384,12 @@ This is your own one-time link! Create SimpleX address - Crear tu dirección SimpleX + Crear dirección SimpleX No comment provided by engineer. Create a group using a random profile. + Crear grupo usando perfil aleatorio. No comment provided by engineer. @@ -1363,6 +1404,7 @@ This is your own one-time link! Create group + Crear grupo No comment provided by engineer. @@ -1387,6 +1429,7 @@ This is your own one-time link! Create profile + Crear perfil No comment provided by engineer. @@ -1549,6 +1592,7 @@ This is your own one-time link! Delete %lld messages? + ¿Elimina %lld mensajes? No comment provided by engineer. @@ -1578,6 +1622,7 @@ This is your own one-time link! Delete and notify contact + Eliminar y notificar contacto No comment provided by engineer. @@ -1613,6 +1658,8 @@ This is your own one-time link! Delete contact? This cannot be undone! + ¿Eliminar contacto? +¡No podrá deshacerse! No comment provided by engineer. @@ -1757,14 +1804,17 @@ This cannot be undone! Desktop address + Dirección ordenador No comment provided by engineer. Desktop app version %@ is not compatible with this app. + La versión de aplicación del ordenador %" no es compatible con esta aplicación. No comment provided by engineer. Desktop devices + Ordenadores No comment provided by engineer. @@ -1859,6 +1909,7 @@ This cannot be undone! Disconnect desktop? + ¿Desconectar ordenador? No comment provided by engineer. @@ -1868,6 +1919,7 @@ This cannot be undone! Discover via local network + Descubrir en red local No comment provided by engineer. @@ -2015,6 +2067,10 @@ This cannot be undone! Mensaje cifrado u otro evento notification + + Encrypted message: app is stopped + notification + Encrypted message: database error Mensaje cifrado: error base de datos @@ -2042,10 +2098,12 @@ This cannot be undone! Encryption re-negotiation error + Error de renegociación de cifrado message decrypt error item Encryption re-negotiation failed. + Renegociación de cifrado fallida. No comment provided by engineer. @@ -2060,6 +2118,7 @@ This cannot be undone! Enter group name… + Nombre del grupo… No comment provided by engineer. @@ -2079,6 +2138,7 @@ This cannot be undone! Enter this device name… + Nombre de este dispositivo… No comment provided by engineer. @@ -2093,6 +2153,7 @@ This cannot be undone! Enter your name… + Introduce tu nombre… No comment provided by engineer. @@ -2240,6 +2301,10 @@ This cannot be undone! Error al cargar servidores %@ No comment provided by engineer. + + Error opening chat + No comment provided by engineer. + Error receiving file Error al recibir archivo @@ -2372,6 +2437,7 @@ This cannot be undone! Expand + Expandir chat item action @@ -2406,6 +2472,7 @@ This cannot be undone! Faster joining and more reliable messages. + Mensajería más segura y conexión más rápida. No comment provided by engineer. @@ -2505,6 +2572,7 @@ This cannot be undone! Found desktop + Ordenador encontrado No comment provided by engineer. @@ -2529,6 +2597,7 @@ This cannot be undone! Fully decentralized – visible only to members. + Completamente descentralizado: sólo visible a los miembros. No comment provided by engineer. @@ -2553,10 +2622,12 @@ This cannot be undone! Group already exists + El grupo ya existe No comment provided by engineer. Group already exists! + ¡El grupo ya existe! No comment provided by engineer. @@ -2831,6 +2902,7 @@ This cannot be undone! Incognito groups + Grupos incógnito No comment provided by engineer. @@ -2865,6 +2937,7 @@ This cannot be undone! Incompatible version + Versión incompatible No comment provided by engineer. @@ -2916,6 +2989,11 @@ This cannot be undone! Invalid name! + ¡Nombre no válido! + No comment provided by engineer. + + + Invalid response No comment provided by engineer. @@ -3011,6 +3089,7 @@ This cannot be undone! Join group? + ¿Unirse al grupo? No comment provided by engineer. @@ -3020,11 +3099,14 @@ This cannot be undone! Join with current profile + Unirte con el perfil actual No comment provided by engineer. Join your group? This is your link for group %@! + ¿Unirse a tu grupo? +¡Este es tu enlace para el grupo %@! No comment provided by engineer. @@ -3034,6 +3116,7 @@ This is your link for group %@! Keep the app open to use it from desktop + Mantén la aplicación abierta para usarla desde el ordenador No comment provided by engineer. @@ -3098,14 +3181,17 @@ This is your link for group %@! Link mobile and desktop apps! 🔗 + ¡Enlazar aplicación móvil con ordenador! 🔗 No comment provided by engineer. Linked desktop options + Opciones ordenador enlazado No comment provided by engineer. Linked desktops + Ordenadores enlazados No comment provided by engineer. @@ -3118,6 +3204,11 @@ This is your link for group %@! Mensajes en vivo No comment provided by engineer. + + Local + Local + No comment provided by engineer. + Local name Nombre local @@ -3260,6 +3351,7 @@ This is your link for group %@! Messages from %@ will be shown! + ¡Los mensajes de %@ serán mostrados! No comment provided by engineer. @@ -3459,6 +3551,7 @@ This is your link for group %@! Not compatible! + ¡No compatible! No comment provided by engineer. @@ -3485,11 +3578,6 @@ This is your link for group %@! Desactivado No comment provided by engineer. - - Off (Local) - Desactivado (Local) - No comment provided by engineer. - Ok Ok @@ -3617,6 +3705,7 @@ This is your link for group %@! Open group + Grupo abierto No comment provided by engineer. @@ -3629,9 +3718,8 @@ This is your link for group %@! Protocolo y código abiertos: cualquiera puede usar los servidores. No comment provided by engineer. - - Opening database… - Abriendo base de datos… + + Opening app… No comment provided by engineer. @@ -3681,6 +3769,7 @@ This is your link for group %@! Paste desktop address + Pegar dirección de ordenador No comment provided by engineer. @@ -3733,6 +3822,11 @@ This is your link for group %@! Comprueba tus preferencias y las de tu contacto. No comment provided by engineer. + + Please contact developers. +Error: %@ + No comment provided by engineer. + Please contact group admin. Póngase en contacto con el administrador del grupo. @@ -3830,10 +3924,12 @@ This is your link for group %@! Profile name + Nombre del perfil No comment provided by engineer. Profile name: + Nombre del perfil: No comment provided by engineer. @@ -4083,10 +4179,12 @@ This is your link for group %@! Repeat connection request? + ¿Repetir solicitud de conexión? No comment provided by engineer. Repeat join request? + ¿Repetir solicitud de admisión? No comment provided by engineer. @@ -4276,6 +4374,7 @@ This is your link for group %@! Scan QR code from desktop + Escanear código QR desde ordenador No comment provided by engineer. @@ -4500,6 +4599,7 @@ This is your link for group %@! Session code + Código de sesión No comment provided by engineer. @@ -4707,6 +4807,10 @@ This is your link for group %@! Iniciar chat No comment provided by engineer. + + Start chat? + No comment provided by engineer. + Start migration Iniciar migración @@ -4814,6 +4918,7 @@ This is your link for group %@! Tap to Connect + Pulsa para conectar No comment provided by engineer. @@ -5000,6 +5105,7 @@ Puede ocurrir por algún bug o cuando la conexión está comprometida. This device name + Nombre del dispositivo No comment provided by engineer. @@ -5014,10 +5120,12 @@ Puede ocurrir por algún bug o cuando la conexión está comprometida. This is your own SimpleX address! + ¡Esta es tu propia dirección SimpleX! No comment provided by engineer. This is your own one-time link! + ¡Este es tu propio enlace de un solo uso! No comment provided by engineer. @@ -5037,6 +5145,7 @@ Puede ocurrir por algún bug o cuando la conexión está comprometida. To hide unwanted messages. + Para ocultar mensajes no deseados. No comment provided by engineer. @@ -5046,7 +5155,7 @@ Puede ocurrir por algún bug o cuando la conexión está comprometida. To protect privacy, instead of user IDs used by all other platforms, SimpleX has identifiers for message queues, separate for each of your contacts. - Para proteger la privacidad, en lugar de los identificadores de usuario que usan el resto de plataformas, SimpleX dispone de identificadores para las colas de mensajes, independientes para cada uno de tus contactos. + Para proteger tu privacidad, en lugar de los identificadores de usuario que usan el resto de plataformas, SimpleX dispone de identificadores para las colas de mensajes, independientes para cada uno de tus contactos. No comment provided by engineer. @@ -5057,7 +5166,7 @@ Puede ocurrir por algún bug o cuando la conexión está comprometida. To protect your information, turn on SimpleX Lock. You will be prompted to complete authentication before this feature is enabled. - Para proteger tu información, activa Bloqueo SimpleX. + Para proteger tu información, activa el Bloqueo SimpleX. Se te pedirá que completes la autenticación antes de activar esta función. No comment provided by engineer. @@ -5106,11 +5215,6 @@ Se te pedirá que completes la autenticación antes de activar esta función.Desactivar No comment provided by engineer. - - Turn off notifications? - ¿Desactivar notificaciones? - No comment provided by engineer. - Turn on Activar @@ -5123,14 +5227,17 @@ Se te pedirá que completes la autenticación antes de activar esta función. Unblock + Desbloquear No comment provided by engineer. Unblock member + Desbloquear miembro No comment provided by engineer. Unblock member? + ¿Desbloquear miembro? No comment provided by engineer. @@ -5198,10 +5305,12 @@ Para conectarte, pide a tu contacto que cree otro enlace de conexión y comprueb Unlink + Desenlazar No comment provided by engineer. Unlink desktop? + ¿Desenlazar ordenador? No comment provided by engineer. @@ -5296,6 +5405,7 @@ Para conectarte, pide a tu contacto que cree otro enlace de conexión y comprueb Use from desktop + Usar desde ordenador No comment provided by engineer. @@ -5308,6 +5418,10 @@ Para conectarte, pide a tu contacto que cree otro enlace de conexión y comprueb Usar nuevo perfil incógnito No comment provided by engineer. + + Use only local notifications? + No comment provided by engineer. + Use server Usar servidor @@ -5330,10 +5444,12 @@ Para conectarte, pide a tu contacto que cree otro enlace de conexión y comprueb Verify code with desktop + Verificar código con ordenador No comment provided by engineer. Verify connection + Verificar conexión No comment provided by engineer. @@ -5343,6 +5459,7 @@ Para conectarte, pide a tu contacto que cree otro enlace de conexión y comprueb Verify connections + Verificar conexiones No comment provided by engineer. @@ -5357,6 +5474,7 @@ Para conectarte, pide a tu contacto que cree otro enlace de conexión y comprueb Via secure quantum resistant protocol. + Mediante protocolo seguro de resistencia cuántica. No comment provided by engineer. @@ -5411,6 +5529,7 @@ Para conectarte, pide a tu contacto que cree otro enlace de conexión y comprueb Waiting for desktop... + Esperando ordenador... No comment provided by engineer. @@ -5515,31 +5634,39 @@ Para conectarte, pide a tu contacto que cree otro enlace de conexión y comprueb You are already connecting to %@. + Ya estás conectando con %@. No comment provided by engineer. You are already connecting via this one-time link! + ¡Ya estás conectando mediante este enlace de un solo uso! No comment provided by engineer. You are already in group %@. + Ya estás en el grupo %@. No comment provided by engineer. You are already joining the group %@. + Ya estás uniéndote al grupo %@. No comment provided by engineer. You are already joining the group via this link! + ¡Ya estás uniéndote al grupo mediante este enlace! No comment provided by engineer. You are already joining the group via this link. + Ya estás uniéndote al grupo mediante este enlace. No comment provided by engineer. You are already joining the group! Repeat join request? + ¡En proceso de unirte al grupo! +¿Repetir solicitud de admisión? No comment provided by engineer. @@ -5582,6 +5709,10 @@ Repeat join request? Puedes ocultar o silenciar un perfil deslizándolo a la derecha. No comment provided by engineer. + + You can make it visible to your SimpleX contacts via Settings. + No comment provided by engineer. + You can now send messages to %@ Ya puedes enviar mensajes a %@ @@ -5639,11 +5770,14 @@ Repeat join request? You have already requested connection via this address! + ¡Ya has solicitado la conexión mediante esta dirección! No comment provided by engineer. You have already requested connection! Repeat connection request? + Ya has solicitado la conexión +¿Repetir solicitud? No comment provided by engineer. @@ -5698,6 +5832,7 @@ Repeat connection request? You will be connected when group link host's device is online, please wait or check later! + Te conectarás cuando el dispositivo propietario del grupo esté en línea, por favor espera o compruébalo más tarde. No comment provided by engineer. @@ -5717,6 +5852,7 @@ Repeat connection request? You will connect to all group members. + Te conectarás con todos los miembros del grupo. No comment provided by engineer. @@ -5806,13 +5942,6 @@ Puedes cancelar esta conexión y eliminar el contacto (e intentarlo más tarde c Tus contactos pueden permitir la eliminación completa de mensajes. No comment provided by engineer. - - Your contacts in SimpleX will see it. -You can change it in Settings. - Tus contactos en SimpleX lo verán. -Puedes cambiarlo en Configuración. - No comment provided by engineer. - Your contacts will remain connected. Tus contactos permanecerán conectados. @@ -5840,6 +5969,7 @@ Puedes cambiarlo en Configuración. Your profile + Tu perfil No comment provided by engineer. @@ -5936,6 +6066,7 @@ Los servidores de SimpleX no pueden ver tu perfil. and %lld other events + y %lld evento(s) más No comment provided by engineer. @@ -5945,6 +6076,7 @@ Los servidores de SimpleX no pueden ver tu perfil. author + autor member role @@ -5959,6 +6091,7 @@ Los servidores de SimpleX no pueden ver tu perfil. blocked + bloqueado No comment provided by engineer. @@ -6133,6 +6266,7 @@ Los servidores de SimpleX no pueden ver tu perfil. deleted contact + contacto eliminado rcv direct event chat item @@ -6317,7 +6451,7 @@ Los servidores de SimpleX no pueden ver tu perfil. invited to connect - invitado a conectarse + invitación a conectarse chat list item title @@ -6529,6 +6663,7 @@ Los servidores de SimpleX no pueden ver tu perfil. v%@ + v%@ No comment provided by engineer. @@ -6628,7 +6763,7 @@ Los servidores de SimpleX no pueden ver tu perfil. you shared one-time link - has compartido un enlace de un uso + enlace de un solo uso chat list item description @@ -6670,6 +6805,7 @@ Los servidores de SimpleX no pueden ver tu perfil. SimpleX uses local network access to allow using user chat profile via desktop app on the same network. + SimpleX utiliza el acceso a la red local para abrir el perfil de chat en la aplicación de ordenador en la misma red. Privacy - Local Network Usage Description 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 cf161efae4..928666ddad 100644 --- a/apps/ios/SimpleX Localizations/fi.xcloc/Localized Contents/fi.xliff +++ b/apps/ios/SimpleX Localizations/fi.xcloc/Localized Contents/fi.xliff @@ -1067,6 +1067,10 @@ Chat on pysäytetty No comment provided by engineer. + + Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat. + No comment provided by engineer. + Chat preferences Chat-asetukset @@ -2009,6 +2013,10 @@ This cannot be undone! Salattu viesti tai muu tapahtuma notification + + Encrypted message: app is stopped + notification + Encrypted message: database error Salattu viesti: tietokantavirhe @@ -2233,6 +2241,10 @@ This cannot be undone! Virhe %@-palvelimien lataamisessa No comment provided by engineer. + + Error opening chat + No comment provided by engineer. + Error receiving file Virhe tiedoston vastaanottamisessa @@ -2910,6 +2922,10 @@ This cannot be undone! Invalid name! No comment provided by engineer. + + Invalid response + No comment provided by engineer. + Invalid server address! Virheellinen palvelinosoite! @@ -3110,6 +3126,11 @@ This is your link for group %@! Live-viestit No comment provided by engineer. + + Local + Paikallinen + No comment provided by engineer. + Local name Paikallinen nimi @@ -3476,11 +3497,6 @@ This is your link for group %@! Pois No comment provided by engineer. - - Off (Local) - Pois (Paikallinen) - No comment provided by engineer. - Ok Ok @@ -3619,9 +3635,8 @@ This is your link for group %@! Avoimen lähdekoodin protokolla ja koodi - kuka tahansa voi käyttää palvelimia. No comment provided by engineer. - - Opening database… - Avataan tietokantaa… + + Opening app… No comment provided by engineer. @@ -3723,6 +3738,11 @@ This is your link for group %@! Tarkista omasi ja kontaktin asetukset. No comment provided by engineer. + + Please contact developers. +Error: %@ + No comment provided by engineer. + Please contact group admin. Ota yhteyttä ryhmän ylläpitäjään. @@ -4695,6 +4715,10 @@ This is your link for group %@! Aloita keskustelu No comment provided by engineer. + + Start chat? + No comment provided by engineer. + Start migration Aloita siirto @@ -5093,11 +5117,6 @@ Sinua kehotetaan suorittamaan todennus loppuun, ennen kuin tämä ominaisuus ote Sammuta No comment provided by engineer. - - Turn off notifications? - Kytke ilmoitukset pois päältä? - No comment provided by engineer. - Turn on Kytke päälle @@ -5294,6 +5313,10 @@ Jos haluat muodostaa yhteyden, pyydä kontaktiasi luomaan toinen yhteyslinkki ja Käytä uutta incognito-profiilia No comment provided by engineer. + + Use only local notifications? + No comment provided by engineer. + Use server Käytä palvelinta @@ -5568,6 +5591,10 @@ Repeat join request? Voit piilottaa tai mykistää käyttäjäprofiilin pyyhkäisemällä sitä oikealle. No comment provided by engineer. + + You can make it visible to your SimpleX contacts via Settings. + No comment provided by engineer. + You can now send messages to %@ Voit nyt lähettää viestejä %@:lle @@ -5792,13 +5819,6 @@ Voit peruuttaa tämän yhteyden ja poistaa kontaktin (ja yrittää myöhemmin uu Kontaktisi voivat sallia viestien täydellisen poistamisen. No comment provided by engineer. - - Your contacts in SimpleX will see it. -You can change it in Settings. - Kontaktisi SimpleX:ssä näkevät sen. -Voit muuttaa sitä Asetuksista. - No comment provided by engineer. - Your contacts will remain connected. Kontaktisi pysyvät yhdistettyinä. 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 153d98be3c..6ec667ed91 100644 --- a/apps/ios/SimpleX Localizations/fr.xcloc/Localized Contents/fr.xliff +++ b/apps/ios/SimpleX Localizations/fr.xcloc/Localized Contents/fr.xliff @@ -1094,6 +1094,10 @@ Le chat est arrêté No comment provided by engineer. + + Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat. + No comment provided by engineer. + Chat preferences Préférences de chat @@ -2063,6 +2067,10 @@ Cette opération ne peut être annulée ! Message chiffrée ou autre événement notification + + Encrypted message: app is stopped + notification + Encrypted message: database error Message chiffrée : erreur de base de données @@ -2293,6 +2301,10 @@ Cette opération ne peut être annulée ! Erreur lors du chargement des serveurs %@ No comment provided by engineer. + + Error opening chat + No comment provided by engineer. + Error receiving file Erreur lors de la réception du fichier @@ -2980,6 +2992,10 @@ Cette opération ne peut être annulée ! Nom invalide ! No comment provided by engineer. + + Invalid response + No comment provided by engineer. + Invalid server address! Adresse de serveur invalide ! @@ -3188,6 +3204,11 @@ Voici votre lien pour le groupe %@ ! Messages dynamiques No comment provided by engineer. + + Local + Local + No comment provided by engineer. + Local name Nom local @@ -3557,11 +3578,6 @@ Voici votre lien pour le groupe %@ ! Off No comment provided by engineer. - - Off (Local) - Off (Local) - No comment provided by engineer. - Ok Ok @@ -3702,9 +3718,8 @@ Voici votre lien pour le groupe %@ ! Protocole et code open-source – n'importe qui peut heberger un serveur. No comment provided by engineer. - - Opening database… - Ouverture de la base de données… + + Opening app… No comment provided by engineer. @@ -3807,6 +3822,11 @@ Voici votre lien pour le groupe %@ ! Veuillez vérifier vos préférences ainsi que celles de votre contact. No comment provided by engineer. + + Please contact developers. +Error: %@ + No comment provided by engineer. + Please contact group admin. Veuillez contacter l'administrateur du groupe. @@ -4787,6 +4807,10 @@ Voici votre lien pour le groupe %@ ! Démarrer le chat No comment provided by engineer. + + Start chat? + No comment provided by engineer. + Start migration Démarrer la migration @@ -5191,11 +5215,6 @@ Vous serez invité à confirmer l'authentification avant que cette fonction ne s Désactiver No comment provided by engineer. - - Turn off notifications? - Désactiver les notifications ? - No comment provided by engineer. - Turn on Activer @@ -5398,6 +5417,10 @@ Pour vous connecter, veuillez demander à votre contact de créer un autre lien Utiliser un nouveau profil incognito No comment provided by engineer. + + Use only local notifications? + No comment provided by engineer. + Use server Utiliser ce serveur @@ -5685,6 +5708,10 @@ Répéter la demande d'adhésion ? Vous pouvez masquer ou mettre en sourdine un profil d'utilisateur - faites-le glisser vers la droite. No comment provided by engineer. + + You can make it visible to your SimpleX contacts via Settings. + No comment provided by engineer. + You can now send messages to %@ Vous pouvez maintenant envoyer des messages à %@ @@ -5914,13 +5941,6 @@ Vous pouvez annuler la connexion et supprimer le contact (et réessayer plus tar Vos contacts peuvent autoriser la suppression complète des messages. No comment provided by engineer. - - Your contacts in SimpleX will see it. -You can change it in Settings. - Vos contacts dans SimpleX la verront. -Vous pouvez modifier ce choix dans les Paramètres. - No comment provided by engineer. - Your contacts will remain connected. Vos contacts resteront connectés. @@ -6537,12 +6557,12 @@ Les serveurs SimpleX ne peuvent pas voir votre profil. offered %@ - offert %@ + propose %@ feature offered item offered %1$@: %2$@ - offert %1$@ : %2$@ + propose %1$@ : %2$@ feature offered item 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 bf1b1ee386..d1a17a3af2 100644 --- a/apps/ios/SimpleX Localizations/it.xcloc/Localized Contents/it.xliff +++ b/apps/ios/SimpleX Localizations/it.xcloc/Localized Contents/it.xliff @@ -94,7 +94,7 @@ %@ and %@ connected - %@ e %@ sono connessi/e + %@ e %@ si sono connessi/e No comment provided by engineer. @@ -139,7 +139,7 @@ %@, %@ and %lld other members connected - %@, %@ e altri %lld membri sono connessi + %@, %@ e altri %lld membri si sono connessi No comment provided by engineer. @@ -1094,6 +1094,10 @@ Chat fermata No comment provided by engineer. + + Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat. + No comment provided by engineer. + Chat preferences Preferenze della chat @@ -1181,7 +1185,7 @@ Confirm new passphrase… - Conferma password nuova… + Conferma nuova password… No comment provided by engineer. @@ -1196,6 +1200,7 @@ Connect automatically + Connetti automaticamente No comment provided by engineer. @@ -1914,6 +1919,7 @@ Non è reversibile! Discover via local network + Individua via rete locale No comment provided by engineer. @@ -2061,6 +2067,10 @@ Non è reversibile! Messaggio crittografato o altro evento notification + + Encrypted message: app is stopped + notification + Encrypted message: database error Messaggio crittografato: errore del database @@ -2291,6 +2301,10 @@ Non è reversibile! Errore nel caricamento dei server %@ No comment provided by engineer. + + Error opening chat + No comment provided by engineer. + Error receiving file Errore nella ricezione del file @@ -2558,6 +2572,7 @@ Non è reversibile! Found desktop + Desktop trovato No comment provided by engineer. @@ -2977,6 +2992,10 @@ Non è reversibile! Nome non valido! No comment provided by engineer. + + Invalid response + No comment provided by engineer. + Invalid server address! Indirizzo del server non valido! @@ -3185,6 +3204,11 @@ Questo è il tuo link per il gruppo %@! Messaggi in diretta No comment provided by engineer. + + Local + Locale + No comment provided by engineer. + Local name Nome locale @@ -3527,6 +3551,7 @@ Questo è il tuo link per il gruppo %@! Not compatible! + Non compatibile! No comment provided by engineer. @@ -3553,11 +3578,6 @@ Questo è il tuo link per il gruppo %@! Off No comment provided by engineer. - - Off (Local) - Off (Locale) - No comment provided by engineer. - Ok Ok @@ -3698,9 +3718,8 @@ Questo è il tuo link per il gruppo %@! Protocollo e codice open source: chiunque può gestire i server. No comment provided by engineer. - - Opening database… - Apertura del database… + + Opening app… No comment provided by engineer. @@ -3803,6 +3822,11 @@ Questo è il tuo link per il gruppo %@! Controlla le preferenze tue e del tuo contatto. No comment provided by engineer. + + Please contact developers. +Error: %@ + No comment provided by engineer. + Please contact group admin. Contatta l'amministratore del gruppo. @@ -4720,7 +4744,7 @@ Questo è il tuo link per il gruppo %@! SimpleX contact address - Indirizzo del contatto SimpleX + Indirizzo di contatto SimpleX simplex link type @@ -4783,6 +4807,10 @@ Questo è il tuo link per il gruppo %@! Avvia chat No comment provided by engineer. + + Start chat? + No comment provided by engineer. + Start migration Avvia la migrazione @@ -5187,11 +5215,6 @@ Ti verrà chiesto di completare l'autenticazione prima di attivare questa funzio Spegni No comment provided by engineer. - - Turn off notifications? - Spegnere le notifiche? - No comment provided by engineer. - Turn on Attiva @@ -5394,6 +5417,10 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e Usa nuovo profilo in incognito No comment provided by engineer. + + Use only local notifications? + No comment provided by engineer. + Use server Usa il server @@ -5501,6 +5528,7 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e Waiting for desktop... + In attesa del desktop... No comment provided by engineer. @@ -5680,6 +5708,10 @@ Ripetere la richiesta di ingresso? Puoi nascondere o silenziare un profilo utente - scorrilo verso destra. No comment provided by engineer. + + You can make it visible to your SimpleX contacts via Settings. + No comment provided by engineer. + You can now send messages to %@ Ora puoi inviare messaggi a %@ @@ -5909,13 +5941,6 @@ Puoi annullare questa connessione e rimuovere il contatto (e riprovare più tard I tuoi contatti possono consentire l'eliminazione completa dei messaggi. No comment provided by engineer. - - Your contacts in SimpleX will see it. -You can change it in Settings. - I tuoi contatti in SimpleX lo vedranno. -Puoi modificarlo nelle impostazioni. - No comment provided by engineer. - Your contacts will remain connected. I tuoi contatti resteranno connessi. @@ -5995,7 +6020,7 @@ I server di SimpleX non possono vedere il tuo profilo. [Star on GitHub](https://github.com/simplex-chat/simplex-chat) - [Stella su GitHub](https://github.com/simplex-chat/simplex-chat) + [Dai una stella su GitHub](https://github.com/simplex-chat/simplex-chat) No comment provided by engineer. @@ -6050,6 +6075,7 @@ I server di SimpleX non possono vedere il tuo profilo. author + autore member role @@ -6631,7 +6657,7 @@ I server di SimpleX non possono vedere il tuo profilo. updated group profile - profilo del gruppo aggiornato + ha aggiornato il profilo del gruppo rcv group event chat item 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 11ca09ba3b..ac7f535e36 100644 --- a/apps/ios/SimpleX Localizations/ja.xcloc/Localized Contents/ja.xliff +++ b/apps/ios/SimpleX Localizations/ja.xcloc/Localized Contents/ja.xliff @@ -103,6 +103,7 @@ %@ connected + %@ 接続中 No comment provided by engineer. @@ -214,10 +215,12 @@ %lld messages marked deleted + %lld 件のメッセージが削除されました No comment provided by engineer. %lld messages moderated by %@ + %@ により%lld 件のメッセージが検閲されました No comment provided by engineer. @@ -1069,6 +1072,10 @@ チャットが停止してます No comment provided by engineer. + + Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat. + No comment provided by engineer. + Chat preferences チャット設定 @@ -2012,6 +2019,10 @@ This cannot be undone! 暗号化されたメッセージまたは別のイベント notification + + Encrypted message: app is stopped + notification + Encrypted message: database error 暗号化されたメッセージ : データベースエラー @@ -2236,6 +2247,10 @@ This cannot be undone! %@ サーバーのロード中にエラーが発生 No comment provided by engineer. + + Error opening chat + No comment provided by engineer. + Error receiving file ファイル受信にエラー発生 @@ -2913,6 +2928,10 @@ This cannot be undone! Invalid name! No comment provided by engineer. + + Invalid response + No comment provided by engineer. + Invalid server address! 無効なサーバアドレス! @@ -3113,6 +3132,11 @@ This is your link for group %@! ライブメッセージ No comment provided by engineer. + + Local + 自分のみ + No comment provided by engineer. + Local name ローカルネーム @@ -3479,11 +3503,6 @@ This is your link for group %@! オフ No comment provided by engineer. - - Off (Local) - オフ(自分のみ) - No comment provided by engineer. - Ok OK @@ -3623,9 +3642,8 @@ This is your link for group %@! プロトコル技術とコードはオープンソースで、どなたでもご自分のサーバを運用できます。 No comment provided by engineer. - - Opening database… - データベースを開いています… + + Opening app… No comment provided by engineer. @@ -3727,6 +3745,11 @@ This is your link for group %@! あなたと連絡先の設定を確認してください。 No comment provided by engineer. + + Please contact developers. +Error: %@ + No comment provided by engineer. + Please contact group admin. グループの管理者に連絡してください。 @@ -4692,6 +4715,10 @@ This is your link for group %@! チャットを開始する No comment provided by engineer. + + Start chat? + No comment provided by engineer. + Start migration 移行の開始 @@ -5089,11 +5116,6 @@ You will be prompted to complete authentication before this feature is enabled.< オフにする No comment provided by engineer. - - Turn off notifications? - 通知をオフにしますか? - No comment provided by engineer. - Turn on オンにする @@ -5290,6 +5312,10 @@ To connect, please ask your contact to create another connection link and check 新しいシークレットプロファイルを使用する No comment provided by engineer. + + Use only local notifications? + No comment provided by engineer. + Use server サーバを使う @@ -5564,6 +5590,10 @@ Repeat join request? ユーザープロファイルを右にスワイプすると、非表示またはミュートにすることができます。 No comment provided by engineer. + + You can make it visible to your SimpleX contacts via Settings. + No comment provided by engineer. + You can now send messages to %@ %@ にメッセージを送信できるようになりました @@ -5788,13 +5818,6 @@ You can cancel this connection and remove the contact (and try later with a new 連絡先がメッセージの完全削除を許可できます。 No comment provided by engineer. - - Your contacts in SimpleX will see it. -You can change it in Settings. - SimpleX の連絡先に表示されます。 -設定で変更できます。 - No comment provided by engineer. - Your contacts will remain connected. 連絡先は接続されたままになります。 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 094a30677a..6b90e549b4 100644 --- a/apps/ios/SimpleX Localizations/nl.xcloc/Localized Contents/nl.xliff +++ b/apps/ios/SimpleX Localizations/nl.xcloc/Localized Contents/nl.xliff @@ -770,7 +770,7 @@ Always use relay - Verbinden via relais + Altijd relay gebruiken No comment provided by engineer. @@ -1094,6 +1094,10 @@ Chat is gestopt No comment provided by engineer. + + Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat. + No comment provided by engineer. + Chat preferences Gesprek voorkeuren @@ -1618,7 +1622,7 @@ Dit is uw eigen eenmalige link! Delete and notify contact - Contact verwijderen en op de hoogte stellen + Verwijderen en contact op de hoogte stellen No comment provided by engineer. @@ -2063,6 +2067,10 @@ Dit kan niet ongedaan gemaakt worden! Versleuteld bericht of een andere gebeurtenis notification + + Encrypted message: app is stopped + notification + Encrypted message: database error Versleuteld bericht: database fout @@ -2293,6 +2301,10 @@ Dit kan niet ongedaan gemaakt worden! Fout bij het laden van %@ servers No comment provided by engineer. + + Error opening chat + No comment provided by engineer. + Error receiving file Fout bij ontvangen van bestand @@ -2425,7 +2437,7 @@ Dit kan niet ongedaan gemaakt worden! Expand - Uitbreiden + Uitklappen chat item action @@ -2962,7 +2974,7 @@ Dit kan niet ongedaan gemaakt worden! Instantly - Meteen + Direct No comment provided by engineer. @@ -2980,6 +2992,10 @@ Dit kan niet ongedaan gemaakt worden! Ongeldige naam! No comment provided by engineer. + + Invalid response + No comment provided by engineer. + Invalid server address! Ongeldig server adres! @@ -3188,6 +3204,11 @@ Dit is jouw link voor groep %@! Live berichten No comment provided by engineer. + + Local + Lokaal + No comment provided by engineer. + Local name Lokale naam @@ -3557,11 +3578,6 @@ Dit is jouw link voor groep %@! Uit No comment provided by engineer. - - Off (Local) - Uit (lokaal) - No comment provided by engineer. - Ok OK @@ -3702,9 +3718,8 @@ Dit is jouw link voor groep %@! Open-source protocol en code. Iedereen kan de servers draaien. No comment provided by engineer. - - Opening database… - Database openen… + + Opening app… No comment provided by engineer. @@ -3807,6 +3822,11 @@ Dit is jouw link voor groep %@! Controleer de uwe en uw contact voorkeuren. No comment provided by engineer. + + Please contact developers. +Error: %@ + No comment provided by engineer. + Please contact group admin. Neem contact op met de groep beheerder. @@ -4787,6 +4807,10 @@ Dit is jouw link voor groep %@! Begin gesprek No comment provided by engineer. + + Start chat? + No comment provided by engineer. + Start migration Start migratie @@ -5191,11 +5215,6 @@ U wordt gevraagd de authenticatie te voltooien voordat deze functie wordt ingesc Uitschakelen No comment provided by engineer. - - Turn off notifications? - Schakel meldingen uit? - No comment provided by engineer. - Turn on Zet aan @@ -5398,6 +5417,10 @@ Om verbinding te maken, vraagt u uw contact om een andere verbinding link te mak Gebruik een nieuw incognitoprofiel No comment provided by engineer. + + Use only local notifications? + No comment provided by engineer. + Use server Gebruik server @@ -5685,6 +5708,10 @@ Deelnameverzoek herhalen? U kunt een gebruikers profiel verbergen of dempen - veeg het naar rechts. No comment provided by engineer. + + You can make it visible to your SimpleX contacts via Settings. + No comment provided by engineer. + You can now send messages to %@ Je kunt nu berichten sturen naar %@ @@ -5914,13 +5941,6 @@ U kunt deze verbinding verbreken en het contact verwijderen en later proberen me Uw contacten kunnen volledige verwijdering van berichten toestaan. No comment provided by engineer. - - Your contacts in SimpleX will see it. -You can change it in Settings. - Uw contacten in SimpleX kunnen het zien. -U kunt dit wijzigen in Instellingen. - No comment provided by engineer. - Your contacts will remain connected. Uw contacten blijven verbonden. @@ -6667,7 +6687,7 @@ SimpleX servers kunnen uw profiel niet zien. via relay - via relais + via relay No comment provided by engineer. 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 ad1924f4c4..1ab569e3c3 100644 --- a/apps/ios/SimpleX Localizations/pl.xcloc/Localized Contents/pl.xliff +++ b/apps/ios/SimpleX Localizations/pl.xcloc/Localized Contents/pl.xliff @@ -1094,6 +1094,10 @@ Czat jest zatrzymany No comment provided by engineer. + + Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat. + No comment provided by engineer. + Chat preferences Preferencje czatu @@ -2063,6 +2067,10 @@ To nie może być cofnięte! Zaszyfrowana wiadomość lub inne zdarzenie notification + + Encrypted message: app is stopped + notification + Encrypted message: database error Zaszyfrowana wiadomość: błąd bazy danych @@ -2293,6 +2301,10 @@ To nie może być cofnięte! Błąd ładowania %@ serwerów No comment provided by engineer. + + Error opening chat + No comment provided by engineer. + Error receiving file Błąd odbioru pliku @@ -2980,6 +2992,10 @@ To nie może być cofnięte! Nieprawidłowa nazwa! No comment provided by engineer. + + Invalid response + No comment provided by engineer. + Invalid server address! Nieprawidłowy adres serwera! @@ -3188,6 +3204,11 @@ To jest twój link do grupy %@! Wiadomości na żywo No comment provided by engineer. + + Local + Lokalnie + No comment provided by engineer. + Local name Nazwa lokalna @@ -3557,11 +3578,6 @@ To jest twój link do grupy %@! Wyłączony No comment provided by engineer. - - Off (Local) - Wyłączony (Lokalnie) - No comment provided by engineer. - Ok Ok @@ -3702,9 +3718,8 @@ To jest twój link do grupy %@! Otwarto źródłowy protokół i kod - każdy może uruchomić serwery. No comment provided by engineer. - - Opening database… - Otwieranie bazy danych… + + Opening app… No comment provided by engineer. @@ -3807,6 +3822,11 @@ To jest twój link do grupy %@! Proszę sprawdzić preferencje Twoje i Twojego kontaktu. No comment provided by engineer. + + Please contact developers. +Error: %@ + No comment provided by engineer. + Please contact group admin. Skontaktuj się z administratorem grupy. @@ -4787,6 +4807,10 @@ To jest twój link do grupy %@! Rozpocznij czat No comment provided by engineer. + + Start chat? + No comment provided by engineer. + Start migration Rozpocznij migrację @@ -5191,11 +5215,6 @@ Przed włączeniem tej funkcji zostanie wyświetlony monit uwierzytelniania.Wyłącz No comment provided by engineer. - - Turn off notifications? - Wyłączyć powiadomienia? - No comment provided by engineer. - Turn on Włącz @@ -5398,6 +5417,10 @@ Aby się połączyć, poproś Twój kontakt o utworzenie kolejnego linku połąc Użyj nowego profilu incognito No comment provided by engineer. + + Use only local notifications? + No comment provided by engineer. + Use server Użyj serwera @@ -5685,6 +5708,10 @@ Powtórzyć prośbę dołączenia? Możesz ukryć lub wyciszyć profil użytkownika - przesuń palcem w prawo. No comment provided by engineer. + + You can make it visible to your SimpleX contacts via Settings. + No comment provided by engineer. + You can now send messages to %@ Możesz teraz wysyłać wiadomości do %@ @@ -5914,13 +5941,6 @@ Możesz anulować to połączenie i usunąć kontakt (i spróbować później z Twoje kontakty mogą zezwolić na pełne usunięcie wiadomości. No comment provided by engineer. - - Your contacts in SimpleX will see it. -You can change it in Settings. - Twoje kontakty w SimpleX będą to widzieć. -Możesz to zmienić w Ustawieniach. - No comment provided by engineer. - Your contacts will remain connected. Twoje kontakty pozostaną połączone. 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 f4970446ae..348b42c948 100644 --- a/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff +++ b/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff @@ -1094,6 +1094,10 @@ Чат остановлен No comment provided by engineer. + + Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat. + No comment provided by engineer. + Chat preferences Предпочтения @@ -2063,6 +2067,10 @@ This cannot be undone! Зашифрованное сообщение или событие чата notification + + Encrypted message: app is stopped + notification + Encrypted message: database error Зашифрованное сообщение: ошибка базы данных @@ -2293,6 +2301,10 @@ This cannot be undone! Ошибка загрузки %@ серверов No comment provided by engineer. + + Error opening chat + No comment provided by engineer. + Error receiving file Ошибка при получении файла @@ -2980,6 +2992,10 @@ This cannot be undone! Неверное имя! No comment provided by engineer. + + Invalid response + No comment provided by engineer. + Invalid server address! Ошибка в адресе сервера! @@ -3188,6 +3204,11 @@ This is your link for group %@! "Живые" сообщения No comment provided by engineer. + + Local + Локальные + No comment provided by engineer. + Local name Локальное имя @@ -3557,11 +3578,6 @@ This is your link for group %@! Выключено No comment provided by engineer. - - Off (Local) - Выключить (Локальные) - No comment provided by engineer. - Ok Ок @@ -3702,9 +3718,8 @@ This is your link for group %@! Открытый протокол и код - кто угодно может запустить сервер. No comment provided by engineer. - - Opening database… - Открытие базы данных… + + Opening app… No comment provided by engineer. @@ -3807,6 +3822,11 @@ This is your link for group %@! Проверьте предпочтения Вашего контакта. No comment provided by engineer. + + Please contact developers. +Error: %@ + No comment provided by engineer. + Please contact group admin. Пожалуйста, свяжитесь с админом группы. @@ -4787,6 +4807,10 @@ This is your link for group %@! Запустить чат No comment provided by engineer. + + Start chat? + No comment provided by engineer. + Start migration Запустить перемещение данных @@ -5191,11 +5215,6 @@ You will be prompted to complete authentication before this feature is enabled.< Выключить No comment provided by engineer. - - Turn off notifications? - Выключить уведомления? - No comment provided by engineer. - Turn on Включить @@ -5398,6 +5417,10 @@ To connect, please ask your contact to create another connection link and check Использовать новый Инкогнито профиль No comment provided by engineer. + + Use only local notifications? + No comment provided by engineer. + Use server Использовать сервер @@ -5685,6 +5708,10 @@ Repeat join request? Вы можете скрыть профиль или выключить уведомления - потяните его вправо. No comment provided by engineer. + + You can make it visible to your SimpleX contacts via Settings. + No comment provided by engineer. + You can now send messages to %@ Вы теперь можете отправлять сообщения %@ @@ -5914,13 +5941,6 @@ You can cancel this connection and remove the contact (and try later with a new Ваши контакты могут разрешить окончательное удаление сообщений. No comment provided by engineer. - - Your contacts in SimpleX will see it. -You can change it in Settings. - Ваши контакты в SimpleX получат этот адрес. -Вы можете изменить это в Настройках. - No comment provided by engineer. - Your contacts will remain connected. Ваши контакты сохранятся. 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 bcb39e6e03..c062999aa5 100644 --- a/apps/ios/SimpleX Localizations/th.xcloc/Localized Contents/th.xliff +++ b/apps/ios/SimpleX Localizations/th.xcloc/Localized Contents/th.xliff @@ -1059,6 +1059,10 @@ การแชทหยุดทํางานแล้ว No comment provided by engineer. + + Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat. + No comment provided by engineer. + Chat preferences ค่ากําหนดในการแชท @@ -1995,6 +1999,10 @@ This cannot be undone! ข้อความที่ encrypt หรือเหตุการณ์อื่น notification + + Encrypted message: app is stopped + notification + Encrypted message: database error ข้อความที่ encrypt: ความผิดพลาดในฐานข้อมูล @@ -2218,6 +2226,10 @@ This cannot be undone! โหลดเซิร์ฟเวอร์ %@ ผิดพลาด No comment provided by engineer. + + Error opening chat + No comment provided by engineer. + Error receiving file เกิดข้อผิดพลาดในการรับไฟล์ @@ -2894,6 +2906,10 @@ This cannot be undone! Invalid name! No comment provided by engineer. + + Invalid response + No comment provided by engineer. + Invalid server address! ที่อยู่เซิร์ฟเวอร์ไม่ถูกต้อง! @@ -3093,6 +3109,11 @@ This is your link for group %@! ข้อความสด No comment provided by engineer. + + Local + ในเครื่อง + No comment provided by engineer. + Local name ชื่อภายในเครื่องเท่านั้น @@ -3457,11 +3478,6 @@ This is your link for group %@! ปิด No comment provided by engineer. - - Off (Local) - ปิด (ในเครื่อง) - No comment provided by engineer. - Ok ตกลง @@ -3600,9 +3616,8 @@ This is your link for group %@! โปรโตคอลและโค้ดโอเพ่นซอร์ส – ใคร ๆ ก็สามารถเปิดใช้เซิร์ฟเวอร์ได้ No comment provided by engineer. - - Opening database… - กำลังเปิดฐานข้อมูล… + + Opening app… No comment provided by engineer. @@ -3703,6 +3718,11 @@ This is your link for group %@! โปรดตรวจสอบความต้องการของคุณและการตั้งค่าผู้ติดต่อ No comment provided by engineer. + + Please contact developers. +Error: %@ + No comment provided by engineer. + Please contact group admin. โปรดติดต่อผู้ดูแลกลุ่ม @@ -4669,6 +4689,10 @@ This is your link for group %@! เริ่มแชท No comment provided by engineer. + + Start chat? + No comment provided by engineer. + Start migration เริ่มการย้ายข้อมูล @@ -5066,11 +5090,6 @@ You will be prompted to complete authentication before this feature is enabled.< ปิด No comment provided by engineer. - - Turn off notifications? - ปิดการแจ้งเตือนไหม? - No comment provided by engineer. - Turn on เปิด @@ -5265,6 +5284,10 @@ To connect, please ask your contact to create another connection link and check Use new incognito profile No comment provided by engineer. + + Use only local notifications? + No comment provided by engineer. + Use server ใช้เซิร์ฟเวอร์ @@ -5539,6 +5562,10 @@ Repeat join request? คุณสามารถซ่อนหรือปิดเสียงโปรไฟล์ผู้ใช้ - ปัดไปทางขวา No comment provided by engineer. + + You can make it visible to your SimpleX contacts via Settings. + No comment provided by engineer. + You can now send messages to %@ ตอนนี้คุณสามารถส่งข้อความถึง %@ @@ -5762,13 +5789,6 @@ You can cancel this connection and remove the contact (and try later with a new ผู้ติดต่อของคุณสามารถอนุญาตให้ลบข้อความทั้งหมดได้ No comment provided by engineer. - - Your contacts in SimpleX will see it. -You can change it in Settings. - ผู้ติดต่อของคุณใน SimpleX จะเห็น -คุณสามารถเปลี่ยนได้ในการตั้งค่า - No comment provided by engineer. - Your contacts will remain connected. ผู้ติดต่อของคุณจะยังคงเชื่อมต่ออยู่ 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 4b2ad1548a..9f2e489bf3 100644 --- a/apps/ios/SimpleX Localizations/tr.xcloc/Localized Contents/tr.xliff +++ b/apps/ios/SimpleX Localizations/tr.xcloc/Localized Contents/tr.xliff @@ -5,25 +5,31 @@ - + + + No comment provided by engineer. - + + No comment provided by engineer. - + + No comment provided by engineer. - + + No comment provided by engineer. - + ( + ( No comment provided by engineer. @@ -343,8 +349,9 @@ 30 saniye No comment provided by engineer. - + : + : No comment provided by engineer. @@ -390,8 +397,9 @@ Abort changing address? No comment provided by engineer. - + About SimpleX + SimpleX Hakkında No comment provided by engineer. @@ -406,8 +414,9 @@ Accent color No comment provided by engineer. - + Accept + Kabul et accept contact request via notification accept incoming call via notification @@ -435,48 +444,57 @@ Add profile No comment provided by engineer. - + Add servers by scanning QR codes. + Karekod taratarak sunucuları ekleyin. No comment provided by engineer. - + Add server… + Sunucu ekle… No comment provided by engineer. Add to another device No comment provided by engineer. - + Add welcome message + Karşılama mesajı ekleyin No comment provided by engineer. - + Address + Adres No comment provided by engineer. - + Address change will be aborted. Old receiving address will be used. + Adres değişikliği iptal edilecek. Eski alıcı adresi kullanılacaktır. No comment provided by engineer. Admins can create the links to join groups. No comment provided by engineer. - + Advanced network settings + GGelişmiş ağ ayarları No comment provided by engineer. - + All app data is deleted. + Tüm uygulama verileri silinir. No comment provided by engineer. - + All chats and messages will be deleted - this cannot be undone! + Tüm konuşmalar ve mesajlar silinecektir. Bu, geri alınamaz! No comment provided by engineer. - + All data is erased when it is entered. + Kullanıldığında bütün veriler silinir. No comment provided by engineer. @@ -484,24 +502,29 @@ Tüm grup üyeleri bağlı kalacaktır. No comment provided by engineer. - + All messages will be deleted - this cannot be undone! The messages will be deleted ONLY for you. + Tüm mesajlar silinecektir. Bu, geri alınamaz! Mesajlar, YALNIZCA senin için silinecektir. No comment provided by engineer. - + All your contacts will remain connected. + Konuştuğun kişilerin tümü bağlı kalacaktır. No comment provided by engineer. - + All your contacts will remain connected. Profile update will be sent to your contacts. + Tüm kişileriniz bağlı kalacaktır. Profil güncellemesi kişilerinize gönderilecektir. No comment provided by engineer. - + Allow + İzin ver No comment provided by engineer. - + Allow calls only if your contact allows them. + Yalnızca irtibat kişiniz izin veriyorsa aramalara izin verin. No comment provided by engineer. @@ -512,8 +535,9 @@ Allow irreversible message deletion only if your contact allows it to you. No comment provided by engineer. - + Allow message reactions only if your contact allows them. + Yalnızca kişin mesaj tepkilerine izin veriyorsa sen de ver. No comment provided by engineer. @@ -525,32 +549,39 @@ Üyelere direkt mesaj göndermeye izin ver. No comment provided by engineer. - + Allow sending disappearing messages. + Kendiliğinden yok olan mesajlar göndermeye izin ver. No comment provided by engineer. - + Allow to irreversibly delete sent messages. + Gönderilen mesajların kalıcı olarak silinmesine izin ver. No comment provided by engineer. - + Allow to send files and media. + Dosya ve medya göndermeye izin ver. No comment provided by engineer. - + Allow to send voice messages. + Sesli mesaj göndermeye izin ver. No comment provided by engineer. - + Allow voice messages only if your contact allows them. + Yalnızca kişiniz sesli mesaj göndermeye izin veriyorsa sen de ver. No comment provided by engineer. - + Allow voice messages? + Sesli mesajlara izin ver? No comment provided by engineer. - + Allow your contacts adding message reactions. + Konuştuğun kişilerin mesajlarına tepki eklemesine izin ver. No comment provided by engineer. @@ -577,24 +608,28 @@ Always use relay No comment provided by engineer. - + An empty chat profile with the provided name is created, and the app opens as usual. + Verilen adla boş bir sohbet profili oluşturulur ve uygulama her zamanki gibi açılır. No comment provided by engineer. - + Answer call + Aramayı cevapla No comment provided by engineer. App build: %@ No comment provided by engineer. - + App icon + Uygulama simgesi No comment provided by engineer. - + App passcode + Uygulama erişim kodu No comment provided by engineer. @@ -4893,6 +4928,41 @@ SimpleX servers cannot see your profile. \~strike~ No comment provided by engineer. + + Accept connection request? + Bağlantı isteğini kabul et? + No comment provided by engineer. + + + # %@ + # %@ + copied message info title, # <title> + + + Already connecting! + Zaten bağlanılıyor! + No comment provided by engineer. + + + A few more things + Birkaç şey daha + No comment provided by engineer. + + + ## History + ## Geçmiş + copied message info + + + A new random profile will be shared. + Yeni bir rastgele profil paylaşılacak. + No comment provided by engineer. + + + Already joining the group! + Zaten gruba bağlanılıyor! + No comment provided by engineer. + 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 abd58231a9..2bb43ba736 100644 --- a/apps/ios/SimpleX Localizations/uk.xcloc/Localized Contents/uk.xliff +++ b/apps/ios/SimpleX Localizations/uk.xcloc/Localized Contents/uk.xliff @@ -89,6 +89,7 @@ %@ and %@ + %@ та %@ No comment provided by engineer. @@ -103,6 +104,7 @@ %@ connected + %@ підключено No comment provided by engineer. @@ -132,6 +134,7 @@ %@, %@ and %lld members + %@, %@ та %lld учасників No comment provided by engineer. @@ -201,6 +204,7 @@ %lld group events + %lld групові заходи No comment provided by engineer. @@ -210,14 +214,17 @@ %lld messages blocked + %lld повідомлень заблоковано No comment provided by engineer. %lld messages marked deleted + %lld повідомлень позначено як видалені No comment provided by engineer. %lld messages moderated by %@ + %lld повідомлень модерує %@ No comment provided by engineer. @@ -227,6 +234,7 @@ %lld new interface languages + %lld нові мови інтерфейсу No comment provided by engineer. @@ -291,10 +299,12 @@ (new) + (новий) No comment provided by engineer. (this device v%@) + (цей пристрій v%@) No comment provided by engineer. @@ -371,6 +381,9 @@ - connect to [directory service](simplex:/contact#/?v=1-4&smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion) (BETA)! - delivery receipts (up to 20 members). - faster and more stable. + - підключитися до [сервера каталогів](simplex:/contact#/?v=1-4&smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex. im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id. цибуля) (БЕТА)! +- підтвердження доставлення (до 20 учасників). +- швидше і стабільніше. No comment provided by engineer. @@ -386,6 +399,9 @@ - optionally notify deleted contacts. - profile names with spaces. - and more! + - опція сповіщати про видалені контакти. +- імена профілів з пробілами. +- та багато іншого! No comment provided by engineer. @@ -404,6 +420,7 @@ 0 sec + 0 сек time to disappear @@ -633,6 +650,7 @@ All new messages from %@ will be hidden! + Всі нові повідомлення від %@ будуть приховані! No comment provided by engineer. @@ -742,10 +760,12 @@ Already connecting! + Вже підключаємось! No comment provided by engineer. Already joining the group! + Вже приєднуємося до групи! No comment provided by engineer. @@ -770,6 +790,7 @@ App encrypts new local files (except videos). + Додаток шифрує нові локальні файли (крім відео). No comment provided by engineer. @@ -869,6 +890,7 @@ Bad desktop address + Неправильна адреса робочого столу No comment provided by engineer. @@ -883,6 +905,7 @@ Better groups + Кращі групи No comment provided by engineer. @@ -892,18 +915,22 @@ Block + Блокувати No comment provided by engineer. Block group members + Учасники групи блокування No comment provided by engineer. Block member + Заблокувати користувача No comment provided by engineer. Block member? + Заблокувати користувача? No comment provided by engineer. @@ -933,6 +960,7 @@ Bulgarian, Finnish, Thai and Ukrainian - thanks to the users and [Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)! + Болгарською, фінською, тайською та українською мовами - завдяки користувачам та [Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)! No comment provided by engineer. @@ -1066,6 +1094,10 @@ Чат зупинено No comment provided by engineer. + + Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat. + No comment provided by engineer. + Chat preferences Налаштування чату @@ -1168,6 +1200,7 @@ Connect automatically + Підключення автоматично No comment provided by engineer. @@ -1177,24 +1210,31 @@ Connect to desktop + Підключення до комп'ютера No comment provided by engineer. Connect to yourself? + З'єднатися з самим собою? No comment provided by engineer. Connect to yourself? This is your own SimpleX address! + З'єднатися з самим собою? +Це ваша власна SimpleX-адреса! No comment provided by engineer. Connect to yourself? This is your own one-time link! + Підключитися до себе? +Це ваше власне одноразове посилання! No comment provided by engineer. Connect via contact address + Підключіться за контактною адресою No comment provided by engineer. @@ -1214,10 +1254,12 @@ This is your own one-time link! Connect with %@ + Підключитися до %@ No comment provided by engineer. Connected desktop + Підключений робочий стіл No comment provided by engineer. @@ -2005,6 +2047,10 @@ This cannot be undone! Зашифроване повідомлення або інша подія notification + + Encrypted message: app is stopped + notification + Encrypted message: database error Зашифроване повідомлення: помилка бази даних @@ -2228,6 +2274,10 @@ This cannot be undone! Помилка завантаження %@ серверів No comment provided by engineer. + + Error opening chat + No comment provided by engineer. + Error receiving file Помилка отримання файлу @@ -2905,6 +2955,10 @@ This cannot be undone! Invalid name! No comment provided by engineer. + + Invalid response + No comment provided by engineer. + Invalid server address! Неправильна адреса сервера! @@ -3105,6 +3159,11 @@ This is your link for group %@! Живі повідомлення No comment provided by engineer. + + Local + Локально + No comment provided by engineer. + Local name Місцева назва @@ -3471,11 +3530,6 @@ This is your link for group %@! Вимкнено No comment provided by engineer. - - Off (Local) - Вимкнено (локально) - No comment provided by engineer. - Ok Гаразд @@ -3614,9 +3668,8 @@ This is your link for group %@! Протокол і код з відкритим вихідним кодом - будь-хто може запускати сервери. No comment provided by engineer. - - Opening database… - Відкриття бази даних… + + Opening app… No comment provided by engineer. @@ -3718,6 +3771,11 @@ This is your link for group %@! Будь ласка, перевірте свої та контактні налаштування. No comment provided by engineer. + + Please contact developers. +Error: %@ + No comment provided by engineer. + Please contact group admin. Зверніться до адміністратора групи. @@ -4690,6 +4748,10 @@ This is your link for group %@! Почати чат No comment provided by engineer. + + Start chat? + No comment provided by engineer. + Start migration Почати міграцію @@ -5088,11 +5150,6 @@ You will be prompted to complete authentication before this feature is enabled.< Вимкнути No comment provided by engineer. - - Turn off notifications? - Вимкнути сповіщення? - No comment provided by engineer. - Turn on Ввімкнути @@ -5289,6 +5346,10 @@ To connect, please ask your contact to create another connection link and check Використовуйте новий профіль інкогніто No comment provided by engineer. + + Use only local notifications? + No comment provided by engineer. + Use server Використовувати сервер @@ -5563,6 +5624,10 @@ Repeat join request? Ви можете приховати або вимкнути звук профілю користувача - проведіть по ньому вправо. No comment provided by engineer. + + You can make it visible to your SimpleX contacts via Settings. + No comment provided by engineer. + You can now send messages to %@ Тепер ви можете надсилати повідомлення на адресу %@ @@ -5787,13 +5852,6 @@ You can cancel this connection and remove the contact (and try later with a new Ваші контакти можуть дозволити повне видалення повідомлень. No comment provided by engineer. - - Your contacts in SimpleX will see it. -You can change it in Settings. - Ваші контакти в SimpleX побачать це. -Ви можете змінити його в Налаштуваннях. - No comment provided by engineer. - Your contacts will remain connected. Ваші контакти залишаться на зв'язку. 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 d96537be3e..6a07b28157 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 @@ -1072,6 +1072,10 @@ 聊天已停止 No comment provided by engineer. + + Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat. + No comment provided by engineer. + Chat preferences 聊天偏好设置 @@ -2015,6 +2019,10 @@ This cannot be undone! 加密消息或其他事件 notification + + Encrypted message: app is stopped + notification + Encrypted message: database error 加密消息:数据库错误 @@ -2240,6 +2248,10 @@ This cannot be undone! 加载 %@ 服务器错误 No comment provided by engineer. + + Error opening chat + No comment provided by engineer. + Error receiving file 接收文件错误 @@ -2918,6 +2930,10 @@ This cannot be undone! Invalid name! No comment provided by engineer. + + Invalid response + No comment provided by engineer. + Invalid server address! 无效的服务器地址! @@ -3118,6 +3134,11 @@ This is your link for group %@! 实时消息 No comment provided by engineer. + + Local + 本地 + No comment provided by engineer. + Local name 本地名称 @@ -3485,11 +3506,6 @@ This is your link for group %@! 关闭 No comment provided by engineer. - - Off (Local) - 关闭(本地) - No comment provided by engineer. - Ok 好的 @@ -3629,9 +3645,8 @@ This is your link for group %@! 开源协议和代码——任何人都可以运行服务器。 No comment provided by engineer. - - Opening database… - 打开数据库中…… + + Opening app… No comment provided by engineer. @@ -3733,6 +3748,11 @@ This is your link for group %@! 请检查您和您的联系人偏好设置。 No comment provided by engineer. + + Please contact developers. +Error: %@ + No comment provided by engineer. + Please contact group admin. 请联系群组管理员。 @@ -4707,6 +4727,10 @@ This is your link for group %@! 开始聊天 No comment provided by engineer. + + Start chat? + No comment provided by engineer. + Start migration 开始迁移 @@ -5106,11 +5130,6 @@ You will be prompted to complete authentication before this feature is enabled.< 关闭 No comment provided by engineer. - - Turn off notifications? - 关闭通知? - No comment provided by engineer. - Turn on 打开 @@ -5307,6 +5326,10 @@ To connect, please ask your contact to create another connection link and check 使用新的隐身配置文件 No comment provided by engineer. + + Use only local notifications? + No comment provided by engineer. + Use server 使用服务器 @@ -5581,6 +5604,10 @@ Repeat join request? 您可以隐藏或静音用户个人资料——只需向右滑动。 No comment provided by engineer. + + You can make it visible to your SimpleX contacts via Settings. + No comment provided by engineer. + You can now send messages to %@ 您现在可以给 %@ 发送消息 @@ -5805,13 +5832,6 @@ You can cancel this connection and remove the contact (and try later with a new 您的联系人可以允许完全删除消息。 No comment provided by engineer. - - Your contacts in SimpleX will see it. -You can change it in Settings. - 您的 SimpleX 的联系人会看到它。 -您可以在设置中更改它。 - No comment provided by engineer. - Your contacts will remain connected. 与您的联系人保持连接。 diff --git a/apps/ios/SimpleX Localizations/zh-Hant.xcloc/Localized Contents/zh-Hant.xliff b/apps/ios/SimpleX Localizations/zh-Hant.xcloc/Localized Contents/zh-Hant.xliff index 821db2620f..03a108d112 100644 --- a/apps/ios/SimpleX Localizations/zh-Hant.xcloc/Localized Contents/zh-Hant.xliff +++ b/apps/ios/SimpleX Localizations/zh-Hant.xcloc/Localized Contents/zh-Hant.xliff @@ -5868,6 +5868,36 @@ It can happen because of some bug or when the connection is compromised.你和你的聯絡人可以新增訊息互動。 No comment provided by engineer. + + %@ connected + %@ 已連接 + No comment provided by engineer. + + + # %@ + # %@ + copied message info title, # <title> + + + %@ and %@ + %@ 和 %@ + No comment provided by engineer. + + + ## History + 紀錄 + copied message info + + + ## In reply to + 回覆 + copied message info + + + %@ and %@ connected + %@ 和 %@ 已連接 + No comment provided by engineer. + diff --git a/apps/ios/bg.lproj/Localizable.strings b/apps/ios/bg.lproj/Localizable.strings index 5a704457d1..bf911b55f7 100644 --- a/apps/ios/bg.lproj/Localizable.strings +++ b/apps/ios/bg.lproj/Localizable.strings @@ -1959,6 +1959,9 @@ /* No comment provided by engineer. */ "Live messages" = "Съобщения на живо"; +/* No comment provided by engineer. */ +"Local" = "Локално"; + /* No comment provided by engineer. */ "Local name" = "Локално име"; @@ -2222,9 +2225,6 @@ /* No comment provided by engineer. */ "Off" = "Изключено"; -/* No comment provided by engineer. */ -"Off (Local)" = "Изключено (Локално)"; - /* feature offered item */ "offered %@" = "предлага %@"; @@ -2315,9 +2315,6 @@ /* No comment provided by engineer. */ "Open-source protocol and code – anybody can run the servers." = "Протокол и код с отворен код – всеки може да оперира собствени сървъри."; -/* No comment provided by engineer. */ -"Opening database…" = "Отваряне на база данни…"; - /* member role */ "owner" = "собственик"; @@ -3218,9 +3215,6 @@ /* No comment provided by engineer. */ "Turn off" = "Изключи"; -/* No comment provided by engineer. */ -"Turn off notifications?" = "Изключи известията?"; - /* No comment provided by engineer. */ "Turn on" = "Включи"; @@ -3641,9 +3635,6 @@ /* No comment provided by engineer. */ "Your contacts can allow full message deletion." = "Вашите контакти могат да позволят пълното изтриване на съобщението."; -/* No comment provided by engineer. */ -"Your contacts in SimpleX will see it.\nYou can change it in Settings." = "Вашите контакти в SimpleX ще го видят.\nМожете да го промените в Настройки."; - /* No comment provided by engineer. */ "Your contacts will remain connected." = "Вашите контакти ще останат свързани."; diff --git a/apps/ios/cs.lproj/Localizable.strings b/apps/ios/cs.lproj/Localizable.strings index 26469bea98..ef7eff477d 100644 --- a/apps/ios/cs.lproj/Localizable.strings +++ b/apps/ios/cs.lproj/Localizable.strings @@ -1956,6 +1956,9 @@ /* No comment provided by engineer. */ "Live messages" = "Živé zprávy"; +/* No comment provided by engineer. */ +"Local" = "Místní"; + /* No comment provided by engineer. */ "Local name" = "Místní název"; @@ -2219,9 +2222,6 @@ /* No comment provided by engineer. */ "Off" = "Vypnout"; -/* No comment provided by engineer. */ -"Off (Local)" = "Vypnuto (místní)"; - /* feature offered item */ "offered %@" = "nabídl %@"; @@ -2312,9 +2312,6 @@ /* No comment provided by engineer. */ "Open-source protocol and code – anybody can run the servers." = "Protokol a kód s otevřeným zdrojovým kódem - servery může provozovat kdokoli."; -/* No comment provided by engineer. */ -"Opening database…" = "Otvírání databáze…"; - /* member role */ "owner" = "vlastník"; @@ -3215,9 +3212,6 @@ /* No comment provided by engineer. */ "Turn off" = "Vypnout"; -/* No comment provided by engineer. */ -"Turn off notifications?" = "Vypnout upozornění?"; - /* No comment provided by engineer. */ "Turn on" = "Zapnout"; @@ -3638,9 +3632,6 @@ /* No comment provided by engineer. */ "Your contacts can allow full message deletion." = "Vaše kontakty mohou povolit úplné mazání zpráv."; -/* No comment provided by engineer. */ -"Your contacts in SimpleX will see it.\nYou can change it in Settings." = "Vaše kontakty v SimpleX ji uvidí.\nMůžete ji změnit v Nastavení."; - /* No comment provided by engineer. */ "Your contacts will remain connected." = "Vaše kontakty zůstanou připojeny."; diff --git a/apps/ios/de.lproj/Localizable.strings b/apps/ios/de.lproj/Localizable.strings index febd4c06a5..12e4e8de78 100644 --- a/apps/ios/de.lproj/Localizable.strings +++ b/apps/ios/de.lproj/Localizable.strings @@ -2163,6 +2163,9 @@ /* No comment provided by engineer. */ "Live messages" = "Live Nachrichten"; +/* No comment provided by engineer. */ +"Local" = "Lokal"; + /* No comment provided by engineer. */ "Local name" = "Lokaler Name"; @@ -2432,9 +2435,6 @@ /* No comment provided by engineer. */ "Off" = "Aus"; -/* No comment provided by engineer. */ -"Off (Local)" = "Aus (Lokal)"; - /* feature offered item */ "offered %@" = "angeboten %@"; @@ -2528,9 +2528,6 @@ /* No comment provided by engineer. */ "Open-source protocol and code – anybody can run the servers." = "Open-Source-Protokoll und -Code – Jede Person kann ihre eigenen Server aufsetzen und nutzen."; -/* No comment provided by engineer. */ -"Opening database…" = "Öffne Datenbank …"; - /* member role */ "owner" = "Eigentümer"; @@ -3467,9 +3464,6 @@ /* No comment provided by engineer. */ "Turn off" = "Abschalten"; -/* No comment provided by engineer. */ -"Turn off notifications?" = "Benachrichtigungen abschalten?"; - /* No comment provided by engineer. */ "Turn on" = "Einschalten"; @@ -3959,9 +3953,6 @@ /* No comment provided by engineer. */ "Your contacts can allow full message deletion." = "Ihre Kontakte können die unwiederbringliche Löschung von Nachrichten erlauben."; -/* No comment provided by engineer. */ -"Your contacts in SimpleX will see it.\nYou can change it in Settings." = "Ihre Kontakte in SimpleX werden es sehen.\nSie können es in den Einstellungen ändern."; - /* No comment provided by engineer. */ "Your contacts will remain connected." = "Ihre Kontakte bleiben verbunden."; diff --git a/apps/ios/es.lproj/Localizable.strings b/apps/ios/es.lproj/Localizable.strings index d9b14eddbd..714692843d 100644 --- a/apps/ios/es.lproj/Localizable.strings +++ b/apps/ios/es.lproj/Localizable.strings @@ -25,6 +25,9 @@ /* No comment provided by engineer. */ "- more stable message delivery.\n- a bit better groups.\n- and more!" = "- entrega de mensajes más estable.\n- grupos un poco mejores.\n- ¡y más!"; +/* No comment provided by engineer. */ +"- optionally notify deleted contacts.\n- profile names with spaces.\n- and more!" = "- notificar opcionalmente a los contactos eliminados.\n- nombres de perfil con espacios.\n- ¡...y más!"; + /* No comment provided by engineer. */ "- voice messages up to 5 minutes.\n- custom time to disappear.\n- editing history." = "- mensajes de voz de hasta 5 minutos.\n- tiempo personalizado para mensajes temporales.\n- historial de edición."; @@ -43,6 +46,12 @@ /* No comment provided by engineer. */ "(" = "("; +/* No comment provided by engineer. */ +"(new)" = "(nuevo)"; + +/* No comment provided by engineer. */ +"(this device v%@)" = "(este dispositivo v%@)"; + /* No comment provided by engineer. */ ")" = ")"; @@ -118,12 +127,18 @@ /* No comment provided by engineer. */ "%@ %@" = "%@ %@"; +/* No comment provided by engineer. */ +"%@ and %@" = "%@ y %@"; + /* No comment provided by engineer. */ "%@ and %@ connected" = "%@ y %@ conectados"; /* copied message info, at odeslat přímou zprávu + smazaný kontakt + Chyba + Vytvořit profil + Připojený počítač + %s a %s + Připojit se automaticky + Adresa počítače + Připojit se do skupiny? + Skupina již existuje! + %s připojený + Toto zařízení + Počítač + Jméno tohoto zařízení + Počítač nalezen + Smazat %d zpráv? + Odebrat člena + Připojený telefon + Odebrat člena? + Otevřít skupinu + Spojení ukončeno + Chyba + Připojit se k počítači + Odpojit + Neplatné jméno! + Autor + Připojený k telefonu + Špatná adresa počítače + Zařízení + Odpojit počítač? + Vytvořit skupinu + Kód relace + Vložit adres počítače + Blokovaný + Lepší skupiny \ No newline at end of file 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 a36eca6663..7401c0d4d9 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/de/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/de/strings.xml @@ -271,7 +271,7 @@ Über Link verbinden Wenn Sie einen SimpleX-Chat-Einladungslink erhalten haben, können Sie ihn in Ihrem Browser öffnen: QR-Code scannen.]]> - In mobiler App öffnen“ und dann auf „Verbinden“.]]> + In mobiler App öffnen“ und dann auf „Verbinden“.]]> Die Verbindungsanfrage akzeptieren? Wenn Sie ablehnen, wird der Absender NICHT benachrichtigt. @@ -1603,4 +1603,14 @@ Gefundener Desktop Nicht kompatibel! Über das lokale Netzwerk auffindbar + Aktualisieren + Chat-Profil erstellen + Mobiltelefone trennen + Kein Mobiltelefon verbunden + Zufällig + Um einer Mobiltelefon-App die Verbindung zum Desktop zu ermöglichen, öffnen Sie diesen Port in Ihrer Firewall, falls Sie diese aktiviert haben + Port in Firewall öffnen + Ansicht abgestürzt + Fehler beim Anzeigen des Inhalts + Fehler beim Anzeigen der Nachricht \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/el/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/el/strings.xml index 7063eb9007..d697fd4f64 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/el/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/el/strings.xml @@ -56,4 +56,168 @@ Να χρησιμοποιείται πάντα αναμεταδότη Αναζήτηση Ανενεργό + "Το προφίλ σας %1$s θα μοιραστεί" + Η SimpleX διεύθυνση σας + Αντίγραφο δεδομένων εφαρμογής + 5 λεπτά + Θα συνδεθείτε όταν η συσκευή της επαφής σας είναι συνδεμένει, παρακαλώ περιμένετε ή ελέγξτε αργότερα! + Ο ICE διακομιστής σας + Έκδοση εφαρμογής + Στείλατε πρόσκληση ομάδας + 1 λεπτό + Ο διακομιστής σας + Διεύθυνση + Ακύρωση + Πίσω + 30 δευτερόλεπτα + Θα συνδεθείτε με όλα τα μέλη της ομάδας. + %1$s θέλει να συνδεθεί μαζί σου μέσω + Επιτρέπονται αντιδράσεις μηνύματος. + Ο διακομιστής XFTP σας + Η διεύθυνση του διακομιστή σας + Το προφίλ, επαφές και παραδομένα μηνύματα σας είναι αποθηκευμένα στην συσκευή σας. + Ο διακομιστής SMP σας + Επιτρέπεται να σταλούν αρχεία και μέσα. + Το τυχαίο προφίλ σας + %1$s ΜΕΛΗ + Επιτρέπεται + Οι προτιμήσεις σας + Συντάκτης + Ο ΙCE διακομιστής σας + Κωδικός εφαρμογής + Αίτημα σύνδεσης θα σταλεί σε αυτό το μέλος της ομάδας. + ΟΙΚΟΝΑ ΕΦΑΡΜΟΓΗΣ + Εφαρμογή + Οι ρυθμίσεις σας + Έκδοση εφαρμογής: v%s + σφάλμα κλήσης + "ακυρώθηκε %s" + ακύρωση πρόβλεψη συνδέσμου + Αλλαγή κωδικού πρόσβασης βάση δεδομένων? + Αλλαγή κωδικού πρόσβασης + Αλλαγή ρόλου του %s σε %s + Φόντο + Δεν είναι δυνατή η προετοιμασία της βάσης δεδομένων + Ένα νέο τυχαίο προφίλ θα μοιραστεί. + Δεν είναι δυνατή η πρόσκληση επαφών! + Αρχείο συνομιλίας + Αλλαγή διεύθυνσης λήψης + Πιστοποίηση μη διαθέσιμη + Αλλαγή + " +\nΔιαθέσιμο στην έκδοση 5.1" + Τέλος κλήσης + ΚΛΗΣΕΙΣ + Αυτόματη αποδοχή + %1$d αποτυχία κρυπτογράφησης μηνύματος + αλλαγή διεύθυνσης για %s… + Αλλαγή ρόλου ομάδας; + ΑΡΧΕΙΟ ΣΥΝΟΜΙΛΙΑΣ + Δεν είναι δυνατή η πρόσκληση επαφής! + Αυτόματη αποδοχή αιτήματος επαφής + Κλήση… + Ακύρωση πρόβλεψη αρχείου + Φραγή + Ακύρωση πρόβλεψη εικόνας + αλλαγή διεύθυνσης… + Μερικά παραπάνω πράγματα + Πιστοποίηση ακυρώθηκε + Αλλαγή κωδικού αυτοκαταστροφής + Αλλαγή ρολου + Ακύρωση ζωντανών μυνημάτων + Όλα τα δεδομένα της εφαρμογής διαγράφηκαν. + Εμφάνιση + Τέλος κλήσης %1$s + Ακύρωση + Αλλαγή διεύθυνσης λήψης; + αλλαγή διεύθυνσης… + Αλλαγή λειτουργίας αυτοκαταστροφής + Κάμερα + κλήση σε εξέλιξη + Αυτόματη αποδοχή εικόνων + Αλλαγή του ρόλου σας σε %s + Κλήση σε εξέλιξη + Πιστοποίηση απέτυχε + "σύνδεση %1$d" + Δημιουργία διεύθυνση SimpleX + επαφή έχει κρυπτογράφηση από άκρο σε άκρο + Δημιουργία μια ομάδας χρησιμοποιώντας ένα τυχαίο προφίλ. + Δημιουργία ομάδας + Δημιουργία προφίλ + Η επαφή και όλα τα μηνύματα θα διαγραφούν - αυτό δεν μπορεί να αναιρεθεί! + Δημιουργία προφίλ + Οι επαφές μπορούν να επισημάνουν μηνύματα προς διαγραφή; θα μπορείτε να τα δείτε. + Σύνδεση μέσω μιας εφάπαξ σύνδεσης; + Δημιουργία σύνδεσμου + Σύνδεση μέσω σύνδεσμο/κωδικό γρήγορης ανταπόκρισης + Σφάλμα σύνδεσης (πιστοποίηση) + συνδέεται + συνδέεται… + Όνομα επαφής + Δημιουργία διεύθυνσης + Αντιγραφή + Συνέχεια + Σύνδεση μέσω σύνδεσμο; + Επαφή υπάρχει ήδη + Σύνδεση στον εαυτό σας; + Δημιουργία μυστικής ομάδας + Συνδεδεμένη σε επιφάνεια εργασίας + δημιουργός + Αίτημα σύνδεσης στάλθηκε! + Συνδεμένο σε επιφάνεια εργασίας + Σύνδεση + Διόρθωση ονόματος σε %s; + Λήξη χρονικού ορίου σύνδεσης + σύνδεση (αποδεκτή) + Σύνδεση με %1$s? + Δημιουργία του προφίλ σου + συνδέεται… + Δημιουργία + Προτιμήσεις επαφής + Συνδεδεμένο κινητό + Σύνδεση + Δημιουργία προφίλ συνομιλίας + συνδέεται… + Σύνδεση τερματίστηκε + Συνδε + Σύνδεση ανώνυμης περιήγησης + σύνδεση επετεύχθη + επαφή δεν έχει κρυπτογράφηση από άκρο σε άκρο + Επαφή επιτρέπει + σύνδεση (ανακοινώθηκε) + Συνδεδεμένος + συνδέεται… + Δημιουργία σύνδεσμο ομάδας + Σύνδεση σε επιφάνεια εργασίας + Δημιουργήθηκε στις %1$s + Συνδεδεμένο στο κινητό + Σύνδεση μέσω σύνδεσμο + Επαφές + Δημιουργία αρχείου + Δημιουργία μυστικής ομάδας + Σφάλμα σύνδεσης + Η επαφή δεν είναι συνδράμει αυτή τη στιγμή! + Συνδεδεμένο απευθείας + Η ιδιωτικότητά σας + Η επαφή σας έστειλε ένα αρχείο το οποίο είναι μεγαλύτερο από το παρόν υποστηριζόμενο μέγεθος (%1$s). + Το προφίλ της συνομιλίας σας θα σταλεί στην επαφή σας + Χρήση νέου ανώνυμου προφίλ + Ήδη συνδέεται + Απορρίψατε την πρόσκληση της ομάδας + Σύνδεση μέσω διεύθυνση επαφής + Χρήση του τρέχων προφίλ + Σύνδεση + Το τρέχον προφίλ σας + αφαιρέσατε %1$s + "Συμμετοχή ομάδας;" + Οι επαφες σας θα παραμένουν συνδεδεμένες. + Προσπάθεια σύνδεσης με τον διακομιστή που χρησιμοποιείται για τη λήψη μηνυμάτων από αυτήν την επαφή. + Το προφίλ σου θα σταλεί στην επαφή από την οποία έλαβες αυτόν τον σύνδεσμο. + σφάλμα + Άνοιγμα βάση δεδομένων… + Η προβολή συνετρίβη + συνδεδεμένο + Κοινοποιήσατε μια μη έγκυρη διαδρομή αρχείου. Αναφέρετε το πρόβλημα στους προγραμματιστές της εφαρμογής. + Μη έγκυρη διαδρομή αρχείου + Είστε συνδεδεμένοι στον διακομιστή που χρησιμοποιείται για τη λήψη μηνυμάτων από αυτήν την επαφή. \ No newline at end of file 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 246ed36859..a656b932de 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/es/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/es/strings.xml @@ -3,8 +3,8 @@ Autenticación no disponible Aceptar Configuración avanzada de red - Mejor para la batería. Recibirás notificaciones sólo cuando la aplicación se esté ejecutando, SIN servicio en segundo plano.]]> - Bueno para la batería. El servicio en segundo plano comprueba si hay mensajes cada 10 minutos. Puedes perder llamadas o mensajes urgentes.]]> + Óptimo para la batería. Recibirás notificaciones sólo cuando la aplicación esté abierta (SIN servicio en segundo plano).]]> + Bueno para la batería. El servicio en segundo plano comprueba si hay mensajes cada 10 minutos. Podrías no recibir a tiempo llamadas o mensajes urgentes.]]> Aceptar Copia de seguridad de los datos de la aplicación un dia @@ -76,7 +76,7 @@ Solicita recibir la imagen Atención: NO podrás recuperar o cambiar la contraseña si la pierdes.]]> Tanto tú como tu contacto podéis enviar mensajes de voz. - ¡Consume más batería! El servicio en segundo plano se ejecuta siempre y las notificaciones se mostrarán en cuanto haya mensajes disponibles.]]> + ¡Consume más batería! El servicio en segundo plano se ejecuta continuamente y las notificaciones se mostrarán de inmediato.]]> Tanto tú como tu contacto podéis eliminar de forma irreversible los mensajes enviados. Tanto tú como tu contacto podéis enviar mensajes temporales. Escanear código QR: para conectar con tu contacto mediante su código QR.]]> @@ -162,7 +162,7 @@ Conectado Copiado en portapapeles Crea enlace de invitación de un uso. - Escanear código QR ]]> + Escanear código QR ]]> Eliminar Eliminar ¡El contacto aun no se ha conectado! @@ -184,13 +184,13 @@ Contacto oculto: Eliminar Editar - ¿Eliminar el mensaje de miembro\? + ¿Eliminar el mensaje del miembro? editado Error de decodificación Crear dirección Eliminar dirección ¿Eliminar la dirección\? - Nombre mostrado: + Nombre del perfil: conectando… Descentralizada La base de datos será cifrada. @@ -413,7 +413,7 @@ PARA CONSOLA Error al cambiar rol SERVIDORES - Introduce un nombre para el grupo: + Nombre del grupo: Preferencias de grupo Los miembros del grupo pueden enviar mensajes directos. Los miembros del grupo pueden eliminar mensajes de forma irreversible. @@ -452,7 +452,7 @@ Configuración de red No se usarán hosts .onion cifrado de extremo a extremo de 2 capas .]]> - Puede cambiarse más tarde en Configuración. + Puedes cambiar estos ajustes más tarde en Configuración. Instantánea Únete Únete en modo incógnito @@ -499,7 +499,7 @@ formato de mensaje no válido EN VIVO eliminado por el moderador - invitado a conectarse + invitación a conectarse ¡Las notificaciones instantáneas están desactivadas! mensaje nuevo Nueva solicitud de contacto @@ -553,7 +553,7 @@ expulsado ha sido invitado Sin contactos que añadir - Nuevo rol de miembro + Nuevo rol del miembro Rol inicial Nombre local Estado de la red @@ -713,7 +713,7 @@ Guardar y notificar a los miembros del grupo A menos que tu contacto haya eliminado la conexión o que este enlace ya se haya usado, podría ser un error. Por favor, notifícalo. \nPara conectarte, pide a tu contacto que cree otro enlace de conexión y comprueba que tienes buena conexión de red. - La aplicación recoge nuevos mensajes periódicamente por lo que usa un pequeño porcentaje de la batería al día. La aplicación no hace uso de notificaciones automáticas: los datos de tu dispositivo no se envían a los servidores. + 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 Este texto está disponible en Configuración @@ -722,7 +722,7 @@ Usando servidores SimpleX Chat. Aislamiento de transporte tachado - Usar Chat + Abrir SimpleX PROXY SOCKS TEMAS Detener @@ -764,8 +764,8 @@ Inciar chat nuevo Para exportar, importar o eliminar la base de datos debes detener Chat. Durante la parada no podrás recibir o enviar mensajes. Gracias por instalar SimpleX Chat! - Para proteger la privacidad, en lugar de los identificadores de usuario que usan el resto de plataformas, SimpleX dispone de identificadores para las colas de mensajes, independientes para cada uno de tus contactos. - Para proteger tu información, activa Bloqueo SimpleX. + Para proteger tu privacidad, en lugar de los identificadores de usuario que usan el resto de plataformas, SimpleX dispone de identificadores para las colas de mensajes, independientes para cada uno de tus contactos. + Para proteger tu información, activa el Bloqueo SimpleX. \nSe te pedirá que completes la autenticación antes de activar esta función. Al actualizar la configuración, el cliente se reconectará a todos los servidores. ¿Usar servidores SimpleX Chat\? @@ -838,7 +838,7 @@ Pulsa el botón Para iniciar un chat nuevo Cambiar servidor de recepción - Completamente descentralizado: sólo visible para los miembros. + Completamente descentralizado: sólo visible a los miembros. Para conectarte mediante enlace ¡Error en prueba del servidor! Algunos servidores no superaron la prueba: @@ -883,7 +883,7 @@ Tu contacto debe estar en línea para que se complete la conexión. \nPuedes cancelar esta conexión y eliminar el contacto (e intentarlo más tarde con un enlace nuevo). La base de datos actual será ELIMINADA y SUSTITUIDA por la importada. -\nEsta acción no se puede deshacer. Tu perfil, contactos, mensajes y archivos se perderán irreversiblemente. +\nEsta acción no podrá deshacerse. Tu perfil, contactos, mensajes y archivos actuales se perderán irreversiblemente. Tu perfil aleatorio Te conectarás cuando tu solicitud se acepte, por favor espera o compruébalo más tarde. Te conectarás cuando el dispositivo de tu contacto esté en línea, por favor espera o compruébalo más tarde. @@ -936,12 +936,12 @@ Permites SimpleX Tu perfil se enviará al contacto del que has recibido este enlace. - Te unirás al grupo al que hace referencia este enlace y te conectarás con sus miembros. + Te conectarás con todos los miembros del grupo. Estás conectado al servidor usado para recibir mensajes de este contacto. mediante enlace de dirección de contacto mediante enlace de grupo - has compartido enlace de un solo uso + enlace de un solo uso has compartido enlace de un solo uso en módo incógnito No tienes chats El contacto ha enviado un archivo mayor al máximo admitido (%1$s ). @@ -1002,7 +1002,7 @@ Puedes ocultar o silenciar un perfil. Mantenlo pulsado para abrir el menú. Seguirás recibiendo llamadas y notificaciones de los perfiles silenciados cuando estén activos. Ahora los administradores pueden: -\n- borrar mensajes de los miembros. +\n- eliminar mensajes de los miembros. \n- desactivar el rol miembro (a rol \"observador\") Para hacer visible tu perfil oculto, introduce la contraseña completa en el campo de búsqueda del menú Mis perfiles. Actualización de la base de datos @@ -1125,7 +1125,7 @@ Más información Si no puedes reunirte en persona, **muestra el código QR por videollamada**, o comparte el enlace. Para conectarse, tu contacto puede escanear el código QR o usar el enlace en la aplicación. - Crear tu dirección SimpleX + Crear dirección SimpleX Auto aceptar Vista previa Abriendo base de datos… @@ -1328,7 +1328,7 @@ ¡Confirmación de entrega de mensajes! - entrega de mensajes más estable. \n- grupos un poco mejores. -\n- ¡y más! +\n- ¡...y más! El envío de confirmaciones de entrega se activará para todos los contactos. ¡El doble check que nos faltaba! ✅ Puedes activar más tarde en Configuración @@ -1391,14 +1391,14 @@ Error al establecer contacto con el miembro Atención: los servidores de retransmisión están conectados mediante SOCKS proxy. Las llamadas y las previsualizaciones de enlaces usan conexión directa.]]> Cifra archivos locales - Nueva aplicación para PC! + Nueva aplicación para ordenador! 6 idiomas nuevos para el interfaz Cifrado de los nuevos archivos locales (excepto vídeos). Enviar mensaje directo para conectar Descubre y únete a grupos Modo incógnito simplificado Árabe, Búlgaro, Finlandés, Hebreo, Tailandés y Ucraniano - gracias a los usuarios y Weblate. - Crea perfil nuevo en la aplicación para PC. 💻 + Crea perfil nuevo en la aplicación para ordenador. 💻 Error al enviar invitación Activa incógnito al conectar. - conexión al servicio de directorio (BETA)! @@ -1407,62 +1407,130 @@ Enviar mensaje directo conectado directamente Expandir - Error en renegociación de cifrado + Error de renegociación de cifrado contacto eliminado Error Crear grupo Crear perfil - Escritorio conectado + Ordenador conectado Nuevo dispositivo móvil - Dirección desktop + Dirección ordenador Sólo un dispositivo puede funcionar al mismo tiempo ¿Unirse a tu grupo? - %d mensajes marcados como borrados + %d mensaje(s) marcado(s) eliminado(s) ¡El grupo ya existe! - ¡Ya está en proceso de conexión! + ¡Ya en proceso de conexión! Versión incompatible (nuevo)]]> - Opciones escritorio enlazado - Desktop enlazados - Descubrir en red - , y hay %d eventos más + Opciones ordenador enlazado + Ordenadores enlazados + Descubrir en red local + y %d evento(s) más ¿Conectar vía enlace? - ¡Ya está en proceso de unirse al grupo! - %d mensajes moderados por %s + ¡En proceso de unirte al grupo! + %d mensaje(s) moderado(s) por %s ¿Conectarte a tí mismo? Móviles enlazados - Desktop - Conectado al escritorio + Ordenador + Conectado con ordenador Cargando archivo - Conectando a desktop - La renegociación de cifrado ha fallado. - Dispositivo desktop + Conectando con ordenador + Renegociación de cifrado fallida. + Ordenadores ¿Corregir el nombre a %s? Elimina %d mensajes? Enlazar móvil ¿Conectar con %1$s? Bloquear - %d mensajes bloqueados + %d mensaje(s) bloqueado(s) Bloquear miembro Móvil conectado Eliminar y notificar contacto Grupo abierto - Conexión terminada + Conexión finalizada (este dispositivo v%s)]]> ¡Los mensajes de %s serán mostrados! - Introduce el nombre de este dispositivo… + Nombre de este dispositivo… Error - Conectar a desktop + Conectar con ordenador Desconectar - Bloquear miembro? - %d eventos de grupo + ¿Bloquear miembro? + %d evento(s) de grupo ¡Nombre no válido! Conectado a móvil - Dirección de escritorio incorrecta + Dirección ordenador incorrecta Dispositivo Ruta archivo no valida. - ¿Desconectar desktop? - Los mensajes nuevos de %s estarán ocultos! - La versión de aplicación del desktop %s no es compatible con esta aplicación. + ¿Desconectar ordenador? + ¡Los mensajes nuevos de %s estarán ocultos! + La versión de aplicación del ordenador %s no es compatible con esta aplicación. bloqueado + Bloquear miembros del grupo + ¿Repetir solicitud de conexión? + Ya estás conectando con %1$s. + Crear grupo usando perfil aleatorio. + Ya estás uniéndote al grupo mediante este enlace. + Recargar + %s y %s + Conectar automáticamente + Ya estás uniéndote al grupo %1$s. + ¡Enlazar aplicación móvil con ordenador! + ¡Este es tu propio enlace de un solo uso! + Mediante protocolo seguro de resistencia cuántica. + Usar desde ordenador en la aplicación móvil y escanea el código QR.]]> + Para ocultar mensajes no deseados. + ¿Desenlazar ordenador? + Grupos mejorados + El vídeo no puede ser decodificado. Por favor, prueba con otro vídeo o contacta con los desarrolladores. + %s conectado + Aleatorio + Grupos incógnito + %s, %s y %d miembros + Este dispositivo + Desbloquear miembro + %s desconectado]]> + Esperando ordenador… + Mensajería más segura y conexión más rápida. + Pulsa para conectar + Nombre del dispositivo + Ya estás en el grupo %1$s. + ¡Esta es tu propia dirección SimpleX! + Ordenador encontrado + ¡No compatible! + Esperando conexión móvil: + Eliminar miembro + ¿Desbloquear miembro? + Para permitir que la aplicación móvil se conecte al ordenador, abre este puerto en el firewall si está habilitado + Usar desde ordenador + Código de sesión + ¿Repetir solicitud de admisión? + Crear perfil de chat + ¿Eliminar miembro? + ¡Ya estás conectando mediante este enlace de un solo uso! + Desenlazar + El nombre del dispositivo será compartido con el cliente móvil conectado. + Verificar código en móvil + Abrir puerto en firewall + Has compartido una ruta no válida. Informa a los desarrolladores del problema. + Desconectar móviles + autor + Pegar dirección de ordenador + ¡Este es tu enlace para el grupo %1$s! + Verificar código con ordenador + Escanear código QR desde ordenador + Desbloquear + Detectable mediante red local + - notificar opcionalmente a los contactos eliminados. +\n- nombres de perfil con espacios. +\n- ¡...y más! + ¡Ya has solicitado la conexión mediante esta dirección! + Mostrar consola en ventana nueva + Escáner desde móvil + Verificar conexiones + Por favor, espere mientras el archivo se carga desde el móvil enlazado + Verificar conexión + Ningún móvil conectado + Error aplicación + error mostrando contenido + error mostrando mensaje \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/fr/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/fr/strings.xml index 849daaeefe..5ad0b3cbfc 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/fr/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/fr/strings.xml @@ -901,8 +901,8 @@ données invalides chat invalide Annuler le message dynamique - offert %s - offert %s: %2s + propose %s + propose %s : %2s annulé %s Version de l\'app simplexmq : v%s (%2s) @@ -1522,4 +1522,14 @@ Bureau trouvé Non compatible ! Accessible via le réseau local + Rafraîchir + Créer un profil de chat + Pas de mobile connecté + Déconnecter les mobiles + Aléatoire + Afin de permettre à une application mobile de se connecter à votre ordinateur, ouvrez ce port dans votre pare-feu, si vous l\'avez activé + Crash d\'aperçu + Ouvrir le port de votre pare-feu + erreur d\'affichage de contenu + erreur d\'affichage de message \ No newline at end of file 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 21a56d7e99..fac97864f7 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/hu/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/hu/strings.xml @@ -14,7 +14,7 @@ Megszakítás 30 másodperc Egyszer használatos link - %1$s szeretne kapcsolatba lépni veled + %1$s szeretne kapcsolatba lépni veled a A SimpleX chatről 1 nap Címváltoztatás megszakítása @@ -24,7 +24,7 @@ Kapcsolódás a szerverekhez SOCKS proxy segítségével a %d? porton? A proxyt el kell indítani mielőtt bekapcsolná ezt az opciót. Elfogad Elfogad - felül, majd pedig: + felül, utána: Elfogadás inkognítóban Elfogadod a kapcsolatfelvételt? Elfogad @@ -50,7 +50,7 @@ Háttér Tudnivaló: az üzenet- és fájl relay szerverek SOCKS proxy által vannak kapcsolatban. A hívások és URL link előnézetek közvetlen kapcsolatot használnak.]]> App adatmentés - Adatbázis inicializálása nem lehetséges + Az adatbázis inicializálása sikertelen A kapcsolat megmarad az összes Ismerősöddel. Profil változtatások frissítésre kerülnek az ismerőseidnél. Chat profile (alap beállítás) avagy kapcsolat által (BÉTA). Egy új véletlenszerű profil lesz megosztva. @@ -62,9 +62,9 @@ Hang- és videóhívások Az app titkosítja a helyi fájlokat (a videók kivételével). Hívás fogadása - Ismerősök küldhetnek eltűnő üzeneteket engedélyezve. + Ismerősök számára engedélyezve az eltűnő üzenetek küldése. Már kapcsolódik! - Fájl fogadás nem lehetséges + Nem tud fájlt fogadni Hitelesítés elérhetetlen App verzió Üdvözlőszöveg hozzáadása @@ -72,7 +72,7 @@ " \nElérhető a v5.1-ben" Mindketten, te és az ismerősöd is visszaállíthatatlanul törölhettek elküldött üzeneteket. - Jobb csoportok + Javított csoportok Minden üzenet törlésre kerül - ez visszafordíthatatlan! Az üzenetek csak NÁLAD törlődnek. Hívás befejeződött HÍVÁSOK @@ -92,7 +92,7 @@ Adminok létrehozhatnak linkeket csoporthoz való csatlakozáshoz. Hívások a lezárási képernyőn: titkosítás egyeztetése… - Ismerős meghívása sikertelen! + Ismerős meghívása tiltott! téves üzenet ID Ismerősnek jelölések automatikus elfogadása Tudnivaló: NEM fogod tudni helyreállítani vagy megváltoztatni a jelmondatot az esetben ha elveszíted.]]> @@ -106,7 +106,7 @@ Blokkolás admin Fénykép előnézet megszakítása - Minden adat törlődik amint bevitelre kerül. + Az adat törlődik miután a számkód bevitelre kerül. Kérte a videó elfogadását Tag blokkolása Néhány további dolog @@ -144,11 +144,11 @@ Jobb üzenetek A cím változtatás megszakításra kerül. A régi fogadó cím marad használatban. Engedélyez - Rossz asztal cím + Téves számítógép cím Adj hozzá profilt Csatolás - App számkód - Kérte, hogy fogfaja a képet + App PIN kódja (számkód) + Felkértek a kép fogadására Fényképező A Keystore-hoz nem sikerül hozzáférni az adatbázis jelszó elmentése végett hívás folyamatban @@ -175,8 +175,8 @@ Adatbázis jelmondat megváltoztatása? kapcsolódva Számkód megváltoztatása - %s to %s megváltozott szerepköre - Fogadó szerver cím megváltoztatása + a szerepkör %s -ról(-ről), %s -ra(-re) változott + A fogadó szerver címének megváltoztatása Változtatás Számkód megerősítése Jelszó megerősítése @@ -186,13 +186,13 @@ kapcsolódva Kapcsolódás kapcsolódva - Összekapcsolt telefon + Csatlakoztatott telefon kapcsolódva Szerepkör megváltoztatása Kapcsolódva Belépési adatok megerősítése - Fogadó szerver cím megváltoztatása - megváltozott azonosító számodra + Fogadó szerver cím megváltoztatása? + megváltozott az azonosító számodra Önmegsemmisítő mód megváltoztatása a szerepköröd megváltoztatva %s-ra(-re) Kapcsolódás @@ -204,7 +204,7 @@ Csoport létrehozása véletlenszerűen létrehozott profillal. Az ismerős és az összes üzenet törlésre kerül - ez visszafordíthatatlan! Ismerősök megjelölhetik az üzeneteket törlendőként; de láthatod azokat. - Kapcsolódás egy Egyszer használatos linkkel? + Kapcsolódás Egyszer használatos linkkel? Kapcsolódás egy link / QR-kód által Kapcsolódási hiba (AUTH) Ismerős neve @@ -242,7 +242,7 @@ \n- kézbesítési igazolások (20 tagig). \n- gyorsabb és stabilabb Hozzájárulás - kapcsolódás (meghívás bemutatkozásra) + csatlakozás (bemutatkozás meghívás) SimpleX azonosító létrehozása törölt ismerős Tag üzenetének törlése? @@ -254,7 +254,7 @@ Csoport létrehozása Chat profil Profil létrehozása - Csatlakoztatott asztal + Csatlakoztatott számítógép Törölve ekkor: %s Törölve ekkor Kínai és spanyol kezelőfelület. @@ -279,7 +279,7 @@ Jelenleg támogatott legnagyobb fájl méret: %1$s. Fájl törlése Hamarosan! - azonosító megváltoztatása %s számára… + azonosító megváltoztatása %s -ra/re… Chat adatbázis importálva CHAT ARCHÍVUM Üzenetek törlése? @@ -290,10 +290,10 @@ Színsémák személyreszabása és megosztása Chat profil törlése? Titkos csoport létrehozása - Kapcsolódva az asztalhoz + Csatlakozva a számítógéphez ICE sezrverek beállítása Csoport törlése - Chat hitelesításe + Hitelesítés törlése szerző Megerősítés Törlés nálam @@ -308,7 +308,7 @@ kapcsolódás… Hívás kapcsolása Fájlok illetve fotók/videók törlése? - befejezve + befejezett CHAT ADATBÁZIS Önmegsemmisító számkód megváltoztatása Várólista létrehozása @@ -335,7 +335,7 @@ Ismerős törlése Létrehozva: %1$s azonosító megváltoztatása… - Kapcsolódva a mobilhoz + Csatlakoztatva a mobilhoz Jelenlegi jelmondat… Fájl választása Egyszer használatos meghívó link létrehozása @@ -355,13 +355,13 @@ Chat kiürítése? Adatbázis downgrade? Chat kiürítése - Adatbázis titkosítási jelmondat meg lesz változtatva. + Adatbázis titkosítási jelmondat frissítve lesz. Kapcsolódás automatikusan Adatbázis hiba Adatbázis titkosítási jelmondat frissül és eltárolásra kerül a beállításokban. Adatbázis ID Adatbázis ID: %d - Adatbázis azonosítók és \"Transport Isolation\" opciók. + Adatbázis azonosítók és Átviteli izolációs beállítások. Az adatbázis titkosítás jelmondata megváltoztatásra és elmentésre kerül a Keystore-ban. Az adatbázis titkosításra kerül és a jelmondat eltárolásra a beállításokban. Szerver törlése @@ -371,9 +371,9 @@ Engedélyezve minden csoportnak engedélyezve az ismerősnek Eltűnő üzenetek tiltottak ebben a csoportban. - Azonosító törlés + Azonosító törlése %d hét - PC címe + Számítógép azonosítója %ds Kézbesítési izagolások! Eszközhitelesítés nincs bekapcsolva. Bekapcsolhatod a SimpleX zárat a Beállításokon keresztük, miután bekapcsoltad az eszközhitelesítést. @@ -407,7 +407,7 @@ ESZKÖZ e2e titkosított videóhívás közvetlen - PC + Számítógép %d perc %d ismerős(-ök) kiválasztva Engedélyez @@ -420,7 +420,7 @@ %d nap Chat archív törlése? Duplikálódott megjelenítési név! - Letiltás(felülírások megtartásával) + Letiltás (felülírások megtartásával) "Adatbázis upgrade" %d üzenet blokkolva Eltűnik ekkor @@ -437,13 +437,13 @@ Az adatbázis titkosításra kerül és a jelmondat eltárolásra a Keystore-ban. Automatikus üzenet törlés engedélyezve? Törlés - az adatbázis verzió újabb, mint az app, de nincs lefelé migráció eddig: %s + az adatbázis verzió újabb, mint az alkalmazás, de nincs lefelé migráció eddig: %s Leírás %d óra %dp Szétkapcsolás Szerkesztés - Letiltás(csoport felülírások megtartásával) + Letiltás (csoport felülírások megtartásával) %d csoportesemény %d hónap Csoport profil szerkesztése @@ -465,7 +465,1066 @@ Kézbesítés %d fájl %s összméretben Adatbázis jelmondat szükséges chat megnyitásához. - %dn + %dnap Engedélyeve mindenki számára Kézbesítési izagolások kikapcsolva! + Lenyit + Hiba az üzenet küldésekor + Add meg a Számkódot + Mindenkinek + Titkosítás újra egyeztetési hiba + Hiba az adatbázis titkosításakor + Hiba a csoport törlésekor + Kilépés mentés nélkül + Tárolt fájlok, képek és videók titkosítása + Hiba az azonosító beállításakor + A csoport meghívó lejárt + Hiba az ICE szerverek elmentésekor + Hiba + Hiba + Hiba az XFTP szerverek betöltésekor + Hiba az SMP szerverek betöltésekor + Hiba a hálózat konfigurációjának frissítésekor + TCP életbentartás engedélyezése + Kamera megfordítása + Szia! +\nKapcsólódj Connect to me via SimpleX Chat: %s + A megjelenített név nem tartalmazhat szóközöket. + Csoport + Add meg az üdvözlőszöveget… (opcionális) + Hiba a chat adatbázis exportálásakor + Hiba a fájl elmentésekor + Helyi fájlok titkosítása + titkosítás egyeztetve %s számára + %d üzenet megjelölve törlésre + titkosítás újra egyeztetése engedélyezve + Önmegsemmisítés engedélyezése + Olvasatlan és kedvenc chatekre szűrés. + Chatek betöltése sikertelen + A csoport már létezik! + Francia kezelőfelület + Csoport linkek + Végre, megvannak! 🚀 + Hiba a chat elindításakor + A csoport profil a tagok eszközein tárolódik, nem a szervereken. + Add meg a jelmondatot… + Hiba a felhasználói beállítások frissítésekor + Titkosít + Csoport nem található! + Hiba az SMP szerverek elmentésekor + Downgrade és chat megnyitása + A csoport inaktív + Gyors és nincs várakozás a küldő online állapotára! + Hiba a csoporthoz csatlakozáskor + Kedvenc + Csoport moderáció + Fájl + Csoport link + titkosítás újra egyeztetés szükséges %s számára + Hiba a profil váltásakor! + Kísérleti funkciók + Engedélyezés (felülírások megtartásával) + Helyes jelmondat bevitele. + A csoport törlésre kerül számodra -ez visszafordíthatatlan! + Adatbázis titkosítása? + Lezárási képernyőn a hívások engedélyezése a beállításokban. + titkosítás egyeztetve + Kézbesítési igazolások engedélyezése? + Hiba a csoport profil elmentésekor + hiba + A fájl törölve lesz a szerverekről. + Akkor is, ha le van tiltva a beszélgetésben. + Gyorsabb csatlakozás és megbízhatóbb üzenet kézbesítés. + Zár engedélyezése + SEGÍTSÉG + Teljesen decentralizált - kizárólag tagok számára látható. + Fájl: %s + Hívás befejezése + Hiba a csoport linkjének törlésekor + Fájl elmentve + Kapcsolat javítása? + Fájlok és médiatartalom + A KONZOL SZÁMÁRA + Titkosítás újra egyeztetés sikertelen. + Hiba a felhasználói profil törlésekor + A javítás nem támogatott a csoporttag által + Add meg az üdvözlőszöveget… + Titkosított adatbázis + Add meg a jelszót a keresőben + A fájl megérkezik amint az ismerősöd befejezi a feltöltését. + Fájl letöltése + Chat betöltése sikertelen + Szerver megadása kézileg + A fájl megérkezik amink az ismerősöd online lesz, kélrlek várj vagy nézz vissza később! + Hiba a csoport linkjének létrehozásakor + A Galériából + Engedélyezés (csoport felülírások megtartásával) + Hiba az ismerős törlésekor + A csoporttagok visszafordíthatatlanul törölhetnek elküldött üzeneteket. + Hiba a szerepkör megváltoztatásakor + Javítás + A csoporttagok küldhetnek eltünő üzeneteket. + Kapcsolat javítása + Hiba a profil létrehozásakor! + Hiba a tag(-ok) hozzáadásakor + Fájl + A csoporttagok küldhetbnek fájlokat és képeket/hangfájlokat. + Törlés miután + Hiba a beállítás megváltoztatásakor + Hiba a csoport link frissítésekor + a csoport törölve + csoport profil frissítve + Hiba a függőben lévő parner kapcsolatának törlésekor + Hiba a chat adatbázis importálásakor + Hiba a kézbesítési igazolások engedélyezésekor! + Hiba az XFTP szerverek mentésekor + A csoporttagok küldhetnek közvetlen üzeneteket. + Hiba a tag eltávolításakor + befejeződött + Csoport üdvözlő szöveg + Csoport neve: + Hiba a meghívó küldésekor + Add meg a nevedet: + Hiba a felhasználó jelszavának mentésekor + Színséma exportálása + Add meg ennek az eszköznek a nevét… + Hiba + A csoport meghívó már nem érvényes, el lett távolítva a küldője által. + A csoport teljes neve: + segítség + Önmegsemmisítő számkód engedélyezése + KÍSÉRLETI + Hiba az azonosító megváltoztatásának megszakításakor + Hiba a fájl fogadásakor + titkosítás rendben + Hiba az ismerős kérés törlésekor + Kézbesítési igazolások engedélyezése csoportok számára? + A javítás nem támogatott az ismerős által + Fájl nem található + Kapcsolat bontása + A csoporttagok reagálhatnak emocikonokkal az üzenetekre. + Adatbázis exportálása + Teljes név: + Tovább csökkentett akkumulátor használat + Hiba a chat megállításakor + titkosítás rendben %s számára + Csoport törlésre kerül minen tag számára - ez visszafordíthatatlan! + Titkosítás javítása az adatmentések helyreállítása után. + Hiba a chat adatbázis törlésekor + Teljes link + Hiba az azonosító megváltoztatásakor + A csoporttagok küldhetnek hangüzeneteket. + Csoport beállítások + Hiba: %s + Eltűnő üzenetek + SimpleX Zár engedélyezése + Hiba a kapcsolat szinkronizációjakor + Hiba az azonosító létrehozásakor + engedélyezve + Hiba a részletek betöltésekor + Hiba az ismerős kérés elfogadása + titkosítás újra egyeztetése engedélyezve %s számára + titkosítás újra egyeztetés szükséges + Rejtett chat profilok + Fájlok és képek/videók + Képek elmentve a fotóalbumba + Elrejt + Azonnal + Fájlok és képek/videók tiltottak! + Profil elrejtése + Hogyan használd a szervereidet + Találd meg a chat üzeneteket gyorsabban + Színséma importálása + Hiba a színséma importálásakor + Ismerős és üzenet elrejtése + Nem kompatibilis adatbázis verzió + Hogyan működik a SimpleX + Nem kompatibilis verzió + Elrejt + Bejövő videóhívás + Téves számkód + Azonnali + Inkognitó csoportok + Hogyan + Elrejt + Kép + Fejlesztett adatvédelm és biztonság + Figyelmen kívül hagyás + Kép elküldve + Rejtett + Házigazda + Kezdeti szerepkör + Érvénytelen chat + órák + Inkognitó + Hogyan használjuk + App képernyőjének elrejtése a gyakran használt appok között. + Javított szerver konfiguráció + Történet + Rejtett profil jelszó + Adatbázis importálása + Importálás + Azonnali értesítések + Inkognitó mód + Chat adatbázis importálása? + Azonnali értesítések kikapcsolva! + Azonnali értesítések! + Kép + Fájlok és képek/videók tiltottak ebben a csoportban. + Hogyan működik + Elrejt: + Hiba az ismerősöddel való kapcsolat létrehozásában + ICE-kiszolgálók (soronként egy) + kiszkennelheted a QR-kódot, vagy a pertnered megoszthat egy meghívó linket.]]> + Ha az alkalmazás megnyitásakor megadod ezt a jelszót, az alkalmazás minden adata visszavonhatatlanul törlődik! + Ha nem tudtok személyesen találkozni, mutassátok meg a QR-kódot egy videohívás során, vagy osszátok meg egymással a linket. + mutassátok meg a QR-kódot a videohívásban, vagy osszátok meg egymással a linket.]]> + Ha megerősíted, az üzenetküldő szerverek láthatják az IP-címedet és a szolgáltatódat, vagyis azt, hogy mely szerverekhez csatlakozol. + A kép akkor érkezik meg, amikor az ismerősöd befejezi a feltöltést. + QR kód beolvasásával]]> + Ha kaptál egy SimpleX Chat meghívó linket, akkor megnyithatod azt a böngészőben: + Ha az alkalmazás megnyitásakor megadod az önmegsemmisítő jelszót: + Megtalált asztali számítógép + Számítógépek + Hogyan használjuk a markdown-t + Csevegő profil létrehozása + Spam és visszaélések elleni védelem + Mobilok leválasztása + Különböző nevek, avatarok és átviteli izoláció. + Ha úgy döntesz, hogy elutasítod a küldő NEM kap értesítést. + Szerepkör kibővítése + A kép akkor érkezik meg, amikor az ismerősöd elérhető lesz, kérlek várj vagy nézd meg később! + meghívott + Érvénytelen kapcsolati hivatkozás + Elnémít + nincsenek részletek + Nem fogadott hívás + Világos + Az üzenet törlésre kerül - ezt nem lehet visszafordítani! + Segítség \"markdown\" funkcióhoz: Üzenetek formázása a szövegbe szúrt speciális karakterekkel + új üzenet + Régi adatbázis archívum + Hálózati beállítások + Nincs kézbesítési információ + moderált + A tag eltávolítása a csoportból - ezt nem lehet visszafordítani! + Győződj meg róla, hogy az XFTP-kiszolgáló címei megfelelő formátumúak, sorszeparáltak és nem duplikáltak. + Nincsenek ismerősök kiválasztva + Nincsenek fogadott vagy küldött fájlok + Megnyitás mobil alkalmazásban, majd koppints a Csatlakozás \u0020gombra az alkalmazásban.]]> + Markdown az üzenetekben + meghívás a %1$s csoportba + Lezárás mód + Új mobil eszköz + Kapcsolatok megtartása + Tagok meghívása + Üzenet reakciók + Egyszerre csak egy eszköz működhet + Csatlakozol a csoportodhoz? + Nagy fájl! + Helyi név + Hálózat és szerverek + Értesítés előnézet + Társítsd össze a mobil és az asztali alkalmazásokat! 🔗! + közvetett (%1$s) + Hamarosan további fejlesztések érkeznek! + Az üzenetreakciók ebben a csevegésben tilosak. + Helytelen biztonsági kód! + Ez akkor fordulhat elő, ha Te vagy az ismerősöd a régi adatbázis biztonsági másolatát használta. + Új asztali alkalmazás! + Most már az adminok is: +\n- törölhetik a tagok üzeneteit. +\n- letiltani a tagokat (\"megfigyelő\" szerepkör) + %1$s meghívott + Az üzenetreakciók ebben a csoportban tilosak. + Nem + nincs szöveg + TAG + Ez később a beállításokon keresztül módosítható. + Új tag szerepköre + Ki + Érvénytelen hivatkozás! + A csatlakozáshoz Onion host-okra lesz szükség. + Változások a %s verzióban + Onion host-okat használ, ha azok rendelkezésre állnak. + Érvénytelen szervercím! + k + soha + (új)]]> + Győződj meg róla, hogy az SMP-kiszolgáló címei megfelelő formátumúak, sorszeparáltak és nincsenek duplikálva. + Onion host-ok nem lesznek használva. + perc + Tudj meg többet + Új kapcsolattartási kérelem + Csatlakozás a csoporthoz + Összekapcsolt asztali eszköz beállítások + meghívva a csoport hivatkozásodon keresztül + elhagyta + Összekapcsolt asztali eszközök + Nincs alkalmazás jelszó + Némítás, ha inaktív! + A meghívó lejárt! + (csak a csoporttagok tárolják) + Moderál + be + Japán és Portugál kezelőfelület + Ebben a csoportban tilos az üzenetek visszafordíthatatlan törlése. + Onion host-ok nem lesznek használva. + %s eszközzel megszakadt a kapcsolat]]> + hónap + Üzenet vázlat + Egy üzenet eltüntetése + Visszafordíthatatlan üzenettörlés + Egyszerre csak 10 videó küldhető el + Csak te adhatsz hozzá üzenetreakciókat. + elhagyta + Ebben a csevegésben tilos az üzenetek visszafordíthatatlan törlése. + Max 40 másodperc, azonnal fogadható. + inkognitó a kapcsolattartási címen keresztül + A csatlakozáshoz Onion host-okra lesz szükség. +\nKérjük, vedd figyelembe: .onion cím nélkül nem fogsz tudni csatlakozni a szerverekhez. + Olasz kezelőfelület + Nincsenek háttérhívások + Üzenetek + Összekapcsolt mobil eszközök + Lehetővé teszi, hogy egyetlen csevegőprofilon belül több anonim kapcsolat legyen, anélkül, hogy megosztott adatok lennének közöttük. + Az üzenet törlésre lesz jelölve. A címzett(ek) képes(ek) lesz(ek) felfedni ezt az üzenetet. + Elhagy + Rendben + Nincsenek szűrt csevegések + Érvénytelen adat + Győződj meg róla, hogy a WebRTC ICE-kiszolgáló címei megfelelő formátumúak, sorszeparáltak és nem duplikáltak. + Csak a csoporttulajdonosok engedélyezhetik a fájlokat és a médiát. + A fájl betöltése + Nincs hozzáadandó ismerős + Üzenet vázlat + meghívott, hogy csatlakozz + Egyszer használatos meghívó link + Értesítések + Egyszerre csak 10 kép küldhető el + ajánlott %s: %2s + Nem kompatibilis! + Tedd priváttá a profilodat! + Üzenet kézbesítési hiba + Több csevegőprofil + töröltnek jelölve + Elnémít + Egy mobil összekapcsolása + Értesítési szolgáltatás + Csak a csoporttulajdonosok engedélyezhetik a hangüzeneteket. + 2 rétegű végponttól-végpontig titkosítással küldött üzeneteidet.]]> + Érvénytelen migrációs visszaigazolás + Csak a csoporttulajdonosok módosíthatják a csoportbeállításokat. + Nincsenek előzmények + Érvénytelen QR-kód + Olvasottnak jelölve + ÉLŐ + Olvasatlannak jelölve + Több + Jelentkezz be a hitelesítő adataiddal + érvénytelen üzenet formátum + Csatlakozás + Az értesítések az alkalmazás elindításáig nem fognak működni. + ki` + (ez az eszköz) v%s)]]> + ajánlott %s + Csoport elhagyása + A %s-től érkező üzenetek megjelennek! + Ha a SimpleX Chat-nek nincs felhasználói azonosítója, hogyan lehet mégis üzeneteket küldeni?]]> + Ez akkor fordulhat elő, ha: +\n1. Az üzenetek az ismerősödnél 2 nap után, vagy a kiszolgálón 30 nap után lejártak. +\n2. Az üzenet visszafejtése sikertelen volt, mert Te vagy az ismerősöd régi adatbázis biztonsági mentést használt. +\n3. A kapcsolat sérült. + megfigyelő + inkognitó a csoportos hivatkozáson keresztül + Onion host-okat használ, ha azok rendelkezésre állnak. + Barátok meghívása + Menük és figyelmeztetések + Tagok meghívása + Csatlakozás mint %s + Nincs kiválasztott csevegés + Csak helyi profiladatok + inkognitó Egyszer használatos link által + Moderálva: %s + Egyszer használatos meghívó link + Érvénytelen név! + Beszélgessünk a SimpleX Chat-ben + Moderálva + Élő üzenetek + Ellenőrzöttként jelölve + Üzenet kézbesítési bizonylatok! + hivatkozás előnézeti képe + Elhagyod a csoportot? + nem + Hamarosan további fejlesztések érkeznek! + ki + Telepítse a SimpleX Chat-et a terminálhoz + Új megjelenített név: + Új jelmondat… + nem fogadott hívás + Migrációk: %s + Válasz neki + Üzenet szövege + Az értesítések csak az alkalmazás bezárásáig érkeznek! + Információ + ÜZENETEK ÉS FÁJLOK + tag + Privát kapcsolat létrehozása + Moderálva %s által + Győződj meg róla, hogy a fájl helyes YAML-szintaxist tartalmaz. Exportáld a témát, hogy legyen egy példa a téma-fájl szerkezetére. + dőlt + Érvénytelen fájl elérési útvonal + Csatlakozol a csoporthoz? + nincs e2e titkosítás + Új adatbázis-archívum + Élő üzenet! + Meghívás a csoportba + Lezárás miután + Bejövő hanghívás + Kulcstartó hiba + Csatlakozol a csoporthoz? + Az inkognitó mód úgy védi a magánéletét, hogy minden egyes kapcsolathoz új, véletlenszerű profilt használ. + - stabilabb üzenetkézbesítés. +\n- egy kicsit jobb csoportok. +\n- és még sok más! + Üzenet reakciók + Nincs csatlakoztatott mobil eszköz + Hálózat állapota + Új jelszó + Valószínűleg ez az ismerősöd törölte a kapcsolatát veled. + Csatlakozás inkognitóban + Chat megnyitása + elutasított hívás + Rendszeres + fogadott, tiltott + Kapcsolódási kérés megismétlése? + Kizárólag te tudsz véglegesen törölni üzeneteket (az ismerősöd csak megjelölheti azokat törlendőként) + Szerepkör + SimpleX ismerős azonosítója + Megállítás + Előre beállított szerver + Új chat kezdése + Nyílt forráskódú protokoll és program - bárki üzemeltethet szervereket. + Megnyitás + Protokoll időtúllépés + titok + Előnézet mutatása + várakozás visszaigazolásra… + Fájl megállítása + csoport linken keresztül + PING időköze + Eltűnő üzenet küldése + Önmegsemmisítési számkód + Mentés és a csoport profil frissítése + A te adatvédelmed + A te SimpleX azonosítód + Kérlek jelentsd a fejlesztőknek! + Az emberek kizárólag az általad megosztott link alapján kapcsolódhatnak hozzád. + Eltűnő üzenetek küldésének tiltása. + Kizárólag te tudsz hangüzeneteket küldeni. + Frissítés + Videó elküldve + Adatbázis jelmondat megváltoztatása + App beállítások megnyitása + Számkód nem változott! + Frissítés + Választás + Kizárólag te tudsz hívásokat indítani. + Biztonságos várólista + Értékeld az appot + Egyszer használatos link megosztása + Hiba az adatbázis visszaállításakor + %s és %s + Te engedélyezed + Takarékos akkumulátor használat + Mentés és az ismerősök értesítése + Előnézet + Használd a chatet + Megosztás + Fogadott üzenet + Üdvözlő szöveg + %s, %s és %d további tagok csatlakozva + Kizárólag az ismerősöd tud hívást indítani. + SZÍNSÉMÁK + Túl sok videó! + Chat szolgáltatás megállítása az adatbázis műveletek elvégzéséhez. + Üdvözöllek! + Önmegsemmisítési számkód + (beolvasás vagy vágólapról beillesztés) + Videóra várakozás + Válasz + Ez a te egyszer használatos linked! + SimpleX Chat hívások + Az új inkognító profil használata + Kérlek frissítsd az appot és jelentsd a fejlesztőknek! + SimpleX + Link előnézet küldése + biztonsági kód megváltozott + Kizárólag az ismerős mutatása + Hangszóró bekapcsolva + Indítsd újra az appot, hogy importált chat adatbázist használj. + jogosulatlan küldés + Kizárólag az ismerősöd tud hangüzeneteket küldeni. + Beállítások + Kapcsolat létrehozásához az ismerősöd beolvassa a QR-kódodat vagy a linket használja az appban. + fogadott visszaigazolás… + A biztonsági kód beolvasása az ismerősöd appjából. + Kérlek vedd fel a kapcsolatot a csoport adminnal! + Videó bekapcsolva + Profil neve: + Beillesztés + Köszönjük, hogy telepítetted a SimpleX Chatet! + Csillag a GitHub-on + Eltávolítás + Keresés + Titkosítás újraegyeztetése? + Önmegsemmisítési számkód engedélyezve! + Biztonsági kiértékelés + Cím + Üzenet Elküldése + Adatbázis mentés visszaállítása + Visszavon + Kérd meg az ismerősödet, hogy engedélyezze a hangüzenetek küldését! + egyszer használatos linket osztottál meg + A link megnyitása böngészőben gyengítheti az adatvédelem és biztonság szintjét. A megbízhatatlan SimpleX linkek vörössel vannak kiemelve. + Az ICE szervereid + A kapcsolódást elfogadtad + Elutasítás + Ismerős és üzenet mutatása + BEÁLLÍTÁSOK + Felhasználói fiók jelszavának elmentése + Fájl küldés megszakítása? + Számítőgép leválasztása? + A hangüzenetek le vannak tilva! + A kapcsolódáshoz közvetlen üzenet küldése + PING számláló + Fejlesztői beállítások mutatása + %s csatlakozva + Rendszer + Amikor elérhető + Hangüzenet (%1$s) + %s (jelenlegi) + A te szervered + Véletlen + Megosztás ismerősökkel... + te + Nincsenek chat üzeneteid + Küldés + %s másodperc + %s: %s + A SimpleX nem tud a háttérben futni. Csak az app futása közben fogod az üzeneteket megkapni. + Túl sok kép! + Archív mentése + "%s, %s és %d tagok" + Chat szolgáltatás megállítása + SimpleX linkek + Az elküldött üzenetek törlésre kerülnek a beállított idő után. + Némítás feloldása + Elküldve ekkor: %s + Jelenlegi profil használata + Ez az eszköz + "Azonosító megosztása az ismerősökkel?" + Profil jelszó + Színséma + Jelmondat eltávolítása a beállításokból? + SimpleX csoport link + Képre várakozás + Önmegsemmisítés + várakozás válaszra… + Ismerős nevének beállítása… + Tag feloldása + QR-kód beolvasása + Szerver tesztelése + Írj nekünk e-mailben! + SZERVEREK + Szerverek tesztelése + Számkód bevitel + Rendszer + Eljuttat + Biztonsági kód + Kérlek írd be a helyes jelmondatot! + Végleges üzenet törlés tiltása. + Üzenetekre adott emoji reakciók tiltása. + Véletlenszerű jelmondat használata + ponttól-pontig + CHAT SZOLGÁLTATÁS INDÍTÁSA + Fogadott link beillesztése + Szerverek elmentése? + A SimpleX Chat biztonsága a Trail of Bits által lett auditálva. + módosított csoport profil + TÁMOGASD A SIMPLEX CHATET! + SimpleX Chat szolgáltatás + Nem tudsz üzeneteket küldeni! + %s ellenőrzött + Jelszó mutatása + Adatvédelem és biztonság + Tag eltávolítása + Számkód beállítva! + Elküldött üzenet + Ismerősök kiválasztása + ismeretlen üzenet formátum + Szerverek elmentése + Üdvözlő üzenet + másodperc + Profil változtatása frissítésre kerül az ismerőseidnél. + Egyszerűsített inkognító mód + Üdvözlőszöbeg elmentése? + Indítsd újra az appot, hogy új felhasználói fiókot hozz létre. + Engedély megtagadva! + Főggőben lévő hívás + Adatbázis megnyitása… + Leállítás? + Jelmondat szükséges + Privát értesítések + Meghívtál egy ismerőst + %s nincs ellenőrizve + A csatlakozáshoz érintsd meg + Ennek az eszköznek a neve + A te jelenlegi profilod + Fájl feltöltése + Hang- és videóhívások tiltása. + Megkövetelt + SimpleX chat üzenetek + Visszaállítás + Adatbázis jelmondat beállítása + Elküldött üzenet + Rendszeresen elindul + Ez a te saját SimpleX azonosítód! + eltávolítva + Link megosztása + SimpleX Csapat + profilkép + A te chat profiljaid + tulajdonos + Bekapcsolás + %s, %s és %s csatlakozva + SimpleX egyszer használatos meghívó + A te hívásaid + küldés sikertelen + SZÍNSÉMA SZÍNEK + Visszaállít + Kérlek írd be az előző jelszót az adatbázis visszaállítása után. Ez a művelet visszafordíthatatlan. + Másodlagos + SOCKS PROXY + Mentés + Újraindítás + Üzenetküldő (SMP) szerverek + Videó + Automatikus elfogadási beállítások mentése + Újraegyzetetés + Videóra várakozás + A te Simplex fájl küldő (XFTP) szervereid + Videó kikapcsolva + Privát fájl nevek + Beállítások elmentése? + Számkód + Ismeretlen hiba + A te szerver címed + Chat konzol megnyitása + Tag eltávolítása + Beállított adatbázis jelmondat + Biztonsági kód megtekintése + Tag feloldása? + A küldő törölhette a kapcsolódási kérelmet. + Téves adatbázis jelmondat + A te Simplex chat (SMP) szervereid + Visszaigazolások letiltva + Adatbázis mappa megnyitása + egyszer használatos linken keresztül + Csoportbeállítások megadása + %1$s keresztül + igen + Hangüzenet + Számítógépről használat + TE + port %d + Kapcsolódás link által + Azonosító megosztása + Szerver QR-kód beolvasása + Megállítás + Azonosítód megosztásának szüneteltetése? + Chat profilok megnyitása + Csatlakozási kérés megismétlése? + Képre várakozás + Hangüzenetek + Tag eltávolítása? + Biztonsági kód megtekintése + eltávolított téged + SimpleX azonosító + Mutat: + fogadott válasz… + Adatbázis mentés visszaállítása? + Üzenetek fogadása… + %s és %s csatlakozva + megfigyelő vagy + Port + Számkód beállítása + Milyen újdonságok vannak + Csoport megnyitása + Elküldve ekkor + Hangüzenetek küldésének tiltása. + Utolsó üzenetek megjelenítése + Előre beállított szerver címe + Rendszeres értesítések letiltva! + Számkód megváltozott! + Akkor fut, amikor az app nyitva van + Ez a QR-kód nem egy link! + Fájlra várakozás + simplexmq: v%s (%2s) + Szétkapcsolás + A te véletlenszerű profilod + Téves jelmondat! + Üzenetekre adott emoji reakciók tiltása. + Rendszer + olvasatlan + Függő + Üdvözöllek %1$s! + Jelmondat eltávolítása a Keystrore-ból? + Feloldás + Eltűnő üzenetek küldésének tiltása. + Videó + Frissítés + Megnyitás + Rendszeres értesítések + Kihagyott üzenetek + Hangüzenetek küldésének tiltása. + Ismerős nevének beállítása... + Kizárólag te tudsz eltűnő üzeneteket küldeni. + Kép/videó megoszása… + te: %1$s + A te beállításaid + Színek alaphelyzetbe állítása + Mentés + Váltás + Illeszd be a kapott linket az ismerősödhöz való kapcsolódáshoz… + Kód beolvasása + Port megnyitása a tűzfalon + indítás… + Szín elmentése + Leállítás + elküldve + SOCKS proxy használata + Élő üzenet küldése + Adatvédelem újraértelmezve + Hangüzenet… + App képernyőjének védelme + QR-kód mutatása + videóhívás + Nem kedvenc + Küldési visszaigazolások + SimpleX Azonosító + Érintsd meg a gombot + Mentés és az ismerős értesítése + Elutasított hívás + SOCKS proxy beállítások + QR-kód + Titkosítás újraegyeztetése + Eltávolítás + TOR .onion hostok használata + Megmutat + SimpleX Zár mód + Fájl visszavonása + Fájl küldő/fogadó (XFTP) SimpleX szerverek + Fájlok, képek és videók küldésének tiltása. + Fájl megosztása… + Mentés + közvetítő szerveren keresztül + Megosztás leállítása + te eltávolítottad %1$s + Jelmondat elmentése és chat megnyitása + Beállítások elmentése? + Az első chat rendszer bármiféle felhasználó azonosító nélkül - privátra lett tervezre. + Tagoknak való közvetlen üzenetküldés tiltása. + SOCKS proxy használata? + Hangszóró kikapcsolva + hét + Mutasd + WebRTC ICE szerverek + Fájl visszavonása? + Közvetlen üzenet küldése + Elutasítás + Küldés + Rendszer hitelesítés + Böngészőn keresztül + A chat profiljaid védelme jelszóval! + Kizárólag az ismerősöd tud eltűnő üzeneteket küldeni. + A te ICE szervereid + QR-kód beolvasása asztali számítógépről + SimpleX Logo + Feloldás + Némítás feloldása + SimpleX chat megnyitása a hívás fogadásához + Fájl fogadás megszakítása? + - opcionális értesítés a törölt ismerősök számára +\n- profil nevek szóközökkel +\n- és továbbiak! + Lengyel kezelőfelület + Használd a szervert + Fogadva ekkor: %s + SimpleX Zár + Mentés és a csoporttagok értesítése + Alaphelyzetbe álítás + Kizárólag az ismerősöd tud emoji reakciókat adni az üzenetekre. + Hangüzenetek + te távoztál + Hangüzenet rögzítése + SimpleX Zár bekapcsolva + közvetlen üzenet küldése + Telefonről beolvasás + Kapcsolatok ellenőrzése + Üzenet megosztása… + másodperc + SimpleX Zár nincs engedélyezve! + SimpleX Zár + A te beállításaid + Chat adatbázis használata + eltávolítva %1$s + Szerver teszt sikertelen! + Kapcsolat ellenőrzése + Tudj meg többet + A küldő megszakította a fájl átvitelt. + Chat szolgáltatás megállítása? + Fogadva ekkor + Beállítva 1 nap + Felfedés + Fogadott üzenet + Kizárólag az ismerősöd tud véglegesen törölni üzeneteket (te csak törlendőként tudod megjelölni azokat). + Önmegsemmisítési számkód megváltozott + SimpleX Chat szerverek használatban. + SimpleX Chat szerverek használata? + Chat profil felfedése + Videók és fájlok 1Gb méretig + TCP kapcsolat időtúllépés + A te %1$s SimpleX azonosítód megosztásra kerül. + Már csatlakozva vagy hozzá: %1$s. + A jelenlegi chat adatbázisod TÖRLÉSRE és FELCSERÉLÉSRE kerül az importált által! +\nEz a művelet nem visszavonható - a profilod, az ismerőseid, a chat üzeneteid és fájljaid mind véglegesen elvesznek! + Ötletek és kérdések beküldése + Figyelem: néhány adatot elveszíthetsz! + Új chat kezdése + Várakozás a számítógépre… + A privát chatelés új generációja + Hálózati beállítások megváltoztatása? + Várakozás a mobiltelefon csatlakozására: + Kapcsolat biztonságának ellenőrzése + fájlok küldése egyelőre még nem támogatott + Megváltoztattad az azonosítót erre: %s + fájlok fogadása egyelőre még nem támogatott + Csoport profil elmentése + Alaphelyzetbe állítás + Hacsaknem az ismerősöd megszakította a kapcsolatot avagy ez a link már használva volt, ez egy programhiba lehet - kérlek jelentsd be. +\nA kapcsolatfelvételhez kérd meg az ismerősödet, hogy készítsen egy új linket a kapcsolatfelvételhez és ellenőrizd az internet kapcsolatodat. + videóhívás (nem e2e titkosított) + Alkalmazás új kapcsolatokhoz + Az app rendszeresen lekéri az új üzeneteket - ez naponta néhány százalék akkumulátort használ. Az app nem használja a Google push értesítési rendszert — az eszközödön lévő adat nem kerül megküldésre a szervereknek. + Számítógép címének beillesztése + ismerős azonosítójának linkjén keresztül + SimpleX háttérszolgáltatást használja - ez naponta néhány százalék akkumulátort használ.]]> + Az ismerősöd online kell legyen ahhoz, hogy a kapcsolat létrejöjjön. +\nMegszakíthatod ezt a kapcsolatfelvételt és törölheted az ismerőst (és később ismét megpróbálhatod egy új linkkel) + Jelmondat nem található a Keystore-ban, kérlek írd be kézileg. Ez akkor történhet, ha helyreállítottad az appot a backup funkcióval. Ha nem így történt, az esetben lépj kapcsolatba a fejlesztőkkel! + Az ismerőseid továbbra is megmaradnak + A szervernek engedélyre van szüksége a várólisták létrehozásához, ellenőrizd a jelszavadat + Az adatbázis nem működik megfelelően. Koppints a további információkért + A fájl küldése leállt. + Csatlakozási kísérlet a kapcsolat üzeneteinek fogadására használt kiszolgálóhoz ettől az ismerősödtől. + Nem sikerült ellenőrizni téged; kérjük, próbáld meg újra. + Az üzenet minden tag számára moderáltként lesz megjelölve. + Ha szeretnél értesítéseket kapni, kérjük, add meg az adatbázis jelszavát. + A teszt a(z) %s lépésnél sikertelen volt. + Az alkalmazás indításakor, vagy 30 másodpercnyi háttérben töltött idő után az alkalmazáshoz visszatérve hitelesítened kell magad. + Az üzenet minden tag számára törlésre kerül. + A videó nem dekódolható. Kérjük, próbálj meg egy másik videót, vagy lépj kapcsolatba a fejlesztőkkel. + Ez a szöveg a beállítások között érhető el + A profilodat elküldjük annak az ismerősödnek, akitől ezt a linket kaptad. + Az alkalmazás 1 perc után bezárható a háttérben. + meg lettél hívva a csoportba + engedélyezd a SimpleX háttérben történő futtatását a következő párbeszédpanelen. Ellenkező esetben az értesítések le lesznek tiltva.]]> + A kiszolgálónak engedélyre van szüksége a várólisták létrehozásához, ellenőrízd a jelszavadat + Csatlakozni fogsz a csoport összes tagjához. + Lehetséges, hogy a kiszolgáló címében szereplő tanúsítvány-ujjlenyomat helytelen + Az adatok védelme érdekében kapcsold be a SimpleX Lock funkciót. +\nA funkció engedélyezése előtt a rendszer felszólít téged a hitelesítés befejezésére. + A videó akkor érkezik, amikor az ismerősöd elérhető, kérlek várj vagy nézd meg később! + "Kérjük, ellenőrizd hálózati kapcsolatodat a(z) %1$s segítségével, és próbáld meg újra." + A SimpleX Lock-ot a Beállításokon keresztül kapcsolhatod be. + Az alkalmazás összeomlott + Kérjük, ellenőrizd, hogy a megfelelő linket használtad-e, vagy kérd meg az ismerősödet, hogy küldjön egy másikat. + A kép nem dekódolható. Kérjük, próbálj meg egy másik képet, vagy lépj kapcsolatba a fejlesztőkkel. + Érvénytelen fájl elérési útvonalat osztottál meg. Jelentsd a problémát az alkalmazás fejlesztőinek. + Önnek már van egy chat-profilja ugyanazzal a megjelenített névvel. Kérjük, válassz másik nevet. + Csatlakozási kísérlet a kapcsolat üzeneteinek fogadására használt szerverhez ettől az ismerősödtől (hiba: %1$s). + A fájl fogadása leállt. + Kérjük, jegyezd meg vagy tárold biztonságosan - az elveszett jelszót nem lehet visszaállítani! + A videó akkor érkezik meg, amikor az ismerősöd befejezi a feltöltést. + egyszeri linket osztottál meg inkognitóban + Csatlakozol ahhoz a kiszolgálóhoz, amely az adott ismerősödtől érkező üzenetek fogadására szolgál. + Később engedélyezheted a Beállításokban + Csatlakozni fogsz a csoporthoz amikor a csoport tulajdonosának az eszköze online lesz. Kérlek várj vagy nézz vissza később! + eltérő migráció az appban/adatbázisban: %s / %s + Már kapcsolatban vagy vele: %1$s. + Profil felfedése + Ez a link nem érvényes meghívó link! + A felek közötti titkosítás (e2e) ellenőrzéséhez hasonlítsd össze (vagy olvasd be) a kódot az ismerősöddel együtt az eszközeiteken! + A legfrissebb chat adatbázis verziódat kell használd, kizárólag egyetlen eszközön, máskülönben leállhat az üzenetek fogadása néhény ismerőstől! + Ez a beállítás a jelenlegi chat profilodban lévő üzenetekre érvényes + Meg vagy hívva a csoportba. Csatlakozz és lépj kapcsolatba a csoporttagokkal! + Ez a csoport többé nem létezik. + A csatlakozásod már folyamatban van a csoporthoz ezzel a linkkel! + Meg vagy hívva a csoportba + Az ismerősöd a jelenleg megengedett maximálisan méretű (%1$s) fájlnál nagyobbat küldött. + Nem tároljuk egyetlen üzenetedet illetve ismerőseidet (kézbesítás után) a SimpleX szervereken. + Üzenetek formázása a szövegbe szúrt speciális karakterekkel: + Mobil appban megnyitás gombra.]]> + A chat profilod megküldésre kerül +\naz ismerősöd számára + Egy olyan ismerőst próbálsz meghívni, akivel inkognító profilt osztottál meg abban a csoportban, amelyben a saját fő profilodat használod + Már folyamatban van a csatlakozásod a %1$s csoporthoz. + Amikor az app fut + Inkognító profilt használsz ehhez a csoporthoz - a fő profilod megosztásának elkerülése érdekében meghívók küldése tiltott + Kapcsolat izolációs mód + Csatlakoztok amikor a meghívód elfogadásra kerül. Kérlek várj vagy nézz vissza később! + A hangüzenetek tiltottak ebben a csoportban. + App akkumulátor használat / Korlátlan módot az app beállításaiban.]]> + Biztonságos kvantum ellenálló protokoll által. + - hangüzenetek 5 percig. +\n- egyedi eltűnési időhatár +\n- előzmény szerkesztése + Használd a számítógépről gombra a mobil appban és olvasd be a QR-kódot!]]> + %s at %s + Csatlakoztok amikor az ismerősöd eszköze online lesz. Kérlek várj vagy nézz vissza később! + Kéretlen üzenetek elrejtése. + Használd az .onion hostokat \u0020NEM-re ha a SOCKS proxy nem támogatja.]]> + Megoszthatod a SimpleX azonosítódat linkben vagy QR-kódban - bárki kapcsolatfelvételt kezdeményezhet veled. + Később létrehozhatod + A profilod a te eszközödön van tárolva és csak az ismerőseiddel kerül megosztásra! A SimpleX chat szerverek nem láthatják a profilodat! + %s szerepkörét megváltoztattad erre: %s + Elutasítottad a meghívót a csoportba + Az adatvédelem érdekében, a más chat platformokon megszokott felhasználói azonosítók helyett, a SimpleX üzenetsorokhoz rendel azonosítókat, minden egyes ismerősödhöz egy különbözőt. + (megosztás az ismerősöddel) + Csoport meghívót küldtél + Kapcsolat izolációs mód frissítése? + Kapcsolat izolációs mód + Ettől a csoporttól nem fogsz értesítéseket kapni. A chat előzmény megmarad. + A chat adatbázisod nem titkosított - állíts be jelmondatot a megvédéséhez! + Közvetlen internet kapcsolat használata? + Továbbra is kapsz hívásokat és értesítéseket az elnémított profilokból amikor azok aktívak. + A saját fő chat profilod megküldésre kerül a csoporttagok számára. + Később engedélyezheted az app Adatvédelmi és Biztonsági beállításaiban. + A rejtett profilod felfedéséhez gépeld be a jelszót a kereső mezőbe a Chat profiljaid oldalon! + A chat frissítése és megnyitása + Ahhoz, hogy hangüzeneteket küldhess, engedélyezned kell az ismerőseidnek is azok küldését. + fogadodaz üzeneteket, míg az ismerőseid a szervereket amelyeken át üzensz nekik.]]> + Már a %1$s csoportban vagy. + megváltoztattad az azonosítót + Az ismerőseid engedélyezhetik a teljes üzenet törlést. + Be kell írd a jelmondatodat a SimpleX app minden indulásakor - nem az eszközön lesz tárolva. + Ahhoz, hogy engedélyezd a mobil app csatlakozását a számítógépedhez, nyisd meg ezt a portot a tűzfaladon, ha az engedélyezve van + A te profilod, ismerőseid és az elküldött üzeneteid a te eszközödön vannak tárolva (a SimpleX chat szerverekről kézbesítés illetve a TTL időkorlát után törlődnek). + App akkumulátor használat / Korlátlan módot az app beállításaiban.]]> + Ez a karakterlánc nem meghívó link! + Új chat kezdése + Csatlakozásod már folyamatban van ezzel az Egyszer használatos link-el! + Nem fogod leveszíteni az ismerőseidet ha később törlöd a SimpleX azonosítódat. + A beállítások frissítése a szerverekhez újra kapcsolódással jár. + kapcsolatba akar lépni veled! + a saját szerepkörödet megváltoztattad erre: %s + A chat szolgáltatást elindíthatod a beállítások / adatbázis pontban vagy az app újraindításával. + Ellenőrizd a kódot a mobilon! + Csatlakoztál ehhez a csoporthoz. Kapcsolódás a meghívó csoporttaghoz. + a SimpleX Chat fejlesztőivel és kérdezhetsz bármit és értesülhetsz az újdonságokról.]]> + Opcionális üdvözlő szöveggel. + Ismeretlen adatbázis hiba: %s + Elrejtheted vagy némíthatod egy felhasználó profilját - tartsd lenyomva a menühöz! + Inkognító mód csatlakozáskor + TOR .onion host beállítások frissítése? + Megoszthatsz egy linket vagy QR-kódot - így bárki csatlakozhat a csoporthoz. Csoporttagokat nem fogsz elveszíteni, az esetben sem ha kásőbb törlöd a csoportot. + Csatlakoztál ehhez a csoporthoz + Ez a linked a %1$s csoporthoz! + A hangüzenetek tiltottak ebben a chatben. + Te tartod kézben chatedet! + Kód ellenőrzése a számítógépen + Az időzóna, kép/hang fájlok megvédése érdekében használd az UTC-t! + A meghívó elküldésre kerül a csoporttag számára. + Amikor megosztasz egy inkognító profilt valakivel, az a profil lesz használva a csoporthoz is amibe meghív. + Már küldtél meghívót ezen az azonosítón keresztül! + Megoszthatod ezt a SimpleX azonosítót az ismerőseiddel, hogy kapcsolatba léphessenek %s-el . + Amikor meghívót kapsz emberektől, elfogadhatod vagy elutasíthatod azokat! + Állítsd be az új tagoknak megjelenő üzenetet! + Köszönet a felhasználóknak - hozzájárulás a Weblaten! + A kézbesítési jelentés küldése minden kapcsolat számára engedélyezve lesz. + Protokoll időkorlát KB-onként + Az adatbázis jelmondatának megváltoztatására tett kísérlet nem fejeződött be. + Ez a művelet nem vonható vissza - a kiválasztottnál korábban küldött és fogadott üzenetek törlésre kerülnek. Ez több percet is igénybe vehet. + A profilod csak az ismerőseid számára kerül megosztásra. + Néhány szerver megbukott a teszten: + Érintsd meg a csatlakozáshoz + Ez a művelet nem vonható vissza - az összes fogadott és küldött fájl a médiatartalommal együtt törlésre kerülnek. Az alacsony felbontású képek viszont megmaradnak. + A kézbesítési jelentés engedélyezve van %d ismerősnél + Küldés ezen keresztül: + Köszönet a felhasználóknak - hozzájárulás a Weblaten! + A kézbesítési jelentés küldése az összes látható csevegőprofilban lévő összes ismerős számára engedélyezve lesz. + Bluetooth támogatás és egyéb fejlesztések. + Ez a funkció még nem támogatott. Próbáld meg a következő kiadásban. + A bejegyzés frissítve: %s + Tagok meghívásának kihagyása + Ezek felülbírálhatóak az ismerős- és csoportbeállításokban. + Az ismerős, akivel megosztottad ezt a linket, NEM fog tudni csatlakozni! + A véletlenszerű jelmondat egyszerű szövegként van tárolva a beállításokban. +\nKésőbb megváltoztathatod. + Érintsd meg az inkognitóban való csatlakozáshoz + Jelmondat beállítása az exportáláshoz + A kézbesítési jelentés le van tiltva %d csoportnál + Néhány nem végzetes hiba történt az importálás során - további részletekért lásd a Chat-konzolt. + Köszönet a felhasználóknak - hozzájárulás a Weblaten! + A relé szerver csak végszükség esetén használatos. Egy másik fél megfigyelheti az IP-címedet. + Állítsa be a rendszerhitelesítés helyett. + A fogadó cím egy másik szerverre változik. A címváltoztatás a feladó online állapotba kerülése után fejeződik be. + A csevegés leállítása a csevegőadatbázis exportálásához, importálásához vagy törléséhez. A csevegés leállítása alatt nem tudsz üzeneteket fogadni és küldeni. + Jelmondat mentése a Kulcstárban + Köszönet a felhasználóknak - hozzájárulás a Weblaten! + Jelmondat mentése a beállításokban + Ennek a csoportnak több mint %1$d tagja van, a kézbesítési jelentések nem kerülnek elküldésre. + A második jelölés, amit kihagytunk! ✅ + A relés szerver védi az IP-címedet, de megfigyelheti a hívás időtartamát. + További információ a GitHub tárolónkban. + Az utolsó üzenet tervezetének megőrzése a mellékletekkel együtt. + A mentett WebRTC ICE-kiszolgálók eltávolításra kerülnek. + A kézbesítési jelentés engedélyezve van %d csoportnál + A szerepkör \"%s\"-re fog változni. A csoportban mindenki értesítést kap. + Profil és szerverkapcsolatok + A Te adatvédelmedet és biztonságodat védő üzenetküldő és alkalmazásplatform. + Érintsd meg a profil aktiválásához. + A kézbesítési jelentés le van tiltva %d ismerősnél + Legalább egy felhasználói profilnak kell lennie. + Munkamenet kód + Köszönet a felhasználóknak - hozzájárulás a Weblaten! + Kis csoportok (max. 20 tag) + Az általad elfogadott kapcsolat törlésre kerül! + Élő üzenet küldése - a címzett(ek) számára frissül, miközben írod az üzenetet. + A KÉZBESÍTÉSI JELENTÉSEKET A KÖVETKEZŐ CÍMRE KELL KÜLDENI + A következő üzenet azonosítója hibás (kisebb vagy egyenlő az előzővel). +\nEz valamilyen hiba, vagy sérült kapcsolat esetén fordulhat elő. + Az eszköz neve megosztásra kerül a csatlakoztatott mobil klienssel. + A címzettek a beírás közben látják a frissítéseket. + Kérjük, hogy a jelmondatot biztonságosan tárold, ha elveszíted, NEM tudod megváltoztatni. + A jelmondat a beállításokban egyszerű szövegként tárolódik, miután megváltoztattad vagy újraindítottad az alkalmazást. + Jelenlenlegi profilod új ismerőseinek kiszolgálói + Fogadás a + Kérjük, hogy a jelmondatot biztonságosan tárold, ha elveszíted, NEM fogsz tudni hozzáférni a chathez. + A szerepkör \"%s\"-re fog változni. A tag új meghívót kap. + Legalább egy látható felhasználói profilnak kell lennie. + profilkép helyőrző + A titkosítás működik, és új titkosítási egyezményre nincs szükség. Ez kapcsolati hibákat eredményezhet! + Ez a művelet nem vonható vissza - profilod, ismerőseid, üzeneteid és fájljaid visszafordíthatatlanul törlésre kerülnek. + A bejegyzés frissítve + Felhasználói útmutatóban olvasható.]]> + A jelmondat a beállításokban egyszerű szövegként van tárolva. + Konzol megjelenítése új ablakban + Az előző üzenet hash-e más. + Ezek a beállítások a jelenlegi profilodra vonatkoznak + Kérjük, várj, amíg a fájl betöltődik az összekapcsolt mobilról. + GitHub tárolónkban.]]> + hiba a tartalom megjelenítése közben + hiba az üzenet megjelenítésekor \ No newline at end of file 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 79c1897153..f01568c03b 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/it/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/it/strings.xml @@ -41,7 +41,7 @@ incognito via link indirizzo del contatto via link una tantum incognito via link una tantum - Indirizzo del contatto SimpleX + Indirizzo di contatto SimpleX Invito SimpleX una tantum Link gruppo SimpleX Link completo @@ -508,7 +508,7 @@ Android Keystore verrà usato per memorizzare in modo sicuro la password dopo il riavvio dell\'app o la modifica della password; consentirà di ricevere le notifiche. Nota bene: NON potrai recuperare o cambiare la password se la perdi.]]> Cambiare password del database\? - Conferma password nuova… + Conferma nuova password… Password attuale… Database crittografato! La password di crittografia del database verrà aggiornata. @@ -623,7 +623,7 @@ Salva I server WebRTC ICE salvati verranno rimossi. Condividi link - Stella su GitHub + Dai una stella su GitHub Aggiornare l\'impostazione degli host .onion\? Usare una connessione internet diretta\? Usa gli host .onion @@ -775,7 +775,7 @@ Tocca per entrare Toccare per entrare in incognito Questo gruppo non esiste più. - profilo del gruppo aggiornato + ha aggiornato il profilo del gruppo Sei stato/a invitato/a al gruppo hai cambiato indirizzo hai cambiato l\'indirizzo per %s @@ -1368,9 +1368,9 @@ SimpleX non può funzionare in secondo piano. Riceverai le notifiche solo quando l\'app è aperta. Utilizzo batteria dell\'app / Senza restrizioni nelle impostazioni.]]> Utilizzo batteria dell\'app / Senza restrizioni nelle impostazioni.]]> - %s e %s sono connessi/e - %s, %s e altri %d membri sono connessi - %s, %s e %s sono connessi/e + %s e %s si sono connessi/e + %s, %s e altri %d membri si sono connessi + %s, %s e %s si sono connessi/e Bozza Mostra gli ultimi messaggi Il database verrà crittografato e la password conservata nelle impostazioni. @@ -1380,7 +1380,7 @@ Rimuovere la password dalle impostazioni\? Usa password casuale Salva password nelle impostazioni - Configura password del database + Configura la password del database Imposta password del database Apri cartella del database La password verrà conservata nelle impostazioni come testo normale dopo averla cambiata o il riavvio dell\'app. @@ -1469,7 +1469,7 @@ Scollegare il desktop? Opzioni del desktop collegato Desktop collegati - Trova nella rete + Individua via rete locale Questo dispositivo Cellulari collegati Desktop @@ -1517,4 +1517,19 @@ \n- e molto altro! In attesa che il cellulare si connette: autore + Connetti automaticamente + In attesa del desktop… + Desktop trovato + Non compatibile! + individuabile via rete locale + Ricarica + Crea profilo di chat + Nessun cellulare connesso + Disconnetti cellulari + Casuale + Per consentire a un\'app mobile di connettersi al desktop, apri questa porta nel tuo firewall, se è attivo + Vedi crash + Apri porta nel firewall + errore di visualizzazione del contenuto + errore di visualizzazione del messaggio \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/nl/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/nl/strings.xml index 5f45304aac..bb5226e3d4 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/nl/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/nl/strings.xml @@ -209,7 +209,7 @@ Maak Maak een profiel aan Adres verwijderen - Verbinden via relais + Altijd relay gebruiken contact heeft e2e-codering contact heeft geen e2e versleuteling De database is versleuteld met een willekeurige wachtwoord. Wijzig dit voordat u exporteert. @@ -741,7 +741,7 @@ Relay server wordt alleen gebruikt als dat nodig is. Een andere partij kan uw IP-adres zien. Uw ICE servers Overgeslagen berichten - via relais + via relay Video uit App scherm verbergen Uw privacy @@ -1383,7 +1383,7 @@ Database map openen Het wachtwoord wordt als platte tekst in de instellingen opgeslagen nadat u deze hebt gewijzigd of de app opnieuw hebt opgestart. Het wachtwoord wordt als leesbare tekst in de instellingen opgeslagen. - Let op: bericht en bestands relais zijn verbonden via SOCKS-proxy. Voor oproepen en het verzenden van link voorbeelden wordt gebruik gemaakt van een directe verbinding.]]> + Let op: bericht en bestands relays zijn verbonden via SOCKS-proxy. Voor oproepen en het verzenden van link voorbeelden wordt gebruik gemaakt van een directe verbinding.]]> Versleutel lokale bestanden Versleutel opgeslagen bestanden en media Nieuwe desktop app! @@ -1402,7 +1402,7 @@ Stuur een direct bericht om verbinding te maken stuur een direct bericht direct verbonden - Uitbreiden + Uitklappen Verbindingsverzoek herhalen? verwijderd contact Fout @@ -1431,7 +1431,7 @@ Lid blokkeren Deelnameverzoek herhalen? Lid verwijderen? - Contact verwijderen en op de hoogte stellen + Verwijderen en contact op de hoogte stellen Open groep Berichten van %s worden getoond! Fout bij verzenden van uitnodiging @@ -1520,4 +1520,14 @@ Desktop gevonden Niet compatibel! Vindbaar via lokaal netwerk + Vernieuwen + Chatprofiel aanmaken + Mobiele telefoons loskoppelen + Geen verbonden mobiel + willekeurig + Om een mobiele app verbinding te laten maken met de desktop, opent u deze poort in uw firewall, als u deze hebt ingeschakeld + Weergave gecrasht + Open poort in firewall + Fout bij het tonen van inhoud + fout bij weergeven bericht \ No newline at end of file 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 9e8bd0af8c..76a49f678d 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/ru/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/ru/strings.xml @@ -1605,4 +1605,11 @@ Несовместимая версия! автор Найти через локальную сеть + Обновить + Случайный + Чтобы разрешить мобильному приложению подключаться к компьютеру, откройте этот порт в брандмауэре, если он включен + Создать профиль чата + Открыть порт в брандмауэре + Отключить мобильные + Нет подключённых мобильных \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/tr/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/tr/strings.xml index ff9febd088..8a3eeef61d 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/tr/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/tr/strings.xml @@ -48,7 +48,7 @@ Uygulama sürümü: v%s sesli arama sesli arama (uçtan uca şifreli değil) - Aramaya cevap ver + Aramayı cevapla Uygulama veri yedekleme Tüm uygulama verileri silinir. UYGULAMA @@ -242,7 +242,7 @@ Geri çevrilmiş çağrı Görüşme bitti. %1$d mesaj atlanıldı. - Konuşma veri tabanı silindi + Sohbet veri tabanı silindi Hata: %s Bilinmeyen hata bağlanıldı @@ -257,10 +257,10 @@ evet Onayla Konuştuğun kişiler, kendiliğinden yok olan mesajlara izin veriyorsa sen de ver. - Konuştuğun kişilerin gönderilen mesajları kalıcı olarak silmesine izin ver. + Kişilerinin gönderilen mesajları kalıcı olarak silmesine izin ver. Kendiliğinden yok olan measj gönderimini engelle. Konuştuğun kişi, kalıcı olarak silinebilen mesajlara izin veriyorsa sen de ver. - Konuştuğun kişi, mesaj tepkilerine izin veriyorsa sen de ver. + Yalnızca kişin mesaj tepkilerine izin veriyorsa sen de ver. Sadece sen kendiliğinden yok olan mesaj gönderebilirsin. Sadece konuştuğun kişi kendiliğinden yok olan mesaj gönderebilir. Konuştuğun kişi de sen de kendiliğinden yok olan mesaj gönderebilirsiniz. @@ -269,17 +269,17 @@ Gönderilen mesajlar, önceden belirlenmiş bir süre sonra silecektir. Kullanıldığında bütün veriler silinir. Kendiliğinden yok olan mesajlar - Konuştuğun kişilerin sana, kendiğinden yok olan mesajlar göndermesine izin ver. + Kişilerinin sana, kendiğinden yok olan mesajlar göndermesine izin ver. Bu grupta kendiliğinden yok olan mesajlara izin verilmiyor. %1$d mesaj deşifrelenemedi. %1$s ÜYE %1$d atlanılmış mesaj - Konuştuğun kişi, aramalara izin veriyorsa sen de ver. + Yalnızca irtibat kişiniz izin veriyorsa aramalara izin verin. Konuştuğun kişilerin mesajlarına tepki eklemesine izin ver. - Konuştuğun kişilerin seni aramasına izin ver. - Konuştuğun kişilerin tümü bağlı kalacaktır. + Kişilerinin seni aramasına izin ver. + Kişilerin tümü bağlı kalacaktır. Dosya ön izlemesini iptal et - Konuşma veri tabanı içe aktarıldı + Sohbet veri tabanı içe aktarıldı Görsel ön izlemesini iptal et Konuşmayı temizle\? Çince ve İspanyolca arayüz @@ -296,7 +296,7 @@ ARAMALAR KONUŞMALAR SEN - KONUŞMA VERİ TABANI + SOHBET VERİ TABANI Kaldır Yanlış parola! Veri tabanının yapısal ilerlemelerini onayla @@ -309,8 +309,8 @@ ÜYE Grup üyeleri kendiliğinden yok olan mesajlar gönderebilir. Kendiliğinden yok olan mesaj gönderimini engelle. - Konuştuğun kişi, sesli mesajlara izin veriyorsa sen de ver. - Konuştuğun kişilerin sesli mesaj göndermesine izin ver. + Yalnızca kişiniz sesli mesaj göndermeye izin veriyorsa sen de ver. + Kişilerinin sesli mesaj göndermesine izin ver. Konuştuğun kişi de sen de mesajlara tepki ekleyebilirsinsiz. Konuştuğun kişi de sen de sesli mesaj gönderebilirsiniz. Kendiliğinden yok olan mesajlar @@ -410,7 +410,7 @@ Özeksiz Erişim kodunu onayla Yanlış erişim kodu - Yeni Şifre + Yeni erişim kodu Gönder Erişim kodu Erişim kodu değişti! @@ -877,9 +877,9 @@ Kişileriniz bağlı kalacaktır. Daha sonra oluşturabilirsiniz Mesajları biçimlendirmek için markdown kullanabilirsiniz: - Mesaj veri tabanınız + Sohbet veri tabanınız Mevcut sohbet veritabanınız SİLİNECEK ve içe aktarılan veritabanıyla DEĞİŞTİRİLECEKTİR. -\nBu işlem geri alınamaz - profiliniz, kişileriniz, mesajlarınız ve dosyalarınız geri alınamaz şekilde kaybolacaktır. +\nBu eylem geri alınamaz - profiliniz, kişileriniz, mesajlarınız ve dosyalarınız geri alınamaz şekilde kaybolacaktır. Bu gruba katıldınız. Davet eden grup üyesine bağlanılıyor. Gruba davetlisiniz. Grup üyeleriyle bağlantı kurmak için katılın. Bu grup için gizli bir profil kullanıyorsunuz - ana profilinizi paylaşmayı önlemek için kişileri davet etmeye izin verilmiyor @@ -1004,7 +1004,7 @@ Alınan linki yapıştır Bilinmeyen veri tabanı hatası: %s Sohbeti aç - Veritabanı yedeğini geri yükledikten sonra önceki şifreyi girin. Bu işlem geri alınamaz. + Veritabanı yedeğini geri yükledikten sonra önceki şifreyi girin. Bu eylem geri alınamaz. PING aralığı KB başına protokol zaman aşımı Sohbet profilini gizlemeyi kaldır @@ -1069,4 +1069,212 @@ Paylaşmayı durdur Dosya almayı durdur? Sohbeti durdur? + Genişlet + Bağlantı isteğini tekrarla? + detay yok + Veri tabanı düzgün çalışmıyor. Daha fazla bilgi için dokunun + Açık kaynaklı protokol ve kod - sunucuları herkes çalıştırabilir. + + Önizlemeyi göster + Depolanan dosyaları ve medyayı şifrele + Sadece sen sesli mesaj gönderebilirsin. + Güncelle + Veritabanı parolasını değiştirme girişimi tamamlanmadı. + Veri tabanı parolasını güncelle + Uygulama ayarlarını aç + Bu eylem geri alınamaz - seçilenden daha önce gönderilen ve alınan mesajlar silinecektir. Birkaç dakika sürebilir. + Grup oluştur + Seç + Sadece sen arama yapabilirsin. + Yeni mobil cihaz + Sohbeti kullan + Otomatik olarak bağlan + Paylaş + %s, %s ve %d diğer üye bağlandı + Sadece senin kişin arama yapabilir. + Masaüstü adresi + Bazı sunucular testi geçemedi: + Sorularınızı ve fikirlerinizi gönderin + Bu eylem geri alınamaz - tüm alınan ve gönderilen dosyalar ve medyalar silinecek. Düşük çözünürlükteki resimlar kalacaktır. + Yerel dosyaları şifrele + SimpleX Chat aramaları + Yeni masaüstü uygulaması! + 6 yeni arayüz dili + Sadece kişiyi göster + Grup zaten mevcut! + Hoparlör açık + Sadece senin kişin sesli mesaj gönderebilir. + Bu özellik henüz desteklenmiyor. Bir sonraki sürümü deneyin. + Masaüstünden kullan seçeneğini aç ve karekodu okut.]]> + SimpleX Chat\'i yüklediğiniz için teşekkürler! + Üyeleri davet etmeyi atla + Zaten bağlanılıyor! + Mesaj Gönder + Bu bağlantıyı paylaştığınız kişi bağlanamayacak! + Uyumsuz sürüm + (yeni)]]> + Kişiyi ve mesajı göster + Daha iyi gruplar + Videonun kodu çözülemiyor. Lütfen farklı bir video deneyin veya geliştiricilerle iletişime geçin. + İçe aktarma sırasında bir takım hatlar oluştu - daha fazla detay için sohbet konsoluna bakabilirsiniz. + Geliştirici seçeneklerini göster + %s bağlandı + Onaylarsanız, mesajlaşma sunucuları IP adresinizi ve sağlayıcınızı - hangi sunuculara bağlandığınızı - görebilecektir. + Kişilerle paylaş + %s saniye (sn) + %s: %s + SimpleX arka planda çalışamaz. Bildirimleri sadece uygulama çalışırken alırsınız. + Bağlantı ile bağlan? + Veri tabanı şifreleme parolası güncellenecek ve ayarlarda depolanacaktır. + Zaten gruba bağlanılıyor! + %s, %s ve %d üye + Bu cihaz + Adresi kişilerle paylaş? + Uygulama arka planda 1 dakika kaldıktan sonra kapatılabilir. + Kişi ismini ayarla… + Bize e-posta gönder + SimpleX Chat\'in güvenliği Trail of Bits tarafından denetlenmiştir. + SimpleX Chat hizmeti + %s onaylı + Göserilecek parola + Tek bir sohbet profilinde, aralarında herhangi bir veri paylaşımı olmadan birden fazla anonim bağlantı kurmaya izin verir. + Kişileri seç + Kullanıcılara teşekkürler - Weblate aracılığıyla katkıda bulunun! + Basitleştirilmiş gizli mod + Ağ ayarlarını güncelle? + Kapat? + Bir kişiyi davet ettin + %s onaylı değil + Bu cihazın ismi + Dosya yükle + Gerekli + SimpleX Chat mesajlar + Bağlantı paylaş + SimpleX Ekibi + %s, %s ve %s bağlandı + Geri al + SOCKS PROXY + Masaüstür cihazlar + SMP sunuclar + Uyumlu değil! + Bağlantı güvenliğini onayla + %1$s ile bağlan? + Üyeyi çıkar + Veri tabanı dosyasını aç + Masaüstünden kullan + port %d + Adres paylaş + Bağlantı talebini tekrarla? + Üyeyi çıkar? + Güvenlik kodunu onayla + Göster: + Küçük gruplar (maks 20) + Arapça, Bulgarca, Fince, İbranice, Tayca ve Ukraynaca - kullanıcılar ve Weblate sayesinde. + Port + Kabul ettiğiniz bağlantı iptal edilecek! + Grubu aç + Son mesajları göster + bu cihaz s%s]]> + simplexmq: v%s (%2s) + Güncelle + Cihaz ismi bağlı olduğu mobil istemci ile paylaşılacak. + Masaüstü uygulamasında yeni bir profil oluştur. 💻 + Kişi ismini ayarla + Kodu mobilde onayla + Medya paylaş… + Parola, siz onu değiştirdikten veya uygulamayı yeniden başlattıktan sonra ayarlarda düz metin olarak depolanacak. + Kişinizle bağlantı kurmak için aldığınız bağlantıyı yapıştırın… + Kapat + gönderildi + Canlı mesaj gönder + Bu cihazın adını girin… + Mevcut sohbet profilinizin yeni bağlantıları için sunucular + QR kodu göster + SOCKS proxy ayarları + %d grup etkinlikleri + Geçersiz isim! + SimpleX Kilit modu + Dosya paylaş… + Uygulama yeni mesajları periyodik olarak alır - günde pilin yüzde birkaçını kullanır. Uygulama anlık bildirimleri kullanmaz - cihazınızdan gelen veriler sunuculara gönderilmez. + Herhangi bir kullanıcı tanımlayıcısı olmayan ilk platform - tasarım gereği gizli. + Hoparlör kapalı + Şifreleme çalışıyor ve yeni bir şifreleme anlaşması gerekli değil. Yoksa bağlantı hataları ortaya çıkabilir! + Göster + Gönder + Masaüstü adresini yapıştır + Kodu masaüstü ile onayla + Masaüstünden karekodu tara + SimpleX logo + Cihazlar + Bu eylem geri alınamaz - profiliniz, kişileriniz, mesajlarınız ve dosyalarınız geri döndürülemez şekilde kaybolacaktır. + - isteğe bağlı olarak silinen kişileri bildirme. +\n- boşluklu profil adları. +\n- ve daha fazlası! + SimpleX Kilit + Bu grup üyesine bağlantı isteği gönderilecek. + Sadece senin kişin mesaj tepkileri ekleyebilir. + Parola, ayarlarda düz metin olarak saklanır. + SimpleX Kilit aktif + Yeni pencerede konsolu göster + Mobilden tara + Bağlantıları onayla + Mesaj paylaş… + Önceki mesajın hash\'i farklı. + SimpleX Kilit aktif değil! + SimpleX Kilit + Direkt bağlan? + Bu ayarlar mevcut profiliniz içindir + Sunucu testi başarısız! + Bağlantıyı onayla + Yeni sohbet başlat + Profiliniz %1$s paylaşılacaktır. + Rastgele bir profil kullanarak grup oluştur. + Gruba zaten bu bağlantı üzerinden katılıyorsunuz. + Sohbet profiliniz kişinize +\ngönderilecek + Gizli bir profil paylaştığınız kişiyi ana profilinizi kullandığınız gruba davet etmeye çalışıyorsunuz + güvenlik kodu değiştirildi + Bluetooth desteği ve diğer iyileştirmeler. + Ayarlar + AYARLAR + Bağlanmak için direkt mesaj gönderin + Güvenlik kodu + Daha hızlı gruplara katılma ve daha güvenilir mesajlar. + Sohbet profiliniz grup üyelerine gönderilecek + Kendine bağlan? + Periyodik olarak başlar + Bu sizin kendi SimpleX adresiniz! + Kişileriniz tam mesaj silme işlemine izin verebilir. + gönderme başarısız + Gönderen kişi bağlantı isteğini silmiş olabilir. + Sohbet profili oluştur + Davetiye gönderirken hata + Sohbeti uygulama Ayarları/Veritabanı üzerinden veya uygulamayı yeniden başlatarak başlatabilirsiniz. + Masaüstüne bağlan + Direkt mesaj gönder + Bu adres üzerinden zaten bağlantı talebinde bulundunuz! + direkt mesaj gönder + Gönderen kişi dosya aktarımını iptal etti. + Mesajları yalnızca siz geri döndürülemez şekilde silebilirsiniz (kişiniz bunları silinmek üzere işaretleyebilir). + Zaten %1$s\'ye bağlanıyorsunuz. + Kullanıcılara teşekkürler - Weblate aracılığıyla katkıda bulunun! + Kilit modu + Aynı anda yalnızca bir cihaz çalışabilir + Zaten %1$s grubuna katılıyorsunuz. + Katılmak için dokun + Kullanıcılara teşekkürler - Weblate aracılığıyla katkıda bulunun! + Güvenli kuantum dirençli protokol ile. + Bize Github\'da yıldız verin + Arka planda 30 saniye kaldıktan sonra uygulamayı başlattığınızda veya devam ettirdiğinizde kimlik doğrulaması yapmanız gerekecektir. + Kullanıcılara teşekkürler - Weblate aracılığıyla katkıda bulunun! + Masaüstü bekleniyor… + Sohbet veri tabanınız şifreli değildir - korumak için parola ayarlayın. + Aktif olduklarında sessize alınmış profillerden arama ve bildirim almaya devam edersiniz. + Zaten %1$s grubundasınız. + Kullanıcılara teşekkürler - Weblate aracılığıyla katkıda bulunun! + Bu tek seferlik bağlantı üzerinden zaten bağlanıyorsunuz! + Geçersiz bir dosya yolu paylaştınız. Sorunu uygulama geliştiricilerine bildirin. + Bildirimleri devre dışı bırak + Geçersiz dosya yolu + Yalnızca kişiniz mesajları geri alınamaz şekilde silebilir (silinmeleri için işaretleyebilirsiniz). \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/uk/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/uk/strings.xml index d9d49aef7d..faf2895827 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/uk/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/uk/strings.xml @@ -2,8 +2,8 @@ 1 хвилина Про SimpleX - Прийняти запит на підключення\? - вище, тоді: + Прийняти запит на з\'єднання? + вище, а потім: Прийняти Прийняти Акцент @@ -14,564 +14,564 @@ Прийняти 5 хвилин 1 місяць - Про адресу SimpleX + Про SimpleX-адресу 1-разове посилання Про SimpleX Chat - Додайте сервери, відсканувавши QR-коди. - Всі чати та повідомлення будуть видалені - це неможливо скасувати! - Дозволяйте дзвінки, тільки якщо ваш контакт дозволяє їх. - Дозволяйте безповоротне видалення повідомлень, тільки якщо контакт дозволяє вам це зробити. + Додавайте сервери, скануючи QR-коди. + Всі чати і повідомлення будуть видалені - цю дію неможливо скасувати! + Дозволяйте дзвінки тільки в разі дозволу вашого контакту. + Дозволяйте невідворотне видалення повідомлень тільки в разі дозволу вашого контакту. Дозволити голосові повідомлення\? - Код доступу до програми замінено на пароль самознищення. - Додавання попередньо встановлених серверів - Резервне копіювання даних програми - Додати до іншого пристрою - Android Keystore використовується для безпечного зберігання парольної фрази - це дозволяє сервісу сповіщень працювати. - Адміни можуть створювати посилання для приєднання до груп. - Збірка програми: %s - Дозволяйте голосові повідомлення, тільки якщо ваш контакт дозволяє їх. - Дозволити відправляти зникаючі повідомлення. - прийнято виклик - Завжди використовуйте реле + Пароль застосунку замінено паролем самознищення. + Додати попередньо встановлені сервери + Резервне копіювання даних застосунку + Додати на інший пристрій + Сховище ключів Android використовується для безпечного збереження ключової фрази - це дозволяє службі сповіщень працювати. + Адміністратори можуть створювати посилання для приєднання до групи. + Збірка додатку: %s + Дозволяйте голосові повідомлення тільки в разі дозволу вашого контакту. + Дозволяйте надсилати повідомлення, які зникають. + прийнятий виклик + Завжди використовувати реле ДОДАТОК - Дозволяє надсилати прямі повідомлення користувачам. - Дозволяє безповоротно видаляти надіслані повідомлення. - Дозволити надсилати голосові повідомлення. - Дозволити реакцію на повідомлення. - Всі дані стираються при введенні. - Пароль додатку - ЗНАЧОК ДОДАТКУ - Дозволяйте зникати повідомленням, тільки якщо ваш контакт дозволяє це робити. + Дозволяйте надсилати прямі повідомлення учасникам. + Дозволяйте невідворотне видалення відправлених повідомлень. + Дозволяйте надсилати голосові повідомлення. + Дозволити реакції на повідомлення. + Вся інформація стирається при його введенні. + Пароль для додатка + ІКОНКА ДОДАТКУ + Дозволяйте повідомлення, які зникають, тільки якщо ваш контакт дозволяє їх. Дозвольте вашим контактам додавати реакції на повідомлення. - Дозволяйте реакції на повідомлення, тільки якщо ваш контакт дозволяє їх. - Створюється порожній профіль чату з вказаним ім\'ям, і додаток відкривається у звичайному режимі. + Дозволяйте реакції на повідомлення тільки в разі дозволу вашого контакту. + Створений порожній профіль чату з наданим ім\'ям, і застосунок відкривається, як завжди. Додатковий акцент - Дозвольте вашим контактам безповоротно видаляти надіслані повідомлення. - Дозвольте + Дозвольте вашим контактам невідворотно видаляти відправлені повідомлення. + Дозволити Розширені налаштування мережі - Доступ до серверів через SOCKS проксі на порту %d\? Перед увімкненням цієї опції проксі має бути запущено. - Всі ваші контакти залишаться на зв\'язку. - Всі дані програми видаляються. - Android Keystore буде використовуватися для безпечного зберігання пароля після перезапуску програми або зміни пароля - це дозволить отримувати сповіщення. - Дозвольте своїм контактам надсилати голосові повідомлення. + Отримувати доступ до серверів через SOCKS-проксі на порті %d? Проксі має бути запущено до активації цієї опції. + Всі ваші контакти залишаться підключеними. + Всі дані застосунку буде видалено. + Після перезапуску додатка або зміни ключової фрази буде використано сховище ключів Android для безпечного збереження ключової фрази - це дозволить отримувати сповіщення. + Дозвольте вашим контактам надсилати голосові повідомлення. Прийняти інкогніто Додати сервер… - адмін - Додати вітальне повідомлення - Всі учасники групи залишаться на зв\'язку. - Дозвольте своїм контактам надсилати зникаючі повідомлення. - Всі повідомлення будуть видалені - це неможливо скасувати! Повідомлення будуть видалені ТІЛЬКИ для вас. - Версія програми - Додайте адресу до свого профілю, щоб ваші контакти могли поділитися нею з іншими людьми. Повідомлення про оновлення профілю буде надіслано вашим контактам. - Всі ваші контакти залишаться на зв\'язку. Повідомлення про оновлення профілю буде надіслано вашим контактам. - Відповісти на дзвінок + адміністратор + Додати привітання + Всі члени групи залишаться підключеними. + Дозвольте вашим контактам надсилати повідомлення, які зникають. + Всі повідомлення будуть видалені - цю дію неможливо скасувати! Повідомлення будуть видалені ЛИШЕ для вас. + Версія додатку + Додайте адресу до свого профілю, щоб ваші контакти могли поділитися нею з іншими людьми. Оновлення профілю буде відправлено вашим контактам. + Всі ваші контакти залишаться підключеними. Оновлення профілю буде відправлено вашим контактам. + Відповісти на виклик Адреса Додати профіль - Додатковий вторинний - Завжди увімкнено - Додаток може отримувати сповіщення лише під час роботи, жодні фонові служби не запускаються + Додатковий другорядний + Завжди включено + Додаток може отримувати сповіщення тільки тоді, коли він працює, фоновий сервіс не буде запущено завжди - Дозвольте вашим контактам телефонувати вам. - Для кожного профілю чату, який ви маєте в додатку, буде використовуватися окреме TCP-з\'єднання (і SOCKS-обліковий запис).]]> - Зовнішній вигляд - Версія програми: v%s - Для кожного контакту і члена групи буде використовуватися окреме TCP-з\'єднання (і SOCKS-обліковий запис). -\nЗверніть увагу: якщо у вас багато з\'єднань, споживання заряду акумулятора і трафіку може бути значно вищим, а деякі з\'єднання можуть обірватися. - Активна оптимізація заряду батареї, яка вимикає фоновий сервіс і періодичні запити на нові повідомлення. Ви можете знову увімкнути їх через налаштування. + Дозвольте вашим контактам дзвонити вам. + для кожного профілю чату, який у вас є в додатку.]]> + Вигляд + Версія додатку: v%s + Окреме TCP-підключення (і обліковий запис SOCKS) буде використовуватися для кожного контакту та учасника групи. +\nЗверніть увагу: якщо у вас багато підключень, споживання заряду батареї та трафіку може значно збільшитися, і деякі підключення можуть бути невдалими. + Активована оптимізація батареї, вимикається фоновий сервіс і періодичні запити нових повідомлень. Ви можете знову увімкнути їх у налаштуваннях. Назад жирний - Корисно для батареї. Фонова служба перевіряє повідомлення кожні 10 хвилин. Ви можете пропустити дзвінки або термінові повідомлення.]]> - Аудіо та відео виклики - Звук вимкнено - Автентифікація недоступна - Попросили отримати відео - Автоматичне прийняття запитів на контакт + Добре для акумулятора. Сервіс фонового запуску перевіряє повідомлення кожні 10 хвилин. Ви можете пропустити виклики чи важливі повідомлення.]]> + Аудіо та відеовиклики + Аудіо вимкнено + Аутентифікація недоступна + Запит на отримання відео + Автоприйняття запитів на контакт аудіовиклик (не зашифрований e2e) - І ви, і ваш контакт можете безповоротно видалити надіслані повідомлення. + Як ви, так і ваш контакт можете невідворотно видаляти відправлені повідомлення. Поганий хеш повідомлення Неправильний ідентифікатор повідомлення - Автоматичне прийняття зображень + Автоматично приймати зображення Кращі повідомлення - Звук увімкнено - Реакції на повідомлення можете додавати як ви, так і ваш контакт. + Аудіо увімкнено + Як ви, так і ваш контакт можуть додавати реакції на повідомлення. аудіовиклик - Найкраще для батареї. Ви отримуватимете сповіщення лише тоді, коли додаток працює (БЕЗ фонового сервісу).]]> - Аудіо та відеодзвінки - Автентифікація - Не вдалося пройти автентифікацію - Аутентифікацію скасовано - Автоприйняття + Найкраще для акумулятора. Ви отримуєте сповіщення тільки тоді, коли додаток працює (НЕТЛЕ фоновий сервіс).]]> + Аудіо та відеовиклики + Аутентифікація + Помилка аутентифікації + Аутентифікація відмінена + Автоприйом поганий хеш повідомлення - помилковий ідентифікатор повідомлення + поганий ідентифікатор повідомлення Фон - Додайте новий контакт: для створення одноразового QR-коду для вашого контакту.]]> - Його можна вимкнути в налаштуваннях - сповіщення все одно будуть показуватися під час роботи програми.]]> - Фоновий сервіс працює постійно - сповіщення з\'являтимуться, щойно повідомлення стануть доступними. - Попросили отримати зображення + Додайте новий контакт: щоб створити одноразовий QR-код для вашого контакту.]]> + Це можна вимкнути у налаштуваннях – сповіщення все одно будуть відображатися, коли програма працює. + Служба фонового режиму завжди активна – сповіщення відображатимуться, як тільки повідомлення будуть доступні. + Запит на отримання зображення Прикріпити Аудіо/відео дзвінки " -\nДоступно у v5.1" +\nДоступно в версії 5.1" Аудіо/відео дзвінки заборонені. SimpleX - Дзвонити можете як ви, так і ваш контакт. - k - Підключитися через контактну адресу? - Підключитися за одноразовим посиланням? + Як ви, так і ваш контакт можуть здійснювати дзвінки. + тис. + Підключитися через адресу контакту? + Підключитися через одноразове посилання? Приєднатися до групи? - Ваш профіль буде надіслано контакту, від якого ви отримали це посилання. - Ви з\'єднаєтеся з усіма учасниками групи. - Підключіться - підключений + Ваш профіль буде відправлено контакту, з якого ви отримали це посилання. + Ви приєднаєтеся до всіх учасників групи. + Підключити + підключено помилка підключення - Ви підключені до сервера, який використовується для отримання повідомлень від цього контакту. - Спроба з\'єднатися з сервером, який використовується для отримання повідомлень від цього контакту (помилка: %1$s ). + Ви підключені до сервера для отримання повідомлень від цього контакту. + Спроба підключитися до сервера для отримання повідомлень від цього контакту (помилка: %1$s). видалено - Спроба з\'єднатися з сервером, який використовується для отримання повідомлень від цього контакту. - з позначкою видалено - модерується %s + Спроба підключитися до сервера для отримання повідомлень від цього контакту. + відзначено як видалено + модеровано %s надсилання файлів поки що не підтримується - отримання файлів поки що не підтримується + приймання файлів поки що не підтримується ви невідомий формат повідомлення - невірний формат повідомлення - НАЖИВО - модерується - недійсний чат - невірні дані - з\'єднання встановлено - запрошено до підключення + неправильний формат повідомлення + LIVE + модеровано + неправильний чат + неправильні дані + підключення встановлено + запрошення на підключення підключення… ви поділилися одноразовим посиланням - ви поділилися одноразовим посиланням анонімно - через групове посилання - інкогніто через групове посилання - за посиланням на контактну адресу - інкогніто за посиланням на контактну адресу - за одноразовим посиланням - інкогніто за одноразовим посиланням - Контактна адреса SimpleX - Одноразове запрошення SimpleX - Посилання на групу SimpleX + ви поділилися одноразовим посиланням в інкогніто + через посилання групи + інкогніто через посилання групи + через посилання адреси контакту + інкогніто через посилання адреси контакту + через одноразове посилання + інкогніто через одноразове посилання + Адреса контакту у SimpleX + Одноразове запрошення у SimpleX + Посилання на групу у SimpleX через %1$s Посилання SimpleX Опис Повне посилання Через браузер - Відкриття посилання в браузері може знизити конфіденційність і безпеку з\'єднання. Ненадійні посилання SimpleX будуть червоного кольору. + Відкриття посилання в браузері може зменшити конфіденційність та безпеку з\'єднання. Ненадійні посилання SimpleX будуть виділені червоним кольором. Не вдалося завантажити чати - Помилка збереження SMP-серверів - Переконайтеся, що адреси SMP-серверів мають правильний формат, розділені рядками і не дублюються. + Помилка збереження серверів SMP + Переконайтеся, що адреси серверів SMP вірного формату, розділені переносами рядків і не дублюються. Помилка оновлення конфігурації мережі Не вдалося завантажити чат - Будь ласка, оновіть додаток та зв\'яжіться з розробниками. - Помилка при створенні профілю! - Ви вже маєте профіль у чаті з таким самим іменем. Будь ласка, виберіть інше ім\'я. - Помилка перемикання профілю! - Тайм-аут з\'єднання + Будь ласка, оновіть додаток і зверніться до розробників. + Помилка створення профілю! + Ви вже маєте профіль чату з таким самим ім\'ям відображення. Будь ласка, виберіть інше ім\'я. + Помилка переключення профілю! + Тайм-аут підключення Помилка підключення - Будь ласка, перевірте своє мережеве з\'єднання за допомогою %1$s і спробуйте ще раз. + Будь ласка, перевірте ваше мережеве підключення з %1$s та спробуйте ще раз. Контакт вже існує Помилка підключення (AUTH) - Можливо, відправник видалив запит на підключення. + Відправник, можливо, видалив запит на з\'єднання. Помилка видалення запиту на контакт Помилка зміни адреси - Помилка тесту на кроці %s. + Тест не пройшов на кроці %s. Сервер вимагає авторизації для створення черг, перевірте пароль - Можливо, в адресі сервера неправильно вказано відбиток сертифіката + Можливо, відбиток цифрового підпису сертифіката в адресі сервера невірний Створити чергу Миттєві сповіщення! Миттєві сповіщення вимкнено! Отримання повідомлень… - Приховати - Повідомлення SimpleX Chat - Показати тільки контакт + Сховати + Повідомлення чату SimpleX + Показати лише контакт Новий запит на контакт Підключено - SimpleX Lock увімкнено + Блокування SimpleX увімкнено Розблокувати - Вимкнути SimpleX Lock + Вимкнути блокування SimpleX Відповісти Зберегти Видалити - Повідомлення буде позначено для видалення. Отримувач(и) зможуть відкрити це повідомлення. - Видалити повідомлення користувача\? - Видалити для мене + Повідомлення буде позначено для видалення. Однак одержувач(і) зможуть розкрити це повідомлення. + Видалити повідомлення учасника? + Видалити лише для мене Для всіх - відредаговано - не вдалося відправити - не прочитано + редаговано + помилка відправки + непрочитане приєднатися як %s Скасувати попередній перегляд зображення Скасувати попередній перегляд файлу - Очікування зображення - Зображення надіслано - Очікування зображення + Очікування на зображення + Зображення відправлене + Очікування на зображення Великий файл! Файл збережено Голосове повідомлення Голосове повідомлення… - Контакт і всі повідомлення будуть видалені - це неможливо скасувати! - В очікуванні - Змінити адресу отримання\? + Контакт і всі повідомлення будуть видалені - цього не можна скасувати! + Очікує + Змінити адресу для отримання? Переглянути код безпеки - Щоб мати змогу надсилати голосові повідомлення, вам потрібно дозволити контакту надсилати їх. + Ви повинні дозволити вашому контакту надсилати голосові повідомлення, щоб мати змогу надсилати їх. Скасувати - ГАРАЗД + OK Скопійовано в буфер обміну - Підключитися за посиланням - Відкрийте в мобільному додатку, потім торкніться Підключіть в додатку.]]> - Вимкнути звук - Увімкнути звук - Ви запросили свого контакта - Контакт, якому ви надали це посилання, НЕ зможе підключитися! + Для підключення через посилання + Відкрити у мобільному додатку, а потім торкніться Підключити в додатку.]]> + Приглушити + Скасувати приглушення + Ви запросили контакт + Контакт, якому ви поділилися посиланням, НЕ зможе підключитися! заповнювач зображення профілю QR-код - допомога - покажіть QR-код у відеодзвінку або поділіться посиланням.]]> - Ваш профіль чату буде надіслано -\nдо вашого контакту - Посилання на одноразове запрошення - Неправильний код безпеки! - Щоб перевірити наскрізне шифрування з вашим контактом, порівняйте (або відскануйте) код на ваших пристроях. + довідка + покажіть QR-код у відеовиклику, або поділіться посиланням.]]> + Ваш профіль чату буде відправлено +\nвашому контакту + Одноразове запрошення + Невірний код безпеки! + Для перевірки end-to-end шифрування порівняйте (або скануйте) код на своїх пристроях. Ваші налаштування - Ваша адреса SimpleX - Допомога з уцінкою - SimpleX Lock + Ваша SimpleX-адреса + Допомога з Markdown + Блокування SimpleX Консоль чату Сервери SMP - Відскануйте QR-код сервера - Використовуйте для нових з\'єднань + Сканувати QR-код сервера + Використовувати для нових підключень Видалити сервер - Зірка на GitHub - Як користуватися вашими серверами - Збережені сервери WebRTC ICE буде видалено. - Налаштування серверів ICE + Оцінити на GitHub + Як використовувати ваші сервери + Збережені сервери WebRTC ICE будуть видалені. + Налаштувати сервери ICE Мережа та сервери Налаштування мережі - Використовувати SOCKS проксі\? - Використовуєте пряме підключення до Інтернету\? - Оновити налаштування хостів .onion\? - Використовуйте хости .onion - При наявності + Використовувати SOCKS-проксі? + Використовувати прямий підключення до Інтернету? + Оновити налаштування .onion-хостів? + Використовувати .onion-хости + Якщо доступно Ні - Onion хости будуть використовуватися за наявності. - Оновити режим транспортної ізоляції\? + .Onion-хости будуть використовуватися, якщо доступні. + Оновити режим ізоляції транспорту? simplexmq: v%s (%2s) Створити адресу - Поділіться посиланням + Поділитися посиланням Видалити адресу Повне ім\'я: Ви керуєте своїм чатом! - Платформа для обміну повідомленнями та додатків, що захищає вашу конфіденційність і безпеку. + Платформа обміну повідомленнями і застосунок, які захищають вашу конфіденційність та безпеку. Введіть своє ім\'я: - виклик у процесі - починаючи… - Перша платформа без жодних ідентифікаторів користувачів – приватна за дизайном. - Децентралізований - Використовуйте чат - Пізніше його можна змінити через налаштування. + дзвінок в процесі + запуск… + Перша платформа без ідентифікаторів користувачів – приватна за конструкцією. + Децентралізована + Використовувати чат + Це можна змінити пізніше в налаштуваннях. Миттєво - Дзвінок вже закінчився! - Ваші дзвінки + Виклик вже завершено! + Ваші виклики Ваші сервери ICE Відкрити через реле Динамік увімкнено - Перевернути камеру - Відхилений дзвінок - %1$d пропущено повідомлення(і) + Повернути камеру + Відхилений виклик + %1$d пропущено повідомлень ЧАТИ - SOCKS PROXY - Помилка запуску чату + SOCKS-ПРОКСІ + Помилка при запуску чату Зупинити - Імпорт + Імпортувати Файли та медіа Повідомлення - Налаштування зміни помилки + Помилка зміни налаштувань База даних зашифрована! - Новий пароль… - Підтвердіть нову парольну фразу… + Нова ключова фраза… + Підтвердіть нову ключову фразу… Зашифрувати базу даних\? - Неправильна парольна фраза! - Введіть правильну парольну фразу. + Неправильна ключова фраза! + Введіть правильну ключову фразу. Архів чату АРХІВ ЧАТУ - підключений - змінив свою роль на %s - ви змінили роль для себе на %s + підключив(лась) + змінив(ла) вашу роль на %s + ви змінили свою роль на %s ви змінили адресу - Не вибрано жодного контакту + Не вибрано контактів Видалити групу\? - Видалити + Вилучити Підключення - прямий - Оновлення + пряме + Оновити Контакт дозволяє Налаштування чату - Заборонити надсилання зникаючих повідомлень. - Заборонити надсилання голосових повідомлень. + Заборонити надсилання повідомлень, які зникають. + Забороняйте надсилання голосових повідомлень. Французький інтерфейс - Помилка збереження XFTP-серверів - Переконайтеся, що адреси XFTP-серверів мають правильний формат, розділені рядками і не дублюються. - Помилка завантаження XFTP-серверів - Помилка додавання користувача(ів) + Помилка збереження серверів XFTP + Переконайтеся, що адреси серверів XFTP вірного формату, розділені переносами рядків і не дублюються. + Помилка завантаження серверів XFTP + Помилка додавання учасників Помилка приєднання до групи - Не вдається отримати файл + Неможливо отримати файл Порівняти файл Видалити файл Періодичні сповіщення вимкнено! - Потрібна парольна фраза + Потрібен пароль Увімкнути - Автентифікація пристрою не ввімкнена. Ви можете увімкнути SimpleX Lock у Налаштуваннях, коли увімкнете автентифікацію пристрою. - Автентифікацію пристрою вимкнено. Вимкнення SimpleX Lock. + Аутентифікація пристрою не увімкнена. Ви можете увімкнути блокування SimpleX через налаштування, якщо увімкнете аутентифікацію пристрою. + Аутентифікація пристрою вимкнена. Вимикається блокування SimpleX. Зупинити чат - Відкрийте консоль чату + Відкрити консоль чату Повідомлення буде позначено як модероване для всіх учасників. Чати підключення… підключення… - Натисніть, щоб почати новий чат - Чат з розробниками + Торкніться, щоб розпочати новий чат + Чат із розробниками У вас немає чатів - Ви не можете надсилати повідомлення! - Будь ласка, зверніться до адміністратора групи. - Файл буде отримано, коли ваш контакт буде онлайн, будь ласка, зачекайте або перевірте пізніше! - Відео надіслано - В очікуванні відео + Ви не можете відправляти повідомлення! + Будь ласка, зв\'яжіться з адміністратором групи. + Файл буде отримано, коли ваш контакт буде в мережі, будь ласка, зачекайте або перевірте пізніше! + Відео відправлене + Очікування на відео Файл Підключено Відключено Живе повідомлення! - Будь ласка, попросіть вашого контакту увімкнути відправку голосових повідомлень. - Надіслати повідомлення в прямому ефірі - Надішліть повідомлення в реальному часі - воно буде оновлюватися для одержувача (одержувачів), поки ви його вводите + Будь ласка, попросіть вашого контакту увімкнути надсилання голосових повідомлень. + Надіслати живе повідомлення + Надішліть живе повідомлення - воно буде оновлюватися для одержувача(-ів), коли ви його набираєте Надіслати - Щоб почати новий чат + Щоб розпочати новий чат Натисніть кнопку - Якщо ви вирішите відхилити, відправник НЕ отримає сповіщення. + Якщо ви виберете відхилити, відправник НЕ буде повідомлений. Очистити чат - Невірне посилання! - Це посилання не є дійсним посиланням для підключення! - Запит на підключення відправлено! - Відкрити в мобільному додатку.]]> - Створіть одноразове посилання-запрошення + Неправильне посилання! + Це посилання не є дійсним з\'єднувальним посиланням! + Запит на з\'єднання відправлено! + Відкрити у мобільному додатку.]]> + Створити одноразове запрошення Сканувати код - Відскануйте код безпеки з додатку вашого контакту. - Неправильна адреса сервера! - Перевірте адресу сервера та спробуйте ще раз. + Скануйте код безпеки з додатка вашого контакту. + Невірна адреса сервера! + Перевірте адресу сервера і спробуйте ще раз. Сервери XFTP - Встановіть SimpleX Chat для терміналу - Зробити внесок - Оцініть програму + Встановити SimpleX Chat для терміналу + Внести вклад + Оцініть додаток Ваші сервери SMP Ваші сервери XFTP Використання серверів SimpleX Chat. - Як зробити - телефоную… - пропущений дзвінок + Як користуватися + дзвінок… + пропущений виклик відхилений виклик - Вхідний відеодзвінок + Вхідний відеовиклик Вхідний аудіовиклик - відеодзвінок (без шифрування e2e) - Дзвінки на екрані блокування: - одноранговий - Покласти слухавку - Створено на %1$s - Розширити вибір ролей - Так - Налаштування контактів + відеовиклик (не зашифрований e2e) + Виклики на екрані блокування: + від абонента до абонента + Завершити дзвінок + Створено %1$s + Розгорнути вибір ролі + так + Налаштування контакту Безпека SimpleX Chat була перевірена компанією Trail of Bits. Ваші контакти можуть дозволити повне видалення повідомлень. База даних буде зашифрована. - Помилка ланцюжка ключів + Помилка сховища ключів Невідома помилка - Відновлення помилки бази даних - ви залишили + Помилка відновлення бази даних + ви залишили групу підключення (прийнято) Запросити учасників Покинути групу - Зміна - Відправлення через + Змінити + Надсилання через Стан мережі Оновити налаштування мережі\? - Тільки локальні дані профілю + Локальні дані профілю тільки Ваш випадковий профіль - увімкнено - увімкнено для вас - Заборонити надсилати прямі повідомлення учасникам. + ввімкнено + ввімкнено для вас + Забороняйте надсилання прямих повідомлень учасникам. Видалити після Оцінка безпеки - Посилання на групи - Покращена конфіденційність та безпека + Посилання на групу + Покращена конфіденційність і безпека Живі повідомлення - Перевірте безпеку підключення - Порівняйте коди безпеки зі своїми контактами. - Кілька профілів чату - Основна версія: v%s + Перевірка безпеки підключення + Порівнюйте коди безпеки із своїми контактами. + Декілька профілів чату + Версія ядра: v%s Видалити адресу\? Ім\'я профілю: - чекаємо на підтвердження… - Переосмислення конфіденційності - Люди можуть підключатися до вас лише за посиланнями, якими ви ділитеся. + очікування підтвердження… + Приватність перевизначена + Люди можуть підключатися до вас лише за допомогою посилань, які ви надаєте. Як працює SimpleX - Детальніше читайте в нашому репозиторії GitHub. - e2e зашифрований аудіодзвінок - Відкрийте SimpleX Chat, щоб прийняти дзвінок - e2e зашифрований + Докладніше читайте в нашому репозиторії на GitHub. + зашифрований e2e аудіовиклик + Відкрийте SimpleX Chat для прийняття виклику + e2e зашифровано Динамік вимкнено - Дзвінок в очікуванні - Пропущений дзвінок - З\'єднувальний дзвінок + Очікування виклику + Пропущений виклик + Підключення виклику Конфіденційність і безпека Ваша конфіденційність НАЛАШТУВАННЯ ДОПОМОГА - ПІДТРИМКА SIMPLEX CHAT + ПІДТРИМАЙТЕ SIMPLEX CHAT Зупиніть чат, щоб експортувати, імпортувати або видалити базу даних чату. Ви не зможете отримувати та надсилати повідомлення, поки чат зупинено. Помилка видалення бази даних чату - Сповіщення будуть надходити лише до моменту зупинки програми! - Видалити + Сповіщення будуть доставлятися лише до зупинки додатка! + Вилучити Зашифрувати - Оновлення - Поточна парольна фраза… - База даних буде зашифрована, а пароль зберігатиметься у сховищі ключів. - Ключову фразу шифрування бази даних буде оновлено і збережено у сховищі ключів. - запрошені %1$s - запрошені за посиланням у вашій групі + Оновити + Поточна ключова фраза… + База даних буде зашифрована, і ключова фраза буде збережена в сховищі ключів. + Ключова фраза шифрування бази даних буде оновлена і збережена в сховищі ключів. + запросив(ла) %1$s + запросив(ла) через ваше посилання на групу ви змінили роль %s на %s ви змінили адресу для %s - зміна адреси для %s… - Не вдається запросити контакт! - %1$s УЧАСНИКИ + змінює адресу для %s… + Неможливо запросити контакт! + %1$s УЧАСНИКІВ Видалити групу Посилання на групу - Редагування профілю групи - Створити групове посилання + Редагувати профіль групи + Створити посилання на групу Змінити роль у групі\? - Помилка видалення учасника - Ваш профіль у чаті буде надіслано учасникам групи + Помилка при вилученні учасника + Ваш профіль чату буде відправлений учасникам групи Зберегти колір - Видалити для всіх + Видалення для всіх Голосові повідомлення - Голосові повідомлення в цьому чаті заборонені. - Максимум 40 секунд, отримується миттєво. - Встановіть його замість системної автентифікації. + Голосові повідомлення заборонені в цьому чаті. + Максимум 40 секунд, надходять миттєво. + Встановіть його замість системної аутентифікації. Вимкнути\? - Поділіться з контактами - Ваш профіль зберігається на вашому пристрої та доступний лише вашим контактам. Сервери SimpleX не бачать ваш профіль. - Збереження та сповіщення контактів - Збереження та сповіщення учасників групи - Вихід без збереження - Приховати профіль - Показати пароль + Поділитися з контактами + Ваш профіль зберігається на вашому пристрої і обмінюється лише з ваших контактів. Сервери SimpleX не можуть його бачити. + Зберегти і повідомити контакти + Зберегти і повідомити учасників групи + Вийти без збереження + Сховати профіль + Пароль для відображення Створити - немає шифрування e2e - контакт має шифрування e2e + без зашифрування e2e + контакт має зашифрування e2e Хеш попереднього повідомлення відрізняється. - Підтвердьте пароль + Підтвердити пароль Новий пароль - Перезавантажити + Перезапустити Ваша база даних чату Чат зупинено БАЗА ДАНИХ ЧАТУ Новий архів бази даних Зупинити чат\? - Вашу поточну базу даних чату буде ВИДАЛЕНО та ЗАМІНЕНО імпортованою. -\nЦю дію неможливо скасувати – ваш профіль, контакти, повідомлення та файли будуть безповоротно втрачені. + Ваша поточна база даних чату буде ВИДАЛЕНА та ЗАМІНЕНА імпортованою. +\nЦя дія незворотня - ваш профіль, контакти, повідомлення та файли буде втрачено безповоротно. ніколи %s секунд(и) - Пониження та відкритий чат + Знизити версію та відкрити чат Нова роль учасника Видалити посилання\? Видалити посилання - Перемикач - Помилка, що змінює роль + Перемкнути + Помилка при зміні ролі Введіть назву групи: Повна назва групи: - Помилка збереження профілю групи - Скидання до налаштувань за замовчуванням + Помилка при збереженні профілю групи + Скинути на замовчування сек Тайм-аут протоколу Зберегти - Оновлення налаштувань призведе до перепідключення клієнта до всіх серверів. - Вимкнути звук - Введіть пароль у пошуку - Ви і ваш контакт можете надсилати зникаючі повідомлення. - Тільки ви можете безповоротно видалити повідомлення (ваш контакт може позначити їх для видалення). + Оновлення налаштувань призведе до повторного підключення клієнта до всіх серверів. + Приглушити + Введіть пароль для пошуку + Як ви, так і ваш контакт можуть надсилати повідомлення, які зникають. + Тільки ви можете невідворотно видаляти повідомлення (ваш контакт може позначати їх для видалення). Тільки ваш контакт може додавати реакції на повідомлення. - Тільки ваш контакт може безповоротно видалити повідомлення (ви можете позначити їх для видалення). + Тільки ваш контакт може невідворотно видаляти повідомлення (ви можете позначати їх для видалення). Тільки ваш контакт може надсилати голосові повідомлення. - Заборонити надсилання зникаючих повідомлень. - Заборонити безповоротне видалення повідомлень. + Забороняйте надсилання повідомлень, які зникають. + Забороняйте невідворотне видалення повідомлень. Учасники групи можуть надсилати голосові повідомлення. - %dм + %dm Нове в %s - Пароль самознищення + Самознищуючий пароль Італійський інтерфейс - годин - днів - Виберіть - нестандартний - таємниця - Приєднуйтесь + години + дні + Вибрати + інше + прихований + Приєднатися Роль - непрямі (%1$s) - Увімкнути звук + непряме (%1$s) + Відглушити Повинен бути принаймні один профіль користувача. Зробіть профіль приватним! - запропонований %s + запропоновано %s Чернетка повідомлення - Зберегти чернетку останнього повідомлення з вкладеннями. - Повідомлення зникає - Надіслати зникаюче повідомлення + Зберігайте останню чернетку повідомлення із вкладеннями. + Зникне повідомлення + Надіслати зникне повідомлення зображення профілю Більше Створити профіль - GitHub.]]> - Відео включено - Це може статися, коли ви або ваше підключення використовували стару резервну копію бази даних. - Відновлення резервної копії бази даних + GitHub.]]> + Відео увімкнено + Це може трапитися, якщо ви або ваше з\'єднання використовували застарілу резервну копію бази даних. + Відновити резервну копію бази даних Зберегти архів запрошення до групи %1$s - Вас запрошено до групи. Приєднуйтесь, щоб спілкуватися з учасниками групи. + Вас запрошено в групу. Приєднуйтесь, щоб спілкуватися з учасниками групи. Реакції на повідомлення - Встановлюється 1 день - Заборонити реакцію на повідомлення. - Реакції на повідомлення в цьому чаті заборонені. + Встановити на 1 день + Забороняйте реакції на повідомлення. + Реакції на повідомлення заборонені в цьому чаті. %ds хвилини - Інтерфейс китайською та іспанською мовами + Китайський та іспанський інтерфейс підключення %1$d Помилка завантаження серверів SMP - Дублююче ім\'я користувача! - Помилка надсилання повідомлення + Дубль імені відображення! + Помилка відправлення повідомлення Відправник скасував передачу файлу. Помилка отримання файлу Помилка створення адреси - Неправильне посилання для підключення - Помилка при прийнятті запиту на контакт + Неправильне посилання на підключення + Помилка прийняття запиту на контакт Створити файл - Помилка видалення профілю користувача + Помилка видалення користувача Помилка оновлення конфіденційності користувача - SimpleX фонову службу – вона використовує кілька відсотків заряду акумулятора на день.]]> + фоновий сервіс SimpleX – він використовує кілька відсотків батареї щодня.]]> Періодичні сповіщення - Сервіс SimpleX Chat + Служба чату SimpleX Перевіряє нові повідомлення кожні 10 хвилин протягом 1 хвилини Приховано - Показати контакт та повідомлення - Приховати контакт і повідомлення - SimpleX Lock - Щоб захистити вашу інформацію, увімкніть SimpleX Lock. -\nПеред увімкненням цієї функції вам буде запропоновано пройти автентифікацію. - Увійдіть, використовуючи свій обліковий запис - Увімкнути SimpleX Lock - SimpleX Lock не ввімкнено! - Поділіться + Показати контакт і повідомлення + Сховати контакт і повідомлення + Блокування SimpleX + Щоб захистити вашу інформацію, увімкніть блокування SimpleX. +\nВам буде запропоновано завершити аутентифікацію перед увімкненням цієї функції. + Увійти за допомогою своїх облікових даних + Увімкнути блокування SimpleX + Блокування SimpleX не увімкнено! + Поділитися Копіювати Повідомлення буде видалено для всіх учасників. - Надсилання файлу буде зупинено. + Відправлення файлу буде зупинено. Зупинити отримання файлу\? Отримання файлу буде зупинено. Зупинити @@ -580,299 +580,299 @@ Файл буде видалено з серверів. Відкликати несанкціонована відправка - Ласкаво просимо %1$s! + Ласкаво просимо, %1$s! Ласкаво просимо! Цей текст доступний у налаштуваннях - вас запрошують до групи + вас запрошено в групу Поділитися повідомленням… - Поділитися медіафайлами… - Поділіться файлом… - Одночасно можна надіслати лише 10 зображень - Одночасно можна надіслати лише 10 відео - Помилка декодування - Зображення не може бути декодовано. Будь ласка, спробуйте інше зображення або зверніться до розробників. + Поділитися медіа… + Поділитися файлом… + Одночасно можна відправити лише 10 зображень + Одночасно можна відправити лише 10 відео + Помилка декодування зображення + Неможливо декодувати зображення. Спробуйте інше зображення або зв\'яжіться з розробниками. Зображення - Зображення буде отримано, коли ваш контакт завершить завантаження. - Зображення буде отримано, коли ваш контакт буде онлайн, будь ласка, зачекайте або перевірте пізніше! - Зображення збережено до Галереї + Зображення буде отримано, коли ваш контакт завершить його вивантаження. + Зображення буде отримано, коли ваш контакт буде в мережі, будь ласка, зачекайте або перевірте пізніше! + Зображення збережено в галереї Відео - Ваш контакт надіслав файл, розмір якого перевищує дозволений максимальний розмір (%1$s). - Наразі максимальний підтримуваний розмір файлу: %1$s . - Ця функція є експериментальною! Вона працюватиме, тільки якщо на іншому клієнті встановлено версію 4.2. Після завершення зміни адреси ви побачите повідомлення в бесіді - будь ласка, перевірте, чи можете ви отримувати повідомлення від цього контакту (або члена групи). - Підтвердіть код безпеки - Відправити повідомлення + Ваш контакт відправив файл, розмір якого більший, ніж поточно підтримуваний максимальний розмір (%1$s). + Поточно максимально підтримуваний розмір файлу - %1$s. + Адреса для отримання буде змінена на інший сервер. Зміна адреси завершиться після включення відправника. + Перевірити код безпеки + Надіслати повідомлення Записати голосове повідомлення - (зберігається тільки учасниками групи) - У дозволі відмовлено! + (зберігається лише на пристроях учасників групи) + Доступ відхилено! Камера - Дякуємо, що встановили SimpleX Chat! - Відскануйте QR-код: щоб з\'єднатися з вашим контактом, який покаже вам QR-код.]]> - Якщо ви отримали посилання на запрошення SimpleX Chat, ви можете відкрити його у своєму браузері: - Чисто + Дякуємо за установку SimpleX Chat! + Сканувати QR-код: щоб підключитися до вашого контакту, який вам показує QR-код.]]> + Якщо ви отримали запрошення від SimpleX Chat, ви можете відкрити його у вашому браузері: + Очистити Видалити Видалити - Позначити прочитано - Позначити як непрочитане + Позначити прочитаним + Позначити непрочитаним Встановити ім\'я контакту - Ви прийняли підключення - Видалити очікуване з\'єднання\? - Ваш контакт має бути онлайн, щоб з’єднання завершилося. -\nВи можете скасувати це з’єднання та видалити контакт (і спробувати пізніше з новим посиланням). - SimpleX Логотип + Ви прийняли з\'єднання + Видалити очікуюче з\'єднання? + Ваш контакт повинен бути в мережі, щоб завершити з\'єднання. +\nВи можете скасувати це з\'єднання і видалити контакт (і спробувати пізніше за допомогою нового посилання). + Логотип SimpleX Електронна пошта Цей QR-код не є посиланням! - Вас буде підключено до групи, коли пристрій хоста групи буде онлайн, зачекайте або перевірте пізніше! - Ви будете підключені, коли ваш запит на підключення буде прийнято, будь ласка, зачекайте або перевірте пізніше! - Поділіться одноразовим посиланням - Детальніше - Щоб підключитися, ваш контакт може відсканувати QR-код або скористатися посиланням у додатку. - Якщо ви не можете зустрітися особисто, покажіть QR-код у відеодзвінку або поділіться посиланням. - Ви можете поділитися своєю адресою у вигляді посилання або QR-коду - будь-хто зможе зв\'язатися з вами. + Ви будете підключені до групи, коли пристрій господаря групи буде в мережі, зачекайте або перевірте пізніше! + Вас підключать, коли ваш запит на з\'єднання буде прийнятий, зачекайте або перевірте пізніше! + Поділитися 1-разовим посиланням + Дізнатися більше + Щоб підключитися, ваш контакт може сканувати QR-код або використовувати посилання у додатку. + Якщо ви не можете зустрітися особисто, покажіть QR-код у відеовиклику або поділіться посиланням. + Ви можете поділитися своєю адресою в якості посилання або QR-коду - кожен може підключитися до вас. Вставити - Цей рядок не є посиланням для з\'єднання! + Цей рядок не є з\'єднувальним посиланням! Код безпеки - Позначку перевірено + Позначити, що перевірено Ваші профілі чату - Ключова фраза бази даних та експорт - Націнка в повідомленнях - Надсилайте запитання та ідеї - Увійдіть на сервер вручну + Пароль бази даних та експорт + Markdown у повідомленнях + Надсилайте питання та ідеї + Ввести адресу сервера вручну Попередньо встановлений сервер - Ваша адреса сервера + Адреса вашого сервера Сервери для нових підключень вашого поточного профілю чату - Використовуєте сервери SimpleX Chat\? - Сервери ICE (по одному на лінію) + Використовувати сервери SimpleX Chat? + Сервери ICE (один на рядок) Помилка збереження серверів ICE - Onion hosts will be required for connection. -\nPlease note: you will not be able to connect to the servers without .onion address. - Onion хости будуть використовуватися за наявності. - Для з\'єднання будуть потрібні хости onion. - Показати опції розробника + .Onion-хости будуть обов\'язковими для підключення. +\nЗверніть увагу: ви не зможете підключитися до серверів без адреси .onion. + Хости .onion будуть використовуватися, якщо доступні. + Хости .onion будуть обов\'язковими для підключення. + Показати параметри розробника Ідентифікатори бази даних та опція ізоляції транспорту. Сповіщення перестануть працювати, поки ви не перезапустите додаток Ви можете створити його пізніше Ваш поточний профіль Видалити зображення Зберегти налаштування\? - Зберегти та повідомити контакт + Зберегти і повідомити контакт Зберегти пароль профілю - Прихований пароль профілю - Профіль доступний лише вашим контактам. - Ім\'я не може містити пробілів. - Як використовувати націнку - Ви можете використовувати розмітку для форматування повідомлень: + Пароль схованого профілю + Профіль обмінюється лише з вашими контактами. + Ім\'я для відображення не може містити пробіли. + Як використовувати markdown + Ви можете використовувати markdown для форматування повідомлень: Створіть свій профіль - Створіть приватне з\'єднання - якщо SimpleX не має ідентифікаторів користувачів, як він може доставляти повідомлення\?]]> - отримувати повідомлення, ваші контакти - сервери, які ви використовуєте для надсилання їм повідомлень.]]> - дворівневого наскрізного шифрування.]]> + Створіть приватне підключення + як в SimpleX можливо доставляти повідомлення, якщо він не має ідентифікаторів користувачів?]]> + отримувати повідомлення, ваші контакти – сервери, які ви використовуєте для надсилання повідомлень їм.]]> + шифрування на двох рівнях.]]> Приватні сповіщення - Використовує більше заряду акумулятора! Завжди працює фоновий сервіс - сповіщення показуються, як тільки з\'являються повідомлення.]]> + Споживає більше заряду акумулятора! Фоновий сервіс завжди працює – сповіщення відображаються, як тільки повідомлення доступні.]]> Вставте отримане посилання Відео вимкнено - Дзвінок завершено - Ідентифікатор наступного повідомлення неправильний (менше або дорівнює попередньому). -\nЦе може статися через помилку або коли з\'єднання скомпрометовано. - Пароль самознищення ввімкнено! + Завершено виклик + Ідентифікатор наступного повідомлення є неправильним (менший або рівний попередньому). +\nЦе може трапитися через якусь помилку або коли з\'єднання скомпрометоване. + Пароль самознищення увімкнено! Пароль самознищення змінено! Ваш профіль, контакти та доставлені повідомлення зберігаються на вашому пристрої. ВИ ПРИСТРІЙ - Вимкнення + Вимкнути ТЕМИ ПОВІДОМЛЕННЯ ТА ФАЙЛИ - Чат запущено - Імпорт бази даних + Чат працює + Імпортувати базу даних Старий архів бази даних Видалити базу даних - Встановіть парольну фразу для експорту - База даних зашифрована за допомогою випадкової парольної фрази. Будь ласка, змініть його перед експортом. + Встановити пароль для експорту + База даних зашифрована випадковим паролем. Змініть його перед експортом. Помилка експорту бази даних чату Імпортувати базу даних чату\? Помилка імпорту бази даних чату Видалити профіль чату\? - Цю дію неможливо скасувати - всі отримані та надіслані файли і медіа будуть видалені. Зображення з низькою роздільною здатністю залишаться. - Видалення повідомлень - Оновити парольну фразу бази даних - База даних зашифрована за допомогою випадкової парольної фрази, яку ви можете змінити. - Парольну фразу шифрування бази даних буде оновлено. - Будь ласка, зберігайте пароль надійно, ви НЕ зможете змінити його, якщо втратите. - Неправильна парольна фраза бази даних - Пароль до бази даних відрізняється від збереженого у сховищі ключів. - Спроба змінити пароль бази даних не була завершена. + Цю дію неможливо відмінити - всі отримані та надіслані файли та медіа будуть видалені. Зображення низької роздільної здатності залишаться. + Видалити повідомлення + Оновити ключову фразу бази даних + База даних зашифрована випадковою ключовою фразою, яку можна змінити. + Ключова фраза шифрування бази даних буде оновлена. + Будь ласка, зберігайте ключову фразу надійно, ви НЕ зможете її змінити, якщо втратите її. + Неправильна ключова фраза бази даних + Ключова фраза бази даних відрізняється від збереженої в сховищі ключів. + Спроба змінити ключову фразу бази даних не була завершена. Відновити резервну копію бази даних\? - Будь ласка, введіть попередній пароль після відновлення резервної копії бази даних. Ця дія не може бути скасована. - Приєднуйтесь інкогніто - ліворуч - змінили роль %s на %s - видалена група + Будь ласка, введіть попередній пароль після відновлення резервної копії бази даних. Цю дію неможливо скасувати. + Приєднатися анонімно + вийшов(ла) + змінив(ла) роль %s на %s + групу видалено оновлено профіль групи - змінили для вас адресу + змінив(ла) адресу для вас змінює адресу… учасник - ліворуч + залишено групу видалено - запрошені + запрошено підключення (введено) Запросити до групи Пропустити запрошення учасників - %d вибрано контакт(и) + %d вибрано контактів ви: %1$s - Група буде видалена для всіх учасників - це неможливо скасувати! - Група буде видалена для вас - це не може бути скасовано! + Група буде видалена для всіх учасників - цю дію неможливо скасувати! + Група буде видалена для вас - цю дію неможливо скасувати! Створити посилання - Помилка оновлення посилання на групу - Помилка видалення посилання на групу - Тільки власники груп можуть змінювати налаштування групи. - Запис оновлено за - Надіслано на - Модерується на - Зникає за + Помилка при оновленні посилання на групу + Помилка при видаленні посилання на групу + Змінювати налаштування групи можуть лише її власники. + Запис оновлено + Надіслано + Модеровано о + Зникає о Ідентифікатор бази даних: %d - Запис оновлено за: %s - Модерується на: %s - Зникає в: %s - (поточний) - Видалити учасника - Роль буде змінено на \"%s\". Всі учасники групи будуть повідомлені про це. + Запис оновлено о: %s + Модеровано о: %s + Зникає о: %s + (поточне) + Вилучити учасника + Роль буде змінено на \"%s\". Всі учасники групи будуть сповіщені. Роль буде змінено на \"%s\". Учасник отримає нове запрошення. Група - Вітальне повідомлення + Ласкаво просимо Профіль групи зберігається на пристроях учасників, а не на серверах. Зберегти профіль групи - Підключення профілю та сервера + Профіль і підключення до серверів Показати - Ви можете приховати або вимкнути звук профілю користувача - утримуйте його для виклику меню. + Ви можете приховати або вимкнути звук профілю користувача - утримуйте його для меню. Показати профіль Показати профіль чату - Коли ви ділитеся з кимось своїм профілем інкогніто, цей профіль буде використовуватися для груп, до яких вони вас запрошують. - Світлий + Коли ви ділитесь анонімним профілем з кимось, цей профіль буде використовуватися для груп, до яких вас запрошують. + Світла Помилка імпорту теми Налаштування групи - Зникнення повідомлень - увімкнено для контакту + Повідомлення зникнення + ввімкнено для контакту вимкнено отримано, заборонено - Контакти можуть позначати повідомлення для видалення; ви зможете їх переглянути. - Заборонити аудіо/відеодзвінки. - Тільки ви можете надсилати зникаючі повідомлення. - Зникаючі повідомлення в цьому чаті заборонені. - У цьому чаті заборонено безповоротне видалення повідомлень. - Надсилати голосові повідомлення можете як ви, так і ваш контакт. + Контакти можуть позначати повідомлення для видалення; ви зможете їх переглядати. + Забороняйте аудіо/відео дзвінки. + Тільки ви можете надсилати повідомлення, які зникають. + Зникнення повідомлень заборонене в цьому чаті. + Невідворотне видалення повідомлень заборонено в цьому чаті. + Як ви, так і ваш контакт можуть надсилати голосові повідомлення. Тільки ви можете надсилати голосові повідомлення. Тільки ви можете додавати реакції на повідомлення. Заборонити реакції на повідомлення. - У цій групі заборонено зникаючі повідомлення. - Учасники групи можуть надсилати прямі повідомлення. - У цій групі заборонені прямі повідомлення між учасниками. - Учасники групи можуть безповоротно видаляти надіслані повідомлення. - У цій групі заборонено безповоротне видалення повідомлень. - Голосові повідомлення в цій групі заборонені. + Самознищувальні повідомлення заборонені в цій групі. + Учасники групи можуть надсилати приватні повідомлення. + Приватні повідомлення між учасниками заборонені в цій групі. + Учасники групи можуть назавжди видаляти відправлені повідомлення. + Назавжди видалення повідомлень заборонене в цій групі. + Голосові повідомлення заборонені в цій групі. Учасники групи можуть додавати реакції на повідомлення. - Реакції на повідомлення в цій групі заборонені. + Реакції на повідомлення заборонені в цій групі. %d година %d тиждень - %d тижнів + %d тижні %dw - запропонував %s: %2s - З необов’язковим вітальним повідомленням. - Приховати екран програми в останніх програмах. - Зникнення повідомлень + запропоновано %s: %2s + З опційним вітанням. + Приховуйте екран додатка в останніх програмах. + Самознищувальні повідомлення Одержувачі бачать оновлення, коли ви їх вводите. - Транспортна ізоляція - Для захисту часового поясу у файлах зображень/голосу використовується UTC. - Дякуємо користувачам - зробіть свій внесок через Weblate! + Ізоляція транспорту + Для захисту часового поясу файли зображень/голосу використовують UTC. + Дякуємо користувачам – приєднуйтеся через Weblate! Тепер адміністратори можуть: -\n- видалити повідомлення учасників. -\n- відключити учасників (роль \"спостерігач\") - Налаштуйте повідомлення, яке показуватиметься новим користувачам! - Подальше зменшення використання акумулятора - Незабаром буде ще більше покращень! - Відео та файли до 1 Гб +\n- видаляти повідомлення учасників. +\n- вимикати учасників (роль спостерігач) + Встановіть повідомлення, яке показується новим учасникам! + Додатково зменшено використання батареї + Більше поліпшень незабаром! + Відео та файли до 1 ГБ Польський інтерфейс - Дякуємо користувачам - зробіть свій внесок через Weblate! + Дякуємо користувачам – приєднуйтеся через Weblate! Реакції на повідомлення - Нарешті, вони у нас є! 🚀 + Нарешті, ми їх маємо! 🚀 Налаштовуйте та діліться кольоровими темами. - Дякуємо користувачам - зробіть свій внесок через Weblate! - секунд - тижнів + Дякуємо користувачам – приєднуйтеся через Weblate! + секунди + тижні місяці - Ви вже підключені до %1$s. + Ви вже підключені до %1$s через це посилання. Режим інкогніто СЕРВЕРИ - Зберегти привітальне повідомлення\? + Зберегти ласкаво просимо? Отримання через - Вимкнено, коли неактивний! + Приглушено, коли неактивно! Видалити профіль Інкогніто - Це дозволяє мати багато анонімних з\'єднань без будь-яких спільних даних між ними в одному профілі чату. + Це дозволяє мати багато анонімних з\'єднань без будь-яких загальних даних між ними в одному чат-профілі. SimpleX - Тільки ваш контакт може надсилати зникаючі повідомлення. - увімкнути - %d годин - Помилка видалення очікуваного з\'єднання контакту + Тільки ваш контакт може надсилати повідомлення, які зникають. + увімк + %d години + Помилка видалення очікуючого з\'єднання з контактом Помилка завантаження деталей - Якщо ваш контакт не видалив з\'єднання або якщо це посилання вже використовувалося, це може бути помилкою - будь ласка, повідомте про це. -\nЩоб підключитися, попросіть вашого контакта створити інше посилання і перевірте, чи маєте ви стабільне з\'єднання з мережею. + Якщо ваш контакт не видалив з\'єднання або це посилання вже використано, це може бути помилкою - будь ласка, повідомте про це. +\nДля підключення попросіть вашого контакту створити інше посилання на з\'єднання та перевірте стабільність мережевого підключення. Помилка видалення контакту Помилка видалення групи - Від\'єднати + Відключити Безпечна черга Видалити чергу - Будь ласка, переконайтеся, що ви використали правильне посилання, або попросіть свого контакта надіслати вам інше. - дозвольте SimpleX працювати у фоновому режимі у наступному діалоговому вікні. \u0020В іншому випадку сповіщення буде вимкнено.]]> + Будь ласка, перевірте, що ви використали правильне посилання або попросіть вашого контакту вислати інше. + дозвольте SimpleX працювати в фоновому режимі в наступному діалозі. В іншому випадку сповіщення будуть вимкнені.]]> Миттєві сповіщення - Контакт приховано: + Контакт прихований: нове повідомлення Редагувати Інформація - Надіслано повідомлення - Вам потрібно буде пройти автентифікацію при запуску або відновленні програми після 30 секунд роботи у фоновому режимі. - Отримано повідомлення + Відправлене повідомлення + Вам буде потрібно пройти аутентифікацію при запуску або відновленні програми через 30 секунд у фоновому режимі. + Отримане повідомлення Історія Розкрити Приховати - Редагування + Модерувати Видалити повідомлення\? - Повідомлення буде видалено - це неможливо скасувати! - надісланий - Голосові повідомлення заборонені! + Повідомлення буде видалено - цю дію неможливо скасувати! + відправлено + Заборонено голосові повідомлення! Надіслати Підтвердити - Індивідуальний час - Створіть одноразове посилання-запрошення - Відскануйте QR-код + Інший час + Створити одноразове запрошення + Сканувати QR-код Зображення Відео - Прийняте вами з\'єднання буде скасовано! - Контакт ще не підключено! + Прийняте вами з\'єднання буде скасоване! + Контакт ще не підключений! Тестові сервери Зберегти сервери Ваш сервер - Тест сервера завершився невдало! + Тест сервера не вдався! Деякі сервери не пройшли тест: Використовувати сервер - Переконайтеся, що адреси серверів WebRTC ICE мають правильний формат, розділені рядками та не дублюються. - Якщо ви підтвердите, сервери обміну повідомленнями зможуть бачити вашу IP-адресу, а ваш провайдер - до яких серверів ви підключаєтеся. - Onion хости не використовуватимуться. - Транспортна ізоляція - Налаштувати тему - Поділіться адресою з контактами\? - З\'єднувальний дзвінок… - Ми не зберігаємо жодних ваших контактів чи повідомлень (після доставки) на серверах. - в очікуванні відповіді… + Переконайтеся, що адреси серверів WebRTC ICE вказані в правильному форматі, розділені по рядках і не повторюються. + Якщо ви підтвердите, сервери обміну повідомленнями матимуть можливість бачити ваш IP-адресу, а ваш постачальник - які саме сервери ви використовуєте для підключення. + .Onion-хости не будуть використовуватися. + Ізоляція транспорту + Налаштування теми + Поділитися адресою з контактами? + підключення дзвінка… + Ми не зберігаємо жодні з ваших контактів чи повідомлень (після доставки) на серверах. + очікування відповіді… Як це працює - відеодзвінок + відеовиклик Показати Вимкнути - Сервер ретрансляції використовується лише за необхідності. Інша сторона може спостерігати за вашою IP-адресою. - %1$d повідомлення не вдалося розшифрувати. - %1$d повідомлення пропущені. - Будь ласка, повідомте про це розробникам. - Надіслати попередній перегляд за посиланням - Блокування після - Представити + Реле-сервер використовується лише у необхідних випадках. Інша сторона може спостерігати за вашою IP-адресою. + %1$d повідомлень не вдалося розшифрувати. + %1$d пропущено повідомлень. + Будь ласка, повідомте розробникам про це. + Надсилати попередні перегляди посилань + Блокувати через + Підтвердити Увімкнути пароль самознищення Змінити режим самознищення Неправильний пароль @@ -880,581 +880,643 @@ Змінити пароль самознищення Пароль самознищення Увімкнути самознищення - Нове ім\'я для відображення: - Якщо ви введете пароль самознищення під час відкриття програми: - Якщо ви введете цей пароль при відкритті програми, всі дані програми будуть безповоротно видалені! + Нове ім\'я профілю: + Якщо ви введете пароль самознищення при відкритті застосунку: + Якщо ви введете цей пароль при відкритті застосунку, всі дані застосунку буде неможливо відновити! Встановити пароль - Цю дію неможливо скасувати - ваш профіль, контакти, повідомлення та файли будуть безповоротно втрачені. - Видалено базу даних чату - Немає отриманих або відправлених файлів + Цю дію неможливо відмінити - ваш профіль, контакти, повідомлення та файли буде втрачено безповоротно. + Базу даних чату видалено + Немає отриманих або відісланих файлів Отримано о - Видалено за - Отримано за: %s - Надіслано: %s - Видалено за: %s - %s (поточний) + Видалено о + Отримано о: %s + Надіслано о: %s + Видалено о: %s + %s (поточне) %dh %d день %d днів скасовано %s - ЗАПУСТИТИ ЧАТ - Ключова фраза бази даних - Експорт бази даних + ЗАПУСК ЧАТУ + Пароль бази даних + Експортувати базу даних Видалити всі файли Видаляйте повідомлення після Увімкнути автоматичне видалення повідомлень\? Повинен бути принаймні один видимий профіль користувача. Приховані профілі чату - Привітальне повідомлення групи - Дякуємо користувачам - зробіть свій внесок через Weblate! - Режим SimpleX Lock - Аутентифікація системи - Для захисту конфіденційності, замість ідентифікаторів користувачів, які використовуються на всіх інших платформах, SimpleX має ідентифікатори для черг повідомлень, окремі для кожного з ваших контактів. - Коли додаток працює - Періодичні - контакт не має шифрування e2e + Повідомлення вітання групи + Дякуємо користувачам – приєднуйтеся через Weblate! + Режим блокування SimpleX + Системна аутентифікація + Для захисту приватності, замість ідентифікаторів користувачів, які використовуються всіма іншими платформами, у SimpleX є ідентифікатори черг повідомлень, окремі для кожного з ваших контактів. + Коли додаток запущено + Періодично + контакт не має зашифрування e2e Увімкнути блокування Пароль не змінено! - Зміна режиму блокування + Змінити режим блокування Зупиніть чат, щоб увімкнути дії з базою даних. Перезапустіть додаток, щоб створити новий профіль чату. - Видалення файлів для всіх профілів чату - Видаляти файли та медіа\? - %d файл(и) загальним розміром %s - Ваша база даних чату не зашифрована - встановіть парольну фразу, щоб захистити її. - Зверніть увагу: ви НЕ зможете відновити або змінити парольну фразу, якщо її втратите.]]> + Видалити файли для всіх профілів чату + Видалити файли та медіа? + %d файл(ів) обсягом %s + Ваша база даних чату не зашифрована - встановіть ключову фразу для її захисту. + Зверніть увагу: ви НЕ зможете відновити або змінити ключову фразу, якщо ви її втратите.]]> Система Несумісна версія бази даних Підтвердити оновлення бази даних - Недійсне підтвердження перенесення - версія бази даних новіша, ніж додаток, але без міграції вниз: %s - інша міграція в додатку/базі даних: %s / %s + Недійсне підтвердження міграції + Версія бази даних новіша, ніж додаток, але немає можливості знизити до: %s + Різна міграція в додатку/базі даних: %s / %s Міграції: %s - Термін дії запрошення закінчився! - Ви більше не будете отримувати повідомлення від цієї групи. Історія чату буде збережена. + Запрошення закінчилось! + Ви перестанете отримувати повідомлення від цієї групи. Історія чату буде збережена. Запросити учасників Група неактивна ви видалили %1$s - Натисніть, щоб активувати профіль. - Не можу видалити профіль користувача! - Заборонити надсилання голосових повідомлень. - Учасники групи можуть надсилати зникаючі повідомлення. + Торкніться для активації профілю. + Не вдається видалити профіль користувача! + Забороняйте надсилання голосових повідомлень. + Учасники групи можуть надсилати самознищувальні повідомлення. %d хв - Зменшення використання акумулятора + Зменшене споживання енергії батареї Редагувати зображення - дублююче повідомлення - Невідома помилка в базі даних: %s - Введіть пароль… + дубльоване повідомлення + Невідома помилка бази даних: %s + Введіть ключову фразу… Відкрити чат - Ви приєдналися до цієї групи. Підключення до запрошеного учасника групи. - оновлений профіль групи + Ви приєдналися до цієї групи. З\'єднання з учасником, який вас запрошував. + оновлено профіль групи змінює адресу… Залишити спостерігач УЧАСНИК Режим інкогніто захищає вашу конфіденційність, використовуючи новий випадковий профіль для кожного контакту. - Незабаром буде ще більше покращень! - Тільки власники груп можуть вмикати голосові повідомлення. + Більше поліпшень незабаром! + Тільки власники груп можуть увімкнути голосові повідомлення. Відхилити Очистити чат\? - посилання для попереднього перегляду зображення + зображення попереднього перегляду посилання скасувати попередній перегляд посилання Налаштування - Onion хости не використовуватимуться. + Хости .onion не будуть використовуватися. Виклик у процесі - Помилка в базі даних + Помилка бази даних Відновити - підключений + підключено творець підключення (оголошено) %d місяць - Різні імена, аватарки та транспортна ізоляція. + Різні імена, аватари та ізоляція транспорту. Приватні імена файлів Покращена конфігурація сервера Помилка збереження пароля користувача - Ви використовуєте профіль анонімного перегляду для цієї групи – щоб запобігти спільному доступу до вашого основного профілю, запрошення контактів заборонено + Ви використовуєте анонімний профіль для цієї групи - для запобігання розголошенню вашого основного профілю запрошення контактів не дозволено. Ви приєдналися до цієї групи - Вас не вдалося перевірити; будь ласка спробуйте ще раз. - Немає пароля додатку - Введіть пароль - Поточний пароль - Введення пароля - Змінити пароль + Вашу особу не вдалося підтвердити; спробуйте ще раз. + Немає коду доступу до додатка + Введіть код доступу + Поточний код доступу + Введення коду доступу + Змінити код доступу Негайно - %d секунд - %d хвилин + %d секунд(и) + %d хвилин(и) Помилка доставки повідомлення Профіль чату Відхилити - Сервер ретрансляції захищає вашу IP-адресу, але він може спостерігати за тривалістю дзвінка. + Реле-сервер захищає ваш IP-адресу, але може відслідковувати тривалість виклику. Режим блокування Пароль змінено! Система Пароль Пароль встановлено! - Оновіть і відкрийте чат - Попередження: ви можете втратити деякі дані! - Ви можете розпочати чат через Налаштування програми / База даних або перезапустивши програму. - Ви надіслали запрошення до групи - Вас запросили до групи - Термін дії групового запрошення закінчився - Контакт перевірено - Ви намагаєтеся запросити контакт, з яким ви поділилися анонімним профілем, до групи, у якій ви використовуєте свій основний профіль - Помилка створення посилання на групу + Оновити та відкрити чат + Попередження: можливо, ви втратите деякі дані! + Ви можете запустити чат через налаштування програми або перезапустивши додаток. + Ви відправили запрошення в групу + Вас запрошено в групу + Запрошення в групу закінчилось + Контакт відмічено + Ви намагаєтеся запросити контакт, з яким ви поділилися інкогніто-профілем, до групи, в якій ви використовуєте основний профіль + Помилка при створенні посилання на групу ДЛЯ КОНСОЛІ - Учасник буде видалений з групи - це неможливо скасувати! + Учасника буде вилучено з групи - цю дію неможливо скасувати! Змінити роль - Повернути - Ви все одно отримуватимете дзвінки та сповіщення від вимкнених профілів, якщо вони активні. - %d місяців - %d міс - Надіслані повідомлення будуть видалені через встановлений час. + Відновити + Ви все ще отримуватимете дзвінки та сповіщення від приглушених профілів, коли вони активні. + %d місяці + %dmth + Надіслані повідомлення будуть видалені після встановленого часу. Відкриття бази даних… - Помилка налаштування адреси - Підключіться - Будь ласка, запам\'ятайте або надійно збережіть його - втрачений пароль неможливо відновити! + Помилка встановлення адреси + Підключити + Будь ласка, запам\'ятайте або збережіть його надійно - немає можливості відновлення втраченого пароля! Відкрити профілі чату - В очікуванні відео - Очікування файлу + Очікування на відео + Очікування на файл Голосове повідомлення (%1$s) Сповіщення Видалити контакт\? - Скасувати повідомлення в прямому ефірі + Скасувати живе повідомлення Скинути - без подробиць + без деталей Підключитися за посиланням / QR-кодом - Чисто + Очистити Неправильний QR-код - Ви будете з\'єднані, коли пристрій вашого контакту буде в мережі, будь ласка, зачекайте або перевірте пізніше! - Ви не втратите свої контакти, якщо згодом видалите свою адресу. - Коли люди звертаються із запитом на підключення, ви можете прийняти або відхилити його. - Посібнику користувача.]]> - Адреса SimpleX - Очистити верифікацію + Вас підключать, коли пристрій вашого контакту буде в мережі, зачекайте або перевірте пізніше! + Ви не втратите свої контакти, якщо ви пізніше видалите свою адресу. + Коли люди просять про з\'єднання, ви можете його прийняти чи відхилити. + Посібнику користувача.]]> + SimpleX-адреса + Очистити перевірку %s перевірено %s не перевірено - Надішліть нам електронний лист + Надішліть нам електронного листа Тестовий сервер Зберегти сервери\? Ваші сервери ICE Зберегти - Налаштування проксі SOCKS - Використовуйте проксі SOCKS + Налаштування SOCKS-проксі + Використовувати SOCKS-проксі порт %d Хост Порт - Потрібно - КОЛЬОРИ ТЕМИ - Створіть адресу, щоб люди могли з вами зв\'язатися. - Ваші контакти залишаться на зв’язку. - Створіть адресу SimpleX - Оновлення профілю буде надіслано вашим контактам. - Припинити ділитися адресою\? - Припиніть ділитися - Введіть вітальне повідомлення... (необов\'язково) + Обов\'язково + КОЛОРИ ТЕМИ + Створіть адресу, щоб дозволити людям підключатися до вас. + Ваші контакти залишаться підключеними. + Створити SimpleX-адресу + Оновлення профілю буде відправлено вашим контактам. + Зупинити поділ адреси? + Зупинити поділ + Введіть текст привітання... (необов\'язково) Зберегти налаштування\? - Зберегти налаштування автоприйняття + Зберегти налаштування автоприйому Привіт! -\nЗв\'яжіться зі мною через SimpleX Chat: %s +\nПриєднуйтесь до мене через SimpleX Chat: %s Запросити друзів - Давайте поговоримо в SimpleX Chat + Давайте говорити в SimpleX Chat Продовжити Не створювати адресу - отримав відповідь… - отримав підтвердження… + отримано відповідь… + отримано підтвердження… підключення… - підключений - закінчився - Імунітет до спаму та зловживань - %1$s хоче зв\'язатися з вами через - e2e зашифрований відеодзвінок + підключено + завершено + Стійка до спаму та зловживань + %1$s хоче підключитися до вас через + зашифрований e2e відеовиклик Ігнорувати - Це може статися, коли: -\n1. Термін дії повідомлень закінчився в клієнті-відправнику через 2 дні або на сервері через 30 днів. -\n2. Не вдалося розшифрувати повідомлення, тому що ви або ваш контакт використовували стару резервну копію бази даних. -\n3. З\'єднання було скомпрометовано. + Це може трапитися, коли: +\n1. Повідомлення застаріли відправником через 2 дні або на сервері через 30 днів. +\n2. Помилка розшифровки повідомлення, оскільки ви або ваш контакт використовували застарілу резервну копію бази даних. +\n3. З\'єднання було компрометоване. Пропущені повідомлення - Захистіть екран програми - Помилка зупинки чату - Імпорт бази даних чату - Перезапустіть програму, щоб використовувати імпортовану базу даних чату. + Захист екрану застосунку + Помилка при зупинці чату + База даних чату імпортована + Перезапустіть додаток, щоб використовувати імпортовану базу даних чату. Файл: %s - Для відкриття чату потрібно ввести пароль до бази даних. + Для відкриття чату потрібна ключова фраза бази даних. Приєднатися до групи\? Оновлення бази даних Видалити архів Видалити архів чату\? - Покинути групу\? + Вийти з групи? Групу не знайдено! - Цієї групи більше не існує. - Неможливо запросити контакти! + Ця група більше не існує. + Неможливо запрошувати контакти! завершено - Вітальне повідомлення - Виберіть контакти + Привітання + Вибрати контакти Поділитися адресою - Ви можете поділитися посиланням або QR-кодом - будь-хто зможе приєднатися до групи. Ви не втратите учасників групи, якщо пізніше видалите її. - Ви можете поділитися цією адресою зі своїми контактами, щоб вони могли зв\'язатися з %s. - Місцева назва + Ви можете поділитися посиланням або QR-кодом - будь-хто зможе приєднатися до групи. Ви не втратите членів групи, якщо потім видалите її. + Ви можете поділитися цією адресою зі своїми контактами, щоб вони могли підключитися до %s. + Локальна назва Ідентифікатор бази даних Попередній перегляд - Введіть вітальне повідомлення… + Введіть ласкаво просимо… Змінити адресу отримання Створити секретну групу - Повністю децентралізована - видима лише для учасників. - Тайм-аут підключення TCP - Більше не показувати - Вторинний - Меню та сповіщення - Назва - Надіслано повідомлення - Отримано повідомлення + Повністю децентралізовано - видимо тільки для учасників. + Тайм-аут з\'єднання TCP + Не показувати знову + Другорядний + Меню та повідомлення + Заголовок + Надіслане повідомлення + Отримане повідомлення Ви дозволяєте ні - вимкнено - Встановіть налаштування групи - Ваші уподобання + вимк + Встановити налаштування групи + Ваші налаштування Прямі повідомлення Помилка - Посилання на одноразове запрошення - Почніть новий чат + Одноразове запрошення + Створити новий чат Кнопка закриття Попередньо встановлена адреса сервера Чат зупинено - Збереження та оновлення профілю групи + Зберегти та оновити профіль групи Тема - Підтримка Bluetooth та інші покращення. - Модерація груп + Підтримка Bluetooth та інші поліпшення. + Модерація групи Пароль профілю - Відео буде отримано, коли ваш контакт завершить завантаження. - Відео буде отримано, коли ваш контакт буде онлайн, будь ласка, зачекайте або перевірте пізніше! - Файл буде отримано, коли ваш контакт завершить завантаження. + Відео буде отримано, коли ваш контакт завершить його вивантаження. + Відео буде отримано, коли ваш контакт буде в мережі, будь ласка, зачекайте або перевірте пізніше! + Файл буде отримано, коли ваш контакт завершить його вивантаження. Помилка збереження файлу Видалити контакт Встановити ім\'я контакту… Файл З галереї - SimpleX Команда - хоче зв\'язатися з вами! - ЕКСПЕРИМЕНТАЛЬНИЙ - Ви повинні використовувати найновішу версію вашої бази даних чату ЛИШЕ на одному пристрої, інакше ви можете перестати отримувати повідомлення від деяких контактів. - Це налаштування застосовується до повідомлень у вашому поточному профілі чату + Команда SimpleX + хоче підключитися до вас! + ЕКСПЕРИМЕНТАЛЬНІ ФУНКЦІЇ + Ви повинні використовувати найновішу версію бази даних чату лише на одному пристрої, інакше ви можете припинити отримання повідомлень від деяких контактів. + Цей параметр застосовується до повідомлень у вашому поточному профілі чату Зашифрована база даних Помилка: %s - Пониження бази даних - Групове запрошення більше не дійсне, воно було видалено відправником. - видалено %1$s - підключення (вступне запрошення) + Зниження версії бази даних + Запрошення в групу більше не дійсне, його видалив відправник. + видалив(ла) %1$s + підключення (запрошення для введення) підключення Немає контактів для додавання Початкова роль - Чисто + Очистити Читати далі - Безповоротне видалення повідомлення - Дякуємо користувачам - зробіть свій внесок через Weblate! - Щоб отримувати повідомлення, будь ласка, введіть пароль до бази даних + Незворотне видалення повідомлень + Дякуємо користувачам – приєднуйтеся через Weblate! + Для отримання сповіщень, будь ласка, введіть пароль бази даних Файл не знайдено - Підключіться за посиланням - Підключіться - Щоб відкрити свій прихований профіль, введіть повний пароль у поле пошуку на сторінці \"Ваші профілі чату\". - Підтвердьте пароль + Підключитися через посилання + Підключитися + Щоб показати ваш схований профіль, введіть повний пароль у поле пошуку на сторінці Ваші профілі чату. + Підтвердити пароль %dd - Захистіть свої профілі чату паролем! - Помилка розшифровки + Захистіть свої чат-профілі паролем! + Помилка дешифрування Сервер вимагає авторизації для завантаження, перевірте пароль Завантажити файл Завантажити файл Не вдається ініціалізувати базу даних База даних працює некоректно. Натисніть, щоб дізнатися більше - Додаток періодично отримує нові повідомлення - він використовує кілька відсотків заряду акумулятора на день. Додаток не використовує push-сповіщення - дані з вашого пристрою не надсилаються на сервери. - Дзвінки SimpleX Chat + Програма періодично отримує нові повідомлення — це використовує кілька відсотків батареї щодня. Програма не використовує торкання сповіщень — дані з вашого пристрою не відправляються на сервери. + Дзвінки чату SimpleX Служба сповіщень Показати попередній перегляд Попередній перегляд сповіщень - Запускається, коли програма відкрита - Періодично запускається + Запускається, коли додаток відкритий + Запускається періодично Текст повідомлення - Ім\'я контактної особи - Підтвердіть свій обліковий запис - Увімкнути SimpleX Lock можна в Налаштуваннях. - Швидше за все, цей контакт видалив зв\'язок з вами. - Контекстна піктограма + Ім\'я контакту + Підтвердіть свої облікові дані + Ви можете увімкнути блокування SimpleX через налаштування. + Ймовірно, цей контакт видалив з вами зв\'язок. + Значок контексту Забагато зображень! Забагато відео! ви спостерігач - кольорові - дзвінок закінчився %1$s - помилка виклику - Наступне покоління приватних повідомлень - Протокол і код з відкритим вихідним кодом - будь-хто може запускати сервери. - Інструменти для розробників - Експериментальні особливості + кольоровий + дзвінок завершено %1$s + помилка дзвінка + Наступне покоління приватного обміну повідомленнями + Відкритий протокол та код – кожен може запустити сервери. + Інструменти розробника + Експериментальні функції ДЗВІНКИ - Збережіть парольну фразу у сховищі ключів + Зберегти ключову фразу в сховищі ключів Помилка шифрування бази даних - Видалити парольну фразу з Keystore\? - Будь ласка, введіть правильний поточний пароль. - Будь ласка, зберігайте пароль надійно, ви НЕ зможете отримати доступ до чату, якщо втратите його. + Вилучити ключову фразу із сховища ключів? + Будь ласка, введіть правильну поточну ключову фразу. + Будь ласка, зберігайте ключову фразу надійно, ви НЕ зможете отримати доступ до чату, якщо втратите її. Видалити профіль чату\? - Зупинити файл - Припинити надсилати файл\? + Зупинити відправлення файлу + Зупинити відправлення файлу? Створити секретну групу (щоб поділитися з вашим контактом) - (відсканувати або вставити з буфера обміну) - зв\'язатися з розробниками SimpleX Chat, щоб задати будь-які питання та отримати оновлення.]]> - Відскануйте QR-код.]]> - SimpleX Адреса + (сканувати або вставити з буферу обміну) + підключитися до розробників SimpleX Chat, щоб задати будь-які питання і отримувати оновлення.]]> + Сканувати QR-код.]]> + Адреса SimpleX Показати QR-код Приєднання до групи курсив - Сервери WebRTC ICE - Увімкніть дзвінки з екрана блокування через Налаштування. - Швидко і без очікування, поки відправник буде онлайн! + WebRTC сервери ICE + Увімкніть прийом викликів з екрану блокування через Налаштування. + Швидко та без очікування, поки відправник у мережі! немає тексту - Надішліть пряме повідомлення + Надіслати пряме повідомлення Інтервал PING Кількість PING Увімкнути TCP keep-alive Видалити профіль чату для Приховати - Темний - Система + Темна + Системна Темна тема - Імпорт теми - Експорт теми + Імпортувати тему + Експортувати тему Переконайтеся, що файл має правильний синтаксис YAML. Експортуйте тему, щоб мати приклад структури файлу теми. Скинути кольори за замовчуванням (%s) - Дзвонити можете тільки ви. + Тільки ви можете здійснювати дзвінки. Тільки ваш контакт може здійснювати дзвінки. Що нового Голосові повідомлення - За профілем чату (за замовчуванням) або за з\'єднанням (BETA). - Користувацькі теми + За профілем чату (типово) або за підключенням (BETA). + Власні теми - голосові повідомлення до 5 хвилин. -\n- користувальницький час зникнення. +\n- власний час на зникнення. \n- історія редагування. Японський та португальський інтерфейс Натисніть, щоб приєднатися - Натисніть, щоб приєднатися інкогніто - Ви відхилили запрошення до групи - видалив вас + Натисніть, щоб приєднатися анонімно + Ви відхилили запрошення в групу + вас видалили власник видалено - відсканувати QR-код у відеодзвінку, або ваш контакт може поділитися посиланням на запрошення.]]> - Як ним користуватися + сканувати QR-код у відеовиклику, або ваш контакт може поділитися посиланням на запрошення.]]> + Як користуватися Підключення - Використовувати .onion хости на Ні, якщо SOCKS проксі не підтримує їх.]]> - Покажи: - Приховати: - Під час імпорту виникли деякі нефатальні помилки – ви можете переглянути консоль чату, щоб дізнатися більше. - Цю дію неможливо скасувати - повідомлення, надіслані та отримані раніше, ніж вибрані, будуть видалені. Це може зайняти кілька хвилин. - Вам доведеться вводити парольну фразу щоразу при запуску програми - вона не зберігається на пристрої. - Змінити пароль до бази даних\? - Не вдається отримати доступ до сховища ключів, щоб зберегти пароль до бази даних - Збережіть пароль і відкрийте чат - Пароль не знайдено у сховищі ключів, будь ласка, введіть його вручну. Це могло статися, якщо ви відновили дані програми за допомогою інструменту резервного копіювання. Якщо це не так, зверніться до розробників. + Використовувати .onion-хости на Ні, якщо SOCKS-проксі їх не підтримує.]]> + Показати: + Сховати: + Під час імпорту сталися деякі невідновні помилки - ви можете переглянути консоль чату для отримання більше деталей. + Цю дію неможливо відмінити - будуть видалені повідомлення, відправлені та отримані раніше вибраного часу. Це може зайняти декілька хвилин. + Вам потрібно вводити ключову фразу кожен раз при запуску додатка - вона не зберігається на пристрої. + Змінити ключову фразу бази даних? + Не вдається отримати доступ до сховища ключів для збереження пароля бази даних + Зберегти ключову фразу і відкрити чат + Ключова фраза не знайдена в сховищі ключів, будь ласка, введіть її вручну. Це може трапитися, якщо ви відновили дані додатка за допомогою інструменту резервного копіювання. Якщо це не так, зверніться до розробників. Видалити профіль чату %d сек Пошук - Вимкнено - Відправлення підтвердження доставлення вимкнено для контакту %d - Вимкнути (зберегти перевизначення) + Вимк. + Надсилання повідомлень про доставку вимкнено для %d контактів + Вимкнути (зберегти заміни) Увімкнути для всіх - шифрування ok + шифрування в порядку узгодження шифрування… узгодження шифрування для %s… - %s в %s - Для всіх контактів буде ввімкнено відправку підтвердження доставки. - Відправлення підтвердження доставлення буде ввімкнено для всіх контактів у всіх видимих профілях чату. - Ви можете увімкнути пізніше в Налаштуваннях - Не вмикати - Помилка активації підтвердження доставлення! - Помилка переривання зміни адреси - Скасувати зміну адреси - Дозволяє надсилати файли та медіа. - Файли та медіа в цій групі заборонені. - Підключайтеся інкогніто + %s о %s + Відправка квитанцій про доставку буде увімкнена для всіх контактів. + Відправка квитанцій про доставку буде увімкнена для всіх контактів у всіх видимих чат-профілях. + Ви можете увімкнути їх пізніше через налаштування + Не увімкнювати + Помилка увімкнення квитанцій про доставку! + Помилка відміни зміни адреси + Перервати зміну адреси + Дозволити надсилання файлів та медіафайлів. + Файли та медіафайли заборонені в цій групі. + Підключити інкогніто Використовувати поточний профіль - Дозвольте + Дозволити Вимкнути сповіщення - Відкрийте налаштування програми - SimpleX не може працювати у фоновому режимі. Ви будете отримувати сповіщення лише під час роботи програми. - Ніяких фонових дзвінків - Додаток можна закрити після 1 хвилини роботи у фоновому режимі. + Відкрити налаштування додатка + SimpleX не може працювати в фоновому режимі. Ви отримуватимете сповіщення лише тоді, коли програма працює. + Обмеженість фонових дзвінків + Додаток може бути закритий після 1 хвилини в фоновому режимі. У відповідь на Немає історії - Файли та медіа заборонені! - Ваш профіль %1$s буде опублікований. + Заборонено файли та медіа! + Буде відправлено ваш профіль %1$s. Вимкнути для всіх груп - НАДІШЛІТЬ ПІДТВЕРДЖЕННЯ ДОСТАВКИ НА АДРЕСУ - Підключатися напряму\? + НАДСИЛАТИ ПОВІДОМЛЕННЯ ПРО ДОСТАВКУ + Підключитися безпосередньо? %s: %s - Запит на підключення буде надіслано цьому учаснику групи. - Виправлення + Запит на підключення буде відправлено учаснику групи. + Виправити Файли та медіа Фільтруйте непрочитані та улюблені чати. Швидше знаходьте чати - Зробити так, щоб одне повідомлення зникло - Немає вибраного чату + Зникайте одне повідомлення + Не обрано жодного чату Скасувати Виберіть файл Контакти Ці налаштування стосуються вашого поточного профілю - Вимкнути підтвердження\? - Активувати підтвердження\? - переузгодження шифрування дозволено - узгоджене шифрування для %s - переузгодження шифрування дозволено для %s - потрібно переузгодження шифрування для %s - змінено код безпеки + Вимкнути повідомлення про доставку? + Увімкнути повідомлення про доставку? + можлива перезапис шифрування + шифрування узгоджено для %s + можлива перезапис шифрування для %s + перезапис шифрування обов\'язковий для %s + код безпеки змінено Виправлення не підтримується контактом - Надсилати звіти про доставку - Заборонити надсилання файлів і медіа. - Виправити шифрування після відновлення резервних копій. - Зберігайте свої зв\'язки - - стабільніше доставлення повідомлень. -\n- трохи кращі групи. -\n- і багато іншого! - Вже скоро! + Надсилати звіти + Заборонити надсилання файлів та медіафайлів. + Виправте шифрування після відновлення резервних копій. + Зберігайте ваші підключення + - стабільніша доставка повідомлень. +\n- трошки кращі групи. +\n- та багато іншого! + Скоро! Доставка - Немає інформації про доставлення + Немає інформації про доставку Немає фільтрованих чатів - Переузгодьте - Неулюблене + Узгодити повторно + Забрати з улюблених Вимкнути для всіх - Увімкнути (зберегти перевизначення) - Підтвердження надсилання ввімкнено для контакту %d - Невеликі групи (максимум 20 осіб) - Вимкнути підтвердження доставлення для груп\? - Активувати підтвердження доставлення для груп\? - Надсилання підтвердження доставлення дозволено для груп %d - Вимкнути (зберегти групові перевизначення) + Увімкнути (зберегти заміни) + Надсилання повідомлень про доставку увімкнено для %d контактів + Невеликі групи (макс. 20) + Вимкнути повідомлення про доставку для груп? + Увімкнути повідомлення про доставку для груп? + Надсилання повідомлень про доставку увімкнено для %d груп + Вимкнути (зберегти заміни для груп) Увімкнути для всіх груп - Увімкнути (зберегти перевизначення групи) - потрібне повторне узгодження шифрування - Підтвердження доставки вимкнено + Увімкнути (зберегти заміни для груп) + перезапис шифрування обов\'язковий + Звіти вимкнено вимкнено - У цій групі більше %1$d учасників, підтвердження доставлення не буде надіслано. - Ця функція поки що не підтримується. Спробуйте наступну версію. - Виправити з\'єднання - Виправити з\'єднання\? - Переузгодьте шифрування - Тайм-аут протоколу на КБ - узгоджено шифрування - %s і %s під\'єднано + У цій групі понад %1$d учасників, звіти про доставку не відправляються. + Ця функція ще не підтримується. Спробуйте наступний випуск. + Виправити підключення + Виправити підключення? + Переговорити щодо шифрування + Тайм-аут протоколу за КБ + шифрування узгоджено + %s і %s підключилися Виправлення не підтримується учасником групи - Підтвердження доставлення повідомлення! - Другу галочку ми пропустили! ✅ - Улюблений - Ще кілька моментів - Буде створено новий випадковий профіль. - Підтвердження доставлення! - Підтвердження доставлення вимкнено! + Підтвердження доставки повідомлень! + Друга галочка, яку ми пропустили! ✅ + Улюблені + Ще кілька речей + Буде відправлено новий випадковий профіль. + Квитанції про доставку! + Квитанції про доставку вимкнено! Увімкнути - шифрування ok для %s - Навіть коли вимкнений у розмові. - Чернетка повідомлення - Тільки власники груп можуть вмикати файли та медіа. - Вставте отримане посилання для зв\'язку з вашим контактом… - Відправлення підтвердження доставки вимкнено для груп %d - %s, %s і %s підключено - Їх можна перевизначити в налаштуваннях контактів і груп. - Використання акумулятора програми / Необмежено в налаштуваннях програми.]]> - Використання акумулятора програми / Без обмежень у налаштуваннях програми.]]> - Використовуйте новий профіль інкогніто - Ви можете увімкнути їх пізніше в налаштуваннях конфіденційності та безпеки програми. - %s, %s та %d інших учасників під\'єднано - Показати останні повідомлення + шифрування в порядку для %s + Навіть коли вимкнено в розмові. + Чорновик повідомлення + Тільки власники групи можуть включити файли та медіа. + Вставте посилання, яке ви отримали, щоб підключитися до свого контакту… + Надсилання повідомлень про доставку вимкнено для %d груп + %s, %s і %s підключилися + Їх можна замінити в налаштуваннях контактів і груп. + Використання батареї додатком / Без обмежень у налаштуваннях додатка.]]> + Використання батареї додатком / Без обмежень у налаштуваннях додатка.]]> + Використовувати новий інкогніто-профіль + Ви зможете увімкнути їх пізніше через налаштування конфіденційності та безпеки додатка. + %s, %s і ще %d учасників підключилися + Показувати останні повідомлення Помилка синхронізації з\'єднання - Скасувати зміну адреси\? - Зміна адреси буде скасована. Буде використано стару адресу отримання. - Переузгодьте шифрування\? - Шифрування працює і нова угода про шифрування не потрібна. Це може призвести до помилок з\'єднання! - Учасники групи можуть надсилати файли та медіа. - База даних буде зашифрована, а ключова фраза збережена в налаштуваннях. + Скасувати зміну адреси для отримання? + Зміна адреси буде скасована. Буде використовуватися стара адреса для отримання. + Повторно узгодити шифрування? + Шифрування працює і нова угода про шифрування не потрібна. Це може призвести до помилок підключення! + Учасники групи можуть надсилати файли та медіафайли. + База даних буде зашифрована, і ключова фраза буде збережена в налаштуваннях. Розгорнути Повторити запит на підключення? - Помилка повторного узгодження шифрування - видалений контакт - Ви вже з\'єднані з %1$s. + Помилка переговорів щодо шифрування + видалено контакт + Ви вже підключаєтеся до %1$s. Відкрити - Шифрування збережених файлів і носіїв + Шифрування збережених файлів та медіа Помилка - Помилка при створенні контакту користувача - Ви вже приєдналися до групи за цим посиланням. + Помилка при створенні контакту учасника + Ви вже приєднуєтеся до групи за цим посиланням. Створити групу - Зверніть увагу: ретранслятори повідомлень і файлів підключаються через проксі SOCKS. Дзвінки та надсилання попередніх переглядів посилань використовують пряме з’єднання.]]> + Зверніть увагу: ретрансляція повідомлень та файлів підключається через SOCKS-проксі. Дзвінки та відправлення переглядів посилань використовують пряме підключення.]]> Створити профіль - %s та %s - Приєднатися до групи? - Ви вже приєдналися до групи %1$s. - Шифрування локальних файлів - Це ваше власне одноразове посилання! - %d повідомлень позначено як видалені - Новий десктопний застосунок! + %s і %s + Приєднатися до вашої групи? + Ви вже приєднуєтеся до групи %1$s. + Шифрувати локальні файли + Це ваш власний одноразовий посилання! + %d повідомлень відзначено як видалені + Новий додаток для комп\'ютера! 6 нових мов інтерфейсу Група вже існує! - Застосунок шифрує нові локальні файли (крім відео). - Вже під\'єднуємося! - Випадкова фраза зберігається у налаштуваннях у вигляді відкритого тексту. + Додаток шифрує нові локальні файли (крім відео). + Вже підключено! + Випадковий пароль зберігається в налаштуваннях у відкритому вигляді. \nВи можете змінити його пізніше. - Надішліть пряме повідомлення, щоб підключитися - Відео не може бути декодовано. Будь ласка, спробуйте інше відео або зверніться до розробників. - %s підключено - ще інших подій - %d - Знаходьте та приєднуйтесь до груп - Підключитися за посиланням? - Пароль для шифрування бази даних буде оновлено і збережено в налаштуваннях. - Вже долучаємось до групи! - члени %s, %s та %d - %d повідомлень модерує %s - Видалити парольну фразу з налаштувань? - Розблокувати - Використовуйте випадкову парольну фразу + Відправте приватне повідомлення для підключення + Неможливо декодувати відео. Спробуйте інше відео або зв\'яжіться з розробниками. + %s підключився + і ще %d подій + Відкривайте та приєднуйтесь до груп + Підключитися за допомогою посилання? + Ключова фраза шифрування бази даних буде оновлена і збережена в налаштуваннях. + Вже приєднано до групи! + %s, %s і %d учасників + %d повідомлень модеровано %s + Вилучити ключову фразу із налаштувань? + Розблокувати учасника + Використовувати випадковий пароль Підключитися до себе? - Зберегти парольну фразу в налаштуваннях + Зберегти ключову фразу в налаштуваннях Спрощений режим інкогніто - Натисніть, щоб підключитися - Ключова фраза для налаштування бази даних + Торкніться, щоб підключитися + Налаштування паролю бази даних Ви вже в групі %1$s. - Це ваша власна SimpleX адреса! - Повторне узгодження шифрування не вдалося. + Це ваш власний адреса SimpleX! + Не вдалося виконати переговори щодо шифрування. Виправити ім\'я на %s? - Видалити %d повідомлень? + Видалити %d повідомлення? Підключитися до %1$s? - Видалити учасника - Встановити пароль до бази даних + Вилучити учасника + Встановити ключову фразу бази даних Заблокувати Розблокувати учасника? %d повідомлень заблоковано Заблокувати учасника - Відкрийте теку з базою даних + Відкрити папку бази даних Повторити запит на приєднання? - Видалити учасника? - Видалити та повідомити контакт - Арабська, Болгарська, Фінська, Іврит, Тайська та Українська – завдяки користувачам і Weblate. - Ви вже підключаєтеся за цим одноразовим посиланням! + Вилучити учасника? + Видалити та сповістити контакт + Арабська, болгарська, фінська, іврит, тайська та українська - завдяки користувачам і Weblate. + Ви вже підключаєтеся через це одноразове посилання! Відкрити групу - Будуть показані повідомлення від %s! - Створіть новий профіль у десктопному застосунку. 💻 - Помилка надсилання запрошення - Після зміни пароля або перезапуску програми він буде збережений у налаштуваннях у вигляді відкритого тексту. - Ви надали невірний шлях до файлу. Повідомте про проблему розробникам програми. + Повідомлення від %s будуть відображені! + Створіть новий профіль у додатку для комп\'ютера. 💻 + Помилка при відправці запрошення + Після зміни ключової фрази або перезапуску додатка ключова фраза буде збережена в налаштуваннях як звичайний текст. + Ви поділилися неправильним шляхом до файлу. Повідомте про цю проблему розробникам додатку. Заблокувати учасника? - %d групових подій - Неправильне ім\'я! - Увімкніть інкогніто при підключенні. + %d подій в групі + Невірне ім\'я! + Перемикайте інкогніто під час підключення. Це ваше посилання для групи %1$s! Розблокувати Неправильний шлях до файлу - - підключитися до служби каталогів (БЕТА)! + - підключайтесь до служби каталогів (BETA)! \n- квитанції про доставку (до 20 учасників). -\n- швидше і стабільніше. - Пароль зберігається у налаштуваннях у вигляді відкритого тексту. - Ви вже надсилали запит на підключення за цією адресою! - надіслати пряме повідомлення - Показати консоль у новому вікні - Всі повідомлення від %s будуть приховані - підключений безпосередньо +\n- швидше та надійніше. + Ключова фраза зберігається в налаштуваннях як звичайний текст. + Ви вже подали запит на підключення за цією адресою! + надіслати приватне повідомлення + Показувати консоль в новому вікні + Всі нові повідомлення від %s будуть приховані! + підключив(лась) безпосередньо заблоковано + Блокувати учасників групи + Створіть групу, використовуючи випадковий профіль. + Підключений робочий стіл + Новий мобільний пристрій + Підключати автоматично + Адреса робочого столу + Одночасно може працювати лише один пристрій + Посилання на мобільний та комп\'ютерний додатки! 🔗 + Через безпечний квантовостійкий протокол. + Використовувати з робочого столу у мобільному додатку і скануйте QR-код.]]> + Щоб приховати небажані повідомлення. + Несумісна версія + (новий)]]> + Відсунути відсилання до робочого столу? + Кращі групи + Параметри пов\'язаних робочих столів + Пов\'язані робочі столи + Виявити через локальну мережу + Інкогніто групи + Цей пристрій + %s був відключений]]> + Очікування робочого столу… + Швидше приєднуйтесь та надійшовні повідомлення. + Пов\'язані мобільні + Робочий стіл + Підключено до робочого столу + Назва цього пристрою + Завантаження файлу + Підключення до робочого столу + Знайдено робочий стіл + Пристрої робочого столу + Не сумісно! + Зв\'язати з мобільним + Використовувати зі стаціонарного комп\'ютера + Підключений мобільний + Код сеансу + Підключення завершено + (цей пристрій v%s)]]> + Відсунути відсилання + Назва пристрою буде надіслана підключеному мобільному клієнту. + Перевірте код на мобільному + Введіть назву цього пристрою… + Помилка + Підключитися до робочого столу + Відключити + автор + Підключено до мобільного + Некоректна адреса робочого столу + Вставити адресу робочого столу + Перевірити код з робочим столом + Сканувати QR-код з робочого столу + Пристрої + Виявлено через локальну мережу + - за бажанням повідомляйте про видалених контактів. +\n- імена профілю з пробілами. +\n- та інше! + Сканувати з мобільного + Перевірити підключення + Відключити робочий стіл? + Будь ласка, зачекайте, поки файл завантажується з підключеного мобільного + Версія робочого столу %s не сумісна з цим додатком. + Перевірити підключення \ No newline at end of file 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 c19a3960f7..7b8d8ec7eb 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 @@ -1521,4 +1521,15 @@ 找到了桌面 不兼容! 可通过本地网络发现 + 刷新 + 创建聊天资料 + 没有已连接的移动设备 + 断开移动设备连接 + 随机 + 要允许移动应用连接到桌面,请在防火墙中打开此端口,如果你已启用了它 + 在防火墙中打开端口 + 查看崩溃 + %d 条消息由 %s 主持 + 显示内容出错 + 显示消息出错 \ No newline at end of file From d637714963340967f2bc0b7eafab9814370723dd Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Thu, 28 Dec 2023 17:52:20 +0000 Subject: [PATCH 005/102] website: translations (#3617) * Translated using Weblate (Ukrainian) Currently translated at 100.0% (252 of 252 strings) Translation: SimpleX Chat/SimpleX Chat website Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/uk/ * Translated using Weblate (Ukrainian) Currently translated at 100.0% (252 of 252 strings) Translation: SimpleX Chat/SimpleX Chat website Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/uk/ * Translated using Weblate (Ukrainian) Currently translated at 100.0% (252 of 252 strings) Translation: SimpleX Chat/SimpleX Chat website Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/uk/ * Translated using Weblate (Spanish) Currently translated at 100.0% (252 of 252 strings) Translation: SimpleX Chat/SimpleX Chat website Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/es/ --------- Co-authored-by: Maksym Lukashenko Co-authored-by: No name --- website/langs/es.json | 6 +- website/langs/uk.json | 368 +++++++++++++++++++++--------------------- 2 files changed, 191 insertions(+), 183 deletions(-) diff --git a/website/langs/es.json b/website/langs/es.json index 7c418b7e25..9b116b4215 100644 --- a/website/langs/es.json +++ b/website/langs/es.json @@ -20,7 +20,7 @@ "hero-overlay-1-title": "¿Cómo funciona SimpleX?", "hero-overlay-2-title": "¿Por qué los ID de usuario son perjudiciales para la privacidad?", "feature-1-title": "Mensajes cifrados E2E con sintáxis markdown y edición", - "feature-3-title": "Grupos secretos descentralizados —
sólo los usuarios saben de su existencia", + "feature-3-title": "Grupos descentralizados cifrados E2E — sólo los usuarios conocen su existencia", "feature-6-title": "Llamadas y videollamadas con cifrado E2E", "simplex-network-overlay-1-title": "Comparativa con protocolos de mensajería P2P", "developers": "Desarrolladores", @@ -30,7 +30,7 @@ "simplex-explained-tab-3-p-1": "Para cada cola los servidores disponen de credenciales separadas y anónimas, por lo que desconocen a qué usuarios pertenecen.", "hero-p-1": "Las demás aplicaciones usan ID de usuario: Signal, Matrix, Session, Briar, Jami, Cwtch, etc.
SimpleX no los tiene, ni siquiera números aleatorios.
Esto mejora radicalmente su privacidad.", "hero-2-header-desc": "El video muestra cómo se conecta con sus amistades a través del código QR de un solo uso, en persona o a través de videollamada. También puede conectarse compartiendo un enlace de invitación.", - "feature-7-title": "Base de datos portable cifrada — transfiera su perfil a otro dispositivo", + "feature-7-title": "Almacenamiento portable y cifrado — podrá transferir su perfil a otro dispositivo", "simplex-private-card-4-point-2": "Para usar SimpleX a través de Tor, instala la aplicación Orbot y activa el proxy SOCKS5 (o VPN en iOS).", "simplex-private-card-3-point-1": "Para las conexiones cliente servidor se usan exclusivamente el protocolo TLS 1.2/1.3 con algoritmos robustos.", "simplex-private-card-4-point-1": "Para proteger tu dirección IP puedes acceder a los servidores a través de la red Tor u otras redes de transporte superpuesto.", @@ -48,7 +48,7 @@ "chat-protocol": "Protocolo Chat", "terminal-cli": "Terminal CLI", "hero-subheader": "La primera aplicación de mensajería
sin ID de usuario", - "feature-2-title": "Cifrado E2E
de imágenes y archivos", + "feature-2-title": "Cifrado E2E
de imágenes, vídeos y archivos", "feature-8-title": "Modo incógnito —
exclusivo de SimpleX Chat", "simplex-private-1-title": "Doble capa de
cifrado de extremo a extremo", "simplex-private-2-title": "Capa de cifrado
adicional en el servidor", diff --git a/website/langs/uk.json b/website/langs/uk.json index 6a48cc5640..e71b7cef8d 100644 --- a/website/langs/uk.json +++ b/website/langs/uk.json @@ -2,245 +2,253 @@ "features": "Особливості", "simplex-explained-tab-3-text": "3. Що бачать сервери", "terms-and-privacy-policy": "Умови та політика конфіденційності", - "feature-4-title": "E2E-зашифровані голосові повідомлення", - "feature-5-title": "Зникаючі повідомлення", - "simplex-private-card-3-point-3": "Відновлення підключення вимкнено для запобігання атакам сеансів.", - "simplex-private-card-7-point-1": "Щоб гарантувати цілісність, повідомлення послідовно нумеруються і включають хеш попереднього повідомлення.", - "simplex-private-card-10-point-2": "Він дозволяє доставляти повідомлення без ідентифікаторів профілю користувача, забезпечуючи кращу конфіденційність метаданих, ніж альтернативи.", - "privacy-matters-2-overlay-1-linkText": "Конфіденційність дає вам силу", - "hero-overlay-card-1-p-5": "Тільки клієнтські пристрої зберігають профілі користувачів, контакти та групи; повідомлення надсилаються з двошаровим наскрізним шифруванням.", - "hero-overlay-card-2-p-1": "Коли користувачі мають постійні ідентифікатори, навіть якщо це просто випадкове число, наприклад, ідентифікатор сеансу, існує ризик, що провайдер або зловмисник може спостерігати, як користувачі підключаються і скільки повідомлень вони надсилають.", - "simplex-network-overlay-card-1-li-5": "Всі відомі P2P-мережі можуть бути вразливими до атаки Sybil, оскільки кожен вузол можна виявити, а мережа працює як єдине ціле. Відомі заходи для її пом'якшення вимагають або централізованого компоненту, або дорогого доказу роботи. Мережа SimpleX не має можливості виявлення серверів, вона фрагментована і працює як кілька ізольованих підмереж, що унеможливлює атаки на всю мережу.", - "simplex-network-overlay-card-1-li-6": "P2P-мережі можуть бути вразливими до DRDoS-атаки, коли клієнти можуть повторно транслювати та збільшувати трафік, що призводить до відмови в обслуговуванні всієї мережі. Клієнти SimpleX лише ретранслюють трафік із відомого з’єднання, і зловмисники не можуть використовувати їх для посилення трафіку в усій мережі.", - "privacy-matters-overlay-card-1-p-2": "Інтернет-магазини знають, що люди з нижчими доходами більш схильні до термінових покупок, тому вони можуть встановлювати вищі ціни або скасовувати знижки.", - "privacy-matters-overlay-card-1-p-3": "Деякі фінансові та страхові компанії використовують соціальні графіки для визначення процентних ставок і премій. Це часто змушує людей з нижчими доходами платити більше —, він відомий як ' премія за бідність'.", - "privacy-matters-overlay-card-1-p-4": "Платформа SimpleX захищає конфіденційність ваших з'єднань краще, ніж будь-яка інша альтернатива, повністю запобігаючи тому, щоб ваш соціальний графік став доступним будь-яким компаніям або організаціям. Навіть коли люди використовують сервери, надані SimpleX Chat, ми не знаємо кількість користувачів та їхніх з'єднань.", - "privacy-matters-overlay-card-2-p-1": "Не так давно ми стали свідками маніпуляцій на великих виборах з боку авторитетної консалтингової компанії, яка використовувала наші соціальні графіки, щоб спотворити наше уявлення про реальний світ і маніпулювати нашими голосами.", - "privacy-matters-overlay-card-2-p-2": "Щоб бути об'єктивним і приймати незалежні рішення, необхідно контролювати свій інформаційний простір. Це можливо лише за умови використання приватної комунікаційної платформи, яка не має доступу до вашого соціального профілю.", - "privacy-matters-overlay-card-2-p-3": "SimpleX - це перша платформа, яка не має жодних ідентифікаторів користувачів, таким чином захищаючи ваш граф зв'язків краще, ніж будь-яка інша відома альтернатива.", - "privacy-matters-overlay-card-3-p-1": "Кожен має дбати про конфіденційність і безпеку своїх комунікацій — нешкідливі розмови можуть наражати вас на небезпеку, навіть якщо вам нема чого приховувати.", - "privacy-matters-overlay-card-3-p-2": "Однією з найбільш шокуючих історій є досвід Мохамеду Ульд Салахі, описаний у його мемуарах та показаний у фільмі \"Мавританець\". Його без суду і слідства помістили в табір Гуантанамо і катували там протягом 15 років після телефонного дзвінка родичу в Афганістані за підозрою в причетності до терактів 11 вересня, хоча він жив у Німеччині протягом останніх 10 років.", - "privacy-matters-overlay-card-3-p-4": "Недостатньо використовувати наскрізний зашифрований месенджер, ми всі повинні використовувати месенджери, які захищають конфіденційність наших особистих мереж — тих, з ким ми пов'язані.", - "simplex-unique-overlay-card-1-p-1": "На відміну від інших платформ обміну повідомленнями, SimpleX не має ніяких ідентифікаторів, призначених користувачам. Він не покладається на телефонні номери, доменні адреси (наприклад, електронну пошту або XMPP), імена користувачів, відкриті ключі або навіть випадкові числа для ідентифікації своїх користувачів — ми не ' знаємо, скільки людей користуються нашими серверами SimpleX.", - "simplex-unique-overlay-card-3-p-3": "На відміну від серверів об'єднаних мереж (електронна пошта, XMPP або Matrix), сервери SimpleX не зберігають облікові записи користувачів, вони лише пересилають повідомлення, захищаючи конфіденційність обох сторін.", - "simplex-unique-card-3-p-2": "Наскрізні зашифровані повідомлення тимчасово зберігаються на релейних серверах SimpleX до моменту отримання, після чого вони назавжди видаляються.", - "simplex-unique-card-4-p-1": "Мережа SimpleX повністю децентралізована і не залежить від будь-якої криптовалюти або будь-якої іншої платформи, окрім Інтернету.", - "simplex-network-overlay-card-1-li-3": "P2P не вирішує атаки MITM проблема, і більшість існуючих реалізацій не використовують позасмугові повідомлення для початкового обміну ключами. SimpleX використовує позасмугові повідомлення або, в деяких випадках, уже існуючі безпечні та надійні з’єднання для початкового обміну ключами.", - "simplex-network-overlay-card-1-li-4": "Реалізації P2P можуть бути заблоковані деякими інтернет-провайдерами (наприклад, BitTorrent). SimpleX є транспортно-агностичним - він може працювати через стандартні веб-протоколи, наприклад, WebSockets.", - "simplex-unique-card-4-p-2": "Ви можете використовувати SimpleX з власними серверами або з серверами, наданими нами — і при цьому підключатися до будь-якого користувача.", - "contact-hero-p-1": "Відкриті ключі та адреса черги повідомлень у цьому посиланні НЕ передаються мережею при перегляді цієї сторінки — вони містяться в хеш-фрагменті URL-адреси посилання.", - "scan-qr-code-from-mobile-app": "Відскануйте QR-код з мобільного додатку", - "to-make-a-connection": "Щоб встановити зв'язок:", - "install-simplex-app": "Встановіть додаток SimpleX", + "feature-4-title": "Голосові повідомлення з шифруванням від кінця до кінця", + "feature-5-title": "Зникнення повідомлень", + "simplex-private-card-3-point-3": "Відновлення з'єднання вимкнено для запобігання атакам на сесію.", + "simplex-private-card-7-point-1": "Для гарантії цілісності повідомлення пронумеровані послідовно та містять хеш попереднього повідомлення.", + "simplex-private-card-10-point-2": "Це дозволяє доставляти повідомлення без ідентифікаторів профілю користувача та забезпечує кращу конфіденційність метаданих, ніж альтернативи.", + "privacy-matters-2-overlay-1-linkText": "Конфіденційність дає вам владу", + "hero-overlay-card-1-p-5": "Тільки пристрої клієнта зберігають профілі користувачів, контакти та групи; повідомлення відправляються із шифруванням від кінця до кінця з двома шарами.", + "hero-overlay-card-2-p-1": "Коли у користувачів є постійні ідентифікатори, навіть якщо це просто випадковий номер, як, наприклад, ідентифікатор сеансу, існує ризик того, що провайдер чи зловмисник може спостерігати, як користувачі підключені та скільки повідомлень вони відправляють.", + "simplex-network-overlay-card-1-li-5": "Всі відомі P2P-мережі можуть бути вразливими до атаки Sybil, оскільки кожен вузол є відкритим, і мережа працює як ціле. Відомі заходи для пом'якшення цієї атаки вимагають або централізованого компонента, або дорогого доказу роботи. Мережа SimpleX не має виявності сервера, вона роздроблена і працює як кілька ізольованих підмереж, що робить неможливими атаки на всю мережу.", + "simplex-network-overlay-card-1-li-6": "P2P-мережі можуть бути вразливими до атаки DRDoS, коли клієнти можуть ребродкастити та збільшувати трафік, що призводить до відмови в обслуговуванні на рівні всієї мережі. Клієнти SimpleX лише пересилають трафік від відомого підключення і не можуть бути використані зловмисником для збільшення трафіку в усій мережі.", + "privacy-matters-overlay-card-1-p-2": "Інтернет-роздрібники знають, що люди з низьким доходом частіше роблять термінові покупки, тому вони можуть встановлювати вищі ціни або скасовувати знижки.", + "privacy-matters-overlay-card-1-p-3": "Деякі фінансові та страхові компанії використовують соціальні графи для визначення ставок та страхових премій. Це часто змушує людей з низькими доходами платити більше — це відомо як 'поширений преміум'.", + "privacy-matters-overlay-card-1-p-4": "Платформа SimpleX захищає конфіденційність ваших з'єднань краще, ніж будь-яка альтернатива, повністю запобігаючи доступу вашого соціального графа будь-яким компаніям чи організаціям. Навіть коли люди використовують сервери, надані SimpleX Chat, ми не знаємо кількість користувачів чи їх зв'язки.", + "privacy-matters-overlay-card-2-p-1": "Не так давно ми спостерігали, як великі вибори маніпулювалися поважною консалтинговою компанією, яка використовувала наші соціальні графи для спотворення нашого уявлення про реальний світ та маніпулювання нашими голосами.", + "privacy-matters-overlay-card-2-p-2": "Щоб бути об'єктивним та приймати незалежні рішення, вам потрібно контролювати ваш інформаційний простір. Це можливо лише за умови використання приватної платформи для спілкування, яка не має доступу до вашого соціального графа.", + "privacy-matters-overlay-card-2-p-3": "SimpleX - це перша платформа, яка не має жодних ідентифікаторів користувачів за своїм дизайном, таким чином, захищаючи ваш графік з'єднань краще, ніж будь-яка відома альтернатива.", + "privacy-matters-overlay-card-3-p-1": "Кожен повинен турбуватися про конфіденційність та безпеку свого спілкування — безпечні розмови можуть поставити вас під загрозу, навіть якщо у вас немає чого приховувати.", + "privacy-matters-overlay-card-3-p-2": "Однією з найшокуючих історій є досвід Мохамеду Ульд Слахі, описаний в його мемуарах і показаний у фільмі \"Мавританець\". Його посадили в табір Гуантанамо без суду і мукили там 15 років після телефонного дзвінка йому родичеві в Афганістані, під підозрою в причетності до атак 11 вересня, навіть не дивлячись на те, що він проживав у Німеччині протягом попередніх 10 років.", + "privacy-matters-overlay-card-3-p-4": "Недостатньо використовувати зашифрований від кінця до кінця месенджер; ми всі повинні використовувати месенджери, які захищають конфіденційність наших особистих мереж — з ким ми з'єднані.", + "simplex-unique-overlay-card-1-p-1": "На відміну від інших платформ обміну повідомленнями, у SimpleX не присвоюються ідентифікатори користувачів. Він не покладається на номери телефонів, адреси на основі домену (наприклад, електронна пошта або XMPP), імена користувачів, публічні ключі або навіть випадкові номери для ідентифікації своїх користувачів — ми не знаємо, скільки людей використовує наші сервери SimpleX.", + "simplex-unique-overlay-card-3-p-3": "На відміну від федеративних мереж серверів (електронна пошта, XMPP або Matrix), сервери SimpleX не зберігають облікові записи користувачів, вони лише ретранслюють повідомлення, захищаючи приватність обох сторін.", + "simplex-unique-card-3-p-2": "Зашифровані повідомлення від кінця до кінця тимчасово зберігаються на ретрансляційних серверах SimpleX до їх отримання, після чого вони назавжди видаляються.", + "simplex-unique-card-4-p-1": "Мережа SimpleX є повністю децентралізованою та незалежною від будь-якої криптовалюти чи іншої платформи, крім Інтернету.", + "simplex-network-overlay-card-1-li-3": "P2P не вирішує проблему атаки MITM, і більшість існуючих реалізацій не використовують поза каналом повідомлень для початкового обміну ключами. SimpleX використовує поза каналом повідомлень або, у деяких випадках, передбачені і безпечні з'єднання для початкового обміну ключами.", + "simplex-network-overlay-card-1-li-4": "Реалізації P2P можуть бути блоковані деякими інтернет-провайдерами (наприклад, BitTorrent). SimpleX є транспортно-агностичним - він може працювати через стандартні веб-протоколи, наприклад, WebSockets.", + "simplex-unique-card-4-p-2": "Ви можете використовувати SimpleX з власними серверами або з серверами, які ми надаємо — і все одно підключатися до будь-якого користувача.", + "contact-hero-p-1": "Публічні ключі та адреса черги повідомлень в цьому посиланні НЕ відправляються по мережі під час перегляду цієї сторінки — вони містяться в хеш-фрагменті URL-посилання.", + "scan-qr-code-from-mobile-app": "Сканувати QR-код з мобільного додатка", + "to-make-a-connection": "Щоб здійснити підключення:", + "install-simplex-app": "Встановити додаток SimpleX", "github-repository": "Репозиторій GitHub", - "no-federated": "Ні - федеративний", - "comparison-section-list-point-1": "Зазвичай на основі номера телефону, в деяких випадках на основі імені користувача", - "comparison-section-list-point-2": "Адреси на основі DNS", - "comparison-section-list-point-3": "Відкритий ключ або інший глобально унікальний ідентифікатор", - "comparison-section-list-point-7": "Мережі P2P або мають центральний орган, або вся мережа може бути скомпрометована", + "no-federated": "Ні - федеративно", + "comparison-section-list-point-1": "Зазвичай базується на номері телефону, у деяких випадках на іменах користувачів", + "comparison-section-list-point-2": "Адреси, засновані на DNS", + "comparison-section-list-point-3": "Відкритий ключ чи який-небудь інший глобально унікальний ідентифікатор", + "comparison-section-list-point-7": "Мережі P2P мають або центральний орган управління, або всю мережу можна порушити", "see-here": "дивіться тут", "guide-dropdown-4": "Профілі чату", - "guide-dropdown-5": "Керування даними", - "guide-dropdown-6": "Аудіо і відео дзвінки", - "guide-dropdown-7": "Конфіденційність і безпека", - "guide-dropdown-8": "Налаштування програми", - "guide-dropdown-9": "Встановлення зв'язків", - "guide": "Путівник", + "guide-dropdown-5": "Управління даними", + "guide-dropdown-6": "Аудіо та відеовиклики", + "guide-dropdown-7": "Конфіденційність та безпека", + "guide-dropdown-8": "Налаштування додатка", + "guide-dropdown-9": "Створення підключень", + "guide": "Посібник", "docs-dropdown-1": "Платформа SimpleX", "docs-dropdown-2": "Доступ до файлів Android", "docs-dropdown-3": "Доступ до бази даних чату", - "docs-dropdown-4": "Хост SMP-сервер", - "docs-dropdown-5": "Хост XFTP-сервер", + "docs-dropdown-4": "Хостинг сервера SMP", + "docs-dropdown-5": "Хостинг сервера XFTP", "docs-dropdown-6": "Сервери WebRTC", - "docs-dropdown-7": "Перекласти чат SimpleX", - "newer-version-of-eng-msg": "Існує новіша версія цієї сторінки англійською мовою.", + "docs-dropdown-7": "Переклад SimpleX Chat", + "newer-version-of-eng-msg": "Є нова версія цієї сторінки англійською мовою.", "click-to-see": "Натисніть, щоб побачити", "menu": "Меню", "on-this-page": "На цій сторінці", - "back-to-top": "Повернутися до початку", + "back-to-top": "Повернутися наверх", "home": "Головна", "developers": "Розробники", "reference": "Посилання", "blog": "Блог", "why-simplex": "Чому SimpleX", - "simplex-privacy": "Конфіденційність SimpleX", + "simplex-privacy": "Приватність у SimpleX", "simplex-network": "Мережа SimpleX", - "simplex-explained": "Simplex пояснення", + "simplex-explained": "Пояснення SimpleX", "simplex-explained-tab-1-text": "1. Що відчувають користувачі", "simplex-explained-tab-2-text": "2. Як це працює", - "simplex-explained-tab-1-p-1": "Ви можете створювати контакти та групи, а також вести двосторонні розмови, як і в будь-якому іншому месенджері.", - "simplex-explained-tab-1-p-2": "Як він може працювати з односпрямованими чергами та без ідентифікаторів профілю користувача?", - "simplex-explained-tab-2-p-1": "Для кожного підключення використовуються дві окремі черги обміну повідомленнями для надсилання та отримання повідомлень через різні сервери.", - "simplex-explained-tab-2-p-2": "Сервери передають повідомлення лише в один бік, не маючи повної картини розмови або з'єднань користувача.", - "simplex-explained-tab-3-p-1": "Сервери мають окремі анонімні облікові дані для кожної черги і не знають, яким користувачам вони належать.", - "simplex-explained-tab-3-p-2": "Користувачі можуть ще більше підвищити конфіденційність метаданих, використовуючи Tor для доступу до серверів, запобігаючи кореляції за IP-адресою.", + "simplex-explained-tab-1-p-1": "Ви можете створювати контакти та групи і вести двосторонні розмови, як у будь-якому іншому месенджері.", + "simplex-explained-tab-1-p-2": "Як це може працювати з однобічними чергами та без ідентифікаторів профілю користувача?", + "simplex-explained-tab-2-p-1": "Для кожного з'єднання ви використовуєте дві окремі черги обміну повідомленнями для відправки та отримання повідомлень через різні сервери.", + "simplex-explained-tab-2-p-2": "Сервери передають повідомлення тільки в одному напрямку, не маючи повної картини розмови або підключень користувача.", + "simplex-explained-tab-3-p-1": "Сервери мають окремі анонімні облікові дані для кожної черги і не знають, які користувачі до них відносяться.", + "simplex-explained-tab-3-p-2": "Користувачі можуть додатково підвищити конфіденційність метаданих, використовуючи Tor для доступу до серверів, що запобігає кореляції за IP-адресою.", "chat-bot-example": "Приклад чат-бота", - "smp-protocol": "SMP протокол", + "smp-protocol": "Протокол SMP", "chat-protocol": "Протокол чату", - "donate": "Пожертвуйте", - "copyright-label": "© 2020-2023 SimpleX | Проект з відкритим вихідним кодом", + "donate": "Пожертвувати", + "copyright-label": "© 2020-2023 SimpleX | Проект з відкритим кодом", "simplex-chat-protocol": "Протокол чату SimpleX", "terminal-cli": "Термінал CLI", - "hero-header": "Конфіденційність переглянута", + "hero-header": "Приватність переосмислена", "hero-subheader": "Перший месенджер
без ідентифікаторів користувачів", - "hero-p-1": "Інші додатки мають ідентифікатори користувачів: Signal, Matrix, Session, Briar, Jami, Cwtch тощо.
SimpleX цього не робить, навіть випадкових чисел.
Це радикально покращує вашу конфіденційність.", - "hero-overlay-1-textlink": "Чому ідентифікатори користувачів шкодять конфіденційності?", + "hero-p-1": "У інших додатках є ідентифікатори користувачів: Signal, Matrix, Session, Briar, Jami, Cwtch, тощо.
У SimpleX немає жодних, навіть випадкових номерів.
Це радикально покращує вашу конфіденційність.", + "hero-overlay-1-textlink": "Чому ідентифікатори користувачів шкідливі для конфіденційності?", "hero-overlay-2-textlink": "Як працює SimpleX?", "hero-2-header": "Створіть приватне з'єднання", - "hero-2-header-desc": "У відео показано, як з'єднатися з другом за допомогою одноразового QR-коду, особисто або за допомогою відеозв'язку. Ви також можете підключитися, поділившись посиланням-запрошенням.", + "hero-2-header-desc": "У відео показано, як ви можете підключитися до свого друга за його одноразовим QR-кодом, особисто або через відеозв'язок. Ви також можете підключитися, поділившись посиланням на запрошення.", "hero-overlay-1-title": "Як працює SimpleX?", - "hero-overlay-2-title": "Чому ідентифікатори користувачів шкодять конфіденційності?", - "feature-1-title": "E2E-зашифровані повідомлення з розміткою і редагуванням", - "feature-2-title": "E2E-зашифровані
зображення та файли", - "feature-3-title": "Децентралізовані секретні групи —
лише користувачі знають про їх існування", - "feature-6-title": "E2E-шифрується
audio і відеодзвінки", - "feature-7-title": "Портативна зашифрована база даних — перенесіть свій профіль на інший пристрій", + "hero-overlay-2-title": "Чому ідентифікатори користувачів шкідливі для конфіденційності?", + "feature-1-title": "Повідомлення з шифруванням від кінця до кінця з можливістю використання Markdown та редагування", + "feature-2-title": "Зображення, відео та файли з шифруванням від кінця до кінця", + "feature-3-title": "Децентралізовані групи з шифруванням від кінця до кінця — тільки користувачі знають про їх існування", + "feature-6-title": "Дзвінки з шифруванням від кінця до кінця для аудіо та відео", + "feature-7-title": "Переносне зашифроване зберігання додатку — переміщуйте профіль на інший пристрій", "feature-8-title": "Режим інкогніто —
унікальний для SimpleX Chat", - "simplex-network-overlay-1-title": "Порівняння з протоколами обміну повідомленнями P2P", - "simplex-private-1-title": "2-рівневе наскрізне шифрування", + "simplex-network-overlay-1-title": "Порівняння з протоколами P2P-повідомлень", + "simplex-private-1-title": "2 рівні шифрування від кінця до кінця", "simplex-private-2-title": "Додатковий рівень
шифрування сервера", - "simplex-private-3-title": "Безпечне автентифіковане
транспортування TLS", - "simplex-private-4-title": "Додатковий
доступ через Tor", - "simplex-private-5-title": "Кілька шарів
заповнення вмісту", - "simplex-private-6-title": "Позадіапазонний
обмін ключами", + "simplex-private-3-title": "Безпечний аутентифікований
транспорт TLS", + "simplex-private-4-title": "Опційний
доступ через Tor", + "simplex-private-5-title": "Кілька рівнів
наповнення вмісту", + "simplex-private-6-title": "Позаканальний
обмін ключами", "simplex-private-7-title": "Перевірка
цілісності повідомлення", - "simplex-private-9-title": "Односпрямовані
черги повідомлень", + "simplex-private-9-title": "Однобічні
черги повідомлень", "simplex-private-8-title": "Змішування повідомлень
для зменшення кореляції", "simplex-private-10-title": "Тимчасові анонімні парні ідентифікатори", - "simplex-private-card-1-point-1": "Протокол double-ratchet —
OTR messaging з ідеальною конфіденційністю та відновленням зламів.", - "simplex-private-card-1-point-2": "Криптобокс NaCL у кожній черзі для запобігання кореляції трафіку між чергами повідомлень, якщо TLS скомпрометовано.", - "simplex-private-card-2-point-1": "Додатковий рівень серверного шифрування для доставки одержувачу, щоб запобігти кореляції між отриманим і відправленим серверним трафіком, якщо TLS скомпрометовано.", - "simplex-private-card-3-point-1": "Для клієнт-серверних з'єднань використовується тільки TLS 1.2/1.3 з сильними алгоритмами.", - "simplex-private-card-3-point-2": "Відбитки пальців сервера та прив'язка каналів запобігають MITM-атакам та повторному відтворенню.", - "simplex-private-card-4-point-1": "Щоб захистити свою IP-адресу, ви можете отримати доступ до серверів через Tor або іншу транспортну мережу.", - "simplex-private-card-4-point-2": "Щоб використовувати SimpleX через Tor, установіть програму Orbot і ввімкніть проксі-сервер SOCKS5 (або VPN на iOS).", - "simplex-private-card-5-point-1": "SimpleX використовує заповнення вмісту для кожного рівня шифрування, щоб запобігти атакам на розмір повідомлення.", - "simplex-private-card-5-point-2": "Це дозволяє повідомленням різного розміру виглядати однаково для серверів і мережевих спостерігачів.", - "simplex-private-card-6-point-1": "Багато комунікаційних платформ вразливі до MITM-атак з боку серверів або мережевих провайдерів.", - "simplex-private-card-6-point-2": "Щоб запобігти цьому, програми SimpleX передають одноразові ключі поза смугою, коли ви надаєте адресу як посилання або QR-код.", - "simplex-private-card-7-point-2": "Якщо будь-яке повідомлення буде додано, видалено або змінено, одержувач отримає сповіщення.", - "simplex-private-card-8-point-1": "Сервери SimpleX працюють як вузли змішування з низькою затримкою - вхідні та вихідні повідомлення йдуть в різному порядку.", - "simplex-private-card-9-point-1": "Кожна черга повідомлень передає повідомлення в одному напрямку, з різними адресами відправлення та отримання.", - "simplex-private-card-9-point-2": "У порівнянні з традиційними брокерами повідомлень, він зменшує кількість векторів атак і доступних мета-даних.", - "simplex-private-card-10-point-1": "SimpleX використовує тимчасові анонімні попарні адреси та облікові дані для кожного контакту користувача або члена групи.", - "privacy-matters-1-title": "Реклама та цінова дискримінація", - "privacy-matters-1-overlay-1-title": "Конфіденційність економить ваші гроші", - "privacy-matters-1-overlay-1-linkText": "Конфіденційність економить ваші гроші", + "simplex-private-card-1-point-1": "Протокол подвійної рейки — OTR-повідомлення з ідеальною передачею секрету та відновленням злому.", + "simplex-private-card-1-point-2": "NaCL криптокоробка в кожній черзі для запобігання кореляції трафіку між чергами повідомлень у разі компрометації TLS.", + "simplex-private-card-2-point-1": "Додатковий рівень шифрування сервера для доставки отримувачу для запобігання кореляції між отриманим та відісланим трафіком сервера у разі компрометації TLS.", + "simplex-private-card-3-point-1": "Використовується лише TLS 1.2/1.3 із сильними алгоритмами для з'єднань клієнт-сервер.", + "simplex-private-card-3-point-2": "Відбиток сервера та зв'язування каналу запобігають MITM та атакам повтору.", + "simplex-private-card-4-point-1": "Для захисту вашої IP-адреси ви можете отримати доступ до серверів через Tor чи іншу транспортну оверлейну мережу.", + "simplex-private-card-4-point-2": "Для використання SimpleX через Tor, будь ласка, встановіть додаток Orbot та активуйте SOCKS5-проксі (або VPN на iOS).", + "simplex-private-card-5-point-1": "SimpleX використовує наповнення вмісту для кожного шару шифрування для ускладнення атак за розміром повідомлень.", + "simplex-private-card-5-point-2": "Це забезпечує, що повідомлення різних розмірів виглядають однаково для серверів та спостерігачів мережі.", + "simplex-private-card-6-point-1": "Багато комунікаційних платформ вразливі до MITM-атак серверів чи постачальників мережі.", + "simplex-private-card-6-point-2": "Щоб запобігти цьому, програми SimpleX передають одноразові ключі позаканально, коли ви ділитесь адресою як посиланням або QR-кодом.", + "simplex-private-card-7-point-2": "Якщо будь-яке повідомлення додається, вилучається чи змінюється, отримувач буде проінформований.", + "simplex-private-card-8-point-1": "Сервери SimpleX виступають як вузли низької затримки для змішування — вхідні та вихідні повідомлення мають різний порядок.", + "simplex-private-card-9-point-1": "Кожна черга повідомлень передає повідомлення в одному напрямку, з різними адресами для відправки та отримання.", + "simplex-private-card-9-point-2": "Це зменшує вектори атак порівняно із традиційними брокерами повідомлень та доступними метаданими.", + "simplex-private-card-10-point-1": "SimpleX використовує тимчасові анонімні парні адреси та облікові дані для кожного користувача, контакту чи учасника групи.", + "privacy-matters-1-title": "Реклама та дискримінація ціни", + "privacy-matters-1-overlay-1-title": "Конфіденційність зекономить вам гроші", + "privacy-matters-1-overlay-1-linkText": "Конфіденційність зекономить вам гроші", "privacy-matters-2-title": "Маніпулювання виборами", - "privacy-matters-2-overlay-1-title": "Конфіденційність дає вам силу", - "privacy-matters-3-title": "Переслідування через невинну асоціацію", + "privacy-matters-2-overlay-1-title": "Конфіденційність дає вам владу", + "privacy-matters-3-title": "Переслідування за невинним зв'язком", "privacy-matters-3-overlay-1-title": "Конфіденційність захищає вашу свободу", "privacy-matters-3-overlay-1-linkText": "Конфіденційність захищає вашу свободу", "simplex-unique-1-title": "Ви маєте повну конфіденційність", - "simplex-unique-1-overlay-1-title": "Повна конфіденційність вашої особи, профілю, контактів і метаданих", - "simplex-unique-2-title": "Ви захищені
від спаму та зловживань", + "simplex-unique-1-overlay-1-title": "Повна конфіденційність вашої ідентичності, профілю, контактів та метаданих", + "simplex-unique-2-title": "Вас захищено
від спаму та зловживань", "simplex-unique-2-overlay-1-title": "Найкращий захист від спаму та зловживань", "simplex-unique-3-title": "Ви контролюєте свої дані", - "simplex-unique-3-overlay-1-title": "Право власності, контроль та безпека ваших даних", - "simplex-unique-4-title": "Ви володієте мережею SimpleX", + "simplex-unique-3-overlay-1-title": "Власність, контроль та безпека ваших даних", + "simplex-unique-4-title": "Ви власник мережі SimpleX", "simplex-unique-4-overlay-1-title": "Повністю децентралізована — користувачі володіють мережею SimpleX", - "hero-overlay-card-1-p-1": "Багато користувачів запитували: якщо SimpleX не має ідентифікаторів користувачів, як він може знати, куди доставляти повідомлення?", - "hero-overlay-card-1-p-2": "Для доставки повідомлень замість ідентифікаторів користувачів, які використовуються всіма іншими платформами, SimpleX використовує тимчасові анонімні парні ідентифікатори черг повідомлень, окремі для кожного з ваших з'єднань — немає ніяких довгострокових ідентифікаторів.", - "hero-overlay-card-1-p-3": "Ви визначаєте, який сервер(и) використовувати для отримання повідомлень, ваші контакти — сервери, які ви використовуєте для надсилання їм повідомлень. У кожній розмові, швидше за все, будуть використовуватися два різних сервери.", - "hero-overlay-card-1-p-4": "Такий дизайн запобігає витоку будь-яких метаданих користувачів на рівні програми. Щоб ще більше підвищити конфіденційність і захистити свою IP-адресу, ви можете підключитися до серверів обміну повідомленнями через Tor.", - "hero-overlay-card-1-p-6": "Читайте більше в Пропонуємо ознайомитися з технічним документом SimpleX.", - "hero-overlay-card-2-p-2": "Потім вони могли співвіднести цю інформацію з існуючими публічними соціальними мережами і встановити деякі реальні особи.", - "hero-overlay-card-2-p-3": "Навіть у найбільш приватних додатках, які використовують сервіси Tor v3, якщо ви розмовляєте з двома різними контактами через один і той самий профіль, вони можуть довести, що пов'язані з однією і тією ж людиною.", - "hero-overlay-card-2-p-4": "SimpleX захищає від цих атак, не використовуючи жодних ідентифікаторів користувачів. А якщо ви використовуєте режим \"Інкогніто\", то для кожного контакту ви будете мати окреме ім'я для відображення, що дозволить уникнути обміну даними між ними.", - "simplex-network-overlay-card-1-p-1": "Протоколи та програми обміну повідомленнями P2P мають різні проблеми, які роблять їх менш надійними, ніж SimpleX, складнішими для аналізу та вразливими до кількох типів атак.", - "simplex-network-overlay-card-1-li-1": "Мережі P2P покладаються на певний варіант DHT для маршрутизації повідомлень. Дизайн DHT має балансувати між гарантією доставки та затримкою. SimpleX має кращу гарантію доставки і меншу затримку, ніж P2P, тому що повідомлення може бути передано через кілька серверів паралельно, використовуючи сервери, обрані одержувачем. У P2P-мережах повідомлення передається через O(log N) вузлів послідовно, використовуючи вузли, обрані алгоритмом.", - "simplex-network-overlay-card-1-li-2": "Дизайн SimpleX, на відміну від більшості мереж P2P, не має жодних глобальних ідентифікаторів користувачів, навіть тимчасових, а використовує тимчасові ідентифікатори лише парами, забезпечуючи кращу анонімність і захист метаданих.", - "privacy-matters-overlay-card-1-p-1": "Багато великих компаній використовують інформацію про те, з ким ви пов'язані, щоб оцінити ваш дохід, продати вам товари, які вам насправді не потрібні, і визначити ціни.", - "privacy-matters-overlay-card-3-p-3": "Звичайних людей заарештовують за те, чим вони діляться в Інтернеті, навіть через свої 'анонімні' облікові записи, навіть у демократичних країнах.", - "simplex-unique-overlay-card-1-p-2": "Для доставки повідомлень SimpleX використовує парні анонімні адреси односпрямованих черг повідомлень, окремо для отриманих і відправлених повідомлень, зазвичай через різні сервери. Використання SimpleX - це все одно, що мати різну “конфорку” електронну пошту або телефон для кожного контакту, і не мати клопоту з управлінням ними.", - "simplex-unique-overlay-card-1-p-3": "Такий дизайн захищає конфіденційність того, з ким ви спілкуєтеся, приховуючи її від серверів платформи SimpleX і від будь-яких спостерігачів. Щоб приховати свою IP-адресу від серверів, ви можете підключитися до серверів SimpleX через Tor.", - "simplex-unique-overlay-card-2-p-1": "Оскільки у вас немає ідентифікатора на платформі SimpleX, ніхто не може зв'язатися з вами, якщо ви не надасте одноразову або тимчасову адресу користувача у вигляді QR-коду або посилання.", - "simplex-unique-overlay-card-2-p-2": "Навіть якщо необов'язкова адреса користувача може бути використана для надсилання спам-повідомлень, ви можете змінити або повністю видалити її, не втрачаючи при цьому жодного з ваших зв'язків.", - "simplex-unique-overlay-card-3-p-1": "SimpleX Chat зберігає всі дані користувача лише на клієнтських пристроях за допомогою портативного формату зашифрованої бази даних, який можна експортувати та передавати на будь-який підтримуваний пристрій.", - "simplex-unique-overlay-card-3-p-2": "Наскрізні зашифровані повідомлення тимчасово зберігаються на релейних серверах SimpleX до моменту отримання, після чого вони назавжди видаляються.", - "simplex-unique-overlay-card-3-p-4": "Між відправленим і отриманим трафіком сервера немає спільних ідентифікаторів або зашифрованого тексту — якщо хтось спостерігає за ним, він не зможе легко визначити, хто з ким спілкується, навіть якщо TLS скомпрометований.", - "simplex-unique-overlay-card-4-p-1": "Ви можете використовувати SimpleX з власними серверами і при цьому спілкуватися з людьми, які використовують попередньо налаштовані сервери, надані нами.", - "simplex-unique-overlay-card-4-p-2": "Платформа SimpleX використовує відкритий протокол та надає SDK для створення чат-ботів, що дозволяє реалізовувати сервіси, з якими користувачі можуть взаємодіяти через додатки SimpleX Chat —. Ми'з нетерпінням чекаємо на те, які сервіси SimpleX ви можете створити.", - "simplex-unique-overlay-card-4-p-3": "Якщо ви розглядаєте можливість розробки для платформи SimpleX, наприклад, чат-бота для користувачів додатків SimpleX або інтеграції бібліотеки SimpleX Chat у ваші мобільні додатки, будь ласка, зв'яжіться з нами для отримання будь-якої консультації та підтримки.", - "simplex-unique-card-1-p-1": "SimpleX захищає конфіденційність вашого профілю, контактів і метаданих, приховуючи їх від серверів платформи SimpleX і будь-яких спостерігачів.", - "simplex-unique-card-1-p-2": "На відміну від будь-якої іншої існуючої платформи обміну повідомленнями, SimpleX не має ніяких ідентифікаторів, призначених користувачам — , навіть випадкових чисел.", - "simplex-unique-card-2-p-1": "Оскільки у вас немає ідентифікатора або фіксованої адреси на платформі SimpleX, ніхто не може зв'язатися з вами, якщо ви не надасте одноразову або тимчасову адресу користувача, наприклад, у вигляді QR-коду або посилання.", - "simplex-unique-card-3-p-1": "SimpleX зберігає всі дані користувача на клієнтських пристроях у портативному форматі зашифрованої бази даних —, його можна перенести на інший пристрій.", - "join": "Приєднуйтесь", - "we-invite-you-to-join-the-conversation": "Запрошуємо вас долучитися до розмови", + "hero-overlay-card-1-p-1": "Багато користувачів запитували: якщо у SimpleX немає ідентифікаторів користувачів, як він може знати, куди відправити повідомлення?", + "hero-overlay-card-1-p-2": "Для доставки повідомлень, замість ідентифікаторів користувачів, які використовують усі інші платформи, SimpleX використовує тимчасові анонімні парні ідентифікатори черг повідомлень, окремі для кожного вашого підключення — тут немає довгострокових ідентифікаторів.", + "hero-overlay-card-1-p-3": "Ви визначаєте, який(кі) сервер(и) використовувати для отримання повідомлень, ваші контакти — сервери, які ви використовуєте для відправки повідомлень їм. Кожна розмова, ймовірно, використовує два різних сервери.", + "hero-overlay-card-1-p-4": "Цей дизайн запобігає витоку метаданих будь-яких користувачів на рівні додатка. Для подальшого покращення конфіденційності та захисту вашої IP-адреси ви можете підключитися до серверів обміну повідомленнями через Tor.", + "hero-overlay-card-1-p-6": "Докладніше читайте у білетному запису SimpleX.", + "hero-overlay-card-2-p-2": "Вони можуть потім корелювати цю інформацію з існуючими громадськими соціальними мережами та визначати деякі реальні ідентифікатори.", + "hero-overlay-card-2-p-3": "Навіть з найбільш приватними додатками, які використовують служби Tor v3, якщо ви розмовляєте з двома різними контактами через той самий профіль, вони можуть довести, що вони підключені до однієї й тієї ж особи.", + "hero-overlay-card-2-p-4": "SimpleX захищає від цих атак, не маючи жодних ідентифікаторів користувачів в своєму дизайні. І, якщо ви використовуєте режим інкогніто, у вас буде різне відображення для кожного контакту, уникнення будь-яких спільних даних між ними.", + "simplex-network-overlay-card-1-p-1": "Протоколи та додатки для P2P-зв'язку мають різні проблеми, які роблять їх менш надійними порівняно із SimpleX, складнішими для аналізу та вразливими до кількох типів атак.", + "simplex-network-overlay-card-1-li-1": "P2P-мережі покладаються на якусь варіацію розподіленої хеш-таблиці (DHT) для маршрутизації повідомлень. Дизайни DHT повинні балансувати гарантію доставки та затримку. У SimpleX є як краща гарантія доставки, так і менша затримка порівняно із P2P, оскільки повідомлення може передаватися паралельно кількома серверами, використовуючи сервери, обрані отримувачем. У P2P-мережах повідомлення проходить через вузли O(log N) послідовно, використовуючи вузли, обрані алгоритмом.", + "simplex-network-overlay-card-1-li-2": "У дизайні SimpleX, на відміну від більшості P2P-мереж, немає жодних глобальних ідентифікаторів користувачів будь-якого виду, навіть тимчасових, та використовуються лише тимчасові парні ідентифікатори, що забезпечує кращу анонімність та захист метаданих.", + "privacy-matters-overlay-card-1-p-1": "Багато великих компаній використовують інформацію про те, з ким ви з'єднані, щоб оцінити ваш дохід, продавати вам продукти, які вам дійсно не потрібні, і визначати ціни.", + "privacy-matters-overlay-card-3-p-3": "Звичайних людей арештовують за те, що вони публікують онлайн, навіть через свої 'анонімні' облікові записи, навіть у демократичних країнах.", + "simplex-unique-overlay-card-1-p-2": "Для доставки повідомлень SimpleX використовує парні анонімні адреси однобічних черг повідомлень, окремо для отриманих та відправлених повідомлень, зазвичай через різні сервери. Використання SimpleX схоже на наявність різної “витратної” електронної пошти або телефону для кожного контакту, і немає неприємностей у їх управлінні.", + "simplex-unique-overlay-card-1-p-3": "Цей дизайн захищає конфіденційність осіб, з якими ви спілкуєтеся, приховуючи це від серверів платформи SimpleX та будь-яких спостерігачів. Щоб сховати свою IP-адресу від серверів, ви можете підключитися до серверів SimpleX через Tor.", + "simplex-unique-overlay-card-2-p-1": "Оскільки у вас немає ідентифікатора на платформі SimpleX, ніхто не може з вами зв'язатися, якщо ви не поділитеся одноразовою або тимчасовою адресою користувача, у вигляді QR-коду або посилання.", + "simplex-unique-overlay-card-2-p-2": "Навіть з необов'язковою адресою користувача, яка може бути використана для відправки спамових запитань на зв'язок, ви можете змінити або повністю видалити її, не втрачаючи жодного з ваших з'єднань.", + "simplex-unique-overlay-card-3-p-1": "SimpleX Chat зберігає всі дані користувачів лише на пристроях клієнтів за допомогою переносного зашифрованого формату бази даних, який можна експортувати і передавати на будь-який підтримуваний пристрій.", + "simplex-unique-overlay-card-3-p-2": "Зашифровані повідомлення від кінця до кінця тимчасово зберігаються на ретрансляційних серверах SimpleX до їх отримання, після чого вони назавжди видаляються.", + "simplex-unique-overlay-card-3-p-4": "Між надісланим і отриманим серверним трафіком немає спільних ідентифікаторів чи шифрованого тексту — якщо хтось його спостерігає, він не може легко визначити, хто спілкується з ким, навіть якщо TLS скомпрометовано.", + "simplex-unique-overlay-card-4-p-1": "Ви можете використовувати SimpleX з власними серверами і все одно спілкуватися з людьми, які використовують надані нам сервери заздалегідь налаштовані.", + "simplex-unique-overlay-card-4-p-2": "Платформа SimpleX використовує відкритий протокол та надає SDK для створення чат-ботів, що дозволяє впроваджувати сервіси, з якими користувачі можуть взаємодіяти через додатки SimpleX Chat — ми дійсно чекаємо, які сервіси SimpleX ви зможете побудувати.", + "simplex-unique-overlay-card-4-p-3": "Якщо ви розглядаєте можливість розробки для платформи SimpleX, наприклад, чат-бота для користувачів додатку SimpleX або інтеграції бібліотеки SimpleX Chat у свої мобільні додатки, будь ласка, зв'яжіться з нами для отримання порад та підтримки.", + "simplex-unique-card-1-p-1": "SimpleX захищає конфіденційність вашого профілю, контактів та метаданих, приховуючи їх від серверів платформи SimpleX та будь-яких спостерігачів.", + "simplex-unique-card-1-p-2": "На відміну від будь-якої іншої існуючої платформи обміну повідомленнями, SimpleX не має ідентифікаторів, призначених користувачам — навіть випадкових чисел.", + "simplex-unique-card-2-p-1": "Оскільки у вас немає ідентифікатора або фіксованої адреси на платформі SimpleX, ніхто не може з вами зв'язатися, якщо ви не поділитесь одноразовою або тимчасовою адресою користувача, як QR-код або посиланням.", + "simplex-unique-card-3-p-1": "SimpleX зберігає всі дані користувачів на пристроях клієнтів у переносному зашифрованому форматі бази даних — його можна передавати на інший пристрій.", + "join": "Приєднатися", + "we-invite-you-to-join-the-conversation": "Ми запрошуємо вас приєднатися до розмови", "join-the-REDDIT-community": "Приєднуйтесь до спільноти REDDIT", "join-us-on-GitHub": "Приєднуйтесь до нас на GitHub", "donate-here-to-help-us": "Пожертвуйте тут, щоб допомогти нам", - "sign-up-to-receive-our-updates": "Підпишіться на наші оновлення", - "enter-your-email-address": "Введіть адресу вашої електронної пошти", - "get-simplex": "Отримати SimpleX desktop app", - "why-simplex-is": "Чому SimpleX це", - "unique": "унікальний", - "learn-more": "Дізнайтеся більше", - "more-info": "Більше інформації", + "sign-up-to-receive-our-updates": "Підпишіться, щоб отримувати наші оновлення", + "enter-your-email-address": "Введіть свою електронну адресу", + "get-simplex": "Отримати SimpleX додаток для настільних комп'ютерів", + "why-simplex-is": "Чому SimpleX є", + "unique": "унікальним", + "learn-more": "Дізнатися більше", + "more-info": "Додаткова інформація", "hide-info": "Приховати інформацію", - "contact-hero-header": "Ви отримали адресу для підключення до чату SimpleX", - "invitation-hero-header": "Ви отримали одноразове посилання для підключення до чату SimpleX", - "contact-hero-subheader": "Відскануйте QR-код за допомогою програми SimpleX Chat на телефоні або планшеті.", + "contact-hero-header": "Ви отримали адресу для підключення в SimpleX Chat", + "invitation-hero-header": "Ви отримали 1-разове посилання для підключення в SimpleX Chat", + "contact-hero-subheader": "Скануйте QR-код за допомогою додатка SimpleX Chat на своєму телефоні чи планшеті.", "contact-hero-p-2": "Ще не завантажили SimpleX Chat?", - "contact-hero-p-3": "Щоб завантажити додаток, скористайтеся посиланнями нижче.", - "connect-in-app": "Підключіться в додатку", - "open-simplex-app": "Відкрийте програму Simplex", - "tap-the-connect-button-in-the-app": "Натисніть кнопку ‘підключитися‘ у додатку", - "scan-the-qr-code-with-the-simplex-chat-app": "Відскануйте QR-код за допомогою програми SimpleX Chat", - "scan-the-qr-code-with-the-simplex-chat-app-description": "Відкриті ключі та адреса черги повідомлень за цим посиланням НЕ передаються мережею при перегляді цієї сторінки —
вони містяться в хеш-фрагменті URL-адреси посилання.", - "installing-simplex-chat-to-terminal": "Встановлення чату SimpleX на термінал", - "use-this-command": "Використовуй цю команду:", - "see-simplex-chat": "Дивіться Чат SimpleX", - "the-instructions--source-code": "інструкції, як завантажити або скомпілювати його з вихідного коду.", + "contact-hero-p-3": "Скористайтеся посиланнями нижче, щоб завантажити додаток.", + "connect-in-app": "Підключитися в додатку", + "open-simplex-app": "Відкрити додаток SimpleX", + "tap-the-connect-button-in-the-app": "Торкніться кнопки ‘підключити’ в додатку", + "scan-the-qr-code-with-the-simplex-chat-app": "Скануйте QR-код за допомогою додатка SimpleX Chat", + "scan-the-qr-code-with-the-simplex-chat-app-description": "Публічні ключі та адреса черги повідомлень в цьому посиланні НЕ відправляються по мережі під час перегляду цієї сторінки —
вони містяться в хеш-фрагменті URL-посилання.", + "installing-simplex-chat-to-terminal": "Встановлення SimpleX Chat для терміналу", + "use-this-command": "Використовуйте цю команду:", + "see-simplex-chat": "Дивіться SimpleX Chat", + "the-instructions--source-code": "інструкції з того, як його завантажити чи скомпілювати з вихідного коду.", "if-you-already-installed-simplex-chat-for-the-terminal": "Якщо ви вже встановили SimpleX Chat для терміналу", "if-you-already-installed": "Якщо ви вже встановили", "simplex-chat-for-the-terminal": "SimpleX Chat для терміналу", - "copy-the-command-below-text": "скопіюйте команду нижче і використовуйте її в чаті:", + "copy-the-command-below-text": "скопіюйте команду нижче та використовуйте її в чаті:", "privacy-matters-section-header": "Чому конфіденційність має значення", - "privacy-matters-section-subheader": "Збереження конфіденційності ваших метаданих — від кого ви спілкуєтеся — захищає вас:", - "privacy-matters-section-label": "Переконайтеся, що ваш месенджер не може отримати доступ до ваших даних!", - "simplex-private-section-header": "Що робить SimpleX приватним", - "tap-to-close": "Натисніть, щоб закрити", - "simplex-network-section-header": "SimpleX Мережа", - "simplex-network-section-desc": "Simplex Chat забезпечує найкращу конфіденційність, поєднуючи переваги P2P та об'єднаних мереж.", - "simplex-network-1-desc": "Всі повідомлення надсилаються через сервери, що забезпечує кращу конфіденційність метаданих і надійну асинхронну доставку повідомлень, уникаючи при цьому багатьох", - "simplex-network-1-header": "На відміну від P2P-мереж", - "simplex-network-1-overlay-linktext": "проблеми P2P-мереж", - "simplex-network-2-header": "На відміну від об'єднаних мереж", - "simplex-network-2-desc": "Сервери ретрансляції SimpleX НЕ зберігають профілі користувачів, контакти та доставлені повідомлення, НЕ з'єднуються один з одним і НЕ мають каталогу серверів.", + "privacy-matters-section-subheader": "Збереження конфіденційності ваших метаданих — з ким ви спілкуєтеся — захищає вас від:", + "privacy-matters-section-label": "Переконайтеся, що ваш месенджер не має доступу до ваших даних!", + "simplex-private-section-header": "Що робить SimpleX конфіденційним", + "tap-to-close": "Торкніться, щоб закрити", + "simplex-network-section-header": "SimpleX Network", + "simplex-network-section-desc": "Simplex Chat надає найкращу конфіденційність, поєднуючи переваги P2P та федеративних мереж.", + "simplex-network-1-desc": "Всі повідомлення відправляються через сервери, що забезпечує кращу конфіденційність метаданих та надійну асинхронну доставку повідомлень, уникаючи багатьох", + "simplex-network-1-header": "На відміну від мереж P2P", + "simplex-network-1-overlay-linktext": "проблем P2P-мереж", + "simplex-network-2-header": "На відміну від федеративних мереж", + "simplex-network-2-desc": "Сервери SimpleX Chat НЕ зберігають профілі користувачів, контакти та доставлені повідомлення, НЕ підключаються один до одного, і НЕ існує каталог серверів.", "simplex-network-3-header": "Мережа SimpleX", - "simplex-network-3-desc": "Сервери надають односпрямовані черги для підключення користувачів, але вони не мають видимості графу мережевих з'єднань —, його бачать лише користувачі.", + "simplex-network-3-desc": "сервери надають однобічні черги для з'єднання користувачів, але вони не мають видимості графа підключень в мережі — лише користувачі.", "comparison-section-header": "Порівняння з іншими протоколами", - "protocol-1-text": "Сигнал, великі платформи", - "protocol-2-text": "XMPP, Матрикс", + "protocol-1-text": "Signal, великі платформи", + "protocol-2-text": "XMPP, Matrix", "protocol-3-text": "Протоколи P2P", - "comparison-point-1-text": "Вимагає глобальної ідентичності", + "comparison-point-1-text": "Потребує глобального ідентифікатора", "comparison-point-2-text": "Можливість MITM", "comparison-point-3-text": "Залежність від DNS", - "comparison-point-4-text": "Окрема або централізована мережа", - "comparison-point-5-text": "Атака на центральний компонент або інша мережева атака", + "comparison-point-4-text": "Одна чи централізована мережа", + "comparison-point-5-text": "Центральний компонент чи інша атака на всю мережу", "yes": "Так", "no": "Ні", - "no-private": "Ні - приватний", + "no-private": "Ні - конфіденційно", "no-secure": "Ні - безпечно", - "no-resilient": "Ні - стійкий", + "no-resilient": "Ні - стійко", "no-decentralized": "Ні - децентралізовано", - "comparison-section-list-point-4": "Якщо сервери оператора скомпрометовані", - "comparison-section-list-point-5": "Не захищає метадані користувачів", - "comparison-section-list-point-6": "Хоча P2P розподілені, вони не об'єднані - вони працюють як єдина мережа", + "comparison-section-list-point-4": "Якщо сервери оператора порушені. Перевірте безпековий код в Signal та деяких інших додатках для зменшення ризику", + "comparison-section-list-point-5": "Не захищає конфіденційність метаданих користувачів", + "comparison-section-list-point-6": "Хоча P2P є розподіленими, вони не є федеративними - вони працюють як єдина мережа", "guide-dropdown-1": "Швидкий старт", - "guide-dropdown-2": "Надсилання повідомлень", + "guide-dropdown-2": "Відправлення повідомлень", "guide-dropdown-3": "Таємні групи", "glossary": "Глосарій", "docs-dropdown-8": "Служба каталогів SimpleX", - "f-droid-page-simplex-chat-repo-section-text": "Щоб додати його в клієнт F-Droid відскануйте QR-код або використовуйте цю URL-адресу:", + "f-droid-page-simplex-chat-repo-section-text": "Щоб додати його до свого клієнта F-Droid, скануйте QR-код або використовуйте цей URL:", "simplex-chat-via-f-droid": "SimpleX Chat через F-Droid", - "signing-key-fingerprint": "Відбиток ключа підпису (SHA-256)", - "stable-versions-built-by-f-droid-org": "Стабільні версії, зібрані на F-Droid.org", - "simplex-chat-repo": "Репо SimpleX Chat", - "f-droid-org-repo": "Репо F-Droid.org", - "releases-to-this-repo-are-done-1-2-days-later": "Релізи в це репо відбуваються на 1-2 дні пізніше", - "stable-and-beta-versions-built-by-developers": "Стабільні та бета-версії, створені розробниками", - "f-droid-page-f-droid-org-repo-section-text": "Репозиторії SimpleX Chat та F-Droid.org підписують збірки з різними ключами. Щоб перемикнутися, будь ласка експорт базу даних чату та перевстановіть додаток." + "signing-key-fingerprint": "Відбиток підпису ключа (SHA-256)", + "stable-versions-built-by-f-droid-org": "Стабільні версії, побудовані F-Droid.org", + "simplex-chat-repo": "Репозитарій SimpleX Chat", + "f-droid-org-repo": "Репозитарій F-Droid.org", + "releases-to-this-repo-are-done-1-2-days-later": "Релізи в цей репозитарій робляться за 1-2 дні пізніше", + "stable-and-beta-versions-built-by-developers": "Стабільні та бета-версії, побудовані розробниками", + "f-droid-page-f-droid-org-repo-section-text": "SimpleX Chat та репозитарії F-Droid.org підписують збірки різними ключами. Щоб переключитися, будь ласка, експортуйте базу даних чату та перевстановіть додаток.", + "hero-overlay-3-title": "Оцінка безпеки", + "hero-overlay-card-3-p-2": "Trail of Bits переглянувало криптографію та компоненти мережі платформи SimpleX у листопаді 2022 року.", + "hero-overlay-card-3-p-3": "Читайте більше в оголошенні.", + "jobs": "Приєднатися до команди", + "hero-overlay-3-textlink": "Оцінка безпеки", + "hero-overlay-card-3-p-1": "Trail of Bits є провідною консалтинговою фірмою з безпеки та технологій, клієнтами якої є великі технологічні компанії, урядові агенції та великі проекти у сфері блокчейну.", + "comparison-section-list-point-4a": "Ретранслятори SimpleX не можуть порушити e2e-шифрування. Перевірте безпековий код для зменшення ризику атаки на зовнішньобандовий канал", + "docs-dropdown-9": "Завантаження" } \ No newline at end of file From 2bacc00a062b1cb255ceca9b6a410439f317d6fb Mon Sep 17 00:00:00 2001 From: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com> Date: Fri, 29 Dec 2023 16:29:49 +0400 Subject: [PATCH 006/102] ios: rework UX of creating new connection (#3482) * ios: connection UI (wip) * custom search * rework invite * connect paste link ui * scan rework, process errors, other fixes * scan layout * clear link on cancel * improved search * further improve search * animation * connect on paste in search * layout * layout * layout * layout, add conn * delete unused invitation, create used invitation chat * remove old views * regular paste button * new chat menu * previews * increase spacing * animation, fix alerts * swipe * change text * less sensitive gesture * layout * search cancel button transition * slow down chat list animation (uses deprecated modifiers) * icons * update code scanner, layout * manage camera permissions * ask to delete unused invitation * comment * remove onDismiss * don't filter chats on link in search, allow to paste text with link * cleanup link after connection * filter chat by link * revert change * show link descr * disabled search * underline * filter own group * simplify * no animation * add delay, move createInvitation * update library * possible fix for ios 15 * add explicit frame to qr code * update library * Revert "add explicit frame to qr code" This reverts commit 95c7d31e47b3da39b5985cd57638885c45b77de1. * remove comment * fix pasteboardHasURLs, disable paste button based on it * align help texts with changed button names Co-authored-by: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> * update library * Revert "fix pasteboardHasURLs, disable paste button based on it" This reverts commit 46f63572e90dbf460faab9ce694181209712bd00. * remove unused var * restore disabled * export localizations --------- Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Co-authored-by: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> --- apps/ios/Shared/AppDelegate.swift | 5 + apps/ios/Shared/Model/ChatModel.swift | 20 +- apps/ios/Shared/Model/SimpleXAPI.swift | 10 +- .../Views/Chat/ChatItem/MsgContentView.swift | 4 +- apps/ios/Shared/Views/Chat/ChatView.swift | 8 +- apps/ios/Shared/Views/ChatList/ChatHelp.swift | 9 +- .../Shared/Views/ChatList/ChatListView.swift | 181 +++- .../ChatList/ContactConnectionInfo.swift | 22 + .../Views/NewChat/AddContactLearnMore.swift | 14 +- .../Shared/Views/NewChat/AddContactView.swift | 129 --- .../Views/NewChat/ConnectViaLinkView.swift | 42 - .../Shared/Views/NewChat/CreateLinkView.swift | 94 -- .../Shared/Views/NewChat/NewChatButton.swift | 466 --------- .../Views/NewChat/NewChatMenuButton.swift | 52 + .../Shared/Views/NewChat/NewChatView.swift | 959 ++++++++++++++++++ .../Views/NewChat/PasteToConnectView.swift | 106 -- apps/ios/Shared/Views/NewChat/QRCode.swift | 5 +- .../Views/NewChat/ScanToConnectView.swift | 79 -- .../Views/UserSettings/IncognitoHelp.swift | 23 +- .../Views/UserSettings/SettingsView.swift | 6 + .../bg.xcloc/Localized Contents/bg.xliff | 153 +-- .../cs.xcloc/Localized Contents/cs.xliff | 153 +-- .../de.xcloc/Localized Contents/de.xliff | 153 +-- .../en.xcloc/Localized Contents/en.xliff | 178 ++-- .../es.xcloc/Localized Contents/es.xliff | 153 +-- .../fi.xcloc/Localized Contents/fi.xliff | 153 +-- .../fr.xcloc/Localized Contents/fr.xliff | 153 +-- .../it.xcloc/Localized Contents/it.xliff | 153 +-- .../ja.xcloc/Localized Contents/ja.xliff | 153 +-- .../nl.xcloc/Localized Contents/nl.xliff | 153 +-- .../pl.xcloc/Localized Contents/pl.xliff | 153 +-- .../ru.xcloc/Localized Contents/ru.xliff | 153 +-- .../th.xcloc/Localized Contents/th.xliff | 152 +-- .../uk.xcloc/Localized Contents/uk.xliff | 153 +-- .../Localized Contents/zh-Hans.xliff | 153 +-- apps/ios/SimpleX.xcodeproj/project.pbxproj | 42 +- apps/ios/SimpleXChat/ChatTypes.swift | 9 + 37 files changed, 2722 insertions(+), 1882 deletions(-) delete mode 100644 apps/ios/Shared/Views/NewChat/AddContactView.swift delete mode 100644 apps/ios/Shared/Views/NewChat/ConnectViaLinkView.swift delete mode 100644 apps/ios/Shared/Views/NewChat/CreateLinkView.swift delete mode 100644 apps/ios/Shared/Views/NewChat/NewChatButton.swift create mode 100644 apps/ios/Shared/Views/NewChat/NewChatMenuButton.swift create mode 100644 apps/ios/Shared/Views/NewChat/NewChatView.swift delete mode 100644 apps/ios/Shared/Views/NewChat/PasteToConnectView.swift delete mode 100644 apps/ios/Shared/Views/NewChat/ScanToConnectView.swift diff --git a/apps/ios/Shared/AppDelegate.swift b/apps/ios/Shared/AppDelegate.swift index 145e362797..24c0eeb605 100644 --- a/apps/ios/Shared/AppDelegate.swift +++ b/apps/ios/Shared/AppDelegate.swift @@ -15,6 +15,7 @@ class AppDelegate: NSObject, UIApplicationDelegate { logger.debug("AppDelegate: didFinishLaunchingWithOptions") application.registerForRemoteNotifications() if #available(iOS 17.0, *) { trackKeyboard() } + NotificationCenter.default.addObserver(self, selector: #selector(pasteboardChanged), name: UIPasteboard.changedNotification, object: nil) return true } @@ -36,6 +37,10 @@ class AppDelegate: NSObject, UIApplicationDelegate { ChatModel.shared.keyboardHeight = 0 } + @objc func pasteboardChanged() { + ChatModel.shared.pasteboardHasStrings = UIPasteboard.general.hasStrings + } + func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { let token = deviceToken.map { String(format: "%02hhx", $0) }.joined() logger.debug("AppDelegate: didRegisterForRemoteNotificationsWithDeviceToken \(token)") diff --git a/apps/ios/Shared/Model/ChatModel.swift b/apps/ios/Shared/Model/ChatModel.swift index 0cc281fda9..db0f138690 100644 --- a/apps/ios/Shared/Model/ChatModel.swift +++ b/apps/ios/Shared/Model/ChatModel.swift @@ -89,14 +89,15 @@ final class ChatModel: ObservableObject { @Published var showCallView = false // remote desktop @Published var remoteCtrlSession: RemoteCtrlSession? - // currently showing QR code - @Published var connReqInv: String? + // currently showing invitation + @Published var showingInvitation: ShowingInvitation? // audio recording and playback @Published var stopPreviousRecPlay: URL? = nil // coordinates currently playing source @Published var draft: ComposeState? @Published var draftChatId: String? // tracks keyboard height via subscription in AppDelegate @Published var keyboardHeight: CGFloat = 0 + @Published var pasteboardHasStrings: Bool = UIPasteboard.general.hasStrings var messageDelivery: Dictionary Void> = [:] @@ -620,14 +621,16 @@ final class ChatModel: ObservableObject { } func dismissConnReqView(_ id: String) { - if let connReqInv = connReqInv, - let c = getChat(id), - case let .contactConnection(contactConnection) = c.chatInfo, - connReqInv == contactConnection.connReqInv { + if id == showingInvitation?.connId { + markShowingInvitationUsed() dismissAllSheets() } } + func markShowingInvitationUsed() { + showingInvitation?.connChatUsed = true + } + func removeChat(_ id: String) { withAnimation { chats.removeAll(where: { $0.id == id }) @@ -704,6 +707,11 @@ final class ChatModel: ObservableObject { } } +struct ShowingInvitation { + var connId: String + var connChatUsed: Bool +} + struct NTFContactRequest { var incognito: Bool var chatId: String diff --git a/apps/ios/Shared/Model/SimpleXAPI.swift b/apps/ios/Shared/Model/SimpleXAPI.swift index eff3110962..ddac78c3da 100644 --- a/apps/ios/Shared/Model/SimpleXAPI.swift +++ b/apps/ios/Shared/Model/SimpleXAPI.swift @@ -581,15 +581,15 @@ func apiVerifyGroupMember(_ groupId: Int64, _ groupMemberId: Int64, connectionCo return nil } -func apiAddContact(incognito: Bool) async -> (String, PendingContactConnection)? { +func apiAddContact(incognito: Bool) async -> ((String, PendingContactConnection)?, Alert?) { guard let userId = ChatModel.shared.currentUser?.userId else { logger.error("apiAddContact: no current user") - return nil + return (nil, nil) } let r = await chatSendCmd(.apiAddContact(userId: userId, incognito: incognito), bgTask: false) - if case let .invitation(_, connReqInvitation, connection) = r { return (connReqInvitation, connection) } - AlertManager.shared.showAlert(connectionErrorAlert(r)) - return nil + if case let .invitation(_, connReqInvitation, connection) = r { return ((connReqInvitation, connection), nil) } + let alert = connectionErrorAlert(r) + return (nil, alert) } func apiSetConnectionIncognito(connId: Int64, incognito: Bool) async throws -> PendingContactConnection? { diff --git a/apps/ios/Shared/Views/Chat/ChatItem/MsgContentView.swift b/apps/ios/Shared/Views/Chat/ChatItem/MsgContentView.swift index d0d2bdf3dd..cad6401cc0 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/MsgContentView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/MsgContentView.swift @@ -9,7 +9,7 @@ import SwiftUI import SimpleXChat -private let uiLinkColor = UIColor(red: 0, green: 0.533, blue: 1, alpha: 1) +let uiLinkColor = UIColor(red: 0, green: 0.533, blue: 1, alpha: 1) private let noTyping = Text(" ") @@ -144,7 +144,7 @@ private func linkText(_ s: String, _ link: String, _ preview: Bool, prefix: Stri ]))).underline() } -private func simplexLinkText(_ linkType: SimplexLinkType, _ smpHosts: [String]) -> String { +func simplexLinkText(_ linkType: SimplexLinkType, _ smpHosts: [String]) -> String { linkType.description + " " + "(via \(smpHosts.first ?? "?"))" } diff --git a/apps/ios/Shared/Views/Chat/ChatView.swift b/apps/ios/Shared/Views/Chat/ChatView.swift index 6e2c0c1555..a09c5643b6 100644 --- a/apps/ios/Shared/Views/Chat/ChatView.swift +++ b/apps/ios/Shared/Views/Chat/ChatView.swift @@ -250,8 +250,8 @@ struct ChatView: View { } private func searchToolbar() -> some View { - HStack { - HStack { + HStack(spacing: 12) { + HStack(spacing: 4) { Image(systemName: "magnifyingglass") TextField("Search", text: $searchText) .focused($searchFocussed) @@ -264,9 +264,9 @@ struct ChatView: View { Image(systemName: "xmark.circle.fill").opacity(searchText == "" ? 0 : 1) } } - .padding(EdgeInsets(top: 8, leading: 6, bottom: 8, trailing: 6)) + .padding(EdgeInsets(top: 7, leading: 7, bottom: 7, trailing: 7)) .foregroundColor(.secondary) - .background(Color(.secondarySystemBackground)) + .background(Color(.tertiarySystemFill)) .cornerRadius(10.0) Button ("Cancel") { diff --git a/apps/ios/Shared/Views/ChatList/ChatHelp.swift b/apps/ios/Shared/Views/ChatList/ChatHelp.swift index 7741512432..2435c9a4f5 100644 --- a/apps/ios/Shared/Views/ChatList/ChatHelp.swift +++ b/apps/ios/Shared/Views/ChatList/ChatHelp.swift @@ -11,7 +11,7 @@ import SwiftUI struct ChatHelp: View { @EnvironmentObject var chatModel: ChatModel @Binding var showSettings: Bool - @State private var showAddChat = false + @State private var newChatMenuOption: NewChatMenuOption? = nil var body: some View { ScrollView { chatHelp() } @@ -39,13 +39,12 @@ struct ChatHelp: View { HStack(spacing: 8) { Text("Tap button ") - NewChatButton(showAddChat: $showAddChat) + NewChatMenuButton(newChatMenuOption: $newChatMenuOption) Text("above, then choose:") } - Text("**Create link / QR code** for your contact to use.") - Text("**Paste received link** or open it in the browser and tap **Open in mobile app**.") - Text("**Scan QR code**: to connect to your contact in person or via video call.") + Text("**Add contact**: to create a new invitation link, or connect via a link you received.") + Text("**Create group**: to create a new group.") } .padding(.top, 24) diff --git a/apps/ios/Shared/Views/ChatList/ChatListView.swift b/apps/ios/Shared/Views/ChatList/ChatListView.swift index 1d86733206..3d0551de66 100644 --- a/apps/ios/Shared/Views/ChatList/ChatListView.swift +++ b/apps/ios/Shared/Views/ChatList/ChatListView.swift @@ -12,8 +12,12 @@ import SimpleXChat struct ChatListView: View { @EnvironmentObject var chatModel: ChatModel @Binding var showSettings: Bool + @State private var searchMode = false + @FocusState private var searchFocussed @State private var searchText = "" - @State private var showAddChat = false + @State private var searchShowingSimplexLink = false + @State private var searchChatFilteredBySimplexLink: String? = nil + @State private var newChatMenuOption: NewChatMenuOption? = nil @State private var userPickerVisible = false @State private var showConnectDesktop = false @AppStorage(DEFAULT_SHOW_UNREAD_AND_FAVORITES) private var showUnreadAndFavorites = false @@ -62,11 +66,7 @@ struct ChatListView: View { private var chatListView: some View { VStack { - if chatModel.chats.count > 0 { - chatList.searchable(text: $searchText) - } else { - chatList - } + chatList } .onDisappear() { withAnimation { userPickerVisible = false } } .refreshable { @@ -85,9 +85,9 @@ struct ChatListView: View { secondaryButton: .cancel() )) } - .offset(x: -8) .listStyle(.plain) .navigationBarTitleDisplayMode(.inline) + .navigationBarHidden(searchMode) .toolbar { ToolbarItem(placement: .navigationBarLeading) { let user = chatModel.currentUser ?? User.sampleData @@ -124,7 +124,7 @@ struct ChatListView: View { } ToolbarItem(placement: .navigationBarTrailing) { switch chatModel.chatRunning { - case .some(true): NewChatButton(showAddChat: $showAddChat) + case .some(true): NewChatMenuButton(newChatMenuOption: $newChatMenuOption) case .some(false): chatStoppedIcon() case .none: EmptyView() } @@ -144,11 +144,25 @@ struct ChatListView: View { @ViewBuilder private var chatList: some View { let cs = filteredChats() ZStack { - List { - ForEach(cs, id: \.viewId) { chat in - ChatListNavLink(chat: chat) - .padding(.trailing, -16) - .disabled(chatModel.chatRunning != true) + VStack { + List { + if !chatModel.chats.isEmpty { + ChatListSearchBar( + searchMode: $searchMode, + searchFocussed: $searchFocussed, + searchText: $searchText, + searchShowingSimplexLink: $searchShowingSimplexLink, + searchChatFilteredBySimplexLink: $searchChatFilteredBySimplexLink + ) + .listRowSeparator(.hidden) + .frame(maxWidth: .infinity) + } + ForEach(cs, id: \.viewId) { chat in + ChatListNavLink(chat: chat) + .padding(.trailing, -16) + .disabled(chatModel.chatRunning != true) + } + .offset(x: -8) } } .onChange(of: chatModel.chatId) { _ in @@ -182,7 +196,7 @@ struct ChatListView: View { .padding(.trailing, 12) connectButton("Tap to start a new chat") { - showAddChat = true + newChatMenuOption = .newContact } Spacer() @@ -214,22 +228,25 @@ struct ChatListView: View { } private func filteredChats() -> [Chat] { - let s = searchText.trimmingCharacters(in: .whitespaces).localizedLowercase - return s == "" && !showUnreadAndFavorites + if let linkChatId = searchChatFilteredBySimplexLink { + return chatModel.chats.filter { $0.id == linkChatId } + } else { + let s = searchString() + return s == "" && !showUnreadAndFavorites ? chatModel.chats : chatModel.chats.filter { chat in let cInfo = chat.chatInfo switch cInfo { case let .direct(contact): return s == "" - ? filtered(chat) - : (viewNameContains(cInfo, s) || - contact.profile.displayName.localizedLowercase.contains(s) || - contact.fullName.localizedLowercase.contains(s)) + ? filtered(chat) + : (viewNameContains(cInfo, s) || + contact.profile.displayName.localizedLowercase.contains(s) || + contact.fullName.localizedLowercase.contains(s)) case let .group(gInfo): return s == "" - ? (filtered(chat) || gInfo.membership.memberStatus == .memInvited) - : viewNameContains(cInfo, s) + ? (filtered(chat) || gInfo.membership.memberStatus == .memInvited) + : viewNameContains(cInfo, s) case .contactRequest: return s == "" || viewNameContains(cInfo, s) case let .contactConnection(conn): @@ -238,6 +255,11 @@ struct ChatListView: View { return false } } + } + + func searchString() -> String { + searchShowingSimplexLink ? "" : searchText.trimmingCharacters(in: .whitespaces).localizedLowercase + } func filtered(_ chat: Chat) -> Bool { (chat.chatInfo.chatSettings?.favorite ?? false) || chat.chatStats.unreadCount > 0 || chat.chatStats.unreadChat @@ -249,6 +271,121 @@ struct ChatListView: View { } } +struct ChatListSearchBar: View { + @EnvironmentObject var m: ChatModel + @Binding var searchMode: Bool + @FocusState.Binding var searchFocussed: Bool + @Binding var searchText: String + @Binding var searchShowingSimplexLink: Bool + @Binding var searchChatFilteredBySimplexLink: String? + @State private var ignoreSearchTextChange = false + @State private var showScanCodeSheet = false + @State private var alert: PlanAndConnectAlert? + @State private var sheet: PlanAndConnectActionSheet? + + var body: some View { + VStack(spacing: 12) { + HStack(spacing: 12) { + HStack(spacing: 4) { + Image(systemName: "magnifyingglass") + TextField("Search or paste SimpleX link", text: $searchText) + .disabled(searchShowingSimplexLink) + .focused($searchFocussed) + .frame(maxWidth: .infinity) + if searchFocussed || searchShowingSimplexLink { + Image(systemName: "xmark.circle.fill") + .opacity(searchText == "" ? 0 : 1) + .onTapGesture { + searchText = "" + } + } else if searchText == "" { + HStack(spacing: 24) { + if m.pasteboardHasStrings { + Image(systemName: "doc") + .onTapGesture { + if let str = UIPasteboard.general.string { + searchText = str + } + } + } + + Image(systemName: "qrcode") + .resizable() + .scaledToFit() + .frame(width: 20, height: 20) + .onTapGesture { + showScanCodeSheet = true + } + } + .padding(.trailing, 2) + } + } + .padding(EdgeInsets(top: 7, leading: 7, bottom: 7, trailing: 7)) + .foregroundColor(.secondary) + .background(Color(.tertiarySystemFill)) + .cornerRadius(10.0) + + if searchFocussed { + Text("Cancel") + .foregroundColor(.accentColor) + .onTapGesture { + searchText = "" + searchFocussed = false + } + } + } + Divider() + } + .sheet(isPresented: $showScanCodeSheet) { + NewChatView(selection: .connect, showQRCodeScanner: true) + .environment(\EnvironmentValues.refresh as! WritableKeyPath, nil) // fixes .refreshable in ChatListView affecting nested view + } + .onChange(of: searchFocussed) { sf in + withAnimation { searchMode = sf } + } + .onChange(of: searchText) { t in + if ignoreSearchTextChange { + ignoreSearchTextChange = false + } else { + if let link = strHasSingleSimplexLink(t.trimmingCharacters(in: .whitespaces)) { // if SimpleX link is pasted, show connection dialogue + searchFocussed = false + if case let .simplexLink(linkType, _, smpHosts) = link.format { + ignoreSearchTextChange = true + searchText = simplexLinkText(linkType, smpHosts) + } + searchShowingSimplexLink = true + searchChatFilteredBySimplexLink = nil + connect(link.text) + } else { + if t != "" { // if some other text is pasted, enter search mode + searchFocussed = true + } + searchShowingSimplexLink = false + searchChatFilteredBySimplexLink = nil + } + } + } + .alert(item: $alert) { a in + planAndConnectAlert(a, dismiss: true, cleanup: { searchText = "" }) + } + .actionSheet(item: $sheet) { s in + planAndConnectActionSheet(s, dismiss: true, cleanup: { searchText = "" }) + } + } + + private func connect(_ link: String) { + planAndConnect( + link, + showAlert: { alert = $0 }, + showActionSheet: { sheet = $0 }, + dismiss: false, + incognito: nil, + filterKnownContact: { searchChatFilteredBySimplexLink = $0.id }, + filterKnownGroup: { searchChatFilteredBySimplexLink = $0.id } + ) + } +} + func chatStoppedIcon() -> some View { Button { AlertManager.shared.showAlertMsg( diff --git a/apps/ios/Shared/Views/ChatList/ContactConnectionInfo.swift b/apps/ios/Shared/Views/ChatList/ContactConnectionInfo.swift index 6d2fba99c6..42e90232d6 100644 --- a/apps/ios/Shared/Views/ChatList/ContactConnectionInfo.swift +++ b/apps/ios/Shared/Views/ChatList/ContactConnectionInfo.swift @@ -164,6 +164,28 @@ struct ContactConnectionInfo: View { } } +private func shareLinkButton(_ connReqInvitation: String) -> some View { + Button { + showShareSheet(items: [simplexChatLink(connReqInvitation)]) + } label: { + settingsRow("square.and.arrow.up") { + Text("Share 1-time link") + } + } +} + +private func oneTimeLinkLearnMoreButton() -> some View { + NavigationLink { + AddContactLearnMore(showTitle: false) + .navigationTitle("One-time invitation link") + .navigationBarTitleDisplayMode(.large) + } label: { + settingsRow("info.circle") { + Text("Learn more") + } + } +} + struct ContactConnectionInfo_Previews: PreviewProvider { static var previews: some View { ContactConnectionInfo(contactConnection: PendingContactConnection.getSampleData()) diff --git a/apps/ios/Shared/Views/NewChat/AddContactLearnMore.swift b/apps/ios/Shared/Views/NewChat/AddContactLearnMore.swift index 182149cbde..45eb783326 100644 --- a/apps/ios/Shared/Views/NewChat/AddContactLearnMore.swift +++ b/apps/ios/Shared/Views/NewChat/AddContactLearnMore.swift @@ -9,8 +9,20 @@ import SwiftUI struct AddContactLearnMore: View { + var showTitle: Bool + var body: some View { List { + if showTitle { + Text("One-time invitation link") + .font(.largeTitle) + .bold() + .fixedSize(horizontal: false, vertical: true) + .padding(.vertical) + .listRowBackground(Color.clear) + .listRowSeparator(.hidden) + .listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0)) + } VStack(alignment: .leading, spacing: 18) { Text("To connect, your contact can scan QR code or use the link in the app.") Text("If you can't meet in person, show QR code in a video call, or share the link.") @@ -23,6 +35,6 @@ struct AddContactLearnMore: View { struct AddContactLearnMore_Previews: PreviewProvider { static var previews: some View { - AddContactLearnMore() + AddContactLearnMore(showTitle: true) } } diff --git a/apps/ios/Shared/Views/NewChat/AddContactView.swift b/apps/ios/Shared/Views/NewChat/AddContactView.swift deleted file mode 100644 index de8e35d2a6..0000000000 --- a/apps/ios/Shared/Views/NewChat/AddContactView.swift +++ /dev/null @@ -1,129 +0,0 @@ -// -// AddContactView.swift -// SimpleX -// -// Created by Evgeny Poberezkin on 29/01/2022. -// Copyright © 2022 SimpleX Chat. All rights reserved. -// - -import SwiftUI -import CoreImage.CIFilterBuiltins -import SimpleXChat - -struct AddContactView: View { - @EnvironmentObject private var chatModel: ChatModel - @Binding var contactConnection: PendingContactConnection? - var connReqInvitation: String - @AppStorage(GROUP_DEFAULT_INCOGNITO, store: groupDefaults) private var incognitoDefault = false - - var body: some View { - VStack { - List { - Section { - if connReqInvitation != "" { - SimpleXLinkQRCode(uri: connReqInvitation) - } else { - ProgressView() - .progressViewStyle(.circular) - .scaleEffect(2) - .frame(maxWidth: .infinity) - .padding(.vertical) - } - IncognitoToggle(incognitoEnabled: $incognitoDefault) - .disabled(contactConnection == nil) - shareLinkButton(connReqInvitation) - oneTimeLinkLearnMoreButton() - } header: { - Text("1-time link") - } footer: { - sharedProfileInfo(incognitoDefault) - } - } - } - .onAppear { chatModel.connReqInv = connReqInvitation } - .onChange(of: incognitoDefault) { incognito in - Task { - do { - if let contactConn = contactConnection, - let conn = try await apiSetConnectionIncognito(connId: contactConn.pccConnId, incognito: incognito) { - await MainActor.run { - contactConnection = conn - chatModel.updateContactConnection(conn) - } - } - } catch { - logger.error("apiSetConnectionIncognito error: \(responseError(error))") - } - } - } - } -} - -struct IncognitoToggle: View { - @Binding var incognitoEnabled: Bool - @State private var showIncognitoSheet = false - - var body: some View { - ZStack(alignment: .leading) { - Image(systemName: incognitoEnabled ? "theatermasks.fill" : "theatermasks") - .frame(maxWidth: 24, maxHeight: 24, alignment: .center) - .foregroundColor(incognitoEnabled ? Color.indigo : .secondary) - .font(.system(size: 14)) - Toggle(isOn: $incognitoEnabled) { - HStack(spacing: 6) { - Text("Incognito") - Image(systemName: "info.circle") - .foregroundColor(.accentColor) - .font(.system(size: 14)) - } - .onTapGesture { - showIncognitoSheet = true - } - } - .padding(.leading, 36) - } - .sheet(isPresented: $showIncognitoSheet) { - IncognitoHelp() - } - } -} - -func sharedProfileInfo(_ incognito: Bool) -> Text { - let name = ChatModel.shared.currentUser?.displayName ?? "" - return Text( - incognito - ? "A new random profile will be shared." - : "Your profile **\(name)** will be shared." - ) -} - -func shareLinkButton(_ connReqInvitation: String) -> some View { - Button { - showShareSheet(items: [simplexChatLink(connReqInvitation)]) - } label: { - settingsRow("square.and.arrow.up") { - Text("Share 1-time link") - } - } -} - -func oneTimeLinkLearnMoreButton() -> some View { - NavigationLink { - AddContactLearnMore() - .navigationTitle("One-time invitation link") - .navigationBarTitleDisplayMode(.large) - } label: { - settingsRow("info.circle") { - Text("Learn more") - } - } -} - -struct AddContactView_Previews: PreviewProvider { - static var previews: some View { - AddContactView( - contactConnection: Binding.constant(PendingContactConnection.getSampleData()), - connReqInvitation: "https://simplex.chat/invitation#/?v=1&smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FFe5ICmvrm4wkrr6X1LTMii-lhBqLeB76%23MCowBQYDK2VuAyEAdhZZsHpuaAk3Hh1q0uNb_6hGTpuwBIrsp2z9U2T0oC0%3D&e2e=v%3D1%26x3dh%3DMEIwBQYDK2VvAzkAcz6jJk71InuxA0bOX7OUhddfB8Ov7xwQIlIDeXBRZaOntUU4brU5Y3rBzroZBdQJi0FKdtt_D7I%3D%2CMEIwBQYDK2VvAzkA-hDvk1duBi1hlOr08VWSI-Ou4JNNSQjseY69QyKm7Kgg1zZjbpGfyBqSZ2eqys6xtoV4ZtoQUXQ%3D" - ) - } -} diff --git a/apps/ios/Shared/Views/NewChat/ConnectViaLinkView.swift b/apps/ios/Shared/Views/NewChat/ConnectViaLinkView.swift deleted file mode 100644 index 9df767485e..0000000000 --- a/apps/ios/Shared/Views/NewChat/ConnectViaLinkView.swift +++ /dev/null @@ -1,42 +0,0 @@ -// -// ConnectViaLinkView.swift -// SimpleX (iOS) -// -// Created by Evgeny on 21/09/2022. -// Copyright © 2022 SimpleX Chat. All rights reserved. -// - -import SwiftUI - -enum ConnectViaLinkTab: String { - case scan - case paste -} - -struct ConnectViaLinkView: View { - @State private var selection: ConnectViaLinkTab = connectViaLinkTabDefault.get() - - var body: some View { - TabView(selection: $selection) { - ScanToConnectView() - .tabItem { - Label("Scan QR code", systemImage: "qrcode") - } - .tag(ConnectViaLinkTab.scan) - PasteToConnectView() - .tabItem { - Label("Paste received link", systemImage: "doc.plaintext") - } - .tag(ConnectViaLinkTab.paste) - } - .onChange(of: selection) { _ in - connectViaLinkTabDefault.set(selection) - } - } -} - -struct ConnectViaLinkView_Previews: PreviewProvider { - static var previews: some View { - ConnectViaLinkView() - } -} diff --git a/apps/ios/Shared/Views/NewChat/CreateLinkView.swift b/apps/ios/Shared/Views/NewChat/CreateLinkView.swift deleted file mode 100644 index 3be9e1c3b3..0000000000 --- a/apps/ios/Shared/Views/NewChat/CreateLinkView.swift +++ /dev/null @@ -1,94 +0,0 @@ -// -// CreateLinkView.swift -// SimpleX (iOS) -// -// Created by Evgeny on 21/09/2022. -// Copyright © 2022 SimpleX Chat. All rights reserved. -// - -import SwiftUI -import SimpleXChat - -enum CreateLinkTab { - case oneTime - case longTerm - - var title: LocalizedStringKey { - switch self { - case .oneTime: return "One-time invitation link" - case .longTerm: return "Your SimpleX address" - } - } -} - -struct CreateLinkView: View { - @EnvironmentObject var m: ChatModel - @State var selection: CreateLinkTab - @State var connReqInvitation: String = "" - @State var contactConnection: PendingContactConnection? = nil - @State private var creatingConnReq = false - var viaNavLink = false - - var body: some View { - if viaNavLink { - createLinkView() - } else { - NavigationView { - createLinkView() - } - } - } - - private func createLinkView() -> some View { - TabView(selection: $selection) { - AddContactView(contactConnection: $contactConnection, connReqInvitation: connReqInvitation) - .tabItem { - Label( - connReqInvitation == "" - ? "Create one-time invitation link" - : "One-time invitation link", - systemImage: "1.circle" - ) - } - .tag(CreateLinkTab.oneTime) - UserAddressView(viaCreateLinkView: true) - .tabItem { - Label("Your SimpleX address", systemImage: "infinity.circle") - } - .tag(CreateLinkTab.longTerm) - } - .onChange(of: selection) { _ in - if case .oneTime = selection, connReqInvitation == "", contactConnection == nil && !creatingConnReq { - createInvitation() - } - } - .onAppear { m.connReqInv = connReqInvitation } - .onDisappear { m.connReqInv = nil } - .navigationTitle(selection.title) - .navigationBarTitleDisplayMode(.large) - } - - private func createInvitation() { - creatingConnReq = true - Task { - if let (connReq, pcc) = await apiAddContact(incognito: incognitoGroupDefault.get()) { - await MainActor.run { - m.updateContactConnection(pcc) - connReqInvitation = connReq - contactConnection = pcc - m.connReqInv = connReq - } - } else { - await MainActor.run { - creatingConnReq = false - } - } - } - } -} - -struct CreateLinkView_Previews: PreviewProvider { - static var previews: some View { - CreateLinkView(selection: CreateLinkTab.oneTime) - } -} diff --git a/apps/ios/Shared/Views/NewChat/NewChatButton.swift b/apps/ios/Shared/Views/NewChat/NewChatButton.swift deleted file mode 100644 index 170805b488..0000000000 --- a/apps/ios/Shared/Views/NewChat/NewChatButton.swift +++ /dev/null @@ -1,466 +0,0 @@ -// -// NewChatButton.swift -// SimpleX -// -// Created by Evgeny Poberezkin on 31/01/2022. -// Copyright © 2022 SimpleX Chat. All rights reserved. -// - -import SwiftUI -import SimpleXChat - -enum NewChatAction: Identifiable { - case createLink(link: String, connection: PendingContactConnection) - case connectViaLink - case createGroup - - var id: String { - switch self { - case let .createLink(link, _): return "createLink \(link)" - case .connectViaLink: return "connectViaLink" - case .createGroup: return "createGroup" - } - } -} - -struct NewChatButton: View { - @Binding var showAddChat: Bool - @State private var actionSheet: NewChatAction? - - var body: some View { - Button { showAddChat = true } label: { - Image(systemName: "square.and.pencil") - .resizable() - .scaledToFit() - .frame(width: 24, height: 24) - } - .confirmationDialog("Start a new chat", isPresented: $showAddChat, titleVisibility: .visible) { - Button("Share one-time invitation link") { addContactAction() } - Button("Connect via link / QR code") { actionSheet = .connectViaLink } - Button("Create secret group") { actionSheet = .createGroup } - } - .sheet(item: $actionSheet) { sheet in - switch sheet { - case let .createLink(link, pcc): - CreateLinkView(selection: .oneTime, connReqInvitation: link, contactConnection: pcc) - case .connectViaLink: ConnectViaLinkView() - case .createGroup: AddGroupView() - } - } - } - - func addContactAction() { - Task { - if let (connReq, pcc) = await apiAddContact(incognito: incognitoGroupDefault.get()) { - await MainActor.run { - ChatModel.shared.updateContactConnection(pcc) - } - actionSheet = .createLink(link: connReq, connection: pcc) - } - } - } -} - -enum PlanAndConnectAlert: Identifiable { - case ownInvitationLinkConfirmConnect(connectionLink: String, connectionPlan: ConnectionPlan, incognito: Bool) - case invitationLinkConnecting(connectionLink: String) - case ownContactAddressConfirmConnect(connectionLink: String, connectionPlan: ConnectionPlan, incognito: Bool) - case contactAddressConnectingConfirmReconnect(connectionLink: String, connectionPlan: ConnectionPlan, incognito: Bool) - case groupLinkConfirmConnect(connectionLink: String, connectionPlan: ConnectionPlan, incognito: Bool) - case groupLinkConnectingConfirmReconnect(connectionLink: String, connectionPlan: ConnectionPlan, incognito: Bool) - case groupLinkConnecting(connectionLink: String, groupInfo: GroupInfo?) - - var id: String { - switch self { - case let .ownInvitationLinkConfirmConnect(connectionLink, _, _): return "ownInvitationLinkConfirmConnect \(connectionLink)" - case let .invitationLinkConnecting(connectionLink): return "invitationLinkConnecting \(connectionLink)" - case let .ownContactAddressConfirmConnect(connectionLink, _, _): return "ownContactAddressConfirmConnect \(connectionLink)" - case let .contactAddressConnectingConfirmReconnect(connectionLink, _, _): return "contactAddressConnectingConfirmReconnect \(connectionLink)" - case let .groupLinkConfirmConnect(connectionLink, _, _): return "groupLinkConfirmConnect \(connectionLink)" - case let .groupLinkConnectingConfirmReconnect(connectionLink, _, _): return "groupLinkConnectingConfirmReconnect \(connectionLink)" - case let .groupLinkConnecting(connectionLink, _): return "groupLinkConnecting \(connectionLink)" - } - } -} - -func planAndConnectAlert(_ alert: PlanAndConnectAlert, dismiss: Bool) -> Alert { - switch alert { - case let .ownInvitationLinkConfirmConnect(connectionLink, connectionPlan, incognito): - return Alert( - title: Text("Connect to yourself?"), - message: Text("This is your own one-time link!"), - primaryButton: .destructive( - Text(incognito ? "Connect incognito" : "Connect"), - action: { connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: incognito) } - ), - secondaryButton: .cancel() - ) - case .invitationLinkConnecting: - return Alert( - title: Text("Already connecting!"), - message: Text("You are already connecting via this one-time link!") - ) - case let .ownContactAddressConfirmConnect(connectionLink, connectionPlan, incognito): - return Alert( - title: Text("Connect to yourself?"), - message: Text("This is your own SimpleX address!"), - primaryButton: .destructive( - Text(incognito ? "Connect incognito" : "Connect"), - action: { connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: incognito) } - ), - secondaryButton: .cancel() - ) - case let .contactAddressConnectingConfirmReconnect(connectionLink, connectionPlan, incognito): - return Alert( - title: Text("Repeat connection request?"), - message: Text("You have already requested connection via this address!"), - primaryButton: .destructive( - Text(incognito ? "Connect incognito" : "Connect"), - action: { connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: incognito) } - ), - secondaryButton: .cancel() - ) - case let .groupLinkConfirmConnect(connectionLink, connectionPlan, incognito): - return Alert( - title: Text("Join group?"), - message: Text("You will connect to all group members."), - primaryButton: .default( - Text(incognito ? "Join incognito" : "Join"), - action: { connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: incognito) } - ), - secondaryButton: .cancel() - ) - case let .groupLinkConnectingConfirmReconnect(connectionLink, connectionPlan, incognito): - return Alert( - title: Text("Repeat join request?"), - message: Text("You are already joining the group via this link!"), - primaryButton: .destructive( - Text(incognito ? "Join incognito" : "Join"), - action: { connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: incognito) } - ), - secondaryButton: .cancel() - ) - case let .groupLinkConnecting(_, groupInfo): - if let groupInfo = groupInfo { - return Alert( - title: Text("Group already exists!"), - message: Text("You are already joining the group \(groupInfo.displayName).") - ) - } else { - return Alert( - title: Text("Already joining the group!"), - message: Text("You are already joining the group via this link.") - ) - } - } -} - -enum PlanAndConnectActionSheet: Identifiable { - case askCurrentOrIncognitoProfile(connectionLink: String, connectionPlan: ConnectionPlan?, title: LocalizedStringKey) - case askCurrentOrIncognitoProfileDestructive(connectionLink: String, connectionPlan: ConnectionPlan, title: LocalizedStringKey) - case askCurrentOrIncognitoProfileConnectContactViaAddress(contact: Contact) - case ownGroupLinkConfirmConnect(connectionLink: String, connectionPlan: ConnectionPlan, incognito: Bool?, groupInfo: GroupInfo) - - var id: String { - switch self { - case let .askCurrentOrIncognitoProfile(connectionLink, _, _): return "askCurrentOrIncognitoProfile \(connectionLink)" - case let .askCurrentOrIncognitoProfileDestructive(connectionLink, _, _): return "askCurrentOrIncognitoProfileDestructive \(connectionLink)" - case let .askCurrentOrIncognitoProfileConnectContactViaAddress(contact): return "askCurrentOrIncognitoProfileConnectContactViaAddress \(contact.contactId)" - case let .ownGroupLinkConfirmConnect(connectionLink, _, _, _): return "ownGroupLinkConfirmConnect \(connectionLink)" - } - } -} - -func planAndConnectActionSheet(_ sheet: PlanAndConnectActionSheet, dismiss: Bool) -> ActionSheet { - switch sheet { - case let .askCurrentOrIncognitoProfile(connectionLink, connectionPlan, title): - return ActionSheet( - title: Text(title), - buttons: [ - .default(Text("Use current profile")) { connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: false) }, - .default(Text("Use new incognito profile")) { connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: true) }, - .cancel() - ] - ) - case let .askCurrentOrIncognitoProfileDestructive(connectionLink, connectionPlan, title): - return ActionSheet( - title: Text(title), - buttons: [ - .destructive(Text("Use current profile")) { connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: false) }, - .destructive(Text("Use new incognito profile")) { connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: true) }, - .cancel() - ] - ) - case let .askCurrentOrIncognitoProfileConnectContactViaAddress(contact): - return ActionSheet( - title: Text("Connect with \(contact.chatViewName)"), - buttons: [ - .default(Text("Use current profile")) { connectContactViaAddress_(contact, dismiss: dismiss, incognito: false) }, - .default(Text("Use new incognito profile")) { connectContactViaAddress_(contact, dismiss: dismiss, incognito: true) }, - .cancel() - ] - ) - case let .ownGroupLinkConfirmConnect(connectionLink, connectionPlan, incognito, groupInfo): - if let incognito = incognito { - return ActionSheet( - title: Text("Join your group?\nThis is your link for group \(groupInfo.displayName)!"), - buttons: [ - .default(Text("Open group")) { openKnownGroup(groupInfo, dismiss: dismiss, showAlreadyExistsAlert: nil) }, - .destructive(Text(incognito ? "Join incognito" : "Join with current profile")) { connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: incognito) }, - .cancel() - ] - ) - } else { - return ActionSheet( - title: Text("Join your group?\nThis is your link for group \(groupInfo.displayName)!"), - buttons: [ - .default(Text("Open group")) { openKnownGroup(groupInfo, dismiss: dismiss, showAlreadyExistsAlert: nil) }, - .destructive(Text("Use current profile")) { connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: false) }, - .destructive(Text("Use new incognito profile")) { connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: true) }, - .cancel() - ] - ) - } - } -} - -func planAndConnect( - _ connectionLink: String, - showAlert: @escaping (PlanAndConnectAlert) -> Void, - showActionSheet: @escaping (PlanAndConnectActionSheet) -> Void, - dismiss: Bool, - incognito: Bool? -) { - Task { - do { - let connectionPlan = try await apiConnectPlan(connReq: connectionLink) - switch connectionPlan { - case let .invitationLink(ilp): - switch ilp { - case .ok: - logger.debug("planAndConnect, .invitationLink, .ok, incognito=\(incognito?.description ?? "nil")") - if let incognito = incognito { - connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: incognito) - } else { - showActionSheet(.askCurrentOrIncognitoProfile(connectionLink: connectionLink, connectionPlan: connectionPlan, title: "Connect via one-time link")) - } - case .ownLink: - logger.debug("planAndConnect, .invitationLink, .ownLink, incognito=\(incognito?.description ?? "nil")") - if let incognito = incognito { - showAlert(.ownInvitationLinkConfirmConnect(connectionLink: connectionLink, connectionPlan: connectionPlan, incognito: incognito)) - } else { - showActionSheet(.askCurrentOrIncognitoProfileDestructive(connectionLink: connectionLink, connectionPlan: connectionPlan, title: "Connect to yourself?\nThis is your own one-time link!")) - } - case let .connecting(contact_): - logger.debug("planAndConnect, .invitationLink, .connecting, incognito=\(incognito?.description ?? "nil")") - if let contact = contact_ { - openKnownContact(contact, dismiss: dismiss) { AlertManager.shared.showAlert(contactAlreadyConnectingAlert(contact)) } - } else { - showAlert(.invitationLinkConnecting(connectionLink: connectionLink)) - } - case let .known(contact): - logger.debug("planAndConnect, .invitationLink, .known, incognito=\(incognito?.description ?? "nil")") - openKnownContact(contact, dismiss: dismiss) { AlertManager.shared.showAlert(contactAlreadyExistsAlert(contact)) } - } - case let .contactAddress(cap): - switch cap { - case .ok: - logger.debug("planAndConnect, .contactAddress, .ok, incognito=\(incognito?.description ?? "nil")") - if let incognito = incognito { - connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: incognito) - } else { - showActionSheet(.askCurrentOrIncognitoProfile(connectionLink: connectionLink, connectionPlan: connectionPlan, title: "Connect via contact address")) - } - case .ownLink: - logger.debug("planAndConnect, .contactAddress, .ownLink, incognito=\(incognito?.description ?? "nil")") - if let incognito = incognito { - showAlert(.ownContactAddressConfirmConnect(connectionLink: connectionLink, connectionPlan: connectionPlan, incognito: incognito)) - } else { - showActionSheet(.askCurrentOrIncognitoProfileDestructive(connectionLink: connectionLink, connectionPlan: connectionPlan, title: "Connect to yourself?\nThis is your own SimpleX address!")) - } - case .connectingConfirmReconnect: - logger.debug("planAndConnect, .contactAddress, .connectingConfirmReconnect, incognito=\(incognito?.description ?? "nil")") - if let incognito = incognito { - showAlert(.contactAddressConnectingConfirmReconnect(connectionLink: connectionLink, connectionPlan: connectionPlan, incognito: incognito)) - } else { - showActionSheet(.askCurrentOrIncognitoProfileDestructive(connectionLink: connectionLink, connectionPlan: connectionPlan, title: "You have already requested connection!\nRepeat connection request?")) - } - case let .connectingProhibit(contact): - logger.debug("planAndConnect, .contactAddress, .connectingProhibit, incognito=\(incognito?.description ?? "nil")") - openKnownContact(contact, dismiss: dismiss) { AlertManager.shared.showAlert(contactAlreadyConnectingAlert(contact)) } - case let .known(contact): - logger.debug("planAndConnect, .contactAddress, .known, incognito=\(incognito?.description ?? "nil")") - openKnownContact(contact, dismiss: dismiss) { AlertManager.shared.showAlert(contactAlreadyExistsAlert(contact)) } - case let .contactViaAddress(contact): - logger.debug("planAndConnect, .contactAddress, .contactViaAddress, incognito=\(incognito?.description ?? "nil")") - if let incognito = incognito { - connectContactViaAddress_(contact, dismiss: dismiss, incognito: incognito) - } else { - showActionSheet(.askCurrentOrIncognitoProfileConnectContactViaAddress(contact: contact)) - } - } - case let .groupLink(glp): - switch glp { - case .ok: - if let incognito = incognito { - showAlert(.groupLinkConfirmConnect(connectionLink: connectionLink, connectionPlan: connectionPlan, incognito: incognito)) - } else { - showActionSheet(.askCurrentOrIncognitoProfile(connectionLink: connectionLink, connectionPlan: connectionPlan, title: "Join group")) - } - case let .ownLink(groupInfo): - logger.debug("planAndConnect, .groupLink, .ownLink, incognito=\(incognito?.description ?? "nil")") - showActionSheet(.ownGroupLinkConfirmConnect(connectionLink: connectionLink, connectionPlan: connectionPlan, incognito: incognito, groupInfo: groupInfo)) - case .connectingConfirmReconnect: - logger.debug("planAndConnect, .groupLink, .connectingConfirmReconnect, incognito=\(incognito?.description ?? "nil")") - if let incognito = incognito { - showAlert(.groupLinkConnectingConfirmReconnect(connectionLink: connectionLink, connectionPlan: connectionPlan, incognito: incognito)) - } else { - showActionSheet(.askCurrentOrIncognitoProfileDestructive(connectionLink: connectionLink, connectionPlan: connectionPlan, title: "You are already joining the group!\nRepeat join request?")) - } - case let .connectingProhibit(groupInfo_): - logger.debug("planAndConnect, .groupLink, .connectingProhibit, incognito=\(incognito?.description ?? "nil")") - showAlert(.groupLinkConnecting(connectionLink: connectionLink, groupInfo: groupInfo_)) - case let .known(groupInfo): - logger.debug("planAndConnect, .groupLink, .known, incognito=\(incognito?.description ?? "nil")") - openKnownGroup(groupInfo, dismiss: dismiss) { AlertManager.shared.showAlert(groupAlreadyExistsAlert(groupInfo)) } - } - } - } catch { - logger.debug("planAndConnect, plan error") - if let incognito = incognito { - connectViaLink(connectionLink, connectionPlan: nil, dismiss: dismiss, incognito: incognito) - } else { - showActionSheet(.askCurrentOrIncognitoProfile(connectionLink: connectionLink, connectionPlan: nil, title: "Connect via link")) - } - } - } -} - -private func connectContactViaAddress_(_ contact: Contact, dismiss: Bool, incognito: Bool) { - Task { - if dismiss { - DispatchQueue.main.async { - dismissAllSheets(animated: true) - } - } - _ = await connectContactViaAddress(contact.contactId, incognito) - } -} - -private func connectViaLink(_ connectionLink: String, connectionPlan: ConnectionPlan?, dismiss: Bool, incognito: Bool) { - Task { - if let (connReqType, pcc) = await apiConnect(incognito: incognito, connReq: connectionLink) { - await MainActor.run { - ChatModel.shared.updateContactConnection(pcc) - } - let crt: ConnReqType - if let plan = connectionPlan { - crt = planToConnReqType(plan) - } else { - crt = connReqType - } - DispatchQueue.main.async { - if dismiss { - dismissAllSheets(animated: true) { - AlertManager.shared.showAlert(connReqSentAlert(crt)) - } - } else { - AlertManager.shared.showAlert(connReqSentAlert(crt)) - } - } - } else { - if dismiss { - DispatchQueue.main.async { - dismissAllSheets(animated: true) - } - } - } - } -} - -func openKnownContact(_ contact: Contact, dismiss: Bool, showAlreadyExistsAlert: (() -> Void)?) { - Task { - let m = ChatModel.shared - if let c = m.getContactChat(contact.contactId) { - DispatchQueue.main.async { - if dismiss { - dismissAllSheets(animated: true) { - m.chatId = c.id - showAlreadyExistsAlert?() - } - } else { - m.chatId = c.id - showAlreadyExistsAlert?() - } - } - } - } -} - -func openKnownGroup(_ groupInfo: GroupInfo, dismiss: Bool, showAlreadyExistsAlert: (() -> Void)?) { - Task { - let m = ChatModel.shared - if let g = m.getGroupChat(groupInfo.groupId) { - DispatchQueue.main.async { - if dismiss { - dismissAllSheets(animated: true) { - m.chatId = g.id - showAlreadyExistsAlert?() - } - } else { - m.chatId = g.id - showAlreadyExistsAlert?() - } - } - } - } -} - -func contactAlreadyConnectingAlert(_ contact: Contact) -> Alert { - mkAlert( - title: "Contact already exists", - message: "You are already connecting to \(contact.displayName)." - ) -} - -func groupAlreadyExistsAlert(_ groupInfo: GroupInfo) -> Alert { - mkAlert( - title: "Group already exists", - message: "You are already in group \(groupInfo.displayName)." - ) -} - -enum ConnReqType: Equatable { - case invitation - case contact - case groupLink - - var connReqSentText: LocalizedStringKey { - switch self { - case .invitation: return "You will be connected when your contact's device is online, please wait or check later!" - case .contact: return "You will be connected when your connection request is accepted, please wait or check later!" - case .groupLink: return "You will be connected when group link host's device is online, please wait or check later!" - } - } -} - -private func planToConnReqType(_ connectionPlan: ConnectionPlan) -> ConnReqType { - switch connectionPlan { - case .invitationLink: return .invitation - case .contactAddress: return .contact - case .groupLink: return .groupLink - } -} - -func connReqSentAlert(_ type: ConnReqType) -> Alert { - return mkAlert( - title: "Connection request sent!", - message: type.connReqSentText - ) -} - -struct NewChatButton_Previews: PreviewProvider { - static var previews: some View { - NewChatButton(showAddChat: Binding.constant(false)) - } -} diff --git a/apps/ios/Shared/Views/NewChat/NewChatMenuButton.swift b/apps/ios/Shared/Views/NewChat/NewChatMenuButton.swift new file mode 100644 index 0000000000..c3452ce18d --- /dev/null +++ b/apps/ios/Shared/Views/NewChat/NewChatMenuButton.swift @@ -0,0 +1,52 @@ +// +// NewChatMenuButton.swift +// SimpleX (iOS) +// +// Created by spaced4ndy on 28.11.2023. +// Copyright © 2023 SimpleX Chat. All rights reserved. +// + +import SwiftUI + +enum NewChatMenuOption: Identifiable { + case newContact + case newGroup + + var id: Self { self } +} + +struct NewChatMenuButton: View { + @Binding var newChatMenuOption: NewChatMenuOption? + + var body: some View { + Menu { + Button { + newChatMenuOption = .newContact + } label: { + Text("Add contact") + } + Button { + newChatMenuOption = .newGroup + } label: { + Text("Create group") + } + } label: { + Image(systemName: "square.and.pencil") + .resizable() + .scaledToFit() + .frame(width: 24, height: 24) + } + .sheet(item: $newChatMenuOption) { opt in + switch opt { + case .newContact: NewChatView(selection: .invite) + case .newGroup: AddGroupView() + } + } + } +} + +#Preview { + NewChatMenuButton( + newChatMenuOption: Binding.constant(nil) + ) +} diff --git a/apps/ios/Shared/Views/NewChat/NewChatView.swift b/apps/ios/Shared/Views/NewChat/NewChatView.swift new file mode 100644 index 0000000000..b78d92ffc8 --- /dev/null +++ b/apps/ios/Shared/Views/NewChat/NewChatView.swift @@ -0,0 +1,959 @@ +// +// NewChatView.swift +// SimpleX (iOS) +// +// Created by spaced4ndy on 28.11.2023. +// Copyright © 2023 SimpleX Chat. All rights reserved. +// + +import SwiftUI +import SimpleXChat +import CodeScanner +import AVFoundation + +enum SomeAlert: Identifiable { + case someAlert(alert: Alert, id: String) + + var id: String { + switch self { + case let .someAlert(_, id): return id + } + } +} + +private enum NewChatViewAlert: Identifiable { + case planAndConnectAlert(alert: PlanAndConnectAlert) + case newChatSomeAlert(alert: SomeAlert) + + var id: String { + switch self { + case let .planAndConnectAlert(alert): return "planAndConnectAlert \(alert.id)" + case let .newChatSomeAlert(alert): return "newChatSomeAlert \(alert.id)" + } + } +} + +enum NewChatOption: Identifiable { + case invite + case connect + + var id: Self { self } +} + +struct NewChatView: View { + @EnvironmentObject var m: ChatModel + @State var selection: NewChatOption + @State var showQRCodeScanner = false + @State private var invitationUsed: Bool = false + @State private var contactConnection: PendingContactConnection? = nil + @State private var connReqInvitation: String = "" + @State private var creatingConnReq = false + @State private var pastedLink: String = "" + @State private var alert: NewChatViewAlert? + + var body: some View { + VStack(alignment: .leading) { + HStack { + Text("New chat") + .font(.largeTitle) + .bold() + .fixedSize(horizontal: false, vertical: true) + Spacer() + InfoSheetButton { + AddContactLearnMore(showTitle: true) + } + } + .padding() + .padding(.top) + + Picker("New chat", selection: $selection) { + Label("Add contact", systemImage: "link") + .tag(NewChatOption.invite) + Label("Connect via link", systemImage: "qrcode") + .tag(NewChatOption.connect) + } + .pickerStyle(.segmented) + .padding() + + VStack { + // it seems there's a bug in iOS 15 if several views in switch (or if-else) statement have different transitions + // https://developer.apple.com/forums/thread/714977?answerId=731615022#731615022 + if case .invite = selection { + prepareAndInviteView() + .transition(.move(edge: .leading)) + .onAppear { + createInvitation() + } + } + if case .connect = selection { + ConnectView(showQRCodeScanner: showQRCodeScanner, pastedLink: $pastedLink, alert: $alert) + .transition(.move(edge: .trailing)) + } + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + .background( + // Rectangle is needed for swipe gesture to work on mostly empty views (creatingLinkProgressView and retryButton) + Rectangle() + .fill(Color(uiColor: .systemGroupedBackground)) + ) + .animation(.easeInOut(duration: 0.3333), value: selection) + .gesture(DragGesture(minimumDistance: 20.0, coordinateSpace: .local) + .onChanged { value in + switch(value.translation.width, value.translation.height) { + case (...0, -30...30): // left swipe + if selection == .invite { + selection = .connect + } + case (0..., -30...30): // right swipe + if selection == .connect { + selection = .invite + } + default: () + } + } + ) + } + .background(Color(.systemGroupedBackground)) + .onChange(of: invitationUsed) { used in + if used && !(m.showingInvitation?.connChatUsed ?? true) { + m.markShowingInvitationUsed() + } + } + .onDisappear { + if !(m.showingInvitation?.connChatUsed ?? true), + let conn = contactConnection { + AlertManager.shared.showAlert(Alert( + title: Text("Keep unused invitation?"), + message: Text("You can view invitation link again in connection details."), + primaryButton: .default(Text("Keep")) {}, + secondaryButton: .destructive(Text("Delete")) { + Task { + await deleteChat(Chat( + chatInfo: .contactConnection(contactConnection: conn), + chatItems: [] + )) + } + } + )) + } + m.showingInvitation = nil + } + .alert(item: $alert) { a in + switch(a) { + case let .planAndConnectAlert(alert): + return planAndConnectAlert(alert, dismiss: true, cleanup: { pastedLink = "" }) + case let .newChatSomeAlert(.someAlert(alert, _)): + return alert + } + } + } + + private func prepareAndInviteView() -> some View { + ZStack { // ZStack is needed for views to not make transitions between each other + if connReqInvitation != "" { + InviteView( + invitationUsed: $invitationUsed, + contactConnection: $contactConnection, + connReqInvitation: connReqInvitation + ) + } else if creatingConnReq { + creatingLinkProgressView() + } else { + retryButton() + } + } + } + + private func createInvitation() { + if connReqInvitation == "" && contactConnection == nil && !creatingConnReq { + creatingConnReq = true + Task { + _ = try? await Task.sleep(nanoseconds: 250_000000) + let (r, apiAlert) = await apiAddContact(incognito: incognitoGroupDefault.get()) + if let (connReq, pcc) = r { + await MainActor.run { + m.updateContactConnection(pcc) + m.showingInvitation = ShowingInvitation(connId: pcc.id, connChatUsed: false) + connReqInvitation = connReq + contactConnection = pcc + } + } else { + await MainActor.run { + creatingConnReq = false + if let apiAlert = apiAlert { + alert = .newChatSomeAlert(alert: .someAlert(alert: apiAlert, id: "createInvitation error")) + } + } + } + } + } + } + + // Rectangle here and in retryButton are needed for gesture to work + private func creatingLinkProgressView() -> some View { + ProgressView("Creating link…") + .progressViewStyle(.circular) + } + + private func retryButton() -> some View { + Button(action: createInvitation) { + VStack(spacing: 6) { + Image(systemName: "arrow.counterclockwise") + Text("Retry") + } + } + } +} + +private struct InviteView: View { + @EnvironmentObject var chatModel: ChatModel + @Binding var invitationUsed: Bool + @Binding var contactConnection: PendingContactConnection? + var connReqInvitation: String + @AppStorage(GROUP_DEFAULT_INCOGNITO, store: groupDefaults) private var incognitoDefault = false + + var body: some View { + List { + Section("Share this 1-time invite link") { + shareLinkView() + } + .listRowInsets(EdgeInsets(top: 0, leading: 20, bottom: 0, trailing: 10)) + + qrCodeView() + + Section { + IncognitoToggle(incognitoEnabled: $incognitoDefault) + } footer: { + sharedProfileInfo(incognitoDefault) + } + } + .onChange(of: incognitoDefault) { incognito in + Task { + do { + if let contactConn = contactConnection, + let conn = try await apiSetConnectionIncognito(connId: contactConn.pccConnId, incognito: incognito) { + await MainActor.run { + contactConnection = conn + chatModel.updateContactConnection(conn) + } + } + } catch { + logger.error("apiSetConnectionIncognito error: \(responseError(error))") + } + } + setInvitationUsed() + } + } + + private func shareLinkView() -> some View { + HStack { + let link = simplexChatLink(connReqInvitation) + linkTextView(link) + Button { + showShareSheet(items: [link]) + setInvitationUsed() + } label: { + Image(systemName: "square.and.arrow.up") + .padding(.top, -7) + } + } + .frame(maxWidth: .infinity) + } + + private func qrCodeView() -> some View { + Section("Or show this code") { + SimpleXLinkQRCode(uri: connReqInvitation, onShare: setInvitationUsed) + .padding() + .background( + RoundedRectangle(cornerRadius: 12, style: .continuous) + .fill(Color(uiColor: .secondarySystemGroupedBackground)) + ) + .padding(.horizontal) + .listRowBackground(Color.clear) + .listRowSeparator(.hidden) + .listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0)) + } + } + + private func setInvitationUsed() { + if !invitationUsed { + invitationUsed = true + } + } +} + +private struct ConnectView: View { + @Environment(\.dismiss) var dismiss: DismissAction + @State var showQRCodeScanner = false + @State private var cameraAuthorizationStatus: AVAuthorizationStatus? + @Binding var pastedLink: String + @Binding var alert: NewChatViewAlert? + @State private var sheet: PlanAndConnectActionSheet? + + var body: some View { + List { + Section("Paste the link you received") { + pasteLinkView() + } + + scanCodeView() + } + .actionSheet(item: $sheet) { s in + planAndConnectActionSheet(s, dismiss: true, cleanup: { pastedLink = "" }) + } + .onAppear { + let status = AVCaptureDevice.authorizationStatus(for: .video) + cameraAuthorizationStatus = status + if showQRCodeScanner { + switch status { + case .notDetermined: askCameraAuthorization() + case .restricted: showQRCodeScanner = false + case .denied: showQRCodeScanner = false + case .authorized: () + @unknown default: askCameraAuthorization() + } + } + } + } + + func askCameraAuthorization(_ cb: (() -> Void)? = nil) { + AVCaptureDevice.requestAccess(for: .video) { allowed in + cameraAuthorizationStatus = AVCaptureDevice.authorizationStatus(for: .video) + if allowed { cb?() } + } + } + + @ViewBuilder private func pasteLinkView() -> some View { + if pastedLink == "" { + Button { + if let str = UIPasteboard.general.string { + if let link = strHasSingleSimplexLink(str.trimmingCharacters(in: .whitespaces)) { + pastedLink = link.text + // It would be good to hide it, but right now it is not clear how to release camera in CodeScanner + // https://github.com/twostraws/CodeScanner/issues/121 + // No known tricks worked (changing view ID, wrapping it in another view, etc.) + // showQRCodeScanner = false + connect(pastedLink) + } else { + alert = .newChatSomeAlert(alert: .someAlert( + alert: mkAlert(title: "Invalid link", message: "The text you pasted is not a SimpleX link."), + id: "pasteLinkView: code is not a SimpleX link" + )) + } + } + } label: { + Text("Tap to paste link") + } + .disabled(!ChatModel.shared.pasteboardHasStrings) + .frame(maxWidth: .infinity, alignment: .center) + } else { + linkTextView(pastedLink) + } + } + + private func scanCodeView() -> some View { + Section("Or scan QR code") { + if showQRCodeScanner, case .authorized = cameraAuthorizationStatus { + CodeScannerView(codeTypes: [.qr], scanMode: .continuous, completion: processQRCode) + .aspectRatio(1, contentMode: .fit) + .cornerRadius(12) + .listRowBackground(Color.clear) + .listRowSeparator(.hidden) + .listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0)) + .padding(.horizontal) + } else { + Button { + switch cameraAuthorizationStatus { + case .notDetermined: askCameraAuthorization { showQRCodeScanner = true } + case .restricted: () + case .denied: UIApplication.shared.open(appSettingsURL) + case .authorized: showQRCodeScanner = true + default: askCameraAuthorization { showQRCodeScanner = true } + } + } label: { + ZStack { + Rectangle() + .aspectRatio(contentMode: .fill) + .frame(maxWidth: .infinity, maxHeight: .infinity) + .foregroundColor(Color.clear) + switch cameraAuthorizationStatus { + case .restricted: Text("Camera not available") + case .denied: Label("Enable camera access", systemImage: "camera") + default: Label("Tap to scan", systemImage: "qrcode") + } + } + } + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center) + .padding() + .background( + RoundedRectangle(cornerRadius: 12, style: .continuous) + .fill(Color(uiColor: .secondarySystemGroupedBackground)) + ) + .padding(.horizontal) + .listRowBackground(Color.clear) + .listRowSeparator(.hidden) + .listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0)) + .disabled(cameraAuthorizationStatus == .restricted) + } + } + } + + private func processQRCode(_ resp: Result) { + switch resp { + case let .success(r): + let link = r.string + if strIsSimplexLink(r.string) { + connect(link) + } else { + alert = .newChatSomeAlert(alert: .someAlert( + alert: mkAlert(title: "Invalid QR code", message: "The code you scanned is not a SimpleX link QR code."), + id: "processQRCode: code is not a SimpleX link" + )) + } + case let .failure(e): + logger.error("processQRCode QR code error: \(e.localizedDescription)") + alert = .newChatSomeAlert(alert: .someAlert( + alert: mkAlert(title: "Invalid QR code", message: "Error scanning code: \(e.localizedDescription)"), + id: "processQRCode: failure" + )) + } + } + + private func connect(_ link: String) { + planAndConnect( + link, + showAlert: { alert = .planAndConnectAlert(alert: $0) }, + showActionSheet: { sheet = $0 }, + dismiss: true, + incognito: nil + ) + } +} + +private func linkTextView(_ link: String) -> some View { + Text(link) + .lineLimit(1) + .font(.caption) + .truncationMode(.middle) +} + +struct InfoSheetButton: View { + @ViewBuilder let content: Content + @State private var showInfoSheet = false + + var body: some View { + Button { + showInfoSheet = true + } label: { + Image(systemName: "info.circle") + .resizable() + .scaledToFit() + .frame(width: 24, height: 24) + } + .sheet(isPresented: $showInfoSheet) { + content + } + } +} + +func strIsSimplexLink(_ str: String) -> Bool { + if let parsedMd = parseSimpleXMarkdown(str), + parsedMd.count == 1, + case .simplexLink = parsedMd[0].format { + return true + } else { + return false + } +} + +func strHasSingleSimplexLink(_ str: String) -> FormattedText? { + if let parsedMd = parseSimpleXMarkdown(str) { + let parsedLinks = parsedMd.filter({ $0.format?.isSimplexLink ?? false }) + if parsedLinks.count == 1 { + return parsedLinks[0] + } else { + return nil + } + } else { + return nil + } +} + +struct IncognitoToggle: View { + @Binding var incognitoEnabled: Bool + @State private var showIncognitoSheet = false + + var body: some View { + ZStack(alignment: .leading) { + Image(systemName: incognitoEnabled ? "theatermasks.fill" : "theatermasks") + .frame(maxWidth: 24, maxHeight: 24, alignment: .center) + .foregroundColor(incognitoEnabled ? Color.indigo : .secondary) + .font(.system(size: 14)) + Toggle(isOn: $incognitoEnabled) { + HStack(spacing: 6) { + Text("Incognito") + Image(systemName: "info.circle") + .foregroundColor(.accentColor) + .font(.system(size: 14)) + } + .onTapGesture { + showIncognitoSheet = true + } + } + .padding(.leading, 36) + } + .sheet(isPresented: $showIncognitoSheet) { + IncognitoHelp() + } + } +} + +func sharedProfileInfo(_ incognito: Bool) -> Text { + let name = ChatModel.shared.currentUser?.displayName ?? "" + return Text( + incognito + ? "A new random profile will be shared." + : "Your profile **\(name)** will be shared." + ) +} + +enum PlanAndConnectAlert: Identifiable { + case ownInvitationLinkConfirmConnect(connectionLink: String, connectionPlan: ConnectionPlan, incognito: Bool) + case invitationLinkConnecting(connectionLink: String) + case ownContactAddressConfirmConnect(connectionLink: String, connectionPlan: ConnectionPlan, incognito: Bool) + case contactAddressConnectingConfirmReconnect(connectionLink: String, connectionPlan: ConnectionPlan, incognito: Bool) + case groupLinkConfirmConnect(connectionLink: String, connectionPlan: ConnectionPlan, incognito: Bool) + case groupLinkConnectingConfirmReconnect(connectionLink: String, connectionPlan: ConnectionPlan, incognito: Bool) + case groupLinkConnecting(connectionLink: String, groupInfo: GroupInfo?) + + var id: String { + switch self { + case let .ownInvitationLinkConfirmConnect(connectionLink, _, _): return "ownInvitationLinkConfirmConnect \(connectionLink)" + case let .invitationLinkConnecting(connectionLink): return "invitationLinkConnecting \(connectionLink)" + case let .ownContactAddressConfirmConnect(connectionLink, _, _): return "ownContactAddressConfirmConnect \(connectionLink)" + case let .contactAddressConnectingConfirmReconnect(connectionLink, _, _): return "contactAddressConnectingConfirmReconnect \(connectionLink)" + case let .groupLinkConfirmConnect(connectionLink, _, _): return "groupLinkConfirmConnect \(connectionLink)" + case let .groupLinkConnectingConfirmReconnect(connectionLink, _, _): return "groupLinkConnectingConfirmReconnect \(connectionLink)" + case let .groupLinkConnecting(connectionLink, _): return "groupLinkConnecting \(connectionLink)" + } + } +} + +func planAndConnectAlert(_ alert: PlanAndConnectAlert, dismiss: Bool, cleanup: (() -> Void)? = nil) -> Alert { + switch alert { + case let .ownInvitationLinkConfirmConnect(connectionLink, connectionPlan, incognito): + return Alert( + title: Text("Connect to yourself?"), + message: Text("This is your own one-time link!"), + primaryButton: .destructive( + Text(incognito ? "Connect incognito" : "Connect"), + action: { connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: incognito, cleanup: cleanup) } + ), + secondaryButton: .cancel() { cleanup?() } + ) + case .invitationLinkConnecting: + return Alert( + title: Text("Already connecting!"), + message: Text("You are already connecting via this one-time link!"), + dismissButton: .default(Text("OK")) { cleanup?() } + ) + case let .ownContactAddressConfirmConnect(connectionLink, connectionPlan, incognito): + return Alert( + title: Text("Connect to yourself?"), + message: Text("This is your own SimpleX address!"), + primaryButton: .destructive( + Text(incognito ? "Connect incognito" : "Connect"), + action: { connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: incognito, cleanup: cleanup) } + ), + secondaryButton: .cancel() { cleanup?() } + ) + case let .contactAddressConnectingConfirmReconnect(connectionLink, connectionPlan, incognito): + return Alert( + title: Text("Repeat connection request?"), + message: Text("You have already requested connection via this address!"), + primaryButton: .destructive( + Text(incognito ? "Connect incognito" : "Connect"), + action: { connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: incognito, cleanup: cleanup) } + ), + secondaryButton: .cancel() { cleanup?() } + ) + case let .groupLinkConfirmConnect(connectionLink, connectionPlan, incognito): + return Alert( + title: Text("Join group?"), + message: Text("You will connect to all group members."), + primaryButton: .default( + Text(incognito ? "Join incognito" : "Join"), + action: { connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: incognito, cleanup: cleanup) } + ), + secondaryButton: .cancel() { cleanup?() } + ) + case let .groupLinkConnectingConfirmReconnect(connectionLink, connectionPlan, incognito): + return Alert( + title: Text("Repeat join request?"), + message: Text("You are already joining the group via this link!"), + primaryButton: .destructive( + Text(incognito ? "Join incognito" : "Join"), + action: { connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: incognito, cleanup: cleanup) } + ), + secondaryButton: .cancel() { cleanup?() } + ) + case let .groupLinkConnecting(_, groupInfo): + if let groupInfo = groupInfo { + return Alert( + title: Text("Group already exists!"), + message: Text("You are already joining the group \(groupInfo.displayName)."), + dismissButton: .default(Text("OK")) { cleanup?() } + ) + } else { + return Alert( + title: Text("Already joining the group!"), + message: Text("You are already joining the group via this link."), + dismissButton: .default(Text("OK")) { cleanup?() } + ) + } + } +} + +enum PlanAndConnectActionSheet: Identifiable { + case askCurrentOrIncognitoProfile(connectionLink: String, connectionPlan: ConnectionPlan?, title: LocalizedStringKey) + case askCurrentOrIncognitoProfileDestructive(connectionLink: String, connectionPlan: ConnectionPlan, title: LocalizedStringKey) + case askCurrentOrIncognitoProfileConnectContactViaAddress(contact: Contact) + case ownGroupLinkConfirmConnect(connectionLink: String, connectionPlan: ConnectionPlan, incognito: Bool?, groupInfo: GroupInfo) + + var id: String { + switch self { + case let .askCurrentOrIncognitoProfile(connectionLink, _, _): return "askCurrentOrIncognitoProfile \(connectionLink)" + case let .askCurrentOrIncognitoProfileDestructive(connectionLink, _, _): return "askCurrentOrIncognitoProfileDestructive \(connectionLink)" + case let .askCurrentOrIncognitoProfileConnectContactViaAddress(contact): return "askCurrentOrIncognitoProfileConnectContactViaAddress \(contact.contactId)" + case let .ownGroupLinkConfirmConnect(connectionLink, _, _, _): return "ownGroupLinkConfirmConnect \(connectionLink)" + } + } +} + +func planAndConnectActionSheet(_ sheet: PlanAndConnectActionSheet, dismiss: Bool, cleanup: (() -> Void)? = nil) -> ActionSheet { + switch sheet { + case let .askCurrentOrIncognitoProfile(connectionLink, connectionPlan, title): + return ActionSheet( + title: Text(title), + buttons: [ + .default(Text("Use current profile")) { connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: false, cleanup: cleanup) }, + .default(Text("Use new incognito profile")) { connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: true, cleanup: cleanup) }, + .cancel() { cleanup?() } + ] + ) + case let .askCurrentOrIncognitoProfileDestructive(connectionLink, connectionPlan, title): + return ActionSheet( + title: Text(title), + buttons: [ + .destructive(Text("Use current profile")) { connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: false, cleanup: cleanup) }, + .destructive(Text("Use new incognito profile")) { connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: true, cleanup: cleanup) }, + .cancel() { cleanup?() } + ] + ) + case let .askCurrentOrIncognitoProfileConnectContactViaAddress(contact): + return ActionSheet( + title: Text("Connect with \(contact.chatViewName)"), + buttons: [ + .default(Text("Use current profile")) { connectContactViaAddress_(contact, dismiss: dismiss, incognito: false, cleanup: cleanup) }, + .default(Text("Use new incognito profile")) { connectContactViaAddress_(contact, dismiss: dismiss, incognito: true, cleanup: cleanup) }, + .cancel() { cleanup?() } + ] + ) + case let .ownGroupLinkConfirmConnect(connectionLink, connectionPlan, incognito, groupInfo): + if let incognito = incognito { + return ActionSheet( + title: Text("Join your group?\nThis is your link for group \(groupInfo.displayName)!"), + buttons: [ + .default(Text("Open group")) { openKnownGroup(groupInfo, dismiss: dismiss, showAlreadyExistsAlert: nil) }, + .destructive(Text(incognito ? "Join incognito" : "Join with current profile")) { connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: incognito, cleanup: cleanup) }, + .cancel() { cleanup?() } + ] + ) + } else { + return ActionSheet( + title: Text("Join your group?\nThis is your link for group \(groupInfo.displayName)!"), + buttons: [ + .default(Text("Open group")) { openKnownGroup(groupInfo, dismiss: dismiss, showAlreadyExistsAlert: nil) }, + .destructive(Text("Use current profile")) { connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: false, cleanup: cleanup) }, + .destructive(Text("Use new incognito profile")) { connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: true, cleanup: cleanup) }, + .cancel() { cleanup?() } + ] + ) + } + } +} + +func planAndConnect( + _ connectionLink: String, + showAlert: @escaping (PlanAndConnectAlert) -> Void, + showActionSheet: @escaping (PlanAndConnectActionSheet) -> Void, + dismiss: Bool, + incognito: Bool?, + cleanup: (() -> Void)? = nil, + filterKnownContact: ((Contact) -> Void)? = nil, + filterKnownGroup: ((GroupInfo) -> Void)? = nil +) { + Task { + do { + let connectionPlan = try await apiConnectPlan(connReq: connectionLink) + switch connectionPlan { + case let .invitationLink(ilp): + switch ilp { + case .ok: + logger.debug("planAndConnect, .invitationLink, .ok, incognito=\(incognito?.description ?? "nil")") + if let incognito = incognito { + connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: incognito, cleanup: cleanup) + } else { + showActionSheet(.askCurrentOrIncognitoProfile(connectionLink: connectionLink, connectionPlan: connectionPlan, title: "Connect via one-time link")) + } + case .ownLink: + logger.debug("planAndConnect, .invitationLink, .ownLink, incognito=\(incognito?.description ?? "nil")") + if let incognito = incognito { + showAlert(.ownInvitationLinkConfirmConnect(connectionLink: connectionLink, connectionPlan: connectionPlan, incognito: incognito)) + } else { + showActionSheet(.askCurrentOrIncognitoProfileDestructive(connectionLink: connectionLink, connectionPlan: connectionPlan, title: "Connect to yourself?\nThis is your own one-time link!")) + } + case let .connecting(contact_): + logger.debug("planAndConnect, .invitationLink, .connecting, incognito=\(incognito?.description ?? "nil")") + if let contact = contact_ { + if let f = filterKnownContact { + f(contact) + } else { + openKnownContact(contact, dismiss: dismiss) { AlertManager.shared.showAlert(contactAlreadyConnectingAlert(contact)) } + } + } else { + showAlert(.invitationLinkConnecting(connectionLink: connectionLink)) + } + case let .known(contact): + logger.debug("planAndConnect, .invitationLink, .known, incognito=\(incognito?.description ?? "nil")") + if let f = filterKnownContact { + f(contact) + } else { + openKnownContact(contact, dismiss: dismiss) { AlertManager.shared.showAlert(contactAlreadyExistsAlert(contact)) } + } + } + case let .contactAddress(cap): + switch cap { + case .ok: + logger.debug("planAndConnect, .contactAddress, .ok, incognito=\(incognito?.description ?? "nil")") + if let incognito = incognito { + connectViaLink(connectionLink, connectionPlan: connectionPlan, dismiss: dismiss, incognito: incognito, cleanup: cleanup) + } else { + showActionSheet(.askCurrentOrIncognitoProfile(connectionLink: connectionLink, connectionPlan: connectionPlan, title: "Connect via contact address")) + } + case .ownLink: + logger.debug("planAndConnect, .contactAddress, .ownLink, incognito=\(incognito?.description ?? "nil")") + if let incognito = incognito { + showAlert(.ownContactAddressConfirmConnect(connectionLink: connectionLink, connectionPlan: connectionPlan, incognito: incognito)) + } else { + showActionSheet(.askCurrentOrIncognitoProfileDestructive(connectionLink: connectionLink, connectionPlan: connectionPlan, title: "Connect to yourself?\nThis is your own SimpleX address!")) + } + case .connectingConfirmReconnect: + logger.debug("planAndConnect, .contactAddress, .connectingConfirmReconnect, incognito=\(incognito?.description ?? "nil")") + if let incognito = incognito { + showAlert(.contactAddressConnectingConfirmReconnect(connectionLink: connectionLink, connectionPlan: connectionPlan, incognito: incognito)) + } else { + showActionSheet(.askCurrentOrIncognitoProfileDestructive(connectionLink: connectionLink, connectionPlan: connectionPlan, title: "You have already requested connection!\nRepeat connection request?")) + } + case let .connectingProhibit(contact): + logger.debug("planAndConnect, .contactAddress, .connectingProhibit, incognito=\(incognito?.description ?? "nil")") + if let f = filterKnownContact { + f(contact) + } else { + openKnownContact(contact, dismiss: dismiss) { AlertManager.shared.showAlert(contactAlreadyConnectingAlert(contact)) } + } + case let .known(contact): + logger.debug("planAndConnect, .contactAddress, .known, incognito=\(incognito?.description ?? "nil")") + if let f = filterKnownContact { + f(contact) + } else { + openKnownContact(contact, dismiss: dismiss) { AlertManager.shared.showAlert(contactAlreadyExistsAlert(contact)) } + } + case let .contactViaAddress(contact): + logger.debug("planAndConnect, .contactAddress, .contactViaAddress, incognito=\(incognito?.description ?? "nil")") + if let incognito = incognito { + connectContactViaAddress_(contact, dismiss: dismiss, incognito: incognito, cleanup: cleanup) + } else { + showActionSheet(.askCurrentOrIncognitoProfileConnectContactViaAddress(contact: contact)) + } + } + case let .groupLink(glp): + switch glp { + case .ok: + if let incognito = incognito { + showAlert(.groupLinkConfirmConnect(connectionLink: connectionLink, connectionPlan: connectionPlan, incognito: incognito)) + } else { + showActionSheet(.askCurrentOrIncognitoProfile(connectionLink: connectionLink, connectionPlan: connectionPlan, title: "Join group")) + } + case let .ownLink(groupInfo): + logger.debug("planAndConnect, .groupLink, .ownLink, incognito=\(incognito?.description ?? "nil")") + if let f = filterKnownGroup { + f(groupInfo) + } + showActionSheet(.ownGroupLinkConfirmConnect(connectionLink: connectionLink, connectionPlan: connectionPlan, incognito: incognito, groupInfo: groupInfo)) + case .connectingConfirmReconnect: + logger.debug("planAndConnect, .groupLink, .connectingConfirmReconnect, incognito=\(incognito?.description ?? "nil")") + if let incognito = incognito { + showAlert(.groupLinkConnectingConfirmReconnect(connectionLink: connectionLink, connectionPlan: connectionPlan, incognito: incognito)) + } else { + showActionSheet(.askCurrentOrIncognitoProfileDestructive(connectionLink: connectionLink, connectionPlan: connectionPlan, title: "You are already joining the group!\nRepeat join request?")) + } + case let .connectingProhibit(groupInfo_): + logger.debug("planAndConnect, .groupLink, .connectingProhibit, incognito=\(incognito?.description ?? "nil")") + showAlert(.groupLinkConnecting(connectionLink: connectionLink, groupInfo: groupInfo_)) + case let .known(groupInfo): + logger.debug("planAndConnect, .groupLink, .known, incognito=\(incognito?.description ?? "nil")") + if let f = filterKnownGroup { + f(groupInfo) + } else { + openKnownGroup(groupInfo, dismiss: dismiss) { AlertManager.shared.showAlert(groupAlreadyExistsAlert(groupInfo)) } + } + } + } + } catch { + logger.debug("planAndConnect, plan error") + if let incognito = incognito { + connectViaLink(connectionLink, connectionPlan: nil, dismiss: dismiss, incognito: incognito, cleanup: cleanup) + } else { + showActionSheet(.askCurrentOrIncognitoProfile(connectionLink: connectionLink, connectionPlan: nil, title: "Connect via link")) + } + } + } +} + +private func connectContactViaAddress_(_ contact: Contact, dismiss: Bool, incognito: Bool, cleanup: (() -> Void)? = nil) { + Task { + if dismiss { + DispatchQueue.main.async { + dismissAllSheets(animated: true) + } + } + _ = await connectContactViaAddress(contact.contactId, incognito) + cleanup?() + } +} + +private func connectViaLink( + _ connectionLink: String, + connectionPlan: ConnectionPlan?, + dismiss: Bool, + incognito: Bool, + cleanup: (() -> Void)? +) { + Task { + if let (connReqType, pcc) = await apiConnect(incognito: incognito, connReq: connectionLink) { + await MainActor.run { + ChatModel.shared.updateContactConnection(pcc) + } + let crt: ConnReqType + if let plan = connectionPlan { + crt = planToConnReqType(plan) + } else { + crt = connReqType + } + DispatchQueue.main.async { + if dismiss { + dismissAllSheets(animated: true) { + AlertManager.shared.showAlert(connReqSentAlert(crt)) + } + } else { + AlertManager.shared.showAlert(connReqSentAlert(crt)) + } + } + } else { + if dismiss { + DispatchQueue.main.async { + dismissAllSheets(animated: true) + } + } + } + cleanup?() + } +} + +func openKnownContact(_ contact: Contact, dismiss: Bool, showAlreadyExistsAlert: (() -> Void)?) { + Task { + let m = ChatModel.shared + if let c = m.getContactChat(contact.contactId) { + DispatchQueue.main.async { + if dismiss { + dismissAllSheets(animated: true) { + m.chatId = c.id + showAlreadyExistsAlert?() + } + } else { + m.chatId = c.id + showAlreadyExistsAlert?() + } + } + } + } +} + +func openKnownGroup(_ groupInfo: GroupInfo, dismiss: Bool, showAlreadyExistsAlert: (() -> Void)?) { + Task { + let m = ChatModel.shared + if let g = m.getGroupChat(groupInfo.groupId) { + DispatchQueue.main.async { + if dismiss { + dismissAllSheets(animated: true) { + m.chatId = g.id + showAlreadyExistsAlert?() + } + } else { + m.chatId = g.id + showAlreadyExistsAlert?() + } + } + } + } +} + +func contactAlreadyConnectingAlert(_ contact: Contact) -> Alert { + mkAlert( + title: "Contact already exists", + message: "You are already connecting to \(contact.displayName)." + ) +} + +func groupAlreadyExistsAlert(_ groupInfo: GroupInfo) -> Alert { + mkAlert( + title: "Group already exists", + message: "You are already in group \(groupInfo.displayName)." + ) +} + +enum ConnReqType: Equatable { + case invitation + case contact + case groupLink + + var connReqSentText: LocalizedStringKey { + switch self { + case .invitation: return "You will be connected when your contact's device is online, please wait or check later!" + case .contact: return "You will be connected when your connection request is accepted, please wait or check later!" + case .groupLink: return "You will be connected when group link host's device is online, please wait or check later!" + } + } +} + +private func planToConnReqType(_ connectionPlan: ConnectionPlan) -> ConnReqType { + switch connectionPlan { + case .invitationLink: return .invitation + case .contactAddress: return .contact + case .groupLink: return .groupLink + } +} + +func connReqSentAlert(_ type: ConnReqType) -> Alert { + return mkAlert( + title: "Connection request sent!", + message: type.connReqSentText + ) +} + +#Preview { + NewChatView( + selection: .invite + ) +} diff --git a/apps/ios/Shared/Views/NewChat/PasteToConnectView.swift b/apps/ios/Shared/Views/NewChat/PasteToConnectView.swift deleted file mode 100644 index 7c272fb631..0000000000 --- a/apps/ios/Shared/Views/NewChat/PasteToConnectView.swift +++ /dev/null @@ -1,106 +0,0 @@ -// -// PasteToConnectView.swift -// SimpleX (iOS) -// -// Created by Ian Davies on 22/04/2022. -// Copyright © 2022 SimpleX Chat. All rights reserved. -// - -import SwiftUI -import SimpleXChat - -struct PasteToConnectView: View { - @Environment(\.dismiss) var dismiss: DismissAction - @State private var connectionLink: String = "" - @AppStorage(GROUP_DEFAULT_INCOGNITO, store: groupDefaults) private var incognitoDefault = false - @FocusState private var linkEditorFocused: Bool - @State private var alert: PlanAndConnectAlert? - @State private var sheet: PlanAndConnectActionSheet? - - var body: some View { - List { - Text("Connect via link") - .font(.largeTitle) - .bold() - .fixedSize(horizontal: false, vertical: true) - .listRowBackground(Color.clear) - .listRowSeparator(.hidden) - .listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0)) - .onTapGesture { linkEditorFocused = false } - - Section { - linkEditor() - - Button { - if connectionLink == "" { - connectionLink = UIPasteboard.general.string ?? "" - } else { - connectionLink = "" - } - } label: { - if connectionLink == "" { - settingsRow("doc.plaintext") { Text("Paste") } - } else { - settingsRow("multiply") { Text("Clear") } - } - } - - Button { - connect() - } label: { - settingsRow("link") { Text("Connect") } - } - .disabled(connectionLink == "" || connectionLink.trimmingCharacters(in: .whitespaces).firstIndex(of: " ") != nil) - - IncognitoToggle(incognitoEnabled: $incognitoDefault) - } footer: { - VStack(alignment: .leading, spacing: 4) { - sharedProfileInfo(incognitoDefault) - Text("You can also connect by clicking the link. If it opens in the browser, click **Open in mobile app** button.") - } - .frame(maxWidth: .infinity, alignment: .leading) - } - } - .alert(item: $alert) { a in planAndConnectAlert(a, dismiss: true) } - .actionSheet(item: $sheet) { s in planAndConnectActionSheet(s, dismiss: true) } - } - - private func linkEditor() -> some View { - ZStack { - Group { - if connectionLink.isEmpty { - TextEditor(text: Binding.constant(NSLocalizedString("Paste the link you received to connect with your contact.", comment: "placeholder"))) - .foregroundColor(.secondary) - .disabled(true) - } - TextEditor(text: $connectionLink) - .onSubmit(connect) - .textInputAutocapitalization(.never) - .disableAutocorrection(true) - .focused($linkEditorFocused) - } - .allowsTightening(false) - .padding(.horizontal, -5) - .padding(.top, -8) - .frame(height: 180, alignment: .topLeading) - .frame(maxWidth: .infinity, alignment: .leading) - } - } - - private func connect() { - let link = connectionLink.trimmingCharacters(in: .whitespaces) - planAndConnect( - link, - showAlert: { alert = $0 }, - showActionSheet: { sheet = $0 }, - dismiss: true, - incognito: incognitoDefault - ) - } -} - -struct PasteToConnectView_Previews: PreviewProvider { - static var previews: some View { - PasteToConnectView() - } -} diff --git a/apps/ios/Shared/Views/NewChat/QRCode.swift b/apps/ios/Shared/Views/NewChat/QRCode.swift index 3ddb85079c..e3bae9287a 100644 --- a/apps/ios/Shared/Views/NewChat/QRCode.swift +++ b/apps/ios/Shared/Views/NewChat/QRCode.swift @@ -24,9 +24,10 @@ struct SimpleXLinkQRCode: View { let uri: String var withLogo: Bool = true var tintColor = UIColor(red: 0.023, green: 0.176, blue: 0.337, alpha: 1) + var onShare: (() -> Void)? = nil var body: some View { - QRCode(uri: simplexChatLink(uri), withLogo: withLogo, tintColor: tintColor) + QRCode(uri: simplexChatLink(uri), withLogo: withLogo, tintColor: tintColor, onShare: onShare) } } @@ -40,6 +41,7 @@ struct QRCode: View { let uri: String var withLogo: Bool = true var tintColor = UIColor(red: 0.023, green: 0.176, blue: 0.337, alpha: 1) + var onShare: (() -> Void)? = nil @State private var image: UIImage? = nil @State private var makeScreenshotFunc: () -> Void = {} @@ -65,6 +67,7 @@ struct QRCode: View { makeScreenshotFunc = { let size = CGSizeMake(1024 / UIScreen.main.scale, 1024 / UIScreen.main.scale) showShareSheet(items: [makeScreenshot(geo.frame(in: .local).origin, size)]) + onShare?() } } .frame(width: geo.size.width, height: geo.size.height) diff --git a/apps/ios/Shared/Views/NewChat/ScanToConnectView.swift b/apps/ios/Shared/Views/NewChat/ScanToConnectView.swift deleted file mode 100644 index 7f3f5e02f8..0000000000 --- a/apps/ios/Shared/Views/NewChat/ScanToConnectView.swift +++ /dev/null @@ -1,79 +0,0 @@ -// -// ConnectContactView.swift -// SimpleX -// -// Created by Evgeny Poberezkin on 29/01/2022. -// Copyright © 2022 SimpleX Chat. All rights reserved. -// - -import SwiftUI -import SimpleXChat -import CodeScanner - -struct ScanToConnectView: View { - @Environment(\.dismiss) var dismiss: DismissAction - @AppStorage(GROUP_DEFAULT_INCOGNITO, store: groupDefaults) private var incognitoDefault = false - @State private var alert: PlanAndConnectAlert? - @State private var sheet: PlanAndConnectActionSheet? - - var body: some View { - ScrollView { - VStack(alignment: .leading) { - Text("Scan QR code") - .font(.largeTitle) - .bold() - .fixedSize(horizontal: false, vertical: true) - .padding(.vertical) - - CodeScannerView(codeTypes: [.qr], scanMode: .continuous, completion: processQRCode) - .aspectRatio(1, contentMode: .fit) - .cornerRadius(12) - - IncognitoToggle(incognitoEnabled: $incognitoDefault) - .padding(.horizontal) - .padding(.vertical, 6) - .background( - RoundedRectangle(cornerRadius: 12, style: .continuous) - .fill(Color(uiColor: .systemBackground)) - ) - .padding(.top) - - VStack(alignment: .leading, spacing: 4) { - sharedProfileInfo(incognitoDefault) - Text("If you cannot meet in person, you can **scan QR code in the video call**, or your contact can share an invitation link.") - } - .frame(maxWidth: .infinity, alignment: .leading) - .font(.footnote) - .foregroundColor(.secondary) - .padding(.horizontal) - } - .padding() - .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top) - } - .background(Color(.systemGroupedBackground)) - .alert(item: $alert) { a in planAndConnectAlert(a, dismiss: true) } - .actionSheet(item: $sheet) { s in planAndConnectActionSheet(s, dismiss: true) } - } - - func processQRCode(_ resp: Result) { - switch resp { - case let .success(r): - planAndConnect( - r.string, - showAlert: { alert = $0 }, - showActionSheet: { sheet = $0 }, - dismiss: true, - incognito: incognitoDefault - ) - case let .failure(e): - logger.error("ConnectContactView.processQRCode QR code error: \(e.localizedDescription)") - dismiss() - } - } -} - -struct ConnectContactView_Previews: PreviewProvider { - static var previews: some View { - ScanToConnectView() - } -} diff --git a/apps/ios/Shared/Views/UserSettings/IncognitoHelp.swift b/apps/ios/Shared/Views/UserSettings/IncognitoHelp.swift index 20dadb7954..fc478596a9 100644 --- a/apps/ios/Shared/Views/UserSettings/IncognitoHelp.swift +++ b/apps/ios/Shared/Views/UserSettings/IncognitoHelp.swift @@ -10,24 +10,23 @@ import SwiftUI struct IncognitoHelp: View { var body: some View { - VStack(alignment: .leading) { + List { Text("Incognito mode") .font(.largeTitle) .bold() + .fixedSize(horizontal: false, vertical: true) .padding(.vertical) - ScrollView { - VStack(alignment: .leading) { - Group { - Text("Incognito mode protects your privacy by using a new random profile for each contact.") - Text("It allows having many anonymous connections without any shared data between them in a single chat profile.") - Text("When you share an incognito profile with somebody, this profile will be used for the groups they invite you to.") - } - .padding(.bottom) - } + .listRowBackground(Color.clear) + .listRowSeparator(.hidden) + .listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0)) + VStack(alignment: .leading, spacing: 18) { + Text("Incognito mode protects your privacy by using a new random profile for each contact.") + Text("It allows having many anonymous connections without any shared data between them in a single chat profile.") + Text("When you share an incognito profile with somebody, this profile will be used for the groups they invite you to.") + Text("Read more in [User Guide](https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode).") } + .listRowBackground(Color.clear) } - .frame(maxWidth: .infinity) - .padding() } } diff --git a/apps/ios/Shared/Views/UserSettings/SettingsView.swift b/apps/ios/Shared/Views/UserSettings/SettingsView.swift index f889d9c394..b73d6b867d 100644 --- a/apps/ios/Shared/Views/UserSettings/SettingsView.swift +++ b/apps/ios/Shared/Views/UserSettings/SettingsView.swift @@ -95,6 +95,12 @@ let appDefaults: [String: Any] = [ DEFAULT_CONNECT_REMOTE_VIA_MULTICAST_AUTO: true, ] +// not used anymore +enum ConnectViaLinkTab: String { + case scan + case paste +} + enum SimpleXLinkMode: String, Identifiable { case description case full 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 44f2d878e6..506df8cf17 100644 --- a/apps/ios/SimpleX Localizations/bg.xcloc/Localized Contents/bg.xliff +++ b/apps/ios/SimpleX Localizations/bg.xcloc/Localized Contents/bg.xliff @@ -303,14 +303,17 @@ ) No comment provided by engineer. + + **Add contact**: to create a new invitation link, or connect via a link you received. + No comment provided by engineer. + **Add new contact**: to create your one-time QR Code or link for your contact. **Добави нов контакт**: за да създадете своя еднократен QR код или линк за вашия контакт. No comment provided by engineer. - - **Create link / QR code** for your contact to use. - **Създай линк / QR код**, който вашият контакт да използва. + + **Create group**: to create a new group. No comment provided by engineer. @@ -323,11 +326,6 @@ **Най-поверително**: не използвайте сървъра за известия SimpleX Chat, периодично проверявайте съобщенията във фонов режим (зависи от това колко често използвате приложението). No comment provided by engineer. - - **Paste received link** or open it in the browser and tap **Open in mobile app**. - **Поставете получения линк** или го отворете в браузъра и докоснете **Отваряне в мобилно приложение**. - No comment provided by engineer. - **Please note**: you will NOT be able to recover or change passphrase if you lose it. **Моля, обърнете внимание**: НЯМА да можете да възстановите или промените паролата, ако я загубите. @@ -338,11 +336,6 @@ **Препоръчително**: токенът на устройството и известията се изпращат до сървъра за уведомяване на SimpleX Chat, но не и съдържанието, размерът на съобщението или от кого е. No comment provided by engineer. - - **Scan QR code**: to connect to your contact in person or via video call. - **Сканирай QR код**: за да се свържете с вашия контакт лично или чрез видеообаждане. - No comment provided by engineer. - **Warning**: Instant push notifications require passphrase saved in Keychain. **Внимание**: Незабавните push известия изискват парола, запазена в Keychain. @@ -440,11 +433,6 @@ 1 седмица time interval - - 1-time link - Еднократен линк - No comment provided by engineer. - 5 minutes 5 минути @@ -560,6 +548,10 @@ Добавете адрес към вашия профил, така че вашите контакти да могат да го споделят с други хора. Актуализацията на профила ще бъде изпратена до вашите контакти. No comment provided by engineer. + + Add contact + No comment provided by engineer. + Add preset servers Добави предварително зададени сървъри @@ -956,6 +948,10 @@ Обаждания No comment provided by engineer. + + Camera not available + No comment provided by engineer. + Can't delete user profile! Потребителският профил не може да се изтрие! @@ -1212,11 +1208,6 @@ This is your own one-time link! Свърване чрез линк No comment provided by engineer. - - Connect via link / QR code - Свърване чрез линк/QR код - No comment provided by engineer. - Connect via one-time link Свързване чрез еднократен линк за връзка @@ -1384,11 +1375,6 @@ This is your own one-time link! Създайте нов профил в [настолното приложение](https://simplex.chat/downloads/). 💻 No comment provided by engineer. - - Create one-time invitation link - Създай линк за еднократна покана - No comment provided by engineer. - Create profile No comment provided by engineer. @@ -1413,6 +1399,10 @@ This is your own one-time link! Създаден на %@ No comment provided by engineer. + + Creating link… + No comment provided by engineer. + Current Passcode Текущ kод за достъп @@ -1954,6 +1944,10 @@ This cannot be undone! Активиране на автоматично изтриване на съобщения? No comment provided by engineer. + + Enable camera access + No comment provided by engineer. + Enable for all Активиране за всички @@ -2292,6 +2286,10 @@ This cannot be undone! Грешка при запазване на потребителска парола No comment provided by engineer. + + Error scanning code: %@ + No comment provided by engineer. + Error sending email Грешка при изпращане на имейл @@ -2761,11 +2759,6 @@ This cannot be undone! Ако не можете да се срещнете лично, покажете QR код във видеоразговора или споделете линка. No comment provided by engineer. - - If you cannot meet in person, you can **scan QR code in the video call**, or your contact can share an invitation link. - Ако не можете да се срещнете на живо, можете да **сканирате QR код във видеообаждането** или вашият контакт може да сподели линк за покана. - No comment provided by engineer. - If you enter this passcode when opening the app, all app data will be irreversibly removed! Ако въведете този kод за достъп, когато отваряте приложението, всички данни от приложението ще бъдат необратимо изтрити! @@ -2921,11 +2914,19 @@ This cannot be undone! Интерфейс No comment provided by engineer. + + Invalid QR code + No comment provided by engineer. + Invalid connection link Невалиден линк за връзка No comment provided by engineer. + + Invalid link + No comment provided by engineer. + Invalid name! No comment provided by engineer. @@ -3048,10 +3049,18 @@ This is your link for group %@! Присъединяване към групата No comment provided by engineer. + + Keep + No comment provided by engineer. + Keep the app open to use it from desktop No comment provided by engineer. + + Keep unused invitation? + No comment provided by engineer. + Keep your connections Запазете връзките си @@ -3378,6 +3387,10 @@ This is your link for group %@! Нов kод за достъп No comment provided by engineer. + + New chat + No comment provided by engineer. + New contact request Нова заявка за контакт @@ -3501,6 +3514,10 @@ This is your link for group %@! - да деактивират членове (роля "наблюдател") No comment provided by engineer. + + OK + No comment provided by engineer. + Off Изключено @@ -3649,6 +3666,14 @@ This is your link for group %@! Opening app… No comment provided by engineer. + + Or scan QR code + No comment provided by engineer. + + + Or show this code + No comment provided by engineer. + PING count PING бройка @@ -3689,11 +3714,6 @@ This is your link for group %@! Парола за показване No comment provided by engineer. - - Paste - Постави - No comment provided by engineer. - Paste desktop address No comment provided by engineer. @@ -3703,16 +3723,10 @@ This is your link for group %@! Постави изображение No comment provided by engineer. - - Paste received link - Постави получения линк + + Paste the link you received No comment provided by engineer. - - Paste the link you received to connect with your contact. - Поставете линка, който сте получили, за да се свържете с вашия контакт. - placeholder - People can connect to you only via the links you share. Хората могат да се свържат с вас само чрез ликовете, които споделяте. @@ -3956,6 +3970,10 @@ Error: %@ Прочетете повече в [Ръководство за потребителя](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address). No comment provided by engineer. + + Read more in [User Guide](https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode). + No comment provided by engineer. + Read more in [User Guide](https://simplex.chat/docs/guide/readme.html#connect-to-friends). Прочетете повече в [Ръководство на потребителя](https://simplex.chat/docs/guide/readme.html#connect-to-friends). @@ -4164,6 +4182,10 @@ Error: %@ Грешка при възстановяване на базата данни No comment provided by engineer. + + Retry + No comment provided by engineer. + Reveal Покажи @@ -4318,6 +4340,10 @@ Error: %@ Търсене No comment provided by engineer. + + Search or paste SimpleX link + No comment provided by engineer. + Secure queue Сигурна опашка @@ -4592,9 +4618,8 @@ Error: %@ Сподели линк No comment provided by engineer. - - Share one-time invitation link - Сподели линк за еднократна покана + + Share this 1-time invite link No comment provided by engineer. @@ -4717,11 +4742,6 @@ Error: %@ Някой notification title - - Start a new chat - Започни нов чат - No comment provided by engineer. - Start chat Започни чат @@ -4855,6 +4875,14 @@ Error: %@ Докосни за инкогнито вход No comment provided by engineer. + + Tap to paste link + No comment provided by engineer. + + + Tap to scan + No comment provided by engineer. + Tap to start a new chat Докосни за започване на нов чат @@ -4917,6 +4945,10 @@ It can happen because of some bug or when the connection is compromised.Опитът за промяна на паролата на базата данни не беше завършен. No comment provided by engineer. + + The code you scanned is not a SimpleX link QR code. + No comment provided by engineer. + The connection you accepted will be cancelled! Връзката, която приехте, ще бъде отказана! @@ -4982,6 +5014,10 @@ It can happen because of some bug or when the connection is compromised.Сървърите за нови връзки на текущия ви чат профил **%@**. No comment provided by engineer. + + The text you pasted is not a SimpleX link. + No comment provided by engineer. + Theme Тема @@ -5579,11 +5615,6 @@ Repeat join request? Можете да приемате обаждания от заключен екран, без идентификация на устройство и приложението. No comment provided by engineer. - - You can also connect by clicking the link. If it opens in the browser, click **Open in mobile app** button. - Можете също да се свържете, като натиснете върху линка. Ако се отвори в браузъра, натиснете върху бутона **Отваряне в мобилно приложение**. - No comment provided by engineer. - You can create it later Можете да го създадете по-късно @@ -5648,6 +5679,10 @@ Repeat join request? Можете да използвате markdown за форматиране на съобщенията: No comment provided by engineer. + + You can view invitation link again in connection details. + No comment provided by engineer. + You can't send messages! Не може да изпращате съобщения! 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 f0abba7bb2..076c2c97fb 100644 --- a/apps/ios/SimpleX Localizations/cs.xcloc/Localized Contents/cs.xliff +++ b/apps/ios/SimpleX Localizations/cs.xcloc/Localized Contents/cs.xliff @@ -303,14 +303,17 @@ ) No comment provided by engineer. + + **Add contact**: to create a new invitation link, or connect via a link you received. + No comment provided by engineer. + **Add new contact**: to create your one-time QR Code or link for your contact. **Přidat nový kontakt**: pro vytvoření jednorázového QR kódu nebo odkazu pro váš kontakt. No comment provided by engineer. - - **Create link / QR code** for your contact to use. - **Vytvořte odkaz / QR kód** pro váš kontakt. + + **Create group**: to create a new group. No comment provided by engineer. @@ -323,11 +326,6 @@ **Nejsoukromější**: nepoužívejte server oznámení SimpleX Chat, pravidelně kontrolujte zprávy na pozadí (závisí na tom, jak často aplikaci používáte). No comment provided by engineer. - - **Paste received link** or open it in the browser and tap **Open in mobile app**. - **Vložte přijatý odkaz** nebo jej otevřete v prohlížeči a klepněte na **Otevřít v mobilní aplikaci**. - No comment provided by engineer. - **Please note**: you will NOT be able to recover or change passphrase if you lose it. **Upozornění**: Pokud heslo ztratíte, NEBUDETE jej moci obnovit ani změnit. @@ -338,11 +336,6 @@ **Doporučeno**: Token zařízení a oznámení se odesílají na oznamovací server SimpleX Chat, ale nikoli obsah, velikost nebo od koho jsou zprávy. No comment provided by engineer. - - **Scan QR code**: to connect to your contact in person or via video call. - ** Naskenujte QR kód**: pro připojení ke kontaktu osobně nebo prostřednictvím videohovoru. - No comment provided by engineer. - **Warning**: Instant push notifications require passphrase saved in Keychain. **Upozornění**: Okamžitě doručovaná oznámení vyžadují přístupové heslo uložené v Klíčence. @@ -440,11 +433,6 @@ 1 týden time interval - - 1-time link - Jednorázový odkaz - No comment provided by engineer. - 5 minutes 5 minut @@ -560,6 +548,10 @@ Přidejte adresu do svého profilu, aby ji vaše kontakty mohly sdílet s dalšími lidmi. Aktualizace profilu bude zaslána vašim kontaktům. No comment provided by engineer. + + Add contact + No comment provided by engineer. + Add preset servers Přidejte přednastavené servery @@ -956,6 +948,10 @@ Hovory No comment provided by engineer. + + Camera not available + No comment provided by engineer. + Can't delete user profile! Nemohu smazat uživatelský profil! @@ -1212,11 +1208,6 @@ This is your own one-time link! Připojte se prostřednictvím odkazu No comment provided by engineer. - - Connect via link / QR code - Připojit se prostřednictvím odkazu / QR kódu - No comment provided by engineer. - Connect via one-time link Připojit se jednorázovým odkazem @@ -1384,11 +1375,6 @@ This is your own one-time link! Vytvořit nový profil v [desktop app](https://simplex.chat/downloads/). 💻 No comment provided by engineer. - - Create one-time invitation link - Vytvořit jednorázovou pozvánku - No comment provided by engineer. - Create profile No comment provided by engineer. @@ -1413,6 +1399,10 @@ This is your own one-time link! Vytvořeno na %@ No comment provided by engineer. + + Creating link… + No comment provided by engineer. + Current Passcode Aktuální heslo @@ -1954,6 +1944,10 @@ This cannot be undone! Povolit automatické mazání zpráv? No comment provided by engineer. + + Enable camera access + No comment provided by engineer. + Enable for all Povolit pro všechny @@ -2292,6 +2286,10 @@ This cannot be undone! Chyba ukládání hesla uživatele No comment provided by engineer. + + Error scanning code: %@ + No comment provided by engineer. + Error sending email Chyba odesílání e-mailu @@ -2761,11 +2759,6 @@ This cannot be undone! Pokud se nemůžete setkat osobně, zobrazte QR kód ve videohovoru nebo sdílejte odkaz. No comment provided by engineer. - - If you cannot meet in person, you can **scan QR code in the video call**, or your contact can share an invitation link. - Pokud se nemůžete setkat osobně, můžete **naskenovat QR kód během videohovoru**, nebo váš kontakt může sdílet odkaz na pozvánku. - No comment provided by engineer. - If you enter this passcode when opening the app, all app data will be irreversibly removed! Pokud tento přístupový kód zadáte při otevření aplikace, všechna data budou nenávratně smazána! @@ -2921,11 +2914,19 @@ This cannot be undone! Rozhranní No comment provided by engineer. + + Invalid QR code + No comment provided by engineer. + Invalid connection link Neplatný odkaz na spojení No comment provided by engineer. + + Invalid link + No comment provided by engineer. + Invalid name! No comment provided by engineer. @@ -3048,10 +3049,18 @@ This is your link for group %@! Připojování ke skupině No comment provided by engineer. + + Keep + No comment provided by engineer. + Keep the app open to use it from desktop No comment provided by engineer. + + Keep unused invitation? + No comment provided by engineer. + Keep your connections Zachovat vaše připojení @@ -3378,6 +3387,10 @@ This is your link for group %@! Nové heslo No comment provided by engineer. + + New chat + No comment provided by engineer. + New contact request Žádost o nový kontakt @@ -3501,6 +3514,10 @@ This is your link for group %@! - zakázat členy (role "pozorovatel") No comment provided by engineer. + + OK + No comment provided by engineer. + Off Vypnout @@ -3649,6 +3666,14 @@ This is your link for group %@! Opening app… No comment provided by engineer. + + Or scan QR code + No comment provided by engineer. + + + Or show this code + No comment provided by engineer. + PING count Počet PING @@ -3689,11 +3714,6 @@ This is your link for group %@! Heslo k zobrazení No comment provided by engineer. - - Paste - Vložit - No comment provided by engineer. - Paste desktop address No comment provided by engineer. @@ -3703,16 +3723,10 @@ This is your link for group %@! Vložit obrázek No comment provided by engineer. - - Paste received link - Vložení přijatého odkazu + + Paste the link you received No comment provided by engineer. - - Paste the link you received to connect with your contact. - Vložte odkaz, který jste obdrželi, do pole níže a spojte se se svým kontaktem. - placeholder - People can connect to you only via the links you share. Lidé se s vámi mohou spojit pouze prostřednictvím odkazů, které sdílíte. @@ -3956,6 +3970,10 @@ Error: %@ Další informace naleznete v [Uživatelské příručce](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address). No comment provided by engineer. + + Read more in [User Guide](https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode). + No comment provided by engineer. + Read more in [User Guide](https://simplex.chat/docs/guide/readme.html#connect-to-friends). Přečtěte si více v [Uživatelské příručce](https://simplex.chat/docs/guide/readme.html#connect-to-friends). @@ -4164,6 +4182,10 @@ Error: %@ Chyba obnovení databáze No comment provided by engineer. + + Retry + No comment provided by engineer. + Reveal Odhalit @@ -4318,6 +4340,10 @@ Error: %@ Hledat No comment provided by engineer. + + Search or paste SimpleX link + No comment provided by engineer. + Secure queue Zabezpečit frontu @@ -4592,9 +4618,8 @@ Error: %@ Sdílet odkaz No comment provided by engineer. - - Share one-time invitation link - Jednorázový zvací odkaz + + Share this 1-time invite link No comment provided by engineer. @@ -4717,11 +4742,6 @@ Error: %@ Někdo notification title - - Start a new chat - Začít nový chat - No comment provided by engineer. - Start chat Začít chat @@ -4855,6 +4875,14 @@ Error: %@ Klepnutím se připojíte inkognito No comment provided by engineer. + + Tap to paste link + No comment provided by engineer. + + + Tap to scan + No comment provided by engineer. + Tap to start a new chat Klepnutím na zahájíte nový chat @@ -4917,6 +4945,10 @@ Může se to stát kvůli nějaké chybě, nebo pokud je spojení kompromitován Pokus o změnu přístupové fráze databáze nebyl dokončen. No comment provided by engineer. + + The code you scanned is not a SimpleX link QR code. + No comment provided by engineer. + The connection you accepted will be cancelled! Připojení, které jste přijali, bude zrušeno! @@ -4982,6 +5014,10 @@ Může se to stát kvůli nějaké chybě, nebo pokud je spojení kompromitován Servery pro nová připojení vašeho aktuálního chat profilu **%@**. No comment provided by engineer. + + The text you pasted is not a SimpleX link. + No comment provided by engineer. + Theme Téma @@ -5579,11 +5615,6 @@ Repeat join request? Můžete přijímat hovory z obrazovky zámku, bez ověření zařízení a aplikace. No comment provided by engineer. - - You can also connect by clicking the link. If it opens in the browser, click **Open in mobile app** button. - Můžete se také připojit kliknutím na odkaz. Pokud se otevře v prohlížeči, klikněte na tlačítko **Otevřít v mobilní aplikaci**. - No comment provided by engineer. - You can create it later Můžete vytvořit později @@ -5648,6 +5679,10 @@ Repeat join request? K formátování zpráv můžete použít markdown: No comment provided by engineer. + + You can view invitation link again in connection details. + No comment provided by engineer. + You can't send messages! Nemůžete posílat zprávy! 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 dda89f5c0c..2b877c32d2 100644 --- a/apps/ios/SimpleX Localizations/de.xcloc/Localized Contents/de.xliff +++ b/apps/ios/SimpleX Localizations/de.xcloc/Localized Contents/de.xliff @@ -312,14 +312,17 @@ ) No comment provided by engineer. + + **Add contact**: to create a new invitation link, or connect via a link you received. + No comment provided by engineer. + **Add new contact**: to create your one-time QR Code or link for your contact. **Fügen Sie einen neuen Kontakt hinzu**: Erzeugen Sie einen Einmal-QR-Code oder -Link für Ihren Kontakt. No comment provided by engineer. - - **Create link / QR code** for your contact to use. - **Generieren Sie einen Einladungs-Link / QR code** für Ihren Kontakt. + + **Create group**: to create a new group. No comment provided by engineer. @@ -332,11 +335,6 @@ **Beste Privatsphäre**: Es wird kein SimpleX-Chat-Benachrichtigungs-Server genutzt, Nachrichten werden in periodischen Abständen im Hintergrund geprüft (dies hängt davon ab, wie häufig Sie die App nutzen). No comment provided by engineer. - - **Paste received link** or open it in the browser and tap **Open in mobile app**. - **Fügen Sie den von Ihrem Kontakt erhaltenen Link ein** oder öffnen Sie ihn im Browser und tippen Sie auf **In mobiler App öffnen**. - No comment provided by engineer. - **Please note**: you will NOT be able to recover or change passphrase if you lose it. **Bitte beachten Sie**: Das Passwort kann NICHT wiederhergestellt oder geändert werden, wenn Sie es vergessen haben oder verlieren. @@ -347,11 +345,6 @@ **Empfohlen**: Nur Ihr Geräte-Token und ihre Benachrichtigungen werden an den SimpleX-Chat-Benachrichtigungs-Server gesendet, aber weder der Nachrichteninhalt noch deren Größe oder von wem sie gesendet wurde. No comment provided by engineer. - - **Scan QR code**: to connect to your contact in person or via video call. - **Scannen Sie den QR-Code**, um sich während einem persönlichen Treffen oder per Videoanruf mit Ihrem Kontakt zu verbinden. - No comment provided by engineer. - **Warning**: Instant push notifications require passphrase saved in Keychain. **Warnung**: Sofortige Push-Benachrichtigungen erfordern die Eingabe eines Passworts, welches in Ihrem Schlüsselbund gespeichert ist. @@ -453,11 +446,6 @@ wöchentlich time interval - - 1-time link - Einmal-Link - No comment provided by engineer. - 5 minutes 5 Minuten @@ -573,6 +561,10 @@ Fügen Sie die Adresse zu Ihrem Profil hinzu, damit Ihre Kontakte sie mit anderen Personen teilen können. Es wird eine Profilaktualisierung an Ihre Kontakte gesendet. No comment provided by engineer. + + Add contact + No comment provided by engineer. + Add preset servers Füge voreingestellte Server hinzu @@ -978,6 +970,10 @@ Anrufe No comment provided by engineer. + + Camera not available + No comment provided by engineer. + Can't delete user profile! Das Benutzerprofil kann nicht gelöscht werden! @@ -1242,11 +1238,6 @@ Das ist Ihr eigener Einmal-Link! Über einen Link verbinden No comment provided by engineer. - - Connect via link / QR code - Über einen Link / QR-Code verbinden - No comment provided by engineer. - Connect via one-time link Über einen Einmal-Link verbinden @@ -1422,11 +1413,6 @@ Das ist Ihr eigener Einmal-Link! Neues Profil in der [Desktop-App] erstellen (https://simplex.chat/downloads/). 💻 No comment provided by engineer. - - Create one-time invitation link - Einmal-Einladungslink erstellen - No comment provided by engineer. - Create profile Profil erstellen @@ -1452,6 +1438,10 @@ Das ist Ihr eigener Einmal-Link! Erstellt am %@ No comment provided by engineer. + + Creating link… + No comment provided by engineer. + Current Passcode Aktueller Zugangscode @@ -2002,6 +1992,10 @@ Das kann nicht rückgängig gemacht werden! Automatisches Löschen von Nachrichten aktivieren? No comment provided by engineer. + + Enable camera access + No comment provided by engineer. + Enable for all Für Alle aktivieren @@ -2345,6 +2339,10 @@ Das kann nicht rückgängig gemacht werden! Fehler beim Speichern des Benutzer-Passworts No comment provided by engineer. + + Error scanning code: %@ + No comment provided by engineer. + Error sending email Fehler beim Senden der eMail @@ -2820,11 +2818,6 @@ Das kann nicht rückgängig gemacht werden! Falls Sie sich nicht persönlich treffen können, zeigen Sie den QR-Code in einem Videoanruf oder teilen Sie den Link. No comment provided by engineer. - - If you cannot meet in person, you can **scan QR code in the video call**, or your contact can share an invitation link. - Wenn Sie sich nicht persönlich treffen können, kann der **QR-Code während eines Videoanrufs gescannt werden**, oder Ihr Kontakt kann den Einladungslink über einen anderen Kanal mit Ihnen teilen. - No comment provided by engineer. - If you enter this passcode when opening the app, all app data will be irreversibly removed! Wenn Sie diesen Zugangscode während des Öffnens der App eingeben, werden alle App-Daten unwiederbringlich gelöscht! @@ -2982,11 +2975,19 @@ Das kann nicht rückgängig gemacht werden! Schnittstelle No comment provided by engineer. + + Invalid QR code + No comment provided by engineer. + Invalid connection link Ungültiger Verbindungslink No comment provided by engineer. + + Invalid link + No comment provided by engineer. + Invalid name! Ungültiger Name! @@ -3114,11 +3115,19 @@ Das ist Ihr Link für die Gruppe %@! Der Gruppe beitreten No comment provided by engineer. + + Keep + No comment provided by engineer. + Keep the app open to use it from desktop Die App muss geöffnet bleiben, um sie vom Desktop aus nutzen zu können No comment provided by engineer. + + Keep unused invitation? + No comment provided by engineer. + Keep your connections Ihre Verbindungen beibehalten @@ -3449,6 +3458,10 @@ Das ist Ihr Link für die Gruppe %@! Neuer Zugangscode No comment provided by engineer. + + New chat + No comment provided by engineer. + New contact request Neue Kontaktanfrage @@ -3573,6 +3586,10 @@ Das ist Ihr Link für die Gruppe %@! - Gruppenmitglieder deaktivieren ("Beobachter"-Rolle) No comment provided by engineer. + + OK + No comment provided by engineer. + Off Aus @@ -3722,6 +3739,14 @@ Das ist Ihr Link für die Gruppe %@! Opening app… No comment provided by engineer. + + Or scan QR code + No comment provided by engineer. + + + Or show this code + No comment provided by engineer. + PING count PING-Zähler @@ -3762,11 +3787,6 @@ Das ist Ihr Link für die Gruppe %@! Passwort anzeigen No comment provided by engineer. - - Paste - Einfügen - No comment provided by engineer. - Paste desktop address Desktop-Adresse einfügen @@ -3777,16 +3797,10 @@ Das ist Ihr Link für die Gruppe %@! Bild einfügen No comment provided by engineer. - - Paste received link - Fügen Sie den erhaltenen Link ein + + Paste the link you received No comment provided by engineer. - - Paste the link you received to connect with your contact. - Um sich mit Ihrem Kontakt zu verbinden, fügen Sie den erhaltenen Link in das Feld unten ein. - placeholder - People can connect to you only via the links you share. Verbindungen mit Kontakten sind nur über Links möglich, die Sie oder Ihre Kontakte untereinander teilen. @@ -4032,6 +4046,10 @@ Error: %@ Mehr dazu in der [Benutzeranleitung](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address) lesen. No comment provided by engineer. + + Read more in [User Guide](https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode). + No comment provided by engineer. + Read more in [User Guide](https://simplex.chat/docs/guide/readme.html#connect-to-friends). Mehr dazu in der [Benutzeranleitung](https://simplex.chat/docs/guide/readme.html#connect-to-friends) lesen. @@ -4242,6 +4260,10 @@ Error: %@ Fehler bei der Wiederherstellung der Datenbank No comment provided by engineer. + + Retry + No comment provided by engineer. + Reveal Aufdecken @@ -4397,6 +4419,10 @@ Error: %@ Suche No comment provided by engineer. + + Search or paste SimpleX link + No comment provided by engineer. + Secure queue Sichere Warteschlange @@ -4672,9 +4698,8 @@ Error: %@ Link teilen No comment provided by engineer. - - Share one-time invitation link - Einmal-Einladungslink teilen + + Share this 1-time invite link No comment provided by engineer. @@ -4797,11 +4822,6 @@ Error: %@ Jemand notification title - - Start a new chat - Starten Sie einen neuen Chat - No comment provided by engineer. - Start chat Starten Sie den Chat @@ -4936,6 +4956,14 @@ Error: %@ Tippen, um Inkognito beizutreten No comment provided by engineer. + + Tap to paste link + No comment provided by engineer. + + + Tap to scan + No comment provided by engineer. + Tap to start a new chat Tippen, um einen neuen Chat zu starten @@ -4998,6 +5026,10 @@ Dies kann passieren, wenn es einen Fehler gegeben hat oder die Verbindung kompro Die Änderung des Datenbank-Passworts konnte nicht abgeschlossen werden. No comment provided by engineer. + + The code you scanned is not a SimpleX link QR code. + No comment provided by engineer. + The connection you accepted will be cancelled! Die von Ihnen akzeptierte Verbindung wird abgebrochen! @@ -5063,6 +5095,10 @@ Dies kann passieren, wenn es einen Fehler gegeben hat oder die Verbindung kompro Server der neuen Verbindungen von Ihrem aktuellen Chat-Profil **%@**. No comment provided by engineer. + + The text you pasted is not a SimpleX link. + No comment provided by engineer. + Theme Design @@ -5683,11 +5719,6 @@ Verbindungsanfrage wiederholen? Sie können Anrufe ohne Geräte- und App-Authentifizierung vom Sperrbildschirm aus annehmen. No comment provided by engineer. - - You can also connect by clicking the link. If it opens in the browser, click **Open in mobile app** button. - Sie können sich auch verbinden, indem Sie auf den Link klicken. Wenn er im Browser geöffnet wird, klicken Sie auf die Schaltfläche **In mobiler App öffnen**. - No comment provided by engineer. - You can create it later Sie können dies später erstellen @@ -5752,6 +5783,10 @@ Verbindungsanfrage wiederholen? Um Nachrichteninhalte zu formatieren, können Sie Markdowns verwenden: No comment provided by engineer. + + You can view invitation link again in connection details. + No comment provided by engineer. + You can't send messages! Sie können keine Nachrichten versenden! 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 4544b823f7..7dd5db3b65 100644 --- a/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff +++ b/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff @@ -312,14 +312,19 @@ ) No comment provided by engineer. + + **Add contact**: to create a new invitation link, or connect via a link you received. + **Add contact**: to create a new invitation link, or connect via a link you received. + No comment provided by engineer. + **Add new contact**: to create your one-time QR Code or link for your contact. **Add new contact**: to create your one-time QR Code or link for your contact. No comment provided by engineer. - - **Create link / QR code** for your contact to use. - **Create link / QR code** for your contact to use. + + **Create group**: to create a new group. + **Create group**: to create a new group. No comment provided by engineer. @@ -332,11 +337,6 @@ **Most private**: do not use SimpleX Chat notifications server, check messages periodically in the background (depends on how often you use the app). No comment provided by engineer. - - **Paste received link** or open it in the browser and tap **Open in mobile app**. - **Paste received link** or open it in the browser and tap **Open in mobile app**. - No comment provided by engineer. - **Please note**: you will NOT be able to recover or change passphrase if you lose it. **Please note**: you will NOT be able to recover or change passphrase if you lose it. @@ -347,11 +347,6 @@ **Recommended**: device token and notifications are sent to SimpleX Chat notification server, but not the message content, size or who it is from. No comment provided by engineer. - - **Scan QR code**: to connect to your contact in person or via video call. - **Scan QR code**: to connect to your contact in person or via video call. - No comment provided by engineer. - **Warning**: Instant push notifications require passphrase saved in Keychain. **Warning**: Instant push notifications require passphrase saved in Keychain. @@ -453,11 +448,6 @@ 1 week time interval - - 1-time link - 1-time link - No comment provided by engineer. - 5 minutes 5 minutes @@ -573,6 +563,11 @@ Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts. No comment provided by engineer. + + Add contact + Add contact + No comment provided by engineer. + Add preset servers Add preset servers @@ -978,6 +973,11 @@ Calls No comment provided by engineer. + + Camera not available + Camera not available + No comment provided by engineer. + Can't delete user profile! Can't delete user profile! @@ -1243,11 +1243,6 @@ This is your own one-time link! Connect via link No comment provided by engineer. - - Connect via link / QR code - Connect via link / QR code - No comment provided by engineer. - Connect via one-time link Connect via one-time link @@ -1423,11 +1418,6 @@ This is your own one-time link! Create new profile in [desktop app](https://simplex.chat/downloads/). 💻 No comment provided by engineer. - - Create one-time invitation link - Create one-time invitation link - No comment provided by engineer. - Create profile Create profile @@ -1453,6 +1443,11 @@ This is your own one-time link! Created on %@ No comment provided by engineer. + + Creating link… + Creating link… + No comment provided by engineer. + Current Passcode Current Passcode @@ -2003,6 +1998,11 @@ This cannot be undone! Enable automatic message deletion? No comment provided by engineer. + + Enable camera access + Enable camera access + No comment provided by engineer. + Enable for all Enable for all @@ -2348,6 +2348,11 @@ This cannot be undone! Error saving user password No comment provided by engineer. + + Error scanning code: %@ + Error scanning code: %@ + No comment provided by engineer. + Error sending email Error sending email @@ -2823,11 +2828,6 @@ This cannot be undone! If you can't meet in person, show QR code in a video call, or share the link. No comment provided by engineer. - - If you cannot meet in person, you can **scan QR code in the video call**, or your contact can share an invitation link. - If you cannot meet in person, you can **scan QR code in the video call**, or your contact can share an invitation link. - No comment provided by engineer. - If you enter this passcode when opening the app, all app data will be irreversibly removed! If you enter this passcode when opening the app, all app data will be irreversibly removed! @@ -2985,11 +2985,21 @@ This cannot be undone! Interface No comment provided by engineer. + + Invalid QR code + Invalid QR code + No comment provided by engineer. + Invalid connection link Invalid connection link No comment provided by engineer. + + Invalid link + Invalid link + No comment provided by engineer. + Invalid name! Invalid name! @@ -3118,11 +3128,21 @@ This is your link for group %@! Joining group No comment provided by engineer. + + Keep + Keep + No comment provided by engineer. + Keep the app open to use it from desktop Keep the app open to use it from desktop No comment provided by engineer. + + Keep unused invitation? + Keep unused invitation? + No comment provided by engineer. + Keep your connections Keep your connections @@ -3453,6 +3473,11 @@ This is your link for group %@! New Passcode No comment provided by engineer. + + New chat + New chat + No comment provided by engineer. + New contact request New contact request @@ -3577,6 +3602,11 @@ This is your link for group %@! - disable members ("observer" role) No comment provided by engineer. + + OK + OK + No comment provided by engineer. + Off Off @@ -3727,6 +3757,16 @@ This is your link for group %@! Opening app… No comment provided by engineer. + + Or scan QR code + Or scan QR code + No comment provided by engineer. + + + Or show this code + Or show this code + No comment provided by engineer. + PING count PING count @@ -3767,11 +3807,6 @@ This is your link for group %@! Password to show No comment provided by engineer. - - Paste - Paste - No comment provided by engineer. - Paste desktop address Paste desktop address @@ -3782,16 +3817,11 @@ This is your link for group %@! Paste image No comment provided by engineer. - - Paste received link - Paste received link + + Paste the link you received + Paste the link you received No comment provided by engineer. - - Paste the link you received to connect with your contact. - Paste the link you received to connect with your contact. - placeholder - People can connect to you only via the links you share. People can connect to you only via the links you share. @@ -4039,6 +4069,11 @@ Error: %@ Read more in [User Guide](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address). No comment provided by engineer. + + Read more in [User Guide](https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode). + Read more in [User Guide](https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode). + No comment provided by engineer. + Read more in [User Guide](https://simplex.chat/docs/guide/readme.html#connect-to-friends). Read more in [User Guide](https://simplex.chat/docs/guide/readme.html#connect-to-friends). @@ -4249,6 +4284,11 @@ Error: %@ Restore database error No comment provided by engineer. + + Retry + Retry + No comment provided by engineer. + Reveal Reveal @@ -4404,6 +4444,11 @@ Error: %@ Search No comment provided by engineer. + + Search or paste SimpleX link + Search or paste SimpleX link + No comment provided by engineer. + Secure queue Secure queue @@ -4679,9 +4724,9 @@ Error: %@ Share link No comment provided by engineer. - - Share one-time invitation link - Share one-time invitation link + + Share this 1-time invite link + Share this 1-time invite link No comment provided by engineer. @@ -4804,11 +4849,6 @@ Error: %@ Somebody notification title - - Start a new chat - Start a new chat - No comment provided by engineer. - Start chat Start chat @@ -4944,6 +4984,16 @@ Error: %@ Tap to join incognito No comment provided by engineer. + + Tap to paste link + Tap to paste link + No comment provided by engineer. + + + Tap to scan + Tap to scan + No comment provided by engineer. + Tap to start a new chat Tap to start a new chat @@ -5006,6 +5056,11 @@ It can happen because of some bug or when the connection is compromised.The attempt to change database passphrase was not completed. No comment provided by engineer. + + The code you scanned is not a SimpleX link QR code. + The code you scanned is not a SimpleX link QR code. + No comment provided by engineer. + The connection you accepted will be cancelled! The connection you accepted will be cancelled! @@ -5071,6 +5126,11 @@ It can happen because of some bug or when the connection is compromised.The servers for new connections of your current chat profile **%@**. No comment provided by engineer. + + The text you pasted is not a SimpleX link. + The text you pasted is not a SimpleX link. + No comment provided by engineer. + Theme Theme @@ -5692,11 +5752,6 @@ Repeat join request? You can accept calls from lock screen, without device and app authentication. No comment provided by engineer. - - You can also connect by clicking the link. If it opens in the browser, click **Open in mobile app** button. - You can also connect by clicking the link. If it opens in the browser, click **Open in mobile app** button. - No comment provided by engineer. - You can create it later You can create it later @@ -5762,6 +5817,11 @@ Repeat join request? You can use markdown to format messages: No comment provided by engineer. + + You can view invitation link again in connection details. + You can view invitation link again in connection details. + No comment provided by engineer. + You can't send messages! You can't send messages! 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 5b3d820d6f..0f2accb893 100644 --- a/apps/ios/SimpleX Localizations/es.xcloc/Localized Contents/es.xliff +++ b/apps/ios/SimpleX Localizations/es.xcloc/Localized Contents/es.xliff @@ -312,14 +312,17 @@ ) No comment provided by engineer. + + **Add contact**: to create a new invitation link, or connect via a link you received. + No comment provided by engineer. + **Add new contact**: to create your one-time QR Code or link for your contact. **Añadir nuevo contacto**: para crear tu código QR o enlace de un uso para tu contacto. No comment provided by engineer. - - **Create link / QR code** for your contact to use. - **Crea enlace / código QR** para que tu contacto lo use. + + **Create group**: to create a new group. No comment provided by engineer. @@ -332,11 +335,6 @@ **Más privado**: no se usa el servidor de notificaciones de SimpleX Chat, los mensajes se comprueban periódicamente en segundo plano (dependiendo de la frecuencia con la que utilices la aplicación). No comment provided by engineer. - - **Paste received link** or open it in the browser and tap **Open in mobile app**. - **Pega el enlace recibido** o ábrelo en el navegador y pulsa **Abrir en aplicación móvil**. - No comment provided by engineer. - **Please note**: you will NOT be able to recover or change passphrase if you lose it. **Atención**: NO podrás recuperar o cambiar la contraseña si la pierdes. @@ -347,11 +345,6 @@ **Recomendado**: el token del dispositivo y las notificaciones se envían al servidor de notificaciones de SimpleX Chat, pero no el contenido del mensaje, su tamaño o su procedencia. No comment provided by engineer. - - **Scan QR code**: to connect to your contact in person or via video call. - **Escanear código QR**: en persona para conectarte con tu contacto, o por videollamada. - No comment provided by engineer. - **Warning**: Instant push notifications require passphrase saved in Keychain. **Advertencia**: Las notificaciones automáticas instantáneas requieren una contraseña guardada en Keychain. @@ -453,11 +446,6 @@ una semana time interval - - 1-time link - Enlace un uso - No comment provided by engineer. - 5 minutes 5 minutos @@ -573,6 +561,10 @@ Añade la dirección a tu perfil para que tus contactos puedan compartirla con otros. La actualización del perfil se enviará a tus contactos. No comment provided by engineer. + + Add contact + No comment provided by engineer. + Add preset servers Añadir servidores predefinidos @@ -978,6 +970,10 @@ Llamadas No comment provided by engineer. + + Camera not available + No comment provided by engineer. + Can't delete user profile! ¡No se puede eliminar el perfil! @@ -1242,11 +1238,6 @@ This is your own one-time link! Conectar mediante enlace No comment provided by engineer. - - Connect via link / QR code - Conecta vía enlace / Código QR - No comment provided by engineer. - Connect via one-time link Conectar mediante enlace de un sólo uso @@ -1422,11 +1413,6 @@ This is your own one-time link! Crea perfil nuevo en la [aplicación para PC](https://simplex.Descargas/de chat/). 💻 No comment provided by engineer. - - Create one-time invitation link - Crea enlace de invitación de un uso - No comment provided by engineer. - Create profile Crear perfil @@ -1452,6 +1438,10 @@ This is your own one-time link! Creado en %@ No comment provided by engineer. + + Creating link… + No comment provided by engineer. + Current Passcode Código de Acceso @@ -2002,6 +1992,10 @@ This cannot be undone! ¿Activar eliminación automática de mensajes? No comment provided by engineer. + + Enable camera access + No comment provided by engineer. + Enable for all Activar para todos @@ -2345,6 +2339,10 @@ This cannot be undone! Error al guardar contraseña de usuario No comment provided by engineer. + + Error scanning code: %@ + No comment provided by engineer. + Error sending email Error al enviar email @@ -2820,11 +2818,6 @@ This cannot be undone! Si no puedes reunirte en persona, muestra el código QR por videollamada, o comparte el enlace. No comment provided by engineer. - - If you cannot meet in person, you can **scan QR code in the video call**, or your contact can share an invitation link. - Si no puedes reunirte en persona, puedes **escanear el código QR por videollamada**, o tu contacto puede compartir un enlace de invitación. - No comment provided by engineer. - If you enter this passcode when opening the app, all app data will be irreversibly removed! ¡Si introduces este código al abrir la aplicación, todos los datos de la misma se eliminarán de forma irreversible! @@ -2982,11 +2975,19 @@ This cannot be undone! Interfaz No comment provided by engineer. + + Invalid QR code + No comment provided by engineer. + Invalid connection link Enlace de conexión no válido No comment provided by engineer. + + Invalid link + No comment provided by engineer. + Invalid name! ¡Nombre no válido! @@ -3114,11 +3115,19 @@ This is your link for group %@! Entrando al grupo No comment provided by engineer. + + Keep + No comment provided by engineer. + Keep the app open to use it from desktop Mantén la aplicación abierta para usarla desde el ordenador No comment provided by engineer. + + Keep unused invitation? + No comment provided by engineer. + Keep your connections Conserva tus conexiones @@ -3449,6 +3458,10 @@ This is your link for group %@! Código Nuevo No comment provided by engineer. + + New chat + No comment provided by engineer. + New contact request Nueva solicitud de contacto @@ -3573,6 +3586,10 @@ This is your link for group %@! - desactivar el rol miembro (a rol "observador") No comment provided by engineer. + + OK + No comment provided by engineer. + Off Desactivado @@ -3722,6 +3739,14 @@ This is your link for group %@! Opening app… No comment provided by engineer. + + Or scan QR code + No comment provided by engineer. + + + Or show this code + No comment provided by engineer. + PING count Contador PING @@ -3762,11 +3787,6 @@ This is your link for group %@! Contraseña para hacerlo visible No comment provided by engineer. - - Paste - Pegar - No comment provided by engineer. - Paste desktop address Pegar dirección de ordenador @@ -3777,16 +3797,10 @@ This is your link for group %@! Pegar imagen No comment provided by engineer. - - Paste received link - Pegar enlace recibido + + Paste the link you received No comment provided by engineer. - - Paste the link you received to connect with your contact. - Pega el enlace que has recibido en el recuadro para conectar con tu contacto. - placeholder - People can connect to you only via the links you share. Las personas pueden conectarse contigo solo mediante los enlaces que compartes. @@ -4032,6 +4046,10 @@ Error: %@ Más información en el [Manual de usuario](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address). No comment provided by engineer. + + Read more in [User Guide](https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode). + No comment provided by engineer. + Read more in [User Guide](https://simplex.chat/docs/guide/readme.html#connect-to-friends). Más información en el [Manual de usuario](https://simplex.chat/docs/guide/readme.html#connect-to-friends). @@ -4242,6 +4260,10 @@ Error: %@ Error al restaurar base de datos No comment provided by engineer. + + Retry + No comment provided by engineer. + Reveal Revelar @@ -4397,6 +4419,10 @@ Error: %@ Buscar No comment provided by engineer. + + Search or paste SimpleX link + No comment provided by engineer. + Secure queue Cola segura @@ -4672,9 +4698,8 @@ Error: %@ Compartir enlace No comment provided by engineer. - - Share one-time invitation link - Compartir enlace de invitación de un uso + + Share this 1-time invite link No comment provided by engineer. @@ -4797,11 +4822,6 @@ Error: %@ Alguien notification title - - Start a new chat - Iniciar chat nuevo - No comment provided by engineer. - Start chat Iniciar chat @@ -4936,6 +4956,14 @@ Error: %@ Pulsa para unirte en modo incógnito No comment provided by engineer. + + Tap to paste link + No comment provided by engineer. + + + Tap to scan + No comment provided by engineer. + Tap to start a new chat Pulsa para iniciar chat nuevo @@ -4998,6 +5026,10 @@ Puede ocurrir por algún bug o cuando la conexión está comprometida. El intento de cambiar la contraseña de la base de datos no se ha completado. No comment provided by engineer. + + The code you scanned is not a SimpleX link QR code. + No comment provided by engineer. + The connection you accepted will be cancelled! ¡La conexión que has aceptado se cancelará! @@ -5063,6 +5095,10 @@ Puede ocurrir por algún bug o cuando la conexión está comprometida. Lista de servidores para las conexiones nuevas de tu perfil actual **%@**. No comment provided by engineer. + + The text you pasted is not a SimpleX link. + No comment provided by engineer. + Theme Tema @@ -5684,11 +5720,6 @@ Repeat join request? Puede aceptar llamadas desde la pantalla de bloqueo, sin autenticación de dispositivos y aplicaciones. No comment provided by engineer. - - You can also connect by clicking the link. If it opens in the browser, click **Open in mobile app** button. - También puedes conectarte haciendo clic en el enlace. Si se abre en el navegador, haz clic en el botón **Abrir en aplicación móvil**. - No comment provided by engineer. - You can create it later Puedes crearla más tarde @@ -5753,6 +5784,10 @@ Repeat join request? Puedes usar la sintaxis markdown para dar formato a tus mensajes: No comment provided by engineer. + + You can view invitation link again in connection details. + No comment provided by engineer. + You can't send messages! ¡No puedes enviar mensajes! 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 928666ddad..81bc19013b 100644 --- a/apps/ios/SimpleX Localizations/fi.xcloc/Localized Contents/fi.xliff +++ b/apps/ios/SimpleX Localizations/fi.xcloc/Localized Contents/fi.xliff @@ -303,14 +303,17 @@ ) No comment provided by engineer. + + **Add contact**: to create a new invitation link, or connect via a link you received. + No comment provided by engineer. + **Add new contact**: to create your one-time QR Code or link for your contact. **Lisää uusi kontakti**: luo kertakäyttöinen QR-koodi tai linkki kontaktille. No comment provided by engineer. - - **Create link / QR code** for your contact to use. - **Luo linkki / QR-koodi* kontaktille. + + **Create group**: to create a new group. No comment provided by engineer. @@ -323,11 +326,6 @@ **Yksityisin**: älä käytä SimpleX Chat -ilmoituspalvelinta, tarkista viestit ajoittain taustalla (riippuu siitä, kuinka usein käytät sovellusta). No comment provided by engineer. - - **Paste received link** or open it in the browser and tap **Open in mobile app**. - **Liitä vastaanotettu linkki** tai avaa se selaimessa ja napauta **Avaa mobiilisovelluksessa**. - No comment provided by engineer. - **Please note**: you will NOT be able to recover or change passphrase if you lose it. **Huomaa**: et voi palauttaa tai muuttaa tunnuslausetta, jos kadotat sen. @@ -338,11 +336,6 @@ **Suositus**: laitetunnus ja ilmoitukset lähetetään SimpleX Chat -ilmoituspalvelimelle, mutta ei viestin sisältöä, kokoa tai sitä, keneltä se on peräisin. No comment provided by engineer. - - **Scan QR code**: to connect to your contact in person or via video call. - **Skannaa QR-koodi**: muodosta yhteys kontaktiisi henkilökohtaisesti tai videopuhelun kautta. - No comment provided by engineer. - **Warning**: Instant push notifications require passphrase saved in Keychain. **Varoitus**: Välittömät push-ilmoitukset vaativat tunnuslauseen, joka on tallennettu Keychainiin. @@ -437,11 +430,6 @@ 1 viikko time interval - - 1-time link - Kertakäyttölinkki - No comment provided by engineer. - 5 minutes 5 minuuttia @@ -557,6 +545,10 @@ Lisää osoite profiiliisi, jotta kontaktisi voivat jakaa sen muiden kanssa. Profiilipäivitys lähetetään kontakteillesi. No comment provided by engineer. + + Add contact + No comment provided by engineer. + Add preset servers Lisää esiasetettuja palvelimia @@ -951,6 +943,10 @@ Puhelut No comment provided by engineer. + + Camera not available + No comment provided by engineer. + Can't delete user profile! Käyttäjäprofiilia ei voi poistaa! @@ -1207,11 +1203,6 @@ This is your own one-time link! Yhdistä linkin kautta No comment provided by engineer. - - Connect via link / QR code - Yhdistä linkillä / QR-koodilla - No comment provided by engineer. - Connect via one-time link Yhdistä kertalinkillä @@ -1379,11 +1370,6 @@ This is your own one-time link! Luo uusi profiili [työpöytäsovelluksessa](https://simplex.chat/downloads/). 💻 No comment provided by engineer. - - Create one-time invitation link - Luo kertakutsulinkki - No comment provided by engineer. - Create profile No comment provided by engineer. @@ -1408,6 +1394,10 @@ This is your own one-time link! Luotu %@ No comment provided by engineer. + + Creating link… + No comment provided by engineer. + Current Passcode Nykyinen pääsykoodi @@ -1949,6 +1939,10 @@ This cannot be undone! Ota automaattinen viestien poisto käyttöön? No comment provided by engineer. + + Enable camera access + No comment provided by engineer. + Enable for all Salli kaikille @@ -2285,6 +2279,10 @@ This cannot be undone! Virhe käyttäjän salasanan tallentamisessa No comment provided by engineer. + + Error scanning code: %@ + No comment provided by engineer. + Error sending email Virhe sähköpostin lähettämisessä @@ -2753,11 +2751,6 @@ This cannot be undone! Jos et voi tavata henkilökohtaisesti, näytä QR-koodi videopuhelussa tai jaa linkki. No comment provided by engineer. - - If you cannot meet in person, you can **scan QR code in the video call**, or your contact can share an invitation link. - Jos et voi tavata henkilökohtaisesti, voit **skannata QR-koodin videopuhelussa** tai kontaktisi voi jakaa kutsulinkin. - No comment provided by engineer. - If you enter this passcode when opening the app, all app data will be irreversibly removed! Jos syötät tämän pääsykoodin sovellusta avatessasi, kaikki sovelluksen tiedot poistetaan peruuttamattomasti! @@ -2913,11 +2906,19 @@ This cannot be undone! Käyttöliittymä No comment provided by engineer. + + Invalid QR code + No comment provided by engineer. + Invalid connection link Virheellinen yhteyslinkki No comment provided by engineer. + + Invalid link + No comment provided by engineer. + Invalid name! No comment provided by engineer. @@ -3040,10 +3041,18 @@ This is your link for group %@! Liittyy ryhmään No comment provided by engineer. + + Keep + No comment provided by engineer. + Keep the app open to use it from desktop No comment provided by engineer. + + Keep unused invitation? + No comment provided by engineer. + Keep your connections Pidä kontaktisi @@ -3370,6 +3379,10 @@ This is your link for group %@! Uusi pääsykoodi No comment provided by engineer. + + New chat + No comment provided by engineer. + New contact request Uusi kontaktipyyntö @@ -3492,6 +3505,10 @@ This is your link for group %@! - poista jäsenet käytöstä ("tarkkailija" rooli) No comment provided by engineer. + + OK + No comment provided by engineer. + Off Pois @@ -3639,6 +3656,14 @@ This is your link for group %@! Opening app… No comment provided by engineer. + + Or scan QR code + No comment provided by engineer. + + + Or show this code + No comment provided by engineer. + PING count PING-määrä @@ -3679,11 +3704,6 @@ This is your link for group %@! Salasana näytettäväksi No comment provided by engineer. - - Paste - Liitä - No comment provided by engineer. - Paste desktop address No comment provided by engineer. @@ -3693,16 +3713,10 @@ This is your link for group %@! Liitä kuva No comment provided by engineer. - - Paste received link - Liitä vastaanotettu linkki + + Paste the link you received No comment provided by engineer. - - Paste the link you received to connect with your contact. - Liitä saamasi linkki, jonka avulla voit muodostaa yhteyden kontaktiisi. - placeholder - People can connect to you only via the links you share. Ihmiset voivat ottaa sinuun yhteyttä vain jakamiesi linkkien kautta. @@ -3946,6 +3960,10 @@ Error: %@ Lue lisää [Käyttöoppaasta](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address). No comment provided by engineer. + + Read more in [User Guide](https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode). + No comment provided by engineer. + Read more in [User Guide](https://simplex.chat/docs/guide/readme.html#connect-to-friends). Lue lisää [Käyttöoppaasta](https://simplex.chat/docs/guide/readme.html#connect-to-friends). @@ -4154,6 +4172,10 @@ Error: %@ Virhe tietokannan palauttamisessa No comment provided by engineer. + + Retry + No comment provided by engineer. + Reveal Paljasta @@ -4308,6 +4330,10 @@ Error: %@ Haku No comment provided by engineer. + + Search or paste SimpleX link + No comment provided by engineer. + Secure queue Turvallinen jono @@ -4581,9 +4607,8 @@ Error: %@ Jaa linkki No comment provided by engineer. - - Share one-time invitation link - Jaa kertakutsulinkki + + Share this 1-time invite link No comment provided by engineer. @@ -4705,11 +4730,6 @@ Error: %@ Joku notification title - - Start a new chat - Aloita uusi keskustelu - No comment provided by engineer. - Start chat Aloita keskustelu @@ -4843,6 +4863,14 @@ Error: %@ Napauta liittyäksesi incognito-tilassa No comment provided by engineer. + + Tap to paste link + No comment provided by engineer. + + + Tap to scan + No comment provided by engineer. + Tap to start a new chat Aloita uusi keskustelu napauttamalla @@ -4905,6 +4933,10 @@ Tämä voi johtua jostain virheestä tai siitä, että yhteys on vaarantunut.Tietokannan tunnuslauseen muuttamista ei suoritettu loppuun. No comment provided by engineer. + + The code you scanned is not a SimpleX link QR code. + No comment provided by engineer. + The connection you accepted will be cancelled! Hyväksymäsi yhteys peruuntuu! @@ -4970,6 +5002,10 @@ Tämä voi johtua jostain virheestä tai siitä, että yhteys on vaarantunut.Palvelimet nykyisen keskusteluprofiilisi uusille yhteyksille **%@**. No comment provided by engineer. + + The text you pasted is not a SimpleX link. + No comment provided by engineer. + Theme Teema @@ -5566,11 +5602,6 @@ Repeat join request? Voit vastaanottaa puheluita lukitusnäytöltä ilman laitteen ja sovelluksen todennusta. No comment provided by engineer. - - You can also connect by clicking the link. If it opens in the browser, click **Open in mobile app** button. - Voit myös muodostaa yhteyden klikkaamalla linkkiä. Jos se avautuu selaimessa, napsauta **Avaa mobiilisovelluksessa**-painiketta. - No comment provided by engineer. - You can create it later Voit luoda sen myöhemmin @@ -5635,6 +5666,10 @@ Repeat join request? Voit käyttää markdownia viestien muotoiluun: No comment provided by engineer. + + You can view invitation link again in connection details. + No comment provided by engineer. + You can't send messages! Et voi lähettää viestejä! 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 6ec667ed91..4d08ee9652 100644 --- a/apps/ios/SimpleX Localizations/fr.xcloc/Localized Contents/fr.xliff +++ b/apps/ios/SimpleX Localizations/fr.xcloc/Localized Contents/fr.xliff @@ -312,14 +312,17 @@ ) No comment provided by engineer. + + **Add contact**: to create a new invitation link, or connect via a link you received. + No comment provided by engineer. + **Add new contact**: to create your one-time QR Code or link for your contact. **Ajouter un nouveau contact** : pour créer un lien ou code QR unique pour votre contact. No comment provided by engineer. - - **Create link / QR code** for your contact to use. - **Créer un lien / code QR** que votre contact pourra utiliser. + + **Create group**: to create a new group. No comment provided by engineer. @@ -332,11 +335,6 @@ **Confidentiel** : ne pas utiliser le serveur de notifications SimpleX, vérification de nouveaux messages periodiquement en arrière plan (dépend de l'utilisation de l'app). No comment provided by engineer. - - **Paste received link** or open it in the browser and tap **Open in mobile app**. - **Collez le lien reçu** ou ouvrez-le dans votre navigateur et appuyez sur **Open in mobile app**. - No comment provided by engineer. - **Please note**: you will NOT be able to recover or change passphrase if you lose it. **Veuillez noter** : vous NE pourrez PAS récupérer ou modifier votre phrase secrète si vous la perdez. @@ -347,11 +345,6 @@ **Recommandé** : le token de l'appareil et les notifications sont envoyés au serveur de notifications SimpleX, mais pas le contenu du message, sa taille ou son auteur. No comment provided by engineer. - - **Scan QR code**: to connect to your contact in person or via video call. - **Scanner le code QR** : pour vous connecter à votre contact en personne ou par appel vidéo. - No comment provided by engineer. - **Warning**: Instant push notifications require passphrase saved in Keychain. **Avertissement** : les notifications push instantanées nécessitent une phrase secrète enregistrée dans la keychain. @@ -453,11 +446,6 @@ 1 semaine time interval - - 1-time link - Lien à usage unique - No comment provided by engineer. - 5 minutes 5 minutes @@ -573,6 +561,10 @@ Ajoutez une adresse à votre profil, afin que vos contacts puissent la partager avec d'autres personnes. La mise à jour du profil sera envoyée à vos contacts. No comment provided by engineer. + + Add contact + No comment provided by engineer. + Add preset servers Ajouter des serveurs prédéfinis @@ -978,6 +970,10 @@ Appels No comment provided by engineer. + + Camera not available + No comment provided by engineer. + Can't delete user profile! Impossible de supprimer le profil d'utilisateur ! @@ -1242,11 +1238,6 @@ Il s'agit de votre propre lien unique ! Se connecter via un lien No comment provided by engineer. - - Connect via link / QR code - Se connecter via un lien / code QR - No comment provided by engineer. - Connect via one-time link Se connecter via un lien unique @@ -1422,11 +1413,6 @@ Il s'agit de votre propre lien unique ! Créer un nouveau profil sur [l'application de bureau](https://simplex.chat/downloads/). 💻 No comment provided by engineer. - - Create one-time invitation link - Créer un lien d'invitation unique - No comment provided by engineer. - Create profile Créer le profil @@ -1452,6 +1438,10 @@ Il s'agit de votre propre lien unique ! Créé le %@ No comment provided by engineer. + + Creating link… + No comment provided by engineer. + Current Passcode Code d'accès actuel @@ -2002,6 +1992,10 @@ Cette opération ne peut être annulée ! Activer la suppression automatique des messages ? No comment provided by engineer. + + Enable camera access + No comment provided by engineer. + Enable for all Activer pour tous @@ -2345,6 +2339,10 @@ Cette opération ne peut être annulée ! Erreur d'enregistrement du mot de passe de l'utilisateur No comment provided by engineer. + + Error scanning code: %@ + No comment provided by engineer. + Error sending email Erreur lors de l'envoi de l'e-mail @@ -2820,11 +2818,6 @@ Cette opération ne peut être annulée ! Si vous ne pouvez pas vous rencontrer en personne, montrez le code QR lors d'un appel vidéo ou partagez le lien. No comment provided by engineer. - - If you cannot meet in person, you can **scan QR code in the video call**, or your contact can share an invitation link. - Si vous ne pouvez pas voir la personne, vous pouvez **scanner le code QR dans un appel vidéo**, ou votre contact peut vous partager un lien d'invitation. - No comment provided by engineer. - If you enter this passcode when opening the app, all app data will be irreversibly removed! Si vous saisissez ce code à l'ouverture de l'application, toutes les données de l'application seront irréversiblement supprimées ! @@ -2982,11 +2975,19 @@ Cette opération ne peut être annulée ! Interface No comment provided by engineer. + + Invalid QR code + No comment provided by engineer. + Invalid connection link Lien de connection invalide No comment provided by engineer. + + Invalid link + No comment provided by engineer. + Invalid name! Nom invalide ! @@ -3114,11 +3115,19 @@ Voici votre lien pour le groupe %@ ! Entrain de rejoindre le groupe No comment provided by engineer. + + Keep + No comment provided by engineer. + Keep the app open to use it from desktop Garder l'application ouverte pour l'utiliser depuis le bureau No comment provided by engineer. + + Keep unused invitation? + No comment provided by engineer. + Keep your connections Conserver vos connexions @@ -3449,6 +3458,10 @@ Voici votre lien pour le groupe %@ ! Nouveau code d'accès No comment provided by engineer. + + New chat + No comment provided by engineer. + New contact request Nouvelle demande de contact @@ -3573,6 +3586,10 @@ Voici votre lien pour le groupe %@ ! - désactiver des membres (rôle "observateur") No comment provided by engineer. + + OK + No comment provided by engineer. + Off Off @@ -3722,6 +3739,14 @@ Voici votre lien pour le groupe %@ ! Opening app… No comment provided by engineer. + + Or scan QR code + No comment provided by engineer. + + + Or show this code + No comment provided by engineer. + PING count Nombre de PING @@ -3762,11 +3787,6 @@ Voici votre lien pour le groupe %@ ! Mot de passe à entrer No comment provided by engineer. - - Paste - Coller - No comment provided by engineer. - Paste desktop address Coller l'adresse du bureau @@ -3777,16 +3797,10 @@ Voici votre lien pour le groupe %@ ! Coller l'image No comment provided by engineer. - - Paste received link - Coller le lien reçu + + Paste the link you received No comment provided by engineer. - - Paste the link you received to connect with your contact. - Collez le lien que vous avez reçu dans le cadre ci-dessous pour vous connecter avec votre contact. - placeholder - People can connect to you only via the links you share. On ne peut se connecter à vous qu’avec les liens que vous partagez. @@ -4032,6 +4046,10 @@ Error: %@ Pour en savoir plus, consultez le [Guide de l'utilisateur](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address). No comment provided by engineer. + + Read more in [User Guide](https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode). + No comment provided by engineer. + Read more in [User Guide](https://simplex.chat/docs/guide/readme.html#connect-to-friends). Pour en savoir plus, consultez le [Guide de l'utilisateur](https://simplex.chat/docs/guide/readme.html#connect-to-friends). @@ -4242,6 +4260,10 @@ Error: %@ Erreur de restauration de la base de données No comment provided by engineer. + + Retry + No comment provided by engineer. + Reveal Révéler @@ -4397,6 +4419,10 @@ Error: %@ Recherche No comment provided by engineer. + + Search or paste SimpleX link + No comment provided by engineer. + Secure queue File d'attente sécurisée @@ -4672,9 +4698,8 @@ Error: %@ Partager le lien No comment provided by engineer. - - Share one-time invitation link - Partager un lien d'invitation unique + + Share this 1-time invite link No comment provided by engineer. @@ -4797,11 +4822,6 @@ Error: %@ Quelqu'un notification title - - Start a new chat - Commencer une nouvelle conversation - No comment provided by engineer. - Start chat Démarrer le chat @@ -4936,6 +4956,14 @@ Error: %@ Appuyez pour rejoindre incognito No comment provided by engineer. + + Tap to paste link + No comment provided by engineer. + + + Tap to scan + No comment provided by engineer. + Tap to start a new chat Appuyez ici pour démarrer une nouvelle discussion @@ -4998,6 +5026,10 @@ Cela peut se produire en raison d'un bug ou lorsque la connexion est compromise. La tentative de modification de la phrase secrète de la base de données n'a pas abouti. No comment provided by engineer. + + The code you scanned is not a SimpleX link QR code. + No comment provided by engineer. + The connection you accepted will be cancelled! La connexion que vous avez acceptée sera annulée ! @@ -5063,6 +5095,10 @@ Cela peut se produire en raison d'un bug ou lorsque la connexion est compromise. Les serveurs pour les nouvelles connexions de votre profil de chat actuel **%@**. No comment provided by engineer. + + The text you pasted is not a SimpleX link. + No comment provided by engineer. + Theme Thème @@ -5683,11 +5719,6 @@ Répéter la demande d'adhésion ? Vous pouvez accepter des appels à partir de l'écran de verrouillage, sans authentification de l'appareil ou de l'application. No comment provided by engineer. - - You can also connect by clicking the link. If it opens in the browser, click **Open in mobile app** button. - Vous pouvez également vous connecter en cliquant sur le lien. S'il s'ouvre dans le navigateur, cliquez sur le bouton **Open in mobile app**. - No comment provided by engineer. - You can create it later Vous pouvez la créer plus tard @@ -5752,6 +5783,10 @@ Répéter la demande d'adhésion ? Vous pouvez utiliser le format markdown pour mettre en forme les messages : No comment provided by engineer. + + You can view invitation link again in connection details. + No comment provided by engineer. + You can't send messages! Vous ne pouvez pas envoyer de messages ! 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 d1a17a3af2..d9d48bd995 100644 --- a/apps/ios/SimpleX Localizations/it.xcloc/Localized Contents/it.xliff +++ b/apps/ios/SimpleX Localizations/it.xcloc/Localized Contents/it.xliff @@ -312,14 +312,17 @@ ) No comment provided by engineer. + + **Add contact**: to create a new invitation link, or connect via a link you received. + No comment provided by engineer. + **Add new contact**: to create your one-time QR Code or link for your contact. **Aggiungi un contatto**: per creare il tuo codice QR o link una tantum per il tuo contatto. No comment provided by engineer. - - **Create link / QR code** for your contact to use. - **Crea link / codice QR** da usare per il tuo contatto. + + **Create group**: to create a new group. No comment provided by engineer. @@ -332,11 +335,6 @@ **Il più privato**: non usare il server di notifica di SimpleX Chat, controlla i messaggi periodicamente in secondo piano (dipende da quanto spesso usi l'app). No comment provided by engineer. - - **Paste received link** or open it in the browser and tap **Open in mobile app**. - **Incolla il link ricevuto** o aprilo nel browser e tocca **Apri in app mobile**. - No comment provided by engineer. - **Please note**: you will NOT be able to recover or change passphrase if you lose it. **Nota bene**: NON potrai recuperare o cambiare la password se la perdi. @@ -347,11 +345,6 @@ **Consigliato**: vengono inviati il token del dispositivo e le notifiche al server di notifica di SimpleX Chat, ma non il contenuto del messaggio,la sua dimensione o il suo mittente. No comment provided by engineer. - - **Scan QR code**: to connect to your contact in person or via video call. - **Scansiona codice QR**: per connetterti al contatto di persona o via videochiamata. - No comment provided by engineer. - **Warning**: Instant push notifications require passphrase saved in Keychain. **Attenzione**: le notifiche push istantanee richiedono una password salvata nel portachiavi. @@ -453,11 +446,6 @@ 1 settimana time interval - - 1-time link - Link una tantum - No comment provided by engineer. - 5 minutes 5 minuti @@ -573,6 +561,10 @@ Aggiungi l'indirizzo al tuo profilo, in modo che i tuoi contatti possano condividerlo con altre persone. L'aggiornamento del profilo verrà inviato ai tuoi contatti. No comment provided by engineer. + + Add contact + No comment provided by engineer. + Add preset servers Aggiungi server preimpostati @@ -978,6 +970,10 @@ Chiamate No comment provided by engineer. + + Camera not available + No comment provided by engineer. + Can't delete user profile! Impossibile eliminare il profilo utente! @@ -1242,11 +1238,6 @@ Questo è il tuo link una tantum! Connetti via link No comment provided by engineer. - - Connect via link / QR code - Connetti via link / codice QR - No comment provided by engineer. - Connect via one-time link Connetti via link una tantum @@ -1422,11 +1413,6 @@ Questo è il tuo link una tantum! Crea un nuovo profilo nell'[app desktop](https://simplex.chat/downloads/). 💻 No comment provided by engineer. - - Create one-time invitation link - Crea link di invito una tantum - No comment provided by engineer. - Create profile Crea profilo @@ -1452,6 +1438,10 @@ Questo è il tuo link una tantum! Creato il %@ No comment provided by engineer. + + Creating link… + No comment provided by engineer. + Current Passcode Codice di accesso attuale @@ -2002,6 +1992,10 @@ Non è reversibile! Attivare l'eliminazione automatica dei messaggi? No comment provided by engineer. + + Enable camera access + No comment provided by engineer. + Enable for all Attiva per tutti @@ -2345,6 +2339,10 @@ Non è reversibile! Errore nel salvataggio della password utente No comment provided by engineer. + + Error scanning code: %@ + No comment provided by engineer. + Error sending email Errore nell'invio dell'email @@ -2820,11 +2818,6 @@ Non è reversibile! Se non potete incontrarvi di persona, mostra il codice QR in una videochiamata o condividi il link. No comment provided by engineer. - - If you cannot meet in person, you can **scan QR code in the video call**, or your contact can share an invitation link. - Se non potete incontrarvi di persona, puoi **scansionare il codice QR durante la videochiamata** oppure il tuo contatto può condividere un link di invito. - No comment provided by engineer. - If you enter this passcode when opening the app, all app data will be irreversibly removed! Se inserisci questo codice all'apertura dell'app, tutti i dati di essa verranno rimossi in modo irreversibile! @@ -2982,11 +2975,19 @@ Non è reversibile! Interfaccia No comment provided by engineer. + + Invalid QR code + No comment provided by engineer. + Invalid connection link Link di connessione non valido No comment provided by engineer. + + Invalid link + No comment provided by engineer. + Invalid name! Nome non valido! @@ -3114,11 +3115,19 @@ Questo è il tuo link per il gruppo %@! Ingresso nel gruppo No comment provided by engineer. + + Keep + No comment provided by engineer. + Keep the app open to use it from desktop Tieni aperta l'app per usarla dal desktop No comment provided by engineer. + + Keep unused invitation? + No comment provided by engineer. + Keep your connections Mantieni le tue connessioni @@ -3449,6 +3458,10 @@ Questo è il tuo link per il gruppo %@! Nuovo codice di accesso No comment provided by engineer. + + New chat + No comment provided by engineer. + New contact request Nuova richiesta di contatto @@ -3573,6 +3586,10 @@ Questo è il tuo link per il gruppo %@! - disattivare i membri (ruolo "osservatore") No comment provided by engineer. + + OK + No comment provided by engineer. + Off Off @@ -3722,6 +3739,14 @@ Questo è il tuo link per il gruppo %@! Opening app… No comment provided by engineer. + + Or scan QR code + No comment provided by engineer. + + + Or show this code + No comment provided by engineer. + PING count Conteggio PING @@ -3762,11 +3787,6 @@ Questo è il tuo link per il gruppo %@! Password per mostrare No comment provided by engineer. - - Paste - Incolla - No comment provided by engineer. - Paste desktop address Incolla l'indirizzo desktop @@ -3777,16 +3797,10 @@ Questo è il tuo link per il gruppo %@! Incolla immagine No comment provided by engineer. - - Paste received link - Incolla il link ricevuto + + Paste the link you received No comment provided by engineer. - - Paste the link you received to connect with your contact. - Incolla il link che hai ricevuto nella casella sottostante per connetterti con il tuo contatto. - placeholder - People can connect to you only via the links you share. Le persone possono connettersi a te solo tramite i link che condividi. @@ -4032,6 +4046,10 @@ Error: %@ Maggiori informazioni nella [Guida per l'utente](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address). No comment provided by engineer. + + Read more in [User Guide](https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode). + No comment provided by engineer. + Read more in [User Guide](https://simplex.chat/docs/guide/readme.html#connect-to-friends). Maggiori informazioni nella [Guida per l'utente](https://simplex.chat/docs/guide/readme.html#connect-to-friends). @@ -4242,6 +4260,10 @@ Error: %@ Errore di ripristino del database No comment provided by engineer. + + Retry + No comment provided by engineer. + Reveal Rivela @@ -4397,6 +4419,10 @@ Error: %@ Cerca No comment provided by engineer. + + Search or paste SimpleX link + No comment provided by engineer. + Secure queue Coda sicura @@ -4672,9 +4698,8 @@ Error: %@ Condividi link No comment provided by engineer. - - Share one-time invitation link - Condividi link di invito una tantum + + Share this 1-time invite link No comment provided by engineer. @@ -4797,11 +4822,6 @@ Error: %@ Qualcuno notification title - - Start a new chat - Inizia una nuova chat - No comment provided by engineer. - Start chat Avvia chat @@ -4936,6 +4956,14 @@ Error: %@ Toccare per entrare in incognito No comment provided by engineer. + + Tap to paste link + No comment provided by engineer. + + + Tap to scan + No comment provided by engineer. + Tap to start a new chat Tocca per iniziare una chat @@ -4998,6 +5026,10 @@ Può accadere a causa di qualche bug o quando la connessione è compromessa.Il tentativo di cambiare la password del database non è stato completato. No comment provided by engineer. + + The code you scanned is not a SimpleX link QR code. + No comment provided by engineer. + The connection you accepted will be cancelled! La connessione che hai accettato verrà annullata! @@ -5063,6 +5095,10 @@ Può accadere a causa di qualche bug o quando la connessione è compromessa.I server per le nuove connessioni del profilo di chat attuale **%@**. No comment provided by engineer. + + The text you pasted is not a SimpleX link. + No comment provided by engineer. + Theme Tema @@ -5683,11 +5719,6 @@ Ripetere la richiesta di ingresso? Puoi accettare chiamate dalla schermata di blocco, senza l'autenticazione del dispositivo e dell'app. No comment provided by engineer. - - You can also connect by clicking the link. If it opens in the browser, click **Open in mobile app** button. - Puoi anche connetterti cliccando il link. Se si apre nel browser, clicca il pulsante **Apri nell'app mobile**. - No comment provided by engineer. - You can create it later Puoi crearlo più tardi @@ -5752,6 +5783,10 @@ Ripetere la richiesta di ingresso? Puoi usare il markdown per formattare i messaggi: No comment provided by engineer. + + You can view invitation link again in connection details. + No comment provided by engineer. + You can't send messages! Non puoi inviare messaggi! 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 ac7f535e36..de25ffb08f 100644 --- a/apps/ios/SimpleX Localizations/ja.xcloc/Localized Contents/ja.xliff +++ b/apps/ios/SimpleX Localizations/ja.xcloc/Localized Contents/ja.xliff @@ -306,14 +306,17 @@ ) No comment provided by engineer. + + **Add contact**: to create a new invitation link, or connect via a link you received. + No comment provided by engineer. + **Add new contact**: to create your one-time QR Code or link for your contact. **新しい連絡先を追加**: 連絡先のワンタイム QR コードまたはリンクを作成します。 No comment provided by engineer. - - **Create link / QR code** for your contact to use. - 連絡先が使用する **リンク/QR コードを作成します**。 + + **Create group**: to create a new group. No comment provided by engineer. @@ -326,11 +329,6 @@ **最もプライベート**: SimpleX Chat 通知サーバーを使用せず、バックグラウンドで定期的にメッセージをチェックします (アプリの使用頻度によって異なります)。 No comment provided by engineer. - - **Paste received link** or open it in the browser and tap **Open in mobile app**. - **受信したリンク**を貼り付けるか、ブラウザーで開いて [**モバイル アプリで開く**] をタップします。 - No comment provided by engineer. - **Please note**: you will NOT be able to recover or change passphrase if you lose it. **注意**: パスフレーズを紛失すると、パスフレーズを復元または変更できなくなります。 @@ -341,11 +339,6 @@ **推奨**: デバイス トークンと通知は SimpleX Chat 通知サーバーに送信されますが、メッセージの内容、サイズ、送信者は送信されません。 No comment provided by engineer. - - **Scan QR code**: to connect to your contact in person or via video call. - **QR コードをスキャン**: 直接またはビデオ通話で連絡先に接続します。 - No comment provided by engineer. - **Warning**: Instant push notifications require passphrase saved in Keychain. **警告**: 即時の プッシュ通知には、キーチェーンに保存されたパスフレーズが必要です。 @@ -440,11 +433,6 @@ 1週間 time interval - - 1-time link - 使い捨てのリンク - No comment provided by engineer. - 5 minutes 5分 @@ -560,6 +548,10 @@ プロフィールにアドレスを追加し、連絡先があなたのアドレスを他の人と共有できるようにします。プロフィールの更新は連絡先に送信されます。 No comment provided by engineer. + + Add contact + No comment provided by engineer. + Add preset servers 既存サーバを追加 @@ -956,6 +948,10 @@ 通話 No comment provided by engineer. + + Camera not available + No comment provided by engineer. + Can't delete user profile! ユーザープロフィールが削除できません! @@ -1212,11 +1208,6 @@ This is your own one-time link! リンク経由で接続 No comment provided by engineer. - - Connect via link / QR code - リンク・QRコード経由で接続 - No comment provided by engineer. - Connect via one-time link 使い捨てリンク経由で接続しますか? @@ -1384,11 +1375,6 @@ This is your own one-time link! [デスクトップアプリ](https://simplex.chat/downloads/)で新しいプロファイルを作成します。 💻 No comment provided by engineer. - - Create one-time invitation link - 使い捨ての招待リンクを生成する - No comment provided by engineer. - Create profile No comment provided by engineer. @@ -1413,6 +1399,10 @@ This is your own one-time link! %@ によって作成されました No comment provided by engineer. + + Creating link… + No comment provided by engineer. + Current Passcode 現在のパスコード @@ -1954,6 +1944,10 @@ This cannot be undone! 自動メッセージ削除を有効にしますか? No comment provided by engineer. + + Enable camera access + No comment provided by engineer. + Enable for all すべて有効 @@ -2291,6 +2285,10 @@ This cannot be undone! ユーザーパスワード保存エラー No comment provided by engineer. + + Error scanning code: %@ + No comment provided by engineer. + Error sending email メールの送信にエラー発生 @@ -2759,11 +2757,6 @@ This cannot be undone! 直接会えない場合は、ビデオ通話で QR コードを表示するか、リンクを共有してください。 No comment provided by engineer. - - If you cannot meet in person, you can **scan QR code in the video call**, or your contact can share an invitation link. - 直接会えない場合は、**ビデオ通話で QR コードを表示する**か、リンクを共有してください。 - No comment provided by engineer. - If you enter this passcode when opening the app, all app data will be irreversibly removed! アプリを開くときにこのパスコードを入力すると、アプリのすべてのデータが元に戻せないように削除されます! @@ -2919,11 +2912,19 @@ This cannot be undone! インターフェース No comment provided by engineer. + + Invalid QR code + No comment provided by engineer. + Invalid connection link 無効な接続リンク No comment provided by engineer. + + Invalid link + No comment provided by engineer. + Invalid name! No comment provided by engineer. @@ -3046,10 +3047,18 @@ This is your link for group %@! グループに参加 No comment provided by engineer. + + Keep + No comment provided by engineer. + Keep the app open to use it from desktop No comment provided by engineer. + + Keep unused invitation? + No comment provided by engineer. + Keep your connections 接続を維持 @@ -3375,6 +3384,10 @@ This is your link for group %@! 新しいパスコード No comment provided by engineer. + + New chat + No comment provided by engineer. + New contact request 新しい繋がりのリクエスト @@ -3498,6 +3511,10 @@ This is your link for group %@! - メンバーを無効にする (メッセージの送信不可) No comment provided by engineer. + + OK + No comment provided by engineer. + Off オフ @@ -3646,6 +3663,14 @@ This is your link for group %@! Opening app… No comment provided by engineer. + + Or scan QR code + No comment provided by engineer. + + + Or show this code + No comment provided by engineer. + PING count PING回数 @@ -3686,11 +3711,6 @@ This is your link for group %@! パスワードを表示する No comment provided by engineer. - - Paste - 貼り付け - No comment provided by engineer. - Paste desktop address No comment provided by engineer. @@ -3700,16 +3720,10 @@ This is your link for group %@! 画像の貼り付け No comment provided by engineer. - - Paste received link - 頂いたリンクを貼り付ける + + Paste the link you received No comment provided by engineer. - - Paste the link you received to connect with your contact. - 連絡相手から頂いたリンクを以下の入力欄に貼り付けて繋がります。 - placeholder - People can connect to you only via the links you share. あなたと繋がることができるのは、あなたからリンクを頂いた方のみです。 @@ -3953,6 +3967,10 @@ Error: %@ 詳しくは[ユーザーガイド](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address)をご覧ください。 No comment provided by engineer. + + Read more in [User Guide](https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode). + No comment provided by engineer. + Read more in [User Guide](https://simplex.chat/docs/guide/readme.html#connect-to-friends). 詳しくは[ユーザーガイド](https://simplex.chat/docs/guide/readme.html#connect-to-friends)をご覧ください。 @@ -4160,6 +4178,10 @@ Error: %@ データベース復元エラー No comment provided by engineer. + + Retry + No comment provided by engineer. + Reveal 開示する @@ -4314,6 +4336,10 @@ Error: %@ 検索 No comment provided by engineer. + + Search or paste SimpleX link + No comment provided by engineer. + Secure queue 待ち行列セキュリティ確認 @@ -4580,9 +4606,8 @@ Error: %@ リンクを送る No comment provided by engineer. - - Share one-time invitation link - 使い捨ての招待リンクを共有 + + Share this 1-time invite link No comment provided by engineer. @@ -4705,11 +4730,6 @@ Error: %@ 誰か notification title - - Start a new chat - 新しいチャットを開始する - No comment provided by engineer. - Start chat チャットを開始する @@ -4843,6 +4863,14 @@ Error: %@ タップしてシークレットモードで参加 No comment provided by engineer. + + Tap to paste link + No comment provided by engineer. + + + Tap to scan + No comment provided by engineer. + Tap to start a new chat タップして新しいチャットを始める @@ -4905,6 +4933,10 @@ It can happen because of some bug or when the connection is compromised.データベースのパスフレーズ変更が完了してません。 No comment provided by engineer. + + The code you scanned is not a SimpleX link QR code. + No comment provided by engineer. + The connection you accepted will be cancelled! 承認済の接続がキャンセルされます! @@ -4970,6 +5002,10 @@ It can happen because of some bug or when the connection is compromised.現在のチャットプロフィールの新しい接続のサーバ **%@**。 No comment provided by engineer. + + The text you pasted is not a SimpleX link. + No comment provided by engineer. + Theme テーマ @@ -5565,11 +5601,6 @@ Repeat join request? デバイスやアプリの認証を行わずに、ロック画面から通話を受けることができます。 No comment provided by engineer. - - You can also connect by clicking the link. If it opens in the browser, click **Open in mobile app** button. - リンクをクリックすることでも接続できます。ブラウザで開いた場合は、**モバイルアプリで開く**ボタンをクリックしてください。 - No comment provided by engineer. - You can create it later 後からでも作成できます @@ -5634,6 +5665,10 @@ Repeat join request? メッセージの書式にmarkdownを使用することができます: No comment provided by engineer. + + You can view invitation link again in connection details. + No comment provided by engineer. + You can't send messages! メッセージを送信できませんでした! 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 6b90e549b4..e8aef28d41 100644 --- a/apps/ios/SimpleX Localizations/nl.xcloc/Localized Contents/nl.xliff +++ b/apps/ios/SimpleX Localizations/nl.xcloc/Localized Contents/nl.xliff @@ -312,14 +312,17 @@ ) No comment provided by engineer. + + **Add contact**: to create a new invitation link, or connect via a link you received. + No comment provided by engineer. + **Add new contact**: to create your one-time QR Code or link for your contact. **Nieuw contact toevoegen**: om uw eenmalige QR-code of link voor uw contact te maken. No comment provided by engineer. - - **Create link / QR code** for your contact to use. - **Maak een link / QR-code aan** die uw contact kan gebruiken. + + **Create group**: to create a new group. No comment provided by engineer. @@ -332,11 +335,6 @@ **Meest privé**: gebruik geen SimpleX Chat-notificatie server, controleer berichten regelmatig op de achtergrond (afhankelijk van hoe vaak u de app gebruikt). No comment provided by engineer. - - **Paste received link** or open it in the browser and tap **Open in mobile app**. - **Plak de ontvangen link** of open deze in de browser en tik op **Openen in mobiele app**. - No comment provided by engineer. - **Please note**: you will NOT be able to recover or change passphrase if you lose it. **Let op**: u kunt het wachtwoord NIET herstellen of wijzigen als u het kwijtraakt. @@ -347,11 +345,6 @@ **Aanbevolen**: apparaattoken en meldingen worden naar de SimpleX Chat-meldingsserver gestuurd, maar niet de berichtinhoud, -grootte of van wie het afkomstig is. No comment provided by engineer. - - **Scan QR code**: to connect to your contact in person or via video call. - **Scan QR-code**: om persoonlijk of via een video gesprek verbinding te maken met uw contact. - No comment provided by engineer. - **Warning**: Instant push notifications require passphrase saved in Keychain. **Waarschuwing**: voor directe push meldingen is een wachtwoord vereist dat is opgeslagen in de Keychain. @@ -453,11 +446,6 @@ 1 week time interval - - 1-time link - Eenmalige link - No comment provided by engineer. - 5 minutes 5 minuten @@ -573,6 +561,10 @@ Voeg een adres toe aan uw profiel, zodat uw contacten het met andere mensen kunnen delen. Profiel update wordt naar uw contacten verzonden. No comment provided by engineer. + + Add contact + No comment provided by engineer. + Add preset servers Vooraf ingestelde servers toevoegen @@ -978,6 +970,10 @@ Oproepen No comment provided by engineer. + + Camera not available + No comment provided by engineer. + Can't delete user profile! Kan gebruikers profiel niet verwijderen! @@ -1242,11 +1238,6 @@ Dit is uw eigen eenmalige link! Maak verbinding via link No comment provided by engineer. - - Connect via link / QR code - Maak verbinding via link / QR-code - No comment provided by engineer. - Connect via one-time link Verbinden via een eenmalige link? @@ -1422,11 +1413,6 @@ Dit is uw eigen eenmalige link! Maak een nieuw profiel aan in [desktop-app](https://simplex.chat/downloads/). 💻 No comment provided by engineer. - - Create one-time invitation link - Maak een eenmalige uitnodiging link - No comment provided by engineer. - Create profile Maak een profiel aan @@ -1452,6 +1438,10 @@ Dit is uw eigen eenmalige link! Gemaakt op %@ No comment provided by engineer. + + Creating link… + No comment provided by engineer. + Current Passcode Huidige toegangscode @@ -2002,6 +1992,10 @@ Dit kan niet ongedaan gemaakt worden! Automatisch verwijderen van berichten aanzetten? No comment provided by engineer. + + Enable camera access + No comment provided by engineer. + Enable for all Inschakelen voor iedereen @@ -2345,6 +2339,10 @@ Dit kan niet ongedaan gemaakt worden! Fout bij opslaan gebruikers wachtwoord No comment provided by engineer. + + Error scanning code: %@ + No comment provided by engineer. + Error sending email Fout bij het verzenden van e-mail @@ -2820,11 +2818,6 @@ Dit kan niet ongedaan gemaakt worden! Als je elkaar niet persoonlijk kunt ontmoeten, laat dan de QR-code zien in een videogesprek of deel de link. No comment provided by engineer. - - If you cannot meet in person, you can **scan QR code in the video call**, or your contact can share an invitation link. - Als u elkaar niet persoonlijk kunt ontmoeten, kunt u **de QR-code scannen in het video gesprek**, of uw contact kan een uitnodiging link delen. - No comment provided by engineer. - If you enter this passcode when opening the app, all app data will be irreversibly removed! Als u deze toegangscode invoert bij het openen van de app, worden alle app-gegevens onomkeerbaar verwijderd! @@ -2982,11 +2975,19 @@ Dit kan niet ongedaan gemaakt worden! Interface No comment provided by engineer. + + Invalid QR code + No comment provided by engineer. + Invalid connection link Ongeldige verbinding link No comment provided by engineer. + + Invalid link + No comment provided by engineer. + Invalid name! Ongeldige naam! @@ -3114,11 +3115,19 @@ Dit is jouw link voor groep %@! Deel nemen aan groep No comment provided by engineer. + + Keep + No comment provided by engineer. + Keep the app open to use it from desktop Houd de app geopend om deze vanaf de desktop te gebruiken No comment provided by engineer. + + Keep unused invitation? + No comment provided by engineer. + Keep your connections Behoud uw verbindingen @@ -3449,6 +3458,10 @@ Dit is jouw link voor groep %@! Nieuwe toegangscode No comment provided by engineer. + + New chat + No comment provided by engineer. + New contact request Nieuw contactverzoek @@ -3573,6 +3586,10 @@ Dit is jouw link voor groep %@! - schakel leden uit ("waarnemer" rol) No comment provided by engineer. + + OK + No comment provided by engineer. + Off Uit @@ -3722,6 +3739,14 @@ Dit is jouw link voor groep %@! Opening app… No comment provided by engineer. + + Or scan QR code + No comment provided by engineer. + + + Or show this code + No comment provided by engineer. + PING count PING count @@ -3762,11 +3787,6 @@ Dit is jouw link voor groep %@! Wachtwoord om weer te geven No comment provided by engineer. - - Paste - Plakken - No comment provided by engineer. - Paste desktop address Desktopadres plakken @@ -3777,16 +3797,10 @@ Dit is jouw link voor groep %@! Afbeelding plakken No comment provided by engineer. - - Paste received link - Plak de ontvangen link + + Paste the link you received No comment provided by engineer. - - Paste the link you received to connect with your contact. - Plak de link die je hebt ontvangen in het vak hieronder om verbinding te maken met je contact. - placeholder - People can connect to you only via the links you share. Mensen kunnen alleen verbinding met u maken via de links die u deelt. @@ -4032,6 +4046,10 @@ Error: %@ Lees meer in de [Gebruikershandleiding](https://simplex.chat/docs/guide/app-settings.html#uw-simplex-contactadres). No comment provided by engineer. + + Read more in [User Guide](https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode). + No comment provided by engineer. + Read more in [User Guide](https://simplex.chat/docs/guide/readme.html#connect-to-friends). Lees meer in de [Gebruikershandleiding](https://simplex.chat/docs/guide/readme.html#connect-to-friends). @@ -4242,6 +4260,10 @@ Error: %@ Database fout herstellen No comment provided by engineer. + + Retry + No comment provided by engineer. + Reveal Onthullen @@ -4397,6 +4419,10 @@ Error: %@ Zoeken No comment provided by engineer. + + Search or paste SimpleX link + No comment provided by engineer. + Secure queue Veilige wachtrij @@ -4672,9 +4698,8 @@ Error: %@ Deel link No comment provided by engineer. - - Share one-time invitation link - Eenmalige uitnodiging link delen + + Share this 1-time invite link No comment provided by engineer. @@ -4797,11 +4822,6 @@ Error: %@ Iemand notification title - - Start a new chat - Begin een nieuw gesprek - No comment provided by engineer. - Start chat Begin gesprek @@ -4936,6 +4956,14 @@ Error: %@ Tik om incognito lid te worden No comment provided by engineer. + + Tap to paste link + No comment provided by engineer. + + + Tap to scan + No comment provided by engineer. + Tap to start a new chat Tik om een nieuw gesprek te starten @@ -4998,6 +5026,10 @@ Het kan gebeuren vanwege een bug of wanneer de verbinding is aangetast. De poging om het wachtwoord van de database te wijzigen is niet voltooid. No comment provided by engineer. + + The code you scanned is not a SimpleX link QR code. + No comment provided by engineer. + The connection you accepted will be cancelled! De door u geaccepteerde verbinding wordt geannuleerd! @@ -5063,6 +5095,10 @@ Het kan gebeuren vanwege een bug of wanneer de verbinding is aangetast. De servers voor nieuwe verbindingen van uw huidige chat profiel **%@**. No comment provided by engineer. + + The text you pasted is not a SimpleX link. + No comment provided by engineer. + Theme Thema @@ -5683,11 +5719,6 @@ Deelnameverzoek herhalen? U kunt oproepen van het vergrendelingsscherm accepteren, zonder apparaat- en app-verificatie. No comment provided by engineer. - - You can also connect by clicking the link. If it opens in the browser, click **Open in mobile app** button. - U kunt ook verbinding maken door op de link te klikken. Als het in de browser wordt geopend, klikt u op de knop **Openen in mobiele app**. - No comment provided by engineer. - You can create it later U kan het later maken @@ -5752,6 +5783,10 @@ Deelnameverzoek herhalen? U kunt markdown gebruiken voor opmaak in berichten: No comment provided by engineer. + + You can view invitation link again in connection details. + No comment provided by engineer. + You can't send messages! Je kunt geen berichten versturen! 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 1ab569e3c3..0cdbb8c7e1 100644 --- a/apps/ios/SimpleX Localizations/pl.xcloc/Localized Contents/pl.xliff +++ b/apps/ios/SimpleX Localizations/pl.xcloc/Localized Contents/pl.xliff @@ -312,14 +312,17 @@ ) No comment provided by engineer. + + **Add contact**: to create a new invitation link, or connect via a link you received. + No comment provided by engineer. + **Add new contact**: to create your one-time QR Code or link for your contact. **Dodaj nowy kontakt**: aby stworzyć swój jednorazowy kod QR lub link dla kontaktu. No comment provided by engineer. - - **Create link / QR code** for your contact to use. - **Utwórz link / kod QR**, aby Twój kontakt mógł z niego skorzystać. + + **Create group**: to create a new group. No comment provided by engineer. @@ -332,11 +335,6 @@ **Najbardziej prywatny**: nie korzystaj z serwera powiadomień SimpleX Chat, sprawdzaj wiadomości okresowo w tle (zależy jak często korzystasz z aplikacji). No comment provided by engineer. - - **Paste received link** or open it in the browser and tap **Open in mobile app**. - **Wklej otrzymany link** lub otwórz go w przeglądarce i dotknij **Otwórz w aplikacji mobilnej**. - No comment provided by engineer. - **Please note**: you will NOT be able to recover or change passphrase if you lose it. **Uwaga**: NIE będziesz w stanie odzyskać lub zmienić hasła, jeśli je stracisz. @@ -347,11 +345,6 @@ **Zalecane**: token urządzenia i powiadomienia są wysyłane do serwera powiadomień SimpleX Chat, ale nie treść wiadomości, rozmiar lub od kogo jest. No comment provided by engineer. - - **Scan QR code**: to connect to your contact in person or via video call. - **Skanuj kod QR**: aby połączyć się z kontaktem osobiście lub za pomocą połączenia wideo. - No comment provided by engineer. - **Warning**: Instant push notifications require passphrase saved in Keychain. **Uwaga**: Natychmiastowe powiadomienia push wymagają hasła zapisanego w Keychain. @@ -453,11 +446,6 @@ 1 tydzień time interval - - 1-time link - 1-razowy link - No comment provided by engineer. - 5 minutes 5 minut @@ -573,6 +561,10 @@ Dodaj adres do swojego profilu, aby Twoje kontakty mogły go udostępnić innym osobom. Aktualizacja profilu zostanie wysłana do Twoich kontaktów. No comment provided by engineer. + + Add contact + No comment provided by engineer. + Add preset servers Dodaj gotowe serwery @@ -978,6 +970,10 @@ Połączenia No comment provided by engineer. + + Camera not available + No comment provided by engineer. + Can't delete user profile! Nie można usunąć profilu użytkownika! @@ -1242,11 +1238,6 @@ To jest twój jednorazowy link! Połącz się przez link No comment provided by engineer. - - Connect via link / QR code - Połącz się przez link / kod QR - No comment provided by engineer. - Connect via one-time link Połącz przez jednorazowy link @@ -1422,11 +1413,6 @@ To jest twój jednorazowy link! Utwórz nowy profil w [aplikacji desktopowej](https://simplex.chat/downloads/). 💻 No comment provided by engineer. - - Create one-time invitation link - Utwórz jednorazowy link do zaproszenia - No comment provided by engineer. - Create profile Utwórz profil @@ -1452,6 +1438,10 @@ To jest twój jednorazowy link! Utworzony w dniu %@ No comment provided by engineer. + + Creating link… + No comment provided by engineer. + Current Passcode Aktualny Pin @@ -2002,6 +1992,10 @@ To nie może być cofnięte! Czy włączyć automatyczne usuwanie wiadomości? No comment provided by engineer. + + Enable camera access + No comment provided by engineer. + Enable for all Włącz dla wszystkich @@ -2345,6 +2339,10 @@ To nie może być cofnięte! Błąd zapisu hasła użytkownika No comment provided by engineer. + + Error scanning code: %@ + No comment provided by engineer. + Error sending email Błąd wysyłania e-mail @@ -2820,11 +2818,6 @@ To nie może być cofnięte! Jeśli nie możesz spotkać się osobiście, pokaż kod QR w rozmowie wideo lub udostępnij link. No comment provided by engineer. - - If you cannot meet in person, you can **scan QR code in the video call**, or your contact can share an invitation link. - Jeśli nie możesz spotkać się osobiście, możesz **zeskanować kod QR w rozmowie wideo** lub Twój kontakt może udostępnić link z zaproszeniem. - No comment provided by engineer. - If you enter this passcode when opening the app, all app data will be irreversibly removed! Jeśli wprowadzisz ten pin podczas otwierania aplikacji, wszystkie dane aplikacji zostaną nieodwracalnie usunięte! @@ -2982,11 +2975,19 @@ To nie może być cofnięte! Interfejs No comment provided by engineer. + + Invalid QR code + No comment provided by engineer. + Invalid connection link Nieprawidłowy link połączenia No comment provided by engineer. + + Invalid link + No comment provided by engineer. + Invalid name! Nieprawidłowa nazwa! @@ -3114,11 +3115,19 @@ To jest twój link do grupy %@! Dołączanie do grupy No comment provided by engineer. + + Keep + No comment provided by engineer. + Keep the app open to use it from desktop Zostaw aplikację otwartą i używaj ją z komputera No comment provided by engineer. + + Keep unused invitation? + No comment provided by engineer. + Keep your connections Zachowaj swoje połączenia @@ -3449,6 +3458,10 @@ To jest twój link do grupy %@! Nowy Pin No comment provided by engineer. + + New chat + No comment provided by engineer. + New contact request Nowa prośba o kontakt @@ -3573,6 +3586,10 @@ To jest twój link do grupy %@! - wyłączyć członków (rola "obserwatora") No comment provided by engineer. + + OK + No comment provided by engineer. + Off Wyłączony @@ -3722,6 +3739,14 @@ To jest twój link do grupy %@! Opening app… No comment provided by engineer. + + Or scan QR code + No comment provided by engineer. + + + Or show this code + No comment provided by engineer. + PING count Liczba PINGÓW @@ -3762,11 +3787,6 @@ To jest twój link do grupy %@! Hasło do wyświetlenia No comment provided by engineer. - - Paste - Wklej - No comment provided by engineer. - Paste desktop address Wklej adres komputera @@ -3777,16 +3797,10 @@ To jest twój link do grupy %@! Wklej obraz No comment provided by engineer. - - Paste received link - Wklej otrzymany link + + Paste the link you received No comment provided by engineer. - - Paste the link you received to connect with your contact. - Wklej otrzymany link w pole poniżej, aby połączyć się z kontaktem. - placeholder - People can connect to you only via the links you share. Ludzie mogą się z Tobą połączyć tylko poprzez linki, które udostępniasz. @@ -4032,6 +4046,10 @@ Error: %@ Przeczytaj więcej w [Podręczniku Użytkownika](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address). No comment provided by engineer. + + Read more in [User Guide](https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode). + No comment provided by engineer. + Read more in [User Guide](https://simplex.chat/docs/guide/readme.html#connect-to-friends). Przeczytaj więcej w [Podręczniku Użytkownika](https://simplex.chat/docs/guide/readme.html#connect-to-friends). @@ -4242,6 +4260,10 @@ Error: %@ Błąd przywracania bazy danych No comment provided by engineer. + + Retry + No comment provided by engineer. + Reveal Ujawnij @@ -4397,6 +4419,10 @@ Error: %@ Szukaj No comment provided by engineer. + + Search or paste SimpleX link + No comment provided by engineer. + Secure queue Bezpieczna kolejka @@ -4672,9 +4698,8 @@ Error: %@ Udostępnij link No comment provided by engineer. - - Share one-time invitation link - Jednorazowy link zaproszenia + + Share this 1-time invite link No comment provided by engineer. @@ -4797,11 +4822,6 @@ Error: %@ Ktoś notification title - - Start a new chat - Rozpocznij nowy czat - No comment provided by engineer. - Start chat Rozpocznij czat @@ -4936,6 +4956,14 @@ Error: %@ Dotnij, aby dołączyć w trybie incognito No comment provided by engineer. + + Tap to paste link + No comment provided by engineer. + + + Tap to scan + No comment provided by engineer. + Tap to start a new chat Dotknij, aby rozpocząć nowy czat @@ -4998,6 +5026,10 @@ Może się to zdarzyć z powodu jakiegoś błędu lub gdy połączenie jest skom Próba zmiany hasła bazy danych nie została zakończona. No comment provided by engineer. + + The code you scanned is not a SimpleX link QR code. + No comment provided by engineer. + The connection you accepted will be cancelled! Zaakceptowane przez Ciebie połączenie zostanie anulowane! @@ -5063,6 +5095,10 @@ Może się to zdarzyć z powodu jakiegoś błędu lub gdy połączenie jest skom Serwery dla nowych połączeń bieżącego profilu czatu **%@**. No comment provided by engineer. + + The text you pasted is not a SimpleX link. + No comment provided by engineer. + Theme Motyw @@ -5683,11 +5719,6 @@ Powtórzyć prośbę dołączenia? Możesz przyjmować połączenia z ekranu blokady, bez uwierzytelniania urządzenia i aplikacji. No comment provided by engineer. - - You can also connect by clicking the link. If it opens in the browser, click **Open in mobile app** button. - Możesz też połączyć się klikając w link. Jeśli otworzy się on w przeglądarce, kliknij przycisk **Otwórz w aplikacji mobilnej**. - No comment provided by engineer. - You can create it later Możesz go utworzyć później @@ -5752,6 +5783,10 @@ Powtórzyć prośbę dołączenia? Możesz używać markdown do formatowania wiadomości: No comment provided by engineer. + + You can view invitation link again in connection details. + No comment provided by engineer. + You can't send messages! Nie możesz wysyłać wiadomości! 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 348b42c948..2129456374 100644 --- a/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff +++ b/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff @@ -312,14 +312,17 @@ ) No comment provided by engineer. + + **Add contact**: to create a new invitation link, or connect via a link you received. + No comment provided by engineer. + **Add new contact**: to create your one-time QR Code or link for your contact. **Добавить новый контакт**: чтобы создать одноразовый QR код или ссылку для Вашего контакта. No comment provided by engineer. - - **Create link / QR code** for your contact to use. - **Создать ссылку / QR код** для Вашего контакта. + + **Create group**: to create a new group. No comment provided by engineer. @@ -332,11 +335,6 @@ **Самый конфиденциальный**: не использовать сервер уведомлений SimpleX Chat, проверять сообщения периодически в фоновом режиме (зависит от того насколько часто Вы используете приложение). No comment provided by engineer. - - **Paste received link** or open it in the browser and tap **Open in mobile app**. - **Вставить полученную ссылку**, или откройте её в браузере и нажмите **Open in mobile app**. - No comment provided by engineer. - **Please note**: you will NOT be able to recover or change passphrase if you lose it. **Внимание**: Вы не сможете восстановить или поменять пароль, если Вы его потеряете. @@ -347,11 +345,6 @@ **Рекомендовано**: токен устройства и уведомления отправляются на сервер SimpleX Chat, но сервер не получает сами сообщения, их размер или от кого они. No comment provided by engineer. - - **Scan QR code**: to connect to your contact in person or via video call. - **Сканировать QR код**: соединиться с Вашим контактом при встрече или во время видеозвонка. - No comment provided by engineer. - **Warning**: Instant push notifications require passphrase saved in Keychain. **Внимание**: для работы мгновенных уведомлений пароль должен быть сохранен в Keychain. @@ -453,11 +446,6 @@ 1 неделю time interval - - 1-time link - Одноразовая ссылка - No comment provided by engineer. - 5 minutes 5 минут @@ -573,6 +561,10 @@ Добавьте адрес в свой профиль, чтобы Ваши контакты могли поделиться им. Профиль будет отправлен Вашим контактам. No comment provided by engineer. + + Add contact + No comment provided by engineer. + Add preset servers Добавить серверы по умолчанию @@ -978,6 +970,10 @@ Звонки No comment provided by engineer. + + Camera not available + No comment provided by engineer. + Can't delete user profile! Нельзя удалить профиль пользователя! @@ -1242,11 +1238,6 @@ This is your own one-time link! Соединиться через ссылку No comment provided by engineer. - - Connect via link / QR code - Соединиться через ссылку / QR код - No comment provided by engineer. - Connect via one-time link Соединиться через одноразовую ссылку @@ -1422,11 +1413,6 @@ This is your own one-time link! Создайте новый профиль в [приложении для компьютера](https://simplex.chat/downloads/). 💻 No comment provided by engineer. - - Create one-time invitation link - Создать ссылку-приглашение - No comment provided by engineer. - Create profile Создать профиль @@ -1452,6 +1438,10 @@ This is your own one-time link! Дата создания %@ No comment provided by engineer. + + Creating link… + No comment provided by engineer. + Current Passcode Текущий Код @@ -2002,6 +1992,10 @@ This cannot be undone! Включить автоматическое удаление сообщений? No comment provided by engineer. + + Enable camera access + No comment provided by engineer. + Enable for all Включить для всех @@ -2345,6 +2339,10 @@ This cannot be undone! Ошибка при сохранении пароля пользователя No comment provided by engineer. + + Error scanning code: %@ + No comment provided by engineer. + Error sending email Ошибка отправки email @@ -2820,11 +2818,6 @@ This cannot be undone! Если Вы не можете встретиться лично, покажите QR-код во время видеозвонка или поделитесь ссылкой. No comment provided by engineer. - - If you cannot meet in person, you can **scan QR code in the video call**, or your contact can share an invitation link. - Если Вы не можете встретиться лично, Вы можете **сосканировать QR код во время видеозвонка**, или Ваш контакт может отправить Вам ссылку. - No comment provided by engineer. - If you enter this passcode when opening the app, all app data will be irreversibly removed! Если Вы введете этот код при открытии приложения, все данные приложения будут безвозвратно удалены! @@ -2982,11 +2975,19 @@ This cannot be undone! Интерфейс No comment provided by engineer. + + Invalid QR code + No comment provided by engineer. + Invalid connection link Ошибка в ссылке контакта No comment provided by engineer. + + Invalid link + No comment provided by engineer. + Invalid name! Неверное имя! @@ -3114,11 +3115,19 @@ This is your link for group %@! Вступление в группу No comment provided by engineer. + + Keep + No comment provided by engineer. + Keep the app open to use it from desktop Оставьте приложение открытым, чтобы использовать его с компьютера No comment provided by engineer. + + Keep unused invitation? + No comment provided by engineer. + Keep your connections Сохраните Ваши соединения @@ -3449,6 +3458,10 @@ This is your link for group %@! Новый Код No comment provided by engineer. + + New chat + No comment provided by engineer. + New contact request Новый запрос на соединение @@ -3573,6 +3586,10 @@ This is your link for group %@! - приостанавливать членов (роль "наблюдатель") No comment provided by engineer. + + OK + No comment provided by engineer. + Off Выключено @@ -3722,6 +3739,14 @@ This is your link for group %@! Opening app… No comment provided by engineer. + + Or scan QR code + No comment provided by engineer. + + + Or show this code + No comment provided by engineer. + PING count Количество PING @@ -3762,11 +3787,6 @@ This is your link for group %@! Пароль чтобы раскрыть No comment provided by engineer. - - Paste - Вставить - No comment provided by engineer. - Paste desktop address Вставить адрес компьютера @@ -3777,16 +3797,10 @@ This is your link for group %@! Вставить изображение No comment provided by engineer. - - Paste received link - Вставить полученную ссылку + + Paste the link you received No comment provided by engineer. - - Paste the link you received to connect with your contact. - Чтобы соединиться, вставьте ссылку, полученную от Вашего контакта. - placeholder - People can connect to you only via the links you share. С Вами можно соединиться только через созданные Вами ссылки. @@ -4032,6 +4046,10 @@ Error: %@ Узнать больше в [Руководстве пользователя](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address). No comment provided by engineer. + + Read more in [User Guide](https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode). + No comment provided by engineer. + Read more in [User Guide](https://simplex.chat/docs/guide/readme.html#connect-to-friends). Узнать больше в [Руководстве пользователя](https://simplex.chat/docs/guide/readme.html#connect-to-friends). @@ -4242,6 +4260,10 @@ Error: %@ Ошибка при восстановлении базы данных No comment provided by engineer. + + Retry + No comment provided by engineer. + Reveal Показать @@ -4397,6 +4419,10 @@ Error: %@ Поиск No comment provided by engineer. + + Search or paste SimpleX link + No comment provided by engineer. + Secure queue Защита очереди @@ -4672,9 +4698,8 @@ Error: %@ Поделиться ссылкой No comment provided by engineer. - - Share one-time invitation link - Поделиться ссылкой-приглашением + + Share this 1-time invite link No comment provided by engineer. @@ -4797,11 +4822,6 @@ Error: %@ Контакт notification title - - Start a new chat - Начать новый разговор - No comment provided by engineer. - Start chat Запустить чат @@ -4936,6 +4956,14 @@ Error: %@ Нажмите, чтобы вступить инкогнито No comment provided by engineer. + + Tap to paste link + No comment provided by engineer. + + + Tap to scan + No comment provided by engineer. + Tap to start a new chat Нажмите, чтобы начать чат @@ -4998,6 +5026,10 @@ It can happen because of some bug or when the connection is compromised.Попытка поменять пароль базы данных не была завершена. No comment provided by engineer. + + The code you scanned is not a SimpleX link QR code. + No comment provided by engineer. + The connection you accepted will be cancelled! Подтвержденное соединение будет отменено! @@ -5063,6 +5095,10 @@ It can happen because of some bug or when the connection is compromised.Серверы для новых соединений Вашего текущего профиля чата **%@**. No comment provided by engineer. + + The text you pasted is not a SimpleX link. + No comment provided by engineer. + Theme Тема @@ -5683,11 +5719,6 @@ Repeat join request? Вы можете принимать звонки на экране блокировки, без аутентификации. No comment provided by engineer. - - You can also connect by clicking the link. If it opens in the browser, click **Open in mobile app** button. - Вы также можете соединиться, открыв ссылку. Если ссылка откроется в браузере, нажмите кнопку **Open in mobile app**. - No comment provided by engineer. - You can create it later Вы можете создать его позже @@ -5752,6 +5783,10 @@ Repeat join request? Вы можете форматировать сообщения: No comment provided by engineer. + + You can view invitation link again in connection details. + No comment provided by engineer. + You can't send messages! Вы не можете отправлять сообщения! 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 c062999aa5..b4520553c5 100644 --- a/apps/ios/SimpleX Localizations/th.xcloc/Localized Contents/th.xliff +++ b/apps/ios/SimpleX Localizations/th.xcloc/Localized Contents/th.xliff @@ -297,14 +297,17 @@ ) No comment provided by engineer. + + **Add contact**: to create a new invitation link, or connect via a link you received. + No comment provided by engineer. + **Add new contact**: to create your one-time QR Code or link for your contact. **เพิ่มผู้ติดต่อใหม่**: เพื่อสร้างคิวอาร์โค้ดแบบใช้ครั้งเดียวหรือลิงก์สำหรับผู้ติดต่อของคุณ No comment provided by engineer. - - **Create link / QR code** for your contact to use. - **สร้างลิงค์ / คิวอาร์โค้ด** เพื่อให้ผู้ติดต่อของคุณใช้ + + **Create group**: to create a new group. No comment provided by engineer. @@ -317,11 +320,6 @@ **ส่วนตัวที่สุด**: ไม่ใช้เซิร์ฟเวอร์การแจ้งเตือนของ SimpleX Chat ตรวจสอบข้อความเป็นระยะในพื้นหลัง (ขึ้นอยู่กับความถี่ที่คุณใช้แอป) No comment provided by engineer. - - **Paste received link** or open it in the browser and tap **Open in mobile app**. - **แปะลิงก์ที่ได้รับ** หรือเปิดในเบราว์เซอร์แล้วแตะ **เปิดในแอปมือถือ** - No comment provided by engineer. - **Please note**: you will NOT be able to recover or change passphrase if you lose it. **โปรดทราบ**: คุณจะไม่สามารถกู้คืนหรือเปลี่ยนรหัสผ่านได้หากคุณทำรหัสผ่านหาย @@ -332,11 +330,6 @@ **แนะนำ**: โทเค็นอุปกรณ์และการแจ้งเตือนจะถูกส่งไปยังเซิร์ฟเวอร์การแจ้งเตือนของ SimpleX Chat แต่ไม่ใช่เนื้อหาข้อความ ขนาด หรือผู้ที่ส่ง No comment provided by engineer. - - **Scan QR code**: to connect to your contact in person or via video call. - **สแกนคิวอาร์โค้ด**: เพื่อเชื่อมต่อกับผู้ติดต่อของคุณด้วยตนเองหรือผ่านการสนทนาทางวิดีโอ - No comment provided by engineer. - **Warning**: Instant push notifications require passphrase saved in Keychain. **คำเตือน**: การแจ้งเตือนแบบพุชทันทีจำเป็นต้องบันทึกรหัสผ่านไว้ใน Keychain @@ -431,11 +424,6 @@ 1 สัปดาห์ time interval - - 1-time link - ลิงก์สำหรับใช้ 1 ครั้ง - No comment provided by engineer. - 5 minutes 5 นาที @@ -549,6 +537,10 @@ เพิ่มที่อยู่ลงในโปรไฟล์ของคุณ เพื่อให้ผู้ติดต่อของคุณสามารถแชร์กับผู้อื่นได้ การอัปเดตโปรไฟล์จะถูกส่งไปยังผู้ติดต่อของคุณ No comment provided by engineer. + + Add contact + No comment provided by engineer. + Add preset servers เพิ่มเซิร์ฟเวอร์ที่ตั้งไว้ล่วงหน้า @@ -943,6 +935,10 @@ โทร No comment provided by engineer. + + Camera not available + No comment provided by engineer. + Can't delete user profile! ไม่สามารถลบโปรไฟล์ผู้ใช้ได้! @@ -1198,11 +1194,6 @@ This is your own one-time link! เชื่อมต่อผ่านลิงก์ No comment provided by engineer. - - Connect via link / QR code - เชื่อมต่อผ่านลิงค์ / คิวอาร์โค้ด - No comment provided by engineer. - Connect via one-time link No comment provided by engineer. @@ -1368,11 +1359,6 @@ This is your own one-time link! Create new profile in [desktop app](https://simplex.chat/downloads/). 💻 No comment provided by engineer. - - Create one-time invitation link - สร้างลิงก์เชิญแบบใช้ครั้งเดียว - No comment provided by engineer. - Create profile No comment provided by engineer. @@ -1397,6 +1383,10 @@ This is your own one-time link! สร้างเมื่อ %@ No comment provided by engineer. + + Creating link… + No comment provided by engineer. + Current Passcode รหัสผ่านปัจจุบัน @@ -1936,6 +1926,10 @@ This cannot be undone! เปิดใช้งานการลบข้อความอัตโนมัติ? No comment provided by engineer. + + Enable camera access + No comment provided by engineer. + Enable for all เปิดใช้งานสําหรับทุกคน @@ -2270,6 +2264,10 @@ This cannot be undone! เกิดข้อผิดพลาดในการบันทึกรหัสผ่านผู้ใช้ No comment provided by engineer. + + Error scanning code: %@ + No comment provided by engineer. + Error sending email เกิดข้อผิดพลาดในการส่งอีเมล @@ -2738,11 +2736,6 @@ This cannot be undone! หากคุณไม่สามารถพบกันในชีวิตจริงได้ ให้แสดงคิวอาร์โค้ดในวิดีโอคอล หรือแชร์ลิงก์ No comment provided by engineer. - - If you cannot meet in person, you can **scan QR code in the video call**, or your contact can share an invitation link. - หากคุณไม่สามารถพบปะด้วยตนเอง คุณสามารถ **สแกนคิวอาร์โค้ดผ่านการสนทนาทางวิดีโอ** หรือผู้ติดต่อของคุณสามารถแชร์ลิงก์เชิญได้ - No comment provided by engineer. - If you enter this passcode when opening the app, all app data will be irreversibly removed! หากคุณใส่รหัสผ่านนี้เมื่อเปิดแอป ข้อมูลแอปทั้งหมดจะถูกลบอย่างถาวร! @@ -2897,11 +2890,19 @@ This cannot be undone! อินเตอร์เฟซ No comment provided by engineer. + + Invalid QR code + No comment provided by engineer. + Invalid connection link ลิงค์เชื่อมต่อไม่ถูกต้อง No comment provided by engineer. + + Invalid link + No comment provided by engineer. + Invalid name! No comment provided by engineer. @@ -3023,10 +3024,18 @@ This is your link for group %@! กำลังจะเข้าร่วมกลุ่ม No comment provided by engineer. + + Keep + No comment provided by engineer. + Keep the app open to use it from desktop No comment provided by engineer. + + Keep unused invitation? + No comment provided by engineer. + Keep your connections รักษาการเชื่อมต่อของคุณ @@ -3352,6 +3361,10 @@ This is your link for group %@! รหัสผ่านใหม่ No comment provided by engineer. + + New chat + No comment provided by engineer. + New contact request คำขอติดต่อใหม่ @@ -3473,6 +3486,10 @@ This is your link for group %@! - ปิดการใช้งานสมาชิก (บทบาท "ผู้สังเกตการณ์") No comment provided by engineer. + + OK + No comment provided by engineer. + Off ปิด @@ -3620,6 +3637,14 @@ This is your link for group %@! Opening app… No comment provided by engineer. + + Or scan QR code + No comment provided by engineer. + + + Or show this code + No comment provided by engineer. + PING count จํานวน PING @@ -3660,11 +3685,6 @@ This is your link for group %@! รหัสผ่านที่จะแสดง No comment provided by engineer. - - Paste - แปะ - No comment provided by engineer. - Paste desktop address No comment provided by engineer. @@ -3674,15 +3694,10 @@ This is your link for group %@! แปะภาพ No comment provided by engineer. - - Paste received link - แปะลิงก์ที่ได้รับ + + Paste the link you received No comment provided by engineer. - - Paste the link you received to connect with your contact. - placeholder - People can connect to you only via the links you share. ผู้คนสามารถเชื่อมต่อกับคุณผ่านลิงก์ที่คุณแบ่งปันเท่านั้น @@ -3926,6 +3941,10 @@ Error: %@ อ่านเพิ่มเติมใน[คู่มือผู้ใช้](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address) No comment provided by engineer. + + Read more in [User Guide](https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode). + No comment provided by engineer. + Read more in [User Guide](https://simplex.chat/docs/guide/readme.html#connect-to-friends). อ่านเพิ่มเติมใน[คู่มือผู้ใช้](https://simplex.chat/docs/guide/readme.html#connect-to-friends) @@ -4132,6 +4151,10 @@ Error: %@ กู้คืนข้อผิดพลาดของฐานข้อมูล No comment provided by engineer. + + Retry + No comment provided by engineer. + Reveal เปิดเผย @@ -4286,6 +4309,10 @@ Error: %@ ค้นหา No comment provided by engineer. + + Search or paste SimpleX link + No comment provided by engineer. + Secure queue คิวที่ปลอดภัย @@ -4557,9 +4584,8 @@ Error: %@ แชร์ลิงก์ No comment provided by engineer. - - Share one-time invitation link - แชร์ลิงก์เชิญแบบใช้ครั้งเดียว + + Share this 1-time invite link No comment provided by engineer. @@ -4679,11 +4705,6 @@ Error: %@ ใครบางคน notification title - - Start a new chat - เริ่มแชทใหม่ - No comment provided by engineer. - Start chat เริ่มแชท @@ -4817,6 +4838,14 @@ Error: %@ แตะเพื่อเข้าร่วมโหมดไม่ระบุตัวตน No comment provided by engineer. + + Tap to paste link + No comment provided by engineer. + + + Tap to scan + No comment provided by engineer. + Tap to start a new chat แตะเพื่อเริ่มแชทใหม่ @@ -4880,6 +4909,10 @@ It can happen because of some bug or when the connection is compromised.ความพยายามในการเปลี่ยนรหัสผ่านของฐานข้อมูลไม่เสร็จสมบูรณ์ No comment provided by engineer. + + The code you scanned is not a SimpleX link QR code. + No comment provided by engineer. + The connection you accepted will be cancelled! การเชื่อมต่อที่คุณยอมรับจะถูกยกเลิก! @@ -4945,6 +4978,10 @@ It can happen because of some bug or when the connection is compromised.เซิร์ฟเวอร์สำหรับการเชื่อมต่อใหม่ของโปรไฟล์การแชทปัจจุบันของคุณ **%@** No comment provided by engineer. + + The text you pasted is not a SimpleX link. + No comment provided by engineer. + Theme ธีม @@ -5537,11 +5574,6 @@ Repeat join request? คุณสามารถรับสายจากหน้าจอล็อกโดยไม่ต้องมีการตรวจสอบสิทธิ์อุปกรณ์และแอป No comment provided by engineer. - - You can also connect by clicking the link. If it opens in the browser, click **Open in mobile app** button. - คุณสามารถเชื่อมต่อได้โดยคลิกที่ลิงค์ หากเปิดในเบราว์เซอร์ ให้คลิกปุ่ม **เปิดในแอปมือถือ** - No comment provided by engineer. - You can create it later คุณสามารถสร้างได้ในภายหลัง @@ -5606,6 +5638,10 @@ Repeat join request? คุณสามารถใช้มาร์กดาวน์เพื่อจัดรูปแบบข้อความ: No comment provided by engineer. + + You can view invitation link again in connection details. + No comment provided by engineer. + You can't send messages! คุณไม่สามารถส่งข้อความได้! 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 2bb43ba736..2d219440f7 100644 --- a/apps/ios/SimpleX Localizations/uk.xcloc/Localized Contents/uk.xliff +++ b/apps/ios/SimpleX Localizations/uk.xcloc/Localized Contents/uk.xliff @@ -312,14 +312,17 @@ ) No comment provided by engineer. + + **Add contact**: to create a new invitation link, or connect via a link you received. + No comment provided by engineer. + **Add new contact**: to create your one-time QR Code or link for your contact. **Додати новий контакт**: щоб створити одноразовий QR-код або посилання для свого контакту. No comment provided by engineer. - - **Create link / QR code** for your contact to use. - **Створіть посилання / QR-код** для використання вашим контактом. + + **Create group**: to create a new group. No comment provided by engineer. @@ -332,11 +335,6 @@ **Найбільш приватний**: не використовуйте сервер сповіщень SimpleX Chat, періодично перевіряйте повідомлення у фоновому режимі (залежить від того, як часто ви користуєтесь додатком). No comment provided by engineer. - - **Paste received link** or open it in the browser and tap **Open in mobile app**. - **Вставте отримане посилання** або відкрийте його в браузері і натисніть **Відкрити в мобільному додатку**. - No comment provided by engineer. - **Please note**: you will NOT be able to recover or change passphrase if you lose it. **Зверніть увагу: ви НЕ зможете відновити або змінити пароль, якщо втратите його. @@ -347,11 +345,6 @@ **Рекомендується**: токен пристрою та сповіщення надсилаються на сервер сповіщень SimpleX Chat, але не вміст повідомлення, його розмір або від кого воно надійшло. No comment provided by engineer. - - **Scan QR code**: to connect to your contact in person or via video call. - **Відскануйте QR-код**: щоб з'єднатися з вашим контактом особисто або за допомогою відеодзвінка. - No comment provided by engineer. - **Warning**: Instant push notifications require passphrase saved in Keychain. **Попередження**: Для отримання миттєвих пуш-сповіщень потрібна парольна фраза, збережена у брелоку. @@ -453,11 +446,6 @@ 1 тиждень time interval - - 1-time link - 1-разове посилання - No comment provided by engineer. - 5 minutes 5 хвилин @@ -573,6 +561,10 @@ Додайте адресу до свого профілю, щоб ваші контакти могли поділитися нею з іншими людьми. Повідомлення про оновлення профілю буде надіслано вашим контактам. No comment provided by engineer. + + Add contact + No comment provided by engineer. + Add preset servers Додавання попередньо встановлених серверів @@ -978,6 +970,10 @@ Дзвінки No comment provided by engineer. + + Camera not available + No comment provided by engineer. + Can't delete user profile! Не можу видалити профіль користувача! @@ -1242,11 +1238,6 @@ This is your own one-time link! Підключіться за посиланням No comment provided by engineer. - - Connect via link / QR code - Підключитися за посиланням / QR-кодом - No comment provided by engineer. - Connect via one-time link Під'єднатися за одноразовим посиланням @@ -1415,11 +1406,6 @@ This is your own one-time link! Create new profile in [desktop app](https://simplex.chat/downloads/). 💻 No comment provided by engineer. - - Create one-time invitation link - Створіть одноразове посилання-запрошення - No comment provided by engineer. - Create profile No comment provided by engineer. @@ -1444,6 +1430,10 @@ This is your own one-time link! Створено %@ No comment provided by engineer. + + Creating link… + No comment provided by engineer. + Current Passcode Поточний пароль @@ -1984,6 +1974,10 @@ This cannot be undone! Увімкнути автоматичне видалення повідомлень? No comment provided by engineer. + + Enable camera access + No comment provided by engineer. + Enable for all Увімкнути для всіх @@ -2318,6 +2312,10 @@ This cannot be undone! Помилка збереження пароля користувача No comment provided by engineer. + + Error scanning code: %@ + No comment provided by engineer. + Error sending email Помилка надсилання електронного листа @@ -2786,11 +2784,6 @@ This cannot be undone! Якщо ви не можете зустрітися особисто, покажіть QR-код у відеодзвінку або поділіться посиланням. No comment provided by engineer. - - If you cannot meet in person, you can **scan QR code in the video call**, or your contact can share an invitation link. - Якщо ви не можете зустрітися особисто, ви можете **сканувати QR-код у відеодзвінку**, або ваш контакт може поділитися посиланням на запрошення. - No comment provided by engineer. - If you enter this passcode when opening the app, all app data will be irreversibly removed! Якщо ви введете цей пароль при відкритті програми, всі дані програми будуть безповоротно видалені! @@ -2946,11 +2939,19 @@ This cannot be undone! Інтерфейс No comment provided by engineer. + + Invalid QR code + No comment provided by engineer. + Invalid connection link Неправильне посилання для підключення No comment provided by engineer. + + Invalid link + No comment provided by engineer. + Invalid name! No comment provided by engineer. @@ -3073,10 +3074,18 @@ This is your link for group %@! Приєднання до групи No comment provided by engineer. + + Keep + No comment provided by engineer. + Keep the app open to use it from desktop No comment provided by engineer. + + Keep unused invitation? + No comment provided by engineer. + Keep your connections Зберігайте свої зв'язки @@ -3403,6 +3412,10 @@ This is your link for group %@! Новий пароль No comment provided by engineer. + + New chat + No comment provided by engineer. + New contact request Новий запит на контакт @@ -3525,6 +3538,10 @@ This is your link for group %@! - відключати користувачів (роль "спостерігач") No comment provided by engineer. + + OK + No comment provided by engineer. + Off Вимкнено @@ -3672,6 +3689,14 @@ This is your link for group %@! Opening app… No comment provided by engineer. + + Or scan QR code + No comment provided by engineer. + + + Or show this code + No comment provided by engineer. + PING count Кількість PING @@ -3712,11 +3737,6 @@ This is your link for group %@! Показати пароль No comment provided by engineer. - - Paste - Вставити - No comment provided by engineer. - Paste desktop address No comment provided by engineer. @@ -3726,16 +3746,10 @@ This is your link for group %@! Вставити зображення No comment provided by engineer. - - Paste received link - Вставте отримане посилання + + Paste the link you received No comment provided by engineer. - - Paste the link you received to connect with your contact. - Вставте отримане посилання для зв'язку з вашим контактом. - placeholder - People can connect to you only via the links you share. Люди можуть зв'язатися з вами лише за посиланнями, якими ви ділитеся. @@ -3979,6 +3993,10 @@ Error: %@ Читайте більше в [Посібнику користувача](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address). No comment provided by engineer. + + Read more in [User Guide](https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode). + No comment provided by engineer. + Read more in [User Guide](https://simplex.chat/docs/guide/readme.html#connect-to-friends). Читайте більше в [Посібнику користувача](https://simplex.chat/docs/guide/readme.html#connect-to-friends). @@ -4187,6 +4205,10 @@ Error: %@ Відновлення помилки бази даних No comment provided by engineer. + + Retry + No comment provided by engineer. + Reveal Показувати @@ -4341,6 +4363,10 @@ Error: %@ Пошук No comment provided by engineer. + + Search or paste SimpleX link + No comment provided by engineer. + Secure queue Безпечна черга @@ -4614,9 +4640,8 @@ Error: %@ Поділіться посиланням No comment provided by engineer. - - Share one-time invitation link - Поділіться посиланням на одноразове запрошення + + Share this 1-time invite link No comment provided by engineer. @@ -4738,11 +4763,6 @@ Error: %@ Хтось notification title - - Start a new chat - Почніть новий чат - No comment provided by engineer. - Start chat Почати чат @@ -4876,6 +4896,14 @@ Error: %@ Натисніть, щоб приєднатися інкогніто No comment provided by engineer. + + Tap to paste link + No comment provided by engineer. + + + Tap to scan + No comment provided by engineer. + Tap to start a new chat Натисніть, щоб почати новий чат @@ -4938,6 +4966,10 @@ It can happen because of some bug or when the connection is compromised.Спроба змінити пароль до бази даних не була завершена. No comment provided by engineer. + + The code you scanned is not a SimpleX link QR code. + No comment provided by engineer. + The connection you accepted will be cancelled! Прийняте вами з'єднання буде скасовано! @@ -5003,6 +5035,10 @@ It can happen because of some bug or when the connection is compromised.Сервери для нових підключень вашого поточного профілю чату **%@**. No comment provided by engineer. + + The text you pasted is not a SimpleX link. + No comment provided by engineer. + Theme Тема @@ -5599,11 +5635,6 @@ Repeat join request? Ви можете приймати дзвінки з екрана блокування без автентифікації пристрою та програми. No comment provided by engineer. - - You can also connect by clicking the link. If it opens in the browser, click **Open in mobile app** button. - Ви також можете підключитися за посиланням. Якщо воно відкриється в браузері, натисніть кнопку **Відкрити в мобільному додатку**. - No comment provided by engineer. - You can create it later Ви можете створити його пізніше @@ -5668,6 +5699,10 @@ Repeat join request? Ви можете використовувати розмітку для форматування повідомлень: No comment provided by engineer. + + You can view invitation link again in connection details. + No comment provided by engineer. + You can't send messages! Ви не можете надсилати повідомлення! 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 6a07b28157..60434b1661 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 @@ -303,14 +303,17 @@ ) No comment provided by engineer. + + **Add contact**: to create a new invitation link, or connect via a link you received. + No comment provided by engineer. + **Add new contact**: to create your one-time QR Code or link for your contact. **添加新联系人**:为您的联系人创建一次性二维码或者链接。 No comment provided by engineer. - - **Create link / QR code** for your contact to use. - **创建链接 / 二维码** 给您的联系人使用。 + + **Create group**: to create a new group. No comment provided by engineer. @@ -323,11 +326,6 @@ **最私密**:不使用 SimpleX Chat 通知服务器,在后台定期检查消息(取决于您多经常使用应用程序)。 No comment provided by engineer. - - **Paste received link** or open it in the browser and tap **Open in mobile app**. - **粘贴收到的链接**或者在浏览器里打开并且点击**在移动应用程序里打开**。 - No comment provided by engineer. - **Please note**: you will NOT be able to recover or change passphrase if you lose it. **请注意**:如果您丢失密码,您将无法恢复或者更改密码。 @@ -338,11 +336,6 @@ **推荐**:设备令牌和通知会发送至 SimpleX Chat 通知服务器,但是消息内容、大小或者发送人不会。 No comment provided by engineer. - - **Scan QR code**: to connect to your contact in person or via video call. - **扫描二维码**:见面或者通过视频通话来连接您的联系人。 - No comment provided by engineer. - **Warning**: Instant push notifications require passphrase saved in Keychain. **警告**:及时推送通知需要保存在钥匙串的密码。 @@ -440,11 +433,6 @@ 1周 time interval - - 1-time link - 一次性链接 - No comment provided by engineer. - 5 minutes 5分钟 @@ -560,6 +548,10 @@ 将地址添加到您的个人资料,以便您的联系人可以与其他人共享。个人资料更新将发送给您的联系人。 No comment provided by engineer. + + Add contact + No comment provided by engineer. + Add preset servers 添加预设服务器 @@ -956,6 +948,10 @@ 通话 No comment provided by engineer. + + Camera not available + No comment provided by engineer. + Can't delete user profile! 无法删除用户个人资料! @@ -1212,11 +1208,6 @@ This is your own one-time link! 通过链接连接 No comment provided by engineer. - - Connect via link / QR code - 通过群组链接/二维码连接 - No comment provided by engineer. - Connect via one-time link 通过一次性链接连接 @@ -1384,11 +1375,6 @@ This is your own one-time link! 在[桌面应用程序](https://simplex.chat/downloads/)中创建新的个人资料。 💻 No comment provided by engineer. - - Create one-time invitation link - 创建一次性邀请链接 - No comment provided by engineer. - Create profile No comment provided by engineer. @@ -1413,6 +1399,10 @@ This is your own one-time link! 创建于 %@ No comment provided by engineer. + + Creating link… + No comment provided by engineer. + Current Passcode 当前密码 @@ -1954,6 +1944,10 @@ This cannot be undone! 启用自动删除消息? No comment provided by engineer. + + Enable camera access + No comment provided by engineer. + Enable for all 全部启用 @@ -2292,6 +2286,10 @@ This cannot be undone! 保存用户密码时出错 No comment provided by engineer. + + Error scanning code: %@ + No comment provided by engineer. + Error sending email 发送电邮错误 @@ -2761,11 +2759,6 @@ This cannot be undone! 如果您不能亲自见面,可以在视频通话中展示二维码,或分享链接。 No comment provided by engineer. - - If you cannot meet in person, you can **scan QR code in the video call**, or your contact can share an invitation link. - 如果您不能亲自见面,您可以**扫描视频通话中的二维码**,或者您的联系人可以分享邀请链接。 - No comment provided by engineer. - If you enter this passcode when opening the app, all app data will be irreversibly removed! 如果您在打开应用时输入该密码,所有应用程序数据将被不可撤回地删除! @@ -2921,11 +2914,19 @@ This cannot be undone! 界面 No comment provided by engineer. + + Invalid QR code + No comment provided by engineer. + Invalid connection link 无效的连接链接 No comment provided by engineer. + + Invalid link + No comment provided by engineer. + Invalid name! No comment provided by engineer. @@ -3048,10 +3049,18 @@ This is your link for group %@! 加入群组中 No comment provided by engineer. + + Keep + No comment provided by engineer. + Keep the app open to use it from desktop No comment provided by engineer. + + Keep unused invitation? + No comment provided by engineer. + Keep your connections 保持连接 @@ -3378,6 +3387,10 @@ This is your link for group %@! 新密码 No comment provided by engineer. + + New chat + No comment provided by engineer. + New contact request 新联系人请求 @@ -3501,6 +3514,10 @@ This is your link for group %@! - 禁用成员(“观察员”角色) No comment provided by engineer. + + OK + No comment provided by engineer. + Off 关闭 @@ -3649,6 +3666,14 @@ This is your link for group %@! Opening app… No comment provided by engineer. + + Or scan QR code + No comment provided by engineer. + + + Or show this code + No comment provided by engineer. + PING count PING 次数 @@ -3689,11 +3714,6 @@ This is your link for group %@! 显示密码 No comment provided by engineer. - - Paste - 粘贴 - No comment provided by engineer. - Paste desktop address No comment provided by engineer. @@ -3703,16 +3723,10 @@ This is your link for group %@! 粘贴图片 No comment provided by engineer. - - Paste received link - 粘贴收到的链接 + + Paste the link you received No comment provided by engineer. - - Paste the link you received to connect with your contact. - 将您收到的链接粘贴到下面的框中以与您的联系人联系。 - placeholder - People can connect to you only via the links you share. 人们只能通过您共享的链接与您建立联系。 @@ -3956,6 +3970,10 @@ Error: %@ 在 [用户指南](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address) 中阅读更多内容。 No comment provided by engineer. + + Read more in [User Guide](https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode). + No comment provided by engineer. + Read more in [User Guide](https://simplex.chat/docs/guide/readme.html#connect-to-friends). 在 [用户指南](https://simplex.chat/docs/guide/readme.html#connect-to-friends) 中阅读更多内容。 @@ -4164,6 +4182,10 @@ Error: %@ 恢复数据库错误 No comment provided by engineer. + + Retry + No comment provided by engineer. + Reveal 揭示 @@ -4318,6 +4340,10 @@ Error: %@ 搜索 No comment provided by engineer. + + Search or paste SimpleX link + No comment provided by engineer. + Secure queue 保护队列 @@ -4592,9 +4618,8 @@ Error: %@ 分享链接 No comment provided by engineer. - - Share one-time invitation link - 分享一次性邀请链接 + + Share this 1-time invite link No comment provided by engineer. @@ -4717,11 +4742,6 @@ Error: %@ 某人 notification title - - Start a new chat - 开始新聊天 - No comment provided by engineer. - Start chat 开始聊天 @@ -4855,6 +4875,14 @@ Error: %@ 点击以加入隐身聊天 No comment provided by engineer. + + Tap to paste link + No comment provided by engineer. + + + Tap to scan + No comment provided by engineer. + Tap to start a new chat 点击开始一个新聊天 @@ -4917,6 +4945,10 @@ It can happen because of some bug or when the connection is compromised.更改数据库密码的尝试未完成。 No comment provided by engineer. + + The code you scanned is not a SimpleX link QR code. + No comment provided by engineer. + The connection you accepted will be cancelled! 您接受的连接将被取消! @@ -4982,6 +5014,10 @@ It can happen because of some bug or when the connection is compromised.您当前聊天资料 **%@** 的新连接服务器。 No comment provided by engineer. + + The text you pasted is not a SimpleX link. + No comment provided by engineer. + Theme 主题 @@ -5579,11 +5615,6 @@ Repeat join request? 您可以从锁屏上接听电话,无需设备和应用程序的认证。 No comment provided by engineer. - - You can also connect by clicking the link. If it opens in the browser, click **Open in mobile app** button. - 您也可以通过点击链接进行连接。如果在浏览器中打开,请点击“在移动应用程序中打开”按钮。 - No comment provided by engineer. - You can create it later 您可以以后创建它 @@ -5648,6 +5679,10 @@ Repeat join request? 您可以使用 markdown 来编排消息格式: No comment provided by engineer. + + You can view invitation link again in connection details. + No comment provided by engineer. + You can't send messages! 您无法发送消息! diff --git a/apps/ios/SimpleX.xcodeproj/project.pbxproj b/apps/ios/SimpleX.xcodeproj/project.pbxproj index 801116bf80..a6b5eb49e9 100644 --- a/apps/ios/SimpleX.xcodeproj/project.pbxproj +++ b/apps/ios/SimpleX.xcodeproj/project.pbxproj @@ -16,7 +16,6 @@ 18415C6C56DBCEC2CBBD2F11 /* WebRTCClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18415323A4082FC92887F906 /* WebRTCClient.swift */; }; 18415F9A2D551F9757DA4654 /* CIVideoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18415FD2E36F13F596A45BB4 /* CIVideoView.swift */; }; 18415FEFE153C5920BFB7828 /* GroupWelcomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1841516F0CE5992B0EDFB377 /* GroupWelcomeView.swift */; }; - 3C8C548928133C84000A3EC7 /* PasteToConnectView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C8C548828133C84000A3EC7 /* PasteToConnectView.swift */; }; 3CDBCF4227FAE51000354CDD /* ComposeLinkView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CDBCF4127FAE51000354CDD /* ComposeLinkView.swift */; }; 3CDBCF4827FF621E00354CDD /* CILinkView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CDBCF4727FF621E00354CDD /* CILinkView.swift */; }; 5C00164428A26FBC0094D739 /* ContextMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C00164328A26FBC0094D739 /* ContextMenu.swift */; }; @@ -61,7 +60,6 @@ 5C5F2B7027EBC704006A9D5F /* ProfileImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C5F2B6F27EBC704006A9D5F /* ProfileImage.swift */; }; 5C65DAF929D0CC20003CEE45 /* DeveloperView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C65DAF829D0CC20003CEE45 /* DeveloperView.swift */; }; 5C65F343297D45E100B67AF3 /* VersionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C65F341297D3F3600B67AF3 /* VersionView.swift */; }; - 5C6AD81327A834E300348BD7 /* NewChatButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C6AD81227A834E300348BD7 /* NewChatButton.swift */; }; 5C6BA667289BD954009B8ECC /* DismissSheets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C6BA666289BD954009B8ECC /* DismissSheets.swift */; }; 5C7031162953C97F00150A12 /* CIFeaturePreferenceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C7031152953C97F00150A12 /* CIFeaturePreferenceView.swift */; }; 5C7505A227B65FDB00BE3227 /* CIMetaView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C7505A127B65FDB00BE3227 /* CIMetaView.swift */; }; @@ -98,8 +96,6 @@ 5CB0BA92282713FD00B3292C /* CreateProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB0BA91282713FD00B3292C /* CreateProfile.swift */; }; 5CB0BA9A2827FD8800B3292C /* HowItWorks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB0BA992827FD8800B3292C /* HowItWorks.swift */; }; 5CB2084F28DA4B4800D024EC /* RTCServers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB2084E28DA4B4800D024EC /* RTCServers.swift */; }; - 5CB2085128DB64CA00D024EC /* CreateLinkView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB2085028DB64CA00D024EC /* CreateLinkView.swift */; }; - 5CB2085328DB7CAF00D024EC /* ConnectViaLinkView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB2085228DB7CAF00D024EC /* ConnectViaLinkView.swift */; }; 5CB346E52868AA7F001FD2EF /* SuspendChat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB346E42868AA7F001FD2EF /* SuspendChat.swift */; }; 5CB346E72868D76D001FD2EF /* NotificationsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB346E62868D76D001FD2EF /* NotificationsView.swift */; }; 5CB346E92869E8BA001FD2EF /* PushEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB346E82869E8BA001FD2EF /* PushEnvironment.swift */; }; @@ -121,8 +117,6 @@ 5CC2C0FF2809BF11000C35E3 /* SimpleX--iOS--InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5CC2C0FD2809BF11000C35E3 /* SimpleX--iOS--InfoPlist.strings */; }; 5CC868F329EB540C0017BBFD /* CIRcvDecryptionError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CC868F229EB540C0017BBFD /* CIRcvDecryptionError.swift */; }; 5CCB939C297EFCB100399E78 /* NavStackCompat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CCB939B297EFCB100399E78 /* NavStackCompat.swift */; }; - 5CCD403427A5F6DF00368C90 /* AddContactView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CCD403327A5F6DF00368C90 /* AddContactView.swift */; }; - 5CCD403727A5F9A200368C90 /* ScanToConnectView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CCD403627A5F9A200368C90 /* ScanToConnectView.swift */; }; 5CD67B8F2B0E858A00C510B1 /* hs_init.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CD67B8D2B0E858A00C510B1 /* hs_init.h */; settings = {ATTRIBUTES = (Public, ); }; }; 5CD67B902B0E858A00C510B1 /* hs_init.c in Sources */ = {isa = PBXBuildFile; fileRef = 5CD67B8E2B0E858A00C510B1 /* hs_init.c */; }; 5CDCAD482818589900503DA2 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CDCAD472818589900503DA2 /* NotificationService.swift */; }; @@ -157,6 +151,8 @@ 5CFA59D12864782E00863A68 /* ChatArchiveView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CFA59CF286477B400863A68 /* ChatArchiveView.swift */; }; 5CFE0921282EEAF60002594B /* ZoomableScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CFE0920282EEAF60002594B /* ZoomableScrollView.swift */; }; 5CFE0922282EEAF60002594B /* ZoomableScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CFE0920282EEAF60002594B /* ZoomableScrollView.swift */; }; + 640417CD2B29B8C200CCB412 /* NewChatMenuButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 640417CB2B29B8C200CCB412 /* NewChatMenuButton.swift */; }; + 640417CE2B29B8C200CCB412 /* NewChatView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 640417CC2B29B8C200CCB412 /* NewChatView.swift */; }; 6407BA83295DA85D0082BA18 /* CIInvalidJSONView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6407BA82295DA85D0082BA18 /* CIInvalidJSONView.swift */; }; 6419EC562AB8BC8B004A607A /* ContextInvitingContactMemberView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6419EC552AB8BC8B004A607A /* ContextInvitingContactMemberView.swift */; }; 6419EC582AB97507004A607A /* CIMemberCreatedContactView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6419EC572AB97507004A607A /* CIMemberCreatedContactView.swift */; }; @@ -177,6 +173,11 @@ 646BB38E283FDB6D001CE359 /* LocalAuthenticationUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 646BB38D283FDB6D001CE359 /* LocalAuthenticationUtils.swift */; }; 647F090E288EA27B00644C40 /* GroupMemberInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 647F090D288EA27B00644C40 /* GroupMemberInfoView.swift */; }; 648010AB281ADD15009009B9 /* CIFileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 648010AA281ADD15009009B9 /* CIFileView.swift */; }; + 64863B9B2B3C536500714A11 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64863B962B3C536500714A11 /* libgmpxx.a */; }; + 64863B9C2B3C536500714A11 /* libHSsimplex-chat-5.4.2.0-1dXNnkvLJVS8FSAgswHDGD-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64863B972B3C536500714A11 /* libHSsimplex-chat-5.4.2.0-1dXNnkvLJVS8FSAgswHDGD-ghc9.6.3.a */; }; + 64863B9D2B3C536500714A11 /* libHSsimplex-chat-5.4.2.0-1dXNnkvLJVS8FSAgswHDGD.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64863B982B3C536500714A11 /* libHSsimplex-chat-5.4.2.0-1dXNnkvLJVS8FSAgswHDGD.a */; }; + 64863B9E2B3C536500714A11 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64863B992B3C536500714A11 /* libgmp.a */; }; + 64863B9F2B3C536500714A11 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64863B9A2B3C536500714A11 /* libffi.a */; }; 649BCDA0280460FD00C3A862 /* ComposeImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649BCD9F280460FD00C3A862 /* ComposeImageView.swift */; }; 649BCDA22805D6EF00C3A862 /* CIImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649BCDA12805D6EF00C3A862 /* CIImageView.swift */; }; 64AA1C6927EE10C800AC7277 /* ContextItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64AA1C6827EE10C800AC7277 /* ContextItemView.swift */; }; @@ -263,7 +264,6 @@ 18415B08031E8FB0F7FC27F9 /* CallViewRenderers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallViewRenderers.swift; sourceTree = ""; }; 18415DAAAD1ADBEDB0EDA852 /* VideoPlayerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideoPlayerView.swift; sourceTree = ""; }; 18415FD2E36F13F596A45BB4 /* CIVideoView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CIVideoView.swift; sourceTree = ""; }; - 3C8C548828133C84000A3EC7 /* PasteToConnectView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasteToConnectView.swift; sourceTree = ""; }; 3CDBCF4127FAE51000354CDD /* ComposeLinkView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeLinkView.swift; sourceTree = ""; }; 3CDBCF4727FF621E00354CDD /* CILinkView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CILinkView.swift; sourceTree = ""; }; 5C00164328A26FBC0094D739 /* ContextMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextMenu.swift; sourceTree = ""; }; @@ -324,7 +324,6 @@ 5C65DAED29CB8908003CEE45 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InfoPlist.strings; sourceTree = ""; }; 5C65DAF829D0CC20003CEE45 /* DeveloperView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeveloperView.swift; sourceTree = ""; }; 5C65F341297D3F3600B67AF3 /* VersionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VersionView.swift; sourceTree = ""; }; - 5C6AD81227A834E300348BD7 /* NewChatButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewChatButton.swift; sourceTree = ""; }; 5C6BA666289BD954009B8ECC /* DismissSheets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DismissSheets.swift; sourceTree = ""; }; 5C6D183229E93FBA00D430B3 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = "pl.lproj/SimpleX--iOS--InfoPlist.strings"; sourceTree = ""; }; 5C6D183329E93FBA00D430B3 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/InfoPlist.strings; sourceTree = ""; }; @@ -381,8 +380,6 @@ 5CB0BA91282713FD00B3292C /* CreateProfile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateProfile.swift; sourceTree = ""; }; 5CB0BA992827FD8800B3292C /* HowItWorks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HowItWorks.swift; sourceTree = ""; }; 5CB2084E28DA4B4800D024EC /* RTCServers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RTCServers.swift; sourceTree = ""; }; - 5CB2085028DB64CA00D024EC /* CreateLinkView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateLinkView.swift; sourceTree = ""; }; - 5CB2085228DB7CAF00D024EC /* ConnectViaLinkView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectViaLinkView.swift; sourceTree = ""; }; 5CB2085428DE647400D024EC /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; 5CB346E42868AA7F001FD2EF /* SuspendChat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuspendChat.swift; sourceTree = ""; }; 5CB346E62868D76D001FD2EF /* NotificationsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsView.swift; sourceTree = ""; }; @@ -408,8 +405,6 @@ 5CC2C0FE2809BF11000C35E3 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = "ru.lproj/SimpleX--iOS--InfoPlist.strings"; sourceTree = ""; }; 5CC868F229EB540C0017BBFD /* CIRcvDecryptionError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIRcvDecryptionError.swift; sourceTree = ""; }; 5CCB939B297EFCB100399E78 /* NavStackCompat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavStackCompat.swift; sourceTree = ""; }; - 5CCD403327A5F6DF00368C90 /* AddContactView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddContactView.swift; sourceTree = ""; }; - 5CCD403627A5F9A200368C90 /* ScanToConnectView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanToConnectView.swift; sourceTree = ""; }; 5CD67B8D2B0E858A00C510B1 /* hs_init.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = hs_init.h; sourceTree = ""; }; 5CD67B8E2B0E858A00C510B1 /* hs_init.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = hs_init.c; sourceTree = ""; }; 5CDCAD452818589900503DA2 /* SimpleX NSE.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "SimpleX NSE.appex"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -444,6 +439,8 @@ 5CFA59C32860BC6200863A68 /* MigrateToAppGroupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrateToAppGroupView.swift; sourceTree = ""; }; 5CFA59CF286477B400863A68 /* ChatArchiveView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatArchiveView.swift; sourceTree = ""; }; 5CFE0920282EEAF60002594B /* ZoomableScrollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ZoomableScrollView.swift; path = Shared/Views/ZoomableScrollView.swift; sourceTree = SOURCE_ROOT; }; + 640417CB2B29B8C200CCB412 /* NewChatMenuButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewChatMenuButton.swift; sourceTree = ""; }; + 640417CC2B29B8C200CCB412 /* NewChatView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewChatView.swift; sourceTree = ""; }; 6407BA82295DA85D0082BA18 /* CIInvalidJSONView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIInvalidJSONView.swift; sourceTree = ""; }; 6419EC552AB8BC8B004A607A /* ContextInvitingContactMemberView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextInvitingContactMemberView.swift; sourceTree = ""; }; 6419EC572AB97507004A607A /* CIMemberCreatedContactView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIMemberCreatedContactView.swift; sourceTree = ""; }; @@ -464,6 +461,11 @@ 646BB38D283FDB6D001CE359 /* LocalAuthenticationUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalAuthenticationUtils.swift; sourceTree = ""; }; 647F090D288EA27B00644C40 /* GroupMemberInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupMemberInfoView.swift; sourceTree = ""; }; 648010AA281ADD15009009B9 /* CIFileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIFileView.swift; sourceTree = ""; }; + 64863B962B3C536500714A11 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = ""; }; + 64863B972B3C536500714A11 /* libHSsimplex-chat-5.4.2.0-1dXNnkvLJVS8FSAgswHDGD-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.4.2.0-1dXNnkvLJVS8FSAgswHDGD-ghc9.6.3.a"; sourceTree = ""; }; + 64863B982B3C536500714A11 /* libHSsimplex-chat-5.4.2.0-1dXNnkvLJVS8FSAgswHDGD.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.4.2.0-1dXNnkvLJVS8FSAgswHDGD.a"; sourceTree = ""; }; + 64863B992B3C536500714A11 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; }; + 64863B9A2B3C536500714A11 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; }; 6493D667280ED77F007A76FB /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; 649BCD9F280460FD00C3A862 /* ComposeImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeImageView.swift; sourceTree = ""; }; 649BCDA12805D6EF00C3A862 /* CIImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIImageView.swift; sourceTree = ""; }; @@ -737,14 +739,10 @@ 5CB924DD27A8622200ACCCDD /* NewChat */ = { isa = PBXGroup; children = ( - 5C6AD81227A834E300348BD7 /* NewChatButton.swift */, - 5CCD403327A5F6DF00368C90 /* AddContactView.swift */, - 5CCD403627A5F9A200368C90 /* ScanToConnectView.swift */, - 3C8C548828133C84000A3EC7 /* PasteToConnectView.swift */, + 640417CB2B29B8C200CCB412 /* NewChatMenuButton.swift */, + 640417CC2B29B8C200CCB412 /* NewChatView.swift */, 5CC1C99127A6C7F5000D9FF6 /* QRCode.swift */, 6442E0B9287F169300CEC0F9 /* AddGroupView.swift */, - 5CB2085028DB64CA00D024EC /* CreateLinkView.swift */, - 5CB2085228DB7CAF00D024EC /* ConnectViaLinkView.swift */, 64D0C2C529FAC1EC00B38D5F /* AddContactLearnMore.swift */, ); path = NewChat; @@ -1113,8 +1111,8 @@ buildActionMask = 2147483647; files = ( 64C06EB52A0A4A7C00792D4D /* ChatItemInfoView.swift in Sources */, + 640417CE2B29B8C200CCB412 /* NewChatView.swift in Sources */, 6440CA03288AECA70062C672 /* AddGroupMembersView.swift in Sources */, - 5C6AD81327A834E300348BD7 /* NewChatButton.swift in Sources */, 5C3F1D58284363C400EC8A82 /* PrivacySettings.swift in Sources */, 5C55A923283CEDE600C4E99E /* SoundPlayer.swift in Sources */, 5C93292F29239A170090FFF9 /* ProtocolServersView.swift in Sources */, @@ -1161,13 +1159,11 @@ 5C063D2727A4564100AEC577 /* ChatPreviewView.swift in Sources */, 5CC868F329EB540C0017BBFD /* CIRcvDecryptionError.swift in Sources */, 5C35CFCB27B2E91D00FB6C6D /* NtfManager.swift in Sources */, - 3C8C548928133C84000A3EC7 /* PasteToConnectView.swift in Sources */, 5C9D13A3282187BB00AB8B43 /* WebRTC.swift in Sources */, 5C9A5BDB2871E05400A5B906 /* SetNotificationsMode.swift in Sources */, 5CB0BA8E2827126500B3292C /* OnboardingView.swift in Sources */, 6442E0BE2880182D00CEC0F9 /* GroupChatInfoView.swift in Sources */, 5C2E261227A30FEA00F70299 /* TerminalView.swift in Sources */, - 5CB2085128DB64CA00D024EC /* CreateLinkView.swift in Sources */, 5C9FD96E27A5D6ED0075386C /* SendMessageView.swift in Sources */, 5CA7DFC329302AF000F7FDDE /* AppSheet.swift in Sources */, 64E972072881BB22008DBC02 /* CIGroupInvitationView.swift in Sources */, @@ -1176,8 +1172,8 @@ 5CB9250D27A9432000ACCCDD /* ChatListNavLink.swift in Sources */, 649BCDA0280460FD00C3A862 /* ComposeImageView.swift in Sources */, 5CA059ED279559F40002BEB4 /* ContentView.swift in Sources */, - 5CCD403427A5F6DF00368C90 /* AddContactView.swift in Sources */, 5C05DF532840AA1D00C683F9 /* CallSettings.swift in Sources */, + 640417CD2B29B8C200CCB412 /* NewChatMenuButton.swift in Sources */, 5CFE0921282EEAF60002594B /* ZoomableScrollView.swift in Sources */, 5C3A88CE27DF50170060F1C2 /* DetermineWidth.swift in Sources */, 5C7505A527B679EE00BE3227 /* NavLinkPlain.swift in Sources */, @@ -1212,7 +1208,6 @@ 6448BBB628FA9D56000D2AB9 /* GroupLinkView.swift in Sources */, 5CB346E92869E8BA001FD2EF /* PushEnvironment.swift in Sources */, 5C55A91F283AD0E400C4E99E /* CallManager.swift in Sources */, - 5CCD403727A5F9A200368C90 /* ScanToConnectView.swift in Sources */, 5CFA59D12864782E00863A68 /* ChatArchiveView.swift in Sources */, 649BCDA22805D6EF00C3A862 /* CIImageView.swift in Sources */, 8C05382E2B39887E006436DC /* VideoUtils.swift in Sources */, @@ -1235,7 +1230,6 @@ 5C93293F2928E0FD0090FFF9 /* AudioRecPlay.swift in Sources */, 5C029EA82837DBB3004A9677 /* CICallItemView.swift in Sources */, 5CE4407227ADB1D0007B033A /* Emoji.swift in Sources */, - 5CB2085328DB7CAF00D024EC /* ConnectViaLinkView.swift in Sources */, 5C9CC7A928C532AB00BEF955 /* DatabaseErrorView.swift in Sources */, 5C1A4C1E27A715B700EAD5AD /* ChatItemView.swift in Sources */, 64AA1C6927EE10C800AC7277 /* ContextItemView.swift in Sources */, diff --git a/apps/ios/SimpleXChat/ChatTypes.swift b/apps/ios/SimpleXChat/ChatTypes.swift index a545d3508c..02c693cd28 100644 --- a/apps/ios/SimpleXChat/ChatTypes.swift +++ b/apps/ios/SimpleXChat/ChatTypes.swift @@ -3121,6 +3121,15 @@ public enum Format: Decodable, Equatable { case simplexLink(linkType: SimplexLinkType, simplexUri: String, smpHosts: [String]) case email case phone + + public var isSimplexLink: Bool { + get { + switch (self) { + case .simplexLink: return true + default: return false + } + } + } } public enum SimplexLinkType: String, Decodable { From 9c061508a41f5f88f1fab25422fe10b12d52d8eb Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Fri, 29 Dec 2023 22:46:45 +0700 Subject: [PATCH 007/102] android, desktop: rework UX of creating new connection (#3529) * android, desktop: rework UX of creating new connection * different place for clipboard listener * changes * changes * changes * button, strings * focus * code optimization and search icon * incognito link * comment * paddings * optimization * icon size and space in search * appbar background color * secondary color for icons in search bar * lighter tool bar and avatars * darker avatars in toolbar * background for selected item and divider * replacing connection view with actual chat view * clear * close unneeded view * filter icon background * filter doesn't hide current chat with empty search field * fixes for review * clearing focus on hiding keyboard * fix invalid qr code message * rename * color * buttons and text visibility when chat is not running yet * loading chats label --------- Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com> --- .../main/java/chat/simplex/app/SimplexApp.kt | 10 + .../common/platform/Modifier.android.kt | 2 + .../chatlist/ChatListNavLinkView.android.kt | 3 +- .../common/views/helpers/Utils.android.kt | 17 +- .../newchat/ConnectViaLinkView.android.kt | 68 -- .../views/newchat/QRCodeScanner.android.kt | 162 +++-- .../newchat/ScanToConnectView.android.kt | 22 - .../kotlin/chat/simplex/common/App.kt | 19 +- .../chat/simplex/common/model/ChatModel.kt | 41 +- .../chat/simplex/common/model/SimpleXAPI.kt | 28 +- .../chat/simplex/common/platform/Core.kt | 7 +- .../chat/simplex/common/platform/Modifier.kt | 2 + .../simplex/common/views/chat/ChatInfoView.kt | 2 +- .../simplex/common/views/chat/ChatView.kt | 681 +++++++++--------- .../simplex/common/views/chat/ScanCodeView.kt | 31 +- .../common/views/chat/VerifyCodeView.kt | 4 +- .../common/views/chat/group/GroupLinkView.kt | 2 +- .../views/chat/group/GroupMemberInfoView.kt | 4 +- .../common/views/chatlist/ChatHelpView.kt | 4 +- .../views/chatlist/ChatListNavLinkView.kt | 47 +- .../common/views/chatlist/ChatListView.kt | 263 +++++-- .../common/views/helpers/AlertManager.kt | 23 +- .../views/helpers/DefaultProgressBar.kt | 27 + .../common/views/helpers/DefaultTopAppBar.kt | 2 +- .../simplex/common/views/helpers/ModalView.kt | 16 +- .../common/views/helpers/SearchTextField.kt | 7 +- .../simplex/common/views/helpers/Utils.kt | 3 + .../views/newchat/AddContactLearnMore.kt | 7 +- .../common/views/newchat/AddContactView.kt | 186 ----- .../{ScanToConnectView.kt => ConnectPlan.kt} | 299 ++++---- .../views/newchat/ConnectViaLinkView.kt | 12 - .../newchat/ContactConnectionInfoView.kt | 49 +- .../common/views/newchat/CreateLinkView.kt | 118 --- .../common/views/newchat/NewChatSheet.kt | 18 +- .../common/views/newchat/NewChatView.kt | 436 +++++++++++ .../common/views/newchat/PasteToConnect.kt | 135 ---- .../simplex/common/views/newchat/QRCode.kt | 35 +- .../common/views/newchat/QRCodeScanner.kt | 10 +- .../views/onboarding/CreateSimpleXAddress.kt | 2 +- .../common/views/remote/ConnectDesktopView.kt | 13 +- .../common/views/remote/ConnectMobileView.kt | 6 +- .../views/usersettings/IncognitoView.kt | 2 + .../views/usersettings/ProtocolServerView.kt | 2 +- .../views/usersettings/ScanProtocolServer.kt | 28 +- .../views/usersettings/UserAddressView.kt | 2 +- .../commonMain/resources/MR/ar/strings.xml | 5 +- .../commonMain/resources/MR/base/strings.xml | 38 +- .../commonMain/resources/MR/bg/strings.xml | 9 +- .../commonMain/resources/MR/cs/strings.xml | 3 - .../commonMain/resources/MR/de/strings.xml | 13 +- .../commonMain/resources/MR/es/strings.xml | 3 - .../commonMain/resources/MR/fi/strings.xml | 3 - .../commonMain/resources/MR/fr/strings.xml | 11 +- .../commonMain/resources/MR/hu/strings.xml | 9 +- .../commonMain/resources/MR/it/strings.xml | 11 +- .../commonMain/resources/MR/iw/strings.xml | 3 - .../commonMain/resources/MR/ja/strings.xml | 3 - .../commonMain/resources/MR/ko/strings.xml | 3 - .../commonMain/resources/MR/lt/strings.xml | 3 - .../commonMain/resources/MR/nl/strings.xml | 11 +- .../commonMain/resources/MR/pl/strings.xml | 11 +- .../resources/MR/pt-rBR/strings.xml | 3 - .../commonMain/resources/MR/pt/strings.xml | 3 - .../commonMain/resources/MR/ru/strings.xml | 13 +- .../commonMain/resources/MR/th/strings.xml | 3 - .../commonMain/resources/MR/tr/strings.xml | 9 +- .../commonMain/resources/MR/uk/strings.xml | 9 +- .../resources/MR/zh-rCN/strings.xml | 11 +- .../resources/MR/zh-rTW/strings.xml | 3 - .../common/platform/Modifier.desktop.kt | 4 + .../chatlist/ChatListNavLinkView.desktop.kt | 14 +- .../common/views/helpers/Utils.desktop.kt | 35 + .../newchat/ConnectViaLinkView.desktop.kt | 11 - .../views/newchat/QRCodeScanner.desktop.kt | 7 +- .../newchat/ScanToConnectView.desktop.kt | 15 - 75 files changed, 1670 insertions(+), 1466 deletions(-) delete mode 100644 apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/newchat/ConnectViaLinkView.android.kt delete mode 100644 apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/newchat/ScanToConnectView.android.kt create mode 100644 apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DefaultProgressBar.kt delete mode 100644 apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/AddContactView.kt rename apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/{ScanToConnectView.kt => ConnectPlan.kt} (71%) delete mode 100644 apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/ConnectViaLinkView.kt delete mode 100644 apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/CreateLinkView.kt create mode 100644 apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatView.kt delete mode 100644 apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/PasteToConnect.kt delete mode 100644 apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/newchat/ConnectViaLinkView.desktop.kt delete mode 100644 apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/newchat/ScanToConnectView.desktop.kt diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/SimplexApp.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/SimplexApp.kt index ee43da5d44..a8c8b5c1b2 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/SimplexApp.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/SimplexApp.kt @@ -1,6 +1,9 @@ package chat.simplex.app import android.app.Application +import android.content.Context +import androidx.compose.ui.platform.ClipboardManager +import chat.simplex.common.platform.Log import android.app.UiModeManager import android.os.* import androidx.lifecycle.* @@ -95,6 +98,13 @@ class SimplexApp: Application(), LifecycleEventObserver { } Lifecycle.Event.ON_RESUME -> { isAppOnForeground = true + /** + * When the app calls [ClipboardManager.shareText] and a user copies text in clipboard, Android denies + * access to clipboard because the app considered in background. + * This will ensure that the app will get the event on resume + * */ + val service = androidAppContext.getSystemService(Context.CLIPBOARD_SERVICE) as android.content.ClipboardManager + chatModel.clipboardHasText.value = service.hasPrimaryClip() if (chatModel.controller.appPrefs.onboardingStage.get() == OnboardingStage.OnboardingComplete && chatModel.currentUser.value != null) { SimplexService.showBackgroundServiceNoticeIfNeeded() } diff --git a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/Modifier.android.kt b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/Modifier.android.kt index 26ada2b7e6..b103367fe8 100644 --- a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/Modifier.android.kt +++ b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/Modifier.android.kt @@ -26,3 +26,5 @@ actual fun Modifier.desktopOnExternalDrag( ): Modifier = this actual fun Modifier.onRightClick(action: () -> Unit): Modifier = this + +actual fun Modifier.desktopPointerHoverIconHand(): Modifier = this diff --git a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.android.kt b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.android.kt index 30f5b81387..f8914c6653 100644 --- a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.android.kt +++ b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.android.kt @@ -17,7 +17,8 @@ actual fun ChatListNavLinkLayout( dropdownMenuItems: (@Composable () -> Unit)?, showMenu: MutableState, stopped: Boolean, - selectedChat: State + selectedChat: State, + nextChatSelected: State, ) { var modifier = Modifier.fillMaxWidth() if (!stopped) modifier = modifier diff --git a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/helpers/Utils.android.kt b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/helpers/Utils.android.kt index d244294763..904f9a555a 100644 --- a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/helpers/Utils.android.kt +++ b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/helpers/Utils.android.kt @@ -1,5 +1,7 @@ package chat.simplex.common.views.helpers +import android.content.ClipboardManager +import android.content.Context import android.content.res.Resources import android.graphics.* import android.graphics.Typeface @@ -12,6 +14,7 @@ import android.text.SpannedString import android.text.style.* import android.util.Base64 import android.view.WindowManager +import androidx.compose.runtime.* import androidx.compose.ui.graphics.* import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.* @@ -24,7 +27,6 @@ import androidx.core.text.HtmlCompat import chat.simplex.common.helpers.* import chat.simplex.common.model.* import chat.simplex.common.platform.* -import chat.simplex.res.MR import dev.icerock.moko.resources.StringResource import java.io.* import java.net.URI @@ -55,6 +57,19 @@ fun keepScreenOn(on: Boolean) { } } +@Composable +actual fun SetupClipboardListener() { + DisposableEffect(Unit) { + val service = androidAppContext.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager + val listener = { chatModel.clipboardHasText.value = service.hasPrimaryClip() } + chatModel.clipboardHasText.value = service.hasPrimaryClip() + service.addPrimaryClipChangedListener(listener) + onDispose { + service.removePrimaryClipChangedListener(listener) + } + } +} + actual fun escapedHtmlToAnnotatedString(text: String, density: Density): AnnotatedString { return spannableStringToAnnotatedString(HtmlCompat.fromHtml(text, HtmlCompat.FROM_HTML_MODE_LEGACY), density) } diff --git a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/newchat/ConnectViaLinkView.android.kt b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/newchat/ConnectViaLinkView.android.kt deleted file mode 100644 index e5a7ae40a5..0000000000 --- a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/newchat/ConnectViaLinkView.android.kt +++ /dev/null @@ -1,68 +0,0 @@ -package chat.simplex.common.views.newchat - -import androidx.compose.foundation.layout.* -import androidx.compose.material.* -import androidx.compose.runtime.* -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import dev.icerock.moko.resources.compose.painterResource -import dev.icerock.moko.resources.compose.stringResource -import androidx.compose.ui.unit.sp -import chat.simplex.common.model.ChatModel -import chat.simplex.common.model.RemoteHostInfo -import chat.simplex.res.MR - -@Composable -actual fun ConnectViaLinkView(m: ChatModel, rh: RemoteHostInfo?, close: () -> Unit) { - // TODO this should close if remote host changes in model - val selection = remember { - mutableStateOf( - runCatching { ConnectViaLinkTab.valueOf(m.controller.appPrefs.connectViaLinkTab.get()!!) }.getOrDefault(ConnectViaLinkTab.SCAN) - ) - } - val tabTitles = ConnectViaLinkTab.values().map { - when (it) { - ConnectViaLinkTab.SCAN -> stringResource(MR.strings.scan_QR_code) - ConnectViaLinkTab.PASTE -> stringResource(MR.strings.paste_the_link_you_received) - } - } - Column( - Modifier.fillMaxHeight(), - verticalArrangement = Arrangement.SpaceBetween - ) { - Column(Modifier.weight(1f)) { - when (selection.value) { - ConnectViaLinkTab.SCAN -> { - ScanToConnectView(m, rh, close) - } - ConnectViaLinkTab.PASTE -> { - PasteToConnectView(m, rh, close) - } - } - } - TabRow( - selectedTabIndex = selection.value.ordinal, - backgroundColor = Color.Transparent, - contentColor = MaterialTheme.colors.primary, - ) { - tabTitles.forEachIndexed { index, it -> - Tab( - selected = selection.value.ordinal == index, - onClick = { - selection.value = ConnectViaLinkTab.values()[index] - m.controller.appPrefs.connectViaLinkTab.set(selection.value .name) - }, - text = { Text(it, fontSize = 13.sp) }, - icon = { - Icon( - if (ConnectViaLinkTab.SCAN.ordinal == index) painterResource(MR.images.ic_qr_code) else painterResource(MR.images.ic_article), - it - ) - }, - selectedContentColor = MaterialTheme.colors.primary, - unselectedContentColor = MaterialTheme.colors.secondary, - ) - } - } - } -} diff --git a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/newchat/QRCodeScanner.android.kt b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/newchat/QRCodeScanner.android.kt index e7453ce20a..362d793e83 100644 --- a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/newchat/QRCodeScanner.android.kt +++ b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/newchat/QRCodeScanner.android.kt @@ -2,16 +2,20 @@ package chat.simplex.common.views.newchat import android.Manifest import android.annotation.SuppressLint +import android.content.pm.PackageManager import android.util.Log import android.view.ViewGroup import androidx.camera.core.* import androidx.camera.lifecycle.ProcessCameraProvider import androidx.camera.view.PreviewView +import androidx.compose.foundation.layout.* +import androidx.compose.material.* import androidx.compose.runtime.* +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clipToBounds -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.platform.LocalLifecycleOwner +import androidx.compose.ui.platform.* +import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView import androidx.core.content.ContextCompat import boofcv.abst.fiducial.QrCodeDetector @@ -20,18 +24,23 @@ import boofcv.android.ConvertCameraImage import boofcv.factory.fiducial.FactoryFiducial import boofcv.struct.image.GrayU8 import chat.simplex.common.platform.TAG +import chat.simplex.common.ui.theme.DEFAULT_PADDING_HALF +import chat.simplex.common.views.helpers.* +import chat.simplex.res.MR import com.google.accompanist.permissions.rememberPermissionState import com.google.common.util.concurrent.ListenableFuture +import dev.icerock.moko.resources.compose.painterResource +import dev.icerock.moko.resources.compose.stringResource import java.util.concurrent.* // Adapted from learntodroid - https://gist.github.com/learntodroid/8f839be0b29d0378f843af70607bd7f5 @Composable -actual fun QRCodeScanner(onBarcode: (String) -> Unit) { - val cameraPermissionState = rememberPermissionState(permission = Manifest.permission.CAMERA) - LaunchedEffect(Unit) { - cameraPermissionState.launchPermissionRequest() - } +actual fun QRCodeScanner( + showQRCodeScanner: MutableState, + padding: PaddingValues, + onBarcode: (String) -> Unit +) { val context = LocalContext.current val lifecycleOwner = LocalLifecycleOwner.current var preview by remember { mutableStateOf(null) } @@ -48,57 +57,102 @@ actual fun QRCodeScanner(onBarcode: (String) -> Unit) { } } - AndroidView( - factory = { AndroidViewContext -> - PreviewView(AndroidViewContext).apply { - this.scaleType = PreviewView.ScaleType.FILL_CENTER - layoutParams = ViewGroup.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT, - ) - implementationMode = PreviewView.ImplementationMode.COMPATIBLE - } - }, - modifier = Modifier.clipToBounds() - ) { previewView -> - val cameraSelector: CameraSelector = CameraSelector.Builder() - .requireLensFacing(CameraSelector.LENS_FACING_BACK) - .build() - val cameraExecutor: ExecutorService = Executors.newSingleThreadExecutor() - cameraProviderFuture?.addListener({ - preview = Preview.Builder().build().also { - it.setSurfaceProvider(previewView.surfaceProvider) - } - val detector: QrCodeDetector = FactoryFiducial.qrcode(null, GrayU8::class.java) - fun getQR(imageProxy: ImageProxy) { - val currentTimeStamp = System.currentTimeMillis() - if (currentTimeStamp - lastAnalyzedTimeStamp >= TimeUnit.SECONDS.toMillis(1)) { - detector.process(imageProxyToGrayU8(imageProxy)) - val found = detector.detections - val qr = found.firstOrNull() - if (qr != null) { - if (qr.message != contactLink) { - // Make sure link is new and not a repeat - contactLink = qr.message - onBarcode(contactLink) + Box(Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) { + val cameraPermissionState = rememberPermissionState(permission = Manifest.permission.CAMERA) + val modifier = Modifier + .padding(padding) + .clipToBounds() + .widthIn(max = 400.dp) + .aspectRatio(1f) + val showScanner = remember { showQRCodeScanner } + if (showScanner.value && cameraPermissionState.hasPermission) { + AndroidView( + factory = { AndroidViewContext -> + PreviewView(AndroidViewContext).apply { + this.scaleType = PreviewView.ScaleType.FILL_CENTER + layoutParams = ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT, + ) + implementationMode = PreviewView.ImplementationMode.COMPATIBLE + } + }, + modifier = modifier + ) { previewView -> + val cameraSelector: CameraSelector = CameraSelector.Builder() + .requireLensFacing(CameraSelector.LENS_FACING_BACK) + .build() + val cameraExecutor: ExecutorService = Executors.newSingleThreadExecutor() + cameraProviderFuture?.addListener({ + preview = Preview.Builder().build().also { + it.setSurfaceProvider(previewView.surfaceProvider) + } + val detector: QrCodeDetector = FactoryFiducial.qrcode(null, GrayU8::class.java) + fun getQR(imageProxy: ImageProxy) { + val currentTimeStamp = System.currentTimeMillis() + if (currentTimeStamp - lastAnalyzedTimeStamp >= TimeUnit.SECONDS.toMillis(1)) { + detector.process(imageProxyToGrayU8(imageProxy)) + val found = detector.detections + val qr = found.firstOrNull() + if (qr != null) { + if (qr.message != contactLink) { + // Make sure link is new and not a repeat + contactLink = qr.message + onBarcode(contactLink) + } + } } + imageProxy.close() + } + + val imageAnalyzer = ImageAnalysis.Analyzer { proxy -> getQR(proxy) } + val imageAnalysis: ImageAnalysis = ImageAnalysis.Builder() + .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST) + .setImageQueueDepth(1) + .build() + .also { it.setAnalyzer(cameraExecutor, imageAnalyzer) } + try { + cameraProviderFuture?.get()?.unbindAll() + cameraProviderFuture?.get()?.bindToLifecycle(lifecycleOwner, cameraSelector, preview, imageAnalysis) + } catch (e: Exception) { + Log.d(TAG, "CameraPreview: ${e.localizedMessage}") + } + }, ContextCompat.getMainExecutor(context)) + } + } else { + val buttonColors = ButtonDefaults.buttonColors( + backgroundColor = MaterialTheme.colors.background.mixWith(MaterialTheme.colors.onBackground, 0.9f), + contentColor = MaterialTheme.colors.primary, + disabledBackgroundColor = MaterialTheme.colors.background.mixWith(MaterialTheme.colors.onBackground, 0.9f), + disabledContentColor = MaterialTheme.colors.primary, + ) + when { + !cameraPermissionState.hasPermission && !cameraPermissionState.permissionRequested && showScanner.value -> { + LaunchedEffect(Unit) { + cameraPermissionState.launchPermissionRequest() + } + } + !cameraPermissionState.hasPermission -> { + Button({ withBGApi { cameraPermissionState.launchPermissionRequest() } }, modifier = modifier, colors = buttonColors) { + Icon(painterResource(MR.images.ic_camera_enhance), null) + Spacer(Modifier.width(DEFAULT_PADDING_HALF)) + Text(stringResource(MR.strings.enable_camera_access)) + } + } + cameraPermissionState.hasPermission -> { + Button({ showQRCodeScanner.value = true }, modifier = modifier, colors = buttonColors) { + Icon(painterResource(MR.images.ic_qr_code), null) + Spacer(Modifier.width(DEFAULT_PADDING_HALF)) + Text(stringResource(MR.strings.tap_to_scan)) + } + } + !LocalContext.current.packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY) -> { + Button({ }, enabled = false, modifier = modifier, colors = buttonColors) { + Text(stringResource(MR.strings.camera_not_available)) } } - imageProxy.close() } - val imageAnalyzer = ImageAnalysis.Analyzer { proxy -> getQR(proxy) } - val imageAnalysis: ImageAnalysis = ImageAnalysis.Builder() - .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST) - .setImageQueueDepth(1) - .build() - .also { it.setAnalyzer(cameraExecutor, imageAnalyzer) } - try { - cameraProviderFuture?.get()?.unbindAll() - cameraProviderFuture?.get()?.bindToLifecycle(lifecycleOwner, cameraSelector, preview, imageAnalysis) - } catch (e: Exception) { - Log.d(TAG, "CameraPreview: ${e.localizedMessage}") - } - }, ContextCompat.getMainExecutor(context)) + } } } diff --git a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/newchat/ScanToConnectView.android.kt b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/newchat/ScanToConnectView.android.kt deleted file mode 100644 index f046f44bee..0000000000 --- a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/newchat/ScanToConnectView.android.kt +++ /dev/null @@ -1,22 +0,0 @@ -package chat.simplex.common.views.newchat - -import android.Manifest -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import chat.simplex.common.model.ChatModel -import chat.simplex.common.model.RemoteHostInfo -import com.google.accompanist.permissions.rememberPermissionState - -@Composable -actual fun ScanToConnectView(chatModel: ChatModel, rh: RemoteHostInfo?, close: () -> Unit) { - val cameraPermissionState = rememberPermissionState(permission = Manifest.permission.CAMERA) - LaunchedEffect(Unit) { - cameraPermissionState.launchPermissionRequest() - } - ConnectContactLayout( - chatModel = chatModel, - rh = rh, - incognitoPref = chatModel.controller.appPrefs.incognito, - close = close - ) -} diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/App.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/App.kt index d457eb57a1..950515f055 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/App.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/App.kt @@ -107,7 +107,7 @@ fun MainScreen() { val localUserCreated = chatModel.localUserCreated.value var showInitializationView by remember { mutableStateOf(false) } when { - chatModel.chatDbStatus.value == null && showInitializationView -> InitializationView() + chatModel.chatDbStatus.value == null && showInitializationView -> DefaultProgressView(stringResource(MR.strings.opening_database)) showChatDatabaseError -> { chatModel.chatDbStatus.value?.let { DatabaseErrorView(chatModel.chatDbStatus, chatModel.controller.appPrefs) @@ -125,6 +125,7 @@ fun MainScreen() { } val scaffoldState = rememberScaffoldState() val settingsState = remember { SettingsViewState(userPickerState, scaffoldState) } + SetupClipboardListener() if (appPlatform.isAndroid) { AndroidScreen(settingsState) } else { @@ -342,22 +343,6 @@ fun DesktopScreen(settingsState: SettingsViewState) { } } -@Composable -fun InitializationView() { - Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { - Column(horizontalAlignment = Alignment.CenterHorizontally) { - CircularProgressIndicator( - Modifier - .padding(bottom = DEFAULT_PADDING) - .size(30.dp), - color = MaterialTheme.colors.secondary, - strokeWidth = 2.5.dp - ) - Text(stringResource(MR.strings.opening_database)) - } - } -} - @Composable private fun SwitchingUsersView() { if (remember { chatModel.switchingUsersAndHosts }.value) { 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 708bbb9073..f51f6986f8 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 @@ -97,8 +97,8 @@ object ChatModel { val showCallView = mutableStateOf(false) val switchingCall = mutableStateOf(false) - // currently showing QR code - val connReqInv = mutableStateOf(null as String?) + // currently showing invitation + val showingInvitation = mutableStateOf(null as ShowingInvitation?) var draft = mutableStateOf(null as ComposeState?) var draftChatId = mutableStateOf(null as String?) @@ -109,6 +109,8 @@ object ChatModel { val filesToDelete = mutableSetOf() val simplexLinkMode by lazy { mutableStateOf(ChatController.appPrefs.simplexLinkMode.get()) } + val clipboardHasText = mutableStateOf(false) + var updatingChatsMutex: Mutex = Mutex() val desktopNoUserNoRemote: Boolean @Composable get() = appPlatform.isDesktop && currentUser.value == null && currentRemoteHost.value == null @@ -561,15 +563,30 @@ object ChatModel { chats.add(index = 0, chat) } - fun dismissConnReqView(id: String) { - if (connReqInv.value == null) return - val info = getChat(id)?.chatInfo as? ChatInfo.ContactConnection ?: return - if (info.contactConnection.connReqInv == connReqInv.value) { - connReqInv.value = null - ModalManager.center.closeModals() + fun replaceConnReqView(id: String, withId: String) { + if (id == showingInvitation.value?.connId) { + showingInvitation.value = null + chatModel.chatItems.clear() + chatModel.chatId.value = withId + ModalManager.end.closeModals() } } + fun dismissConnReqView(id: String) { + if (id == showingInvitation.value?.connId) { + showingInvitation.value = null + chatModel.chatItems.clear() + chatModel.chatId.value = null + // Close NewChatView + ModalManager.center.closeModals() + ModalManager.end.closeModals() + } + } + + fun markShowingInvitationUsed() { + showingInvitation.value = showingInvitation.value?.copy(connChatUsed = true) + } + fun removeChat(rhId: Long?, id: String) { chats.removeAll { it.id == id && it.remoteHostId == rhId } } @@ -630,6 +647,12 @@ object ChatModel { fun connectedToRemote(): Boolean = currentRemoteHost.value != null || remoteCtrlSession.value?.active == true } +data class ShowingInvitation( + val connId: String, + val connReq: String, + val connChatUsed: Boolean +) + enum class ChatType(val type: String) { Direct("@"), Group("#"), @@ -2664,6 +2687,8 @@ sealed class Format { is Phone -> linkStyle } + val isSimplexLink = this is SimplexLink + companion object { val linkStyle @Composable get() = SpanStyle(color = MaterialTheme.colors.primary, textDecoration = TextDecoration.Underline) } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt index e3f565b77c..619238f6d3 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt @@ -9,7 +9,6 @@ import dev.icerock.moko.resources.compose.painterResource import chat.simplex.common.platform.* import chat.simplex.common.ui.theme.* import chat.simplex.common.views.call.* -import chat.simplex.common.views.newchat.ConnectViaLinkTab import chat.simplex.common.views.onboarding.OnboardingStage import chat.simplex.common.views.usersettings.* import com.charleskorn.kaml.Yaml @@ -135,7 +134,6 @@ class AppPreferences { val networkTCPKeepIntvl = mkIntPreference(SHARED_PREFS_NETWORK_TCP_KEEP_INTVL, KeepAliveOpts.defaults.keepIntvl) val networkTCPKeepCnt = mkIntPreference(SHARED_PREFS_NETWORK_TCP_KEEP_CNT, KeepAliveOpts.defaults.keepCnt) val incognito = mkBoolPreference(SHARED_PREFS_INCOGNITO, false) - val connectViaLinkTab = mkStrPreference(SHARED_PREFS_CONNECT_VIA_LINK_TAB, ConnectViaLinkTab.SCAN.name) val liveMessageAlertShown = mkBoolPreference(SHARED_PREFS_LIVE_MESSAGE_ALERT_SHOWN, false) val showHiddenProfilesNotice = mkBoolPreference(SHARED_PREFS_SHOW_HIDDEN_PROFILES_NOTICE, true) val showMuteProfileAlert = mkBoolPreference(SHARED_PREFS_SHOW_MUTE_PROFILE_ALERT, true) @@ -292,7 +290,6 @@ class AppPreferences { private const val SHARED_PREFS_NETWORK_TCP_KEEP_INTVL = "NetworkTCPKeepIntvl" private const val SHARED_PREFS_NETWORK_TCP_KEEP_CNT = "NetworkTCPKeepCnt" private const val SHARED_PREFS_INCOGNITO = "Incognito" - private const val SHARED_PREFS_CONNECT_VIA_LINK_TAB = "ConnectViaLinkTab" private const val SHARED_PREFS_LIVE_MESSAGE_ALERT_SHOWN = "LiveMessageAlertShown" private const val SHARED_PREFS_SHOW_HIDDEN_PROFILES_NOTICE = "ShowHiddenProfilesNotice" private const val SHARED_PREFS_SHOW_MUTE_PROFILE_ALERT = "ShowMuteProfileAlert" @@ -890,19 +887,19 @@ object ChatController { - suspend fun apiAddContact(rh: Long?, incognito: Boolean): Pair? { + suspend fun apiAddContact(rh: Long?, incognito: Boolean): Pair?, (() -> Unit)?> { val userId = chatModel.currentUser.value?.userId ?: run { Log.e(TAG, "apiAddContact: no current user") - return null + return null to null } val r = sendCmd(rh, CC.APIAddContact(userId, incognito)) return when (r) { - is CR.Invitation -> r.connReqInvitation to r.connection + is CR.Invitation -> (r.connReqInvitation to r.connection) to null else -> { if (!(networkErrorAlert(r))) { - apiErrorAlert("apiAddContact", generalGetString(MR.strings.connection_error), r) + return null to { apiErrorAlert("apiAddContact", generalGetString(MR.strings.connection_error), r) } } - null + null to null } } } @@ -981,6 +978,13 @@ object ChatController { } } + suspend fun deleteChat(chat: Chat, notify: Boolean? = null) { + val cInfo = chat.chatInfo + if (apiDeleteChat(rh = chat.remoteHostId, type = cInfo.chatType, id = cInfo.apiId, notify = notify)) { + chatModel.removeChat(chat.remoteHostId, cInfo.id) + } + } + suspend fun apiDeleteChat(rh: Long?, type: ChatType, id: Long, notify: Boolean? = null): Boolean { val r = sendCmd(rh, CC.ApiDeleteChat(type, id, notify)) when { @@ -1568,7 +1572,7 @@ object ChatController { chatModel.updateContact(rhId, r.contact) val conn = r.contact.activeConn if (conn != null) { - chatModel.dismissConnReqView(conn.id) + chatModel.replaceConnReqView(conn.id, "@${r.contact.contactId}") chatModel.removeChat(rhId, conn.id) } } @@ -1582,7 +1586,7 @@ object ChatController { chatModel.updateContact(rhId, r.contact) val conn = r.contact.activeConn if (conn != null) { - chatModel.dismissConnReqView(conn.id) + chatModel.replaceConnReqView(conn.id, "@${r.contact.contactId}") chatModel.removeChat(rhId, conn.id) } } @@ -1717,7 +1721,7 @@ object ChatController { chatModel.updateGroup(rhId, r.groupInfo) val conn = r.hostContact?.activeConn if (conn != null) { - chatModel.dismissConnReqView(conn.id) + chatModel.replaceConnReqView(conn.id, "#${r.groupInfo.groupId}") chatModel.removeChat(rhId, conn.id) } } @@ -1727,7 +1731,7 @@ object ChatController { chatModel.updateGroup(rhId, r.groupInfo) val hostConn = r.hostMember.activeConn if (hostConn != null) { - chatModel.dismissConnReqView(hostConn.id) + chatModel.replaceConnReqView(hostConn.id, "#${r.groupInfo.groupId}") chatModel.removeChat(rhId, hostConn.id) } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Core.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Core.kt index 7d097efb7a..52ff269f54 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Core.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Core.kt @@ -73,11 +73,14 @@ suspend fun initChatController(useKey: String? = null, confirmMigrations: Migrat } } else { val savedOnboardingStage = appPreferences.onboardingStage.get() - appPreferences.onboardingStage.set(if (listOf(OnboardingStage.Step1_SimpleXInfo, OnboardingStage.Step2_CreateProfile).contains(savedOnboardingStage) && chatModel.users.size == 1) { + val newStage = if (listOf(OnboardingStage.Step1_SimpleXInfo, OnboardingStage.Step2_CreateProfile).contains(savedOnboardingStage) && chatModel.users.size == 1) { OnboardingStage.Step3_CreateSimpleXAddress } else { savedOnboardingStage - }) + } + if (appPreferences.onboardingStage.get() != newStage) { + appPreferences.onboardingStage.set(newStage) + } if (appPreferences.onboardingStage.get() == OnboardingStage.OnboardingComplete && !chatModel.controller.appPrefs.privacyDeliveryReceiptsSet.get()) { chatModel.setDeliveryReceipts.value = true } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Modifier.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Modifier.kt index 1141ab21ab..4a10027746 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Modifier.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Modifier.kt @@ -23,3 +23,5 @@ expect fun Modifier.desktopOnExternalDrag( ): Modifier expect fun Modifier.onRightClick(action: () -> Unit): Modifier + +expect fun Modifier.desktopPointerHoverIconHand(): Modifier diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatInfoView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatInfoView.kt index 694ec2ba18..d87fce5fba 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatInfoView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatInfoView.kt @@ -355,7 +355,7 @@ fun ChatInfoLayout( if (contact.contactLink != null) { SectionView(stringResource(MR.strings.address_section_title).uppercase()) { - SimpleXLinkQRCode(contact.contactLink, Modifier.padding(horizontal = DEFAULT_PADDING, vertical = DEFAULT_PADDING_HALF).aspectRatio(1f)) + SimpleXLinkQRCode(contact.contactLink) val clipboard = LocalClipboardManager.current ShareAddressButton { clipboard.shareText(simplexChatLink(contact.contactLink)) } SectionTextFooter(stringResource(MR.strings.you_can_share_this_address_with_your_contacts).format(contact.displayName)) 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 0e2a7c1680..69a1b50e28 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 @@ -33,6 +33,7 @@ import chat.simplex.common.views.helpers.* import chat.simplex.common.model.GroupInfo import chat.simplex.common.platform.* import chat.simplex.common.platform.AudioPlayer +import chat.simplex.common.views.newchat.ContactConnectionInfoView import chat.simplex.res.MR import kotlinx.coroutines.* import kotlinx.coroutines.flow.* @@ -114,343 +115,371 @@ fun ChatView(chatId: String, chatModel: ChatModel, onComposed: suspend (chatId: } } val clipboard = LocalClipboardManager.current - - ChatLayout( - chat, - unreadCount, - composeState, - composeView = { - Column( - Modifier.fillMaxWidth(), - horizontalAlignment = Alignment.CenterHorizontally - ) { - if ( - chat.chatInfo is ChatInfo.Direct - && !chat.chatInfo.contact.ready - && chat.chatInfo.contact.active - && !chat.chatInfo.contact.nextSendGrpInv - ) { - Text( - generalGetString(MR.strings.contact_connection_pending), - Modifier.padding(top = 4.dp), - fontSize = 14.sp, - color = MaterialTheme.colors.secondary - ) - } - ComposeView( - chatModel, chat, composeState, attachmentOption, - showChooseAttachment = { scope.launch { attachmentBottomSheetState.show() } } - ) - } - }, - attachmentOption, - attachmentBottomSheetState, - chatModel.chatItems, - searchText, - useLinkPreviews = useLinkPreviews, - linkMode = chatModel.simplexLinkMode.value, - back = { - hideKeyboard(view) - AudioPlayer.stop() - chatModel.chatId.value = null - chatModel.groupMembers.clear() - }, - info = { - if (ModalManager.end.hasModalsOpen()) { - ModalManager.end.closeModals() - return@ChatLayout - } - hideKeyboard(view) - withApi { - // The idea is to preload information before showing a modal because large groups can take time to load all members - var preloadedContactInfo: Pair? = null - var preloadedCode: String? = null - var preloadedLink: Pair? = null - if (chat.chatInfo is ChatInfo.Direct) { - preloadedContactInfo = chatModel.controller.apiContactInfo(chatRh, chat.chatInfo.apiId) - preloadedCode = chatModel.controller.apiGetContactCode(chatRh, chat.chatInfo.apiId)?.second - } else if (chat.chatInfo is ChatInfo.Group) { - setGroupMembers(chatRh, chat.chatInfo.groupInfo, chatModel) - preloadedLink = chatModel.controller.apiGetGroupLink(chatRh, chat.chatInfo.groupInfo.groupId) - } - ModalManager.end.showModalCloseable(true) { close -> - val chat = remember { activeChat }.value - if (chat?.chatInfo is ChatInfo.Direct) { - var contactInfo: Pair? by remember { mutableStateOf(preloadedContactInfo) } - var code: String? by remember { mutableStateOf(preloadedCode) } - KeyChangeEffect(chat.id, ChatModel.networkStatuses.toMap()) { - contactInfo = chatModel.controller.apiContactInfo(chatRh, chat.chatInfo.apiId) - preloadedContactInfo = contactInfo - code = chatModel.controller.apiGetContactCode(chatRh, chat.chatInfo.apiId)?.second - preloadedCode = code + when (chat.chatInfo) { + is ChatInfo.Direct, is ChatInfo.Group -> { + ChatLayout( + chat, + unreadCount, + composeState, + composeView = { + Column( + Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally + ) { + if ( + chat.chatInfo is ChatInfo.Direct + && !chat.chatInfo.contact.ready + && chat.chatInfo.contact.active + && !chat.chatInfo.contact.nextSendGrpInv + ) { + Text( + generalGetString(MR.strings.contact_connection_pending), + Modifier.padding(top = 4.dp), + fontSize = 14.sp, + color = MaterialTheme.colors.secondary + ) } - ChatInfoView(chatModel, (chat.chatInfo as ChatInfo.Direct).contact, contactInfo?.first, contactInfo?.second, chat.chatInfo.localAlias, code, close) - } else if (chat?.chatInfo is ChatInfo.Group) { - var link: Pair? by remember(chat.id) { mutableStateOf(preloadedLink) } - KeyChangeEffect(chat.id) { - setGroupMembers(chatRh, (chat.chatInfo as ChatInfo.Group).groupInfo, chatModel) - link = chatModel.controller.apiGetGroupLink(chatRh, chat.chatInfo.groupInfo.groupId) - preloadedLink = link + ComposeView( + chatModel, chat, composeState, attachmentOption, + showChooseAttachment = { scope.launch { attachmentBottomSheetState.show() } } + ) + } + }, + attachmentOption, + attachmentBottomSheetState, + chatModel.chatItems, + searchText, + useLinkPreviews = useLinkPreviews, + linkMode = chatModel.simplexLinkMode.value, + back = { + hideKeyboard(view) + AudioPlayer.stop() + chatModel.chatId.value = null + chatModel.groupMembers.clear() + }, + info = { + if (ModalManager.end.hasModalsOpen()) { + ModalManager.end.closeModals() + return@ChatLayout + } + hideKeyboard(view) + withApi { + // The idea is to preload information before showing a modal because large groups can take time to load all members + var preloadedContactInfo: Pair? = null + var preloadedCode: String? = null + var preloadedLink: Pair? = null + if (chat.chatInfo is ChatInfo.Direct) { + preloadedContactInfo = chatModel.controller.apiContactInfo(chatRh, chat.chatInfo.apiId) + preloadedCode = chatModel.controller.apiGetContactCode(chatRh, chat.chatInfo.apiId)?.second + } else if (chat.chatInfo is ChatInfo.Group) { + setGroupMembers(chatRh, chat.chatInfo.groupInfo, chatModel) + preloadedLink = chatModel.controller.apiGetGroupLink(chatRh, chat.chatInfo.groupInfo.groupId) } - GroupChatInfoView(chatModel, chatRh, chat.id, link?.first, link?.second, { - link = it - preloadedLink = it - }, close) - } - } - } - }, - showMemberInfo = { groupInfo: GroupInfo, member: GroupMember -> - hideKeyboard(view) - withApi { - val r = chatModel.controller.apiGroupMemberInfo(chatRh, groupInfo.groupId, member.groupMemberId) - val stats = r?.second - val (_, code) = if (member.memberActive) { - val memCode = chatModel.controller.apiGetGroupMemberCode(chatRh, groupInfo.apiId, member.groupMemberId) - member to memCode?.second - } else { - member to null - } - setGroupMembers(chatRh, groupInfo, chatModel) - ModalManager.end.closeModals() - ModalManager.end.showModalCloseable(true) { close -> - remember { derivedStateOf { chatModel.getGroupMember(member.groupMemberId) } }.value?.let { mem -> - GroupMemberInfoView(chatRh, groupInfo, mem, stats, code, chatModel, close, close) - } - } - } - }, - loadPrevMessages = { - if (chatModel.chatId.value != activeChat.value?.id) return@ChatLayout - val c = chatModel.getChat(chatModel.chatId.value ?: return@ChatLayout) - val firstId = chatModel.chatItems.firstOrNull()?.id - if (c != null && firstId != null) { - withApi { - Log.d(TAG, "TODOCHAT: loadPrevMessages: loading for ${c.id}, current chatId ${ChatModel.chatId.value}, size was ${ChatModel.chatItems.size}") - apiLoadPrevMessages(c, chatModel, firstId, searchText.value) - Log.d(TAG, "TODOCHAT: loadPrevMessages: loaded for ${c.id}, current chatId ${ChatModel.chatId.value}, size now ${ChatModel.chatItems.size}") - } - } - }, - deleteMessage = { itemId, mode -> - withApi { - val cInfo = chat.chatInfo - val toDeleteItem = chatModel.chatItems.firstOrNull { it.id == itemId } - val toModerate = toDeleteItem?.memberToModerate(chat.chatInfo) - val groupInfo = toModerate?.first - val groupMember = toModerate?.second - val deletedChatItem: ChatItem? - val toChatItem: ChatItem? - if (mode == CIDeleteMode.cidmBroadcast && groupInfo != null && groupMember != null) { - val r = chatModel.controller.apiDeleteMemberChatItem( - chatRh, - groupId = groupInfo.groupId, - groupMemberId = groupMember.groupMemberId, - itemId = itemId - ) - deletedChatItem = r?.first - toChatItem = r?.second - } else { - val r = chatModel.controller.apiDeleteChatItem( - chatRh, - type = cInfo.chatType, - id = cInfo.apiId, - itemId = itemId, - mode = mode - ) - deletedChatItem = r?.deletedChatItem?.chatItem - toChatItem = r?.toChatItem?.chatItem - } - if (toChatItem == null && deletedChatItem != null) { - chatModel.removeChatItem(chatRh, cInfo, deletedChatItem) - } else if (toChatItem != null) { - chatModel.upsertChatItem(chatRh, cInfo, toChatItem) - } - } - }, - deleteMessages = { itemIds -> - if (itemIds.isNotEmpty()) { - val chatInfo = chat.chatInfo - withBGApi { - val deletedItems: ArrayList = arrayListOf() - for (itemId in itemIds) { - val di = chatModel.controller.apiDeleteChatItem( - chatRh, chatInfo.chatType, chatInfo.apiId, itemId, CIDeleteMode.cidmInternal - )?.deletedChatItem?.chatItem - if (di != null) { - deletedItems.add(di) + ModalManager.end.showModalCloseable(true) { close -> + val chat = remember { activeChat }.value + if (chat?.chatInfo is ChatInfo.Direct) { + var contactInfo: Pair? by remember { mutableStateOf(preloadedContactInfo) } + var code: String? by remember { mutableStateOf(preloadedCode) } + KeyChangeEffect(chat.id, ChatModel.networkStatuses.toMap()) { + contactInfo = chatModel.controller.apiContactInfo(chatRh, chat.chatInfo.apiId) + preloadedContactInfo = contactInfo + code = chatModel.controller.apiGetContactCode(chatRh, chat.chatInfo.apiId)?.second + preloadedCode = code + } + ChatInfoView(chatModel, (chat.chatInfo as ChatInfo.Direct).contact, contactInfo?.first, contactInfo?.second, chat.chatInfo.localAlias, code, close) + } else if (chat?.chatInfo is ChatInfo.Group) { + var link: Pair? by remember(chat.id) { mutableStateOf(preloadedLink) } + KeyChangeEffect(chat.id) { + setGroupMembers(chatRh, (chat.chatInfo as ChatInfo.Group).groupInfo, chatModel) + link = chatModel.controller.apiGetGroupLink(chatRh, chat.chatInfo.groupInfo.groupId) + preloadedLink = link + } + GroupChatInfoView(chatModel, chatRh, chat.id, link?.first, link?.second, { + link = it + preloadedLink = it + }, close) + } } } - for (di in deletedItems) { - chatModel.removeChatItem(chatRh, chatInfo, di) + }, + showMemberInfo = { groupInfo: GroupInfo, member: GroupMember -> + hideKeyboard(view) + withApi { + val r = chatModel.controller.apiGroupMemberInfo(chatRh, groupInfo.groupId, member.groupMemberId) + val stats = r?.second + val (_, code) = if (member.memberActive) { + val memCode = chatModel.controller.apiGetGroupMemberCode(chatRh, groupInfo.apiId, member.groupMemberId) + member to memCode?.second + } else { + member to null + } + setGroupMembers(chatRh, groupInfo, chatModel) + ModalManager.end.closeModals() + ModalManager.end.showModalCloseable(true) { close -> + remember { derivedStateOf { chatModel.getGroupMember(member.groupMemberId) } }.value?.let { mem -> + GroupMemberInfoView(chatRh, groupInfo, mem, stats, code, chatModel, close, close) + } + } } - } - } - }, - receiveFile = { fileId, encrypted -> - withApi { chatModel.controller.receiveFile(chatRh, user, fileId, encrypted) } - }, - cancelFile = { fileId -> - withApi { chatModel.controller.cancelFile(chatRh, user, fileId) } - }, - joinGroup = { groupId, onComplete -> - withApi { - chatModel.controller.apiJoinGroup(chatRh, groupId) - onComplete.invoke() - } - }, - startCall = out@ { media -> - withBGApi { - val cInfo = chat.chatInfo - if (cInfo is ChatInfo.Direct) { - chatModel.activeCall.value = Call(remoteHostId = chatRh, contact = cInfo.contact, callState = CallState.WaitCapabilities, localMedia = media) - chatModel.showCallView.value = true - chatModel.callCommand.add(WCallCommand.Capabilities(media)) - } - } - }, - endCall = { - val call = chatModel.activeCall.value - if (call != null) withApi { chatModel.callManager.endCall(call) } - }, - acceptCall = { contact -> - hideKeyboard(view) - val invitation = chatModel.callInvitations.remove(contact.id) - if (invitation == null) { - AlertManager.shared.showAlertMsg(generalGetString(MR.strings.call_already_ended)) - } else { - chatModel.callManager.acceptIncomingCall(invitation = invitation) - } - }, - acceptFeature = { contact, feature, param -> - withApi { - chatModel.controller.allowFeatureToContact(chatRh, contact, feature, param) - } - }, - openDirectChat = { contactId -> - withApi { - openDirectChat(chatRh, contactId, chatModel) - } - }, - updateContactStats = { contact -> - withApi { - val r = chatModel.controller.apiContactInfo(chatRh, chat.chatInfo.apiId) - if (r != null) { - val contactStats = r.first - if (contactStats != null) - chatModel.updateContactConnectionStats(chatRh, contact, contactStats) - } - } - }, - updateMemberStats = { groupInfo, member -> - withApi { - val r = chatModel.controller.apiGroupMemberInfo(chatRh, groupInfo.groupId, member.groupMemberId) - if (r != null) { - val memStats = r.second - if (memStats != null) { - chatModel.updateGroupMemberConnectionStats(chatRh, groupInfo, r.first, memStats) + }, + loadPrevMessages = { + if (chatModel.chatId.value != activeChat.value?.id) return@ChatLayout + val c = chatModel.getChat(chatModel.chatId.value ?: return@ChatLayout) + val firstId = chatModel.chatItems.firstOrNull()?.id + if (c != null && firstId != null) { + withApi { + Log.d(TAG, "TODOCHAT: loadPrevMessages: loading for ${c.id}, current chatId ${ChatModel.chatId.value}, size was ${ChatModel.chatItems.size}") + apiLoadPrevMessages(c, chatModel, firstId, searchText.value) + Log.d(TAG, "TODOCHAT: loadPrevMessages: loaded for ${c.id}, current chatId ${ChatModel.chatId.value}, size now ${ChatModel.chatItems.size}") + } } - } - } - }, - syncContactConnection = { contact -> - withApi { - val cStats = chatModel.controller.apiSyncContactRatchet(chatRh, contact.contactId, force = false) - if (cStats != null) { - chatModel.updateContactConnectionStats(chatRh, contact, cStats) - } - } - }, - syncMemberConnection = { groupInfo, member -> - withApi { - val r = chatModel.controller.apiSyncGroupMemberRatchet(chatRh, groupInfo.apiId, member.groupMemberId, force = false) - if (r != null) { - chatModel.updateGroupMemberConnectionStats(chatRh, groupInfo, r.first, r.second) - } - } - }, - findModelChat = { chatId -> - chatModel.getChat(chatId) - }, - findModelMember = { memberId -> - chatModel.groupMembers.find { it.id == memberId } - }, - setReaction = { cInfo, cItem, add, reaction -> - withApi { - val updatedCI = chatModel.controller.apiChatItemReaction( - rh = chatRh, - type = cInfo.chatType, - id = cInfo.apiId, - itemId = cItem.id, - add = add, - reaction = reaction - ) - if (updatedCI != null) { - chatModel.updateChatItem(cInfo, updatedCI) - } - } - }, - showItemDetails = { cInfo, cItem -> - withApi { - val ciInfo = chatModel.controller.apiGetChatItemInfo(chatRh, cInfo.chatType, cInfo.apiId, cItem.id) - if (ciInfo != null) { - if (chat.chatInfo is ChatInfo.Group) { - setGroupMembers(chatRh, chat.chatInfo.groupInfo, chatModel) + }, + deleteMessage = { itemId, mode -> + withApi { + val cInfo = chat.chatInfo + val toDeleteItem = chatModel.chatItems.firstOrNull { it.id == itemId } + val toModerate = toDeleteItem?.memberToModerate(chat.chatInfo) + val groupInfo = toModerate?.first + val groupMember = toModerate?.second + val deletedChatItem: ChatItem? + val toChatItem: ChatItem? + if (mode == CIDeleteMode.cidmBroadcast && groupInfo != null && groupMember != null) { + val r = chatModel.controller.apiDeleteMemberChatItem( + chatRh, + groupId = groupInfo.groupId, + groupMemberId = groupMember.groupMemberId, + itemId = itemId + ) + deletedChatItem = r?.first + toChatItem = r?.second + } else { + val r = chatModel.controller.apiDeleteChatItem( + chatRh, + type = cInfo.chatType, + id = cInfo.apiId, + itemId = itemId, + mode = mode + ) + deletedChatItem = r?.deletedChatItem?.chatItem + toChatItem = r?.toChatItem?.chatItem + } + if (toChatItem == null && deletedChatItem != null) { + chatModel.removeChatItem(chatRh, cInfo, deletedChatItem) + } else if (toChatItem != null) { + chatModel.upsertChatItem(chatRh, cInfo, toChatItem) + } } - ModalManager.end.closeModals() - ModalManager.end.showModal(endButtons = { ShareButton { - clipboard.shareText(itemInfoShareText(chatModel, cItem, ciInfo, chatModel.controller.appPrefs.developerTools.get())) - } }) { - ChatItemInfoView(chatModel, cItem, ciInfo, devTools = chatModel.controller.appPrefs.developerTools.get()) + }, + deleteMessages = { itemIds -> + if (itemIds.isNotEmpty()) { + val chatInfo = chat.chatInfo + withBGApi { + val deletedItems: ArrayList = arrayListOf() + for (itemId in itemIds) { + val di = chatModel.controller.apiDeleteChatItem( + chatRh, chatInfo.chatType, chatInfo.apiId, itemId, CIDeleteMode.cidmInternal + )?.deletedChatItem?.chatItem + if (di != null) { + deletedItems.add(di) + } + } + for (di in deletedItems) { + chatModel.removeChatItem(chatRh, chatInfo, di) + } + } } - } - } - }, - addMembers = { groupInfo -> - hideKeyboard(view) - withApi { - setGroupMembers(chatRh, groupInfo, chatModel) + }, + receiveFile = { fileId, encrypted -> + withApi { chatModel.controller.receiveFile(chatRh, user, fileId, encrypted) } + }, + cancelFile = { fileId -> + withApi { chatModel.controller.cancelFile(chatRh, user, fileId) } + }, + joinGroup = { groupId, onComplete -> + withApi { + chatModel.controller.apiJoinGroup(chatRh, groupId) + onComplete.invoke() + } + }, + startCall = out@{ media -> + withBGApi { + val cInfo = chat.chatInfo + if (cInfo is ChatInfo.Direct) { + chatModel.activeCall.value = Call(remoteHostId = chatRh, contact = cInfo.contact, callState = CallState.WaitCapabilities, localMedia = media) + chatModel.showCallView.value = true + chatModel.callCommand.add(WCallCommand.Capabilities(media)) + } + } + }, + endCall = { + val call = chatModel.activeCall.value + if (call != null) withApi { chatModel.callManager.endCall(call) } + }, + acceptCall = { contact -> + hideKeyboard(view) + val invitation = chatModel.callInvitations.remove(contact.id) + if (invitation == null) { + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.call_already_ended)) + } else { + chatModel.callManager.acceptIncomingCall(invitation = invitation) + } + }, + acceptFeature = { contact, feature, param -> + withApi { + chatModel.controller.allowFeatureToContact(chatRh, contact, feature, param) + } + }, + openDirectChat = { contactId -> + withApi { + openDirectChat(chatRh, contactId, chatModel) + } + }, + updateContactStats = { contact -> + withApi { + val r = chatModel.controller.apiContactInfo(chatRh, chat.chatInfo.apiId) + if (r != null) { + val contactStats = r.first + if (contactStats != null) + chatModel.updateContactConnectionStats(chatRh, contact, contactStats) + } + } + }, + updateMemberStats = { groupInfo, member -> + withApi { + val r = chatModel.controller.apiGroupMemberInfo(chatRh, groupInfo.groupId, member.groupMemberId) + if (r != null) { + val memStats = r.second + if (memStats != null) { + chatModel.updateGroupMemberConnectionStats(chatRh, groupInfo, r.first, memStats) + } + } + } + }, + syncContactConnection = { contact -> + withApi { + val cStats = chatModel.controller.apiSyncContactRatchet(chatRh, contact.contactId, force = false) + if (cStats != null) { + chatModel.updateContactConnectionStats(chatRh, contact, cStats) + } + } + }, + syncMemberConnection = { groupInfo, member -> + withApi { + val r = chatModel.controller.apiSyncGroupMemberRatchet(chatRh, groupInfo.apiId, member.groupMemberId, force = false) + if (r != null) { + chatModel.updateGroupMemberConnectionStats(chatRh, groupInfo, r.first, r.second) + } + } + }, + findModelChat = { chatId -> + chatModel.getChat(chatId) + }, + findModelMember = { memberId -> + chatModel.groupMembers.find { it.id == memberId } + }, + setReaction = { cInfo, cItem, add, reaction -> + withApi { + val updatedCI = chatModel.controller.apiChatItemReaction( + rh = chatRh, + type = cInfo.chatType, + id = cInfo.apiId, + itemId = cItem.id, + add = add, + reaction = reaction + ) + if (updatedCI != null) { + chatModel.updateChatItem(cInfo, updatedCI) + } + } + }, + showItemDetails = { cInfo, cItem -> + withApi { + val ciInfo = chatModel.controller.apiGetChatItemInfo(chatRh, cInfo.chatType, cInfo.apiId, cItem.id) + if (ciInfo != null) { + if (chat.chatInfo is ChatInfo.Group) { + setGroupMembers(chatRh, chat.chatInfo.groupInfo, chatModel) + } + ModalManager.end.closeModals() + ModalManager.end.showModal(endButtons = { + ShareButton { + clipboard.shareText(itemInfoShareText(chatModel, cItem, ciInfo, chatModel.controller.appPrefs.developerTools.get())) + } + }) { + ChatItemInfoView(chatModel, cItem, ciInfo, devTools = chatModel.controller.appPrefs.developerTools.get()) + } + } + } + }, + addMembers = { groupInfo -> + hideKeyboard(view) + withApi { + setGroupMembers(chatRh, groupInfo, chatModel) + ModalManager.end.closeModals() + ModalManager.end.showModalCloseable(true) { close -> + AddGroupMembersView(chatRh, groupInfo, false, chatModel, close) + } + } + }, + openGroupLink = { groupInfo -> + hideKeyboard(view) + withApi { + val link = chatModel.controller.apiGetGroupLink(chatRh, groupInfo.groupId) + ModalManager.end.closeModals() + ModalManager.end.showModalCloseable(true) { + GroupLinkView(chatModel, chatRh, groupInfo, link?.first, link?.second, onGroupLinkUpdated = null) + } + } + }, + markRead = { range, unreadCountAfter -> + chatModel.markChatItemsRead(chat, range, unreadCountAfter) + ntfManager.cancelNotificationsForChat(chat.id) + withBGApi { + chatModel.controller.apiChatRead( + chatRh, + chat.chatInfo.chatType, + chat.chatInfo.apiId, + range + ) + } + }, + changeNtfsState = { enabled, currentValue -> toggleNotifications(chat, enabled, chatModel, currentValue) }, + onSearchValueChanged = { value -> + if (searchText.value == value) return@ChatLayout + if (chatModel.chatId.value != activeChat.value?.id) return@ChatLayout + val c = chatModel.getChat(chatModel.chatId.value ?: return@ChatLayout) ?: return@ChatLayout + withApi { + apiFindMessages(c, chatModel, value) + searchText.value = value + } + }, + onComposed, + developerTools = chatModel.controller.appPrefs.developerTools.get(), + ) + } + is ChatInfo.ContactConnection -> { + val close = { chatModel.chatId.value = null } + ModalView(close, showClose = appPlatform.isAndroid, content = { + ContactConnectionInfoView(chatModel, chat.remoteHostId, chat.chatInfo.contactConnection.connReqInv, chat.chatInfo.contactConnection, false, close) + }) + LaunchedEffect(chat.id) { + onComposed(chat.id) ModalManager.end.closeModals() - ModalManager.end.showModalCloseable(true) { close -> - AddGroupMembersView(chatRh, groupInfo, false, chatModel, close) - } + chatModel.chatItems.clear() } - }, - openGroupLink = { groupInfo -> - hideKeyboard(view) - withApi { - val link = chatModel.controller.apiGetGroupLink(chatRh, groupInfo.groupId) + } + is ChatInfo.InvalidJSON -> { + val close = { chatModel.chatId.value = null } + ModalView(close, showClose = appPlatform.isAndroid, content = { + InvalidJSONView(chat.chatInfo.json) + }) + LaunchedEffect(chat.id) { + onComposed(chat.id) ModalManager.end.closeModals() - ModalManager.end.showModalCloseable(true) { - GroupLinkView(chatModel, chatRh, groupInfo, link?.first, link?.second, onGroupLinkUpdated = null) - } + chatModel.chatItems.clear() } - }, - markRead = { range, unreadCountAfter -> - chatModel.markChatItemsRead(chat, range, unreadCountAfter) - ntfManager.cancelNotificationsForChat(chat.id) - withBGApi { - chatModel.controller.apiChatRead( - chatRh, - chat.chatInfo.chatType, - chat.chatInfo.apiId, - range - ) - } - }, - changeNtfsState = { enabled, currentValue -> toggleNotifications(chat, enabled, chatModel, currentValue) }, - onSearchValueChanged = { value -> - if (searchText.value == value) return@ChatLayout - if (chatModel.chatId.value != activeChat.value?.id) return@ChatLayout - val c = chatModel.getChat(chatModel.chatId.value ?: return@ChatLayout) ?: return@ChatLayout - withApi { - apiFindMessages(c, chatModel, value) - searchText.value = value - } - }, - onComposed, - developerTools = chatModel.controller.appPrefs.developerTools.get(), - ) + } + else -> {} + } } } @@ -733,7 +762,7 @@ fun ChatInfoToolbar( } @Composable -fun ChatInfoToolbarTitle(cInfo: ChatInfo, imageSize: Dp = 40.dp, iconColor: Color = MaterialTheme.colors.secondaryVariant) { +fun ChatInfoToolbarTitle(cInfo: ChatInfo, imageSize: Dp = 40.dp, iconColor: Color = MaterialTheme.colors.secondaryVariant.mixWith(MaterialTheme.colors.onBackground, 0.97f)) { Row( horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ScanCodeView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ScanCodeView.kt index bb479d8eb3..73017c3d42 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ScanCodeView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ScanCodeView.kt @@ -13,29 +13,20 @@ import dev.icerock.moko.resources.compose.stringResource @Composable fun ScanCodeView(verifyCode: (String?, cb: (Boolean) -> Unit) -> Unit, close: () -> Unit) { Column( - Modifier - .fillMaxSize() - .padding(horizontal = DEFAULT_PADDING) + Modifier.fillMaxSize() ) { - AppBarTitle(stringResource(MR.strings.scan_code), withPadding = false) - Box( - Modifier - .fillMaxWidth() - .aspectRatio(ratio = 1F) - .padding(bottom = DEFAULT_PADDING) - ) { - QRCodeScanner { text -> - verifyCode(text) { - if (it) { - close() - } else { - AlertManager.shared.showAlertMsg( - title = generalGetString(MR.strings.incorrect_code) - ) - } + AppBarTitle(stringResource(MR.strings.scan_code)) + QRCodeScanner { text -> + verifyCode(text) { + if (it) { + close() + } else { + AlertManager.shared.showAlertMsg( + title = generalGetString(MR.strings.incorrect_code) + ) } } } - Text(stringResource(MR.strings.scan_code_from_contacts_app)) + Text(stringResource(MR.strings.scan_code_from_contacts_app), Modifier.padding(horizontal = DEFAULT_PADDING)) } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/VerifyCodeView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/VerifyCodeView.kt index e1840dd885..57c469adf2 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/VerifyCodeView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/VerifyCodeView.kt @@ -74,9 +74,7 @@ private fun VerifyCodeLayout( } } - SectionView { - QRCode(connectionCode, Modifier.aspectRatio(1f)) - } + QRCode(connectionCode, padding = PaddingValues(vertical = DEFAULT_PADDING_HALF)) Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) { Spacer(Modifier.weight(2f)) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupLinkView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupLinkView.kt index 02ce90243c..dfb679c081 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupLinkView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupLinkView.kt @@ -153,7 +153,7 @@ fun GroupLinkLayout( } initialLaunch = false } - SimpleXLinkQRCode(groupLink, Modifier.aspectRatio(1f).padding(horizontal = DEFAULT_PADDING)) + SimpleXLinkQRCode(groupLink) Row( horizontalArrangement = Arrangement.spacedBy(10.dp), verticalAlignment = Alignment.CenterVertically, diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupMemberInfoView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupMemberInfoView.kt index 00b236c7dd..c6654dc818 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupMemberInfoView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupMemberInfoView.kt @@ -289,7 +289,7 @@ fun GroupMemberInfoLayout( if (member.contactLink != null) { SectionView(stringResource(MR.strings.address_section_title).uppercase()) { - SimpleXLinkQRCode(member.contactLink, Modifier.padding(horizontal = DEFAULT_PADDING, vertical = DEFAULT_PADDING_HALF).aspectRatio(1f)) + SimpleXLinkQRCode(member.contactLink) val clipboard = LocalClipboardManager.current ShareAddressButton { clipboard.shareText(simplexChatLink(member.contactLink)) } if (contactId != null) { @@ -506,7 +506,7 @@ fun connectViaMemberAddressAlert(rhId: Long?, connReqUri: String) { try { val uri = URI(connReqUri) withApi { - planAndConnect(chatModel, rhId, uri, incognito = null, close = { ModalManager.closeAllModalsEverywhere() }) + planAndConnect(rhId, uri, incognito = null, close = { ModalManager.closeAllModalsEverywhere() }) } } catch (e: RuntimeException) { AlertManager.shared.showAlertMsg( diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatHelpView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatHelpView.kt index 866ad04b02..f36978cd3c 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatHelpView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatHelpView.kt @@ -50,8 +50,8 @@ fun ChatHelpView(addContact: (() -> Unit)? = null) { ) Text(stringResource(MR.strings.above_then_preposition_continuation)) } - Text(annotatedStringResource(MR.strings.add_new_contact_to_create_one_time_QR_code), lineHeight = 22.sp) - Text(annotatedStringResource(MR.strings.scan_QR_code_to_connect_to_contact_who_shows_QR_code), lineHeight = 22.sp) + Text(annotatedStringResource(MR.strings.add_contact_button_to_create_link_or_connect_via_link), lineHeight = 22.sp) + Text(annotatedStringResource(MR.strings.create_group_button_to_create_new_group), lineHeight = 22.sp) } Column( diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.kt index 8d5446aa53..84ad14ed77 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.kt @@ -24,17 +24,15 @@ import chat.simplex.common.ui.theme.* import chat.simplex.common.views.chat.* import chat.simplex.common.views.chat.group.deleteGroupDialog import chat.simplex.common.views.chat.group.leaveGroupDialog -import chat.simplex.common.views.chat.item.InvalidJSONView import chat.simplex.common.views.chat.item.ItemAction import chat.simplex.common.views.helpers.* import chat.simplex.common.views.newchat.* import chat.simplex.res.MR import kotlinx.coroutines.delay import kotlinx.datetime.Clock -import java.net.URI @Composable -fun ChatListNavLinkView(chat: Chat, chatModel: ChatModel) { +fun ChatListNavLinkView(chat: Chat, nextChatSelected: State) { val showMenu = remember { mutableStateOf(false) } val showMarkRead = remember(chat.chatStats.unreadCount, chat.chatStats.unreadChat) { chat.chatStats.unreadCount > 0 || chat.chatStats.unreadChat @@ -45,7 +43,7 @@ fun ChatListNavLinkView(chat: Chat, chatModel: ChatModel) { showMenu.value = false delay(500L) } - val selectedChat = remember(chat.id) { derivedStateOf { chat.id == ChatModel.chatId.value } } + val selectedChat = remember(chat.id) { derivedStateOf { chat.id == chatModel.chatId.value } } val showChatPreviews = chatModel.showChatPreviews.value val inProgress = remember { mutableStateOf(false) } var progressByTimeout by rememberSaveable { mutableStateOf(false) } @@ -75,7 +73,8 @@ fun ChatListNavLinkView(chat: Chat, chatModel: ChatModel) { }, showMenu, stopped, - selectedChat + selectedChat, + nextChatSelected, ) } is ChatInfo.Group -> @@ -93,7 +92,8 @@ fun ChatListNavLinkView(chat: Chat, chatModel: ChatModel) { }, showMenu, stopped, - selectedChat + selectedChat, + nextChatSelected, ) is ChatInfo.ContactRequest -> ChatListNavLinkLayout( @@ -110,7 +110,8 @@ fun ChatListNavLinkView(chat: Chat, chatModel: ChatModel) { }, showMenu, stopped, - selectedChat + selectedChat, + nextChatSelected, ) is ChatInfo.ContactConnection -> ChatListNavLinkLayout( @@ -120,11 +121,7 @@ fun ChatListNavLinkView(chat: Chat, chatModel: ChatModel) { } }, click = { - ModalManager.center.closeModals() - ModalManager.end.closeModals() - ModalManager.center.showModalCloseable(true, showClose = appPlatform.isAndroid) { close -> - ContactConnectionInfoView(chatModel, chat.remoteHostId, chat.chatInfo.contactConnection.connReqInv, chat.chatInfo.contactConnection, false, close) - } + chatModel.chatId.value = chat.id }, dropdownMenuItems = { tryOrShowError("${chat.id}ChatListNavLinkDropdown", error = {}) { @@ -133,7 +130,8 @@ fun ChatListNavLinkView(chat: Chat, chatModel: ChatModel) { }, showMenu, stopped, - selectedChat + selectedChat, + nextChatSelected, ) is ChatInfo.InvalidJSON -> ChatListNavLinkLayout( @@ -143,13 +141,13 @@ fun ChatListNavLinkView(chat: Chat, chatModel: ChatModel) { } }, click = { - ModalManager.end.closeModals() - ModalManager.center.showModal(true) { InvalidJSONView(chat.chatInfo.json) } + chatModel.chatId.value = chat.id }, dropdownMenuItems = null, showMenu, stopped, - selectedChat + selectedChat, + nextChatSelected, ) } } @@ -476,10 +474,7 @@ fun ContactConnectionMenuItems(rhId: Long?, chatInfo: ChatInfo.ContactConnection painterResource(MR.images.ic_delete), onClick = { deleteContactConnectionAlert(rhId, chatInfo.contactConnection, chatModel) { - if (chatModel.chatId.value == null) { - ModalManager.center.closeModals() - ModalManager.end.closeModals() - } + chatModel.dismissConnReqView(chatInfo.contactConnection.id) } showMenu.value = false }, @@ -804,7 +799,8 @@ expect fun ChatListNavLinkLayout( dropdownMenuItems: (@Composable () -> Unit)?, showMenu: MutableState, stopped: Boolean, - selectedChat: State + selectedChat: State, + nextChatSelected: State, ) @Preview/*( @@ -846,7 +842,8 @@ fun PreviewChatListNavLinkDirect() { dropdownMenuItems = null, showMenu = remember { mutableStateOf(false) }, stopped = false, - selectedChat = remember { mutableStateOf(false) } + selectedChat = remember { mutableStateOf(false) }, + nextChatSelected = remember { mutableStateOf(false) } ) } } @@ -890,7 +887,8 @@ fun PreviewChatListNavLinkGroup() { dropdownMenuItems = null, showMenu = remember { mutableStateOf(false) }, stopped = false, - selectedChat = remember { mutableStateOf(false) } + selectedChat = remember { mutableStateOf(false) }, + nextChatSelected = remember { mutableStateOf(false) } ) } } @@ -911,7 +909,8 @@ fun PreviewChatListNavLinkContactRequest() { dropdownMenuItems = null, showMenu = remember { mutableStateOf(false) }, stopped = false, - selectedChat = remember { mutableStateOf(false) } + selectedChat = remember { mutableStateOf(false) }, + nextChatSelected = remember { mutableStateOf(false) } ) } } 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 cf12727d74..4280f51368 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 @@ -10,11 +10,15 @@ import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.* import androidx.compose.ui.graphics.* import androidx.compose.ui.text.font.FontStyle +import androidx.compose.ui.platform.* +import androidx.compose.ui.text.TextRange import dev.icerock.moko.resources.compose.painterResource import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.unit.* import chat.simplex.common.SettingsViewState import chat.simplex.common.model.* @@ -29,6 +33,7 @@ import chat.simplex.common.views.newchat.* import chat.simplex.res.MR import kotlinx.coroutines.* import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.distinctUntilChanged import java.net.URI @Composable @@ -60,10 +65,10 @@ fun ChatListView(chatModel: ChatModel, settingsState: SettingsViewState, setPerf } } val endPadding = if (appPlatform.isDesktop) 56.dp else 0.dp - var searchInList by rememberSaveable { mutableStateOf("") } + val searchText = rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue("")) } val scope = rememberCoroutineScope() val (userPickerState, scaffoldState ) = settingsState - Scaffold(topBar = { Box(Modifier.padding(end = endPadding)) { ChatListToolbar(chatModel, scaffoldState.drawerState, userPickerState, stopped) { searchInList = it.trim() } } }, + Scaffold(topBar = { Box(Modifier.padding(end = endPadding)) { ChatListToolbar(searchText, scaffoldState.drawerState, userPickerState, stopped)} }, scaffoldState = scaffoldState, drawerContent = { tryOrShowError("Settings", error = { ErrorSettingsView() }) { @@ -73,7 +78,7 @@ fun ChatListView(chatModel: ChatModel, settingsState: SettingsViewState, setPerf drawerScrimColor = MaterialTheme.colors.onSurface.copy(alpha = if (isInDarkTheme()) 0.16f else 0.32f), drawerGesturesEnabled = appPlatform.isAndroid, floatingActionButton = { - if (searchInList.isEmpty() && !chatModel.desktopNoUserNoRemote) { + if (searchText.value.text.isEmpty() && !chatModel.desktopNoUserNoRemote && chatModel.chatRunning.value == true) { FloatingActionButton( onClick = { if (!stopped) { @@ -101,19 +106,20 @@ fun ChatListView(chatModel: ChatModel, settingsState: SettingsViewState, setPerf .fillMaxSize() ) { if (chatModel.chats.isNotEmpty()) { - ChatList(chatModel, search = searchInList) + ChatList(chatModel, searchText = searchText) } else if (!chatModel.switchingUsersAndHosts.value && !chatModel.desktopNoUserNoRemote) { Box(Modifier.fillMaxSize()) { - if (!stopped && !newChatSheetState.collectAsState().value.isVisible()) { + if (!stopped && !newChatSheetState.collectAsState().value.isVisible() && chatModel.chatRunning.value == true) { OnboardingButtons(showNewChatSheet) } - Text(stringResource(MR.strings.you_have_no_chats), Modifier.align(Alignment.Center), color = MaterialTheme.colors.secondary) + Text(stringResource( + if (chatModel.chatRunning.value == null) MR.strings.loading_chats else MR.strings.you_have_no_chats), Modifier.align(Alignment.Center), color = MaterialTheme.colors.secondary) } } } } } - if (searchInList.isEmpty()) { + if (searchText.value.text.isEmpty()) { DesktopActiveCallOverlayLayout(newChatSheetState) // TODO disable this button and sheet for the duration of the switch tryOrShowError("NewChatSheet", error = {}) { @@ -168,20 +174,8 @@ private fun ConnectButton(text: String, onClick: () -> Unit) { } @Composable -private fun ChatListToolbar(chatModel: ChatModel, drawerState: DrawerState, userPickerState: MutableStateFlow, stopped: Boolean, onSearchValueChanged: (String) -> Unit) { - var showSearch by rememberSaveable { mutableStateOf(false) } - val hideSearchOnBack = { onSearchValueChanged(""); showSearch = false } - if (showSearch) { - BackHandler(onBack = hideSearchOnBack) - } +private fun ChatListToolbar(searchInList: State, drawerState: DrawerState, userPickerState: MutableStateFlow, stopped: Boolean) { val barButtons = arrayListOf<@Composable RowScope.() -> Unit>() - if (chatModel.chats.size > 0) { - barButtons.add { - IconButton({ showSearch = true }) { - Icon(painterResource(MR.images.ic_search_500), stringResource(MR.strings.search_verb), tint = MaterialTheme.colors.primary) - } - } - } if (stopped) { barButtons.add { IconButton(onClick = { @@ -201,9 +195,7 @@ private fun ChatListToolbar(chatModel: ChatModel, drawerState: DrawerState, user val scope = rememberCoroutineScope() DefaultTopAppBar( navigationButton = { - if (showSearch) { - NavigationButtonBack(hideSearchOnBack) - } else if (chatModel.users.isEmpty() && !chatModel.desktopNoUserNoRemote) { + if (chatModel.users.isEmpty() && !chatModel.desktopNoUserNoRemote) { NavigationButtonMenu { scope.launch { if (drawerState.isOpen) drawerState.close() else drawerState.open() } } } else { val users by remember { derivedStateOf { chatModel.users.filter { u -> u.user.activeUser || !u.user.hidden } } } @@ -227,13 +219,18 @@ private fun ChatListToolbar(chatModel: ChatModel, drawerState: DrawerState, user fontWeight = FontWeight.SemiBold, ) if (chatModel.chats.size > 0) { - ToggleFilterButton() + val enabled = remember { derivedStateOf { searchInList.value.text.isEmpty() } } + if (enabled.value) { + ToggleFilterEnabledButton() + } else { + ToggleFilterDisabledButton() + } } } }, onTitleClick = null, - showSearch = showSearch, - onSearchValueChanged = onSearchValueChanged, + showSearch = false, + onSearchValueChanged = {}, buttons = barButtons ) Divider(Modifier.padding(top = AppBarHeight)) @@ -246,7 +243,8 @@ fun UserProfileButton(image: String?, allRead: Boolean, onButtonClicked: () -> U Box { ProfileImage( image = image, - size = 37.dp + size = 37.dp, + color = MaterialTheme.colors.secondaryVariant.mixWith(MaterialTheme.colors.onBackground, 0.97f) ) if (!allRead) { unreadBadge() @@ -281,7 +279,7 @@ private fun BoxScope.unreadBadge(text: String? = "") { } @Composable -private fun ToggleFilterButton() { +private fun ToggleFilterEnabledButton() { val pref = remember { ChatController.appPrefs.showUnreadAndFavorites } IconButton(onClick = { pref.set(!pref.get()) }) { Icon( @@ -290,7 +288,7 @@ private fun ToggleFilterButton() { tint = if (pref.state.value) MaterialTheme.colors.background else MaterialTheme.colors.primary, modifier = Modifier .padding(3.dp) - .background(color = if (pref.state.value) MaterialTheme.colors.primary else MaterialTheme.colors.background, shape = RoundedCornerShape(50)) + .background(color = if (pref.state.value) MaterialTheme.colors.primary else Color.Unspecified, shape = RoundedCornerShape(50)) .border(width = 1.dp, color = MaterialTheme.colors.primary, shape = RoundedCornerShape(50)) .padding(3.dp) .size(16.dp) @@ -298,6 +296,22 @@ private fun ToggleFilterButton() { } } +@Composable +private fun ToggleFilterDisabledButton() { + IconButton({}, enabled = false) { + Icon( + painterResource(MR.images.ic_filter_list), + null, + tint = MaterialTheme.colors.secondary, + modifier = Modifier + .padding(3.dp) + .border(width = 1.dp, color = MaterialTheme.colors.secondary, shape = RoundedCornerShape(50)) + .padding(3.dp) + .size(16.dp) + ) + } +} + @Composable expect fun DesktopActiveCallOverlayLayout(newChatSheetState: MutableStateFlow) @@ -307,11 +321,115 @@ fun connectIfOpenedViaUri(rhId: Long?, uri: URI, chatModel: ChatModel) { chatModel.appOpenUrl.value = rhId to uri } else { withApi { - planAndConnect(chatModel, rhId, uri, incognito = null, close = null) + planAndConnect(rhId, uri, incognito = null, close = null) } } } +@Composable +private fun ChatListSearchBar(listState: LazyListState, searchText: MutableState, searchShowingSimplexLink: MutableState, searchChatFilteredBySimplexLink: MutableState) { + Row(verticalAlignment = Alignment.CenterVertically) { + val focusRequester = remember { FocusRequester() } + var focused by remember { mutableStateOf(false) } + Icon(painterResource(MR.images.ic_search), null, Modifier.padding(horizontal = DEFAULT_PADDING_HALF), tint = MaterialTheme.colors.secondary) + SearchTextField( + Modifier.weight(1f).onFocusChanged { focused = it.hasFocus }.focusRequester(focusRequester), + placeholder = stringResource(MR.strings.search_or_paste_simplex_link), + alwaysVisible = true, + searchText = searchText, + enabled = !remember { searchShowingSimplexLink }.value, + trailingContent = null, + ) { + searchText.value = searchText.value.copy(it) + } + val hasText = remember { derivedStateOf { searchText.value.text.isNotEmpty() } } + if (hasText.value) { + val hideSearchOnBack: () -> Unit = { searchText.value = TextFieldValue() } + BackHandler(onBack = hideSearchOnBack) + KeyChangeEffect(chatModel.currentRemoteHost.value) { + hideSearchOnBack() + } + } else { + Row { + val padding = if (appPlatform.isDesktop) 0.dp else 7.dp + val clipboard = LocalClipboardManager.current + val clipboardHasText = remember(focused) { chatModel.clipboardHasText }.value + if (clipboardHasText) { + IconButton( + onClick = { searchText.value = searchText.value.copy(clipboard.getText()?.text ?: return@IconButton) }, + Modifier.size(30.dp).desktopPointerHoverIconHand() + ) { + Icon(painterResource(MR.images.ic_article), null, tint = MaterialTheme.colors.secondary) + } + } + Spacer(Modifier.width(padding)) + IconButton( + onClick = { + val fixedRhId = chatModel.currentRemoteHost.value + ModalManager.center.closeModals() + ModalManager.center.showModalCloseable { close -> + NewChatView(fixedRhId, selection = NewChatOption.CONNECT, showQRCodeScanner = true, close = close) + } + }, + Modifier.size(30.dp).desktopPointerHoverIconHand() + ) { + Icon(painterResource(MR.images.ic_qr_code), null, tint = MaterialTheme.colors.secondary) + } + Spacer(Modifier.width(padding)) + } + } + val focusManager = LocalFocusManager.current + val keyboardState = getKeyboardState() + LaunchedEffect(keyboardState.value) { + if (keyboardState.value == KeyboardState.Closed && focused) { + focusManager.clearFocus() + } + } + val view = LocalMultiplatformView() + LaunchedEffect(Unit) { + snapshotFlow { searchText.value.text } + .distinctUntilChanged() + .collect { + val link = strHasSingleSimplexLink(it.trim()) + if (link != null) { + // if SimpleX link is pasted, show connection dialogue + hideKeyboard(view) + if (link.format is Format.SimplexLink) { + val linkText = link.simplexLinkText(link.format.linkType, link.format.smpHosts) + searchText.value = searchText.value.copy(linkText, selection = TextRange.Zero) + } + searchShowingSimplexLink.value = true + searchChatFilteredBySimplexLink.value = null + connect(link.text, searchChatFilteredBySimplexLink) { searchText.value = TextFieldValue() } + } else if (!searchShowingSimplexLink.value || it.isEmpty()) { + if (it.isNotEmpty()) { + // if some other text is pasted, enter search mode + focusRequester.requestFocus() + } else if (listState.layoutInfo.totalItemsCount > 0) { + listState.scrollToItem(0) + } + searchShowingSimplexLink.value = false + searchChatFilteredBySimplexLink.value = null + } + } + } + } +} + +private fun connect(link: String, searchChatFilteredBySimplexLink: MutableState, cleanup: (() -> Unit)?) { + withBGApi { + planAndConnect( + chatModel.remoteHostId(), + URI.create(link), + incognito = null, + filterKnownContact = { searchChatFilteredBySimplexLink.value = it.id }, + filterKnownGroup = { searchChatFilteredBySimplexLink.value = it.id }, + close = null, + cleanup = cleanup, + ) + } +} + @Composable private fun ErrorSettingsView() { Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { @@ -322,7 +440,7 @@ private fun ErrorSettingsView() { private var lazyListState = 0 to 0 @Composable -private fun ChatList(chatModel: ChatModel, search: String) { +private fun ChatList(chatModel: ChatModel, searchText: MutableState) { val listState = rememberLazyListState(lazyListState.first, lazyListState.second) DisposableEffect(Unit) { onDispose { lazyListState = listState.firstVisibleItemIndex to listState.firstVisibleItemScrollOffset } @@ -332,13 +450,35 @@ private fun ChatList(chatModel: ChatModel, search: String) { // In some not always reproducible situations this code produce IndexOutOfBoundsException on Compose's side // which is related to [derivedStateOf]. Using safe alternative instead // val chats by remember(search, showUnreadAndFavorites) { derivedStateOf { filteredChats(showUnreadAndFavorites, search, allChats.toList()) } } - val chats = filteredChats(showUnreadAndFavorites, search, allChats.toList()) + val searchShowingSimplexLink = remember { mutableStateOf(false) } + val searchChatFilteredBySimplexLink = remember { mutableStateOf(null) } + val chats = filteredChats(showUnreadAndFavorites, searchShowingSimplexLink, searchChatFilteredBySimplexLink, searchText.value.text, allChats.toList()) LazyColumn( - modifier = Modifier.fillMaxWidth(), + Modifier.fillMaxWidth(), listState ) { - items(chats) { chat -> - ChatListNavLinkView(chat, chatModel) + stickyHeader { + Column( + Modifier + .offset { + val y = if (searchText.value.text.isEmpty()) { + if (listState.firstVisibleItemIndex == 0) -listState.firstVisibleItemScrollOffset else -1000 + } else { + 0 + } + IntOffset(0, y) + } + .background(MaterialTheme.colors.background) + ) { + ChatListSearchBar(listState, searchText, searchShowingSimplexLink, searchChatFilteredBySimplexLink) + Divider() + } + } + itemsIndexed(chats) { index, chat -> + val nextChatSelected = remember(chat.id, chats) { derivedStateOf { + chatModel.chatId.value != null && chats.getOrNull(index + 1)?.id == chatModel.chatId.value + } } + ChatListNavLinkView(chat, nextChatSelected) } } if (chats.isEmpty() && !chatModel.chats.isEmpty()) { @@ -348,28 +488,39 @@ private fun ChatList(chatModel: ChatModel, search: String) { } } -private fun filteredChats(showUnreadAndFavorites: Boolean, searchText: String, chats: List): List { - val s = searchText.trim().lowercase() - return if (s.isEmpty() && !showUnreadAndFavorites) - chats - else { - chats.filter { chat -> - when (val cInfo = chat.chatInfo) { - is ChatInfo.Direct -> if (s.isEmpty()) { - filtered(chat) - } else { - (viewNameContains(cInfo, s) || - cInfo.contact.profile.displayName.lowercase().contains(s) || - cInfo.contact.fullName.lowercase().contains(s)) +private fun filteredChats( + showUnreadAndFavorites: Boolean, + searchShowingSimplexLink: State, + searchChatFilteredBySimplexLink: State, + searchText: String, + chats: List +): List { + val linkChatId = searchChatFilteredBySimplexLink.value + return if (linkChatId != null) { + chats.filter { it.id == linkChatId } + } else { + val s = if (searchShowingSimplexLink.value) "" else searchText.trim().lowercase() + if (s.isEmpty() && !showUnreadAndFavorites) + chats + else { + chats.filter { chat -> + when (val cInfo = chat.chatInfo) { + is ChatInfo.Direct -> if (s.isEmpty()) { + chat.id == chatModel.chatId.value || filtered(chat) + } else { + (viewNameContains(cInfo, s) || + cInfo.contact.profile.displayName.lowercase().contains(s) || + cInfo.contact.fullName.lowercase().contains(s)) + } + is ChatInfo.Group -> if (s.isEmpty()) { + chat.id == chatModel.chatId.value || filtered(chat) || cInfo.groupInfo.membership.memberStatus == GroupMemberStatus.MemInvited + } else { + viewNameContains(cInfo, s) + } + is ChatInfo.ContactRequest -> s.isEmpty() || viewNameContains(cInfo, s) + is ChatInfo.ContactConnection -> (s.isNotEmpty() && cInfo.contactConnection.localAlias.lowercase().contains(s)) || (s.isEmpty() && chat.id == chatModel.chatId.value) + is ChatInfo.InvalidJSON -> chat.id == chatModel.chatId.value } - is ChatInfo.Group -> if (s.isEmpty()) { - (filtered(chat) || cInfo.groupInfo.membership.memberStatus == GroupMemberStatus.MemInvited) - } else { - viewNameContains(cInfo, s) - } - is ChatInfo.ContactRequest -> s.isEmpty() || viewNameContains(cInfo, s) - is ChatInfo.ContactConnection -> s.isNotEmpty() && cInfo.contactConnection.localAlias.lowercase().contains(s) - is ChatInfo.InvalidJSON -> false } } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/AlertManager.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/AlertManager.kt index 177efbfddc..f518f1c964 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/AlertManager.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/AlertManager.kt @@ -62,7 +62,28 @@ class AlertManager { fun showAlertDialogButtonsColumn( title: String, - text: AnnotatedString? = null, + text: String? = null, + onDismissRequest: (() -> Unit)? = null, + hostDevice: Pair? = null, + buttons: @Composable () -> Unit, + ) { + showAlert { + AlertDialog( + onDismissRequest = { onDismissRequest?.invoke(); hideAlert() }, + title = alertTitle(title), + buttons = { + AlertContent(text, hostDevice, extraPadding = true) { + buttons() + } + }, + shape = RoundedCornerShape(corner = CornerSize(25.dp)) + ) + } + } + + fun showAlertDialogButtonsColumn( + title: String, + text: AnnotatedString, onDismissRequest: (() -> Unit)? = null, hostDevice: Pair? = null, buttons: @Composable () -> Unit, diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DefaultProgressBar.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DefaultProgressBar.kt new file mode 100644 index 0000000000..ec2500ab2e --- /dev/null +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DefaultProgressBar.kt @@ -0,0 +1,27 @@ +package chat.simplex.common.views.helpers + +import androidx.compose.foundation.layout.* +import androidx.compose.material.* +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import chat.simplex.common.ui.theme.DEFAULT_PADDING + +@Composable +fun DefaultProgressView(description: String?) { + Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { + Column(horizontalAlignment = Alignment.CenterHorizontally) { + CircularProgressIndicator( + Modifier + .padding(bottom = DEFAULT_PADDING) + .size(30.dp), + color = MaterialTheme.colors.secondary, + strokeWidth = 2.5.dp + ) + if (description != null) { + Text(description) + } + } + } +} diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DefaultTopAppBar.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DefaultTopAppBar.kt index 0162ac7e78..93be24d921 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DefaultTopAppBar.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DefaultTopAppBar.kt @@ -36,7 +36,7 @@ fun DefaultTopAppBar( SearchTextField(Modifier.fillMaxWidth(), alwaysVisible = false, onValueChange = onSearchValueChanged) } }, - backgroundColor = if (isInDarkTheme()) ToolbarDark else ToolbarLight, + backgroundColor = MaterialTheme.colors.background.mixWith(MaterialTheme.colors.onBackground, 0.97f), navigationIcon = navigationButton, buttons = if (!showSearch) buttons else emptyList(), centered = !showSearch, diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ModalView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ModalView.kt index 703b6f905f..7e9cefa31c 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ModalView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ModalView.kt @@ -38,6 +38,12 @@ enum class ModalPlacement { START, CENTER, END, FULLSCREEN } +class ModalData { + private val state = mutableMapOf>() + fun stateGetOrPut (key: String, default: () -> T): MutableState = + state.getOrPut(key) { mutableStateOf(default() as Any) } as MutableState +} + class ModalManager(private val placement: ModalPlacement? = null) { private val modalViews = arrayListOf Unit) -> Unit)>>() private val modalCount = mutableStateOf(0) @@ -45,15 +51,17 @@ class ModalManager(private val placement: ModalPlacement? = null) { private var oldViewChanging = AtomicBoolean(false) private var passcodeView: MutableState<(@Composable (close: () -> Unit) -> Unit)?> = mutableStateOf(null) - fun showModal(settings: Boolean = false, showClose: Boolean = true, endButtons: @Composable RowScope.() -> Unit = {}, content: @Composable () -> Unit) { + fun showModal(settings: Boolean = false, showClose: Boolean = true, endButtons: @Composable RowScope.() -> Unit = {}, content: @Composable ModalData.() -> Unit) { + val data = ModalData() showCustomModal { close -> - ModalView(close, showClose = showClose, endButtons = endButtons, content = content) + ModalView(close, showClose = showClose, endButtons = endButtons, content = { data.content() }) } } - fun showModalCloseable(settings: Boolean = false, showClose: Boolean = true, content: @Composable (close: () -> Unit) -> Unit) { + fun showModalCloseable(settings: Boolean = false, showClose: Boolean = true, content: @Composable ModalData.(close: () -> Unit) -> Unit) { + val data = ModalData() showCustomModal { close -> - ModalView(close, showClose = showClose, content = { content(close) }) + ModalView(close, showClose = showClose, content = { data.content(close) }) } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/SearchTextField.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/SearchTextField.kt index 4b6c70df44..23fac21e79 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/SearchTextField.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/SearchTextField.kt @@ -34,6 +34,8 @@ fun SearchTextField( alwaysVisible: Boolean, searchText: MutableState = rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue("")) }, placeholder: String = stringResource(MR.strings.search_verb), + enabled: Boolean = true, + trailingContent: @Composable (() -> Unit)? = null, onValueChange: (String) -> Unit ) { val focusRequester = remember { FocusRequester() } @@ -54,12 +56,12 @@ fun SearchTextField( } } - val enabled = true val colors = TextFieldDefaults.textFieldColors( backgroundColor = Color.Unspecified, textColor = MaterialTheme.colors.onBackground, focusedIndicatorColor = Color.Unspecified, unfocusedIndicatorColor = Color.Unspecified, + disabledIndicatorColor = Color.Unspecified, ) val shape = MaterialTheme.shapes.small.copy(bottomEnd = ZeroCornerSize, bottomStart = ZeroCornerSize) val interactionSource = remember { MutableInteractionSource() } @@ -77,6 +79,7 @@ fun SearchTextField( searchText.value = it onValueChange(it.text) }, + enabled = rememberUpdatedState(enabled).value, cursorBrush = SolidColor(colors.cursorColor(false).value), visualTransformation = VisualTransformation.None, keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search), @@ -105,7 +108,7 @@ fun SearchTextField( }) { Icon(painterResource(MR.images.ic_close), stringResource(MR.strings.icon_descr_close_button), tint = MaterialTheme.colors.primary,) } - }} else null, + }} else trailingContent, singleLine = true, enabled = enabled, interactionSource = interactionSource, diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/Utils.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/Utils.kt index 9a81b9f9d7..cae9523e1b 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/Utils.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/Utils.kt @@ -60,6 +60,9 @@ fun annotatedStringResource(id: StringResource, vararg args: Any?): AnnotatedStr } } +@Composable +expect fun SetupClipboardListener() + // maximum image file size to be auto-accepted const val MAX_IMAGE_SIZE: Long = 261_120 // 255KB const val MAX_IMAGE_SIZE_AUTO_RCV: Long = MAX_IMAGE_SIZE * 2 diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/AddContactLearnMore.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/AddContactLearnMore.kt index 2913f6ac79..c2523c9b2e 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/AddContactLearnMore.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/AddContactLearnMore.kt @@ -4,14 +4,16 @@ import androidx.compose.foundation.* import androidx.compose.foundation.layout.Column import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import chat.simplex.common.platform.chatModel import dev.icerock.moko.resources.compose.stringResource import chat.simplex.common.views.helpers.AppBarTitle +import chat.simplex.common.views.helpers.KeyChangeEffect import chat.simplex.common.views.onboarding.ReadableText import chat.simplex.common.views.onboarding.ReadableTextWithLink import chat.simplex.res.MR @Composable -fun AddContactLearnMore() { +fun AddContactLearnMore(close: () -> Unit) { Column( Modifier.verticalScroll(rememberScrollState()), ) { @@ -20,4 +22,7 @@ fun AddContactLearnMore() { ReadableText(MR.strings.if_you_cant_meet_in_person) ReadableTextWithLink(MR.strings.read_more_in_user_guide_with_link, "https://simplex.chat/docs/guide/readme.html#connect-to-friends") } + KeyChangeEffect(chatModel.chatId.value) { + close() + } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/AddContactView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/AddContactView.kt deleted file mode 100644 index 84080d5b97..0000000000 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/AddContactView.kt +++ /dev/null @@ -1,186 +0,0 @@ -package chat.simplex.common.views.newchat - -import SectionBottomSpacer -import SectionTextFooter -import SectionView -import androidx.compose.desktop.ui.tooling.preview.Preview -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll -import androidx.compose.material.* -import dev.icerock.moko.resources.compose.painterResource -import androidx.compose.runtime.* -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalClipboardManager -import dev.icerock.moko.resources.compose.stringResource -import androidx.compose.ui.unit.dp -import chat.simplex.common.model.* -import chat.simplex.common.platform.shareText -import chat.simplex.common.ui.theme.* -import chat.simplex.common.views.helpers.* -import chat.simplex.common.views.usersettings.* -import chat.simplex.res.MR - -@Composable -fun AddContactView( - chatModel: ChatModel, - rh: RemoteHostInfo?, - connReqInvitation: String, - contactConnection: MutableState -) { - val clipboard = LocalClipboardManager.current - AddContactLayout( - rh = rh, - chatModel = chatModel, - incognitoPref = chatModel.controller.appPrefs.incognito, - connReq = connReqInvitation, - contactConnection = contactConnection, - learnMore = { - ModalManager.center.showModal { - Column( - Modifier - .fillMaxHeight() - .padding(horizontal = DEFAULT_PADDING), - verticalArrangement = Arrangement.SpaceBetween - ) { - AddContactLearnMore() - } - } - } - ) -} - -@Composable -fun AddContactLayout( - chatModel: ChatModel, - rh: RemoteHostInfo?, - incognitoPref: SharedPreference, - connReq: String, - contactConnection: MutableState, - learnMore: () -> Unit -) { - val incognito = remember { mutableStateOf(incognitoPref.get()) } - - LaunchedEffect(incognito.value) { - withApi { - val contactConnVal = contactConnection.value - if (contactConnVal != null) { - chatModel.controller.apiSetConnectionIncognito(rh?.remoteHostId, contactConnVal.pccConnId, incognito.value)?.let { - contactConnection.value = it - chatModel.updateContactConnection(rh?.remoteHostId, it) - } - } - } - } - - Column( - Modifier - .verticalScroll(rememberScrollState()), - verticalArrangement = Arrangement.SpaceBetween, - ) { - AppBarTitle(stringResource(MR.strings.add_contact), hostDevice(rh?.remoteHostId)) - - SectionView(stringResource(MR.strings.one_time_link_short).uppercase()) { - if (connReq.isNotEmpty()) { - SimpleXLinkQRCode( - connReq, Modifier - .padding(horizontal = DEFAULT_PADDING, vertical = DEFAULT_PADDING_HALF) - .aspectRatio(1f) - ) - } else { - CircularProgressIndicator( - Modifier - .size(36.dp) - .padding(4.dp) - .align(Alignment.CenterHorizontally), - color = MaterialTheme.colors.secondary, - strokeWidth = 3.dp - ) - } - - IncognitoToggle(incognitoPref, incognito) { ModalManager.start.showModal { IncognitoView() } } - ShareLinkButton(connReq) - OneTimeLinkLearnMoreButton(learnMore) - } - SectionTextFooter(sharedProfileInfo(chatModel, incognito.value)) - - SectionBottomSpacer() - } -} - -@Composable -fun ShareLinkButton(connReqInvitation: String) { - val clipboard = LocalClipboardManager.current - SettingsActionItem( - painterResource(MR.images.ic_share), - stringResource(MR.strings.share_invitation_link), - click = { clipboard.shareText(simplexChatLink(connReqInvitation)) }, - iconColor = MaterialTheme.colors.primary, - textColor = MaterialTheme.colors.primary, - ) -} - -@Composable -fun OneTimeLinkLearnMoreButton(onClick: () -> Unit) { - SettingsActionItem( - painterResource(MR.images.ic_info), - stringResource(MR.strings.learn_more), - onClick, - ) -} - -@Composable -fun IncognitoToggle( - incognitoPref: SharedPreference, - incognito: MutableState, - onClickInfo: () -> Unit -) { - SettingsActionItemWithContent( - icon = if (incognito.value) painterResource(MR.images.ic_theater_comedy_filled) else painterResource(MR.images.ic_theater_comedy), - text = null, - click = onClickInfo, - iconColor = if (incognito.value) Indigo else MaterialTheme.colors.secondary, - extraPadding = false - ) { - SharedPreferenceToggleWithIcon( - stringResource(MR.strings.incognito), - painterResource(MR.images.ic_info), - stopped = false, - onClickInfo = onClickInfo, - preference = incognitoPref, - preferenceState = incognito - ) - } -} - -fun sharedProfileInfo( - chatModel: ChatModel, - incognito: Boolean -): String { - val name = chatModel.currentUser.value?.displayName ?: "" - return if (incognito) { - generalGetString(MR.strings.connect__a_new_random_profile_will_be_shared) - } else { - String.format(generalGetString(MR.strings.connect__your_profile_will_be_shared), name) - } -} - -@Preview/*( - uiMode = Configuration.UI_MODE_NIGHT_YES, - showBackground = true, - name = "Dark Mode" -)*/ -@Composable -fun PreviewAddContactView() { - SimpleXTheme { - AddContactLayout( - rh = null, - chatModel = ChatModel, - incognitoPref = SharedPreference({ false }, {}), - connReq = "https://simplex.chat/contact#/?v=1&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FK1rslx-m5bpXVIdMZg9NLUZ_8JBm8xTt%23MCowBQYDK2VuAyEALDeVe-sG8mRY22LsXlPgiwTNs9dbiLrNuA7f3ZMAJ2w%3D", - contactConnection = mutableStateOf(PendingContactConnection.getSampleData()), - learnMore = {}, - ) - } -} diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/ScanToConnectView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/ConnectPlan.kt similarity index 71% rename from apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/ScanToConnectView.kt rename to apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/ConnectPlan.kt index 9f28074aef..adbacca6bc 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/ScanToConnectView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/ConnectPlan.kt @@ -1,57 +1,51 @@ package chat.simplex.common.views.newchat -import SectionBottomSpacer import SectionItemView -import SectionTextFooter -import androidx.compose.desktop.ui.tooling.preview.Preview import androidx.compose.foundation.layout.* -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll import androidx.compose.material.* -import androidx.compose.runtime.* import androidx.compose.ui.Modifier -import androidx.compose.ui.text.AnnotatedString -import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.style.TextAlign import dev.icerock.moko.resources.compose.stringResource -import androidx.compose.ui.unit.dp import chat.simplex.common.model.* import chat.simplex.common.platform.* -import chat.simplex.common.ui.theme.* import chat.simplex.common.views.chatlist.* import chat.simplex.common.views.helpers.* -import chat.simplex.common.views.usersettings.IncognitoView import chat.simplex.res.MR import java.net.URI -@Composable -expect fun ScanToConnectView(chatModel: ChatModel, rh: RemoteHostInfo?, close: () -> Unit) - enum class ConnectionLinkType { INVITATION, CONTACT, GROUP } suspend fun planAndConnect( - chatModel: ChatModel, rhId: Long?, uri: URI, incognito: Boolean?, - close: (() -> Unit)? + close: (() -> Unit)?, + cleanup: (() -> Unit)? = null, + filterKnownContact: ((Contact) -> Unit)? = null, + filterKnownGroup: ((GroupInfo) -> Unit)? = null, ) { val connectionPlan = chatModel.controller.apiConnectPlan(rhId, uri.toString()) if (connectionPlan != null) { + val link = strHasSingleSimplexLink(uri.toString().trim()) + val linkText = if (link?.format is Format.SimplexLink) + "

${link.simplexLinkText(link.format.linkType, link.format.smpHosts)}" + else + "" when (connectionPlan) { is ConnectionPlan.InvitationLink -> when (connectionPlan.invitationLinkPlan) { InvitationLinkPlan.Ok -> { Log.d(TAG, "planAndConnect, .InvitationLink, .Ok, incognito=$incognito") if (incognito != null) { - connectViaUri(chatModel, rhId, uri, incognito, connectionPlan, close) + connectViaUri(chatModel, rhId, uri, incognito, connectionPlan, close, cleanup) } else { askCurrentOrIncognitoProfileAlert( chatModel, rhId, uri, connectionPlan, close, title = generalGetString(MR.strings.connect_via_invitation_link), - text = AnnotatedString(generalGetString(MR.strings.profile_will_be_sent_to_contact_sending_link)), - connectDestructive = false + text = generalGetString(MR.strings.profile_will_be_sent_to_contact_sending_link) + linkText, + connectDestructive = false, + cleanup = cleanup, ) } } @@ -60,9 +54,11 @@ suspend fun planAndConnect( if (incognito != null) { AlertManager.privacySensitive.showAlertDialog( title = generalGetString(MR.strings.connect_plan_connect_to_yourself), - text = generalGetString(MR.strings.connect_plan_this_is_your_own_one_time_link), + text = generalGetString(MR.strings.connect_plan_this_is_your_own_one_time_link) + linkText, confirmText = if (incognito) generalGetString(MR.strings.connect_via_link_incognito) else generalGetString(MR.strings.connect_via_link_verb), - onConfirm = { withApi { connectViaUri(chatModel, rhId, uri, incognito, connectionPlan, close) } }, + onConfirm = { withApi { connectViaUri(chatModel, rhId, uri, incognito, connectionPlan, close, cleanup) } }, + onDismiss = cleanup, + onDismissRequest = cleanup, destructive = true, hostDevice = hostDevice(rhId), ) @@ -70,8 +66,9 @@ suspend fun planAndConnect( askCurrentOrIncognitoProfileAlert( chatModel, rhId, uri, connectionPlan, close, title = generalGetString(MR.strings.connect_plan_connect_to_yourself), - text = AnnotatedString(generalGetString(MR.strings.connect_plan_this_is_your_own_one_time_link)), - connectDestructive = true + text = generalGetString(MR.strings.connect_plan_this_is_your_own_one_time_link) + linkText, + connectDestructive = true, + cleanup = cleanup, ) } } @@ -79,42 +76,54 @@ suspend fun planAndConnect( Log.d(TAG, "planAndConnect, .InvitationLink, .Connecting, incognito=$incognito") val contact = connectionPlan.invitationLinkPlan.contact_ if (contact != null) { - openKnownContact(chatModel, rhId, close, contact) - AlertManager.privacySensitive.showAlertMsg( - generalGetString(MR.strings.contact_already_exists), - String.format(generalGetString(MR.strings.connect_plan_you_are_already_connecting_to_vName), contact.displayName), - hostDevice = hostDevice(rhId), - ) + if (filterKnownContact != null) { + filterKnownContact(contact) + } else { + openKnownContact(chatModel, rhId, close, contact) + AlertManager.privacySensitive.showAlertMsg( + generalGetString(MR.strings.contact_already_exists), + String.format(generalGetString(MR.strings.connect_plan_you_are_already_connecting_to_vName), contact.displayName) + linkText, + hostDevice = hostDevice(rhId), + ) + cleanup?.invoke() + } } else { AlertManager.privacySensitive.showAlertMsg( generalGetString(MR.strings.connect_plan_already_connecting), - generalGetString(MR.strings.connect_plan_you_are_already_connecting_via_this_one_time_link), + generalGetString(MR.strings.connect_plan_you_are_already_connecting_via_this_one_time_link) + linkText, hostDevice = hostDevice(rhId), ) + cleanup?.invoke() } } is InvitationLinkPlan.Known -> { Log.d(TAG, "planAndConnect, .InvitationLink, .Known, incognito=$incognito") val contact = connectionPlan.invitationLinkPlan.contact - openKnownContact(chatModel, rhId, close, contact) - AlertManager.privacySensitive.showAlertMsg( - generalGetString(MR.strings.contact_already_exists), - String.format(generalGetString(MR.strings.you_are_already_connected_to_vName_via_this_link), contact.displayName), - hostDevice = hostDevice(rhId), - ) + if (filterKnownContact != null) { + filterKnownContact(contact) + } else { + openKnownContact(chatModel, rhId, close, contact) + AlertManager.privacySensitive.showAlertMsg( + generalGetString(MR.strings.contact_already_exists), + String.format(generalGetString(MR.strings.you_are_already_connected_to_vName_via_this_link), contact.displayName) + linkText, + hostDevice = hostDevice(rhId), + ) + cleanup?.invoke() + } } } is ConnectionPlan.ContactAddress -> when (connectionPlan.contactAddressPlan) { ContactAddressPlan.Ok -> { Log.d(TAG, "planAndConnect, .ContactAddress, .Ok, incognito=$incognito") if (incognito != null) { - connectViaUri(chatModel, rhId, uri, incognito, connectionPlan, close) + connectViaUri(chatModel, rhId, uri, incognito, connectionPlan, close, cleanup) } else { askCurrentOrIncognitoProfileAlert( chatModel, rhId, uri, connectionPlan, close, title = generalGetString(MR.strings.connect_via_contact_link), - text = AnnotatedString(generalGetString(MR.strings.profile_will_be_sent_to_contact_sending_link)), - connectDestructive = false + text = generalGetString(MR.strings.profile_will_be_sent_to_contact_sending_link) + linkText, + connectDestructive = false, + cleanup, ) } } @@ -123,18 +132,21 @@ suspend fun planAndConnect( if (incognito != null) { AlertManager.privacySensitive.showAlertDialog( title = generalGetString(MR.strings.connect_plan_connect_to_yourself), - text = generalGetString(MR.strings.connect_plan_this_is_your_own_simplex_address), + text = generalGetString(MR.strings.connect_plan_this_is_your_own_simplex_address) + linkText, confirmText = if (incognito) generalGetString(MR.strings.connect_via_link_incognito) else generalGetString(MR.strings.connect_via_link_verb), - onConfirm = { withApi { connectViaUri(chatModel, rhId, uri, incognito, connectionPlan, close) } }, + onConfirm = { withApi { connectViaUri(chatModel, rhId, uri, incognito, connectionPlan, close, cleanup) } }, destructive = true, + onDismiss = cleanup, + onDismissRequest = cleanup, hostDevice = hostDevice(rhId), ) } else { askCurrentOrIncognitoProfileAlert( chatModel, rhId, uri, connectionPlan, close, title = generalGetString(MR.strings.connect_plan_connect_to_yourself), - text = AnnotatedString(generalGetString(MR.strings.connect_plan_this_is_your_own_simplex_address)), - connectDestructive = true + text = generalGetString(MR.strings.connect_plan_this_is_your_own_simplex_address) + linkText, + connectDestructive = true, + cleanup = cleanup, ) } } @@ -143,9 +155,11 @@ suspend fun planAndConnect( if (incognito != null) { AlertManager.privacySensitive.showAlertDialog( title = generalGetString(MR.strings.connect_plan_repeat_connection_request), - text = generalGetString(MR.strings.connect_plan_you_have_already_requested_connection_via_this_address), + text = generalGetString(MR.strings.connect_plan_you_have_already_requested_connection_via_this_address) + linkText, confirmText = if (incognito) generalGetString(MR.strings.connect_via_link_incognito) else generalGetString(MR.strings.connect_via_link_verb), - onConfirm = { withApi { connectViaUri(chatModel, rhId, uri, incognito, connectionPlan, close) } }, + onConfirm = { withApi { connectViaUri(chatModel, rhId, uri, incognito, connectionPlan, close, cleanup) } }, + onDismiss = cleanup, + onDismissRequest = cleanup, destructive = true, hostDevice = hostDevice(rhId), ) @@ -153,30 +167,41 @@ suspend fun planAndConnect( askCurrentOrIncognitoProfileAlert( chatModel, rhId, uri, connectionPlan, close, title = generalGetString(MR.strings.connect_plan_repeat_connection_request), - text = AnnotatedString(generalGetString(MR.strings.connect_plan_you_have_already_requested_connection_via_this_address)), - connectDestructive = true + text = generalGetString(MR.strings.connect_plan_you_have_already_requested_connection_via_this_address) + linkText, + connectDestructive = true, + cleanup = cleanup, ) } } is ContactAddressPlan.ConnectingProhibit -> { Log.d(TAG, "planAndConnect, .ContactAddress, .ConnectingProhibit, incognito=$incognito") val contact = connectionPlan.contactAddressPlan.contact - openKnownContact(chatModel, rhId, close, contact) - AlertManager.privacySensitive.showAlertMsg( - generalGetString(MR.strings.contact_already_exists), - String.format(generalGetString(MR.strings.connect_plan_you_are_already_connecting_to_vName), contact.displayName), - hostDevice = hostDevice(rhId), - ) + if (filterKnownContact != null) { + filterKnownContact(contact) + } else { + openKnownContact(chatModel, rhId, close, contact) + AlertManager.privacySensitive.showAlertMsg( + generalGetString(MR.strings.contact_already_exists), + String.format(generalGetString(MR.strings.connect_plan_you_are_already_connecting_to_vName), contact.displayName) + linkText, + hostDevice = hostDevice(rhId), + ) + cleanup?.invoke() + } } is ContactAddressPlan.Known -> { Log.d(TAG, "planAndConnect, .ContactAddress, .Known, incognito=$incognito") val contact = connectionPlan.contactAddressPlan.contact - openKnownContact(chatModel, rhId, close, contact) - AlertManager.privacySensitive.showAlertMsg( - generalGetString(MR.strings.contact_already_exists), - String.format(generalGetString(MR.strings.you_are_already_connected_to_vName_via_this_link), contact.displayName), - hostDevice = hostDevice(rhId), - ) + if (filterKnownContact != null) { + filterKnownContact(contact) + } else { + openKnownContact(chatModel, rhId, close, contact) + AlertManager.privacySensitive.showAlertMsg( + generalGetString(MR.strings.contact_already_exists), + String.format(generalGetString(MR.strings.you_are_already_connected_to_vName_via_this_link), contact.displayName) + linkText, + hostDevice = hostDevice(rhId), + ) + cleanup?.invoke() + } } is ContactAddressPlan.ContactViaAddress -> { Log.d(TAG, "planAndConnect, .ContactAddress, .ContactViaAddress, incognito=$incognito") @@ -187,6 +212,7 @@ suspend fun planAndConnect( } else { askCurrentOrIncognitoProfileConnectContactViaAddress(chatModel, rhId, contact, close, openChat = false) } + cleanup?.invoke() } } is ConnectionPlan.GroupLink -> when (connectionPlan.groupLinkPlan) { @@ -195,33 +221,42 @@ suspend fun planAndConnect( if (incognito != null) { AlertManager.privacySensitive.showAlertDialog( title = generalGetString(MR.strings.connect_via_group_link), - text = generalGetString(MR.strings.you_will_join_group), + text = generalGetString(MR.strings.you_will_join_group) + linkText, confirmText = if (incognito) generalGetString(MR.strings.join_group_incognito_button) else generalGetString(MR.strings.join_group_button), - onConfirm = { withApi { connectViaUri(chatModel, rhId, uri, incognito, connectionPlan, close) } }, + onConfirm = { withApi { connectViaUri(chatModel, rhId, uri, incognito, connectionPlan, close, cleanup) } }, + onDismiss = cleanup, + onDismissRequest = cleanup, hostDevice = hostDevice(rhId), ) } else { askCurrentOrIncognitoProfileAlert( chatModel, rhId, uri, connectionPlan, close, title = generalGetString(MR.strings.connect_via_group_link), - text = AnnotatedString(generalGetString(MR.strings.you_will_join_group)), - connectDestructive = false + text = generalGetString(MR.strings.you_will_join_group) + linkText, + connectDestructive = false, + cleanup = cleanup, ) } } is GroupLinkPlan.OwnLink -> { Log.d(TAG, "planAndConnect, .GroupLink, .OwnLink, incognito=$incognito") val groupInfo = connectionPlan.groupLinkPlan.groupInfo - ownGroupLinkConfirmConnect(chatModel, rhId, uri, incognito, connectionPlan, groupInfo, close) + if (filterKnownGroup != null) { + filterKnownGroup(groupInfo) + } else { + ownGroupLinkConfirmConnect(chatModel, rhId, uri, linkText, incognito, connectionPlan, groupInfo, close, cleanup) + } } GroupLinkPlan.ConnectingConfirmReconnect -> { Log.d(TAG, "planAndConnect, .GroupLink, .ConnectingConfirmReconnect, incognito=$incognito") if (incognito != null) { AlertManager.privacySensitive.showAlertDialog( title = generalGetString(MR.strings.connect_plan_repeat_join_request), - text = generalGetString(MR.strings.connect_plan_you_are_already_joining_the_group_via_this_link), + text = generalGetString(MR.strings.connect_plan_you_are_already_joining_the_group_via_this_link) + linkText, confirmText = if (incognito) generalGetString(MR.strings.join_group_incognito_button) else generalGetString(MR.strings.join_group_button), - onConfirm = { withApi { connectViaUri(chatModel, rhId, uri, incognito, connectionPlan, close) } }, + onConfirm = { withApi { connectViaUri(chatModel, rhId, uri, incognito, connectionPlan, close, cleanup) } }, + onDismiss = cleanup, + onDismissRequest = cleanup, destructive = true, hostDevice = hostDevice(rhId), ) @@ -229,8 +264,9 @@ suspend fun planAndConnect( askCurrentOrIncognitoProfileAlert( chatModel, rhId, uri, connectionPlan, close, title = generalGetString(MR.strings.connect_plan_repeat_join_request), - text = AnnotatedString(generalGetString(MR.strings.connect_plan_you_are_already_joining_the_group_via_this_link)), - connectDestructive = true + text = generalGetString(MR.strings.connect_plan_you_are_already_joining_the_group_via_this_link) + linkText, + connectDestructive = true, + cleanup = cleanup, ) } } @@ -240,37 +276,44 @@ suspend fun planAndConnect( if (groupInfo != null) { AlertManager.privacySensitive.showAlertMsg( generalGetString(MR.strings.connect_plan_group_already_exists), - String.format(generalGetString(MR.strings.connect_plan_you_are_already_joining_the_group_vName), groupInfo.displayName) + String.format(generalGetString(MR.strings.connect_plan_you_are_already_joining_the_group_vName), groupInfo.displayName) + linkText ) } else { AlertManager.privacySensitive.showAlertMsg( generalGetString(MR.strings.connect_plan_already_joining_the_group), - generalGetString(MR.strings.connect_plan_you_are_already_joining_the_group_via_this_link), + generalGetString(MR.strings.connect_plan_you_are_already_joining_the_group_via_this_link) + linkText, hostDevice = hostDevice(rhId), ) } + cleanup?.invoke() } is GroupLinkPlan.Known -> { Log.d(TAG, "planAndConnect, .GroupLink, .Known, incognito=$incognito") val groupInfo = connectionPlan.groupLinkPlan.groupInfo - openKnownGroup(chatModel, rhId, close, groupInfo) - AlertManager.privacySensitive.showAlertMsg( - generalGetString(MR.strings.connect_plan_group_already_exists), - String.format(generalGetString(MR.strings.connect_plan_you_are_already_in_group_vName), groupInfo.displayName), - hostDevice = hostDevice(rhId), - ) + if (filterKnownGroup != null) { + filterKnownGroup(groupInfo) + } else { + openKnownGroup(chatModel, rhId, close, groupInfo) + AlertManager.privacySensitive.showAlertMsg( + generalGetString(MR.strings.connect_plan_group_already_exists), + String.format(generalGetString(MR.strings.connect_plan_you_are_already_in_group_vName), groupInfo.displayName) + linkText, + hostDevice = hostDevice(rhId), + ) + cleanup?.invoke() + } } } } } else { Log.d(TAG, "planAndConnect, plan error") if (incognito != null) { - connectViaUri(chatModel, rhId, uri, incognito, connectionPlan = null, close) + connectViaUri(chatModel, rhId, uri, incognito, connectionPlan = null, close, cleanup) } else { askCurrentOrIncognitoProfileAlert( chatModel, rhId, uri, connectionPlan = null, close, title = generalGetString(MR.strings.connect_plan_connect_via_link), - connectDestructive = false + connectDestructive = false, + cleanup = cleanup, ) } } @@ -282,7 +325,8 @@ suspend fun connectViaUri( uri: URI, incognito: Boolean, connectionPlan: ConnectionPlan?, - close: (() -> Unit)? + close: (() -> Unit)?, + cleanup: (() -> Unit)?, ) { val pcc = chatModel.controller.apiConnect(rhId, incognito, uri.toString()) val connLinkType = if (connectionPlan != null) planToConnectionLinkType(connectionPlan) else ConnectionLinkType.INVITATION @@ -300,6 +344,7 @@ suspend fun connectViaUri( hostDevice = hostDevice(rhId), ) } + cleanup?.invoke() } fun planToConnectionLinkType(connectionPlan: ConnectionPlan): ConnectionLinkType { @@ -317,8 +362,9 @@ fun askCurrentOrIncognitoProfileAlert( connectionPlan: ConnectionPlan?, close: (() -> Unit)?, title: String, - text: AnnotatedString? = null, + text: String? = null, connectDestructive: Boolean, + cleanup: (() -> Unit)?, ) { AlertManager.privacySensitive.showAlertDialogButtonsColumn( title = title, @@ -329,7 +375,7 @@ fun askCurrentOrIncognitoProfileAlert( SectionItemView({ AlertManager.privacySensitive.hideAlert() withApi { - connectViaUri(chatModel, rhId, uri, incognito = false, connectionPlan, close) + connectViaUri(chatModel, rhId, uri, incognito = false, connectionPlan, close, cleanup) } }) { Text(generalGetString(MR.strings.connect_use_current_profile), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = connectColor) @@ -337,18 +383,20 @@ fun askCurrentOrIncognitoProfileAlert( SectionItemView({ AlertManager.privacySensitive.hideAlert() withApi { - connectViaUri(chatModel, rhId, uri, incognito = true, connectionPlan, close) + connectViaUri(chatModel, rhId, uri, incognito = true, connectionPlan, close, cleanup) } }) { Text(generalGetString(MR.strings.connect_use_new_incognito_profile), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = connectColor) } SectionItemView({ AlertManager.privacySensitive.hideAlert() + cleanup?.invoke() }) { Text(stringResource(MR.strings.cancel_verb), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.primary) } } }, + onDismissRequest = cleanup, hostDevice = hostDevice(rhId), ) } @@ -367,20 +415,23 @@ fun ownGroupLinkConfirmConnect( chatModel: ChatModel, rhId: Long?, uri: URI, + linkText: String, incognito: Boolean?, connectionPlan: ConnectionPlan?, groupInfo: GroupInfo, close: (() -> Unit)?, + cleanup: (() -> Unit)?, ) { AlertManager.privacySensitive.showAlertDialogButtonsColumn( title = generalGetString(MR.strings.connect_plan_join_your_group), - text = AnnotatedString(String.format(generalGetString(MR.strings.connect_plan_this_is_your_link_for_group_vName), groupInfo.displayName)), + text = String.format(generalGetString(MR.strings.connect_plan_this_is_your_link_for_group_vName), groupInfo.displayName) + linkText, buttons = { Column { // Open group SectionItemView({ AlertManager.privacySensitive.hideAlert() openKnownGroup(chatModel, rhId, close, groupInfo) + cleanup?.invoke() }) { Text(generalGetString(MR.strings.connect_plan_open_group), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.primary) } @@ -389,7 +440,7 @@ fun ownGroupLinkConfirmConnect( SectionItemView({ AlertManager.privacySensitive.hideAlert() withApi { - connectViaUri(chatModel, rhId, uri, incognito, connectionPlan, close) + connectViaUri(chatModel, rhId, uri, incognito, connectionPlan, close, cleanup) } }) { Text( @@ -402,7 +453,7 @@ fun ownGroupLinkConfirmConnect( SectionItemView({ AlertManager.privacySensitive.hideAlert() withApi { - connectViaUri(chatModel, rhId, uri, incognito = false, connectionPlan, close) + connectViaUri(chatModel, rhId, uri, incognito = false, connectionPlan, close, cleanup) } }) { Text(generalGetString(MR.strings.connect_use_current_profile), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.error) @@ -411,7 +462,7 @@ fun ownGroupLinkConfirmConnect( SectionItemView({ AlertManager.privacySensitive.hideAlert() withApi { - connectViaUri(chatModel, rhId, uri, incognito = true, connectionPlan, close) + connectViaUri(chatModel, rhId, uri, incognito = true, connectionPlan, close, cleanup) } }) { Text(generalGetString(MR.strings.connect_use_new_incognito_profile), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.error) @@ -420,11 +471,13 @@ fun ownGroupLinkConfirmConnect( // Cancel SectionItemView({ AlertManager.privacySensitive.hideAlert() + cleanup?.invoke() }) { Text(stringResource(MR.strings.cancel_verb), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.primary) } } }, + onDismissRequest = cleanup, hostDevice = hostDevice(rhId), ) } @@ -438,77 +491,3 @@ fun openKnownGroup(chatModel: ChatModel, rhId: Long?, close: (() -> Unit)?, grou } } } - -@Composable -fun ConnectContactLayout( - chatModel: ChatModel, - rh: RemoteHostInfo?, - incognitoPref: SharedPreference, - close: () -> Unit -) { - val incognito = remember { mutableStateOf(incognitoPref.get()) } - - @Composable - fun QRCodeScanner(close: () -> Unit) { - QRCodeScanner { connReqUri -> - try { - val uri = URI(connReqUri) - withApi { - planAndConnect(chatModel, rh?.remoteHostId, uri, incognito = incognito.value, close) - } - } catch (e: RuntimeException) { - AlertManager.shared.showAlertMsg( - title = generalGetString(MR.strings.invalid_QR_code), - text = generalGetString(MR.strings.this_QR_code_is_not_a_link) - ) - } - } - } - - Column( - Modifier.verticalScroll(rememberScrollState()).padding(horizontal = DEFAULT_PADDING), - verticalArrangement = Arrangement.SpaceBetween - ) { - AppBarTitle(stringResource(MR.strings.scan_QR_code), hostDevice(rh?.remoteHostId), withPadding = false) - Box( - Modifier - .fillMaxWidth() - .aspectRatio(ratio = 1F) - .padding(bottom = 12.dp) - ) { QRCodeScanner(close) } - - IncognitoToggle(incognitoPref, incognito) { ModalManager.start.showModal { IncognitoView() } } - - SectionTextFooter( - buildAnnotatedString { - append(sharedProfileInfo(chatModel, incognito.value)) - append("\n\n") - append(annotatedStringResource(MR.strings.if_you_cannot_meet_in_person_scan_QR_in_video_call_or_ask_for_invitation_link)) - } - ) - - SectionBottomSpacer() - } -} - -fun URI.getQueryParameter(param: String): String? { - if (!query.contains("$param=")) return null - return query.substringAfter("$param=").substringBefore("&") -} - -@Preview/*( - uiMode = Configuration.UI_MODE_NIGHT_YES, - showBackground = true, - name = "Dark Mode" -)*/ -@Composable -fun PreviewConnectContactLayout() { - SimpleXTheme { - ConnectContactLayout( - chatModel = ChatModel, - rh = null, - incognitoPref = SharedPreference({ false }, {}), - close = {}, - ) - } -} diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/ConnectViaLinkView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/ConnectViaLinkView.kt deleted file mode 100644 index 0077e2849c..0000000000 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/ConnectViaLinkView.kt +++ /dev/null @@ -1,12 +0,0 @@ -package chat.simplex.common.views.newchat - -import androidx.compose.runtime.* -import chat.simplex.common.model.ChatModel -import chat.simplex.common.model.RemoteHostInfo - -enum class ConnectViaLinkTab { - SCAN, PASTE -} - -@Composable -expect fun ConnectViaLinkView(m: ChatModel, rh: RemoteHostInfo?, close: () -> Unit) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/ContactConnectionInfoView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/ContactConnectionInfoView.kt index 5e9495e866..7fa0e6a704 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/ContactConnectionInfoView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/ContactConnectionInfoView.kt @@ -23,7 +23,7 @@ import chat.simplex.common.views.chatlist.deleteContactConnectionAlert import chat.simplex.common.views.helpers.* import chat.simplex.common.model.ChatModel import chat.simplex.common.model.PendingContactConnection -import chat.simplex.common.platform.shareText +import chat.simplex.common.platform.* import chat.simplex.common.views.usersettings.* import chat.simplex.res.MR @@ -37,16 +37,19 @@ fun ContactConnectionInfoView( close: () -> Unit ) { LaunchedEffect(connReqInvitation) { - chatModel.connReqInv.value = connReqInvitation + if (connReqInvitation != null) { + chatModel.showingInvitation.value = ShowingInvitation(contactConnection.id, connReqInvitation, false) + } } - /** When [AddContactView] is open, we don't need to drop [chatModel.connReqInv]. - * Otherwise, it will be called here AFTER [AddContactView] is launched and will clear the value too soon. + /** When [AddContactLearnMore] is open, we don't need to drop [ChatModel.showingInvitation]. + * Otherwise, it will be called here AFTER [AddContactLearnMore] is launched and will clear the value too soon. * It will be dropped automatically when connection established or when user goes away from this screen. + * It applies only to Android because on Desktop center space will not be overlapped by [AddContactLearnMore] **/ DisposableEffect(Unit) { onDispose { - if (!ModalManager.center.hasModalsOpen()) { - chatModel.connReqInv.value = null + if (!ModalManager.center.hasModalsOpen() || appPlatform.isDesktop) { + chatModel.showingInvitation.value = null } } } @@ -61,14 +64,14 @@ fun ContactConnectionInfoView( onLocalAliasChanged = { setContactAlias(rhId, contactConnection, it, chatModel) }, share = { if (connReqInvitation != null) clipboard.shareText(connReqInvitation) }, learnMore = { - ModalManager.center.showModal { + ModalManager.end.showModalCloseable { close -> Column( Modifier .fillMaxHeight() .padding(horizontal = DEFAULT_PADDING), verticalArrangement = Arrangement.SpaceBetween ) { - AddContactLearnMore() + AddContactLearnMore(close) } } } @@ -135,11 +138,7 @@ private fun ContactConnectionInfoLayout( SectionView { if (!connReq.isNullOrEmpty() && contactConnection.initiated) { - SimpleXLinkQRCode( - connReq, Modifier - .padding(horizontal = DEFAULT_PADDING, vertical = DEFAULT_PADDING_HALF) - .aspectRatio(1f) - ) + SimpleXLinkQRCode(connReq) incognitoEnabled() ShareLinkButton(connReq) OneTimeLinkLearnMoreButton(learnMore) @@ -158,6 +157,30 @@ private fun ContactConnectionInfoLayout( } } +@Composable +fun ShareLinkButton(connReqInvitation: String) { + val clipboard = LocalClipboardManager.current + SettingsActionItem( + painterResource(MR.images.ic_share), + stringResource(MR.strings.share_invitation_link), + click = { + chatModel.showingInvitation.value = chatModel.showingInvitation.value?.copy(connChatUsed = true) + clipboard.shareText(simplexChatLink(connReqInvitation)) + }, + iconColor = MaterialTheme.colors.primary, + textColor = MaterialTheme.colors.primary, + ) +} + +@Composable +fun OneTimeLinkLearnMoreButton(onClick: () -> Unit) { + SettingsActionItem( + painterResource(MR.images.ic_info), + stringResource(MR.strings.learn_more), + onClick, + ) +} + @Composable fun DeleteButton(onClick: () -> Unit) { SettingsActionItem( diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/CreateLinkView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/CreateLinkView.kt deleted file mode 100644 index 6f3caf4674..0000000000 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/CreateLinkView.kt +++ /dev/null @@ -1,118 +0,0 @@ -package chat.simplex.common.views.newchat - -import androidx.compose.foundation.layout.* -import androidx.compose.material.* -import androidx.compose.runtime.* -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import dev.icerock.moko.resources.compose.painterResource -import dev.icerock.moko.resources.compose.stringResource -import androidx.compose.ui.unit.sp -import chat.simplex.common.model.* -import chat.simplex.common.views.helpers.* -import chat.simplex.common.views.usersettings.UserAddressView -import chat.simplex.res.MR - -enum class CreateLinkTab { - ONE_TIME, LONG_TERM -} - -@Composable -fun CreateLinkView(m: ChatModel, rh: RemoteHostInfo?, initialSelection: CreateLinkTab) { - val selection = remember { mutableStateOf(initialSelection) } - val connReqInvitation = rememberSaveable { m.connReqInv } - val contactConnection: MutableState = rememberSaveable(stateSaver = serializableSaver()) { mutableStateOf(null) } - val creatingConnReq = rememberSaveable { mutableStateOf(false) } - LaunchedEffect(selection.value) { - if ( - selection.value == CreateLinkTab.ONE_TIME - && connReqInvitation.value.isNullOrEmpty() - && contactConnection.value == null - && !creatingConnReq.value - ) { - createInvitation(m, rh?.remoteHostId, creatingConnReq, connReqInvitation, contactConnection) - } - } - /** When [AddContactView] is open, we don't need to drop [chatModel.connReqInv]. - * Otherwise, it will be called here AFTER [AddContactView] is launched and will clear the value too soon. - * It will be dropped automatically when connection established or when user goes away from this screen. - **/ - DisposableEffect(Unit) { - onDispose { - if (!ModalManager.center.hasModalsOpen()) { - m.connReqInv.value = null - } - } - } - val tabTitles = CreateLinkTab.values().map { - when { - it == CreateLinkTab.ONE_TIME && connReqInvitation.value.isNullOrEmpty() && contactConnection.value == null -> - stringResource(MR.strings.create_one_time_link) - it == CreateLinkTab.ONE_TIME -> - stringResource(MR.strings.one_time_link) - it == CreateLinkTab.LONG_TERM -> - stringResource(MR.strings.your_simplex_contact_address) - else -> "" - } - } - Column( - Modifier - .fillMaxHeight(), - verticalArrangement = Arrangement.SpaceBetween - ) { - Column(Modifier.weight(1f)) { - when (selection.value) { - CreateLinkTab.ONE_TIME -> { - AddContactView(m, rh,connReqInvitation.value ?: "", contactConnection) - } - CreateLinkTab.LONG_TERM -> { - UserAddressView(m, viaCreateLinkView = true, close = {}) - } - } - } - TabRow( - selectedTabIndex = selection.value.ordinal, - backgroundColor = Color.Transparent, - contentColor = MaterialTheme.colors.primary, - ) { - tabTitles.forEachIndexed { index, it -> - Tab( - selected = selection.value.ordinal == index, - onClick = { - selection.value = CreateLinkTab.values()[index] - }, - text = { Text(it, fontSize = 13.sp) }, - icon = { - Icon( - if (CreateLinkTab.ONE_TIME.ordinal == index) painterResource(MR.images.ic_repeat_one) else painterResource(MR.images.ic_all_inclusive), - it - ) - }, - selectedContentColor = MaterialTheme.colors.primary, - unselectedContentColor = MaterialTheme.colors.secondary, - ) - } - } - } -} - -private fun createInvitation( - m: ChatModel, - rhId: Long?, - creatingConnReq: MutableState, - connReqInvitation: MutableState, - contactConnection: MutableState -) { - creatingConnReq.value = true - withApi { - val r = m.controller.apiAddContact(rhId, incognito = m.controller.appPrefs.incognito.get()) - if (r != null) { - m.updateContactConnection(rhId, r.second) - connReqInvitation.value = r.first - contactConnection.value = r.second - } else { - creatingConnReq.value = false - } - } -} diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatSheet.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatSheet.kt index 86929584c1..f2f2e9ec5f 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatSheet.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatSheet.kt @@ -42,12 +42,7 @@ fun NewChatSheet(chatModel: ChatModel, newChatSheetState: StateFlow ConnectViaLinkView(chatModel, chatModel.currentRemoteHost.value, close) } + ModalManager.center.showModalCloseable { close -> NewChatView(chatModel.currentRemoteHost.value, NewChatOption.INVITE, close = close) } }, createGroup = { closeNewChatSheet(false) @@ -59,18 +54,16 @@ fun NewChatSheet(chatModel: ChatModel, newChatSheetState: StateFlow, stopped: Boolean, addContact: () -> Unit, - connectViaLink: () -> Unit, createGroup: () -> Unit, closeNewChatSheet: (animated: Boolean) -> Unit, ) { @@ -109,7 +102,7 @@ private fun NewChatSheetLayout( verticalArrangement = Arrangement.Bottom, horizontalAlignment = Alignment.End ) { - val actions = remember { listOf(addContact, connectViaLink, createGroup) } + val actions = remember { listOf(addContact, createGroup) } val backgroundColor = if (isInDarkTheme()) blendARGB(MaterialTheme.colors.primary, Color.Black, 0.7F) else @@ -271,7 +264,6 @@ private fun PreviewNewChatSheet() { MutableStateFlow(AnimatedViewState.VISIBLE), stopped = false, addContact = {}, - connectViaLink = {}, createGroup = {}, closeNewChatSheet = {}, ) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatView.kt new file mode 100644 index 0000000000..0686f3c861 --- /dev/null +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatView.kt @@ -0,0 +1,436 @@ +package chat.simplex.common.views.newchat + +import SectionBottomSpacer +import SectionItemView +import SectionTextFooter +import SectionView +import androidx.compose.foundation.* +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.pager.HorizontalPager +import androidx.compose.foundation.pager.rememberPagerState +import androidx.compose.foundation.text.BasicTextField +import androidx.compose.material.* +import androidx.compose.runtime.* +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalClipboardManager +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.input.VisualTransformation +import androidx.compose.ui.unit.dp +import dev.icerock.moko.resources.compose.painterResource +import dev.icerock.moko.resources.compose.stringResource +import androidx.compose.ui.unit.sp +import chat.simplex.common.model.* +import chat.simplex.common.model.ChatModel.controller +import chat.simplex.common.platform.* +import chat.simplex.common.ui.theme.* +import chat.simplex.common.views.helpers.* +import chat.simplex.common.views.usersettings.* +import chat.simplex.res.MR +import kotlinx.coroutines.launch +import java.net.URI + +enum class NewChatOption { + INVITE, CONNECT +} + +@Composable +fun ModalData.NewChatView(rh: RemoteHostInfo?, selection: NewChatOption, showQRCodeScanner: Boolean = false, close: () -> Unit) { + val selection = remember { stateGetOrPut("selection") { selection } } + val showQRCodeScanner = remember { stateGetOrPut("showQRCodeScanner") { showQRCodeScanner } } + val contactConnection: MutableState = rememberSaveable(stateSaver = serializableSaver()) { mutableStateOf(null) } + val connReqInvitation by remember { derivedStateOf { chatModel.showingInvitation.value?.connReq ?: "" } } + val creatingConnReq = rememberSaveable { mutableStateOf(false) } + val pastedLink = rememberSaveable { mutableStateOf("") } + LaunchedEffect(selection.value) { + if ( + selection.value == NewChatOption.INVITE + && connReqInvitation.isEmpty() + && contactConnection.value == null + && !creatingConnReq.value + ) { + createInvitation(rh?.remoteHostId, creatingConnReq, connReqInvitation, contactConnection) + } + } + DisposableEffect(Unit) { + onDispose { + /** When [AddContactLearnMore] is open, we don't need to drop [ChatModel.showingInvitation]. + * Otherwise, it will be called here AFTER [AddContactLearnMore] is launched and will clear the value too soon. + * It will be dropped automatically when connection established or when user goes away from this screen. + * It applies only to Android because on Desktop center space will not be overlapped by [AddContactLearnMore] + **/ + if (chatModel.showingInvitation.value != null && (!ModalManager.center.hasModalsOpen() || appPlatform.isDesktop)) { + val conn = contactConnection.value + if (chatModel.showingInvitation.value?.connChatUsed == false && conn != null) { + AlertManager.shared.showAlertDialog( + title = generalGetString(MR.strings.keep_unused_invitation_question), + text = generalGetString(MR.strings.you_can_view_invitation_link_again), + confirmText = generalGetString(MR.strings.delete_verb), + dismissText = generalGetString(MR.strings.keep_invitation_link), + destructive = true, + onConfirm = { + withBGApi { + val chatInfo = ChatInfo.ContactConnection(conn) + controller.deleteChat(Chat(remoteHostId = rh?.remoteHostId, chatInfo = chatInfo, chatItems = listOf())) + if (chatModel.chatId.value == chatInfo.id) { + chatModel.chatId.value = null + ModalManager.end.closeModals() + } + } + } + ) + } + chatModel.showingInvitation.value = null + } + } + } + val tabTitles = NewChatOption.values().map { + when(it) { + NewChatOption.INVITE -> + stringResource(MR.strings.add_contact_tab) + NewChatOption.CONNECT -> + stringResource(MR.strings.connect_via_link) + } + } + + Column( + Modifier.fillMaxSize(), + ) { + Box(contentAlignment = Alignment.Center) { + val bottomPadding = DEFAULT_PADDING + AppBarTitle(stringResource(MR.strings.new_chat), hostDevice(rh?.remoteHostId), bottomPadding = bottomPadding) + Column(Modifier.align(Alignment.CenterEnd).padding(bottom = bottomPadding, end = DEFAULT_PADDING)) { + AddContactLearnMoreButton() + } + } + val scope = rememberCoroutineScope() + val pagerState = rememberPagerState( + initialPage = selection.value.ordinal, + initialPageOffsetFraction = 0f + ) { NewChatOption.values().size } + KeyChangeEffect(pagerState.currentPage) { + selection.value = NewChatOption.values()[pagerState.currentPage] + } + TabRow( + selectedTabIndex = pagerState.currentPage, + backgroundColor = Color.Transparent, + contentColor = MaterialTheme.colors.primary, + ) { + tabTitles.forEachIndexed { index, it -> + LeadingIconTab( + selected = pagerState.currentPage == index, + onClick = { + scope.launch { + pagerState.animateScrollToPage(index) + } + }, + text = { Text(it, fontSize = 13.sp) }, + icon = { + Icon( + if (NewChatOption.INVITE.ordinal == index) painterResource(MR.images.ic_repeat_one) else painterResource(MR.images.ic_qr_code), + it + ) + }, + selectedContentColor = MaterialTheme.colors.primary, + unselectedContentColor = MaterialTheme.colors.secondary, + ) + } + } + + HorizontalPager(state = pagerState, Modifier.fillMaxSize(), verticalAlignment = Alignment.Top) { index -> + Column( + Modifier + .fillMaxSize() + .verticalScroll(rememberScrollState()), + verticalArrangement = if (index == NewChatOption.INVITE.ordinal && connReqInvitation.isEmpty()) Arrangement.Center else Arrangement.Top) { + Spacer(Modifier.height(DEFAULT_PADDING)) + when (index) { + NewChatOption.INVITE.ordinal -> { + PrepareAndInviteView(rh?.remoteHostId, contactConnection, connReqInvitation, creatingConnReq) + } + NewChatOption.CONNECT.ordinal -> { + ConnectView(rh?.remoteHostId, showQRCodeScanner, pastedLink, close) + } + } + SectionBottomSpacer() + } + } + } +} + +@Composable +private fun PrepareAndInviteView(rhId: Long?, contactConnection: MutableState, connReqInvitation: String, creatingConnReq: MutableState) { + if (connReqInvitation.isNotEmpty()) { + InviteView( + rhId, + connReqInvitation = connReqInvitation, + contactConnection = contactConnection, + ) + } else if (creatingConnReq.value) { + CreatingLinkProgressView() + } else { + RetryButton { createInvitation(rhId, creatingConnReq, connReqInvitation, contactConnection) } + } +} + +@Composable +private fun CreatingLinkProgressView() { + DefaultProgressView(stringResource(MR.strings.creating_link)) +} + +@Composable +private fun RetryButton(onClick: () -> Unit) { + Column( + Modifier.fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + IconButton(onClick, Modifier.size(30.dp)) { + Icon(painterResource(MR.images.ic_refresh), null) + } + Spacer(Modifier.height(DEFAULT_PADDING)) + Text(stringResource(MR.strings.retry_verb)) + } +} + +@Composable +private fun InviteView(rhId: Long?, connReqInvitation: String, contactConnection: MutableState) { + SectionView(stringResource(MR.strings.share_this_1_time_link).uppercase()) { + LinkTextView(connReqInvitation, true) + } + + Spacer(Modifier.height(10.dp)) + + SectionView(stringResource(MR.strings.or_show_this_qr_code).uppercase()) { + SimpleXLinkQRCode(connReqInvitation, onShare = { chatModel.markShowingInvitationUsed() }) + } + + Spacer(Modifier.height(10.dp)) + val incognito = remember { mutableStateOf(controller.appPrefs.incognito.get()) } + IncognitoToggle(controller.appPrefs.incognito, incognito) { + if (appPlatform.isDesktop) ModalManager.end.closeModals() + ModalManager.end.showModal { IncognitoView() } + } + KeyChangeEffect(incognito.value) { + withBGApi { + val contactConn = contactConnection.value ?: return@withBGApi + val conn = controller.apiSetConnectionIncognito(rhId, contactConn.pccConnId, incognito.value) ?: return@withBGApi + contactConnection.value = conn + chatModel.updateContactConnection(rhId, conn) + } + chatModel.markShowingInvitationUsed() + } + SectionTextFooter(sharedProfileInfo(chatModel, incognito.value)) +} + +@Composable +private fun AddContactLearnMoreButton() { + IconButton( + { + if (appPlatform.isDesktop) ModalManager.end.closeModals() + ModalManager.end.showModalCloseable { close -> + Column( + Modifier + .fillMaxHeight() + .padding(horizontal = DEFAULT_PADDING), + verticalArrangement = Arrangement.SpaceBetween + ) { + AddContactLearnMore(close) + } + } + } + ) { + Icon( + painterResource(MR.images.ic_info), + stringResource(MR.strings.learn_more), + ) + } +} + +@Composable +private fun ConnectView(rhId: Long?, showQRCodeScanner: MutableState, pastedLink: MutableState, close: () -> Unit) { + SectionView(stringResource(MR.strings.paste_the_link_you_received).uppercase()) { + PasteLinkView(rhId, pastedLink, showQRCodeScanner, close) + } + + if (appPlatform.isAndroid) { + Spacer(Modifier.height(10.dp)) + + SectionView(stringResource(MR.strings.or_scan_qr_code).uppercase()) { + QRCodeScanner(showQRCodeScanner) { text -> + withBGApi { + val res = verify(rhId, text, close) + if (!res) { + AlertManager.shared.showAlertMsg( + title = generalGetString(MR.strings.invalid_qr_code), + text = generalGetString(MR.strings.code_you_scanned_is_not_simplex_link_qr_code) + ) + } + } + } + } + } +} + +@Composable +private fun PasteLinkView(rhId: Long?, pastedLink: MutableState, showQRCodeScanner: MutableState, close: () -> Unit) { + if (pastedLink.value.isEmpty()) { + val clipboard = LocalClipboardManager.current + SectionItemView({ + val str = clipboard.getText()?.text ?: return@SectionItemView + val link = strHasSingleSimplexLink(str.trim()) + if (link != null) { + pastedLink.value = link.text + showQRCodeScanner.value = false + withBGApi { connect(rhId, link.text, close) { pastedLink.value = "" } } + } else { + AlertManager.shared.showAlertMsg( + title = generalGetString(MR.strings.invalid_contact_link), + text = generalGetString(MR.strings.the_text_you_pasted_is_not_a_link) + ) + } + }) { + Text(stringResource(MR.strings.tap_to_paste_link)) + } + } else { + LinkTextView(pastedLink.value, false) + } +} + +@Composable +private fun LinkTextView(link: String, share: Boolean) { + val clipboard = LocalClipboardManager.current + Row(Modifier.fillMaxWidth().heightIn(min = 46.dp).padding(horizontal = DEFAULT_PADDING), verticalAlignment = Alignment.CenterVertically) { + Box(Modifier.weight(1f).clickable { + chatModel.markShowingInvitationUsed() + clipboard.shareText(link) + }) { + BasicTextField( + value = link, + onValueChange = { }, + enabled = false, + textStyle = TextStyle(fontSize = 16.sp, color = MaterialTheme.colors.onBackground), + singleLine = true, + decorationBox = @Composable { innerTextField -> + TextFieldDefaults.TextFieldDecorationBox( + value = link, + innerTextField = innerTextField, + contentPadding = PaddingValues(), + label = null, + visualTransformation = VisualTransformation.None, + leadingIcon = null, + trailingIcon = null, + singleLine = true, + enabled = false, + isError = false, + interactionSource = remember { MutableInteractionSource() }, + ) + }) + } + // Element Text() can add ellipsis (...) in random place of the string, sometimes even after half of width of a screen. + // So using BasicTextField + manual ... + Text("…", fontSize = 16.sp) + if (share) { + Spacer(Modifier.width(DEFAULT_PADDING)) + IconButton({ + chatModel.markShowingInvitationUsed() + clipboard.shareText(link) + }, Modifier.size(20.dp)) { + Icon(painterResource(MR.images.ic_share_filled), null, tint = MaterialTheme.colors.primary) + } + } + } +} + +private suspend fun verify(rhId: Long?, text: String?, close: () -> Unit): Boolean { + if (text != null && strIsSimplexLink(text)) { + connect(rhId, text, close) + return true + } + return false +} + +private suspend fun connect(rhId: Long?, link: String, close: () -> Unit, cleanup: (() -> Unit)? = null) { + planAndConnect( + rhId, + URI.create(link), + close = close, + cleanup = cleanup, + incognito = null + ) +} + +private fun createInvitation( + rhId: Long?, + creatingConnReq: MutableState, + connReqInvitation: String, + contactConnection: MutableState +) { + if (connReqInvitation.isNotEmpty() || contactConnection.value != null || creatingConnReq.value) return + creatingConnReq.value = true + withApi { + val (r, alert) = controller.apiAddContact(rhId, incognito = controller.appPrefs.incognito.get()) + if (r != null) { + chatModel.updateContactConnection(rhId, r.second) + chatModel.showingInvitation.value = ShowingInvitation(connId = r.second.id, connReq = simplexChatLink(r.first), connChatUsed = false) + contactConnection.value = r.second + } else { + creatingConnReq.value = false + if (alert != null) { + alert() + } + } + } +} + +fun strIsSimplexLink(str: String): Boolean { + val parsedMd = parseToMarkdown(str) + return parsedMd != null && parsedMd.size == 1 && parsedMd[0].format is Format.SimplexLink +} + +fun strHasSingleSimplexLink(str: String): FormattedText? { + val parsedMd = parseToMarkdown(str) ?: return null + val parsedLinks = parsedMd.filter { it.format?.isSimplexLink ?: false } + if (parsedLinks.size != 1) return null + + return parsedLinks[0] +} + +@Composable +fun IncognitoToggle( + incognitoPref: SharedPreference, + incognito: MutableState, + onClickInfo: () -> Unit +) { + SettingsActionItemWithContent( + icon = if (incognito.value) painterResource(MR.images.ic_theater_comedy_filled) else painterResource(MR.images.ic_theater_comedy), + text = null, + click = onClickInfo, + iconColor = if (incognito.value) Indigo else MaterialTheme.colors.secondary, + extraPadding = false + ) { + SharedPreferenceToggleWithIcon( + stringResource(MR.strings.incognito), + painterResource(MR.images.ic_info), + stopped = false, + onClickInfo = onClickInfo, + preference = incognitoPref, + preferenceState = incognito + ) + } +} + +fun sharedProfileInfo( + chatModel: ChatModel, + incognito: Boolean +): String { + val name = chatModel.currentUser.value?.displayName ?: "" + return if (incognito) { + generalGetString(MR.strings.connect__a_new_random_profile_will_be_shared) + } else { + String.format(generalGetString(MR.strings.connect__your_profile_will_be_shared), name) + } +} diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/PasteToConnect.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/PasteToConnect.kt deleted file mode 100644 index dacf937575..0000000000 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/PasteToConnect.kt +++ /dev/null @@ -1,135 +0,0 @@ -package chat.simplex.common.views.newchat - -import SectionBottomSpacer -import SectionTextFooter -import androidx.compose.desktop.ui.tooling.preview.Preview -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll -import androidx.compose.material.MaterialTheme -import androidx.compose.runtime.* -import androidx.compose.ui.Modifier -import dev.icerock.moko.resources.compose.painterResource -import dev.icerock.moko.resources.compose.stringResource -import androidx.compose.ui.platform.LocalClipboardManager -import androidx.compose.ui.text.buildAnnotatedString -import androidx.compose.ui.unit.dp -import chat.simplex.common.model.* -import chat.simplex.common.ui.theme.* -import chat.simplex.common.views.helpers.* -import chat.simplex.common.views.usersettings.IncognitoView -import chat.simplex.common.views.usersettings.SettingsActionItem -import chat.simplex.res.MR -import java.net.URI - -@Composable -fun PasteToConnectView(chatModel: ChatModel, rh: RemoteHostInfo?, close: () -> Unit) { - val connectionLink = remember { mutableStateOf("") } - val clipboard = LocalClipboardManager.current - PasteToConnectLayout( - chatModel = chatModel, - rh = rh, - incognitoPref = chatModel.controller.appPrefs.incognito, - connectionLink = connectionLink, - pasteFromClipboard = { - connectionLink.value = clipboard.getText()?.text ?: return@PasteToConnectLayout - }, - close = close - ) -} - -@Composable -fun PasteToConnectLayout( - chatModel: ChatModel, - rh: RemoteHostInfo?, - incognitoPref: SharedPreference, - connectionLink: MutableState, - pasteFromClipboard: () -> Unit, - close: () -> Unit -) { - val incognito = remember { mutableStateOf(incognitoPref.get()) } - val rhId = rh?.remoteHostId - fun connectViaLink(connReqUri: String) { - try { - val uri = URI(connReqUri) - withApi { - planAndConnect(chatModel, rhId, uri, incognito = incognito.value, close) - } - } catch (e: RuntimeException) { - AlertManager.shared.showAlertMsg( - title = generalGetString(MR.strings.invalid_connection_link), - text = generalGetString(MR.strings.this_string_is_not_a_connection_link) - ) - } - } - - Column( - Modifier.verticalScroll(rememberScrollState()).padding(horizontal = DEFAULT_PADDING), - verticalArrangement = Arrangement.SpaceBetween, - ) { - AppBarTitle(stringResource(MR.strings.connect_via_link), hostDevice(rhId), withPadding = false) - - Box(Modifier.padding(top = DEFAULT_PADDING, bottom = 6.dp)) { - TextEditor( - connectionLink, - Modifier.height(180.dp), - contentPadding = PaddingValues(), - placeholder = stringResource(MR.strings.paste_the_link_you_received_to_connect_with_your_contact) - ) - } - - if (connectionLink.value == "") { - SettingsActionItem( - painterResource(MR.images.ic_content_paste), - stringResource(MR.strings.paste_button), - click = pasteFromClipboard, - ) - } else { - SettingsActionItem( - painterResource(MR.images.ic_close), - stringResource(MR.strings.clear_verb), - click = { connectionLink.value = "" }, - ) - } - - SettingsActionItem( - painterResource(MR.images.ic_link), - stringResource(MR.strings.connect_button), - click = { connectViaLink(connectionLink.value) }, - textColor = MaterialTheme.colors.primary, - iconColor = MaterialTheme.colors.primary, - disabled = connectionLink.value.isEmpty() || connectionLink.value.trim().contains(" ") - ) - - IncognitoToggle(incognitoPref, incognito) { ModalManager.start.showModal { IncognitoView() } } - - SectionTextFooter( - buildAnnotatedString { - append(sharedProfileInfo(chatModel, incognito.value)) - append("\n\n") - append(annotatedStringResource(MR.strings.you_can_also_connect_by_clicking_the_link)) - } - ) - - SectionBottomSpacer() - } -} - - -@Preview/*( - uiMode = Configuration.UI_MODE_NIGHT_YES, - name = "Dark Mode" -)*/ -@Composable -fun PreviewPasteToConnectTextbox() { - SimpleXTheme { - PasteToConnectLayout( - chatModel = ChatModel, - rh = null, - incognitoPref = SharedPreference({ false }, {}), - connectionLink = remember { mutableStateOf("") }, - pasteFromClipboard = {}, - close = {} - ) - } -} diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/QRCode.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/QRCode.kt index 7f9fae60a3..e38c983487 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/QRCode.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/QRCode.kt @@ -14,7 +14,7 @@ import boofcv.alg.drawing.FiducialImageEngine import boofcv.alg.fiducial.qrcode.* import chat.simplex.common.model.CryptoFile import chat.simplex.common.platform.* -import chat.simplex.common.ui.theme.SimpleXTheme +import chat.simplex.common.ui.theme.* import chat.simplex.common.views.helpers.* import chat.simplex.res.MR import kotlinx.coroutines.launch @@ -23,14 +23,18 @@ import kotlinx.coroutines.launch fun SimpleXLinkQRCode( connReq: String, modifier: Modifier = Modifier, + padding: PaddingValues = PaddingValues(horizontal = DEFAULT_PADDING * 2f, vertical = DEFAULT_PADDING_HALF), tintColor: Color = Color(0xff062d56), - withLogo: Boolean = true + withLogo: Boolean = true, + onShare: (() -> Unit)? = null, ) { QRCode( simplexChatLink(connReq), modifier, + padding, tintColor, - withLogo + withLogo, + onShare, ) } @@ -46,22 +50,24 @@ fun simplexChatLink(uri: String): String { fun QRCode( connReq: String, modifier: Modifier = Modifier, + padding: PaddingValues = PaddingValues(horizontal = DEFAULT_PADDING * 2f, vertical = DEFAULT_PADDING_HALF), tintColor: Color = Color(0xff062d56), - withLogo: Boolean = true + withLogo: Boolean = true, + onShare: (() -> Unit)? = null, ) { val scope = rememberCoroutineScope() - - BoxWithConstraints(Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) { - val maxWidthInPx = with(LocalDensity.current) { maxWidth.roundToPx() } - val qr = remember(maxWidthInPx, connReq, tintColor, withLogo) { - qrCodeBitmap(connReq, maxWidthInPx).replaceColor(Color.Black.toArgb(), tintColor.toArgb()) - .let { if (withLogo) it.addLogo() else it } - } + val qr = remember(connReq, tintColor, withLogo) { + qrCodeBitmap(connReq, 1024).replaceColor(Color.Black.toArgb(), tintColor.toArgb()) + .let { if (withLogo) it.addLogo() else it } + } + Box(Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) { Image( bitmap = qr, contentDescription = stringResource(MR.strings.image_descr_qr_code), Modifier - .widthIn(max = 360.dp) + .padding(padding) + .widthIn(max = 400.dp) + .aspectRatio(1f) .then(modifier) .clickable { scope.launch { @@ -70,6 +76,7 @@ fun QRCode( val file = saveTempImageUncompressed(image, true) if (file != null) { shareFile("", CryptoFile.plain(file.absolutePath)) + onShare?.invoke() } } } @@ -81,7 +88,9 @@ fun qrCodeBitmap(content: String, size: Int = 1024): ImageBitmap { val qrCode = QrCodeEncoder().addAutomatic(content).setError(QrCode.ErrorLevel.L).fixate() /** See [QrCodeGeneratorImage.initialize] and [FiducialImageEngine.configure] for size calculation */ val numModules = QrCode.totalModules(qrCode.version) - val borderModule = 1 + // Hide border on light themes to make it fit to the same place as camera in QRCodeScanner. + // On dark themes better to show the border + val borderModule = if (CurrentColors.value.colors.isLight) 0 else 1 // val calculatedFinalWidth = (pixelsPerModule * numModules) + 2 * (borderModule * pixelsPerModule) // size = (x * numModules) + 2 * (borderModule * x) // size / x = numModules + 2 * borderModule diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/QRCodeScanner.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/QRCodeScanner.kt index 66ba595e17..1e497e0581 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/QRCodeScanner.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/QRCodeScanner.kt @@ -1,6 +1,14 @@ package chat.simplex.common.views.newchat +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.runtime.* +import androidx.compose.ui.unit.dp +import chat.simplex.common.ui.theme.DEFAULT_PADDING +import chat.simplex.common.ui.theme.DEFAULT_PADDING_HALF @Composable -expect fun QRCodeScanner(onBarcode: (String) -> Unit) +expect fun QRCodeScanner( + showQRCodeScanner: MutableState = remember { mutableStateOf(true) }, + padding: PaddingValues = PaddingValues(horizontal = DEFAULT_PADDING * 2f, vertical = DEFAULT_PADDING_HALF), + onBarcode: (String) -> Unit +) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/CreateSimpleXAddress.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/CreateSimpleXAddress.kt index 8534198028..a5442a5bca 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/CreateSimpleXAddress.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/CreateSimpleXAddress.kt @@ -84,7 +84,7 @@ private fun CreateSimpleXAddressLayout( Spacer(Modifier.weight(1f)) if (userAddress != null) { - SimpleXLinkQRCode(userAddress.connReqContact, Modifier.padding(horizontal = DEFAULT_PADDING, vertical = DEFAULT_PADDING_HALF).aspectRatio(1f)) + SimpleXLinkQRCode(userAddress.connReqContact) ShareAddressButton { share(simplexChatLink(userAddress.connReqContact)) } Spacer(Modifier.weight(1f)) ShareViaEmailButton { sendEmail(userAddress) } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/remote/ConnectDesktopView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/remote/ConnectDesktopView.kt index 44e6969b8d..5acb240cb3 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/remote/ConnectDesktopView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/remote/ConnectDesktopView.kt @@ -339,16 +339,9 @@ private fun DevicesView(deviceName: String, remoteCtrls: SnapshotStateList) { SectionView(stringResource(MR.strings.scan_qr_code_from_desktop).uppercase()) { - Box( - Modifier - .fillMaxWidth() - .aspectRatio(ratio = 1F) - .padding(DEFAULT_PADDING) - ) { - QRCodeScanner { text -> - sessionAddress.value = text - processDesktopQRCode(sessionAddress, text) - } + QRCodeScanner { text -> + sessionAddress.value = text + processDesktopQRCode(sessionAddress, text) } } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/remote/ConnectMobileView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/remote/ConnectMobileView.kt index a3218c961b..c06265e70c 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/remote/ConnectMobileView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/remote/ConnectMobileView.kt @@ -187,11 +187,7 @@ private fun ConnectMobileViewLayout( SectionView { if (invitation != null && sessionCode == null && port != null) { Box { - QRCode( - invitation, Modifier - .padding(start = DEFAULT_PADDING, top = DEFAULT_PADDING_HALF, end = DEFAULT_PADDING, bottom = DEFAULT_PADDING_HALF) - .aspectRatio(1f) - ) + QRCode(invitation) if (staleQrCode) { Box(Modifier.matchParentSize().background(MaterialTheme.colors.background.copy(alpha = 0.9f)), contentAlignment = Alignment.Center) { SimpleButtonDecorated(stringResource(MR.strings.refresh_qr_code), painterResource(MR.images.ic_refresh), click = refreshQrCode) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/IncognitoView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/IncognitoView.kt index e264172f9c..6da0d34bd3 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/IncognitoView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/IncognitoView.kt @@ -11,6 +11,7 @@ import androidx.compose.ui.unit.dp import chat.simplex.common.ui.theme.DEFAULT_PADDING import chat.simplex.common.views.helpers.AppBarTitle import chat.simplex.common.views.helpers.generalGetString +import chat.simplex.common.views.onboarding.ReadableTextWithLink import chat.simplex.res.MR @Composable @@ -31,6 +32,7 @@ fun IncognitoLayout() { Text(generalGetString(MR.strings.incognito_info_protects)) Text(generalGetString(MR.strings.incognito_info_allows)) Text(generalGetString(MR.strings.incognito_info_share)) + ReadableTextWithLink(MR.strings.read_more_in_user_guide_with_link, "https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode") SectionBottomSpacer() } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/ProtocolServerView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/ProtocolServerView.kt index 4e8da36a7e..08ebc4ef15 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/ProtocolServerView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/ProtocolServerView.kt @@ -160,7 +160,7 @@ private fun CustomServer( if (valid.value) { SectionDividerSpaced() SectionView(stringResource(MR.strings.smp_servers_add_to_another_device).uppercase()) { - QRCode(serverAddress.value, Modifier.aspectRatio(1f).padding(horizontal = DEFAULT_PADDING)) + QRCode(serverAddress.value) } } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/ScanProtocolServer.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/ScanProtocolServer.kt index 77cb0ead13..502b579d64 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/ScanProtocolServer.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/ScanProtocolServer.kt @@ -20,25 +20,17 @@ fun ScanProtocolServerLayout(rhId: Long?, onNext: (ServerCfg) -> Unit) { Column( Modifier .fillMaxSize() - .padding(horizontal = DEFAULT_PADDING) ) { - AppBarTitle(stringResource(MR.strings.smp_servers_scan_qr), withPadding = false) - Box( - Modifier - .fillMaxWidth() - .aspectRatio(ratio = 1F) - .padding(bottom = 12.dp) - ) { - QRCodeScanner { text -> - val res = parseServerAddress(text) - if (res != null) { - onNext(ServerCfg(remoteHostId = rhId, text, false, null, true)) - } else { - AlertManager.shared.showAlertMsg( - title = generalGetString(MR.strings.smp_servers_invalid_address), - text = generalGetString(MR.strings.smp_servers_check_address) - ) - } + AppBarTitle(stringResource(MR.strings.smp_servers_scan_qr)) + QRCodeScanner { text -> + val res = parseServerAddress(text) + if (res != null) { + onNext(ServerCfg(remoteHostId = rhId, text, false, null, true)) + } else { + AlertManager.shared.showAlertMsg( + title = generalGetString(MR.strings.smp_servers_invalid_address), + text = generalGetString(MR.strings.smp_servers_check_address) + ) } } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserAddressView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserAddressView.kt index 915120d81d..299be43223 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserAddressView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserAddressView.kt @@ -207,7 +207,7 @@ private fun UserAddressLayout( val autoAcceptState = remember { mutableStateOf(AutoAcceptState(userAddress)) } val autoAcceptStateSaved = remember { mutableStateOf(autoAcceptState.value) } SectionView(stringResource(MR.strings.address_section_title).uppercase()) { - SimpleXLinkQRCode(userAddress.connReqContact, Modifier.padding(horizontal = DEFAULT_PADDING, vertical = DEFAULT_PADDING_HALF).aspectRatio(1f)) + SimpleXLinkQRCode(userAddress.connReqContact) ShareAddressButton { share(simplexChatLink(userAddress.connReqContact)) } ShareViaEmailButton { sendEmail(userAddress) } ShareWithContactsButton(shareViaProfile, setProfileAddress) diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/ar/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/ar/strings.xml index 1e6f1b0643..883e5e5f46 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/ar/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/ar/strings.xml @@ -147,8 +147,6 @@ تم تغيير العنوان من أجلك لا يمكن حذف ملف تعريف المستخدم! طلب لاستلام الفيديو - إضافة جهة اتصال جديدة : لإنشاء رمز الاستجابة السريعة الخاص بك لمرة واحدة لجهة اتصالك.]]> - امسح رمز الاستجابة السريعة : للاتصال بجهة الاتصال التي تعرض لك رمز الاستجابة السريعة.]]> مكالمتك تحت الإجراء تغيير عبارة مرور قاعدة البيانات؟ لا يمكن الوصول إلى Keystore لحفظ كلمة مرور قاعدة البيانات @@ -198,7 +196,6 @@ قارن الملف خطأ إنشاء مجموعة سرية - إنشاء رابط دعوة لمرة واحدة خطأ في إحباط تغيير العنوان تفعيل قفل SimpleX تأكد من بيانات الاعتماد الخاصة بك @@ -1324,7 +1321,7 @@ لا يمكنك إرسال رسائل! تحتاج إلى السماح لجهة الاتصال الخاصة بك بإرسال رسائل صوتية لتتمكن من إرسالها. أرسلت جهة اتصالك ملفًا أكبر من الحجم الأقصى المعتمد حاليًا (%1$s). - الاتصال بمطوري SimpleX Chat لطرح أي أسئلة وتلقي التحديثات.]]> + الاتصال بمطوري SimpleX Chat لطرح أي أسئلة وتلقي التحديثات.]]> خادمك يُخزن ملف تعريفك على جهازك ومشاركته فقط مع جهات اتصالك. لا تستطيع خوادم SimpleX رؤية ملف تعريفك. الفيديو مقفل diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml index 4ad40d7a62..e30b4eb56d 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml @@ -293,9 +293,11 @@ Tap to start a new chat Chat with the developers You have no chats + Loading chats… No filtered chats Tap to Connect Connect with %1$s? + Search or paste SimpleX link No selected chat @@ -427,6 +429,11 @@ (scan or paste from clipboard) (only stored by group members) + + Enable camera access + Tap to scan + Camera not available + Permission Denied! Camera @@ -442,8 +449,8 @@ To start a new chat Tap button above, then: - Add new contact: to create your one-time QR Code for your contact.]]> - Scan QR code: to connect to your contact who shows QR code to you.]]> + Add contact: to create a new invitation link, or connect via a link you received.]]> + Create group: to create a new group.]]> To connect via link If you received SimpleX Chat invitation link, you can open it in your browser: Scan QR code.]]> @@ -546,11 +553,26 @@ This string is not a connection link! Open in mobile app button.]]> - - Create one-time invitation link + + New chat + Add contact One-time invitation link 1-time link SimpleX address + Or show this code + Or scan QR code + Keep unused invitation? + You can view invitation link again in connection details. + Keep + Creating link… + Retry + Share this 1-time invite link + Paste the link you received + The text you pasted is not a SimpleX link. + Tap to paste link + + Invalid QR code + The code you scanned is not a SimpleX link QR code. Scan code @@ -1708,20 +1730,20 @@ Connect to yourself? This is your own one-time link! - You are already connecting to %1$s. + %1$s.]]> Already connecting! You are already connecting via this one-time link! This is your own SimpleX address! Repeat connection request? You have already requested connection via this address! Join your group? - This is your link for group %1$s! + %1$s!]]> Open group Repeat join request? Group already exists! - You are already joining the group %1$s. + %1$s.]]> Already joining the group! You are already joining the group via this link. - You are already in group %1$s. + %1$s.]]> Connect via link? \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/bg/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/bg/strings.xml index bdb9b39beb..4101b1c932 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/bg/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/bg/strings.xml @@ -119,8 +119,6 @@ Назад Отказ Спри живото съобщение - Добави нов контакт: за да създадете своя еднократен QR код за вашия контакт.]]> - Сканирай QR код: за да се свържете с вашия контакт, който ви показва QR код.]]> Камера Ако не можете да се срещнете лично, покажете QR код във видеоразговора или споделете линка. спри визуализацията на линка @@ -404,7 +402,6 @@ Изтрий Изтрий Свърване чрез линк - Създай линк за еднократна покана Парола за базата данни и експортиране Допринеси Продължи @@ -794,7 +791,7 @@ Без звук QR код Повече - Ръководство за потребителя.]]> + Ръководство за потребителя.]]> Маркирай като проверено %s не е потвърдено %s е потвърдено @@ -814,7 +811,7 @@ Няма се използват Onion хостове. Нека да поговорим в SimpleX Chat Парола за показване - GitHub хранилище.]]> + GitHub хранилище.]]> Когато приложението работи Периодично Постави получения линк @@ -1328,7 +1325,7 @@ Ще трябва да се идентифицирате, когато стартирате или възобновите приложението след 30 секунди във фонов режим. вие сте наблюдател Видео - се свържете с разработчиците на SimpleX Chat, за да задавате въпроси и да получавате актуализации;.]]> + се свържете с разработчиците на SimpleX Chat, за да задавате въпроси и да получавате актуализации;.]]> иска да се свърже с вас! Отваряне в мобилно приложение.]]> XFTP сървъри diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/cs/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/cs/strings.xml index 83fc06e87e..ae19884220 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/cs/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/cs/strings.xml @@ -191,8 +191,6 @@ Pro zahájení nové konverzace Klepněte na tlačítko potom: - Přidejte nový kontakt: vytvořte jednorázý QR kód pro váš kontakt.]]> - Naskenujte QR kód: připojíte se ke kontaktu, který vám QR kód ukázal.]]> Skenovat QR kód.]]> Vyčistit chat\? Vyčistit @@ -209,7 +207,6 @@ Ke skupině budete připojeni, až bude zařízení hostitele skupiny online, vyčkejte prosím nebo se podívejte později! Budete připojeni, jakmile bude vaše žádost o připojení přijata, vyčkejte prosím nebo se podívejte později! Požadavek na připojení byl odeslán! - Vytvořit jednorázovou pozvánku Jednorázová pozvánka Bezpečnostní kód %s je ověřeno 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 7401c0d4d9..20fa5c88aa 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/de/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/de/strings.xml @@ -262,12 +262,10 @@ Video Danke, dass Sie SimpleX Chat installiert haben! - mit SimpleX-Chat-Entwicklern verbinden, um Fragen zu stellen und Updates zu erhalten.]]> + mit SimpleX-Chat-Entwicklern verbinden, um Fragen zu stellen und Updates zu erhalten.]]> Um einen neuen Chat zu starten Schaltfläche antippen Danach die gewünschte Aktion auswählen: - Neuen Kontakt hinzufügen: Um Ihren Einmal-QR-Code für Ihren Kontakt zu erstellen.]]> - QR-Code scannen: Um sich mit Ihrem Kontakt zu verbinden, der Ihnen seinen QR-Code zeigt.]]> Über Link verbinden Wenn Sie einen SimpleX-Chat-Einladungslink erhalten haben, können Sie ihn in Ihrem Browser öffnen: QR-Code scannen.]]> @@ -341,7 +339,6 @@ Diese Zeichenfolge entspricht keinem gültigen Verbindungslink! In mobiler App öffnen“.]]> - Einmal-Einladungslink erstellen Einmal-Einladungslink Ihre Einstellungen @@ -1488,14 +1485,14 @@ Erweitern Verbindungsanfrage wiederholen? Gelöschter Kontakt - Sie sind bereits mit %1$s verbunden. + %1$s verbunden.]]> Fehler Sie sind über diesen Link bereits Mitglied der Gruppe. Gruppe erstellen Profil erstellen %s und %s Ihrer Gruppe beitreten? - Sie sind bereits Mitglied in der Gruppe %1$s. + %1$s.]]> Das ist Ihr eigener Einmal-Link! %d Nachrichten als gelöscht markiert Gruppe besteht bereits! @@ -1510,7 +1507,7 @@ Mitglied freigeben Mit Ihnen selbst verbinden? Zum Verbinden antippen - Sie sind bereits Mitglied in der Gruppe %1$s. + %1$s.]]> Das ist Ihre eigene SimpleX-Adresse! Richtiger Name für %s? %d Nachrichten löschen? @@ -1531,7 +1528,7 @@ Mitglied blockieren? %d Gruppenereignisse Ungültiger Name! - Das ist Ihr Link für die Gruppe %1$s! + %1$s!]]> Freigeben Ungültiger Datei-Pfad Sie haben über diese Adresse bereits eine Verbindung beantragt! 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 a656b932de..928f007635 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/es/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/es/strings.xml @@ -27,7 +27,6 @@ Siempre activo Permitir y después: - Añadir nuevo contacto: para crear tu código QR de un solo uso para tu contacto.]]> ¿Aceptar solicitud de conexión\? Aceptar incógnito Se eliminarán todos los mensajes SOLO para tí. ¡No podrá deshacerse! @@ -79,9 +78,7 @@ ¡Consume más batería! El servicio en segundo plano se ejecuta continuamente y las notificaciones se mostrarán de inmediato.]]> Tanto tú como tu contacto podéis eliminar de forma irreversible los mensajes enviados. Tanto tú como tu contacto podéis enviar mensajes temporales. - Escanear código QR: para conectar con tu contacto mediante su código QR.]]> Crear - Crea enlace de invitación de un uso Crea grupo secreto La contraseña de cifrado de la base de datos será actualizada. ID base de datos diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/fi/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/fi/strings.xml index be4072c4bf..78edeaecda 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/fi/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/fi/strings.xml @@ -188,7 +188,6 @@ Salli kontaktiesi lähettää katoavia viestejä. Katoavat viestit Kontekstikuvake - Skannaa QR-koodi: muodostaaksesi yhteyden kontaktiisi, joka näyttää QR-koodin sinulle.]]> Peruuta live-viesti Määritä ICE-palvelimet Lisää osoite profiiliisi, jotta kontaktisi voivat jakaa sen muiden kanssa. Profiilipäivitys lähetetään kontakteillesi. @@ -231,7 +230,6 @@ Tyhjennä Tyhjennä keskustelu Tyhjennä keskustelu\? - Luo kertaluonteinen kutsulinkki Sovellusversio: v%s soittaa… Poista keskusteluprofiili @@ -271,7 +269,6 @@ Katkaistu Takaisin Yhdistä linkillä / QR-koodilla - Lisää uusi kontakti: luo kertakäyttöinen QR-koodi kontaktille.]]> Tyhjennä Skannaa QR-koodi.]]> Poistetaanko odottava yhteys\? diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/fr/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/fr/strings.xml index 5ad0b3cbfc..4532e0aff5 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/fr/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/fr/strings.xml @@ -206,7 +206,6 @@ Vidéo Pour démarrer une nouvelle discussion Appuyez sur le bouton - Scanner un code QR : pour vous connecter à votre contact qui vous montre un code QR.]]> Pour se connecter via un lien Si vous avez reçu un lien d\'invitation SimpleX Chat, vous pouvez l\'ouvrir dans votre navigateur : Scanner le code QR.]]> @@ -246,7 +245,6 @@ Coller Cette chaîne n\'est pas un lien de connexion ! Ouvrir dans l\'app mobile.]]> - Créer un lien d\'invitation unique Définir le nom du contact… Déconnecté Erreur @@ -296,7 +294,6 @@ Merci d\'avoir installé SimpleX Chat ! vous connecter aux développeurs de SimpleX Chat pour leur poser des questions et recevoir des réponses :.]]> ci-dessus, puis : - Ajouter un nouveau contact : afin de créer un code QR à usage unique pour votre contact.]]> Si vous choisissez de la rejeter, l\'expéditeur·rice NE sera PAS notifié·e. Accepter Muet @@ -1407,14 +1404,14 @@ Développer Répéter la demande de connexion ? contact supprimé - Vous êtes déjà connecté(e) à %1$s. + %1$s.]]> Erreur Vous êtes déjà en train de rejoindre le groupe via ce lien. Créer un groupe Créer le profil %s et %s Rejoindre votre groupe ? - Vous êtes déjà en train de rejoindre le groupe %1$s. + %1$s.]]> Voici votre propre lien unique ! %d messages marqués comme supprimés Ce groupe existe déjà ! @@ -1429,7 +1426,7 @@ Débloquer ce membre Se connecter à soi-même ? Tapez pour vous connecter - Vous êtes déjà dans le groupe %1$s. + %1$s.]]> Voici votre propre adresse SimpleX ! Corriger le nom pour %s ? Supprimer %d messages ? @@ -1450,7 +1447,7 @@ Bloquer ce membre ? %d événements de groupe Nom invalide ! - Voici votre lien pour le groupe %1$s ! + %1$s !]]> Débloquer Chemin du fichier invalide Vous avez déjà demandé une connexion via cette adresse ! 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 fac97864f7..6e2ba94ea9 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/hu/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/hu/strings.xml @@ -44,7 +44,6 @@ minden chat profilodra az appban.]]> Mindketten, te és az ismerősöd is küldhettek eltűnő üzeneteket. Az Android Keystore-t jelmondat biztonságos tárolására használják - lehetővé teszi az értesítési szolgáltatás működését. - QR-kód beolvasása: kapcsolódás ismerőshöz a megmutatott QR-kódja alapján]]> Téves üzenet hash Felhasználói profil törlése nem lehetséges! Háttér @@ -117,7 +116,6 @@ vastagított Az app számkód helyettesítésre kerül egy önmegsemmisítő számkóddal. Arab, bulgár, finn, héber, thai és ukrán - köszönet a felhasználóknak és a Weblate-nek! - Új ismerős hozzáadása: egyszer használatos QR-kód készítése az ismerős számára.]]> Hangüzenetek engedélyezése? Mindig használt relay szervert mindig @@ -338,7 +336,6 @@ Csatlakoztatva a mobilhoz Jelenlegi jelmondat… Fájl választása - Egyszer használatos meghívó link létrehozása Kép törlése Fájl létrehozása Tikos csoport létrehozása @@ -1432,7 +1429,7 @@ A chat szolgáltatást elindíthatod a beállítások / adatbázis pontban vagy az app újraindításával. Ellenőrizd a kódot a mobilon! Csatlakoztál ehhez a csoporthoz. Kapcsolódás a meghívó csoporttaghoz. - a SimpleX Chat fejlesztőivel és kérdezhetsz bármit és értesülhetsz az újdonságokról.]]> + a SimpleX Chat fejlesztőivel és kérdezhetsz bármit és értesülhetsz az újdonságokról.]]> Opcionális üdvözlő szöveggel. Ismeretlen adatbázis hiba: %s Elrejtheted vagy némíthatod egy felhasználó profilját - tartsd lenyomva a menühöz! @@ -1518,13 +1515,13 @@ A titkosítás működik, és új titkosítási egyezményre nincs szükség. Ez kapcsolati hibákat eredményezhet! Ez a művelet nem vonható vissza - profilod, ismerőseid, üzeneteid és fájljaid visszafordíthatatlanul törlésre kerülnek. A bejegyzés frissítve - Felhasználói útmutatóban olvasható.]]> + Felhasználói útmutatóban olvasható.]]> A jelmondat a beállításokban egyszerű szövegként van tárolva. Konzol megjelenítése új ablakban Az előző üzenet hash-e más. Ezek a beállítások a jelenlegi profilodra vonatkoznak Kérjük, várj, amíg a fájl betöltődik az összekapcsolt mobilról. - GitHub tárolónkban.]]> + GitHub tárolónkban.]]> hiba a tartalom megjelenítése közben hiba az üzenet megjelenítésekor \ No newline at end of file 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 f01568c03b..21713ba93f 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/it/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/it/strings.xml @@ -292,8 +292,6 @@ Elimina I messaggi diretti tra i membri sono vietati in questo gruppo. Inserisci il tuo nome: - Aggiungi un contatto: per creare il tuo codice QR una tantum per il tuo contatto.]]> - Scansiona codice QR: per connetterti al contatto che ti mostra il codice QR.]]> File Svuota chat Svuotare la chat\? @@ -319,7 +317,6 @@ Annulla la verifica Connetti Connetti via link - Crea link di invito una tantum Password del database ed esportazione Inserisci il server manualmente Come si usa @@ -1407,14 +1404,14 @@ Espandi Ripetere la richiesta di connessione? contatto eliminato - Ti stai già connettendo a %1$s. + %1$s.]]> Errore Stai già entrando nel gruppo tramite questo link. Crea gruppo Crea profilo %s e %s Entrare nel tuo gruppo? - Stai già entrando nel gruppo %1$s. + %1$s.]]> Questo è il tuo link una tantum! %d messaggi contrassegnati eliminati Il gruppo esiste già! @@ -1429,7 +1426,7 @@ Sblocca membro Connettersi a te stesso? Tocca per connettere - Sei già nel gruppo %1$s. + %1$s.]]> Questo è il tuo indirizzo SimpleX! Correggere il nome a %s? Eliminare %d messaggi? @@ -1450,7 +1447,7 @@ Bloccare il membro? %d eventi del gruppo Nome non valido! - Questo è il tuo link per il gruppo %1$s! + %1$s!]]> Sblocca Percorso file non valido Hai già richiesto la connessione tramite questo indirizzo! diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/iw/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/iw/strings.xml index 58bb6b0a0a..e1657ed6db 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/iw/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/iw/strings.xml @@ -93,7 +93,6 @@ אשר אוטומטית בקשות ליצירת קשר. אימות בוטל אימות לא זמין - הוסיפו איש קשר חדש: ליצירת קוד QR חד־פעמי עבור איש הקשר שלכם.]]> הטוב ביותר לסוללה. התראות יוצגו רק כאשר האפליקציה מופעלת (ללא שירות רקע).]]> טוב לסוללה. שירות הרקע ייבדוק הודעות כל 10 דקות. שיחות או הודעות דחופות עלולות להתפספס.]]> גם אתם וגם איש הקשר יכולים למחוק באופן בלתי הפיך הודעות שנשלחו. @@ -103,7 +102,6 @@ ביטול בטל הודעה חיה מצלמה - סירקו קוד QR: כדי להתחבר לאיש קשר המציג לכם קוד QR.]]> בטל תצוגה מקדימה של קישורים שגיאת שיחה שיחה מתמשכת @@ -219,7 +217,6 @@ הועתק ללוח צור קישור הזמנה חד־פעמי צור קבוצה סודית - צור קישור הזמנה חד־פעמי תרומה גרסת ליבה: v%s צור כתובת diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/ja/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/ja/strings.xml index bebf716e0d..419e0c3a6e 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/ja/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/ja/strings.xml @@ -73,12 +73,10 @@ 認証不可能 画像を自動的に受信 バックグラウンド機能が常にオンで、メッセージが到着次第に通知が出ます。 - 新しい連絡先を追加:使い捨てのQRコードを発行]]> 電池省エネをオンに、バックグラウンド機能と定期的な受信依頼をオフにします。設定メニューにて変更できます。 電池消費が最少:アプリがアクティブ時のみに通知が出ます(バックグラウンドサービス無し)。]]> 設定メニューにてオフにできます。 アプリがアクティブ時に通知が出ます。]]> あなたと連絡相手が送信済みメッセージを永久削除できます。 - QRコードを読み込み:連絡相手のQRコードをスキャンすると繋がります。]]> チャットのアーカイブ チャットのアーカイブを削除しますか? シークレットモードで参加 @@ -524,7 +522,6 @@ ミュート 接続待ちの繋がりを削除しますか? 接続 - 使い捨てリンクを発行する 使い捨ての招待リンク データベース暗証フレーズとエキスポート 使い方 diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/ko/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/ko/strings.xml index 3c7554c972..b059cc5ccd 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/ko/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/ko/strings.xml @@ -27,7 +27,6 @@ 컨텍스트 아이콘 연결됨 뒤로 - 새 대화 상대 추가 : 대화를 위한 일회용 QR 코드 만들기]]> 취소 라이브 메시지 취소 파일 선택 @@ -171,7 +170,6 @@ 배터리에 가장 좋음. 앱이 실행 중일 때만 알림을 받게 됩니다 (백그라운드에서 실행되지 않음).]]> 설정을 통해 비활성화할 수 있습니다. – 앱이 실행되는 동안 알림이 표시됩니다.]]> 당신과 대화 상대 모두 사라지는 메시지를 보낼 수 있습니다. - QR 코드 스캔: QR 코드를 보여주는 사람과 대화할 수 있습니다.]]> 데이터베이스 암호를 저장하고 있는 Keystore에 접근할 수 없습니다. 배터리 더욱 사용! 백그라운드 서비스가 항상 실행됩니다. - 메시지를 수신되는 즉시 알림이 표시됩니다.]]> 통화 종료됨 %1$s @@ -202,7 +200,6 @@ 대화 상대와 종단간 암호화됨 대화 상대와 아직 연결되지 않았습니다! %1$s에 생성 완료 - 일회용 초대 링크 생성 비밀 그룹 생성 익명 수락 1개월 diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/lt/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/lt/strings.xml index 163645c7d5..5d74cac33a 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/lt/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/lt/strings.xml @@ -117,7 +117,6 @@ QR kodas pagalba El. paštas - Sukurti vienkartinio pakvietimo nuorodą Skenuoti kodą Duomenų bazės slaptafrazė ir eksportavimas Ištrinti serverį @@ -387,8 +386,6 @@ Gali būti, kad liudijimo kontrolinis kodas serverio adrese yra neteisingas Ištrinti failą Dekodavimo klaida - Pridėti naują adresatą: norėdami sukurti adresatui vienkartinį QR kodą.]]> - Skenuoti QR kodą: norėdami prisijungti prie adresato, kuris jums rodo QR kodą.]]> Išvalyti pokalbį Įjungti pranešimus Neteisingas QR kodas diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/nl/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/nl/strings.xml index bb5226e3d4..b9dfb6866e 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/nl/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/nl/strings.xml @@ -66,7 +66,6 @@ Spraak berichten toestaan\? Goed voor de batterij. Achtergrondservice controleert berichten elke 10 minuten. Mogelijk mist u oproepen of dringende berichten.]]> Onjuiste bericht hash - Scan QR-code: om verbinding te maken met uw contact die u de QR-code laat zien.]]> Onjuiste bericht-ID Oproep al beëindigd! 1 maand @@ -94,7 +93,6 @@ voor elk chat profiel dat je in de app hebt .]]> audio oproep (niet e2e versleuteld) Achtergrondservice is altijd actief, meldingen worden weergegeven zodra de berichten beschikbaar zijn. - Nieuw contact toevoegen: om een eenmalige QR-code voor uw contact te maken.]]> Oproep beëindigd Batterijoptimalisatie is actief, waardoor achtergrondservice en periodieke verzoeken om nieuwe berichten worden uitgeschakeld. Je kunt ze weer inschakelen via instellingen. Het beste voor de batterij. U ontvangt alleen meldingen wanneer de app wordt uitgevoerd (GEEN achtergrondservice).]]> @@ -203,7 +201,6 @@ Verwijderd verificatie Verbind Maak verbinding via link - Maak een eenmalige uitnodiging link gekleurd Oproep verbinden… Maak @@ -1442,17 +1439,17 @@ Console in nieuw venster weergeven Alle nieuwe berichten van %s worden verborgen! geblokkeerd - Je bent al verbonden met %1$s. + %1$s.]]> Je wordt al lid van de groep via deze link. - Je bent al lid van de groep %1$s. + %1$s.]]> Dit is uw eigen eenmalige link! Lid deblokkeren - Je zit al in groep %1$s. + %1$s.]]> Dit is uw eigen SimpleX adres! Lid deblokkeren? Je maakt al verbinding via deze eenmalige link! Je hebt een ongeldig bestandslocatie gedeeld. Rapporteer het probleem aan de app-ontwikkelaars. - Dit is jouw link voor groep %1$s! + %1$s!]]> Deblokkeren U heeft al een verbinding aangevraagd via dit adres! Fout bij heronderhandeling van codering diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/pl/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/pl/strings.xml index e811e47ea1..6e1fdfbbba 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/pl/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/pl/strings.xml @@ -229,7 +229,6 @@ Akceptuj Akceptuj incognito Wszystkie wiadomości zostaną usunięte - nie można tego cofnąć! Wiadomości zostaną usunięte TYLKO dla Ciebie. - Zeskanuj kod QR: aby połączyć się z kontaktem, który pokaże Ci kod QR.]]> anuluj podgląd linku Wyczyść Wyczyść @@ -917,7 +916,6 @@ Uwierzytelnianie niedostępne Dołącz Wstecz - Dodaj nowy kontakt: aby stworzyć swój jednorazowy kod QR dla kontaktu.]]> Optymalizacja baterii jest aktywna, wyłącza usługi w tle i okresowe żądania nowych wiadomości. Możesz je ponownie włączyć za pośrednictwem ustawień. Można je wyłączyć poprzez ustawienia - powiadomienia nadal będą pokazywane podczas działania aplikacji.]]> Najlepsze dla baterii. Będziesz otrzymywać powiadomienia tylko wtedy, gdy aplikacja jest uruchomiona (NIE w tle).]]> @@ -933,7 +931,6 @@ Błąd połączenia (UWIERZYTELNIANIE) Połącz się przez link / kod QR Utworzony na %1$s - Utwórz jednorazowy link do zaproszenia Utwórz tajną grupę Utwórz tajną grupę Baza danych jest zaszyfrowana przy użyciu losowego hasła. Proszę zmienić je przed eksportem. @@ -1427,12 +1424,12 @@ zablokowany Rozszerz Powtórzyć prośbę połączenia? - Już jesteś połączony z %1$s. + %1$s.]]> Błąd Już dołączasz do grupy przez ten link. %s i %s Dołączyć do twojej grupy? - Już dołączasz do grupy %1$s. + %1$s.]]> To jest twój jednorazowy link! Grupa już istnieje! Wideo nie może zostać zdekodowane, spróbuj inne wideo lub skontaktuj się z deweloperami. @@ -1440,7 +1437,7 @@ %s, %s i %d członków Odblokuj członka Dotknij aby połączyć - Już jesteś w grupie %1$s. + %1$s.]]> To jest twój własny adres SimpleX! Usuń członka Odblokować członka? @@ -1452,7 +1449,7 @@ Błąd wysyłania zaproszenia Udostępniłeś nieprawidłową ścieżkę pliku. Zgłoś problem do deweloperów aplikacji. Nieprawidłowa nazwa! - To jest twój link zaproszenia do grupy %1$s! + %1$s!]]> Odblokuj Nieprawidłowa ścieżka pliku Już prosiłeś o połączenie na ten adres! diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/pt-rBR/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/pt-rBR/strings.xml index 622ad8b2d6..769375604d 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/pt-rBR/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/pt-rBR/strings.xml @@ -24,8 +24,6 @@ Cancelar mensagem ao vivo Voltar Arquivo - Adicionar novo contato: para criar seu QR code de uso único para seu contato.]]> - Escanear código QR: para se conectar ao seu contato que mostra o código QR para você.]]> Aceitar Limpar chat\? Limpar @@ -374,7 +372,6 @@ A autenticação do dispositivo está desativada. Desativando o bloqueio SimpleX. Para todos Oculto - Gerar um link de convite de uso único. Como usar seus servidores Importar Importar banco de dados de chat\? diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/pt/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/pt/strings.xml index 072eb97ebf..e755d9aab9 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/pt/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/pt/strings.xml @@ -211,7 +211,6 @@ Grupo Áudio ligado Autenticação cancelada - Adicionar novo contato: para criar o seu código QR de utilização única para o seu contato.]]> Bom para a bateria . O serviço em segundo plano verifica se há mensagens a cada 10 minutos. Você pode perder chamadas ou mensagens urgentes.]]> A otimização da bateria está ativa, desativando o serviço em segundo plano e os pedidos periódicos de novas mensagens. Você pode reativá-los através das definições. Melhor para a bateria. Apenas receberá notificações enquanto a app estiver em execução (SEM serviço em segundo plano)]]> @@ -225,7 +224,6 @@ Chamadas de áudio/vídeo são proibidas. O serviço em segundo plano está sempre em execução - as notificações serão exibidas assim que as mensagens estiverem disponíveis. Autenticar - Leia o código QR : para se conectar ao seu contato que lhe mostra o código QR.]]> chamada finalizada %1$s a chamar… erro de chamada @@ -366,7 +364,6 @@ Erro de conexão conexão %1$d O contato já existe - Criar convite de ligação de utilização única Convite de ligação de utilização única Salvar Modo anónimo 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 76a49f678d..aa0e3282f2 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/ru/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/ru/strings.xml @@ -267,12 +267,10 @@ Чтобы начать новый чат Нажмите кнопку сверху, затем: - Добавить новый контакт: чтобы создать одноразовый QR код/ссылку для Вашего контакта.]]> - Сканировать QR код: чтобы соединиться с контактом, который показывает Вам QR код.]]> Чтобы соединиться через ссылку Если Вы получили ссылку с приглашением из SimpleX Chat, Вы можете открыть ее в браузере: Сканировать QR код.]]> - Open in mobile app на веб странице, затем нажмите Соединиться в приложении.]]> + Open in mobile app на веб странице, затем нажмите Соединиться в приложении.]]> Принять запрос на соединение? Отправителю НЕ будет послано уведомление, если Вы отклоните запрос на соединение. @@ -339,7 +337,6 @@ Соединиться Вставить - Создать одноразовую ссылку Одноразовая ссылка Настройки @@ -1566,9 +1563,9 @@ Все новые сообщения от %s будут скрыты! Версия настольного приложения %s несовместима с этим приложением. заблокировано - Вы уже соединяетесь с %1$s. + %1$s.]]> Вы уже вступаете в группу по этой ссылке. - Вы уже вступаете в группу %1$s. + %1$s.]]> Это ваша собственная одноразовая ссылка! Через безопасный квантово-устойчивый протокол. Чтобы скрыть нежелательные сообщения. @@ -1580,7 +1577,7 @@ Разблокировать члена группы Нажмите чтобы соединиться Имя этого устройства - Вы уже состоите в группе %1$s. + %1$s.]]> Это ваш собственный адрес SimpleX! Разблокировать члена группы? Использовать с компьютера @@ -1590,7 +1587,7 @@ Имя устройства будет доступно подключенному мобильному клиенту. Сверьте код на мобильном Указан неверный путь к файлу. Сообщите о проблеме разработчикам приложения. - Это ваша ссылка на группу %1$s! + %1$s!]]> Сверьте код с компьютером Сканировать QR код с компьютера Разблокировать diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/th/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/th/strings.xml index 91330717c4..3eec7777f6 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/th/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/th/strings.xml @@ -112,8 +112,6 @@ ทั้งคุณและผู้ติดต่อของคุณสามารถเพิ่มปฏิกิริยาต่อข้อความได้ ทั้งคุณและผู้ติดต่อของคุณสามารถลบข้อความที่ส่งแล้วอย่างถาวรได้ กล้อง - เพิ่มผู้ติดต่อใหม่ : เพื่อสร้างรหัส QR แบบใช้ครั้งเดียวสําหรับผู้ติดต่อของคุณ]]> - สแกนรหัส QR: เพื่อเชื่อมต่อกับผู้ติดต่อที่แสดงรหัส QR ให้คุณ]]> เกี่ยวกับที่อยู่ SimpleX ตัวหนา กำลังโทร… @@ -205,7 +203,6 @@ ปุ่มปิด เชื่อมต่อ เชื่อมต่อผ่านลิงก์ - สร้างลิงก์เชิญแบบใช้ครั้งเดียว ล้างการยืนยัน คอนโซลแชท ตรวจสอบที่อยู่เซิร์ฟเวอร์แล้วลองอีกครั้ง diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/tr/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/tr/strings.xml index 8a3eeef61d..1cffad1df1 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/tr/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/tr/strings.xml @@ -3,7 +3,6 @@ Bildirimler Bağlantı ya da karekod ile bağlan Gizli grup oluştur - Tek seferlik davet bağlantısı oluştur SimpleX addresin cevapsız çağrı Gelen görüntülü arama @@ -736,7 +735,6 @@ Geri alınamaz mesaj silme İtalyanca arayüz Dosya seç - QR kodunu tara: size QR kodunu gösteren kişiyle bağlantı kurmak için.]]> Arkadaşlarınızı davet edin kalın İtalik @@ -790,7 +788,6 @@ Mesajlar silinecek - bu geri alınamaz! Alıcı adresini değiştir\? Geri - Yeni kişi ekle: Kişiniz için tek seferlik QR Kodunuzu oluşturmak için.]]> Bağlantı isteğiniz kabul edildiğinde bağlanacaksınız, lütfen bekleyin veya daha sonra kontrol edin! Kişinizin cihazı çevrimiçi olduğunda bağlanacaksınız, lütfen bekleyin veya daha sonra kontrol edin! Daha fazla bilgi edinin @@ -902,7 +899,7 @@ Kişiniz desteklenen maksimum boyuttan (%1$s) daha büyük bir dosya gönderdi. Kişiniz yüklemeyi tamamladığında video alınacaktır. mobil uygulamada aç seçeneğine tıklayın.]]> - SimpleX Chat geliştiricilerine bağlanabilirsiniz.]]> + SimpleX Chat geliştiricilerine bağlanabilirsiniz.]]> Bir kullanıcının profilini gizleyebilir veya sessize alabilirsiniz - menü için basılı tutun. Sohbet veritabanınızın en son sürümünü SADECE bir cihazda kullanmalısınız, aksi takdirde bazı kişilerden daha fazla mesaj alamayabilirsiniz. Yanlış veritabanı parolası @@ -976,7 +973,7 @@ Link ile bağlanmak için Bu geçerli bir bağlantı linki değil Bu QR kodu bir bağlantı değil! - Kullanıcı Kılavuzu.]]> + Kullanıcı Kılavuzu.]]> Yapıştır Bu dize bir bağlantı linki değil! Uygulamaya puan verin @@ -1020,7 +1017,7 @@ Favorilerden çıkar Sohbeti gizli yap! Profil güncellemesi kişilerinize gönderilecektir. - GitHub repomuzda daha fazlasını okuyun.]]> + GitHub repomuzda daha fazlasını okuyun.]]> Lütfen geliştiricilere bildirin. Profil ve sunucu bağlantıları gizlemeyi kaldır diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/uk/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/uk/strings.xml index faf2895827..beb5584b9a 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/uk/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/uk/strings.xml @@ -104,7 +104,6 @@ поганий хеш повідомлення поганий ідентифікатор повідомлення Фон - Додайте новий контакт: щоб створити одноразовий QR-код для вашого контакту.]]> Це можна вимкнути у налаштуваннях – сповіщення все одно будуть відображатися, коли програма працює. Служба фонового режиму завжди активна – сповіщення відображатимуться, як тільки повідомлення будуть доступні. Запит на отримання зображення @@ -356,7 +355,6 @@ Це посилання не є дійсним з\'єднувальним посиланням! Запит на з\'єднання відправлено! Відкрити у мобільному додатку.]]> - Створити одноразове запрошення Сканувати код Скануйте код безпеки з додатка вашого контакту. Невірна адреса сервера! @@ -529,7 +527,7 @@ зображення профілю Більше Створити профіль - GitHub.]]> + GitHub.]]> Відео увімкнено Це може трапитися, якщо ви або ваше з\'єднання використовували застарілу резервну копію бази даних. Відновити резервну копію бази даних @@ -606,7 +604,6 @@ Доступ відхилено! Камера Дякуємо за установку SimpleX Chat! - Сканувати QR-код: щоб підключитися до вашого контакту, який вам показує QR-код.]]> Якщо ви отримали запрошення від SimpleX Chat, ви можете відкрити його у вашому браузері: Очистити Видалити @@ -1028,7 +1025,7 @@ Вас підключать, коли пристрій вашого контакту буде в мережі, зачекайте або перевірте пізніше! Ви не втратите свої контакти, якщо ви пізніше видалите свою адресу. Коли люди просять про з\'єднання, ви можете його прийняти чи відхилити. - Посібнику користувача.]]> + Посібнику користувача.]]> SimpleX-адреса Очистити перевірку %s перевірено @@ -1200,7 +1197,7 @@ Створити секретну групу (щоб поділитися з вашим контактом) (сканувати або вставити з буферу обміну) - підключитися до розробників SimpleX Chat, щоб задати будь-які питання і отримувати оновлення.]]> + підключитися до розробників SimpleX Chat, щоб задати будь-які питання і отримувати оновлення.]]> Сканувати QR-код.]]> Адреса SimpleX Показати QR-код 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 7b8d8ec7eb..449f983606 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 @@ -118,7 +118,6 @@ 每个联系人和群组成员 将使用单独的 TCP 连接(和 SOCKS 凭证)。 \n请注意:如果您有很多连接,您的电池和流量消耗可能会大大增加,并且某些连接可能会失败。 返回 - 添加新联系人:为您的联系人创建一次性二维码。]]> 最长续航 。您只会在应用程序运行时收到通知(无后台服务)。]]> 较长续航 。后台服务每 10 分钟检查一次消息。您可能会错过来电或者紧急信息。]]> 加粗 @@ -129,7 +128,6 @@ 使用更多电量 !后台服务始终运行——一旦收到消息,就会显示通知。]]> 请注意:如果您丢失密码,您将无法恢复或者更改密码。]]> 通话已结束! - 扫描二维码 :与向您展示二维码的联系人联系。]]> 无法邀请联系人! 无法邀请联系人! 取消 @@ -338,7 +336,6 @@ 创建私密群组 不同的名字、头像和传输隔离。 法语界面 - 创建一次性邀请链接 如何使用它 错误 连接中…… @@ -1407,14 +1404,14 @@ 展开 重复连接请求吗? 已删除联系人 - 你已经在连接到 %1$s。 + %1$s。]]> 错误 你已经在通过此链接加入该群。 建群 创建个人资料 %s 和 %s 加入你的群吗? - 你已经在加入 %1$s 群。 + %1$s 群。]]> 这是你自己的一次性链接! %d 条消息被标记为删除 群已存在! @@ -1428,7 +1425,7 @@ 解封成员 连接到你自己? 轻按连接 - 你已经在%1$s 群内。 + %1$s 群内。]]> 这是你自己的 SimpleX 地址! 更正名称为 %s? 删除 %d 条消息吗? @@ -1449,7 +1446,7 @@ 封禁成员吗? %d 个群事件 无效名称! - 这是给你的 %1$s 群链接! + %1$s 群链接!]]> 解封 无效的文件路径 你已经请求通过此地址进行连接! diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/zh-rTW/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/zh-rTW/strings.xml index 7ab98ca323..f5b6e69871 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/zh-rTW/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/zh-rTW/strings.xml @@ -47,8 +47,6 @@ 允許使用語音訊息? 取消 取消實況訊息 - 新增新的聯絡人:建立你的一次性二維碼給你的聯絡人。]]> - 掃描二維碼:連接到向你出示二維碼的聯絡人。]]> 選擇檔案 相機 從圖片庫選擇圖片 @@ -424,7 +422,6 @@ 掃描二維碼。]]> 設定 這個二維碼不是一個連結! - 建立一次性邀請連結 當可行的時候 核心版本:v%s simplexmq: v%s (%2s) diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/Modifier.desktop.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/Modifier.desktop.kt index 6f317acb92..9245f2b950 100644 --- a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/Modifier.desktop.kt +++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/Modifier.desktop.kt @@ -4,6 +4,8 @@ import androidx.compose.foundation.contextMenuOpenDetector import androidx.compose.runtime.Composable import androidx.compose.ui.* import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.input.pointer.PointerIcon +import androidx.compose.ui.input.pointer.pointerHoverIcon import java.io.File import java.net.URI @@ -36,3 +38,5 @@ onExternalDrag(enabled) { } actual fun Modifier.onRightClick(action: () -> Unit): Modifier = contextMenuOpenDetector { action() } + +actual fun Modifier.desktopPointerHoverIconHand(): Modifier = Modifier.pointerHoverIcon(PointerIcon.Hand) diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.desktop.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.desktop.kt index 6c37c93ccc..b2fc451969 100644 --- a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.desktop.kt +++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.desktop.kt @@ -1,5 +1,6 @@ package chat.simplex.common.views.chatlist +import SectionDivider import androidx.compose.foundation.* import androidx.compose.foundation.interaction.InteractionSource import androidx.compose.foundation.layout.* @@ -33,11 +34,11 @@ actual fun ChatListNavLinkLayout( dropdownMenuItems: (@Composable () -> Unit)?, showMenu: MutableState, stopped: Boolean, - selectedChat: State + selectedChat: State, + nextChatSelected: State, ) { var modifier = Modifier.fillMaxWidth() if (!stopped) modifier = modifier - .background(color = if (selectedChat.value) MaterialTheme.colors.background.mixWith(MaterialTheme.colors.onBackground, 0.95f) else Color.Unspecified) .combinedClickable(onClick = click, onLongClick = { showMenu.value = true }) .onRightClick { showMenu.value = true } CompositionLocalProvider( @@ -52,10 +53,17 @@ actual fun ChatListNavLinkLayout( ) { chatLinkPreview() } + if (selectedChat.value) { + Box(Modifier.matchParentSize().background(MaterialTheme.colors.onBackground.copy(0.05f))) + } if (dropdownMenuItems != null) { DefaultDropdownMenu(showMenu, dropdownMenuItems = dropdownMenuItems) } } } - Divider() + if (selectedChat.value || nextChatSelected.value) { + Divider() + } else { + SectionDivider() + } } diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/helpers/Utils.desktop.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/helpers/Utils.desktop.kt index 19c9fc0fd7..9fa93cdfdf 100644 --- a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/helpers/Utils.desktop.kt +++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/helpers/Utils.desktop.kt @@ -1,14 +1,20 @@ package chat.simplex.common.views.helpers +import androidx.compose.runtime.* import androidx.compose.ui.graphics.* +import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.text.* import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.unit.Density import chat.simplex.common.model.CIFile import chat.simplex.common.model.readCryptoFile import chat.simplex.common.platform.* import chat.simplex.common.simplexWindowState +import kotlinx.coroutines.delay +import java.io.ByteArrayInputStream +import java.io.File import java.io.* import java.net.URI import javax.imageio.ImageIO @@ -17,6 +23,7 @@ import kotlin.io.encoding.ExperimentalEncodingApi private val bStyle = SpanStyle(fontWeight = FontWeight.Bold) private val iStyle = SpanStyle(fontStyle = FontStyle.Italic) +private val uStyle = SpanStyle(textDecoration = TextDecoration.Underline) private fun fontStyle(color: String) = SpanStyle(color = Color(color.replace("#", "ff").toLongOrNull(16) ?: Color.White.toArgb().toLong())) @@ -54,6 +61,22 @@ actual fun escapedHtmlToAnnotatedString(text: String, density: Density): Annotat } break } + text.substringSafe(innerI, 2) == "u>" -> { + val textStart = innerI + 2 + for (insideTagI in textStart until text.length) { + if (text[insideTagI] == '<') { + withStyle(uStyle) { append(text.substring(textStart, insideTagI)) } + skipTil = insideTagI + 4 + break + } + } + break + } + text.substringSafe(innerI, 3) == "br>" -> { + val textStart = innerI + 3 + append("\n") + skipTil = textStart + } text.substringSafe(innerI, 4) == "font" -> { var textStart = innerI + 5 var color = "#000000" @@ -85,6 +108,18 @@ actual fun escapedHtmlToAnnotatedString(text: String, density: Density): Annotat AnnotatedString(text) } +@Composable +actual fun SetupClipboardListener() { + val clipboard = LocalClipboardManager.current + chatModel.clipboardHasText.value = clipboard.hasText() + LaunchedEffect(Unit) { + while (true) { + delay(1000) + chatModel.clipboardHasText.value = clipboard.hasText() + } + } +} + actual fun getAppFileUri(fileName: String): URI { val rh = chatModel.currentRemoteHost.value return if (rh == null) { diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/newchat/ConnectViaLinkView.desktop.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/newchat/ConnectViaLinkView.desktop.kt deleted file mode 100644 index 72d9678154..0000000000 --- a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/newchat/ConnectViaLinkView.desktop.kt +++ /dev/null @@ -1,11 +0,0 @@ -package chat.simplex.common.views.newchat - -import androidx.compose.runtime.* -import chat.simplex.common.model.ChatModel -import chat.simplex.common.model.RemoteHostInfo - -@Composable -actual fun ConnectViaLinkView(m: ChatModel, rh: RemoteHostInfo?, close: () -> Unit) { - // TODO this should close if remote host changes in model - PasteToConnectView(m, rh, close) -} diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/newchat/QRCodeScanner.desktop.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/newchat/QRCodeScanner.desktop.kt index 16d35b5b8d..0142afb4ac 100644 --- a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/newchat/QRCodeScanner.desktop.kt +++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/newchat/QRCodeScanner.desktop.kt @@ -1,8 +1,13 @@ package chat.simplex.common.views.newchat +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.runtime.* @Composable -actual fun QRCodeScanner(onBarcode: (String) -> Unit) { +actual fun QRCodeScanner( + showQRCodeScanner: MutableState, + padding: PaddingValues, + onBarcode: (String) -> Unit +) { //LALAL } diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/newchat/ScanToConnectView.desktop.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/newchat/ScanToConnectView.desktop.kt deleted file mode 100644 index 7579f09fa5..0000000000 --- a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/newchat/ScanToConnectView.desktop.kt +++ /dev/null @@ -1,15 +0,0 @@ -package chat.simplex.common.views.newchat - -import androidx.compose.runtime.Composable -import chat.simplex.common.model.ChatModel -import chat.simplex.common.model.RemoteHostInfo - -@Composable -actual fun ScanToConnectView(chatModel: ChatModel, rh: RemoteHostInfo?, close: () -> Unit) { - ConnectContactLayout( - chatModel = chatModel, - rh = rh, - incognitoPref = chatModel.controller.appPrefs.incognito, - close = close - ) -} From 05b55d3fb5fb570d576d844d11d0c39f73c7d661 Mon Sep 17 00:00:00 2001 From: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com> Date: Fri, 29 Dec 2023 21:46:28 +0400 Subject: [PATCH 008/102] ui: group history preference, enable in new groups by default; core: create group history feature items (#3596) * Revert "core: do not create group history item (#3586)" This reverts commit 2834b192ce8e10ef17bb240623df4211bbea378c. * ios: group history preference * fix tests * android * texts * enable in new groups ios * enable in new groups android * android texts * ios texts * remove ellipsis --------- Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> --- .../Views/Chat/ContactPreferencesView.swift | 1 - .../Chat/Group/GroupPreferencesView.swift | 2 +- .../Shared/Views/NewChat/AddGroupView.swift | 1 + .../Views/UserSettings/PreferencesView.swift | 1 - apps/ios/SimpleXChat/ChatTypes.swift | 57 +++++++++++++------ .../chat/simplex/common/model/SimpleXAPI.kt | 31 +++++++--- .../views/chat/group/GroupPreferences.kt | 5 ++ .../common/views/newchat/AddGroupView.kt | 3 +- .../commonMain/resources/MR/base/strings.xml | 19 ++++--- .../resources/MR/images/ic_schedule.svg | 1 + .../MR/images/ic_schedule_filled.svg | 1 + src/Simplex/Chat.hs | 4 +- src/Simplex/Chat/Types/Preferences.hs | 10 ++-- tests/ChatTests/Groups.hs | 6 +- tests/ChatTests/Utils.hs | 4 +- 15 files changed, 98 insertions(+), 48 deletions(-) create mode 100644 apps/multiplatform/common/src/commonMain/resources/MR/images/ic_schedule.svg create mode 100644 apps/multiplatform/common/src/commonMain/resources/MR/images/ic_schedule_filled.svg diff --git a/apps/ios/Shared/Views/Chat/ContactPreferencesView.swift b/apps/ios/Shared/Views/Chat/ContactPreferencesView.swift index ff1892d996..57007fff3f 100644 --- a/apps/ios/Shared/Views/Chat/ContactPreferencesView.swift +++ b/apps/ios/Shared/Views/Chat/ContactPreferencesView.swift @@ -116,7 +116,6 @@ struct ContactPreferencesView: View { private func featureFooter(_ feature: ChatFeature, _ enabled: FeatureEnabled) -> some View { Text(feature.enabledDescription(enabled)) - .frame(height: 36, alignment: .topLeading) } private func savePreferences() { diff --git a/apps/ios/Shared/Views/Chat/Group/GroupPreferencesView.swift b/apps/ios/Shared/Views/Chat/Group/GroupPreferencesView.swift index 860a6febb0..d88bdfa4a4 100644 --- a/apps/ios/Shared/Views/Chat/Group/GroupPreferencesView.swift +++ b/apps/ios/Shared/Views/Chat/Group/GroupPreferencesView.swift @@ -28,6 +28,7 @@ struct GroupPreferencesView: View { featureSection(.reactions, $preferences.reactions.enable) featureSection(.voice, $preferences.voice.enable) featureSection(.files, $preferences.files.enable) + featureSection(.history, $preferences.history.enable) if groupInfo.canEdit { Section { @@ -96,7 +97,6 @@ struct GroupPreferencesView: View { } } footer: { Text(feature.enableDescription(enableFeature.wrappedValue, groupInfo.canEdit)) - .frame(height: 36, alignment: .topLeading) } } diff --git a/apps/ios/Shared/Views/NewChat/AddGroupView.swift b/apps/ios/Shared/Views/NewChat/AddGroupView.swift index 6c7919669b..3f3623033e 100644 --- a/apps/ios/Shared/Views/NewChat/AddGroupView.swift +++ b/apps/ios/Shared/Views/NewChat/AddGroupView.swift @@ -187,6 +187,7 @@ struct AddGroupView: View { hideKeyboard() do { profile.displayName = profile.displayName.trimmingCharacters(in: .whitespaces) + profile.groupPreferences = GroupPreferences(history: GroupPreference(enable: .on)) let gInfo = try apiNewGroup(incognito: incognitoDefault, groupProfile: profile) Task { let groupMembers = await apiListMembers(gInfo.groupId) diff --git a/apps/ios/Shared/Views/UserSettings/PreferencesView.swift b/apps/ios/Shared/Views/UserSettings/PreferencesView.swift index 960afb6d38..2e560f8578 100644 --- a/apps/ios/Shared/Views/UserSettings/PreferencesView.swift +++ b/apps/ios/Shared/Views/UserSettings/PreferencesView.swift @@ -63,7 +63,6 @@ struct PreferencesView: View { private func featureFooter(_ feature: ChatFeature, _ allowFeature: Binding) -> some View { Text(feature.allowDescription(allowFeature.wrappedValue)) - .frame(height: 36, alignment: .topLeading) } private func savePreferences() { diff --git a/apps/ios/SimpleXChat/ChatTypes.swift b/apps/ios/SimpleXChat/ChatTypes.swift index 02c693cd28..74e5e4a3cb 100644 --- a/apps/ios/SimpleXChat/ChatTypes.swift +++ b/apps/ios/SimpleXChat/ChatTypes.swift @@ -616,8 +616,8 @@ public enum ChatFeature: String, Decodable, Feature { } case .fullDelete: switch allowed { - case .always: return "Allow your contacts to irreversibly delete sent messages." - case .yes: return "Allow irreversible message deletion only if your contact allows it to you." + case .always: return "Allow your contacts to irreversibly delete sent messages. (24 hours)" + case .yes: return "Allow irreversible message deletion only if your contact allows it to you. (24 hours)" case .no: return "Contacts can mark messages for deletion; you will be able to view them." } case .reactions: @@ -653,11 +653,11 @@ public enum ChatFeature: String, Decodable, Feature { : "Disappearing messages are prohibited in this chat." case .fullDelete: return enabled.forUser && enabled.forContact - ? "Both you and your contact can irreversibly delete sent messages." + ? "Both you and your contact can irreversibly delete sent messages. (24 hours)" : enabled.forUser - ? "Only you can irreversibly delete messages (your contact can mark them for deletion)." + ? "Only you can irreversibly delete messages (your contact can mark them for deletion). (24 hours)" : enabled.forContact - ? "Only your contact can irreversibly delete messages (you can mark them for deletion)." + ? "Only your contact can irreversibly delete messages (you can mark them for deletion). (24 hours)" : "Irreversible message deletion is prohibited in this chat." case .reactions: return enabled.forUser && enabled.forContact @@ -694,6 +694,7 @@ public enum GroupFeature: String, Decodable, Feature { case reactions case voice case files + case history public var id: Self { self } @@ -712,6 +713,7 @@ public enum GroupFeature: String, Decodable, Feature { case .reactions: return NSLocalizedString("Message reactions", comment: "chat feature") case .voice: return NSLocalizedString("Voice messages", comment: "chat feature") case .files: return NSLocalizedString("Files and media", comment: "chat feature") + case .history: return NSLocalizedString("Visible history", comment: "chat feature") } } @@ -723,6 +725,7 @@ public enum GroupFeature: String, Decodable, Feature { case .reactions: return "face.smiling" case .voice: return "mic" case .files: return "doc" + case .history: return "clock" } } @@ -734,6 +737,7 @@ public enum GroupFeature: String, Decodable, Feature { case .reactions: return "face.smiling.fill" case .voice: return "mic.fill" case .files: return "doc.fill" + case .history: return "clock.fill" } } @@ -759,7 +763,7 @@ public enum GroupFeature: String, Decodable, Feature { } case .fullDelete: switch enabled { - case .on: return "Allow to irreversibly delete sent messages." + case .on: return "Allow to irreversibly delete sent messages. (24 hours)" case .off: return "Prohibit irreversible message deletion." } case .reactions: @@ -777,6 +781,11 @@ public enum GroupFeature: String, Decodable, Feature { case .on: return "Allow to send files and media." case .off: return "Prohibit sending files and media." } + case .history: + switch enabled { + case .on: return "Send up to 100 last messages to new members." + case .off: return "Do not send history to new members." + } } } else { switch self { @@ -792,7 +801,7 @@ public enum GroupFeature: String, Decodable, Feature { } case .fullDelete: switch enabled { - case .on: return "Group members can irreversibly delete sent messages." + case .on: return "Group members can irreversibly delete sent messages. (24 hours)" case .off: return "Irreversible message deletion is prohibited in this group." } case .reactions: @@ -810,6 +819,11 @@ public enum GroupFeature: String, Decodable, Feature { case .on: return "Group members can send files and media." case .off: return "Files and media are prohibited in this group." } + case .history: + switch enabled { + case .on: return "Up to 100 last messages are sent to new members." + case .off: return "History is not sent to new members." + } } } } @@ -949,6 +963,7 @@ public struct FullGroupPreferences: Decodable, Equatable { public var reactions: GroupPreference public var voice: GroupPreference public var files: GroupPreference + public var history: GroupPreference public init( timedMessages: TimedMessagesGroupPreference, @@ -956,7 +971,8 @@ public struct FullGroupPreferences: Decodable, Equatable { fullDelete: GroupPreference, reactions: GroupPreference, voice: GroupPreference, - files: GroupPreference + files: GroupPreference, + history: GroupPreference ) { self.timedMessages = timedMessages self.directMessages = directMessages @@ -964,6 +980,7 @@ public struct FullGroupPreferences: Decodable, Equatable { self.reactions = reactions self.voice = voice self.files = files + self.history = history } public static let sampleData = FullGroupPreferences( @@ -972,7 +989,8 @@ public struct FullGroupPreferences: Decodable, Equatable { fullDelete: GroupPreference(enable: .off), reactions: GroupPreference(enable: .on), voice: GroupPreference(enable: .on), - files: GroupPreference(enable: .on) + files: GroupPreference(enable: .on), + history: GroupPreference(enable: .on) ) } @@ -983,14 +1001,16 @@ public struct GroupPreferences: Codable { public var reactions: GroupPreference? public var voice: GroupPreference? public var files: GroupPreference? + public var history: GroupPreference? public init( - timedMessages: TimedMessagesGroupPreference?, - directMessages: GroupPreference?, - fullDelete: GroupPreference?, - reactions: GroupPreference?, - voice: GroupPreference?, - files: GroupPreference? + timedMessages: TimedMessagesGroupPreference? = nil, + directMessages: GroupPreference? = nil, + fullDelete: GroupPreference? = nil, + reactions: GroupPreference? = nil, + voice: GroupPreference? = nil, + files: GroupPreference? = nil, + history: GroupPreference? = nil ) { self.timedMessages = timedMessages self.directMessages = directMessages @@ -998,6 +1018,7 @@ public struct GroupPreferences: Codable { self.reactions = reactions self.voice = voice self.files = files + self.history = history } public static let sampleData = GroupPreferences( @@ -1006,7 +1027,8 @@ public struct GroupPreferences: Codable { fullDelete: GroupPreference(enable: .off), reactions: GroupPreference(enable: .on), voice: GroupPreference(enable: .on), - files: GroupPreference(enable: .on) + files: GroupPreference(enable: .on), + history: GroupPreference(enable: .on) ) } @@ -1017,7 +1039,8 @@ public func toGroupPreferences(_ fullPreferences: FullGroupPreferences) -> Group fullDelete: fullPreferences.fullDelete, reactions: fullPreferences.reactions, voice: fullPreferences.voice, - files: fullPreferences.files + files: fullPreferences.files, + history: fullPreferences.history ) } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt index 619238f6d3..e2ab3a4d99 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt @@ -3308,7 +3308,8 @@ enum class GroupFeature: Feature { @SerialName("fullDelete") FullDelete, @SerialName("reactions") Reactions, @SerialName("voice") Voice, - @SerialName("files") Files; + @SerialName("files") Files, + @SerialName("history") History; override val hasParam: Boolean get() = when(this) { TimedMessages -> true @@ -3323,6 +3324,7 @@ enum class GroupFeature: Feature { Reactions -> generalGetString(MR.strings.message_reactions) Voice -> generalGetString(MR.strings.voice_messages) Files -> generalGetString(MR.strings.files_and_media) + History -> generalGetString(MR.strings.recent_history) } val icon: Painter @@ -3333,6 +3335,7 @@ enum class GroupFeature: Feature { Reactions -> painterResource(MR.images.ic_add_reaction) Voice -> painterResource(MR.images.ic_keyboard_voice) Files -> painterResource(MR.images.ic_draft) + History -> painterResource(MR.images.ic_schedule) } @Composable @@ -3343,6 +3346,7 @@ enum class GroupFeature: Feature { Reactions -> painterResource(MR.images.ic_add_reaction_filled) Voice -> painterResource(MR.images.ic_keyboard_voice_filled) Files -> painterResource(MR.images.ic_draft_filled) + History -> painterResource(MR.images.ic_schedule_filled) } fun enableDescription(enabled: GroupFeatureEnabled, canEdit: Boolean): String = @@ -3372,6 +3376,10 @@ enum class GroupFeature: Feature { GroupFeatureEnabled.ON -> generalGetString(MR.strings.allow_to_send_files) GroupFeatureEnabled.OFF -> generalGetString(MR.strings.prohibit_sending_files) } + History -> when(enabled) { + GroupFeatureEnabled.ON -> generalGetString(MR.strings.enable_sending_recent_history) + GroupFeatureEnabled.OFF -> generalGetString(MR.strings.disable_sending_recent_history) + } } } else { when(this) { @@ -3399,6 +3407,10 @@ enum class GroupFeature: Feature { GroupFeatureEnabled.ON -> generalGetString(MR.strings.group_members_can_send_files) GroupFeatureEnabled.OFF -> generalGetString(MR.strings.files_are_prohibited_in_group) } + History -> when(enabled) { + GroupFeatureEnabled.ON -> generalGetString(MR.strings.recent_history_is_sent_to_new_members) + GroupFeatureEnabled.OFF -> generalGetString(MR.strings.recent_history_is_not_sent_to_new_members) + } } } } @@ -3513,6 +3525,7 @@ data class FullGroupPreferences( val reactions: GroupPreference, val voice: GroupPreference, val files: GroupPreference, + val history: GroupPreference, ) { fun toGroupPreferences(): GroupPreferences = GroupPreferences( @@ -3522,6 +3535,7 @@ data class FullGroupPreferences( reactions = reactions, voice = voice, files = files, + history = history ) companion object { @@ -3532,18 +3546,20 @@ data class FullGroupPreferences( reactions = GroupPreference(GroupFeatureEnabled.ON), voice = GroupPreference(GroupFeatureEnabled.ON), files = GroupPreference(GroupFeatureEnabled.ON), + history = GroupPreference(GroupFeatureEnabled.ON), ) } } @Serializable data class GroupPreferences( - val timedMessages: TimedMessagesGroupPreference?, - val directMessages: GroupPreference?, - val fullDelete: GroupPreference?, - val reactions: GroupPreference?, - val voice: GroupPreference?, - val files: GroupPreference?, + val timedMessages: TimedMessagesGroupPreference? = null, + val directMessages: GroupPreference? = null, + val fullDelete: GroupPreference? = null, + val reactions: GroupPreference? = null, + val voice: GroupPreference? = null, + val files: GroupPreference? = null, + val history: GroupPreference? = null, ) { companion object { val sampleData = GroupPreferences( @@ -3553,6 +3569,7 @@ data class GroupPreferences( reactions = GroupPreference(GroupFeatureEnabled.ON), voice = GroupPreference(GroupFeatureEnabled.ON), files = GroupPreference(GroupFeatureEnabled.ON), + history = GroupPreference(GroupFeatureEnabled.ON), ) } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupPreferences.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupPreferences.kt index 3cdfaad2d9..bd584f0c8b 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupPreferences.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupPreferences.kt @@ -112,6 +112,11 @@ private fun GroupPreferencesLayout( FeatureSection(GroupFeature.Files, allowFiles, groupInfo, preferences, onTTLUpdated) { applyPrefs(preferences.copy(files = GroupPreference(enable = it))) } + SectionDividerSpaced(true, maxBottomPadding = false) + val enableHistory = remember(preferences) { mutableStateOf(preferences.history.enable) } + FeatureSection(GroupFeature.History, enableHistory, groupInfo, preferences, onTTLUpdated) { + applyPrefs(preferences.copy(history = GroupPreference(enable = it))) + } if (groupInfo.canEdit) { SectionDividerSpaced(maxTopPadding = true, maxBottomPadding = false) ResetSaveButtons( diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/AddGroupView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/AddGroupView.kt index 4f71e81b0d..eca579bcc8 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/AddGroupView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/AddGroupView.kt @@ -139,7 +139,8 @@ fun AddGroupLayout( createGroup(incognito.value, GroupProfile( displayName = displayName.value.trim(), fullName = "", - image = profileImage.value + image = profileImage.value, + groupPreferences = GroupPreferences(history = GroupPreference(GroupFeatureEnabled.ON)) )) }, textColor = MaterialTheme.colors.primary, diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml index e30b4eb56d..09ccf1e409 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml @@ -1461,6 +1461,7 @@ Message reactions Voice messages Files and media + Visible history Audio/video calls \nAvailable in v5.1 enabled @@ -1473,8 +1474,8 @@ Allow your contacts to send disappearing messages. Allow disappearing messages only if your contact allows them. Prohibit sending disappearing messages. - Allow your contacts to irreversibly delete sent messages. - Allow irreversible message deletion only if your contact allows it to you. + Allow your contacts to irreversibly delete sent messages. (24 hours) + Allow irreversible message deletion only if your contact allows it to you. (24 hours) Contacts can mark messages for deletion; you will be able to view them. Allow your contacts to send voice messages. Allow voice messages only if your contact allows them. @@ -1489,9 +1490,9 @@ Only you can send disappearing messages. Only your contact can send disappearing messages. Disappearing messages are prohibited in this chat. - Both you and your contact can irreversibly delete sent messages. - Only you can irreversibly delete messages (your contact can mark them for deletion). - Only your contact can irreversibly delete messages (you can mark them for deletion). + Both you and your contact can irreversibly delete sent messages. (24 hours) + Only you can irreversibly delete messages (your contact can mark them for deletion). (24 hours) + Only your contact can irreversibly delete messages (you can mark them for deletion). (24 hours) Irreversible message deletion is prohibited in this chat. Both you and your contact can send voice messages. Only you can send voice messages. @@ -1509,7 +1510,7 @@ Prohibit sending disappearing messages. Allow sending direct messages to members. Prohibit sending direct messages to members. - Allow to irreversibly delete sent messages. + Allow to irreversibly delete sent messages. (24 hours) Prohibit irreversible message deletion. Allow to send voice messages. Prohibit sending voice messages. @@ -1517,11 +1518,13 @@ Prohibit messages reactions. Allow to send files and media. Prohibit sending files and media. + Send up to 100 last messages to new members. + Do not send history to new members. Group members can send disappearing messages. Disappearing messages are prohibited in this group. Group members can send direct messages. Direct messages between members are prohibited in this group. - Group members can irreversibly delete sent messages. + Group members can irreversibly delete sent messages. (24 hours) Irreversible message deletion is prohibited in this group. Group members can send voice messages. Voice messages are prohibited in this group. @@ -1529,6 +1532,8 @@ Message reactions are prohibited in this group. Group members can send files and media. Files and media are prohibited in this group. + Up to 100 last messages are sent to new members. + History is not sent to new members. Delete after %d sec %ds diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_schedule.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_schedule.svg new file mode 100644 index 0000000000..4bd8e90cb6 --- /dev/null +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_schedule.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_schedule_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_schedule_filled.svg new file mode 100644 index 0000000000..368e2fcc1f --- /dev/null +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_schedule_filled.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/Simplex/Chat.hs b/src/Simplex/Chat.hs index 1b61fb7487..fb2abf23d7 100644 --- a/src/Simplex/Chat.hs +++ b/src/Simplex/Chat.hs @@ -4798,7 +4798,7 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage = createGroupFeatureItems :: GroupInfo -> GroupMember -> m () createGroupFeatureItems g@GroupInfo {fullGroupPreferences} m = - forM_ allGroupFeatureItems $ \(AGF f) -> do + forM_ allGroupFeatures $ \(AGF f) -> do let p = getGroupPreference f fullGroupPreferences (_, param) = groupFeatureState p createInternalChatItem user (CDGroupRcv g m) (CIRcvGroupFeature (toGroupFeature f) (toGroupPreference p) param) Nothing @@ -6002,7 +6002,7 @@ createFeatureItems user Contact {mergedPreferences = cups} ct'@Contact {mergedPr createGroupFeatureChangedItems :: (MsgDirectionI d, ChatMonad m) => User -> ChatDirection 'CTGroup d -> (GroupFeature -> GroupPreference -> Maybe Int -> CIContent d) -> GroupInfo -> GroupInfo -> m () createGroupFeatureChangedItems user cd ciContent GroupInfo {fullGroupPreferences = gps} GroupInfo {fullGroupPreferences = gps'} = - forM_ allGroupFeatureItems $ \(AGF f) -> do + forM_ allGroupFeatures $ \(AGF f) -> do let state = groupFeatureState $ getGroupPreference f gps pref' = getGroupPreference f gps' state'@(_, int') = groupFeatureState pref' diff --git a/src/Simplex/Chat/Types/Preferences.hs b/src/Simplex/Chat/Types/Preferences.hs index 18a10a83f4..5c79680c50 100644 --- a/src/Simplex/Chat/Types/Preferences.hs +++ b/src/Simplex/Chat/Types/Preferences.hs @@ -184,19 +184,17 @@ groupFeatureAllowed' :: GroupFeatureI f => SGroupFeature f -> FullGroupPreferenc groupFeatureAllowed' feature prefs = getField @"enable" (getGroupPreference feature prefs) == FEOn -allGroupFeatureItems :: [AGroupFeature] -allGroupFeatureItems = +allGroupFeatures :: [AGroupFeature] +allGroupFeatures = [ AGF SGFTimedMessages, AGF SGFDirectMessages, AGF SGFFullDelete, AGF SGFReactions, AGF SGFVoice, - AGF SGFFiles + AGF SGFFiles, + AGF SGFHistory ] -allGroupFeatures :: [AGroupFeature] -allGroupFeatures = allGroupFeatureItems <> [AGF SGFHistory] - groupPrefSel :: SGroupFeature f -> GroupPreferences -> Maybe (GroupFeaturePreference f) groupPrefSel f ps = case f of SGFTimedMessages -> ps.timedMessages diff --git a/tests/ChatTests/Groups.hs b/tests/ChatTests/Groups.hs index 76bc520aa4..f90e7f14d8 100644 --- a/tests/ChatTests/Groups.hs +++ b/tests/ChatTests/Groups.hs @@ -2681,7 +2681,7 @@ testGroupLinkNoContact = ] threadDelay 100000 - alice #$> ("/_get chat #1 count=100", chat, [(0, "invited via your group link"), (0, "connected")]) + alice #$> ("/_get chat #1 count=100", chat, [(1, "Recent history: off"), (0, "invited via your group link"), (0, "connected")]) alice @@@ [("#team", "connected")] bob @@@ [("#team", "connected")] @@ -2744,7 +2744,7 @@ testGroupLinkNoContactInviteesWereConnected = ] threadDelay 100000 - alice #$> ("/_get chat #1 count=100", chat, [(0, "invited via your group link"), (0, "connected")]) + alice #$> ("/_get chat #1 count=100", chat, [(1, "Recent history: off"), (0, "invited via your group link"), (0, "connected")]) alice @@@ [("#team", "connected")] bob @@@ [("#team", "connected"), ("@cath", "hey")] @@ -2825,7 +2825,7 @@ testGroupLinkNoContactAllMembersWereConnected = ] threadDelay 100000 - alice #$> ("/_get chat #1 count=100", chat, [(0, "invited via your group link"), (0, "connected")]) + alice #$> ("/_get chat #1 count=100", chat, [(1, "Recent history: off"), (0, "invited via your group link"), (0, "connected")]) alice @@@ [("#team", "connected"), ("@bob", "hey"), ("@cath", "hey")] bob @@@ [("#team", "connected"), ("@alice", "hey"), ("@cath", "hey")] diff --git a/tests/ChatTests/Utils.hs b/tests/ChatTests/Utils.hs index 65fa3bc4c1..ac87311c9e 100644 --- a/tests/ChatTests/Utils.hs +++ b/tests/ChatTests/Utils.hs @@ -223,8 +223,8 @@ groupFeatures'' = ((0, "Full deletion: off"), Nothing, Nothing), ((0, "Message reactions: on"), Nothing, Nothing), ((0, "Voice messages: on"), Nothing, Nothing), - ((0, "Files and media: on"), Nothing, Nothing) - -- ((0, "Recent history: on"), Nothing, Nothing) + ((0, "Files and media: on"), Nothing, Nothing), + ((0, "Recent history: on"), Nothing, Nothing) ] itemId :: Int -> String From 1438fd00e2164608e99cdd42917978dc304de16e Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Sat, 30 Dec 2023 00:47:25 +0700 Subject: [PATCH 009/102] android, desktop: self destruct becomes better (#3598) * android, desktop: self destruct becomes better * better way of doing it * fix script * firstOrNull * changes for review * comment --------- Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> --- .../main/java/chat/simplex/app/SimplexApp.kt | 5 +- .../src/commonMain/cpp/android/simplex-api.c | 7 ++ .../src/commonMain/cpp/desktop/simplex-api.c | 7 ++ .../kotlin/chat/simplex/common/App.kt | 5 +- .../chat/simplex/common/model/ChatModel.kt | 1 + .../chat/simplex/common/model/SimpleXAPI.kt | 10 +- .../chat/simplex/common/platform/Core.kt | 117 ++++++++++-------- .../common/views/chatlist/UserPicker.kt | 5 +- .../common/views/database/DatabaseView.kt | 20 ++- .../common/views/helpers/DatabaseUtils.kt | 10 +- .../common/views/localauth/LocalAuthView.kt | 57 +++++++-- .../common/views/localauth/PasscodeView.kt | 13 +- .../views/localauth/SetAppPasscodeView.kt | 5 +- .../views/usersettings/PrivacySettings.kt | 4 +- .../commonMain/resources/MR/base/strings.xml | 1 + .../common/platform/AppCommon.desktop.kt | 8 +- libsimplex.dll.def | 1 + 17 files changed, 188 insertions(+), 88 deletions(-) diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/SimplexApp.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/SimplexApp.kt index a8c8b5c1b2..84b39e983f 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/SimplexApp.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/SimplexApp.kt @@ -63,10 +63,7 @@ class SimplexApp: Application(), LifecycleEventObserver { tmpDir.deleteRecursively() tmpDir.mkdir() - withBGApi { - initChatController() - runMigrations() - } + initChatControllerAndRunMigrations(false) ProcessLifecycleOwner.get().lifecycle.addObserver(this@SimplexApp) } diff --git a/apps/multiplatform/common/src/commonMain/cpp/android/simplex-api.c b/apps/multiplatform/common/src/commonMain/cpp/android/simplex-api.c index 676c58fb49..5936bd5ff2 100644 --- a/apps/multiplatform/common/src/commonMain/cpp/android/simplex-api.c +++ b/apps/multiplatform/common/src/commonMain/cpp/android/simplex-api.c @@ -57,6 +57,7 @@ typedef long* chat_ctrl; */ extern char *chat_migrate_init(const char *path, const char *key, const char *confirm, chat_ctrl *ctrl); +extern char *chat_close_store(chat_ctrl ctrl); extern char *chat_send_cmd(chat_ctrl ctrl, const char *cmd); extern char *chat_send_remote_cmd(chat_ctrl ctrl, const int rhId, const char *cmd); extern char *chat_recv_msg(chat_ctrl ctrl); // deprecated @@ -93,6 +94,12 @@ Java_chat_simplex_common_platform_CoreKt_chatMigrateInit(JNIEnv *env, __unused j return ret; } +JNIEXPORT jstring JNICALL +Java_chat_simplex_common_platform_CoreKt_chatCloseStore(JNIEnv *env, __unused jclass clazz, jlong controller) { + jstring res = (*env)->NewStringUTF(env, chat_close_store((void*)controller)); + return res; +} + JNIEXPORT jstring JNICALL Java_chat_simplex_common_platform_CoreKt_chatSendCmd(JNIEnv *env, __unused jclass clazz, jlong controller, jstring msg) { const char *_msg = (*env)->GetStringUTFChars(env, msg, JNI_FALSE); diff --git a/apps/multiplatform/common/src/commonMain/cpp/desktop/simplex-api.c b/apps/multiplatform/common/src/commonMain/cpp/desktop/simplex-api.c index 292715bdc5..f15689285a 100644 --- a/apps/multiplatform/common/src/commonMain/cpp/desktop/simplex-api.c +++ b/apps/multiplatform/common/src/commonMain/cpp/desktop/simplex-api.c @@ -30,6 +30,7 @@ typedef long* chat_ctrl; */ extern char *chat_migrate_init(const char *path, const char *key, const char *confirm, chat_ctrl *ctrl); +extern char *chat_close_store(chat_ctrl ctrl); extern char *chat_send_cmd(chat_ctrl ctrl, const char *cmd); extern char *chat_send_remote_cmd(chat_ctrl ctrl, const int rhId, const char *cmd); extern char *chat_recv_msg(chat_ctrl ctrl); // deprecated @@ -106,6 +107,12 @@ Java_chat_simplex_common_platform_CoreKt_chatMigrateInit(JNIEnv *env, jclass cla return ret; } +JNIEXPORT jstring JNICALL +Java_chat_simplex_common_platform_CoreKt_chatCloseStore(JNIEnv *env, jclass clazz, jlong controller) { + jstring res = decode_to_utf8_string(env, chat_close_store((void*)controller)); + return res; +} + JNIEXPORT jstring JNICALL Java_chat_simplex_common_platform_CoreKt_chatSendCmd(JNIEnv *env, jclass clazz, jlong controller, jstring msg) { const char *_msg = encode_to_utf8_chars(env, msg); diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/App.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/App.kt index 950515f055..f61f3b4b80 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/App.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/App.kt @@ -103,13 +103,15 @@ fun MainScreen() { } Box { + val unauthorized = remember { derivedStateOf { AppLock.userAuthorized.value != true } } val onboarding by remember { chatModel.controller.appPrefs.onboardingStage.state } val localUserCreated = chatModel.localUserCreated.value var showInitializationView by remember { mutableStateOf(false) } when { chatModel.chatDbStatus.value == null && showInitializationView -> DefaultProgressView(stringResource(MR.strings.opening_database)) showChatDatabaseError -> { - chatModel.chatDbStatus.value?.let { + // Prevent showing keyboard on Android when: passcode enabled and database password not saved + if (!unauthorized.value && chatModel.chatDbStatus.value != null) { DatabaseErrorView(chatModel.chatDbStatus, chatModel.controller.appPrefs) } } @@ -150,7 +152,6 @@ fun MainScreen() { SwitchingUsersView() } - val unauthorized = remember { derivedStateOf { AppLock.userAuthorized.value != true } } if (unauthorized.value && !(chatModel.activeCallViewIsVisible.value && chatModel.showCallView.value)) { LaunchedEffect(Unit) { // With these constrains when user presses back button while on ChatList, activity destroys and shows auth request 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 f51f6986f8..b8d421b07b 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 @@ -47,6 +47,7 @@ object ChatModel { val chatDbChanged = mutableStateOf(false) val chatDbEncrypted = mutableStateOf(false) val chatDbStatus = mutableStateOf(null) + val ctrlInitInProgress = mutableStateOf(false) val chats = mutableStateListOf() // map of connections network statuses, key is agent connection id val networkStatuses = mutableStateMapOf() diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt index e2ab3a4d99..07e091b484 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt @@ -2145,7 +2145,15 @@ class SharedPreference(val get: () -> T, set: (T) -> Unit) { init { this.set = { value -> set(value) - _state.value = value + try { + _state.value = value + } catch (e: IllegalStateException) { + // Can be `Reading a state that was created after the snapshot was taken or in a snapshot that has not yet been applied` + Log.i(TAG, e.stackTraceToString()) + withApi { + _state.value = value + } + } } } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Core.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Core.kt index 52ff269f54..07e59a55e0 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Core.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Core.kt @@ -14,6 +14,7 @@ external fun pipeStdOutToSocket(socketName: String) : Int // SimpleX API typealias ChatCtrl = Long external fun chatMigrateInit(dbPath: String, dbKey: String, confirm: String): Array +external fun chatCloseStore(ctrl: ChatCtrl): String external fun chatSendCmd(ctrl: ChatCtrl, msg: String): String external fun chatSendRemoteCmd(ctrl: ChatCtrl, rhId: Int, msg: String): String external fun chatRecvMsg(ctrl: ChatCtrl): String @@ -35,57 +36,71 @@ val appPreferences: AppPreferences val chatController: ChatController = ChatController -suspend fun initChatController(useKey: String? = null, confirmMigrations: MigrationConfirmation? = null, startChat: Boolean = true) { - val dbKey = useKey ?: DatabaseUtils.useDatabaseKey() - val confirm = confirmMigrations ?: if (appPreferences.confirmDBUpgrades.get()) MigrationConfirmation.Error else MigrationConfirmation.YesUp - val migrated: Array = chatMigrateInit(dbAbsolutePrefixPath, dbKey, confirm.value) - val res: DBMigrationResult = kotlin.runCatching { - json.decodeFromString(migrated[0] as String) - }.getOrElse { DBMigrationResult.Unknown(migrated[0] as String) } - val ctrl = if (res is DBMigrationResult.OK) { - migrated[1] as Long - } else null - chatController.ctrl = ctrl - chatModel.chatDbEncrypted.value = dbKey != "" - chatModel.chatDbStatus.value = res - if (res != DBMigrationResult.OK) { - Log.d(TAG, "Unable to migrate successfully: $res") - } else if (startChat) { - // If we migrated successfully means previous re-encryption process on database level finished successfully too - if (appPreferences.encryptionStartedAt.get() != null) appPreferences.encryptionStartedAt.set(null) - val user = chatController.apiGetActiveUser(null) - if (user == null) { - chatModel.controller.appPrefs.privacyDeliveryReceiptsSet.set(true) - chatModel.currentUser.value = null - chatModel.users.clear() - if (appPlatform.isDesktop) { - /** - * Setting it here to null because otherwise the screen will flash in [MainScreen] after the first start - * because of default value of [OnboardingStage.OnboardingComplete] - * */ - chatModel.localUserCreated.value = null - if (chatController.listRemoteHosts()?.isEmpty() == true) { - chatController.appPrefs.onboardingStage.set(OnboardingStage.Step1_SimpleXInfo) - } - chatController.startChatWithoutUser() - } else { - chatController.appPrefs.onboardingStage.set(OnboardingStage.Step1_SimpleXInfo) - } - } else { - val savedOnboardingStage = appPreferences.onboardingStage.get() - val newStage = if (listOf(OnboardingStage.Step1_SimpleXInfo, OnboardingStage.Step2_CreateProfile).contains(savedOnboardingStage) && chatModel.users.size == 1) { - OnboardingStage.Step3_CreateSimpleXAddress - } else { - savedOnboardingStage - } - if (appPreferences.onboardingStage.get() != newStage) { - appPreferences.onboardingStage.set(newStage) - } - if (appPreferences.onboardingStage.get() == OnboardingStage.OnboardingComplete && !chatModel.controller.appPrefs.privacyDeliveryReceiptsSet.get()) { - chatModel.setDeliveryReceipts.value = true - } - chatController.startChat(user) - platform.androidChatInitializedAndStarted() +fun initChatControllerAndRunMigrations(ignoreSelfDestruct: Boolean) { + if (ignoreSelfDestruct || DatabaseUtils.ksSelfDestructPassword.get() == null) { + withBGApi { + initChatController() + runMigrations() } } } + +suspend fun initChatController(useKey: String? = null, confirmMigrations: MigrationConfirmation? = null, startChat: Boolean = true) { + try { + chatModel.ctrlInitInProgress.value = true + val dbKey = useKey ?: DatabaseUtils.useDatabaseKey() + val confirm = confirmMigrations ?: if (appPreferences.confirmDBUpgrades.get()) MigrationConfirmation.Error else MigrationConfirmation.YesUp + val migrated: Array = chatMigrateInit(dbAbsolutePrefixPath, dbKey, confirm.value) + val res: DBMigrationResult = kotlin.runCatching { + json.decodeFromString(migrated[0] as String) + }.getOrElse { DBMigrationResult.Unknown(migrated[0] as String) } + val ctrl = if (res is DBMigrationResult.OK) { + migrated[1] as Long + } else null + chatController.ctrl = ctrl + chatModel.chatDbEncrypted.value = dbKey != "" + chatModel.chatDbStatus.value = res + if (res != DBMigrationResult.OK) { + Log.d(TAG, "Unable to migrate successfully: $res") + } else if (startChat) { + // If we migrated successfully means previous re-encryption process on database level finished successfully too + if (appPreferences.encryptionStartedAt.get() != null) appPreferences.encryptionStartedAt.set(null) + val user = chatController.apiGetActiveUser(null) + if (user == null) { + chatModel.controller.appPrefs.privacyDeliveryReceiptsSet.set(true) + chatModel.currentUser.value = null + chatModel.users.clear() + if (appPlatform.isDesktop) { + /** + * Setting it here to null because otherwise the screen will flash in [MainScreen] after the first start + * because of default value of [OnboardingStage.OnboardingComplete] + * */ + chatModel.localUserCreated.value = null + if (chatController.listRemoteHosts()?.isEmpty() == true) { + chatController.appPrefs.onboardingStage.set(OnboardingStage.Step1_SimpleXInfo) + } + chatController.startChatWithoutUser() + } else { + chatController.appPrefs.onboardingStage.set(OnboardingStage.Step1_SimpleXInfo) + } + } else { + val savedOnboardingStage = appPreferences.onboardingStage.get() + val newStage = if (listOf(OnboardingStage.Step1_SimpleXInfo, OnboardingStage.Step2_CreateProfile).contains(savedOnboardingStage) && chatModel.users.size == 1) { + OnboardingStage.Step3_CreateSimpleXAddress + } else { + savedOnboardingStage + } + if (appPreferences.onboardingStage.get() != newStage) { + appPreferences.onboardingStage.set(newStage) + } + if (appPreferences.onboardingStage.get() == OnboardingStage.OnboardingComplete && !chatModel.controller.appPrefs.privacyDeliveryReceiptsSet.get()) { + chatModel.setDeliveryReceipts.value = true + } + chatController.startChat(user) + platform.androidChatInitializedAndStarted() + } + } + } finally { + chatModel.ctrlInitInProgress.value = false + } +} diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/UserPicker.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/UserPicker.kt index d87c05a913..a0db4188ad 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/UserPicker.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/UserPicker.kt @@ -116,7 +116,10 @@ fun UserPicker( } } LaunchedEffect(Unit) { - controller.reloadRemoteHosts() + // Controller.ctrl can be null when self-destructing activates + if (controller.ctrl != null && controller.ctrl != -1L) { + controller.reloadRemoteHosts() + } } val UsersView: @Composable ColumnScope.() -> Unit = { users.forEach { u -> diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseView.kt index 224317f949..5e1abb6846 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseView.kt @@ -4,7 +4,6 @@ import SectionBottomSpacer import SectionDividerSpaced import SectionTextFooter import SectionItemView -import SectionSpacer import SectionView import androidx.compose.desktop.ui.tooling.preview.Preview import androidx.compose.foundation.layout.* @@ -426,6 +425,7 @@ private fun authStopChat(m: ChatModel) { } is LAResult.Error -> { m.chatRunning.value = true + laFailedAlert() } is LAResult.Failed -> { m.chatRunning.value = true @@ -459,6 +459,24 @@ suspend fun deleteChatAsync(m: ChatModel) { m.controller.apiDeleteStorage() DatabaseUtils.ksDatabasePassword.remove() m.controller.appPrefs.storeDBPassphrase.set(true) + deleteChatDatabaseFiles() +} + +fun deleteChatDatabaseFiles() { + val chat = File(dataDir, chatDatabaseFileName) + val chatBak = File(dataDir, "$chatDatabaseFileName.bak") + val agent = File(dataDir, agentDatabaseFileName) + val agentBak = File(dataDir, "$agentDatabaseFileName.bak") + chat.delete() + chatBak.delete() + agent.delete() + agentBak.delete() + filesDir.deleteRecursively() + remoteHostsDir.deleteRecursively() + tmpDir.deleteRecursively() + tmpDir.mkdir() + DatabaseUtils.ksDatabasePassword.remove() + controller.appPrefs.storeDBPassphrase.set(true) } private fun exportArchive( diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DatabaseUtils.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DatabaseUtils.kt index e7da47f8f0..c984e16452 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DatabaseUtils.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DatabaseUtils.kt @@ -17,7 +17,7 @@ object DatabaseUtils { val ksAppPassword = KeyStoreItem(APP_PASSWORD_ALIAS, appPreferences.encryptedAppPassphrase, appPreferences.initializationVectorAppPassphrase) val ksSelfDestructPassword = KeyStoreItem(SELF_DESTRUCT_PASSWORD_ALIAS, appPreferences.encryptedSelfDestructPassphrase, appPreferences.initializationVectorSelfDestructPassphrase) - class KeyStoreItem(private val alias: String, val passphrase: SharedPreference, val initVector: SharedPreference) { + class KeyStoreItem(val alias: String, val passphrase: SharedPreference, val initVector: SharedPreference) { fun get(): String? { return cryptor.decryptData( passphrase.get()?.toByteArrayFromBase64ForPassphrase() ?: return null, @@ -75,11 +75,11 @@ object DatabaseUtils { sealed class DBMigrationResult { @Serializable @SerialName("ok") object OK: DBMigrationResult() @Serializable @SerialName("invalidConfirmation") object InvalidConfirmation: DBMigrationResult() - @Serializable @SerialName("errorNotADatabase") class ErrorNotADatabase(val dbFile: String): DBMigrationResult() - @Serializable @SerialName("errorMigration") class ErrorMigration(val dbFile: String, val migrationError: MigrationError): DBMigrationResult() - @Serializable @SerialName("errorSQL") class ErrorSQL(val dbFile: String, val migrationSQLError: String): DBMigrationResult() + @Serializable @SerialName("errorNotADatabase") data class ErrorNotADatabase(val dbFile: String): DBMigrationResult() + @Serializable @SerialName("errorMigration") data class ErrorMigration(val dbFile: String, val migrationError: MigrationError): DBMigrationResult() + @Serializable @SerialName("errorSQL") data class ErrorSQL(val dbFile: String, val migrationSQLError: String): DBMigrationResult() @Serializable @SerialName("errorKeychain") object ErrorKeychain: DBMigrationResult() - @Serializable @SerialName("unknown") class Unknown(val json: String): DBMigrationResult() + @Serializable @SerialName("unknown") data class Unknown(val json: String): DBMigrationResult() } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/localauth/LocalAuthView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/localauth/LocalAuthView.kt index 468dd8580e..0401906527 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/localauth/LocalAuthView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/localauth/LocalAuthView.kt @@ -1,32 +1,45 @@ package chat.simplex.common.views.localauth -import androidx.compose.runtime.Composable -import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable +import chat.simplex.common.model.* +import chat.simplex.common.model.ChatModel.controller import dev.icerock.moko.resources.compose.stringResource -import chat.simplex.common.views.database.deleteChatAsync -import chat.simplex.common.views.database.stopChatAsync import chat.simplex.common.views.helpers.* import chat.simplex.common.views.helpers.DatabaseUtils.ksSelfDestructPassword import chat.simplex.common.views.helpers.DatabaseUtils.ksAppPassword import chat.simplex.common.views.onboarding.OnboardingStage -import chat.simplex.common.model.ChatModel -import chat.simplex.common.model.Profile import chat.simplex.common.platform.* +import chat.simplex.common.views.database.* import chat.simplex.res.MR +import kotlinx.coroutines.delay @Composable fun LocalAuthView(m: ChatModel, authRequest: LocalAuthRequest) { val passcode = rememberSaveable { mutableStateOf("") } - PasscodeView(passcode, authRequest.title ?: stringResource(MR.strings.la_enter_app_passcode), authRequest.reason, stringResource(MR.strings.submit_passcode), + val allowToReact = rememberSaveable { mutableStateOf(true) } + if (!allowToReact.value) { + BackHandler { + // do nothing until submit action finishes to prevent concurrent removing of storage + } + } + PasscodeView(passcode, authRequest.title ?: stringResource(MR.strings.la_enter_app_passcode), authRequest.reason, stringResource(MR.strings.submit_passcode), buttonsEnabled = allowToReact, submit = { val sdPassword = ksSelfDestructPassword.get() if (sdPassword == passcode.value && authRequest.selfDestruct) { + allowToReact.value = false deleteStorageAndRestart(m, sdPassword) { r -> authRequest.completed(r) } } else { - val r: LAResult = if (passcode.value == authRequest.password) LAResult.Success else LAResult.Error(generalGetString(MR.strings.incorrect_passcode)) + val r: LAResult = if (passcode.value == authRequest.password) { + if (authRequest.selfDestruct && sdPassword != null && controller.ctrl == -1L) { + initChatControllerAndRunMigrations(true) + } + LAResult.Success + } else { + LAResult.Error(generalGetString(MR.strings.incorrect_passcode)) + } authRequest.completed(r) } }, @@ -38,8 +51,28 @@ fun LocalAuthView(m: ChatModel, authRequest: LocalAuthRequest) { private fun deleteStorageAndRestart(m: ChatModel, password: String, completed: (LAResult) -> Unit) { withBGApi { try { - stopChatAsync(m) - deleteChatAsync(m) + /** Waiting until [initChatController] finishes */ + while (m.ctrlInitInProgress.value) { + delay(50) + } + if (m.chatRunning.value == true) { + stopChatAsync(m) + } + val ctrl = m.controller.ctrl + if (ctrl != null && ctrl != -1L) { + /** + * The following sequence can bring a user here: + * the user opened the app, entered app passcode, went to background, returned back, entered self-destruct code. + * In this case database should be closed to prevent possible situation when OS can deny database removal command + * */ + chatCloseStore(ctrl) + } + deleteChatDatabaseFiles() + // Clear sensitive data on screen just in case ModalManager will fail to prevent hiding its modals while database encrypts itself + m.chatId.value = null + m.chatItems.clear() + m.chats.clear() + m.users.clear() ksAppPassword.set(password) ksSelfDestructPassword.remove() ntfManager.cancelAllNotifications() @@ -67,13 +100,15 @@ private fun deleteStorageAndRestart(m: ChatModel, password: String, completed: ( m.currentUser.value = createdUser m.controller.appPrefs.onboardingStage.set(OnboardingStage.OnboardingComplete) if (createdUser != null) { + controller.chatModel.chatRunning.value = false m.controller.startChat(createdUser) } - ModalManager.fullscreen.closeModals() + ModalManager.closeAllModalsEverywhere() AlertManager.shared.hideAllAlerts() AlertManager.privacySensitive.hideAllAlerts() completed(LAResult.Success) } catch (e: Exception) { + Log.e(TAG, "Unable to delete storage: ${e.stackTraceToString()}") completed(LAResult.Error(generalGetString(MR.strings.incorrect_passcode))) } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/localauth/PasscodeView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/localauth/PasscodeView.kt index 4784951ad0..2b2f006d25 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/localauth/PasscodeView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/localauth/PasscodeView.kt @@ -12,6 +12,7 @@ import dev.icerock.moko.resources.compose.painterResource import androidx.compose.ui.unit.dp import chat.simplex.common.platform.* import chat.simplex.common.ui.theme.DEFAULT_PADDING +import chat.simplex.common.views.chat.group.ProgressIndicator import chat.simplex.common.views.helpers.SimpleButton import chat.simplex.common.views.helpers.* import chat.simplex.res.MR @@ -23,6 +24,7 @@ fun PasscodeView( reason: String? = null, submitLabel: String, submitEnabled: ((String) -> Boolean)? = null, + buttonsEnabled: State = remember { mutableStateOf(true) }, submit: () -> Unit, cancel: () -> Unit, ) { @@ -74,9 +76,9 @@ fun PasscodeView( } PasscodeEntry(passcode, true) Row(Modifier.heightIn(min = 70.dp), verticalAlignment = Alignment.CenterVertically) { - SimpleButton(generalGetString(MR.strings.cancel_verb), icon = painterResource(MR.images.ic_close), click = cancel) + SimpleButton(generalGetString(MR.strings.cancel_verb), icon = painterResource(MR.images.ic_close), disabled = !buttonsEnabled.value, click = cancel) Spacer(Modifier.size(20.dp)) - SimpleButton(submitLabel, icon = painterResource(MR.images.ic_done_filled), disabled = submitEnabled?.invoke(passcode.value) == false || passcode.value.length < 4, click = submit) + SimpleButton(submitLabel, icon = painterResource(MR.images.ic_done_filled), disabled = submitEnabled?.invoke(passcode.value) == false || passcode.value.length < 4 || !buttonsEnabled.value, click = submit) } } } @@ -117,8 +119,8 @@ fun PasscodeView( Modifier.padding(start = 30.dp).height(s * 3), verticalArrangement = Arrangement.SpaceEvenly ) { - SimpleButton(generalGetString(MR.strings.cancel_verb), icon = painterResource(MR.images.ic_close), click = cancel) - SimpleButton(submitLabel, icon = painterResource(MR.images.ic_done_filled), disabled = submitEnabled?.invoke(passcode.value) == false || passcode.value.length < 4, click = submit) + SimpleButton(generalGetString(MR.strings.cancel_verb), icon = painterResource(MR.images.ic_close), disabled = !buttonsEnabled.value, click = cancel) + SimpleButton(submitLabel, icon = painterResource(MR.images.ic_done_filled), disabled = submitEnabled?.invoke(passcode.value) == false || passcode.value.length < 4 || !buttonsEnabled.value, click = submit) } } } @@ -130,6 +132,9 @@ fun PasscodeView( } else { HorizontalLayout() } + if (!buttonsEnabled.value) { + ProgressIndicator() + } LaunchedEffect(Unit) { focusRequester.requestFocus() // Disallow to steal a focus by clicking on buttons or using Tab diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/localauth/SetAppPasscodeView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/localauth/SetAppPasscodeView.kt index 18437dbf98..eadd399428 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/localauth/SetAppPasscodeView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/localauth/SetAppPasscodeView.kt @@ -5,6 +5,7 @@ import androidx.compose.runtime.saveable.rememberSaveable import chat.simplex.common.platform.BackHandler import chat.simplex.common.views.helpers.DatabaseUtils import chat.simplex.common.views.helpers.DatabaseUtils.ksAppPassword +import chat.simplex.common.views.helpers.DatabaseUtils.ksSelfDestructPassword import chat.simplex.common.views.helpers.generalGetString import chat.simplex.res.MR @@ -48,7 +49,9 @@ fun SetAppPasscodeView( } } } else { - SetPasswordView(title, generalGetString(MR.strings.save_verb)) { + SetPasswordView(title, generalGetString(MR.strings.save_verb), + // Do not allow to set app passcode == selfDestruct passcode + submitEnabled = { pwd -> pwd != (if (passcodeKeychain.alias == ksSelfDestructPassword.alias) ksAppPassword else ksSelfDestructPassword).get() }) { enteredPassword = passcode.value passcode.value = "" confirming = true diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/PrivacySettings.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/PrivacySettings.kt index 3d2b7b7fa5..9a4f083746 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/PrivacySettings.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/PrivacySettings.kt @@ -429,6 +429,7 @@ fun SimplexLockView( ModalManager.fullscreen.showCustomModal { close -> Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background) { SetAppPasscodeView( + reason = generalGetString(MR.strings.la_app_passcode), submit = { passcodeAlert(generalGetString(MR.strings.passcode_changed)) }, cancel = { @@ -453,6 +454,7 @@ fun SimplexLockView( Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background) { SetAppPasscodeView( passcodeKeychain = ksSelfDestructPassword, + reason = generalGetString(MR.strings.self_destruct), submit = { selfDestructPasscodeAlert(generalGetString(MR.strings.self_destruct_passcode_changed)) }, cancel = { @@ -553,7 +555,7 @@ fun SimplexLockView( fontSize = 16.sp, modifier = Modifier.padding(bottom = DEFAULT_PADDING_HALF) ) - ProfileNameField(selfDestructDisplayName, "", ::isValidDisplayName) + ProfileNameField(selfDestructDisplayName, "", { isValidDisplayName(it.trim()) }) LaunchedEffect(selfDestructDisplayName.value) { val new = selfDestructDisplayName.value if (isValidDisplayName(new) && selfDestructDisplayNamePref.get() != new) { diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml index 09ccf1e409..8f5f6338fa 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml @@ -919,6 +919,7 @@ Authentication cancelled System Passcode + App passcode Off Passcode set! Passcode changed! diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/AppCommon.desktop.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/AppCommon.desktop.kt index 92111f162a..4e70956be7 100644 --- a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/AppCommon.desktop.kt +++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/AppCommon.desktop.kt @@ -2,8 +2,7 @@ package chat.simplex.common.platform import chat.simplex.common.model.* import chat.simplex.common.views.call.RcvCallInvitation -import chat.simplex.common.views.helpers.generalGetString -import chat.simplex.common.views.helpers.withBGApi +import chat.simplex.common.views.helpers.* import java.util.* import chat.simplex.res.MR @@ -25,10 +24,7 @@ fun initApp() { override fun cancelAllNotifications() = chat.simplex.common.model.NtfManager.cancelAllNotifications() } applyAppLocale() - withBGApi { - initChatController() - runMigrations() - } + initChatControllerAndRunMigrations(false) // LALAL //testCrypto() } diff --git a/libsimplex.dll.def b/libsimplex.dll.def index 4255f4409c..f927e3ee24 100644 --- a/libsimplex.dll.def +++ b/libsimplex.dll.def @@ -3,6 +3,7 @@ EXPORTS hs_init hs_init_with_rtsopts chat_migrate_init + chat_close_store chat_send_cmd chat_send_remote_cmd chat_recv_msg From 478bb32cdb1f631b77ed22c9d3438c97936cc60c Mon Sep 17 00:00:00 2001 From: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com> Date: Fri, 29 Dec 2023 22:42:55 +0400 Subject: [PATCH 010/102] core: send group description to new members as welcome message after sending history (fixes welcome message being created before history) (#3623) --- src/Simplex/Chat.hs | 17 ++++++++++-- src/Simplex/Chat/Protocol.hs | 6 +++- tests/ChatTests/Groups.hs | 54 ++++++++++++++++++++++++++++++++++++ tests/ProtocolTests.hs | 8 +++--- 4 files changed, 77 insertions(+), 8 deletions(-) diff --git a/src/Simplex/Chat.hs b/src/Simplex/Chat.hs index fb2abf23d7..9d7f5bccc3 100644 --- a/src/Simplex/Chat.hs +++ b/src/Simplex/Chat.hs @@ -3593,7 +3593,11 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage = createGroupFeatureItems gInfo m let GroupInfo {groupProfile = GroupProfile {description}} = gInfo memberConnectedChatItem gInfo m - forM_ description $ groupDescriptionChatItem gInfo m + unless expectHistory $ forM_ description $ groupDescriptionChatItem gInfo m + where + expectHistory = + groupFeatureAllowed SGFHistory gInfo + && isCompatibleRange (memberChatVRange' m) groupHistoryIncludeWelcomeVRange GCInviteeMember -> do memberConnectedChatItem gInfo m toView $ CRJoinedGroupMember user gInfo m {memberStatus = GSMemConnected} @@ -3636,8 +3640,15 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage = (errs', events) <- partitionEithers <$> mapM (tryChatError . itemForwardEvents) items let errors = map ChatErrorStore errs <> errs' unless (null errors) $ toView $ CRChatErrors (Just user) errors - forM_ (L.nonEmpty $ concat events) $ \events' -> - sendGroupMemberMessages user conn events' groupId + let events' = maybe (concat events) (\x -> concat events <> [x]) descrEvent_ + forM_ (L.nonEmpty events') $ \events'' -> + sendGroupMemberMessages user conn events'' groupId + descrEvent_ :: Maybe (ChatMsgEvent 'Json) + descrEvent_ + | isCompatibleRange (memberChatVRange' m) groupHistoryIncludeWelcomeVRange = do + let GroupInfo {groupProfile = GroupProfile {description}} = gInfo + fmap (\descr -> XMsgNew $ MCSimple $ extMsgContent (MCText descr) Nothing) description + | otherwise = Nothing itemForwardEvents :: CChatItem 'CTGroup -> m [ChatMsgEvent 'Json] itemForwardEvents cci = case cci of (CChatItem SMDRcv ci@ChatItem {chatDir = CIGroupRcv sender, content = CIRcvMsgContent mc, file}) -> do diff --git a/src/Simplex/Chat/Protocol.hs b/src/Simplex/Chat/Protocol.hs index a0df9f9865..220d521322 100644 --- a/src/Simplex/Chat/Protocol.hs +++ b/src/Simplex/Chat/Protocol.hs @@ -56,7 +56,7 @@ import Simplex.Messaging.Version hiding (version) -- This indirection is needed for backward/forward compatibility testing. -- Testing with real app versions is still needed, as tests use the current code with different version ranges, not the old code. currentChatVersion :: Version -currentChatVersion = 5 +currentChatVersion = 6 -- This should not be used directly in code, instead use `chatVRange` from ChatConfig (see comment above) supportedChatVRange :: VersionRange @@ -82,6 +82,10 @@ groupForwardVRange = mkVersionRange 4 currentChatVersion batchSendVRange :: VersionRange batchSendVRange = mkVersionRange 5 currentChatVersion +-- version range that supports sending group welcome message in group history +groupHistoryIncludeWelcomeVRange :: VersionRange +groupHistoryIncludeWelcomeVRange = mkVersionRange 6 currentChatVersion + data ConnectionEntity = RcvDirectMsgConnection {entityConnection :: Connection, contact :: Maybe Contact} | RcvGroupMsgConnection {entityConnection :: Connection, groupInfo :: GroupInfo, groupMember :: GroupMember} diff --git a/tests/ChatTests/Groups.hs b/tests/ChatTests/Groups.hs index f90e7f14d8..28ca35cbab 100644 --- a/tests/ChatTests/Groups.hs +++ b/tests/ChatTests/Groups.hs @@ -131,6 +131,7 @@ chatGroupTests = do it "quoted messages" testGroupHistoryQuotes it "deleted message is not included" testGroupHistoryDeletedMessage it "disappearing message is sent as disappearing" testGroupHistoryDisappearingMessage + it "welcome message (group description) is sent after history" testGroupHistoryWelcomeMessage where _0 = supportedChatVRange -- don't create direct connections _1 = groupCreateDirectVRange @@ -5125,3 +5126,56 @@ testGroupHistoryDisappearingMessage = r2 `shouldContain` [(0, "1"), (0, "4")] r2 `shouldNotContain` [(0, "2")] r2 `shouldNotContain` [(0, "3")] + +testGroupHistoryWelcomeMessage :: HasCallStack => FilePath -> IO () +testGroupHistoryWelcomeMessage = + testChat3 aliceProfile bobProfile cathProfile $ + \alice bob cath -> do + createGroup2 "team" alice bob + + alice ##> "/set welcome #team welcome to team" + alice <## "description changed to:" + alice <## "welcome to team" + + bob <## "alice updated group #team:" + bob <## "description changed to:" + bob <## "welcome to team" + + threadDelay 1000000 + + alice #> "#team hello" + bob <# "#team alice> hello" + + threadDelay 1000000 + + bob #> "#team hey!" + alice <# "#team bob> hey!" + + connectUsers alice cath + addMember "team" alice cath GRAdmin + cath ##> "/j team" + concurrentlyN_ + [ alice <## "#team: cath joined the group", + cath + <### [ "#team: you joined the group", + WithTime "#team alice> hello [>>]", + WithTime "#team bob> hey! [>>]", + WithTime "#team alice> welcome to team", + "#team: member bob (Bob) is connected" + ], + do + bob <## "#team: alice added cath (Catherine) to the group (connecting...)" + bob <## "#team: new member cath is connected" + ] + + cath ##> "/_get chat #1 count=100" + r <- chat <$> getTermLine cath + r `shouldContain` [(0, "hello"), (0, "hey!"), (0, "welcome to team")] + + -- message delivery works after sending history + alice #> "#team 1" + [bob, cath] *<# "#team alice> 1" + bob #> "#team 2" + [alice, cath] *<# "#team bob> 2" + cath #> "#team 3" + [alice, bob] *<# "#team cath> 3" diff --git a/tests/ProtocolTests.hs b/tests/ProtocolTests.hs index 23fbce249e..782cf3a3e0 100644 --- a/tests/ProtocolTests.hs +++ b/tests/ProtocolTests.hs @@ -130,7 +130,7 @@ decodeChatMessageTest = describe "Chat message encoding/decoding" $ do "{\"v\":\"1\",\"msgId\":\"AQIDBA==\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"hello\",\"type\":\"text\"}}}" ##==## ChatMessage chatInitialVRange (Just $ SharedMsgId "\1\2\3\4") (XMsgNew (MCSimple (extMsgContent (MCText "hello") Nothing))) it "x.msg.new chat message with chat version range" $ - "{\"v\":\"1-5\",\"msgId\":\"AQIDBA==\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"hello\",\"type\":\"text\"}}}" + "{\"v\":\"1-6\",\"msgId\":\"AQIDBA==\",\"event\":\"x.msg.new\",\"params\":{\"content\":{\"text\":\"hello\",\"type\":\"text\"}}}" ##==## ChatMessage supportedChatVRange (Just $ SharedMsgId "\1\2\3\4") (XMsgNew (MCSimple (extMsgContent (MCText "hello") Nothing))) 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\"}}}}" @@ -240,13 +240,13 @@ decodeChatMessageTest = describe "Chat message encoding/decoding" $ do "{\"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\"}}}}}}" #==# XGrpMemNew MemberInfo {memberId = MemberId "\1\2\3\4", memberRole = GRAdmin, v = Nothing, profile = testProfile} 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-5\",\"profile\":{\"fullName\":\"Alice\",\"displayName\":\"alice\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}}" + "{\"v\":\"1\",\"event\":\"x.grp.mem.new\",\"params\":{\"memberInfo\":{\"memberRole\":\"admin\",\"memberId\":\"AQIDBA==\",\"v\":\"1-6\",\"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} 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\"}}}}}}" #==# XGrpMemIntro MemberInfo {memberId = MemberId "\1\2\3\4", memberRole = GRAdmin, v = Nothing, profile = testProfile} 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-5\",\"profile\":{\"fullName\":\"Alice\",\"displayName\":\"alice\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}}" + "{\"v\":\"1\",\"event\":\"x.grp.mem.intro\",\"params\":{\"memberInfo\":{\"memberRole\":\"admin\",\"memberId\":\"AQIDBA==\",\"v\":\"1-6\",\"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} 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-2%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D1-2%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-2%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D1-2%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\"}}}" @@ -258,7 +258,7 @@ decodeChatMessageTest = describe "Chat message encoding/decoding" $ do "{\"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-2%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D1-2%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-2%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D1-2%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} 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-2%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D1-2%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\"},\"memberInfo\":{\"memberRole\":\"admin\",\"memberId\":\"AQIDBA==\",\"v\":\"1-5\",\"profile\":{\"fullName\":\"Alice\",\"displayName\":\"alice\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}}" + "{\"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-2%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D1-2%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\"},\"memberInfo\":{\"memberRole\":\"admin\",\"memberId\":\"AQIDBA==\",\"v\":\"1-6\",\"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} 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\"}}}}}" From e253c55ba41f9158b695413f2151d091b0f5cad4 Mon Sep 17 00:00:00 2001 From: Alexander Bondarenko <486682+dpwiz@users.noreply.github.com> Date: Fri, 29 Dec 2023 23:15:14 +0200 Subject: [PATCH 011/102] core: compatibility with GHC 8.10.7 (#3608) * GHC-8.10 compatibility * tweak setters * restore membership * remove Show Batch * fix bytestring-10 compat * preserve membership qualifier in names * a few more memberships * rename * remove with-compiler * ci: add 8.10 builds, limit releases to 9.6 * use matrix.asset_name as release guard * fix windows_build * actually use ghc version from matrix * fix typo * revert build/hash split * add ghc to cache key * Force cache between build and tests * use explicit caching steps * skip unneeded tasks --------- Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Co-authored-by: Avently <7953703+avently@users.noreply.github.com> --- .github/workflows/build.yml | 60 ++++++++---- cabal.project | 2 - src/Simplex/Chat.hs | 127 ++++++++++++++------------ src/Simplex/Chat/Messages.hs | 5 +- src/Simplex/Chat/Messages/Batch.hs | 1 - src/Simplex/Chat/Mobile/Shared.hs | 6 +- src/Simplex/Chat/Store/Direct.hs | 3 +- src/Simplex/Chat/Store/Files.hs | 3 +- src/Simplex/Chat/Store/Groups.hs | 9 +- src/Simplex/Chat/Types.hs | 15 ++- src/Simplex/Chat/Types/Preferences.hs | 95 ++++++++++--------- src/Simplex/Chat/View.hs | 13 +-- tests/Bots/BroadcastTests.hs | 5 +- tests/Bots/DirectoryTests.hs | 5 +- tests/ChatClient.hs | 36 ++++---- 15 files changed, 207 insertions(+), 178 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index afdb9bea1a..2727fc4add 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -42,7 +42,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} build: - name: build-${{ matrix.os }} + name: build-${{ matrix.os }}-${{ matrix.ghc }} if: always() needs: prepare-release runs-on: ${{ matrix.os }} @@ -51,18 +51,25 @@ jobs: matrix: include: - os: ubuntu-20.04 + ghc: "8.10.7" + cache_path: ~/.cabal/store + - os: ubuntu-20.04 + ghc: "9.6.3" cache_path: ~/.cabal/store asset_name: simplex-chat-ubuntu-20_04-x86-64 desktop_asset_name: simplex-desktop-ubuntu-20_04-x86_64.deb - os: ubuntu-22.04 + ghc: "9.6.3" cache_path: ~/.cabal/store asset_name: simplex-chat-ubuntu-22_04-x86-64 desktop_asset_name: simplex-desktop-ubuntu-22_04-x86_64.deb - os: macos-latest + ghc: "9.6.3" cache_path: ~/.cabal/store asset_name: simplex-chat-macos-x86-64 desktop_asset_name: simplex-desktop-macos-x86_64.dmg - os: windows-latest + ghc: "9.6.3" cache_path: C:/cabal asset_name: simplex-chat-windows-x86-64 desktop_asset_name: simplex-desktop-windows-x86_64.msi @@ -81,16 +88,17 @@ jobs: - name: Setup Haskell uses: haskell-actions/setup@v2 with: - ghc-version: "9.6.3" + ghc-version: ${{ matrix.ghc }} cabal-version: "3.10.1.0" - - name: Cache dependencies - uses: actions/cache@v3 + - name: Restore cached build + id: restore_cache + uses: actions/cache/restore@v3 with: path: | ${{ matrix.cache_path }} dist-newstyle - key: ${{ matrix.os }}-${{ hashFiles('cabal.project', 'simplex-chat.cabal') }} + key: ${{ matrix.os }}-ghc${{ matrix.ghc }}-${{ hashFiles('cabal.project', 'simplex-chat.cabal') }} # / Unix @@ -105,7 +113,7 @@ jobs: echo " flags: +openssl" >> cabal.project.local - name: Install AppImage dependencies - if: startsWith(github.ref, 'refs/tags/v') && matrix.os == 'ubuntu-20.04' + if: startsWith(github.ref, 'refs/tags/v') && matrix.asset_name && matrix.os == 'ubuntu-20.04' run: sudo apt install -y desktop-file-utils - name: Install pkg-config for Mac @@ -131,7 +139,7 @@ jobs: echo "bin_hash=$(echo SHA2-512\(${{ matrix.asset_name }}\)= $(openssl sha512 $path | cut -d' ' -f 2))" >> $GITHUB_OUTPUT - name: Unix upload CLI binary to release - if: startsWith(github.ref, 'refs/tags/v') && matrix.os != 'windows-latest' + if: startsWith(github.ref, 'refs/tags/v') && matrix.asset_name && matrix.os != 'windows-latest' uses: svenstaro/upload-release-action@v2 with: repo_token: ${{ secrets.GITHUB_TOKEN }} @@ -140,7 +148,7 @@ jobs: tag: ${{ github.ref }} - name: Unix update CLI binary hash - if: startsWith(github.ref, 'refs/tags/v') && matrix.os != 'windows-latest' + if: startsWith(github.ref, 'refs/tags/v') && matrix.asset_name && matrix.os != 'windows-latest' uses: softprops/action-gh-release@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -150,7 +158,7 @@ jobs: ${{ steps.unix_cli_build.outputs.bin_hash }} - name: Setup Java - if: startsWith(github.ref, 'refs/tags/v') + if: startsWith(github.ref, 'refs/tags/v') && matrix.asset_name uses: actions/setup-java@v3 with: distribution: 'corretto' @@ -159,7 +167,7 @@ jobs: - name: Linux build desktop id: linux_desktop_build - if: startsWith(github.ref, 'refs/tags/v') && (matrix.os == 'ubuntu-20.04' || matrix.os == 'ubuntu-22.04') + if: startsWith(github.ref, 'refs/tags/v') && matrix.asset_name && (matrix.os == 'ubuntu-20.04' || matrix.os == 'ubuntu-22.04') shell: bash run: | scripts/desktop/build-lib-linux.sh @@ -168,10 +176,10 @@ jobs: path=$(echo $PWD/release/main/deb/simplex_*_amd64.deb) echo "package_path=$path" >> $GITHUB_OUTPUT echo "package_hash=$(echo SHA2-512\(${{ matrix.desktop_asset_name }}\)= $(openssl sha512 $path | cut -d' ' -f 2))" >> $GITHUB_OUTPUT - + - name: Linux make AppImage id: linux_appimage_build - if: startsWith(github.ref, 'refs/tags/v') && matrix.os == 'ubuntu-20.04' + if: startsWith(github.ref, 'refs/tags/v') && matrix.asset_name && matrix.os == 'ubuntu-20.04' shell: bash run: | scripts/desktop/make-appimage-linux.sh @@ -194,7 +202,7 @@ jobs: echo "package_hash=$(echo SHA2-512\(${{ matrix.desktop_asset_name }}\)= $(openssl sha512 $path | cut -d' ' -f 2))" >> $GITHUB_OUTPUT - name: Linux upload desktop package to release - if: startsWith(github.ref, 'refs/tags/v') && (matrix.os == 'ubuntu-20.04' || matrix.os == 'ubuntu-22.04') + if: startsWith(github.ref, 'refs/tags/v') && matrix.asset_name && (matrix.os == 'ubuntu-20.04' || matrix.os == 'ubuntu-22.04') uses: svenstaro/upload-release-action@v2 with: repo_token: ${{ secrets.GITHUB_TOKEN }} @@ -203,7 +211,7 @@ jobs: tag: ${{ github.ref }} - name: Linux update desktop package hash - if: startsWith(github.ref, 'refs/tags/v') && (matrix.os == 'ubuntu-20.04' || matrix.os == 'ubuntu-22.04') + if: startsWith(github.ref, 'refs/tags/v') && matrix.asset_name && (matrix.os == 'ubuntu-20.04' || matrix.os == 'ubuntu-22.04') uses: softprops/action-gh-release@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -213,7 +221,7 @@ jobs: ${{ steps.linux_desktop_build.outputs.package_hash }} - name: Linux upload AppImage to release - if: startsWith(github.ref, 'refs/tags/v') && matrix.os == 'ubuntu-20.04' + if: startsWith(github.ref, 'refs/tags/v') && matrix.asset_name && matrix.os == 'ubuntu-20.04' uses: svenstaro/upload-release-action@v2 with: repo_token: ${{ secrets.GITHUB_TOKEN }} @@ -222,7 +230,7 @@ jobs: tag: ${{ github.ref }} - name: Linux update AppImage hash - if: startsWith(github.ref, 'refs/tags/v') && matrix.os == 'ubuntu-20.04' + if: startsWith(github.ref, 'refs/tags/v') && matrix.asset_name && matrix.os == 'ubuntu-20.04' uses: softprops/action-gh-release@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -250,6 +258,15 @@ jobs: body: | ${{ steps.mac_desktop_build.outputs.package_hash }} + - name: Cache unix build + uses: actions/cache/save@v3 + if: matrix.os != 'windows-latest' + with: + path: | + ${{ matrix.cache_path }} + dist-newstyle + key: ${{ steps.restore_cache.outputs.cache-primary-key }} + - name: Unix test if: matrix.os != 'windows-latest' timeout-minutes: 30 @@ -330,7 +347,7 @@ jobs: path=$(echo $PWD/release/main/msi/*imple*.msi | sed 's#/\([a-z]\)#\1:#' | sed 's#/#\\#g') echo "package_path=$path" >> $GITHUB_OUTPUT echo "package_hash=$(echo SHA2-512\(${{ matrix.desktop_asset_name }}\)= $(openssl sha512 $path | cut -d' ' -f 2))" >> $GITHUB_OUTPUT - + - name: Windows upload desktop package to release if: startsWith(github.ref, 'refs/tags/v') && matrix.os == 'windows-latest' uses: svenstaro/upload-release-action@v2 @@ -350,4 +367,13 @@ jobs: body: | ${{ steps.windows_desktop_build.outputs.package_hash }} + - name: Cache windows build + uses: actions/cache/save@v3 + if: matrix.os == 'windows-latest' + with: + path: | + ${{ matrix.cache_path }} + dist-newstyle + key: ${{ steps.restore_cache.outputs.cache-primary-key }} + # Windows / diff --git a/cabal.project b/cabal.project index baf7d5c4c1..dbd050bcf1 100644 --- a/cabal.project +++ b/cabal.project @@ -2,8 +2,6 @@ packages: . -- packages: . ../simplexmq -- packages: . ../simplexmq ../direct-sqlcipher ../sqlcipher-simple -with-compiler: ghc-9.6.3 - index-state: 2023-12-12T00:00:00Z package cryptostore diff --git a/src/Simplex/Chat.hs b/src/Simplex/Chat.hs index 9d7f5bccc3..d61fc5f5a5 100644 --- a/src/Simplex/Chat.hs +++ b/src/Simplex/Chat.hs @@ -5,7 +5,6 @@ {-# LANGUAGE LambdaCase #-} {-# LANGUAGE MultiWayIf #-} {-# LANGUAGE NamedFieldPuns #-} -{-# LANGUAGE OverloadedRecordDot #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} @@ -279,8 +278,9 @@ newChatController where configServers :: DefaultAgentServers configServers = - let smp' = fromMaybe (defaultServers.smp) (nonEmpty smpServers) - xftp' = fromMaybe (defaultServers.xftp) (nonEmpty xftpServers) + let DefaultAgentServers {smp = defSmp, xftp = defXftp} = defaultServers + smp' = fromMaybe defSmp (nonEmpty smpServers) + xftp' = fromMaybe defXftp (nonEmpty xftpServers) in defaultServers {smp = smp', xftp = xftp', netCfg = networkConfig} agentServers :: ChatConfig -> IO InitialAgentServers agentServers config@ChatConfig {defaultServers = defServers@DefaultAgentServers {ntf, netCfg}} = do @@ -307,9 +307,9 @@ activeAgentServers ChatConfig {defaultServers} p = . filter (\ServerCfg {enabled} -> enabled) cfgServers :: UserProtocol p => SProtocolType p -> (DefaultAgentServers -> NonEmpty (ProtoServerWithAuth p)) -cfgServers p s = case p of - SPSMP -> s.smp - SPXFTP -> s.xftp +cfgServers p DefaultAgentServers {smp, xftp} = case p of + SPSMP -> smp + SPXFTP -> xftp startChatController :: forall m. ChatMonad' m => Bool -> Bool -> Bool -> m (Async ()) startChatController subConns enableExpireCIs startXFTPWorkers = do @@ -971,7 +971,8 @@ processChatCommand' vr = \case pure $ CRContactConnectionDeleted user conn CTGroup -> do Group gInfo@GroupInfo {membership} members <- withStore $ \db -> getGroup db vr user chatId - let isOwner = membership.memberRole == GROwner + let GroupMember {memberRole = membershipMemRole} = membership + let isOwner = membershipMemRole == GROwner canDelete = isOwner || not (memberCurrent membership) unless canDelete $ throwChatError $ CEGroupUserRole gInfo GROwner filesInfo <- withStore' $ \db -> getGroupFileInfo db user gInfo @@ -1611,11 +1612,12 @@ processChatCommand' vr = \case inv@ReceivedGroupInvitation {fromMember} <- getGroupInvitation db vr user groupId (inv,) <$> getContactViaMember db user fromMember let ReceivedGroupInvitation {fromMember, connRequest, groupInfo = g@GroupInfo {membership}} = invitation + GroupMember {memberId = membershipMemId} = membership Contact {activeConn} = ct case activeConn of Just Connection {peerChatVRange} -> do subMode <- chatReadVar subscriptionMode - dm <- directMessage $ XGrpAcpt membership.memberId + dm <- directMessage $ XGrpAcpt membershipMemId agentConnId <- withAgent $ \a -> joinConnection a (aUserId user) True connRequest dm subMode withStore' $ \db -> do createMemberConnection db userId fromMember agentConnId (fromJVersionRange peerChatVRange) subMode @@ -1767,12 +1769,12 @@ processChatCommand' vr = \case pure $ CRNewMemberContact user ct g m _ -> throwChatError CEGroupMemberNotActive APISendMemberContactInvitation contactId msgContent_ -> withUser $ \user -> do - (g, m, ct, cReq) <- withStore $ \db -> getMemberContact db vr user contactId + (g@GroupInfo {groupId}, m, ct, cReq) <- withStore $ \db -> getMemberContact db vr user contactId when (contactGrpInvSent ct) $ throwChatError $ CECommandError "x.grp.direct.inv already sent" case memberConn m of Just mConn -> do let msg = XGrpDirectInv cReq msgContent_ - (sndMsg, _) <- sendDirectMessage mConn msg (GroupId $ g.groupId) + (sndMsg, _) <- sendDirectMessage mConn msg $ GroupId groupId withStore' $ \db -> setContactGrpInvSent db ct True let ct' = ct {contactGrpInvSent = True} forM_ msgContent_ $ \mc -> do @@ -2191,7 +2193,8 @@ processChatCommand' vr = \case when (displayName /= validName) $ throwChatError CEInvalidDisplayName {displayName, validName} assertUserGroupRole :: GroupInfo -> GroupMemberRole -> m () assertUserGroupRole g@GroupInfo {membership} requiredRole = do - when (membership.memberRole < requiredRole) $ throwChatError $ CEGroupUserRole g requiredRole + let GroupMember {memberRole = membershipMemRole} = membership + when (membershipMemRole < requiredRole) $ throwChatError $ CEGroupUserRole g requiredRole when (memberStatus membership == GSMemInvited) $ throwChatError (CEGroupNotJoined g) when (memberRemoved membership) $ throwChatError CEGroupMemberUserRemoved unless (memberActive membership) $ throwChatError CEGroupMemberNotActive @@ -2235,7 +2238,7 @@ processChatCommand' vr = \case forwardFile chatName fileId sendCommand = withUser $ \user -> do withStore (\db -> getFileTransfer db user fileId) >>= \case FTRcv RcvFileTransfer {fileStatus = RFSComplete RcvFileInfo {filePath}, cryptoArgs} -> forward filePath cryptoArgs - FTSnd {fileTransferMeta = FileTransferMeta {filePath, xftpSndFile}} -> forward filePath $ xftpSndFile >>= \f -> f.cryptoArgs + FTSnd {fileTransferMeta = FileTransferMeta {filePath, xftpSndFile}} -> forward filePath $ xftpSndFile >>= \XFTPSndFile {cryptoArgs} -> cryptoArgs _ -> throwChatError CEFileNotReceived {fileId} where forward path cfArgs = processChatCommand . sendCommand chatName $ CryptoFile path cfArgs @@ -2327,7 +2330,7 @@ processChatCommand' vr = \case _ -> throwChatError $ CECommandError "not supported" processChatCommand $ APISetChatSettings (ChatRef cType chatId) $ updateSettings chatSettings connectPlan :: User -> AConnectionRequestUri -> m ConnectionPlan - connectPlan user (ACR SCMInvitation cReq) = do + connectPlan user (ACR SCMInvitation (CRInvitationUri crData e2e)) = do withStore' (\db -> getConnectionEntityByConnReq db vr user cReqSchemas) >>= \case Nothing -> pure $ CPInvitationLink ILPOk Just (RcvDirectMsgConnection conn ct_) -> do @@ -2343,13 +2346,12 @@ processChatCommand' vr = \case Just _ -> throwChatError $ CECommandError "found connection entity is not RcvDirectMsgConnection" where cReqSchemas :: (ConnReqInvitation, ConnReqInvitation) - cReqSchemas = case cReq of - (CRInvitationUri crData e2e) -> - ( CRInvitationUri crData {crScheme = CRSSimplex} e2e, - CRInvitationUri crData {crScheme = simplexChat} e2e - ) - connectPlan user (ACR SCMContact cReq) = do - let CRContactUri ConnReqUriData {crClientData} = cReq + cReqSchemas = + ( CRInvitationUri crData {crScheme = CRSSimplex} e2e, + CRInvitationUri crData {crScheme = simplexChat} e2e + ) + connectPlan user (ACR SCMContact (CRContactUri crData)) = do + let ConnReqUriData {crClientData} = crData groupLinkId = crClientData >>= decodeJSON >>= \(CRDataGroup gli) -> Just gli case groupLinkId of -- contact address @@ -2389,11 +2391,10 @@ processChatCommand' vr = \case | otherwise -> pure $ CPGroupLink GLPOk where cReqSchemas :: (ConnReqContact, ConnReqContact) - cReqSchemas = case cReq of - (CRContactUri crData) -> - ( CRContactUri crData {crScheme = CRSSimplex}, - CRContactUri crData {crScheme = simplexChat} - ) + cReqSchemas = + ( CRContactUri crData {crScheme = CRSSimplex}, + CRContactUri crData {crScheme = simplexChat} + ) cReqHashes :: (ConnReqUriHash, ConnReqUriHash) cReqHashes = bimap hash hash cReqSchemas hash = ConnReqUriHash . C.sha256Hash . strEncode @@ -3561,9 +3562,10 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage = case chatMsgEvent of XGrpMemInfo memId _memProfile | sameMemberId memId m -> do + let GroupMember {memberId = membershipMemId} = membership -- TODO update member profile -- [async agent commands] no continuation needed, but command should be asynchronous for stability - allowAgentConnectionAsync user conn' confId $ XGrpMemInfo membership.memberId (fromLocalProfile $ memberProfile membership) + allowAgentConnectionAsync user conn' confId $ XGrpMemInfo membershipMemId (fromLocalProfile $ memberProfile membership) | otherwise -> messageError "x.grp.mem.info: memberId is different from expected" _ -> messageError "CONF from member must have x.grp.mem.info" INFO connInfo -> do @@ -3689,7 +3691,7 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage = fInv = xftpFileInvitation fileName fileSize fInvDescr in Just (fInv, fileDescrText) | otherwise = Nothing - processContentItem :: GroupMember -> ChatItem 'CTGroup d -> MsgContent -> Maybe (FileInvitation, RcvFileDescrText) -> m [ChatMsgEvent Json] + processContentItem :: GroupMember -> ChatItem 'CTGroup d -> MsgContent -> Maybe (FileInvitation, RcvFileDescrText) -> m [ChatMsgEvent 'Json] processContentItem sender ChatItem {meta, quotedItem} mc fInvDescr_ = if isNothing fInvDescr_ && not (msgContentHasText mc) then pure [] @@ -3724,17 +3726,18 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage = when (memCategory == GCPreMember) $ probeMatchingContactsAndMembers ct connectedIncognito True sendXGrpMemCon memCategory where + GroupMember {memberId} = m sendXGrpMemCon = \case GCPreMember -> forM_ (invitedByGroupMemberId membership) $ \hostId -> do host <- withStore $ \db -> getGroupMember db user groupId hostId forM_ (memberConn host) $ \hostConn -> - void $ sendDirectMessage hostConn (XGrpMemCon m.memberId) (GroupId groupId) + void $ sendDirectMessage hostConn (XGrpMemCon memberId) (GroupId groupId) GCPostMember -> forM_ (invitedByGroupMemberId m) $ \invitingMemberId -> do im <- withStore $ \db -> getGroupMember db user groupId invitingMemberId forM_ (memberConn im) $ \imConn -> - void $ sendDirectMessage imConn (XGrpMemCon m.memberId) (GroupId groupId) + void $ sendDirectMessage imConn (XGrpMemCon memberId) (GroupId groupId) _ -> messageWarning "sendXGrpMemCon: member category GCPreMember or GCPostMember is expected" MSG msgMeta _msgFlags msgBody -> do checkIntegrityCreateItem (CDGroupRcv gInfo m) msgMeta `catchChatError` \_ -> pure () @@ -3747,7 +3750,8 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage = Left e -> toView $ CRChatError (Just user) (ChatError . CEException $ "error parsing chat message: " <> e) checkSendRcpt $ rights aChatMsgs -- currently only a single message is forwarded - when (membership.memberRole >= GRAdmin) $ case aChatMsgs of + let GroupMember {memberRole = membershipMemRole} = membership + when (membershipMemRole >= GRAdmin) $ case aChatMsgs of [Right (ACMsg _ chatMsg)] -> forwardMsg_ chatMsg _ -> pure () where @@ -3807,8 +3811,9 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage = else pure [] -- invited members to which this member was introduced invitedMembers <- withStore' $ \db -> getForwardInvitedMembers db user m highlyAvailable - let ms = introducedMembers <> invitedMembers - msg = XGrpMsgForward m.memberId chatMsg' brokerTs + let GroupMember {memberId} = m + ms = introducedMembers <> invitedMembers + msg = XGrpMsgForward memberId chatMsg' brokerTs unless (null ms) . void $ sendGroupMessage user gInfo ms msg RCVD msgMeta msgRcpt -> @@ -4069,8 +4074,8 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage = _ -> toView $ CRReceivedContactRequest user cReq memberCanSend :: GroupMember -> m () -> m () - memberCanSend mem a - | mem.memberRole <= GRObserver = messageError "member is not allowed to send messages" + memberCanSend GroupMember {memberRole} a + | memberRole <= GRObserver = messageError "member is not allowed to send messages" | otherwise = a incAuthErrCounter :: ConnectionEntity -> Connection -> AgentErrorType -> m () @@ -4692,12 +4697,12 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage = when (fromRole < GRAdmin || fromRole < memRole) $ throwChatError (CEGroupContactRole c) when (fromMemId == memId) $ throwChatError CEGroupDuplicateMemberId -- [incognito] if direct connection with host is incognito, create membership using the same incognito profile - (gInfo@GroupInfo {groupId, localDisplayName, groupProfile, membership = membership@GroupMember {groupMemberId, memberId}}, hostId) <- - withStore $ \db -> createGroupInvitation db vr user ct inv customUserProfileId + (gInfo@GroupInfo {groupId, localDisplayName, groupProfile, membership}, hostId) <- withStore $ \db -> createGroupInvitation db vr user ct inv customUserProfileId + let GroupMember {groupMemberId, memberId = membershipMemId} = membership if sameGroupLinkId groupLinkId groupLinkId' then do subMode <- chatReadVar subscriptionMode - dm <- directMessage $ XGrpAcpt memberId + dm <- directMessage $ XGrpAcpt membershipMemId connIds <- joinAgentConnectionAsync user True connRequest dm subMode withStore' $ \db -> do setViaGroupLinkHash db groupId connId @@ -5128,6 +5133,7 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage = xGrpMemFwd :: GroupInfo -> GroupMember -> MemberInfo -> IntroInvitation -> m () xGrpMemFwd gInfo@GroupInfo {membership, chatSettings} m memInfo@(MemberInfo memId memRole memChatVRange _) introInv@IntroInvitation {groupConnReq, directConnReq} = do + let GroupMember {memberId = membershipMemId} = membership checkHostRole m memRole toMember <- withStore' (\db -> runExceptT $ getGroupMemberByMemberId db user gInfo memId) >>= \case @@ -5140,7 +5146,7 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage = withStore' $ \db -> saveMemberInvitation db toMember introInv subMode <- chatReadVar subscriptionMode -- [incognito] send membership incognito profile, create direct connection as incognito - dm <- directMessage $ XGrpMemInfo membership.memberId (fromLocalProfile $ memberProfile membership) + dm <- directMessage $ XGrpMemInfo membershipMemId (fromLocalProfile $ memberProfile membership) -- [async agent commands] no continuation needed, but commands should be asynchronous for stability groupConnIds <- joinAgentConnectionAsync user (chatHasNtfs chatSettings) groupConnReq dm subMode directConnIds <- forM directConnReq $ \dcr -> joinAgentConnectionAsync user True dcr dm subMode @@ -5150,7 +5156,7 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage = xGrpMemRole :: GroupInfo -> GroupMember -> MemberId -> GroupMemberRole -> RcvMessage -> UTCTime -> m () xGrpMemRole gInfo@GroupInfo {membership} m@GroupMember {memberRole = senderRole} memId memRole msg brokerTs - | membership.memberId == memId = + | membershipMemId == memId = let gInfo' = gInfo {membership = membership {memberRole = memRole}} in changeMemberRole gInfo' membership $ RGEUserRole memRole | otherwise = @@ -5158,6 +5164,7 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage = Right member -> changeMemberRole gInfo member $ RGEMemberRole (groupMemberId' member) (fromLocalProfile $ memberProfile member) memRole Left _ -> messageError "x.grp.mem.role with unknown member ID" where + GroupMember {memberId = membershipMemId} = membership changeMemberRole gInfo' member@GroupMember {memberRole = fromRole} gEvent | senderRole < GRAdmin || senderRole < fromRole = messageError "x.grp.mem.role with insufficient member permissions" | otherwise = do @@ -5211,7 +5218,8 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage = xGrpMemDel :: GroupInfo -> GroupMember -> MemberId -> RcvMessage -> UTCTime -> m () xGrpMemDel gInfo@GroupInfo {membership} m@GroupMember {memberRole = senderRole} memId msg brokerTs = do - if membership.memberId == memId + let GroupMember {memberId = membershipMemId} = membership + if membershipMemId == memId then checkRole membership $ do deleteGroupLinkIfExists user gInfo -- member records are not deleted to keep history @@ -5323,8 +5331,8 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage = createInternalChatItem user (CDDirectRcv ct) (CIRcvConnEvent RCEVerificationCodeReset) Nothing xGrpMsgForward :: GroupInfo -> GroupMember -> MemberId -> ChatMessage 'Json -> UTCTime -> m () - xGrpMsgForward gInfo@GroupInfo {groupId} m memberId msg msgTs = do - when (m.memberRole < GRAdmin) $ throwChatError (CEGroupContactRole m.localDisplayName) + xGrpMsgForward gInfo@GroupInfo {groupId} m@GroupMember {memberRole, localDisplayName} memberId msg msgTs = do + when (memberRole < GRAdmin) $ throwChatError (CEGroupContactRole localDisplayName) author <- withStore $ \db -> getGroupMemberByMemberId db user gInfo memberId processForwardedMsg author msg where @@ -5501,7 +5509,7 @@ parseFileChunk :: ChatMonad m => ByteString -> m FileChunk parseFileChunk = liftEither . first (ChatError . CEFileRcvChunk) . smpDecode appendFileChunk :: forall m. ChatMonad m => RcvFileTransfer -> Integer -> ByteString -> Bool -> m () -appendFileChunk ft@RcvFileTransfer {fileId, fileStatus, cryptoArgs} chunkNo chunk final = +appendFileChunk ft@RcvFileTransfer {fileId, fileStatus, cryptoArgs, fileInvitation = FileInvitation {fileName}} chunkNo chunk final = case fileStatus of RFSConnected RcvFileInfo {filePath} -> append_ filePath -- sometimes update of file transfer status to FSConnected @@ -5519,7 +5527,7 @@ appendFileChunk ft@RcvFileTransfer {fileId, fileStatus, cryptoArgs} chunkNo chun when final $ do closeFileHandle fileId rcvFiles forM_ cryptoArgs $ \cfArgs -> do - tmpFile <- getChatTempDirectory >>= (`uniqueCombine` ft.fileInvitation.fileName) + tmpFile <- getChatTempDirectory >>= (`uniqueCombine` fileName) tryChatError (liftError encryptErr $ encryptFile fsFilePath tmpFile cfArgs) >>= \case Right () -> do removeFile fsFilePath `catchChatError` \_ -> pure () @@ -5734,7 +5742,7 @@ sendGroupMessage user GroupInfo {groupId} members chatMsgEvent = do data MemberSendAction = MSASend Connection | MSAPending memberSendAction :: ChatMsgEvent e -> [GroupMember] -> GroupMember -> Maybe MemberSendAction -memberSendAction chatMsgEvent members m = case memberConn m of +memberSendAction chatMsgEvent members m@GroupMember {invitedByGroupMemberId} = case memberConn m of Nothing -> pendingOrForwarded Just conn@Connection {connStatus} | connDisabled conn || connStatus == ConnDeleted -> Nothing @@ -5749,7 +5757,7 @@ memberSendAction chatMsgEvent members m = case memberConn m of forwardSupported = let mcvr = memberChatVRange' m in isCompatibleRange mcvr groupForwardVRange && invitingMemberSupportsForward - invitingMemberSupportsForward = case m.invitedByGroupMemberId of + invitingMemberSupportsForward = case invitedByGroupMemberId of Just invMemberId -> -- can be optimized for large groups by replacing [GroupMember] with Map GroupMemberId GroupMember case find (\m' -> groupMemberId' m' == invMemberId) members of @@ -5804,34 +5812,33 @@ saveDirectRcvMSG conn@Connection {connId} agentMsgMeta agentAckCmdId msgBody = saveGroupRcvMsg :: (MsgEncodingI e, ChatMonad m) => User -> GroupId -> GroupMember -> Connection -> MsgMeta -> CommandId -> MsgBody -> ChatMessage e -> m (GroupMember, Connection, RcvMessage) saveGroupRcvMsg user groupId authorMember conn@Connection {connId} agentMsgMeta agentAckCmdId msgBody ChatMessage {chatVRange, msgId = sharedMsgId_, chatMsgEvent} = do - (am', conn') <- updateMemberChatVRange authorMember conn chatVRange + (am'@GroupMember {memberId = amMemId, groupMemberId = amGroupMemId}, conn') <- updateMemberChatVRange authorMember conn chatVRange let agentMsgId = fst $ recipient agentMsgMeta newMsg = NewRcvMessage {chatMsgEvent, msgBody} rcvMsgDelivery = RcvMsgDelivery {connId, agentMsgId, agentMsgMeta, agentAckCmdId} - amId = Just am'.groupMemberId msg <- - withStore (\db -> createNewMessageAndRcvMsgDelivery db (GroupId groupId) newMsg sharedMsgId_ rcvMsgDelivery amId) + withStore (\db -> createNewMessageAndRcvMsgDelivery db (GroupId groupId) newMsg sharedMsgId_ rcvMsgDelivery $ Just amGroupMemId) `catchChatError` \e -> case e of ChatErrorStore (SEDuplicateGroupMessage _ _ _ (Just forwardedByGroupMemberId)) -> do fm <- withStore $ \db -> getGroupMember db user groupId forwardedByGroupMemberId forM_ (memberConn fm) $ \fmConn -> - void $ sendDirectMessage fmConn (XGrpMemCon am'.memberId) (GroupId groupId) + void $ sendDirectMessage fmConn (XGrpMemCon amMemId) (GroupId groupId) throwError e _ -> throwError e pure (am', conn', msg) saveGroupFwdRcvMsg :: (MsgEncodingI e, ChatMonad m) => User -> GroupId -> GroupMember -> GroupMember -> MsgBody -> ChatMessage e -> m RcvMessage -saveGroupFwdRcvMsg user groupId forwardingMember refAuthorMember msgBody ChatMessage {msgId = sharedMsgId_, chatMsgEvent} = do +saveGroupFwdRcvMsg user groupId forwardingMember refAuthorMember@GroupMember {memberId = refMemberId} msgBody ChatMessage {msgId = sharedMsgId_, chatMsgEvent} = do let newMsg = NewRcvMessage {chatMsgEvent, msgBody} fwdMemberId = Just $ groupMemberId' forwardingMember refAuthorId = Just $ groupMemberId' refAuthorMember withStore (\db -> createNewRcvMessage db (GroupId groupId) newMsg sharedMsgId_ refAuthorId fwdMemberId) `catchChatError` \e -> case e of ChatErrorStore (SEDuplicateGroupMessage _ _ (Just authorGroupMemberId) Nothing) -> do - am <- withStore $ \db -> getGroupMember db user groupId authorGroupMemberId - if sameMemberId refAuthorMember.memberId am + am@GroupMember {memberId = amMemberId} <- withStore $ \db -> getGroupMember db user groupId authorGroupMemberId + if sameMemberId refMemberId am then forM_ (memberConn forwardingMember) $ \fmConn -> - void $ sendDirectMessage fmConn (XGrpMemCon am.memberId) (GroupId groupId) + void $ sendDirectMessage fmConn (XGrpMemCon amMemberId) (GroupId groupId) else toView $ CRMessageError user "error" "saveGroupFwdRcvMsg: referenced author member id doesn't match message member id" throwError e _ -> throwError e @@ -5977,7 +5984,9 @@ createSndFeatureItems :: forall m. ChatMonad m => User -> Contact -> Contact -> createSndFeatureItems user ct ct' = createFeatureItems user ct ct' CDDirectSnd CISndChatFeature CISndChatPreference getPref where - getPref u = (userPreference u).preference + getPref ContactUserPreference {userPreference} = case userPreference of + CUPContact {preference} -> preference + CUPUser {preference} -> preference type FeatureContent a d = ChatFeature -> a -> Maybe Int -> CIContent d @@ -6060,8 +6069,8 @@ getCreateActiveUser st testView = do Left e -> putStrLn ("database error " <> show e) >> exitFailure Right user -> pure user selectUser :: [User] -> IO User - selectUser [user] = do - withTransaction st (`setActiveUser` user.userId) + selectUser [user@User {userId}] = do + withTransaction st (`setActiveUser` userId) pure user selectUser users = do putStrLn "Select user profile:" @@ -6075,8 +6084,8 @@ getCreateActiveUser st testView = do Just n | n <= 0 || n > length users -> putStrLn "invalid user number" >> loop | otherwise -> do - let user = users !! (n - 1) - withTransaction st (`setActiveUser` user.userId) + let user@User {userId} = users !! (n - 1) + withTransaction st (`setActiveUser` userId) pure user userStr :: User -> String userStr User {localDisplayName, profile = LocalProfile {fullName}} = diff --git a/src/Simplex/Chat/Messages.hs b/src/Simplex/Chat/Messages.hs index 74b41dc9f2..4ee2e9cc15 100644 --- a/src/Simplex/Chat/Messages.hs +++ b/src/Simplex/Chat/Messages.hs @@ -5,7 +5,6 @@ {-# LANGUAGE KindSignatures #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE NamedFieldPuns #-} -{-# LANGUAGE OverloadedRecordDot #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StandaloneDeriving #-} @@ -345,7 +344,9 @@ contactTimedTTL Contact {mergedPreferences = ContactUserPreferences {timedMessag | forUser enabled && forContact enabled = Just ttl | otherwise = Nothing where - TimedMessagesPreference {ttl} = userPreference.preference + TimedMessagesPreference {ttl} = case userPreference of + CUPContact {preference} -> preference + CUPUser {preference} -> preference groupTimedTTL :: GroupInfo -> Maybe (Maybe Int) groupTimedTTL GroupInfo {fullGroupPreferences = FullGroupPreferences {timedMessages = TimedMessagesGroupPreference {enable, ttl}}} diff --git a/src/Simplex/Chat/Messages/Batch.hs b/src/Simplex/Chat/Messages/Batch.hs index 8b06873a33..3e3a1fd0b6 100644 --- a/src/Simplex/Chat/Messages/Batch.hs +++ b/src/Simplex/Chat/Messages/Batch.hs @@ -16,7 +16,6 @@ import Simplex.Chat.Controller (ChatError (..), ChatErrorType (..)) import Simplex.Chat.Messages data MsgBatch = MsgBatch Builder [SndMessage] - deriving (Show) -- | Batches [SndMessage] into batches of ByteString builders in form of JSON arrays. -- Does not check if the resulting batch is a valid JSON. diff --git a/src/Simplex/Chat/Mobile/Shared.hs b/src/Simplex/Chat/Mobile/Shared.hs index a4961c15f3..5f13f58c72 100644 --- a/src/Simplex/Chat/Mobile/Shared.hs +++ b/src/Simplex/Chat/Mobile/Shared.hs @@ -16,12 +16,12 @@ type JSONByteString = LB.ByteString getByteString :: Ptr Word8 -> CInt -> IO ByteString getByteString ptr len = do fp <- newForeignPtr_ ptr - pure $ BS fp $ fromIntegral len + pure $ PS fp 0 (fromIntegral len) {-# INLINE getByteString #-} putByteString :: Ptr Word8 -> ByteString -> IO () -putByteString ptr (BS fp len) = - withForeignPtr fp $ \p -> memcpy ptr p len +putByteString ptr (PS fp offset len) = + withForeignPtr fp $ \p -> memcpy ptr (p `plusPtr` offset) len {-# INLINE putByteString #-} putLazyByteString :: Ptr Word8 -> LB.ByteString -> IO () diff --git a/src/Simplex/Chat/Store/Direct.hs b/src/Simplex/Chat/Store/Direct.hs index 7504f19c95..4222994651 100644 --- a/src/Simplex/Chat/Store/Direct.hs +++ b/src/Simplex/Chat/Store/Direct.hs @@ -2,7 +2,6 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE NamedFieldPuns #-} -{-# LANGUAGE OverloadedRecordDot #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE ScopedTypeVariables #-} @@ -489,7 +488,7 @@ createOrUpdateContactRequest db user@User {userId} userContactLinkId invId (Vers ExceptT $ maybeM getContactRequestByXContactId xContactId_ >>= \case Nothing -> createContactRequest - Just cr -> updateContactRequest cr $> Right cr.contactRequestId + Just cr@UserContactRequest {contactRequestId} -> updateContactRequest cr $> Right contactRequestId getContactRequest db user cReqId createContactRequest :: IO (Either StoreError Int64) createContactRequest = do diff --git a/src/Simplex/Chat/Store/Files.hs b/src/Simplex/Chat/Store/Files.hs index 4d419c5727..8789ccd868 100644 --- a/src/Simplex/Chat/Store/Files.hs +++ b/src/Simplex/Chat/Store/Files.hs @@ -2,7 +2,6 @@ {-# LANGUAGE GADTs #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE NamedFieldPuns #-} -{-# LANGUAGE OverloadedRecordDot #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE ScopedTypeVariables #-} @@ -929,7 +928,7 @@ getLocalCryptoFile db userId fileId sent = _ -> do unless sent $ throwError $ SEFileNotFound fileId FileTransferMeta {filePath, xftpSndFile} <- getFileTransferMeta_ db userId fileId - pure $ CryptoFile filePath $ xftpSndFile >>= \f -> f.cryptoArgs + pure $ CryptoFile filePath $ xftpSndFile >>= \XFTPSndFile {cryptoArgs} -> cryptoArgs updateDirectCIFileStatus :: forall d. MsgDirectionI d => DB.Connection -> VersionRange -> User -> Int64 -> CIFileStatus d -> ExceptT StoreError IO AChatItem updateDirectCIFileStatus db vr user fileId fileStatus = do diff --git a/src/Simplex/Chat/Store/Groups.hs b/src/Simplex/Chat/Store/Groups.hs index 2066626364..e9ec8be28c 100644 --- a/src/Simplex/Chat/Store/Groups.hs +++ b/src/Simplex/Chat/Store/Groups.hs @@ -2,7 +2,6 @@ {-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE NamedFieldPuns #-} -{-# LANGUAGE OverloadedRecordDot #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE RecordWildCards #-} @@ -320,7 +319,7 @@ createNewGroup db vr gVar user@User {userId} groupProfile incognitoProfile = Exc -- | creates a new group record for the group the current user was invited to, or returns an existing one createGroupInvitation :: DB.Connection -> VersionRange -> User -> Contact -> GroupInvitation -> Maybe ProfileId -> ExceptT StoreError IO (GroupInfo, GroupMemberId) createGroupInvitation _ _ _ Contact {localDisplayName, activeConn = Nothing} _ _ = throwError $ SEContactNotReady localDisplayName -createGroupInvitation db vr user@User {userId} contact@Contact {contactId, activeConn = Just hostConn@Connection {customUserProfileId}} GroupInvitation {fromMember, invitedMember, connRequest, groupProfile} incognitoProfileId = do +createGroupInvitation db vr user@User {userId} contact@Contact {contactId, activeConn = Just Connection {customUserProfileId, peerChatVRange}} GroupInvitation {fromMember, invitedMember, connRequest, groupProfile} incognitoProfileId = do liftIO getInvitationGroupId_ >>= \case Nothing -> createGroupInvitation_ Just gId -> do @@ -358,7 +357,7 @@ createGroupInvitation db vr user@User {userId} contact@Contact {contactId, activ "INSERT INTO groups (group_profile_id, local_display_name, inv_queue_info, host_conn_custom_user_profile_id, user_id, enable_ntfs, created_at, updated_at, chat_ts) VALUES (?,?,?,?,?,?,?,?,?)" (profileId, localDisplayName, connRequest, customUserProfileId, userId, True, currentTs, currentTs, currentTs) insertedRowId db - let JVersionRange hostVRange = hostConn.peerChatVRange + let JVersionRange hostVRange = peerChatVRange GroupMember {groupMemberId} <- createContactMemberInv_ db user groupId Nothing contact fromMember GCHostMember GSMemInvited IBUnknown Nothing currentTs hostVRange membership <- createContactMemberInv_ db user groupId (Just groupMemberId) user invitedMember GCUserMember GSMemInvited (IBContact contactId) incognitoProfileId currentTs vr let chatSettings = ChatSettings {enableNtfs = MFAll, sendRcpts = Nothing, favorite = False} @@ -1041,7 +1040,7 @@ updateIntroStatus db introId introStatus = do [":intro_status" := introStatus, ":updated_at" := currentTs, ":intro_id" := introId] saveIntroInvitation :: DB.Connection -> GroupMember -> GroupMember -> IntroInvitation -> ExceptT StoreError IO GroupMemberIntro -saveIntroInvitation db reMember toMember introInv = do +saveIntroInvitation db reMember toMember introInv@IntroInvitation {groupConnReq} = do intro <- getIntroduction db reMember toMember liftIO $ do currentTs <- getCurrentTime @@ -1056,7 +1055,7 @@ saveIntroInvitation db reMember toMember introInv = do WHERE group_member_intro_id = :intro_id |] [ ":intro_status" := GMIntroInvReceived, - ":group_queue_info" := introInv.groupConnReq, + ":group_queue_info" := groupConnReq, ":direct_queue_info" := directConnReq introInv, ":updated_at" := currentTs, ":intro_id" := introId intro diff --git a/src/Simplex/Chat/Types.hs b/src/Simplex/Chat/Types.hs index de2dfa8b58..dd832d6fa4 100644 --- a/src/Simplex/Chat/Types.hs +++ b/src/Simplex/Chat/Types.hs @@ -9,7 +9,6 @@ {-# LANGUAGE LambdaCase #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE NamedFieldPuns #-} -{-# LANGUAGE OverloadedRecordDot #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE ScopedTypeVariables #-} @@ -61,21 +60,21 @@ class IsContact a where preferences' :: a -> Maybe Preferences instance IsContact User where - contactId' u = u.userContactId + contactId' User {userContactId} = userContactId {-# INLINE contactId' #-} - profile' u = u.profile + profile' User {profile} = profile {-# INLINE profile' #-} - localDisplayName' u = u.localDisplayName + localDisplayName' User {localDisplayName} = localDisplayName {-# INLINE localDisplayName' #-} preferences' User {profile = LocalProfile {preferences}} = preferences {-# INLINE preferences' #-} instance IsContact Contact where - contactId' c = c.contactId + contactId' Contact {contactId} = contactId {-# INLINE contactId' #-} - profile' c = c.profile + profile' Contact {profile} = profile {-# INLINE profile' #-} - localDisplayName' c = c.localDisplayName + localDisplayName' Contact {localDisplayName} = localDisplayName {-# INLINE localDisplayName' #-} preferences' Contact {profile = LocalProfile {preferences}} = preferences {-# INLINE preferences' #-} @@ -196,7 +195,7 @@ directOrUsed ct@Contact {contactUsed} = contactDirect ct || contactUsed anyDirectOrUsed :: Contact -> Bool -anyDirectOrUsed Contact {contactUsed, activeConn} = ((\c -> c.connLevel) <$> activeConn) == Just 0 || contactUsed +anyDirectOrUsed Contact {contactUsed, activeConn} = ((\Connection {connLevel} -> connLevel) <$> activeConn) == Just 0 || contactUsed contactReady :: Contact -> Bool contactReady Contact {activeConn} = maybe False connReady activeConn diff --git a/src/Simplex/Chat/Types/Preferences.hs b/src/Simplex/Chat/Types/Preferences.hs index 5c79680c50..2286ae8f40 100644 --- a/src/Simplex/Chat/Types/Preferences.hs +++ b/src/Simplex/Chat/Types/Preferences.hs @@ -7,7 +7,6 @@ {-# LANGUAGE LambdaCase #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE NamedFieldPuns #-} -{-# LANGUAGE OverloadedRecordDot #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StandaloneDeriving #-} @@ -79,12 +78,12 @@ allChatFeatures = ] chatPrefSel :: SChatFeature f -> Preferences -> Maybe (FeaturePreference f) -chatPrefSel f ps = case f of - SCFTimedMessages -> ps.timedMessages - SCFFullDelete -> ps.fullDelete - SCFReactions -> ps.reactions - SCFVoice -> ps.voice - SCFCalls -> ps.calls +chatPrefSel f Preferences {timedMessages, fullDelete, reactions, voice, calls} = case f of + SCFTimedMessages -> timedMessages + SCFFullDelete -> fullDelete + SCFReactions -> reactions + SCFVoice -> voice + SCFCalls -> calls chatFeature :: SChatFeature f -> ChatFeature chatFeature = \case @@ -104,12 +103,12 @@ instance PreferenceI (Maybe Preferences) where getPreference f prefs = fromMaybe (getPreference f defaultChatPrefs) (chatPrefSel f =<< prefs) instance PreferenceI FullPreferences where - getPreference f ps = case f of - SCFTimedMessages -> ps.timedMessages - SCFFullDelete -> ps.fullDelete - SCFReactions -> ps.reactions - SCFVoice -> ps.voice - SCFCalls -> ps.calls + getPreference f FullPreferences {timedMessages, fullDelete, reactions, voice, calls} = case f of + SCFTimedMessages -> timedMessages + SCFFullDelete -> fullDelete + SCFReactions -> reactions + SCFVoice -> voice + SCFCalls -> calls {-# INLINE getPreference #-} setPreference :: forall f. FeatureI f => SChatFeature f -> Maybe FeatureAllowed -> Maybe Preferences -> Preferences @@ -196,14 +195,14 @@ allGroupFeatures = ] groupPrefSel :: SGroupFeature f -> GroupPreferences -> Maybe (GroupFeaturePreference f) -groupPrefSel f ps = case f of - SGFTimedMessages -> ps.timedMessages - SGFDirectMessages -> ps.directMessages - SGFFullDelete -> ps.fullDelete - SGFReactions -> ps.reactions - SGFVoice -> ps.voice - SGFFiles -> ps.files - SGFHistory -> ps.history +groupPrefSel f GroupPreferences {timedMessages, directMessages, fullDelete, reactions, voice, files, history} = case f of + SGFTimedMessages -> timedMessages + SGFDirectMessages -> directMessages + SGFFullDelete -> fullDelete + SGFReactions -> reactions + SGFVoice -> voice + SGFFiles -> files + SGFHistory -> history toGroupFeature :: SGroupFeature f -> GroupFeature toGroupFeature = \case @@ -225,14 +224,14 @@ instance GroupPreferenceI (Maybe GroupPreferences) where getGroupPreference pt prefs = fromMaybe (getGroupPreference pt defaultGroupPrefs) (groupPrefSel pt =<< prefs) instance GroupPreferenceI FullGroupPreferences where - getGroupPreference f ps = case f of - SGFTimedMessages -> ps.timedMessages - SGFDirectMessages -> ps.directMessages - SGFFullDelete -> ps.fullDelete - SGFReactions -> ps.reactions - SGFVoice -> ps.voice - SGFFiles -> ps.files - SGFHistory -> ps.history + getGroupPreference f FullGroupPreferences {timedMessages, directMessages, fullDelete, reactions, voice, files, history} = case f of + SGFTimedMessages -> timedMessages + SGFDirectMessages -> directMessages + SGFFullDelete -> fullDelete + SGFReactions -> reactions + SGFVoice -> voice + SGFFiles -> files + SGFHistory -> history {-# INLINE getGroupPreference #-} -- collection of optional group preferences @@ -382,19 +381,19 @@ class (Eq (FeaturePreference f), HasField "allow" (FeaturePreference f) FeatureA prefParam :: FeaturePreference f -> Maybe Int instance HasField "allow" TimedMessagesPreference FeatureAllowed where - hasField p = (\allow -> p {allow}, p.allow) + hasField p@TimedMessagesPreference {allow} = (\a -> p {allow = a}, allow) instance HasField "allow" FullDeletePreference FeatureAllowed where - hasField p = (\allow -> p {allow}, p.allow) + hasField p@FullDeletePreference {allow} = (\a -> p {allow = a}, allow) instance HasField "allow" ReactionsPreference FeatureAllowed where - hasField p = (\allow -> p {allow}, p.allow) + hasField p@ReactionsPreference {allow} = (\a -> p {allow = a}, allow) instance HasField "allow" VoicePreference FeatureAllowed where - hasField p = (\allow -> p {allow}, p.allow) + hasField p@VoicePreference {allow} = (\a -> p {allow = a}, allow) instance HasField "allow" CallsPreference FeatureAllowed where - hasField p = (\allow -> p {allow}, p.allow) + hasField p@CallsPreference {allow} = (\a -> p {allow = a}, allow) instance FeatureI 'CFTimedMessages where type FeaturePreference 'CFTimedMessages = TimedMessagesPreference @@ -461,28 +460,28 @@ class (Eq (GroupFeaturePreference f), HasField "enable" (GroupFeaturePreference groupPrefParam :: GroupFeaturePreference f -> Maybe Int instance HasField "enable" GroupPreference GroupFeatureEnabled where - hasField p = (\enable -> p {enable}, p.enable) + hasField p@GroupPreference {enable} = (\e -> p {enable = e}, enable) instance HasField "enable" TimedMessagesGroupPreference GroupFeatureEnabled where - hasField p = (\enable -> p {enable}, p.enable) + hasField p@TimedMessagesGroupPreference {enable} = (\e -> p {enable = e}, enable) instance HasField "enable" DirectMessagesGroupPreference GroupFeatureEnabled where - hasField p = (\enable -> p {enable}, p.enable) + hasField p@DirectMessagesGroupPreference {enable} = (\e -> p {enable = e}, enable) instance HasField "enable" ReactionsGroupPreference GroupFeatureEnabled where - hasField p = (\enable -> p {enable}, p.enable) + hasField p@ReactionsGroupPreference {enable} = (\e -> p {enable = e}, enable) instance HasField "enable" FullDeleteGroupPreference GroupFeatureEnabled where - hasField p = (\enable -> p {enable}, p.enable) + hasField p@FullDeleteGroupPreference {enable} = (\e -> p {enable = e}, enable) instance HasField "enable" VoiceGroupPreference GroupFeatureEnabled where - hasField p = (\enable -> p {enable}, p.enable) + hasField p@VoiceGroupPreference {enable} = (\e -> p {enable = e}, enable) instance HasField "enable" FilesGroupPreference GroupFeatureEnabled where - hasField p = (\enable -> p {enable}, p.enable) + hasField p@FilesGroupPreference {enable} = (\e -> p {enable = e}, enable) instance HasField "enable" HistoryGroupPreference GroupFeatureEnabled where - hasField p = (\enable -> p {enable}, p.enable) + hasField p@HistoryGroupPreference {enable} = (\e -> p {enable = e}, enable) instance GroupFeatureI 'GFTimedMessages where type GroupFeaturePreference 'GFTimedMessages = TimedMessagesGroupPreference @@ -720,12 +719,12 @@ preferenceState pref = in (allow, param) getContactUserPreference :: SChatFeature f -> ContactUserPreferences -> ContactUserPreference (FeaturePreference f) -getContactUserPreference f ps = case f of - SCFTimedMessages -> ps.timedMessages - SCFFullDelete -> ps.fullDelete - SCFReactions -> ps.reactions - SCFVoice -> ps.voice - SCFCalls -> ps.calls +getContactUserPreference f ContactUserPreferences {timedMessages, fullDelete, reactions, voice, calls} = case f of + SCFTimedMessages -> timedMessages + SCFFullDelete -> fullDelete + SCFReactions -> reactions + SCFVoice -> voice + SCFCalls -> calls $(J.deriveJSON (enumJSON $ dropPrefix "CF") ''ChatFeature) diff --git a/src/Simplex/Chat/View.hs b/src/Simplex/Chat/View.hs index b0408690ae..bc17432760 100644 --- a/src/Simplex/Chat/View.hs +++ b/src/Simplex/Chat/View.hs @@ -3,7 +3,6 @@ {-# LANGUAGE GADTs #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE NamedFieldPuns #-} -{-# LANGUAGE OverloadedRecordDot #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE ScopedTypeVariables #-} @@ -212,7 +211,9 @@ responseToView hu@(currentRH, user_) ChatConfig {logLevel, showReactions, showRe CRContactConnecting u _ -> ttyUser u [] CRContactConnected u ct userCustomProfile -> ttyUser u $ viewContactConnected ct userCustomProfile testView CRContactAnotherClient u c -> ttyUser u [ttyContact' c <> ": contact is connected to another client"] - CRSubscriptionEnd u acEntity -> ttyUser u [sShow ((entityConnection acEntity).connId) <> ": END"] + CRSubscriptionEnd u acEntity -> + let Connection {connId} = entityConnection acEntity + in ttyUser u [sShow connId <> ": END"] CRContactsDisconnected srv cs -> [plain $ "server disconnected " <> showSMPServer srv <> " (" <> contactList cs <> ")"] CRContactsSubscribed srv cs -> [plain $ "server connected " <> showSMPServer srv <> " (" <> contactList cs <> ")"] CRContactSubError u c e -> ttyUser u [ttyContact' c <> ": contact error " <> sShow e] @@ -494,7 +495,7 @@ viewGroupSubscribed :: GroupInfo -> [StyledString] viewGroupSubscribed g = [membershipIncognito g <> ttyFullGroup g <> ": connected to server(s)"] showSMPServer :: SMPServer -> String -showSMPServer srv = B.unpack $ strEncode srv.host +showSMPServer ProtocolServer {host} = B.unpack $ strEncode host viewHostEvent :: AProtocolType -> TransportHost -> String viewHostEvent p h = map toUpper (B.unpack $ strEncode p) <> " host " <> B.unpack (strEncode h) @@ -953,7 +954,7 @@ viewGroupMembers (Group GroupInfo {membership} members) = map groupMember . filt removedOrLeft m = let s = memberStatus m in s == GSMemRemoved || s == GSMemLeft groupMember m = memIncognito m <> ttyFullMember m <> ": " <> plain (intercalate ", " $ [role m] <> category m <> status m <> muted m) role :: GroupMember -> String - role m = B.unpack . strEncode $ m.memberRole + role GroupMember {memberRole} = B.unpack $ strEncode memberRole category m = case memberCategory m of GCUserMember -> ["you"] GCInviteeMember -> ["invited"] @@ -991,7 +992,7 @@ viewGroupsList [] = ["you have no groups!", "to create: " <> highlight' "/g Text - ldn_ g = T.toLower g.localDisplayName + ldn_ GroupInfo {localDisplayName} = T.toLower localDisplayName groupSS (g@GroupInfo {membership, chatSettings = ChatSettings {enableNtfs}}, GroupSummary {currentMembers}) = case memberStatus membership of GSMemInvited -> groupInvitation' g @@ -1906,7 +1907,7 @@ viewChatError logLevel testView = \case "[" <> connEntityLabel entity <> ", userContactLinkId: " <> sShow userContactLinkId <> ", connId: " <> cId conn <> "] " Nothing -> "" cId :: Connection -> StyledString - cId conn = sShow conn.connId + cId Connection {connId} = sShow connId ChatErrorRemoteCtrl e -> [plain $ "remote controller error: " <> show e] ChatErrorRemoteHost RHNew e -> [plain $ "new remote host error: " <> show e] ChatErrorRemoteHost (RHId rhId) e -> [plain $ "remote host " <> show rhId <> " error: " <> show e] diff --git a/tests/Bots/BroadcastTests.hs b/tests/Bots/BroadcastTests.hs index ed0b9e069a..6eee414c32 100644 --- a/tests/Bots/BroadcastTests.hs +++ b/tests/Bots/BroadcastTests.hs @@ -1,6 +1,5 @@ {-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE NamedFieldPuns #-} -{-# LANGUAGE OverloadedRecordDot #-} {-# LANGUAGE OverloadedStrings #-} module Bots.BroadcastTests where @@ -13,7 +12,7 @@ import Control.Concurrent (forkIO, killThread, threadDelay) import Control.Exception (bracket) import Simplex.Chat.Bot.KnownContacts import Simplex.Chat.Core -import Simplex.Chat.Options (ChatOpts (..), CoreChatOpts (..)) +import Simplex.Chat.Options (CoreChatOpts (..)) import Simplex.Chat.Types (Profile (..)) import System.FilePath (()) import Test.Hspec @@ -34,7 +33,7 @@ broadcastBotProfile = Profile {displayName = "broadcast_bot", fullName = "Broadc mkBotOpts :: FilePath -> [KnownContact] -> BroadcastBotOpts mkBotOpts tmp publishers = BroadcastBotOpts - { coreOptions = testOpts.coreOptions {dbFilePrefix = tmp botDbPrefix}, + { coreOptions = testCoreOpts {dbFilePrefix = tmp botDbPrefix}, publishers, welcomeMessage = defaultWelcomeMessage publishers, prohibitedMessage = defaultWelcomeMessage publishers diff --git a/tests/Bots/DirectoryTests.hs b/tests/Bots/DirectoryTests.hs index 3c6991bb52..4ddf9fff1b 100644 --- a/tests/Bots/DirectoryTests.hs +++ b/tests/Bots/DirectoryTests.hs @@ -1,6 +1,5 @@ {-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE NamedFieldPuns #-} -{-# LANGUAGE OverloadedRecordDot #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE PostfixOperators #-} @@ -19,7 +18,7 @@ import GHC.IO.Handle (hClose) import Simplex.Chat.Bot.KnownContacts import Simplex.Chat.Controller (ChatConfig (..)) import Simplex.Chat.Core -import Simplex.Chat.Options (ChatOpts (..), CoreChatOpts (..)) +import Simplex.Chat.Options (CoreChatOpts (..)) import Simplex.Chat.Types (GroupMemberRole (..), Profile (..)) import System.FilePath (()) import Test.Hspec @@ -64,7 +63,7 @@ directoryProfile = Profile {displayName = "SimpleX-Directory", fullName = "", im mkDirectoryOpts :: FilePath -> [KnownContact] -> DirectoryOpts mkDirectoryOpts tmp superUsers = DirectoryOpts - { coreOptions = testOpts.coreOptions {dbFilePrefix = tmp serviceDbPrefix}, + { coreOptions = testCoreOpts {dbFilePrefix = tmp serviceDbPrefix}, superUsers, directoryLog = Just $ tmp "directory_service.log", serviceName = "SimpleX-Directory", diff --git a/tests/ChatClient.hs b/tests/ChatClient.hs index d2165db04f..942f43bbe7 100644 --- a/tests/ChatClient.hs +++ b/tests/ChatClient.hs @@ -58,22 +58,7 @@ serverPort = "7001" testOpts :: ChatOpts testOpts = ChatOpts - { coreOptions = - CoreChatOpts - { dbFilePrefix = undefined, - dbKey = "", - -- dbKey = "this is a pass-phrase to encrypt the database", - smpServers = ["smp://LcJUMfVhwD8yxjAiSaDzzGF3-kLG4Uh0Fl_ZIjrRwjI=:server_password@localhost:7001"], - xftpServers = ["xftp://LcJUMfVhwD8yxjAiSaDzzGF3-kLG4Uh0Fl_ZIjrRwjI=:server_password@localhost:7002"], - networkConfig = defaultNetworkConfig, - logLevel = CLLImportant, - logConnections = False, - logServerHosts = False, - logAgent = Nothing, - logFile = Nothing, - tbqSize = 16, - highlyAvailable = False - }, + { coreOptions = testCoreOpts, deviceName = Nothing, chatCmd = "", chatCmdDelay = 3, @@ -87,8 +72,25 @@ testOpts = maintenance = False } +testCoreOpts :: CoreChatOpts +testCoreOpts = CoreChatOpts + { dbFilePrefix = undefined, + dbKey = "", + -- dbKey = "this is a pass-phrase to encrypt the database", + smpServers = ["smp://LcJUMfVhwD8yxjAiSaDzzGF3-kLG4Uh0Fl_ZIjrRwjI=:server_password@localhost:7001"], + xftpServers = ["xftp://LcJUMfVhwD8yxjAiSaDzzGF3-kLG4Uh0Fl_ZIjrRwjI=:server_password@localhost:7002"], + networkConfig = defaultNetworkConfig, + logLevel = CLLImportant, + logConnections = False, + logServerHosts = False, + logAgent = Nothing, + logFile = Nothing, + tbqSize = 16, + highlyAvailable = False + } + getTestOpts :: Bool -> ScrubbedBytes -> ChatOpts -getTestOpts maintenance dbKey = testOpts {maintenance, coreOptions = (coreOptions testOpts) {dbKey}} +getTestOpts maintenance dbKey = testOpts {maintenance, coreOptions = testCoreOpts {dbKey}} termSettings :: VirtualTerminalSettings termSettings = From 78eefee6cc972ae34b7e36f849f834d1c7266934 Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Sat, 30 Dec 2023 04:28:11 +0700 Subject: [PATCH 012/102] android, desktop: search view will be shown always (#3625) * android, desktop: search view will be shown always * rearrange tree * optimization --- .../common/views/chatlist/ChatListView.kt | 19 ++++++++----------- .../commonMain/resources/MR/base/strings.xml | 3 --- 2 files changed, 8 insertions(+), 14 deletions(-) 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 4280f51368..59c18c9703 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 @@ -101,19 +101,16 @@ fun ChatListView(chatModel: ChatModel, settingsState: SettingsViewState, setPerf } ) { Box(Modifier.padding(it).padding(end = endPadding)) { - Column( + Box( modifier = Modifier .fillMaxSize() ) { - if (chatModel.chats.isNotEmpty()) { - ChatList(chatModel, searchText = searchText) - } else if (!chatModel.switchingUsersAndHosts.value && !chatModel.desktopNoUserNoRemote) { - Box(Modifier.fillMaxSize()) { - if (!stopped && !newChatSheetState.collectAsState().value.isVisible() && chatModel.chatRunning.value == true) { - OnboardingButtons(showNewChatSheet) - } - Text(stringResource( - if (chatModel.chatRunning.value == null) MR.strings.loading_chats else MR.strings.you_have_no_chats), Modifier.align(Alignment.Center), color = MaterialTheme.colors.secondary) + ChatList(chatModel, searchText = searchText) + if (chatModel.chats.isEmpty() && !chatModel.switchingUsersAndHosts.value && !chatModel.desktopNoUserNoRemote) { + Text(stringResource( + if (chatModel.chatRunning.value == null) MR.strings.loading_chats else MR.strings.you_have_no_chats), Modifier.align(Alignment.Center), color = MaterialTheme.colors.secondary) + if (!stopped && !newChatSheetState.collectAsState().value.isVisible() && chatModel.chatRunning.value == true && searchText.value.text.isEmpty()) { + OnboardingButtons(showNewChatSheet) } } } @@ -481,7 +478,7 @@ private fun ChatList(chatModel: ChatModel, searchText: MutableStateRandom passphrase is stored in settings as plaintext.\nYou can change it later. Use random passphrase - - Paste received link - Incoming video call Incoming audio call From 644169b8358e40bf482738e3600cda69ab9fd792 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Sat, 30 Dec 2023 10:02:55 +0000 Subject: [PATCH 013/102] cli: prompt for database key entry if required (#3626) --- src/Simplex/Chat/Terminal.hs | 41 ++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/src/Simplex/Chat/Terminal.hs b/src/Simplex/Chat/Terminal.hs index c27675678e..2060e529eb 100644 --- a/src/Simplex/Chat/Terminal.hs +++ b/src/Simplex/Chat/Terminal.hs @@ -1,12 +1,16 @@ {-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-} module Simplex.Chat.Terminal where import Control.Exception (handle, throwIO) import Control.Monad +import qualified Data.ByteArray as BA import qualified Data.List.NonEmpty as L +import qualified Data.Text as T +import Data.Text.Encoding (encodeUtf8) import Database.SQLite.Simple (SQLError (..)) import qualified Database.SQLite.Simple as DB import Simplex.Chat (defaultChatConfig) @@ -19,7 +23,7 @@ import Simplex.Chat.Terminal.Output import Simplex.FileTransfer.Client.Presets (defaultXFTPServers) import Simplex.Messaging.Client (defaultNetworkConfig) import Simplex.Messaging.Util (raceAny_) -import System.Exit (exitFailure) +import System.IO (hFlush, hSetEcho, stdin, stdout) terminalChatConfig :: ChatConfig terminalChatConfig = @@ -40,18 +44,29 @@ terminalChatConfig = } simplexChatTerminal :: WithTerminal t => ChatConfig -> ChatOpts -> t -> IO () -simplexChatTerminal cfg opts t = - handle checkDBKeyError . simplexChatCore cfg opts $ \u cc -> do - ct <- newChatTerminal t opts - when (firstTime cc) . printToTerminal ct $ chatWelcome u - runChatTerminal ct cc opts - -checkDBKeyError :: SQLError -> IO () -checkDBKeyError e = case sqlError e of - DB.ErrorNotADatabase -> do - putStrLn "Database file is invalid or you passed an incorrect encryption key" - exitFailure - _ -> throwIO e +simplexChatTerminal cfg options t = run options + where + run opts@ChatOpts {coreOptions = coreOptions@CoreChatOpts {dbKey}} = + handle checkDBKeyError . simplexChatCore cfg opts $ \u cc -> do + ct <- newChatTerminal t opts + when (firstTime cc) . printToTerminal ct $ chatWelcome u + runChatTerminal ct cc opts + where + checkDBKeyError :: SQLError -> IO () + checkDBKeyError e = case sqlError e of + DB.ErrorNotADatabase -> do + putStrLn $ "Database file is invalid or " <> if BA.null dbKey then "encrypted." else "you passed an incorrect encryption key." + run =<< getKeyOpts + _ -> throwIO e + getKeyOpts :: IO ChatOpts + getKeyOpts = do + putStr "Enter database encryption key (Ctrl-C to exit):" + hFlush stdout + hSetEcho stdin False + key <- getLine + hSetEcho stdin True + putStrLn "" + pure opts {coreOptions = coreOptions {dbKey = BA.convert $ encodeUtf8 $ T.pack key}} runChatTerminal :: ChatTerminal -> ChatController -> ChatOpts -> IO () runChatTerminal ct cc opts = raceAny_ [runTerminalInput ct cc, runTerminalOutput ct cc opts, runInputLoop ct cc] From 4ab078bd183455c74d632b47b04a65547d0b7417 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Sat, 30 Dec 2023 14:09:07 +0000 Subject: [PATCH 014/102] ios: show clear search button when search is not empty (#3627) --- apps/ios/Shared/Views/ChatList/ChatListView.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/ios/Shared/Views/ChatList/ChatListView.swift b/apps/ios/Shared/Views/ChatList/ChatListView.swift index 3d0551de66..62955a1040 100644 --- a/apps/ios/Shared/Views/ChatList/ChatListView.swift +++ b/apps/ios/Shared/Views/ChatList/ChatListView.swift @@ -289,16 +289,16 @@ struct ChatListSearchBar: View { HStack(spacing: 4) { Image(systemName: "magnifyingglass") TextField("Search or paste SimpleX link", text: $searchText) + .foregroundColor(searchShowingSimplexLink ? .secondary : .primary) .disabled(searchShowingSimplexLink) .focused($searchFocussed) .frame(maxWidth: .infinity) - if searchFocussed || searchShowingSimplexLink { + if !searchText.isEmpty { Image(systemName: "xmark.circle.fill") - .opacity(searchText == "" ? 0 : 1) .onTapGesture { searchText = "" } - } else if searchText == "" { + } else if !searchFocussed { HStack(spacing: 24) { if m.pasteboardHasStrings { Image(systemName: "doc") From 809040c7bc40f908a1f16fe5c718be5422aedfc4 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Sat, 30 Dec 2023 18:57:10 +0000 Subject: [PATCH 015/102] ui: show secrets on tap (#3628) * ios: show secrets on tap * android: show secrets on tap/click * android: clickable links in group descriptions * android: hide secrets one by one * ios: clickable links in welcome message preview * refactor * refactor2 --- .../Views/Chat/ChatItem/FramedItemView.swift | 34 +++++++++++++------ .../Views/Chat/ChatItem/MsgContentView.swift | 22 ++++++++---- .../Shared/Views/Chat/ChatItemInfoView.swift | 15 ++++++-- .../Chat/ComposeMessage/ContextItemView.swift | 3 +- .../Views/Chat/Group/GroupWelcomeView.swift | 3 +- .../Views/ChatList/ChatPreviewView.swift | 4 +-- apps/ios/SimpleXChat/ChatTypes.swift | 4 +++ .../common/views/chat/ChatItemInfoView.kt | 1 + .../common/views/chat/ContextItemView.kt | 1 + .../views/chat/group/WelcomeMessageView.kt | 5 ++- .../common/views/chat/item/FramedItemView.kt | 3 +- .../common/views/chat/item/TextItemView.kt | 27 ++++++++++++--- .../common/views/chatlist/ChatPreviewView.kt | 1 + .../common/views/onboarding/HowItWorks.kt | 11 ------ 14 files changed, 91 insertions(+), 43 deletions(-) diff --git a/apps/ios/Shared/Views/Chat/ChatItem/FramedItemView.swift b/apps/ios/Shared/Views/Chat/ChatItem/FramedItemView.swift index 51dfa3cb50..7b5dd40e97 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/FramedItemView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/FramedItemView.swift @@ -28,7 +28,9 @@ struct FramedItemView: View { @State var metaColor = Color.secondary @State var showFullScreenImage = false @Binding var allowMenu: Bool - + @State private var showSecrets = false + @State private var showQuoteSecrets = false + @Binding var audioPlayer: AudioPlayer? @Binding var playbackState: VoiceMessagePlaybackState @Binding var playbackTime: TimeInterval? @@ -252,10 +254,12 @@ struct FramedItemView: View { } private func ciQuotedMsgTextView(_ qi: CIQuote, lines: Int) -> some View { - MsgContentView(chat: chat, text: qi.text, formattedText: qi.formattedText) - .lineLimit(lines) - .font(.subheadline) - .padding(.bottom, 6) + toggleSecrets(qi.formattedText, $showQuoteSecrets, + MsgContentView(chat: chat, text: qi.text, formattedText: qi.formattedText, showSecrets: showQuoteSecrets) + .lineLimit(lines) + .font(.subheadline) + .padding(.bottom, 6) + ) } private func ciQuoteIconView(_ image: String) -> some View { @@ -278,13 +282,15 @@ struct FramedItemView: View { @ViewBuilder private func ciMsgContentView(_ ci: ChatItem) -> some View { let text = ci.meta.isLive ? ci.content.msgContent?.text ?? ci.text : ci.text let rtl = isRightToLeft(text) - let v = MsgContentView( + let ft = text == "" ? [] : ci.formattedText + let v = toggleSecrets(ft, $showSecrets, MsgContentView( chat: chat, text: text, - formattedText: text == "" ? [] : ci.formattedText, + formattedText: ft, meta: ci.meta, - rightToLeft: rtl - ) + rightToLeft: rtl, + showSecrets: showSecrets + )) .multilineTextAlignment(rtl ? .trailing : .leading) .padding(.vertical, 6) .padding(.horizontal, 12) @@ -298,7 +304,7 @@ struct FramedItemView: View { v } } - + @ViewBuilder private func ciFileView(_ ci: ChatItem, _ text: String) -> some View { CIFileView(file: chatItem.file, edited: chatItem.meta.itemEdited) .overlay(DetermineWidth()) @@ -318,6 +324,14 @@ struct FramedItemView: View { } } +@ViewBuilder func toggleSecrets(_ ft: [FormattedText]?, _ showSecrets: Binding, _ v: V) -> some View { + if let ft = ft, ft.contains(where: { $0.isSecret }) { + v.onTapGesture { showSecrets.wrappedValue.toggle() } + } else { + v + } +} + func isRightToLeft(_ s: String) -> Bool { if let lang = CFStringTokenizerCopyBestStringLanguage(s as CFString, CFRange(location: 0, length: min(s.count, 80))) { return NSLocale.characterDirection(forLanguage: lang as String) == .rightToLeft diff --git a/apps/ios/Shared/Views/Chat/ChatItem/MsgContentView.swift b/apps/ios/Shared/Views/Chat/ChatItem/MsgContentView.swift index cad6401cc0..ccd7ac0a12 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/MsgContentView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/MsgContentView.swift @@ -31,6 +31,7 @@ struct MsgContentView: View { var sender: String? = nil var meta: CIMeta? = nil var rightToLeft = false + var showSecrets: Bool @State private var typingIdx = 0 @State private var timer: Timer? @@ -62,7 +63,7 @@ struct MsgContentView: View { } private func msgContentView() -> Text { - var v = messageText(text, formattedText, sender) + var v = messageText(text, formattedText, sender, showSecrets: showSecrets) if let mt = meta { if mt.isLive { v = v + typingIndicator(mt.recent) @@ -84,14 +85,14 @@ struct MsgContentView: View { } } -func messageText(_ text: String, _ formattedText: [FormattedText]?, _ sender: String?, icon: String? = nil, preview: Bool = false) -> Text { +func messageText(_ text: String, _ formattedText: [FormattedText]?, _ sender: String?, icon: String? = nil, preview: Bool = false, showSecrets: Bool) -> Text { let s = text var res: Text if let ft = formattedText, ft.count > 0 && ft.count <= 200 { - res = formatText(ft[0], preview) + res = formatText(ft[0], preview, showSecret: showSecrets) var i = 1 while i < ft.count { - res = res + formatText(ft[i], preview) + res = res + formatText(ft[i], preview, showSecret: showSecrets) i = i + 1 } } else { @@ -110,7 +111,7 @@ func messageText(_ text: String, _ formattedText: [FormattedText]?, _ sender: St } } -private func formatText(_ ft: FormattedText, _ preview: Bool) -> Text { +private func formatText(_ ft: FormattedText, _ preview: Bool, showSecret: Bool) -> Text { let t = ft.text if let f = ft.format { switch (f) { @@ -118,7 +119,13 @@ private func formatText(_ ft: FormattedText, _ preview: Bool) -> Text { case .italic: return Text(t).italic() case .strikeThrough: return Text(t).strikethrough() case .snippet: return Text(t).font(.body.monospaced()) - case .secret: return Text(t).foregroundColor(.clear).underline(color: .primary) + case .secret: return + showSecret + ? Text(t) + : Text(AttributedString(t, attributes: AttributeContainer([ + .foregroundColor: UIColor.clear as Any, + .backgroundColor: UIColor.secondarySystemFill as Any + ]))) case let .colored(color): return Text(t).foregroundColor(color.uiColor) case .uri: return linkText(t, t, preview, prefix: "") case let .simplexLink(linkType, simplexUri, smpHosts): @@ -156,7 +163,8 @@ struct MsgContentView_Previews: PreviewProvider { text: chatItem.text, formattedText: chatItem.formattedText, sender: chatItem.memberDisplayName, - meta: chatItem.meta + meta: chatItem.meta, + showSecrets: false ) .environmentObject(Chat.sampleData) } diff --git a/apps/ios/Shared/Views/Chat/ChatItemInfoView.swift b/apps/ios/Shared/Views/Chat/ChatItemInfoView.swift index 83c4cdcda6..69cfcd2caf 100644 --- a/apps/ios/Shared/Views/Chat/ChatItemInfoView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItemInfoView.swift @@ -168,7 +168,6 @@ struct ChatItemInfoView: View { @ViewBuilder private func itemVersionView(_ itemVersion: ChatItemVersion, _ maxWidth: CGFloat, current: Bool) -> some View { VStack(alignment: .leading, spacing: 4) { textBubble(itemVersion.msgContent.text, itemVersion.formattedText, nil) - .allowsHitTesting(false) .padding(.horizontal, 12) .padding(.vertical, 6) .background(chatItemFrameColor(ci, colorScheme)) @@ -198,7 +197,7 @@ struct ChatItemInfoView: View { @ViewBuilder private func textBubble(_ text: String, _ formattedText: [FormattedText]?, _ sender: String? = nil) -> some View { if text != "" { - messageText(text, formattedText, sender) + TextBubble(text: text, formattedText: formattedText, sender: sender) } else { Text("no text") .italic() @@ -206,6 +205,17 @@ struct ChatItemInfoView: View { } } + private struct TextBubble: View { + var text: String + var formattedText: [FormattedText]? + var sender: String? = nil + @State private var showSecrets = false + + var body: some View { + toggleSecrets(formattedText, $showSecrets, messageText(text, formattedText, sender, showSecrets: showSecrets)) + } + } + @ViewBuilder private func quoteTab(_ qi: CIQuote) -> some View { GeometryReader { g in let maxWidth = (g.size.width - 32) * 0.84 @@ -227,7 +237,6 @@ struct ChatItemInfoView: View { @ViewBuilder private func quotedMsgView(_ qi: CIQuote, _ maxWidth: CGFloat) -> some View { VStack(alignment: .leading, spacing: 4) { textBubble(qi.text, qi.formattedText, qi.getSender(nil)) - .allowsHitTesting(false) .padding(.horizontal, 12) .padding(.vertical, 6) .background(quotedMsgFrameColor(qi, colorScheme)) diff --git a/apps/ios/Shared/Views/Chat/ComposeMessage/ContextItemView.swift b/apps/ios/Shared/Views/Chat/ComposeMessage/ContextItemView.swift index 868ae3274a..3eb128cded 100644 --- a/apps/ios/Shared/Views/Chat/ComposeMessage/ContextItemView.swift +++ b/apps/ios/Shared/Views/Chat/ComposeMessage/ContextItemView.swift @@ -51,7 +51,8 @@ struct ContextItemView: View { MsgContentView( chat: chat, text: contextItem.text, - formattedText: contextItem.formattedText + formattedText: contextItem.formattedText, + showSecrets: false ) .multilineTextAlignment(isRightToLeft(contextItem.text) ? .trailing : .leading) .lineLimit(lines) diff --git a/apps/ios/Shared/Views/Chat/Group/GroupWelcomeView.swift b/apps/ios/Shared/Views/Chat/Group/GroupWelcomeView.swift index 0e47d9dddf..e5ff644a91c 100644 --- a/apps/ios/Shared/Views/Chat/Group/GroupWelcomeView.swift +++ b/apps/ios/Shared/Views/Chat/Group/GroupWelcomeView.swift @@ -53,8 +53,7 @@ struct GroupWelcomeView: View { } private func textPreview() -> some View { - messageText(welcomeText, parseSimpleXMarkdown(welcomeText), nil) - .allowsHitTesting(false) + messageText(welcomeText, parseSimpleXMarkdown(welcomeText), nil, showSecrets: false) .frame(minHeight: 140, alignment: .topLeading) .frame(maxWidth: .infinity, alignment: .leading) } diff --git a/apps/ios/Shared/Views/ChatList/ChatPreviewView.swift b/apps/ios/Shared/Views/ChatList/ChatPreviewView.swift index 30068114f3..13d91881e6 100644 --- a/apps/ios/Shared/Views/ChatList/ChatPreviewView.swift +++ b/apps/ios/Shared/Views/ChatList/ChatPreviewView.swift @@ -150,7 +150,7 @@ struct ChatPreviewView: View { let msg = draft.message return image("rectangle.and.pencil.and.ellipsis", color: .accentColor) + attachment() - + messageText(msg, parseSimpleXMarkdown(msg), nil, preview: true) + + messageText(msg, parseSimpleXMarkdown(msg), nil, preview: true, showSecrets: false) func image(_ s: String, color: Color = Color(uiColor: .tertiaryLabel)) -> Text { Text(Image(systemName: s)).foregroundColor(color) + Text(" ") @@ -169,7 +169,7 @@ struct ChatPreviewView: View { func chatItemPreview(_ cItem: ChatItem) -> Text { let itemText = cItem.meta.itemDeleted == nil ? cItem.text : NSLocalizedString("marked deleted", comment: "marked deleted chat item preview text") let itemFormattedText = cItem.meta.itemDeleted == nil ? cItem.formattedText : nil - return messageText(itemText, itemFormattedText, cItem.memberDisplayName, icon: attachment(), preview: true) + return messageText(itemText, itemFormattedText, cItem.memberDisplayName, icon: attachment(), preview: true, showSecrets: false) func attachment() -> String? { switch cItem.content.msgContent { diff --git a/apps/ios/SimpleXChat/ChatTypes.swift b/apps/ios/SimpleXChat/ChatTypes.swift index 74e5e4a3cb..96281a5013 100644 --- a/apps/ios/SimpleXChat/ChatTypes.swift +++ b/apps/ios/SimpleXChat/ChatTypes.swift @@ -3131,6 +3131,10 @@ extension MsgContent: Encodable { public struct FormattedText: Decodable { public var text: String public var format: Format? + + public var isSecret: Bool { + if case .secret = format { true } else { false } + } } public enum Format: Decodable, Equatable { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatItemInfoView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatItemInfoView.kt index 63cd25092e..3754315d05 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatItemInfoView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatItemInfoView.kt @@ -53,6 +53,7 @@ fun ChatItemInfoView(chatModel: ChatModel, ci: ChatItem, ciInfo: ChatItemInfo, d text, if (text.isEmpty()) emptyList() else formattedText, sender = sender, senderBold = true, + toggleSecrets = true, linkMode = SimplexLinkMode.DESCRIPTION, uriHandler = uriHandler, onLinkLongClick = { showMenu.value = true } ) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ContextItemView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ContextItemView.kt index 49203c7cfb..b53574cfa4 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ContextItemView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ContextItemView.kt @@ -34,6 +34,7 @@ fun ContextItemView( fun msgContentView(lines: Int) { MarkdownText( contextItem.text, contextItem.formattedText, + toggleSecrets = false, maxLines = lines, linkMode = SimplexLinkMode.DESCRIPTION, modifier = Modifier.fillMaxWidth(), diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/WelcomeMessageView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/WelcomeMessageView.kt index 577c19648d..c50a80c4e9 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/WelcomeMessageView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/WelcomeMessageView.kt @@ -15,6 +15,7 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.platform.LocalClipboardManager +import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.text.AnnotatedString import dev.icerock.moko.resources.compose.painterResource import dev.icerock.moko.resources.compose.stringResource @@ -119,13 +120,15 @@ private fun GroupWelcomeLayout( @Composable private fun TextPreview(text: String, linkMode: SimplexLinkMode, markdown: Boolean = true) { + val uriHandler = LocalUriHandler.current Column { SelectionContainer(Modifier.fillMaxWidth()) { MarkdownText( text, formattedText = if (markdown) remember(text) { parseToMarkdown(text) } else null, + toggleSecrets = false, modifier = Modifier.fillMaxHeight().padding(horizontal = DEFAULT_PADDING), - linkMode = linkMode, + linkMode = linkMode, uriHandler = uriHandler, style = MaterialTheme.typography.body1.copy(color = MaterialTheme.colors.onBackground, lineHeight = 22.sp) ) } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/FramedItemView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/FramedItemView.kt index c391200c2d..475e9779e6 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/FramedItemView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/FramedItemView.kt @@ -54,6 +54,7 @@ fun FramedItemView( MarkdownText( qi.text, qi.formattedText, + toggleSecrets = true, maxLines = lines, overflow = TextOverflow.Ellipsis, style = TextStyle(fontSize = 15.sp, color = MaterialTheme.colors.onSurface), @@ -288,7 +289,7 @@ fun CIMarkdownText( Box(Modifier.padding(vertical = 6.dp, horizontal = 12.dp)) { val text = if (ci.meta.isLive) ci.content.msgContent?.text ?: ci.text else ci.text MarkdownText( - text, if (text.isEmpty()) emptyList() else ci.formattedText, + text, if (text.isEmpty()) emptyList() else ci.formattedText, toggleSecrets = true, meta = ci.meta, chatTTL = chatTTL, linkMode = linkMode, uriHandler = uriHandler, senderBold = true, onLinkLongClick = onLinkLongClick ) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/TextItemView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/TextItemView.kt index ff1267d0fa..5169d944c8 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/TextItemView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/TextItemView.kt @@ -60,6 +60,7 @@ fun MarkdownText ( sender: String? = null, meta: CIMeta? = null, chatTTL: Int? = null, + toggleSecrets: Boolean, style: TextStyle = MaterialTheme.typography.body1.copy(color = MaterialTheme.colors.onSurface, lineHeight = 22.sp), maxLines: Int = Int.MAX_VALUE, overflow: TextOverflow = TextOverflow.Clip, @@ -89,6 +90,7 @@ fun MarkdownText ( ) { var timer: Job? by remember { mutableStateOf(null) } var typingIdx by rememberSaveable { mutableStateOf(0) } + val showSecrets = remember { mutableStateMapOf() } fun stopTyping() { timer?.cancel() timer = null @@ -127,15 +129,22 @@ fun MarkdownText ( } Text(annotatedText, style = style, modifier = modifier, maxLines = maxLines, overflow = overflow, inlineContent = inlineContent ?: mapOf()) } else { - var hasLinks = false + var hasAnnotations = false val annotatedText = buildAnnotatedString { appendSender(this, sender, senderBold) - for (ft in formattedText) { + for ((i, ft) in formattedText.withIndex()) { if (ft.format == null) append(ft.text) - else { + else if (toggleSecrets && ft.format is Format.Secret) { + val ftStyle = ft.format.style + hasAnnotations = true + val key = i.toString() + withAnnotation(tag = "SECRET", annotation = key) { + if (showSecrets[key] == true) append(ft.text) else withStyle(ftStyle) { append(ft.text) } + } + } else { val link = ft.link(linkMode) if (link != null) { - hasLinks = true + hasAnnotations = true val ftStyle = ft.format.style withAnnotation(tag = if (ft.format is Format.SimplexLink) "SIMPLEX_URL" else "URL", annotation = link) { withStyle(ftStyle) { append(ft.viewText(linkMode)) } @@ -153,7 +162,7 @@ fun MarkdownText ( withStyle(reserveTimestampStyle) { append("\n" + metaText) } else */if (meta != null) withStyle(reserveTimestampStyle) { append(reserve) } } - if (hasLinks && uriHandler != null) { + if (hasAnnotations && uriHandler != null) { val icon = remember { mutableStateOf(PointerIcon.Default) } ClickableText(annotatedText, style = style, modifier = modifier.pointerHoverIcon(icon.value), maxLines = maxLines, overflow = overflow, onLongClick = { offset -> @@ -177,12 +186,20 @@ fun MarkdownText ( .firstOrNull()?.let { annotation -> uriHandler.openVerifiedSimplexUri(annotation.item) } + annotatedText.getStringAnnotations(tag = "SECRET", start = offset, end = offset) + .firstOrNull()?.let { annotation -> + val key = annotation.item + showSecrets[key] = !(showSecrets[key] ?: false) + } }, onHover = { offset -> icon.value = annotatedText.getStringAnnotations(tag = "URL", start = offset, end = offset) .firstOrNull()?.let { PointerIcon.Hand } ?: annotatedText.getStringAnnotations(tag = "SIMPLEX_URL", start = offset, end = offset) + .firstOrNull()?.let { + PointerIcon.Hand + } ?: annotatedText.getStringAnnotations(tag = "SECRET", start = offset, end = offset) .firstOrNull()?.let { PointerIcon.Hand } ?: PointerIcon.Default diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatPreviewView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatPreviewView.kt index af1f49a088..d59dac37bf 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatPreviewView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatPreviewView.kt @@ -173,6 +173,7 @@ fun ChatPreviewView( cInfo is ChatInfo.Group && !ci.chatDir.sent -> ci.memberDisplayName else -> null }, + toggleSecrets = false, linkMode = linkMode, senderBold = true, maxLines = 2, diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/HowItWorks.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/HowItWorks.kt index 6c76acc3e8..14b36d0718 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/HowItWorks.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/HowItWorks.kt @@ -78,17 +78,6 @@ fun ReadableText(text: String, textAlign: TextAlign = TextAlign.Start, padding: Text(text, modifier = Modifier.padding(padding), textAlign = textAlign, lineHeight = 22.sp) } -@Composable -fun ReadableMarkdownText(text: String, textAlign: TextAlign = TextAlign.Start, padding: PaddingValues = PaddingValues(bottom = 12.dp)) { - MarkdownText( - text, - formattedText = remember(text) { parseToMarkdown(text) }, - modifier = Modifier.padding(padding), - style = TextStyle(textAlign = textAlign, lineHeight = 22.sp, fontSize = 16.sp), - linkMode = ChatController.appPrefs.simplexLinkMode.get(), - ) -} - @Preview/*( uiMode = Configuration.UI_MODE_NIGHT_YES, showBackground = true, From 5399212e482a21f4b3fd77780eb6007613b7efb3 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Sat, 30 Dec 2023 18:59:00 +0000 Subject: [PATCH 016/102] core: 5.5.0.0 --- package.yaml | 2 +- simplex-chat.cabal | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.yaml b/package.yaml index 4a7a2550fd..889df9db71 100644 --- a/package.yaml +++ b/package.yaml @@ -1,5 +1,5 @@ name: simplex-chat -version: 5.4.2.1 +version: 5.5.0.0 #synopsis: #description: homepage: https://github.com/simplex-chat/simplex-chat#readme diff --git a/simplex-chat.cabal b/simplex-chat.cabal index 114c22f360..5090fc5adc 100644 --- a/simplex-chat.cabal +++ b/simplex-chat.cabal @@ -5,7 +5,7 @@ cabal-version: 1.12 -- see: https://github.com/sol/hpack name: simplex-chat -version: 5.4.2.1 +version: 5.5.0.0 category: Web, System, Services, Cryptography homepage: https://github.com/simplex-chat/simplex-chat#readme author: simplex.chat From 05065e919b9603322312817210648bc3e67d18da Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Sat, 30 Dec 2023 21:09:01 +0000 Subject: [PATCH 017/102] 5.5-beta.0: ios 187, android 168, desktop 21 --- apps/ios/SimpleX.xcodeproj/project.pbxproj | 74 ++++++++++------------ apps/multiplatform/gradle.properties | 8 +-- 2 files changed, 36 insertions(+), 46 deletions(-) diff --git a/apps/ios/SimpleX.xcodeproj/project.pbxproj b/apps/ios/SimpleX.xcodeproj/project.pbxproj index a6b5eb49e9..2167d4beee 100644 --- a/apps/ios/SimpleX.xcodeproj/project.pbxproj +++ b/apps/ios/SimpleX.xcodeproj/project.pbxproj @@ -42,11 +42,11 @@ 5C3F1D562842B68D00EC8A82 /* IntegrityErrorItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C3F1D552842B68D00EC8A82 /* IntegrityErrorItemView.swift */; }; 5C3F1D58284363C400EC8A82 /* PrivacySettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C3F1D57284363C400EC8A82 /* PrivacySettings.swift */; }; 5C4B3B0A285FB130003915F2 /* DatabaseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C4B3B09285FB130003915F2 /* DatabaseView.swift */; }; - 5C4E80DA2B3CCD090080FAE2 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C4E80D52B3CCD090080FAE2 /* libgmp.a */; }; - 5C4E80DB2B3CCD090080FAE2 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C4E80D62B3CCD090080FAE2 /* libffi.a */; }; - 5C4E80DC2B3CCD090080FAE2 /* libHSsimplex-chat-5.4.2.1-FP1oxJSttEYhorN1FRfI5.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C4E80D72B3CCD090080FAE2 /* libHSsimplex-chat-5.4.2.1-FP1oxJSttEYhorN1FRfI5.a */; }; - 5C4E80DD2B3CCD090080FAE2 /* libHSsimplex-chat-5.4.2.1-FP1oxJSttEYhorN1FRfI5-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C4E80D82B3CCD090080FAE2 /* libHSsimplex-chat-5.4.2.1-FP1oxJSttEYhorN1FRfI5-ghc9.6.3.a */; }; - 5C4E80DE2B3CCD090080FAE2 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C4E80D92B3CCD090080FAE2 /* libgmpxx.a */; }; + 5C4E80E42B40A96C0080FAE2 /* libHSsimplex-chat-5.5.0.0-FwZXD1cMpkc1VLQMq43OyQ.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C4E80DF2B40A96C0080FAE2 /* libHSsimplex-chat-5.5.0.0-FwZXD1cMpkc1VLQMq43OyQ.a */; }; + 5C4E80E52B40A96C0080FAE2 /* libHSsimplex-chat-5.5.0.0-FwZXD1cMpkc1VLQMq43OyQ-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C4E80E02B40A96C0080FAE2 /* libHSsimplex-chat-5.5.0.0-FwZXD1cMpkc1VLQMq43OyQ-ghc9.6.3.a */; }; + 5C4E80E62B40A96C0080FAE2 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C4E80E12B40A96C0080FAE2 /* libgmp.a */; }; + 5C4E80E72B40A96C0080FAE2 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C4E80E22B40A96C0080FAE2 /* libgmpxx.a */; }; + 5C4E80E82B40A96C0080FAE2 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C4E80E32B40A96C0080FAE2 /* libffi.a */; }; 5C5346A827B59A6A004DF848 /* ChatHelp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C5346A727B59A6A004DF848 /* ChatHelp.swift */; }; 5C55A91F283AD0E400C4E99E /* CallManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C55A91E283AD0E400C4E99E /* CallManager.swift */; }; 5C55A921283CCCB700C4E99E /* IncomingCallView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C55A920283CCCB700C4E99E /* IncomingCallView.swift */; }; @@ -173,11 +173,6 @@ 646BB38E283FDB6D001CE359 /* LocalAuthenticationUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 646BB38D283FDB6D001CE359 /* LocalAuthenticationUtils.swift */; }; 647F090E288EA27B00644C40 /* GroupMemberInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 647F090D288EA27B00644C40 /* GroupMemberInfoView.swift */; }; 648010AB281ADD15009009B9 /* CIFileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 648010AA281ADD15009009B9 /* CIFileView.swift */; }; - 64863B9B2B3C536500714A11 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64863B962B3C536500714A11 /* libgmpxx.a */; }; - 64863B9C2B3C536500714A11 /* libHSsimplex-chat-5.4.2.0-1dXNnkvLJVS8FSAgswHDGD-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64863B972B3C536500714A11 /* libHSsimplex-chat-5.4.2.0-1dXNnkvLJVS8FSAgswHDGD-ghc9.6.3.a */; }; - 64863B9D2B3C536500714A11 /* libHSsimplex-chat-5.4.2.0-1dXNnkvLJVS8FSAgswHDGD.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64863B982B3C536500714A11 /* libHSsimplex-chat-5.4.2.0-1dXNnkvLJVS8FSAgswHDGD.a */; }; - 64863B9E2B3C536500714A11 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64863B992B3C536500714A11 /* libgmp.a */; }; - 64863B9F2B3C536500714A11 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64863B9A2B3C536500714A11 /* libffi.a */; }; 649BCDA0280460FD00C3A862 /* ComposeImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649BCD9F280460FD00C3A862 /* ComposeImageView.swift */; }; 649BCDA22805D6EF00C3A862 /* CIImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649BCDA12805D6EF00C3A862 /* CIImageView.swift */; }; 64AA1C6927EE10C800AC7277 /* ContextItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64AA1C6827EE10C800AC7277 /* ContextItemView.swift */; }; @@ -294,11 +289,11 @@ 5C3F1D57284363C400EC8A82 /* PrivacySettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacySettings.swift; sourceTree = ""; }; 5C422A7C27A9A6FA0097A1E1 /* SimpleX (iOS).entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "SimpleX (iOS).entitlements"; sourceTree = ""; }; 5C4B3B09285FB130003915F2 /* DatabaseView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatabaseView.swift; sourceTree = ""; }; - 5C4E80D52B3CCD090080FAE2 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; }; - 5C4E80D62B3CCD090080FAE2 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; }; - 5C4E80D72B3CCD090080FAE2 /* libHSsimplex-chat-5.4.2.1-FP1oxJSttEYhorN1FRfI5.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.4.2.1-FP1oxJSttEYhorN1FRfI5.a"; sourceTree = ""; }; - 5C4E80D82B3CCD090080FAE2 /* libHSsimplex-chat-5.4.2.1-FP1oxJSttEYhorN1FRfI5-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.4.2.1-FP1oxJSttEYhorN1FRfI5-ghc9.6.3.a"; sourceTree = ""; }; - 5C4E80D92B3CCD090080FAE2 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = ""; }; + 5C4E80DF2B40A96C0080FAE2 /* libHSsimplex-chat-5.5.0.0-FwZXD1cMpkc1VLQMq43OyQ.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.5.0.0-FwZXD1cMpkc1VLQMq43OyQ.a"; sourceTree = ""; }; + 5C4E80E02B40A96C0080FAE2 /* libHSsimplex-chat-5.5.0.0-FwZXD1cMpkc1VLQMq43OyQ-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.5.0.0-FwZXD1cMpkc1VLQMq43OyQ-ghc9.6.3.a"; sourceTree = ""; }; + 5C4E80E12B40A96C0080FAE2 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; }; + 5C4E80E22B40A96C0080FAE2 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = ""; }; + 5C4E80E32B40A96C0080FAE2 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; }; 5C5346A727B59A6A004DF848 /* ChatHelp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatHelp.swift; sourceTree = ""; }; 5C55A91E283AD0E400C4E99E /* CallManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallManager.swift; sourceTree = ""; }; 5C55A920283CCCB700C4E99E /* IncomingCallView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IncomingCallView.swift; sourceTree = ""; }; @@ -461,11 +456,6 @@ 646BB38D283FDB6D001CE359 /* LocalAuthenticationUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalAuthenticationUtils.swift; sourceTree = ""; }; 647F090D288EA27B00644C40 /* GroupMemberInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupMemberInfoView.swift; sourceTree = ""; }; 648010AA281ADD15009009B9 /* CIFileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIFileView.swift; sourceTree = ""; }; - 64863B962B3C536500714A11 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = ""; }; - 64863B972B3C536500714A11 /* libHSsimplex-chat-5.4.2.0-1dXNnkvLJVS8FSAgswHDGD-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.4.2.0-1dXNnkvLJVS8FSAgswHDGD-ghc9.6.3.a"; sourceTree = ""; }; - 64863B982B3C536500714A11 /* libHSsimplex-chat-5.4.2.0-1dXNnkvLJVS8FSAgswHDGD.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.4.2.0-1dXNnkvLJVS8FSAgswHDGD.a"; sourceTree = ""; }; - 64863B992B3C536500714A11 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; }; - 64863B9A2B3C536500714A11 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; }; 6493D667280ED77F007A76FB /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; 649BCD9F280460FD00C3A862 /* ComposeImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeImageView.swift; sourceTree = ""; }; 649BCDA12805D6EF00C3A862 /* CIImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIImageView.swift; sourceTree = ""; }; @@ -521,13 +511,13 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 5C4E80DD2B3CCD090080FAE2 /* libHSsimplex-chat-5.4.2.1-FP1oxJSttEYhorN1FRfI5-ghc9.6.3.a in Frameworks */, + 5C4E80E72B40A96C0080FAE2 /* libgmpxx.a in Frameworks */, 5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */, - 5C4E80DA2B3CCD090080FAE2 /* libgmp.a in Frameworks */, - 5C4E80DC2B3CCD090080FAE2 /* libHSsimplex-chat-5.4.2.1-FP1oxJSttEYhorN1FRfI5.a in Frameworks */, + 5C4E80E62B40A96C0080FAE2 /* libgmp.a in Frameworks */, 5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */, - 5C4E80DB2B3CCD090080FAE2 /* libffi.a in Frameworks */, - 5C4E80DE2B3CCD090080FAE2 /* libgmpxx.a in Frameworks */, + 5C4E80E82B40A96C0080FAE2 /* libffi.a in Frameworks */, + 5C4E80E52B40A96C0080FAE2 /* libHSsimplex-chat-5.5.0.0-FwZXD1cMpkc1VLQMq43OyQ-ghc9.6.3.a in Frameworks */, + 5C4E80E42B40A96C0080FAE2 /* libHSsimplex-chat-5.5.0.0-FwZXD1cMpkc1VLQMq43OyQ.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -589,11 +579,11 @@ 5C764E5C279C70B7000C6508 /* Libraries */ = { isa = PBXGroup; children = ( - 5C4E80D62B3CCD090080FAE2 /* libffi.a */, - 5C4E80D52B3CCD090080FAE2 /* libgmp.a */, - 5C4E80D92B3CCD090080FAE2 /* libgmpxx.a */, - 5C4E80D82B3CCD090080FAE2 /* libHSsimplex-chat-5.4.2.1-FP1oxJSttEYhorN1FRfI5-ghc9.6.3.a */, - 5C4E80D72B3CCD090080FAE2 /* libHSsimplex-chat-5.4.2.1-FP1oxJSttEYhorN1FRfI5.a */, + 5C4E80E32B40A96C0080FAE2 /* libffi.a */, + 5C4E80E12B40A96C0080FAE2 /* libgmp.a */, + 5C4E80E22B40A96C0080FAE2 /* libgmpxx.a */, + 5C4E80E02B40A96C0080FAE2 /* libHSsimplex-chat-5.5.0.0-FwZXD1cMpkc1VLQMq43OyQ-ghc9.6.3.a */, + 5C4E80DF2B40A96C0080FAE2 /* libHSsimplex-chat-5.5.0.0-FwZXD1cMpkc1VLQMq43OyQ.a */, ); path = Libraries; sourceTree = ""; @@ -1512,7 +1502,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 186; + CURRENT_PROJECT_VERSION = 187; DEVELOPMENT_TEAM = 5NN7GUYB6T; ENABLE_BITCODE = NO; ENABLE_PREVIEWS = YES; @@ -1534,7 +1524,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 5.4.2; + MARKETING_VERSION = 5.5; PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app; PRODUCT_NAME = SimpleX; SDKROOT = iphoneos; @@ -1555,7 +1545,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 186; + CURRENT_PROJECT_VERSION = 187; DEVELOPMENT_TEAM = 5NN7GUYB6T; ENABLE_BITCODE = NO; ENABLE_PREVIEWS = YES; @@ -1577,7 +1567,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 5.4.2; + MARKETING_VERSION = 5.5; PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app; PRODUCT_NAME = SimpleX; SDKROOT = iphoneos; @@ -1636,7 +1626,7 @@ CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 186; + CURRENT_PROJECT_VERSION = 187; DEVELOPMENT_TEAM = 5NN7GUYB6T; ENABLE_BITCODE = NO; GENERATE_INFOPLIST_FILE = YES; @@ -1649,7 +1639,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 5.4.2; + MARKETING_VERSION = 5.5; PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-NSE"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1668,7 +1658,7 @@ CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 186; + CURRENT_PROJECT_VERSION = 187; DEVELOPMENT_TEAM = 5NN7GUYB6T; ENABLE_BITCODE = NO; GENERATE_INFOPLIST_FILE = YES; @@ -1681,7 +1671,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 5.4.2; + MARKETING_VERSION = 5.5; PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-NSE"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1700,7 +1690,7 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 186; + CURRENT_PROJECT_VERSION = 187; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5NN7GUYB6T; DYLIB_COMPATIBILITY_VERSION = 1; @@ -1724,7 +1714,7 @@ "$(inherited)", "$(PROJECT_DIR)/Libraries/sim", ); - MARKETING_VERSION = 5.4.2; + MARKETING_VERSION = 5.5; PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.SimpleXChat; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SDKROOT = iphoneos; @@ -1746,7 +1736,7 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 186; + CURRENT_PROJECT_VERSION = 187; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5NN7GUYB6T; DYLIB_COMPATIBILITY_VERSION = 1; @@ -1770,7 +1760,7 @@ "$(inherited)", "$(PROJECT_DIR)/Libraries/sim", ); - MARKETING_VERSION = 5.4.2; + MARKETING_VERSION = 5.5; PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.SimpleXChat; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SDKROOT = iphoneos; diff --git a/apps/multiplatform/gradle.properties b/apps/multiplatform/gradle.properties index 9a7b8ab811..d94fe6f915 100644 --- a/apps/multiplatform/gradle.properties +++ b/apps/multiplatform/gradle.properties @@ -25,11 +25,11 @@ android.nonTransitiveRClass=true android.enableJetifier=true kotlin.mpp.androidSourceSetLayoutVersion=2 -android.version_name=5.4.2 -android.version_code=166 +android.version_name=5.5-beta.0 +android.version_code=168 -desktop.version_name=5.4.2 -desktop.version_code=20 +desktop.version_name=5.5-beta.0 +desktop.version_code=21 kotlin.version=1.8.20 gradle.plugin.version=7.4.2 From c9b1d54f1308841ced44ae4e19c3baa5e60fac83 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Sat, 30 Dec 2023 22:04:01 +0000 Subject: [PATCH 018/102] docs: update downloads --- docs/DOWNLOADS.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/DOWNLOADS.md b/docs/DOWNLOADS.md index 5362e4f2c3..bd88f7a175 100644 --- a/docs/DOWNLOADS.md +++ b/docs/DOWNLOADS.md @@ -7,7 +7,7 @@ revision: 25.11.2023 | Updated 25.11.2023 | Languages: EN | # Download SimpleX apps -The latest stable version is v5.4.1. +The latest stable version is v5.4.2. You can get the latest beta releases from [GitHub](https://github.com/simplex-chat/simplex-chat/releases). @@ -21,24 +21,24 @@ You can get the latest beta releases from [GitHub](https://github.com/simplex-ch Using the same profile as on mobile device is not yet supported – you need to create a separate profile to use desktop apps. -**Linux**: [AppImage](https://github.com/simplex-chat/simplex-chat/releases/download/v5.4.1/simplex-desktop-x86_64.AppImage) (most Linux distros), [Ubuntu 20.04](https://github.com/simplex-chat/simplex-chat/releases/download/v5.4.1/simplex-desktop-ubuntu-20_04-x86_64.deb) (and Debian-based distros), [Ubuntu 22.04](https://github.com/simplex-chat/simplex-chat/releases/download/v5.4.1/simplex-desktop-ubuntu-22_04-x86_64.deb). +**Linux**: [AppImage](https://github.com/simplex-chat/simplex-chat/releases/download/v5.4.2/simplex-desktop-x86_64.AppImage) (most Linux distros), [Ubuntu 20.04](https://github.com/simplex-chat/simplex-chat/releases/download/v5.4.2/simplex-desktop-ubuntu-20_04-x86_64.deb) (and Debian-based distros), [Ubuntu 22.04](https://github.com/simplex-chat/simplex-chat/releases/download/v5.4.2/simplex-desktop-ubuntu-22_04-x86_64.deb). -**Mac**: [x86_64](https://github.com/simplex-chat/simplex-chat/releases/download/v5.4.1/simplex-desktop-macos-x86_64.dmg) (Intel), [aarch64](https://github.com/simplex-chat/simplex-chat/releases/download/v5.4.1/simplex-desktop-macos-aarch64.dmg) (Apple Silicon). +**Mac**: [x86_64](https://github.com/simplex-chat/simplex-chat/releases/download/v5.4.2/simplex-desktop-macos-x86_64.dmg) (Intel), [aarch64](https://github.com/simplex-chat/simplex-chat/releases/download/v5.4.2/simplex-desktop-macos-aarch64.dmg) (Apple Silicon). -**Windows**: [x86_64](https://github.com/simplex-chat/simplex-chat/releases/download/v5.4.1/simplex-desktop-windows-x86_64.msi). +**Windows**: [x86_64](https://github.com/simplex-chat/simplex-chat/releases/download/v5.4.2/simplex-desktop-windows-x86_64.msi). ## Mobile apps **iOS**: [App store](https://apps.apple.com/us/app/simplex-chat/id1605771084), [TestFlight](https://testflight.apple.com/join/DWuT2LQu). -**Android**: [Play store](https://play.google.com/store/apps/details?id=chat.simplex.app), [F-Droid](https://simplex.chat/fdroid/), [APK aarch64](https://github.com/simplex-chat/simplex-chat/releases/download/v5.4.1/simplex.apk), [APK armv7](https://github.com/simplex-chat/simplex-chat/releases/download/v5.4.1/simplex-armv7a.apk). +**Android**: [Play store](https://play.google.com/store/apps/details?id=chat.simplex.app), [F-Droid](https://simplex.chat/fdroid/), [APK aarch64](https://github.com/simplex-chat/simplex-chat/releases/download/v5.4.2/simplex.apk), [APK armv7](https://github.com/simplex-chat/simplex-chat/releases/download/v5.4.2/simplex-armv7a.apk). ## Terminal (console) app See [Using terminal app](/docs/CLI.md). -**Linux**: [Ubuntu 20.04](https://github.com/simplex-chat/simplex-chat/releases/download/v5.4.1/simplex-chat-ubuntu-20_04-x86-64), [Ubuntu 22.04](https://github.com/simplex-chat/simplex-chat/releases/download/v5.4.1/simplex-chat-ubuntu-22_04-x86-64). +**Linux**: [Ubuntu 20.04](https://github.com/simplex-chat/simplex-chat/releases/download/v5.4.2/simplex-chat-ubuntu-20_04-x86-64), [Ubuntu 22.04](https://github.com/simplex-chat/simplex-chat/releases/download/v5.4.2/simplex-chat-ubuntu-22_04-x86-64). -**Mac** [x86_64](https://github.com/simplex-chat/simplex-chat/releases/download/v5.4.1/simplex-chat-macos-x86-64), aarch64 - [compile from source](./CLI.md#). +**Mac** [x86_64](https://github.com/simplex-chat/simplex-chat/releases/download/v5.4.2/simplex-chat-macos-x86-64), aarch64 - [compile from source](./CLI.md#). -**Windows**: [x86_64](https://github.com/simplex-chat/simplex-chat/releases/download/v5.4.1/simplex-chat-windows-x86-64). +**Windows**: [x86_64](https://github.com/simplex-chat/simplex-chat/releases/download/v5.4.2/simplex-chat-windows-x86-64). From e6b57270030e84606b49b6fb1ca2b0f929f256a9 Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Tue, 2 Jan 2024 21:21:39 +0700 Subject: [PATCH 019/102] android, desktop: run with stopped chat (#3624) * android, desktop: run with stopped chat * way to prevent starting a chat in case of not saved database key * rename * change position of a call * new way of doing the same * better * exit process --------- Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> --- .../java/chat/simplex/app/SimplexService.kt | 9 +- .../simplex/common/platform/UI.android.kt | 14 +-- .../chat/simplex/common/model/SimpleXAPI.kt | 26 ++--- .../chat/simplex/common/platform/Core.kt | 100 ++++++++++++------ .../views/database/DatabaseErrorView.kt | 7 +- .../common/views/database/DatabaseView.kt | 7 +- .../common/views/helpers/DatabaseUtils.kt | 1 - .../common/views/localauth/LocalAuthView.kt | 2 +- .../commonMain/resources/MR/base/strings.xml | 2 + 9 files changed, 100 insertions(+), 68 deletions(-) diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/SimplexService.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/SimplexService.kt index 2cb6c12da0..d1e0d9721e 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/SimplexService.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/SimplexService.kt @@ -13,7 +13,6 @@ import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp -import chat.simplex.common.platform.Log import androidx.core.app.NotificationCompat import androidx.core.content.ContextCompat import androidx.work.* @@ -21,12 +20,13 @@ import chat.simplex.common.AppLock import chat.simplex.common.helpers.requiresIgnoringBattery import chat.simplex.common.model.ChatController import chat.simplex.common.model.NotificationsMode -import chat.simplex.common.platform.androidAppContext +import chat.simplex.common.platform.* import chat.simplex.common.views.helpers.* import kotlinx.coroutines.* import chat.simplex.res.MR import dev.icerock.moko.resources.compose.painterResource import dev.icerock.moko.resources.compose.stringResource +import kotlin.system.exitProcess // based on: // https://robertohuertas.com/2019/06/29/android_foreground_services/ @@ -173,6 +173,11 @@ class SimplexService: Service() { // Just to make sure that after restart of the app the user will need to re-authenticate AppLock.clearAuthState() + if (appPreferences.chatStopped.get()) { + stopSelf() + exitProcess(0) + } + // If notification service isn't enabled or battery optimization isn't disabled, we shouldn't restart the service if (!SimplexApp.context.allowToStartServiceAfterAppExit()) { return diff --git a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/UI.android.kt b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/UI.android.kt index 371c140133..d360c44b44 100644 --- a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/UI.android.kt +++ b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/UI.android.kt @@ -97,12 +97,14 @@ actual class GlobalExceptionsHandler: Thread.UncaughtExceptionHandler { mainActivity.get()?.recreate() } else { mainActivity.get()?.apply { - window - ?.decorView - ?.findViewById(android.R.id.content) - ?.removeViewAt(0) - setContent { - AppScreen() + runOnUiThread { + window + ?.decorView + ?.findViewById(android.R.id.content) + ?.removeViewAt(0) + setContent { + AppScreen() + } } } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt index 07e091b484..fc0d097728 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt @@ -106,6 +106,7 @@ class AppPreferences { val chatArchiveName = mkStrPreference(SHARED_PREFS_CHAT_ARCHIVE_NAME, null) val chatArchiveTime = mkDatePreference(SHARED_PREFS_CHAT_ARCHIVE_TIME, null) val chatLastStart = mkDatePreference(SHARED_PREFS_CHAT_LAST_START, null) + val chatStopped = mkBoolPreference(SHARED_PREFS_CHAT_STOPPED, false) val developerTools = mkBoolPreference(SHARED_PREFS_DEVELOPER_TOOLS, false) val terminalAlwaysVisible = mkBoolPreference(SHARED_PREFS_TERMINAL_ALWAYS_VISIBLE, false) val networkUseSocksProxy = mkBoolPreference(SHARED_PREFS_NETWORK_USE_SOCKS_PROXY, false) @@ -273,6 +274,7 @@ class AppPreferences { private const val SHARED_PREFS_APP_LANGUAGE = "AppLanguage" private const val SHARED_PREFS_ONBOARDING_STAGE = "OnboardingStage" private const val SHARED_PREFS_CHAT_LAST_START = "ChatLastStart" + private const val SHARED_PREFS_CHAT_STOPPED = "ChatStopped" private const val SHARED_PREFS_DEVELOPER_TOOLS = "DeveloperTools" private const val SHARED_PREFS_TERMINAL_ALWAYS_VISIBLE = "TerminalAlwaysVisible" private const val SHARED_PREFS_NETWORK_USE_SOCKS_PROXY = "NetworkUseSocksProxy" @@ -346,14 +348,8 @@ object ChatController { try { if (chatModel.chatRunning.value == true) return apiSetNetworkConfig(getNetCfg()) - apiSetTempFolder(coreTmpDir.absolutePath) - apiSetFilesFolder(appFilesDir.absolutePath) - if (appPlatform.isDesktop) { - apiSetRemoteHostsFolder(remoteHostsDir.absolutePath) - } - apiSetXFTPConfig(getXFTPCfg()) - apiSetEncryptLocalFiles(appPrefs.privacyEncryptLocalFiles.get()) val justStarted = apiStartChat() + appPrefs.chatStopped.set(false) val users = listUsers(null) chatModel.users.clear() chatModel.users.addAll(users) @@ -365,6 +361,9 @@ object ChatController { chatModel.chatRunning.value = true startReceiver() setLocalDeviceName(appPrefs.deviceNameForRemoteAccess.get()!!) + if (appPreferences.onboardingStage.get() == OnboardingStage.OnboardingComplete && !chatModel.controller.appPrefs.privacyDeliveryReceiptsSet.get()) { + chatModel.setDeliveryReceipts.value = true + } Log.d(TAG, "startChat: started") } else { updatingChatsMutex.withLock { @@ -383,13 +382,6 @@ object ChatController { Log.d(TAG, "user: null") try { if (chatModel.chatRunning.value == true) return - apiSetTempFolder(coreTmpDir.absolutePath) - apiSetFilesFolder(appFilesDir.absolutePath) - if (appPlatform.isDesktop) { - apiSetRemoteHostsFolder(remoteHostsDir.absolutePath) - } - apiSetXFTPConfig(getXFTPCfg()) - apiSetEncryptLocalFiles(appPrefs.privacyEncryptLocalFiles.get()) chatModel.users.clear() chatModel.currentUser.value = null chatModel.localUserCreated.value = false @@ -596,19 +588,19 @@ object ChatController { } } - private suspend fun apiSetTempFolder(tempFolder: String) { + suspend fun apiSetTempFolder(tempFolder: String) { val r = sendCmd(null, CC.SetTempFolder(tempFolder)) if (r is CR.CmdOk) return throw Error("failed to set temp folder: ${r.responseType} ${r.details}") } - private suspend fun apiSetFilesFolder(filesFolder: String) { + suspend fun apiSetFilesFolder(filesFolder: String) { val r = sendCmd(null, CC.SetFilesFolder(filesFolder)) if (r is CR.CmdOk) return throw Error("failed to set files folder: ${r.responseType} ${r.details}") } - private suspend fun apiSetRemoteHostsFolder(remoteHostsFolder: String) { + suspend fun apiSetRemoteHostsFolder(remoteHostsFolder: String) { val r = sendCmd(null, CC.SetRemoteHostsFolder(remoteHostsFolder)) if (r is CR.CmdOk) return throw Error("failed to set remote hosts folder: ${r.responseType} ${r.details}") diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Core.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Core.kt index 07e59a55e0..00a8244380 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Core.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Core.kt @@ -1,8 +1,13 @@ package chat.simplex.common.platform import chat.simplex.common.model.* +import chat.simplex.common.model.ChatModel.controller +import chat.simplex.common.model.ChatModel.currentUser import chat.simplex.common.views.helpers.* +import chat.simplex.common.views.helpers.DatabaseUtils.ksDatabasePassword import chat.simplex.common.views.onboarding.OnboardingStage +import chat.simplex.res.MR +import kotlinx.coroutines.* import kotlinx.serialization.decodeFromString import java.nio.ByteBuffer @@ -39,13 +44,17 @@ val chatController: ChatController = ChatController fun initChatControllerAndRunMigrations(ignoreSelfDestruct: Boolean) { if (ignoreSelfDestruct || DatabaseUtils.ksSelfDestructPassword.get() == null) { withBGApi { - initChatController() + if (appPreferences.chatStopped.get() && appPreferences.storeDBPassphrase.get() && ksDatabasePassword.get() != null) { + initChatController(startChat = ::showStartChatAfterRestartAlert) + } else { + initChatController() + } runMigrations() } } } -suspend fun initChatController(useKey: String? = null, confirmMigrations: MigrationConfirmation? = null, startChat: Boolean = true) { +suspend fun initChatController(useKey: String? = null, confirmMigrations: MigrationConfirmation? = null, startChat: () -> CompletableDeferred = { CompletableDeferred(true) }) { try { chatModel.ctrlInitInProgress.value = true val dbKey = useKey ?: DatabaseUtils.useDatabaseKey() @@ -62,45 +71,66 @@ suspend fun initChatController(useKey: String? = null, confirmMigrations: Migrat chatModel.chatDbStatus.value = res if (res != DBMigrationResult.OK) { Log.d(TAG, "Unable to migrate successfully: $res") - } else if (startChat) { - // If we migrated successfully means previous re-encryption process on database level finished successfully too - if (appPreferences.encryptionStartedAt.get() != null) appPreferences.encryptionStartedAt.set(null) - val user = chatController.apiGetActiveUser(null) - if (user == null) { - chatModel.controller.appPrefs.privacyDeliveryReceiptsSet.set(true) - chatModel.currentUser.value = null - chatModel.users.clear() - if (appPlatform.isDesktop) { - /** - * Setting it here to null because otherwise the screen will flash in [MainScreen] after the first start - * because of default value of [OnboardingStage.OnboardingComplete] - * */ - chatModel.localUserCreated.value = null - if (chatController.listRemoteHosts()?.isEmpty() == true) { - chatController.appPrefs.onboardingStage.set(OnboardingStage.Step1_SimpleXInfo) - } - chatController.startChatWithoutUser() - } else { + return + } + controller.apiSetTempFolder(coreTmpDir.absolutePath) + controller.apiSetFilesFolder(appFilesDir.absolutePath) + if (appPlatform.isDesktop) { + controller.apiSetRemoteHostsFolder(remoteHostsDir.absolutePath) + } + controller.apiSetXFTPConfig(controller.getXFTPCfg()) + controller.apiSetEncryptLocalFiles(controller.appPrefs.privacyEncryptLocalFiles.get()) + // If we migrated successfully means previous re-encryption process on database level finished successfully too + if (appPreferences.encryptionStartedAt.get() != null) appPreferences.encryptionStartedAt.set(null) + val user = chatController.apiGetActiveUser(null) + chatModel.currentUser.value = user + if (user == null) { + chatModel.controller.appPrefs.privacyDeliveryReceiptsSet.set(true) + chatModel.currentUser.value = null + chatModel.users.clear() + if (appPlatform.isDesktop) { + /** + * Setting it here to null because otherwise the screen will flash in [MainScreen] after the first start + * because of default value of [OnboardingStage.OnboardingComplete] + * */ + chatModel.localUserCreated.value = null + if (chatController.listRemoteHosts()?.isEmpty() == true) { chatController.appPrefs.onboardingStage.set(OnboardingStage.Step1_SimpleXInfo) } + chatController.startChatWithoutUser() } else { - val savedOnboardingStage = appPreferences.onboardingStage.get() - val newStage = if (listOf(OnboardingStage.Step1_SimpleXInfo, OnboardingStage.Step2_CreateProfile).contains(savedOnboardingStage) && chatModel.users.size == 1) { - OnboardingStage.Step3_CreateSimpleXAddress - } else { - savedOnboardingStage - } - if (appPreferences.onboardingStage.get() != newStage) { - appPreferences.onboardingStage.set(newStage) - } - if (appPreferences.onboardingStage.get() == OnboardingStage.OnboardingComplete && !chatModel.controller.appPrefs.privacyDeliveryReceiptsSet.get()) { - chatModel.setDeliveryReceipts.value = true - } - chatController.startChat(user) - platform.androidChatInitializedAndStarted() + chatController.appPrefs.onboardingStage.set(OnboardingStage.Step1_SimpleXInfo) } + } else if (startChat().await()) { + val savedOnboardingStage = appPreferences.onboardingStage.get() + val newStage = if (listOf(OnboardingStage.Step1_SimpleXInfo, OnboardingStage.Step2_CreateProfile).contains(savedOnboardingStage) && chatModel.users.size == 1) { + OnboardingStage.Step3_CreateSimpleXAddress + } else { + savedOnboardingStage + } + if (appPreferences.onboardingStage.get() != newStage) { + appPreferences.onboardingStage.set(newStage) + } + chatController.startChat(user) + platform.androidChatInitializedAndStarted() + } else { + chatController.getUserChatData(null) + chatModel.localUserCreated.value = currentUser.value != null + chatModel.chatRunning.value = false } } finally { chatModel.ctrlInitInProgress.value = false } } + +fun showStartChatAfterRestartAlert(): CompletableDeferred { + val deferred = CompletableDeferred() + AlertManager.shared.showAlertDialog( + title = generalGetString(MR.strings.start_chat_question), + text = generalGetString(MR.strings.chat_is_stopped_you_should_transfer_database), + onConfirm = { deferred.complete(true) }, + onDismiss = { deferred.complete(false) }, + onDismissRequest = { deferred.complete(false) } + ) + return deferred +} diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseErrorView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseErrorView.kt index 22d69de1cc..0c208c06e8 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseErrorView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseErrorView.kt @@ -44,7 +44,7 @@ fun DatabaseErrorView( fun callRunChat(confirmMigrations: MigrationConfirmation? = null) { val useKey = if (useKeychain) null else dbKey.value - runChat(useKey, confirmMigrations, chatDbStatus, progressIndicator, appPreferences) + runChat(useKey, confirmMigrations, chatDbStatus, progressIndicator) } fun saveAndRunChatOnClick() { @@ -190,13 +190,14 @@ private fun runChat( confirmMigrations: MigrationConfirmation? = null, chatDbStatus: State, progressIndicator: MutableState, - prefs: AppPreferences ) = CoroutineScope(Dispatchers.Default).launch { // Don't do things concurrently. Shouldn't be here concurrently, just in case if (progressIndicator.value) return@launch progressIndicator.value = true try { - initChatController(dbKey, confirmMigrations) + initChatController(dbKey, confirmMigrations, + startChat = if (appPreferences.chatStopped.get()) ::showStartChatAfterRestartAlert else { { CompletableDeferred(true) } } + ) } catch (e: Exception) { Log.d(TAG, "initializeChat ${e.stackTraceToString()}") } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseView.kt index 5e1abb6846..3769e0fc95 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseView.kt @@ -378,12 +378,12 @@ private fun startChat(m: ChatModel, chatLastStart: MutableState, chatD ModalManager.closeAllModalsEverywhere() return@withApi } - if (m.currentUser.value == null) { + val user = m.currentUser.value + if (user == null) { ModalManager.closeAllModalsEverywhere() return@withApi } else { - m.controller.apiStartChat() - m.chatRunning.value = true + m.controller.startChat(user) } val ts = Clock.System.now() m.controller.appPrefs.chatLastStart.set(ts) @@ -453,6 +453,7 @@ private fun stopChat(m: ChatModel) { suspend fun stopChatAsync(m: ChatModel) { m.controller.apiStopChat() m.chatRunning.value = false + controller.appPrefs.chatStopped.set(true) } suspend fun deleteChatAsync(m: ChatModel) { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DatabaseUtils.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DatabaseUtils.kt index c984e16452..cc06716dab 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DatabaseUtils.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DatabaseUtils.kt @@ -82,7 +82,6 @@ sealed class DBMigrationResult { @Serializable @SerialName("unknown") data class Unknown(val json: String): DBMigrationResult() } - enum class MigrationConfirmation(val value: String) { YesUp("yesUp"), YesUpDown ("yesUpDown"), diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/localauth/LocalAuthView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/localauth/LocalAuthView.kt index 0401906527..b758ecdcff 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/localauth/LocalAuthView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/localauth/LocalAuthView.kt @@ -84,7 +84,7 @@ private fun deleteStorageAndRestart(m: ChatModel, password: String, completed: ( m.chatDbChanged.value = true m.chatDbStatus.value = null try { - initChatController(startChat = true) + initChatController() } catch (e: Exception) { Log.d(TAG, "initializeChat ${e.stackTraceToString()}") } diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml index bd61d94739..1cf1922c5e 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml @@ -1112,6 +1112,8 @@ Chat is stopped You can start chat via app Settings / Database or by restarting the app. + Start chat? + Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat. Chat archive From f758a5526a1e650134629b4f66d7edfdb42ce4ee Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Tue, 2 Jan 2024 21:28:36 +0700 Subject: [PATCH 020/102] android, desktop: specifying text color globally (#3635) * android, desktop: specifying text color globally * typography --- .../chat/simplex/common/ui/theme/Theme.kt | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt index 6af3156ca2..21bee2b2b3 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt @@ -6,6 +6,7 @@ import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.* +import androidx.compose.ui.text.TextStyle import androidx.compose.ui.unit.dp import chat.simplex.common.model.ChatController import chat.simplex.common.platform.isInNightMode @@ -282,8 +283,27 @@ fun SimpleXTheme(darkTheme: Boolean? = null, content: @Composable () -> Unit) { val theme by CurrentColors.collectAsState() MaterialTheme( colors = theme.colors, - typography = Typography, + typography = Typography.copy( + h1 = Typography.h1.copy(color = theme.colors.onBackground), + h2 = Typography.h2.copy(color = theme.colors.onBackground), + h3 = Typography.h3.copy(color = theme.colors.onBackground), + h4 = Typography.h4.copy(color = theme.colors.onBackground), + h5 = Typography.h5.copy(color = theme.colors.onBackground), + h6 = Typography.h6.copy(color = theme.colors.onBackground), + subtitle1 = Typography.subtitle1.copy(color = theme.colors.onBackground), + subtitle2 = Typography.subtitle2.copy(color = theme.colors.onBackground), + body1 = Typography.body1.copy(color = theme.colors.onBackground), + body2 = Typography.body2.copy(color = theme.colors.onBackground), + button = Typography.button.copy(color = theme.colors.onBackground), + caption = Typography.caption.copy(color = theme.colors.onBackground), + overline = Typography.overline.copy(color = theme.colors.onBackground) + ), shapes = Shapes, - content = content + content = { + ProvideTextStyle( + value = TextStyle(color = theme.colors.onBackground), + content = content + ) + } ) } From d00977790129403199510a22c27c0bea1f966531 Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Tue, 2 Jan 2024 21:38:28 +0700 Subject: [PATCH 021/102] android, desktop: close gallery when media was deleted (#3636) --- .../kotlin/chat/simplex/common/views/chat/ChatView.kt | 4 +++- .../simplex/common/views/chat/item/ImageFullScreenView.kt | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) 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 69a1b50e28..d6e75feeb5 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 @@ -1353,6 +1353,8 @@ private fun providerForGallery( fun item(skipInternalIndex: Int, initialChatId: Long): Pair? { var processedInternalIndex = -skipInternalIndex.sign val indexOfFirst = chatItems.indexOfFirst { it.id == initialChatId } + // The first was deleted or moderated + if (indexOfFirst == -1) return null for (chatItemsIndex in if (skipInternalIndex >= 0) indexOfFirst downTo 0 else indexOfFirst..chatItems.lastIndex) { val item = chatItems[chatItemsIndex] if (canShowMedia(item)) { @@ -1402,7 +1404,7 @@ private fun providerForGallery( override fun scrollToStart() { initialIndex = 0 - initialChatId = chatItems.first { canShowMedia(it) }.id + initialChatId = chatItems.firstOrNull { canShowMedia(it) }?.id ?: return } override fun onDismiss(index: Int) { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/ImageFullScreenView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/ImageFullScreenView.kt index c7268592bf..825211ac85 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/ImageFullScreenView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/ImageFullScreenView.kt @@ -86,6 +86,8 @@ fun ImageFullScreenView(imageProvider: () -> ImageGalleryProvider, close: () -> provider.scrollToStart() pagerState.scrollToPage(0) } + // Current media was deleted or moderated, close gallery + index -> close() } } } From 767522e70184fae1c388edc125ae27a2388770c7 Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Wed, 3 Jan 2024 03:20:05 +0700 Subject: [PATCH 022/102] ios: better way of starting chat after stop (#3637) Co-authored-by: Avently --- apps/ios/Shared/Model/SimpleXAPI.swift | 34 +++++++++++++++++-- apps/ios/Shared/Model/SuspendChat.swift | 18 +++------- .../Views/Database/DatabaseErrorView.swift | 2 +- 3 files changed, 37 insertions(+), 17 deletions(-) diff --git a/apps/ios/Shared/Model/SimpleXAPI.swift b/apps/ios/Shared/Model/SimpleXAPI.swift index ddac78c3da..2dbb43eecc 100644 --- a/apps/ios/Shared/Model/SimpleXAPI.swift +++ b/apps/ios/Shared/Model/SimpleXAPI.swift @@ -1212,7 +1212,7 @@ private func currentUserId(_ funcName: String) throws -> Int64 { throw RuntimeError("\(funcName): no current user") } -func initializeChat(start: Bool, dbKey: String? = nil, refreshInvitations: Bool = true, confirmMigrations: MigrationConfirmation? = nil) throws { +func initializeChat(start: Bool, confirmStart: Bool = false, dbKey: String? = nil, refreshInvitations: Bool = true, confirmMigrations: MigrationConfirmation? = nil) throws { logger.debug("initializeChat") let m = ChatModel.shared (m.chatDbEncrypted, m.chatDbStatus) = chatMigrateInit(dbKey, confirmMigrations: confirmMigrations) @@ -1231,7 +1231,37 @@ func initializeChat(start: Bool, dbKey: String? = nil, refreshInvitations: Bool onboardingStageDefault.set(.step1_SimpleXInfo) privacyDeliveryReceiptsSet.set(true) m.onboardingStage = .step1_SimpleXInfo - } else if start { + } else if confirmStart { + showStartChatAfterRestartAlert { start in + do { + if start { AppChatState.shared.set(.active) } + try chatInitialized(start: start, refreshInvitations: refreshInvitations) + } catch let error { + logger.error("ChatInitialized error: \(error)") + } + } + } else { + try chatInitialized(start: start, refreshInvitations: refreshInvitations) + } +} + +func showStartChatAfterRestartAlert(result: @escaping (_ start: Bool) -> Void) { + AlertManager.shared.showAlert(Alert( + title: Text("Start chat?"), + message: Text("Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat."), + primaryButton: .default(Text("Ok")) { + result(true) + }, + secondaryButton: .cancel { + result(false) + } + )) +} + +private func chatInitialized(start: Bool, refreshInvitations: Bool) throws { + let m = ChatModel.shared + if m.currentUser == nil { return } + if start { try startChat(refreshInvitations: refreshInvitations) } else { m.chatRunning = false diff --git a/apps/ios/Shared/Model/SuspendChat.swift b/apps/ios/Shared/Model/SuspendChat.swift index 9b03f38f3c..965e567aa5 100644 --- a/apps/ios/Shared/Model/SuspendChat.swift +++ b/apps/ios/Shared/Model/SuspendChat.swift @@ -105,26 +105,16 @@ func initChatAndMigrate(refreshInvitations: Bool = true) { let m = ChatModel.shared if (!m.chatInitialized) { m.v3DBMigration = v3DBMigrationDefault.get() - if AppChatState.shared.value == .stopped { - AlertManager.shared.showAlert(Alert( - title: Text("Start chat?"), - message: Text("Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat."), - primaryButton: .default(Text("Ok")) { - AppChatState.shared.set(.active) - initialize(start: true) - }, - secondaryButton: .cancel { - initialize(start: false) - } - )) + if AppChatState.shared.value == .stopped && storeDBPassphraseGroupDefault.get() && kcDatabasePassword.get() != nil { + initialize(start: true, confirmStart: true) } else { initialize(start: true) } } - func initialize(start: Bool) { + func initialize(start: Bool, confirmStart: Bool = false) { do { - try initializeChat(start: m.v3DBMigration.startChat && start, refreshInvitations: refreshInvitations) + try initializeChat(start: m.v3DBMigration.startChat && start, confirmStart: m.v3DBMigration.startChat && confirmStart, refreshInvitations: refreshInvitations) } catch let error { AlertManager.shared.showAlertMsg( title: start ? "Error starting chat" : "Error opening chat", diff --git a/apps/ios/Shared/Views/Database/DatabaseErrorView.swift b/apps/ios/Shared/Views/Database/DatabaseErrorView.swift index 04e377f3a5..52ded44782 100644 --- a/apps/ios/Shared/Views/Database/DatabaseErrorView.swift +++ b/apps/ios/Shared/Views/Database/DatabaseErrorView.swift @@ -149,7 +149,7 @@ struct DatabaseErrorView: View { private func runChatSync(confirmMigrations: MigrationConfirmation? = nil) { do { resetChatCtrl() - try initializeChat(start: m.v3DBMigration.startChat, dbKey: useKeychain ? nil : dbKey, confirmMigrations: confirmMigrations) + try initializeChat(start: m.v3DBMigration.startChat, confirmStart: m.v3DBMigration.startChat && AppChatState.shared.value == .stopped, dbKey: useKeychain ? nil : dbKey, confirmMigrations: confirmMigrations) if let s = m.chatDbStatus { status = s let am = AlertManager.shared From 8882284fb7e295f6d75a4abd6099fb1d757d6704 Mon Sep 17 00:00:00 2001 From: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com> Date: Thu, 4 Jan 2024 16:22:16 +0400 Subject: [PATCH 023/102] core: always check integrity on MSG in direct chats (#3641) --- src/Simplex/Chat.hs | 75 ++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 41 deletions(-) diff --git a/src/Simplex/Chat.hs b/src/Simplex/Chat.hs index d61fc5f5a5..cfd8f224fb 100644 --- a/src/Simplex/Chat.hs +++ b/src/Simplex/Chat.hs @@ -3356,6 +3356,7 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage = sendXGrpMemInv hostConnId (Just directConnReq) xGrpMemIntroCont CRContactUri _ -> throwChatError $ CECommandError "unexpected ConnectionRequestUri type" MSG msgMeta _msgFlags msgBody -> do + checkIntegrityCreateItem (CDDirectRcv ct) msgMeta cmdId <- createAckCmd conn withAckMessage agentConnId cmdId msgMeta $ do (conn', msg@RcvMessage {chatMsgEvent = ACME _ event}) <- saveDirectRcvMSG conn msgMeta cmdId msgBody @@ -3364,14 +3365,14 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage = updateChatLock "directMessage" event case event of XMsgNew mc -> newContentMessage ct' mc msg msgMeta - XMsgFileDescr sharedMsgId fileDescr -> messageFileDescription ct' sharedMsgId fileDescr msgMeta + XMsgFileDescr sharedMsgId fileDescr -> messageFileDescription ct' sharedMsgId fileDescr XMsgUpdate sharedMsgId mContent ttl live -> messageUpdate ct' sharedMsgId mContent msg msgMeta ttl live XMsgDel sharedMsgId _ -> messageDelete ct' sharedMsgId msg msgMeta XMsgReact sharedMsgId _ reaction add -> directMsgReaction ct' sharedMsgId reaction add msg msgMeta -- TODO discontinue XFile XFile fInv -> processFileInvitation' ct' fInv msg msgMeta - XFileCancel sharedMsgId -> xFileCancel ct' sharedMsgId msgMeta - XFileAcptInv sharedMsgId fileConnReq_ fName -> xFileAcptInv ct' sharedMsgId fileConnReq_ fName msgMeta + XFileCancel sharedMsgId -> xFileCancel ct' sharedMsgId + XFileAcptInv sharedMsgId fileConnReq_ fName -> xFileAcptInv ct' sharedMsgId fileConnReq_ fName XInfo p -> xInfo ct' p XDirectDel -> xDirectDel ct' msg msgMeta XGrpInv gInv -> processGroupInvitation ct' gInv msg msgMeta @@ -3379,10 +3380,10 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage = XInfoProbeCheck probeHash -> xInfoProbeCheck (COMContact ct') probeHash XInfoProbeOk probe -> xInfoProbeOk (COMContact ct') probe XCallInv callId invitation -> xCallInv ct' callId invitation msg msgMeta - XCallOffer callId offer -> xCallOffer ct' callId offer msg msgMeta - XCallAnswer callId answer -> xCallAnswer ct' callId answer msg msgMeta - XCallExtra callId extraInfo -> xCallExtra ct' callId extraInfo msg msgMeta - XCallEnd callId -> xCallEnd ct' callId msg msgMeta + XCallOffer callId offer -> xCallOffer ct' callId offer msg + XCallAnswer callId answer -> xCallAnswer ct' callId answer msg + XCallExtra callId extraInfo -> xCallExtra ct' callId extraInfo msg + XCallEnd callId -> xCallEnd ct' callId msg BFileChunk sharedMsgId chunk -> bFileChunk ct' sharedMsgId chunk msgMeta _ -> messageError $ "unsupported message: " <> T.pack (show event) let Contact {chatSettings = ChatSettings {sendRcpts}} = ct' @@ -3740,7 +3741,7 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage = void $ sendDirectMessage imConn (XGrpMemCon memberId) (GroupId groupId) _ -> messageWarning "sendXGrpMemCon: member category GCPreMember or GCPostMember is expected" MSG msgMeta _msgFlags msgBody -> do - checkIntegrityCreateItem (CDGroupRcv gInfo m) msgMeta `catchChatError` \_ -> pure () + checkIntegrityCreateItem (CDGroupRcv gInfo m) msgMeta cmdId <- createAckCmd conn let aChatMsgs = parseChatMessages msgBody withAckMessage agentConnId cmdId msgMeta $ do @@ -4231,7 +4232,6 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage = newContentMessage :: Contact -> MsgContainer -> RcvMessage -> MsgMeta -> m () newContentMessage ct@Contact {contactUsed} mc msg@RcvMessage {sharedMsgId_} msgMeta = do unless contactUsed $ withStore' $ \db -> updateContactUsed db user ct - checkIntegrityCreateItem (CDDirectRcv ct) msgMeta let ExtMsgContent content fInv_ _ _ = mcExtMsgContent mc -- Uncomment to test stuck delivery on errors - see test testDirectMessageDelete -- case content of @@ -4261,9 +4261,8 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage = ChatConfig {autoAcceptFileSize = sz} <- asks config when (sz > fileSize) $ receiveFile' user ft Nothing Nothing >>= toView - messageFileDescription :: Contact -> SharedMsgId -> FileDescr -> MsgMeta -> m () - messageFileDescription ct@Contact {contactId} sharedMsgId fileDescr msgMeta = do - checkIntegrityCreateItem (CDDirectRcv ct) msgMeta + messageFileDescription :: Contact -> SharedMsgId -> FileDescr -> m () + messageFileDescription Contact {contactId} sharedMsgId fileDescr = do fileId <- withStore $ \db -> getFileIdBySharedMsgId db userId contactId sharedMsgId processFDMessage fileId fileDescr @@ -4306,7 +4305,6 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage = messageUpdate :: Contact -> SharedMsgId -> MsgContent -> RcvMessage -> MsgMeta -> Maybe Int -> Maybe Bool -> m () messageUpdate ct@Contact {contactId} sharedMsgId mc msg@RcvMessage {msgId} msgMeta ttl live_ = do - checkIntegrityCreateItem (CDDirectRcv ct) msgMeta updateRcvChatItem `catchCINotFound` \_ -> do -- This patches initial sharedMsgId into chat item when locally deleted chat item -- received an update from the sender, so that it can be referenced later (e.g. by broadcast delete). @@ -4339,10 +4337,10 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage = _ -> messageError "x.msg.update: contact attempted invalid message update" messageDelete :: Contact -> SharedMsgId -> RcvMessage -> MsgMeta -> m () - messageDelete ct@Contact {contactId} sharedMsgId RcvMessage {msgId} msgMeta@MsgMeta {broker = (_, brokerTs)} = do - checkIntegrityCreateItem (CDDirectRcv ct) msgMeta + messageDelete ct@Contact {contactId} sharedMsgId RcvMessage {msgId} msgMeta = do deleteRcvChatItem `catchCINotFound` (toView . CRChatItemDeletedNotFound user ct) where + brokerTs = metaBrokerTs msgMeta deleteRcvChatItem = do CChatItem msgDir ci <- withStore $ \db -> getDirectChatItemBySharedMsgId db user contactId sharedMsgId case msgDir of @@ -4510,7 +4508,6 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage = -- TODO remove once XFile is discontinued processFileInvitation' :: Contact -> FileInvitation -> RcvMessage -> MsgMeta -> m () processFileInvitation' ct fInv@FileInvitation {fileName, fileSize} msg@RcvMessage {sharedMsgId_} msgMeta = do - checkIntegrityCreateItem (CDDirectRcv ct) msgMeta ChatConfig {fileChunkSize} <- asks config inline <- receiveInlineMode fInv Nothing fileChunkSize RcvFileTransfer {fileId, xftpRcvFile} <- withStore $ \db -> createRcvFileTransfer db userId ct fInv inline fileChunkSize @@ -4547,9 +4544,8 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage = inline' receiveInstant = if mode == IFMOffer || (receiveInstant && maybe False isVoice mc_) then fileInline else Nothing _ -> pure Nothing - xFileCancel :: Contact -> SharedMsgId -> MsgMeta -> m () - xFileCancel ct@Contact {contactId} sharedMsgId msgMeta = do - checkIntegrityCreateItem (CDDirectRcv ct) msgMeta + xFileCancel :: Contact -> SharedMsgId -> m () + xFileCancel Contact {contactId} sharedMsgId = do fileId <- withStore $ \db -> getFileIdBySharedMsgId db userId contactId sharedMsgId ft <- withStore (\db -> getRcvFileTransfer db user fileId) unless (rcvFileCompleteOrCancelled ft) $ do @@ -4557,9 +4553,8 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage = ci <- withStore $ \db -> getChatItemByFileId db vr user fileId toView $ CRRcvFileSndCancelled user ci ft - xFileAcptInv :: Contact -> SharedMsgId -> Maybe ConnReqInvitation -> String -> MsgMeta -> m () - xFileAcptInv ct sharedMsgId fileConnReq_ fName msgMeta = do - checkIntegrityCreateItem (CDDirectRcv ct) msgMeta + xFileAcptInv :: Contact -> SharedMsgId -> Maybe ConnReqInvitation -> String -> m () + xFileAcptInv ct sharedMsgId fileConnReq_ fName = do fileId <- withStore $ \db -> getDirectFileIdBySharedMsgId db user ct sharedMsgId (AChatItem _ _ _ ci) <- withStore $ \db -> getChatItemByFileId db vr user fileId assertSMPAcceptNotProhibited ci @@ -4693,7 +4688,6 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage = let Contact {localDisplayName = c, activeConn} = ct GroupInvitation {fromMember = (MemberIdRole fromMemId fromRole), invitedMember = (MemberIdRole memId memRole), connRequest, groupLinkId} = inv forM_ activeConn $ \Connection {connId, peerChatVRange, customUserProfileId, groupLinkId = groupLinkId'} -> do - checkIntegrityCreateItem (CDDirectRcv ct) msgMeta when (fromRole < GRAdmin || fromRole < memRole) $ throwChatError (CEGroupContactRole c) when (fromMemId == memId) $ throwChatError CEGroupDuplicateMemberId -- [incognito] if direct connection with host is incognito, create membership using the same incognito profile @@ -4725,7 +4719,9 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage = checkIntegrityCreateItem :: forall c. ChatTypeI c => ChatDirection c 'MDRcv -> MsgMeta -> m () checkIntegrityCreateItem cd MsgMeta {integrity, broker = (_, brokerTs)} = case integrity of MsgOk -> pure () - MsgError e -> createInternalChatItem user cd (CIRcvIntegrityError e) (Just brokerTs) + MsgError e -> + createInternalChatItem user cd (CIRcvIntegrityError e) (Just brokerTs) + `catchChatError` \_ -> pure () xInfo :: Contact -> Profile -> m () xInfo c p' = void $ processContactProfileUpdate c p' True @@ -4734,7 +4730,6 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage = xDirectDel c msg msgMeta = if directOrUsed c then do - checkIntegrityCreateItem (CDDirectRcv c) msgMeta ct' <- withStore' $ \db -> updateContactStatus db user c CSDeleted contactConns <- withStore' $ \db -> getContactConnections db userId ct' deleteAgentConnectionsAsync user $ map aConnId contactConns @@ -4894,7 +4889,6 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage = -- to party accepting call xCallInv :: Contact -> CallId -> CallInvitation -> RcvMessage -> MsgMeta -> m () xCallInv ct@Contact {contactId} callId CallInvitation {callType, callDhPubKey} msg@RcvMessage {sharedMsgId_} msgMeta = do - checkIntegrityCreateItem (CDDirectRcv ct) msgMeta if featureAllowed SCFCalls forContact ct then do g <- asks random @@ -4921,9 +4915,9 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage = toView $ CRNewChatItem user (AChatItem SCTDirect SMDRcv (DirectChat ct) ci) -- to party initiating call - xCallOffer :: Contact -> CallId -> CallOffer -> RcvMessage -> MsgMeta -> m () - xCallOffer ct callId CallOffer {callType, rtcSession, callDhPubKey} msg msgMeta = do - msgCurrentCall ct callId "x.call.offer" msg msgMeta $ + xCallOffer :: Contact -> CallId -> CallOffer -> RcvMessage -> m () + xCallOffer ct callId CallOffer {callType, rtcSession, callDhPubKey} msg = do + msgCurrentCall ct callId "x.call.offer" msg $ \call -> case callState call of CallInvitationSent {localCallType, localDhPrivKey} -> do let sharedKey = C.Key . C.dhBytes' <$> (C.dh' <$> callDhPubKey <*> localDhPrivKey) @@ -4936,9 +4930,9 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage = pure (Just call, Nothing) -- to party accepting call - xCallAnswer :: Contact -> CallId -> CallAnswer -> RcvMessage -> MsgMeta -> m () - xCallAnswer ct callId CallAnswer {rtcSession} msg msgMeta = do - msgCurrentCall ct callId "x.call.answer" msg msgMeta $ + xCallAnswer :: Contact -> CallId -> CallAnswer -> RcvMessage -> m () + xCallAnswer ct callId CallAnswer {rtcSession} msg = do + msgCurrentCall ct callId "x.call.answer" msg $ \call -> case callState call of CallOfferSent {localCallType, peerCallType, localCallSession, sharedKey} -> do let callState' = CallNegotiated {localCallType, peerCallType, localCallSession, peerCallSession = rtcSession, sharedKey} @@ -4949,9 +4943,9 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage = pure (Just call, Nothing) -- to any call party - xCallExtra :: Contact -> CallId -> CallExtraInfo -> RcvMessage -> MsgMeta -> m () - xCallExtra ct callId CallExtraInfo {rtcExtraInfo} msg msgMeta = do - msgCurrentCall ct callId "x.call.extra" msg msgMeta $ + xCallExtra :: Contact -> CallId -> CallExtraInfo -> RcvMessage -> m () + xCallExtra ct callId CallExtraInfo {rtcExtraInfo} msg = do + msgCurrentCall ct callId "x.call.extra" msg $ \call -> case callState call of CallOfferReceived {localCallType, peerCallType, peerCallSession, sharedKey} -> do -- TODO update the list of ice servers in peerCallSession @@ -4968,15 +4962,14 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage = pure (Just call, Nothing) -- to any call party - xCallEnd :: Contact -> CallId -> RcvMessage -> MsgMeta -> m () - xCallEnd ct callId msg msgMeta = - msgCurrentCall ct callId "x.call.end" msg msgMeta $ \Call {chatItemId} -> do + xCallEnd :: Contact -> CallId -> RcvMessage -> m () + xCallEnd ct callId msg = + msgCurrentCall ct callId "x.call.end" msg $ \Call {chatItemId} -> do toView $ CRCallEnded user ct (Nothing,) <$> callStatusItemContent user ct chatItemId WCSDisconnected - msgCurrentCall :: Contact -> CallId -> Text -> RcvMessage -> MsgMeta -> (Call -> m (Maybe Call, Maybe ACIContent)) -> m () - msgCurrentCall ct@Contact {contactId = ctId'} callId' eventName RcvMessage {msgId} msgMeta action = do - checkIntegrityCreateItem (CDDirectRcv ct) msgMeta + msgCurrentCall :: Contact -> CallId -> Text -> RcvMessage -> (Call -> m (Maybe Call, Maybe ACIContent)) -> m () + msgCurrentCall ct@Contact {contactId = ctId'} callId' eventName RcvMessage {msgId} action = do calls <- asks currentCalls atomically (TM.lookup ctId' calls) >>= \case Nothing -> messageError $ eventName <> ": no current call" From 0ef2c55983df65843922c5f9c880cc70c455651c Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Thu, 4 Jan 2024 19:29:28 +0000 Subject: [PATCH 024/102] core: invalid name error when it matches hidden profile (#3647) --- src/Simplex/Chat.hs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Simplex/Chat.hs b/src/Simplex/Chat.hs index cfd8f224fb..93f10b416b 100644 --- a/src/Simplex/Chat.hs +++ b/src/Simplex/Chat.hs @@ -454,8 +454,9 @@ processChatCommand' vr = \case withStore' getUsers >>= \case [] -> pure 1 users -> do - when (any (\User {localDisplayName = n} -> n == displayName) users) $ - throwChatError (CEUserExists displayName) + forM_ users $ \User {localDisplayName = n, activeUser, viewPwdHash} -> + when (n == displayName) . throwChatError $ + if activeUser || isNothing viewPwdHash then CEUserExists displayName else CEInvalidDisplayName {displayName, validName = ""} withAgent (\a -> createUser a smp xftp) ts <- liftIO $ getCurrentTime >>= if pastTimestamp then coupleDaysAgo else pure user <- withStore $ \db -> createUserRecordAt db (AgentUserId auId) p True ts From 9e87fe73a5797da6fa07d41950bec224216de633 Mon Sep 17 00:00:00 2001 From: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com> Date: Fri, 5 Jan 2024 11:35:48 +0400 Subject: [PATCH 025/102] core: batch send profile update (#3618) * core: batch send profile update * redundant * reorder * remove type * createSndMessages * refactor * batched create internal item * create feature items for multiple contacts * comments * refactor call site * synonim * refactor createSndMessages * more batching * remove partitionWith * unite filter and fold * refactor * refactor * refactor * fix merge * add test * rename * refactor * refactor * withExceptT * refactor * refactor2 * remove notChanged * deliver with sendMessagesB (#3646) * deliver with sendMessagesB * refactor --------- Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> --------- Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Co-authored-by: Alexander Bondarenko <486682+dpwiz@users.noreply.github.com> --- apps/ios/SimpleXChat/ChatTypes.swift | 1 - .../chat/simplex/common/model/ChatModel.kt | 1 - cabal.project | 2 +- scripts/nix/sha256map.nix | 2 +- src/Simplex/Chat.hs | 232 ++++++++++++------ src/Simplex/Chat/Controller.hs | 3 +- tests/ChatTests/Profiles.hs | 28 +++ 7 files changed, 188 insertions(+), 81 deletions(-) diff --git a/apps/ios/SimpleXChat/ChatTypes.swift b/apps/ios/SimpleXChat/ChatTypes.swift index 96281a5013..cd58b20002 100644 --- a/apps/ios/SimpleXChat/ChatTypes.swift +++ b/apps/ios/SimpleXChat/ChatTypes.swift @@ -172,7 +172,6 @@ public func fromLocalProfile (_ profile: LocalProfile) -> Profile { } public struct UserProfileUpdateSummary: Decodable { - public var notChanged: Int public var updateSuccesses: Int public var updateFailures: Int public var changedContacts: [Contact] 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 b8d421b07b..ff7cfed0fd 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 @@ -1151,7 +1151,6 @@ data class LocalProfile( @Serializable data class UserProfileUpdateSummary( - val notChanged: Int, val updateSuccesses: Int, val updateFailures: Int, val changedContacts: List diff --git a/cabal.project b/cabal.project index dbd050bcf1..b3ecbe6b51 100644 --- a/cabal.project +++ b/cabal.project @@ -12,7 +12,7 @@ constraints: zip +disable-bzip2 +disable-zstd source-repository-package type: git location: https://github.com/simplex-chat/simplexmq.git - tag: d0588bd0ac23a459cbfc9a4789633014e91ffa19 + tag: 6d4834f306963e2d3f2f62af212fe855ea9c7595 source-repository-package type: git diff --git a/scripts/nix/sha256map.nix b/scripts/nix/sha256map.nix index b22cef750e..233918be45 100644 --- a/scripts/nix/sha256map.nix +++ b/scripts/nix/sha256map.nix @@ -1,5 +1,5 @@ { - "https://github.com/simplex-chat/simplexmq.git"."d0588bd0ac23a459cbfc9a4789633014e91ffa19" = "0b17qy74capb0jyli8f3pg1xi4aawhcgpmaz2ykl9g3605png1na"; + "https://github.com/simplex-chat/simplexmq.git"."6d4834f306963e2d3f2f62af212fe855ea9c7595" = "1603nlzkncrl8kg9xb8yi4kjbk8d8gmyw7wzvlni7lgbf0hjrffz"; "https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38"; "https://github.com/simplex-chat/direct-sqlcipher.git"."f814ee68b16a9447fbb467ccc8f29bdd3546bfd9" = "1ql13f4kfwkbaq7nygkxgw84213i0zm7c1a8hwvramayxl38dq5d"; "https://github.com/simplex-chat/sqlcipher-simple.git"."a46bd361a19376c5211f1058908fc0ae6bf42446" = "1z0r78d8f0812kxbgsm735qf6xx8lvaz27k1a0b4a2m0sshpd5gl"; diff --git a/src/Simplex/Chat.hs b/src/Simplex/Chat.hs index 93f10b416b..bbb34c570e 100644 --- a/src/Simplex/Chat.hs +++ b/src/Simplex/Chat.hs @@ -24,7 +24,7 @@ import Control.Monad.Reader import qualified Data.Aeson as J import Data.Attoparsec.ByteString.Char8 (Parser) import qualified Data.Attoparsec.ByteString.Char8 as A -import Data.Bifunctor (bimap, first) +import Data.Bifunctor (bimap, first, second) import Data.ByteArray (ScrubbedBytes) import qualified Data.ByteArray as BA import qualified Data.ByteString.Base64 as B64 @@ -37,6 +37,7 @@ import Data.Constraint (Dict (..)) import Data.Either (fromRight, lefts, partitionEithers, rights) import Data.Fixed (div') import Data.Functor (($>)) +import Data.Functor.Identity import Data.Int (Int64) import Data.List (find, foldl', isSuffixOf, partition, sortOn) import Data.List.NonEmpty (NonEmpty (..), nonEmpty, toList, (<|)) @@ -87,6 +88,7 @@ import Simplex.Messaging.Agent.Client (AgentStatsKey (..), SubInfo (..), agentCl import Simplex.Messaging.Agent.Env.SQLite (AgentConfig (..), InitialAgentServers (..), createAgentStore, defaultAgentConfig) import Simplex.Messaging.Agent.Lock import Simplex.Messaging.Agent.Protocol +import qualified Simplex.Messaging.Agent.Protocol as AP (AgentErrorType (..)) import Simplex.Messaging.Agent.Store.SQLite (MigrationConfirmation (..), MigrationError, SQLiteStore (dbNew), execSQL, upMigration, withConnection) import Simplex.Messaging.Agent.Store.SQLite.DB (SlowQueryStats (..)) import qualified Simplex.Messaging.Agent.Store.SQLite.DB as DB @@ -2136,31 +2138,41 @@ processChatCommand' vr = \case | otherwise = do when (n /= n') $ checkValidName n' -- read contacts before user update to correctly merge preferences - -- [incognito] filter out contacts with whom user has incognito connections - contacts <- - filter (\ct -> contactReady ct && contactActive ct && not (contactConnIncognito ct)) - <$> withStore' (`getUserContacts` user) + contacts <- withStore' (`getUserContacts` user) user' <- updateUser asks currentUser >>= atomically . (`writeTVar` Just user') withChatLock "updateProfile" . procCmd $ do - ChatConfig {logLevel} <- asks config - summary <- foldM (processAndCount user' logLevel) (UserProfileUpdateSummary 0 0 0 []) contacts + let changedCts = foldr (addChangedProfileContact user') [] contacts + idsEvts = map ctSndMsg changedCts + msgReqs_ <- zipWith ctMsgReq changedCts <$> createSndMessages idsEvts + (errs, cts) <- partitionEithers . zipWith (second . const) changedCts <$> deliverMessagesB msgReqs_ + unless (null errs) $ toView $ CRChatErrors (Just user) errs + let changedCts' = filter (\ChangedProfileContact {ct, ct'} -> directOrUsed ct' && mergedPreferences ct' /= mergedPreferences ct) cts + createContactsSndFeatureItems user' changedCts' + let summary = + UserProfileUpdateSummary + { updateSuccesses = length cts, + updateFailures = length errs, + changedContacts = map (\ChangedProfileContact {ct'} -> ct') changedCts' + } pure $ CRUserProfileUpdated user' (fromLocalProfile p) p' summary where - processAndCount user' ll s@UserProfileUpdateSummary {notChanged, updateSuccesses, updateFailures, changedContacts = cts} ct = do - let mergedProfile = userProfileToSend user Nothing $ Just ct - ct' = updateMergedPreferences user' ct - mergedProfile' = userProfileToSend user' Nothing $ Just ct' - if mergedProfile' == mergedProfile - then pure s {notChanged = notChanged + 1} - else - let cts' = if mergedPreferences ct == mergedPreferences ct' then cts else ct' : cts - in (notifyContact mergedProfile' ct' $> s {updateSuccesses = updateSuccesses + 1, changedContacts = cts'}) - `catchChatError` \e -> when (ll <= CLLInfo) (toView $ CRChatError (Just user) e) $> s {updateFailures = updateFailures + 1, changedContacts = cts'} + -- [incognito] filter out contacts with whom user has incognito connections + addChangedProfileContact :: User -> Contact -> [ChangedProfileContact] -> [ChangedProfileContact] + addChangedProfileContact user' ct changedCts = case contactSendConn_ ct' of + Left _ -> changedCts + Right conn + | connIncognito conn || mergedProfile' == mergedProfile -> changedCts + | otherwise -> ChangedProfileContact ct ct' mergedProfile' conn : changedCts where - notifyContact mergedProfile' ct' = do - void $ sendDirectContactMessage ct' (XInfo mergedProfile') - when (directOrUsed ct') $ createSndFeatureItems user' ct ct' + mergedProfile = userProfileToSend user Nothing $ Just ct + ct' = updateMergedPreferences user' ct + mergedProfile' = userProfileToSend user' Nothing $ Just ct' + ctSndMsg :: ChangedProfileContact -> (ConnOrGroupId, ChatMsgEvent 'Json) + ctSndMsg ChangedProfileContact {mergedProfile', conn = Connection {connId}} = (ConnectionId connId, XInfo mergedProfile') + ctMsgReq :: ChangedProfileContact -> Either ChatError SndMessage -> Either ChatError MsgReq + ctMsgReq ChangedProfileContact {conn} = fmap $ \SndMessage {msgId, msgBody} -> + (conn, MsgFlags {notification = hasNotification XInfo_}, msgBody, msgId) updateContactPrefs :: User -> Contact -> Preferences -> m ChatResponse updateContactPrefs _ ct@Contact {activeConn = Nothing} _ = throwChatError $ CEContactNotActive ct updateContactPrefs user@User {userId} ct@Contact {activeConn = Just Connection {customUserProfileId}, userPreferences = contactUserPrefs} contactUserPrefs' @@ -2400,6 +2412,13 @@ processChatCommand' vr = \case cReqHashes = bimap hash hash cReqSchemas hash = ConnReqUriHash . C.sha256Hash . strEncode +data ChangedProfileContact = ChangedProfileContact + { ct :: Contact, + ct' :: Contact, + mergedProfile' :: Profile, + conn :: Connection + } + prepareGroupMsg :: forall m. ChatMonad m => User -> GroupInfo -> MsgContent -> Maybe ChatItemId -> Maybe FileInvitation -> Maybe CITimed -> Bool -> m (MsgContainer, Maybe (CIQuote 'CTGroup)) prepareGroupMsg user GroupInfo {groupId, membership} mc quotedItemId_ fInv_ timed_ live = case quotedItemId_ of Nothing -> pure (MCSimple (ExtMsgContent mc fInv_ (ttl' <$> timed_) (justTrue live)), Nothing) @@ -5625,12 +5644,20 @@ deleteOrUpdateMemberRecord user@User {userId} member = Nothing -> deleteGroupMember db user member sendDirectContactMessage :: (MsgEncodingI e, ChatMonad m) => Contact -> ChatMsgEvent e -> m (SndMessage, Int64) -sendDirectContactMessage ct@Contact {activeConn = Nothing} _ = throwChatError $ CEContactNotReady ct -sendDirectContactMessage ct@Contact {activeConn = Just conn@Connection {connId, connStatus}, contactStatus} chatMsgEvent - | connStatus /= ConnReady && connStatus /= ConnSndReady = throwChatError $ CEContactNotReady ct - | contactStatus /= CSActive = throwChatError $ CEContactNotActive ct - | connDisabled conn = throwChatError $ CEContactDisabled ct - | otherwise = sendDirectMessage conn chatMsgEvent (ConnectionId connId) +sendDirectContactMessage ct chatMsgEvent = do + conn@Connection {connId} <- liftEither $ contactSendConn_ ct + sendDirectMessage conn chatMsgEvent (ConnectionId connId) + +contactSendConn_ :: Contact -> Either ChatError Connection +contactSendConn_ ct@Contact {activeConn} = case activeConn of + Nothing -> err $ CEContactNotReady ct + Just conn + | not (connReady conn) -> err $ CEContactNotReady ct + | not (contactActive ct) -> err $ CEContactNotActive ct + | connDisabled conn -> err $ CEContactDisabled ct + | otherwise -> Right conn + where + err = Left . ChatError sendDirectMessage :: (MsgEncodingI e, ChatMonad m) => Connection -> ChatMsgEvent e -> ConnOrGroupId -> m (SndMessage, Int64) sendDirectMessage conn chatMsgEvent connOrGroupId = do @@ -5639,18 +5666,25 @@ sendDirectMessage conn chatMsgEvent connOrGroupId = do (msg,) <$> deliverMessage conn (toCMEventTag chatMsgEvent) msgBody msgId createSndMessage :: (MsgEncodingI e, ChatMonad m) => ChatMsgEvent e -> ConnOrGroupId -> m SndMessage -createSndMessage chatMsgEvent connOrGroupId = do +createSndMessage chatMsgEvent connOrGroupId = + liftEither . runIdentity =<< createSndMessages (Identity (connOrGroupId, chatMsgEvent)) + +createSndMessages :: forall e m t. (MsgEncodingI e, ChatMonad' m, Traversable t) => t (ConnOrGroupId, ChatMsgEvent e) -> m (t (Either ChatError SndMessage)) +createSndMessages idsEvents = do gVar <- asks random vr <- chatVersionRange - withStore $ \db -> createNewSndMessage db gVar connOrGroupId chatMsgEvent (encodeMessage vr) + withStoreBatch $ \db -> fmap (uncurry (createMsg db gVar vr)) idsEvents where - encodeMessage chatVRange sharedMsgId = - encodeChatMessage ChatMessage {chatVRange, msgId = Just sharedMsgId, chatMsgEvent} + createMsg db gVar chatVRange connOrGroupId evnt = runExceptT $ do + withExceptT ChatErrorStore $ createNewSndMessage db gVar connOrGroupId evnt (encodeMessage chatVRange evnt) + encodeMessage chatVRange evnt sharedMsgId = + encodeChatMessage ChatMessage {chatVRange, msgId = Just sharedMsgId, chatMsgEvent = evnt} sendGroupMemberMessages :: forall e m. (MsgEncodingI e, ChatMonad m) => User -> Connection -> NonEmpty (ChatMsgEvent e) -> GroupId -> m () sendGroupMemberMessages user conn@Connection {connId} events groupId = do when (connDisabled conn) $ throwChatError (CEConnectionDisabled conn) - (errs, msgs) <- partitionEithers <$> createSndMessages + let idsEvts = L.map (GroupId groupId,) events + (errs, msgs) <- partitionEithers . L.toList <$> createSndMessages idsEvts unless (null errs) $ toView $ CRChatErrors (Just user) errs unless (null msgs) $ do let (errs', msgBatches) = partitionEithers $ batchMessages maxChatMsgSize msgs @@ -5665,16 +5699,6 @@ sendGroupMemberMessages user conn@Connection {connId} events groupId = do agentMsgId <- withAgent $ \a -> sendMessage a (aConnId conn) MsgFlags {notification = True} batchBody let sndMsgDelivery = SndMsgDelivery {connId, agentMsgId} void . withStoreBatch' $ \db -> map (\SndMessage {msgId} -> createSndMsgDelivery db sndMsgDelivery msgId) sndMsgs - createSndMessages :: m [Either ChatError SndMessage] - createSndMessages = do - gVar <- asks random - vr <- chatVersionRange - withStoreBatch $ \db -> map (createMsg db gVar vr) (toList events) - createMsg db gVar chatVRange evnt = do - r <- runExceptT $ createNewSndMessage db gVar (GroupId groupId) evnt (encodeMessage chatVRange evnt) - pure $ first ChatErrorStore r - encodeMessage chatVRange evnt sharedMsgId = - encodeChatMessage ChatMessage {chatVRange, msgId = Just sharedMsgId, chatMsgEvent = evnt} directMessage :: (MsgEncodingI e, ChatMonad m) => ChatMsgEvent e -> m ByteString directMessage chatMsgEvent = do @@ -5695,14 +5719,23 @@ deliverMessage' conn msgFlags msgBody msgId = [r] -> liftEither r rs -> throwChatError $ CEInternalError $ "deliverMessage: expected 1 result, got " <> show (length rs) -deliverMessages :: ChatMonad' m => [(Connection, MsgFlags, LazyMsgBody, MessageId)] -> m [Either ChatError Int64] -deliverMessages msgReqs = do - sent <- zipWith prepareBatch msgReqs <$> withAgent' (`sendMessages` aReqs) +type MsgReq = (Connection, MsgFlags, LazyMsgBody, MessageId) + +deliverMessages :: ChatMonad' m => [MsgReq] -> m [Either ChatError Int64] +deliverMessages = deliverMessagesB . map Right + +deliverMessagesB :: ChatMonad' m => [Either ChatError MsgReq] -> m [Either ChatError Int64] +deliverMessagesB msgReqs = do + sent <- zipWith prepareBatch msgReqs <$> withAgent' (`sendMessagesB` map toAgent msgReqs) withStoreBatch $ \db -> map (bindRight $ createDelivery db) sent where - aReqs = map (\(conn, msgFlags, msgBody, _msgId) -> (aConnId conn, msgFlags, LB.toStrict msgBody)) msgReqs - prepareBatch req = bimap (`ChatErrorAgent` Nothing) (req,) - createDelivery :: DB.Connection -> ((Connection, MsgFlags, LazyMsgBody, MessageId), AgentMsgId) -> IO (Either ChatError Int64) + toAgent = \case + Right (conn, msgFlags, msgBody, _msgId) -> Right (aConnId conn, msgFlags, LB.toStrict msgBody) + Left _ce -> Left (AP.INTERNAL "ChatError, skip") -- as long as it is Left, the agent batchers should just step over it + prepareBatch (Right req) (Right ar) = Right (req, ar) + prepareBatch (Left ce) _ = Left ce -- restore original ChatError + prepareBatch _ (Left ae) = Left $ ChatErrorAgent ae Nothing + createDelivery :: DB.Connection -> (MsgReq, AgentMsgId) -> IO (Either ChatError Int64) createDelivery db ((Connection {connId}, _, _, msgId), agentMsgId) = Right <$> createSndMsgDelivery db (SndMsgDelivery {connId, agentMsgId}) msgId @@ -5848,7 +5881,7 @@ saveSndChatItem' user cd msg@SndMessage {sharedMsgId} content ciFile quotedItem ciId <- createNewSndChatItem db user cd msg content quotedItem itemTimed live createdAt forM_ ciFile $ \CIFile {fileId} -> updateFileTransferChatItemId db fileId ciId createdAt pure ciId - liftIO $ mkChatItem cd ciId content ciFile quotedItem (Just sharedMsgId) itemTimed live createdAt Nothing createdAt + pure $ mkChatItem cd ciId content ciFile quotedItem (Just sharedMsgId) itemTimed live createdAt Nothing createdAt saveRcvChatItem :: ChatMonad m => User -> ChatDirection c 'MDRcv -> RcvMessage -> UTCTime -> CIContent 'MDRcv -> m (ChatItem c 'MDRcv) saveRcvChatItem user cd msg@RcvMessage {sharedMsgId_} brokerTs content = @@ -5862,14 +5895,14 @@ saveRcvChatItem' user cd msg@RcvMessage {forwardedByMember} sharedMsgId_ brokerT (ciId, quotedItem) <- createNewRcvChatItem db user cd msg sharedMsgId_ content itemTimed live brokerTs createdAt forM_ ciFile $ \CIFile {fileId} -> updateFileTransferChatItemId db fileId ciId createdAt pure (ciId, quotedItem) - liftIO $ mkChatItem cd ciId content ciFile quotedItem sharedMsgId_ itemTimed live brokerTs forwardedByMember createdAt + pure $ mkChatItem cd ciId content ciFile quotedItem sharedMsgId_ itemTimed live brokerTs forwardedByMember createdAt -mkChatItem :: forall c d. MsgDirectionI d => ChatDirection c d -> ChatItemId -> CIContent d -> Maybe (CIFile d) -> Maybe (CIQuote c) -> Maybe SharedMsgId -> Maybe CITimed -> Bool -> ChatItemTs -> Maybe GroupMemberId -> UTCTime -> IO (ChatItem c d) -mkChatItem cd ciId content file quotedItem sharedMsgId itemTimed live itemTs forwardedByMember currentTs = do +mkChatItem :: forall c d. MsgDirectionI d => ChatDirection c d -> ChatItemId -> CIContent d -> Maybe (CIFile d) -> Maybe (CIQuote c) -> Maybe SharedMsgId -> Maybe CITimed -> Bool -> ChatItemTs -> Maybe GroupMemberId -> UTCTime -> ChatItem c d +mkChatItem cd ciId content file quotedItem sharedMsgId itemTimed live itemTs forwardedByMember currentTs = let itemText = ciContentToText content itemStatus = ciCreateStatus content meta = mkCIMeta ciId content itemText itemStatus sharedMsgId Nothing False itemTimed (justTrue live) currentTs itemTs forwardedByMember currentTs currentTs - pure ChatItem {chatDir = toCIDirection cd, meta, content, formattedText = parseMaybeMarkdownList itemText, quotedItem, reactions = [], file} + in ChatItem {chatDir = toCIDirection cd, meta, content, formattedText = parseMaybeMarkdownList itemText, quotedItem, reactions = [], file} deleteDirectCI :: (ChatMonad m, MsgDirectionI d) => User -> Contact -> ChatItem 'CTDirect d -> Bool -> Bool -> m ChatResponse deleteDirectCI user ct ci@ChatItem {file} byUser timed = do @@ -5982,6 +6015,15 @@ createSndFeatureItems user ct ct' = CUPContact {preference} -> preference CUPUser {preference} -> preference +createContactsSndFeatureItems :: forall m. ChatMonad m => User -> [ChangedProfileContact] -> m () +createContactsSndFeatureItems user cts = + createContactsFeatureItems user cts' CDDirectSnd CISndChatFeature CISndChatPreference getPref + where + cts' = map (\ChangedProfileContact {ct, ct'} -> (ct, ct')) cts + getPref ContactUserPreference {userPreference} = case userPreference of + CUPContact {preference} -> preference + CUPUser {preference} -> preference + type FeatureContent a d = ChatFeature -> a -> Maybe Int -> CIContent d createFeatureItems :: @@ -5995,24 +6037,44 @@ createFeatureItems :: FeatureContent FeatureAllowed d -> (forall f. ContactUserPreference (FeaturePreference f) -> FeaturePreference f) -> m () -createFeatureItems user Contact {mergedPreferences = cups} ct'@Contact {mergedPreferences = cups'} chatDir ciFeature ciOffer getPref = - forM_ allChatFeatures $ \(ACF f) -> createItem f +createFeatureItems user ct ct' = createContactsFeatureItems user [(ct, ct')] + +createContactsFeatureItems :: + forall d m. + (MsgDirectionI d, ChatMonad m) => + User -> + [(Contact, Contact)] -> + (Contact -> ChatDirection 'CTDirect d) -> + FeatureContent PrefEnabled d -> + FeatureContent FeatureAllowed d -> + (forall f. ContactUserPreference (FeaturePreference f) -> FeaturePreference f) -> + m () +createContactsFeatureItems user cts chatDir ciFeature ciOffer getPref = do + let dirsCIContents = map contactChangedFeatures cts + (errs, acis) <- partitionEithers <$> createInternalItemsForChats user Nothing dirsCIContents + unless (null errs) $ toView $ CRChatErrors (Just user) errs + forM_ acis $ \aci -> toView $ CRNewChatItem user aci where - createItem :: forall f. FeatureI f => SChatFeature f -> m () - createItem f - | state /= state' = create ciFeature state' - | prefState /= prefState' = create ciOffer prefState' - | otherwise = pure () + contactChangedFeatures :: (Contact, Contact) -> (ChatDirection 'CTDirect d, [CIContent d]) + contactChangedFeatures (Contact {mergedPreferences = cups}, ct'@Contact {mergedPreferences = cups'}) = do + let contents = mapMaybe (\(ACF f) -> featureCIContent_ f) allChatFeatures + (chatDir ct', contents) where - create :: FeatureContent a d -> (a, Maybe Int) -> m () - create ci (s, param) = createInternalChatItem user (chatDir ct') (ci f' s param) Nothing - f' = chatFeature f - state = featureState cup - state' = featureState cup' - prefState = preferenceState $ getPref cup - prefState' = preferenceState $ getPref cup' - cup = getContactUserPreference f cups - cup' = getContactUserPreference f cups' + featureCIContent_ :: forall f. FeatureI f => SChatFeature f -> Maybe (CIContent d) + featureCIContent_ f + | state /= state' = Just $ fContent ciFeature state' + | prefState /= prefState' = Just $ fContent ciOffer prefState' + | otherwise = Nothing + where + fContent :: FeatureContent a d -> (a, Maybe Int) -> CIContent d + fContent ci (s, param) = ci f' s param + f' = chatFeature f + state = featureState cup + state' = featureState cup' + prefState = preferenceState $ getPref cup + prefState' = preferenceState $ getPref cup' + cup = getContactUserPreference f cups + cup' = getContactUserPreference f cups' createGroupFeatureChangedItems :: (MsgDirectionI d, ChatMonad m) => User -> ChatDirection 'CTGroup d -> (GroupFeature -> GroupPreference -> Maybe Int -> CIContent d) -> GroupInfo -> GroupInfo -> m () createGroupFeatureChangedItems user cd ciContent GroupInfo {fullGroupPreferences = gps} GroupInfo {fullGroupPreferences = gps'} = @@ -6026,15 +6088,35 @@ createGroupFeatureChangedItems user cd ciContent GroupInfo {fullGroupPreferences sameGroupProfileInfo :: GroupProfile -> GroupProfile -> Bool sameGroupProfileInfo p p' = p {groupPreferences = Nothing} == p' {groupPreferences = Nothing} -createInternalChatItem :: forall c d m. (ChatTypeI c, MsgDirectionI d, ChatMonad m) => User -> ChatDirection c d -> CIContent d -> Maybe UTCTime -> m () -createInternalChatItem user cd content itemTs_ = do +createInternalChatItem :: (ChatTypeI c, MsgDirectionI d, ChatMonad m) => User -> ChatDirection c d -> CIContent d -> Maybe UTCTime -> m () +createInternalChatItem user cd content itemTs_ = + createInternalItemsForChats user itemTs_ [(cd, [content])] >>= \case + [Right aci] -> toView $ CRNewChatItem user aci + [Left e] -> throwError e + rs -> throwChatError $ CEInternalError $ "createInternalChatItem: expected 1 result, got " <> show (length rs) + +createInternalItemsForChats :: + forall c d m. + (ChatTypeI c, MsgDirectionI d, ChatMonad' m) => + User -> + Maybe UTCTime -> + [(ChatDirection c d, [CIContent d])] -> + m [Either ChatError AChatItem] +createInternalItemsForChats user itemTs_ dirsCIContents = do createdAt <- liftIO getCurrentTime let itemTs = fromMaybe createdAt itemTs_ - ciId <- withStore' $ \db -> do - when (ciRequiresAttention content) $ updateChatTs db user cd createdAt - createNewChatItemNoMsg db user cd content itemTs createdAt - ci <- liftIO $ mkChatItem cd ciId content Nothing Nothing Nothing Nothing False itemTs Nothing createdAt - toView $ CRNewChatItem user (AChatItem (chatTypeI @c) (msgDirection @d) (toChatInfo cd) ci) + void . withStoreBatch' $ \db -> map (uncurry $ updateChat db createdAt) dirsCIContents + withStoreBatch' $ \db -> concatMap (uncurry $ createACIs db itemTs createdAt) dirsCIContents + where + updateChat :: DB.Connection -> UTCTime -> ChatDirection c d -> [CIContent d] -> IO () + updateChat db createdAt cd contents + | any ciRequiresAttention contents = updateChatTs db user cd createdAt + | otherwise = pure () + createACIs :: DB.Connection -> UTCTime -> UTCTime -> ChatDirection c d -> [CIContent d] -> [IO AChatItem] + createACIs db itemTs createdAt cd = map $ \content -> do + ciId <- createNewChatItemNoMsg db user cd content itemTs createdAt + let ci = mkChatItem cd ciId content Nothing Nothing Nothing Nothing False itemTs Nothing createdAt + pure $ AChatItem (chatTypeI @c) (msgDirection @d) (toChatInfo cd) ci getCreateActiveUser :: SQLiteStore -> Bool -> IO User getCreateActiveUser st testView = do diff --git a/src/Simplex/Chat/Controller.hs b/src/Simplex/Chat/Controller.hs index b198cccbf7..0a8c32dd29 100644 --- a/src/Simplex/Chat/Controller.hs +++ b/src/Simplex/Chat/Controller.hs @@ -894,8 +894,7 @@ data PendingSubStatus = PendingSubStatus deriving (Show) data UserProfileUpdateSummary = UserProfileUpdateSummary - { notChanged :: Int, - updateSuccesses :: Int, + { updateSuccesses :: Int, updateFailures :: Int, changedContacts :: [Contact] } diff --git a/tests/ChatTests/Profiles.hs b/tests/ChatTests/Profiles.hs index 6813a4cc72..afa9fb3cff 100644 --- a/tests/ChatTests/Profiles.hs +++ b/tests/ChatTests/Profiles.hs @@ -67,6 +67,7 @@ chatProfileTests = do xit'' "enable timed messages with contact" testEnableTimedMessagesContact it "enable timed messages in group" testEnableTimedMessagesGroup xit'' "timed messages enabled globally, contact turns on" testTimedMessagesEnabledGlobally + it "update multiple user preferences for multiple contacts" testUpdateMultipleUserPrefs testUpdateProfile :: HasCallStack => FilePath -> IO () testUpdateProfile = @@ -1864,3 +1865,30 @@ testTimedMessagesEnabledGlobally = bob <## "timed message deleted: hey" alice #$> ("/_get chat @2 count=100", chat, chatFeatures <> [(0, "Disappearing messages: enabled (1 sec)")]) bob #$> ("/_get chat @2 count=100", chat, chatFeatures <> [(1, "Disappearing messages: enabled (1 sec)")]) + +testUpdateMultipleUserPrefs :: HasCallStack => FilePath -> IO () +testUpdateMultipleUserPrefs = testChat3 aliceProfile bobProfile cathProfile $ + \alice bob cath -> do + connectUsers alice bob + alice #> "@bob hi bob" + bob <# "alice> hi bob" + + connectUsers alice cath + alice #> "@cath hi cath" + cath <# "alice> hi cath" + + alice ##> "/_profile 1 {\"displayName\": \"alice\", \"fullName\": \"Alice\", \"preferences\": {\"fullDelete\": {\"allow\": \"always\"}, \"reactions\": {\"allow\": \"no\"}, \"receipts\": {\"allow\": \"yes\", \"activated\": true}}}" + alice <## "updated preferences:" + alice <## "Full deletion allowed: always" + alice <## "Message reactions allowed: no" + + bob <## "alice updated preferences for you:" + bob <## "Full deletion: enabled for you (you allow: default (no), contact allows: always)" + bob <## "Message reactions: off (you allow: default (yes), contact allows: no)" + + cath <## "alice updated preferences for you:" + cath <## "Full deletion: enabled for you (you allow: default (no), contact allows: always)" + cath <## "Message reactions: off (you allow: default (yes), contact allows: no)" + + alice #$> ("/_get chat @2 count=100", chat, chatFeatures <> [(1, "hi bob"), (1, "Full deletion: enabled for contact"), (1, "Message reactions: off")]) + alice #$> ("/_get chat @3 count=100", chat, chatFeatures <> [(1, "hi cath"), (1, "Full deletion: enabled for contact"), (1, "Message reactions: off")]) From fe865c5e11d33d897475735658eb378fbec447dc Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Sat, 6 Jan 2024 01:45:52 +0700 Subject: [PATCH 026/102] android, desktop: consistent colors in themes (#3649) --- .../app/views/call/IncomingCallActivity.kt | 9 +++++--- .../kotlin/chat/simplex/common/App.kt | 4 ++-- .../kotlin/chat/simplex/common/AppLock.kt | 5 ++--- .../chat/simplex/common/ui/theme/Color.kt | 5 ++++- .../chat/simplex/common/ui/theme/Theme.kt | 21 ++----------------- .../chat/simplex/common/views/SplashView.kt | 6 +++--- .../chat/simplex/common/views/TerminalView.kt | 5 ++++- .../chat/simplex/common/views/WelcomeView.kt | 2 +- .../views/call/IncomingCallAlertView.kt | 3 ++- .../simplex/common/views/chat/ChatView.kt | 2 ++ .../simplex/common/views/chat/SendMsgView.kt | 3 ++- .../common/views/chat/item/CIFileView.kt | 3 ++- .../views/chat/item/CIGroupInvitationView.kt | 1 + .../views/chat/item/CIRcvDecryptionError.kt | 2 ++ .../common/views/chat/item/CIVIdeoView.kt | 6 ++++-- .../common/views/chat/item/CIVoiceView.kt | 3 ++- .../common/views/chat/item/ChatItemView.kt | 4 ++-- .../common/views/chat/item/DeletedItemView.kt | 1 + .../views/chat/item/IntegrityErrorItemView.kt | 1 + .../views/chat/item/MarkedDeletedItemView.kt | 1 + .../common/views/chatlist/ChatListView.kt | 2 ++ .../common/views/chatlist/ShareListView.kt | 2 ++ .../common/views/chatlist/UserPicker.kt | 17 +++++++-------- .../common/views/helpers/CustomTimePicker.kt | 3 ++- .../helpers/ExposedDropDownSettingRow.kt | 2 +- .../views/helpers/LocalAuthentication.kt | 5 ++--- .../simplex/common/views/helpers/ModalView.kt | 2 +- .../common/views/newchat/NewChatSheet.kt | 4 ++-- .../usersettings/AdvancedNetworkSettings.kt | 3 ++- .../views/usersettings/PrivacySettings.kt | 10 ++++----- .../common/views/usersettings/RTCServers.kt | 3 ++- .../views/usersettings/UserAddressView.kt | 2 +- .../platform/PlatformTextField.desktop.kt | 3 ++- .../views/helpers/DefaultDialog.desktop.kt | 6 +++--- 34 files changed, 81 insertions(+), 70 deletions(-) diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/call/IncomingCallActivity.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/call/IncomingCallActivity.kt index f5c46a0eb5..d09cb019f8 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/call/IncomingCallActivity.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/call/IncomingCallActivity.kt @@ -97,7 +97,8 @@ fun IncomingCallActivityView(m: ChatModel) { Surface( Modifier .fillMaxSize(), - color = MaterialTheme.colors.background + color = MaterialTheme.colors.background, + contentColor = LocalContentColor.current ) { if (showCallView) { Box { @@ -200,7 +201,8 @@ private fun SimpleXLogo() { private fun LockScreenCallButton(text: String, icon: Painter, color: Color, action: () -> Unit) { Surface( shape = RoundedCornerShape(10.dp), - color = Color.Transparent + color = Color.Transparent, + contentColor = LocalContentColor.current ) { Column( Modifier @@ -227,7 +229,8 @@ fun PreviewIncomingCallLockScreenAlert() { Surface( Modifier .fillMaxSize(), - color = MaterialTheme.colors.background + color = MaterialTheme.colors.background, + contentColor = LocalContentColor.current ) { IncomingCallLockScreenAlertLayout( invitation = RcvCallInvitation( diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/App.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/App.kt index f61f3b4b80..a233ba6d59 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/App.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/App.kt @@ -44,7 +44,7 @@ data class SettingsViewState( fun AppScreen() { SimpleXTheme { ProvideWindowInsets(windowInsetsAnimationsEnabled = true) { - Surface(color = MaterialTheme.colors.background) { + Surface(color = MaterialTheme.colors.background, contentColor = LocalContentColor.current) { MainScreen() } } @@ -85,7 +85,7 @@ fun MainScreen() { @Composable fun AuthView() { - Surface(color = MaterialTheme.colors.background) { + Surface(color = MaterialTheme.colors.background, contentColor = LocalContentColor.current) { Box( Modifier.fillMaxSize(), contentAlignment = Alignment.Center diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/AppLock.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/AppLock.kt index a1d4c0c62a..d6214c252c 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/AppLock.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/AppLock.kt @@ -1,8 +1,7 @@ package chat.simplex.common import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.material.MaterialTheme -import androidx.compose.material.Surface +import androidx.compose.material.* import androidx.compose.runtime.mutableStateOf import androidx.compose.ui.Modifier import chat.simplex.common.model.* @@ -107,7 +106,7 @@ object AppLock { private fun setPasscode() { val appPrefs = ChatController.appPrefs ModalManager.fullscreen.showCustomModal { close -> - Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background) { + Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background, contentColor = LocalContentColor.current) { SetAppPasscodeView( submit = { ChatModel.performLA.value = true diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Color.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Color.kt index a01fc9de51..dc9ea2def7 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Color.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Color.kt @@ -1,5 +1,7 @@ package chat.simplex.common.ui.theme +import androidx.compose.material.LocalContentColor +import androidx.compose.runtime.Composable import androidx.compose.ui.graphics.Color val Purple200 = Color(0xFFBB86FC) @@ -25,4 +27,5 @@ val WarningOrange = Color(255, 127, 0, 255) val WarningYellow = Color(255, 192, 0, 255) val FileLight = Color(183, 190, 199, 255) val FileDark = Color(101, 101, 106, 255) -val MenuTextColorDark = Color.White.copy(alpha = 0.8f) + +val MenuTextColor: Color @Composable get () = if (isInDarkTheme()) LocalContentColor.current.copy(alpha = 0.8f) else Color.Black diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt index 21bee2b2b3..bef0d7e345 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt @@ -283,27 +283,10 @@ fun SimpleXTheme(darkTheme: Boolean? = null, content: @Composable () -> Unit) { val theme by CurrentColors.collectAsState() MaterialTheme( colors = theme.colors, - typography = Typography.copy( - h1 = Typography.h1.copy(color = theme.colors.onBackground), - h2 = Typography.h2.copy(color = theme.colors.onBackground), - h3 = Typography.h3.copy(color = theme.colors.onBackground), - h4 = Typography.h4.copy(color = theme.colors.onBackground), - h5 = Typography.h5.copy(color = theme.colors.onBackground), - h6 = Typography.h6.copy(color = theme.colors.onBackground), - subtitle1 = Typography.subtitle1.copy(color = theme.colors.onBackground), - subtitle2 = Typography.subtitle2.copy(color = theme.colors.onBackground), - body1 = Typography.body1.copy(color = theme.colors.onBackground), - body2 = Typography.body2.copy(color = theme.colors.onBackground), - button = Typography.button.copy(color = theme.colors.onBackground), - caption = Typography.caption.copy(color = theme.colors.onBackground), - overline = Typography.overline.copy(color = theme.colors.onBackground) - ), + typography = Typography, shapes = Shapes, content = { - ProvideTextStyle( - value = TextStyle(color = theme.colors.onBackground), - content = content - ) + CompositionLocalProvider(LocalContentColor provides MaterialTheme.colors.onBackground, content = content) } ) } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/SplashView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/SplashView.kt index cf9a8dfb62..5265f3187b 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/SplashView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/SplashView.kt @@ -1,8 +1,7 @@ package chat.simplex.common.views import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.material.MaterialTheme -import androidx.compose.material.Surface +import androidx.compose.material.* import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -11,7 +10,8 @@ fun SplashView() { Surface( Modifier .fillMaxSize(), - color = MaterialTheme.colors.background + color = MaterialTheme.colors.background, + contentColor = LocalContentColor.current ) { // Image( // painter = painterResource(MR.images.logo), diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/TerminalView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/TerminalView.kt index 4f01d4a39f..d3d30b58cf 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/TerminalView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/TerminalView.kt @@ -101,13 +101,16 @@ fun TerminalLayout( ) } }, + contentColor = LocalContentColor.current, + drawerContentColor = LocalContentColor.current, modifier = Modifier.navigationBarsWithImePadding() ) { contentPadding -> Surface( modifier = Modifier .padding(contentPadding) .fillMaxWidth(), - color = MaterialTheme.colors.background + color = MaterialTheme.colors.background, + contentColor = LocalContentColor.current ) { TerminalLog() } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/WelcomeView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/WelcomeView.kt index 29d7033290..3d025942d6 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/WelcomeView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/WelcomeView.kt @@ -239,7 +239,7 @@ fun OnboardingButtons(displayName: MutableState, close: () -> Unit) { val enabled = canCreateProfile(displayName.value) val createModifier: Modifier = Modifier.clickable(enabled) { createProfileOnboarding(chatModel, displayName.value, close) }.padding(8.dp) val createColor: Color = if (enabled) MaterialTheme.colors.primary else MaterialTheme.colors.secondary - Surface(shape = RoundedCornerShape(20.dp), color = Color.Transparent) { + Surface(shape = RoundedCornerShape(20.dp), color = Color.Transparent, contentColor = LocalContentColor.current) { Row(verticalAlignment = Alignment.CenterVertically, modifier = createModifier) { Text(stringResource(MR.strings.create_profile_button), style = MaterialTheme.typography.caption, color = createColor, fontWeight = FontWeight.Medium) Icon(painterResource(MR.images.ic_arrow_forward_ios), stringResource(MR.strings.create_profile_button), tint = createColor) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/call/IncomingCallAlertView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/call/IncomingCallAlertView.kt index 47dd0a27d1..be0c574b71 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/call/IncomingCallAlertView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/call/IncomingCallAlertView.kt @@ -85,7 +85,8 @@ fun IncomingCallInfo(invitation: RcvCallInvitation, chatModel: ChatModel) { private fun CallButton(text: String, icon: Painter, color: Color, action: () -> Unit) { Surface( shape = RoundedCornerShape(10.dp), - color = Color.Transparent + color = Color.Transparent, + contentColor = LocalContentColor.current ) { Column( Modifier 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 d6e75feeb5..25cb8315e0 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 @@ -570,6 +570,8 @@ fun ChatLayout( bottomBar = composeView, modifier = Modifier.navigationBarsWithImePadding(), floatingActionButton = { floatingButton.value() }, + contentColor = LocalContentColor.current, + drawerContentColor = LocalContentColor.current, ) { contentPadding -> BoxWithConstraints(Modifier .fillMaxHeight() diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/SendMsgView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/SendMsgView.kt index e566cf30d3..f1079d2f5f 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/SendMsgView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/SendMsgView.kt @@ -258,7 +258,8 @@ private fun CustomDisappearingMessageDialog( DefaultDialog(onDismissRequest = { setShowDialog(false) }) { Surface( - shape = RoundedCornerShape(corner = CornerSize(25.dp)) + shape = RoundedCornerShape(corner = CornerSize(25.dp)), + contentColor = LocalContentColor.current ) { Box( contentAlignment = Alignment.Center diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIFileView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIFileView.kt index 0d439f1235..068dd362b8 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIFileView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIFileView.kt @@ -131,7 +131,8 @@ fun CIFileView( Surface( Modifier.drawRingModifier(angle, strokeColor, strokeWidth), color = Color.Transparent, - shape = MaterialTheme.shapes.small.copy(CornerSize(percent = 50)) + shape = MaterialTheme.shapes.small.copy(CornerSize(percent = 50)), + contentColor = LocalContentColor.current ) { Box(Modifier.size(32.dp)) } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIGroupInvitationView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIGroupInvitationView.kt index 56dd7a360a..911bbaf833 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIGroupInvitationView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIGroupInvitationView.kt @@ -88,6 +88,7 @@ fun CIGroupInvitationView( }) else Modifier, shape = RoundedCornerShape(18.dp), color = if (sent) sentColor else receivedColor, + contentColor = LocalContentColor.current ) { Box( Modifier diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIRcvDecryptionError.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIRcvDecryptionError.kt index 318735d73e..318a8a6a05 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIRcvDecryptionError.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIRcvDecryptionError.kt @@ -142,6 +142,7 @@ fun DecryptionErrorItemFixButton( Modifier.clickable(onClick = onClick), shape = RoundedCornerShape(18.dp), color = receivedColor, + contentColor = LocalContentColor.current ) { Box( Modifier.padding(vertical = 6.dp, horizontal = 12.dp), @@ -188,6 +189,7 @@ fun DecryptionErrorItem( Modifier.clickable(onClick = onClick), shape = RoundedCornerShape(18.dp), color = receivedColor, + contentColor = LocalContentColor.current ) { Box( Modifier.padding(vertical = 6.dp, horizontal = 12.dp), diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIVIdeoView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIVIdeoView.kt index 04ec307358..42e90c35f1 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIVIdeoView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIVIdeoView.kt @@ -153,7 +153,8 @@ private fun BoxScope.PlayButton(error: Boolean = false, onLongClick: () -> Unit, Surface( Modifier.align(Alignment.Center), color = Color.Black.copy(alpha = 0.25f), - shape = RoundedCornerShape(percent = 50) + shape = RoundedCornerShape(percent = 50), + contentColor = LocalContentColor.current ) { Box( Modifier @@ -264,7 +265,8 @@ private fun progressCircle(progress: Long, total: Long) { Surface( Modifier.drawRingModifier(angle, strokeColor, strokeWidth), color = Color.Transparent, - shape = MaterialTheme.shapes.small.copy(CornerSize(percent = 50)) + shape = MaterialTheme.shapes.small.copy(CornerSize(percent = 50)), + contentColor = LocalContentColor.current ) { Box(Modifier.size(16.dp)) } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIVoiceView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIVoiceView.kt index 0c8487458f..8b01d9d1b5 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIVoiceView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIVoiceView.kt @@ -225,7 +225,8 @@ private fun PlayPauseButton( Surface( Modifier.drawRingModifier(angle, strokeColor, strokeWidth), color = if (sent) sentColor else receivedColor, - shape = MaterialTheme.shapes.small.copy(CornerSize(percent = 50)) + shape = MaterialTheme.shapes.small.copy(CornerSize(percent = 50)), + contentColor = LocalContentColor.current ) { Box( Modifier diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/ChatItemView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/ChatItemView.kt index daf887e8c3..38507237a3 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/ChatItemView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/ChatItemView.kt @@ -613,7 +613,7 @@ private fun ShrinkItemAction(revealed: MutableState, showMenu: MutableS @Composable fun ItemAction(text: String, icon: Painter, color: Color = Color.Unspecified, onClick: () -> Unit) { val finalColor = if (color == Color.Unspecified) { - if (isInDarkTheme()) MenuTextColorDark else Color.Black + MenuTextColor } else color DropdownMenuItem(onClick, contentPadding = PaddingValues(horizontal = DEFAULT_PADDING * 1.5f)) { Row(verticalAlignment = Alignment.CenterVertically) { @@ -633,7 +633,7 @@ fun ItemAction(text: String, icon: Painter, color: Color = Color.Unspecified, on @Composable fun ItemAction(text: String, icon: ImageVector, onClick: () -> Unit, color: Color = Color.Unspecified) { val finalColor = if (color == Color.Unspecified) { - if (isInDarkTheme()) MenuTextColorDark else Color.Black + MenuTextColor } else color DropdownMenuItem(onClick, contentPadding = PaddingValues(horizontal = DEFAULT_PADDING * 1.5f)) { Row(verticalAlignment = Alignment.CenterVertically) { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/DeletedItemView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/DeletedItemView.kt index 2d949e1737..7514b6e280 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/DeletedItemView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/DeletedItemView.kt @@ -23,6 +23,7 @@ fun DeletedItemView(ci: ChatItem, timedMessagesTTL: Int?) { Surface( shape = RoundedCornerShape(18.dp), color = if (sent) sentColor else receivedColor, + contentColor = LocalContentColor.current ) { Row( Modifier.padding(horizontal = 12.dp, vertical = 6.dp), diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/IntegrityErrorItemView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/IntegrityErrorItemView.kt index 582730b8f5..7be0cc2f6c 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/IntegrityErrorItemView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/IntegrityErrorItemView.kt @@ -56,6 +56,7 @@ fun CIMsgError(ci: ChatItem, timedMessagesTTL: Int?, onClick: () -> Unit) { Modifier.clickable(onClick = onClick), shape = RoundedCornerShape(18.dp), color = receivedColor, + contentColor = LocalContentColor.current ) { Row( Modifier.padding(horizontal = 12.dp, vertical = 6.dp), diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/MarkedDeletedItemView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/MarkedDeletedItemView.kt index 50d905ef76..f397954992 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/MarkedDeletedItemView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/MarkedDeletedItemView.kt @@ -26,6 +26,7 @@ fun MarkedDeletedItemView(ci: ChatItem, timedMessagesTTL: Int?, revealed: Mutabl Surface( shape = RoundedCornerShape(18.dp), color = if (ci.chatDir.sent) sentColor else receivedColor, + contentColor = LocalContentColor.current ) { Row( Modifier.padding(horizontal = 12.dp, vertical = 6.dp), 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 59c18c9703..0d8285f6f8 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 @@ -75,6 +75,8 @@ fun ChatListView(chatModel: ChatModel, settingsState: SettingsViewState, setPerf SettingsView(chatModel, setPerformLA, scaffoldState.drawerState) } }, + contentColor = LocalContentColor.current, + drawerContentColor = LocalContentColor.current, drawerScrimColor = MaterialTheme.colors.onSurface.copy(alpha = if (isInDarkTheme()) 0.16f else 0.32f), drawerGesturesEnabled = appPlatform.isAndroid, floatingActionButton = { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ShareListView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ShareListView.kt index ac8331007e..b1e87823c8 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ShareListView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ShareListView.kt @@ -30,6 +30,8 @@ fun ShareListView(chatModel: ChatModel, settingsState: SettingsViewState, stoppe val endPadding = if (appPlatform.isDesktop) 56.dp else 0.dp Scaffold( Modifier.padding(end = endPadding), + contentColor = LocalContentColor.current, + drawerContentColor = LocalContentColor.current, scaffoldState = scaffoldState, topBar = { Column { ShareListToolbar(chatModel, userPickerState, stopped) { searchInList = it.trim() } } }, ) { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/UserPicker.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/UserPicker.kt index a0db4188ad..0400a5e332 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/UserPicker.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/UserPicker.kt @@ -31,7 +31,6 @@ import chat.simplex.common.views.remote.* import chat.simplex.common.views.usersettings.doWithAuth import chat.simplex.res.MR import dev.icerock.moko.resources.compose.stringResource -import kotlinx.coroutines.delay import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import kotlin.math.roundToInt @@ -303,7 +302,7 @@ fun UserProfileRow(u: User) { u.displayName, modifier = Modifier .padding(start = 10.dp, end = 8.dp), - color = if (isInDarkTheme()) MenuTextColorDark else Color.Black, + color = MenuTextColor, fontWeight = if (u.activeUser) FontWeight.Medium else FontWeight.Normal ) } @@ -346,7 +345,7 @@ fun RemoteHostRow(h: RemoteHostInfo) { Text( h.hostDeviceName, modifier = Modifier.padding(start = 26.dp, end = 8.dp), - color = if (h.activeHost) MaterialTheme.colors.onBackground else if (isInDarkTheme()) MenuTextColorDark else Color.Black, + color = if (h.activeHost) MaterialTheme.colors.onBackground else MenuTextColor, fontSize = 14.sp, ) } @@ -387,7 +386,7 @@ fun LocalDeviceRow(active: Boolean) { Text( stringResource(MR.strings.this_device), modifier = Modifier.padding(start = 26.dp, end = 8.dp), - color = if (active) MaterialTheme.colors.onBackground else if (isInDarkTheme()) MenuTextColorDark else Color.Black, + color = if (active) MaterialTheme.colors.onBackground else MenuTextColor, fontSize = 14.sp, ) } @@ -399,7 +398,7 @@ private fun UseFromDesktopPickerItem(onClick: () -> Unit) { val text = generalGetString(MR.strings.settings_section_title_use_from_desktop).lowercase().capitalize(Locale.current) Icon(painterResource(MR.images.ic_desktop), text, Modifier.size(20.dp), tint = MaterialTheme.colors.onBackground) Spacer(Modifier.width(DEFAULT_PADDING + 6.dp)) - Text(text, color = if (isInDarkTheme()) MenuTextColorDark else Color.Black) + Text(text, color = MenuTextColor) } } @@ -409,7 +408,7 @@ private fun LinkAMobilePickerItem(onClick: () -> Unit) { val text = generalGetString(MR.strings.link_a_mobile) Icon(painterResource(MR.images.ic_smartphone_300), text, Modifier.size(20.dp), tint = MaterialTheme.colors.onBackground) Spacer(Modifier.width(DEFAULT_PADDING + 6.dp)) - Text(text, color = if (isInDarkTheme()) MenuTextColorDark else Color.Black) + Text(text, color = MenuTextColor) } } @@ -419,7 +418,7 @@ private fun CreateInitialProfile(onClick: () -> Unit) { val text = generalGetString(MR.strings.create_chat_profile) Icon(painterResource(MR.images.ic_manage_accounts), text, Modifier.size(20.dp), tint = MaterialTheme.colors.onBackground) Spacer(Modifier.width(DEFAULT_PADDING + 6.dp)) - Text(text, color = if (isInDarkTheme()) MenuTextColorDark else Color.Black) + Text(text, color = MenuTextColor) } } @@ -429,7 +428,7 @@ private fun SettingsPickerItem(onClick: () -> Unit) { val text = generalGetString(MR.strings.settings_section_title_settings).lowercase().capitalize(Locale.current) Icon(painterResource(MR.images.ic_settings), text, Modifier.size(20.dp), tint = MaterialTheme.colors.onBackground) Spacer(Modifier.width(DEFAULT_PADDING + 6.dp)) - Text(text, color = if (isInDarkTheme()) MenuTextColorDark else Color.Black) + Text(text, color = MenuTextColor) } } @@ -439,7 +438,7 @@ private fun CancelPickerItem(onClick: () -> Unit) { val text = generalGetString(MR.strings.cancel_verb) Icon(painterResource(MR.images.ic_close), text, Modifier.size(20.dp), tint = MaterialTheme.colors.onBackground) Spacer(Modifier.width(DEFAULT_PADDING + 6.dp)) - Text(text, color = if (isInDarkTheme()) MenuTextColorDark else Color.Black) + Text(text, color = MenuTextColor) } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/CustomTimePicker.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/CustomTimePicker.kt index fb1df940d9..f13edd618d 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/CustomTimePicker.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/CustomTimePicker.kt @@ -152,7 +152,8 @@ fun CustomTimePickerDialog( ) { DefaultDialog(onDismissRequest = cancel) { Surface( - shape = RoundedCornerShape(corner = CornerSize(25.dp)) + shape = RoundedCornerShape(corner = CornerSize(25.dp)), + contentColor = LocalContentColor.current ) { Box( contentAlignment = Alignment.Center diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ExposedDropDownSettingRow.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ExposedDropDownSettingRow.kt index 290bc2cd07..043aa5ec84 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ExposedDropDownSettingRow.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ExposedDropDownSettingRow.kt @@ -70,7 +70,7 @@ fun ExposedDropDownSetting( selectionOption.second + (if (label != null) " $label" else ""), maxLines = 1, overflow = TextOverflow.Ellipsis, - color = if (isInDarkTheme()) MenuTextColorDark else Color.Black, + color = MenuTextColor, fontSize = fontSize, ) } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/LocalAuthentication.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/LocalAuthentication.kt index 8e6c9fffc1..022ee37589 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/LocalAuthentication.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/LocalAuthentication.kt @@ -1,8 +1,7 @@ package chat.simplex.common.views.helpers import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.material.MaterialTheme -import androidx.compose.material.Surface +import androidx.compose.material.* import androidx.compose.ui.Modifier import chat.simplex.common.model.ChatController import chat.simplex.common.model.ChatModel @@ -50,7 +49,7 @@ fun authenticateWithPasscode( close() completed(LAResult.Error(generalGetString(MR.strings.authentication_cancelled))) } - Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background) { + Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background, contentColor = LocalContentColor.current) { LocalAuthView(ChatModel, LocalAuthRequest(promptTitle, promptSubtitle, password, selfDestruct && ChatController.appPrefs.selfDestruct.get()) { close() completed(it) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ModalView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ModalView.kt index 7e9cefa31c..2e7f401bfd 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ModalView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ModalView.kt @@ -26,7 +26,7 @@ fun ModalView( if (showClose) { BackHandler(onBack = close) } - Surface(Modifier.fillMaxSize()) { + Surface(Modifier.fillMaxSize(), contentColor = LocalContentColor.current) { Column(if (background != MaterialTheme.colors.background) Modifier.background(background) else Modifier.themedBackground()) { CloseSheetBar(close, showClose, endButtons) Box(modifier) { content() } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatSheet.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatSheet.kt index f2f2e9ec5f..26c5422623 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatSheet.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatSheet.kt @@ -175,7 +175,7 @@ fun ActionButton( disabled: Boolean = false, click: () -> Unit = {} ) { - Surface(shape = RoundedCornerShape(18.dp), color = Color.Transparent) { + Surface(shape = RoundedCornerShape(18.dp), color = Color.Transparent, contentColor = LocalContentColor.current) { Column( Modifier .clickable(onClick = click) @@ -220,7 +220,7 @@ fun ActionButton( disabled: Boolean = false, click: () -> Unit = {} ) { - Surface(modifier, shape = RoundedCornerShape(18.dp)) { + Surface(modifier, shape = RoundedCornerShape(18.dp), contentColor = LocalContentColor.current) { Column( Modifier .fillMaxWidth() diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/AdvancedNetworkSettings.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/AdvancedNetworkSettings.kt index 5fb8bfb03e..29a507c697 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/AdvancedNetworkSettings.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/AdvancedNetworkSettings.kt @@ -380,7 +380,8 @@ fun SettingsSectionFooter(revert: () -> Unit, save: () -> Unit, disabled: Boolea fun FooterButton(icon: Painter, title: String, action: () -> Unit, disabled: Boolean) { Surface( shape = RoundedCornerShape(20.dp), - color = Color.Black.copy(alpha = 0f) + color = Color.Black.copy(alpha = 0f), + contentColor = LocalContentColor.current ) { val modifier = if (disabled) Modifier else Modifier.clickable { action() } Row( diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/PrivacySettings.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/PrivacySettings.kt index 9a4f083746..82196a9b6c 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/PrivacySettings.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/PrivacySettings.kt @@ -383,7 +383,7 @@ fun SimplexLockView( } LAMode.PASSCODE -> { ModalManager.fullscreen.showCustomModal { close -> - Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background) { + Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background, contentColor = LocalContentColor.current) { SetAppPasscodeView( submit = { laLockDelay.set(30) @@ -427,7 +427,7 @@ fun SimplexLockView( when (laResult) { LAResult.Success -> { ModalManager.fullscreen.showCustomModal { close -> - Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background) { + Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background, contentColor = LocalContentColor.current) { SetAppPasscodeView( reason = generalGetString(MR.strings.la_app_passcode), submit = { @@ -451,7 +451,7 @@ fun SimplexLockView( when (laResult) { LAResult.Success -> { ModalManager.fullscreen.showCustomModal { close -> - Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background) { + Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background, contentColor = LocalContentColor.current) { SetAppPasscodeView( passcodeKeychain = ksSelfDestructPassword, reason = generalGetString(MR.strings.self_destruct), @@ -487,7 +487,7 @@ fun SimplexLockView( } LAMode.PASSCODE -> { ModalManager.fullscreen.showCustomModal { close -> - Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background) { + Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background, contentColor = LocalContentColor.current) { SetAppPasscodeView( submit = { laLockDelay.set(30) @@ -598,7 +598,7 @@ private fun EnableSelfDestruct( selfDestruct: SharedPreference, close: () -> Unit ) { - Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background) { + Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background, contentColor = LocalContentColor.current) { SetAppPasscodeView( passcodeKeychain = ksSelfDestructPassword, title = generalGetString(MR.strings.set_passcode), reason = generalGetString(MR.strings.enabled_self_destruct_passcode), submit = { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/RTCServers.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/RTCServers.kt index 7cb30440d3..50bed458cc 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/RTCServers.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/RTCServers.kt @@ -155,7 +155,8 @@ fun RTCServersLayout( .height(160.dp) .fillMaxWidth(), shape = RoundedCornerShape(10.dp), - border = BorderStroke(1.dp, MaterialTheme.colors.secondaryVariant) + border = BorderStroke(1.dp, MaterialTheme.colors.secondaryVariant), + contentColor = LocalContentColor.current ) { SelectionContainer( Modifier.verticalScroll(rememberScrollState()) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserAddressView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserAddressView.kt index 299be43223..98b8b26f47 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserAddressView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserAddressView.kt @@ -155,7 +155,7 @@ fun UserAddressView( contentAlignment = Alignment.Center ) { if (userAddress.value != null) { - Surface(Modifier.size(50.dp), color = MaterialTheme.colors.background.copy(0.9f), shape = RoundedCornerShape(50)){} + Surface(Modifier.size(50.dp), color = MaterialTheme.colors.background.copy(0.9f), contentColor = LocalContentColor.current, shape = RoundedCornerShape(50)){} } CircularProgressIndicator( Modifier diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/PlatformTextField.desktop.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/PlatformTextField.desktop.kt index 8016b18b12..3ca74a6d84 100644 --- a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/PlatformTextField.desktop.kt +++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/PlatformTextField.desktop.kt @@ -167,7 +167,8 @@ actual fun PlatformTextField( decorationBox = { innerTextField -> Surface( shape = RoundedCornerShape(18.dp), - border = BorderStroke(1.dp, MaterialTheme.colors.secondary) + border = BorderStroke(1.dp, MaterialTheme.colors.secondary), + contentColor = LocalContentColor.current ) { Row( Modifier.background(MaterialTheme.colors.background), diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/helpers/DefaultDialog.desktop.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/helpers/DefaultDialog.desktop.kt index 79fcda7a50..7341c6af23 100644 --- a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/helpers/DefaultDialog.desktop.kt +++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/helpers/DefaultDialog.desktop.kt @@ -2,8 +2,7 @@ package chat.simplex.common.views.helpers import androidx.compose.foundation.* import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.MaterialTheme -import androidx.compose.material.Surface +import androidx.compose.material.* import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.input.key.* @@ -39,7 +38,8 @@ actual fun DefaultDialog( ) { Surface( Modifier - .border(border = BorderStroke(1.dp, MaterialTheme.colors.secondary.copy(alpha = 0.3F)), shape = RoundedCornerShape(8)) + .border(border = BorderStroke(1.dp, MaterialTheme.colors.secondary.copy(alpha = 0.3F)), shape = RoundedCornerShape(8)), + contentColor = LocalContentColor.current ) { content() } From 3428f4d2eed52e3a9ec338e76311798d3a2c58f6 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Fri, 5 Jan 2024 18:51:18 +0000 Subject: [PATCH 027/102] core: update simplexmq (critical errors, worker restarts, subscription timeouts) --- cabal.project | 2 +- scripts/nix/sha256map.nix | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cabal.project b/cabal.project index b3ecbe6b51..61442845b3 100644 --- a/cabal.project +++ b/cabal.project @@ -12,7 +12,7 @@ constraints: zip +disable-bzip2 +disable-zstd source-repository-package type: git location: https://github.com/simplex-chat/simplexmq.git - tag: 6d4834f306963e2d3f2f62af212fe855ea9c7595 + tag: fa794d7878c82c370f1547f01e76f9691d229b92 source-repository-package type: git diff --git a/scripts/nix/sha256map.nix b/scripts/nix/sha256map.nix index 233918be45..4539ae45c9 100644 --- a/scripts/nix/sha256map.nix +++ b/scripts/nix/sha256map.nix @@ -1,5 +1,5 @@ { - "https://github.com/simplex-chat/simplexmq.git"."6d4834f306963e2d3f2f62af212fe855ea9c7595" = "1603nlzkncrl8kg9xb8yi4kjbk8d8gmyw7wzvlni7lgbf0hjrffz"; + "https://github.com/simplex-chat/simplexmq.git"."fa794d7878c82c370f1547f01e76f9691d229b92" = "0fmgq7yy42rlpf4a0agz3149iqkw5cri85xppwgicl4i9c7bs9gi"; "https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38"; "https://github.com/simplex-chat/direct-sqlcipher.git"."f814ee68b16a9447fbb467ccc8f29bdd3546bfd9" = "1ql13f4kfwkbaq7nygkxgw84213i0zm7c1a8hwvramayxl38dq5d"; "https://github.com/simplex-chat/sqlcipher-simple.git"."a46bd361a19376c5211f1058908fc0ae6bf42446" = "1z0r78d8f0812kxbgsm735qf6xx8lvaz27k1a0b4a2m0sshpd5gl"; From 61c507e7da02d604691523b353b025766a65c325 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Sat, 6 Jan 2024 11:32:26 +0000 Subject: [PATCH 028/102] core: replace deprecated memcpy (#3652) --- src/Simplex/Chat/Mobile/Shared.hs | 4 ++-- tests/MobileTests.hs | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Simplex/Chat/Mobile/Shared.hs b/src/Simplex/Chat/Mobile/Shared.hs index 5f13f58c72..fcde581ea3 100644 --- a/src/Simplex/Chat/Mobile/Shared.hs +++ b/src/Simplex/Chat/Mobile/Shared.hs @@ -3,7 +3,7 @@ module Simplex.Chat.Mobile.Shared where import qualified Data.ByteString as B -import Data.ByteString.Internal (ByteString (..), memcpy) +import Data.ByteString.Internal (ByteString (..)) import qualified Data.ByteString.Lazy as LB import qualified Data.ByteString.Lazy.Internal as LB import Foreign @@ -21,7 +21,7 @@ getByteString ptr len = do putByteString :: Ptr Word8 -> ByteString -> IO () putByteString ptr (PS fp offset len) = - withForeignPtr fp $ \p -> memcpy ptr (p `plusPtr` offset) len + withForeignPtr fp $ \p -> copyBytes ptr (p `plusPtr` offset) len {-# INLINE putByteString #-} putLazyByteString :: Ptr Word8 -> LB.ByteString -> IO () diff --git a/tests/MobileTests.hs b/tests/MobileTests.hs index a6231fa27e..27e1d6f8b7 100644 --- a/tests/MobileTests.hs +++ b/tests/MobileTests.hs @@ -16,11 +16,12 @@ import qualified Data.Aeson.TH as JQ import Data.ByteString (ByteString) import qualified Data.ByteString as B import qualified Data.ByteString.Char8 as BS -import Data.ByteString.Internal (create, memcpy) +import Data.ByteString.Internal (create) import qualified Data.ByteString.Lazy.Char8 as LB import Data.Word (Word8, Word32) import Foreign.C import Foreign.Marshal.Alloc (mallocBytes) +import Foreign.Marshal.Utils (copyBytes) import Foreign.Ptr import Foreign.StablePtr import Foreign.Storable (peek) @@ -291,7 +292,7 @@ testFileCApi fileName tmp = do peek ptr' `shouldReturn` (0 :: Word8) sz :: Word32 <- peek (ptr' `plusPtr` 1) let sz' = fromIntegral sz - contents <- create sz' $ \toPtr -> memcpy toPtr (ptr' `plusPtr` 5) sz' + contents <- create sz' $ \toPtr -> copyBytes toPtr (ptr' `plusPtr` 5) sz' contents `shouldBe` src sz' `shouldBe` fromIntegral len From a853ba3a156bdbe5e41f2c46d4faf4cdafde3de5 Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Tue, 9 Jan 2024 16:59:21 +0700 Subject: [PATCH 029/102] android, desktop: adapted code for self destruct for ios logic (#3643) * android, desktop: adapted code for self destruct for ios logic * init db in case of periodic && self destruct enabled --- .../chat/simplex/app/MessagesFetcherWorker.kt | 9 +++++++-- .../main/java/chat/simplex/app/SimplexApp.kt | 9 ++++++--- .../java/chat/simplex/app/SimplexService.kt | 4 ++++ .../kotlin/chat/simplex/common/platform/Core.kt | 17 ++++++++--------- .../common/views/database/DatabaseView.kt | 5 +++-- .../common/views/helpers/DatabaseUtils.kt | 2 +- .../common/views/localauth/LocalAuthView.kt | 6 +++--- .../views/localauth/SetAppPasscodeView.kt | 3 ++- .../views/usersettings/PrivacySettings.kt | 3 ++- .../common/platform/AppCommon.desktop.kt | 4 +++- 10 files changed, 39 insertions(+), 23 deletions(-) diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/MessagesFetcherWorker.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/MessagesFetcherWorker.kt index 3b8902b58c..0152f5e8c2 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/MessagesFetcherWorker.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/MessagesFetcherWorker.kt @@ -3,11 +3,12 @@ package chat.simplex.app import android.content.Context import android.util.Log import androidx.work.* -import chat.simplex.app.* import chat.simplex.app.SimplexService.Companion.showPassphraseNotification import chat.simplex.common.model.ChatController import chat.simplex.common.views.helpers.DBMigrationResult -import chat.simplex.app.BuildConfig +import chat.simplex.common.platform.chatModel +import chat.simplex.common.platform.initChatControllerAndRunMigrations +import chat.simplex.common.views.helpers.DatabaseUtils import kotlinx.coroutines.* import java.util.Date import java.util.concurrent.TimeUnit @@ -57,6 +58,10 @@ class MessagesFetcherWork( val durationSeconds = inputData.getInt(INPUT_DATA_DURATION, 60) var shouldReschedule = true try { + // In case of self-destruct is enabled the initialization process will not start in SimplexApp, Let's start it here + if (DatabaseUtils.ksSelfDestructPassword.get() != null && chatModel.chatDbStatus.value == null) { + initChatControllerAndRunMigrations() + } withTimeout(durationSeconds * 1000L) { val chatController = ChatController SimplexService.waitDbMigrationEnds(chatController) diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/SimplexApp.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/SimplexApp.kt index 84b39e983f..6273263f48 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/SimplexApp.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/SimplexApp.kt @@ -26,6 +26,7 @@ import kotlinx.coroutines.sync.withLock import java.io.* import java.util.* import java.util.concurrent.TimeUnit +import kotlin.system.exitProcess const val TAG = "SIMPLEX" @@ -46,8 +47,8 @@ class SimplexApp: Application(), LifecycleEventObserver { try { Looper.loop() } catch (e: Throwable) { - if (e.message != null && e.message!!.startsWith("Unable to start activity")) { - android.os.Process.killProcess(android.os.Process.myPid()) + if (e is UnsatisfiedLinkError || e.message?.startsWith("Unable to start activity") == true) { + Process.killProcess(Process.myPid()) break } else { // Send it to our exception handled because it will not get the exception otherwise @@ -63,7 +64,9 @@ class SimplexApp: Application(), LifecycleEventObserver { tmpDir.deleteRecursively() tmpDir.mkdir() - initChatControllerAndRunMigrations(false) + if (DatabaseUtils.ksSelfDestructPassword.get() == null) { + initChatControllerAndRunMigrations() + } ProcessLifecycleOwner.get().lifecycle.addObserver(this@SimplexApp) } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/SimplexService.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/SimplexService.kt index d1e0d9721e..8dfe04b3dc 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/SimplexService.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/SimplexService.kt @@ -72,6 +72,10 @@ class SimplexService: Service() { stopSelf() } else { isServiceStarted = true + // In case of self-destruct is enabled the initialization process will not start in SimplexApp, Let's start it here + if (DatabaseUtils.ksSelfDestructPassword.get() != null && chatModel.chatDbStatus.value == null) { + initChatControllerAndRunMigrations() + } } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Core.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Core.kt index 00a8244380..8ed662ae67 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Core.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Core.kt @@ -41,21 +41,20 @@ val appPreferences: AppPreferences val chatController: ChatController = ChatController -fun initChatControllerAndRunMigrations(ignoreSelfDestruct: Boolean) { - if (ignoreSelfDestruct || DatabaseUtils.ksSelfDestructPassword.get() == null) { - withBGApi { - if (appPreferences.chatStopped.get() && appPreferences.storeDBPassphrase.get() && ksDatabasePassword.get() != null) { - initChatController(startChat = ::showStartChatAfterRestartAlert) - } else { - initChatController() - } - runMigrations() +fun initChatControllerAndRunMigrations() { + withBGApi { + if (appPreferences.chatStopped.get() && appPreferences.storeDBPassphrase.get() && ksDatabasePassword.get() != null) { + initChatController(startChat = ::showStartChatAfterRestartAlert) + } else { + initChatController() } + runMigrations() } } suspend fun initChatController(useKey: String? = null, confirmMigrations: MigrationConfirmation? = null, startChat: () -> CompletableDeferred = { CompletableDeferred(true) }) { try { + if (chatModel.ctrlInitInProgress.value) return chatModel.ctrlInitInProgress.value = true val dbKey = useKey ?: DatabaseUtils.useDatabaseKey() val confirm = confirmMigrations ?: if (appPreferences.confirmDBUpgrades.get()) MigrationConfirmation.Error else MigrationConfirmation.YesUp diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseView.kt index 3769e0fc95..cc1953afce 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseView.kt @@ -460,10 +460,10 @@ suspend fun deleteChatAsync(m: ChatModel) { m.controller.apiDeleteStorage() DatabaseUtils.ksDatabasePassword.remove() m.controller.appPrefs.storeDBPassphrase.set(true) - deleteChatDatabaseFiles() + deleteAppDatabaseAndFiles() } -fun deleteChatDatabaseFiles() { +fun deleteAppDatabaseAndFiles() { val chat = File(dataDir, chatDatabaseFileName) val chatBak = File(dataDir, "$chatDatabaseFileName.bak") val agent = File(dataDir, agentDatabaseFileName) @@ -473,6 +473,7 @@ fun deleteChatDatabaseFiles() { agent.delete() agentBak.delete() filesDir.deleteRecursively() + filesDir.mkdir() remoteHostsDir.deleteRecursively() tmpDir.deleteRecursively() tmpDir.mkdir() diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DatabaseUtils.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DatabaseUtils.kt index cc06716dab..3ab74a6ad8 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DatabaseUtils.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DatabaseUtils.kt @@ -17,7 +17,7 @@ object DatabaseUtils { val ksAppPassword = KeyStoreItem(APP_PASSWORD_ALIAS, appPreferences.encryptedAppPassphrase, appPreferences.initializationVectorAppPassphrase) val ksSelfDestructPassword = KeyStoreItem(SELF_DESTRUCT_PASSWORD_ALIAS, appPreferences.encryptedSelfDestructPassphrase, appPreferences.initializationVectorSelfDestructPassphrase) - class KeyStoreItem(val alias: String, val passphrase: SharedPreference, val initVector: SharedPreference) { + class KeyStoreItem(private val alias: String, val passphrase: SharedPreference, val initVector: SharedPreference) { fun get(): String? { return cryptor.decryptData( passphrase.get()?.toByteArrayFromBase64ForPassphrase() ?: return null, diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/localauth/LocalAuthView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/localauth/LocalAuthView.kt index b758ecdcff..16d8a34b19 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/localauth/LocalAuthView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/localauth/LocalAuthView.kt @@ -34,7 +34,7 @@ fun LocalAuthView(m: ChatModel, authRequest: LocalAuthRequest) { } else { val r: LAResult = if (passcode.value == authRequest.password) { if (authRequest.selfDestruct && sdPassword != null && controller.ctrl == -1L) { - initChatControllerAndRunMigrations(true) + initChatControllerAndRunMigrations() } LAResult.Success } else { @@ -67,8 +67,8 @@ private fun deleteStorageAndRestart(m: ChatModel, password: String, completed: ( * */ chatCloseStore(ctrl) } - deleteChatDatabaseFiles() - // Clear sensitive data on screen just in case ModalManager will fail to prevent hiding its modals while database encrypts itself + deleteAppDatabaseAndFiles() + // Clear sensitive data on screen just in case ModalManager fails to hide its modals while new database is created m.chatId.value = null m.chatItems.clear() m.chats.clear() diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/localauth/SetAppPasscodeView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/localauth/SetAppPasscodeView.kt index eadd399428..1d620c915f 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/localauth/SetAppPasscodeView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/localauth/SetAppPasscodeView.kt @@ -12,6 +12,7 @@ import chat.simplex.res.MR @Composable fun SetAppPasscodeView( passcodeKeychain: DatabaseUtils.KeyStoreItem = ksAppPassword, + prohibitedPasscodeKeychain: DatabaseUtils.KeyStoreItem = ksSelfDestructPassword, title: String = generalGetString(MR.strings.new_passcode), reason: String? = null, submit: () -> Unit, @@ -51,7 +52,7 @@ fun SetAppPasscodeView( } else { SetPasswordView(title, generalGetString(MR.strings.save_verb), // Do not allow to set app passcode == selfDestruct passcode - submitEnabled = { pwd -> pwd != (if (passcodeKeychain.alias == ksSelfDestructPassword.alias) ksAppPassword else ksSelfDestructPassword).get() }) { + submitEnabled = { pwd -> pwd != prohibitedPasscodeKeychain.get() }) { enteredPassword = passcode.value passcode.value = "" confirming = true diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/PrivacySettings.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/PrivacySettings.kt index 82196a9b6c..f163a54649 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/PrivacySettings.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/PrivacySettings.kt @@ -454,6 +454,7 @@ fun SimplexLockView( Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background, contentColor = LocalContentColor.current) { SetAppPasscodeView( passcodeKeychain = ksSelfDestructPassword, + prohibitedPasscodeKeychain = ksAppPassword, reason = generalGetString(MR.strings.self_destruct), submit = { selfDestructPasscodeAlert(generalGetString(MR.strings.self_destruct_passcode_changed)) @@ -600,7 +601,7 @@ private fun EnableSelfDestruct( ) { Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background, contentColor = LocalContentColor.current) { SetAppPasscodeView( - passcodeKeychain = ksSelfDestructPassword, title = generalGetString(MR.strings.set_passcode), reason = generalGetString(MR.strings.enabled_self_destruct_passcode), + passcodeKeychain = ksSelfDestructPassword, prohibitedPasscodeKeychain = ksAppPassword, title = generalGetString(MR.strings.set_passcode), reason = generalGetString(MR.strings.enabled_self_destruct_passcode), submit = { selfDestruct.set(true) selfDestructPasscodeAlert(generalGetString(MR.strings.self_destruct_passcode_enabled)) diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/AppCommon.desktop.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/AppCommon.desktop.kt index 4e70956be7..9cf1943987 100644 --- a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/AppCommon.desktop.kt +++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/AppCommon.desktop.kt @@ -24,7 +24,9 @@ fun initApp() { override fun cancelAllNotifications() = chat.simplex.common.model.NtfManager.cancelAllNotifications() } applyAppLocale() - initChatControllerAndRunMigrations(false) + if (DatabaseUtils.ksSelfDestructPassword.get() == null) { + initChatControllerAndRunMigrations() + } // LALAL //testCrypto() } From 7a207fd64177f022ab588cc31f1e829d0c6a1c44 Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Tue, 9 Jan 2024 21:21:29 +0700 Subject: [PATCH 030/102] android, desktop: alerts when device was disconnected (#3483) --- .../chat/simplex/common/model/SimpleXAPI.kt | 71 ++++++++++++++++++- .../commonMain/resources/MR/base/strings.xml | 18 +++++ 2 files changed, 86 insertions(+), 3 deletions(-) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt index df23906b0f..700bdc4a59 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt @@ -1880,9 +1880,34 @@ object ChatController { val disconnectedHost = chatModel.remoteHosts.firstOrNull { it.remoteHostId == r.remoteHostId_ } chatModel.remoteHostPairing.value = null if (disconnectedHost != null) { - showToast( - generalGetString(MR.strings.remote_host_was_disconnected_toast).format(disconnectedHost.hostDeviceName.ifEmpty { disconnectedHost.remoteHostId.toString() }) - ) + val deviceName = disconnectedHost.hostDeviceName.ifEmpty { disconnectedHost.remoteHostId.toString() } + when (r.rhStopReason) { + is RemoteHostStopReason.ConnectionFailed -> { + AlertManager.shared.showAlertMsg( + generalGetString(MR.strings.remote_host_was_disconnected_title), + if (r.rhStopReason.chatError is ChatError.ChatErrorRemoteHost) { + r.rhStopReason.chatError.remoteHostError.localizedString(deviceName) + } else { + generalGetString(MR.strings.remote_host_disconnected_from).format(deviceName, r.rhStopReason.chatError.string) + } + ) + } + is RemoteHostStopReason.Crashed -> { + AlertManager.shared.showAlertMsg( + generalGetString(MR.strings.remote_host_was_disconnected_title), + if (r.rhStopReason.chatError is ChatError.ChatErrorRemoteHost) { + r.rhStopReason.chatError.remoteHostError.localizedString(deviceName) + } else { + generalGetString(MR.strings.remote_host_disconnected_from).format(deviceName, r.rhStopReason.chatError.string) + } + ) + } + is RemoteHostStopReason.Disconnected -> { + if (r.rhsState is RemoteHostSessionState.Connected || r.rhsState is RemoteHostSessionState.Confirmed) { + showToast(generalGetString(MR.strings.remote_host_was_disconnected_toast).format(deviceName)) + } + } + } } if (chatModel.remoteHostId() == r.remoteHostId_) { chatModel.currentRemoteHost.value = null @@ -1913,6 +1938,27 @@ object ChatController { val sess = chatModel.remoteCtrlSession.value if (sess != null) { chatModel.remoteCtrlSession.value = null + fun showAlert(chatError: ChatError) { + AlertManager.shared.showAlertMsg( + generalGetString(MR.strings.remote_ctrl_was_disconnected_title), + if (chatError is ChatError.ChatErrorRemoteCtrl) { + chatError.remoteCtrlError.localizedString + } else { + generalGetString(MR.strings.remote_ctrl_disconnected_with_reason).format(chatError.string) + } + ) + } + when (r.rcStopReason) { + is RemoteCtrlStopReason.DiscoveryFailed -> showAlert(r.rcStopReason.chatError) + is RemoteCtrlStopReason.ConnectionFailed -> showAlert(r.rcStopReason.chatError) + is RemoteCtrlStopReason.SetupFailed -> showAlert(r.rcStopReason.chatError) + is RemoteCtrlStopReason.Disconnected -> { + /*AlertManager.shared.showAlertMsg( + generalGetString(MR.strings.remote_ctrl_was_disconnected_title), + )*/ + } + } + if (sess.sessionState is UIRemoteCtrlSessionState.Connected) { switchToLocalSession() } @@ -4973,6 +5019,15 @@ sealed class RemoteHostError { is BadVersion -> "badVersion" is Disconnected -> "disconnected" } + fun localizedString(name: String): String = when (this) { + is Missing -> generalGetString(MR.strings.remote_host_error_missing) + is Inactive -> generalGetString(MR.strings.remote_host_error_inactive) + is Busy -> generalGetString(MR.strings.remote_host_error_busy) + is Timeout -> generalGetString(MR.strings.remote_host_error_timeout) + is BadState -> generalGetString(MR.strings.remote_host_error_bad_state) + is BadVersion -> generalGetString(MR.strings.remote_host_error_bad_version) + is Disconnected -> generalGetString(MR.strings.remote_host_error_disconnected) + }.format(name) @Serializable @SerialName("missing") object Missing: RemoteHostError() @Serializable @SerialName("inactive") object Inactive: RemoteHostError() @Serializable @SerialName("busy") object Busy: RemoteHostError() @@ -4993,6 +5048,16 @@ sealed class RemoteCtrlError { is BadInvitation -> "badInvitation" is BadVersion -> "badVersion" } + val localizedString: String get() = when (this) { + is Inactive -> generalGetString(MR.strings.remote_ctrl_error_inactive) + is BadState -> generalGetString(MR.strings.remote_ctrl_error_bad_state) + is Busy -> generalGetString(MR.strings.remote_ctrl_error_busy) + is Timeout -> generalGetString(MR.strings.remote_ctrl_error_timeout) + is Disconnected -> generalGetString(MR.strings.remote_ctrl_error_disconnected) + is BadInvitation -> generalGetString(MR.strings.remote_ctrl_error_bad_invitation) + is BadVersion -> generalGetString(MR.strings.remote_ctrl_error_bad_version) + } + @Serializable @SerialName("inactive") object Inactive: RemoteCtrlError() @Serializable @SerialName("badState") object BadState: RemoteCtrlError() @Serializable @SerialName("busy") object Busy: RemoteCtrlError() diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml index 2e6928c600..45c8bfe48e 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml @@ -1694,6 +1694,10 @@ Disconnect Disconnect mobiles %s was disconnected]]> + Connection stopped + Connection stopped + %s with the reason: %s]]> + Disconnected with the reason: %s Disconnect desktop? Only one device can work at the same time Use from desktop in mobile app and scan QR code.]]> @@ -1728,6 +1732,20 @@ Random Open port in firewall To allow a mobile app to connect to the desktop, open this port in your firewall, if you have it enabled + %s is missing]]> + %s is inactive]]> + %s is busy]]> + %s]]> + %s is in a bad state]]> + %s has an unsupported version. Please, make sure you use the same version on both devices]]> + %s was disconnected]]> + Desktop is inactive + Connection to the desktop is in a bad state + Desktop is busy + Timeout reached while connecting to the desktop + Desktop was disconnected + Desktop has wrong invitation code + Desktop has an unsupported version. Please, make sure you use the same version on both devices Coming soon! From a55a8b116a2630985dc51edd23716ab8d2b0c537 Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Wed, 10 Jan 2024 00:23:20 +0700 Subject: [PATCH 031/102] script: changes in script for downloading libs (#3663) * script: changes in script for downloading libs * ios script --- scripts/android/download-libs.sh | 4 ++-- scripts/ios/download-libs.sh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/android/download-libs.sh b/scripts/android/download-libs.sh index 4702f03600..21699fbe95 100755 --- a/scripts/android/download-libs.sh +++ b/scripts/android/download-libs.sh @@ -37,12 +37,12 @@ for ((i = 0 ; i < ${#arches[@]}; i++)); do mkdir -p "$output_dir" 2> /dev/null - curl --location -o libsupport.zip $job_repo/$arch-android:lib:support.x86_64-linux/latest/download/1 && \ + curl --location -o libsupport.zip $job_repo/x86_64-linux."$arch"-android:lib:support/latest/download/1 && \ unzip -o libsupport.zip && \ mv libsupport.so "$output_dir" && \ rm libsupport.zip - curl --location -o libsimplex.zip "$job_repo"/"$arch"-android:lib:simplex-chat.x86_64-linux/latest/download/1 && \ + curl --location -o libsimplex.zip "$job_repo"/x86_64-linux."$arch"-android:lib:simplex-chat/latest/download/1 && \ unzip -o libsimplex.zip && \ mv libsimplex.so "$output_dir" && \ rm libsimplex.zip diff --git a/scripts/ios/download-libs.sh b/scripts/ios/download-libs.sh index 9d7e388870..d757e495c6 100755 --- a/scripts/ios/download-libs.sh +++ b/scripts/ios/download-libs.sh @@ -35,7 +35,7 @@ for ((i = 0 ; i < ${#arches[@]}; i++)); do output_arch="${output_arches[$i]}" output_dir="$HOME/Downloads" - curl --location -o "$output_dir"/pkg-ios-"$arch"-swift-json.zip "$job_repo"/"$arch"-darwin-ios:lib:simplex-chat."$arch"-darwin/latest/download/1 && \ + curl --location -o "$output_dir"/pkg-ios-"$arch"-swift-json.zip "$job_repo"/"$arch"-darwin."$arch"-darwin-ios:lib:simplex-chat/latest/download/1 && \ unzip -o "$output_dir"/pkg-ios-"$output_arch"-swift-json.zip -d ~/Downloads/pkg-ios-"$output_arch"-swift-json done -sh "$root_dir"/scripts/ios/prepare-x86_64.sh +sh "$root_dir"/scripts/ios/prepare-x86_64.sh \ No newline at end of file From 0bf3d054c6e142a89ea6461a6a284f302219aba4 Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Wed, 10 Jan 2024 02:26:47 +0700 Subject: [PATCH 032/102] mobile, desktop: invalid display name alert (#3664) * ios: invalid display name alert * android, desktop: invalid display name --------- Co-authored-by: Avently --- .../Shared/Views/Onboarding/CreateProfile.swift | 16 ++++++++++++++++ apps/ios/SimpleXChat/APITypes.swift | 1 + .../chat/simplex/common/model/SimpleXAPI.kt | 6 ++++++ .../src/commonMain/resources/MR/base/strings.xml | 2 ++ 4 files changed, 25 insertions(+) diff --git a/apps/ios/Shared/Views/Onboarding/CreateProfile.swift b/apps/ios/Shared/Views/Onboarding/CreateProfile.swift index f5db37dacf..3f835e25d4 100644 --- a/apps/ios/Shared/Views/Onboarding/CreateProfile.swift +++ b/apps/ios/Shared/Views/Onboarding/CreateProfile.swift @@ -11,12 +11,14 @@ import SimpleXChat enum UserProfileAlert: Identifiable { case duplicateUserError + case invalidDisplayNameError case createUserError(error: LocalizedStringKey) case invalidNameError(validName: String) var id: String { switch self { case .duplicateUserError: return "duplicateUserError" + case .invalidDisplayNameError: return "invalidDisplayNameError" case .createUserError: return "createUserError" case let .invalidNameError(validName): return "invalidNameError \(validName)" } @@ -187,6 +189,12 @@ private func createProfile(_ displayName: String, showAlert: (UserProfileAlert) } else { showAlert(.duplicateUserError) } + case .chatCmdError(_, .error(.invalidDisplayName)): + if m.currentUser == nil { + AlertManager.shared.showAlert(invalidDisplayNameAlert) + } else { + showAlert(.invalidDisplayNameError) + } default: let err: LocalizedStringKey = "Error: \(responseError(error))" if m.currentUser == nil { @@ -207,6 +215,7 @@ private func canCreateProfile(_ displayName: String) -> Bool { func userProfileAlert(_ alert: UserProfileAlert, _ displayName: Binding) -> Alert { switch alert { case .duplicateUserError: return duplicateUserAlert + case .invalidDisplayNameError: return invalidDisplayNameAlert case let .createUserError(err): return creatUserErrorAlert(err) case let .invalidNameError(name): return createInvalidNameAlert(name, displayName) } @@ -219,6 +228,13 @@ private var duplicateUserAlert: Alert { ) } +private var invalidDisplayNameAlert: Alert { + Alert( + title: Text("Invalid display name!"), + message: Text("This display name is invalid. Please choose another name.") + ) +} + private func creatUserErrorAlert(_ err: LocalizedStringKey) -> Alert { Alert( title: Text("Error creating profile!"), diff --git a/apps/ios/SimpleXChat/APITypes.swift b/apps/ios/SimpleXChat/APITypes.swift index 411a1ab9cf..1a8f935f2b 100644 --- a/apps/ios/SimpleXChat/APITypes.swift +++ b/apps/ios/SimpleXChat/APITypes.swift @@ -1610,6 +1610,7 @@ public enum ChatErrorType: Decodable { case userUnknown case activeUserExists case userExists + case invalidDisplayName case differentActiveUser(commandUserId: Int64, activeUserId: Int64) case cantDeleteActiveUser(userId: Int64) case cantDeleteLastUser(userId: Int64) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt index 700bdc4a59..60157f014e 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt @@ -506,6 +506,10 @@ object ChatController { r is CR.ChatCmdError && r.chatError is ChatError.ChatErrorChat && r.chatError.errorType is ChatErrorType.UserExists ) { AlertManager.shared.showAlertMsg(generalGetString(MR.strings.failed_to_create_user_duplicate_title), generalGetString(MR.strings.failed_to_create_user_duplicate_desc)) + } else if ( + r is CR.ChatCmdError && r.chatError is ChatError.ChatErrorChat && r.chatError.errorType is ChatErrorType.InvalidDisplayName + ) { + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.failed_to_create_user_invalid_title), generalGetString(MR.strings.failed_to_create_user_invalid_desc)) } else { AlertManager.shared.showAlertMsg(generalGetString(MR.strings.failed_to_create_user_title), r.details) } @@ -4493,6 +4497,7 @@ sealed class ChatErrorType { is EmptyUserPassword -> "emptyUserPassword" is UserAlreadyHidden -> "userAlreadyHidden" is UserNotHidden -> "userNotHidden" + is InvalidDisplayName -> "invalidDisplayName" is ChatNotStarted -> "chatNotStarted" is ChatNotStopped -> "chatNotStopped" is ChatStoreChanged -> "chatStoreChanged" @@ -4570,6 +4575,7 @@ sealed class ChatErrorType { @Serializable @SerialName("emptyUserPassword") class EmptyUserPassword(val userId: Long): ChatErrorType() @Serializable @SerialName("userAlreadyHidden") class UserAlreadyHidden(val userId: Long): ChatErrorType() @Serializable @SerialName("userNotHidden") class UserNotHidden(val userId: Long): ChatErrorType() + @Serializable @SerialName("invalidDisplayName") object InvalidDisplayName: ChatErrorType() @Serializable @SerialName("chatNotStarted") object ChatNotStarted: ChatErrorType() @Serializable @SerialName("chatNotStopped") object ChatNotStopped: ChatErrorType() @Serializable @SerialName("chatStoreChanged") object ChatStoreChanged: ChatErrorType() diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml index 45c8bfe48e..e3870c66ab 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml @@ -90,6 +90,8 @@ Error creating profile! Duplicate display name! You already have a chat profile with the same display name. Please choose another name. + Invalid display name! + This display name is invalid. Please choose another name. Error switching profile! From a30da38af740e85b549ab0a3e1f5c695f22f016a Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Wed, 10 Jan 2024 02:31:01 +0700 Subject: [PATCH 033/102] android, desktop: accept calls after restart (#3662) --- .../kotlin/chat/simplex/common/model/SimpleXAPI.kt | 13 +++++++++++++ .../chat/simplex/common/views/chat/ChatView.kt | 14 +++++++++----- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt index 60157f014e..110f12273f 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt @@ -1128,6 +1128,13 @@ object ChatController { return false } + suspend fun apiGetCallInvitations(rh: Long?): List { + val r = sendCmd(rh, CC.ApiGetCallInvitations()) + if (r is CR.CallInvitations) return r.callInvitations + Log.e(TAG, "apiGetCallInvitations bad response: ${r.responseType} ${r.details}") + return emptyList() + } + suspend fun apiSendCallInvitation(rh: Long?, contact: Contact, callType: CallType): Boolean { val r = sendCmd(rh, CC.ApiSendCallInvitation(contact, callType)) return r is CR.CmdOk @@ -2296,6 +2303,7 @@ sealed class CC { class ApiShowMyAddress(val userId: Long): CC() class ApiSetProfileAddress(val userId: Long, val on: Boolean): CC() class ApiAddressAutoAccept(val userId: Long, val autoAccept: AutoAccept?): CC() + class ApiGetCallInvitations: CC() class ApiSendCallInvitation(val contact: Contact, val callType: CallType): CC() class ApiRejectCall(val contact: Contact): CC() class ApiSendCallOffer(val contact: Contact, val callOffer: WebRTCCallOffer): CC() @@ -2432,6 +2440,7 @@ sealed class CC { is ApiAddressAutoAccept -> "/_auto_accept $userId ${AutoAccept.cmdString(autoAccept)}" is ApiAcceptContact -> "/_accept incognito=${onOff(incognito)} $contactReqId" is ApiRejectContact -> "/_reject $contactReqId" + is ApiGetCallInvitations -> "/_call get" is ApiSendCallInvitation -> "/_call invite @${contact.apiId} ${json.encodeToString(callType)}" is ApiRejectCall -> "/_call reject @${contact.apiId}" is ApiSendCallOffer -> "/_call offer @${contact.apiId} ${json.encodeToString(callOffer)}" @@ -2555,6 +2564,7 @@ sealed class CC { is ApiAddressAutoAccept -> "apiAddressAutoAccept" is ApiAcceptContact -> "apiAcceptContact" is ApiRejectContact -> "apiRejectContact" + is ApiGetCallInvitations -> "apiGetCallInvitations" is ApiSendCallInvitation -> "apiSendCallInvitation" is ApiRejectCall -> "apiRejectCall" is ApiSendCallOffer -> "apiSendCallOffer" @@ -3930,6 +3940,7 @@ sealed class CR { @Serializable @SerialName("sndFileError") class SndFileError(val user: UserRef, val chatItem: AChatItem): CR() // call events @Serializable @SerialName("callInvitation") class CallInvitation(val callInvitation: RcvCallInvitation): CR() + @Serializable @SerialName("callInvitations") class CallInvitations(val callInvitations: List): CR() @Serializable @SerialName("callOffer") class CallOffer(val user: UserRef, val contact: Contact, val callType: CallType, val offer: WebRTCSession, val sharedKey: String? = null, val askConfirmation: Boolean): CR() @Serializable @SerialName("callAnswer") class CallAnswer(val user: UserRef, val contact: Contact, val answer: WebRTCSession): CR() @Serializable @SerialName("callExtraInfo") class CallExtraInfo(val user: UserRef, val contact: Contact, val extraInfo: WebRTCExtraInfo): CR() @@ -4077,6 +4088,7 @@ sealed class CR { is SndFileProgressXFTP -> "sndFileProgressXFTP" is SndFileCompleteXFTP -> "sndFileCompleteXFTP" is SndFileError -> "sndFileError" + is CallInvitations -> "callInvitations" is CallInvitation -> "callInvitation" is CallOffer -> "callOffer" is CallAnswer -> "callAnswer" @@ -4223,6 +4235,7 @@ sealed class CR { is SndFileProgressXFTP -> withUser(user, "chatItem: ${json.encodeToString(chatItem)}\nsentSize: $sentSize\ntotalSize: $totalSize") is SndFileCompleteXFTP -> withUser(user, json.encodeToString(chatItem)) is SndFileError -> withUser(user, json.encodeToString(chatItem)) + is CallInvitations -> "callInvitations: ${json.encodeToString(callInvitations)}" is CallInvitation -> "contact: ${callInvitation.contact.id}\ncallType: $callInvitation.callType\nsharedKey: ${callInvitation.sharedKey ?: ""}" is CallOffer -> withUser(user, "contact: ${contact.id}\ncallType: $callType\nsharedKey: ${sharedKey ?: ""}\naskConfirmation: $askConfirmation\noffer: ${json.encodeToString(offer)}") is CallAnswer -> withUser(user, "contact: ${contact.id}\nanswer: ${json.encodeToString(answer)}") 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 25cb8315e0..38c8112e4f 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 @@ -24,6 +24,7 @@ import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.text.* import androidx.compose.ui.unit.* import chat.simplex.common.model.* +import chat.simplex.common.model.ChatModel.controller import chat.simplex.common.ui.theme.* import chat.simplex.common.views.call.* import chat.simplex.common.views.chat.group.* @@ -317,11 +318,14 @@ fun ChatView(chatId: String, chatModel: ChatModel, onComposed: suspend (chatId: }, acceptCall = { contact -> hideKeyboard(view) - val invitation = chatModel.callInvitations.remove(contact.id) - if (invitation == null) { - AlertManager.shared.showAlertMsg(generalGetString(MR.strings.call_already_ended)) - } else { - chatModel.callManager.acceptIncomingCall(invitation = invitation) + withApi { + val invitation = chatModel.callInvitations.remove(contact.id) + ?: controller.apiGetCallInvitations(chatModel.remoteHostId()).firstOrNull { it.contact.id == contact.id } + if (invitation == null) { + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.call_already_ended)) + } else { + chatModel.callManager.acceptIncomingCall(invitation = invitation) + } } }, acceptFeature = { contact, feature, param -> From fc56873f1cf337bfa7d2728f40d2e5023131f2d4 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Tue, 9 Jan 2024 19:33:37 +0000 Subject: [PATCH 034/102] ios: update core library --- apps/ios/SimpleX.xcodeproj/project.pbxproj | 40 +++++++++++----------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/apps/ios/SimpleX.xcodeproj/project.pbxproj b/apps/ios/SimpleX.xcodeproj/project.pbxproj index 2167d4beee..b11df53ec7 100644 --- a/apps/ios/SimpleX.xcodeproj/project.pbxproj +++ b/apps/ios/SimpleX.xcodeproj/project.pbxproj @@ -29,6 +29,11 @@ 5C116CDC27AABE0400E66D01 /* ContactRequestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C116CDB27AABE0400E66D01 /* ContactRequestView.swift */; }; 5C13730B28156D2700F43030 /* ContactConnectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C13730A28156D2700F43030 /* ContactConnectionView.swift */; }; 5C1A4C1E27A715B700EAD5AD /* ChatItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C1A4C1D27A715B700EAD5AD /* ChatItemView.swift */; }; + 5C245F192B4DB982001CC39F /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C245F142B4DB982001CC39F /* libgmpxx.a */; }; + 5C245F1A2B4DB982001CC39F /* libHSsimplex-chat-5.5.0.0-K5xQiJJwtSUKGqIyB7d1Tl-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C245F152B4DB982001CC39F /* libHSsimplex-chat-5.5.0.0-K5xQiJJwtSUKGqIyB7d1Tl-ghc9.6.3.a */; }; + 5C245F1B2B4DB982001CC39F /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C245F162B4DB982001CC39F /* libgmp.a */; }; + 5C245F1C2B4DB982001CC39F /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C245F172B4DB982001CC39F /* libffi.a */; }; + 5C245F1D2B4DB982001CC39F /* libHSsimplex-chat-5.5.0.0-K5xQiJJwtSUKGqIyB7d1Tl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C245F182B4DB982001CC39F /* libHSsimplex-chat-5.5.0.0-K5xQiJJwtSUKGqIyB7d1Tl.a */; }; 5C2E260727A2941F00F70299 /* SimpleXAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260627A2941F00F70299 /* SimpleXAPI.swift */; }; 5C2E260B27A30CFA00F70299 /* ChatListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260A27A30CFA00F70299 /* ChatListView.swift */; }; 5C2E260F27A30FDC00F70299 /* ChatView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260E27A30FDC00F70299 /* ChatView.swift */; }; @@ -42,11 +47,6 @@ 5C3F1D562842B68D00EC8A82 /* IntegrityErrorItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C3F1D552842B68D00EC8A82 /* IntegrityErrorItemView.swift */; }; 5C3F1D58284363C400EC8A82 /* PrivacySettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C3F1D57284363C400EC8A82 /* PrivacySettings.swift */; }; 5C4B3B0A285FB130003915F2 /* DatabaseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C4B3B09285FB130003915F2 /* DatabaseView.swift */; }; - 5C4E80E42B40A96C0080FAE2 /* libHSsimplex-chat-5.5.0.0-FwZXD1cMpkc1VLQMq43OyQ.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C4E80DF2B40A96C0080FAE2 /* libHSsimplex-chat-5.5.0.0-FwZXD1cMpkc1VLQMq43OyQ.a */; }; - 5C4E80E52B40A96C0080FAE2 /* libHSsimplex-chat-5.5.0.0-FwZXD1cMpkc1VLQMq43OyQ-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C4E80E02B40A96C0080FAE2 /* libHSsimplex-chat-5.5.0.0-FwZXD1cMpkc1VLQMq43OyQ-ghc9.6.3.a */; }; - 5C4E80E62B40A96C0080FAE2 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C4E80E12B40A96C0080FAE2 /* libgmp.a */; }; - 5C4E80E72B40A96C0080FAE2 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C4E80E22B40A96C0080FAE2 /* libgmpxx.a */; }; - 5C4E80E82B40A96C0080FAE2 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C4E80E32B40A96C0080FAE2 /* libffi.a */; }; 5C5346A827B59A6A004DF848 /* ChatHelp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C5346A727B59A6A004DF848 /* ChatHelp.swift */; }; 5C55A91F283AD0E400C4E99E /* CallManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C55A91E283AD0E400C4E99E /* CallManager.swift */; }; 5C55A921283CCCB700C4E99E /* IncomingCallView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C55A920283CCCB700C4E99E /* IncomingCallView.swift */; }; @@ -275,6 +275,11 @@ 5C13730A28156D2700F43030 /* ContactConnectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactConnectionView.swift; sourceTree = ""; }; 5C13730C2815740A00F43030 /* DebugJSON.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = DebugJSON.playground; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 5C1A4C1D27A715B700EAD5AD /* ChatItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatItemView.swift; sourceTree = ""; }; + 5C245F142B4DB982001CC39F /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = ""; }; + 5C245F152B4DB982001CC39F /* libHSsimplex-chat-5.5.0.0-K5xQiJJwtSUKGqIyB7d1Tl-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.5.0.0-K5xQiJJwtSUKGqIyB7d1Tl-ghc9.6.3.a"; sourceTree = ""; }; + 5C245F162B4DB982001CC39F /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; }; + 5C245F172B4DB982001CC39F /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; }; + 5C245F182B4DB982001CC39F /* libHSsimplex-chat-5.5.0.0-K5xQiJJwtSUKGqIyB7d1Tl.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.5.0.0-K5xQiJJwtSUKGqIyB7d1Tl.a"; sourceTree = ""; }; 5C2E260627A2941F00F70299 /* SimpleXAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleXAPI.swift; sourceTree = ""; }; 5C2E260A27A30CFA00F70299 /* ChatListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatListView.swift; sourceTree = ""; }; 5C2E260E27A30FDC00F70299 /* ChatView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatView.swift; sourceTree = ""; }; @@ -289,11 +294,6 @@ 5C3F1D57284363C400EC8A82 /* PrivacySettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacySettings.swift; sourceTree = ""; }; 5C422A7C27A9A6FA0097A1E1 /* SimpleX (iOS).entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "SimpleX (iOS).entitlements"; sourceTree = ""; }; 5C4B3B09285FB130003915F2 /* DatabaseView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatabaseView.swift; sourceTree = ""; }; - 5C4E80DF2B40A96C0080FAE2 /* libHSsimplex-chat-5.5.0.0-FwZXD1cMpkc1VLQMq43OyQ.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.5.0.0-FwZXD1cMpkc1VLQMq43OyQ.a"; sourceTree = ""; }; - 5C4E80E02B40A96C0080FAE2 /* libHSsimplex-chat-5.5.0.0-FwZXD1cMpkc1VLQMq43OyQ-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.5.0.0-FwZXD1cMpkc1VLQMq43OyQ-ghc9.6.3.a"; sourceTree = ""; }; - 5C4E80E12B40A96C0080FAE2 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; }; - 5C4E80E22B40A96C0080FAE2 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = ""; }; - 5C4E80E32B40A96C0080FAE2 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; }; 5C5346A727B59A6A004DF848 /* ChatHelp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatHelp.swift; sourceTree = ""; }; 5C55A91E283AD0E400C4E99E /* CallManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallManager.swift; sourceTree = ""; }; 5C55A920283CCCB700C4E99E /* IncomingCallView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IncomingCallView.swift; sourceTree = ""; }; @@ -511,13 +511,13 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 5C4E80E72B40A96C0080FAE2 /* libgmpxx.a in Frameworks */, + 5C245F192B4DB982001CC39F /* libgmpxx.a in Frameworks */, + 5C245F1C2B4DB982001CC39F /* libffi.a in Frameworks */, + 5C245F1D2B4DB982001CC39F /* libHSsimplex-chat-5.5.0.0-K5xQiJJwtSUKGqIyB7d1Tl.a in Frameworks */, + 5C245F1B2B4DB982001CC39F /* libgmp.a in Frameworks */, 5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */, - 5C4E80E62B40A96C0080FAE2 /* libgmp.a in Frameworks */, + 5C245F1A2B4DB982001CC39F /* libHSsimplex-chat-5.5.0.0-K5xQiJJwtSUKGqIyB7d1Tl-ghc9.6.3.a in Frameworks */, 5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */, - 5C4E80E82B40A96C0080FAE2 /* libffi.a in Frameworks */, - 5C4E80E52B40A96C0080FAE2 /* libHSsimplex-chat-5.5.0.0-FwZXD1cMpkc1VLQMq43OyQ-ghc9.6.3.a in Frameworks */, - 5C4E80E42B40A96C0080FAE2 /* libHSsimplex-chat-5.5.0.0-FwZXD1cMpkc1VLQMq43OyQ.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -579,11 +579,11 @@ 5C764E5C279C70B7000C6508 /* Libraries */ = { isa = PBXGroup; children = ( - 5C4E80E32B40A96C0080FAE2 /* libffi.a */, - 5C4E80E12B40A96C0080FAE2 /* libgmp.a */, - 5C4E80E22B40A96C0080FAE2 /* libgmpxx.a */, - 5C4E80E02B40A96C0080FAE2 /* libHSsimplex-chat-5.5.0.0-FwZXD1cMpkc1VLQMq43OyQ-ghc9.6.3.a */, - 5C4E80DF2B40A96C0080FAE2 /* libHSsimplex-chat-5.5.0.0-FwZXD1cMpkc1VLQMq43OyQ.a */, + 5C245F172B4DB982001CC39F /* libffi.a */, + 5C245F162B4DB982001CC39F /* libgmp.a */, + 5C245F142B4DB982001CC39F /* libgmpxx.a */, + 5C245F152B4DB982001CC39F /* libHSsimplex-chat-5.5.0.0-K5xQiJJwtSUKGqIyB7d1Tl-ghc9.6.3.a */, + 5C245F182B4DB982001CC39F /* libHSsimplex-chat-5.5.0.0-K5xQiJJwtSUKGqIyB7d1Tl.a */, ); path = Libraries; sourceTree = ""; From 99a9fb2e1f30d8793a3f592a2638af6d3e52c4a4 Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Wed, 10 Jan 2024 04:01:41 +0700 Subject: [PATCH 035/102] ios: self destruct improvements (#3640) * ios: self destruct improvements * test * adapted to stopped chat * wait until ctrl initialization finishes * Revert "test" This reverts commit 7c199293cc0193c7a0ee6e5d9977a4ed56b20098. * refactor * simplify,fix * refactor2 * refactor3 * comment * fix * fix * comment Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com> * flip and rename flag --------- Co-authored-by: Avently Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com> --- apps/ios/Shared/ContentView.swift | 8 +++- apps/ios/Shared/Model/ChatModel.swift | 1 + apps/ios/Shared/Model/SimpleXAPI.swift | 2 + apps/ios/Shared/SimpleXApp.swift | 6 ++- .../Shared/Views/Database/DatabaseView.swift | 1 + .../Views/LocalAuth/LocalAuthView.swift | 42 +++++++++++++++---- .../Shared/Views/LocalAuth/PasscodeView.swift | 7 +++- .../Views/LocalAuth/SetAppPasscodeView.swift | 8 +++- .../Views/UserSettings/PrivacySettings.swift | 13 +++++- apps/ios/SimpleXChat/FileUtils.swift | 24 +++++++++-- 10 files changed, 91 insertions(+), 21 deletions(-) diff --git a/apps/ios/Shared/ContentView.swift b/apps/ios/Shared/ContentView.swift index d7b9fef218..c3a8ec2809 100644 --- a/apps/ios/Shared/ContentView.swift +++ b/apps/ios/Shared/ContentView.swift @@ -31,6 +31,7 @@ struct ContentView: View { @State private var showWhatsNew = false @State private var showChooseLAMode = false @State private var showSetPasscode = false + @State private var waitingForOrPassedAuth = true @State private var chatListActionSheet: ChatListActionSheet? = nil private enum ChatListActionSheet: Identifiable { @@ -61,6 +62,10 @@ struct ContentView: View { } if !showSettings, let la = chatModel.laRequest { LocalAuthView(authRequest: la) + .onDisappear { + // this flag is separate from accessAuthenticated to show initializationView while we wait for authentication + waitingForOrPassedAuth = accessAuthenticated + } } else if showSetPasscode { SetAppPasscodeView { chatModel.contentViewAccessAuthenticated = true @@ -73,8 +78,7 @@ struct ContentView: View { showSetPasscode = false alertManager.showAlert(laPasscodeNotSetAlert()) } - } - if chatModel.chatDbStatus == nil { + } else if chatModel.chatDbStatus == nil && AppChatState.shared.value != .stopped && waitingForOrPassedAuth { initializationView() } } diff --git a/apps/ios/Shared/Model/ChatModel.swift b/apps/ios/Shared/Model/ChatModel.swift index db0f138690..e5022751cd 100644 --- a/apps/ios/Shared/Model/ChatModel.swift +++ b/apps/ios/Shared/Model/ChatModel.swift @@ -54,6 +54,7 @@ final class ChatModel: ObservableObject { @Published var chatDbChanged = false @Published var chatDbEncrypted: Bool? @Published var chatDbStatus: DBMigrationResult? + @Published var ctrlInitInProgress: Bool = false // local authentication @Published var contentViewAccessAuthenticated: Bool = false @Published var laRequest: LocalAuthRequest? diff --git a/apps/ios/Shared/Model/SimpleXAPI.swift b/apps/ios/Shared/Model/SimpleXAPI.swift index 154328a7ba..ee31dd65c1 100644 --- a/apps/ios/Shared/Model/SimpleXAPI.swift +++ b/apps/ios/Shared/Model/SimpleXAPI.swift @@ -1215,6 +1215,8 @@ private func currentUserId(_ funcName: String) throws -> Int64 { func initializeChat(start: Bool, confirmStart: Bool = false, dbKey: String? = nil, refreshInvitations: Bool = true, confirmMigrations: MigrationConfirmation? = nil) throws { logger.debug("initializeChat") let m = ChatModel.shared + m.ctrlInitInProgress = true + defer { m.ctrlInitInProgress = false } (m.chatDbEncrypted, m.chatDbStatus) = chatMigrateInit(dbKey, confirmMigrations: confirmMigrations) if m.chatDbStatus != .ok { return } // If we migrated successfully means previous re-encryption process on database level finished successfully too diff --git a/apps/ios/Shared/SimpleXApp.swift b/apps/ios/Shared/SimpleXApp.swift index 60d1cf7256..e5b98589a0 100644 --- a/apps/ios/Shared/SimpleXApp.swift +++ b/apps/ios/Shared/SimpleXApp.swift @@ -44,8 +44,10 @@ struct SimpleXApp: App { chatModel.appOpenUrl = url } .onAppear() { - DispatchQueue.main.asyncAfter(deadline: .now() + 0.15) { - initChatAndMigrate() + if kcAppPassword.get() == nil || kcSelfDestructPassword.get() == nil { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.15) { + initChatAndMigrate() + } } } .onChange(of: scenePhase) { phase in diff --git a/apps/ios/Shared/Views/Database/DatabaseView.swift b/apps/ios/Shared/Views/Database/DatabaseView.swift index 72515a1fac..31b1f618e3 100644 --- a/apps/ios/Shared/Views/Database/DatabaseView.swift +++ b/apps/ios/Shared/Views/Database/DatabaseView.swift @@ -484,6 +484,7 @@ func deleteChatAsync() async throws { try await apiDeleteStorage() _ = kcDatabasePassword.remove() storeDBPassphraseGroupDefault.set(true) + deleteAppDatabaseAndFiles() } struct DatabaseView_Previews: PreviewProvider { diff --git a/apps/ios/Shared/Views/LocalAuth/LocalAuthView.swift b/apps/ios/Shared/Views/LocalAuth/LocalAuthView.swift index bdb5b03e8c..9691a9efd3 100644 --- a/apps/ios/Shared/Views/LocalAuth/LocalAuthView.swift +++ b/apps/ios/Shared/Views/LocalAuth/LocalAuthView.swift @@ -13,19 +13,28 @@ struct LocalAuthView: View { @EnvironmentObject var m: ChatModel var authRequest: LocalAuthRequest @State private var password = "" + @State private var allowToReact = true var body: some View { - PasscodeView(passcode: $password, title: authRequest.title ?? "Enter Passcode", reason: authRequest.reason, submitLabel: "Submit") { + PasscodeView(passcode: $password, title: authRequest.title ?? "Enter Passcode", reason: authRequest.reason, submitLabel: "Submit", + buttonsEnabled: $allowToReact) { if let sdPassword = kcSelfDestructPassword.get(), authRequest.selfDestruct && password == sdPassword { + allowToReact = false deleteStorageAndRestart(sdPassword) { r in m.laRequest = nil authRequest.completed(r) } return } - let r: LAResult = password == authRequest.password - ? .success - : .failed(authError: NSLocalizedString("Incorrect passcode", comment: "PIN entry")) + let r: LAResult + if password == authRequest.password { + if authRequest.selfDestruct && kcSelfDestructPassword.get() != nil && !m.chatInitialized { + initChatAndMigrate() + } + r = .success + } else { + r = .failed(authError: NSLocalizedString("Incorrect passcode", comment: "PIN entry")) + } m.laRequest = nil authRequest.completed(r) } cancel: { @@ -37,8 +46,27 @@ struct LocalAuthView: View { private func deleteStorageAndRestart(_ password: String, completed: @escaping (LAResult) -> Void) { Task { do { - try await stopChatAsync() - try await deleteChatAsync() + /** Waiting until [initializeChat] finishes */ + while (m.ctrlInitInProgress) { + try await Task.sleep(nanoseconds: 50_000000) + } + if m.chatRunning == true { + try await stopChatAsync() + } + if m.chatInitialized { + /** + * The following sequence can bring a user here: + * the user opened the app, entered app passcode, went to background, returned back, entered self-destruct code. + * In this case database should be closed to prevent possible situation when OS can deny database removal command + * */ + chatCloseStore() + } + deleteAppDatabaseAndFiles() + // Clear sensitive data on screen just in case app fails to hide its views while new database is created + m.chatId = nil + m.reversedChatItems = [] + m.chats = [] + m.users = [] _ = kcAppPassword.set(password) _ = kcSelfDestructPassword.remove() await NtfManager.shared.removeAllNotifications() @@ -53,7 +81,7 @@ struct LocalAuthView: View { try initializeChat(start: true) m.chatDbChanged = false AppChatState.shared.set(.active) - if m.currentUser != nil { return } + if m.currentUser != nil || !m.chatInitialized { return } var profile: Profile? = nil if let displayName = displayName, displayName != "" { profile = Profile(displayName: displayName, fullName: "") diff --git a/apps/ios/Shared/Views/LocalAuth/PasscodeView.swift b/apps/ios/Shared/Views/LocalAuth/PasscodeView.swift index c73ded2d28..9e0d7f38b5 100644 --- a/apps/ios/Shared/Views/LocalAuth/PasscodeView.swift +++ b/apps/ios/Shared/Views/LocalAuth/PasscodeView.swift @@ -14,6 +14,8 @@ struct PasscodeView: View { var reason: String? = nil var submitLabel: LocalizedStringKey var submitEnabled: ((String) -> Bool)? + @Binding var buttonsEnabled: Bool + var submit: () -> Void var cancel: () -> Void @@ -70,11 +72,11 @@ struct PasscodeView: View { @ViewBuilder private func buttonsView() -> some View { Button(action: cancel) { Label("Cancel", systemImage: "multiply") - } + }.disabled(!buttonsEnabled) Button(action: submit) { Label(submitLabel, systemImage: "checkmark") } - .disabled(submitEnabled?(passcode) == false || passcode.count < 4) + .disabled(submitEnabled?(passcode) == false || passcode.count < 4 || !buttonsEnabled) } } @@ -85,6 +87,7 @@ struct PasscodeViewView_Previews: PreviewProvider { title: "Enter Passcode", reason: "Unlock app", submitLabel: "Submit", + buttonsEnabled: Binding.constant(true), submit: {}, cancel: {} ) diff --git a/apps/ios/Shared/Views/LocalAuth/SetAppPasscodeView.swift b/apps/ios/Shared/Views/LocalAuth/SetAppPasscodeView.swift index 76cd3e279a..7ec3ee1a42 100644 --- a/apps/ios/Shared/Views/LocalAuth/SetAppPasscodeView.swift +++ b/apps/ios/Shared/Views/LocalAuth/SetAppPasscodeView.swift @@ -11,6 +11,7 @@ import SimpleXChat struct SetAppPasscodeView: View { var passcodeKeychain: KeyChainItem = kcAppPassword + var prohibitedPasscodeKeychain: KeyChainItem = kcSelfDestructPassword var title: LocalizedStringKey = "New Passcode" var reason: String? var submit: () -> Void @@ -41,7 +42,10 @@ struct SetAppPasscodeView: View { } } } else { - setPasswordView(title: title, submitLabel: "Save") { + setPasswordView(title: title, + submitLabel: "Save", + // Do not allow to set app passcode == selfDestruct passcode + submitEnabled: { pwd in pwd != prohibitedPasscodeKeychain.get() }) { enteredPassword = passcode passcode = "" confirming = true @@ -54,7 +58,7 @@ struct SetAppPasscodeView: View { } private func setPasswordView(title: LocalizedStringKey, submitLabel: LocalizedStringKey, submitEnabled: (((String) -> Bool))? = nil, submit: @escaping () -> Void) -> some View { - PasscodeView(passcode: $passcode, title: title, reason: reason, submitLabel: submitLabel, submitEnabled: submitEnabled, submit: submit) { + PasscodeView(passcode: $passcode, title: title, reason: reason, submitLabel: submitLabel, submitEnabled: submitEnabled, buttonsEnabled: Binding.constant(true), submit: submit) { dismiss() cancel() } diff --git a/apps/ios/Shared/Views/UserSettings/PrivacySettings.swift b/apps/ios/Shared/Views/UserSettings/PrivacySettings.swift index d8ff2c2f89..8d13c6fb39 100644 --- a/apps/ios/Shared/Views/UserSettings/PrivacySettings.swift +++ b/apps/ios/Shared/Views/UserSettings/PrivacySettings.swift @@ -491,14 +491,23 @@ struct SimplexLockView: View { showLAAlert(.laPasscodeNotChangedAlert) } case .enableSelfDestruct: - SetAppPasscodeView(passcodeKeychain: kcSelfDestructPassword, title: "Set passcode", reason: NSLocalizedString("Enable self-destruct passcode", comment: "set passcode view")) { + SetAppPasscodeView( + passcodeKeychain: kcSelfDestructPassword, + prohibitedPasscodeKeychain: kcAppPassword, + title: "Set passcode", + reason: NSLocalizedString("Enable self-destruct passcode", comment: "set passcode view") + ) { updateSelfDestruct() showLAAlert(.laSelfDestructPasscodeSetAlert) } cancel: { revertSelfDestruct() } case .changeSelfDestructPasscode: - SetAppPasscodeView(passcodeKeychain: kcSelfDestructPassword, reason: NSLocalizedString("Change self-destruct passcode", comment: "set passcode view")) { + SetAppPasscodeView( + passcodeKeychain: kcSelfDestructPassword, + prohibitedPasscodeKeychain: kcAppPassword, + reason: NSLocalizedString("Change self-destruct passcode", comment: "set passcode view") + ) { showLAAlert(.laSelfDestructPasscodeChangedAlert) } cancel: { showLAAlert(.laPasscodeNotChangedAlert) diff --git a/apps/ios/SimpleXChat/FileUtils.swift b/apps/ios/SimpleXChat/FileUtils.swift index 60d281f146..748a7841d9 100644 --- a/apps/ios/SimpleXChat/FileUtils.swift +++ b/apps/ios/SimpleXChat/FileUtils.swift @@ -69,13 +69,29 @@ func fileModificationDate(_ path: String) -> Date? { } } +public func deleteAppDatabaseAndFiles() { + let fm = FileManager.default + let dbPath = getAppDatabasePath().path + do { + try fm.removeItem(atPath: dbPath + CHAT_DB) + try fm.removeItem(atPath: dbPath + AGENT_DB) + } catch let error { + logger.error("Failed to delete all databases: \(error)") + } + try? fm.removeItem(atPath: dbPath + CHAT_DB_BAK) + try? fm.removeItem(atPath: dbPath + AGENT_DB_BAK) + try? fm.removeItem(at: getTempFilesDirectory()) + try? fm.createDirectory(at: getTempFilesDirectory(), withIntermediateDirectories: true) + deleteAppFiles() + _ = kcDatabasePassword.remove() + storeDBPassphraseGroupDefault.set(true) +} + public func deleteAppFiles() { let fm = FileManager.default do { - let fileNames = try fm.contentsOfDirectory(atPath: getAppFilesDirectory().path) - for fileName in fileNames { - removeFile(fileName) - } + try fm.removeItem(at: getAppFilesDirectory()) + try fm.createDirectory(at: getAppFilesDirectory(), withIntermediateDirectories: true) } catch { logger.error("FileUtils deleteAppFiles error: \(error.localizedDescription)") } From 283c90f5ae9d82e7cf5081beb0579bb4ea6e46f3 Mon Sep 17 00:00:00 2001 From: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com> Date: Wed, 10 Jan 2024 11:09:09 +0400 Subject: [PATCH 036/102] core: fix db method reserving extra local display name (#3659) Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> --- src/Simplex/Chat/Store/Groups.hs | 33 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/src/Simplex/Chat/Store/Groups.hs b/src/Simplex/Chat/Store/Groups.hs index e9ec8be28c..7fedc10fa9 100644 --- a/src/Simplex/Chat/Store/Groups.hs +++ b/src/Simplex/Chat/Store/Groups.hs @@ -460,24 +460,23 @@ createGroupInvitedViaLink "INSERT INTO groups (group_profile_id, local_display_name, host_conn_custom_user_profile_id, user_id, enable_ntfs, created_at, updated_at, chat_ts) VALUES (?,?,?,?,?,?,?,?)" (profileId, localDisplayName, customUserProfileId, userId, True, currentTs, currentTs, currentTs) insertedRowId db - insertHost_ currentTs groupId = ExceptT $ do + insertHost_ currentTs groupId = do let fromMemberProfile = profileFromName fromMemberName - withLocalDisplayName db userId fromMemberName $ \localDisplayName -> runExceptT $ do - (_, profileId) <- createNewMemberProfile_ db user fromMemberProfile currentTs - let MemberIdRole {memberId, memberRole} = fromMember - liftIO $ do - DB.execute - db - [sql| - INSERT INTO group_members - ( group_id, member_id, member_role, member_category, member_status, invited_by, - user_id, local_display_name, contact_id, contact_profile_id, created_at, updated_at) - VALUES (?,?,?,?,?,?,?,?,?,?,?,?) - |] - ( (groupId, memberId, memberRole, GCHostMember, GSMemAccepted, fromInvitedBy userContactId IBUnknown) - :. (userId, localDisplayName, Nothing :: (Maybe Int64), profileId, currentTs, currentTs) - ) - insertedRowId db + (localDisplayName, profileId) <- createNewMemberProfile_ db user fromMemberProfile currentTs + let MemberIdRole {memberId, memberRole} = fromMember + liftIO $ do + DB.execute + db + [sql| + INSERT INTO group_members + ( group_id, member_id, member_role, member_category, member_status, invited_by, + user_id, local_display_name, contact_id, contact_profile_id, created_at, updated_at) + VALUES (?,?,?,?,?,?,?,?,?,?,?,?) + |] + ( (groupId, memberId, memberRole, GCHostMember, GSMemAccepted, fromInvitedBy userContactId IBUnknown) + :. (userId, localDisplayName, Nothing :: (Maybe Int64), profileId, currentTs, currentTs) + ) + insertedRowId db setViaGroupLinkHash :: DB.Connection -> GroupId -> Int64 -> IO () setViaGroupLinkHash db groupId connId = From 25a47194141b466ef9237526433cad3bff8652de Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Wed, 10 Jan 2024 12:06:29 +0000 Subject: [PATCH 037/102] core: 5.5.0.1 --- package.yaml | 2 +- simplex-chat.cabal | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.yaml b/package.yaml index 889df9db71..a9b7e77708 100644 --- a/package.yaml +++ b/package.yaml @@ -1,5 +1,5 @@ name: simplex-chat -version: 5.5.0.0 +version: 5.5.0.1 #synopsis: #description: homepage: https://github.com/simplex-chat/simplex-chat#readme diff --git a/simplex-chat.cabal b/simplex-chat.cabal index 5090fc5adc..ebb167936c 100644 --- a/simplex-chat.cabal +++ b/simplex-chat.cabal @@ -5,7 +5,7 @@ cabal-version: 1.12 -- see: https://github.com/sol/hpack name: simplex-chat -version: 5.5.0.0 +version: 5.5.0.1 category: Web, System, Services, Cryptography homepage: https://github.com/simplex-chat/simplex-chat#readme author: simplex.chat From 61b14b22d54dc91197757f58e2067dcc2db7cbcc Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Wed, 10 Jan 2024 14:18:14 +0000 Subject: [PATCH 038/102] 5.5-beta.1: ios 189, android 171, desktop 23 --- apps/ios/SimpleX.xcodeproj/project.pbxproj | 52 +++++++++++----------- apps/multiplatform/gradle.properties | 8 ++-- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/apps/ios/SimpleX.xcodeproj/project.pbxproj b/apps/ios/SimpleX.xcodeproj/project.pbxproj index b11df53ec7..94a814c436 100644 --- a/apps/ios/SimpleX.xcodeproj/project.pbxproj +++ b/apps/ios/SimpleX.xcodeproj/project.pbxproj @@ -29,11 +29,11 @@ 5C116CDC27AABE0400E66D01 /* ContactRequestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C116CDB27AABE0400E66D01 /* ContactRequestView.swift */; }; 5C13730B28156D2700F43030 /* ContactConnectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C13730A28156D2700F43030 /* ContactConnectionView.swift */; }; 5C1A4C1E27A715B700EAD5AD /* ChatItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C1A4C1D27A715B700EAD5AD /* ChatItemView.swift */; }; - 5C245F192B4DB982001CC39F /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C245F142B4DB982001CC39F /* libgmpxx.a */; }; - 5C245F1A2B4DB982001CC39F /* libHSsimplex-chat-5.5.0.0-K5xQiJJwtSUKGqIyB7d1Tl-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C245F152B4DB982001CC39F /* libHSsimplex-chat-5.5.0.0-K5xQiJJwtSUKGqIyB7d1Tl-ghc9.6.3.a */; }; - 5C245F1B2B4DB982001CC39F /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C245F162B4DB982001CC39F /* libgmp.a */; }; - 5C245F1C2B4DB982001CC39F /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C245F172B4DB982001CC39F /* libffi.a */; }; - 5C245F1D2B4DB982001CC39F /* libHSsimplex-chat-5.5.0.0-K5xQiJJwtSUKGqIyB7d1Tl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C245F182B4DB982001CC39F /* libHSsimplex-chat-5.5.0.0-K5xQiJJwtSUKGqIyB7d1Tl.a */; }; + 5C245F372B4ED5BE001CC39F /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C245F322B4ED5BE001CC39F /* libgmpxx.a */; }; + 5C245F382B4ED5BE001CC39F /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C245F332B4ED5BE001CC39F /* libgmp.a */; }; + 5C245F392B4ED5BE001CC39F /* libHSsimplex-chat-5.5.0.1-88BIBmZS0745eqQdRbJ61V-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C245F342B4ED5BE001CC39F /* libHSsimplex-chat-5.5.0.1-88BIBmZS0745eqQdRbJ61V-ghc9.6.3.a */; }; + 5C245F3A2B4ED5BE001CC39F /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C245F352B4ED5BE001CC39F /* libffi.a */; }; + 5C245F3B2B4ED5BE001CC39F /* libHSsimplex-chat-5.5.0.1-88BIBmZS0745eqQdRbJ61V.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C245F362B4ED5BE001CC39F /* libHSsimplex-chat-5.5.0.1-88BIBmZS0745eqQdRbJ61V.a */; }; 5C2E260727A2941F00F70299 /* SimpleXAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260627A2941F00F70299 /* SimpleXAPI.swift */; }; 5C2E260B27A30CFA00F70299 /* ChatListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260A27A30CFA00F70299 /* ChatListView.swift */; }; 5C2E260F27A30FDC00F70299 /* ChatView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260E27A30FDC00F70299 /* ChatView.swift */; }; @@ -275,11 +275,11 @@ 5C13730A28156D2700F43030 /* ContactConnectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactConnectionView.swift; sourceTree = ""; }; 5C13730C2815740A00F43030 /* DebugJSON.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = DebugJSON.playground; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 5C1A4C1D27A715B700EAD5AD /* ChatItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatItemView.swift; sourceTree = ""; }; - 5C245F142B4DB982001CC39F /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = ""; }; - 5C245F152B4DB982001CC39F /* libHSsimplex-chat-5.5.0.0-K5xQiJJwtSUKGqIyB7d1Tl-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.5.0.0-K5xQiJJwtSUKGqIyB7d1Tl-ghc9.6.3.a"; sourceTree = ""; }; - 5C245F162B4DB982001CC39F /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; }; - 5C245F172B4DB982001CC39F /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; }; - 5C245F182B4DB982001CC39F /* libHSsimplex-chat-5.5.0.0-K5xQiJJwtSUKGqIyB7d1Tl.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.5.0.0-K5xQiJJwtSUKGqIyB7d1Tl.a"; sourceTree = ""; }; + 5C245F322B4ED5BE001CC39F /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = ""; }; + 5C245F332B4ED5BE001CC39F /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; }; + 5C245F342B4ED5BE001CC39F /* libHSsimplex-chat-5.5.0.1-88BIBmZS0745eqQdRbJ61V-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.5.0.1-88BIBmZS0745eqQdRbJ61V-ghc9.6.3.a"; sourceTree = ""; }; + 5C245F352B4ED5BE001CC39F /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; }; + 5C245F362B4ED5BE001CC39F /* libHSsimplex-chat-5.5.0.1-88BIBmZS0745eqQdRbJ61V.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.5.0.1-88BIBmZS0745eqQdRbJ61V.a"; sourceTree = ""; }; 5C2E260627A2941F00F70299 /* SimpleXAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleXAPI.swift; sourceTree = ""; }; 5C2E260A27A30CFA00F70299 /* ChatListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatListView.swift; sourceTree = ""; }; 5C2E260E27A30FDC00F70299 /* ChatView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatView.swift; sourceTree = ""; }; @@ -511,13 +511,13 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 5C245F192B4DB982001CC39F /* libgmpxx.a in Frameworks */, - 5C245F1C2B4DB982001CC39F /* libffi.a in Frameworks */, - 5C245F1D2B4DB982001CC39F /* libHSsimplex-chat-5.5.0.0-K5xQiJJwtSUKGqIyB7d1Tl.a in Frameworks */, - 5C245F1B2B4DB982001CC39F /* libgmp.a in Frameworks */, + 5C245F372B4ED5BE001CC39F /* libgmpxx.a in Frameworks */, + 5C245F3A2B4ED5BE001CC39F /* libffi.a in Frameworks */, 5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */, - 5C245F1A2B4DB982001CC39F /* libHSsimplex-chat-5.5.0.0-K5xQiJJwtSUKGqIyB7d1Tl-ghc9.6.3.a in Frameworks */, + 5C245F382B4ED5BE001CC39F /* libgmp.a in Frameworks */, 5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */, + 5C245F3B2B4ED5BE001CC39F /* libHSsimplex-chat-5.5.0.1-88BIBmZS0745eqQdRbJ61V.a in Frameworks */, + 5C245F392B4ED5BE001CC39F /* libHSsimplex-chat-5.5.0.1-88BIBmZS0745eqQdRbJ61V-ghc9.6.3.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -579,11 +579,11 @@ 5C764E5C279C70B7000C6508 /* Libraries */ = { isa = PBXGroup; children = ( - 5C245F172B4DB982001CC39F /* libffi.a */, - 5C245F162B4DB982001CC39F /* libgmp.a */, - 5C245F142B4DB982001CC39F /* libgmpxx.a */, - 5C245F152B4DB982001CC39F /* libHSsimplex-chat-5.5.0.0-K5xQiJJwtSUKGqIyB7d1Tl-ghc9.6.3.a */, - 5C245F182B4DB982001CC39F /* libHSsimplex-chat-5.5.0.0-K5xQiJJwtSUKGqIyB7d1Tl.a */, + 5C245F352B4ED5BE001CC39F /* libffi.a */, + 5C245F332B4ED5BE001CC39F /* libgmp.a */, + 5C245F322B4ED5BE001CC39F /* libgmpxx.a */, + 5C245F342B4ED5BE001CC39F /* libHSsimplex-chat-5.5.0.1-88BIBmZS0745eqQdRbJ61V-ghc9.6.3.a */, + 5C245F362B4ED5BE001CC39F /* libHSsimplex-chat-5.5.0.1-88BIBmZS0745eqQdRbJ61V.a */, ); path = Libraries; sourceTree = ""; @@ -1502,7 +1502,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 187; + CURRENT_PROJECT_VERSION = 189; DEVELOPMENT_TEAM = 5NN7GUYB6T; ENABLE_BITCODE = NO; ENABLE_PREVIEWS = YES; @@ -1545,7 +1545,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 187; + CURRENT_PROJECT_VERSION = 189; DEVELOPMENT_TEAM = 5NN7GUYB6T; ENABLE_BITCODE = NO; ENABLE_PREVIEWS = YES; @@ -1626,7 +1626,7 @@ CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 187; + CURRENT_PROJECT_VERSION = 189; DEVELOPMENT_TEAM = 5NN7GUYB6T; ENABLE_BITCODE = NO; GENERATE_INFOPLIST_FILE = YES; @@ -1658,7 +1658,7 @@ CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 187; + CURRENT_PROJECT_VERSION = 189; DEVELOPMENT_TEAM = 5NN7GUYB6T; ENABLE_BITCODE = NO; GENERATE_INFOPLIST_FILE = YES; @@ -1690,7 +1690,7 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 187; + CURRENT_PROJECT_VERSION = 189; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5NN7GUYB6T; DYLIB_COMPATIBILITY_VERSION = 1; @@ -1736,7 +1736,7 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 187; + CURRENT_PROJECT_VERSION = 189; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5NN7GUYB6T; DYLIB_COMPATIBILITY_VERSION = 1; diff --git a/apps/multiplatform/gradle.properties b/apps/multiplatform/gradle.properties index d94fe6f915..555f024a36 100644 --- a/apps/multiplatform/gradle.properties +++ b/apps/multiplatform/gradle.properties @@ -25,11 +25,11 @@ android.nonTransitiveRClass=true android.enableJetifier=true kotlin.mpp.androidSourceSetLayoutVersion=2 -android.version_name=5.5-beta.0 -android.version_code=168 +android.version_name=5.5-beta.1 +android.version_code=171 -desktop.version_name=5.5-beta.0 -desktop.version_code=21 +desktop.version_name=5.5-beta.1 +desktop.version_code=23 kotlin.version=1.8.20 gradle.plugin.version=7.4.2 From acd05c43dbc59b93088ed7f03dcc32e93aac595f Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Wed, 10 Jan 2024 23:57:34 +0700 Subject: [PATCH 039/102] mobile: chat deletion avoiding race conditions (#3650) * android, desktop: chat items deletion * rename * ios: chat items deletion * correct id * android: adding progress of deletion * ios: text color while deleting chats * change only text color --------- Co-authored-by: Avently Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> --- apps/ios/Shared/Model/ChatModel.swift | 1 + apps/ios/Shared/Model/SimpleXAPI.swift | 3 ++ .../Shared/Views/ChatList/ChatListView.swift | 2 +- .../Views/ChatList/ChatPreviewView.swift | 12 +++++--- .../chatlist/ChatListNavLinkView.android.kt | 4 +-- .../chat/simplex/common/model/ChatModel.kt | 2 ++ .../chat/simplex/common/model/SimpleXAPI.kt | 13 +++++---- .../views/chatlist/ChatListNavLinkView.kt | 28 +++++++++---------- .../common/views/chatlist/ChatPreviewView.kt | 24 ++++++++++++---- .../chatlist/ChatListNavLinkView.desktop.kt | 7 ++--- 10 files changed, 60 insertions(+), 36 deletions(-) diff --git a/apps/ios/Shared/Model/ChatModel.swift b/apps/ios/Shared/Model/ChatModel.swift index e5022751cd..21ef80cf6e 100644 --- a/apps/ios/Shared/Model/ChatModel.swift +++ b/apps/ios/Shared/Model/ChatModel.swift @@ -60,6 +60,7 @@ final class ChatModel: ObservableObject { @Published var laRequest: LocalAuthRequest? // list of chat "previews" @Published var chats: [Chat] = [] + @Published var deletedChats: Set = [] // map of connections network statuses, key is agent connection id @Published var networkStatuses: Dictionary = [:] // current chat diff --git a/apps/ios/Shared/Model/SimpleXAPI.swift b/apps/ios/Shared/Model/SimpleXAPI.swift index ee31dd65c1..f2aa6cbd91 100644 --- a/apps/ios/Shared/Model/SimpleXAPI.swift +++ b/apps/ios/Shared/Model/SimpleXAPI.swift @@ -691,6 +691,9 @@ func apiConnectContactViaAddress(incognito: Bool, contactId: Int64) async -> (Co } func apiDeleteChat(type: ChatType, id: Int64, notify: Bool? = nil) async throws { + let chatId = type.rawValue + id.description + DispatchQueue.main.async { ChatModel.shared.deletedChats.insert(chatId) } + defer { DispatchQueue.main.async { ChatModel.shared.deletedChats.remove(chatId) } } let r = await chatSendCmd(.apiDeleteChat(type: type, id: id, notify: notify), bgTask: false) if case .direct = type, case .contactDeleted = r { return } if case .contactConnection = type, case .contactConnectionDeleted = r { return } diff --git a/apps/ios/Shared/Views/ChatList/ChatListView.swift b/apps/ios/Shared/Views/ChatList/ChatListView.swift index 62955a1040..1b4531b08c 100644 --- a/apps/ios/Shared/Views/ChatList/ChatListView.swift +++ b/apps/ios/Shared/Views/ChatList/ChatListView.swift @@ -160,7 +160,7 @@ struct ChatListView: View { ForEach(cs, id: \.viewId) { chat in ChatListNavLink(chat: chat) .padding(.trailing, -16) - .disabled(chatModel.chatRunning != true) + .disabled(chatModel.chatRunning != true || chatModel.deletedChats.contains(chat.chatInfo.id)) } .offset(x: -8) } diff --git a/apps/ios/Shared/Views/ChatList/ChatPreviewView.swift b/apps/ios/Shared/Views/ChatList/ChatPreviewView.swift index 13d91881e6..0a53e0511a 100644 --- a/apps/ios/Shared/Views/ChatList/ChatPreviewView.swift +++ b/apps/ios/Shared/Views/ChatList/ChatPreviewView.swift @@ -13,6 +13,7 @@ struct ChatPreviewView: View { @EnvironmentObject var chatModel: ChatModel @ObservedObject var chat: Chat @Binding var progressByTimeout: Bool + @State var deleting: Bool = false @Environment(\.colorScheme) var colorScheme var darkGreen = Color(red: 0, green: 0.5, blue: 0) @@ -55,6 +56,9 @@ struct ChatPreviewView: View { .frame(maxHeight: .infinity) } .padding(.bottom, -8) + .onChange(of: chatModel.deletedChats.contains(chat.chatInfo.id)) { contains in + deleting = contains + } } @ViewBuilder private func chatPreviewImageOverlayIcon() -> some View { @@ -87,13 +91,13 @@ struct ChatPreviewView: View { let t = Text(chat.chatInfo.chatViewName).font(.title3).fontWeight(.bold) switch chat.chatInfo { case let .direct(contact): - previewTitle(contact.verified == true ? verifiedIcon + t : t) + previewTitle(contact.verified == true ? verifiedIcon + t : t).foregroundColor(deleting ? Color.secondary : nil) case let .group(groupInfo): - let v = previewTitle(t) + let v = previewTitle(t).foregroundColor(deleting ? Color.secondary : nil) switch (groupInfo.membership.memberStatus) { - case .memInvited: v.foregroundColor(chat.chatInfo.incognito ? .indigo : .accentColor) + case .memInvited: v.foregroundColor(deleting ? .secondary : chat.chatInfo.incognito ? .indigo : .accentColor) case .memAccepted: v.foregroundColor(.secondary) - default: v + default: v.foregroundColor(deleting ? Color.secondary : nil) } default: previewTitle(t) } diff --git a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.android.kt b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.android.kt index f8914c6653..f0f733111a 100644 --- a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.android.kt +++ b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.android.kt @@ -16,12 +16,12 @@ actual fun ChatListNavLinkLayout( click: () -> Unit, dropdownMenuItems: (@Composable () -> Unit)?, showMenu: MutableState, - stopped: Boolean, + disabled: Boolean, selectedChat: State, nextChatSelected: State, ) { var modifier = Modifier.fillMaxWidth() - if (!stopped) modifier = modifier + if (!disabled) modifier = modifier .combinedClickable(onClick = click, onLongClick = { showMenu.value = true }) .onRightClick { showMenu.value = true } Box(modifier) { 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 98c7336c2e..00d19b06f2 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 @@ -56,6 +56,8 @@ object ChatModel { // current chat val chatId = mutableStateOf(null) val chatItems = mutableStateListOf() + // rhId, chatId + val deletedChats = mutableStateOf>>(emptyList()) val chatItemStatuses = mutableMapOf() val groupMembers = mutableStateListOf() diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt index 110f12273f..363a3bcdbb 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt @@ -984,11 +984,12 @@ object ChatController { } suspend fun apiDeleteChat(rh: Long?, type: ChatType, id: Long, notify: Boolean? = null): Boolean { + chatModel.deletedChats.value += rh to type.type + id val r = sendCmd(rh, CC.ApiDeleteChat(type, id, notify)) - when { - r is CR.ContactDeleted && type == ChatType.Direct -> return true - r is CR.ContactConnectionDeleted && type == ChatType.ContactConnection -> return true - r is CR.GroupDeletedUser && type == ChatType.Group -> return true + val success = when { + r is CR.ContactDeleted && type == ChatType.Direct -> true + r is CR.ContactConnectionDeleted && type == ChatType.ContactConnection -> true + r is CR.GroupDeletedUser && type == ChatType.Group -> true else -> { val titleId = when (type) { ChatType.Direct -> MR.strings.error_deleting_contact @@ -997,9 +998,11 @@ object ChatController { ChatType.ContactConnection -> MR.strings.error_deleting_pending_contact_connection } apiErrorAlert("apiDeleteChat", generalGetString(titleId), r) + false } } - return false + chatModel.deletedChats.value -= rh to type.type + id + return success } suspend fun apiClearChat(rh: Long?, type: ChatType, id: Long): ChatInfo? { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.kt index 84ad14ed77..8cff56342d 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.kt @@ -37,7 +37,7 @@ fun ChatListNavLinkView(chat: Chat, nextChatSelected: State) { val showMarkRead = remember(chat.chatStats.unreadCount, chat.chatStats.unreadChat) { chat.chatStats.unreadCount > 0 || chat.chatStats.unreadChat } - val stopped = chatModel.chatRunning.value == false + val disabled = chatModel.chatRunning.value == false || chatModel.deletedChats.value.contains(chat.remoteHostId to chat.chatInfo.id) val linkMode by remember { chatModel.controller.appPrefs.simplexLinkMode.state } LaunchedEffect(chat.id) { showMenu.value = false @@ -62,7 +62,7 @@ fun ChatListNavLinkView(chat: Chat, nextChatSelected: State) { ChatListNavLinkLayout( chatLinkPreview = { tryOrShowError("${chat.id}ChatListNavLink", error = { ErrorChatListItem() }) { - ChatPreviewView(chat, showChatPreviews, chatModel.draft.value, chatModel.draftChatId.value, chatModel.currentUser.value?.profile?.displayName, contactNetworkStatus, stopped, linkMode, inProgress = false, progressByTimeout = false) + ChatPreviewView(chat, showChatPreviews, chatModel.draft.value, chatModel.draftChatId.value, chatModel.currentUser.value?.profile?.displayName, contactNetworkStatus, disabled, linkMode, inProgress = false, progressByTimeout = false) } }, click = { directChatAction(chat.remoteHostId, chat.chatInfo.contact, chatModel) }, @@ -72,7 +72,7 @@ fun ChatListNavLinkView(chat: Chat, nextChatSelected: State) { } }, showMenu, - stopped, + disabled, selectedChat, nextChatSelected, ) @@ -81,7 +81,7 @@ fun ChatListNavLinkView(chat: Chat, nextChatSelected: State) { ChatListNavLinkLayout( chatLinkPreview = { tryOrShowError("${chat.id}ChatListNavLink", error = { ErrorChatListItem() }) { - ChatPreviewView(chat, showChatPreviews, chatModel.draft.value, chatModel.draftChatId.value, chatModel.currentUser.value?.profile?.displayName, null, stopped, linkMode, inProgress.value, progressByTimeout) + ChatPreviewView(chat, showChatPreviews, chatModel.draft.value, chatModel.draftChatId.value, chatModel.currentUser.value?.profile?.displayName, null, disabled, linkMode, inProgress.value, progressByTimeout) } }, click = { if (!inProgress.value) groupChatAction(chat.remoteHostId, chat.chatInfo.groupInfo, chatModel, inProgress) }, @@ -91,7 +91,7 @@ fun ChatListNavLinkView(chat: Chat, nextChatSelected: State) { } }, showMenu, - stopped, + disabled, selectedChat, nextChatSelected, ) @@ -109,7 +109,7 @@ fun ChatListNavLinkView(chat: Chat, nextChatSelected: State) { } }, showMenu, - stopped, + disabled, selectedChat, nextChatSelected, ) @@ -129,7 +129,7 @@ fun ChatListNavLinkView(chat: Chat, nextChatSelected: State) { } }, showMenu, - stopped, + disabled, selectedChat, nextChatSelected, ) @@ -145,7 +145,7 @@ fun ChatListNavLinkView(chat: Chat, nextChatSelected: State) { }, dropdownMenuItems = null, showMenu, - stopped, + disabled, selectedChat, nextChatSelected, ) @@ -798,7 +798,7 @@ expect fun ChatListNavLinkLayout( click: () -> Unit, dropdownMenuItems: (@Composable () -> Unit)?, showMenu: MutableState, - stopped: Boolean, + disabled: Boolean, selectedChat: State, nextChatSelected: State, ) @@ -832,7 +832,7 @@ fun PreviewChatListNavLinkDirect() { null, null, null, - stopped = false, + disabled = false, linkMode = SimplexLinkMode.DESCRIPTION, inProgress = false, progressByTimeout = false @@ -841,7 +841,7 @@ fun PreviewChatListNavLinkDirect() { click = {}, dropdownMenuItems = null, showMenu = remember { mutableStateOf(false) }, - stopped = false, + disabled = false, selectedChat = remember { mutableStateOf(false) }, nextChatSelected = remember { mutableStateOf(false) } ) @@ -877,7 +877,7 @@ fun PreviewChatListNavLinkGroup() { null, null, null, - stopped = false, + disabled = false, linkMode = SimplexLinkMode.DESCRIPTION, inProgress = false, progressByTimeout = false @@ -886,7 +886,7 @@ fun PreviewChatListNavLinkGroup() { click = {}, dropdownMenuItems = null, showMenu = remember { mutableStateOf(false) }, - stopped = false, + disabled = false, selectedChat = remember { mutableStateOf(false) }, nextChatSelected = remember { mutableStateOf(false) } ) @@ -908,7 +908,7 @@ fun PreviewChatListNavLinkContactRequest() { click = {}, dropdownMenuItems = null, showMenu = remember { mutableStateOf(false) }, - stopped = false, + disabled = false, selectedChat = remember { mutableStateOf(false) }, nextChatSelected = remember { mutableStateOf(false) } ) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatPreviewView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatPreviewView.kt index d59dac37bf..08e95f391a 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatPreviewView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatPreviewView.kt @@ -25,6 +25,7 @@ import chat.simplex.common.views.chat.item.MarkdownText import chat.simplex.common.views.helpers.* import chat.simplex.common.model.* import chat.simplex.common.model.GroupInfo +import chat.simplex.common.platform.chatModel import chat.simplex.res.MR import dev.icerock.moko.resources.ImageResource @@ -36,7 +37,7 @@ fun ChatPreviewView( chatModelDraftChatId: ChatId?, currentUserProfileDisplayName: String?, contactNetworkStatus: NetworkStatus?, - stopped: Boolean, + disabled: Boolean, linkMode: SimplexLinkMode, inProgress: Boolean, progressByTimeout: Boolean @@ -127,24 +128,35 @@ fun ChatPreviewView( @Composable fun chatPreviewTitle() { + val deleting by remember(disabled, chat.id) { mutableStateOf(chatModel.deletedChats.value.contains(chat.remoteHostId to chat.chatInfo.id)) } when (cInfo) { is ChatInfo.Direct -> Row(verticalAlignment = Alignment.CenterVertically) { if (cInfo.contact.verified) { VerifiedIcon() } - chatPreviewTitleText() + chatPreviewTitleText( + if (deleting) + MaterialTheme.colors.secondary + else + Color.Unspecified + ) } is ChatInfo.Group -> when (cInfo.groupInfo.membership.memberStatus) { GroupMemberStatus.MemInvited -> chatPreviewTitleText( - if (inProgress) + if (inProgress || deleting) MaterialTheme.colors.secondary else if (chat.chatInfo.incognito) Indigo else MaterialTheme.colors.primary ) GroupMemberStatus.MemAccepted -> chatPreviewTitleText(MaterialTheme.colors.secondary) - else -> chatPreviewTitleText() + else -> chatPreviewTitleText( + if (deleting) + MaterialTheme.colors.secondary + else + Color.Unspecified + ) } else -> chatPreviewTitleText() } @@ -293,7 +305,7 @@ fun ChatPreviewView( color = Color.White, fontSize = 11.sp, modifier = Modifier - .background(if (stopped || showNtfsIcon) MaterialTheme.colors.secondary else MaterialTheme.colors.primaryVariant, shape = CircleShape) + .background(if (disabled || showNtfsIcon) MaterialTheme.colors.secondary else MaterialTheme.colors.primaryVariant, shape = CircleShape) .badgeLayout() .padding(horizontal = 3.dp) .padding(vertical = 1.dp) @@ -374,6 +386,6 @@ fun unreadCountStr(n: Int): String { @Composable fun PreviewChatPreviewView() { SimpleXTheme { - ChatPreviewView(Chat.sampleData, true, null, null, "", contactNetworkStatus = NetworkStatus.Connected(), stopped = false, linkMode = SimplexLinkMode.DESCRIPTION, inProgress = false, progressByTimeout = false) + ChatPreviewView(Chat.sampleData, true, null, null, "", contactNetworkStatus = NetworkStatus.Connected(), disabled = false, linkMode = SimplexLinkMode.DESCRIPTION, inProgress = false, progressByTimeout = false) } } diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.desktop.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.desktop.kt index b2fc451969..189f1842dd 100644 --- a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.desktop.kt +++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/chatlist/ChatListNavLinkView.desktop.kt @@ -9,7 +9,6 @@ import androidx.compose.material.MaterialTheme import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.drawscope.ContentDrawScope import androidx.compose.ui.unit.dp import chat.simplex.common.platform.onRightClick @@ -33,16 +32,16 @@ actual fun ChatListNavLinkLayout( click: () -> Unit, dropdownMenuItems: (@Composable () -> Unit)?, showMenu: MutableState, - stopped: Boolean, + disabled: Boolean, selectedChat: State, nextChatSelected: State, ) { var modifier = Modifier.fillMaxWidth() - if (!stopped) modifier = modifier + if (!disabled) modifier = modifier .combinedClickable(onClick = click, onLongClick = { showMenu.value = true }) .onRightClick { showMenu.value = true } CompositionLocalProvider( - LocalIndication provides if (selectedChat.value && !stopped) NoIndication else LocalIndication.current + LocalIndication provides if (selectedChat.value && !disabled) NoIndication else LocalIndication.current ) { Box(modifier) { Row( From afbb3b4e4b7e42c7ded5a3cd13c49d56e02000b9 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Wed, 10 Jan 2024 20:35:59 +0000 Subject: [PATCH 040/102] website: translations (#3667) * Translated using Weblate (Arabic) Currently translated at 100.0% (252 of 252 strings) Translation: SimpleX Chat/SimpleX Chat website Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/ar/ * Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (252 of 252 strings) Translation: SimpleX Chat/SimpleX Chat website Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/zh_Hans/ * Translated using Weblate (Japanese) Currently translated at 100.0% (252 of 252 strings) Translation: SimpleX Chat/SimpleX Chat website Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/ja/ * correction * correction * revert * keep new, revert changes in old ja strings --------- Co-authored-by: jonnysemon Co-authored-by: Eric Co-authored-by: yokoba0413 --- website/langs/ar.json | 120 ++++++++++++++++++------------------- website/langs/ja.json | 11 +++- website/langs/zh_Hans.json | 14 ++--- 3 files changed, 76 insertions(+), 69 deletions(-) diff --git a/website/langs/ar.json b/website/langs/ar.json index 73a0da295a..9a5207a779 100644 --- a/website/langs/ar.json +++ b/website/langs/ar.json @@ -8,8 +8,8 @@ "simplex-explained-tab-1-text": "1. تجربة المستخدم", "simplex-privacy": "خصوصية SimpleX", "simplex-explained-tab-3-text": "3. ما الذي تراة الخوادم", - "simplex-explained-tab-1-p-1": "يمكنك إنشاء جهات اتصال ومجموعات وإجراء محادثات ثنائية الاتجاه، كما هو الحال في أي برنامج مراسلة آخر.", - "simplex-explained-tab-3-p-2": "يمكن للمستخدمين زيادة تحسين خصوصية البيانات الوصفية باستخدام Tor للوصول إلى الخوادم، ومنع الارتباط بواسطة عنوان IP.", + "simplex-explained-tab-1-p-1": "يمكنك إنشاء جهات اتصال ومجموعات وإجراء مُحادثات ثنائية الاتجاه، كما هو الحال في أي برنامج مُراسلة آخر.", + "simplex-explained-tab-3-p-2": "يمكن للمستخدمين زيادة تحسين خصوصية البيانات الوصفية باستخدام تور للوصول إلى الخوادم، ومنع الارتباط بواسطة عنوان IP.", "chat-bot-example": "مثال بوت الدردشة", "smp-protocol": "بروتوكول SMP", "chat-protocol": "بروتوكول الدردشة", @@ -17,51 +17,51 @@ "terminal-cli": "طرفية CLI", "terms-and-privacy-policy": "الشروط وسياسة الخصوصية", "hero-header": "إعادة تعريف الخصوصية", - "hero-overlay-1-textlink": "لماذا تعتبر معرفات المستخدم ضارة بالخصوصية؟", + "hero-overlay-1-textlink": "لماذا تعتبر معرّفات المستخدم ضارة بالخصوصية؟", "hero-overlay-2-textlink": "كيف يعمل SimpleX؟", - "hero-overlay-2-title": "لماذا تعتبر معرفات المستخدم ضارة بالخصوصية؟", - "feature-2-title": "تشفير
الصور والفيديوهات والملفات بين الطرفين", - "feature-3-title": "مجموعات لامركزية مشفرة — المستخدمون فقط يعرفون بوجودها", - "feature-5-title": "محادثات سرية اختفائية", - "feature-6-title": "تشفير المكالمات الصوتية والفيديو
بين الطرفين", - "simplex-network-overlay-1-title": "مقارنة مع بروتوكولات المراسلة P2P", - "simplex-private-4-title": "وصول
اختياري عبر Tor", + "hero-overlay-2-title": "لماذا تعتبر معرّفات المستخدم ضارة بالخصوصية؟", + "feature-2-title": "تَعْمِيَة
الصور والفيديوهات والملفات بين الطرفين", + "feature-3-title": "المجموعات اللامركزية — المستخدمون فقط يعرفون بوجودها", + "feature-5-title": "رسائل ذاتية الاختفاء", + "feature-6-title": "تَعْمِيَة المكالمات الصوتية والفيديو
بين الطرفين", + "simplex-network-overlay-1-title": "مقارنة مع بروتوكولات المُراسلة P2P", + "simplex-private-4-title": "وصول
اختياري عبر تور", "simplex-explained-tab-2-text": "2. كيف يعمل", - "simplex-explained-tab-1-p-2": "كيف يمكن أن تعمل مع قوائم انتظار أحادية الاتجاه وبدون معرفات ملف تعريف المستخدم؟", - "simplex-explained-tab-2-p-1": "لكل اتصال، تستخدم قائمتي انتظار منفصلتين للمراسلة لإرسال واستقبال الرسائل عبر خوادم مختلفة.", - "simplex-explained-tab-2-p-2": "تقوم الخوادم بتمرير الرسائل في اتجاه واحد فقط، دون الحصول على الصورة الكاملة لمحادثات المستخدم أو اتصالاته.", + "simplex-explained-tab-1-p-2": "كيف يمكن أن تعمل مع قوائم انتظار أحادية الاتجاه وبدون معرّفات ملف تعريف المستخدم؟", + "simplex-explained-tab-2-p-1": "لكل اتصال، تستخدم قائمتي انتظار منفصلتين للمُراسلة لإرسال واستلام الرسائل عبر خوادم مختلفة.", + "simplex-explained-tab-2-p-2": "تقوم الخوادم بتمرير الرسائل في اتجاه واحد فقط، دون الحصول على الصورة الكاملة لمُحادثات المستخدم أو اتصالاته.", "simplex-explained-tab-3-p-1": "تحتوي الخوادم على بيانات اعتماد مجهولة منفصلة لكل قائمة انتظار، ولا تعرف المستخدمين الذين ينتمون إليهم.", "copyright-label": "مشروع مفتوح المصدر © SimpleX 2020-2023", "simplex-chat-protocol": "بروتوكول دردشة SimpleX", "developers": "المطورين", - "hero-subheader": "أول نظام مراسلة
بدون معرفات المستخدم", + "hero-subheader": "أول نظام مُراسلة
بدون معرّفات المستخدم", "hero-p-1": "تحتوي التطبيقات الأخرى على معرّفات مستخدم: Signal ،Matrix ،Session ،Briar ،Jami ،Cwtch وما إلى ذلك.
SimpleX ليس لديه، ولا حتى أرقام عشوائية.
وهذا يحسن خصوصيتك بشكل جذري.", "features": "الميزات", - "hero-2-header": "قم بإجراء اتصال خاص", + "hero-2-header": "أجري اتصال خاص", "hero-overlay-1-title": "كيف يعمل SimpleX؟", "hero-2-header-desc": "يُظهر الفيديو كيفية اتصالك بصديقك عبر رمز الاستجابة السريعة لمرة واحدة (QR code)، شخصيًا أو عبر رابط فيديو. يمكنك أيضًا الاتصال من خلال مشاركة رابط الدعوة.", - "feature-1-title": "تشفير الرسائل بين الطرفين مع دعم ماركداون والتحرير", - "feature-4-title": "تشفير الرسائل الصوتية بين الطرفين", + "feature-1-title": "تَعْمِيَة الرسائل بين الطرفين مع دعم ماركداون والتعديل", + "feature-4-title": "تَعْمِيَة الرسائل الصوتية بين الطرفين", "privacy-matters-overlay-card-1-p-1": "تستخدم العديد من الشركات الكبيرة معلومات حول من تتصل به لتقدير دخلك، وبيع المنتجات التي لا تحتاجها حقًا، ولتحديد الأسعار.", - "feature-7-title": "تخزين التطبيقات المشفرة المحمولة — نقل ملف التعريف إلى جهاز آخر", + "feature-7-title": "تخزين بيانات التطبيق مُعمَّاة ومحمولة — نقل ملف التعريف إلى جهاز آخر", "feature-8-title": "وضع التخفي —
فريد من نوعه لـ SimpleX Chat", - "simplex-private-1-title": "طبقتان من
التشفير بين الطرفين", - "simplex-private-2-title": "طبقة إضافية من
تشفير الخادم", + "simplex-private-1-title": "طبقتان من
التَعْمِيَة بين الطرفين", + "simplex-private-2-title": "طبقة إضافية من
تَعْمِيَة الخادم", "simplex-private-3-title": "تأمين نقل
TLS المصدق عليه", "simplex-private-5-title": "طبقات متعددة من
حشوة المحتوى", "simplex-private-7-title": "التحقق
من سلامة الرسالة", "simplex-private-8-title": "خلط الرسائل
لتقليل من الارتباط", - "simplex-private-10-title": "معرفات مزدوجة مؤقتة مجهولة الهوية", + "simplex-private-10-title": "معرفات زوجية مجهولة مؤقتة", "simplex-private-card-3-point-1": "يتم استخدام TLS 1.2 / 1.3 مع خوارزميات قوية فقط لاتصالات الخادم والعميل.", "simplex-private-card-3-point-2": "تعمل بصمة الخادم وربط القناة على منع هجمات الوسيط (MITM) وإعادة التشغيل.", "simplex-private-card-3-point-3": "استئناف الاتصال معطل لمنع هجمات الجلسة.", - "simplex-private-card-4-point-1": "لحماية عنوان IP الخاص بك، يمكنك الوصول إلى الخوادم عبر Tor أو بعض شبكات تراكب النقل الأخرى.", - "simplex-private-card-5-point-1": "يستخدم SimpleX حشوة المحتوى لكل طبقة تشفير لإحباط هجمات حجم الرسالة.", + "simplex-private-card-4-point-1": "لحماية عنوان IP الخاص بك، يمكنك الوصول إلى الخوادم عبر تور أو بعض شبكات تراكب النقل الأخرى.", + "simplex-private-card-5-point-1": "يستخدم SimpleX حشوة المحتوى لكل طبقة تَعْمِيَة لإحباط هجمات حجم الرسالة.", "simplex-private-card-6-point-2": "لمنع ذلك، تقوم تطبيقات SimpleX بتمرير مفاتيح لمرة واحدة خارج النطاق، عند مشاركة عنوان كرابط أو رمز QR.", "simplex-private-card-8-point-1": "تعمل خوادم SimpleX كعقد مختلطة بزمن انتقال منخفض — الرسائل الواردة والصادرة لها ترتيب مختلف.", "simplex-private-card-9-point-1": "كل رسالة انتظار تمرر الرسائل في اتجاه واحد، بعناوين إرسال واستلام مختلفة.", "simplex-private-card-9-point-2": "إنه يقلل من نواقل الهجوم، مقارنة بوسطاء الرسائل التقليديين، والبيانات الوصفية المتاحة.", - "simplex-private-card-10-point-1": "يستخدم SimpleX معرفات مزدوجة مؤقتة مجهولة الهوية للعناوين وبيانات الاعتماد لكل جهة اتصال مستخدم أو عضو مجموعة.", + "simplex-private-card-10-point-1": "يستخدم SimpleX معرّفات مزدوجة مؤقتة مجهولة الهوية للعناوين وبيانات الاعتماد لكل جهة اتصال مستخدم أو عضو مجموعة.", "privacy-matters-1-title": "الإعلانات والتمييز السعري", "privacy-matters-1-overlay-1-title": "الخصوصية توفر لك المال", "privacy-matters-1-overlay-1-linkText": "الخصوصية توفر لك المال", @@ -78,7 +78,7 @@ "simplex-unique-4-title": "أنت تمتلك شبكة SimpleX", "simplex-unique-4-overlay-1-title": "لامركزية بالكامل — يمتلك المستخدمون شبكة SimpleX", "hero-overlay-card-1-p-4": "هذا التصميم يمنع تسريب أي البيانات الوصفية للمستخدمين على مستوى التطبيق. لزيادة تحسين الخصوصية وحماية عنوان IP الخاص بك، يمكنك الاتصال بخوادم المراسلة عبر Tor.", - "hero-overlay-card-1-p-5": "الأجهزة العميلة فقط هي التي تخزن ملفات تعريف المستخدمين، جهات الاتصال والمجموعات؛ يتم إرسال الرسائل بتشفير ثنائي الطبقة من طرف إلى طرف.", + "hero-overlay-card-1-p-5": "الأجهزة العميلة فقط هي التي تخزن ملفات تعريف المستخدمين، جهات الاتصال والمجموعات؛ يتم إرسال الرسائل بتَعْمِيَة ثنائية الطبقة من طرف إلى طرف.", "hero-overlay-card-2-p-2": "يمكنهم بعد ذلك ربط هذه المعلومات بالشبكات الاجتماعية العامة الحالية، وتحديد بعض الهويات الحقيقية.", "simplex-network-overlay-card-1-li-3": "P2P لا يحل مشكلة هجوم الوسيط (MITM)، ومعظم التطبيقات الحالية لا تستخدم خارج النطاق رسائل للتبادل الأولي للمفاتيح. يستخدم SimpleX رسائل خارج النطاق أو، في بعض الحالات، اتصالات آمنة وموثوق بها موجودة مسبقًا لتبادل المفاتيح الأولي.", "privacy-matters-overlay-card-1-p-3": "تستخدم بعض الشركات المالية والتأمين رسوماً بيانية اجتماعية لتحديد أسعار الفائدة وأقساط التأمين. عادةً ما تجعل الأشخاص ذوي الدخل المنخفض يدفعون أكثر — أو كما يسمى \"علاوة الفقر\".", @@ -88,45 +88,45 @@ "privacy-matters-overlay-card-1-p-4": "تحمي منصة SimpleX خصوصية اتصالاتك بشكل أفضل من أي بديل آخر، مما يمنع تمامًا الرسم البياني الاجتماعي الخاص بك من أن يصبح متاحًا لأي شركات أو مؤسسات. حتى عندما يستخدم الأشخاص الخوادم التي توفرها SimpleX Chat، فإننا لا نعرف عدد المستخدمين أو اتصالاتهم.", "simplex-private-card-1-point-1": "بروتوكول السقاطة المزدوجة —
رسائل OTR مع السرية المستمرة واستعادة الاختراق.", "simplex-private-card-1-point-2": "NaCL cryptobox في كل قائمة انتظار لمنع ارتباط حركة مرور البيانات بين قوائم انتظار الرسائل في حالة اختراق TLS.", - "simplex-private-card-2-point-1": "طبقة إضافية من تشفير الخادم للتسليم إلى المستلم، لمنع الارتباط بين حركة مرور بيانات الخادم المستلمة والمرسلة في حالة اختراق TLS.", - "simplex-private-card-4-point-2": "لاستخدام SimpleX عبر Tor، يرجى تثبيت تطبيق Orbot وتمكين وكيل SOCKS5 (أو VPN على iOS ).", + "simplex-private-card-2-point-1": "طبقة إضافية من تَعْمِيَة الخادم للتسليم إلى المُستلم، لمنع الارتباط بين حركة مرور بيانات الخادم المُستلمة والمُرسلة في حالة اختراق TLS.", + "simplex-private-card-4-point-2": "لاستخدام SimpleX عبر تور، يُرجى تثبيت تطبيق Orbot وتمكّين وكيل SOCKS5 (أو VPN على iOS ).", "simplex-private-card-5-point-2": "يجعل الرسائل ذات الأحجام المختلفة تبدو متشابهة للخوادم ومراقبي الشبكة.", "simplex-private-card-6-point-1": "العديد من منصات الاتصال عرضة لهجمات الوسيط (MITM) من قبل الخوادم أو موفري الشبكات.", "simplex-private-card-7-point-1": "لضمان سلامة الرسائل يتم ترقيمها بالتسلسل وتضمين تجزئة الرسالة السابقة.", - "simplex-private-card-7-point-2": "إذا تمت إضافة أي رسالة أو إزالتها أو تغييرها، فسيتم تنبيه المستلم.", - "simplex-private-card-10-point-2": "يسمح بتسليم الرسائل بدون معرفات ملف تعريف المستخدم، مما يوفر خصوصية بيانات وصفية أفضل من البدائل.", + "simplex-private-card-7-point-2": "إذا أُضيفت أي رسالة أو أُزيلت أو تغيّرت، فسيتم تنبيه المُستلم.", + "simplex-private-card-10-point-2": "يسمح بتسليم الرسائل بدون معرّفات ملف تعريف المستخدم، مما يوفر خصوصية للبيانات الوصفية أفضل من البدائل.", "privacy-matters-2-overlay-1-linkText": "تمنحك الخصوصية القوة", "simplex-unique-2-overlay-1-title": "أفضل حماية من البريد العشوائي وإساءة الاستخدام", - "hero-overlay-card-1-p-3": "أنت تحدد الخادم (الخوادم) المراد استخدامه لتلقي الرسائل وجهات الاتصال الخاصة بك — الخوادم التي تستخدمها لإرسال الرسائل إليهم. من المرجح أن تستخدم كل محادثة خادمين مختلفين.", - "hero-overlay-card-1-p-1": "سأل العديد من المستخدمين: إذا لم يكن لدى SimpleX معرفات مستخدم، فكيف يمكنها معرفة مكان تسليم الرسائل؟ ", - "hero-overlay-card-1-p-2": "لتوصيل الرسائل، بدلاً من معرفات المستخدم التي تستخدمها جميع المنصات الأخرى، يستخدم SimpleX معرفات مزدوجة مؤقتة مجهولة الهوية لقوائم انتظار الرسائل، مختلفة لكل اتصال من اتصالاتك — لا توجد معرفات مستخدم دائمة.", - "simplex-network-overlay-card-1-p-1": "بروتوكولات المراسلة والتطبيقات P2P بها مشاكل مختلفة تجعلها أقل موثوقية من SimpleX وأكثر تعقيدًا في التحليل و عرضة لعدة أنواع من الهجمات.", + "hero-overlay-card-1-p-3": "أنت تحدد الخادم (الخوادم) المراد استخدامه لاستلام الرسائل وجهات الاتصال الخاصة بك — الخوادم التي تستخدمها لإرسال الرسائل إليهم. من المرجح أن تستخدم كل مُحادثة خادمين مختلفين.", + "hero-overlay-card-1-p-1": "سأل العديد من المستخدمين: إذا لم يكن لدى SimpleX معرّفات مستخدم، فكيف يمكنها معرفة مكان تسليم الرسائل؟ ", + "hero-overlay-card-1-p-2": "لتوصيل الرسائل، بدلاً من معرفات المستخدم التي تستخدمها جميع المنصات الأخرى، يستخدم SimpleX معرّفات مزدوجة مؤقتة مجهولة الهوية لقوائم انتظار الرسائل، مختلفة لكل اتصال من اتصالاتك — لا توجد معرفات مستخدم دائمة.", + "simplex-network-overlay-card-1-p-1": "بروتوكولات المُراسلة والتطبيقات P2P بها مشاكل مختلفة تجعلها أقل موثوقية من SimpleX وأكثر تعقيدًا في التحليل و عرضة لعدة أنواع من الهجمات.", "hero-overlay-card-2-p-1": "عندما يكون لدى المستخدمين هويات ثابتة، حتى لو كان هذا مجرد رقم عشوائي، مثل معرف الجلسة، فهناك خطر يتمثل في أن الموفر أو المهاجم يمكنه مراقبة كيفية اتصال المستخدمين وعدد الرسائل التي يرسلونها.", "hero-overlay-card-1-p-6": "اقرأ المزيد في SimpleX whitepaper .", "hero-overlay-card-2-p-3": "حتى مع معظم التطبيقات الخاصة التي تستخدم خدمات Tor v3، إذا تحدثت إلى جهتي اتصال مختلفتين عبر نفس الملف الشخصي، فيمكنهما إثبات أنهما متصلان بنفس الشخص.", - "hero-overlay-card-2-p-4": "يحمي SimpleX من هذه الهجمات من خلال عدم وجود أي معرفات مستخدم في تصميمه. وإذا كنت تستخدم وضع التخفي، فسيكون لديك اسم عرض مختلف لكل جهة اتصال، مع تجنب أي بيانات مشتركة بينهما.", - "simplex-network-overlay-card-1-li-6": "قد تكون شبكات P2P عرضة هجوم DRDoS، عندما يتمكن العملاء من إعادة بث حركة مرور البيانات وتضخيمها، مما يؤدي إلى رفض الخدمة على مستوى الشبكة. يقوم عملاء SimpleX فقط بترحيل حركة مرور البيانات من اتصال معروف ولا يمكن للمهاجم استخدامها لتضخيم حركة مرور البيانات في الشبكة بالكامل.", - "simplex-network-overlay-card-1-li-1": "تعتمد شبكات P2P على بعض المتغيرات من DHT لتوجيه الرسائل. يجب أن توازن تصميمات DHT بين ضمان التسليم وزمن الوصول. تتمتع SimpleX بضمان تسليم أفضل وزمن انتقال أقل من P2P، لأنه يمكن تمرير الرسالة بشكل متكرر عبر عدة خوادم بالتوازي، باستخدام الخوادم التي اختارها المستلم. في شبكات P2P، يتم تمرير الرسالة عبر عُقد O (log N) بالتسلسل، باستخدام العقد التي تختارها الخوارزمية.", + "hero-overlay-card-2-p-4": "يحمي SimpleX من هذه الهجمات من خلال عدم وجود أي معرّفات مستخدم في تصميمه. وإذا كنت تستخدم وضع التخفي، فسيكون لديك اسم عرض مختلف لكل جهة اتصال، مع تجنب أي بيانات مشتركة بينهما.", + "simplex-network-overlay-card-1-li-6": "قد تكون شبكات P2P عرضة هجوم DRDoS، عندما يتمكّن العملاء من إعادة بث حركة مرور البيانات وتضخيمها، مما يؤدي إلى رفض الخدمة على مستوى الشبكة. يقوم عملاء SimpleX فقط بترحيل حركة مرور البيانات من اتصال معروف ولا يمكن للمهاجم استخدامها لتضخيم حركة مرور البيانات في الشبكة بالكامل.", + "simplex-network-overlay-card-1-li-1": "تعتمد شبكات P2P على بعض المتغيرات من DHT لتوجيه الرسائل. يجب أن توازن تصميمات DHT بين ضمان التسليم وزمن الوصول. تتمتع SimpleX بضمان تسليم أفضل وزمن انتقال أقل من P2P، لأنه يمكّن تمرير الرسالة بشكل متكرر عبر عدة خوادم بالتوازي، باستخدام الخوادم التي اختارها المُستلم. في شبكات P2P، يتم تمرير الرسالة عبر عُقد O (log N) بالتسلسل، باستخدام العُقد التي تختارها الخوارزمية.", "simplex-network-overlay-card-1-li-2": "لا يحتوي تصميم SimpleX، عكس معظم شبكات P2P، على معرّفات مستخدم عالمية من أي نوع، حتى مؤقتة، ويستخدم فقط المعرّفات المزدوجة المؤقتة، مما يوفر إخفاء هوية أفضل وحماية للبيانات الوصفية.", "simplex-network-overlay-card-1-li-4": "يمكن لبعض مزودي خدمة الإنترنت حظر تطبيقات P2P (مثل BitTorrent ). SimpleX حيادي النقل - يمكنه العمل عبر بروتوكولات الويب القياسية، على سبيل المثال WebSockets.", "simplex-network-overlay-card-1-li-5": "قد تكون جميع شبكات P2P المعروفة عرضة لهجوم Sybil، لأن كل عقدة قابلة للاكتشاف، وتعمل الشبكة ككل. تتطلب الإجراءات المعروفة لتخفيفها إما مكونًا مركزيًا أو إثبات عمل مكلف . لا تحتوي شبكة SimpleX على إمكانية اكتشاف الخادم، فهي مجزأة وتعمل كشبكات فرعية متعددة ومعزولة، مما يجعل الهجمات على مستوى الشبكة مستحيلة.", - "privacy-matters-overlay-card-3-p-1": "يجب على الجميع الاهتمام بخصوصية وأمان اتصالاتهم — يمكن للمحادثات غير الضارة أن تعرضك للخطر، حتى لو لم يكن لديك ما تخفيه.", - "privacy-matters-overlay-card-3-p-4": "لا يكفي استخدام برنامج مراسلة مشفر من طرف إلى طرف، يجب علينا جميعًا استخدام برامج المراسلة التي تحمي خصوصية شبكاتنا الشخصية — مع من نحن مرتبطون.", - "simplex-unique-overlay-card-1-p-3": "يحمي هذا التصميم خصوصية الأشخاص الذين تتواصل معهم، ويخفيها عن خوادم منصة SimpleX ومن أي مراقبين. لإخفاء عنوان IP الخاص بك من الخوادم، يمكنك الاتصال بخوادم SimpleX عبر Tor.", + "privacy-matters-overlay-card-3-p-1": "يجب على الجميع الاهتمام بخصوصية وأمان اتصالاتهم — يمكن للمُحادثات غير الضارة أن تعرضك للخطر، حتى لو لم يكن لديك ما تخفيه.", + "privacy-matters-overlay-card-3-p-4": "لا يكفي استخدام برنامج مُراسلة مُعمَّاة من طرف إلى طرف، يجب علينا جميعًا استخدام برامج مُراسلة التي تحمي خصوصية شبكاتنا الشخصية — مع من نحن مرتبطون.", + "simplex-unique-overlay-card-1-p-3": "يحمي هذا التصميم خصوصية الأشخاص الذين تتواصل معهم، ويخفيها عن خوادم منصة SimpleX ومن أي مراقبين. لإخفاء عنوان IP الخاص بك من الخوادم، يمكنك الاتصال بخوادم SimpleX عبر تور.", "simplex-unique-overlay-card-2-p-1": "نظرًا لعدم وجود معرف لديك على نظام SimpleX، لا يمكن لأي شخص الاتصال بك ما لم تشارك عنوان مستخدم لمرة واحدة أو مؤقتًا، كرمز QR أو رابط.", "simplex-unique-overlay-card-2-p-2": "حتى مع عنوان المستخدم الاختياري، بينما يمكن استخدامه لإرسال طلبات جهات اتصال غير مرغوب فيها، يمكنك تغييره أو حذفه بالكامل دون فقد أي من اتصالاتك.", - "simplex-unique-overlay-card-3-p-2": "يتم الاحتفاظ بالرسائل المشفرة من طرف إلى طرف مؤقتًا على خوادم ترحيل SimpleX حتى يتم استلامها، ثم يتم حذفها نهائيًا.", - "simplex-unique-overlay-card-3-p-4": "لا توجد معرفات أو نص مشفر مشترك بين حركة مرور بيانات الخادم المرسلة والمستلمة — ؛ إذا كان أي شخص يراقب ذلك، فلن يتمكن بسهولة من تحديد من يتواصل مع من، حتى لو تم اختراق TLS.", + "simplex-unique-overlay-card-3-p-2": "يتم الاحتفاظ بالرسائل المُعمَّاة من طرف إلى طرف مؤقتًا على خوادم ترحيل SimpleX حتى يتم استلامها، ثُمَّ تُحذف نهائيًا.", + "simplex-unique-overlay-card-3-p-4": "لا توجد معرفّات أو نص مُعَمَّى مشترك بين حركة مرور بيانات الخادم المُرسلة والمُستلمة — ؛ إذا كان أي شخص يراقب ذلك، فلن يتمكّن بسهولة من تحديد من يتواصل مع من، حتى لو اختُرق TLS.", "simplex-unique-card-1-p-1": "يحمي SimpleX خصوصية ملف التعريف الخاص بك، جهات الاتصال والبيانات الوصفية، ويخفيه عن خوادم منصة SimpleX وأي مراقبين.", "privacy-matters-overlay-card-2-p-1": "منذ وقت ليس ببعيد، لاحظنا أن الانتخابات الرئيسية يتم التلاعب بها بواسطة شركة استشارية ذات سمعة طيبة التي استخدمت الرسوم البيانية الاجتماعية لتشويه نظرتنا للعالم الحقيقي والتلاعب بأصواتنا.", "privacy-matters-overlay-card-2-p-2": "لكي تكون موضوعيًا وتتخذ قرارات مستقلة، يجب أن تكون متحكمًا في مساحة المعلومات الخاصة بك. هذا ممكن فقط إذا كنت تستخدم منصة اتصالات خاصة لا يمكنها الوصول إلى الرسم البياني الاجتماعي الخاص بك.", - "privacy-matters-overlay-card-2-p-3": "SimpleX هو النظام الأساسي الأول الذي لا يحتوي على أي معرفات مستخدم صمّم ليكون خاصًا، وبهذه الطريقة تحمي مخطط اتصالاتك بشكل أفضل من أي بديل معروف.", + "privacy-matters-overlay-card-2-p-3": "SimpleX هو النظام الأساسي الأول الذي لا يحتوي على أي معرّفات مستخدم صمّم ليكون خاصًا، وبهذه الطريقة تحمي مخطط اتصالاتك بشكل أفضل من أي بديل معروف.", "privacy-matters-overlay-card-3-p-2": "واحدة من أكثر القصص إثارة للصدمة هي تجربة محمدو ولد صلاحي الموصوفة في مذكراته والموضحة في فيلم موريتاني. تم وضعه في معتقل غوانتانامو بدون محاكمة، وتعرض للتعذيب هناك لمدة 15 عامًا بعد مكالمة هاتفية مع قريبه في أفغانستان، للاشتباه في تورطه في هجمات 11 سبتمبر، على الرغم من أنه عاش في ألمانيا طوال السنوات العشر الماضية.", "privacy-matters-overlay-card-3-p-3": "يتم القبض على الأشخاص العاديين بسبب ما يشاركونه عبر الإنترنت، حتى عبر حساباتهم \"المجهولة\"، وحتى في البلدان الديمقراطية.", - "simplex-unique-overlay-card-1-p-1": "على عكس أنظمة المراسلة الأخرى، لا يحتوي SimpleX على معرفات مخصصة للمستخدمين. لا يعتمد على أرقام الهواتف أو العناوين المستندة إلى النطاقات (مثل البريد الإلكتروني أو XMPP)، أسماء المستخدمين، المفاتيح العامة أو حتى الأرقام العشوائية لتحديد مستخدميها — لا نعرف عدد الأشخاص الذين يستخدمون خوادم SimpleX الخاصة بنا.", - "simplex-unique-overlay-card-1-p-2": "لتسليم الرسائل، يستخدم SimpleX العناوين المزدوجة المجهولة لقوائم انتظار الرسائل أحادية الاتجاه، منفصلة عن الرسائل المستلمة والمرسلة، عادةً عبر خوادم مختلفة. إن استخدام SimpleX يشبه امتلاك بريد إلكتروني أو هاتف “مؤقت” مختلف لكل جهة اتصال، ولا توجد متاعب في إدارتها.", - "simplex-unique-overlay-card-3-p-1": "يخزن SimpleX Chat جميع بيانات المستخدم على أجهزة العميل فقط باستخدام تنسيق قاعدة بيانات محمولة مشفرة يمكن تصديرها ونقلها إلى أي جهاز مدعوم.", - "simplex-unique-overlay-card-3-p-3": "على عكس خوادم الشبكات الموحدة (البريد الإلكتروني أو XMPP أو Matrix)، لا تقوم خوادم SimpleX بتخزين حسابات المستخدمين، فهي تقوم فقط بترحيل الرسائل، مما يحمي خصوصية كلا الطرفين.", + "simplex-unique-overlay-card-1-p-1": "على عكس أنظمة المُراسلة الأخرى، لا يحتوي SimpleX على معرّفات مخصصة للمستخدمين. لا يعتمد على أرقام الهواتف أو العناوين المستندة إلى النطاقات (مثل البريد الإلكتروني أو XMPP)، أسماء المستخدمين، المفاتيح العامة أو حتى الأرقام العشوائية لتحديد مستخدميها — لا نعرف عدد الأشخاص الذين يستخدمون خوادم SimpleX الخاصة بنا.", + "simplex-unique-overlay-card-1-p-2": "لتسليم الرسائل، يستخدم SimpleX العناوين المزدوجة المجهولة لقوائم انتظار الرسائل أحادية الاتجاه، منفصلة عن الرسائل المُستلمة والمُرسلة، عادةً عبر خوادم مختلفة. إن استخدام SimpleX يشبه امتلاك بريد إلكتروني أو هاتف “مؤقت” مختلف لكل جهة اتصال، ولا توجد متاعب في إدارتها.", + "simplex-unique-overlay-card-3-p-1": "يخزن SimpleX Chat جميع بيانات المستخدم على أجهزة العميل فقط باستخدام تنسيق قاعدة بيانات محمولة مُعمَّاة يمكّن تصديرها ونقلها إلى أي جهاز مدعوم.", + "simplex-unique-overlay-card-3-p-3": "على عكس خوادم الشبكات الاتحادية (البريد الإلكتروني أو XMPP أو Matrix)، لا تقوم خوادم SimpleX بتخزين حسابات المستخدمين، فهي تقوم فقط بترحيل الرسائل، مما يحمي خصوصية كلا الطرفين.", "simplex-unique-overlay-card-4-p-1": "يمكنك استخدام SimpleX مع الخوادم الخاصة بك والاستمرار في التواصل مع الأشخاص الذين يستخدمون الخوادم المهيأة مسبقًا التي نقدمها.", "simplex-unique-overlay-card-4-p-3": "إذا كنت تفكر في التطوير لمنصة SimpleX، على سبيل المثال، بوت الدردشة لمستخدمي تطبيق SimpleX، أو دمج مكتبة SimpleX Chat في تطبيقات الأجهزة المحمولة، من فضلك تواصل معي لأي نصيحة والدعم.", "donate-here-to-help-us": "تبرّع هنا لمساعدتنا", @@ -151,21 +151,21 @@ "no-private": "لا - خصوصي", "no-resilient": "لا - مرن", "no-decentralized": "لا - لامركزي", - "no-federated": "لا - فدرالي", + "no-federated": "لا - اتِحاديّ", "comparison-section-list-point-2": "العناوين تعتمد على الـDNS", "comparison-section-list-point-3": "المفتاح العام أو معرف آخر فريد وعام", "comparison-section-list-point-7": "شبكات P2P إما لديها سلطة مركزية أو أن الشبكة كلها يمكن عرضة للخطر", "see-here": "اقرأ هنا", "no-secure": "لا - آمن", "comparison-section-list-point-5": "لا يحمي خصوصية البيانات الوصفية للمستخدمين", - "comparison-section-list-point-6": "على الرغم من أن الـP2P موزعة، إلا أنها ليست فدرالية - يعملون كشبكة واحدة", + "comparison-section-list-point-6": "على الرغم من أن الـP2P موزعة، إلا أنها ليست اتِحاديَّة - يعملون كشبكة واحدة", "comparison-section-list-point-1": "عادة ما يكون مكوناً من رقم الهاتف، أو اسم المستخدم في بعض الأحيان", "comparison-section-list-point-4": "إذا خوادم المشغّل مُخترقة. تحقق من رمز الأمان في Signal وبعض التطبيقات الأخرى للتخفيف منه", - "simplex-unique-card-3-p-1": "يخزن SimpleX جميع بيانات المستخدم على الأجهزة العميلة بتنسيق قاعدة بيانات محمولة مشفرة — يمكن نقله إلى جهاز آخر.", - "simplex-unique-card-4-p-1": "شبكة SimpleX لا مركزية بالكامل ومستقلة عن أي عملة مشفرة أو أي منصة أخرى، بخلاف الإنترنت.", + "simplex-unique-card-3-p-1": "يخزن SimpleX جميع بيانات المستخدم على الأجهزة العميلة بتنسيق قاعدة بيانات محمولة مُعمَّاة — يمكّن نقله إلى جهاز آخر.", + "simplex-unique-card-4-p-1": "شبكة SimpleX لا مركزية بالكامل ومستقلة عن أي عملة مُعمَّاة أو أي منصة أخرى، بخلاف الإنترنت.", "simplex-unique-card-4-p-2": "يمكنك استخدام SimpleX مع خوادمك الخاصة أو مع الخوادم التي نوفرها — ولا يزال الاتصال ممكن بأي مستخدم.", "join": "انضم إلى", - "we-invite-you-to-join-the-conversation": "نحن ندعوك للانضمام إلى محادثة", + "we-invite-you-to-join-the-conversation": "نحن ندعوك للانضمام إلى المُحادثة", "join-the-REDDIT-community": "انضم إلى مجتمع REDDIT", "join-us-on-GitHub": "انضم إلينا على GitHub", "contact-hero-p-2": "لم تقم بتنزيل SimpleX Chat حتى الآن؟", @@ -183,27 +183,27 @@ "if-you-already-installed-simplex-chat-for-the-terminal": "إذا قمت بالفعل بتثبيت SimpleX Chat للوحدة الطرفية", "simplex-chat-for-the-terminal": "SimpleX Chat للوحدة الطرفية", "privacy-matters-section-header": "لماذا الخصوصية مهمة", - "privacy-matters-section-label": "تأكد من أن برنامج المراسلة الخاص بك لا يمكنه الوصول إلى بياناتك!", + "privacy-matters-section-label": "تأكّد من أن برنامج المُراسلة الخاص بك لا يمكنه الوصول إلى بياناتك!", "tap-to-close": "انقر للإغلاق", "simplex-network-section-header": "شبكة SimpleX ", "simplex-network-1-header": "على عكس شبكات P2P", "simplex-network-3-header": "شبكة SimpleX", "protocol-1-text": "Signal، منصات كبيرة", "protocol-2-text": "XMPP ،Matrix", - "simplex-unique-card-1-p-2": "بخلاف أي نظام أساسي آخر للمراسلة، لا يحتوي SimpleX على معرّفات مخصصة للمستخدمين — ولا حتى أرقام عشوائية.", + "simplex-unique-card-1-p-2": "بخلاف أي نظام مُراسلة آخر، لا يحتوي SimpleX على معرّفات مخصصة للمستخدمين — ولا حتى أرقام عشوائية.", "simplex-unique-card-2-p-1": "نظرًا لعدم وجود معرف أو عنوان ثابت على منصة SimpleX، لا يمكن لأي شخص الاتصال بك ما لم تشارك عنوان مستخدم لمرة واحدة أو مؤقتًا، كرمز QR أو رابط.", - "simplex-unique-card-3-p-2": "يتم الاحتفاظ بالرسائل المشفرة من طرف إلى طرف مؤقتًا على خوادم ترحيل SimpleX حتى يتم استلامها، ثم يتم حذفها نهائيًا.", + "simplex-unique-card-3-p-2": "يتم الاحتفاظ بالرسائل المُعمَّاة من طرف إلى طرف مؤقتًا على خوادم ترحيل SimpleX حتى يتم استلامها، ثُمَّ تُحذف نهائيًا.", "tap-the-connect-button-in-the-app": "اضغط على زر \"اتصال\" في التطبيق", "scan-the-qr-code-with-the-simplex-chat-app": "امسح رمز QR باستخدام تطبيق SimpleX Chat", "scan-the-qr-code-with-the-simplex-chat-app-description": "لا يتم إرسال المفاتيح العامة وعنوان قائمة انتظار الرسائل في هذا الارتباط عبر الشبكة عند عرض هذه الصفحة —
فهي موجودة في جزء التجزئة لعنوان URL للرابط.", "if-you-already-installed": "إذا قمت بالفعل بتثبيت", "copy-the-command-below-text": "انسخ الأمر الذي في الاسفل واستخدمه في الدردشة:", - "simplex-private-section-header": "ما الذي يجعل SimpleX خاصًا ", + "simplex-private-section-header": "ما الذي يجعل SimpleX خصوصيًّا", "privacy-matters-section-subheader": "الحفاظ على خصوصية بياناتك الوصفية — مع من تتحدث — يحميك من:", "simplex-network-1-overlay-linktext": "مشاكل شبكات P2P", - "simplex-network-section-desc": "يوفر Simplex Chat أفضل خصوصية من خلال الجمع بين مزايا P2P والشبكات الموحدة.", + "simplex-network-section-desc": "يوفر Simplex Chat أفضل خصوصية من خلال الجمع بين مزايا P2P والشبكات الاتحادية.", "simplex-network-1-desc": "يتم إرسال جميع الرسائل عبر الخوادم، مما يوفر خصوصية أفضل للبيانات الوصفية وتسليمًا موثوقًا للرسائل غير المتزامنة، مع تجنب الكثير", - "simplex-network-2-header": "على عكس الشبكات الفيدرالية", + "simplex-network-2-header": "على عكس الشبكات الاتحادية", "simplex-network-3-desc": "توفر الخوادم قوائم انتظار أحادية الاتجاه لتوصيل المستخدمين، لكن ليس لديهم رؤية للرسم البياني لاتصال الشبكة — إلا للمستخدمين فقط.", "comparison-section-header": "مقارنة مع البروتوكولات الأخرى", "simplex-network-2-desc": "لا تقوم خوادم الترحيل SimpleX بتخزين ملفات تعريف المستخدمين وجهات الاتصال والرسائل التي تم تسليمها، ولا تتصل ببعضها البعض، ولا يوجد دليل خوادم.", @@ -216,7 +216,7 @@ "guide-dropdown-4": "ملفات تعريف الدردشة", "guide-dropdown-5": "إدارة البيانات", "guide-dropdown-6": "مكالمات الصوت والفيديو", - "guide-dropdown-7": "الخصوصية والأمن", + "guide-dropdown-7": "الخصوصية و الأمان", "guide-dropdown-8": "إعدادات التطبيق", "guide-dropdown-9": "إجراء اتصالات", "docs-dropdown-4": "استضافة خادم SMP", @@ -242,8 +242,8 @@ "stable-versions-built-by-f-droid-org": "الإصدارات الثابتة التي تم إنشاؤها بواسطة F-Droid.org", "releases-to-this-repo-are-done-1-2-days-later": "يتم إصدار الإصدارات إلى هذا المستودع بعد يوم أو يومين", "f-droid-page-simplex-chat-repo-section-text": "لإضافته إلى عميل F-Droid، امسح رمز QR أو استخدم عنوان URL هذا:", - "f-droid-page-f-droid-org-repo-section-text": "مستودعات SimpleX Chat و F-Droid.org مبنية على مفاتيح مختلفة. للتبديل، يرجى تصدير قاعدة بيانات الدردشة وإعادة تثبيت التطبيق.", - "comparison-section-list-point-4a": "مُرحلات SimpleX لا يمكنها أن تتنازل عن تشفير بين الطرفين. تحقق من رمز الأمان للتخفيف من الهجوم على القناة خارج النطاق", + "f-droid-page-f-droid-org-repo-section-text": "مستودعات SimpleX Chat و F-Droid.org مبنية على مفاتيح مختلفة. للتبديل، يُرجى تصدير قاعدة بيانات الدردشة وإعادة تثبيت التطبيق.", + "comparison-section-list-point-4a": "مُرحلات SimpleX لا يمكنها أن تتنازل عن تَعْمِيَة بين الطرفين. تحقق من رمز الأمان للتخفيف من الهجوم على القناة خارج النطاق", "hero-overlay-3-title": "التقييم الأمني", "hero-overlay-card-3-p-2": "قامت Trail of Bits بمراجعة مكونات التشفير والشبكات الخاصة بمنصة SimpleX في نوفمبر 2022.", "hero-overlay-card-3-p-3": "اقرأ المزيد في الإعلان.", diff --git a/website/langs/ja.json b/website/langs/ja.json index b2ac7ecbc0..967d6c27f3 100644 --- a/website/langs/ja.json +++ b/website/langs/ja.json @@ -243,5 +243,12 @@ "hero-overlay-card-1-p-3": "メッセージの受信に使用するサーバー、連絡先を定義します —メッセージを送信するために使用するサーバー。 すべての会話では 2 つの異なるサーバーが使用される可能性があります。", "simplex-unique-overlay-card-1-p-1": "他のメッセージング プラットフォームとは異なり、SimpleX にはユーザーに割り当てられる識別子がありません。 ユーザーを識別するために、電話番号、ドメインベースのアドレス (電子メールや XMPP など)、ユーザー名、公開キー、さらには乱数にも依存しません。 —我々もSimpleX サーバーを何人が使用しているかはわかりません。", "f-droid-page-f-droid-org-repo-section-text": "SimpleX Chat と F-Droid.org リポジトリは、異なるキーを使用してビルドに署名します。 切り替えるには、チャット データベースをエクスポートし、アプリを再インストールしてください。", - "simplex-private-5-title": "何レイヤーもの
コンテンツパディング" -} + "simplex-private-5-title": "何レイヤーもの
コンテンツパディング", + "hero-overlay-card-3-p-1": "Trail of Bitsは、大手ハイテク企業、政府機関、主要なブロックチェーン・プロジェクトなどを顧客に持つ、セキュリティとテクノロジーの大手コンサルタント会社です。", + "hero-overlay-card-3-p-3": "詳しくは お知らせをご覧ください。", + "jobs": "チームに参加する", + "hero-overlay-3-textlink": "セキュリティ監査", + "hero-overlay-3-title": "セキュリティ監査", + "hero-overlay-card-3-p-2": "Trail of Bitsは2022年11月にSimpleXプラットフォームの暗号とネットワークのコンポーネントを検証しました。", + "docs-dropdown-9": "ダウンロード" +} \ No newline at end of file diff --git a/website/langs/zh_Hans.json b/website/langs/zh_Hans.json index 8fb012963a..e787bced83 100644 --- a/website/langs/zh_Hans.json +++ b/website/langs/zh_Hans.json @@ -34,7 +34,7 @@ "simplex-network-1-header": "与 P2P 网络不同", "simplex-network-1-overlay-linktext": "P2P网络存在的问题", "simplex-network-2-header": "不同于联邦网络", - "comparison-point-1-text": "需要全球身份", + "comparison-point-1-text": "需要全局身份", "no-secure": "不可能 - 安全", "simplex-privacy": "SimpleX 的隐私性", "home": "主页", @@ -175,21 +175,21 @@ "tap-to-close": "点击关闭", "simplex-network-section-header": "SimpleX 网络", "simplex-network-section-desc": "Simplex Chat 通过结合 P2P 和联邦网络的优势使其保密性无与伦比。", - "no-private": "不需要 - 私密", + "no-private": "否 - 私密", "simplex-network-1-desc": "所有消息都通过服务器发送,既能更好地保护元数据隐私和可靠地传递异步消息,同时也能避免许多", - "simplex-network-3-header": "SimpleX网络", + "simplex-network-3-header": "SimpleX 网络", "protocol-1-text": "Signal、其他大平台", - "comparison-point-4-text": "单一或集中式网络", + "comparison-point-4-text": "单一或中心化网络", "simplex-network-3-desc": "服务器提供单向队列来连接用户,但是他们看不到网络连接图图谱— 只有用户可以。", "comparison-section-header": "与其他协议的比较", "protocol-3-text": "P2P协议", - "no": "不需要", + "no": "否", "comparison-point-3-text": "对 DNS 的依赖", "no-federated": "不依赖 - 联邦式网络", "protocol-2-text": "XMPP、Matrix", "comparison-point-2-text": "中间人攻击的可能性", "comparison-point-5-text": "中央组件或其他全网攻击", - "yes": "需要", + "yes": "是", "comparison-section-list-point-5": "不保护用户的元数据", "no-resilient": "不依赖 - 有韧性", "no-decentralized": "不依赖 - 去中心化的", @@ -199,7 +199,7 @@ "comparison-section-list-point-2": "基于 DNS 的地址", "comparison-section-list-point-6": "P2P 是分布式的,而非联邦式的 - 它们作为单个网络运行", "see-here": "参见此处", - "comparison-section-list-point-7": "P2P 网络要么拥有中央管理机制,要么整个网络都可能受到损害", + "comparison-section-list-point-7": "P2P 网络要么拥有中央权威,要么整个网络可能被攻陷", "simplex-private-card-5-point-1": "SimpleX 为每个加密层进行内容填充来对抗长度扩展攻击。", "simplex-unique-overlay-card-4-p-2": "SimpleX 平台使用开放协议并提供用于创建聊天机器人的 SDK, 允许用户实现通过 SimpleX Chat 应用程序与之交互的服务—— 我们真的很期待看到您可以依托SimpleX构建哪些服务。", "simplex-unique-overlay-card-2-p-2": "即使使用可选的用户地址,当它被用于发送垃圾邮件联系请求,您可以更改或完全删除它而不会丢失任何连接。", From 9e369c3ac913d2e4662cde32f8d18d86b15dfd5c Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Thu, 11 Jan 2024 04:31:16 +0700 Subject: [PATCH 041/102] android, desktop: lock on changing user (#3669) * android, desktop: lock on changing user * rename * change * change --- .../chat/simplex/common/model/ChatModel.kt | 3 ++- .../chat/simplex/common/model/SimpleXAPI.kt | 27 ++++++++----------- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/ChatModel.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/ChatModel.kt index 00d19b06f2..b59d57d8a1 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 @@ -114,7 +114,8 @@ object ChatModel { val clipboardHasText = mutableStateOf(false) - var updatingChatsMutex: Mutex = Mutex() + val updatingChatsMutex: Mutex = Mutex() + val changingActiveUserMutex: Mutex = Mutex() val desktopNoUserNoRemote: Boolean @Composable get() = appPlatform.isDesktop && currentUser.value == null && currentRemoteHost.value == null fun desktopNoUserNoRemote(): Boolean = appPlatform.isDesktop && currentUser.value == null && currentRemoteHost.value == null diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt index 363a3bcdbb..d1927e405d 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt @@ -5,6 +5,7 @@ import androidx.compose.runtime.* import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.painter.Painter import chat.simplex.common.model.ChatModel.updatingChatsMutex +import chat.simplex.common.model.ChatModel.changingActiveUserMutex import dev.icerock.moko.resources.compose.painterResource import chat.simplex.common.platform.* import chat.simplex.common.ui.theme.* @@ -335,14 +336,14 @@ object ChatController { var lastMsgReceivedTimestamp: Long = System.currentTimeMillis() private set - private fun currentUserId(funcName: String): Long { + private suspend fun currentUserId(funcName: String): Long = changingActiveUserMutex.withLock { val userId = chatModel.currentUser.value?.userId if (userId == null) { val error = "$funcName: no current user" Log.e(TAG, error) throw Exception(error) } - return userId + userId } suspend fun startChat(user: User) { @@ -408,8 +409,11 @@ object ChatController { } suspend fun changeActiveUser_(rhId: Long?, toUserId: Long, viewPwd: String?) { - val currentUser = apiSetActiveUser(rhId, toUserId, viewPwd) - chatModel.currentUser.value = currentUser + val currentUser = changingActiveUserMutex.withLock { + apiSetActiveUser(rhId, toUserId, viewPwd).also { + chatModel.currentUser.value = it + } + } val users = listUsers(rhId) chatModel.users.clear() chatModel.users.addAll(users) @@ -886,10 +890,7 @@ object ChatController { suspend fun apiAddContact(rh: Long?, incognito: Boolean): Pair?, (() -> Unit)?> { - val userId = chatModel.currentUser.value?.userId ?: run { - Log.e(TAG, "apiAddContact: no current user") - return null to null - } + val userId = try { currentUserId("apiAddContact") } catch (e: Exception) { return null to null } val r = sendCmd(rh, CC.APIAddContact(userId, incognito)) return when (r) { is CR.Invitation -> (r.connReqInvitation to r.connection) to null @@ -918,10 +919,7 @@ object ChatController { } suspend fun apiConnect(rh: Long?, incognito: Boolean, connReq: String): PendingContactConnection? { - val userId = chatModel.currentUser.value?.userId ?: run { - Log.e(TAG, "apiConnect: no current user") - return null - } + val userId = try { currentUserId("apiConnect") } catch (e: Exception) { return null } val r = sendCmd(rh, CC.APIConnect(userId, incognito, connReq)) when { r is CR.SentConfirmation -> return r.connection @@ -960,10 +958,7 @@ object ChatController { } suspend fun apiConnectContactViaAddress(rh: Long?, incognito: Boolean, contactId: Long): Contact? { - val userId = chatModel.currentUser.value?.userId ?: run { - Log.e(TAG, "apiConnectContactViaAddress: no current user") - return null - } + val userId = try { currentUserId("apiConnectContactViaAddress") } catch (e: Exception) { return null } val r = sendCmd(rh, CC.ApiConnectContactViaAddress(userId, incognito, contactId)) when { r is CR.SentInvitationToContact -> return r.contact From f45b24367c53fbcb55fefe65dbce3193997845ab Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Thu, 11 Jan 2024 08:20:49 +0000 Subject: [PATCH 042/102] cli: short command --- src/Simplex/Chat.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Simplex/Chat.hs b/src/Simplex/Chat.hs index e649ac5e36..dbf7c6079a 100644 --- a/src/Simplex/Chat.hs +++ b/src/Simplex/Chat.hs @@ -6508,7 +6508,7 @@ chatCommandP = "/delete remote host " *> (DeleteRemoteHost <$> A.decimal), "/store remote file " *> (StoreRemoteFile <$> A.decimal <*> optional (" encrypt=" *> onOffP) <* A.space <*> filePath), "/get remote file " *> (GetRemoteFile <$> A.decimal <* A.space <*> jsonP), - "/connect remote ctrl " *> (ConnectRemoteCtrl <$> strP), + ("/connect remote ctrl " <|> "/crc ") *> (ConnectRemoteCtrl <$> strP), "/find remote ctrl" $> FindKnownRemoteCtrl, "/confirm remote ctrl " *> (ConfirmRemoteCtrl <$> A.decimal), "/verify remote ctrl " *> (VerifyRemoteCtrlSession <$> textP), From 2872b30e8c7a62d1e95bd6b7114e46dc33337ebc Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Thu, 11 Jan 2024 10:14:27 +0000 Subject: [PATCH 043/102] ui: translations (#3666) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Translated using Weblate (German) Currently translated at 100.0% (1510 of 1510 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/ * Translated using Weblate (German) Currently translated at 100.0% (1352 of 1352 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/de/ * Translated using Weblate (Italian) Currently translated at 100.0% (1510 of 1510 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/ * Translated using Weblate (Italian) Currently translated at 100.0% (1352 of 1352 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/it/ * Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (1510 of 1510 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/ * Translated using Weblate (Czech) Currently translated at 98.5% (1488 of 1510 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/cs/ * Translated using Weblate (Czech) Currently translated at 91.4% (1236 of 1352 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/cs/ * Translated using Weblate (Polish) Currently translated at 100.0% (1510 of 1510 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/pl/ * Translated using Weblate (Polish) Currently translated at 100.0% (1352 of 1352 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/pl/ * Translated using Weblate (Hungarian) Currently translated at 99.9% (1509 of 1510 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/ * Translated using Weblate (Hungarian) Currently translated at 99.9% (1509 of 1510 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/ * Translated using Weblate (Hungarian) Currently translated at 99.9% (1509 of 1510 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/ * Translated using Weblate (Hungarian) Currently translated at 100.0% (1510 of 1510 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/ * Translated using Weblate (Hungarian) Currently translated at 100.0% (1510 of 1510 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/ * Translated using Weblate (Polish) Currently translated at 100.0% (1364 of 1364 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/pl/ * Translated using Weblate (Hungarian) Currently translated at 100.0% (1510 of 1510 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/ * Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (1534 of 1534 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/ * Translated using Weblate (German) Currently translated at 100.0% (1534 of 1534 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/ * Translated using Weblate (German) Currently translated at 100.0% (1364 of 1364 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/de/ * Translated using Weblate (Spanish) Currently translated at 97.3% (1494 of 1534 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 97.5% (1330 of 1364 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/ * Translated using Weblate (Spanish) Currently translated at 100.0% (1534 of 1534 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% (1364 of 1364 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/ * Translated using Weblate (Polish) Currently translated at 100.0% (1534 of 1534 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/pl/ * Translated using Weblate (Greek) Currently translated at 14.7% (227 of 1534 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/el/ * Translated using Weblate (Greek) Currently translated at 1.6% (23 of 1364 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/el/ * Translated using Weblate (German) Currently translated at 100.0% (1534 of 1534 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% (1497 of 1534 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ru/ * Translated using Weblate (German) Currently translated at 100.0% (1364 of 1364 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/de/ * Translated using Weblate (French) Currently translated at 100.0% (1534 of 1534 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fr/ * Translated using Weblate (French) Currently translated at 100.0% (1364 of 1364 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/fr/ * Translated using Weblate (Italian) Currently translated at 100.0% (1534 of 1534 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/ * Translated using Weblate (Italian) Currently translated at 100.0% (1364 of 1364 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/it/ * Translated using Weblate (Dutch) Currently translated at 100.0% (1534 of 1534 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/ * Translated using Weblate (Dutch) Currently translated at 100.0% (1364 of 1364 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/ * Translated using Weblate (Japanese) Currently translated at 88.5% (1208 of 1364 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ja/ * Translated using Weblate (Japanese) Currently translated at 90.3% (1386 of 1534 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ja/ * Translated using Weblate (Arabic) Currently translated at 99.7% (1530 of 1534 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/ * Translated using Weblate (Bulgarian) Currently translated at 91.9% (1254 of 1364 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/bg/ * Translated using Weblate (Bulgarian) Currently translated at 100.0% (1534 of 1534 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/bg/ * Translated using Weblate (Japanese) Currently translated at 91.0% (1399 of 1536 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ja/ * Translated using Weblate (Japanese) Currently translated at 92.3% (1418 of 1536 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ja/ * Translated using Weblate (German) Currently translated at 100.0% (1536 of 1536 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/ * Translated using Weblate (French) Currently translated at 100.0% (1536 of 1536 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fr/ * Translated using Weblate (French) Currently translated at 100.0% (1364 of 1364 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/fr/ * Translated using Weblate (Japanese) Currently translated at 88.5% (1208 of 1364 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ja/ * Translated using Weblate (Japanese) Currently translated at 92.7% (1424 of 1536 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ja/ * Translated using Weblate (Italian) Currently translated at 100.0% (1536 of 1536 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/ * Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (1536 of 1536 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/ * Translated using Weblate (Japanese) Currently translated at 100.0% (1536 of 1536 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ja/ * Translated using Weblate (Turkish) Currently translated at 36.8% (503 of 1364 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/tr/ * Translated using Weblate (Turkish) Currently translated at 100.0% (1536 of 1536 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/tr/ * Translated using Weblate (Turkish) Currently translated at 58.8% (803 of 1364 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/tr/ * Translated using Weblate (Turkish) Currently translated at 100.0% (1536 of 1536 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/tr/ * Translated using Weblate (Turkish) Currently translated at 64.0% (873 of 1364 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/tr/ * Translated using Weblate (Hungarian) Currently translated at 97.9% (1505 of 1536 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/ * Translated using Weblate (Hungarian) Currently translated at 100.0% (1536 of 1536 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/ * Translated using Weblate (Hungarian) Currently translated at 100.0% (1536 of 1536 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/ * Translated using Weblate (Hungarian) Currently translated at 100.0% (1536 of 1536 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/ * Translated using Weblate (Hungarian) Currently translated at 100.0% (1536 of 1536 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/ * Translated using Weblate (Hungarian) Currently translated at 100.0% (1536 of 1536 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/ * Translated using Weblate (Turkish) Currently translated at 86.1% (1175 of 1364 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/tr/ * Translated using Weblate (Turkish) Currently translated at 100.0% (1536 of 1536 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/tr/ * Translated using Weblate (Hungarian) Currently translated at 100.0% (1536 of 1536 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/ * Translated using Weblate (Hungarian) Currently translated at 100.0% (1536 of 1536 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/ * Translated using Weblate (Turkish) Currently translated at 87.4% (1193 of 1364 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/tr/ * Translated using Weblate (Turkish) Currently translated at 100.0% (1536 of 1536 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/tr/ * Translated using Weblate (Turkish) Currently translated at 100.0% (1364 of 1364 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/tr/ * Translated using Weblate (Turkish) Currently translated at 100.0% (1536 of 1536 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/tr/ * Translated using Weblate (Czech) Currently translated at 97.9% (1504 of 1536 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/cs/ * Translated using Weblate (Arabic) Currently translated at 99.7% (1532 of 1536 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/ * Translated using Weblate (Bulgarian) Currently translated at 100.0% (1364 of 1364 strings) Translation: SimpleX Chat/SimpleX Chat iOS Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/bg/ * Translated using Weblate (Bulgarian) Currently translated at 100.0% (1536 of 1536 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/bg/ * Translated using Weblate (Hungarian) Currently translated at 100.0% (1536 of 1536 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/ * Translated using Weblate (Italian) Currently translated at 100.0% (1542 of 1542 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/ * Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (1542 of 1542 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/ * Translated using Weblate (Arabic) Currently translated at 99.7% (1538 of 1542 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/ * Translated using Weblate (Hungarian) Currently translated at 99.2% (1549 of 1560 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/ * Translated using Weblate (German) Currently translated at 100.0% (1562 of 1562 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/ * Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (1562 of 1562 strings) Translation: SimpleX Chat/SimpleX Chat Android Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/ * fixing * fix * change * fix * import/export * restore some lost translations * 24hours * Revert "24hours" This reverts commit b715d46e6fa67ee982be1e90e228703264477df0. * 24 hours, import --------- Co-authored-by: mlanp Co-authored-by: Random Co-authored-by: Eric Co-authored-by: zenobit Co-authored-by: B.O.S.S Co-authored-by: J R Co-authored-by: summoner001 Co-authored-by: No name Co-authored-by: diodepon Co-authored-by: v1s7 Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com> Co-authored-by: M1K4 Co-authored-by: 小林照幸 Co-authored-by: jonnysemon Co-authored-by: elgratea Co-authored-by: yokoba0413 Co-authored-by: Kaan P Co-authored-by: Ghost of Sparta Co-authored-by: Avently <7953703+avently@users.noreply.github.com> Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com> --- .../bg.xcloc/Localized Contents/bg.xliff | 221 +- .../cs.xcloc/Localized Contents/cs.xliff | 72 +- .../de.xcloc/Localized Contents/de.xliff | 159 +- .../el.xcloc/Localized Contents/el.xliff | 27 +- .../en.xcloc/Localized Contents/en.xliff | 77 +- .../es.xcloc/Localized Contents/es.xliff | 175 +- .../fi.xcloc/Localized Contents/fi.xliff | 70 +- .../fr.xcloc/Localized Contents/fr.xliff | 155 +- .../it.xcloc/Localized Contents/it.xliff | 105 +- .../ja.xcloc/Localized Contents/ja.xliff | 80 +- .../nl.xcloc/Localized Contents/nl.xliff | 105 +- .../pl.xcloc/Localized Contents/pl.xliff | 105 +- .../ru.xcloc/Localized Contents/ru.xliff | 70 +- .../th.xcloc/Localized Contents/th.xliff | 56 +- .../tr.xcloc/Localized Contents/tr.xliff | 4175 +++++++++++++---- .../uk.xcloc/Localized Contents/uk.xliff | 70 +- .../Localized Contents/zh-Hans.xliff | 56 +- apps/ios/bg.lproj/Localizable.strings | 452 +- .../bg.lproj/SimpleX--iOS--InfoPlist.strings | 3 + apps/ios/cs.lproj/Localizable.strings | 59 +- apps/ios/de.lproj/Localizable.strings | 195 +- apps/ios/es.lproj/Localizable.strings | 211 +- apps/ios/fi.lproj/Localizable.strings | 53 +- apps/ios/fr.lproj/Localizable.strings | 191 +- apps/ios/it.lproj/Localizable.strings | 141 +- apps/ios/ja.lproj/Localizable.strings | 69 +- .../ja.lproj/SimpleX--iOS--InfoPlist.strings | 8 +- apps/ios/nl.lproj/Localizable.strings | 141 +- apps/ios/pl.lproj/Localizable.strings | 141 +- apps/ios/ru.lproj/Localizable.strings | 53 +- apps/ios/th.lproj/Localizable.strings | 50 +- apps/ios/uk.lproj/Localizable.strings | 53 +- apps/ios/zh-Hans.lproj/Localizable.strings | 53 +- .../commonMain/resources/MR/ar/strings.xml | 130 +- .../commonMain/resources/MR/base/strings.xml | 2 +- .../commonMain/resources/MR/bg/strings.xml | 68 +- .../commonMain/resources/MR/cs/strings.xml | 143 +- .../commonMain/resources/MR/de/strings.xml | 134 +- .../commonMain/resources/MR/el/strings.xml | 7 + .../commonMain/resources/MR/es/strings.xml | 118 +- .../commonMain/resources/MR/fr/strings.xml | 110 +- .../commonMain/resources/MR/hu/strings.xml | 297 +- .../commonMain/resources/MR/it/strings.xml | 58 +- .../commonMain/resources/MR/ja/strings.xml | 347 +- .../commonMain/resources/MR/nl/strings.xml | 48 +- .../commonMain/resources/MR/pl/strings.xml | 56 +- .../commonMain/resources/MR/ru/strings.xml | 3 +- .../commonMain/resources/MR/tr/strings.xml | 507 +- .../commonMain/resources/MR/uk/strings.xml | 2 +- .../resources/MR/zh-rCN/strings.xml | 92 +- 50 files changed, 7076 insertions(+), 2697 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 506df8cf17..5758ddc30a 100644 --- a/apps/ios/SimpleX Localizations/bg.xcloc/Localized Contents/bg.xliff +++ b/apps/ios/SimpleX Localizations/bg.xcloc/Localized Contents/bg.xliff @@ -89,6 +89,7 @@
%@ and %@ + %@ и %@ No comment provided by engineer. @@ -103,6 +104,7 @@ %@ connected + %@ свързан No comment provided by engineer. @@ -132,6 +134,7 @@ %@, %@ and %lld members + %@, %@ и %lld членове No comment provided by engineer. @@ -201,6 +204,7 @@ %lld group events + %lld групови събития No comment provided by engineer. @@ -210,14 +214,17 @@ %lld messages blocked + %lld блокирани съобщения No comment provided by engineer. %lld messages marked deleted + %lld съобщения, маркирани като изтрити No comment provided by engineer. %lld messages moderated by %@ + %lld съобщения, модерирани от %@ No comment provided by engineer. @@ -292,10 +299,12 @@ (new) + (ново) No comment provided by engineer. (this device v%@) + (това устройство v%@) No comment provided by engineer. @@ -305,6 +314,7 @@ **Add contact**: to create a new invitation link, or connect via a link you received. + **Добави контакт**: за създаване на нов линк или свързване чрез получен линк за връзка. No comment provided by engineer. @@ -314,6 +324,7 @@ **Create group**: to create a new group. + **Създай група**: за създаване на нова група. No comment provided by engineer. @@ -383,6 +394,9 @@ - optionally notify deleted contacts. - profile names with spaces. - and more! + - по желание уведомете изтритите контакти. +- имена на профили с интервали. +- и още! No comment provided by engineer. @@ -401,6 +415,7 @@ 0 sec + 0 сек time to disappear @@ -550,6 +565,7 @@ Add contact + Добави контакт No comment provided by engineer. @@ -629,6 +645,7 @@ All new messages from %@ will be hidden! + Всички нови съобщения от %@ ще бъдат скрити! No comment provided by engineer. @@ -656,9 +673,9 @@ Позволи изчезващи съобщения само ако вашият контакт ги разрешава. No comment provided by engineer. - - Allow irreversible message deletion only if your contact allows it to you. - Позволи необратимо изтриване на съобщение само ако вашият контакт го рарешава. + + Allow irreversible message deletion only if your contact allows it to you. (24 hours) + Позволи необратимо изтриване на съобщение само ако вашият контакт го рарешава. (24 часа) No comment provided by engineer. @@ -681,9 +698,9 @@ Разреши изпращането на изчезващи съобщения. No comment provided by engineer. - - Allow to irreversibly delete sent messages. - Позволи необратимо изтриване на изпратените съобщения. + + Allow to irreversibly delete sent messages. (24 hours) + Позволи необратимо изтриване на изпратените съобщения. (24 часа) No comment provided by engineer. @@ -716,9 +733,9 @@ Позволи на вашите контакти да ви се обаждат. No comment provided by engineer. - - Allow your contacts to irreversibly delete sent messages. - Позволи на вашите контакти да изтриват необратимо изпратените съобщения. + + Allow your contacts to irreversibly delete sent messages. (24 hours) + Позволи на вашите контакти да изтриват необратимо изпратените съобщения. (24 часа) No comment provided by engineer. @@ -738,10 +755,12 @@ Already connecting! + В процес на свързване! No comment provided by engineer. Already joining the group! + Вече се присъединихте към групата! No comment provided by engineer. @@ -866,6 +885,7 @@ Bad desktop address + Грешен адрес на настолното устройство No comment provided by engineer. @@ -880,6 +900,7 @@ Better groups + По-добри групи No comment provided by engineer. @@ -889,18 +910,22 @@ Block + Блокирай No comment provided by engineer. Block group members + Блокиране на членове на групата No comment provided by engineer. Block member + Блокирай член No comment provided by engineer. Block member? + Блокирай члена? No comment provided by engineer. @@ -908,9 +933,9 @@ И вие, и вашият контакт можете да добавяте реакции към съобщението. No comment provided by engineer. - - Both you and your contact can irreversibly delete sent messages. - И вие, и вашият контакт можете да изтриете необратимо изпратените съобщения. + + Both you and your contact can irreversibly delete sent messages. (24 hours) + И вие, и вашият контакт можете да изтриете необратимо изпратените съобщения. (24 часа) No comment provided by engineer. @@ -950,6 +975,7 @@ Camera not available + Камерата е неодстъпна No comment provided by engineer. @@ -1070,6 +1096,7 @@ Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat. + Чатът е спрян. Ако вече сте използвали тази база данни на друго устройство, трябва да я прехвърлите обратно, преди да стартирате чата отново. No comment provided by engineer. @@ -1174,6 +1201,7 @@ Connect automatically + Автоматично свъзрване No comment provided by engineer. @@ -1183,24 +1211,31 @@ Connect to desktop + Свързване с настолно устройство No comment provided by engineer. Connect to yourself? + Свърване със себе си? No comment provided by engineer. Connect to yourself? This is your own SimpleX address! + Свърване със себе си? +Това е вашият личен SimpleX адрес! No comment provided by engineer. Connect to yourself? This is your own one-time link! + Свърване със себе си? +Това е вашят еднократен линк за връзка! No comment provided by engineer. Connect via contact address + Свързване чрез адрес за контакт No comment provided by engineer. @@ -1215,14 +1250,17 @@ This is your own one-time link! Connect with %@ + Свързване с %@ No comment provided by engineer. Connected desktop + Свързано настолно устройство No comment provided by engineer. Connected to desktop + Свързан с настолно устройство No comment provided by engineer. @@ -1237,6 +1275,7 @@ This is your own one-time link! Connecting to desktop + Свързване с настолно устройство No comment provided by engineer. @@ -1261,6 +1300,7 @@ This is your own one-time link! Connection terminated + Връзката е прекратена No comment provided by engineer. @@ -1330,6 +1370,7 @@ This is your own one-time link! Correct name to %@? + Поправи име на %@? No comment provided by engineer. @@ -1344,6 +1385,7 @@ This is your own one-time link! Create a group using a random profile. + Създай група с автоматично генериран профилл. No comment provided by engineer. @@ -1358,6 +1400,7 @@ This is your own one-time link! Create group + Създай група No comment provided by engineer. @@ -1377,6 +1420,7 @@ This is your own one-time link! Create profile + Създай профил No comment provided by engineer. @@ -1401,6 +1445,7 @@ This is your own one-time link! Creating link… + Линкът се създава… No comment provided by engineer. @@ -1543,6 +1588,7 @@ This is your own one-time link! Delete %lld messages? + Изтриване на %lld съобщения? No comment provided by engineer. @@ -1572,6 +1618,7 @@ This is your own one-time link! Delete and notify contact + Изтрий и уведоми контакт No comment provided by engineer. @@ -1607,6 +1654,8 @@ This is your own one-time link! Delete contact? This cannot be undone! + Изтрий контакт? +Това не може да бъде отменено! No comment provided by engineer. @@ -1751,14 +1800,17 @@ This cannot be undone! Desktop address + Адрес на настолно устройство No comment provided by engineer. Desktop app version %@ is not compatible with this app. + Версията на настолното приложение %@ не е съвместима с това приложение. No comment provided by engineer. Desktop devices + Настолни устройства No comment provided by engineer. @@ -1853,6 +1905,7 @@ This cannot be undone! Disconnect desktop? + Прекъсни връзката с настолното устройство? No comment provided by engineer. @@ -1862,6 +1915,7 @@ This cannot be undone! Discover via local network + Открий през локалната мрежа No comment provided by engineer. @@ -1874,6 +1928,10 @@ This cannot be undone! Отложи No comment provided by engineer. + + Do not send history to new members. + No comment provided by engineer. + Don't create address Не създавай адрес @@ -1946,6 +2004,7 @@ This cannot be undone! Enable camera access + Разреши достъпа до камерата No comment provided by engineer. @@ -2015,6 +2074,7 @@ This cannot be undone! Encrypted message: app is stopped + Криптирано съобщение: приложението е спряно notification @@ -2044,10 +2104,12 @@ This cannot be undone! Encryption re-negotiation error + Грешка при повторно договаряне на криптиране message decrypt error item Encryption re-negotiation failed. + Неуспешно повторно договаряне на криптирането. No comment provided by engineer. @@ -2062,6 +2124,7 @@ This cannot be undone! Enter group name… + Въведи име на групата… No comment provided by engineer. @@ -2081,6 +2144,7 @@ This cannot be undone! Enter this device name… + Въведи името на това устройство… No comment provided by engineer. @@ -2095,6 +2159,7 @@ This cannot be undone! Enter your name… + Въведи своето име… No comment provided by engineer. @@ -2244,6 +2309,7 @@ This cannot be undone! Error opening chat + Грешка при отваряне на чата No comment provided by engineer. @@ -2288,6 +2354,7 @@ This cannot be undone! Error scanning code: %@ + Грешка при сканиране на кода: %@ No comment provided by engineer. @@ -2382,6 +2449,7 @@ This cannot be undone! Expand + Разшири chat item action @@ -2416,6 +2484,7 @@ This cannot be undone! Faster joining and more reliable messages. + По-бързо присъединяване и по-надеждни съобщения. No comment provided by engineer. @@ -2515,6 +2584,7 @@ This cannot be undone! Found desktop + Намерено настолно устройство No comment provided by engineer. @@ -2539,6 +2609,7 @@ This cannot be undone! Fully decentralized – visible only to members. + Напълно децентрализирана – видима е само за членовете. No comment provided by engineer. @@ -2563,10 +2634,12 @@ This cannot be undone! Group already exists + Групата вече съществува No comment provided by engineer. Group already exists! + Групата вече съществува! No comment provided by engineer. @@ -2614,9 +2687,9 @@ This cannot be undone! Членовете на групата могат да добавят реакции към съобщенията. No comment provided by engineer. - - Group members can irreversibly delete sent messages. - Членовете на групата могат необратимо да изтриват изпратените съобщения. + + Group members can irreversibly delete sent messages. (24 hours) + Членовете на групата могат необратимо да изтриват изпратените съобщения. (24 часа) No comment provided by engineer. @@ -2724,6 +2797,10 @@ This cannot be undone! История No comment provided by engineer. + + History is not sent to new members. + No comment provided by engineer. + How SimpleX works Как работи SimpleX @@ -2836,6 +2913,7 @@ This cannot be undone! Incognito groups + Инкогнито групи No comment provided by engineer. @@ -2870,6 +2948,7 @@ This cannot be undone! Incompatible version + Несъвместима версия No comment provided by engineer. @@ -2916,6 +2995,7 @@ This cannot be undone! Invalid QR code + Невалиден QR код No comment provided by engineer. @@ -2923,16 +3003,23 @@ This cannot be undone! Невалиден линк за връзка No comment provided by engineer. + + Invalid display name! + No comment provided by engineer. + Invalid link + Невалиден линк No comment provided by engineer. Invalid name! + Невалидно име! No comment provided by engineer. Invalid response + Невалиден отговор No comment provided by engineer. @@ -3028,6 +3115,7 @@ This cannot be undone! Join group? + Влез в групата? No comment provided by engineer. @@ -3037,11 +3125,14 @@ This cannot be undone! Join with current profile + Присъединяване с текущия профил No comment provided by engineer. Join your group? This is your link for group %@! + Влез в твоята група? +Това е вашят линк за група %@! No comment provided by engineer. @@ -3051,14 +3142,17 @@ This is your link for group %@! Keep + Запази No comment provided by engineer. Keep the app open to use it from desktop + Дръжте приложението отворено, за да го използвате от настолното устройство No comment provided by engineer. Keep unused invitation? + Запази неизползваната покана за връзка? No comment provided by engineer. @@ -3123,14 +3217,17 @@ This is your link for group %@! Link mobile and desktop apps! 🔗 + Свържете мобилни и настолни приложения! 🔗 No comment provided by engineer. Linked desktop options + Настройки на запомнени настолни устройства No comment provided by engineer. Linked desktops + Запомнени настолни устройства No comment provided by engineer. @@ -3290,6 +3387,7 @@ This is your link for group %@! Messages from %@ will be shown! + Съобщенията от %@ ще бъдат показани! No comment provided by engineer. @@ -3389,6 +3487,7 @@ This is your link for group %@! New chat + Нов чат No comment provided by engineer. @@ -3493,6 +3592,7 @@ This is your link for group %@! Not compatible! + Несъвместим! No comment provided by engineer. @@ -3516,6 +3616,7 @@ This is your link for group %@! OK + ОК No comment provided by engineer. @@ -3583,9 +3684,9 @@ This is your link for group %@! Само вие можете да добавяте реакции на съобщенията. No comment provided by engineer. - - Only you can irreversibly delete messages (your contact can mark them for deletion). - Само вие можете необратимо да изтриете съобщения (вашият контакт може да ги маркира за изтриване). + + Only you can irreversibly delete messages (your contact can mark them for deletion). (24 hours) + Само вие можете необратимо да изтриете съобщения (вашият контакт може да ги маркира за изтриване). (24 часа) No comment provided by engineer. @@ -3608,9 +3709,9 @@ This is your link for group %@! Само вашият контакт може да добавя реакции на съобщенията. No comment provided by engineer. - - Only your contact can irreversibly delete messages (you can mark them for deletion). - Само вашият контакт може необратимо да изтрие съобщения (можете да ги маркирате за изтриване). + + Only your contact can irreversibly delete messages (you can mark them for deletion). (24 hours) + Само вашият контакт може необратимо да изтрие съобщения (можете да ги маркирате за изтриване). (24 часа) No comment provided by engineer. @@ -3650,6 +3751,7 @@ This is your link for group %@! Open group + Отвори група No comment provided by engineer. @@ -3664,14 +3766,17 @@ This is your link for group %@! Opening app… + Приложението се отваря… No comment provided by engineer. Or scan QR code + Или сканирай QR код No comment provided by engineer. Or show this code + Или покажи този код No comment provided by engineer. @@ -3716,6 +3821,7 @@ This is your link for group %@! Paste desktop address + Постави адрес на настолно устройство No comment provided by engineer. @@ -3725,6 +3831,7 @@ This is your link for group %@! Paste the link you received + Постави получения линк No comment provided by engineer. @@ -3765,6 +3872,8 @@ This is your link for group %@! Please contact developers. Error: %@ + Моля, свържете се с разработчиците. +Грешка: %@ No comment provided by engineer. @@ -3864,10 +3973,12 @@ Error: %@ Profile name + Име на профила No comment provided by engineer. Profile name: + Име на профила: No comment provided by engineer. @@ -3972,6 +4083,7 @@ Error: %@ Read more in [User Guide](https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode). + Прочетете повече в [Ръководство за потребителя](https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode). No comment provided by engineer. @@ -4121,10 +4233,12 @@ Error: %@ Repeat connection request? + Изпрати отново заявката за свързване? No comment provided by engineer. Repeat join request? + Изпрати отново заявката за присъединяване? No comment provided by engineer. @@ -4184,6 +4298,7 @@ Error: %@ Retry + Опитай отново No comment provided by engineer. @@ -4318,6 +4433,7 @@ Error: %@ Scan QR code from desktop + Сканирай QR код от настолното устройство No comment provided by engineer. @@ -4342,6 +4458,7 @@ Error: %@ Search or paste SimpleX link + Търсене или поставяне на SimpleX линк No comment provided by engineer. @@ -4449,6 +4566,10 @@ Error: %@ Изпрати от галерия или персонализирани клавиатури. No comment provided by engineer. + + Send up to 100 last messages to new members. + No comment provided by engineer. + Sender cancelled file transfer. Подателят отмени прехвърлянето на файла. @@ -4546,6 +4667,7 @@ Error: %@ Session code + Код на сесията No comment provided by engineer. @@ -4620,6 +4742,7 @@ Error: %@ Share this 1-time invite link + Сподели този еднократен линк за връзка No comment provided by engineer. @@ -4749,6 +4872,7 @@ Error: %@ Start chat? + Стартирай чата? No comment provided by engineer. @@ -4858,6 +4982,7 @@ Error: %@ Tap to Connect + Докосни за свързване No comment provided by engineer. @@ -4877,10 +5002,12 @@ Error: %@ Tap to paste link + Докосни за поставяне на линк за връзка No comment provided by engineer. Tap to scan + Докосни за сканиране No comment provided by engineer. @@ -4947,6 +5074,7 @@ It can happen because of some bug or when the connection is compromised. The code you scanned is not a SimpleX link QR code. + QR кодът, който сканирахте, не е SimpleX линк за връзка. No comment provided by engineer. @@ -5016,6 +5144,7 @@ It can happen because of some bug or when the connection is compromised. The text you pasted is not a SimpleX link. + Текстът, който поставихте, не е SimpleX линк за връзка. No comment provided by engineer. @@ -5060,6 +5189,11 @@ It can happen because of some bug or when the connection is compromised. This device name + Името на това устройство + No comment provided by engineer. + + + This display name is invalid. Please choose another name. No comment provided by engineer. @@ -5074,10 +5208,12 @@ It can happen because of some bug or when the connection is compromised. This is your own SimpleX address! + Това е вашият личен SimpleX адрес! No comment provided by engineer. This is your own one-time link! + Това е вашят еднократен линк за връзка! No comment provided by engineer. @@ -5097,6 +5233,7 @@ It can happen because of some bug or when the connection is compromised. To hide unwanted messages. + Скриване на нежелани съобщения. No comment provided by engineer. @@ -5178,14 +5315,17 @@ You will be prompted to complete authentication before this feature is enabled.< Unblock + Отблокирай No comment provided by engineer. Unblock member + Отблокирай член No comment provided by engineer. Unblock member? + Отблокирай член? No comment provided by engineer. @@ -5252,10 +5392,12 @@ To connect, please ask your contact to create another connection link and check Unlink + Забрави No comment provided by engineer. Unlink desktop? + Забрави настолно устройство? No comment provided by engineer. @@ -5278,6 +5420,10 @@ To connect, please ask your contact to create another connection link and check Непрочетено No comment provided by engineer. + + Up to 100 last messages are sent to new members. + No comment provided by engineer. + Update Актуализация @@ -5350,6 +5496,7 @@ To connect, please ask your contact to create another connection link and check Use from desktop + Използвай от настолно устройство No comment provided by engineer. @@ -5364,6 +5511,7 @@ To connect, please ask your contact to create another connection link and check Use only local notifications? + Използвай само локални известия? No comment provided by engineer. @@ -5388,10 +5536,12 @@ To connect, please ask your contact to create another connection link and check Verify code with desktop + Потвръди кода с настолното устройство No comment provided by engineer. Verify connection + Потвръди връзките No comment provided by engineer. @@ -5401,6 +5551,7 @@ To connect, please ask your contact to create another connection link and check Verify connections + Потвръди връзките No comment provided by engineer. @@ -5415,6 +5566,7 @@ To connect, please ask your contact to create another connection link and check Via secure quantum resistant protocol. + Чрез сигурен квантово устойчив протокол. No comment provided by engineer. @@ -5442,6 +5594,10 @@ To connect, please ask your contact to create another connection link and check Виж кода за сигурност No comment provided by engineer. + + Visible history + chat feature + Voice messages Гласови съобщения @@ -5469,6 +5625,7 @@ To connect, please ask your contact to create another connection link and check Waiting for desktop... + Изчакване на настолно устройство… No comment provided by engineer. @@ -5573,31 +5730,39 @@ To connect, please ask your contact to create another connection link and check You are already connecting to %@. + Вече се свързвате с %@. No comment provided by engineer. You are already connecting via this one-time link! + Вече се свързвате чрез този еднократен линк за връзка! No comment provided by engineer. You are already in group %@. + Вече сте в група %@. No comment provided by engineer. You are already joining the group %@. + Вече се присъединявате към групата %@. No comment provided by engineer. You are already joining the group via this link! + Вие вече се присъединявате към групата чрез този линк! No comment provided by engineer. You are already joining the group via this link. + Вие вече се присъединявате към групата чрез този линк. No comment provided by engineer. You are already joining the group! Repeat join request? + Вече се присъединихте към групата! +Изпрати отново заявката за присъединяване? No comment provided by engineer. @@ -5637,6 +5802,7 @@ Repeat join request? You can make it visible to your SimpleX contacts via Settings. + Можете да го направите видим за вашите контакти в SimpleX чрез Настройки. No comment provided by engineer. @@ -5681,6 +5847,7 @@ Repeat join request? You can view invitation link again in connection details. + Можете да видите отново линкът за покана в подробностите за връзката. No comment provided by engineer. @@ -5700,11 +5867,14 @@ Repeat join request? You have already requested connection via this address! + Вече сте заявили връзка през този адрес! No comment provided by engineer. You have already requested connection! Repeat connection request? + Вече сте направили заявката за връзка! +Изпрати отново заявката за свързване? No comment provided by engineer. @@ -5759,6 +5929,7 @@ Repeat connection request? You will be connected when group link host's device is online, please wait or check later! + Ще бъдете свързани, когато устройството на хоста на груповата връзка е онлайн, моля, изчакайте или проверете по-късно! No comment provided by engineer. @@ -5778,6 +5949,7 @@ Repeat connection request? You will connect to all group members. + Ще се свържете с всички членове на групата. No comment provided by engineer. @@ -5894,6 +6066,7 @@ You can cancel this connection and remove the contact (and try later with a new Your profile + Вашият профил No comment provided by engineer. @@ -5990,6 +6163,7 @@ SimpleX сървърите не могат да видят вашия профи and %lld other events + и %lld други събития No comment provided by engineer. @@ -5999,6 +6173,7 @@ SimpleX сървърите не могат да видят вашия профи author + автор member role @@ -6013,6 +6188,7 @@ SimpleX сървърите не могат да видят вашия профи blocked + блокиран No comment provided by engineer. @@ -6187,6 +6363,7 @@ SimpleX сървърите не могат да видят вашия профи deleted contact + изтрит контакт rcv direct event chat item @@ -6583,6 +6760,7 @@ SimpleX сървърите не могат да видят вашия профи v%@ + v%@ No comment provided by engineer. @@ -6724,6 +6902,7 @@ SimpleX сървърите не могат да видят вашия профи SimpleX uses local network access to allow using user chat profile via desktop app on the same network. + SimpleX използва достъп до локална мрежа, за да позволи използването на потребителския чат профил чрез настолно приложение в същата мрежа. Privacy - Local Network Usage Description 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 076c2c97fb..cd2b59fb03 100644 --- a/apps/ios/SimpleX Localizations/cs.xcloc/Localized Contents/cs.xliff +++ b/apps/ios/SimpleX Localizations/cs.xcloc/Localized Contents/cs.xliff @@ -89,6 +89,7 @@ %@ and %@ + %@ a %@ No comment provided by engineer. @@ -103,6 +104,7 @@ %@ connected + %@ připojen No comment provided by engineer. @@ -656,9 +658,9 @@ Povolte mizící zprávy, pouze pokud vám to váš kontakt dovolí. No comment provided by engineer. - - Allow irreversible message deletion only if your contact allows it to you. - Povolte nevratné smazání zprávy pouze v případě, že vám to váš kontakt dovolí. + + Allow irreversible message deletion only if your contact allows it to you. (24 hours) + Povolte nevratné smazání zprávy pouze v případě, že vám to váš kontakt dovolí. (24 hodin) No comment provided by engineer. @@ -681,9 +683,9 @@ Povolit odesílání mizících zpráv. No comment provided by engineer. - - Allow to irreversibly delete sent messages. - Povolit nevratné smazání odeslaných zpráv. + + Allow to irreversibly delete sent messages. (24 hours) + Povolit nevratné smazání odeslaných zpráv. (24 hodin) No comment provided by engineer. @@ -716,9 +718,9 @@ Povolte svým kontaktům vám volat. No comment provided by engineer. - - Allow your contacts to irreversibly delete sent messages. - Umožněte svým kontaktům nevratně odstranit odeslané zprávy. + + Allow your contacts to irreversibly delete sent messages. (24 hours) + Umožněte svým kontaktům nevratně odstranit odeslané zprávy. (24 hodin) No comment provided by engineer. @@ -908,9 +910,9 @@ Vy i váš kontakt můžete přidávat reakce na zprávy. No comment provided by engineer. - - Both you and your contact can irreversibly delete sent messages. - Vy i váš kontakt můžete nevratně mazat odeslané zprávy. + + Both you and your contact can irreversibly delete sent messages. (24 hours) + Vy i váš kontakt můžete nevratně mazat odeslané zprávy. (24 hodin) No comment provided by engineer. @@ -1874,6 +1876,10 @@ This cannot be undone! Udělat později No comment provided by engineer. + + Do not send history to new members. + No comment provided by engineer. + Don't create address Nevytvářet adresu @@ -2614,9 +2620,9 @@ This cannot be undone! Členové skupin mohou přidávat reakce na zprávy. No comment provided by engineer. - - Group members can irreversibly delete sent messages. - Členové skupiny mohou nevratně mazat odeslané zprávy. + + Group members can irreversibly delete sent messages. (24 hours) + Členové skupiny mohou nevratně mazat odeslané zprávy. (24 hodin) No comment provided by engineer. @@ -2724,6 +2730,10 @@ This cannot be undone! Historie No comment provided by engineer. + + History is not sent to new members. + No comment provided by engineer. + How SimpleX works Jak SimpleX funguje @@ -2923,6 +2933,10 @@ This cannot be undone! Neplatný odkaz na spojení No comment provided by engineer. + + Invalid display name! + No comment provided by engineer. + Invalid link No comment provided by engineer. @@ -3583,9 +3597,9 @@ This is your link for group %@! Reakce na zprávy můžete přidávat pouze vy. No comment provided by engineer. - - Only you can irreversibly delete messages (your contact can mark them for deletion). - Nevratně mazat zprávy můžete pouze vy (váš kontakt je může označit ke smazání). + + Only you can irreversibly delete messages (your contact can mark them for deletion). (24 hours) + Nevratně mazat zprávy můžete pouze vy (váš kontakt je může označit ke smazání). (24 hodin) No comment provided by engineer. @@ -3608,9 +3622,9 @@ This is your link for group %@! Reakce na zprávy může přidávat pouze váš kontakt. No comment provided by engineer. - - Only your contact can irreversibly delete messages (you can mark them for deletion). - Nevratně mazat zprávy může pouze váš kontakt (vy je můžete označit ke smazání). + + Only your contact can irreversibly delete messages (you can mark them for deletion). (24 hours) + Nevratně mazat zprávy může pouze váš kontakt (vy je můžete označit ke smazání). (24 hodin) No comment provided by engineer. @@ -4449,6 +4463,10 @@ Error: %@ Odeslat je z galerie nebo vlastní klávesnice. No comment provided by engineer. + + Send up to 100 last messages to new members. + No comment provided by engineer. + Sender cancelled file transfer. Odesílatel zrušil přenos souboru. @@ -5062,6 +5080,10 @@ Může se to stát kvůli nějaké chybě, nebo pokud je spojení kompromitován This device name No comment provided by engineer. + + This display name is invalid. Please choose another name. + No comment provided by engineer. + This group has over %lld members, delivery receipts are not sent. Tato skupina má více než %lld členů, potvrzení o doručení nejsou odesílány. @@ -5278,6 +5300,10 @@ Chcete-li se připojit, požádejte svůj kontakt o vytvoření dalšího odkazu Nepřečtený No comment provided by engineer. + + Up to 100 last messages are sent to new members. + No comment provided by engineer. + Update Aktualizovat @@ -5442,6 +5468,10 @@ Chcete-li se připojit, požádejte svůj kontakt o vytvoření dalšího odkazu Zobrazení bezpečnostního kódu No comment provided by engineer. + + Visible history + chat feature + Voice messages Hlasové zprávy 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 2b877c32d2..591bf02e42 100644 --- a/apps/ios/SimpleX Localizations/de.xcloc/Localized Contents/de.xliff +++ b/apps/ios/SimpleX Localizations/de.xcloc/Localized Contents/de.xliff @@ -49,7 +49,7 @@ ## History - ## Vergangenheit + ## Verlauf copied message info @@ -314,15 +314,17 @@ **Add contact**: to create a new invitation link, or connect via a link you received. + **Kontakt hinzufügen**: Um einen neuen Einladungslink zu erstellen oder eine Verbindung über einen Link herzustellen, den Sie erhalten haben. No comment provided by engineer. **Add new contact**: to create your one-time QR Code or link for your contact. - **Fügen Sie einen neuen Kontakt hinzu**: Erzeugen Sie einen Einmal-QR-Code oder -Link für Ihren Kontakt. + **Neuen Kontakt hinzufügen**: Um einen Einmal-QR-Code oder -Link für Ihren Kontakt zu erzeugen. No comment provided by engineer. **Create group**: to create a new group. + **Gruppe erstellen**: Um eine neue Gruppe zu erstellen. No comment provided by engineer. @@ -403,7 +405,7 @@ - editing history. - Bis zu 5 Minuten lange Sprachnachrichten. - Zeitdauer für verschwindende Nachrichten anpassen. -- Nachrichten-Historie bearbeiten. +- Nachrichten-Verlauf bearbeiten. No comment provided by engineer. @@ -507,12 +509,12 @@ Abort changing address - Wechsel der Adresse abbrechen + Wechsel der Empfängeradresse abbrechen No comment provided by engineer. Abort changing address? - Wechsel der Adresse abbrechen? + Wechsel der Empfängeradresse abbrechen? No comment provided by engineer. @@ -558,11 +560,12 @@ Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts. - Fügen Sie die Adresse zu Ihrem Profil hinzu, damit Ihre Kontakte sie mit anderen Personen teilen können. Es wird eine Profilaktualisierung an Ihre Kontakte gesendet. + Fügen Sie die Adresse Ihrem Profil hinzu, damit Ihre Kontakte sie mit anderen Personen teilen können. Es wird eine Profilaktualisierung an Ihre Kontakte gesendet. No comment provided by engineer. Add contact + Kontakt hinzufügen No comment provided by engineer. @@ -602,7 +605,7 @@ Address change will be aborted. Old receiving address will be used. - Der Wechsel der Adresse wird abgebrochen. Die bisherige Adresse wird weiter verwendet. + Der Wechsel der Empfängeradresse wird abgebrochen. Die bisherige Adresse wird weiter verwendet. No comment provided by engineer. @@ -667,12 +670,12 @@ Allow disappearing messages only if your contact allows it to you. - Erlauben Sie verschwindende Nachrichten nur dann, wenn es Ihnen Ihr Kontakt ebenfalls erlaubt. + Erlauben Sie verschwindende Nachrichten nur dann, wenn es Ihr Kontakt ebenfalls erlaubt. No comment provided by engineer. - - Allow irreversible message deletion only if your contact allows it to you. - Erlauben Sie das unwiederbringliche Löschen von Nachrichten nur dann, wenn es Ihnen Ihr Kontakt ebenfalls erlaubt. + + Allow irreversible message deletion only if your contact allows it to you. (24 hours) + Erlauben Sie das unwiederbringliche Löschen von Nachrichten nur dann, wenn es Ihnen Ihr Kontakt ebenfalls erlaubt. (24 Stunden) No comment provided by engineer. @@ -695,9 +698,9 @@ Das Senden von verschwindenden Nachrichten erlauben. No comment provided by engineer. - - Allow to irreversibly delete sent messages. - Unwiederbringliches löschen von gesendeten Nachrichten erlauben. + + Allow to irreversibly delete sent messages. (24 hours) + Unwiederbringliches löschen von gesendeten Nachrichten erlauben. (24 Stunden) No comment provided by engineer. @@ -730,9 +733,9 @@ Erlaubt Ihren Kontakten Sie anzurufen. No comment provided by engineer. - - Allow your contacts to irreversibly delete sent messages. - Erlauben Sie Ihren Kontakten gesendete Nachrichten unwiederbringlich zu löschen. + + Allow your contacts to irreversibly delete sent messages. (24 hours) + Erlauben Sie Ihren Kontakten gesendete Nachrichten unwiederbringlich zu löschen. (24 Stunden) No comment provided by engineer. @@ -930,9 +933,9 @@ Sowohl Sie, als auch Ihr Kontakt können Reaktionen auf Nachrichten geben. No comment provided by engineer. - - Both you and your contact can irreversibly delete sent messages. - Sowohl Ihr Kontakt, als auch Sie können gesendete Nachrichten unwiederbringlich löschen. + + Both you and your contact can irreversibly delete sent messages. (24 hours) + Sowohl Ihr Kontakt, als auch Sie können gesendete Nachrichten unwiederbringlich löschen. (24 Stunden) No comment provided by engineer. @@ -972,6 +975,7 @@ Camera not available + Kamera nicht verfügbar No comment provided by engineer. @@ -1092,6 +1096,7 @@ Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat. + Der Chat ist angehalten. Wenn Sie diese Datenbank bereits auf einem anderen Gerät genutzt haben, sollten Sie diese vor dem Starten des Chats wieder zurückspielen. No comment provided by engineer. @@ -1217,7 +1222,7 @@ Connect to yourself? This is your own SimpleX address! - Mit Ihnen selbst verbinden? + Sich mit Ihnen selbst verbinden? Das ist Ihre eigene SimpleX-Adresse! No comment provided by engineer. @@ -1440,6 +1445,7 @@ Das ist Ihr eigener Einmal-Link! Creating link… + Link wird erstellt… No comment provided by engineer. @@ -1869,7 +1875,7 @@ Das kann nicht rückgängig gemacht werden! Disappearing messages - verschwindende Nachrichten + Verschwindende Nachrichten chat feature @@ -1922,6 +1928,10 @@ Das kann nicht rückgängig gemacht werden! Später wiederholen No comment provided by engineer. + + Do not send history to new members. + No comment provided by engineer. + Don't create address Keine Adresse erstellt @@ -1994,6 +2004,7 @@ Das kann nicht rückgängig gemacht werden! Enable camera access + Kamera-Zugriff aktivieren No comment provided by engineer. @@ -2063,6 +2074,7 @@ Das kann nicht rückgängig gemacht werden! Encrypted message: app is stopped + Verschlüsselte Nachricht: Die App ist angehalten notification @@ -2177,7 +2189,7 @@ Das kann nicht rückgängig gemacht werden! Error changing address - Fehler beim Wechseln der Adresse + Fehler beim Wechseln der Empfängeradresse No comment provided by engineer. @@ -2297,6 +2309,7 @@ Das kann nicht rückgängig gemacht werden! Error opening chat + Fehler beim Öffnen des Chats No comment provided by engineer. @@ -2341,6 +2354,7 @@ Das kann nicht rückgängig gemacht werden! Error scanning code: %@ + Fehler beim Scannen des Codes: %@ No comment provided by engineer. @@ -2673,9 +2687,9 @@ Das kann nicht rückgängig gemacht werden! Gruppenmitglieder können eine Reaktion auf Nachrichten geben. No comment provided by engineer. - - Group members can irreversibly delete sent messages. - Gruppenmitglieder können gesendete Nachrichten unwiederbringlich löschen. + + Group members can irreversibly delete sent messages. (24 hours) + Gruppenmitglieder können gesendete Nachrichten unwiederbringlich löschen. (24 Stunden) No comment provided by engineer. @@ -2780,7 +2794,11 @@ Das kann nicht rückgängig gemacht werden! History - Vergangenheit + Verlauf + No comment provided by engineer. + + + History is not sent to new members. No comment provided by engineer. @@ -2977,6 +2995,7 @@ Das kann nicht rückgängig gemacht werden! Invalid QR code + Ungültiger QR-Code No comment provided by engineer. @@ -2984,8 +3003,13 @@ Das kann nicht rückgängig gemacht werden! Ungültiger Verbindungslink No comment provided by engineer. + + Invalid display name! + No comment provided by engineer. + Invalid link + Ungültiger Link No comment provided by engineer. @@ -2995,6 +3019,7 @@ Das kann nicht rückgängig gemacht werden! Invalid response + Ungültige Reaktion No comment provided by engineer. @@ -3117,6 +3142,7 @@ Das ist Ihr Link für die Gruppe %@! Keep + Behalten No comment provided by engineer. @@ -3126,6 +3152,7 @@ Das ist Ihr Link für die Gruppe %@! Keep unused invitation? + Nicht genutzte Einladung behalten? No comment provided by engineer. @@ -3260,7 +3287,7 @@ Das ist Ihr Link für die Gruppe %@! Make sure WebRTC ICE server addresses are in correct format, line separated and are not duplicated. - Stellen Sie sicher, dass die WebRTC ICE-Server Adressen das richtige Format haben, zeilenweise angeordnet und nicht doppelt vorhanden sind. + Stellen Sie sicher, dass die WebRTC ICE-Server Adressen das richtige Format haben, zeilenweise getrennt und nicht doppelt vorhanden sind. No comment provided by engineer. @@ -3460,6 +3487,7 @@ Das ist Ihr Link für die Gruppe %@! New chat + Neuer Chat No comment provided by engineer. @@ -3549,7 +3577,7 @@ Das ist Ihr Link für die Gruppe %@! No history - Keine Vergangenheit + Kein Verlauf No comment provided by engineer. @@ -3588,6 +3616,7 @@ Das ist Ihr Link für die Gruppe %@! OK + OK No comment provided by engineer. @@ -3655,9 +3684,9 @@ Das ist Ihr Link für die Gruppe %@! Nur Sie können Reaktionen auf Nachrichten geben. No comment provided by engineer. - - Only you can irreversibly delete messages (your contact can mark them for deletion). - Nur Sie können Nachrichten unwiederbringlich löschen (Ihr Kontakt kann sie zum Löschen markieren). + + Only you can irreversibly delete messages (your contact can mark them for deletion). (24 hours) + Nur Sie können Nachrichten unwiederbringlich löschen (Ihr Kontakt kann sie zum Löschen markieren). (24 Stunden) No comment provided by engineer. @@ -3680,9 +3709,9 @@ Das ist Ihr Link für die Gruppe %@! Nur Ihr Kontakt kann Reaktionen auf Nachrichten geben. No comment provided by engineer. - - Only your contact can irreversibly delete messages (you can mark them for deletion). - Nur Ihr Kontakt kann Nachrichten unwiederbringlich löschen (Sie können sie zum Löschen markieren). + + Only your contact can irreversibly delete messages (you can mark them for deletion). (24 hours) + Nur Ihr Kontakt kann Nachrichten unwiederbringlich löschen (Sie können sie zum Löschen markieren). (24 Stunden) No comment provided by engineer. @@ -3737,14 +3766,17 @@ Das ist Ihr Link für die Gruppe %@! Opening app… + App wird geöffnet… No comment provided by engineer. Or scan QR code + Oder den QR-Code scannen No comment provided by engineer. Or show this code + Oder diesen QR-Code anzeigen No comment provided by engineer. @@ -3799,6 +3831,7 @@ Das ist Ihr Link für die Gruppe %@! Paste the link you received + Fügen Sie den erhaltenen Link ein No comment provided by engineer. @@ -3839,6 +3872,8 @@ Das ist Ihr Link für die Gruppe %@! Please contact developers. Error: %@ + Bitte nehmen Sie Kontakt mit den Entwicklern auf. +Fehler: %@ No comment provided by engineer. @@ -4048,6 +4083,7 @@ Error: %@ Read more in [User Guide](https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode). + Lesen Sie mehr dazu im [Benutzerhandbuch](https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode). No comment provided by engineer. @@ -4262,6 +4298,7 @@ Error: %@ Retry + Wiederholen No comment provided by engineer. @@ -4421,6 +4458,7 @@ Error: %@ Search or paste SimpleX link + Suchen oder fügen Sie den SimpleX-Link ein No comment provided by engineer. @@ -4528,6 +4566,10 @@ Error: %@ Senden Sie diese aus dem Fotoalbum oder von individuellen Tastaturen. No comment provided by engineer. + + Send up to 100 last messages to new members. + No comment provided by engineer. + Sender cancelled file transfer. Der Absender hat die Dateiübertragung abgebrochen. @@ -4700,6 +4742,7 @@ Error: %@ Share this 1-time invite link + Teilen Sie diesen Einmal-Einladungslink No comment provided by engineer. @@ -4829,6 +4872,7 @@ Error: %@ Start chat? + Chat starten? No comment provided by engineer. @@ -4938,12 +4982,12 @@ Error: %@ Tap to Connect - Zum Verbinden antippen + Zum Verbinden tippen No comment provided by engineer. Tap to activate profile. - Tippen Sie auf das Profil um es zu aktivieren. + Zum Aktivieren des Profils tippen. No comment provided by engineer. @@ -4953,20 +4997,22 @@ Error: %@ Tap to join incognito - Tippen, um Inkognito beizutreten + Zum Inkognito beitreten tippen No comment provided by engineer. Tap to paste link + Zum Link einfügen tippen No comment provided by engineer. Tap to scan + Zum Scannen tippen No comment provided by engineer. Tap to start a new chat - Tippen, um einen neuen Chat zu starten + Zum Starten eines neuen Chats tippen No comment provided by engineer. @@ -5028,6 +5074,7 @@ Dies kann passieren, wenn es einen Fehler gegeben hat oder die Verbindung kompro The code you scanned is not a SimpleX link QR code. + Der von Ihnen gescannte Code ist kein SimpleX-Link-QR-Code. No comment provided by engineer. @@ -5092,11 +5139,12 @@ Dies kann passieren, wenn es einen Fehler gegeben hat oder die Verbindung kompro The servers for new connections of your current chat profile **%@**. - Server der neuen Verbindungen von Ihrem aktuellen Chat-Profil **%@**. + Mögliche Server für neue Verbindungen von Ihrem aktuellen Chat-Profil **%@**. No comment provided by engineer. The text you pasted is not a SimpleX link. + Der von Ihnen eingefügte Text ist kein SimpleX-Link. No comment provided by engineer. @@ -5144,6 +5192,10 @@ Dies kann passieren, wenn es einen Fehler gegeben hat oder die Verbindung kompro Dieser Gerätename No comment provided by engineer. + + This display name is invalid. Please choose another name. + No comment provided by engineer. + This group has over %lld members, delivery receipts are not sent. Es werden keine Empfangsbestätigungen gesendet, da diese Gruppe über %lld Mitglieder hat. @@ -5368,6 +5420,10 @@ Bitten Sie Ihren Kontakt darum einen weiteren Verbindungs-Link zu erzeugen, um s Ungelesen No comment provided by engineer. + + Up to 100 last messages are sent to new members. + No comment provided by engineer. + Update Aktualisieren @@ -5455,6 +5511,7 @@ Bitten Sie Ihren Kontakt darum einen weiteren Verbindungs-Link zu erzeugen, um s Use only local notifications? + Nur lokale Benachrichtigungen nutzen? No comment provided by engineer. @@ -5537,6 +5594,10 @@ Bitten Sie Ihren Kontakt darum einen weiteren Verbindungs-Link zu erzeugen, um s Schauen Sie sich den Sicherheitscode an No comment provided by engineer. + + Visible history + chat feature + Voice messages Sprachnachrichten @@ -5644,7 +5705,7 @@ Bitten Sie Ihren Kontakt darum einen weiteren Verbindungs-Link zu erzeugen, um s You - Ihre Daten + Profil No comment provided by engineer. @@ -5741,6 +5802,7 @@ Verbindungsanfrage wiederholen? You can make it visible to your SimpleX contacts via Settings. + Sie können sie über Einstellungen für Ihre SimpleX-Kontakte sichtbar machen. No comment provided by engineer. @@ -5785,6 +5847,7 @@ Verbindungsanfrage wiederholen? You can view invitation link again in connection details. + Den Einladungslink können Sie in den Details der Verbindung nochmals sehen. No comment provided by engineer. @@ -5901,7 +5964,7 @@ Verbindungsanfrage wiederholen? You won't lose your contacts if you later delete your address. - Sie werden Ihre mit dieser Adresse verbundenen Kontakte nicht verlieren, wenn Sie diese Adresse später löschen. + Sie werden Ihre damit verbundenen Kontakte nicht verlieren, wenn Sie diese Adresse später löschen. No comment provided by engineer. @@ -6040,7 +6103,7 @@ SimpleX-Server können Ihr Profil nicht einsehen. Your settings - Ihre Einstellungen + Einstellungen No comment provided by engineer. @@ -6155,7 +6218,7 @@ SimpleX-Server können Ihr Profil nicht einsehen. changed address for you - wechselte die Adresse für Sie + Wechselte die Empfängeradresse von Ihnen chat item text @@ -6170,12 +6233,12 @@ SimpleX-Server können Ihr Profil nicht einsehen. changing address for %@… - Adresse von %@ wechseln… + Empfängeradresse für %@ wechseln wird gestartet… chat item text changing address… - Wechsel der Adresse… + Wechsel der Empfängeradresse wurde gestartet… chat item text @@ -6767,12 +6830,12 @@ SimpleX-Server können Ihr Profil nicht einsehen. you changed address - Sie haben die Adresse gewechselt + Die Empfängeradresse wurde gewechselt chat item text you changed address for %@ - Sie haben die Adresse für %@ gewechselt + Die Empfängeradresse für %@ wurde gewechselt chat item text diff --git a/apps/ios/SimpleX Localizations/el.xcloc/Localized Contents/el.xliff b/apps/ios/SimpleX Localizations/el.xcloc/Localized Contents/el.xliff index c6dcc84e99..18051ae350 100644 --- a/apps/ios/SimpleX Localizations/el.xcloc/Localized Contents/el.xliff +++ b/apps/ios/SimpleX Localizations/el.xcloc/Localized Contents/el.xliff @@ -66,20 +66,24 @@ Available in v5.1 %@ είναι συνδεδεμένο! notification title - + %@ is not verified + %@ δεν είναι επαληθευμένο No comment provided by engineer. - + %@ is verified + %@ είναι επαληθευμένο No comment provided by engineer. - + %@ servers + %@ διακομιστές No comment provided by engineer. - + %@ wants to connect! + %@ θέλει να συνδεθεί! notification title @@ -4214,6 +4218,21 @@ SimpleX servers cannot see your profile. %@ και %@ συνδεδεμένο No comment provided by engineer. + + %@: + %@: + copied message info + + + %@, %@ and %lld members + %@, %@ και %lld μέλη + No comment provided by engineer. + + + %@, %@ and %lld other members connected + %@, %@ και %lld άλλα μέλη συνδέθηκαν + No comment provided by engineer. + 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 7dd5db3b65..7cbf91ac9a 100644 --- a/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff +++ b/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff @@ -673,9 +673,9 @@ Allow disappearing messages only if your contact allows it to you. No comment provided by engineer. - - Allow irreversible message deletion only if your contact allows it to you. - Allow irreversible message deletion only if your contact allows it to you. + + Allow irreversible message deletion only if your contact allows it to you. (24 hours) + Allow irreversible message deletion only if your contact allows it to you. (24 hours) No comment provided by engineer. @@ -698,9 +698,9 @@ Allow sending disappearing messages. No comment provided by engineer. - - Allow to irreversibly delete sent messages. - Allow to irreversibly delete sent messages. + + Allow to irreversibly delete sent messages. (24 hours) + Allow to irreversibly delete sent messages. (24 hours) No comment provided by engineer. @@ -733,9 +733,9 @@ Allow your contacts to call you. No comment provided by engineer. - - Allow your contacts to irreversibly delete sent messages. - Allow your contacts to irreversibly delete sent messages. + + Allow your contacts to irreversibly delete sent messages. (24 hours) + Allow your contacts to irreversibly delete sent messages. (24 hours) No comment provided by engineer. @@ -933,9 +933,9 @@ Both you and your contact can add message reactions. No comment provided by engineer. - - Both you and your contact can irreversibly delete sent messages. - Both you and your contact can irreversibly delete sent messages. + + Both you and your contact can irreversibly delete sent messages. (24 hours) + Both you and your contact can irreversibly delete sent messages. (24 hours) No comment provided by engineer. @@ -1928,6 +1928,11 @@ This cannot be undone! Do it later No comment provided by engineer. + + Do not send history to new members. + Do not send history to new members. + No comment provided by engineer. + Don't create address Don't create address @@ -2683,9 +2688,9 @@ This cannot be undone! Group members can add message reactions. No comment provided by engineer. - - Group members can irreversibly delete sent messages. - Group members can irreversibly delete sent messages. + + Group members can irreversibly delete sent messages. (24 hours) + Group members can irreversibly delete sent messages. (24 hours) No comment provided by engineer. @@ -2793,6 +2798,11 @@ This cannot be undone! History No comment provided by engineer. + + History is not sent to new members. + History is not sent to new members. + No comment provided by engineer. + How SimpleX works How SimpleX works @@ -2995,6 +3005,11 @@ This cannot be undone! Invalid connection link No comment provided by engineer. + + Invalid display name! + Invalid display name! + No comment provided by engineer. + Invalid link Invalid link @@ -3672,9 +3687,9 @@ This is your link for group %@! Only you can add message reactions. No comment provided by engineer. - - Only you can irreversibly delete messages (your contact can mark them for deletion). - Only you can irreversibly delete messages (your contact can mark them for deletion). + + Only you can irreversibly delete messages (your contact can mark them for deletion). (24 hours) + Only you can irreversibly delete messages (your contact can mark them for deletion). (24 hours) No comment provided by engineer. @@ -3697,9 +3712,9 @@ This is your link for group %@! Only your contact can add message reactions. No comment provided by engineer. - - Only your contact can irreversibly delete messages (you can mark them for deletion). - Only your contact can irreversibly delete messages (you can mark them for deletion). + + Only your contact can irreversibly delete messages (you can mark them for deletion). (24 hours) + Only your contact can irreversibly delete messages (you can mark them for deletion). (24 hours) No comment provided by engineer. @@ -4554,6 +4569,11 @@ Error: %@ Send them from gallery or custom keyboards. No comment provided by engineer. + + Send up to 100 last messages to new members. + Send up to 100 last messages to new members. + No comment provided by engineer. + Sender cancelled file transfer. Sender cancelled file transfer. @@ -5176,6 +5196,11 @@ It can happen because of some bug or when the connection is compromised.This device name No comment provided by engineer. + + This display name is invalid. Please choose another name. + This display name is invalid. Please choose another name. + No comment provided by engineer. + This group has over %lld members, delivery receipts are not sent. This group has over %lld members, delivery receipts are not sent. @@ -5400,6 +5425,11 @@ To connect, please ask your contact to create another connection link and check Unread No comment provided by engineer. + + Up to 100 last messages are sent to new members. + Up to 100 last messages are sent to new members. + No comment provided by engineer. + Update Update @@ -5570,6 +5600,11 @@ To connect, please ask your contact to create another connection link and check View security code No comment provided by engineer. + + Visible history + Visible history + chat feature + Voice messages Voice messages 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 0f2accb893..95a99befb6 100644 --- a/apps/ios/SimpleX Localizations/es.xcloc/Localized Contents/es.xliff +++ b/apps/ios/SimpleX Localizations/es.xcloc/Localized Contents/es.xliff @@ -314,6 +314,7 @@ **Add contact**: to create a new invitation link, or connect via a link you received. + **Añadir contacto**: crea un enlace de invitación nuevo o usa un enlace recibido. No comment provided by engineer. @@ -323,6 +324,7 @@ **Create group**: to create a new group. + **Crear grupo**: crea un grupo nuevo. No comment provided by engineer. @@ -507,12 +509,12 @@ Abort changing address - Cancelar cambio de dirección + Cancelar cambio de servidor No comment provided by engineer. Abort changing address? - ¿Cancelar el cambio de dirección? + ¿Cancelar el cambio de servidor? No comment provided by engineer. @@ -563,6 +565,7 @@ Add contact + Añadir contacto No comment provided by engineer. @@ -670,9 +673,9 @@ Se permiten los mensajes temporales pero sólo si tu contacto también los permite para tí. No comment provided by engineer. - - Allow irreversible message deletion only if your contact allows it to you. - Se permite la eliminación irreversible de mensajes pero sólo si tu contacto también la permite para tí. + + Allow irreversible message deletion only if your contact allows it to you. (24 hours) + Se permite la eliminación irreversible de mensajes pero sólo si tu contacto también la permite para tí. (24 horas) No comment provided by engineer. @@ -682,7 +685,7 @@ Allow message reactions. - Permitir reacciones a los mensajes. + Se permiten reacciones a los mensajes. No comment provided by engineer. @@ -695,9 +698,9 @@ Permites el envío de mensajes temporales. No comment provided by engineer. - - Allow to irreversibly delete sent messages. - Se permite la eliminación irreversible de mensajes. + + Allow to irreversibly delete sent messages. (24 hours) + Se permite la eliminación irreversible de mensajes. (24 horas) No comment provided by engineer. @@ -730,9 +733,9 @@ Permites que tus contactos puedan llamarte. No comment provided by engineer. - - Allow your contacts to irreversibly delete sent messages. - Permites a tus contactos eliminar irreversiblemente los mensajes enviados. + + Allow your contacts to irreversibly delete sent messages. (24 hours) + Permites a tus contactos eliminar irreversiblemente los mensajes enviados. (24 horas) No comment provided by engineer. @@ -757,7 +760,7 @@ Already joining the group! - ¡Ya en proceso de unirse al grupo! + ¡Ya en proceso de unirte al grupo! No comment provided by engineer. @@ -930,9 +933,9 @@ Tanto tú como tu contacto podéis añadir reacciones a los mensajes. No comment provided by engineer. - - Both you and your contact can irreversibly delete sent messages. - Tanto tú como tu contacto podéis eliminar de forma irreversible los mensajes enviados. + + Both you and your contact can irreversibly delete sent messages. (24 hours) + Tanto tú como tu contacto podéis eliminar de forma irreversible los mensajes enviados. (24 horas) No comment provided by engineer. @@ -972,6 +975,7 @@ Camera not available + Cámara no disponible No comment provided by engineer. @@ -986,7 +990,7 @@ Can't invite contacts! - ¡No se puede invitar a los contactos! + ¡No se pueden invitar contactos! No comment provided by engineer. @@ -1021,7 +1025,7 @@ Change member role? - ¿Cambiar el rol del miembro? + ¿Cambiar rol? No comment provided by engineer. @@ -1092,6 +1096,7 @@ Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat. + Chat está detenido. Si estás usando esta base de datos en otro dispositivo, deberías transferirla de vuelta antes de iniciarlo. No comment provided by engineer. @@ -1440,6 +1445,7 @@ This is your own one-time link! Creating link… + Creando enlace… No comment provided by engineer. @@ -1744,7 +1750,7 @@ This cannot be undone! Delete pending connection? - ¿Eliminar la conexion pendiente? + ¿Eliminar conexión pendiente? No comment provided by engineer. @@ -1922,6 +1928,10 @@ This cannot be undone! Hacer más tarde No comment provided by engineer. + + Do not send history to new members. + No comment provided by engineer. + Don't create address No crear dirección SimpleX @@ -1994,6 +2004,7 @@ This cannot be undone! Enable camera access + Permitir acceso a la cámara No comment provided by engineer. @@ -2063,6 +2074,7 @@ This cannot be undone! Encrypted message: app is stopped + Mensaje cifrado: la aplicación está parada notification @@ -2177,7 +2189,7 @@ This cannot be undone! Error changing address - Error al cambiar dirección + Error al cambiar servidor No comment provided by engineer. @@ -2287,7 +2299,7 @@ This cannot be undone! Error joining group - Error al unirse al grupo + Error al unirte al grupo No comment provided by engineer. @@ -2297,6 +2309,7 @@ This cannot be undone! Error opening chat + Error al abrir chat No comment provided by engineer. @@ -2341,6 +2354,7 @@ This cannot be undone! Error scanning code: %@ + Error al escanear código: %@ No comment provided by engineer. @@ -2673,9 +2687,9 @@ This cannot be undone! Los miembros pueden añadir reacciones a los mensajes. No comment provided by engineer. - - Group members can irreversibly delete sent messages. - Los miembros del grupo pueden eliminar mensajes de forma irreversible. + + Group members can irreversibly delete sent messages. (24 hours) + Los miembros del grupo pueden eliminar mensajes de forma irreversible. (24 horas) No comment provided by engineer. @@ -2710,7 +2724,7 @@ This cannot be undone! Group preferences - Preferencias de grupo + Preferencias del grupo No comment provided by engineer. @@ -2783,6 +2797,10 @@ This cannot be undone! Historial No comment provided by engineer. + + History is not sent to new members. + No comment provided by engineer. + How SimpleX works Cómo funciona SimpleX @@ -2977,6 +2995,7 @@ This cannot be undone! Invalid QR code + Código QR no válido No comment provided by engineer. @@ -2984,8 +3003,13 @@ This cannot be undone! Enlace de conexión no válido No comment provided by engineer. + + Invalid display name! + No comment provided by engineer. + Invalid link + Enlace no válido No comment provided by engineer. @@ -2995,6 +3019,7 @@ This cannot be undone! Invalid response + Respuesta no válida No comment provided by engineer. @@ -3080,22 +3105,22 @@ This cannot be undone! Join - Únete + Unirte No comment provided by engineer. Join group - Únete al grupo + Unirte al grupo No comment provided by engineer. Join group? - ¿Unirse al grupo? + ¿Unirte al grupo? No comment provided by engineer. Join incognito - Únete en modo incógnito + Unirte en modo incógnito No comment provided by engineer. @@ -3117,6 +3142,7 @@ This is your link for group %@! Keep + Guardar No comment provided by engineer. @@ -3126,6 +3152,7 @@ This is your link for group %@! Keep unused invitation? + ¿Guardar invitación no usada? No comment provided by engineer. @@ -3300,12 +3327,12 @@ This is your link for group %@! Member role will be changed to "%@". All group members will be notified. - El rol de miembro cambiará a "%@". Todos los miembros del grupo serán notificados. + El rol del miembro cambiará a "%@" y se notificará al grupo. No comment provided by engineer. Member role will be changed to "%@". The member will receive a new invitation. - El rol del miembro cambiará a "%@". El miembro recibirá una invitación nueva. + El rol del miembro cambiará a "%@" y recibirá una invitación nueva. No comment provided by engineer. @@ -3330,7 +3357,7 @@ This is your link for group %@! Message reactions - Reacciones a los mensajes + Reacciones a mensajes chat feature @@ -3460,6 +3487,7 @@ This is your link for group %@! New chat + Nuevo chat No comment provided by engineer. @@ -3588,6 +3616,7 @@ This is your link for group %@! OK + OK No comment provided by engineer. @@ -3637,7 +3666,7 @@ This is your link for group %@! Only group owners can change group preferences. - Sólo los propietarios pueden modificar las preferencias de grupo. + Sólo los propietarios pueden modificar las preferencias del grupo. No comment provided by engineer. @@ -3655,9 +3684,9 @@ This is your link for group %@! Sólo tú puedes añadir reacciones a los mensajes. No comment provided by engineer. - - Only you can irreversibly delete messages (your contact can mark them for deletion). - Sólo tú puedes eliminar mensajes de forma irreversible (tu contacto puede marcarlos para eliminar). + + Only you can irreversibly delete messages (your contact can mark them for deletion). (24 hours) + Sólo tú puedes eliminar mensajes de forma irreversible (tu contacto puede marcarlos para eliminar). (24 horas) No comment provided by engineer. @@ -3680,9 +3709,9 @@ This is your link for group %@! Sólo tu contacto puede añadir reacciones a los mensajes. No comment provided by engineer. - - Only your contact can irreversibly delete messages (you can mark them for deletion). - Sólo tu contacto puede eliminar mensajes de forma irreversible (tu puedes marcarlos para eliminar). + + Only your contact can irreversibly delete messages (you can mark them for deletion). (24 hours) + Sólo tu contacto puede eliminar mensajes de forma irreversible (tu puedes marcarlos para eliminar). (24 horas) No comment provided by engineer. @@ -3737,14 +3766,17 @@ This is your link for group %@! Opening app… + Iniciando aplicación… No comment provided by engineer. Or scan QR code + O escanear código QR No comment provided by engineer. Or show this code + O mostrar este código No comment provided by engineer. @@ -3799,6 +3831,7 @@ This is your link for group %@! Paste the link you received + Pegar el enlace recibido No comment provided by engineer. @@ -3839,11 +3872,13 @@ This is your link for group %@! Please contact developers. Error: %@ + Por favor, contacta con los desarrolladores. +Error: %@ No comment provided by engineer. Please contact group admin. - Póngase en contacto con el administrador del grupo. + Ponte en contacto con el administrador del grupo. No comment provided by engineer. @@ -4043,26 +4078,27 @@ Error: %@ Read more in [User Guide](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address). - Más información en el [Manual de usuario](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address). + Saber más en el [Manual del Usuario](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address). No comment provided by engineer. Read more in [User Guide](https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode). + Saber más en [Guía de Usuario](https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode). No comment provided by engineer. Read more in [User Guide](https://simplex.chat/docs/guide/readme.html#connect-to-friends). - Más información en el [Manual de usuario](https://simplex.chat/docs/guide/readme.html#connect-to-friends). + Saber más en el [Manual del Usuario](https://simplex.chat/docs/guide/readme.html#connect-to-friends). No comment provided by engineer. Read more in our GitHub repository. - Más información en nuestro repositorio GitHub. + Saber más en nuestro repositorio GitHub. No comment provided by engineer. Read more in our [GitHub repository](https://github.com/simplex-chat/simplex-chat#readme). - Más información en nuestro [repositorio GitHub](https://github.com/simplex-chat/simplex-chat#readme). + Saber más en nuestro [repositorio GitHub](https://github.com/simplex-chat/simplex-chat#readme). No comment provided by engineer. @@ -4262,6 +4298,7 @@ Error: %@ Retry + Reintentar No comment provided by engineer. @@ -4321,12 +4358,12 @@ Error: %@ Save and notify group members - Guardar y notificar a los miembros del grupo + Guardar y notificar grupo No comment provided by engineer. Save and update group profile - Guardar y actualizar perfil de grupo + Guardar y actualizar perfil del grupo No comment provided by engineer. @@ -4421,6 +4458,7 @@ Error: %@ Search or paste SimpleX link + Buscar o pegar enlace SimpleX No comment provided by engineer. @@ -4528,6 +4566,10 @@ Error: %@ Envíalos desde la galería o desde teclados personalizados. No comment provided by engineer. + + Send up to 100 last messages to new members. + No comment provided by engineer. + Sender cancelled file transfer. El remitente ha cancelado la transferencia de archivos. @@ -4700,6 +4742,7 @@ Error: %@ Share this 1-time invite link + Compartir este enlace de un uso No comment provided by engineer. @@ -4829,6 +4872,7 @@ Error: %@ Start chat? + ¿Iniciar chat? No comment provided by engineer. @@ -4948,7 +4992,7 @@ Error: %@ Tap to join - Pulsa para unirse + Pulsa para unirte No comment provided by engineer. @@ -4958,10 +5002,12 @@ Error: %@ Tap to paste link + Pulsa para pegar enlace No comment provided by engineer. Tap to scan + Pulsa para escanear No comment provided by engineer. @@ -5028,6 +5074,7 @@ Puede ocurrir por algún bug o cuando la conexión está comprometida. The code you scanned is not a SimpleX link QR code. + El código QR escaneado no es un enlace SimpleX. No comment provided by engineer. @@ -5097,6 +5144,7 @@ Puede ocurrir por algún bug o cuando la conexión está comprometida. The text you pasted is not a SimpleX link. + El texto pegado no es un enlace SimpleX. No comment provided by engineer. @@ -5144,6 +5192,10 @@ Puede ocurrir por algún bug o cuando la conexión está comprometida. Nombre del dispositivo No comment provided by engineer. + + This display name is invalid. Please choose another name. + No comment provided by engineer. + This group has over %lld members, delivery receipts are not sent. Este grupo tiene más de %lld miembros, no se enviarán confirmaciones de entrega. @@ -5223,7 +5275,7 @@ Se te pedirá que completes la autenticación antes de activar esta función. To verify end-to-end encryption with your contact compare (or scan) the code on your devices. - Para comprobar el cifrado de extremo a extremo con tu contacto compara (o escanea) el código en tus dispositivos. + 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. @@ -5369,6 +5421,10 @@ Para conectarte, pide a tu contacto que cree otro enlace de conexión y comprueb No leído No comment provided by engineer. + + Up to 100 last messages are sent to new members. + No comment provided by engineer. + Update Actualizar @@ -5456,6 +5512,7 @@ Para conectarte, pide a tu contacto que cree otro enlace de conexión y comprueb Use only local notifications? + ¿Usar sólo notificaciones locales? No comment provided by engineer. @@ -5538,6 +5595,10 @@ Para conectarte, pide a tu contacto que cree otro enlace de conexión y comprueb Mostrar código de seguridad No comment provided by engineer. + + Visible history + chat feature + Voice messages Mensajes de voz @@ -5712,7 +5773,7 @@ Repeat join request? You are invited to group - Has sido invitado al grupo + Has sido invitado a un grupo No comment provided by engineer. @@ -5742,6 +5803,7 @@ Repeat join request? You can make it visible to your SimpleX contacts via Settings. + Puedes hacerlo visible para tus contactos de SimpleX en Configuración. No comment provided by engineer. @@ -5756,7 +5818,7 @@ Repeat join request? You can share a link or a QR code - anybody will be able to join the group. You won't lose members of the group if you later delete it. - Puedes compartir un enlace o un código QR: cualquiera podrá unirse al grupo. Si lo eliminas más tarde los miembros del grupo no se perderán. + Puedes compartir un enlace o código QR para que cualquiera pueda unirse al grupo. Si decides eliminarlo más tarde, los miembros del grupo se mantendrán. No comment provided by engineer. @@ -5766,7 +5828,7 @@ Repeat join request? You can share your address as a link or QR code - anybody can connect to you. - Puedes compartir tu dirección como enlace o como código QR: cualquiera podrá conectarse contigo. + Puedes compartir tu dirección como enlace o código QR para que cualquiera pueda conectarse contigo. No comment provided by engineer. @@ -5786,6 +5848,7 @@ Repeat join request? You can view invitation link again in connection details. + Podrás ver el enlace de invitación en detalles de conexión. No comment provided by engineer. @@ -5912,7 +5975,7 @@ Repeat connection request? You're using an incognito profile for this group - to prevent sharing your main profile inviting contacts is not allowed - Estás usando un perfil incógnito para este grupo, por tanto para evitar compartir tu perfil principal no se permite invitar a contactos + Estás usando un perfil incógnito en este grupo. Para evitar descubrir tu perfil principal no se permite invitar contactos No comment provided by engineer. @@ -6156,7 +6219,7 @@ Los servidores de SimpleX no pueden ver tu perfil. changed address for you - el servidor de envío ha cambiado para tí + ha cambiado tu servidor de envío chat item text @@ -6171,12 +6234,12 @@ Los servidores de SimpleX no pueden ver tu perfil. changing address for %@… - cambiando dirección para %@… + cambiando el servidor para %@… chat item text changing address… - cambiando dirección… + cambiando de servidor… chat item text @@ -6758,7 +6821,7 @@ Los servidores de SimpleX no pueden ver tu perfil. you are invited to group - has sido invitado al grupo + has sido invitado a un grupo 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 81bc19013b..1d497ace5a 100644 --- a/apps/ios/SimpleX Localizations/fi.xcloc/Localized Contents/fi.xliff +++ b/apps/ios/SimpleX Localizations/fi.xcloc/Localized Contents/fi.xliff @@ -653,9 +653,9 @@ Salli katoavat viestit vain, jos kontaktisi sallii sen sinulle. No comment provided by engineer. - - Allow irreversible message deletion only if your contact allows it to you. - Salli peruuttamaton viestien poisto vain, jos kontaktisi sallii ne sinulle. + + Allow irreversible message deletion only if your contact allows it to you. (24 hours) + Salli peruuttamaton viestien poisto vain, jos kontaktisi sallii ne sinulle. (24 tuntia) No comment provided by engineer. @@ -678,9 +678,9 @@ Salli katoavien viestien lähettäminen. No comment provided by engineer. - - Allow to irreversibly delete sent messages. - Salli lähetettyjen viestien peruuttamaton poistaminen. + + Allow to irreversibly delete sent messages. (24 hours) + Salli lähetettyjen viestien peruuttamaton poistaminen. (24 tuntia) No comment provided by engineer. @@ -713,9 +713,9 @@ Salli kontaktiesi soittaa sinulle. No comment provided by engineer. - - Allow your contacts to irreversibly delete sent messages. - Salli kontaktiesi poistaa lähetetyt viestit peruuttamattomasti. + + Allow your contacts to irreversibly delete sent messages. (24 hours) + Salli kontaktiesi poistaa lähetetyt viestit peruuttamattomasti. (24 tuntia) No comment provided by engineer. @@ -904,9 +904,9 @@ Sekä sinä että kontaktisi voivat käyttää viestireaktioita. No comment provided by engineer. - - Both you and your contact can irreversibly delete sent messages. - Sekä sinä että kontaktisi voitte peruuttamattomasti poistaa lähetetyt viestit. + + Both you and your contact can irreversibly delete sent messages. (24 hours) + Sekä sinä että kontaktisi voitte peruuttamattomasti poistaa lähetetyt viestit. (24 tuntia) No comment provided by engineer. @@ -1869,6 +1869,10 @@ This cannot be undone! Tee myöhemmin No comment provided by engineer. + + Do not send history to new members. + No comment provided by engineer. + Don't create address Älä luo osoitetta @@ -2606,9 +2610,9 @@ This cannot be undone! Ryhmän jäsenet voivat lisätä viestireaktioita. No comment provided by engineer. - - Group members can irreversibly delete sent messages. - Ryhmän jäsenet voivat poistaa lähetetyt viestit peruuttamattomasti. + + Group members can irreversibly delete sent messages. (24 hours) + Ryhmän jäsenet voivat poistaa lähetetyt viestit peruuttamattomasti. (24 tuntia) No comment provided by engineer. @@ -2716,6 +2720,10 @@ This cannot be undone! Historia No comment provided by engineer. + + History is not sent to new members. + No comment provided by engineer. + How SimpleX works Miten SimpleX toimii @@ -2915,6 +2923,10 @@ This cannot be undone! Virheellinen yhteyslinkki No comment provided by engineer. + + Invalid display name! + No comment provided by engineer. + Invalid link No comment provided by engineer. @@ -3574,9 +3586,9 @@ This is your link for group %@! Vain sinä voit lisätä viestireaktioita. No comment provided by engineer. - - Only you can irreversibly delete messages (your contact can mark them for deletion). - Vain sinä voit poistaa viestejä peruuttamattomasti (kontaktisi voi merkitä ne poistettavaksi). + + Only you can irreversibly delete messages (your contact can mark them for deletion). (24 hours) + Vain sinä voit poistaa viestejä peruuttamattomasti (kontaktisi voi merkitä ne poistettavaksi). (24 tuntia) No comment provided by engineer. @@ -3599,9 +3611,9 @@ This is your link for group %@! Vain kontaktisi voi lisätä viestireaktioita. No comment provided by engineer. - - Only your contact can irreversibly delete messages (you can mark them for deletion). - Vain kontaktisi voi poistaa viestejä peruuttamattomasti (voit merkitä ne poistettavaksi). + + Only your contact can irreversibly delete messages (you can mark them for deletion). (24 hours) + Vain kontaktisi voi poistaa viestejä peruuttamattomasti (voit merkitä ne poistettavaksi). (24 tuntia) No comment provided by engineer. @@ -4438,6 +4450,10 @@ Error: %@ Lähetä ne galleriasta tai mukautetuista näppäimistöistä. No comment provided by engineer. + + Send up to 100 last messages to new members. + No comment provided by engineer. + Sender cancelled file transfer. Lähettäjä peruutti tiedoston siirron. @@ -5050,6 +5066,10 @@ Tämä voi johtua jostain virheestä tai siitä, että yhteys on vaarantunut.This device name No comment provided by engineer. + + This display name is invalid. Please choose another name. + No comment provided by engineer. + This group has over %lld members, delivery receipts are not sent. Tässä ryhmässä on yli %lld jäsentä, lähetyskuittauksia ei lähetetä. @@ -5265,6 +5285,10 @@ Jos haluat muodostaa yhteyden, pyydä kontaktiasi luomaan toinen yhteyslinkki ja Lukematon No comment provided by engineer. + + Up to 100 last messages are sent to new members. + No comment provided by engineer. + Update Päivitä @@ -5429,6 +5453,10 @@ Jos haluat muodostaa yhteyden, pyydä kontaktiasi luomaan toinen yhteyslinkki ja Näytä turvakoodi No comment provided by engineer. + + Visible history + chat feature + Voice messages Ääniviestit 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 4d08ee9652..7c7a789803 100644 --- a/apps/ios/SimpleX Localizations/fr.xcloc/Localized Contents/fr.xliff +++ b/apps/ios/SimpleX Localizations/fr.xcloc/Localized Contents/fr.xliff @@ -314,6 +314,7 @@ **Add contact**: to create a new invitation link, or connect via a link you received. + **Ajouter un contact** : pour créer un nouveau lien d'invitation ou vous connecter via un lien que vous avez reçu. No comment provided by engineer. @@ -323,6 +324,7 @@ **Create group**: to create a new group. + **Créer un groupe** : pour créer un nouveau groupe. No comment provided by engineer. @@ -563,6 +565,7 @@ Add contact + Ajouter le contact No comment provided by engineer. @@ -670,9 +673,9 @@ Autorise les messages éphémères seulement si votre contact vous l’autorise. No comment provided by engineer. - - Allow irreversible message deletion only if your contact allows it to you. - Autoriser la suppression irréversible des messages uniquement si votre contact vous l'autorise. + + Allow irreversible message deletion only if your contact allows it to you. (24 hours) + Autoriser la suppression irréversible des messages uniquement si votre contact vous l'autorise. (24 heures) No comment provided by engineer. @@ -695,9 +698,9 @@ Autorise l’envoi de messages éphémères. No comment provided by engineer. - - Allow to irreversibly delete sent messages. - Autoriser la suppression irréversible de messages envoyés. + + Allow to irreversibly delete sent messages. (24 hours) + Autoriser la suppression irréversible de messages envoyés. (24 heures) No comment provided by engineer. @@ -730,9 +733,9 @@ Autorise vos contacts à vous appeler. No comment provided by engineer. - - Allow your contacts to irreversibly delete sent messages. - Autorise vos contacts à supprimer de manière irréversible les messages envoyés. + + Allow your contacts to irreversibly delete sent messages. (24 hours) + Autorise vos contacts à supprimer de manière irréversible les messages envoyés. (24 heures) No comment provided by engineer. @@ -930,9 +933,9 @@ Vous et votre contact pouvez ajouter des réactions aux messages. No comment provided by engineer. - - Both you and your contact can irreversibly delete sent messages. - Vous et votre contact êtes tous deux en mesure de supprimer de manière irréversible les messages envoyés. + + Both you and your contact can irreversibly delete sent messages. (24 hours) + Vous et votre contact êtes tous deux en mesure de supprimer de manière irréversible les messages envoyés. (24 heures) No comment provided by engineer. @@ -972,6 +975,7 @@ Camera not available + Caméra non disponible No comment provided by engineer. @@ -1092,6 +1096,7 @@ Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat. + Le chat est arrêté. Si vous avez déjà utilisé cette base de données sur un autre appareil, vous devez la transférer à nouveau avant de démarrer le chat. No comment provided by engineer. @@ -1101,7 +1106,7 @@ Chats - Chats + Discussions No comment provided by engineer. @@ -1206,7 +1211,7 @@ Connect to desktop - Se connecter au bureau + Connexion au bureau No comment provided by engineer. @@ -1440,6 +1445,7 @@ Il s'agit de votre propre lien unique ! Creating link… + Création d'un lien… No comment provided by engineer. @@ -1922,6 +1928,10 @@ Cette opération ne peut être annulée ! Faites-le plus tard No comment provided by engineer. + + Do not send history to new members. + No comment provided by engineer. + Don't create address Ne pas créer d'adresse @@ -1994,6 +2004,7 @@ Cette opération ne peut être annulée ! Enable camera access + Autoriser l'accès à la caméra No comment provided by engineer. @@ -2063,6 +2074,7 @@ Cette opération ne peut être annulée ! Encrypted message: app is stopped + Message chiffré : l'application est arrêtée notification @@ -2297,6 +2309,7 @@ Cette opération ne peut être annulée ! Error opening chat + Erreur lors de l'ouverture du chat No comment provided by engineer. @@ -2341,6 +2354,7 @@ Cette opération ne peut être annulée ! Error scanning code: %@ + Erreur lors du scan du code : %@ No comment provided by engineer. @@ -2430,7 +2444,7 @@ Cette opération ne peut être annulée ! Exit without saving - Quitter sans sauvegarder + Quitter sans enregistrer No comment provided by engineer. @@ -2530,7 +2544,7 @@ Cette opération ne peut être annulée ! Find chats faster - Trouver des messages plus rapidement + Recherche de message plus rapide No comment provided by engineer. @@ -2673,9 +2687,9 @@ Cette opération ne peut être annulée ! Les membres du groupe peuvent ajouter des réactions aux messages. No comment provided by engineer. - - Group members can irreversibly delete sent messages. - Les membres du groupe peuvent supprimer de manière irréversible les messages envoyés. + + Group members can irreversibly delete sent messages. (24 hours) + Les membres du groupe peuvent supprimer de manière irréversible les messages envoyés. (24 heures) No comment provided by engineer. @@ -2783,6 +2797,10 @@ Cette opération ne peut être annulée ! Historique No comment provided by engineer. + + History is not sent to new members. + No comment provided by engineer. + How SimpleX works Comment SimpleX fonctionne @@ -2977,6 +2995,7 @@ Cette opération ne peut être annulée ! Invalid QR code + Code QR invalide No comment provided by engineer. @@ -2984,8 +3003,13 @@ Cette opération ne peut être annulée ! Lien de connection invalide No comment provided by engineer. + + Invalid display name! + No comment provided by engineer. + Invalid link + Lien invalide No comment provided by engineer. @@ -2995,6 +3019,7 @@ Cette opération ne peut être annulée ! Invalid response + Réponse invalide No comment provided by engineer. @@ -3117,6 +3142,7 @@ Voici votre lien pour le groupe %@ ! Keep + Conserver No comment provided by engineer. @@ -3126,6 +3152,7 @@ Voici votre lien pour le groupe %@ ! Keep unused invitation? + Conserver l'invitation inutilisée ? No comment provided by engineer. @@ -3460,6 +3487,7 @@ Voici votre lien pour le groupe %@ ! New chat + Nouveau chat No comment provided by engineer. @@ -3539,7 +3567,7 @@ Voici votre lien pour le groupe %@ ! No filtered chats - Pas de chats filtrés + Aucune discussion filtrés No comment provided by engineer. @@ -3588,6 +3616,7 @@ Voici votre lien pour le groupe %@ ! OK + OK No comment provided by engineer. @@ -3655,9 +3684,9 @@ Voici votre lien pour le groupe %@ ! Vous seul pouvez ajouter des réactions aux messages. No comment provided by engineer. - - Only you can irreversibly delete messages (your contact can mark them for deletion). - Vous êtes le seul à pouvoir supprimer des messages de manière irréversible (votre contact peut les marquer comme supprimé). + + Only you can irreversibly delete messages (your contact can mark them for deletion). (24 hours) + Vous êtes le seul à pouvoir supprimer des messages de manière irréversible (votre contact peut les marquer comme supprimé). (24 heures) No comment provided by engineer. @@ -3680,9 +3709,9 @@ Voici votre lien pour le groupe %@ ! Seul votre contact peut ajouter des réactions aux messages. No comment provided by engineer. - - Only your contact can irreversibly delete messages (you can mark them for deletion). - Seul votre contact peut supprimer de manière irréversible des messages (vous pouvez les marquer comme supprimé). + + Only your contact can irreversibly delete messages (you can mark them for deletion). (24 hours) + Seul votre contact peut supprimer de manière irréversible des messages (vous pouvez les marquer comme supprimé). (24 heures) No comment provided by engineer. @@ -3737,14 +3766,17 @@ Voici votre lien pour le groupe %@ ! Opening app… + Ouverture de l'app… No comment provided by engineer. Or scan QR code + Ou scanner le code QR No comment provided by engineer. Or show this code + Ou présenter ce code No comment provided by engineer. @@ -3799,6 +3831,7 @@ Voici votre lien pour le groupe %@ ! Paste the link you received + Collez le lien que vous avez reçu No comment provided by engineer. @@ -3839,6 +3872,8 @@ Voici votre lien pour le groupe %@ ! Please contact developers. Error: %@ + Veuillez contacter les développeurs. +Erreur : %@ No comment provided by engineer. @@ -4048,6 +4083,7 @@ Error: %@ Read more in [User Guide](https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode). + Pour en savoir plus, consultez le [Guide de l'utilisateur](https ://simplex.chat/docs/guide/chat-profiles.html#incognito-mode). No comment provided by engineer. @@ -4262,6 +4298,7 @@ Error: %@ Retry + Réessayer No comment provided by engineer. @@ -4306,57 +4343,57 @@ Error: %@ Save - Sauvegarder + Enregistrer chat item action Save (and notify contacts) - Sauvegarder (et en informer les contacts) + Enregistrer (et en informer les contacts) No comment provided by engineer. Save and notify contact - Sauvegarder et en informer les contacts + Enregistrer et en informer le contact No comment provided by engineer. Save and notify group members - Sauvegarder et en informer les membres du groupe + Enregistrer et en informer les membres du groupe No comment provided by engineer. Save and update group profile - Sauvegarder et mettre à jour le profil du groupe + Enregistrer et mettre à jour le profil du groupe No comment provided by engineer. Save archive - Sauvegarder l'archive + Enregistrer l'archive No comment provided by engineer. Save auto-accept settings - Sauvegarder les paramètres d'acceptation automatique + Enregistrer les paramètres de validation automatique No comment provided by engineer. Save group profile - Sauvegarder le profil du groupe + Enregistrer le profil du groupe No comment provided by engineer. Save passphrase and open chat - Sauvegarder la phrase secrète et ouvrir le chat + Enregistrer la phrase secrète et ouvrir le chat No comment provided by engineer. Save passphrase in Keychain - Sauvegarder la phrase secrète dans la keychain + Enregistrer la phrase secrète dans la Keychain No comment provided by engineer. Save preferences? - Sauvegarder les préférences ? + Enregistrer les préférences ? No comment provided by engineer. @@ -4366,22 +4403,22 @@ Error: %@ Save servers - Sauvegarder les serveurs + Enregistrer les serveurs No comment provided by engineer. Save servers? - Sauvegarder les serveurs ? + Enregistrer les serveurs ? No comment provided by engineer. Save settings? - Sauvegarder les paramètres ? + Enregistrer les paramètres ? No comment provided by engineer. Save welcome message? - Sauvegarder le message d'accueil ? + Enregistrer le message d'accueil ? No comment provided by engineer. @@ -4396,7 +4433,7 @@ Error: %@ Scan QR code from desktop - Scanner le code QR du bureau + Scannez le code QR du bureau No comment provided by engineer. @@ -4416,11 +4453,12 @@ Error: %@ Search - Recherche + Rechercher No comment provided by engineer. Search or paste SimpleX link + Rechercher ou coller un lien SimpleX No comment provided by engineer. @@ -4520,7 +4558,7 @@ Error: %@ Send receipts - Envoyer les justificatifs + Envoi de justificatifs No comment provided by engineer. @@ -4528,6 +4566,10 @@ Error: %@ Envoyez-les depuis la phototèque ou des claviers personnalisés. No comment provided by engineer. + + Send up to 100 last messages to new members. + No comment provided by engineer. + Sender cancelled file transfer. L'expéditeur a annulé le transfert de fichiers. @@ -4700,6 +4742,7 @@ Error: %@ Share this 1-time invite link + Partager ce lien d'invitation unique No comment provided by engineer. @@ -4829,6 +4872,7 @@ Error: %@ Start chat? + Lancer le chat ? No comment provided by engineer. @@ -4958,10 +5002,12 @@ Error: %@ Tap to paste link + Appuyez pour coller le lien No comment provided by engineer. Tap to scan + Appuyez pour scanner No comment provided by engineer. @@ -5028,6 +5074,7 @@ Cela peut se produire en raison d'un bug ou lorsque la connexion est compromise. The code you scanned is not a SimpleX link QR code. + Le code scanné n'est pas un code QR de lien SimpleX. No comment provided by engineer. @@ -5097,6 +5144,7 @@ Cela peut se produire en raison d'un bug ou lorsque la connexion est compromise. The text you pasted is not a SimpleX link. + Le texte collé n'est pas un lien SimpleX. No comment provided by engineer. @@ -5141,7 +5189,11 @@ Cela peut se produire en raison d'un bug ou lorsque la connexion est compromise. This device name - Ce nom d'appareil + Nom de cet appareil + No comment provided by engineer. + + + This display name is invalid. Please choose another name. No comment provided by engineer. @@ -5368,6 +5420,10 @@ Pour vous connecter, veuillez demander à votre contact de créer un autre lien Non lu No comment provided by engineer. + + Up to 100 last messages are sent to new members. + No comment provided by engineer. + Update Mise à jour @@ -5440,7 +5496,7 @@ Pour vous connecter, veuillez demander à votre contact de créer un autre lien Use from desktop - Utilisation depuis le bureau + Accès au bureau No comment provided by engineer. @@ -5455,6 +5511,7 @@ Pour vous connecter, veuillez demander à votre contact de créer un autre lien Use only local notifications? + Utilisation de notifications locales uniquement ? No comment provided by engineer. @@ -5537,6 +5594,10 @@ Pour vous connecter, veuillez demander à votre contact de créer un autre lien Afficher le code de sécurité No comment provided by engineer. + + Visible history + chat feature + Voice messages Messages vocaux @@ -5741,6 +5802,7 @@ Répéter la demande d'adhésion ? You can make it visible to your SimpleX contacts via Settings. + Vous pouvez le rendre visible à vos contacts SimpleX via Paramètres. No comment provided by engineer. @@ -5785,6 +5847,7 @@ Répéter la demande d'adhésion ? You can view invitation link again in connection details. + Vous pouvez à nouveau consulter le lien d'invitation dans les détails de la connexion. No comment provided by engineer. 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 d9d48bd995..f5a7e1bb9a 100644 --- a/apps/ios/SimpleX Localizations/it.xcloc/Localized Contents/it.xliff +++ b/apps/ios/SimpleX Localizations/it.xcloc/Localized Contents/it.xliff @@ -314,6 +314,7 @@ **Add contact**: to create a new invitation link, or connect via a link you received. + **Aggiungi contatto**: per creare un nuovo link di invito o connetterti tramite un link che hai ricevuto. No comment provided by engineer. @@ -323,6 +324,7 @@ **Create group**: to create a new group. + **Crea gruppo**: per creare un nuovo gruppo. No comment provided by engineer. @@ -563,6 +565,7 @@ Add contact + Aggiungi contatto No comment provided by engineer. @@ -670,9 +673,9 @@ Consenti i messaggi a tempo solo se il contatto li consente a te. No comment provided by engineer. - - Allow irreversible message deletion only if your contact allows it to you. - Consenti l'eliminazione irreversibile dei messaggi solo se il contatto la consente a te. + + Allow irreversible message deletion only if your contact allows it to you. (24 hours) + Consenti l'eliminazione irreversibile dei messaggi solo se il contatto la consente a te. (24 ore) No comment provided by engineer. @@ -695,9 +698,9 @@ Permetti l'invio di messaggi a tempo. No comment provided by engineer. - - Allow to irreversibly delete sent messages. - Permetti di eliminare irreversibilmente i messaggi inviati. + + Allow to irreversibly delete sent messages. (24 hours) + Permetti di eliminare irreversibilmente i messaggi inviati. (24 ore) No comment provided by engineer. @@ -730,9 +733,9 @@ Consenti ai tuoi contatti di chiamarti. No comment provided by engineer. - - Allow your contacts to irreversibly delete sent messages. - Permetti ai tuoi contatti di eliminare irreversibilmente i messaggi inviati. + + Allow your contacts to irreversibly delete sent messages. (24 hours) + Permetti ai tuoi contatti di eliminare irreversibilmente i messaggi inviati. (24 ore) No comment provided by engineer. @@ -930,9 +933,9 @@ Sia tu che il tuo contatto potete aggiungere reazioni ai messaggi. No comment provided by engineer. - - Both you and your contact can irreversibly delete sent messages. - Sia tu che il tuo contatto potete eliminare irreversibilmente i messaggi inviati. + + Both you and your contact can irreversibly delete sent messages. (24 hours) + Sia tu che il tuo contatto potete eliminare irreversibilmente i messaggi inviati. (24 ore) No comment provided by engineer. @@ -972,6 +975,7 @@ Camera not available + Fotocamera non disponibile No comment provided by engineer. @@ -1092,6 +1096,7 @@ Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat. + La chat è ferma. Se hai già usato questo database su un altro dispositivo, dovresti trasferirlo prima di avviare la chat. No comment provided by engineer. @@ -1440,6 +1445,7 @@ Questo è il tuo link una tantum! Creating link… + Creazione link… No comment provided by engineer. @@ -1922,6 +1928,10 @@ Non è reversibile! Fallo dopo No comment provided by engineer. + + Do not send history to new members. + No comment provided by engineer. + Don't create address Non creare un indirizzo @@ -1994,6 +2004,7 @@ Non è reversibile! Enable camera access + Attiva l'accesso alla fotocamera No comment provided by engineer. @@ -2063,6 +2074,7 @@ Non è reversibile! Encrypted message: app is stopped + Messaggio cifrato: l'app è ferma notification @@ -2297,6 +2309,7 @@ Non è reversibile! Error opening chat + Errore di apertura della chat No comment provided by engineer. @@ -2341,6 +2354,7 @@ Non è reversibile! Error scanning code: %@ + Errore di scansione del codice: %@ No comment provided by engineer. @@ -2673,9 +2687,9 @@ Non è reversibile! I membri del gruppo possono aggiungere reazioni ai messaggi. No comment provided by engineer. - - Group members can irreversibly delete sent messages. - I membri del gruppo possono eliminare irreversibilmente i messaggi inviati. + + Group members can irreversibly delete sent messages. (24 hours) + I membri del gruppo possono eliminare irreversibilmente i messaggi inviati. (24 ore) No comment provided by engineer. @@ -2783,6 +2797,10 @@ Non è reversibile! Cronologia No comment provided by engineer. + + History is not sent to new members. + No comment provided by engineer. + How SimpleX works Come funziona SimpleX @@ -2977,6 +2995,7 @@ Non è reversibile! Invalid QR code + Codice QR non valido No comment provided by engineer. @@ -2984,8 +3003,13 @@ Non è reversibile! Link di connessione non valido No comment provided by engineer. + + Invalid display name! + No comment provided by engineer. + Invalid link + Link non valido No comment provided by engineer. @@ -2995,6 +3019,7 @@ Non è reversibile! Invalid response + Risposta non valida No comment provided by engineer. @@ -3117,6 +3142,7 @@ Questo è il tuo link per il gruppo %@! Keep + Tieni No comment provided by engineer. @@ -3126,6 +3152,7 @@ Questo è il tuo link per il gruppo %@! Keep unused invitation? + Tenere l'invito inutilizzato? No comment provided by engineer. @@ -3460,6 +3487,7 @@ Questo è il tuo link per il gruppo %@! New chat + Nuova chat No comment provided by engineer. @@ -3588,6 +3616,7 @@ Questo è il tuo link per il gruppo %@! OK + OK No comment provided by engineer. @@ -3655,9 +3684,9 @@ Questo è il tuo link per il gruppo %@! Solo tu puoi aggiungere reazioni ai messaggi. No comment provided by engineer. - - Only you can irreversibly delete messages (your contact can mark them for deletion). - Solo tu puoi eliminare irreversibilmente i messaggi (il tuo contatto può contrassegnarli per l'eliminazione). + + Only you can irreversibly delete messages (your contact can mark them for deletion). (24 hours) + Solo tu puoi eliminare irreversibilmente i messaggi (il tuo contatto può contrassegnarli per l'eliminazione). (24 ore) No comment provided by engineer. @@ -3680,9 +3709,9 @@ Questo è il tuo link per il gruppo %@! Solo il tuo contatto può aggiungere reazioni ai messaggi. No comment provided by engineer. - - Only your contact can irreversibly delete messages (you can mark them for deletion). - Solo il tuo contatto può eliminare irreversibilmente i messaggi (tu puoi contrassegnarli per l'eliminazione). + + Only your contact can irreversibly delete messages (you can mark them for deletion). (24 hours) + Solo il tuo contatto può eliminare irreversibilmente i messaggi (tu puoi contrassegnarli per l'eliminazione). (24 ore) No comment provided by engineer. @@ -3737,14 +3766,17 @@ Questo è il tuo link per il gruppo %@! Opening app… + Apertura dell'app… No comment provided by engineer. Or scan QR code + O scansiona il codice QR No comment provided by engineer. Or show this code + O mostra questo codice No comment provided by engineer. @@ -3799,6 +3831,7 @@ Questo è il tuo link per il gruppo %@! Paste the link you received + Incolla il link che hai ricevuto No comment provided by engineer. @@ -3839,6 +3872,8 @@ Questo è il tuo link per il gruppo %@! Please contact developers. Error: %@ + Contatta gli sviluppatori. +Errore: %@ No comment provided by engineer. @@ -4048,6 +4083,7 @@ Error: %@ Read more in [User Guide](https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode). + Leggi di più nella [Guida utente](https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode). No comment provided by engineer. @@ -4262,6 +4298,7 @@ Error: %@ Retry + Riprova No comment provided by engineer. @@ -4421,6 +4458,7 @@ Error: %@ Search or paste SimpleX link + Cerca o incolla un link SimpleX No comment provided by engineer. @@ -4528,6 +4566,10 @@ Error: %@ Inviali dalla galleria o dalle tastiere personalizzate. No comment provided by engineer. + + Send up to 100 last messages to new members. + No comment provided by engineer. + Sender cancelled file transfer. Il mittente ha annullato il trasferimento del file. @@ -4700,6 +4742,7 @@ Error: %@ Share this 1-time invite link + Condividi questo link di invito una tantum No comment provided by engineer. @@ -4829,6 +4872,7 @@ Error: %@ Start chat? + Avviare la chat? No comment provided by engineer. @@ -4958,10 +5002,12 @@ Error: %@ Tap to paste link + Tocca per incollare il link No comment provided by engineer. Tap to scan + Tocca per scansionare No comment provided by engineer. @@ -5028,6 +5074,7 @@ Può accadere a causa di qualche bug o quando la connessione è compromessa. The code you scanned is not a SimpleX link QR code. + Il codice che hai scansionato non è un codice QR di link SimpleX. No comment provided by engineer. @@ -5097,6 +5144,7 @@ Può accadere a causa di qualche bug o quando la connessione è compromessa. The text you pasted is not a SimpleX link. + Il testo che hai incollato non è un link SimpleX. No comment provided by engineer. @@ -5144,6 +5192,10 @@ Può accadere a causa di qualche bug o quando la connessione è compromessa.Il nome di questo dispositivo No comment provided by engineer. + + This display name is invalid. Please choose another name. + No comment provided by engineer. + This group has over %lld members, delivery receipts are not sent. Questo gruppo ha più di %lld membri, le ricevute di consegna non vengono inviate. @@ -5368,6 +5420,10 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e Non letto No comment provided by engineer. + + Up to 100 last messages are sent to new members. + No comment provided by engineer. + Update Aggiorna @@ -5455,6 +5511,7 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e Use only local notifications? + Usare solo notifiche locali? No comment provided by engineer. @@ -5537,6 +5594,10 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e Vedi codice di sicurezza No comment provided by engineer. + + Visible history + chat feature + Voice messages Messaggi vocali @@ -5741,6 +5802,7 @@ Ripetere la richiesta di ingresso? You can make it visible to your SimpleX contacts via Settings. + Puoi renderlo visibile ai tuoi contatti SimpleX nelle impostazioni. No comment provided by engineer. @@ -5785,6 +5847,7 @@ Ripetere la richiesta di ingresso? You can view invitation link again in connection details. + Puoi vedere di nuovo il link di invito nei dettagli di connessione. No comment provided by engineer. 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 de25ffb08f..ad34f76182 100644 --- a/apps/ios/SimpleX Localizations/ja.xcloc/Localized Contents/ja.xliff +++ b/apps/ios/SimpleX Localizations/ja.xcloc/Localized Contents/ja.xliff @@ -346,17 +346,17 @@ **e2e encrypted** audio call - **e2e 暗号化**された音声通話 + **e2e 暗号化**音声通話 No comment provided by engineer. **e2e encrypted** video call - **エンドツーエンド暗号化済み**のビデオ通話 + **e2e暗号化**ビデオ通話 No comment provided by engineer. \*bold* - \*太文字* + \*太字* No comment provided by engineer. @@ -530,7 +530,7 @@ Accept connection request? - 連絡を受け入れる + 接続要求を承認? No comment provided by engineer. @@ -638,7 +638,7 @@ All your contacts will remain connected. Profile update will be sent to your contacts. - あなたの連絡先が繋がったまま継続します。 + すべての連絡先は維持されます。連絡先に更新されたプロフィールを送信します。 No comment provided by engineer. @@ -656,8 +656,8 @@ 連絡先が許可している場合のみ消えるメッセージを許可する。 No comment provided by engineer. - - Allow irreversible message deletion only if your contact allows it to you. + + Allow irreversible message deletion only if your contact allows it to you. (24 hours) 送信相手も永久メッセージ削除を許可する時のみに許可する。 No comment provided by engineer. @@ -681,8 +681,8 @@ 消えるメッセージの送信を許可する。 No comment provided by engineer. - - Allow to irreversibly delete sent messages. + + Allow to irreversibly delete sent messages. (24 hours) 送信済みメッセージの永久削除を許可する。 No comment provided by engineer. @@ -716,8 +716,8 @@ 連絡先からの通話を許可する。 No comment provided by engineer. - - Allow your contacts to irreversibly delete sent messages. + + Allow your contacts to irreversibly delete sent messages. (24 hours) 送信相手が永久メッセージ削除するのを許可する。 No comment provided by engineer. @@ -908,8 +908,8 @@ 自分も相手もメッセージへのリアクションを追加できます。 No comment provided by engineer. - - Both you and your contact can irreversibly delete sent messages. + + Both you and your contact can irreversibly delete sent messages. (24 hours) あなたと連絡相手が送信済みメッセージを永久削除できます。 No comment provided by engineer. @@ -1210,7 +1210,7 @@ This is your own one-time link! Connect via one-time link - 使い捨てリンク経由で接続しますか? + ワンタイムリンクで接続 No comment provided by engineer. @@ -1731,12 +1731,12 @@ This cannot be undone! Delivery - Delivery + 配信 No comment provided by engineer. Delivery receipts are disabled! - Delivery receipts are disabled! + 配信通知の停止! No comment provided by engineer. @@ -1874,6 +1874,10 @@ This cannot be undone! 後で行う No comment provided by engineer. + + Do not send history to new members. + No comment provided by engineer. + Don't create address アドレスを作成しないでください @@ -2612,8 +2616,8 @@ This cannot be undone! グループメンバーはメッセージへのリアクションを追加できます。 No comment provided by engineer. - - Group members can irreversibly delete sent messages. + + Group members can irreversibly delete sent messages. (24 hours) グループのメンバーがメッセージを完全削除することができます。 No comment provided by engineer. @@ -2722,6 +2726,10 @@ This cannot be undone! 履歴 No comment provided by engineer. + + History is not sent to new members. + No comment provided by engineer. + How SimpleX works SimpleX の仕組み @@ -2921,6 +2929,10 @@ This cannot be undone! 無効な接続リンク No comment provided by engineer. + + Invalid display name! + No comment provided by engineer. + Invalid link No comment provided by engineer. @@ -3580,8 +3592,8 @@ This is your link for group %@! メッセージへのリアクションを追加できるのは、あなただけです。 No comment provided by engineer. - - Only you can irreversibly delete messages (your contact can mark them for deletion). + + Only you can irreversibly delete messages (your contact can mark them for deletion). (24 hours) メッセージの完全削除はあなたにしかできません (あなたの連絡先は削除対象とすることができます)。 No comment provided by engineer. @@ -3605,8 +3617,8 @@ This is your link for group %@! メッセージへのリアクションを追加できるのは連絡先だけです。 No comment provided by engineer. - - Only your contact can irreversibly delete messages (you can mark them for deletion). + + Only your contact can irreversibly delete messages (you can mark them for deletion). (24 hours) メッセージを完全削除できるのはあなたの連絡相手だけです (あなたは削除対象とすることができます)。 No comment provided by engineer. @@ -4443,6 +4455,10 @@ Error: %@ ギャラリーまたはカスタム キーボードから送信します。 No comment provided by engineer. + + Send up to 100 last messages to new members. + No comment provided by engineer. + Sender cancelled file transfer. 送信者がファイル転送をキャンセルしました。 @@ -5050,6 +5066,10 @@ It can happen because of some bug or when the connection is compromised.This device name No comment provided by engineer. + + This display name is invalid. Please choose another name. + No comment provided by engineer. + This group has over %lld members, delivery receipts are not sent. No comment provided by engineer. @@ -5264,6 +5284,10 @@ To connect, please ask your contact to create another connection link and check 未読 No comment provided by engineer. + + Up to 100 last messages are sent to new members. + No comment provided by engineer. + Update 更新 @@ -5428,6 +5452,10 @@ To connect, please ask your contact to create another connection link and check セキュリティコードを確認 No comment provided by engineer. + + Visible history + chat feature + Voice messages 音声メッセージ @@ -6698,12 +6726,12 @@ SimpleX サーバーはあなたのプロファイルを参照できません。 SimpleX needs camera access to scan QR codes to connect to other users and for video calls. - SimpleX は、他のユーザーに接続したりビデオ通話を行うために QR コードをスキャンするためにカメラにアクセスする必要があります。 + SimpleXは他のユーザーに接続したりビデオ通話する際にQRコード読み取りのためにカメラにアクセスする必要があります。 Privacy - Camera Usage Description SimpleX uses Face ID for local authentication - SimpleX はローカル認証に Face ID を使用します + SimpleXはローカル認証にFace IDを使用します Privacy - Face ID Usage Description @@ -6712,12 +6740,12 @@ SimpleX サーバーはあなたのプロファイルを参照できません。 SimpleX needs microphone access for audio and video calls, and to record voice messages. - SimpleX では、音声通話やビデオ通話、および音声メッセージの録音のためにマイクへのアクセスが必要です。 + SimpleXは音声通話やビデオ通話および音声メッセージの録音のためにマイクにアクセスする必要があります。 Privacy - Microphone Usage Description SimpleX needs access to Photo Library for saving captured and received media - SimpleX は、キャプチャおよび受信したメディアを保存するためにフォト ライブラリにアクセスする必要があります + SimpleXはキャプチャおよび受信したメディアを保存するためにフォトライブラリにアクセスする必要があります Privacy - Photo Library Additions Usage Description 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 e8aef28d41..38fd6b91fd 100644 --- a/apps/ios/SimpleX Localizations/nl.xcloc/Localized Contents/nl.xliff +++ b/apps/ios/SimpleX Localizations/nl.xcloc/Localized Contents/nl.xliff @@ -314,6 +314,7 @@ **Add contact**: to create a new invitation link, or connect via a link you received. + **Contact toevoegen**: om een nieuwe uitnodigingslink aan te maken, of verbinding te maken via een link die u heeft ontvangen. No comment provided by engineer. @@ -323,6 +324,7 @@ **Create group**: to create a new group. + **Groep aanmaken**: om een nieuwe groep aan te maken. No comment provided by engineer. @@ -563,6 +565,7 @@ Add contact + Contact toevoegen No comment provided by engineer. @@ -670,9 +673,9 @@ Sta verdwijnende berichten alleen toe als uw contact dit toestaat. No comment provided by engineer. - - Allow irreversible message deletion only if your contact allows it to you. - Sta het onomkeerbaar verwijderen van berichten alleen toe als uw contact dit toestaat. + + Allow irreversible message deletion only if your contact allows it to you. (24 hours) + Sta het onomkeerbaar verwijderen van berichten alleen toe als uw contact dit toestaat. (24 uur) No comment provided by engineer. @@ -695,9 +698,9 @@ Toestaan dat verdwijnende berichten worden verzonden. No comment provided by engineer. - - Allow to irreversibly delete sent messages. - Sta toe om verzonden berichten onomkeerbaar te verwijderen. + + Allow to irreversibly delete sent messages. (24 hours) + Sta toe om verzonden berichten onomkeerbaar te verwijderen. (24 uur) No comment provided by engineer. @@ -730,9 +733,9 @@ Sta toe dat uw contacten u bellen. No comment provided by engineer. - - Allow your contacts to irreversibly delete sent messages. - Laat uw contacten verzonden berichten onomkeerbaar verwijderen. + + Allow your contacts to irreversibly delete sent messages. (24 hours) + Laat uw contacten verzonden berichten onomkeerbaar verwijderen. (24 uur) No comment provided by engineer. @@ -930,9 +933,9 @@ Zowel u als uw contact kunnen berichtreacties toevoegen. No comment provided by engineer. - - Both you and your contact can irreversibly delete sent messages. - Zowel jij als je contact kunnen verzonden berichten onherroepelijk verwijderen. + + Both you and your contact can irreversibly delete sent messages. (24 hours) + Zowel jij als je contact kunnen verzonden berichten onherroepelijk verwijderen. (24 uur) No comment provided by engineer. @@ -972,6 +975,7 @@ Camera not available + Camera niet beschikbaar No comment provided by engineer. @@ -1092,6 +1096,7 @@ Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat. + Chat is gestopt. Als je deze database al op een ander apparaat hebt gebruikt, moet je deze terugzetten voordat je met chatten begint. No comment provided by engineer. @@ -1440,6 +1445,7 @@ Dit is uw eigen eenmalige link! Creating link… + Link maken… No comment provided by engineer. @@ -1922,6 +1928,10 @@ Dit kan niet ongedaan gemaakt worden! Doe het later No comment provided by engineer. + + Do not send history to new members. + No comment provided by engineer. + Don't create address Maak geen adres aan @@ -1994,6 +2004,7 @@ Dit kan niet ongedaan gemaakt worden! Enable camera access + Schakel cameratoegang in No comment provided by engineer. @@ -2063,6 +2074,7 @@ Dit kan niet ongedaan gemaakt worden! Encrypted message: app is stopped + Versleuteld bericht: app is gestopt notification @@ -2297,6 +2309,7 @@ Dit kan niet ongedaan gemaakt worden! Error opening chat + Fout bij het openen van de chat No comment provided by engineer. @@ -2341,6 +2354,7 @@ Dit kan niet ongedaan gemaakt worden! Error scanning code: %@ + Fout bij het scannen van code: %@ No comment provided by engineer. @@ -2673,9 +2687,9 @@ Dit kan niet ongedaan gemaakt worden! Groepsleden kunnen berichtreacties toevoegen. No comment provided by engineer. - - Group members can irreversibly delete sent messages. - Groepsleden kunnen verzonden berichten onherroepelijk verwijderen. + + Group members can irreversibly delete sent messages. (24 hours) + Groepsleden kunnen verzonden berichten onherroepelijk verwijderen. (24 uur) No comment provided by engineer. @@ -2783,6 +2797,10 @@ Dit kan niet ongedaan gemaakt worden! Geschiedenis No comment provided by engineer. + + History is not sent to new members. + No comment provided by engineer. + How SimpleX works Hoe SimpleX werkt @@ -2977,6 +2995,7 @@ Dit kan niet ongedaan gemaakt worden! Invalid QR code + Ongeldige QR-code No comment provided by engineer. @@ -2984,8 +3003,13 @@ Dit kan niet ongedaan gemaakt worden! Ongeldige verbinding link No comment provided by engineer. + + Invalid display name! + No comment provided by engineer. + Invalid link + Ongeldige link No comment provided by engineer. @@ -2995,6 +3019,7 @@ Dit kan niet ongedaan gemaakt worden! Invalid response + Ongeldig antwoord No comment provided by engineer. @@ -3117,6 +3142,7 @@ Dit is jouw link voor groep %@! Keep + Bewaar No comment provided by engineer. @@ -3126,6 +3152,7 @@ Dit is jouw link voor groep %@! Keep unused invitation? + Ongebruikte uitnodiging bewaren? No comment provided by engineer. @@ -3460,6 +3487,7 @@ Dit is jouw link voor groep %@! New chat + Nieuw gesprek No comment provided by engineer. @@ -3588,6 +3616,7 @@ Dit is jouw link voor groep %@! OK + OK No comment provided by engineer. @@ -3655,9 +3684,9 @@ Dit is jouw link voor groep %@! Alleen jij kunt berichtreacties toevoegen. No comment provided by engineer. - - Only you can irreversibly delete messages (your contact can mark them for deletion). - Alleen jij kunt berichten onomkeerbaar verwijderen (je contact kan ze markeren voor verwijdering). + + Only you can irreversibly delete messages (your contact can mark them for deletion). (24 hours) + Alleen jij kunt berichten onomkeerbaar verwijderen (je contact kan ze markeren voor verwijdering). (24 uur) No comment provided by engineer. @@ -3680,9 +3709,9 @@ Dit is jouw link voor groep %@! Alleen uw contact kan berichtreacties toevoegen. No comment provided by engineer. - - Only your contact can irreversibly delete messages (you can mark them for deletion). - Alleen uw contact kan berichten onherroepelijk verwijderen (u kunt ze markeren voor verwijdering). + + Only your contact can irreversibly delete messages (you can mark them for deletion). (24 hours) + Alleen uw contact kan berichten onherroepelijk verwijderen (u kunt ze markeren voor verwijdering). (24 uur) No comment provided by engineer. @@ -3737,14 +3766,17 @@ Dit is jouw link voor groep %@! Opening app… + App openen… No comment provided by engineer. Or scan QR code + Of scan de QR-code No comment provided by engineer. Or show this code + Of laat deze code zien No comment provided by engineer. @@ -3799,6 +3831,7 @@ Dit is jouw link voor groep %@! Paste the link you received + Plak de link die je hebt ontvangen No comment provided by engineer. @@ -3839,6 +3872,8 @@ Dit is jouw link voor groep %@! Please contact developers. Error: %@ + Neem contact op met ontwikkelaars. +Fout: %@ No comment provided by engineer. @@ -4048,6 +4083,7 @@ Error: %@ Read more in [User Guide](https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode). + Lees meer in de [Gebruikershandleiding](https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode). No comment provided by engineer. @@ -4262,6 +4298,7 @@ Error: %@ Retry + Opnieuw proberen No comment provided by engineer. @@ -4421,6 +4458,7 @@ Error: %@ Search or paste SimpleX link + Zoek of plak de SimpleX link No comment provided by engineer. @@ -4528,6 +4566,10 @@ Error: %@ Stuur ze vanuit de galerij of aangepaste toetsenborden. No comment provided by engineer. + + Send up to 100 last messages to new members. + No comment provided by engineer. + Sender cancelled file transfer. Afzender heeft bestandsoverdracht geannuleerd. @@ -4700,6 +4742,7 @@ Error: %@ Share this 1-time invite link + Deel deze eenmalige uitnodigingslink No comment provided by engineer. @@ -4829,6 +4872,7 @@ Error: %@ Start chat? + Begin chat? No comment provided by engineer. @@ -4958,10 +5002,12 @@ Error: %@ Tap to paste link + Tik om de link te plakken No comment provided by engineer. Tap to scan + Tik om te scannen No comment provided by engineer. @@ -5028,6 +5074,7 @@ Het kan gebeuren vanwege een bug of wanneer de verbinding is aangetast. The code you scanned is not a SimpleX link QR code. + De code die u heeft gescand is geen SimpleX link QR-code. No comment provided by engineer. @@ -5097,6 +5144,7 @@ Het kan gebeuren vanwege een bug of wanneer de verbinding is aangetast. The text you pasted is not a SimpleX link. + De tekst die u hebt geplakt is geen SimpleX link. No comment provided by engineer. @@ -5144,6 +5192,10 @@ Het kan gebeuren vanwege een bug of wanneer de verbinding is aangetast. Deze apparaatnaam No comment provided by engineer. + + This display name is invalid. Please choose another name. + No comment provided by engineer. + This group has over %lld members, delivery receipts are not sent. Deze groep heeft meer dan %lld -leden, ontvangstbevestigingen worden niet verzonden. @@ -5368,6 +5420,10 @@ Om verbinding te maken, vraagt u uw contact om een andere verbinding link te mak Ongelezen No comment provided by engineer. + + Up to 100 last messages are sent to new members. + No comment provided by engineer. + Update Update @@ -5455,6 +5511,7 @@ Om verbinding te maken, vraagt u uw contact om een andere verbinding link te mak Use only local notifications? + Alleen lokale meldingen gebruiken? No comment provided by engineer. @@ -5537,6 +5594,10 @@ Om verbinding te maken, vraagt u uw contact om een andere verbinding link te mak Beveiligingscode bekijken No comment provided by engineer. + + Visible history + chat feature + Voice messages Spraak berichten @@ -5741,6 +5802,7 @@ Deelnameverzoek herhalen? You can make it visible to your SimpleX contacts via Settings. + Je kunt het via Instellingen zichtbaar maken voor je SimpleX contacten. No comment provided by engineer. @@ -5785,6 +5847,7 @@ Deelnameverzoek herhalen? You can view invitation link again in connection details. + U kunt de uitnodigingslink opnieuw bekijken in de verbindingsdetails. No comment provided by engineer. 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 0cdbb8c7e1..14e3a0067d 100644 --- a/apps/ios/SimpleX Localizations/pl.xcloc/Localized Contents/pl.xliff +++ b/apps/ios/SimpleX Localizations/pl.xcloc/Localized Contents/pl.xliff @@ -314,6 +314,7 @@ **Add contact**: to create a new invitation link, or connect via a link you received. + **Dodaj kontakt**: aby utworzyć nowy link z zaproszeniem lub połączyć się za pomocą otrzymanego linku. No comment provided by engineer. @@ -323,6 +324,7 @@ **Create group**: to create a new group. + **Utwórz grupę**: aby utworzyć nową grupę. No comment provided by engineer. @@ -563,6 +565,7 @@ Add contact + Dodaj kontakt No comment provided by engineer. @@ -670,9 +673,9 @@ Zezwól na znikające wiadomości tylko wtedy, gdy Twój kontakt Ci na to pozwoli. No comment provided by engineer. - - Allow irreversible message deletion only if your contact allows it to you. - Zezwalaj na nieodwracalne usuwanie wiadomości tylko wtedy, gdy Twój kontakt Ci na to pozwoli. + + Allow irreversible message deletion only if your contact allows it to you. (24 hours) + Zezwalaj na nieodwracalne usuwanie wiadomości tylko wtedy, gdy Twój kontakt Ci na to pozwoli. (24 godziny) No comment provided by engineer. @@ -695,9 +698,9 @@ Zezwól na wysyłanie znikających wiadomości. No comment provided by engineer. - - Allow to irreversibly delete sent messages. - Zezwól na nieodwracalne usunięcie wysłanych wiadomości. + + Allow to irreversibly delete sent messages. (24 hours) + Zezwól na nieodwracalne usunięcie wysłanych wiadomości. (24 godziny) No comment provided by engineer. @@ -730,9 +733,9 @@ Zezwól swoim kontaktom na połączenia do Ciebie. No comment provided by engineer. - - Allow your contacts to irreversibly delete sent messages. - Zezwól swoim kontaktom na nieodwracalne usuwanie wysłanych wiadomości. + + Allow your contacts to irreversibly delete sent messages. (24 hours) + Zezwól swoim kontaktom na nieodwracalne usuwanie wysłanych wiadomości. (24 godziny) No comment provided by engineer. @@ -930,9 +933,9 @@ Zarówno Ty, jak i Twój kontakt możecie dodawać reakcje wiadomości. No comment provided by engineer. - - Both you and your contact can irreversibly delete sent messages. - Zarówno Ty, jak i Twój kontakt możecie nieodwracalnie usunąć wysłane wiadomości. + + Both you and your contact can irreversibly delete sent messages. (24 hours) + Zarówno Ty, jak i Twój kontakt możecie nieodwracalnie usunąć wysłane wiadomości. (24 godziny) No comment provided by engineer. @@ -972,6 +975,7 @@ Camera not available + Kamera nie dostępna No comment provided by engineer. @@ -1092,6 +1096,7 @@ Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat. + Czat został zatrzymany. Jeśli korzystałeś już z tej bazy danych na innym urządzeniu, powinieneś przenieść ją z powrotem przed rozpoczęciem czatu. No comment provided by engineer. @@ -1440,6 +1445,7 @@ To jest twój jednorazowy link! Creating link… + Tworzenie linku… No comment provided by engineer. @@ -1922,6 +1928,10 @@ To nie może być cofnięte! Zrób to później No comment provided by engineer. + + Do not send history to new members. + No comment provided by engineer. + Don't create address Nie twórz adresu @@ -1994,6 +2004,7 @@ To nie może być cofnięte! Enable camera access + Włącz dostęp do kamery No comment provided by engineer. @@ -2063,6 +2074,7 @@ To nie może być cofnięte! Encrypted message: app is stopped + Zaszyfrowana wiadomość: aplikacja jest zatrzymana notification @@ -2297,6 +2309,7 @@ To nie może być cofnięte! Error opening chat + Błąd otwierania czatu No comment provided by engineer. @@ -2341,6 +2354,7 @@ To nie może być cofnięte! Error scanning code: %@ + Błąd skanowanie kodu: %@ No comment provided by engineer. @@ -2673,9 +2687,9 @@ To nie może być cofnięte! Członkowie grupy mogą dodawać reakcje wiadomości. No comment provided by engineer. - - Group members can irreversibly delete sent messages. - Członkowie grupy mogą nieodwracalnie usuwać wysłane wiadomości. + + Group members can irreversibly delete sent messages. (24 hours) + Członkowie grupy mogą nieodwracalnie usuwać wysłane wiadomości. (24 godziny) No comment provided by engineer. @@ -2783,6 +2797,10 @@ To nie może być cofnięte! Historia No comment provided by engineer. + + History is not sent to new members. + No comment provided by engineer. + How SimpleX works Jak działa SimpleX @@ -2977,6 +2995,7 @@ To nie może być cofnięte! Invalid QR code + Nieprawidłowy kod QR No comment provided by engineer. @@ -2984,8 +3003,13 @@ To nie może być cofnięte! Nieprawidłowy link połączenia No comment provided by engineer. + + Invalid display name! + No comment provided by engineer. + Invalid link + Nieprawidłowy link No comment provided by engineer. @@ -2995,6 +3019,7 @@ To nie może być cofnięte! Invalid response + Nieprawidłowa odpowiedź No comment provided by engineer. @@ -3117,6 +3142,7 @@ To jest twój link do grupy %@! Keep + Zachowaj No comment provided by engineer. @@ -3126,6 +3152,7 @@ To jest twój link do grupy %@! Keep unused invitation? + Zachować nieużyte zaproszenie? No comment provided by engineer. @@ -3460,6 +3487,7 @@ To jest twój link do grupy %@! New chat + Nowy czat No comment provided by engineer. @@ -3588,6 +3616,7 @@ To jest twój link do grupy %@! OK + OK No comment provided by engineer. @@ -3655,9 +3684,9 @@ To jest twój link do grupy %@! Tylko Ty możesz dodawać reakcje wiadomości. No comment provided by engineer. - - Only you can irreversibly delete messages (your contact can mark them for deletion). - Tylko Ty możesz nieodwracalnie usunąć wiadomości (Twój kontakt może oznaczyć je do usunięcia). + + Only you can irreversibly delete messages (your contact can mark them for deletion). (24 hours) + Tylko Ty możesz nieodwracalnie usunąć wiadomości (Twój kontakt może oznaczyć je do usunięcia). (24 godziny) No comment provided by engineer. @@ -3680,9 +3709,9 @@ To jest twój link do grupy %@! Tylko Twój kontakt może dodawać reakcje wiadomości. No comment provided by engineer. - - Only your contact can irreversibly delete messages (you can mark them for deletion). - Tylko Twój kontakt może nieodwracalnie usunąć wiadomości (możesz oznaczyć je do usunięcia). + + Only your contact can irreversibly delete messages (you can mark them for deletion). (24 hours) + Tylko Twój kontakt może nieodwracalnie usunąć wiadomości (możesz oznaczyć je do usunięcia). (24 godziny) No comment provided by engineer. @@ -3737,14 +3766,17 @@ To jest twój link do grupy %@! Opening app… + Otwieranie aplikacji… No comment provided by engineer. Or scan QR code + Lub zeskanuj kod QR No comment provided by engineer. Or show this code + Lub pokaż ten kod No comment provided by engineer. @@ -3799,6 +3831,7 @@ To jest twój link do grupy %@! Paste the link you received + Wklej link, który otrzymałeś No comment provided by engineer. @@ -3839,6 +3872,8 @@ To jest twój link do grupy %@! Please contact developers. Error: %@ + Proszę skontaktować się z deweloperami. +Błąd: %@ No comment provided by engineer. @@ -4048,6 +4083,7 @@ Error: %@ Read more in [User Guide](https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode). + Przeczytaj więcej w [Poradniku Użytkownika](https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode). No comment provided by engineer. @@ -4262,6 +4298,7 @@ Error: %@ Retry + Ponów No comment provided by engineer. @@ -4421,6 +4458,7 @@ Error: %@ Search or paste SimpleX link + Wyszukaj lub wklej link SimpleX No comment provided by engineer. @@ -4528,6 +4566,10 @@ Error: %@ Wyślij je z galerii lub niestandardowych klawiatur. No comment provided by engineer. + + Send up to 100 last messages to new members. + No comment provided by engineer. + Sender cancelled file transfer. Nadawca anulował transfer pliku. @@ -4700,6 +4742,7 @@ Error: %@ Share this 1-time invite link + Udostępnij ten jednorazowy link No comment provided by engineer. @@ -4829,6 +4872,7 @@ Error: %@ Start chat? + Rozpocząć czat? No comment provided by engineer. @@ -4958,10 +5002,12 @@ Error: %@ Tap to paste link + Dotknij, aby wkleić link No comment provided by engineer. Tap to scan + Dotknij, aby zeskanować No comment provided by engineer. @@ -5028,6 +5074,7 @@ Może się to zdarzyć z powodu jakiegoś błędu lub gdy połączenie jest skom The code you scanned is not a SimpleX link QR code. + Kod, który zeskanowałeś nie jest kodem QR linku SimpleX. No comment provided by engineer. @@ -5097,6 +5144,7 @@ Może się to zdarzyć z powodu jakiegoś błędu lub gdy połączenie jest skom The text you pasted is not a SimpleX link. + Tekst, który wkleiłeś nie jest linkiem SimpleX. No comment provided by engineer. @@ -5144,6 +5192,10 @@ Może się to zdarzyć z powodu jakiegoś błędu lub gdy połączenie jest skom Nazwa tego urządzenia No comment provided by engineer. + + This display name is invalid. Please choose another name. + No comment provided by engineer. + This group has over %lld members, delivery receipts are not sent. Ta grupa ma ponad %lld członków, potwierdzenia dostawy nie są wysyłane. @@ -5368,6 +5420,10 @@ Aby się połączyć, poproś Twój kontakt o utworzenie kolejnego linku połąc Nieprzeczytane No comment provided by engineer. + + Up to 100 last messages are sent to new members. + No comment provided by engineer. + Update Aktualizuj @@ -5455,6 +5511,7 @@ Aby się połączyć, poproś Twój kontakt o utworzenie kolejnego linku połąc Use only local notifications? + Używać tylko lokalnych powiadomień? No comment provided by engineer. @@ -5537,6 +5594,10 @@ Aby się połączyć, poproś Twój kontakt o utworzenie kolejnego linku połąc Pokaż kod bezpieczeństwa No comment provided by engineer. + + Visible history + chat feature + Voice messages Wiadomości głosowe @@ -5741,6 +5802,7 @@ Powtórzyć prośbę dołączenia? You can make it visible to your SimpleX contacts via Settings. + Możesz ustawić go jako widoczny dla swoich kontaktów SimpleX w Ustawieniach. No comment provided by engineer. @@ -5785,6 +5847,7 @@ Powtórzyć prośbę dołączenia? You can view invitation link again in connection details. + Możesz zobaczyć link zaproszenia ponownie w szczegółach połączenia. No comment provided by engineer. 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 2129456374..b882a36575 100644 --- a/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff +++ b/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff @@ -670,9 +670,9 @@ Разрешить исчезающие сообщения, только если Ваш контакт разрешает их Вам. No comment provided by engineer. - - Allow irreversible message deletion only if your contact allows it to you. - Разрешить необратимое удаление сообщений, только если Ваш контакт разрешает это Вам. + + Allow irreversible message deletion only if your contact allows it to you. (24 hours) + Разрешить необратимое удаление сообщений, только если Ваш контакт разрешает это Вам. (24 часа) No comment provided by engineer. @@ -695,9 +695,9 @@ Разрешить посылать исчезающие сообщения. No comment provided by engineer. - - Allow to irreversibly delete sent messages. - Разрешить необратимо удалять отправленные сообщения. + + Allow to irreversibly delete sent messages. (24 hours) + Разрешить необратимо удалять отправленные сообщения. (24 часа) No comment provided by engineer. @@ -730,9 +730,9 @@ Разрешить Вашим контактам звонить Вам. No comment provided by engineer. - - Allow your contacts to irreversibly delete sent messages. - Разрешить Вашим контактам необратимо удалять отправленные сообщения. + + Allow your contacts to irreversibly delete sent messages. (24 hours) + Разрешить Вашим контактам необратимо удалять отправленные сообщения. (24 часа) No comment provided by engineer. @@ -930,9 +930,9 @@ И Вы, и Ваш контакт можете добавлять реакции на сообщения. No comment provided by engineer. - - Both you and your contact can irreversibly delete sent messages. - Вы и Ваш контакт можете необратимо удалять отправленные сообщения. + + Both you and your contact can irreversibly delete sent messages. (24 hours) + Вы и Ваш контакт можете необратимо удалять отправленные сообщения. (24 часа) No comment provided by engineer. @@ -1922,6 +1922,10 @@ This cannot be undone! Отложить No comment provided by engineer. + + Do not send history to new members. + No comment provided by engineer. + Don't create address Не создавать адрес @@ -2673,9 +2677,9 @@ This cannot be undone! Члены группы могут добавлять реакции на сообщения. No comment provided by engineer. - - Group members can irreversibly delete sent messages. - Члены группы могут необратимо удалять отправленные сообщения. + + Group members can irreversibly delete sent messages. (24 hours) + Члены группы могут необратимо удалять отправленные сообщения. (24 часа) No comment provided by engineer. @@ -2783,6 +2787,10 @@ This cannot be undone! История No comment provided by engineer. + + History is not sent to new members. + No comment provided by engineer. + How SimpleX works Как SimpleX работает @@ -2984,6 +2992,10 @@ This cannot be undone! Ошибка в ссылке контакта No comment provided by engineer. + + Invalid display name! + No comment provided by engineer. + Invalid link No comment provided by engineer. @@ -3655,9 +3667,9 @@ This is your link for group %@! Только Вы можете добавлять реакции на сообщения. No comment provided by engineer. - - Only you can irreversibly delete messages (your contact can mark them for deletion). - Только Вы можете необратимо удалять сообщения (Ваш контакт может помечать их на удаление). + + Only you can irreversibly delete messages (your contact can mark them for deletion). (24 hours) + Только Вы можете необратимо удалять сообщения (Ваш контакт может помечать их на удаление). (24 часа) No comment provided by engineer. @@ -3680,9 +3692,9 @@ This is your link for group %@! Только Ваш контакт может добавлять реакции на сообщения. No comment provided by engineer. - - Only your contact can irreversibly delete messages (you can mark them for deletion). - Только Ваш контакт может необратимо удалять сообщения (Вы можете помечать их на удаление). + + Only your contact can irreversibly delete messages (you can mark them for deletion). (24 hours) + Только Ваш контакт может необратимо удалять сообщения (Вы можете помечать их на удаление). (24 часа) No comment provided by engineer. @@ -4528,6 +4540,10 @@ Error: %@ Отправьте из галереи или из дополнительных клавиатур. No comment provided by engineer. + + Send up to 100 last messages to new members. + No comment provided by engineer. + Sender cancelled file transfer. Отправитель отменил передачу файла. @@ -5144,6 +5160,10 @@ It can happen because of some bug or when the connection is compromised.Имя этого устройства No comment provided by engineer. + + This display name is invalid. Please choose another name. + No comment provided by engineer. + This group has over %lld members, delivery receipts are not sent. В группе более %lld членов, отчёты о доставке выключены. @@ -5368,6 +5388,10 @@ To connect, please ask your contact to create another connection link and check Не прочитано No comment provided by engineer. + + Up to 100 last messages are sent to new members. + No comment provided by engineer. + Update Обновить @@ -5537,6 +5561,10 @@ To connect, please ask your contact to create another connection link and check Показать код безопасности No comment provided by engineer. + + Visible history + chat feature + Voice messages Голосовые сообщения 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 b4520553c5..1ca44c5be1 100644 --- a/apps/ios/SimpleX Localizations/th.xcloc/Localized Contents/th.xliff +++ b/apps/ios/SimpleX Localizations/th.xcloc/Localized Contents/th.xliff @@ -645,8 +645,8 @@ อนุญาตให้ข้อความที่หายไปเฉพาะในกรณีที่ผู้ติดต่อของคุณอนุญาตเท่านั้น. No comment provided by engineer. - - Allow irreversible message deletion only if your contact allows it to you. + + Allow irreversible message deletion only if your contact allows it to you. (24 hours) อนุญาตให้ลบข้อความแบบถาวรเฉพาะในกรณีที่ผู้ติดต่อของคุณอนุญาตให้คุณเท่านั้น No comment provided by engineer. @@ -670,8 +670,8 @@ อนุญาตให้ส่งข้อความที่จะหายไปหลังปิดแชท (disappearing message) No comment provided by engineer. - - Allow to irreversibly delete sent messages. + + Allow to irreversibly delete sent messages. (24 hours) อนุญาตให้ลบข้อความที่ส่งไปแล้วอย่างถาวร No comment provided by engineer. @@ -705,8 +705,8 @@ อนุญาตให้ผู้ติดต่อของคุณโทรหาคุณ No comment provided by engineer. - - Allow your contacts to irreversibly delete sent messages. + + Allow your contacts to irreversibly delete sent messages. (24 hours) อนุญาตให้ผู้ติดต่อของคุณลบข้อความที่ส่งแล้วอย่างถาวร No comment provided by engineer. @@ -896,8 +896,8 @@ ทั้งคุณและผู้ติดต่อของคุณสามารถเพิ่มปฏิกิริยาของข้อความได้ No comment provided by engineer. - - Both you and your contact can irreversibly delete sent messages. + + Both you and your contact can irreversibly delete sent messages. (24 hours) ทั้งคุณและผู้ติดต่อของคุณสามารถลบข้อความที่ส่งแล้วอย่างถาวรได้ No comment provided by engineer. @@ -1856,6 +1856,10 @@ This cannot be undone! ทำในภายหลัง No comment provided by engineer. + + Do not send history to new members. + No comment provided by engineer. + Don't create address อย่าสร้างที่อยู่ @@ -2591,8 +2595,8 @@ This cannot be undone! สมาชิกกลุ่มสามารถเพิ่มการแสดงปฏิกิริยาต่อข้อความได้ No comment provided by engineer. - - Group members can irreversibly delete sent messages. + + Group members can irreversibly delete sent messages. (24 hours) สมาชิกกลุ่มสามารถลบข้อความที่ส่งแล้วอย่างถาวร No comment provided by engineer. @@ -2701,6 +2705,10 @@ This cannot be undone! ประวัติ No comment provided by engineer. + + History is not sent to new members. + No comment provided by engineer. + How SimpleX works วิธีการ SimpleX ทํางานอย่างไร @@ -2899,6 +2907,10 @@ This cannot be undone! ลิงค์เชื่อมต่อไม่ถูกต้อง No comment provided by engineer. + + Invalid display name! + No comment provided by engineer. + Invalid link No comment provided by engineer. @@ -3555,8 +3567,8 @@ This is your link for group %@! มีเพียงคุณเท่านั้นที่สามารถแสดงปฏิกิริยาต่อข้อความได้ No comment provided by engineer. - - Only you can irreversibly delete messages (your contact can mark them for deletion). + + Only you can irreversibly delete messages (your contact can mark them for deletion). (24 hours) มีเพียงคุณเท่านั้นที่สามารถลบข้อความแบบย้อนกลับไม่ได้ (ผู้ติดต่อของคุณสามารถทำเครื่องหมายเพื่อลบได้) No comment provided by engineer. @@ -3580,8 +3592,8 @@ This is your link for group %@! เฉพาะผู้ติดต่อของคุณเท่านั้นที่สามารถเพิ่มการโต้ตอบข้อความได้ No comment provided by engineer. - - Only your contact can irreversibly delete messages (you can mark them for deletion). + + Only your contact can irreversibly delete messages (you can mark them for deletion). (24 hours) เฉพาะผู้ติดต่อของคุณเท่านั้นที่สามารถลบข้อความแบบย้อนกลับไม่ได้ (คุณสามารถทำเครื่องหมายเพื่อลบได้) No comment provided by engineer. @@ -4417,6 +4429,10 @@ Error: %@ ส่งจากแกลเลอรีหรือแป้นพิมพ์แบบกำหนดเอง No comment provided by engineer. + + Send up to 100 last messages to new members. + No comment provided by engineer. + Sender cancelled file transfer. ผู้ส่งยกเลิกการโอนไฟล์ @@ -5025,6 +5041,10 @@ It can happen because of some bug or when the connection is compromised.This device name No comment provided by engineer. + + This display name is invalid. Please choose another name. + No comment provided by engineer. + This group has over %lld members, delivery receipts are not sent. No comment provided by engineer. @@ -5239,6 +5259,10 @@ To connect, please ask your contact to create another connection link and check เปลี่ยนเป็นยังไม่ได้อ่าน No comment provided by engineer. + + Up to 100 last messages are sent to new members. + No comment provided by engineer. + Update อัปเดต @@ -5401,6 +5425,10 @@ To connect, please ask your contact to create another connection link and check ดูรหัสความปลอดภัย No comment provided by engineer. + + Visible history + chat feature + Voice messages ข้อความเสียง 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 9f2e489bf3..6563a0adaf 100644 --- a/apps/ios/SimpleX Localizations/tr.xcloc/Localized Contents/tr.xliff +++ b/apps/ios/SimpleX Localizations/tr.xcloc/Localized Contents/tr.xliff @@ -8,28 +8,28 @@ - + No comment provided by engineer. - + . No comment provided by engineer. - + No comment provided by engineer. - + . No comment provided by engineer. ( - ( + ( No comment provided by engineer. @@ -39,7 +39,7 @@ !1 colored! - !1 renkli! + !1 renklendirilmiş! No comment provided by engineer. @@ -72,8 +72,9 @@ %@ / %@ No comment provided by engineer. - + %1$@ at %2$@: + %1$@, %2$@ de copied message info, <sender> at <time> @@ -218,7 +219,7 @@ %u messages failed to decrypt. - %u mesaj deşifrelenememektedir. + %u mesajın şifreleme çözümü başarısız oldu. No comment provided by engineer. @@ -246,62 +247,76 @@ Kişisel kullanım için **Bağlantı / QR Kodu**. No comment provided by engineer. - + **More private**: check new messages every 20 minutes. Device token is shared with SimpleX Chat server, but not how many contacts or messages you have. + **Daha gizli**: her 20 dakikada yeni mesajlar için kontrol et. Cihaz jetonu SimpleX Chat sunucusuyla paylaşılacak, ama ne kadar kişi veya mesaja sahip olduğun paylaşılmayacak. No comment provided by engineer. - + **Most private**: do not use SimpleX Chat notifications server, check messages periodically in the background (depends on how often you use the app). + **En gizli**: SimpleX Chat bildirim sunucusunu kullanma, arkaplanda mesajları periyodik olarak kontrol edin (uygulamayı ne sıklıkta kullandığınıza bağlıdır). No comment provided by engineer. **Paste received link** or open it in the browser and tap **Open in mobile app**. No comment provided by engineer. - + **Please note**: you will NOT be able to recover or change passphrase if you lose it. + **Lütfen aklınızda bulunsun**: eğer parolanızı kaybederseniz parolanızı değiştirme veya geri kurtarma ihtimaliniz YOKTUR. No comment provided by engineer. - + **Recommended**: device token and notifications are sent to SimpleX Chat notification server, but not the message content, size or who it is from. + **Önerilen**: cihaz tokeni ve bildirimler SimpleX Chat bildirim sunucularına gönderilir, ama mesajın içeriği, boyutu veya kimden geldiği gönderilmez. No comment provided by engineer. **Scan QR code**: to connect to your contact in person or via video call. No comment provided by engineer. - + **Warning**: Instant push notifications require passphrase saved in Keychain. + **Dikkat**: Anında iletilen bildirimlere Anahtar Zinciri'nde kaydedilmiş parola gereklidir. No comment provided by engineer. - + **e2e encrypted** audio call + **uçtan uca şifrelenmiş** sesli arama No comment provided by engineer. - + **e2e encrypted** video call + **uçtan uca şifrelenmiş** görüntülü arama No comment provided by engineer. - + \*bold* + \*kalın* No comment provided by engineer. - + , + , No comment provided by engineer. - + - voice messages up to 5 minutes. - custom time to disappear. - editing history. + - 5 dakikaya kadar süren sesli mesajlar. +- mesaj kaybolması için özel zaman. +- düzenleme geçmişi. No comment provided by engineer. - + . + . No comment provided by engineer. - + 0s + 0 saniye No comment provided by engineer. @@ -351,7 +366,7 @@ : - : + : No comment provided by engineer. @@ -376,25 +391,31 @@ Kişinize rastgele bir profil gönderilecek No comment provided by engineer. - + A separate TCP connection will be used **for each chat profile you have in the app**. + **uygulamandaki olan her sohbet profili için** ayrı bir TCP bağlantısı kullanılacaktır. No comment provided by engineer. - + A separate TCP connection will be used **for each contact and group member**. **Please note**: if you have many connections, your battery and traffic consumption can be substantially higher and some connections may fail. + **uygulamandaki olan her sohbet profili için** ayrı bir TCP bağlantısı kullanılacaktır. +**Lütfen aklınızda bulunsun**: eğer çok fazla bağlantılarınız var ise pil kullanımı ve internet kullanımınız oldukça artabilir ve bazı bağlantılar hatayla karşılaşabilir. No comment provided by engineer. - + Abort + İptal Et No comment provided by engineer. - + Abort changing address + Adres değişimini iptal et No comment provided by engineer. - + Abort changing address? + Adres değişimi iptal edilsin mi? No comment provided by engineer. @@ -402,16 +423,19 @@ SimpleX Hakkında No comment provided by engineer. - + About SimpleX Chat + SimpleX Chat hakkında No comment provided by engineer. - + About SimpleX address + SimpleX Chat adresi hakkında No comment provided by engineer. - + Accent color + Vurgu rengi No comment provided by engineer. @@ -424,24 +448,29 @@ Accept contact No comment provided by engineer. - + Accept contact request from %@? + %@ 'den gelen iletişim isteği kabul edilsin mi? notification body - + Accept incognito + Takma adla kabul et No comment provided by engineer. - + Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts. + Kişilerinizin başkalarıyla paylaşabilmesi için profilinize adres ekleyin. Profil güncellemesi kişilerinize gönderilecek. No comment provided by engineer. - + Add preset servers + Önceden ayarlanmış sunucu ekle No comment provided by engineer. - + Add profile + Profil ekle No comment provided by engineer. @@ -454,8 +483,9 @@ Sunucu ekle… No comment provided by engineer. - + Add to another device + Başka bir cihaza ekle No comment provided by engineer. @@ -473,8 +503,9 @@ Adres değişikliği iptal edilecek. Eski alıcı adresi kullanılacaktır. No comment provided by engineer. - + Admins can create the links to join groups. + Yöneticiler gruplara katılmak için bağlantılar oluşturabilir. No comment provided by engineer. @@ -527,12 +558,14 @@ Yalnızca irtibat kişiniz izin veriyorsa aramalara izin verin. No comment provided by engineer. - + Allow disappearing messages only if your contact allows it to you. + Eğer kişide izin verirse kaybolan mesajlara izin ver. No comment provided by engineer. - + Allow irreversible message deletion only if your contact allows it to you. + Eğer kişide izin verirse geri dönüşü olmayan mesaj silimine izin ver. No comment provided by engineer. @@ -540,8 +573,9 @@ Yalnızca kişin mesaj tepkilerine izin veriyorsa sen de ver. No comment provided by engineer. - + Allow message reactions. + Mesaj tepkilerine izin ver. No comment provided by engineer. @@ -584,28 +618,34 @@ Konuştuğun kişilerin mesajlarına tepki eklemesine izin ver. No comment provided by engineer. - + Allow your contacts to call you. + Kişilerinin seni aramasına izin ver. No comment provided by engineer. - + Allow your contacts to irreversibly delete sent messages. + Kişilerinizin gönderilen mesajları geri alınamayacak şekilde silmesine izin verin. No comment provided by engineer. - + Allow your contacts to send disappearing messages. + Kişilerinizin kaybolan mesajlar göndermesine izin verin. No comment provided by engineer. - + Allow your contacts to send voice messages. + Kişilerinizin sesli mesajlar göndermesine izin verin. No comment provided by engineer. - + Already connected? + Zaten bağlandı? No comment provided by engineer. - + Always use relay + Her zaman yönlendirici kulan No comment provided by engineer. @@ -618,8 +658,9 @@ Aramayı cevapla No comment provided by engineer. - + App build: %@ + Uygulama sürümü: %@ No comment provided by engineer. @@ -632,289 +673,360 @@ Uygulama erişim kodu No comment provided by engineer. - + App passcode is replaced with self-destruct passcode. + Uygulama parolası kendi kendini imha eden parolayla değiştirildi. No comment provided by engineer. - + App version + Uygulama sürümü No comment provided by engineer. - + App version: v%@ + Uygulama sürümü: v%@ No comment provided by engineer. - + Appearance + Görünüş No comment provided by engineer. - + Attach + Ekle No comment provided by engineer. - + Audio & video calls + Sesli & görüntülü aramalar No comment provided by engineer. - + Audio and video calls + Sesli ve görüntülü aramalar No comment provided by engineer. - + Audio/video calls + Sesli/görüntülü aramalar chat feature - + Audio/video calls are prohibited. + Sesli/görüntülü aramalar yasaklandı. No comment provided by engineer. - + Authentication cancelled + Kimlik doğrulama iptal edildi PIN entry - + Authentication failed + Kimlik doğrulama başarısız oldu No comment provided by engineer. - + Authentication is required before the call is connected, but you may miss calls. + Kimlik doğrulama aramalara bağlanmadan önce gereklidir, ama aramaları kaçırabilirsin. No comment provided by engineer. - + Authentication unavailable + Kimlik doğrulama kullanım dışı No comment provided by engineer. - + Auto-accept + Otomatik-kabul et No comment provided by engineer. - + Auto-accept contact requests + İletişim isteklerini otomatik kabul et No comment provided by engineer. - + Auto-accept images + Fotoğrafları otomatik kabul et No comment provided by engineer. - + Back + Geri No comment provided by engineer. - + Bad message ID + Kötü mesaj kimliği No comment provided by engineer. - + Bad message hash + Kötü mesaj karması No comment provided by engineer. - + Better messages + Daha iyi mesajlar No comment provided by engineer. - + Both you and your contact can add message reactions. + Sen ve konuştuğun kişi mesaj tepkileri ekleyebilir. No comment provided by engineer. - + Both you and your contact can irreversibly delete sent messages. + Sen ve konuştuğun kişi gönderilmiş mesajları geri dönüşsüz silebilirsiniz. No comment provided by engineer. - + Both you and your contact can make calls. + Sen ve konuştuğun kişi aramalar yapabilir. No comment provided by engineer. - + Both you and your contact can send disappearing messages. + Sen ve konuştuğun kişi kaybolan mesajlar gönderebilir. No comment provided by engineer. - + Both you and your contact can send voice messages. + Sen ve konuştuğun kişi sesli mesaj gönderebilir. No comment provided by engineer. - + By chat profile (default) or [by connection](https://simplex.chat/blog/20230204-simplex-chat-v4-5-user-chat-profiles.html#transport-isolation) (BETA). + Sohbet profiline göre (varsayılan) veya [bağlantıya göre](https://simplex.chat/blog/20230204-simplex-chat-v4-5-user-chat-profiles.html#transport-isolation) (BETA). No comment provided by engineer. - + Call already ended! + Arama çoktan bitti! No comment provided by engineer. - + Calls + Aramalar No comment provided by engineer. - + Can't delete user profile! + Kullanıcı profili silinemiyor! No comment provided by engineer. - + Can't invite contact! + Kişi davet edilemiyor! No comment provided by engineer. - + Can't invite contacts! + Kişiler davet edilemiyor! No comment provided by engineer. - + Cancel + İptal et No comment provided by engineer. - + Cannot access keychain to save database password + Veritabanı şifresini kaydetmek için Anahtar Zinciri'ne erişilemiyor No comment provided by engineer. - + Cannot receive file + Dosya alınamıyor No comment provided by engineer. - + Change + Değiştir No comment provided by engineer. - + Change database passphrase? + Veritabanı parolasını değiştir? No comment provided by engineer. - + Change lock mode + Kilit modunu değiştir authentication reason - + Change member role? + Üye rolünü değiştir? No comment provided by engineer. - + Change passcode + Şifreyi değiştir authentication reason - + Change receiving address + Alıcı adresini değiştir No comment provided by engineer. - + Change receiving address? + Alıcı adresi değiştirilsin mi? No comment provided by engineer. - + Change role + Rolü değiştir No comment provided by engineer. - + Change self-destruct mode + Kendini yok etme modunu değiştir authentication reason - + Change self-destruct passcode + Kendini yok eden parolayı değiştir authentication reason set passcode view - + Chat archive + Sohbet arşivi No comment provided by engineer. - + Chat console + Sohbet konsolu No comment provided by engineer. - + Chat database + Sohbet veritabanı No comment provided by engineer. - + Chat database deleted + Sohbet veritabanı silindi No comment provided by engineer. - + Chat database imported + Sohbet veritabanı içe aktarıldı No comment provided by engineer. - + Chat is running + Sohbet çalışıyor No comment provided by engineer. - + Chat is stopped + Sohbet durdu No comment provided by engineer. - + Chat preferences + Sohbet tercihleri No comment provided by engineer. - + Chats + Sohbetler No comment provided by engineer. - + Check server address and try again. + Sunucu adresini kontrol edip tekrar deneyin. No comment provided by engineer. - + Chinese and Spanish interface + Çince ve İspanyolca arayüz No comment provided by engineer. - + Choose file + Dosya seç No comment provided by engineer. - + Choose from library + Kütüphaneden seç No comment provided by engineer. - + Clear + Temizle No comment provided by engineer. - + Clear conversation + Sohbeti temizle No comment provided by engineer. - + Clear conversation? + Sohbet temizlensin mi? No comment provided by engineer. - + Clear verification + Doğrulamayı temizle No comment provided by engineer. - + Colors + Renkler No comment provided by engineer. - + Compare file + Dosya karşılaştır server test step - + Compare security codes with your contacts. + Güvenlik kodlarını kişilerinle karşılaştır. No comment provided by engineer. - + Configure ICE servers + ICE sunucularını ayarla No comment provided by engineer. - + Confirm + Onayla No comment provided by engineer. - + Confirm Passcode + Parolayı onayla No comment provided by engineer. - + Confirm database upgrades + Veritabanı geliştirmelerini onayla No comment provided by engineer. - + Confirm new passphrase… + Yeni parolayı onayla… No comment provided by engineer. - + Confirm password + Şifreyi onayla No comment provided by engineer. - + Connect + Bağlan server test step @@ -925,8 +1037,9 @@ Connect via group link? No comment provided by engineer. - + Connect via link + Bağlantı aracılığıyla bağlan No comment provided by engineer. @@ -937,388 +1050,483 @@ Connect via one-time link? No comment provided by engineer. - + Connecting to server… + Sunucuya bağlanıyor… No comment provided by engineer. - + Connecting to server… (error: %@) + Sunucuya bağlanıyor…(hata:%@) No comment provided by engineer. - + Connection + Bağlantı No comment provided by engineer. - + Connection error + Bağlantı hatası No comment provided by engineer. - + Connection error (AUTH) + Bağlantı hatası (DOĞRULAMA) No comment provided by engineer. Connection request No comment provided by engineer. - + Connection request sent! + Bağlantı daveti gönderildi! No comment provided by engineer. - + Connection timeout + Bağlantı süresi geçmiş No comment provided by engineer. - + Contact allows + Kişi izin veriyor No comment provided by engineer. - + Contact already exists + Kişi zaten mevcut No comment provided by engineer. Contact and all messages will be deleted - this cannot be undone! No comment provided by engineer. - + Contact hidden: + Kişi gizli: notification - + Contact is connected + Kişi bağlandı notification - + Contact is not connected yet! + Kişi şuan bağlanmadı! No comment provided by engineer. - + Contact name + Kişi adı No comment provided by engineer. - + Contact preferences + Kişi tercihleri No comment provided by engineer. - + Contacts + Kişiler No comment provided by engineer. - + Contacts can mark messages for deletion; you will be able to view them. + Kişiler silinmesi için mesajları işaretleyebilir; onları görüntüleyebilirsin. No comment provided by engineer. - + Continue + Devam et No comment provided by engineer. - + Copy + Kopyala chat item action - + Core version: v%@ + Çekirdek sürümü: v%@ No comment provided by engineer. - + Create + Oluştur No comment provided by engineer. - + Create SimpleX address + SimpleX adresi oluştur No comment provided by engineer. - + Create an address to let people connect with you. + İnsanların seninle bağlanması için bir adres oluştur. No comment provided by engineer. - + Create file + Dosya oluştur server test step - + Create group link + Grup bağlantısı oluştur No comment provided by engineer. - + Create link + Bağlantı oluştur No comment provided by engineer. Create one-time invitation link No comment provided by engineer. - + Create queue + Sıra oluştur server test step - + Create secret group + Gizli grup oluştur No comment provided by engineer. - + Create your profile + Profilini oluştur No comment provided by engineer. - + Created on %@ + %@ de oluşturuldu No comment provided by engineer. - + Current Passcode + Şu anki şifre No comment provided by engineer. - + Current passphrase… + Şu anki parola… No comment provided by engineer. - + Currently maximum supported file size is %@. + Şu anki maksimum desteklenen dosya boyutu %@ kadardır. No comment provided by engineer. - + Custom time + Özel saat No comment provided by engineer. - + Dark + Karanlık No comment provided by engineer. - + Database ID + Veritabanı kimliği No comment provided by engineer. - + Database ID: %d + Veritabanı kimliği: %d copied message info - + Database IDs and Transport isolation option. + Veritabanı kimlikleri ve Taşıma izolasyonu seçeneği. No comment provided by engineer. - + Database downgrade + Veritabanı sürüm düşürme No comment provided by engineer. - + Database encrypted! + Veritabanı şifrelendi! No comment provided by engineer. - + Database encryption passphrase will be updated and stored in the keychain. + Veritabanı şifreleme parolası güncellenecek ve Anahtar Zinciri'nde saklanacaktır. + No comment provided by engineer. - + Database encryption passphrase will be updated. + Veritabanı şifreleme parolası güncellenecektir. + No comment provided by engineer. - + Database error + Veritabanı hatası No comment provided by engineer. - + Database is encrypted using a random passphrase, you can change it. + Veritabanı rastgele bir parola kullanılarak şifrelenir, bunu değiştirebilirsiniz. No comment provided by engineer. - + Database is encrypted using a random passphrase. Please change it before exporting. + Veritabanı rastgele bir parola kullanılarak şifrelenir. Lütfen dışa aktarmadan önce değiştirin. No comment provided by engineer. - + Database passphrase + Veritabanı parolası No comment provided by engineer. - + Database passphrase & export + Veritabanı parolası ve dışa aktarma No comment provided by engineer. - + Database passphrase is different from saved in the keychain. + Veritabanı parolası Anahtar Zinciri'nde kayıtlı olandan farklıdır. No comment provided by engineer. - + Database passphrase is required to open chat. + Sohbeti açmak için veritabanı parolası gereklidir. No comment provided by engineer. - + Database upgrade + Veritabanı yükseltmesi No comment provided by engineer. - + Database will be encrypted and the passphrase stored in the keychain. + Veritabanı şifrelenecek ve parola Anahtar Zinciri'nde saklanacaktır. + No comment provided by engineer. - + Database will be encrypted. + Veritabanı şifrelenecektir. + No comment provided by engineer. - + Database will be migrated when the app restarts + Uygulama yeniden başlatıldığında veritabanı taşınacaktır No comment provided by engineer. - + Decentralized + Merkezi Olmayan No comment provided by engineer. - + Decryption error + Şifre çözme hatası message decrypt error item - + Delete + Sil chat item action - + Delete Contact + Kişiyi sil No comment provided by engineer. - + Delete address + Adresi sil No comment provided by engineer. - + Delete address? + Adres silinsin mi? No comment provided by engineer. - + Delete after + Sonra sil No comment provided by engineer. - + Delete all files + Bütün dosyaları sil No comment provided by engineer. - + Delete archive + Arşivi sil No comment provided by engineer. - + Delete chat archive? + Sohbet arşivi silinsin mi? No comment provided by engineer. - + Delete chat profile + Sohbet profilini sil No comment provided by engineer. - + Delete chat profile? + Sohbet profili silinsin mi? No comment provided by engineer. - + Delete connection + Bağlantıyı sil No comment provided by engineer. - + Delete contact + Kişiyi sil No comment provided by engineer. Delete contact? No comment provided by engineer. - + Delete database + Veritabanını sil No comment provided by engineer. - + Delete file + Dosyayı sil server test step - + Delete files and media? + Dosyalar ve medya silinsin mi? No comment provided by engineer. - + Delete files for all chat profiles + Bütün sohbet profilleri için dosyaları sil No comment provided by engineer. - + Delete for everyone + Herkesten sil chat feature - + Delete for me + Benden sil No comment provided by engineer. - + Delete group + Grubu sil No comment provided by engineer. - + Delete group? + Grup silinsin mi? No comment provided by engineer. - + Delete invitation + Daveti sil No comment provided by engineer. - + Delete link + Bağlantıyı sil No comment provided by engineer. - + Delete link? + Bağlantı silinsin mi? No comment provided by engineer. - + Delete member message? + Kişinin mesajı silinsin mi? No comment provided by engineer. - + Delete message? + Mesaj silinsin mi? No comment provided by engineer. - + Delete messages + Mesajları sil No comment provided by engineer. - + Delete messages after + Mesajları sonra sil No comment provided by engineer. - + Delete old database + Eski veritabanını sil No comment provided by engineer. - + Delete old database? + Eski veritabanı silinsin mi? No comment provided by engineer. - + Delete pending connection + Bekleyen bağlantıyı sil No comment provided by engineer. - + Delete pending connection? + Bekleyen bağlantı silinsin mi? No comment provided by engineer. - + Delete profile + Profili sil No comment provided by engineer. - + Delete queue + Sırayı sil server test step - + Delete user profile? + Kullanıcı profili silinsin mi? No comment provided by engineer. - + Deleted at + de silindi No comment provided by engineer. - + Deleted at: %@ + %@ de silindi copied message info - + Delivery receipts are disabled! + Mesaj gönderim bilgisi devre dışı! No comment provided by engineer. @@ -1329,40 +1537,49 @@ Delivery receipts will be enabled for all contacts. No comment provided by engineer. - + Delivery receipts! + Mesaj gönderildi bilgisi! No comment provided by engineer. - + Description + Açıklama No comment provided by engineer. - + Develop + Geliştir No comment provided by engineer. - + Developer tools + Geliştirici araçları No comment provided by engineer. - + Device + Cihaz No comment provided by engineer. - + Device authentication is disabled. Turning off SimpleX Lock. + Cihaz kimlik doğrulaması devre dışı. SimpleX Kilidi kapatılıyor. No comment provided by engineer. - + Device authentication is not enabled. You can turn on SimpleX Lock via Settings, once you enable device authentication. + Cihaz kimlik doğrulaması etkin değil. Cihaz kimlik doğrulamasını etkinleştirdikten sonra SimpleX Kilidini Ayarlar üzerinden açabilirsiniz. No comment provided by engineer. - + Different names, avatars and transport isolation. + Farklı isimler, profil fotoğrafları ve taşıma izolasyonu. No comment provided by engineer. - + Direct messages + Doğrudan mesajlar chat feature @@ -1370,36 +1587,44 @@ Bu grupta üyeler arasında direkt mesajlaşma yasaktır. No comment provided by engineer. - + Disable SimpleX Lock + SimpleX Kilidini devre dışı bırak authentication reason - + Disappearing message + Kaybolan mesaj No comment provided by engineer. - + Disappearing messages + Kaybolan mesajlar chat feature - + Disappearing messages are prohibited in this chat. + Kaybolan mesajlar bu sohbette yasaklanmış. No comment provided by engineer. - + Disappearing messages are prohibited in this group. + Kaybolan mesajlar bu grupta yasaklanmış. No comment provided by engineer. - + Disappears at + da kaybolur No comment provided by engineer. - + Disappears at: %@ + %@ da kaybolur copied message info - + Disconnect + Bağlantıyı kes server test step @@ -1410,692 +1635,861 @@ Display name: No comment provided by engineer. - + Do NOT use SimpleX for emergency calls. + Acil aramalar için SimpleX'i KULLANMAYIN. No comment provided by engineer. - + Do it later + Sonra yap No comment provided by engineer. - + Don't create address + Adres oluşturma No comment provided by engineer. - + Don't show again + Yeniden gösterme No comment provided by engineer. - + Downgrade and open chat + Sürüm düşür ve sohbeti aç No comment provided by engineer. - + Download file + Dosya indir server test step - + Duplicate display name! + Yinelenen görünen ad! No comment provided by engineer. - + Duration + Süre No comment provided by engineer. - + Edit + Düzenle chat item action - + Edit group profile + Grup profilini düzenle No comment provided by engineer. - + Enable + Etkinleştir No comment provided by engineer. - + Enable SimpleX Lock + SimpleX Kilidini etkinleştir authentication reason - + Enable TCP keep-alive + TCP canlı tutmayı etkinleştir No comment provided by engineer. - + Enable automatic message deletion? + Otomatik mesaj silme etkinleştirilsin mi? No comment provided by engineer. - + Enable instant notifications? + Anlık bildirimler etkinleştirilsin mi? No comment provided by engineer. Enable later via Settings No comment provided by engineer. - + Enable lock + Kilidi etkinleştir No comment provided by engineer. - + Enable notifications + Bildirimleri etkinleştir No comment provided by engineer. - + Enable periodic notifications? + Periyodik bildirimler etkinleştirilsin mi? No comment provided by engineer. - + Enable self-destruct + Kendini imhayı etkinleştir No comment provided by engineer. - + Enable self-destruct passcode + Kendini imha şifresini etkinleştir set passcode view - + Encrypt + Şifreleme No comment provided by engineer. - + Encrypt database? + Veritabanı şifrelensin mi? No comment provided by engineer. - + Encrypted database + Şifrelenmiş veritabanı No comment provided by engineer. - + Encrypted message or another event + Şifrelenmiş mesaj veya başka bir etkinlik notification - + Encrypted message: database error + Şifrelenmiş mesaj: veritabanı hatası notification - + Encrypted message: database migration error + Şifrelenmiş mesaj: veritabanı taşıma hatası notification - + Encrypted message: keychain error + Şifrelenmiş mesaj: Anahtar Zinciri hatası notification - + Encrypted message: no passphrase + Şifrelenmiş mesaj: parola yok notification - + Encrypted message: unexpected error + Şifrelenmiş mesaj: beklenmeyen hata notification - + Enter Passcode + Şifre gir No comment provided by engineer. - + Enter correct passphrase. + Doğru şifreyi gir. No comment provided by engineer. - + Enter passphrase… + Parola gir… No comment provided by engineer. - + Enter password above to show! + Göstermek için yukarıdaki şifreyi gir! No comment provided by engineer. - + Enter server manually + Sunucuya manuel olarak gir No comment provided by engineer. - + Enter welcome message… + Hoşgeldin mesajı gir… placeholder - + Enter welcome message… (optional) + Hoşgeldin mesajı gir... (opsiyonel) placeholder - + Error + Hata No comment provided by engineer. - + Error aborting address change + Adres değişikliği iptal edilirken hata oluştu No comment provided by engineer. - + Error accepting contact request + Bağlantı isteği kabul edilirken hata oluştu No comment provided by engineer. - + Error accessing database file + Veritabanı dosyasına erişilirken hata oluştu No comment provided by engineer. - + Error adding member(s) + Üye(ler) eklenirken hata oluştu No comment provided by engineer. - + Error changing address + Adres değiştirilirken hata oluştu No comment provided by engineer. - + Error changing role + Rol değiştirilirken hata oluştu No comment provided by engineer. - + Error changing setting + Ayar değiştirilirken hata oluştu No comment provided by engineer. - + Error creating address + Adres oluşturulurken hata oluştu No comment provided by engineer. - + Error creating group + Grup oluşturulurken hata oluştu No comment provided by engineer. - + Error creating group link + Grup bağlantısı oluşturulurken hata oluştu No comment provided by engineer. - + Error creating profile! + Profil oluşturulurken hata oluştu! No comment provided by engineer. - + Error deleting chat database + Sohbet veritabanı silinirken sorun oluştu No comment provided by engineer. - + Error deleting chat! + Sohbet silinirken hata oluştu! No comment provided by engineer. - + Error deleting connection + Bağlantı silinirken hata oluştu No comment provided by engineer. - + Error deleting contact + Kişi silinirken hata oluştu No comment provided by engineer. - + Error deleting database + Veritabanı silinirken hata oluştu No comment provided by engineer. - + Error deleting old database + Eski veritabanı silinirken hata oluştu No comment provided by engineer. - + Error deleting token + Token silinirken hata oluştu No comment provided by engineer. - + Error deleting user profile + Kullanıcı profili silinirken hata oluştu No comment provided by engineer. - + Error enabling notifications + Bildirimler etkinleştirilirken hata oluştu No comment provided by engineer. - + Error encrypting database + Veritabanı şifrelemesi çözülürken hata oluştu No comment provided by engineer. - + Error exporting chat database + Sohbet veritabanı dışa aktarılırken hata oluştu No comment provided by engineer. - + Error importing chat database + Sohbet veritabanı içe aktarılırken hata oluştu No comment provided by engineer. - + Error joining group + Gruba katılırken hata oluştu No comment provided by engineer. - + Error loading %@ servers + %@ sunucuları yüklenirken hata oluştu No comment provided by engineer. - + Error receiving file + Dosya alınırken sorun oluştu No comment provided by engineer. - + Error removing member + Kişiyi silerken sorun oluştu No comment provided by engineer. - + Error saving %@ servers + %@ sunucuları kaydedilirken sorun oluştu No comment provided by engineer. - + Error saving ICE servers + ICE sunucularını kaydedirken sorun oluştu No comment provided by engineer. - + Error saving group profile + Grup profili kaydedilirken sorun oluştu No comment provided by engineer. - + Error saving passcode + Parola kaydedilirken sorun oluştu No comment provided by engineer. - + Error saving passphrase to keychain + Parolayı Anahtar Zincirine kaydederken hata oluştu No comment provided by engineer. - + Error saving user password + Kullanıcı şifresi kaydedilirken hata oluştu No comment provided by engineer. - + Error sending email + Eposta gönderilirken hata oluştu No comment provided by engineer. - + Error sending message + Mesaj gönderilirken hata oluştu No comment provided by engineer. - + Error starting chat + Sohbet başlatılırken hata oluştu No comment provided by engineer. - + Error stopping chat + Sohbet durdurulurken hata oluştu No comment provided by engineer. - + Error switching profile! + Profil değiştirilirken hata oluştu! No comment provided by engineer. - + Error synchronizing connection + Bağlantı senkronizasyonunda hata oluştu No comment provided by engineer. - + Error updating group link + Grup bağlantısı güncellenirken hata oluştu No comment provided by engineer. - + Error updating message + Mesaj güncellenirken hata oluştu No comment provided by engineer. - + Error updating settings + Ayarları güncellerken hata oluştu No comment provided by engineer. - + Error updating user privacy + Kullanıcı gizliliği güncellenirken hata oluştu No comment provided by engineer. - + Error: + Hata: No comment provided by engineer. - + Error: %@ + Hata: %@ No comment provided by engineer. - + Error: URL is invalid + Hata: URL geçersiz No comment provided by engineer. - + Error: no database file + Hata: veritabanı dosyası yok No comment provided by engineer. - + Exit without saving + Kaydetmeden çık No comment provided by engineer. - + Export database + Veritabanını dışarı aktar No comment provided by engineer. - + Export error: + Dışarı çıkarma hatası: No comment provided by engineer. - + Exported database archive. + Dışarı çıkarılmış veritabanı arşivi. No comment provided by engineer. Exporting database archive... No comment provided by engineer. - + Exporting database archive… + Dışarı çıkarılmış veritabanı arşivi… No comment provided by engineer. - + Failed to remove passphrase + Parola kaldırılamadı No comment provided by engineer. - + Fast and no wait until the sender is online! + Hızlı ve gönderici çevrimiçi olana kadar beklemek yok! No comment provided by engineer. - + Favorite + Favori No comment provided by engineer. - + File will be deleted from servers. + Dosya sunuculardan silinecek. No comment provided by engineer. - + File will be received when your contact completes uploading it. + Dosya kişi yüklemeyi tamamladığında alınacak. No comment provided by engineer. - + File will be received when your contact is online, please wait or check later! + Dosya kişi çevrimiçi olduğunda alınacaktır, lütfen bekleyin veya daha sonra kontrol edin! No comment provided by engineer. - + File: %@ + Dosya: %@ No comment provided by engineer. - + Files & media + Dosyalar & medya No comment provided by engineer. - + Files and media + Dosyalar ve medya chat feature - + Files and media are prohibited in this group. + Dosyalar ve medya bu grupta yasaklandı. No comment provided by engineer. - + Files and media prohibited! + Dosyalar ve medya yasaklandı! No comment provided by engineer. - + Finally, we have them! 🚀 + Sonunda, onlara sahibiz! 🚀 No comment provided by engineer. - + Fix + Düzelt No comment provided by engineer. - + Fix connection + Bağlantıyı düzelt No comment provided by engineer. - + Fix connection? + Bağlantı düzeltilsin mi? No comment provided by engineer. - + Fix not supported by contact + Düzeltme kişi tarafından desteklenmiyor No comment provided by engineer. - + Fix not supported by group member + Düzeltme grup üyesi tarafından desteklenmiyor No comment provided by engineer. - + For console + Konsol için No comment provided by engineer. - + French interface + Fransızca arayüz No comment provided by engineer. - + Full link + Bütün bağlantı adresi No comment provided by engineer. - + Full name (optional) + Bütün isim (opsiyonel) No comment provided by engineer. - + Full name: + Bütün isim: No comment provided by engineer. - + Fully re-implemented - work in background! + Arkaplanda çalışma - tamamiyle yeniden yapıldı! No comment provided by engineer. - + Further reduced battery usage + Daha da azaltılmış pil kullanımı No comment provided by engineer. - + GIFs and stickers + GİFler ve çıkartmalar No comment provided by engineer. - + Group + Grup No comment provided by engineer. - + Group display name + Grup görünen adı No comment provided by engineer. - + Group full name (optional) + Grubun bütün ismi (opsiyonel) No comment provided by engineer. - + Group image + Grup fotoğrafı No comment provided by engineer. - + Group invitation + Grup daveti No comment provided by engineer. - + Group invitation expired + Grup davetinin süresi doldu No comment provided by engineer. - + Group invitation is no longer valid, it was removed by sender. + Grup davet artık geçerli değil, gönderici tarafından silindi. No comment provided by engineer. - + Group link + Grup bağlantısı No comment provided by engineer. - + Group links + Grup bağlantıları No comment provided by engineer. - + Group members can add message reactions. + Grup üyeleri mesaj tepkileri ekleyebilir. No comment provided by engineer. - + Group members can irreversibly delete sent messages. + Grup üyeleri gönderilen mesajları geri alınamaz şekilde silebilir. No comment provided by engineer. - + Group members can send direct messages. + Grup üyeleri doğrudan mesajlar gönderebilir. No comment provided by engineer. - + Group members can send disappearing messages. + Grup üyeleri kaybolan mesajlar gönderebilir. No comment provided by engineer. - + Group members can send files and media. + Grup üyeleri dosyalar ve medya gönderebilir. No comment provided by engineer. - + Group members can send voice messages. + Grup üyeleri sesli mesajlar gönderebilir. No comment provided by engineer. - + Group message: + Grup mesajı: notification - + Group moderation + Grup yöneticiliği No comment provided by engineer. - + Group preferences + Grup tercihleri No comment provided by engineer. - + Group profile + Grup profili No comment provided by engineer. - + Group profile is stored on members' devices, not on the servers. + Grup profili üyelerin cihazlarında saklanır, sunucularda değil. No comment provided by engineer. - + Group welcome message + Grup hoşgeldin mesajı No comment provided by engineer. - + Group will be deleted for all members - this cannot be undone! + Grup tüm üyelerden silinecektir - bu geri alınamaz! No comment provided by engineer. - + Group will be deleted for you - this cannot be undone! + Grup senden silinecektir - bu geri alınamaz! No comment provided by engineer. - + Help + Yardım No comment provided by engineer. - + Hidden + Gizlenmiş No comment provided by engineer. - + Hidden chat profiles + Gizlenmiş sohbet profilleri No comment provided by engineer. - + Hidden profile password + Gizlenmiş profil şifresi No comment provided by engineer. - + Hide + Gizle chat item action - + Hide app screen in the recent apps. + Son uygulamalarda uygulama ekranını gizle. No comment provided by engineer. - + Hide profile + Profili gizle No comment provided by engineer. - + Hide: + Gizle: No comment provided by engineer. - + History + Geçmiş copied message info - + How SimpleX works + SimpleX nasıl çalışır No comment provided by engineer. - + How it works + Nasıl çalışıyor No comment provided by engineer. - + How to + Nasıl yapılır No comment provided by engineer. - + How to use it + Nasıl kullanılır No comment provided by engineer. - + How to use your servers + Sunucularını nasıl kullanabilirsin No comment provided by engineer. - + ICE servers (one per line) + ICE sunucuları (her satıra bir tane) No comment provided by engineer. - + If you can't meet in person, show QR code in a video call, or share the link. + Eğer onunla buluşamıyorsan görüntülü aramada QR kod göster veya bağlantığı paylaş. No comment provided by engineer. If you cannot meet in person, you can **scan QR code in the video call**, or your contact can share an invitation link. No comment provided by engineer. - + If you enter this passcode when opening the app, all app data will be irreversibly removed! + Eğer bu şifreyi uygulamayı açarken girersen, bütün uygulama verileri geri dönülemeyen bir şekilde silinecektir! No comment provided by engineer. - + If you enter your self-destruct passcode while opening the app: + Uygulamayı açarken kendi kendini imha eden şifrenizi girerseniz: No comment provided by engineer. - + If you need to use the chat now tap **Do it later** below (you will be offered to migrate the database when you restart the app). + Sohbeti şimdi kullanmanız gerekiyorsa aşağıdaki **Daha sonra yap** seçeneğine dokunun (uygulamayı yeniden başlattığınızda veritabanını taşımanız önerilecektir). No comment provided by engineer. - + Ignore + Yok say No comment provided by engineer. - + Image will be received when your contact completes uploading it. + Kişi yüklemeyi bitirdiğinde fotoğraf alınacaktır. No comment provided by engineer. - + Image will be received when your contact is online, please wait or check later! + Kişi çevrimiçi olduğunda fotoğraf alınacaktır, lütfen bekleyin veya daha sonra kontrol et! No comment provided by engineer. - + Immediately + Hemen No comment provided by engineer. - + Immune to spam and abuse + Spam ve kötüye kullanıma karşı bağışıklı No comment provided by engineer. - + Import + İçe aktar No comment provided by engineer. - + Import chat database? + Sohbet veritabanı içe aktarılsın mı? No comment provided by engineer. - + Import database + Veritabanını içe aktar No comment provided by engineer. - + Improved privacy and security + Geliştirilmiş gizlilik ve güvenlik No comment provided by engineer. - + Improved server configuration + Geliştirilmiş sunucu yapılandırması No comment provided by engineer. - + In reply to + Cevap olarak copied message info - + Incognito + Gizli No comment provided by engineer. - + Incognito mode + Gizli mod No comment provided by engineer. @@ -2106,152 +2500,192 @@ Incognito mode protects the privacy of your main profile name and image — for each new contact a new random profile is created. No comment provided by engineer. - + Incoming audio call + Gelen sesli arama notification - + Incoming call + Gelen arama notification - + Incoming video call + Gelen görüntülü arama notification - + Incompatible database version + Uyumsuz veritabanı sürümü No comment provided by engineer. - + Incorrect passcode + Uyumsuz parola PIN entry - + Incorrect security code! + Uyumsuz güvenlik kodu! No comment provided by engineer. - + Info + Bilgi chat item action - + Initial role + Başlangıç rolü No comment provided by engineer. - + Install [SimpleX Chat for terminal](https://github.com/simplex-chat/simplex-chat) + [Terminal için SimpleX Chat]i indir(https://github.com/simplex-chat/simplex-chat) No comment provided by engineer. - + Instant push notifications will be hidden! + Anlık bildirimler gizlenecek! + No comment provided by engineer. - + Instantly + Anında No comment provided by engineer. - + Interface + Arayüz No comment provided by engineer. - + Invalid connection link + Geçersiz bağlanma bağlantısı No comment provided by engineer. - + Invalid server address! + Geçersiz sunucu adresi! No comment provided by engineer. - + Invitation expired! + Davetin süresi geçti! No comment provided by engineer. - + Invite friends + Arkadaşları davet et No comment provided by engineer. - + Invite members + Üyeleri davet et No comment provided by engineer. - + Invite to group + Gruba davet et No comment provided by engineer. - + Irreversible message deletion + Geri dönülemeyen mesaj silimi No comment provided by engineer. - + Irreversible message deletion is prohibited in this chat. + Bu sohbette geri döndürülemez mesaj silme yasaktır. No comment provided by engineer. - + Irreversible message deletion is prohibited in this group. + Bu grupta geri döndürülemez mesaj silme yasaktır. No comment provided by engineer. - + It allows having many anonymous connections without any shared data between them in a single chat profile. + Tek bir sohbet profilinde aralarında herhangi bir veri paylaşımı olmadan birçok anonim bağlantıya sahip olmaya izin verir. No comment provided by engineer. - + It can happen when you or your connection used the old database backup. + Siz veya bağlantınız eski veritabanı yedeğini kullandığında bu durum ortaya çıkabilir. No comment provided by engineer. - + It can happen when: 1. The messages expired in the sending client after 2 days or on the server after 30 days. 2. Message decryption failed, because you or your contact used old database backup. 3. The connection was compromised. + Şu durumlarda ortaya çıkabilir: +1. Mesajların gönderici istemcide 2 gün sonra veya sunucuda 30 gün sonra süresi dolmuştur. +2. Siz veya kişi eski veritabanı yedeği kullandığı için mesaj şifre çözme işlemi başarısız olmuştur. +3. Bağlantı tehlikeye girmiştir. 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 (%@). + Bu bağlantı üzerinden zaten bağlanmışsınız gibi görünüyor. Eğer durum böyle değilse, bir hata oluştu (%@). No comment provided by engineer. - + Italian interface + İtalyanca arayüz No comment provided by engineer. - + Japanese interface + Japonca arayüz No comment provided by engineer. - + Join + Katıl No comment provided by engineer. - + Join group + Gruba katıl No comment provided by engineer. - + Join incognito + Gizli katıl No comment provided by engineer. - + Joining group + Gruba katılınıyor No comment provided by engineer. - + KeyChain error + Anahtar Zinciri hatası No comment provided by engineer. - + Keychain error + Anahtar Zinciri hatası No comment provided by engineer. - + LIVE + CANLI No comment provided by engineer. - + Large file! + Büyük dosya! No comment provided by engineer. - + Learn more + Daha fazlası No comment provided by engineer. @@ -2264,406 +2698,506 @@ Gruptan ayrıl No comment provided by engineer. - + Leave group? + Gruptan çıkılsın mı? No comment provided by engineer. - + Let's talk in SimpleX Chat + Hadi SimpleX Chat'te konuşalım email subject - + Light + Açık No comment provided by engineer. - + Limitations + Sınırlamalar No comment provided by engineer. - + Live message! + Canlı mesaj! No comment provided by engineer. - + Live messages + Canlı mesajlar No comment provided by engineer. - + Local name + Yerel isim No comment provided by engineer. - + Local profile data only + Sadece yerel profil verisi No comment provided by engineer. - + Lock after + Sonra kilitle No comment provided by engineer. - + Lock mode + Kilit modu No comment provided by engineer. - + Make a private connection + Gizli bir bağlantı oluştur No comment provided by engineer. - + Make profile private! + Profili gizli yap! No comment provided by engineer. - + Make sure %@ server addresses are in correct format, line separated and are not duplicated (%@). + %@ sunucu adreslerinin doğru formatta olduğundan, satır ayrımı yapıldığından ve yinelenmediğinden (%@) emin olun. No comment provided by engineer. - + Make sure WebRTC ICE server addresses are in correct format, line separated and are not duplicated. + WebRTC ICE sunucu adreslerinin doğru formatta olduğundan, satırlara ayrıldığından ve yinelenmediğinden emin olun. No comment provided by engineer. - + Many people asked: *if SimpleX has no user identifiers, how can it deliver messages?* + Çoğu kişi sordu: *eğer SimpleX'in hiç kullanıcı tanımlayıcıları yok, o zaman mesajları nasıl gönderebiliyor?* No comment provided by engineer. - + Mark deleted for everyone + Herkes için silinmiş olarak işaretle No comment provided by engineer. - + Mark read + Okunmuş olarak işaretle No comment provided by engineer. - + Mark verified + Onaylanmış olarak işaretle No comment provided by engineer. - + Markdown in messages + Mesajlarda işaretleme No comment provided by engineer. - + Max 30 seconds, received instantly. + Maksimum 30 saniye, anında alındı. No comment provided by engineer. - + Member + Kişi No comment provided by engineer. - + Member role will be changed to "%@". All group members will be notified. + Üye rolü "%@" olarak değiştirilecektir. Ve tüm grup üyeleri bilgilendirilecektir. No comment provided by engineer. - + Member role will be changed to "%@". The member will receive a new invitation. + Üye rolü "%@" olarak değiştirilecektir. Ve üye yeni bir davetiye alacaktır. No comment provided by engineer. - + Member will be removed from group - this cannot be undone! + Üye gruptan çıkarılacaktır - bu geri alınamaz! No comment provided by engineer. - + Message delivery error + Mesaj gönderim hatası No comment provided by engineer. - + Message draft + Mesaj taslağı No comment provided by engineer. - + Message reactions + Mesaj tepkileri chat feature - + Message reactions are prohibited in this chat. + Mesaj tepkileri bu sohbette yasaklandı. No comment provided by engineer. - + Message reactions are prohibited in this group. + Mesaj tepkileri bu grupta yasaklandı. No comment provided by engineer. - + Message text + Mesaj yazısı No comment provided by engineer. - + Messages + Mesajlar No comment provided by engineer. - + Messages & files + Mesajlar & dosyalar No comment provided by engineer. Migrating database archive... No comment provided by engineer. - + Migrating database archive… + Veritabanı arşivine geçiliyor… No comment provided by engineer. - + Migration error: + Geçiş hatası: No comment provided by engineer. - + Migration failed. Tap **Skip** below to continue using the current database. Please report the issue to the app developers via chat or email [chat@simplex.chat](mailto:chat@simplex.chat). + Geçiş başarısız oldu. Alttaki **Geç** tuşuna basarak şu anki veritabanını kullanabilirsiniz. Lütfen sorunu sohbet veya e-posta yoluyla uygulama geliştiricilerine bildirin[chat@simplex.chat](mailto:chat@simplex.chat). No comment provided by engineer. - + Migration is completed + Geçiş tamamlandı No comment provided by engineer. - + Migrations: %@ + Geçişler: %@ No comment provided by engineer. - + Moderate + Yönet chat item action - + Moderated at + de yönetildi No comment provided by engineer. - + Moderated at: %@ + %@ de yönetildi copied message info - + More improvements are coming soon! + Daha fazla geliştirmeler yakında geliyor! No comment provided by engineer. - + Most likely this contact has deleted the connection with you. + Büyük ihtimalle bu kişi seninle bağlantını sildi. No comment provided by engineer. - + Multiple chat profiles + Çoklu sohbet profili No comment provided by engineer. - + Mute + Sustur No comment provided by engineer. - + Muted when inactive! + Aktif değilken susturuldu! No comment provided by engineer. - + Name + İsim No comment provided by engineer. - + Network & servers + Ağ & sunucular No comment provided by engineer. - + Network settings + Ağ ayarları No comment provided by engineer. - + Network status + Ağ durumu No comment provided by engineer. - + New Passcode + Yeni şifre No comment provided by engineer. - + New contact request + Yeni bağlantı isteği notification - + New contact: + Yeni kişi: notification - + New database archive + Yeni veritabanı arşivi No comment provided by engineer. - + New display name + Yeni görünen ad No comment provided by engineer. - + New in %@ + %@ da yeni No comment provided by engineer. - + New member role + Yeni üye rolü No comment provided by engineer. - + New message + Yeni mesaj notification - + New passphrase… + Yeni parola… No comment provided by engineer. - + No + Hayır No comment provided by engineer. - + No app password + Uygulama şifresi yok Authentication unavailable - + No contacts selected + Hiçbir kişi seçilmedi No comment provided by engineer. - + No contacts to add + Eklenecek kişi yok No comment provided by engineer. - + No device token! + Cihaz tokeni yok! No comment provided by engineer. - + No filtered chats + Filtrelenmiş sohbetler yok No comment provided by engineer. - + Group not found! + Grup bulunamadı! No comment provided by engineer. - + No history + Geçmiş yok No comment provided by engineer. - + No permission to record voice message + Sesli mesaj kaydetmek için izin yok No comment provided by engineer. - + No received or sent files + Hiç alınmış veya gönderilmiş dosya yok No comment provided by engineer. - + Notifications + Bildirimler No comment provided by engineer. - + Notifications are disabled! + Bildirimler devre dışı! No comment provided by engineer. - + Now admins can: - delete members' messages. - disable members ("observer" role) + Şimdi yöneticiler: +- üyelerin mesajlarını silebilir +- üyeleri devre dışı bırakabilir ("gözlemci" rolü) No comment provided by engineer. - + Off + Kapalı No comment provided by engineer. Off (Local) No comment provided by engineer. - + Ok + Tamam No comment provided by engineer. - + Old database + Eski veritabanı No comment provided by engineer. - + Old database archive + Eski veritabanı arşivi No comment provided by engineer. - + One-time invitation link + Tek zamanlı bağlantı daveti No comment provided by engineer. - + Onion hosts will be required for connection. Requires enabling VPN. + Bağlantı için Onion ana bilgisayarları gerekecektir. VPN'nin etkinleştirilmesi gerekir. No comment provided by engineer. - + Onion hosts will be used when available. Requires enabling VPN. + Onion ana bilgisayarları mevcutsa kullanılacaktır. VPN'nin etkinleştirilmesi gerekir. No comment provided by engineer. - + Onion hosts will not be used. + Onion ana bilgisayarları kullanılmayacaktır. No comment provided by engineer. - + Only client devices store user profiles, contacts, groups, and messages sent with **2-layer end-to-end encryption**. + Yalnızca istemci cihazlar kullanıcı profillerini, kişileri, grupları ve **2 katmanlı uçtan uca şifreleme** ile gönderilen mesajları depolar. No comment provided by engineer. - + Only group owners can change group preferences. + Grup tercihlerini yalnızca grup sahipleri değiştirebilir. No comment provided by engineer. - + Only group owners can enable files and media. + Yalnızca grup sahipleri dosyaları ve medyayı etkinleştirebilir. No comment provided by engineer. - + Only group owners can enable voice messages. + Yalnızca grup sahipleri sesli mesajları etkinleştirebilir. No comment provided by engineer. - + Only you can add message reactions. + Sadece siz mesaj tepkileri ekleyebilirsiniz. No comment provided by engineer. - + Only you can irreversibly delete messages (your contact can mark them for deletion). + Mesajları yalnızca siz geri döndürülemez şekilde silebilirsiniz (kişi bunları silinmek üzere işaretleyebilir). No comment provided by engineer. - + Only you can make calls. + Sadece sen aramalar yapabilirsin. No comment provided by engineer. - + Only you can send disappearing messages. + Sadece sen kaybolan mesajlar gönderebilirsin. No comment provided by engineer. - + Only you can send voice messages. + Sadece sen sesli mesajlar gönderebilirsin. No comment provided by engineer. - + Only your contact can add message reactions. + Sadece karşıdaki kişi mesaj tepkileri ekleyebilir. No comment provided by engineer. - + Only your contact can irreversibly delete messages (you can mark them for deletion). + Sadece karşıdaki kişi mesajları geri döndürülemez şekilde silebilir (silinmeleri için işaretleyebilirsiniz). No comment provided by engineer. - + Only your contact can make calls. + Sadece karşıdaki kişi aramalar yapabilir. No comment provided by engineer. - + Only your contact can send disappearing messages. + Sadece karşıdaki kişi kaybolan mesajlar gönderebilir. No comment provided by engineer. - + Only your contact can send voice messages. + Sadece karşıdaki kişi sesli mesajlar gönderebilir. No comment provided by engineer. - + Open Settings + Ayarları aç No comment provided by engineer. - + Open chat + Sohbeti aç No comment provided by engineer. - + Open chat console + Sohbet konsolunu aç authentication reason - + Open user profiles + Kullanıcı profillerini aç authentication reason - + Open-source protocol and code – anybody can run the servers. + Açık kaynak protokolü ve kodu - herhangi biri sunucuları çalıştırabilir. No comment provided by engineer. @@ -2674,44 +3208,53 @@ Opening the link in the browser may reduce connection privacy and security. Untrusted SimpleX links will be red. No comment provided by engineer. - + PING count + PING sayısı No comment provided by engineer. - + PING interval + PING aralığı No comment provided by engineer. - + Passcode + Şifre No comment provided by engineer. - + Passcode changed! + Şifre değiştirildi! No comment provided by engineer. - + Passcode entry + Şifre girişi No comment provided by engineer. - + Passcode not changed! + Şifre değiştirilmedi! No comment provided by engineer. - + Passcode set! + Şifre ayarlandı! No comment provided by engineer. - + Password to show + Gösterilecek şifre No comment provided by engineer. Paste No comment provided by engineer. - + Paste image + Fotoğraf yapıştır No comment provided by engineer. @@ -2722,1511 +3265,1879 @@ Paste the link you received into the box below to connect with your contact. No comment provided by engineer. - + People can connect to you only via the links you share. + İnsanlar size yalnızca paylaştığınız bağlantılar üzerinden ulaşabilir. No comment provided by engineer. - + Periodically + Periyodik olarak No comment provided by engineer. - + Permanent decryption error + Kalıcı şifre çözümü hatası message decrypt error item - + Please ask your contact to enable sending voice messages. + Lütfen konuştuğunuz kişiden sesli mesaj göndermeyi etkinleştirmesini isteyin. No comment provided by engineer. - + Please check that you used the correct link or ask your contact to send you another one. + Lütfen doğru bağlantıyı kullandığınızı kontrol edin veya kişiden size başka bir bağlantı göndermesini isteyin. No comment provided by engineer. - + Please check your network connection with %@ and try again. + Lütfen ağ bağlantınızı %@ ile kontrol edin ve tekrar deneyin. No comment provided by engineer. - + Please check yours and your contact preferences. + Lütfen sizinkini ve iletişim tercihlerinizi kontrol edin. No comment provided by engineer. - + Please contact group admin. + Lütfen grup yöneticisiyle irtibata geçin. No comment provided by engineer. - + Please enter correct current passphrase. + Lütfen şu anki doğru olan parolayı girin. No comment provided by engineer. - + Please enter the previous password after restoring database backup. This action can not be undone. + Veritabanı yedeğini geri yükledikten sonra lütfen önceki şifreyi girin. Bu işlem geri alınamaz. No comment provided by engineer. - + Please remember or store it securely - there is no way to recover a lost passcode! + Lütfen iyi hatırlayın veya güvenli bir şekilde saklayın - kaybolmuş bir parolayı kurtarmanın bir yolu yoktur! No comment provided by engineer. - + Please report it to the developers. + Lütfen geliştiricilere bildirin. No comment provided by engineer. - + Please restart the app and migrate the database to enable push notifications. + Lütfen uygulamayı yeniden başlatın ve anlık bildirimleri etkinleştirmek için veritabanını taşıyın. No comment provided by engineer. - + Please store passphrase securely, you will NOT be able to access chat if you lose it. + Lütfen parolayı güvenli bir şekilde saklayın, kaybederseniz sohbete ERİŞEMEZSİNİZ. No comment provided by engineer. - + Please store passphrase securely, you will NOT be able to change it if you lose it. + Lütfen parolayı güvenli bir şekilde saklayın, kaybederseniz parolayı DEĞİŞTİREMEZSİNİZ. No comment provided by engineer. - + Polish interface + Lehçe arayüz No comment provided by engineer. - + Possibly, certificate fingerprint in server address is incorrect + Muhtemelen, sunucu adresindeki parmakizi sertifikası doğru değil server test error - + Preserve the last message draft, with attachments. + Son mesaj taslağını ekleriyle birlikte koru. No comment provided by engineer. - + Preset server + Ön ayarlı sunucu No comment provided by engineer. - + Preset server address + Ön ayarlı sunucu adresi No comment provided by engineer. - + Preview + Ön izleme No comment provided by engineer. - + Privacy & security + Gizlilik & güvenlik No comment provided by engineer. - + Privacy redefined + Gizlilik yeniden tanımlandı No comment provided by engineer. - + Private filenames + Gizli dosya adları No comment provided by engineer. - + Profile and server connections + Profil ve sunucu bağlantıları No comment provided by engineer. - + Profile image + Profil fotoğrafı No comment provided by engineer. - + Profile password + Profil parolası No comment provided by engineer. - + Profile update will be sent to your contacts. + Profil güncellemesi kişilerinize gönderilecektir. No comment provided by engineer. - + Prohibit audio/video calls. + Sesli/görüntülü aramaları yasakla. No comment provided by engineer. - + Prohibit irreversible message deletion. + Geri dönüşsüz mesaj silme işlemini yasakla. No comment provided by engineer. - + Prohibit message reactions. + Mesaj tepkisini yasakla. No comment provided by engineer. - + Prohibit messages reactions. + Mesajlarda tepkileri yasakla. No comment provided by engineer. - + Prohibit sending direct messages to members. + Geri dönülmez mesaj silme işlemini yasakla. No comment provided by engineer. - + Prohibit sending disappearing messages. + Kaybolan mesajların gönderimini yasakla. No comment provided by engineer. - + Prohibit sending files and media. + Dosyalar ve medya gönderimlerini yasakla. No comment provided by engineer. - + Prohibit sending voice messages. + Sesli mesajların gönderimini yasakla. No comment provided by engineer. - + Protect app screen + Uygulama ekranını koru No comment provided by engineer. - + Protect your chat profiles with a password! + Bir parolayla birlikte sohbet profillerini koru! No comment provided by engineer. - + Protocol timeout + Protokol zaman aşımı No comment provided by engineer. - + Protocol timeout per KB + KB başına protokol zaman aşımı No comment provided by engineer. - + Push notifications + Anında bildirimler No comment provided by engineer. - + Rate the app + Uygulamayı değerlendir No comment provided by engineer. - + React… + Tepki ver… chat item menu - + Read + Oku No comment provided by engineer. - + Read more + Dahasını oku No comment provided by engineer. - + Read more in [User Guide](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address). + [Kullanıcı Rehberi]nde daha fazlasını okuyun(https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address). No comment provided by engineer. - + Read more in [User Guide](https://simplex.chat/docs/guide/readme.html#connect-to-friends). + [Kullanıcı Rehberi]nde daha fazlasını okuyun(https://simplex.chat/docs/guide/readme.html#connect-to-friends). No comment provided by engineer. - + Read more in our GitHub repository. + Daha fazlasını GitHub depomuzdan oku. No comment provided by engineer. - + Read more in our [GitHub repository](https://github.com/simplex-chat/simplex-chat#readme). + [GitHub deposu]nda daha fazlasını okuyun(https://github.com/simplex-chat/simplex-chat#readme). No comment provided by engineer. - + Received at + Şuradan alındı No comment provided by engineer. - + Received at: %@ + Şuradan alındı: %@ copied message info - + Received file event + Dosya etkinliği alındı notification - + Received message + Mesaj alındı message info title - + Receiving address will be changed to a different server. Address change will complete after sender comes online. + Alıcı adresi farklı bir sunucuya değiştirilecektir. Gönderici çevrimiçi olduktan sonra adres değişikliği tamamlanacaktır. No comment provided by engineer. - + Receiving file will be stopped. + Dosya alımı durdurulacaktır. No comment provided by engineer. - + Receiving via + Aracılığıyla alınıyor No comment provided by engineer. - + Recipients see updates as you type them. + Alıcılar yazdığına göre güncellemeleri görecektir. No comment provided by engineer. - + Reconnect all connected servers to force message delivery. It uses additional traffic. + Mesaj teslimini zorlamak için bağlı tüm sunucuları yeniden bağlayın. Ek trafik kullanır. No comment provided by engineer. - + Reconnect servers? + Sunuculara yeniden bağlanılsın mı? No comment provided by engineer. - + Record updated at + Kayıt şu zamanda güncellendi No comment provided by engineer. - + Record updated at: %@ + Kayıt şu zamanda güncellendi: %@ copied message info - + Reduced battery usage + Azaltılmış pil kullanımı No comment provided by engineer. - + Reject + Reddet reject incoming call via notification Reject contact (sender NOT notified) No comment provided by engineer. - + Reject contact request + Bağlanma isteğini reddet No comment provided by engineer. - + Relay server is only used if necessary. Another party can observe your IP address. + Aktarma sunucusu yalnızca gerekli olduğunda kullanılır. Başka bir taraf IP adresinizi gözlemleyebilir. No comment provided by engineer. - + Relay server protects your IP address, but it can observe the duration of the call. + Aktarıcı sunucu IP adresinizi korur, ancak aramanın süresini gözlemleyebilir. No comment provided by engineer. - + Remove + Sil No comment provided by engineer. - + Remove member + Kişiyi sil No comment provided by engineer. - + Remove member? + Kişi silinsin mi? No comment provided by engineer. - + Remove passphrase from keychain? + Anahtar Zinciri'ndeki parola silinsin mi? No comment provided by engineer. - + Renegotiate + Yeniden müzakere No comment provided by engineer. - + Renegotiate encryption + Şifrelemeyi yeniden müzakere et No comment provided by engineer. - + Renegotiate encryption? + Şifreleme yeniden müzakere edilsin mi? No comment provided by engineer. - + Reply + Yanıtla chat item action - + Required + Gerekli No comment provided by engineer. - + Reset + Sıfırla No comment provided by engineer. - + Reset colors + Renkleri sıfırla No comment provided by engineer. - + Reset to defaults + Varsayılanlara sıfırla No comment provided by engineer. - + Restart the app to create a new chat profile + Yeni bir sohbet profili oluşturmak için uygulamayı yeniden başlatın No comment provided by engineer. - + Restart the app to use imported chat database + İçe aktarılmış sohbet veritabanını kullanmak için uygulamayı yeniden başlatın No comment provided by engineer. - + Restore + Geri yükle No comment provided by engineer. - + Restore database backup + Veritabanı yedeğini geri yükle No comment provided by engineer. - + Restore database backup? + Veritabanı yedeği geri yüklensin mi? No comment provided by engineer. - + Restore database error + Veritabanını geri yüklerken hata oluştu No comment provided by engineer. - + Reveal + Göster chat item action - + Revert + Geri al No comment provided by engineer. - + Revoke + İptal et No comment provided by engineer. - + Revoke file + Dosyayı iptal et cancel file action - + Revoke file? + Dosya iptal edilsin mi? No comment provided by engineer. - + Role + Rol No comment provided by engineer. - + Run chat + Sohbeti çalıştır No comment provided by engineer. - + SMP servers + SMP sunucuları No comment provided by engineer. - + Save + Kaydet chat item action - + Save (and notify contacts) + Kaydet (ve kişilere bildir) No comment provided by engineer. - + Save and notify contact + Kaydet ve kişilere bildir No comment provided by engineer. - + Save and notify group members + Kaydet ve grup üyelerine bildir No comment provided by engineer. - + Save and update group profile + Kaydet ve grup profilini güncelle No comment provided by engineer. - + Save archive + Arşivi kaydet No comment provided by engineer. - + Save auto-accept settings + Otomatik kabul et ayarlarını kaydet No comment provided by engineer. - + Save group profile + Grup profilini kaydet No comment provided by engineer. - + Save passphrase and open chat + Parolayı kaydet ve sohbeti aç No comment provided by engineer. - + Save passphrase in Keychain + Parolayı Anahtar Zincirinde kaydet No comment provided by engineer. - + Save preferences? + Tercihler kaydedilsin mi? No comment provided by engineer. - + Save profile password + Profil şifresini kaydet No comment provided by engineer. - + Save servers + Sunucuları kaydet No comment provided by engineer. - + Save servers? + Sunucular kaydedilsin mi? No comment provided by engineer. - + Save settings? + Ayarlar kaydedilsin mi? No comment provided by engineer. - + Save welcome message? + Hoşgeldin mesajı kaydedilsin mi? No comment provided by engineer. - + Saved WebRTC ICE servers will be removed + Kaydedilmiş WebRTC ICE sunucuları silinecek No comment provided by engineer. - + Scan QR code + QR kodu okut No comment provided by engineer. - + Scan code + Kod okut No comment provided by engineer. - + Scan security code from your contact's app. + Kişinin uygulamasından güvenlik kodunu okut. No comment provided by engineer. - + Scan server QR code + Sunucu QR kodu okut No comment provided by engineer. - + Search + Ara No comment provided by engineer. - + Secure queue + Sırayı koru server test step - + Security assessment + Güvenlik değerlendirmesi No comment provided by engineer. - + Security code + Güvenlik kodu No comment provided by engineer. - + Select + Seç No comment provided by engineer. - + Self-destruct + Kendi kendini imha No comment provided by engineer. - + Self-destruct passcode + Kendini imha eden şifre No comment provided by engineer. - + Self-destruct passcode changed! + Kendini imha eden şifre değiştirildi! No comment provided by engineer. - + Self-destruct passcode enabled! + Kendini imha eden şifre etkinleştirildi! No comment provided by engineer. - + Send + Gönder No comment provided by engineer. - + Send a live message - it will update for the recipient(s) as you type it + Bir canlı mesaj gönder - yazışına göre kişiye(lere) kendini günceller No comment provided by engineer. - + Send delivery receipts to + Görüldü bilgilerini şuraya gönder No comment provided by engineer. - + Send direct message + Doğrudan mesaj gönder No comment provided by engineer. - + Send disappearing message + Kaybolan bir mesaj gönder No comment provided by engineer. - + Send link previews + Bağlantı ön gösterimleri gönder No comment provided by engineer. - + Send live message + Canlı mesaj gönder No comment provided by engineer. - + Send notifications + Bildirimler gönder No comment provided by engineer. - + Send notifications: + Bildirimler gönder: No comment provided by engineer. - + Send questions and ideas + Fikirler ve sorular gönderin No comment provided by engineer. - + Send receipts + Mesajlar gönder No comment provided by engineer. - + Send them from gallery or custom keyboards. + Bunları galeriden veya özel klavyelerden gönder. No comment provided by engineer. - + Sender cancelled file transfer. + Gönderici dosya gönderimini iptal etti. No comment provided by engineer. - + Sender may have deleted the connection request. + Gönderici bağlantı isteğini silmiş olabilir. No comment provided by engineer. - + Sending file will be stopped. + Dosya gönderimi durdurulacaktır. No comment provided by engineer. - + Sending via + Aracılığıyla gönderiliyor No comment provided by engineer. - + Sent at + Şuradan gönderildi No comment provided by engineer. - + Sent at: %@ + Şuradan gönderildi: %@ copied message info - + Sent file event + Dosya etkinliği gönderildi notification - + Sent message + Mesaj gönderildi message info title - + Sent messages will be deleted after set time. + Gönderilen mesajlar ayarlanan süreden sonra silinecektir. No comment provided by engineer. - + Server requires authorization to create queues, check password + Sunucunun sıra oluşturması için yetki gereklidir, şifreyi kontrol edin server test error - + Server requires authorization to upload, check password + Sunucunun yükleme yapması için yetki gereklidir, şifreyi kontrol edin server test error - + Server test failed! + Sunucu testinde hata oluştu! No comment provided by engineer. - + Servers + Sunucular No comment provided by engineer. - + Set 1 day + 1 günlüğüne ayarla No comment provided by engineer. - + Set contact name… + Kişi adı gir… No comment provided by engineer. - + Set group preferences + Grup tercihlerini ayarla No comment provided by engineer. - + Set it instead of system authentication. + Sistem kimlik doğrulaması yerine ayarla. No comment provided by engineer. - + Set passcode + Şifre ayarla No comment provided by engineer. - + Set passphrase to export + Dışa aktarmak için parola ayarla No comment provided by engineer. - + Set the message shown to new members! + Yeni üyeler için gösterilen bir mesaj ayarla! No comment provided by engineer. - + Set timeouts for proxy/VPN + Vekil/VPN için zaman aşımları ayarla No comment provided by engineer. - + Settings + Ayarlar No comment provided by engineer. - + Share + Paylaş chat item action - + Share 1-time link + Tek kullanımlık bağlantıyı paylaş No comment provided by engineer. - + Share address + Adresi paylaş No comment provided by engineer. - + Share address with contacts? + Kişilerle adres paylaşılsın mı? No comment provided by engineer. - + Share link + Bağlantıyı paylaş No comment provided by engineer. Share one-time invitation link No comment provided by engineer. - + Share with contacts + Kişilerle paylaş No comment provided by engineer. - + Show calls in phone history + Telefon geçmişinde aramaları göster No comment provided by engineer. - + Show developer options + Geliştirici ayarlarını göster No comment provided by engineer. - + Show preview + Ön gösterimi göser No comment provided by engineer. - + Show: + Göster: No comment provided by engineer. - + SimpleX Address + SimpleX Adresi No comment provided by engineer. - + SimpleX Chat security was audited by Trail of Bits. + SimpleX Chat güvenliği Trails of Bits tarafından denetlenmiştir. No comment provided by engineer. - + SimpleX Lock + SimpleX Kilidi No comment provided by engineer. - + SimpleX Lock mode + SimpleX Kilidi modu No comment provided by engineer. - + SimpleX Lock not enabled! + SimpleX Kilidi etkinleştirilmedi! No comment provided by engineer. - + SimpleX Lock turned on + SimpleX Kilidi açıldı No comment provided by engineer. - + SimpleX address + SimpleX adresi No comment provided by engineer. - + SimpleX contact address + SimpleX kişi adresi simplex link type - + SimpleX encrypted message or connection event + SimpleX şifrelenmiş mesaj veya bağlantı etkinliği notification - + SimpleX group link + SimpleX grup bağlantısı simplex link type - + SimpleX links + SimpleX bağlantıları No comment provided by engineer. - + SimpleX one-time invitation + SimpleX tek kullanımlık davet simplex link type - + Skip + Atla No comment provided by engineer. - + Skipped messages + Atlanmış mesajlar No comment provided by engineer. Small groups (max 10) No comment provided by engineer. - + Some non-fatal errors occurred during import - you may see Chat console for more details. + İçe aktarma sırasında bazı ölümcül olmayan hatalar oluştu - daha fazla ayrıntı için Sohbet konsoluna bakabilirsiniz. No comment provided by engineer. - + Somebody + Biri notification title Start a new chat No comment provided by engineer. - + Start chat + Sohbeti başlat No comment provided by engineer. - + Start migration + Geçişi başlat No comment provided by engineer. - + Stop + Dur No comment provided by engineer. - + Stop SimpleX + SimpleX'i durdur authentication reason - + Stop chat to enable database actions + Veritabanı eylemlerini etkinleştirmek için sohbeti durdur No comment provided by engineer. - + Stop chat to export, import or delete chat database. You will not be able to receive and send messages while the chat is stopped. + Sohbet veritabanını dışa aktarmak, içe aktarmak veya silmek için sohbeti durdurun. Sohbet durdurulduğunda mesaj alamaz ve gönderemezsiniz. No comment provided by engineer. - + Stop chat? + Sohbet durdurulsun mu? No comment provided by engineer. - + Stop file + Dosyayı durdur cancel file action - + Stop receiving file? + Dosya alımı durdurulsun mu? No comment provided by engineer. - + Stop sending file? + Dosya gönderimi durdurulsun mu? No comment provided by engineer. - + Stop sharing + Paylaşmayı durdur No comment provided by engineer. - + Stop sharing address? + Adresi paylaşmak durdurulsun mu? No comment provided by engineer. - + Submit + Gönder No comment provided by engineer. - + Support SimpleX Chat + SimpleX Chat'e destek ol No comment provided by engineer. - + System + Sistem No comment provided by engineer. - + System authentication + Sistem yetkilendirilmesi No comment provided by engineer. - + TCP connection timeout + TCP bağlantı zaman aşımı No comment provided by engineer. - + TCP_KEEPCNT + TCP_CNTYİTUT No comment provided by engineer. - + TCP_KEEPIDLE + TCP_BOŞTAKAL No comment provided by engineer. - + TCP_KEEPINTVL + TCP_TVLDEKAL No comment provided by engineer. - + Take picture + Fotoğraf çek No comment provided by engineer. - + Tap button + Tuşa bas No comment provided by engineer. - + Tap to activate profile. + Profili etkinleştirmek için tıkla. No comment provided by engineer. - + Tap to join + Katılmak için tıkla No comment provided by engineer. - + Tap to join incognito + Gizli katılmak için tıkla No comment provided by engineer. - + Tap to start a new chat + Yeni bir sohbet başlatmak için tıkla No comment provided by engineer. - + Test failed at step %@. + Test %@ adımında başarısız oldu. server test failure - + Test server + Sunucuyu test et No comment provided by engineer. - + Test servers + Sunucuları test et No comment provided by engineer. - + Tests failed! + Testler başarısız oldu! No comment provided by engineer. - + Thank you for installing SimpleX Chat! + SimpleX Chat'i indirdiğin için teşekkürler! No comment provided by engineer. - + Thanks to the users – [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)! + Kullanıcılar için teşekkürler - [Weblate aracılığıyla katkıda bulun](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)! No comment provided by engineer. - + Thanks to the users – contribute via Weblate! + Kullanıcılar için teşekkürler - Weblate aracılığıyla katkıda bulun! No comment provided by engineer. - + The 1st platform without any user identifiers – private by design. + Herhangi bir kullanıcı tanımlayıcısı olmayan ilk platform - tasarım gereği gizli. No comment provided by engineer. - + The ID of the next message is incorrect (less or equal to the previous). It can happen because of some bug or when the connection is compromised. + Bir sonraki mesajın kimliği yanlış (bir öncekinden az veya aynı). +Bazı hatalar nedeniyle veya bağlantı tehlikeye girdiğinde meydana gelebilir. No comment provided by engineer. - + The app can notify you when you receive messages or contact requests - please open settings to enable. + Uygulama, mesaj veya iletişim isteği aldığınızda sizi bilgilendirebilir - etkinleştirmek için lütfen ayarları açın. No comment provided by engineer. - + The attempt to change database passphrase was not completed. + Veritabanı parolasını değiştirme girişimi tamamlanmadı. No comment provided by engineer. - + The connection you accepted will be cancelled! + Bağlantı kabulünüz iptal edilecektir! No comment provided by engineer. - + The contact you shared this link with will NOT be able to connect! + Bu bağlantıyı paylaştığınız kişi BAĞLANAMAYACAKTIR! No comment provided by engineer. - + The created archive is available via app Settings / Database / Old database archive. + Oluşturulan arşive uygulama üzerinden Ayarlar / Veritabanı / Eski veritabanı arşivi üzerinden erişilebilir. No comment provided by engineer. - + The encryption is working and the new encryption agreement is not required. It may result in connection errors! + Şifreleme çalışıyor ve yeni şifreleme anlaşması gerekli değil. Bağlantı hatalarına neden olabilir! No comment provided by engineer. The group is fully decentralized – it is visible only to the members. No comment provided by engineer. - + The hash of the previous message is different. + Önceki mesajın hash'i farklı. No comment provided by engineer. - + The message will be deleted for all members. + Mesaj tüm üyeler için silinecektir. No comment provided by engineer. - + The message will be marked as moderated for all members. + Mesaj tüm üyeler için yönetilmiş olarak işaretlenecektir. No comment provided by engineer. - + The next generation of private messaging + Gizli mesajlaşmanın yeni nesli No comment provided by engineer. - + The old database was not removed during the migration, it can be deleted. + Eski veritabanı geçiş sırasında kaldırılmadı, silinebilir. No comment provided by engineer. - + The profile is only shared with your contacts. + Profil sadece kişilerinle paylaşılacak. No comment provided by engineer. - + The sender will NOT be notified + Gönderene BİLDİRİLMEYECEKTİR No comment provided by engineer. - + The servers for new connections of your current chat profile **%@**. + Mevcut sohbet profilinizin yeni bağlantıları için sunucular **%@**. No comment provided by engineer. - + Theme + Tema No comment provided by engineer. - + There should be at least one user profile. + En az bir kullanıcı profili olmalıdır. No comment provided by engineer. - + There should be at least one visible user profile. + En az bir görünür kullanıcı profili olmalıdır. No comment provided by engineer. - + These settings are for your current profile **%@**. + Bu ayarlar mevcut profiliniz **%@** içindir. No comment provided by engineer. They can be overridden in contact and group settings No comment provided by engineer. - + This action cannot be undone - all received and sent files and media will be deleted. Low resolution pictures will remain. + Bu işlem geri alınamaz - alınan ve gönderilen tüm dosyalar ve medya silinecektir. Düşük çözünürlüklü resimler kalacaktır. No comment provided by engineer. - + This action cannot be undone - the messages sent and received earlier than selected will be deleted. It may take several minutes. + Bu işlem geri alınamaz - seçilenden daha önce gönderilen ve alınan mesajlar silinecektir. Bu işlem birkaç dakika sürebilir. No comment provided by engineer. - + This action cannot be undone - your profile, contacts, messages and files will be irreversibly lost. + Bu işlem geri alınamaz - profiliniz, kişileriniz, mesajlarınız ve dosyalarınız geri döndürülemez şekilde kaybolacaktır. No comment provided by engineer. - + This group no longer exists. + Bu grup artık mevcut değildir. No comment provided by engineer. - + This setting applies to messages in your current chat profile **%@**. + Bu ayar, geçerli sohbet profiliniz **%@** deki mesajlara uygulanır. No comment provided by engineer. - + To ask any questions and to receive updates: + Soru sormak ve güncellemeleri almak için: No comment provided by engineer. - + To connect, your contact can scan QR code or use the link in the app. + Bağlanmak için, kişi QR kodu okutabilir veya uygulama içinden bağlantıyı kullanabilir. No comment provided by engineer. To find the profile used for an incognito connection, tap the contact or group name on top of the chat. No comment provided by engineer. - + To make a new connection + Yeni bir bağlantı oluşturmak için No comment provided by engineer. - + To protect privacy, instead of user IDs used by all other platforms, SimpleX has identifiers for message queues, separate for each of your contacts. + Gizliliği korumak için, diğer tüm platformlar gibi kullanıcı kimliği kullanmak yerine, SimpleX mesaj kuyrukları için kişilerinizin her biri için ayrı tanımlayıcılara sahiptir. No comment provided by engineer. - + To protect timezone, image/voice files use UTC. + Zaman bölgesini korumak için,fotoğraf/ses dosyaları UTC kullanır. No comment provided by engineer. - + To protect your information, turn on SimpleX Lock. You will be prompted to complete authentication before this feature is enabled. + Bilgilerinizi korumak için SimpleX Lock özelliğini açın. +Bu özellik etkinleştirilmeden önce kimlik doğrulamayı tamamlamanız istenecektir. No comment provided by engineer. - + To record voice message please grant permission to use Microphone. + Sesli mesaj kaydetmek için lütfen Mikrofon kullanım izni verin. No comment provided by engineer. - + To reveal your hidden profile, enter a full password into a search field in **Your chat profiles** page. + Gizli profilinizi ortaya çıkarmak için **Sohbet profilleriniz** sayfasındaki arama alanına tam bir şifre girin. No comment provided by engineer. - + To support instant push notifications the chat database has to be migrated. + Anlık anlık bildirimleri desteklemek için sohbet veritabanının taşınması gerekir. No comment provided by engineer. - + To verify end-to-end encryption with your contact compare (or scan) the code on your devices. + Kişinizle uçtan uca şifrelemeyi doğrulamak için cihazlarınızdaki kodu karşılaştırın (veya tarayın). No comment provided by engineer. - + Transport isolation + Taşıma izolasyonu No comment provided by engineer. - + Trying to connect to the server used to receive messages from this contact (error: %@). + Bu kişiden mesaj almak için kullanılan sunucuya bağlanılmaya çalışılıyor (hata: %@). No comment provided by engineer. - + Trying to connect to the server used to receive messages from this contact. + Bu kişiden mesaj almak için kullanılan sunucuya bağlanılmaya çalışılıyor. No comment provided by engineer. - + Turn off + Kapat No comment provided by engineer. Turn off notifications? No comment provided by engineer. - + Turn on + No comment provided by engineer. - + Unable to record voice message + Sesli mesaj kaydedilemedi No comment provided by engineer. - + Unexpected error: %@ + Beklenmeyen hata: %@ No comment provided by engineer. - + Unexpected migration state + Beklenmeyen geçiş durumu No comment provided by engineer. - + Unfav. + Favorilerden çık. No comment provided by engineer. - + Unhide + Gizlemeyi kaldır No comment provided by engineer. - + Unhide chat profile + Sohbet profilinin gizlemesini kaldır No comment provided by engineer. - + Unhide profile + Proflin gizlenmesini kaldır No comment provided by engineer. - + Unit + Birim No comment provided by engineer. - + Unknown caller + Bilinmeyen arayan callkit banner - + Unknown database error: %@ + Bilinmeyen veritabanı hatası: %@ No comment provided by engineer. - + Unknown error + Bilinmeyen hata No comment provided by engineer. - + Unless you use iOS call interface, enable Do Not Disturb mode to avoid interruptions. + iOS arama arayüzünü kullanmadığınız sürece, kesintileri önlemek için Rahatsız Etmeyin modunu etkinleştirin. No comment provided by engineer. - + Unless your contact deleted the connection or this link was already used, it might be a bug - please report it. To connect, please ask your contact to create another connection link and check that you have a stable network connection. + Kişiniz bağlantıyı silmediyse veya bu bağlantı kullanılmadıysa, bu bir hata olabilir - lütfen bildirin. +Bağlanmak için lütfen kişinizden başka bir bağlantı oluşturmasını isteyin ve sabit bir ağ bağlantınız olduğunu kontrol edin. No comment provided by engineer. - + Unlock + Kilidi aç No comment provided by engineer. - + Unlock app + Uygulama kilidini aç authentication reason - + Unmute + Susturmayı kaldır No comment provided by engineer. - + Unread + Okunmamış No comment provided by engineer. - + Update + Güncelle No comment provided by engineer. - + Update .onion hosts setting? + .onion ana bilgisayarların ayarı güncellensin mi? No comment provided by engineer. - + Update database passphrase + Veritabanı parolasını güncelle No comment provided by engineer. - + Update network settings? + Bağlantı ayarları güncellensin mi? No comment provided by engineer. - + Update transport isolation mode? + Taşıma izolasyon modu güncellensin mi? No comment provided by engineer. - + Updating settings will re-connect the client to all servers. + Ayarların güncellenmesi, istemciyi tüm sunuculara yeniden bağlayacaktır. No comment provided by engineer. - + Updating this setting will re-connect the client to all servers. + Bu ayarın güncellenmesi, istemciyi tüm sunuculara yeniden bağlayacaktır. No comment provided by engineer. - + Upgrade and open chat + Yükselt ve sohbeti aç No comment provided by engineer. - + Upload file + Dosya yükle server test step - + Use .onion hosts + .onion ana bilgisayarlarını kullan No comment provided by engineer. - + Use SimpleX Chat servers? + SimpleX Chat sunucuları kullanılsın mı? No comment provided by engineer. - + Use chat + Sohbeti kullan No comment provided by engineer. - + Use for new connections + Yeni bağlantılar için kullan No comment provided by engineer. - + Use iOS call interface + iOS arama arayüzünden kullan No comment provided by engineer. - + Use server + Sunucu kullan No comment provided by engineer. - + User profile + Kullanıcı profili No comment provided by engineer. - + Using .onion hosts requires compatible VPN provider. + .onion ana bilgisayarlarını kullanmak için uyumlu VPN sağlayıcısı gerekir. No comment provided by engineer. - + Using SimpleX Chat servers. + SimpleX Chat sunucuları kullanılıyor. No comment provided by engineer. - + Verify connection security + Bağlantı güvenliğini doğrula No comment provided by engineer. - + Verify security code + Güvenlik kodunu doğrula No comment provided by engineer. - + Via browser + Tarayıcı üzerinden No comment provided by engineer. - + Video call + Görüntülü arama No comment provided by engineer. - + Video will be received when your contact completes uploading it. + Kişiniz yüklemeyi tamamladığında video alınacaktır. No comment provided by engineer. - + Video will be received when your contact is online, please wait or check later! + Kişiniz çevrimiçi olduğunda video alınacaktır, lütfen bekleyin veya daha sonra kontrol edin! No comment provided by engineer. - + Videos and files up to 1gb + 1gb'a kadar videolar ve dosyalar No comment provided by engineer. - + View security code + Güvenlik kodunu görüntüle No comment provided by engineer. - + Voice messages + Sesli mesajlar chat feature - + Voice messages are prohibited in this chat. + Bu sohbette sesli mesajlar yasaktır. No comment provided by engineer. - + Voice messages are prohibited in this group. + Bu grupta sesli mesajlar yasaktır. No comment provided by engineer. - + Voice messages prohibited! + Sesli mesajlar yasaktır! No comment provided by engineer. - + Voice message… + Sesli mesaj… No comment provided by engineer. - + Waiting for file + Dosya bekleniyor No comment provided by engineer. - + Waiting for image + Görsel bekleniyor No comment provided by engineer. - + Waiting for video + Video bekleniyor No comment provided by engineer. - + Warning: you may lose some data! + Uyarı: Bazı verileri kaybedebilirsin! No comment provided by engineer. - + WebRTC ICE servers + WebRTC ICE sunucuları No comment provided by engineer. - + Welcome %@! + Hoşgeldin %@! No comment provided by engineer. - + Welcome message + Karşılama mesajı No comment provided by engineer. - + What's new + Neler yeni No comment provided by engineer. - + When available + Mevcut olduğunda No comment provided by engineer. - + When people request to connect, you can accept or reject it. + İnsanlar bağlantı talebinde bulunduğunda, kabul edebilir veya reddedebilirsiniz. No comment provided by engineer. - + When you share an incognito profile with somebody, this profile will be used for the groups they invite you to. + Biriyle gizli bir profil paylaştığınızda, bu profil sizi davet ettikleri gruplar için kullanılacaktır. No comment provided by engineer. - + With optional welcome message. + İsteğe bağlı karşılama mesajı ile. No comment provided by engineer. - + Wrong database passphrase + Yanlış veritabanı parolası No comment provided by engineer. - + Wrong passphrase! + Yanlış parola! No comment provided by engineer. - + XFTP servers + XFTP sunucuları No comment provided by engineer. - + You + Sen No comment provided by engineer. - + You accepted connection + Bağlantıyı onayladın No comment provided by engineer. - + You allow + İzin veriyorsunuz No comment provided by engineer. - + You already have a chat profile with the same display name. Please choose another name. + Aynı görünen ada sahip bir konuşma profilin zaten var. Lütfen başka bir ad seç. No comment provided by engineer. - + You are already connected to %@. + Zaten %@'a bağlısınız. No comment provided by engineer. - + You are connected to the server used to receive messages from this contact. + Bu kişiden mesaj almak için kullanılan sunucuya bağlısınız. No comment provided by engineer. - + You are invited to group + Gruba davet edildiniz No comment provided by engineer. - + You can accept calls from lock screen, without device and app authentication. + Cihaz ve uygulama kimlik doğrulaması olmadan kilit ekranından çağrı kabul edebilirsiniz. No comment provided by engineer. You can also connect by clicking the link. If it opens in the browser, click **Open in mobile app** button. No comment provided by engineer. - + You can create it later + Daha sonra oluşturabilirsiniz No comment provided by engineer. - + You can enable them later via app Privacy & Security settings. + Daha sonra uygulamanın Gizlilik ve Güvenlik ayarlarından etkinleştirebilirsiniz. No comment provided by engineer. - + You can hide or mute a user profile - swipe it to the right. + Bir kullanıcı profilini gizleyebilir veya sessize alabilirsiniz - sağa kaydırın. No comment provided by engineer. - + You can now send messages to %@ + Artık %@ adresine mesaj gönderebilirsin notification body - + You can set lock screen notification preview via settings. + Kilit ekranı bildirim önizlemesini ayarlar üzerinden ayarlayabilirsiniz. No comment provided by engineer. - + You can share a link or a QR code - anybody will be able to join the group. You won't lose members of the group if you later delete it. + Bir bağlantı veya QR kodu paylaşabilirsiniz - bu durumda herkes gruba katılabilir. Daha sonra silseniz bile grubun üyelerini kaybetmezsiniz. No comment provided by engineer. - + You can share this address with your contacts to let them connect with **%@**. + Bu adresi kişilerinizle paylaşarak onların **%@** ile bağlantı kurmasını sağlayabilirsiniz. No comment provided by engineer. - + You can share your address as a link or QR code - anybody can connect to you. + Adresinizi bir bağlantı veya QR kodu olarak paylaşabilirsiniz - herkes size bağlanabilir. No comment provided by engineer. - + You can start chat via app Settings / Database or by restarting the app + Sohbeti uygulamada Ayarlar / Veritabanı üzerinden veya uygulamayı yeniden başlatarak başlatabilirsiniz No comment provided by engineer. - + You can turn on SimpleX Lock via Settings. + SimpleX Kilidini Ayarlar üzerinden açabilirsiniz. No comment provided by engineer. - + You can use markdown to format messages: + Mesajları biçimlendirmek için markdown kullanabilirsiniz: No comment provided by engineer. - + You can't send messages! + Mesajlar gönderemezsiniz! No comment provided by engineer. - + You control through which server(s) **to receive** the messages, your contacts – the servers you use to message them. + Mesajların hangi sunucu(lar)dan **alınacağını**, kişilerinizi - onlara mesaj göndermek için kullandığınız sunucuları - siz kontrol edersiniz. No comment provided by engineer. - + You could not be verified; please try again. + Doğrulanamadınız; lütfen tekrar deneyin. No comment provided by engineer. - + You have no chats + Hiç sohbetiniz yok No comment provided by engineer. - + You have to enter passphrase every time the app starts - it is not stored on the device. + Uygulama her başladığında parola girmeniz gerekir - parola cihazınızda saklanmaz. No comment provided by engineer. You invited your contact No comment provided by engineer. - + You joined this group + Bu gruba katıldınız No comment provided by engineer. - + You joined this group. Connecting to inviting group member. + Bu gruba katıldınız. Davet eden grup üyesine bağlanılıyor. No comment provided by engineer. - + You must use the most recent version of your chat database on one device ONLY, otherwise you may stop receiving the messages from some contacts. + Sohbet veritabanınızın en son sürümünü SADECE bir cihazda kullanmalısınız, aksi takdirde bazı kişilerden daha fazla mesaj alamayabilirsiniz. No comment provided by engineer. - + You need to allow your contact to send voice messages to be able to send them. + Sesli mesaj gönderebilmeniz için kişinizin de sesli mesaj göndermesine izin vermeniz gerekir. No comment provided by engineer. - + You rejected group invitation + Grup davetini reddettiniz. No comment provided by engineer. - + You sent group invitation + Grup daveti gönderdiniz No comment provided by engineer. - + You will be connected to group when the group host's device is online, please wait or check later! + Grup sahibinin cihazı çevrimiçi olduğunda gruba bağlanacaksınız, lütfen bekleyin veya daha sonra kontrol edin! No comment provided by engineer. - + You will be connected when your connection request is accepted, please wait or check later! + Bağlantı isteğiniz kabul edildiğinde bağlanacaksınız, lütfen bekleyin veya daha sonra kontrol edin! No comment provided by engineer. - + You will be connected when your contact's device is online, please wait or check later! + Kişinizin cihazı çevrimiçi olduğunda bağlanacaksınız, lütfen bekleyin veya daha sonra kontrol edin! No comment provided by engineer. - + You will be required to authenticate when you start or resume the app after 30 seconds in background. + Arka planda 30 saniye kaldıktan sonra uygulamayı başlattığınızda veya devam ettirdiğinizde kimlik doğrulaması yapmanız gerekecektir. No comment provided by engineer. You will join a group this link refers to and connect to its group members. No comment provided by engineer. - + You will still receive calls and notifications from muted profiles when they are active. + Aktif olduklarında sessize alınmış profillerden arama ve bildirim almaya devam edersiniz. No comment provided by engineer. - + You will stop receiving messages from this group. Chat history will be preserved. + Bu gruptan artık mesaj almayacaksınız. Sohbet geçmişi korunacaktır. No comment provided by engineer. - + You won't lose your contacts if you later delete your address. + Eğer sonradan bağlantınızı silseniz bile kişilerinizi kaybetmeyeceksiniz. No comment provided by engineer. - + You're trying to invite contact with whom you've shared an incognito profile to the group in which you're using your main profile + Gizli bir profil paylaştığınız kişiyi ana profilinizi kullandığınız gruba davet etmeye çalışıyorsunuz No comment provided by engineer. - + You're using an incognito profile for this group - to prevent sharing your main profile inviting contacts is not allowed + Bu grup için gizli bir profil kullanıyorsunuz - ana profilinizi paylaşmayı önlemek için kişileri davet etmeye izin verilmiyor No comment provided by engineer. - + Your %@ servers + %@ sunucularınız No comment provided by engineer. - + Your ICE servers + ICE sunucularınız No comment provided by engineer. - + Your SMP servers + SMP sunucularınız No comment provided by engineer. - + Your SimpleX address + SimpleX adresin No comment provided by engineer. - + Your XFTP servers + XFTP sunucularınız No comment provided by engineer. - + Your calls + Aramaların No comment provided by engineer. - + Your chat database + Sohbet veritabanınız No comment provided by engineer. - + Your chat database is not encrypted - set passphrase to encrypt it. + Sohbet veritabanınız şifrelenmemiş - şifrelemek için parola ayarlayın. No comment provided by engineer. @@ -4237,21 +5148,26 @@ To connect, please ask your contact to create another connection link and check Your chat profile will be sent to your contact No comment provided by engineer. - + Your chat profiles + Sohbet profillerin No comment provided by engineer. - + Your contact needs to be online for the connection to complete. You can cancel this connection and remove the contact (and try later with a new link). + Bağlantının tamamlanması için kişinizin çevrimiçi olması gerekir. +Bu bağlantıyı iptal edebilir ve kişiyi kaldırabilirsiniz (ve daha sonra yeni bir bağlantıyla deneyebilirsiniz). No comment provided by engineer. - + Your contact sent a file that is larger than currently supported maximum size (%@). + Kişiniz şu anda desteklenen maksimum boyuttan (%@) daha büyük bir dosya gönderdi. No comment provided by engineer. - + Your contacts can allow full message deletion. + Kişileriniz tam mesaj silme işlemine izin verebilir. No comment provided by engineer. @@ -4259,409 +5175,510 @@ You can cancel this connection and remove the contact (and try later with a new You can change it in Settings. No comment provided by engineer. - + Your contacts will remain connected. + Kişileriniz bağlı kalacaktır. No comment provided by engineer. - + Your current chat database will be DELETED and REPLACED with the imported one. + Mevcut sohbet veritabanınız SİLİNECEK ve içe aktarılan veritabanıyla DEĞİŞTİRİLECEKTİR. No comment provided by engineer. - + Your current profile + Mevcut profiliniz No comment provided by engineer. - + Your preferences + Tercihleriniz No comment provided by engineer. - + Your privacy + Gizliliğiniz No comment provided by engineer. - + Your profile is stored on your device and shared only with your contacts. SimpleX servers cannot see your profile. + Profiliniz cihazınızda saklanır ve sadece kişilerinizle paylaşılır. +SimpleX sunucuları profilinizi göremez. No comment provided by engineer. Your profile will be sent to the contact that you received this link from No comment provided by engineer. - + Your profile, contacts and delivered messages are stored on your device. + Profiliniz, kişileriniz ve gönderilmiş mesajlar cihazınızda saklanır. No comment provided by engineer. - + Your random profile + Rasgele profiliniz No comment provided by engineer. - + Your server + Sunucunuz No comment provided by engineer. - + Your server address + Sunucu adresiniz No comment provided by engineer. - + Your settings + Ayarlarınız No comment provided by engineer. - + [Contribute](https://github.com/simplex-chat/simplex-chat#contribute) + [Katkıda bulun](https://github.com/simplex-chat/simplex-chat#contribute) No comment provided by engineer. - + [Send us email](mailto:chat@simplex.chat) + [Bize e-posta gönder](mailto:chat@simplex.chat) No comment provided by engineer. - + [Star on GitHub](https://github.com/simplex-chat/simplex-chat) + [Bize GitHub'da yıldız verin](https://github.com/simplex-chat/simplex-chat) No comment provided by engineer. - + \_italic_ + \_italik_ No comment provided by engineer. - + \`a + b` + \`a + b` No comment provided by engineer. - + above, then choose: + yukarı çıkın, ardından seçin: No comment provided by engineer. - + accepted call + kabul edilen arama call status - + admin + yönetici member role - + agreeing encryption for %@… + %@ için şifreleme kabul ediliyor… chat item text - + agreeing encryption… + şifreleme kabul ediliyor… chat item text - + always + her zaman pref value - + audio call (not e2e encrypted) + sesli arama (uçtan uca şifreli değil) No comment provided by engineer. - + bad message ID + kötü mesaj kimliği integrity error chat item - + bad message hash + kötü mesaj hash'i integrity error chat item - + bold + kalın No comment provided by engineer. - + call error + arama hatası call status - + call in progress + arama yapılıyor call status - + calling… + aranıyor… call status - + cancelled %@ + %@ iptal edildi feature offered item - + changed address for you + senin için adres değiştirildi chat item text - + changed role of %1$@ to %2$@ + 1$@ rolünü %2$@ olarak değiştirdi rcv group event chat item - + changed your role to %@ + rolünü %@ olarak değiştirdi rcv group event chat item - + changing address for %@… + %@ için adres değiştiriliyor… chat item text - + changing address… + adres değiştiriliyor… chat item text - + colored + renklendirilmiş No comment provided by engineer. - + complete + tamamlandı No comment provided by engineer. - + connect to SimpleX Chat developers. + SimpleX Chat geliştiricilerine bağlan. No comment provided by engineer. - + connected + bağlanıldı No comment provided by engineer. - + connecting + bağlanılıyor No comment provided by engineer. - + connecting (accepted) + bağlanılıyor (onaylandı) No comment provided by engineer. - + connecting (announced) + bağlanılıyor (duyuruldu) No comment provided by engineer. - + connecting (introduced) + bağlanılıyor (tanıtıldı) No comment provided by engineer. - + connecting (introduction invitation) + bağlanılıyor (tanıtılma isteği) No comment provided by engineer. - + connecting call… + aramaya bağlanılıyor… call status - + connecting… + bağlanılıyor… chat list item title - + connection established + bağlantı kuruldu chat list item title (it should not be shown - + connection:%@ + bağlantı:%@ connection information - + contact has e2e encryption + kişi uçtan uca şifrelemeye sahiptir No comment provided by engineer. - + contact has no e2e encryption + kişi uçtan uca şifrelemeye sahip değildir No comment provided by engineer. - + creator + oluşturan No comment provided by engineer. - + custom + özel dropdown time picker choice - + database version is newer than the app, but no down migration for: %@ + veritabanı sürümü uygulamadan daha yeni, ancak aşağı geçiş yok: %@ No comment provided by engineer. - + days + gün time unit - + default (%@) + varsayılan (%@) pref value - + default (no) + varsayılan (hayır) No comment provided by engineer. - + default (yes) + varsayılan (evet) No comment provided by engineer. - + deleted + silindi deleted chat item - + deleted group + silinmiş grup rcv group event chat item - + different migration in the app/database: %@ / %@ + uygulamada/veritabanında farklı geçiş: %@ / %@ No comment provided by engineer. - + direct + doğrudan connection level description - + duplicate message + yinelenen mesaj integrity error chat item - + e2e encrypted + uçtan uca şifrelenmiş No comment provided by engineer. - + enabled + etkin enabled status - + enabled for contact + konuşulan kişi için etkinleşti enabled status - + enabled for you + senin için etkinleştirildi enabled status - + encryption agreed + şifreleme kabul edildi chat item text - + encryption agreed for %@ + şifreleme %@ için kabul edildi chat item text - + encryption ok + şifreleme etkin chat item text - + encryption ok for %@ + şifreleme %@ için etkin chat item text - + encryption re-negotiation allowed + şifrelemenin yeniden anlaşmasına izin verildi chat item text - + encryption re-negotiation allowed for %@ + şifrelemenin yeniden anlaşmasına %@ için izin verildi chat item text - + encryption re-negotiation required + şifrelemenin yeniden anlaşması gerekiyor chat item text - + encryption re-negotiation required for %@ + şifrelemenin yeniden anlaşması %@ için gerekiyor chat item text - + ended + bitti No comment provided by engineer. - + ended call %@ + %@ araması bitti call status - + error + hata No comment provided by engineer. - + group deleted + grup silindi No comment provided by engineer. - + group profile updated + grup profili güncellendi snd group event chat item - + hours + saat time unit - + iOS Keychain is used to securely store passphrase - it allows receiving push notifications. + iOS Anahtar Zinciri parolayı güvenli bir şekilde saklamak için kullanılır - anlık bildirimlerin alınmasını sağlar. No comment provided by engineer. - + iOS Keychain will be used to securely store passphrase after you restart the app or change passphrase - it will allow receiving push notifications. + iOS Anahtar Zinciri, uygulamayı yeniden başlattıktan veya parolayı değiştirdikten sonra parolayı güvenli bir şekilde saklamak için kullanılacaktır - anlık bildirimlerin alınmasına izin verecektir. No comment provided by engineer. - + incognito via contact address link + kişi bağlantı linki aracılığıyla gizli chat list item description - + incognito via group link + grup bağlantısı aracılığıyla gizli chat list item description - + incognito via one-time link + tek seferlik bağlantısı aracılığıyla gizli chat list item description - + indirect (%d) + dolaylı (%d) connection level description - + invalid chat + geçersi̇z sohbet invalid chat data - + invalid chat data + geçersi̇z sohbet verisi No comment provided by engineer. - + invalid data + geçersiz veri invalid chat item - + invitation to group %@ + %@ grubuna davet group name - + invited + davet edildi No comment provided by engineer. - + invited %@ + %@ a davet edildi rcv group event chat item - + invited to connect + bağlanmaya davet edildi chat list item title - + invited via your group link + grup bağlantınız üzerinden davet edildi rcv group event chat item - + italic + italik No comment provided by engineer. - + join as %@ + %@ olarak katıl No comment provided by engineer. - + left + ayrıldı rcv group event chat item - + marked deleted + silinmiş olarak işaretlenmiş marked deleted chat item preview text - + member + üye member role - + connected + bağlanıldı rcv group event chat item @@ -4681,7 +5698,7 @@ SimpleX servers cannot see your profile. moderated - moderated + yönetildi moderated chat item @@ -4694,93 +5711,114 @@ SimpleX servers cannot see your profile. aylar time unit - + never + asla No comment provided by engineer. - + new message + yeni mesaj notification - + no + hayır pref value - + no e2e encryption + uçtan uca şifreleme yok No comment provided by engineer. - + no text + metin yok copied message info in history - + observer + gözlemci member role - + off + kapalı enabled status group pref value - + offered %@ + %@ teklif edildi feature offered item - + offered %1$@: %2$@ + %1$@: %2$@ teklif etti feature offered item - + on + açık group pref value or chat with the developers No comment provided by engineer. - + owner + sahip member role - + peer-to-peer + eşler arası No comment provided by engineer. - + received answer… + alınan cevap… No comment provided by engineer. - + received confirmation… + onaylama alındı… No comment provided by engineer. - + rejected call + geri çevrilmiş çağrı call status - + removed + kaldırıldı No comment provided by engineer. - + removed %@ + %@ kaldırıldı rcv group event chat item - + removed you + sen kaldırıldın rcv group event chat item - + sec + sn network option - + seconds + saniye time unit - + secret + gizli No comment provided by engineer. @@ -4790,12 +5828,12 @@ SimpleX servers cannot see your profile. starting… - başlıyor… + başlatılıyor… No comment provided by engineer. strike - strike + grev No comment provided by engineer. @@ -4835,7 +5873,7 @@ SimpleX servers cannot see your profile. via relay - via relay + yönlendirici aracılığıyla No comment provided by engineer. @@ -4925,17 +5963,17 @@ SimpleX servers cannot see your profile. \~strike~ - \~strike~ + \~strike~ No comment provided by engineer. Accept connection request? - Bağlantı isteğini kabul et? + Bağlantı isteği kabul edilsin mi? No comment provided by engineer. # %@ - # %@ + # %@ copied message info title, # <title> @@ -4963,6 +6001,1047 @@ SimpleX servers cannot see your profile. Zaten gruba bağlanılıyor! No comment provided by engineer. + + Block + Engelle + No comment provided by engineer. + + + %@ connected + %@ bağlandı + No comment provided by engineer. + + + Discover and join groups + Keşfet ve gruplara katıl + No comment provided by engineer. + + + Disconnect desktop? + Bilgisayarla bağlantı kesilsin mi? + No comment provided by engineer. + + + Bulgarian, Finnish, Thai and Ukrainian - thanks to the users and [Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)! + Bulgarca, Fince, Tayca ve Ukraynaca - kullanıcılara ve [Weblate] e teşekkürler! (https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)! + No comment provided by engineer. + + + Create a group using a random profile. + Rasgele profil kullanarak grup oluştur. + No comment provided by engineer. + + + Don't enable + Etkinleştirme + No comment provided by engineer. + + + Connect with %@ + %@ ile bağlan + No comment provided by engineer. + + + Discover via local network + Yerel ağ aracılığıyla keşfet + No comment provided by engineer. + + + Enter this device name… + Bu cihazın adını gir… + No comment provided by engineer. + + + Better groups + Daha iyi gruplar + No comment provided by engineer. + + + Error opening chat + Sohbeti açarken sorun oluştu + No comment provided by engineer. + + + - more stable message delivery. +- a bit better groups. +- and more! + - daha stabil mesaj gönderimi. +- birazcık daha iyi gruplar. +- ve fazlası! + No comment provided by engineer. + + + - optionally notify deleted contacts. +- profile names with spaces. +- and more! + - isteğe bağlı olarak silinen kişilere bildirme. +- boşluklu profil adları +- ve fazlası! + No comment provided by engineer. + + + 0 sec + 0 saniye + time to disappear + + + Block member + Üyeyi engelle + No comment provided by engineer. + + + Connect via one-time link + Tek kullanımlık bağlantı aracılığıyla bağlan + No comment provided by engineer. + + + Camera not available + Kamera mevcut değil + No comment provided by engineer. + + + Desktop app version %@ is not compatible with this app. + Masaüstü uygulaması sürümü %@ bu uygulama ile uyumlu değildir. + No comment provided by engineer. + + + Connect incognito + Gizli bağlan + No comment provided by engineer. + + + Create group + Grup oluştur + No comment provided by engineer. + + + Enter group name… + Grup adı gir… + No comment provided by engineer. + + + Delete contact? +This cannot be undone! + Kişi silinsin mi? +Bu geri alınamaz! + No comment provided by engineer. + + + Connect to desktop + Bilgisayara bağlan + No comment provided by engineer. + + + All new messages from %@ will be hidden! + %@ 'den gelen bütün yeni mesajlar saklı olacak! + No comment provided by engineer. + + + Delete and notify contact + Sil ve kişiye bildir + No comment provided by engineer. + + + - connect to [directory service](simplex:/contact#/?v=1-4&smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion) (BETA)! +- delivery receipts (up to 20 members). +- faster and more stable. + - [dizin hizmeti] 'ne bağlan(simplex:/contact#/?v=1-4&smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion) (BETA)! +- çoklu mesaj gönderimi (20 kişiye kadar). +- daha hızlı ve daha stabil. + No comment provided by engineer. + + + %@ and %@ + %@ ve %@ + No comment provided by engineer. + + + %lld messages moderated by %@ + %lld mesajları %@ tarafından yönetildi + No comment provided by engineer. + + + %lld new interface languages + %lld yeni arayüz dilleri + No comment provided by engineer. + + + Delivery + Teslimat + No comment provided by engineer. + + + Correct name to %@? + İsim %@ olarak düzeltilsin mi? + No comment provided by engineer. + + + **Add contact**: to create a new invitation link, or connect via a link you received. + **Kişi ekle**: yeni bir davet bağlantısı oluşturmak için, ya da aldığın bağlantıyla bağlan. + No comment provided by engineer. + + + Creating link… + Link oluşturuluyor… + No comment provided by engineer. + + + ## In reply to + ## cevap olarak + copied message info + + + Delete %lld messages? + %lld mesajları silinsin mi? + No comment provided by engineer. + + + %lld messages blocked + %lld mesajlar engellendi + No comment provided by engineer. + + + Error creating member contact + Kişi iletişimi oluşturulurken hata oluştu + No comment provided by engineer. + + + Disable for all + Herkes için devre dışı bırak + No comment provided by engineer. + + + Connection terminated + Bağlantı sonlandırılmış + No comment provided by engineer. + + + Connect via contact address + Kişi adresi aracılığıyla bağlan + No comment provided by engineer. + + + Encrypt stored files & media + Saklanan dosyaları ve medyayı şifreleyin + No comment provided by engineer. + + + %lld messages marked deleted + %lld mesajlar silinmiş olarak işaretlendi + No comment provided by engineer. + + + %lld group events + %lld grup etkinlikleri + No comment provided by engineer. + + + Add contact + Kişi ekle + No comment provided by engineer. + + + Connected to desktop + Bilgisayara bağlanıldı + No comment provided by engineer. + + + **Create group**: to create a new group. + **Grup oluştur**: yeni bir grup oluşturmak için. + No comment provided by engineer. + + + Error enabling delivery receipts! + Görüldü bilgisi etkinleştirilirken hata oluştu! + No comment provided by engineer. + + + Enter your name… + Adını gir… + No comment provided by engineer. + + + (this device v%@) + (bu cihaz v%@) + No comment provided by engineer. + + + Expand + Genişlet + chat item action + + + Enable (keep overrides) + Etkinleştir (geçersiz kılmaları koru) + No comment provided by engineer. + + + Desktop devices + Bilgisayar cihazları + No comment provided by engineer. + + + Enable camera access + Kamera erişimini etkinleştir + No comment provided by engineer. + + + Error decrypting file + Dosya şifresi çözülürken hata oluştu + No comment provided by engineer. + + + Encrypted message: app is stopped + Şifrelenmiş mesaj: uygulama durdu + notification + + + Create profile + Profil oluştur + No comment provided by engineer. + + + Disable (keep overrides) + Devre dışı bırak (geçersiz kılmaları koru) + No comment provided by engineer. + + + Encrypt local files + Yerel dosyaları şifrele + No comment provided by engineer. + + + Connect automatically + Otomatik olarak bağlan + No comment provided by engineer. + + + Enable for all + Herkes için etkinleştir + No comment provided by engineer. + + + App encrypts new local files (except videos). + Uygulama yerel dosyaları şifreler (videolar dışında). + No comment provided by engineer. + + + Connected desktop + Bilgisayara bağlandı + No comment provided by engineer. + + + Connect to yourself? + Kendine mi bağlanacaksın? + No comment provided by engineer. + + + Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat. + Sohbet durduruldu. Bu veritabanını zaten başka bir cihazda kullandıysanız, sohbete başlamadan önce onu geri aktarmalısınız. + No comment provided by engineer. + + + %@, %@ and %lld members + %@, %@ ve %lld üyeleri + No comment provided by engineer. + + + Connect to yourself? +This is your own SimpleX address! + Kendine mi bağlanacaksın? +Bu senin kendi SimpleX adresin! + No comment provided by engineer. + + + Block group members + Grup üyelerini engelle + No comment provided by engineer. + + + Block member? + Üyeyi engelle? + No comment provided by engineer. + + + %@, %@ and %lld other members connected + %@, %@ ve %lld diğer üyeler bağlandı + No comment provided by engineer. + + + Encryption re-negotiation failed. + Şifreleme yeniden anlaşma başarısız oldu. + No comment provided by engineer. + + + Create new profile in [desktop app](https://simplex.chat/downloads/). 💻 + [bilgisayar uygulaması] nda yeni bir profil oluştur(https://simplex.chat/downloads/). 💻 + No comment provided by engineer. + + + Bad desktop address + Kötü bilgisayar adresi + No comment provided by engineer. + + + Connect to yourself? +This is your own one-time link! + Kendine mi bağlanacaksın? +Bu senin kendi tek kullanımlık bağlantın! + No comment provided by engineer. + + + Desktop address + Bilgisayar adresi + No comment provided by engineer. + + + (new) + (yeni) + No comment provided by engineer. + + + Encryption re-negotiation error + Şifreleme yeniden anlaşma hatası + message decrypt error item + + + %@ and %@ connected + %@ ve %@ bağlandı + No comment provided by engineer. + + + Connecting to desktop + Bilgisayara bağlanıyor + No comment provided by engineer. + + + Open + + No comment provided by engineer. + + + Or show this code + Veya bu kodu göster + No comment provided by engineer. + + + Open group + Grubu aç + No comment provided by engineer. + + + Found desktop + Bilgisayar bulundu + No comment provided by engineer. + + + Incognito groups + Gizli gruplar + No comment provided by engineer. + + + Error scanning code: %@ + Kod taranırken hata oluştu: %@ + No comment provided by engineer. + + + Invalid QR code + Geçersiz QR kodu + No comment provided by engineer. + + + Fully decentralized – visible only to members. + Tamamiyle merkezi olmayan - sadece kişilere görünür. + No comment provided by engineer. + + + New desktop app! + Yeni bilgisayar uygulaması! + No comment provided by engineer. + + + Not compatible! + Uyumlu değil! + No comment provided by engineer. + + + Invalid name! + Geçersiz isim! + No comment provided by engineer. + + + Filter unread and favorite chats. + Favori ve okunmamış sohbetleri filtrele. + No comment provided by engineer. + + + Incompatible version + Uyumsuz sürüm + No comment provided by engineer. + + + Paste the link you received + Aldığın bağlantıyı yapıştır + No comment provided by engineer. + + + Opening app… + Uygulama açılıyor… + No comment provided by engineer. + + + Linked desktop options + Bağlanmış bilgisayar ayarları + No comment provided by engineer. + + + Join group? + Gruba katılınsın mı? + No comment provided by engineer. + + + Keep unused invitation? + Kullanılmamış davet tutulsun mu? + No comment provided by engineer. + + + Most likely this connection is deleted. + Büyük ihtimalle bu bağlantı silinmiş. + item status description + + + Faster joining and more reliable messages. + Daha hızlı katılma ve daha güvenilir mesajlar. + No comment provided by engineer. + + + Join your group? +This is your link for group %@! + Bu gruba katılınsın mı? +Bu senin grup için bağlantın %@! + No comment provided by engineer. + + + Keep your connections + Bağlantılarınızı koruyun + No comment provided by engineer. + + + Messages from %@ will be shown! + %@ den gelen mesajlar gösterilecektir! + No comment provided by engineer. + + + Paste desktop address + Bilgisayar adresini yapıştır + No comment provided by engineer. + + + Group already exists! + Grup çoktan mevcut! + No comment provided by engineer. + + + Even when disabled in the conversation. + Konuşma sırasında devre dışı bırakılsa bile. + No comment provided by engineer. + + + Message delivery receipts! + Mesaj alındı bilgisi! + No comment provided by engineer. + + + Join with current profile + Şu anki profille katıl + No comment provided by engineer. + + + Keep + Tut + No comment provided by engineer. + + + Error setting delivery receipts! + Görüldü ayarlanırken hata oluştu! + No comment provided by engineer. + + + Fix encryption after restoring backups. + Yedekleri geri yükledikten sonra şifrelemeyi düzelt. + No comment provided by engineer. + + + Invalid link + Geçersiz bağlantı + No comment provided by engineer. + + + No delivery information + Gönderim bilgisi yok + No comment provided by engineer. + + + Local + Yerel + No comment provided by engineer. + + + Please contact developers. +Error: %@ + Lütfen geliştiricilerle irtibata geçin. +Hata: %@ + No comment provided by engineer. + + + Incognito mode protects your privacy by using a new random profile for each contact. + Gizli mod her kişiye farklı olarak rasgele profiller kullanarak gizliliğinizi korur. + No comment provided by engineer. + + + New chat + Yeni sohbet + No comment provided by engineer. + + + Make one message disappear + Bir mesajın kaybolmasını sağlayın + No comment provided by engineer. + + + Group already exists + Grup çoktan mevcut + No comment provided by engineer. + + + Invalid status + Geçersiz durum + item status text + + + Linked desktops + Bağlanmış bilgisayarlar + No comment provided by engineer. + + + OK + TAMAM + No comment provided by engineer. + + + Keep the app open to use it from desktop + Bilgisayardan kullanmak için uygulamayı açık tut + No comment provided by engineer. + + + Invalid response + Geçersiz yanıt + No comment provided by engineer. + + + Find chats faster + Sohbetleri daha hızlı bul + No comment provided by engineer. + + + Link mobile and desktop apps! 🔗 + Telefon ve bilgisayar uygulamalarını bağla! 🔗 + No comment provided by engineer. + + + Error sending member contact invitation + Kişi iletişim daveti gönderilirken hata oluştu + No comment provided by engineer. + + + Or scan QR code + Veya QR kodu okut + No comment provided by engineer. + + + Search or paste SimpleX link + Ara veya SimpleX bağlantısını yapıştır + No comment provided by engineer. + + + Retry + Yeniden dene + No comment provided by engineer. + + + Receipts are disabled + Görüldü devre dışı bırakıldı + No comment provided by engineer. + + + Profile name + Profil ismi + No comment provided by engineer. + + + Reject (sender NOT notified) + Reddet (göndericiye bildirim GİTMEYECEKTİR) + No comment provided by engineer. + + + Scan QR code from desktop + Bilgisayardan QR kodu okut + No comment provided by engineer. + + + Profile name: + Profil ismi: + No comment provided by engineer. + + + Sending receipts is disabled for %lld contacts + Görüldü bilgisi %lld kişileri için devre dışı bırakıldı + No comment provided by engineer. + + + Share this 1-time invite link + Bu tek kullanımlık bağlantı davetini paylaş + No comment provided by engineer. + + + Unblock member + Üyenin engelini kaldır + No comment provided by engineer. + + + Via secure quantum resistant protocol. + Güvenli kuantum dirençli protokol ile. + No comment provided by engineer. + + + Sending receipts is enabled for %lld groups + Görüldü bilgisi %lld grupları için etkinleştirildi + No comment provided by engineer. + + + Sending receipts is disabled for %lld groups + Görüldü bilgisi %lld grupları için devre dışı bırakıldı + No comment provided by engineer. + + + To hide unwanted messages. + İstenmeyen mesajları gizlemek için. + No comment provided by engineer. + + + Sending delivery receipts will be enabled for all contacts. + Görüldü bilgisi bütün kişileri için etkinleştirilecektir. + No comment provided by engineer. + + + Sending receipts is enabled for %lld contacts + Görüldü bilgisi %lld kişileri için etkinleştirildi + No comment provided by engineer. + + + Verify code with desktop + Bilgisayarla kodu doğrula + No comment provided by engineer. + + + This group has over %lld members, delivery receipts are not sent. + Bu grubun %lld den fazla üyesi var,görüldü bilgisi gönderilmedi. + No comment provided by engineer. + + + Repeat join request? + Katılma isteği tekrarlansın mı? + No comment provided by engineer. + + + Unlink desktop? + Bilgisayarla bağlantı kaldırılsın mı? + No comment provided by engineer. + + + You are already in group %@. + Zaten %@ grubundasın. + No comment provided by engineer. + + + Unblock member? + Üyenin engeli kaldırılsın mı? + No comment provided by engineer. + + + Sending delivery receipts will be enabled for all contacts in all visible chat profiles. + Görüldü bilgisi, tüm görünür sohbet profillerindeki tüm kişiler için etkinleştirilecektir. + No comment provided by engineer. + + + You are already connecting via this one-time link! + Bu tek seferlik bağlantı üzerinden zaten bağlanıyorsunuz! + No comment provided by engineer. + + + Repeat connection request? + Bağlantı isteği tekrarlansın mı? + No comment provided by engineer. + + + Tap to Connect + Bağlanmak için Tıkla + No comment provided by engineer. + + + They can be overridden in contact and group settings. + Bunlar kişi ve grup ayarlarında geçersiz kılınabilir. + No comment provided by engineer. + + + You are already joining the group via this link! + Bu bağlantı üzerinden gruba zaten katılıyorsunuz! + No comment provided by engineer. + + + Session code + Oturum kodu + No comment provided by engineer. + + + You are already joining the group via this link. + Gruba zaten bu bağlantı üzerinden katılıyorsunuz. + No comment provided by engineer. + + + Use current profile + Şu anki profili kullan + No comment provided by engineer. + + + You can enable later via Settings + Daha sonra Ayarlardan etkinleştirebilirsin + No comment provided by engineer. + + + Start chat? + Sohbet başlatılsın mı? + No comment provided by engineer. + + + Toggle incognito when connecting. + Bağlanırken gizli moda geçiş yap. + No comment provided by engineer. + + + Tap to scan + Taramak için tıkla + No comment provided by engineer. + + + Verify connections + Bağlantıları doğrula + No comment provided by engineer. + + + The code you scanned is not a SimpleX link QR code. + Taradığınız kod bir SimpleX bağlantı QR kodu değildir. + No comment provided by engineer. + + + Waiting for desktop... + Bilgisayar için bekleniyor... + No comment provided by engineer. + + + You are already joining the group %@. + Zaten %@ grubuna katılıyorsunuz. + No comment provided by engineer. + + + Use only local notifications? + Sadece yerel bildirimler kullanılsın mı? + No comment provided by engineer. + + + Use new incognito profile + Yeni gizli profilden kullan + No comment provided by engineer. + + + This is your own one-time link! + Bu senin kendi tek kullanımlık bağlantın! + No comment provided by engineer. + + + Verify connection + Bağlantıyı doğrula + No comment provided by engineer. + + + Tap to paste link + Bağlantıyı yapıştırmak için tıkla + No comment provided by engineer. + + + This is your own SimpleX address! + Bu senin kendi SimpleX adresin! + No comment provided by engineer. + + + Simplified incognito mode + Basitleştirilmiş gizli mod + No comment provided by engineer. + + + The second tick we missed! ✅ + Özlediğimiz ikinci tik! ✅ + No comment provided by engineer. + + + Unblock + Engeli kaldır + No comment provided by engineer. + + + You are already connecting to %@. + Zaten %@'a bağlanıyorsunuz. + No comment provided by engineer. + + + This device name + Bu cihazın ismi + No comment provided by engineer. + + + Read more in [User Guide](https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode). + [Kullanıcı Rehberi]nde daha fazlasını okuyun(https://simplex.chat/docs/guide/chat-profiles.html#incognito-mode). + No comment provided by engineer. + + + Unlink + Bağlantıyı Kaldır + No comment provided by engineer. + + + Use from desktop + Bilgisayardan kullan + No comment provided by engineer. + + + You are already joining the group! +Repeat join request? + Gruba zaten katılıyorsunuz! +Katılma isteği tekrarlansın mı? + No comment provided by engineer. + + + The text you pasted is not a SimpleX link. + Yapıştırdığın metin bir SimpleX bağlantısı değildir. + No comment provided by engineer. + + + Small groups (max 20) + Küçük gruplar (en fazla 20 kişi) + No comment provided by engineer. + + + Show last messages + Son mesajları göster + No comment provided by engineer. + + + Send direct message to connect + Bağlanmak için doğrudan mesaj gönder + No comment provided by engineer. + + + You have already requested connection via this address! + Bu adres üzerinden zaten bağlantı talebinde bulundunuz! + No comment provided by engineer. + + + You can make it visible to your SimpleX contacts via Settings. + Ayarlardan SimpleX kişilerinize görünür yapabilirsiniz. + No comment provided by engineer. + + + You have already requested connection! +Repeat connection request? + Zaten bağlantı isteğinde bulundunuz! +Bağlantı isteği tekrarlansın mı? + No comment provided by engineer. + + + You can view invitation link again in connection details. + Bağlantı detaylarından davet bağlantısını yeniden görüntüleyebilirsin. + No comment provided by engineer. + + + You will connect to all group members. + Bütün grup üyelerine bağlanacaksın. + No comment provided by engineer. + + + disabled + devre dışı + No comment provided by engineer. + + + You will be connected when group link host's device is online, please wait or check later! + Grup sahibinin cihazı çevrimiçi olduğunda gruba bağlanacaksınız, lütfen bekleyin veya daha sonra kontrol edin! + No comment provided by engineer. + + + connected directly + doğrudan bağlandı + rcv group event chat item + + + Your profile **%@** will be shared. + Profiliniz **%@** paylaşılacaktır. + No comment provided by engineer. + + + send direct message + doğrudan mesaj gönder + No comment provided by engineer. + + + event happened + etkinliği yaşandı + No comment provided by engineer. + + + and %lld other events + ve %lld diğer etkinlikler + No comment provided by engineer. + + + deleted contact + silinmiş kişi + rcv direct event chat item + + + v%@ + v%@ + No comment provided by engineer. + + + You invited a contact + Bir kişiyi davet ettin + No comment provided by engineer. + + + Your profile + Profiliniz + No comment provided by engineer. + + + author + yetkili + member role + + + blocked + engellendi + No comment provided by engineer. + @@ -4975,22 +7054,31 @@ SimpleX servers cannot see your profile. SimpleX Bundle name - + SimpleX needs camera access to scan QR codes to connect to other users and for video calls. + SimpleX, diğer kullanıcılara bağlanmak amacıyla QR kodlarını taramak ve görüntülü aramalar için kamera erişimine ihtiyaç duyar. Privacy - Camera Usage Description - + SimpleX uses Face ID for local authentication + SimpleX yerel kimlik doğrulama için Face ID kullanır Privacy - Face ID Usage Description - + SimpleX needs microphone access for audio and video calls, and to record voice messages. + SimpleX'in sesli ve görüntülü aramalar ve sesli mesajları kaydetmek için mikrofon erişimine ihtiyacı vardır. Privacy - Microphone Usage Description - + SimpleX needs access to Photo Library for saving captured and received media + SimpleX'in çekilen ve alınan medyayı kaydetmek için Fotoğraf Kitaplığı'na erişmesi gerekir Privacy - Photo Library Additions Usage Description + + SimpleX uses local network access to allow using user chat profile via desktop app on the same network. + SimpleX, aynı ağdaki masaüstü uygulaması aracılığıyla kullanıcı sohbet profilinin kullanılmasına izin vermek için yerel ağ erişimini kullanır. + Privacy - Local Network Usage Description + @@ -4998,16 +7086,19 @@ SimpleX servers cannot see your profile. - + SimpleX NSE + SimpleX NSE Bundle display name - + SimpleX NSE + SimpleX NSE Bundle name - + Copyright © 2022 SimpleX Chat. All rights reserved. + Telif Hakkı © 2024 SimpleX Chat. Tüm hakları saklıdır. Copyright (human-readable) 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 2d219440f7..244a728f87 100644 --- a/apps/ios/SimpleX Localizations/uk.xcloc/Localized Contents/uk.xliff +++ b/apps/ios/SimpleX Localizations/uk.xcloc/Localized Contents/uk.xliff @@ -670,9 +670,9 @@ Дозволяйте зникати повідомленням, тільки якщо контакт дозволяє вам це робити. No comment provided by engineer. - - Allow irreversible message deletion only if your contact allows it to you. - Дозволяйте безповоротне видалення повідомлень, тільки якщо контакт дозволяє вам це зробити. + + Allow irreversible message deletion only if your contact allows it to you. (24 hours) + Дозволяйте безповоротне видалення повідомлень, тільки якщо контакт дозволяє вам це зробити. (24 години) No comment provided by engineer. @@ -695,9 +695,9 @@ Дозволити надсилання зникаючих повідомлень. No comment provided by engineer. - - Allow to irreversibly delete sent messages. - Дозволяє безповоротно видаляти надіслані повідомлення. + + Allow to irreversibly delete sent messages. (24 hours) + Дозволяє безповоротно видаляти надіслані повідомлення. (24 години) No comment provided by engineer. @@ -730,9 +730,9 @@ Дозвольте вашим контактам телефонувати вам. No comment provided by engineer. - - Allow your contacts to irreversibly delete sent messages. - Дозвольте вашим контактам безповоротно видаляти надіслані повідомлення. + + Allow your contacts to irreversibly delete sent messages. (24 hours) + Дозвольте вашим контактам безповоротно видаляти надіслані повідомлення. (24 години) No comment provided by engineer. @@ -930,9 +930,9 @@ Реакції на повідомлення можете додавати як ви, так і ваш контакт. No comment provided by engineer. - - Both you and your contact can irreversibly delete sent messages. - І ви, і ваш контакт можете безповоротно видалити надіслані повідомлення. + + Both you and your contact can irreversibly delete sent messages. (24 hours) + І ви, і ваш контакт можете безповоротно видалити надіслані повідомлення. (24 години) No comment provided by engineer. @@ -1904,6 +1904,10 @@ This cannot be undone! Зробіть це пізніше No comment provided by engineer. + + Do not send history to new members. + No comment provided by engineer. + Don't create address Не створювати адресу @@ -2639,9 +2643,9 @@ This cannot be undone! Учасники групи можуть додавати реакції на повідомлення. No comment provided by engineer. - - Group members can irreversibly delete sent messages. - Учасники групи можуть безповоротно видаляти надіслані повідомлення. + + Group members can irreversibly delete sent messages. (24 hours) + Учасники групи можуть безповоротно видаляти надіслані повідомлення. (24 години) No comment provided by engineer. @@ -2749,6 +2753,10 @@ This cannot be undone! Історія No comment provided by engineer. + + History is not sent to new members. + No comment provided by engineer. + How SimpleX works Як працює SimpleX @@ -2948,6 +2956,10 @@ This cannot be undone! Неправильне посилання для підключення No comment provided by engineer. + + Invalid display name! + No comment provided by engineer. + Invalid link No comment provided by engineer. @@ -3607,9 +3619,9 @@ This is your link for group %@! Тільки ви можете додавати реакції на повідомлення. No comment provided by engineer. - - Only you can irreversibly delete messages (your contact can mark them for deletion). - Тільки ви можете безповоротно видалити повідомлення (ваш контакт може позначити їх для видалення). + + Only you can irreversibly delete messages (your contact can mark them for deletion). (24 hours) + Тільки ви можете безповоротно видалити повідомлення (ваш контакт може позначити їх для видалення). (24 години) No comment provided by engineer. @@ -3632,9 +3644,9 @@ This is your link for group %@! Тільки ваш контакт може додавати реакції на повідомлення. No comment provided by engineer. - - Only your contact can irreversibly delete messages (you can mark them for deletion). - Тільки ваш контакт може безповоротно видалити повідомлення (ви можете позначити їх для видалення). + + Only your contact can irreversibly delete messages (you can mark them for deletion). (24 hours) + Тільки ваш контакт може безповоротно видалити повідомлення (ви можете позначити їх для видалення). (24 години) No comment provided by engineer. @@ -4471,6 +4483,10 @@ Error: %@ Надсилайте їх із галереї чи власних клавіатур. No comment provided by engineer. + + Send up to 100 last messages to new members. + No comment provided by engineer. + Sender cancelled file transfer. Відправник скасував передачу файлу. @@ -5083,6 +5099,10 @@ It can happen because of some bug or when the connection is compromised.This device name No comment provided by engineer. + + This display name is invalid. Please choose another name. + No comment provided by engineer. + This group has over %lld members, delivery receipts are not sent. У цій групі більше %lld учасників, підтвердження доставки не надсилаються. @@ -5298,6 +5318,10 @@ To connect, please ask your contact to create another connection link and check Непрочитане No comment provided by engineer. + + Up to 100 last messages are sent to new members. + No comment provided by engineer. + Update Оновлення @@ -5462,6 +5486,10 @@ To connect, please ask your contact to create another connection link and check Переглянути код безпеки No comment provided by engineer. + + Visible history + chat feature + Voice messages Голосові повідомлення 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 60434b1661..911df9701d 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 @@ -656,8 +656,8 @@ 仅当您的联系人允许时才允许限时消息。 No comment provided by engineer. - - Allow irreversible message deletion only if your contact allows it to you. + + Allow irreversible message deletion only if your contact allows it to you. (24 hours) 仅有您的联系人许可后才允许不可撤回消息移除。 No comment provided by engineer. @@ -681,8 +681,8 @@ 允许发送限时消息。 No comment provided by engineer. - - Allow to irreversibly delete sent messages. + + Allow to irreversibly delete sent messages. (24 hours) 允许不可撤回地删除已发送消息。 No comment provided by engineer. @@ -716,8 +716,8 @@ 允许您的联系人给您打电话。 No comment provided by engineer. - - Allow your contacts to irreversibly delete sent messages. + + Allow your contacts to irreversibly delete sent messages. (24 hours) 允许您的联系人不可撤回地删除已发送消息。 No comment provided by engineer. @@ -908,8 +908,8 @@ 您和您的联系人都可以添加消息回应。 No comment provided by engineer. - - Both you and your contact can irreversibly delete sent messages. + + Both you and your contact can irreversibly delete sent messages. (24 hours) 您和您的联系人都可以不可逆转地删除已发送的消息。 No comment provided by engineer. @@ -1874,6 +1874,10 @@ This cannot be undone! 稍后再做 No comment provided by engineer. + + Do not send history to new members. + No comment provided by engineer. + Don't create address 不创建地址 @@ -2614,8 +2618,8 @@ This cannot be undone! 群组成员可以添加信息回应。 No comment provided by engineer. - - Group members can irreversibly delete sent messages. + + Group members can irreversibly delete sent messages. (24 hours) 群组成员可以不可撤回地删除已发送的消息。 No comment provided by engineer. @@ -2724,6 +2728,10 @@ This cannot be undone! 历史记录 No comment provided by engineer. + + History is not sent to new members. + No comment provided by engineer. + How SimpleX works SimpleX的工作原理 @@ -2923,6 +2931,10 @@ This cannot be undone! 无效的连接链接 No comment provided by engineer. + + Invalid display name! + No comment provided by engineer. + Invalid link No comment provided by engineer. @@ -3583,8 +3595,8 @@ This is your link for group %@! 只有您可以添加消息回应。 No comment provided by engineer. - - Only you can irreversibly delete messages (your contact can mark them for deletion). + + Only you can irreversibly delete messages (your contact can mark them for deletion). (24 hours) 只有您可以不可撤回地删除消息(您的联系人可以将它们标记为删除)。 No comment provided by engineer. @@ -3608,8 +3620,8 @@ This is your link for group %@! 只有您的联系人可以添加消息回应。 No comment provided by engineer. - - Only your contact can irreversibly delete messages (you can mark them for deletion). + + Only your contact can irreversibly delete messages (you can mark them for deletion). (24 hours) 只有您的联系人才能不可撤回地删除消息(您可以将它们标记为删除)。 No comment provided by engineer. @@ -4449,6 +4461,10 @@ Error: %@ 发送它们来自图库或自定义键盘。 No comment provided by engineer. + + Send up to 100 last messages to new members. + No comment provided by engineer. + Sender cancelled file transfer. 发送人已取消文件传输。 @@ -5062,6 +5078,10 @@ It can happen because of some bug or when the connection is compromised.This device name No comment provided by engineer. + + This display name is invalid. Please choose another name. + No comment provided by engineer. + This group has over %lld members, delivery receipts are not sent. 该组有超过 %lld 个成员,不发送送货单。 @@ -5278,6 +5298,10 @@ To connect, please ask your contact to create another connection link and check 未读 No comment provided by engineer. + + Up to 100 last messages are sent to new members. + No comment provided by engineer. + Update 更新 @@ -5442,6 +5466,10 @@ To connect, please ask your contact to create another connection link and check 查看安全码 No comment provided by engineer. + + Visible history + chat feature + Voice messages 语音消息 diff --git a/apps/ios/bg.lproj/Localizable.strings b/apps/ios/bg.lproj/Localizable.strings index bf911b55f7..6d18b1a406 100644 --- a/apps/ios/bg.lproj/Localizable.strings +++ b/apps/ios/bg.lproj/Localizable.strings @@ -25,6 +25,9 @@ /* No comment provided by engineer. */ "- more stable message delivery.\n- a bit better groups.\n- and more!" = "- по-стабилна доставка на съобщения.\n- малко по-добри групи.\n- и още!"; +/* No comment provided by engineer. */ +"- optionally notify deleted contacts.\n- profile names with spaces.\n- and more!" = "- по желание уведомете изтритите контакти.\n- имена на профили с интервали.\n- и още!"; + /* No comment provided by engineer. */ "- voice messages up to 5 minutes.\n- custom time to disappear.\n- editing history." = "- гласови съобщения до 5 минути.\n- персонализирано време за изчезване.\n- история на редактиране."; @@ -43,6 +46,12 @@ /* No comment provided by engineer. */ "(" = "("; +/* No comment provided by engineer. */ +"(new)" = "(ново)"; + +/* No comment provided by engineer. */ +"(this device v%@)" = "(това устройство v%@)"; + /* No comment provided by engineer. */ ")" = ")"; @@ -55,11 +64,14 @@ /* No comment provided by engineer. */ "[Star on GitHub](https://github.com/simplex-chat/simplex-chat)" = "[Звезда в GitHub](https://github.com/simplex-chat/simplex-chat)"; +/* No comment provided by engineer. */ +"**Add contact**: to create a new invitation link, or connect via a link you received." = "**Добави контакт**: за създаване на нов линк или свързване чрез получен линк за връзка."; + /* No comment provided by engineer. */ "**Add new contact**: to create your one-time QR Code for your contact." = "**Добави нов контакт**: за да създадете своя еднократен QR код или линк за вашия контакт."; /* No comment provided by engineer. */ -"**Create link / QR code** for your contact to use." = "**Създай линк / QR код**, който вашият контакт да използва."; +"**Create group**: to create a new group." = "**Създай група**: за създаване на нова група."; /* No comment provided by engineer. */ "**e2e encrypted** audio call" = "**e2e криптиран**аудио разговор"; @@ -73,18 +85,12 @@ /* No comment provided by engineer. */ "**Most private**: do not use SimpleX Chat notifications server, check messages periodically in the background (depends on how often you use the app)." = "**Най-поверително**: не използвайте сървъра за известия SimpleX Chat, периодично проверявайте съобщенията във фонов режим (зависи от това колко често използвате приложението)."; -/* No comment provided by engineer. */ -"**Paste received link** or open it in the browser and tap **Open in mobile app**." = "**Поставете получения линк** или го отворете в браузъра и докоснете **Отваряне в мобилно приложение**."; - /* No comment provided by engineer. */ "**Please note**: you will NOT be able to recover or change passphrase if you lose it." = "**Моля, обърнете внимание**: НЯМА да можете да възстановите или промените паролата, ако я загубите."; /* No comment provided by engineer. */ "**Recommended**: device token and notifications are sent to SimpleX Chat notification server, but not the message content, size or who it is from." = "**Препоръчително**: токенът на устройството и известията се изпращат до сървъра за уведомяване на SimpleX Chat, но не и съдържанието, размерът на съобщението или от кого е."; -/* No comment provided by engineer. */ -"**Scan QR code**: to connect to your contact in person or via video call." = "**Сканирай QR код**: за да се свържете с вашия контакт лично или чрез видеообаждане."; - /* No comment provided by engineer. */ "**Warning**: Instant push notifications require passphrase saved in Keychain." = "**Внимание**: Незабавните push известия изискват парола, запазена в Keychain."; @@ -118,12 +124,18 @@ /* No comment provided by engineer. */ "%@ %@" = "%@ %@"; +/* No comment provided by engineer. */ +"%@ and %@" = "%@ и %@"; + /* No comment provided by engineer. */ "%@ and %@ connected" = "%@ и %@ са свързани"; /* copied message info, at