Compare commits

..

258 Commits

Author SHA1 Message Date
shum 4e5ee981e5 Revert "ui: comment smp proxy ui (#4204)"
This reverts commit a0d6ae15ab.
2024-05-21 14:04:40 +00:00
Evgeny Poberezkin c59eb06b8a 5.8-beta.2: ios 218, android 210, desktop 47 2024-05-20 21:23:40 +01:00
Evgeny Poberezkin 423fc96638 core: 5.8.0.2 (simplexmq 5.8.0.2) 2024-05-20 18:38:46 +01:00
spaced4ndy ba203faad4 android: check known relays before file reception, support user approval of unknown relays (#4196) 2024-05-20 17:58:30 +04:00
spaced4ndy ec7b35adb9 ios: check known relays before file reception, support user approval of unknown relays (#4044)
* ios: check known relays before file reception, support user approval of unknown relays

* add privacyAskToApproveRelays to AppSettings

* less text

* ui improvements, fixes

* fix ntf

* shorter alert

* simplify settings

* rename

* icon

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-05-20 17:49:19 +04:00
spaced4ndy d2d450d1d7 core: check known relays before file reception, support user approval of unknown relays (#4043)
* core: check known relays before file reception, support user approval of unknown relays

* comment

* reset on not approved agent error

* add privacyAskToApproveRelays to AppSettings

* filter distinct servers

* update simplexmq

* remember user_approved_relays

* refactor

* rename

* update simplexmq

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-05-20 17:23:29 +04:00
Evgeny Poberezkin b4caefb17c 5.8-beta.1: ios 217, android 209, desktop 46 2024-05-18 08:20:38 +01:00
Evgeny Poberezkin fd791f3fb8 ios: update core library 2024-05-17 15:54:51 +01:00
Evgeny Poberezkin 0720292ebf core: 5.8.0.1 (simplexmq: 5.8.0.1, faster reconnection when switching networks) 2024-05-17 15:39:58 +01:00
spaced4ndy a0d6ae15ab ui: comment smp proxy ui (#4204) 2024-05-17 16:36:25 +04:00
Evgeny Poberezkin 3e76a2d49c blog: image 2024-05-16 19:47:24 +01:00
Evgeny Poberezkin ed3365bb6d website: fix links 2024-05-16 18:16:00 +01:00
Evgeny Poberezkin b2a8797ed4 blog: Redefining Privacy by Making Hard Choices (#4195)
* blog: Redefining Privacy by Making Hard Choices

* update

* update

* revert

* update

* corrections

Co-authored-by: Esra'a Al Shafei <alshafei@users.noreply.github.com>

* update

---------

Co-authored-by: Esra'a Al Shafei <alshafei@users.noreply.github.com>
2024-05-16 18:02:37 +01:00
spaced4ndy d3e522e169 ui: disable send field for disabled connection (based on authErrCounter) (#4193) 2024-05-16 17:08:31 +04:00
spaced4ndy 49e09ca449 core: contact disabled event (#4194) 2024-05-16 17:08:13 +04:00
spaced4ndy d1dde3d0c8 ui: support message forwarding with custom ttl (#4192) 2024-05-16 14:12:58 +04:00
spaced4ndy ef75eceb40 core: support message forwarding with custom ttl (#4191) 2024-05-16 14:11:55 +04:00
spaced4ndy 96ce59f330 multiplatform: SMP proxy configuration buttons (#4188)
* multiplatform: SMP proxy configuration buttons

* fix

* icons

* icon

* icon
2024-05-15 20:09:51 +01:00
spaced4ndy 98a67fa2e4 multiplatform: SMP proxy support (#4179)
* android: SMP proxy support

* android types

* show in meta

* reserve

* remove comment

* texts
2024-05-15 13:56:29 +01:00
spaced4ndy 4b13512950 ios: SMP proxy support (#4178)
* ios: SMP proxy support

* statuses

* group statuses

* error texts

* update

* change icon

* texts

* texts

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-05-15 13:09:42 +01:00
spaced4ndy 4c0d47bbd4 core: message statuses for sending proxies (#4161)
* core: delivery path

* update simplexmq

* via proxy snd flags

* error statuses

* rework errors

* proxy expired errors

* corrections

* move backwards compatibile parser to new type

* update simplexmq

* names

* refactor, style

* simplexmq

* refactor

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-05-15 12:30:05 +01:00
Evgeny Poberezkin 3129602a78 Merge branch 'stable' 2024-05-15 11:44:22 +01:00
Stanislav Dmitrenko a0c257962e android, desktop: fix file menu and icon (#4185)
* android, desktop: fix file menu and icon

* simplify

* space
2024-05-15 11:43:20 +01:00
Evgeny Poberezkin 93ae1145bc core: update simplexmq (use MVar for better DB connection concurrency) (#4183)
* core: update simplexmq (use MVar for better DB connection concurrency)

* focus failing tests

* add timeouts to test

* fix tests

* more delays

* increase timeouts

* prints

* delay

* delay

* empty

* more delays

* enable all

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2024-05-15 11:16:38 +01:00
Evgeny Poberezkin d02668386f directory: debug logging (#4104) 2024-05-14 21:32:53 +01:00
M. Sarmad Qadeer bd8c8b5a8c web: fix the links of faq & some other (#4144)
* web: fix the links of faq & some other

* web: fix links

* web: update .eleventy.js to fix links

* web: fix some links and improve the logic

* web: fix links & improve the logic

* remove semicolon

* update links

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-05-14 19:59:51 +01:00
Evgeny Poberezkin e359ec02f5 5.8-beta.0: ios 216, android 208, desktop 45 2024-05-13 23:34:14 +01:00
Evgeny Poberezkin a1948d549b ios: update core library 2024-05-13 22:24:10 +01:00
Evgeny Poberezkin 396b73b480 core: 5.8.0.0 2024-05-13 21:13:07 +01:00
Evgeny Poberezkin 331b4633fc core: platform independent encoding for delete command (#4176) 2024-05-13 20:39:13 +01:00
Evgeny Poberezkin 29db2b4e9b core: command to show duplicate message count (#4172)
* core: command to show duplicate message count

* update

* updated

* update

* update

* simplexmq
2024-05-13 19:55:57 +01:00
spaced4ndy f091384aa7 ui: apply model updates only for active user for switch and ratchet sync events (#4175) 2024-05-13 17:25:24 +01:00
spaced4ndy f40ba6f04d core: api to differentiate contacts and conversations (#4111) 2024-05-13 16:51:54 +04:00
Evgeny Poberezkin 06d61ea73e core: update simplexmq 2024-05-13 08:19:40 +01:00
Evgeny Poberezkin 84d7a77a9f core: update simplexmq (better subscription management) (#4131)
* core: update simplexmq (better subscription management)

* ui: update settings

* update simplexmq

* simplexmq

* simplexmq

* test output

* delay

* disable test
2024-05-13 08:04:12 +01:00
Evgeny Poberezkin 878eea774d core: save app themes as map with any text key (#4159)
* core: save app themes as map with any text key

* remove theme preset name

* list of themes

* theme id

* theme IDs

* moar

* colors

* default to dark

* fix
2024-05-12 23:35:14 +01:00
Narasimha-sc 4575dc6e30 langs: change 1-2 days to several days on fdroid (#4170) 2024-05-12 18:19:27 +01:00
Evgeny Poberezkin 554ef4eefc 5.7.3: ios 215, android 206, desktop 44 2024-05-12 11:36:30 +01:00
Evgeny Poberezkin 567e9981be core: 5.7.3.0 2024-05-11 23:48:39 +01:00
Evgeny Poberezkin 1183fe427f Merge branch 'stable' 2024-05-10 20:30:42 +01:00
Evgeny Poberezkin c49a1f42e7 5.7.2: ios 214, android 204, desktop 43 2024-05-10 18:32:07 +01:00
Narasimha-sc 4f173215c6 docs: fix broken simplex group invite links (#4155)
* Fix non-working #simplex-devs invite

* Fix #simplex-devs link in pl

* replace SimpleX-Group-2

* replace simplex-group-2 link

* Update README.md
2024-05-10 17:43:06 +01:00
Evgeny Poberezkin 41597e563e website: translations (#4165)
* Translated using Weblate (French)

Currently translated at 100.0% (257 of 257 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/fr/

* Translated using Weblate (Czech)

Currently translated at 98.0% (252 of 257 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/cs/

* Translated using Weblate (Russian)

Currently translated at 99.6% (256 of 257 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/ru/

* Translated using Weblate (French)

Currently translated at 100.0% (257 of 257 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/fr/

* Translated using Weblate (Czech)

Currently translated at 98.0% (252 of 257 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/cs/

* Translated using Weblate (Russian)

Currently translated at 99.6% (256 of 257 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/ru/

---------

Co-authored-by: J'informatique <hello@jinformatique.net>
Co-authored-by: zenobit <zen@osowoso.xyz>
Co-authored-by: link2xt <link2xt@testrun.org>
2024-05-10 17:39:51 +01:00
Evgeny Poberezkin aa127f0cea ui: translations (#4164)
* Translated using Weblate (Japanese)

Currently translated at 100.0% (1741 of 1741 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 100.0% (1515 of 1515 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% (1741 of 1741 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% (1741 of 1741 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Persian)

Currently translated at 25.3% (441 of 1741 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fa/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1515 of 1515 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Vietnamese)

Currently translated at 10.1% (176 of 1741 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/vi/

* Translated using Weblate (Persian)

Currently translated at 26.8% (467 of 1741 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fa/

* Translated using Weblate (Persian)

Currently translated at 33.6% (586 of 1741 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fa/

* Translated using Weblate (Romanian)

Currently translated at 6.0% (105 of 1741 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ro/

* Translated using Weblate (Persian)

Currently translated at 36.8% (642 of 1741 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fa/

* Translated using Weblate (Romanian)

Currently translated at 9.1% (159 of 1741 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ro/

* Translated using Weblate (Persian)

Currently translated at 39.0% (679 of 1741 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fa/

* Translated using Weblate (Persian)

Currently translated at 39.0% (680 of 1741 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fa/

* import/export localizations

---------

Co-authored-by: Miyu Sakatsuki <miyu-sakatsuki@outlook.jp>
Co-authored-by: z0rden <kaanpeker196@gmail.com>
Co-authored-by: summoner001 <summoner@vivaldi.net>
Co-authored-by: Siavash <ciavash@proton.me>
Co-authored-by: tuananh-ng <158744840+tuananh-ng@users.noreply.github.com>
Co-authored-by: Flavian <3zorro.1@gmail.com>
2024-05-10 17:38:42 +01:00
Evgeny Poberezkin f9c64ba39c ios: update core library 2024-05-10 17:22:39 +01:00
Evgeny Poberezkin 1025fa94a1 core: 5.7.2.0 (simplexmq 5.7.3.0: update protocol versions, fix file downloads) 2024-05-10 15:18:42 +01:00
Stanislav Dmitrenko a59769b91d android, desktop: fix crash in contact preferences when updating user profile (#4158) 2024-05-10 09:45:44 +01:00
spaced4ndy 76248b4878 core: on receive set file crypto args only for new files (#4152) 2024-05-09 15:40:23 +04:00
Stanislav Dmitrenko 93a7ddb128 android, desktop: fix presenting large images (#4139)
* android, desktop: fix presenting large images

* 4320 px limitation

* revert line

* onClick

* onClick
2024-05-09 10:39:49 +01:00
Evgeny Poberezkin bc5af35a3e core: wallpapers api (#4110)
* core: wallpapers api

* optional colors

* update

* api

* update

* whitespace

* typo

* test, fix

* fix color parsing

* separate UI and Theme color schemes

* update

* enable test

* multiple themes, one per color scheme

* theme overrides as a separate type

* rename

---------

Co-authored-by: Avently <7953703+avently@users.noreply.github.com>
2024-05-08 15:36:20 +01:00
Evgeny Poberezkin e38d5bd885 core: update simplexmq (upgrade client protocol versions SMP v7, NTF v2) 2024-05-08 13:40:25 +01:00
M. Sarmad Qadeer 10f41aa1c9 web: add scroll to navbar (#4100)
* web: add scroll to navbar

* web: add scroll to whole navbar instead of scrolling the opened menu
2024-05-08 09:31:02 +01:00
spaced4ndy 1b081197d4 multiplatform: add error to response (#4140) 2024-05-06 20:27:35 +04:00
M. Sarmad Qadeer 9615e525c0 web: fix list numbering for safari (#4106)
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-05-06 08:36:13 +01:00
M. Sarmad Qadeer db136116d3 web: make image of full width for mobile screen (#4101) 2024-05-06 08:31:34 +01:00
Evgeny Poberezkin 98f5e5d22b 5.7.1: ios 213, android 202, desktop 42 2024-05-05 21:01:57 +01:00
Evgeny Poberezkin 9f33e5d35e website: translations (#4136)
* Translated using Weblate (German)

Currently translated at 100.0% (257 of 257 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/de/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (257 of 257 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/nl/

* Translated using Weblate (Arabic)

Currently translated at 100.0% (257 of 257 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/ar/

* Translated using Weblate (Italian)

Currently translated at 100.0% (257 of 257 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/it/

* Translated using Weblate (Polish)

Currently translated at 100.0% (257 of 257 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/pl/

* Translated using Weblate (German)

Currently translated at 100.0% (257 of 257 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/de/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (257 of 257 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/nl/

* Translated using Weblate (Arabic)

Currently translated at 100.0% (257 of 257 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/ar/

* Translated using Weblate (Italian)

Currently translated at 100.0% (257 of 257 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/it/

* Translated using Weblate (Polish)

Currently translated at 100.0% (257 of 257 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/pl/

* Translated using Weblate (Arabic)

Currently translated at 100.0% (257 of 257 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% (257 of 257 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% (257 of 257 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/ja/

---------

Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: B.O.S.S <BxOxSxS@protonmail.com>
Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Co-authored-by: Miyu Sakatsuki <miyu-sakatsuki@outlook.jp>
2024-05-05 19:00:16 +01:00
Evgeny Poberezkin b8e8124faf ui: translations (#4135)
* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1515 of 1515 strings)

Translated using Weblate (Hungarian)

Currently translated at 100.0% (1741 of 1741 strings)

Co-authored-by: summoner001 <summoner@vivaldi.net>
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/
Translation: SimpleX Chat/SimpleX Chat Android
Translation: SimpleX Chat/SimpleX Chat iOS

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1515 of 1515 strings)

Translated using Weblate (Hungarian)

Currently translated at 100.0% (1741 of 1741 strings)

Co-authored-by: Ghost of Sparta <makesocialfoss32@keemail.me>
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/
Translation: SimpleX Chat/SimpleX Chat Android
Translation: SimpleX Chat/SimpleX Chat iOS

* Translated using Weblate (Polish)

Currently translated at 100.0% (1515 of 1515 strings)

Translated using Weblate (Polish)

Currently translated at 99.9% (1740 of 1741 strings)

Translated using Weblate (Polish)

Currently translated at 99.1% (1727 of 1741 strings)

Co-authored-by: B.O.S.S <BxOxSxS@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/pl/
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/pl/
Translation: SimpleX Chat/SimpleX Chat Android
Translation: SimpleX Chat/SimpleX Chat iOS

* Translated using Weblate (German)

Currently translated at 100.0% (1515 of 1515 strings)

Translated using Weblate (German)

Currently translated at 100.0% (1741 of 1741 strings)

Co-authored-by: mlanp <github@lang.xyz>
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/de/
Translation: SimpleX Chat/SimpleX Chat Android
Translation: SimpleX Chat/SimpleX Chat iOS

* Translated using Weblate (Italian)

Currently translated at 100.0% (1515 of 1515 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (1741 of 1741 strings)

Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/it/
Translation: SimpleX Chat/SimpleX Chat Android
Translation: SimpleX Chat/SimpleX Chat iOS

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1515 of 1515 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (1741 of 1741 strings)

Co-authored-by: No name <CertainBot@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/es/
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/
Translation: SimpleX Chat/SimpleX Chat Android
Translation: SimpleX Chat/SimpleX Chat iOS

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1515 of 1515 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (1741 of 1741 strings)

Co-authored-by: M1K4 <oomikaoo@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/
Translation: SimpleX Chat/SimpleX Chat Android
Translation: SimpleX Chat/SimpleX Chat iOS

* Translated using Weblate (Arabic)

Currently translated at 100.0% (1741 of 1741 strings)

Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/
Translation: SimpleX Chat/SimpleX Chat Android

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1741 of 1741 strings)

Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/
Translation: SimpleX Chat/SimpleX Chat Android

* Translated using Weblate (Japanese)

Currently translated at 100.0% (1741 of 1741 strings)

Co-authored-by: Miyu Sakatsuki <miyu-sakatsuki@outlook.jp>
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ja/
Translation: SimpleX Chat/SimpleX Chat Android

* Translated using Weblate (Czech)

Currently translated at 98.1% (1709 of 1741 strings)

Co-authored-by: zenobit <zen@osowoso.xyz>
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/cs/
Translation: SimpleX Chat/SimpleX Chat Android

* Translated using Weblate (Bulgarian)

Currently translated at 100.0% (1741 of 1741 strings)

Translated using Weblate (Bulgarian)

Currently translated at 100.0% (1515 of 1515 strings)

Co-authored-by: elgratea <weblate@fastmail.com>
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/bg/
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/bg/
Translation: SimpleX Chat/SimpleX Chat Android
Translation: SimpleX Chat/SimpleX Chat iOS

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1741 of 1741 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (1515 of 1515 strings)

Co-authored-by: z0rden <kaanpeker196@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/tr/
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/tr/
Translation: SimpleX Chat/SimpleX Chat Android
Translation: SimpleX Chat/SimpleX Chat iOS

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1515 of 1515 strings)

Translated using Weblate (Hungarian)

Currently translated at 100.0% (1741 of 1741 strings)

Translated using Weblate (Hungarian)

Currently translated at 100.0% (1515 of 1515 strings)

Translated using Weblate (Hungarian)

Currently translated at 100.0% (1741 of 1741 strings)

Translated using Weblate (Hungarian)

Currently translated at 100.0% (1515 of 1515 strings)

Translated using Weblate (Hungarian)

Currently translated at 100.0% (1741 of 1741 strings)

Co-authored-by: summoner001 <summoner@vivaldi.net>
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/
Translation: SimpleX Chat/SimpleX Chat Android
Translation: SimpleX Chat/SimpleX Chat iOS

* Translated using Weblate (Japanese)

Currently translated at 80.7% (1224 of 1515 strings)

Translated using Weblate (Japanese)

Currently translated at 80.3% (1218 of 1515 strings)

Co-authored-by: koreirozzu <trueworldfacts+asjfsajfhajfh@proton.me>
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ja/
Translation: SimpleX Chat/SimpleX Chat iOS

* Translated using Weblate (Japanese)

Currently translated at 80.3% (1218 of 1515 strings)

Co-authored-by: a4318 <dalse.077@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ja/
Translation: SimpleX Chat/SimpleX Chat iOS

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1515 of 1515 strings)

Co-authored-by: xe1st <dnzkckali@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/tr/
Translation: SimpleX Chat/SimpleX Chat iOS

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1741 of 1741 strings)

Co-authored-by: J R <jr@simplex.chat>
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/tr/
Translation: SimpleX Chat/SimpleX Chat Android

* Translated using Weblate (Persian)

Currently translated at 9.8% (171 of 1741 strings)

Translated using Weblate (Persian)

Currently translated at 9.4% (164 of 1741 strings)

Co-authored-by: Siavash <ciavash@proton.me>
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fa/
Translation: SimpleX Chat/SimpleX Chat Android

* Translated using Weblate (Persian)

Currently translated at 10.1% (176 of 1741 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fa/

* Translated using Weblate (French)

Currently translated at 100.0% (1741 of 1741 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% (1515 of 1515 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/fr/

* Translated using Weblate (Persian)

Currently translated at 11.9% (208 of 1741 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fa/

* Translated using Weblate (Vietnamese)

Currently translated at 8.5% (148 of 1741 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/vi/

* import/export localizations

* tr revert

---------

Co-authored-by: summoner001 <summoner@vivaldi.net>
Co-authored-by: Ghost of Sparta <makesocialfoss32@keemail.me>
Co-authored-by: B.O.S.S <BxOxSxS@protonmail.com>
Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: No name <CertainBot@users.noreply.hosted.weblate.org>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Co-authored-by: Miyu Sakatsuki <miyu-sakatsuki@outlook.jp>
Co-authored-by: zenobit <zen@osowoso.xyz>
Co-authored-by: elgratea <weblate@fastmail.com>
Co-authored-by: z0rden <kaanpeker196@gmail.com>
Co-authored-by: koreirozzu <trueworldfacts+asjfsajfhajfh@proton.me>
Co-authored-by: a4318 <dalse.077@gmail.com>
Co-authored-by: xe1st <dnzkckali@gmail.com>
Co-authored-by: J R <jr@simplex.chat>
Co-authored-by: Siavash <ciavash@proton.me>
Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com>
Co-authored-by: tuananh-ng <158744840+tuananh-ng@users.noreply.github.com>
2024-05-05 18:57:52 +01:00
Evgeny Poberezkin 156e41950a ios: update library 2024-05-05 18:01:14 +01:00
Evgeny Poberezkin 26c5ed4caf core: 5.7.1.0 (simplexmq 5.7.2.0: reduce "ping" traffic, remove TLS timeouts) 2024-05-05 17:43:09 +01:00
Evgeny Poberezkin d832afa7e8 docs: calls without e2e encryption (#4134) 2024-05-05 16:56:34 +01:00
Stanislav Dmitrenko 2e18b97077 android: enable Android 8 support (API 26) (#4132) 2024-05-05 16:30:17 +01:00
Evgeny Poberezkin b6e57c0fa2 core: fix connection failure because of race condition when connecting via link or joining group via invitation (#4133)
* core: fix connection failure because of race condition when connecting via link or joining group via invitation

* fix race for connection via contact address

* simplexmq
2024-05-05 13:11:30 +01:00
spaced4ndy 15a226cfd1 ui: limit length of member names in chat view (#4122) 2024-05-03 12:34:15 +01:00
Evgeny Poberezkin c4cbf751b9 Merge branch 'stable' 2024-05-02 23:28:59 +01:00
Stanislav Dmitrenko 535ff1d836 actions: add macos aarch64 build and fix openssl include path (#4107) 2024-05-02 21:41:15 +01:00
Evgeny Poberezkin fb0718adac core: forward agent errors without connections to UI (to show CRITICAL alerts) (#4120) 2024-05-02 21:40:08 +01:00
Stanislav Dmitrenko 5f501f1cb9 android, desktop: fix android video calls (#4118) 2024-05-02 16:47:52 +01:00
Evgeny Poberezkin 7cc86574fe core: update simplexmq to 5.7.1.0 2024-05-02 16:43:08 +01:00
Evgeny Poberezkin 19fc44efae rfc: commercial model for infrastructure operators (#4102) 2024-04-30 07:53:27 +01:00
spaced4ndy 37e03a838c core: forward group message before ack (fixes forwarding message that deleted connection causing error in ackMsg) (#4108) 2024-04-29 19:49:04 +04:00
spaced4ndy aeb28400e9 core: take entity lock before processing file (#4105) 2024-04-29 19:32:53 +04:00
sh d5a0c5e56a scripts/build-android: update nix and refactor (#4099) 2024-04-27 09:23:14 +01:00
Evgeny Poberezkin a28d965a65 website: fix privacy page 2024-04-26 23:24:54 +01:00
Evgeny Poberezkin 9148425eba blog: legally binding transparency, v5.7 announcement (#4097)
* blog: legally binding transparency, v5.7 announcement

* update

* update, images

* readme

* update
2024-04-26 23:06:40 +01:00
M. Sarmad Qadeer 406c35958e web: add privacy page to website (#4096)
* web: add privacy page to website

* web: fix a blog frontmatter

* web: fix privacy link from other docs

* update

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-04-26 23:00:49 +01:00
Evgeny Poberezkin be9ae61a32 5.7: ios 212, android 200, desktop 41 2024-04-26 20:59:21 +01:00
Stanislav Dmitrenko 9db65a1775 ios: audio device picker (#4091)
* ios: audio device picker

* removed unused

* removed logs

* correct routing

* Revert "removed unused"

This reverts commit d883d7a719.

* changes

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-04-26 19:59:00 +01:00
Evgeny Poberezkin 1033f55597 ios: fix sound in outgoing calls in iOS 15 2024-04-26 19:41:44 +01:00
Stanislav Dmitrenko 7f2462c936 android: black background in call (#4098) 2024-04-26 18:31:52 +01:00
Evgeny Poberezkin e675efe6f3 ios: update library 2024-04-26 17:38:57 +01:00
Evgeny Poberezkin b3f8068446 core: 5.7.0.5, increase min version of remote host/controller to 5.7.0.3 2024-04-26 15:42:13 +01:00
Evgeny Poberezkin 957eda8a78 ui: variable profile image size (#4094)
* ui: variable profile image size

* changes

* fix

* clean up

---------

Co-authored-by: Avently <7953703+avently@users.noreply.github.com>
2024-04-25 22:09:06 +01:00
Evgeny Poberezkin 0fe949e225 5.7-beta.3: ios 210, android 199, desktop 40 2024-04-25 15:51:23 +01:00
Evgeny Poberezkin 5325b0a543 core: update simplexmq to 5.7.0.3 2024-04-25 13:40:06 +01:00
Evgeny Poberezkin f712eb0d1f ui: add link to the release post 2024-04-25 13:16:49 +01:00
spaced4ndy fc6fa5315b android: show disappearing message timer on calls and group invitations (#4090)
* android: show disappearing message timer on calls and group invitations

* fix padding
2024-04-25 12:15:52 +01:00
Evgeny Poberezkin 3eb88ab896 5.7.0.4 (simplexmq 5.7.0.3) 2024-04-25 11:15:28 +01:00
Alexander Bondarenko 20fa366231 core: use contextless decompression (#4089)
* core: use contextless decompression

* fuse concatMap/map

* nix

* update simplexmq

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-04-25 10:52:26 +01:00
Evgeny Poberezkin db05436e50 Merge branch 'stable' 2024-04-25 10:42:28 +01:00
Evgeny Poberezkin a1093b0671 docs: update privacy policy (#4076) 2024-04-25 10:41:27 +01:00
spaced4ndy 6a8a8f242a ui: allow to delete any items (#4082)
* ios: allow to delete any items

* android

* remove button android

* remove button ios
2024-04-25 10:20:52 +01:00
spaced4ndy 1163fe7b56 ios: show disappearing message timer on calls and group invitations (#4086) 2024-04-25 12:41:20 +04:00
spaced4ndy 063a6dbc92 core: apply disappearing messages setting to call and group invitation chat items (#4080)
* core: apply disappearing messages setting to call and group invitation chat items

* remove comment

* fix incorrectly set edited field

* sent group invitations

* refactor

* Revert "refactor"

This reverts commit 4dd3070c2d.
2024-04-25 09:37:05 +01:00
Stanislav Dmitrenko 9e2a3fe848 android, desktop: more relaxed way of showing alerts for encryption/decryption errors (#4085) 2024-04-24 21:39:59 +01:00
Stanislav Dmitrenko 2b7f3099a6 android, desktop: customizable profile images (#4087)
* android, desktop: customizable profile images

* better

* fixes

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-04-24 21:22:52 +01:00
Evgeny Poberezkin cfa7e0bb28 ios: customizable profile images (#4084)
* ios: customizable profile images

* update slider

* whats new
2024-04-24 21:20:26 +01:00
Evgeny Poberezkin 1967ac0880 ui: translations (#4079)
* Translated using Weblate (German)

Currently translated at 100.0% (1738 of 1738 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 100.0% (1738 of 1738 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% (1512 of 1512 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/de/

* Translated using Weblate (Russian)

Currently translated at 100.0% (1512 of 1512 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ru/

* update

---------

Co-authored-by: mlanp <github@lang.xyz>
2024-04-24 14:42:17 +01:00
Stanislav Dmitrenko 68966a1551 android, desktop: alert for local encryption/decryption errors (#4081)
* android, desktop: more alert in case of local encryption/decryption errors

* sending a message without a file
2024-04-24 14:39:06 +01:00
Evgeny Poberezkin 5ba7b58d7d website: translations (#4078)
* Translated using Weblate (German)

Currently translated at 100.0% (257 of 257 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/de/

* Translated using Weblate (Japanese)

Currently translated at 100.0% (257 of 257 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/ja/

---------

Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: Miyu Sakatsuki <miyu-sakatsuki@outlook.jp>
2024-04-24 12:45:20 +01:00
Evgeny Poberezkin 9979983742 ui: translations (#4075)
* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1507 of 1507 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* ios: Hungarian translations

* Translated using Weblate (German)

Currently translated at 99.5% (1730 of 1738 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1738 of 1738 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% (1512 of 1512 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% (1738 of 1738 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% (1512 of 1512 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/

* Translated using Weblate (Lithuanian)

Currently translated at 100.0% (1738 of 1738 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/lt/

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1512 of 1512 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% (1738 of 1738 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% (1512 of 1512 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* import/export

---------

Co-authored-by: summoner001 <summoner@vivaldi.net>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: No name <CertainBot@users.noreply.hosted.weblate.org>
Co-authored-by: Anonimas <Anonimas3@users.noreply.hosted.weblate.org>
Co-authored-by: z0rden <kaanpeker196@gmail.com>
2024-04-24 09:44:44 +01:00
Evgeny Poberezkin ab76e93df7 docs: security policy (#4068)
* docs: security policy

* update

* add to website
2024-04-23 19:30:42 +01:00
Evgeny Poberezkin f30287c4df docs: FAQ (#4013)
* Addd FAQ.md (#3814)

* faq

* typos

* add troubleshooting

* update links

---------

Co-authored-by: ungespurv <87089788+ungespurv@users.noreply.github.com>
2024-04-23 19:19:51 +01:00
Evgeny Poberezkin 2807e53d4c ui: traslations (#4070)
* Translated using Weblate (Dutch)

Currently translated at 99.9% (1728 of 1729 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 99.9% (1506 of 1507 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/

* Translated using Weblate (Arabic)

Currently translated at 100.0% (1729 of 1729 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 100.0% (1729 of 1729 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% (1507 of 1507 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (German)

Currently translated at 100.0% (1730 of 1730 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% (1507 of 1507 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% (1730 of 1730 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% (1507 of 1507 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/it/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1730 of 1730 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Romanian)

Currently translated at 5.1% (89 of 1730 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ro/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 99.8% (1736 of 1738 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 80.8% (1218 of 1507 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 100.0% (1738 of 1738 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ja/

* Translated using Weblate (Lithuanian)

Currently translated at 98.5% (1713 of 1738 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/lt/

* Translated using Weblate (Bulgarian)

Currently translated at 100.0% (1507 of 1507 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% (1738 of 1738 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% (1738 of 1738 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% (1738 of 1738 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Romanian)

Currently translated at 5.3% (93 of 1738 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ro/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1507 of 1507 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1738 of 1738 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/

* Translated using Weblate (Lithuanian)

Currently translated at 98.8% (1718 of 1738 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/lt/

* Translated using Weblate (Romanian)

Currently translated at 5.4% (94 of 1738 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ro/

* import/export localizations

---------

Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: summoner001 <summoner@vivaldi.net>
Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: Ghost of Sparta <makesocialfoss32@keemail.me>
Co-authored-by: Flavian <3zorro.1@gmail.com>
Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Co-authored-by: yokoba0413 <yokoba0413@gmail.com>
Co-authored-by: Anonimas <Anonimas3@users.noreply.hosted.weblate.org>
Co-authored-by: elgratea <weblate@fastmail.com>
2024-04-23 19:16:12 +01:00
Stanislav Dmitrenko 642e6d677e android, desktop: updating delivery tab in chat item info (#4074) 2024-04-23 19:14:58 +01:00
Stanislav Dmitrenko 944a0b3aad android: longer delay before showing keyboard when creating a group (#4073) 2024-04-23 19:14:35 +01:00
Stanislav Dmitrenko e5ac472da3 android, desktop: restore message TTL in database settings if confirmation is dismissed (#4072) 2024-04-23 18:51:04 +01:00
Stanislav Dmitrenko 2f79bfb075 android: current audio device will be set in init step (#4071) 2024-04-23 18:47:15 +01:00
Evgeny Poberezkin ae9e63d1be ios: export localizations 2024-04-23 09:59:16 +01:00
Evgeny Poberezkin d864603d01 website: do not build from stable 2024-04-23 00:14:02 +01:00
Evgeny Poberezkin 06ac15b282 5.7-beta.2: ios 209, android 198, desktop 39 2024-04-23 00:11:37 +01:00
Stanislav Dmitrenko 4c1dfc76d4 android: sound from speaker fix (#4067) 2024-04-22 23:26:01 +01:00
Evgeny Poberezkin bea19f76e9 5.7.0.3 (simplexmq 5.7.0.2) 2024-04-22 22:24:00 +01:00
Stanislav Dmitrenko f80ac6dc50 android: proper hiding keyboard when entering passcode (#4066) 2024-04-22 22:13:14 +01:00
spaced4ndy 2b6764fc36 android: 5.7 what's new (#4064)
* android: 5.7 what's new

* icon

* update LT language name

* Lithuanian

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-04-22 22:03:18 +01:00
Esra'a Al Shafei 7c74f02d01 docs: typo in simplex-chat.md (#4037)
typo fix
2024-04-22 18:26:41 +01:00
Stanislav Dmitrenko d53aa69691 android: managing audio sources in call in a better way (#4063) 2024-04-22 18:24:26 +01:00
spaced4ndy 9e3f528d44 android: remove experimental PQ toggle (#4060) 2024-04-22 17:50:52 +01:00
spaced4ndy 22fd2d7189 ios: remove experimental PQ toggle (#4051)
* ios: remove experimental PQ toggle

* remove header
2024-04-22 17:50:28 +01:00
spaced4ndy 7567791866 core: enable PQ encryption for contacts (#4049)
* wip

* migration

* remove migration

* remove flag wip

* Revert "remove migration"

This reverts commit 9e64663f9d.

* wip

* remove vrange parameterization

* tests mostly pass

* more tests pass

* enable for upgraded contacts

* remove migration

* core: test large messages (#4061)

* update simplexmq, fix tests

* test test

* another test

* enable tests

* empty

* empty
2024-04-22 17:46:48 +01:00
spaced4ndy 529ba7a0e7 ios: 5.7 what's new (#4062)
* ios: 5.7 what's new

* add about pq

* update

* update

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-04-22 17:46:14 +01:00
Evgeny Poberezkin 3b3a68da15 core: 5.7.0.2 2024-04-22 08:07:42 +01:00
Evgeny Poberezkin e0e94d78b0 core, ui: revert timeout changes (#4059)
* core, ui: revert timeout changes

* update core library
2024-04-22 07:45:20 +01:00
Evgeny Poberezkin d68369b32a android, desktop: add Lithuanian language 2024-04-21 20:37:14 +01:00
Evgeny Poberezkin d29886dbd2 ui: translations (#4056)
* Translated using Weblate (French)

Currently translated at 100.0% (1696 of 1696 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.8% (1693 of 1696 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/es/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1696 of 1696 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1696 of 1696 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 95.0% (1405 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (French)

Currently translated at 100.0% (1696 of 1696 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fr/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1696 of 1696 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% (1696 of 1696 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% (1696 of 1696 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% (1478 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/

* Translated using Weblate (Japanese)

Currently translated at 100.0% (1696 of 1696 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ja/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1696 of 1696 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% (1478 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/

* Translated using Weblate (Japanese)

Currently translated at 82.4% (1218 of 1478 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 100.0% (1696 of 1696 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 100.0% (1696 of 1696 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% (1478 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (German)

Currently translated at 100.0% (1696 of 1696 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/

* Translated using Weblate (Portuguese)

Currently translated at 8.0% (119 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/pt/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1696 of 1696 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% (1478 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (German)

Currently translated at 100.0% (1696 of 1696 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% (1478 of 1478 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% (1696 of 1696 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/

* Translated using Weblate (Portuguese)

Currently translated at 10.5% (156 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/pt/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1696 of 1696 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Vietnamese)

Currently translated at 6.3% (108 of 1696 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/vi/

* Translated using Weblate (Portuguese)

Currently translated at 10.6% (157 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/pt/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1696 of 1696 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% (1696 of 1696 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% (1478 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (French)

Currently translated at 100.0% (1696 of 1696 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.8% (1693 of 1696 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/es/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1696 of 1696 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1696 of 1696 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 95.0% (1405 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (French)

Currently translated at 100.0% (1696 of 1696 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fr/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1696 of 1696 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% (1696 of 1696 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% (1696 of 1696 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% (1478 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/

* Translated using Weblate (Japanese)

Currently translated at 100.0% (1696 of 1696 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ja/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1696 of 1696 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% (1478 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/

* Translated using Weblate (Japanese)

Currently translated at 82.4% (1218 of 1478 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 100.0% (1696 of 1696 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 100.0% (1696 of 1696 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% (1478 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (German)

Currently translated at 100.0% (1696 of 1696 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/

* Translated using Weblate (Portuguese)

Currently translated at 8.0% (119 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/pt/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1696 of 1696 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% (1478 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (German)

Currently translated at 100.0% (1696 of 1696 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% (1478 of 1478 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% (1696 of 1696 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/

* Translated using Weblate (Portuguese)

Currently translated at 10.5% (156 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/pt/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1696 of 1696 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Vietnamese)

Currently translated at 6.3% (108 of 1696 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/vi/

* Translated using Weblate (Portuguese)

Currently translated at 10.6% (157 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/pt/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1696 of 1696 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% (1696 of 1696 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% (1478 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (German)

Currently translated at 100.0% (1696 of 1696 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% (1478 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/de/

* Translated using Weblate (Arabic)

Currently translated at 100.0% (1696 of 1696 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/

* Translated using Weblate (Lithuanian)

Currently translated at 64.3% (1091 of 1696 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/lt/

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1696 of 1696 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/tr/

* Translated using Weblate (Lithuanian)

Currently translated at 72.1% (1223 of 1696 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/lt/

* Translated using Weblate (Arabic)

Currently translated at 100.0% (1696 of 1696 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/

* Translated using Weblate (Lithuanian)

Currently translated at 72.4% (1228 of 1696 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/lt/

* Translated using Weblate (Polish)

Currently translated at 99.9% (1695 of 1696 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/pl/

* Translated using Weblate (Lithuanian)

Currently translated at 78.4% (1330 of 1696 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/lt/

* Translated using Weblate (Lithuanian)

Currently translated at 100.0% (1696 of 1696 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/lt/

* Translated using Weblate (Polish)

Currently translated at 99.9% (1695 of 1696 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% (1478 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/pl/

* Translated using Weblate (Vietnamese)

Currently translated at 6.6% (113 of 1696 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/vi/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1702 of 1702 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 100.0% (1702 of 1702 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ru/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1702 of 1702 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/

* Translated using Weblate (Chinese (Traditional))

Currently translated at 71.2% (1213 of 1702 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hant/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1702 of 1702 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% (1478 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Vietnamese)

Currently translated at 7.2% (124 of 1702 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/vi/

* 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 (Dutch)

Currently translated at 100.0% (1703 of 1703 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/

* Translated using Weblate (Japanese)

Currently translated at 99.6% (1697 of 1703 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ja/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1703 of 1703 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% (1703 of 1703 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% (1703 of 1703 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/

* Translated using Weblate (Japanese)

Currently translated at 99.9% (1702 of 1703 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 100.0% (1703 of 1703 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 100.0% (1703 of 1703 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% (1703 of 1703 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% (1478 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1478 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Hungarian)

Currently translated at 99.8% (1712 of 1715 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% (1715 of 1715 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/

* Translated using Weblate (Japanese)

Currently translated at 99.8% (1713 of 1715 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 100.0% (1715 of 1715 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/

* Translated using Weblate (Polish)

Currently translated at 99.9% (1714 of 1715 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/pl/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1715 of 1715 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% (1715 of 1715 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1715 of 1715 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/

* Translated using Weblate (Japanese)

Currently translated at 99.8% (1713 of 1715 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ja/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1715 of 1715 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% (1478 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (French)

Currently translated at 100.0% (1715 of 1715 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% (1715 of 1715 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/

* Translated using Weblate (Polish)

Currently translated at 99.9% (1714 of 1715 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/pl/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1715 of 1715 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% (1478 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Vietnamese)

Currently translated at 7.5% (130 of 1715 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/vi/

* Translated using Weblate (Vietnamese)

Currently translated at 7.8% (135 of 1715 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/vi/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1715 of 1715 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% (1478 of 1478 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% (1715 of 1715 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% (1478 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1715 of 1715 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% (1478 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Italian)

Currently translated at 100.0% (1478 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/it/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1715 of 1715 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% (1478 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/

* Translated using Weblate (Bulgarian)

Currently translated at 99.8% (1712 of 1715 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% (1715 of 1715 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% (1478 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1715 of 1715 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% (1478 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1725 of 1725 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/es/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1725 of 1725 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1725 of 1725 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% (1725 of 1725 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% (1725 of 1725 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% (1725 of 1725 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% (1478 of 1478 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 99.9% (1724 of 1725 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/pl/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1728 of 1728 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* process localizations

* update RU translations

* revert PL changes for "passphrase"

---------

Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com>
Co-authored-by: khalidbelk <khalid.belkassmi-el-hafi@epitech.eu>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: Ghost of Sparta <makesocialfoss32@keemail.me>
Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Co-authored-by: No name <CertainBot@users.noreply.hosted.weblate.org>
Co-authored-by: Miyu Sakatsuki <miyu-sakatsuki@outlook.jp>
Co-authored-by: z0rden <kaanpeker196@gmail.com>
Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: Andre <andrefeliciano@duck.com>
Co-authored-by: summoner001 <summoner@vivaldi.net>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: tuananh-ng <158744840+tuananh-ng@users.noreply.github.com>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: Anonimas <qdq5ih+3ewax7y4esw98@cs.email>
Co-authored-by: B.O.S.S <BxOxSxS@protonmail.com>
Co-authored-by: Anonimas <Anonimas3@users.noreply.hosted.weblate.org>
Co-authored-by: Arturro43 <Arturro43.kontakt@gmail.com>
Co-authored-by: Alex <github@lippiece.anonaddy.me>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Kingpin <radoslav.najdenov@gmail.com>
2024-04-21 20:16:08 +01:00
Evgeny Poberezkin 50d3a29715 website: translations (#4057)
* Translated using Weblate (French)

Currently translated at 100.0% (255 of 255 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/fr/

* Translated using Weblate (German)

Currently translated at 100.0% (255 of 255 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/de/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (255 of 255 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/nl/

* Translated using Weblate (Arabic)

Currently translated at 100.0% (255 of 255 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/ar/

* Translated using Weblate (Italian)

Currently translated at 100.0% (255 of 255 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/it/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (255 of 255 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/es/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (255 of 255 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% (255 of 255 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/ja/

* Translated using Weblate (Russian)

Currently translated at 100.0% (255 of 255 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/ru/

* Translated using Weblate (French)

Currently translated at 100.0% (255 of 255 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/fr/

* Translated using Weblate (German)

Currently translated at 100.0% (255 of 255 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/de/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (255 of 255 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/nl/

* Translated using Weblate (Arabic)

Currently translated at 100.0% (255 of 255 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/ar/

* Translated using Weblate (Italian)

Currently translated at 100.0% (255 of 255 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/it/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (255 of 255 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/es/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (255 of 255 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% (255 of 255 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/ja/

* Translated using Weblate (Russian)

Currently translated at 100.0% (255 of 255 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/ru/

* Translated using Weblate (Bulgarian)

Currently translated at 13.7% (35 of 255 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/bg/

---------

Co-authored-by: khalidbelk <khalid.belkassmi-el-hafi@epitech.eu>
Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Co-authored-by: Miyu Sakatsuki <miyu-sakatsuki@outlook.jp>
Co-authored-by: Alex <github@lippiece.anonaddy.me>
Co-authored-by: Kingpin <radoslav.najdenov@gmail.com>
2024-04-21 11:10:07 +01:00
Evgeny Poberezkin 8e3a713a49 ui: limit max size of events, sort members by role (#4058) 2024-04-21 10:57:54 +01:00
Evgeny Poberezkin 7cec79e79b 5.7-beta.1: ios 208, android 197, desktop 38 2024-04-20 22:07:04 +01:00
Evgeny Poberezkin e9db7e8e58 ios: export translations 2024-04-20 19:57:40 +01:00
Evgeny Poberezkin f53882049f ios: update core library 2024-04-20 19:54:47 +01:00
Evgeny Poberezkin 8f4c9a673a core: 5.7.0.1 2024-04-20 19:39:20 +01:00
Evgeny Poberezkin 02f980e968 core: update simplexmq (better newtork congestion handling, larger connection timeouts) (#4055)
* core: update simplexmq (better newtork congestion handling, larger connection timeouts)

* ui: update default TCP connect timeout, add receiving concurrency

* update simplexmq
2024-04-20 19:35:11 +01:00
Stanislav Dmitrenko 412f75219a android: select audio source (#4040)
* android, desktop: select audio source

* improvements

* fix possible crash

* changes
2024-04-20 19:19:37 +01:00
Evgeny Poberezkin c8c81a840b core: revert build to use two branches (#4052)
* Revert "scripts: ghc version update (#4010)"

This reverts commit 35b7f2cb1c.

* Revert "Force include hs_init_with_rtsopts (#4028)"

This reverts commit 76a33a3743.

* Revert "core: fix nix config (#4003)"

This reverts commit f8e6a78a3b.

* Revert "ci: build armv7a with 8.10.7 in the main branches (master, stable) (#3733)"

This reverts commit 0d7a32877f.
2024-04-19 21:17:22 +01:00
Stanislav Dmitrenko 925cb39397 desktop: using system sound in screenshare (#4035)
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-04-19 17:37:47 +01:00
Stanislav Dmitrenko f6ceb89c4b android, desktop: forward ui (#4039)
* android, desktop: forward ui

* changes

* attachment icon

* reorder lines

* reorder lines

* change

* inline content + formatted text

* fix header padding

* fix

* fix2

* Revert "fix header padding"

This reverts commit 63f2b15f02.

* broken default parameter

* changes

* more checks for file forwarding

* paddings

* padding

* padding and fix

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2024-04-19 17:36:32 +01:00
Evgeny Poberezkin a35d392f76 core: update simplexmq 2024-04-19 17:25:34 +01:00
spaced4ndy 1306c84938 ios: in item context menu don't show forward button if file doesn't exist, add download button (#4048) 2024-04-19 17:21:35 +01:00
Stanislav Dmitrenko 6484e36b82 ios: fix mute/unmute button state (#4046) 2024-04-19 17:20:31 +01:00
Stanislav Dmitrenko 918be31f2c desktop: fix freeze that happened when new chat items arrives while scrolling via scrollbar (#4050) 2024-04-19 15:57:00 +01:00
spaced4ndy 648884044f core: prohibit forwarding file if it's not found (#4047) 2024-04-19 11:31:44 +04:00
Stanislav Dmitrenko 505c6cb062 ios: prevent a crash when exiting the app (#4041)
* ios: prevent a crash when exiting the app

* log
2024-04-19 07:23:13 +01:00
Stanislav Dmitrenko 065c8f8861 ios: fix typing using keyboard suggestions (#4045) 2024-04-19 07:17:17 +01:00
spaced4ndy 6c509027f7 docs: IP address protection rfc (#4036) 2024-04-17 13:53:45 +04:00
Evgeny Poberezkin 4eafdc3723 blog: metadata in messengers (#4038)
* blog: metadata in messengers

* readme

* call.js

* picture

* revert call.js
2024-04-16 20:18:22 +01:00
spaced4ndy 77f5c678d5 ios: forward ui (#4024)
* wip

* wip

* fixes

* improvements

* info

* fix

* dont cleanup file

* info design, text

* text

* rework with LazyVStack

* delay

* refactor

* move delay

* fix

* refactor

* refactor 2

* keep current message

* forward with quote, context icons

* info

* preserve draft

* remove newline

* improve search

* info

* layout

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-04-16 09:28:39 +01:00
Stanislav Dmitrenko 5e71d00ace android, desktop: workaround of missing stuns support in calls (#4033)
* android, desktop: workaround of missing stuns support in calls

* const
2024-04-16 08:38:46 +01:00
Stanislav Dmitrenko c2169f7813 desktop: fix video calls in Firefox (#4034)
* desktop: fix video calls in Firefox

* one more play()
2024-04-16 08:22:40 +01:00
spaced4ndy 7ff4b05c90 core: remember new origin for received forwarded messages (#4032) 2024-04-15 17:19:37 +04:00
Evgeny Poberezkin d7f8bff957 Merge branch 'stable' 2024-04-15 11:16:33 +01:00
sh bda0917787 github: fix cla action (#4030) 2024-04-15 10:51:24 +01:00
Evgeny Poberezkin 0eae7f56f3 5.7-beta.0: ios 207, android 196, desktop 37 2024-04-14 21:14:15 +01:00
Stanislav Dmitrenko 24e3806b25 webrtc: updated credentials (#4011)
* webrtc: updated credentials

* no udp

* change

* stuns

* added stun back

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-04-14 19:18:12 +01:00
Evgeny Poberezkin f606e5742c ios: update library 2024-04-14 19:11:15 +01:00
Evgeny Poberezkin c6af2c285a core: 5.7.0.0 (#4027) 2024-04-14 17:31:56 +01:00
Stanislav Dmitrenko 35b7f2cb1c scripts: ghc version update (#4010) 2024-04-14 16:42:04 +01:00
Evgeny Poberezkin 76a33a3743 Force include hs_init_with_rtsopts (#4028)
Co-authored-by: Moritz Angermann <moritz.angermann@gmail.com>
2024-04-14 16:12:34 +01:00
Evgeny Poberezkin b6fd5e61b6 Merge branch 'stable' 2024-04-13 12:12:51 +01:00
artur fe639eed48 docs: Add Polish translation (#4001)
* docs: Add polish translation

* README: Add link to polish translation

* docs: Polish version of README - Fix links

* docs: Add links to polish translation, fix

* docs: Fix polish translation thanks to support team

* docs: Add links to polish translation in english version of docs

* fix links

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-04-13 12:12:21 +01:00
spaced4ndy 638fd3756a core: correctly populate data for items forwarded from groups (#4025) 2024-04-13 11:52:39 +01:00
Stanislav Dmitrenko de81434b36 android, desktop: role-based preferences, SimpleX links preference (#4023)
* android, desktop: role-based preferences, SimpleX links preference

* disable for now

* different way of disabling send button

* mic icon filled

* icons

* braces

* colors

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-04-13 11:51:10 +01:00
Evgeny Poberezkin 433b3652fb core: simplexmq 5.6.2.2 2024-04-13 09:33:37 +01:00
Alexander Bondarenko 86fe2212c3 chat: forward files with streaming re-encryption (#4022)
* chat: forward files with streaming re-encryption

* refactor
2024-04-13 09:32:43 +01:00
Evgeny Poberezkin 182225a5b1 ios: role-based preferences, SimpleX links preference (#4021)
* ios: role-based preferences, SimpleX links preference

* disable some options
2024-04-12 11:29:58 +01:00
spaced4ndy e10c63dc64 ui: deletable field (#4019) 2024-04-12 13:10:47 +04:00
spaced4ndy 29941729d2 ui: forwarded item header (#4017) 2024-04-12 12:56:09 +04:00
spaced4ndy ee53377070 core: fix forwarded item deletion (#4018) 2024-04-12 12:55:04 +04:00
spaced4ndy 0deb6a4eb1 ui: forward types (#4008)
* ios: forward types

* android

* move
2024-04-11 13:58:56 +01:00
Stanislav Dmitrenko b84ef0ce35 android: network observer (#3992)
* android: network observer

* removed unused code

* rename

* rename

* new line

* rename

* changes in logic

* adapted to ios logic

* change

* change

* change

* networkLost

* item in settings

* reorder

* changes

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-04-11 13:26:24 +01:00
Stanislav Dmitrenko 34dee32def android, desktop: sound prompts and vibration (#3997)
* android, desktop: sound prompts and vibration

* moved audio playing to js

* Revert "moved audio playing to js"

This reverts commit a9355c2d88.

* sound from speaker/earpiece

* better

* changes

* license of audio

* reorder lines

* loop fix

* awaiting call receipt

* desktop

* new line
2024-04-11 13:19:00 +01:00
Stanislav Dmitrenko 94851f177b ios: noRcvUser handling while downloading a file in migration process (#4012) 2024-04-11 12:05:01 +01:00
Stanislav Dmitrenko e560b49d14 ios: sound prompts and vibration during calls (#4005)
* ios: sound prompts and vibration

* awaiting call receipt

* update

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-04-11 12:02:41 +01:00
Stanislav Dmitrenko d8b52ee0d3 ios: network observer (#3996)
* ios: network observer

* update

* remove metered

* update tcpTimeoutPerKb

* network connection in settings

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-04-11 11:31:30 +01:00
Evgeny Poberezkin a9c0f356b4 ios: update core library 2024-04-11 11:25:06 +01:00
Evgeny Poberezkin 8a3710482b core: update simplexmq 2024-04-11 10:47:51 +01:00
Evgeny Poberezkin b3a4ea8e57 core: api to update user network state (#3998)
* core: api to update user network state

* simplexmq

* update simplexmq

* simplexmq
2024-04-10 23:32:55 +01:00
Evgeny Poberezkin 4be6c69633 core: update simplexmq 2024-04-10 08:49:06 +01:00
Evgeny Poberezkin 005d99ad50 docs: trasparency reports (#4007) 2024-04-09 21:45:48 +01:00
Narasimha-sc 36f86beafd docs: device linking info on downloads page #4004 2024-04-09 20:30:08 +01:00
Evgeny Poberezkin 1fa79a2654 android, desktop: fix incorrect event type for critical/internal error alerts 2024-04-09 18:18:11 +01:00
Evgeny Poberezkin 72611084d3 core: debug events (#4006) 2024-04-09 17:31:52 +01:00
Evgeny Poberezkin a5db36469d core: api to forward messages (#3968)
* wip

* wip

* test

* mute

* tests

* simplify (only bool flag)

* re-encrypt file

* tests

* more tests (wip)

* fix relative paths, refactor

* more tests

* more locks

* fix, tests

* more tests

* rework (revert from bool to ids)

* update schema

* more tests

* add to info

* ForwardedMsg container

* Revert "ForwardedMsg container"

This reverts commit bb57f12151.

* parser

* more tests

* rework api

* more locks

* test

* move

* remove from

* view

* prohibit editing

* item info view

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2024-04-09 16:02:59 +04:00
Evgeny Poberezkin f8e6a78a3b core: fix nix config (#4003)
* bump

* more compilers

* i686 32bit only 8.10.7

---------

Co-authored-by: Moritz Angermann <moritz.angermann@gmail.com>
2024-04-09 08:15:29 +01:00
spaced4ndy 5b0c8e0f76 core: improve some tests (#4000) 2024-04-08 18:16:29 +04:00
Evgeny Poberezkin 2968cd0460 rfc: protocol extensions for channels/super-peers (#3980) 2024-04-05 16:46:37 +01:00
Evgeny Poberezkin 8ffb4e500e Merge branch 'stable' 2024-04-05 15:30:09 +01:00
Stanislav Dmitrenko 6133993cfe android, desktop: fix build error related to JVM version (#3995) 2024-04-05 15:29:41 +01:00
Evgeny Poberezkin 0d7a32877f ci: build armv7a with 8.10.7 in the main branches (master, stable) (#3733)
Co-authored-by: Moritz Angermann <moritz.angermann@gmail.com>
2024-04-05 12:24:34 +01:00
Evgeny Poberezkin 18efc28d16 core: additional group preferences: prohibit SimpleX links, restrict some features to specific roles (#3964)
* core: additional group preferences: prohibit SimpleX links, restrict some features to specific roles

* add role to group preference items, tests
2024-04-04 20:41:56 +01:00
spaced4ndy 069395c2a0 core: entity locks (#3962)
* core: entity locks

* more locks

* update sha256map

* add delay

* clean up

* empty

* fix tests

* empty

* empty

* more delays

* empty

* comment delays

* Revert "comment delays"

This reverts commit 4245b545fb.

* Revert "Revert "comment delays""

This reverts commit f803386945.

* take lock in the beginning of processing loop

* empty

* empty

* remove lock

* rework file locks

* empty

* fix

* empty

* add connection locks

* empty

* fix test

* empty

* remove commented delays

* add to debug locks

* update

* refactor

* refactor

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-04-04 19:24:42 +01:00
Stanislav Dmitrenko a725d2efac desktop (windows): fix build (#3990) 2024-04-04 14:18:33 +01:00
Evgeny Poberezkin 5f9710e4bb blog: post 2024-04-04 13:17:20 +01:00
Evgeny Poberezkin ea6c5bfb0b 5.6.1: ios 206, android 193, desktop 36 2024-04-04 08:58:24 +01:00
Stanislav Dmitrenko 14c279d1e0 android: possibly, prevent TooManyRequests exception (#3989)
* android: possibly, prevent TooManyRequests exception

* new line
2024-04-03 15:15:44 +01:00
Stanislav Dmitrenko d2de81100d android: workaround of pager's bug (#3988) 2024-04-03 15:11:04 +01:00
Stanislav Dmitrenko 9b28ae6d9e desktop: remote connection host/port fix (#3987) 2024-04-03 11:58:32 +01:00
Evgeny Poberezkin ea862a8f34 core: 5.6.1.1 (simplexmq 5.6.2.1) 2024-04-03 11:43:42 +01:00
Evgeny Poberezkin 2bd1a82b7d core: revert "deps: switch to base64 via simplexmq (#3957)" (#3985)
* Revert "deps: switch to base64 via simplexmq (#3957)"

This reverts commit d65137882b.

* update simplexmq
2024-04-03 10:47:38 +01:00
Evgeny Poberezkin 97a37634ef ios: 5.6.1 build 205 2024-04-03 01:47:01 +01:00
Stanislav Dmitrenko 28fbc1cd84 desktop: correct height of a window (#3982) 2024-04-02 20:05:14 +01:00
Stanislav Dmitrenko b8ee2af5b7 deskop: show window icon (#3983)
* deskop: show window icon

* size
2024-04-02 18:57:23 +01:00
Stanislav Dmitrenko c234809894 ios: improvement of chat item context menu (#3981)
* ios: improvement of chat item context menu

* rename

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-04-02 17:00:24 +01:00
Evgeny Poberezkin e1a997877a rfc: groups based on super-peers (WIP) (#3917) 2024-04-01 15:04:13 +01:00
Evgeny Poberezkin 69218952c3 core: 5.6.1.0 2024-04-01 14:36:45 +01:00
Evgeny Poberezkin dc2591b0bf ios: build settings (#3978) 2024-04-01 13:55:26 +01:00
Evgeny Poberezkin 2272b77b53 ios: refactor notifications (#3976)
* ios: refactor notifications

* refactor
2024-04-01 13:52:28 +01:00
Evgeny Poberezkin d90e2f4436 core: remove mtl typeclasses to reduce overhead (#3975)
* core: remove mtl typeclasses to reduce overhead

* strict data, optimization

* update simplexmq, clean up

* un-unlift attachRevHTTP2Client

* remote

---------

Co-authored-by: Alexander Bondarenko <486682+dpwiz@users.noreply.github.com>
2024-04-01 13:34:45 +01:00
Evgeny Poberezkin 9b6ca23dcb ios: fix UI freezes on start and when exiting background (#3972)
* ios: fix UI freezes on start and when exiting background

* remove unused code

* comments
2024-03-29 22:58:36 +00:00
Evgeny Poberezkin 1410b4bd85 ios: prevent call to apiContactInfo after the app is suspended 2024-03-29 19:43:16 +00:00
Evgeny Poberezkin 42a35e8c72 ios: prevent call to listUsers after the app is suspended and database is closed 2024-03-29 18:58:55 +00:00
Evgeny Poberezkin 86fe28f1ed core: chat hooks allowing to extend or customize chat core (#3953)
* core: chat hooks allowing to extend or customize chat core

* update

* json

* custom response

* user in db queries
2024-03-29 18:30:17 +00:00
Evgeny Poberezkin 735359c279 android: strings for permissions 2024-03-29 18:28:54 +00:00
Stanislav Dmitrenko 3d20465662 android: more user-friendly way of granting permissions in call (#3945)
* android: more user-friendly way of granting permissions in call

* changes

* ask permissions without click at first

* changes in logic and UI

* enhancements

* show alert only when non in PiP

* change

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-03-29 18:19:36 +00:00
Stanislav Dmitrenko b64ae90850 ios: NotificationService refactoring (#3961)
* ios: NotificationService refactoring

* refactor

* removed unused code

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-03-28 17:28:10 +00:00
spaced4ndy 366b58ead5 core: don't save async commands records for ack (#3904) 2024-03-28 19:52:06 +04:00
spaced4ndy 32bcaad126 ui: add missing error types (#3925) 2024-03-28 17:49:09 +04:00
Alexander Bondarenko d65137882b deps: switch to base64 via simplexmq (#3957)
* deps: switch to base64 via simplexmq

* update error text

* update nix

* set simplexmq to master

* update paths
2024-03-28 13:09:04 +00:00
spaced4ndy 095d613f01 website: translations (#3960)
* Translated using Weblate (Polish)

Currently translated at 100.0% (254 of 254 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/pl/

* Translated using Weblate (Russian)

Currently translated at 100.0% (254 of 254 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/ru/

* Translated using Weblate (Hebrew)

Currently translated at 100.0% (254 of 254 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/he/

* Translated using Weblate (Finnish)

Currently translated at 100.0% (254 of 254 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/fi/

* Translated using Weblate (Finnish)

Currently translated at 100.0% (254 of 254 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/fi/

---------

Co-authored-by: Jakub <fioletowy.temp@tutanota.com>
Co-authored-by: whoami11 <hvhdinik@gmail.com>
Co-authored-by: You and me <trash.93m78@slmail.me>
Co-authored-by: Jiri Grönroos <jiri.gronroos@iki.fi>
2024-03-28 12:30:31 +00:00
spaced4ndy f22beefbd4 ui: translations (#3959)
* Translated using Weblate (German)

Currently translated at 100.0% (1687 of 1687 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 100.0% (1687 of 1687 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% (1478 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/de/

* Translated using Weblate (Russian)

Currently translated at 100.0% (1478 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ru/

* Translated using Weblate (French)

Currently translated at 100.0% (1478 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/fr/

* Translated using Weblate (French)

Currently translated at 100.0% (1478 of 1478 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% (1687 of 1687 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% (1478 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/it/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1687 of 1687 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% (1478 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/

* Translated using Weblate (Japanese)

Currently translated at 98.3% (1659 of 1687 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ja/

* Translated using Weblate (Czech)

Currently translated at 98.2% (1657 of 1687 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 95.9% (1619 of 1687 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (1687 of 1687 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% (1478 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/uk/

* Translated using Weblate (Portuguese)

Currently translated at 0.3% (5 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/pt/

* Translated using Weblate (Hebrew)

Currently translated at 100.0% (1687 of 1687 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/he/

* Translated using Weblate (Hebrew)

Currently translated at 41.7% (617 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/he/

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1478 of 1478 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 100.0% (1687 of 1687 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% (1478 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1478 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Japanese)

Currently translated at 98.4% (1661 of 1687 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ja/

* Translated using Weblate (Portuguese)

Currently translated at 45.2% (763 of 1687 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/pt/

* Translated using Weblate (Portuguese)

Currently translated at 3.7% (55 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/pt/

* Translated using Weblate (Hebrew)

Currently translated at 100.0% (1687 of 1687 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/he/

* Translated using Weblate (Japanese)

Currently translated at 99.4% (1678 of 1687 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ja/

* Translated using Weblate (Portuguese)

Currently translated at 3.7% (56 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/pt/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1687 of 1687 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% (1478 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/

* Translated using Weblate (Portuguese)

Currently translated at 7.3% (109 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/pt/

* Translated using Weblate (Bulgarian)

Currently translated at 96.7% (1430 of 1478 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% (1687 of 1687 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/bg/

* Translated using Weblate (Vietnamese)

Currently translated at 5.6% (96 of 1687 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/vi/

* Translated using Weblate (Japanese)

Currently translated at 100.0% (1687 of 1687 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% (1688 of 1688 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% (1688 of 1688 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/

* Translated using Weblate (Japanese)

Currently translated at 100.0% (1688 of 1688 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ja/

* Translated using Weblate (Bulgarian)

Currently translated at 99.4% (1470 of 1478 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 99.9% (1687 of 1688 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% (1688 of 1688 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Vietnamese)

Currently translated at 6.0% (102 of 1688 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/vi/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1688 of 1688 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* android

* ios import

* ios export

---------

Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: subjection yogirt <subjectiongithub@yogirt.com>
Co-authored-by: whoami11 <hvhdinik@gmail.com>
Co-authored-by: khalidbelk <khalid.belkassmi-el-hafi@epitech.eu>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: Miyu Sakatsuki <miyu-sakatsuki@outlook.jp>
Co-authored-by: zenobit <zen@osowoso.xyz>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: You and me <trash.93m78@slmail.me>
Co-authored-by: summoner001 <summoner@vivaldi.net>
Co-authored-by: Ghost of Sparta <makesocialfoss32@keemail.me>
Co-authored-by: Andre <andrefeliciano@duck.com>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: elgratea <weblate@fastmail.com>
Co-authored-by: tuananh-ng <158744840+tuananh-ng@users.noreply.github.com>
2024-03-28 12:27:58 +00:00
spaced4ndy c9bf36291b ios: fix default (#3958) 2024-03-27 09:59:15 +00:00
spaced4ndy 42ebe8bc60 core: batch broadcast send db operations (#3956)
* core: batch broadcast send db operations

* refactor

* Update src/Simplex/Chat.hs

Co-authored-by: Alexander Bondarenko <486682+dpwiz@users.noreply.github.com>

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
Co-authored-by: Alexander Bondarenko <486682+dpwiz@users.noreply.github.com>
2024-03-27 11:49:14 +04:00
Stanislav Dmitrenko 96fb61ccfc desktop: show toast if failed to show notification (#3955)
* desktop: show toast if failed to show notification

* longer timeout

* returned old version of the lib
2024-03-26 12:43:45 +00:00
spaced4ndy 1d698c114f docs: communicate rejection rfc (#3946) 2024-03-26 11:29:28 +04:00
Stanislav Dmitrenko 154ce5843d android, desktop: update dependencies (#3954)
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-03-25 15:59:00 +00:00
Evgeny Poberezkin a5817d9feb core: fix cabal paths (#3952)
* fixed install cabal file paths.

* updated package.yaml

* fix

---------

Co-authored-by: Andor Kesselman <andor@magic-pro-3.local>
2024-03-25 08:24:46 +00:00
Evgeny Poberezkin 72082af139 docs: update version 2024-03-23 19:20:37 +00:00
Evgeny Poberezkin eb36704f59 Merge branch 'stable' 2024-03-23 18:42:53 +00:00
Evgeny Poberezkin 84fbff6148 blog: v5.6 release, non-profit governance (#3951)
* blog: v5.6 release

* images, preview

* corrections

* update image

* update readme
2024-03-23 18:42:18 +00:00
Evgeny Poberezkin dd75d30c08 blog: update PQ encryption post (#3948)
* blog: update pq encryption post

* correction
2024-03-23 18:29:05 +00:00
spaced4ndy 52803ae976 core: add delays to some failing tests (#3947) 2024-03-22 22:01:11 +04:00
spaced4ndy ec73a31cb5 directory: fix double logic inversion on roles check, incorrect error message (#3944) 2024-03-22 15:07:01 +04:00
Evgeny Poberezkin 6ad5048b58 5.6: ios 204, android 191, desktop 35 2024-03-21 22:30:30 +00:00
Stanislav Dmitrenko ca0ce4dfdd ios: making chat state .active when starting chat, correctly handle hidden users when deleting the last profile (#3936)
* ios: making chat state .active when starting chat

* changes

* refactor

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-03-21 19:36:05 +00:00
spaced4ndy d27502ec47 ios: restore reveal/hide animation (#3933)
* ios: restore reveal/hide animation

* remove comment

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-03-21 19:12:47 +00:00
spaced4ndy 655ad4d813 ui: translations (#3940)
* Translated using Weblate (Dutch)

Currently translated at 96.6% (1622 of 1679 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 96.2% (1624 of 1687 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 97.0% (1638 of 1687 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% (1687 of 1687 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 96.9% (1433 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/

* Translated using Weblate (Dutch)

Currently translated at 98.5% (1456 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1687 of 1687 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% (1478 of 1478 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 97.0% (1637 of 1687 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 96.6% (1631 of 1687 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 97.2% (1640 of 1687 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% (1687 of 1687 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 97.4% (1441 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/it/

* Translated using Weblate (Czech)

Currently translated at 95.2% (1607 of 1687 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/cs/

* Translated using Weblate (Hungarian)

Currently translated at 97.0% (1637 of 1687 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% (1687 of 1687 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% (1478 of 1478 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% (1687 of 1687 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% (1478 of 1478 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% (1478 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/it/

* Translated using Weblate (Czech)

Currently translated at 98.2% (1657 of 1687 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/cs/

* Translated using Weblate (Polish)

Currently translated at 99.9% (1686 of 1687 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 95.1% (1406 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/pl/

* Translated using Weblate (Turkish)

Currently translated at 97.2% (1438 of 1478 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% (1687 of 1687 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 99.6% (1681 of 1687 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.6% (1681 of 1687 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 99.9% (1686 of 1687 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% (1478 of 1478 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.8% (1685 of 1687 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.8% (1476 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Arabic)

Currently translated at 95.8% (1617 of 1687 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 100.0% (1687 of 1687 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% (1478 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1687 of 1687 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% (1478 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Italian)

Currently translated at 100.0% (1687 of 1687 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% (1478 of 1478 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% (1687 of 1687 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 95.9% (1619 of 1687 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 95.8% (1417 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/

* Translated using Weblate (Russian)

Currently translated at 100.0% (1687 of 1687 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ru/

* Translated using Weblate (Russian)

Currently translated at 100.0% (1478 of 1478 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ru/

* android

* import

* export

* ru corrections

* export/update ru

---------

Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: Ghost of Sparta <makesocialfoss32@keemail.me>
Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: zenobit <zen@osowoso.xyz>
Co-authored-by: summoner001 <summoner@vivaldi.net>
Co-authored-by: B.O.S.S <BxOxSxS@protonmail.com>
Co-authored-by: cervezagua <cervezagua@pm.me>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Co-authored-by: No name <CertainBot@users.noreply.hosted.weblate.org>
Co-authored-by: khalidbelk <khalid.belkassmi-el-hafi@epitech.eu>
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-03-21 19:07:12 +00:00
Evgeny Poberezkin e0566599a4 core: 5.6.0.4 (#3939) 2024-03-21 19:00:19 +00:00
Evgeny Poberezkin 2546ad5351 Translated using Weblate (Czech) (#3941)
Currently translated at 99.2% (252 of 254 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/cs/

Co-authored-by: zenobit <zen@osowoso.xyz>
2024-03-21 17:37:56 +00:00
Stanislav Dmitrenko 0706e6e464 android: stopping chat after deleting the last user (#3937)
* android: stopping chat after deleting the last user

* fix for hidden users + onboarding
2024-03-21 14:02:38 +00:00
spaced4ndy c2adf40b5a ui: align finalize migration destructive/default button colors (#3938)
* ios: align finalize migration destructive/default button colors

* android
2024-03-21 14:00:27 +00:00
Stanislav Dmitrenko b220ea23e2 ios: stop chat after deleting the last profile (#3935) 2024-03-21 13:58:04 +00:00
spaced4ndy a16e3eebd1 ui: improve "allow PQ" button (#3932)
* ios: improve "allow PQ" button

* android
2024-03-21 09:13:18 +00:00
Stanislav Dmitrenko 6d54c21774 ios: chatitem height with menu workaround (#3930)
* ios: chatitem height with menu workaround

* turned on animation

* disabled animation in some places again
2024-03-20 17:49:53 +00:00
spaced4ndy d2e6313ce3 ui: swap finalize migration buttons (make destructive harder to reach, consistent order of primary and destructive with previous page) (#3931) 2024-03-20 20:20:10 +04:00
Evgeny Poberezkin c2707d3c2b 5.6-beta.1: ios 203, android 190, desktop 34 2024-03-19 17:58:29 +00:00
Stanislav Dmitrenko 43381b5cf0 desktop: scroll bars (#3920)
* desktop: scroll bar

* more places with scrollbar

* removed unused code

* color

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-03-19 16:56:36 +00:00
Evgeny Poberezkin 3f1d86623a core: 5.6.0.3 2024-03-19 15:20:04 +00:00
Stanislav Dmitrenko 5fde879fea ios: better layout performance for chat item (#3911)
* ios: better layout performance for chat item

* different way of disabling menu

* two fixes

---------

Co-authored-by: Avently <avently@local>
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-03-19 14:40:46 +00:00
Evgeny Poberezkin 157c4722ca ui: increase chunk size for new allocations in core to 64mb (#3928) 2024-03-19 14:35:40 +00:00
Alexander Bondarenko 5bc8bbe16c chat: use context-less compression (#3913)
* chat: use context-less compression

* update sha256map

* space

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-03-19 13:33:27 +00:00
Alexander Bondarenko d835f9df3d ios: remove recursion in receiveMsgLoop (#3922)
* ios: remove recursion in receiveMsgLoop

* comment

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-03-19 11:44:30 +00:00
Evgeny Poberezkin 8f04e13750 ios: add Hungarian interface language (#3927) 2024-03-19 11:34:11 +00:00
spaced4ndy 39167ab3dd multiplatform: 5.6 what's new (#3926) 2024-03-19 11:27:05 +00:00
spaced4ndy e925d87548 ios: 5.6 what's new (#3923)
* ios: 5.6 what's new

* update

* update

* release announcement stub, update link

* Hungarian

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-03-19 10:53:46 +00:00
Evgeny Poberezkin c2e2408394 website: translations (#3919)
* ios: update library

* Translated using Weblate (Finnish)

Currently translated at 97.2% (245 of 252 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/fi/

* Translated using Weblate (French)

Currently translated at 100.0% (254 of 254 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/fr/

* Translated using Weblate (German)

Currently translated at 100.0% (254 of 254 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/de/

* Translated using Weblate (Arabic)

Currently translated at 100.0% (254 of 254 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/ar/

* Translated using Weblate (Italian)

Currently translated at 100.0% (254 of 254 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/it/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (254 of 254 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/zh_Hans/

* Translated using Weblate (Polish)

Currently translated at 100.0% (254 of 254 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/pl/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (254 of 254 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/es/

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (254 of 254 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/pt_BR/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (254 of 254 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/nl/

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (254 of 254 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/uk/

* Translated using Weblate (Bulgarian)

Currently translated at 1.5% (4 of 254 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/bg/

* Translated using Weblate (Arabic)

Currently translated at 100.0% (254 of 254 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/ar/

* Translated using Weblate (Japanese)

Currently translated at 100.0% (254 of 254 strings)

Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/ja/

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
Co-authored-by: Jiri Grönroos <jiri.gronroos@iki.fi>
Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com>
Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: Float <float.hu+@gmail.com>
Co-authored-by: Jakub <fioletowy.temp@tutanota.com>
Co-authored-by: muralito <muralito@montevideo.com.uy>
Co-authored-by: N1DH0GG <janpstrunn@duck.com>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: Maksym Lukashenko <livelmaxim@gmail.com>
Co-authored-by: Salif Mehmed <mail@salif.eu>
Co-authored-by: ActiveTK <webmaster@activetk.jp>
2024-03-19 09:53:25 +00:00
Evgeny Poberezkin bb16922634 ui: translations (#3918)
* Added translation using Weblate (Hungarian)

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1403 of 1403 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% (1605 of 1605 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/tr/

* Translated using Weblate (Persian)

Currently translated at 9.2% (149 of 1605 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fa/

* Translated using Weblate (Italian)

Currently translated at 100.0% (1605 of 1605 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% (1403 of 1403 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/it/

* Translated using Weblate (Bulgarian)

Currently translated at 100.0% (1403 of 1403 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% (1605 of 1605 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/bg/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1605 of 1605 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% (1403 of 1403 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 100.0% (1605 of 1605 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% (1607 of 1607 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/

* Translated using Weblate (Arabic)

Currently translated at 99.7% (1603 of 1607 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1403 of 1403 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% (1607 of 1607 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% (1607 of 1607 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 0.2% (4 of 1403 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Hungarian)

Currently translated at 0.2% (4 of 1403 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Hungarian)

Currently translated at 0.6% (9 of 1403 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Hungarian)

Currently translated at 5.9% (84 of 1403 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1608 of 1608 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% (1608 of 1608 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 20.8% (292 of 1403 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1608 of 1608 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% (1608 of 1608 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 29.8% (419 of 1403 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Hungarian)

Currently translated at 29.8% (419 of 1403 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Arabic)

Currently translated at 99.7% (1604 of 1608 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 100.0% (1608 of 1608 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 43.6% (613 of 1403 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (German)

Currently translated at 100.0% (1608 of 1608 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% (1403 of 1403 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% (1608 of 1608 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% (1403 of 1403 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% (1608 of 1608 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/

* Translated using Weblate (Spanish)

Currently translated at 98.0% (1577 of 1608 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/es/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1608 of 1608 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% (1403 of 1403 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/

* Translated using Weblate (Lithuanian)

Currently translated at 45.2% (727 of 1608 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/lt/

* Translated using Weblate (Polish)

Currently translated at 100.0% (1608 of 1608 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/pl/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1608 of 1608 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% (1608 of 1608 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.6% (1398 of 1403 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Hungarian)

Currently translated at 99.6% (1398 of 1403 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/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 (Persian)

Currently translated at 9.6% (155 of 1608 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fa/

* Translated using Weblate (German)

Currently translated at 100.0% (1608 of 1608 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% (1403 of 1403 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/de/

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1608 of 1608 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/tr/

* Translated using Weblate (Ukrainian)

Currently translated at 99.9% (1607 of 1608 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/uk/

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1403 of 1403 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/tr/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1608 of 1608 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% (1403 of 1403 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/

* Translated using Weblate (Czech)

Currently translated at 95.5% (1536 of 1608 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/cs/

* Translated using Weblate (Bulgarian)

Currently translated at 100.0% (1608 of 1608 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% (1608 of 1608 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% (1403 of 1403 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (German)

Currently translated at 100.0% (1611 of 1611 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% (1611 of 1611 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 97.3% (1568 of 1611 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ja/

* Translated using Weblate (Ukrainian)

Currently translated at 87.9% (1234 of 1403 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/uk/

* Added translation using Weblate (Vietnamese)

* Translated using Weblate (French)

Currently translated at 100.0% (1611 of 1611 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% (1611 of 1611 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (1611 of 1611 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% (1403 of 1403 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/

* Translated using Weblate (Arabic)

Currently translated at 100.0% (1611 of 1611 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 100.0% (1611 of 1611 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% (1613 of 1613 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.9% (1612 of 1613 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/pt_BR/

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (1613 of 1613 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/pt_BR/

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (1613 of 1613 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/pt_BR/

* Translated using Weblate (French)

Currently translated at 100.0% (1613 of 1613 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fr/

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (1613 of 1613 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/pt_BR/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1613 of 1613 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% (1613 of 1613 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% (1613 of 1613 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/

* Translated using Weblate (French)

Currently translated at 100.0% (1613 of 1613 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% (1403 of 1403 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/fr/

* Translated using Weblate (Arabic)

Currently translated at 100.0% (1613 of 1613 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 100.0% (1613 of 1613 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% (1613 of 1613 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 87.2% (1224 of 1403 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/zh_Hans/

* Translated using Weblate (Polish)

Currently translated at 99.9% (1612 of 1613 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/pl/

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 59.7% (838 of 1403 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/pt_BR/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (1613 of 1613 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/

* Translated using Weblate (French)

Currently translated at 100.0% (1613 of 1613 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% (1403 of 1403 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/fr/

* Translated using Weblate (Turkish)

Currently translated at 100.0% (1613 of 1613 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/tr/

* Translated using Weblate (Persian)

Currently translated at 10.0% (162 of 1613 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fa/

* Translated using Weblate (Vietnamese)

Currently translated at 1.4% (24 of 1613 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/vi/

* Translated using Weblate (Vietnamese)

Currently translated at 1.4% (24 of 1613 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/vi/

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (1613 of 1613 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 88.5% (1243 of 1403 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/uk/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1613 of 1613 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% (1613 of 1613 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% (1613 of 1613 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Vietnamese)

Currently translated at 3.0% (49 of 1613 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/vi/

* Translated using Weblate (Vietnamese)

Currently translated at 3.0% (49 of 1613 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/vi/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1613 of 1613 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% (1613 of 1613 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Japanese)

Currently translated at 85.9% (1206 of 1403 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ja/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1613 of 1613 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% (1613 of 1613 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% (1613 of 1613 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% (1613 of 1613 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% (1613 of 1613 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% (1613 of 1613 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% (1613 of 1613 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% (1613 of 1613 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% (1613 of 1613 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% (1613 of 1613 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Vietnamese)

Currently translated at 4.0% (66 of 1613 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/vi/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1613 of 1613 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% (1613 of 1613 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% (1613 of 1613 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% (1403 of 1403 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/fr/

* Translated using Weblate (Arabic)

Currently translated at 100.0% (1613 of 1613 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 100.0% (1613 of 1613 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% (1613 of 1613 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% (1613 of 1613 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% (1613 of 1613 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% (1403 of 1403 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1613 of 1613 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% (1403 of 1403 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1613 of 1613 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% (1403 of 1403 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1403 of 1403 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Czech)

Currently translated at 96.4% (1555 of 1613 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/cs/

* Translated using Weblate (Vietnamese)

Currently translated at 5.0% (81 of 1613 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/vi/

* Translated using Weblate (Czech)

Currently translated at 97.5% (1574 of 1613 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 98.8% (1594 of 1613 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% (1613 of 1613 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% (1403 of 1403 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/fr/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1613 of 1613 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% (1403 of 1403 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1613 of 1613 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% (1403 of 1403 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Vietnamese)

Currently translated at 5.3% (87 of 1613 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/vi/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1403 of 1403 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1613 of 1613 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 96.1% (1349 of 1403 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/zh_Hans/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1613 of 1613 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% (1403 of 1403 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Vietnamese)

Currently translated at 5.6% (91 of 1613 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/vi/

* fix android strings

* ios: import

* ios: export

---------

Co-authored-by: z0rden <kaanpeker196@gmail.com>
Co-authored-by: Siavash <ciavash@proton.me>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: elgratea <weblate@fastmail.com>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: summoner001 <summoner@vivaldi.net>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: Ghost of Sparta <makesocialfoss32@keemail.me>
Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com>
Co-authored-by: Dan Hessel Kennet Miranda Cardona <kennetmiranda@skiff.com>
Co-authored-by: Moo <hazap@hotmail.com>
Co-authored-by: Jakub <fioletowy.temp@tutanota.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Cooly <whiteglass67@proton.me>
Co-authored-by: No name <CertainBot@users.noreply.hosted.weblate.org>
Co-authored-by: zenobit <zen@osowoso.xyz>
Co-authored-by: tomato potato <tomato.games@protonmail.com>
Co-authored-by: sr sr <sr1919os@gmail.com>
Co-authored-by: N1DH0GG <janpstrunn@duck.com>
Co-authored-by: axmfs <axmfs@proton.me>
Co-authored-by: Zhiyounihao <jilywen@outlook.com>
Co-authored-by: K0RR <rdkracz@gmail.com>
Co-authored-by: tuananh-ng <github.zvjhi@slmail.me>
Co-authored-by: tuananh-ng <158744840+tuananh-ng@users.noreply.github.com>
Co-authored-by: Groovy394 <groovy394@gmail.com>
Co-authored-by: Deleted User <noreply+78511@weblate.org>
Co-authored-by: ActiveTK <webmaster@activetk.jp>
Co-authored-by: sith-on-mars <groguko36@pm.me>
2024-03-19 09:53:01 +00:00
spaced4ndy a3310cd62e ios: fix decoder crashing (#3921)
* ios: fix ios decoder crashing

* change

* fix

* refactor

* simplify

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-03-18 18:38:49 +00:00
spaced4ndy 94a6f300ed core: fix creation of empty files (#3912) 2024-03-15 18:17:31 +04:00
spaced4ndy 1f8eb1d638 update simplexmq (xftp fixes) 2024-03-15 12:48:55 +04:00
494 changed files with 46928 additions and 6171 deletions
+32 -9
View File
@@ -65,6 +65,11 @@ jobs:
asset_name: simplex-chat-ubuntu-22_04-x86-64 asset_name: simplex-chat-ubuntu-22_04-x86-64
desktop_asset_name: simplex-desktop-ubuntu-22_04-x86_64.deb desktop_asset_name: simplex-desktop-ubuntu-22_04-x86_64.deb
- os: macos-latest - os: macos-latest
ghc: "9.6.3"
cache_path: ~/.cabal/store
asset_name: simplex-chat-macos-aarch64
desktop_asset_name: simplex-desktop-macos-aarch64.dmg
- os: macos-13
ghc: "9.6.3" ghc: "9.6.3"
cache_path: ~/.cabal/store cache_path: ~/.cabal/store
asset_name: simplex-chat-macos-x86-64 asset_name: simplex-chat-macos-x86-64
@@ -107,18 +112,36 @@ jobs:
if: matrix.os == 'macos-latest' if: matrix.os == 'macos-latest'
shell: bash shell: bash
run: | run: |
echo "ignore-project: False" >> cabal.project.local echo "ignore-project: False" >> cabal.project.local
echo "package direct-sqlcipher" >> cabal.project.local echo "package simplexmq" >> cabal.project.local
echo " extra-include-dirs: /usr/local/opt/openssl@1.1/include" >> cabal.project.local echo " extra-include-dirs: /opt/homebrew/opt/openssl@1.1/include" >> cabal.project.local
echo " extra-lib-dirs: /usr/local/opt/openssl@1.1/lib" >> cabal.project.local echo " extra-lib-dirs: /opt/homebrew/opt/openssl@1.1/lib" >> cabal.project.local
echo " flags: +openssl" >> cabal.project.local echo "" >> cabal.project.local
echo "package direct-sqlcipher" >> cabal.project.local
echo " extra-include-dirs: /opt/homebrew/opt/openssl@1.1/include" >> cabal.project.local
echo " extra-lib-dirs: /opt/homebrew/opt/openssl@1.1/lib" >> cabal.project.local
echo " flags: +openssl" >> cabal.project.local
- name: Unix prepare cabal.project.local for Mac
if: matrix.os == 'macos-13'
shell: bash
run: |
echo "ignore-project: False" >> cabal.project.local
echo "package simplexmq" >> cabal.project.local
echo " extra-include-dirs: /usr/local/opt/openssl@1.1/include" >> cabal.project.local
echo " extra-lib-dirs: /usr/local/opt/openssl@1.1/lib" >> cabal.project.local
echo "" >> cabal.project.local
echo "package direct-sqlcipher" >> cabal.project.local
echo " extra-include-dirs: /usr/local/opt/openssl@1.1/include" >> cabal.project.local
echo " extra-lib-dirs: /usr/local/opt/openssl@1.1/lib" >> cabal.project.local
echo " flags: +openssl" >> cabal.project.local
- name: Install AppImage dependencies - name: Install AppImage dependencies
if: startsWith(github.ref, 'refs/tags/v') && matrix.asset_name && 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 run: sudo apt install -y desktop-file-utils
- name: Install pkg-config for Mac - name: Install pkg-config for Mac
if: matrix.os == 'macos-latest' if: matrix.os == 'macos-latest' || matrix.os == 'macos-13'
run: brew install pkg-config run: brew install pkg-config
- name: Unix prepare cabal.project.local for Ubuntu - name: Unix prepare cabal.project.local for Ubuntu
@@ -190,7 +213,7 @@ jobs:
- name: Mac build desktop - name: Mac build desktop
id: mac_desktop_build id: mac_desktop_build
if: startsWith(github.ref, 'refs/tags/v') && matrix.os == 'macos-latest' if: startsWith(github.ref, 'refs/tags/v') && (matrix.os == 'macos-latest' || matrix.os == 'macos-13')
shell: bash shell: bash
env: env:
APPLE_SIMPLEX_SIGNING_KEYCHAIN: ${{ secrets.APPLE_SIMPLEX_SIGNING_KEYCHAIN }} APPLE_SIMPLEX_SIGNING_KEYCHAIN: ${{ secrets.APPLE_SIMPLEX_SIGNING_KEYCHAIN }}
@@ -241,7 +264,7 @@ jobs:
${{ steps.linux_appimage_build.outputs.appimage_hash }} ${{ steps.linux_appimage_build.outputs.appimage_hash }}
- name: Mac upload desktop package to release - name: Mac upload desktop package to release
if: startsWith(github.ref, 'refs/tags/v') && matrix.os == 'macos-latest' if: startsWith(github.ref, 'refs/tags/v') && (matrix.os == 'macos-latest' || matrix.os == 'macos-13')
uses: svenstaro/upload-release-action@v2 uses: svenstaro/upload-release-action@v2
with: with:
repo_token: ${{ secrets.GITHUB_TOKEN }} repo_token: ${{ secrets.GITHUB_TOKEN }}
@@ -250,7 +273,7 @@ jobs:
tag: ${{ github.ref }} tag: ${{ github.ref }}
- name: Mac update desktop package hash - name: Mac update desktop package hash
if: startsWith(github.ref, 'refs/tags/v') && matrix.os == 'macos-latest' if: startsWith(github.ref, 'refs/tags/v') && (matrix.os == 'macos-latest' || matrix.os == 'macos-13')
uses: softprops/action-gh-release@v1 uses: softprops/action-gh-release@v1
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+9 -3
View File
@@ -5,14 +5,20 @@ on:
pull_request_target: pull_request_target:
types: [opened, closed, synchronize] types: [opened, closed, synchronize]
permissions:
actions: write
contents: write
pull-requests: write
statuses: write
jobs: jobs:
CLAssistant: CLAssistant:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: "CLA Assistant" - name: "CLA Assistant"
if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request' if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target'
# Beta Release # Beta Release
uses: cla-assistant/github-action@v2.1.3-beta uses: cla-assistant/github-action@v2.3.0
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# the below token should have repo scope and must be manually added by you in the repository's secret # the below token should have repo scope and must be manually added by you in the repository's secret
@@ -33,4 +39,4 @@ jobs:
#custom-pr-sign-comment: 'The signature to be committed in order to sign the CLA' #custom-pr-sign-comment: 'The signature to be committed in order to sign the CLA'
#custom-allsigned-prcomment: 'pull request comment when all contributors has signed, defaults to **CLA Assistant Lite bot** All Contributors have signed the CLA.' #custom-allsigned-prcomment: 'pull request comment when all contributors has signed, defaults to **CLA Assistant Lite bot** All Contributors have signed the CLA.'
#lock-pullrequest-aftermerge: false - if you don't want this bot to automatically lock the pull request after merging (default - true) #lock-pullrequest-aftermerge: false - if you don't want this bot to automatically lock the pull request after merging (default - true)
#use-dco-flag: true - If you are using DCO instead of CLA #use-dco-flag: true - If you are using DCO instead of CLA
-1
View File
@@ -4,7 +4,6 @@ on:
push: push:
branches: branches:
- master - master
- stable
paths: paths:
- website/** - website/**
- images/** - images/**
+1
View File
@@ -54,6 +54,7 @@ website/translations.json
website/src/img/images/ website/src/img/images/
website/src/images/ website/src/images/
website/src/js/lottie.min.js website/src/js/lottie.min.js
website/src/privacy.md
# Generated files # Generated files
website/package/generated* website/package/generated*
+17 -10
View File
@@ -1,16 +1,21 @@
---
layout: layouts/privacy.html
permalink: /privacy/index.html
---
# SimpleX Chat Privacy Policy and Conditions of Use # SimpleX Chat Privacy Policy and Conditions of Use
SimpleX Chat is the first communication network based on a new protocol stack that builds on the same ideas of complete openness and decentralization as email and web, with the focus on providing security and privacy of communications, and without compromising on usability. SimpleX Chat is the first communication network based on a new protocol stack that builds on the same ideas of complete openness and decentralization as email and web, with the focus on providing security and privacy of communications, and without compromising on usability.
SimpleX Chat communication protocol is the first protocol that has no user profile IDs of any kind, not even random numbers, cryptographic keys or hashes that identify the users. SimpleX Chat apps allow their users to send messages and files via relay server infrastructure. Relay server owners and providers do not have any access to your messages, thanks to double-ratchet end-to-end encryption algorithm (also known as Signal algorithm - do not confuse with Signal protocols or platform) and additional encryption layers, and they also have no access to your profile and contacts - as they do not provide any user accounts. SimpleX Chat communication protocol is the first protocol that has no user profile IDs of any kind, not even random numbers, cryptographic keys or hashes that identify the users. SimpleX Chat apps allow their users to send messages and files via relay server infrastructure. Relay server owners and providers do not have any access to your messages, thanks to double-ratchet end-to-end encryption algorithm (also known as Signal algorithm - do not confuse with Signal protocols or platform) and additional encryption layers, and they also have no access to your profile and contacts - as they do not provide any user accounts.
Double ratchet algorithm has such important properties as [forward secrecy](./docs/GLOSSARY.md#forward-secrecy), sender [repudiation](./docs/GLOSSARY.md#) and break-in recovery (also known as [post-compromise security](./docs/GLOSSARY.md#post-compromise-security)). Double ratchet algorithm has such important properties as [forward secrecy](/docs/GLOSSARY.md#forward-secrecy), sender [repudiation](/docs/GLOSSARY.md#) and break-in recovery (also known as [post-compromise security](/docs/GLOSSARY.md#post-compromise-security)).
If you believe that any part of this document is not aligned with our mission or values, please raise it with us via [email](chat@simplex.chat) or [chat](https://simplex.chat/contact#/?v=1&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FK1rslx-m5bpXVIdMZg9NLUZ_8JBm8xTt%23%2F%3Fv%3D1%26dh%3DMCowBQYDK2VuAyEALDeVe-sG8mRY22LsXlPgiwTNs9dbiLrNuA7f3ZMAJ2w%253D%26srv%3Dbylepyau3ty4czmn77q4fglvperknl4bi2eb2fdy2bh4jxtf32kf73yd.onion). If you believe that any part of this document is not aligned with our mission or values, please raise it with us via [email](mailto:chat@simplex.chat) or [chat](https://simplex.chat/contact#/?v=1&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FK1rslx-m5bpXVIdMZg9NLUZ_8JBm8xTt%23%2F%3Fv%3D1%26dh%3DMCowBQYDK2VuAyEALDeVe-sG8mRY22LsXlPgiwTNs9dbiLrNuA7f3ZMAJ2w%253D%26srv%3Dbylepyau3ty4czmn77q4fglvperknl4bi2eb2fdy2bh4jxtf32kf73yd.onion).
## Privacy Policy ## Privacy Policy
SimpleX Chat Ltd uses the best industry practices for security and encryption to provide client and server software for secure [end-to-end encrypted](./docs/GLOSSARY.md#end-to-end-encryption) messaging via private connections. This encryption cannot be compromised by the relays servers, even if they are modified or compromised, via [man-in-the-middle attack](./docs/GLOSSARY.md#man-in-the-middle-attack), unlike most other communication platforms, services and networks. SimpleX Chat Ltd uses the best industry practices for security and encryption to provide client and server software for secure [end-to-end encrypted](/docs/GLOSSARY.md#end-to-end-encryption) messaging via private connections. This encryption cannot be compromised by the relays servers, even if they are modified or compromised, via [man-in-the-middle attack](/docs/GLOSSARY.md#man-in-the-middle-attack), unlike most other communication platforms, services and networks.
SimpleX Chat software is built on top of SimpleX messaging and application protocols, based on a new message routing protocol allowing to establish private connections without having any kind of addresses or other identifiers assigned to its users - it does not use emails, phone numbers, usernames, identity keys or any other user profile identifiers to pass messages between the user applications. SimpleX Chat software is built on top of SimpleX messaging and application protocols, based on a new message routing protocol allowing to establish private connections without having any kind of addresses or other identifiers assigned to its users - it does not use emails, phone numbers, usernames, identity keys or any other user profile identifiers to pass messages between the user applications.
@@ -20,7 +25,7 @@ While SimpleX Chat Ltd is not a communication service provider, and provide publ
We see users and data sovereignty, and device and provider portability as critically important properties for any communication system. We see users and data sovereignty, and device and provider portability as critically important properties for any communication system.
SimpleX Chat security assessment was done in October 2022 by [Trail of Bits](https://www.trailofbits.com/about), and most fixes were released in v4.2 see [the announcement](./blog/20221108-simplex-chat-v4.2-security-audit-new-website.md). SimpleX Chat security assessment was done in October 2022 by [Trail of Bits](https://www.trailofbits.com/about), and most fixes were released in v4.2 see [the announcement](/blog/20221108-simplex-chat-v4.2-security-audit-new-website.md).
### Your information ### Your information
@@ -34,7 +39,7 @@ You can transfer the profile to another device by creating a backup of the app d
#### Messages and Files #### Messages and Files
SimpleX relay servers cannot decrypt or otherwise access the content or even the size of your messages and files you send or receive. Each message is padded to a fixed size of 16kb. Each file is sent in chunks of 64kb, 256kb, 1mb or 8mb via all or some of the configured file relay servers. Both messages and files are sent end-to-end encrypted, and the servers do not have technical means to compromise this encryption, because part of the [key exchange](./docs/GLOSSARY.md#key-exchange) happens out-of-band. SimpleX relay servers cannot decrypt or otherwise access the content or even the size of your messages and files you send or receive. Each message is padded to a fixed size of 16kb. Each file is sent in chunks of 64kb, 256kb, 1mb or 8mb via all or some of the configured file relay servers. Both messages and files are sent end-to-end encrypted, and the servers do not have technical means to compromise this encryption, because part of the [key exchange](/docs/GLOSSARY.md#key-exchange) happens out-of-band.
Your message history is stored only on your own device and the devices of your contacts. While the recipients' devices are offline, messaging relay servers temporarily store end-to-end encrypted messages you can configure which relay servers are used to receive the messages from the new contacts, and you can manually change them for the existing contacts too. Your message history is stored only on your own device and the devices of your contacts. While the recipients' devices are offline, messaging relay servers temporarily store end-to-end encrypted messages you can configure which relay servers are used to receive the messages from the new contacts, and you can manually change them for the existing contacts too.
@@ -74,7 +79,7 @@ When you choose to use instant push notifications in SimpleX iOS app, because th
Preset notification server cannot observe the actual addresses of these queues, as a separate address is used to subscribe to the notifications. It also cannot observe who sends messages to you. Apple push notifications servers can only observe how many notifications are sent to you, but not from how many contacts, or from which messaging relays, as notifications are delivered to your device end-to-end encrypted by one of the preset notification servers - these notifications only contain end-to-end encrypted metadata, not even encrypted message content, and they look completely random to Apple push notification servers. Preset notification server cannot observe the actual addresses of these queues, as a separate address is used to subscribe to the notifications. It also cannot observe who sends messages to you. Apple push notifications servers can only observe how many notifications are sent to you, but not from how many contacts, or from which messaging relays, as notifications are delivered to your device end-to-end encrypted by one of the preset notification servers - these notifications only contain end-to-end encrypted metadata, not even encrypted message content, and they look completely random to Apple push notification servers.
You can read more about the design of iOS push notifications [here](https://simplex.chat/blog/20220404-simplex-chat-instant-notifications.html#our-ios-approach-has-one-trade-off). You can read more about the design of iOS push notifications [here](./blog/20220404-simplex-chat-instant-notifications.md#our-ios-approach-has-one-trade-off).
#### Another information stored on the servers #### Another information stored on the servers
@@ -82,7 +87,7 @@ Additional technical information can be stored on our servers, including randoml
#### SimpleX Directory #### SimpleX Directory
[SimpleX Directory](./docs/DIRECTORY.md) stores: your search requests, the messages and the members profiles in the registered groups. You can connect to SimpleX Directory via [this address](https://simplex.chat/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). [SimpleX Directory](/docs/DIRECTORY.md) stores: your search requests, the messages and the members profiles in the registered groups. You can connect to SimpleX Directory via [this address](https://simplex.chat/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).
#### User Support #### User Support
@@ -103,13 +108,15 @@ The cases when SimpleX Chat Ltd may share the data temporarily stored on the ser
At the time of updating this document, we have never provided or have been requested the access to the preset relay servers or any information from the servers by any third parties. If we are ever requested to provide such access or information, we will follow the due legal process to limit any information shared with the third parties to the minimally required by law. At the time of updating this document, we have never provided or have been requested the access to the preset relay servers or any information from the servers by any third parties. If we are ever requested to provide such access or information, we will follow the due legal process to limit any information shared with the third parties to the minimally required by law.
We will publish information we are legally allowed to share about such requests in the [Transparency reports](./docs/TRANSPARENCY.md).
### Updates ### Updates
We will update this Privacy Policy as needed so that it is current, accurate, and as clear as possible. Your continued use of our software applications and preset relays infrastructure confirms your acceptance of our updated Privacy Policy. We will update this Privacy Policy as needed so that it is current, accurate, and as clear as possible. Your continued use of our software applications and preset relays infrastructure confirms your acceptance of our updated Privacy Policy.
Please also read our Conditions of Use of Software and Infrastructure below. Please also read our Conditions of Use of Software and Infrastructure below.
If you have questions about our Privacy Policy please contact us via [email](chat@simplex.chat) or [chat](https://simplex.chat/contact#/?v=1&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FK1rslx-m5bpXVIdMZg9NLUZ_8JBm8xTt%23%2F%3Fv%3D1%26dh%3DMCowBQYDK2VuAyEALDeVe-sG8mRY22LsXlPgiwTNs9dbiLrNuA7f3ZMAJ2w%253D%26srv%3Dbylepyau3ty4czmn77q4fglvperknl4bi2eb2fdy2bh4jxtf32kf73yd.onion). If you have questions about our Privacy Policy please contact us via [email](mailto:chat@simplex.chat) or [chat](https://simplex.chat/contact#/?v=1&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FK1rslx-m5bpXVIdMZg9NLUZ_8JBm8xTt%23%2F%3Fv%3D1%26dh%3DMCowBQYDK2VuAyEALDeVe-sG8mRY22LsXlPgiwTNs9dbiLrNuA7f3ZMAJ2w%253D%26srv%3Dbylepyau3ty4czmn77q4fglvperknl4bi2eb2fdy2bh4jxtf32kf73yd.onion).
## Conditions of Use of Software and Infrastructure ## Conditions of Use of Software and Infrastructure
@@ -131,7 +138,7 @@ You accept the Conditions of Use of Software and Infrastructure ("Conditions") b
**Traffic and device costs**. You are solely responsible for the traffic and device costs that you incur while using our Applications, and any associated taxes. **Traffic and device costs**. You are solely responsible for the traffic and device costs that you incur while using our Applications, and any associated taxes.
**Legal and acceptable usage**. You agree to use our Applications only for legal and acceptable purposes. You will not use (or assist others in using) our Applications in ways that: 1) violate or infringe the rights of Software users, SimpleX Chat Ltd, or others, including privacy, publicity, intellectual property, or other proprietary rights; 2) involve sending illegal or impermissible communications, e.g. spam. While we cannot access content or identify messages or groups, in some cases the links to the illegal or impermissible communications available via our Applications can be shared publicly on social media or websites. We reserve the right to remove such links from the preset servers and disrupt the conversations that send illegal content via our servers, whether they were reported by the users or discovered by our team. **Legal usage**. You agree to use our Applications only for legal purposes. You will not use (or assist others in using) our Applications in ways that: 1) violate or infringe the rights of Software users, SimpleX Chat Ltd, or others, including privacy, publicity, intellectual property, or other proprietary rights; 2) involve sending illegal communications, e.g. spam. While we cannot access content or identify messages or groups, in some cases the links to the illegal communications available via our Applications can be shared publicly on social media or websites. We reserve the right to remove such links from the preset servers and disrupt the conversations that send illegal content via our servers, whether they were reported by the users or discovered by our team.
**Damage to SimpleX Chat Ltd**. You must not (or assist others to) access, use, modify, distribute, transfer, or exploit our Applications in unauthorized manners, or in ways that harm Software users, SimpleX Chat Ltd, our Infrastructure, or any other systems. For example, you must not 1) access our Infrastructure or systems without authorization, in any way other than by using the Software; 2) disrupt the integrity or performance of our Infrastructure; 3) collect information about our users in any manner; or 4) sell, rent, or charge for our Infrastructure. This does not prohibit you from providing your own Infrastructure to others, whether free or for a fee, as long as you do not violate these Conditions and AGPLv3 license, including the requirement to publish any modifications of the relay server software. **Damage to SimpleX Chat Ltd**. You must not (or assist others to) access, use, modify, distribute, transfer, or exploit our Applications in unauthorized manners, or in ways that harm Software users, SimpleX Chat Ltd, our Infrastructure, or any other systems. For example, you must not 1) access our Infrastructure or systems without authorization, in any way other than by using the Software; 2) disrupt the integrity or performance of our Infrastructure; 3) collect information about our users in any manner; or 4) sell, rent, or charge for our Infrastructure. This does not prohibit you from providing your own Infrastructure to others, whether free or for a fee, as long as you do not violate these Conditions and AGPLv3 license, including the requirement to publish any modifications of the relay server software.
@@ -165,4 +172,4 @@ You accept the Conditions of Use of Software and Infrastructure ("Conditions") b
**Ending these conditions**. You may end these Conditions with SimpleX Chat Ltd at any time by deleting our Applications from your devices and discontinuing use of our Infrastructure. The provisions related to Licenses, Disclaimers, Limitation of Liability, Resolving dispute, Availability, Changes to the conditions, Enforcing the conditions, and Ending these conditions will survive termination of your relationship with SimpleX Chat Ltd. **Ending these conditions**. You may end these Conditions with SimpleX Chat Ltd at any time by deleting our Applications from your devices and discontinuing use of our Infrastructure. The provisions related to Licenses, Disclaimers, Limitation of Liability, Resolving dispute, Availability, Changes to the conditions, Enforcing the conditions, and Ending these conditions will survive termination of your relationship with SimpleX Chat Ltd.
Updated February 24, 2024 Updated April 24, 2024
+11 -6
View File
@@ -4,7 +4,7 @@
[![Join on Reddit](https://img.shields.io/reddit/subreddit-subscribers/SimpleXChat?style=social)](https://www.reddit.com/r/SimpleXChat) [![Join on Reddit](https://img.shields.io/reddit/subreddit-subscribers/SimpleXChat?style=social)](https://www.reddit.com/r/SimpleXChat)
<a rel="me" href="https://mastodon.social/@simplex">![Follow on Mastodon](https://img.shields.io/mastodon/follow/108619463746856738?domain=https%3A%2F%2Fmastodon.social&style=social)</a> <a rel="me" href="https://mastodon.social/@simplex">![Follow on Mastodon](https://img.shields.io/mastodon/follow/108619463746856738?domain=https%3A%2F%2Fmastodon.social&style=social)</a>
| 30/03/2023 | EN, [FR](/docs/lang/fr/README.md), [CZ](/docs/lang/cs/README.md) | | 30/03/2023 | EN, [FR](/docs/lang/fr/README.md), [CZ](/docs/lang/cs/README.md), [PL](/docs/lang/pl/README.md) |
<img src="images/simplex-chat-logo.svg" alt="SimpleX logo" width="100%"> <img src="images/simplex-chat-logo.svg" alt="SimpleX logo" width="100%">
@@ -74,7 +74,7 @@ Messages not following these rules will be deleted, the right to send messages m
You can join an English-speaking users group if you want to ask any questions: [#SimpleX users group](https://simplex.chat/contact#/?v=1-4&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2Fos8FftfoV8zjb2T89fUEjJtF7y64p5av%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAQqMgh0fw2lPhjn3PDIEfAKA_E0-gf8Hr8zzhYnDivRs%253D%26srv%3Dbylepyau3ty4czmn77q4fglvperknl4bi2eb2fdy2bh4jxtf32kf73yd.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22lBPiveK2mjfUH43SN77R0w%3D%3D%22%7D) You can join an English-speaking users group if you want to ask any questions: [#SimpleX users group](https://simplex.chat/contact#/?v=1-4&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2Fos8FftfoV8zjb2T89fUEjJtF7y64p5av%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAQqMgh0fw2lPhjn3PDIEfAKA_E0-gf8Hr8zzhYnDivRs%253D%26srv%3Dbylepyau3ty4czmn77q4fglvperknl4bi2eb2fdy2bh4jxtf32kf73yd.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22lBPiveK2mjfUH43SN77R0w%3D%3D%22%7D)
There is also a group [#simplex-devs](https://simplex.chat/contact#/?v=1-2&smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2F6eHqy7uAbZPOcA6qBtrQgQquVlt4Ll91%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAqV_pg3FF00L98aCXp4D3bOs4Sxv_UmSd-gb0juVoQVs%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22XonlixcHBIb2ijCehbZoiw%3D%3D%22%7D) for developers who build on SimpleX platform: There is also a group [#simplex-devs](https://simplex.chat/contact#/?v=1-4&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FvYCRjIflKNMGYlfTkuHe4B40qSlQ0439%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAHNdcqNbzXZhyMoSBjT2R0-Eb1EPaLyUg3KZjn-kmM1w%253D%26srv%3Dbylepyau3ty4czmn77q4fglvperknl4bi2eb2fdy2bh4jxtf32kf73yd.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22PD20tcXjw7IpkkMCfR6HLA%3D%3D%22%7D) for developers who build on SimpleX platform:
- chat bots and automations - chat bots and automations
- integrations with other apps - integrations with other apps
@@ -234,6 +234,10 @@ You can use SimpleX with your own servers and still communicate with people usin
Recent and important updates: Recent and important updates:
[Apr 26, 2024. SimpleX network: legally binding transparency, v5.7 released with better calls and messages.](./blog/20240426-simplex-legally-binding-transparency-v5-7-better-user-experience.md)
[Mar 23, 2024. SimpleX network: real privacy and stable profits, non-profits for protocols, v5.6 released with quantum resistant e2e encryption and simple profile migration.](./blog/20240323-simplex-network-privacy-non-profit-v5-6-quantum-resistant-e2e-encryption-simple-migration.md)
[Mar 14, 2024. SimpleX Chat v5.6 beta: adding quantum resistance to Signal double ratchet algorithm.](./blog/20240314-simplex-chat-v5-6-quantum-resistance-signal-double-ratchet-algorithm.md) [Mar 14, 2024. SimpleX Chat v5.6 beta: adding quantum resistance to Signal double ratchet algorithm.](./blog/20240314-simplex-chat-v5-6-quantum-resistance-signal-double-ratchet-algorithm.md)
[Jan 24, 2024. SimpleX Chat: free infrastructure from Linode, v5.5 released with private notes, group history and a simpler UX to connect.](./blog/20240124-simplex-chat-infrastructure-costs-v5-5-simplex-ux-private-notes-group-history.md) [Jan 24, 2024. SimpleX Chat: free infrastructure from Linode, v5.5 released with private notes, group history and a simpler UX to connect.](./blog/20240124-simplex-chat-infrastructure-costs-v5-5-simplex-ux-private-notes-group-history.md)
@@ -377,8 +381,9 @@ Please also join [#simplex-devs](https://simplex.chat/contact#/?v=1-2&smp=smp%3A
- ✅ Using mobile profiles from the desktop app. - ✅ Using mobile profiles from the desktop app.
- ✅ Private notes. - ✅ Private notes.
- ✅ Improve sending videos (including encryption of locally stored videos). - ✅ Improve sending videos (including encryption of locally stored videos).
- ✅ Post-quantum resistant key exchange in double ratchet protocol.
- 🏗 Improve stability and reduce battery usage.
- 🏗 Improve experience for the new users. - 🏗 Improve experience for the new users.
- 🏗 Post-quantum resistant key exchange in double ratchet protocol.
- 🏗 Large groups, communities and public channels. - 🏗 Large groups, communities and public channels.
- 🏗 Message delivery relay for senders (to conceal IP address from the recipients' servers and to reduce the traffic). - 🏗 Message delivery relay for senders (to conceal IP address from the recipients' servers and to reduce the traffic).
- Privacy & security slider - a simple way to set all settings at once. - Privacy & security slider - a simple way to set all settings at once.
@@ -409,13 +414,13 @@ We have never provided or have been requested access to our servers or any infor
We do not log IP addresses of the users and we do not perform any traffic correlation on our servers. If transport level security is critical you must use Tor or some other similar network to access messaging servers. We will be improving the client applications to reduce the opportunities for traffic correlation. We do not log IP addresses of the users and we do not perform any traffic correlation on our servers. If transport level security is critical you must use Tor or some other similar network to access messaging servers. We will be improving the client applications to reduce the opportunities for traffic correlation.
Please read more in [Terms & privacy policy](./PRIVACY.md). Please read more in [Privacy Policy](./PRIVACY.md).
## Security contact ## Security contact
To report a security vulnerability, please send us email to chat@simplex.chat. We will coordinate the fix and disclosure. Please do NOT report security vulnerabilities via GitHub issues. Please see our [Security Policy](./docs/SECURITY.md) on how to report security vulnerabilities to us. We will coordinate the fix and disclosure.
Please treat any findings of possible traffic correlation attacks allowing to correlate two different conversations to the same user, other than covered in [the threat model](https://github.com/simplex-chat/simplexmq/blob/stable/protocol/overview-tjr.md#threat-model), as security vulnerabilities, and follow this disclosure process. Please do NOT report security vulnerabilities via GitHub issues.
## License ## License
+1 -1
View File
@@ -179,7 +179,7 @@ class AudioPlayer: NSObject, AVAudioPlayerDelegate {
if playback { if playback {
if AVAudioSession.sharedInstance().category != .playback { if AVAudioSession.sharedInstance().category != .playback {
logger.log("AudioSession: playback") logger.log("AudioSession: playback")
try? AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, options: .duckOthers) try? AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, options: [.duckOthers, .allowBluetooth, .allowAirPlay, .allowBluetoothA2DP])
} }
} else { } else {
if AVAudioSession.sharedInstance().category != .soloAmbient { if AVAudioSession.sharedInstance().category != .soloAmbient {
+19
View File
@@ -103,6 +103,7 @@ final class ChatModel: ObservableObject {
// tracks keyboard height via subscription in AppDelegate // tracks keyboard height via subscription in AppDelegate
@Published var keyboardHeight: CGFloat = 0 @Published var keyboardHeight: CGFloat = 0
@Published var pasteboardHasStrings: Bool = UIPasteboard.general.hasStrings @Published var pasteboardHasStrings: Bool = UIPasteboard.general.hasStrings
@Published var networkInfo = UserNetworkInfo(networkType: .other, online: true)
var messageDelivery: Dictionary<Int64, () -> Void> = [:] var messageDelivery: Dictionary<Int64, () -> Void> = [:]
@@ -778,6 +779,24 @@ final class Chat: ObservableObject, Identifiable {
var viewId: String { get { "\(chatInfo.id) \(created.timeIntervalSince1970)" } } var viewId: String { get { "\(chatInfo.id) \(created.timeIntervalSince1970)" } }
func groupFeatureEnabled(_ feature: GroupFeature) -> Bool {
if case let .group(groupInfo) = self.chatInfo {
let p = groupInfo.fullGroupPreferences
return switch feature {
case .timedMessages: p.timedMessages.on
case .directMessages: p.directMessages.on(for: groupInfo.membership)
case .fullDelete: p.fullDelete.on
case .reactions: p.reactions.on
case .voice: p.voice.on(for: groupInfo.membership)
case .files: p.files.on(for: groupInfo.membership)
case .simplexLinks: p.simplexLinks.on(for: groupInfo.membership)
case .history: p.history.on
}
} else {
return true
}
}
public static var sampleData: Chat = Chat(chatInfo: ChatInfo.sampleData.direct, chatItems: []) public static var sampleData: Chat = Chat(chatInfo: ChatInfo.sampleData.direct, chatItems: [])
} }
@@ -0,0 +1,73 @@
//
// NetworkObserver.swift
// SimpleX (iOS)
//
// Created by Avently on 05.04.2024.
// Copyright © 2024 SimpleX Chat. All rights reserved.
//
import Foundation
import Network
import SimpleXChat
class NetworkObserver {
static let shared = NetworkObserver()
private let queue: DispatchQueue = DispatchQueue(label: "chat.simplex.app.NetworkObserver")
private var prevInfo: UserNetworkInfo? = nil
private var monitor: NWPathMonitor?
private let monitorLock: DispatchQueue = DispatchQueue(label: "chat.simplex.app.monitorLock")
func restartMonitor() {
monitorLock.sync {
monitor?.cancel()
let mon = NWPathMonitor()
mon.pathUpdateHandler = { [weak self] path in
self?.networkPathChanged(path: path)
}
mon.start(queue: queue)
monitor = mon
}
}
private func networkPathChanged(path: NWPath) {
let info = UserNetworkInfo(
networkType: networkTypeFromPath(path),
online: path.status == .satisfied
)
if (prevInfo != info) {
prevInfo = info
setNetworkInfo(info)
}
}
private func networkTypeFromPath(_ path: NWPath) -> UserNetworkType {
if path.usesInterfaceType(.wiredEthernet) {
.ethernet
} else if path.usesInterfaceType(.wifi) {
.wifi
} else if path.usesInterfaceType(.cellular) {
.cellular
} else if path.usesInterfaceType(.other) {
.other
} else {
.none
}
}
private static var networkObserver: NetworkObserver? = nil
private func setNetworkInfo(_ info: UserNetworkInfo) {
logger.debug("setNetworkInfo Network changed: \(String(describing: info))")
DispatchQueue.main.sync {
ChatModel.shared.networkInfo = info
}
if !hasChatCtrl() { return }
self.monitorLock.sync {
do {
try apiSetNetworkInfo(info)
} catch let err {
logger.error("setNetworkInfo error: \(responseError(err))")
}
}
}
}
+120 -87
View File
@@ -21,6 +21,8 @@ public let CURRENT_CHAT_VERSION: Int = 2
// version range that supports establishing direct connection with a group member (xGrpDirectInvVRange in core) // version range that supports establishing direct connection with a group member (xGrpDirectInvVRange in core)
public let CREATE_MEMBER_CONTACT_VRANGE = VersionRange(minVersion: 2, maxVersion: CURRENT_CHAT_VERSION) public let CREATE_MEMBER_CONTACT_VRANGE = VersionRange(minVersion: 2, maxVersion: CURRENT_CHAT_VERSION)
private let networkStatusesLock = DispatchQueue(label: "chat.simplex.app.network-statuses.lock")
enum TerminalItem: Identifiable { enum TerminalItem: Identifiable {
case cmd(Date, ChatCommand) case cmd(Date, ChatCommand)
case resp(Date, ChatResponse) case resp(Date, ChatResponse)
@@ -270,18 +272,6 @@ func apiGetAppSettings(settings: AppSettings) throws -> AppSettings {
throw r throw r
} }
func apiSetPQEncryption(_ enable: Bool) throws {
let r = chatSendCmdSync(.apiSetPQEncryption(enable: enable))
if case .cmdOk = r { return }
throw r
}
func apiSetContactPQ(_ contactId: Int64, _ enable: Bool) async throws -> Contact {
let r = await chatSendCmd(.apiSetContactPQ(contactId: contactId, enable: enable))
if case let .contactPQAllowed(_, contact, _) = r { return contact }
throw r
}
func apiExportArchive(config: ArchiveConfig) async throws { func apiExportArchive(config: ArchiveConfig) async throws {
try await sendCommandOkResp(.apiExportArchive(config: config)) try await sendCommandOkResp(.apiExportArchive(config: config))
} }
@@ -351,11 +341,20 @@ func apiGetChatItemInfo(type: ChatType, id: Int64, itemId: Int64) async throws -
throw r throw r
} }
func apiForwardChatItem(toChatType: ChatType, toChatId: Int64, fromChatType: ChatType, fromChatId: Int64, itemId: Int64, ttl: Int?) async -> ChatItem? {
let cmd: ChatCommand = .apiForwardChatItem(toChatType: toChatType, toChatId: toChatId, fromChatType: fromChatType, fromChatId: fromChatId, itemId: itemId, ttl: ttl)
return await processSendMessageCmd(toChatType: toChatType, cmd: cmd)
}
func apiSendMessage(type: ChatType, id: Int64, file: CryptoFile?, quotedItemId: Int64?, msg: MsgContent, live: Bool = false, ttl: Int? = nil) async -> ChatItem? { func apiSendMessage(type: ChatType, id: Int64, file: CryptoFile?, quotedItemId: Int64?, msg: MsgContent, live: Bool = false, ttl: Int? = nil) async -> ChatItem? {
let chatModel = ChatModel.shared
let cmd: ChatCommand = .apiSendMessage(type: type, id: id, file: file, quotedItemId: quotedItemId, msg: msg, live: live, ttl: ttl) let cmd: ChatCommand = .apiSendMessage(type: type, id: id, file: file, quotedItemId: quotedItemId, msg: msg, live: live, ttl: ttl)
return await processSendMessageCmd(toChatType: type, cmd: cmd)
}
private func processSendMessageCmd(toChatType: ChatType, cmd: ChatCommand) async -> ChatItem? {
let chatModel = ChatModel.shared
let r: ChatResponse let r: ChatResponse
if type == .direct { if toChatType == .direct {
var cItem: ChatItem? = nil var cItem: ChatItem? = nil
let endTask = beginBGTask({ let endTask = beginBGTask({
if let cItem = cItem { if let cItem = cItem {
@@ -395,7 +394,7 @@ func apiCreateChatItem(noteFolderId: Int64, file: CryptoFile?, msg: MsgContent)
} }
private func sendMessageErrorAlert(_ r: ChatResponse) { private func sendMessageErrorAlert(_ r: ChatResponse) {
logger.error("apiSendMessage error: \(String(describing: r))") logger.error("send message error: \(String(describing: r))")
AlertManager.shared.showAlertMsg( AlertManager.shared.showAlertMsg(
title: "Error sending message", title: "Error sending message",
message: "Error: \(String(describing: r))" message: "Error: \(String(describing: r))"
@@ -532,6 +531,12 @@ func setNetworkConfig(_ cfg: NetCfg, ctrl: chat_ctrl? = nil) throws {
throw r throw r
} }
func apiSetNetworkInfo(_ networkInfo: UserNetworkInfo) throws {
let r = chatSendCmdSync(.apiSetNetworkInfo(networkInfo: networkInfo))
if case .cmdOk = r { return }
throw r
}
func reconnectAllServers() async throws { func reconnectAllServers() async throws {
try await sendCommandOkResp(.reconnectAllServers) try await sendCommandOkResp(.reconnectAllServers)
} }
@@ -922,14 +927,19 @@ func standaloneFileInfo(url: String, ctrl: chat_ctrl? = nil) async -> MigrationF
} }
} }
func receiveFile(user: any UserLike, fileId: Int64, auto: Bool = false) async { func receiveFile(user: any UserLike, fileId: Int64, userApprovedRelays: Bool = false, auto: Bool = false) async {
if let chatItem = await apiReceiveFile(fileId: fileId, encrypted: privacyEncryptLocalFilesGroupDefault.get(), auto: auto) { if let chatItem = await apiReceiveFile(
fileId: fileId,
userApprovedRelays: userApprovedRelays || !privacyAskToApproveRelaysGroupDefault.get(),
encrypted: privacyEncryptLocalFilesGroupDefault.get(),
auto: auto
) {
await chatItemSimpleUpdate(user, chatItem) await chatItemSimpleUpdate(user, chatItem)
} }
} }
func apiReceiveFile(fileId: Int64, encrypted: Bool, inline: Bool? = nil, auto: Bool = false) async -> AChatItem? { func apiReceiveFile(fileId: Int64, userApprovedRelays: Bool, encrypted: Bool, inline: Bool? = nil, auto: Bool = false) async -> AChatItem? {
let r = await chatSendCmd(.receiveFile(fileId: fileId, encrypted: encrypted, inline: inline)) let r = await chatSendCmd(.receiveFile(fileId: fileId, userApprovedRelays: userApprovedRelays, encrypted: encrypted, inline: inline))
let am = AlertManager.shared let am = AlertManager.shared
if case let .rcvFileAccepted(_, chatItem) = r { return chatItem } if case let .rcvFileAccepted(_, chatItem) = r { return chatItem }
if case .rcvFileAcceptedSndCancelled = r { if case .rcvFileAcceptedSndCancelled = r {
@@ -942,19 +952,50 @@ func apiReceiveFile(fileId: Int64, encrypted: Bool, inline: Bool? = nil, auto: B
} }
} else if let networkErrorAlert = networkErrorAlert(r) { } else if let networkErrorAlert = networkErrorAlert(r) {
logger.error("apiReceiveFile network error: \(String(describing: r))") logger.error("apiReceiveFile network error: \(String(describing: r))")
am.showAlert(networkErrorAlert) if !auto {
am.showAlert(networkErrorAlert)
}
} else { } else {
switch chatError(r) { switch chatError(r) {
case .fileCancelled: case .fileCancelled:
logger.debug("apiReceiveFile ignoring fileCancelled error") logger.debug("apiReceiveFile ignoring fileCancelled error")
case .fileAlreadyReceiving: case .fileAlreadyReceiving:
logger.debug("apiReceiveFile ignoring fileAlreadyReceiving error") logger.debug("apiReceiveFile ignoring fileAlreadyReceiving error")
case let .fileNotApproved(fileId, unknownServers):
logger.debug("apiReceiveFile fileNotApproved error")
if !auto {
let srvs = unknownServers.map { s in
if let srv = parseServerAddress(s), !srv.hostnames.isEmpty {
srv.hostnames[0]
} else {
serverHost(s)
}
}
am.showAlert(Alert(
title: Text("Unknown servers!"),
message: Text("Without Tor or VPN, your IP address will be visible to these XFTP relays: \(srvs.sorted().joined(separator: ", "))."),
primaryButton: .default(
Text("Download"),
action: {
Task {
logger.debug("apiReceiveFile fileNotApproved alert - in Task")
if let user = ChatModel.shared.currentUser {
await receiveFile(user: user, fileId: fileId, userApprovedRelays: true)
}
}
}
),
secondaryButton: .cancel()
))
}
default: default:
logger.error("apiReceiveFile error: \(String(describing: r))") logger.error("apiReceiveFile error: \(String(describing: r))")
am.showAlertMsg( if !auto {
title: "Error receiving file", am.showAlertMsg(
message: "Error: \(String(describing: r))" title: "Error receiving file",
) message: "Error: \(String(describing: r))"
)
}
} }
} }
return nil return nil
@@ -1295,6 +1336,7 @@ func initializeChat(start: Bool, confirmStart: Bool = false, dbKey: String? = ni
defer { m.ctrlInitInProgress = false } defer { m.ctrlInitInProgress = false }
(m.chatDbEncrypted, m.chatDbStatus) = chatMigrateInit(dbKey, confirmMigrations: confirmMigrations) (m.chatDbEncrypted, m.chatDbStatus) = chatMigrateInit(dbKey, confirmMigrations: confirmMigrations)
if m.chatDbStatus != .ok { return } if m.chatDbStatus != .ok { return }
NetworkObserver.shared.restartMonitor()
// If we migrated successfully means previous re-encryption process on database level finished successfully too // If we migrated successfully means previous re-encryption process on database level finished successfully too
if encryptionStartedDefault.get() { if encryptionStartedDefault.get() {
encryptionStartedDefault.set(false) encryptionStartedDefault.set(false)
@@ -1302,7 +1344,6 @@ func initializeChat(start: Bool, confirmStart: Bool = false, dbKey: String? = ni
try apiSetTempFolder(tempFolder: getTempFilesDirectory().path) try apiSetTempFolder(tempFolder: getTempFilesDirectory().path)
try apiSetFilesFolder(filesFolder: getAppFilesDirectory().path) try apiSetFilesFolder(filesFolder: getAppFilesDirectory().path)
try apiSetEncryptLocalFiles(privacyEncryptLocalFilesGroupDefault.get()) try apiSetEncryptLocalFiles(privacyEncryptLocalFilesGroupDefault.get())
try apiSetPQEncryption(pqExperimentalEnabledDefault.get())
m.chatInitialized = true m.chatInitialized = true
m.currentUser = try apiGetActiveUser() m.currentUser = try apiGetActiveUser()
if m.currentUser == nil { if m.currentUser == nil {
@@ -1460,6 +1501,8 @@ class ChatReceiver {
private var receiveMessages = true private var receiveMessages = true
private var _lastMsgTime = Date.now private var _lastMsgTime = Date.now
var messagesChannel: ((ChatResponse) -> Void)? = nil
static let shared = ChatReceiver() static let shared = ChatReceiver()
var lastMsgTime: Date { get { _lastMsgTime } } var lastMsgTime: Date { get { _lastMsgTime } }
@@ -1473,14 +1516,15 @@ class ChatReceiver {
} }
func receiveMsgLoop() async { func receiveMsgLoop() async {
// TODO use function that has timeout while self.receiveMessages {
if let msg = await chatRecvMsg() { if let msg = await chatRecvMsg() {
self._lastMsgTime = .now self._lastMsgTime = .now
await processReceivedMsg(msg) await processReceivedMsg(msg)
} if let messagesChannel {
if self.receiveMessages { messagesChannel(msg)
}
}
_ = try? await Task.sleep(nanoseconds: 7_500_000) _ = try? await Task.sleep(nanoseconds: 7_500_000)
await receiveMsgLoop()
} }
} }
@@ -1568,34 +1612,30 @@ func processReceivedMsg(_ res: ChatResponse) async {
m.removeChat(mergedContact.id) m.removeChat(mergedContact.id)
} }
} }
case let .contactsSubscribed(_, contactRefs):
await updateContactsStatus(contactRefs, status: .connected)
case let .contactsDisconnected(_, contactRefs):
await updateContactsStatus(contactRefs, status: .disconnected)
case let .contactSubSummary(_, contactSubscriptions):
await MainActor.run {
for sub in contactSubscriptions {
// no need to update contact here, and it is slow
// if active(user) {
// m.updateContact(sub.contact)
// }
if let err = sub.contactError {
processContactSubError(sub.contact, err)
} else {
m.setContactNetworkStatus(sub.contact, .connected)
}
}
}
case let .networkStatus(status, connections): case let .networkStatus(status, connections):
await MainActor.run { // dispatch queue to synchronize access
networkStatusesLock.sync {
var ns = m.networkStatuses
// slow loop is on the background thread
for cId in connections { for cId in connections {
m.networkStatuses[cId] = status ns[cId] = status
}
// fast model update is on the main thread
DispatchQueue.main.sync {
m.networkStatuses = ns
} }
} }
case let .networkStatuses(_, statuses): () case let .networkStatuses(_, statuses): ()
await MainActor.run { // dispatch queue to synchronize access
networkStatusesLock.sync {
var ns = m.networkStatuses
// slow loop is on the background thread
for s in statuses { for s in statuses {
m.networkStatuses[s.agentConnId] = s.networkStatus ns[s.agentConnId] = s.networkStatus
}
// fast model update is on the main thread
DispatchQueue.main.sync {
m.networkStatuses = ns
} }
} }
case let .newChatItem(user, aChatItem): case let .newChatItem(user, aChatItem):
@@ -1795,7 +1835,6 @@ func processReceivedMsg(_ res: ChatResponse) async {
} }
case let .sndFileCompleteXFTP(user, aChatItem, _): case let .sndFileCompleteXFTP(user, aChatItem, _):
await chatItemSimpleUpdate(user, aChatItem) await chatItemSimpleUpdate(user, aChatItem)
Task { cleanupFile(aChatItem) }
case let .sndFileError(user, aChatItem, _): case let .sndFileError(user, aChatItem, _):
if let aChatItem = aChatItem { if let aChatItem = aChatItem {
await chatItemSimpleUpdate(user, aChatItem) await chatItemSimpleUpdate(user, aChatItem)
@@ -1846,21 +1885,35 @@ func processReceivedMsg(_ res: ChatResponse) async {
} }
case .chatSuspended: case .chatSuspended:
chatSuspended() chatSuspended()
case let .contactSwitch(_, contact, switchProgress): case let .contactSwitch(user, contact, switchProgress):
await MainActor.run { if active(user) {
m.updateContactConnectionStats(contact, switchProgress.connectionStats) await MainActor.run {
m.updateContactConnectionStats(contact, switchProgress.connectionStats)
}
} }
case let .groupMemberSwitch(_, groupInfo, member, switchProgress): case let .groupMemberSwitch(user, groupInfo, member, switchProgress):
await MainActor.run { if active(user) {
m.updateGroupMemberConnectionStats(groupInfo, member, switchProgress.connectionStats) await MainActor.run {
m.updateGroupMemberConnectionStats(groupInfo, member, switchProgress.connectionStats)
}
} }
case let .contactRatchetSync(_, contact, ratchetSyncProgress): case let .contactRatchetSync(user, contact, ratchetSyncProgress):
await MainActor.run { if active(user) {
m.updateContactConnectionStats(contact, ratchetSyncProgress.connectionStats) await MainActor.run {
m.updateContactConnectionStats(contact, ratchetSyncProgress.connectionStats)
}
} }
case let .groupMemberRatchetSync(_, groupInfo, member, ratchetSyncProgress): case let .groupMemberRatchetSync(user, groupInfo, member, ratchetSyncProgress):
await MainActor.run { if active(user) {
m.updateGroupMemberConnectionStats(groupInfo, member, ratchetSyncProgress.connectionStats) await MainActor.run {
m.updateGroupMemberConnectionStats(groupInfo, member, ratchetSyncProgress.connectionStats)
}
}
case let .contactDisabled(user, contact):
if active(user) {
await MainActor.run {
m.updateContact(contact)
}
} }
case let .remoteCtrlFound(remoteCtrl, ctrlAppInfo_, appVersion, compatible): case let .remoteCtrlFound(remoteCtrl, ctrlAppInfo_, appVersion, compatible):
await MainActor.run { await MainActor.run {
@@ -1946,26 +1999,6 @@ func chatItemSimpleUpdate(_ user: any UserLike, _ aChatItem: AChatItem) async {
} }
} }
func updateContactsStatus(_ contactRefs: [ContactRef], status: NetworkStatus) async {
let m = ChatModel.shared
await MainActor.run {
for c in contactRefs {
m.networkStatuses[c.agentConnId] = status
}
}
}
func processContactSubError(_ contact: Contact, _ chatError: ChatError) {
let m = ChatModel.shared
var err: String
switch chatError {
case .errorAgent(agentError: .BROKER(_, .NETWORK)): err = "network"
case .errorAgent(agentError: .SMP(smpErr: .AUTH)): err = "contact deleted"
default: err = String(describing: chatError)
}
m.setContactNetworkStatus(contact, .error(connectionError: err))
}
func refreshCallInvitations() throws { func refreshCallInvitations() throws {
let m = ChatModel.shared let m = ChatModel.shared
let callInvitations = try justRefreshCallInvitations() let callInvitations = try justRefreshCallInvitations()
@@ -9,6 +9,7 @@
import SwiftUI import SwiftUI
import WebKit import WebKit
import SimpleXChat import SimpleXChat
import AVFoundation
struct ActiveCallView: View { struct ActiveCallView: View {
@EnvironmentObject var m: ChatModel @EnvironmentObject var m: ChatModel
@@ -21,6 +22,7 @@ struct ActiveCallView: View {
@Binding var canConnectCall: Bool @Binding var canConnectCall: Bool
@State var prevColorScheme: ColorScheme = .dark @State var prevColorScheme: ColorScheme = .dark
@State var pipShown = false @State var pipShown = false
@State var wasConnected = false
var body: some View { var body: some View {
ZStack(alignment: .topLeading) { ZStack(alignment: .topLeading) {
@@ -69,6 +71,11 @@ struct ActiveCallView: View {
Task { await m.callCommand.setClient(nil) } Task { await m.callCommand.setClient(nil) }
AppDelegate.keepScreenOn(false) AppDelegate.keepScreenOn(false)
client?.endCall() client?.endCall()
CallSoundsPlayer.shared.stop()
try? AVAudioSession.sharedInstance().setCategory(.soloAmbient)
if (wasConnected) {
CallSoundsPlayer.shared.vibrate(long: true)
}
} }
.background(m.activeCallViewIsCollapsed ? .clear : .black) .background(m.activeCallViewIsCollapsed ? .clear : .black)
// Quite a big delay when opening/closing the view when a scheme changes (globally) this way. It's not needed when CallKit is used since status bar is green with white text on it // Quite a big delay when opening/closing the view when a scheme changes (globally) this way. It's not needed when CallKit is used since status bar is green with white text on it
@@ -103,6 +110,11 @@ struct ActiveCallView: View {
call.callState = .invitationSent call.callState = .invitationSent
call.localCapabilities = capabilities call.localCapabilities = capabilities
} }
if call.supportsVideo && !AVAudioSession.sharedInstance().hasExternalAudioDevice() {
try? AVAudioSession.sharedInstance().setCategory(.playback, options: [.allowBluetooth, .allowAirPlay, .allowBluetoothA2DP])
}
CallSoundsPlayer.shared.startConnectingCallSound()
activeCallWaitDeliveryReceipt()
} }
case let .offer(offer, iceCandidates, capabilities): case let .offer(offer, iceCandidates, capabilities):
Task { Task {
@@ -126,6 +138,7 @@ struct ActiveCallView: View {
} }
await MainActor.run { await MainActor.run {
call.callState = .negotiated call.callState = .negotiated
CallSoundsPlayer.shared.stop()
} }
} }
case let .ice(iceCandidates): case let .ice(iceCandidates):
@@ -144,6 +157,10 @@ struct ActiveCallView: View {
: CallController.shared.reportIncomingCall(call: call, connectedAt: nil) : CallController.shared.reportIncomingCall(call: call, connectedAt: nil)
call.callState = .connected call.callState = .connected
call.connectedAt = .now call.connectedAt = .now
if !wasConnected {
CallSoundsPlayer.shared.vibrate(long: false)
wasConnected = true
}
} }
if state.connectionState == "closed" { if state.connectionState == "closed" {
closeCallView(client) closeCallView(client)
@@ -161,6 +178,10 @@ struct ActiveCallView: View {
call.callState = .connected call.callState = .connected
call.connectionInfo = connectionInfo call.connectionInfo = connectionInfo
call.connectedAt = .now call.connectedAt = .now
if !wasConnected {
CallSoundsPlayer.shared.vibrate(long: false)
wasConnected = true
}
case .ended: case .ended:
closeCallView(client) closeCallView(client)
call.callState = .ended call.callState = .ended
@@ -187,6 +208,22 @@ struct ActiveCallView: View {
} }
} }
private func activeCallWaitDeliveryReceipt() {
ChatReceiver.shared.messagesChannel = { msg in
guard let call = ChatModel.shared.activeCall, call.callState == .invitationSent else {
ChatReceiver.shared.messagesChannel = nil
return
}
if case let .chatItemStatusUpdated(_, msg) = msg,
msg.chatInfo.id == call.contact.id,
case .sndCall = msg.chatItem.content,
case .sndRcvd = msg.chatItem.meta.itemStatus {
CallSoundsPlayer.shared.startInCallSound()
ChatReceiver.shared.messagesChannel = nil
}
}
}
private func closeCallView(_ client: WebRTCClient) { private func closeCallView(_ client: WebRTCClient) {
if m.activeCall != nil { if m.activeCall != nil {
m.showCallView = false m.showCallView = false
@@ -198,6 +235,7 @@ struct ActiveCallOverlay: View {
@EnvironmentObject var chatModel: ChatModel @EnvironmentObject var chatModel: ChatModel
@ObservedObject var call: Call @ObservedObject var call: Call
var client: WebRTCClient var client: WebRTCClient
@ObservedObject private var deviceManager = CallAudioDeviceManager.shared
var body: some View { var body: some View {
VStack { VStack {
@@ -213,7 +251,16 @@ struct ActiveCallOverlay: View {
HStack { HStack {
toggleAudioButton() toggleAudioButton()
Spacer() Spacer()
Color.clear.frame(width: 40, height: 40) if deviceManager.availableInputs.allSatisfy({ $0.portType == .builtInMic }) {
toggleSpeakerButton()
.frame(width: 40, height: 40)
} else if call.hasMedia {
AudioDevicePicker()
.scaleEffect(2)
.frame(maxWidth: 40, maxHeight: 40)
} else {
Color.clear.frame(width: 40, height: 40)
}
Spacer() Spacer()
endCallButton() endCallButton()
Spacer() Spacer()
@@ -239,9 +286,7 @@ struct ActiveCallOverlay: View {
.foregroundColor(.white.opacity(0.8)) .foregroundColor(.white.opacity(0.8))
} }
VStack { VStack {
ProfileImage(imageStr: call.contact.profile.image) ProfileImage(imageStr: call.contact.profile.image, size: 192)
.scaledToFit()
.frame(width: 192, height: 192)
audioCallInfoView(call) audioCallInfoView(call)
} }
.foregroundColor(.white) .foregroundColor(.white)
@@ -256,14 +301,33 @@ struct ActiveCallOverlay: View {
toggleAudioButton() toggleAudioButton()
.frame(maxWidth: .infinity, alignment: .leading) .frame(maxWidth: .infinity, alignment: .leading)
endCallButton() endCallButton()
toggleSpeakerButton() // Check if the only input is microphone. And in this case show toggle button,
.frame(maxWidth: .infinity, alignment: .trailing) // If there are more inputs, it probably means something like bluetooth headphones are available
// and in this case show iOS button for choosing different output.
// There is no way to get available outputs, only inputs
if deviceManager.availableInputs.allSatisfy({ $0.portType == .builtInMic }) {
toggleSpeakerButton()
.frame(maxWidth: .infinity, alignment: .trailing)
} else if call.hasMedia {
AudioDevicePicker()
.scaleEffect(2)
.frame(maxWidth: 50, maxHeight: 40)
.frame(maxWidth: .infinity, alignment: .trailing)
} else {
Color.clear.frame(width: 50, height: 40)
}
} }
.padding(.bottom, 60) .padding(.bottom, 60)
.padding(.horizontal, 48) .padding(.horizontal, 48)
} }
} }
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
.onAppear {
deviceManager.start()
}
.onDisappear {
deviceManager.stop()
}
} }
private func audioCallInfoView(_ call: Call) -> some View { private func audioCallInfoView(_ call: Call) -> some View {
@@ -341,12 +405,17 @@ struct ActiveCallOverlay: View {
private func toggleSpeakerButton() -> some View { private func toggleSpeakerButton() -> some View {
controlButton(call, call.speakerEnabled ? "speaker.wave.2.fill" : "speaker.wave.1.fill") { controlButton(call, call.speakerEnabled ? "speaker.wave.2.fill" : "speaker.wave.1.fill") {
Task { Task {
client.setSpeakerEnabledAndConfigureSession(!call.speakerEnabled) let speakerEnabled = AVAudioSession.sharedInstance().currentRoute.outputs.first?.portType == .builtInSpeaker
client.setSpeakerEnabledAndConfigureSession(!speakerEnabled)
DispatchQueue.main.async { DispatchQueue.main.async {
call.speakerEnabled = !call.speakerEnabled call.speakerEnabled = !speakerEnabled
} }
} }
} }
.onAppear {
deviceManager.call = call
//call.speakerEnabled = AVAudioSession.sharedInstance().currentRoute.outputs.first?.portType == .builtInSpeaker
}
} }
private func toggleVideoButton() -> some View { private func toggleVideoButton() -> some View {
@@ -0,0 +1,25 @@
//
// MPVolumeView.swift
// SimpleX (iOS)
//
// Created by Stanislav on 24.04.2024.
// Copyright © 2024 SimpleX Chat. All rights reserved.
//
import Foundation
import SwiftUI
import UIKit
import AVKit
struct AudioDevicePicker: UIViewRepresentable {
func makeUIView(context: Context) -> some UIView {
let v = AVRoutePickerView(frame: .zero)
v.activeTintColor = .white
v.tintColor = .white
return v
}
func updateUIView(_ uiView: UIViewType, context: Context) {
}
}
@@ -0,0 +1,67 @@
//
// CallAudioDeviceManager.swift
// SimpleX (iOS)
//
// Created by Avently on 23.04.2024.
// Copyright © 2024 SimpleX Chat. All rights reserved.
//
import Foundation
import SwiftUI
import SimpleXChat
import AVKit
import WebRTC
class CallAudioDeviceManager: ObservableObject {
static let shared = CallAudioDeviceManager()
let audioSession: AVAudioSession
let nc = NotificationCenter.default
var call: Call?
var timer: Timer? = nil
// Actually, only one output
@Published var outputs: [AVAudioSessionPortDescription]
@Published var currentDevice: AVAudioSessionPortDescription? = nil
// All devices that can record audio (the ones that can play audio are not included)
@Published var availableInputs: [AVAudioSessionPortDescription] = []
init(_ audioSession: AVAudioSession? = nil) {
self.audioSession = audioSession ?? RTCAudioSession.sharedInstance().session
self.outputs = self.audioSession.currentRoute.outputs
self.availableInputs = self.audioSession.availableInputs ?? []
}
func reloadDevices() {
outputs = audioSession.currentRoute.outputs
currentDevice = audioSession.currentRoute.outputs.first
availableInputs = audioSession.availableInputs ?? []
call?.speakerEnabled = currentDevice?.portType == .builtInSpeaker
// Workaround situation:
// have bluetooth device connected, choosing speaker, disconnecting bluetooth device. In this case iOS will not post notification, so do it manually
timer?.invalidate()
if availableInputs.contains(where: { $0.portType != .builtInReceiver && $0.portType != .builtInSpeaker }) {
timer = Timer.scheduledTimer(withTimeInterval: 2, repeats: false) { t in
self.reloadDevices()
}
}
}
@objc func audioCallback(notification: Notification) {
reloadDevices()
logger.debug("Changes in devices, current audio devices: \(String(describing: self.availableInputs.map({ $0.portType.rawValue }))), output: \(String(describing: self.currentDevice?.portType.rawValue))")
}
func start() {
nc.addObserver(self, selector: #selector(audioCallback), name: AVAudioSession.routeChangeNotification, object: nil)
}
func stop() {
nc.removeObserver(self, name: AVAudioSession.routeChangeNotification, object: nil)
timer?.invalidate()
}
}
@@ -103,7 +103,23 @@ class CallController: NSObject, CXProviderDelegate, PKPushRegistryDelegate, Obse
RTCAudioSession.sharedInstance().audioSessionDidActivate(audioSession) RTCAudioSession.sharedInstance().audioSessionDidActivate(audioSession)
RTCAudioSession.sharedInstance().isAudioEnabled = true RTCAudioSession.sharedInstance().isAudioEnabled = true
do { do {
try audioSession.setCategory(.playAndRecord, mode: .voiceChat, options: .mixWithOthers) let supportsVideo = ChatModel.shared.activeCall?.supportsVideo == true
if supportsVideo {
try audioSession.setCategory(.playAndRecord, mode: .videoChat, options: [.defaultToSpeaker, .mixWithOthers, .allowBluetooth, .allowAirPlay, .allowBluetoothA2DP])
} else {
try audioSession.setCategory(.playAndRecord, mode: .voiceChat, options: [.mixWithOthers, .allowBluetooth, .allowAirPlay, .allowBluetoothA2DP])
}
// Without any delay sound is not playing from speaker or external device in incoming call
Task {
for i in 0 ... 3 {
try? await Task.sleep(nanoseconds: UInt64(i) * 300_000000)
if let preferred = audioSession.preferredInputDevice() {
await MainActor.run { try? audioSession.setPreferredInput(preferred) }
} else if supportsVideo {
await MainActor.run { try? audioSession.overrideOutputAudioPort(.speaker) }
}
}
}
logger.debug("audioSession category set") logger.debug("audioSession category set")
try audioSession.setActive(true) try audioSession.setActive(true)
logger.debug("audioSession activated") logger.debug("audioSession activated")
@@ -30,8 +30,7 @@ struct IncomingCallView: View {
VStack(alignment: .leading, spacing: 6) { VStack(alignment: .leading, spacing: 6) {
HStack { HStack {
if m.users.count > 1 { if m.users.count > 1 {
ProfileImage(imageStr: invitation.user.image, color: .white) ProfileImage(imageStr: invitation.user.image, size: 24, color: .white)
.frame(width: 24, height: 24)
} }
Image(systemName: invitation.callType.media == .video ? "video.fill" : "phone.fill").foregroundColor(.green) Image(systemName: invitation.callType.media == .video ? "video.fill" : "phone.fill").foregroundColor(.green)
Text(invitation.callTypeText) Text(invitation.callTypeText)
@@ -8,6 +8,7 @@
import Foundation import Foundation
import AVFoundation import AVFoundation
import UIKit
class SoundPlayer { class SoundPlayer {
static let shared = SoundPlayer() static let shared = SoundPlayer()
@@ -43,3 +44,63 @@ class SoundPlayer {
audioPlayer = nil audioPlayer = nil
} }
} }
class CallSoundsPlayer {
static let shared = CallSoundsPlayer()
private var audioPlayer: AVAudioPlayer?
private var playerTask: Task = Task {}
private func start(_ soundName: String, delayMs: Double) {
audioPlayer?.stop()
playerTask.cancel()
logger.debug("start \(soundName)")
guard let path = Bundle.main.path(forResource: soundName, ofType: "mp3", inDirectory: "sounds") else {
logger.debug("start: file not found")
return
}
do {
let player = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: path))
if player.prepareToPlay() {
audioPlayer = player
}
} catch {
logger.debug("start: AVAudioPlayer error \(error.localizedDescription)")
}
playerTask = Task {
while let player = audioPlayer {
player.play()
do {
try await Task.sleep(nanoseconds: UInt64((player.duration * 1_000_000_000) + delayMs * 1_000_000))
} catch {
break
}
}
}
}
func startConnectingCallSound() {
start("connecting_call", delayMs: 0)
}
func startInCallSound() {
// Taken from https://github.com/TelegramOrg/Telegram-Android
// https://github.com/TelegramOrg/Telegram-Android/blob/master/LICENSE
start("in_call", delayMs: 1000)
}
func stop() {
playerTask.cancel()
audioPlayer?.stop()
audioPlayer = nil
}
func vibrate(long: Bool) {
// iOS just don't want to vibrate more than once after a short period of time, and all 'styles' feel the same
if long {
AudioServicesPlayAlertSound(kSystemSoundID_Vibrate)
} else {
UIImpactFeedbackGenerator(style: .heavy).impactOccurred()
}
}
}
+4 -3
View File
@@ -431,17 +431,18 @@ struct RTCIceServer: Codable, Equatable {
} }
// the servers are expected in this format: // the servers are expected in this format:
// stun:stun.simplex.im:443?transport=tcp // stuns:stun.simplex.im:443?transport=tcp
// turn:private:yleob6AVkiNI87hpR94Z@turn.simplex.im:443?transport=tcp // turns:private2:Hxuq2QxUjnhj96Zq2r4HjqHRj@turn.simplex.im:443?transport=tcp
func parseRTCIceServer(_ str: String) -> RTCIceServer? { func parseRTCIceServer(_ str: String) -> RTCIceServer? {
var s = replaceScheme(str, "stun:") var s = replaceScheme(str, "stun:")
s = replaceScheme(s, "stuns:")
s = replaceScheme(s, "turn:") s = replaceScheme(s, "turn:")
s = replaceScheme(s, "turns:") s = replaceScheme(s, "turns:")
if let u: URL = URL(string: s), if let u: URL = URL(string: s),
let scheme = u.scheme, let scheme = u.scheme,
let host = u.host, let host = u.host,
let port = u.port, let port = u.port,
u.path == "" && (scheme == "stun" || scheme == "turn" || scheme == "turns") { u.path == "" && (scheme == "stun" || scheme == "stuns" || scheme == "turn" || scheme == "turns") {
let query = u.query == nil || u.query == "" ? "" : "?" + (u.query ?? "") let query = u.query == nil || u.query == "" ? "" : "?" + (u.query ?? "")
return RTCIceServer( return RTCIceServer(
urls: ["\(scheme):\(host):\(port)\(query)"], urls: ["\(scheme):\(host):\(port)\(query)"],
+33 -8
View File
@@ -49,7 +49,7 @@ final class WebRTCClient: NSObject, RTCVideoViewDelegate, RTCFrameEncryptorDeleg
} }
private let rtcAudioSession = RTCAudioSession.sharedInstance() private let rtcAudioSession = RTCAudioSession.sharedInstance()
private let audioQueue = DispatchQueue(label: "audio") private let audioQueue = DispatchQueue(label: "chat.simplex.app.audio")
private var sendCallResponse: (WVAPIMessage) async -> Void private var sendCallResponse: (WVAPIMessage) async -> Void
var activeCall: Binding<Call?> var activeCall: Binding<Call?>
private var localRendererAspectRatio: Binding<CGFloat?> private var localRendererAspectRatio: Binding<CGFloat?>
@@ -65,14 +65,14 @@ final class WebRTCClient: NSObject, RTCVideoViewDelegate, RTCFrameEncryptorDeleg
self.localRendererAspectRatio = localRendererAspectRatio self.localRendererAspectRatio = localRendererAspectRatio
rtcAudioSession.useManualAudio = CallController.useCallKit() rtcAudioSession.useManualAudio = CallController.useCallKit()
rtcAudioSession.isAudioEnabled = !CallController.useCallKit() rtcAudioSession.isAudioEnabled = !CallController.useCallKit()
logger.debug("WebRTCClient: rtcAudioSession has manual audio \(self.rtcAudioSession.useManualAudio) and audio enabled \(self.rtcAudioSession.isAudioEnabled)}") logger.debug("WebRTCClient: rtcAudioSession has manual audio \(self.rtcAudioSession.useManualAudio) and audio enabled \(self.rtcAudioSession.isAudioEnabled)")
super.init() super.init()
} }
let defaultIceServers: [WebRTC.RTCIceServer] = [ let defaultIceServers: [WebRTC.RTCIceServer] = [
WebRTC.RTCIceServer(urlStrings: ["stun:stun.simplex.im:443"]), WebRTC.RTCIceServer(urlStrings: ["stuns:stun.simplex.im:443"]),
WebRTC.RTCIceServer(urlStrings: ["turn:turn.simplex.im:443?transport=udp"], username: "private", credential: "yleob6AVkiNI87hpR94Z"), //WebRTC.RTCIceServer(urlStrings: ["turns:turn.simplex.im:443?transport=udp"], username: "private2", credential: "Hxuq2QxUjnhj96Zq2r4HjqHRj"),
WebRTC.RTCIceServer(urlStrings: ["turn:turn.simplex.im:443?transport=tcp"], username: "private", credential: "yleob6AVkiNI87hpR94Z"), WebRTC.RTCIceServer(urlStrings: ["turns:turn.simplex.im:443?transport=tcp"], username: "private2", credential: "Hxuq2QxUjnhj96Zq2r4HjqHRj"),
] ]
func initializeCall(_ iceServers: [WebRTC.RTCIceServer]?, _ mediaType: CallMediaType, _ aesKey: String?, _ relay: Bool?) -> Call { func initializeCall(_ iceServers: [WebRTC.RTCIceServer]?, _ mediaType: CallMediaType, _ aesKey: String?, _ relay: Bool?) -> Call {
@@ -605,9 +605,23 @@ extension WebRTCClient {
self.rtcAudioSession.unlockForConfiguration() self.rtcAudioSession.unlockForConfiguration()
} }
do { do {
try self.rtcAudioSession.setCategory(AVAudioSession.Category.playAndRecord.rawValue) let hasExternalAudioDevice = self.rtcAudioSession.session.hasExternalAudioDevice()
try self.rtcAudioSession.setMode(AVAudioSession.Mode.voiceChat.rawValue) if enabled {
try self.rtcAudioSession.overrideOutputAudioPort(enabled ? .speaker : .none) try self.rtcAudioSession.setCategory(AVAudioSession.Category.playAndRecord.rawValue, with: [.defaultToSpeaker, .allowBluetooth, .allowAirPlay, .allowBluetoothA2DP])
try self.rtcAudioSession.setMode(AVAudioSession.Mode.videoChat.rawValue)
if hasExternalAudioDevice, let preferred = self.rtcAudioSession.session.preferredInputDevice() {
try self.rtcAudioSession.setPreferredInput(preferred)
} else {
try self.rtcAudioSession.overrideOutputAudioPort(.speaker)
}
} else {
try self.rtcAudioSession.setCategory(AVAudioSession.Category.playAndRecord.rawValue, with: [.allowBluetooth, .allowAirPlay, .allowBluetoothA2DP])
try self.rtcAudioSession.setMode(AVAudioSession.Mode.voiceChat.rawValue)
try self.rtcAudioSession.overrideOutputAudioPort(.none)
}
if hasExternalAudioDevice {
logger.debug("WebRTCClient: configuring session with external device available, skip configuring speaker")
}
try self.rtcAudioSession.setActive(true) try self.rtcAudioSession.setActive(true)
logger.debug("WebRTCClient: configuring session with speaker enabled \(enabled) success") logger.debug("WebRTCClient: configuring session with speaker enabled \(enabled) success")
} catch let error { } catch let error {
@@ -658,6 +672,17 @@ extension WebRTCClient {
} }
} }
extension AVAudioSession {
func hasExternalAudioDevice() -> Bool {
availableInputs?.allSatisfy({ $0.portType == .builtInMic }) != true
}
func preferredInputDevice() -> AVAudioSessionPortDescription? {
// logger.debug("Preferred input device: \(String(describing: self.availableInputs?.filter({ $0.portType != .builtInMic })))")
return availableInputs?.filter({ $0.portType != .builtInMic }).last
}
}
struct CustomRTCSessionDescription: Codable { struct CustomRTCSessionDescription: Codable {
public var type: RTCSdpType? public var type: RTCSdpType?
public var sdp: String? public var sdp: String?
@@ -25,11 +25,11 @@ struct ChatInfoToolbar: View {
} }
ChatInfoImage( ChatInfoImage(
chat: chat, chat: chat,
size: imageSize,
color: colorScheme == .dark color: colorScheme == .dark
? chatImageColorDark ? chatImageColorDark
: chatImageColorLight : chatImageColorLight
) )
.frame(width: imageSize, height: imageSize)
.padding(.trailing, 4) .padding(.trailing, 4)
VStack { VStack {
let t = Text(cInfo.displayName).font(.headline) let t = Text(cInfo.displayName).font(.headline)
+3 -55
View File
@@ -49,7 +49,7 @@ func localizedInfoRow(_ title: LocalizedStringKey, _ value: LocalizedStringKey)
} }
} }
private func serverHost(_ s: String) -> String { func serverHost(_ s: String) -> String {
if let i = s.range(of: "@")?.lowerBound { if let i = s.range(of: "@")?.lowerBound {
return String(s[i...].dropFirst()) return String(s[i...].dropFirst())
} else { } else {
@@ -103,7 +103,6 @@ struct ChatInfoView: View {
@State private var sendReceipts = SendReceipts.userDefault(true) @State private var sendReceipts = SendReceipts.userDefault(true)
@State private var sendReceiptsUserDefault = true @State private var sendReceiptsUserDefault = true
@AppStorage(DEFAULT_DEVELOPER_TOOLS) private var developerTools = false @AppStorage(DEFAULT_DEVELOPER_TOOLS) private var developerTools = false
@AppStorage(GROUP_DEFAULT_PQ_EXPERIMENTAL_ENABLED, store: groupDefaults) private var pqExperimentalEnabled = false
enum ChatInfoViewAlert: Identifiable { enum ChatInfoViewAlert: Identifiable {
case clearChatAlert case clearChatAlert
@@ -111,7 +110,6 @@ struct ChatInfoView: View {
case switchAddressAlert case switchAddressAlert
case abortSwitchAddressAlert case abortSwitchAddressAlert
case syncConnectionForceAlert case syncConnectionForceAlert
case allowContactPQEncryptionAlert
case error(title: LocalizedStringKey, error: LocalizedStringKey = "") case error(title: LocalizedStringKey, error: LocalizedStringKey = "")
var id: String { var id: String {
@@ -121,7 +119,6 @@ struct ChatInfoView: View {
case .switchAddressAlert: return "switchAddressAlert" case .switchAddressAlert: return "switchAddressAlert"
case .abortSwitchAddressAlert: return "abortSwitchAddressAlert" case .abortSwitchAddressAlert: return "abortSwitchAddressAlert"
case .syncConnectionForceAlert: return "syncConnectionForceAlert" case .syncConnectionForceAlert: return "syncConnectionForceAlert"
case .allowContactPQEncryptionAlert: return "allowContactPQEncryptionAlert"
case let .error(title, _): return "error \(title)" case let .error(title, _): return "error \(title)"
} }
} }
@@ -168,19 +165,9 @@ struct ChatInfoView: View {
} }
.disabled(!contact.ready || !contact.active) .disabled(!contact.ready || !contact.active)
if pqExperimentalEnabled, if let conn = contact.activeConn {
let conn = contact.activeConn {
Section { Section {
infoRow(Text(String("E2E encryption")), conn.connPQEnabled ? "Quantum resistant" : "Standard") infoRow(Text(String("E2E encryption")), conn.connPQEnabled ? "Quantum resistant" : "Standard")
if !conn.pqEncryption {
allowPQButton()
}
} header: {
Text(String("Quantum resistant E2E encryption"))
} footer: {
if !conn.pqEncryption {
Text(String("After allowing quantum resistant encryption, it will be enabled after several messages if your contact also allows it."))
}
} }
} }
@@ -256,7 +243,6 @@ struct ChatInfoView: View {
case .switchAddressAlert: return switchAddressAlert(switchContactAddress) case .switchAddressAlert: return switchAddressAlert(switchContactAddress)
case .abortSwitchAddressAlert: return abortSwitchAddressAlert(abortSwitchContactAddress) case .abortSwitchAddressAlert: return abortSwitchAddressAlert(abortSwitchContactAddress)
case .syncConnectionForceAlert: return syncConnectionForceAlert({ syncContactConnection(force: true) }) case .syncConnectionForceAlert: return syncConnectionForceAlert({ syncContactConnection(force: true) })
case .allowContactPQEncryptionAlert: return allowContactPQEncryptionAlert()
case let .error(title, error): return mkAlert(title: title, message: error) case let .error(title, error): return mkAlert(title: title, message: error)
} }
} }
@@ -285,8 +271,7 @@ struct ChatInfoView: View {
private func contactInfoHeader() -> some View { private func contactInfoHeader() -> some View {
VStack { VStack {
let cInfo = chat.chatInfo let cInfo = chat.chatInfo
ChatInfoImage(chat: chat, color: Color(uiColor: .tertiarySystemFill)) ChatInfoImage(chat: chat, size: 192, color: Color(uiColor: .tertiarySystemFill))
.frame(width: 192, height: 192)
.padding(.top, 12) .padding(.top, 12)
.padding() .padding()
if contact.verified { if contact.verified {
@@ -430,15 +415,6 @@ struct ChatInfoView: View {
} }
} }
private func allowPQButton() -> some View {
Button {
alert = .allowContactPQEncryptionAlert
} label: {
Label(String("Allow PQ encryption"), systemImage: "exclamationmark.triangle")
.foregroundColor(.orange)
}
}
private func networkStatusRow() -> some View { private func networkStatusRow() -> some View {
HStack { HStack {
Text("Network status") Text("Network status")
@@ -572,34 +548,6 @@ struct ChatInfoView: View {
} }
} }
} }
private func allowContactPQEncryption() {
Task {
do {
let ct = try await apiSetContactPQ(contact.apiId, true)
contact = ct
await MainActor.run {
chatModel.updateContact(contact)
dismiss()
}
} catch let error {
logger.error("allowContactPQEncryption apiSetContactPQ error: \(responseError(error))")
let a = getErrorAlert(error, "Error allowing contact PQ encryption")
await MainActor.run {
alert = .error(title: a.title, error: a.message)
}
}
}
}
func allowContactPQEncryptionAlert() -> Alert {
Alert(
title: Text(String("Allow quantum resistant encryption?")),
message: Text(String("This is an experimental feature, it is not recommended to enable it for important chats.")),
primaryButton: .destructive(Text(String("Allow")), action: allowContactPQEncryption),
secondaryButton: .cancel()
)
}
} }
func switchAddressAlert(_ switchAddress: @escaping () -> Void) -> Alert { func switchAddressAlert(_ switchAddress: @escaping () -> Void) -> Alert {
@@ -35,9 +35,7 @@ struct CICallItemView: View {
case .error: missedCallIcon(sent).foregroundColor(.orange) case .error: missedCallIcon(sent).foregroundColor(.orange)
} }
chatItem.timestampText CIMetaView(chat: chat, chatItem: chatItem, showStatus: false, showEdited: false)
.font(.caption)
.foregroundColor(.secondary)
.padding(.bottom, 8) .padding(.bottom, 8)
.padding(.horizontal, 12) .padding(.horizontal, 12)
} }
@@ -11,6 +11,7 @@ import SimpleXChat
struct CIChatFeatureView: View { struct CIChatFeatureView: View {
@EnvironmentObject var m: ChatModel @EnvironmentObject var m: ChatModel
@ObservedObject var chat: Chat
var chatItem: ChatItem var chatItem: ChatItem
@Binding var revealed: Bool @Binding var revealed: Bool
var feature: Feature var feature: Feature
@@ -18,7 +19,7 @@ struct CIChatFeatureView: View {
var iconColor: Color var iconColor: Color
var body: some View { var body: some View {
if !revealed, let fs = mergedFeautures() { if !revealed, let fs = mergedFeatures() {
HStack { HStack {
ForEach(fs, content: featureIconView) ForEach(fs, content: featureIconView)
} }
@@ -47,7 +48,7 @@ struct CIChatFeatureView: View {
} }
} }
private func mergedFeautures() -> [FeatureInfo]? { private func mergedFeatures() -> [FeatureInfo]? {
var fs: [FeatureInfo] = [] var fs: [FeatureInfo] = []
var icons: Set<String> = [] var icons: Set<String> = []
if var i = m.getChatItemIndex(chatItem) { if var i = m.getChatItemIndex(chatItem) {
@@ -67,8 +68,8 @@ struct CIChatFeatureView: View {
switch ci.content { switch ci.content {
case let .rcvChatFeature(feature, enabled, param): FeatureInfo(feature, enabled.iconColor, param) case let .rcvChatFeature(feature, enabled, param): FeatureInfo(feature, enabled.iconColor, param)
case let .sndChatFeature(feature, enabled, param): FeatureInfo(feature, enabled.iconColor, param) case let .sndChatFeature(feature, enabled, param): FeatureInfo(feature, enabled.iconColor, param)
case let .rcvGroupFeature(feature, preference, param): FeatureInfo(feature, preference.enable.iconColor, param) case let .rcvGroupFeature(feature, preference, param, role): FeatureInfo(feature, preference.enabled(role, for: chat.chatInfo.groupInfo?.membership).iconColor, param)
case let .sndGroupFeature(feature, preference, param): FeatureInfo(feature, preference.enable.iconColor, param) case let .sndGroupFeature(feature, preference, param, role): FeatureInfo(feature, preference.enabled(role, for: chat.chatInfo.groupInfo?.membership).iconColor, param)
default: nil default: nil
} }
} }
@@ -103,6 +104,6 @@ struct CIChatFeatureView: View {
struct CIChatFeatureView_Previews: PreviewProvider { struct CIChatFeatureView_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
let enabled = FeatureEnabled(forUser: false, forContact: false) let enabled = FeatureEnabled(forUser: false, forContact: false)
CIChatFeatureView(chatItem: ChatItem.getChatFeatureSample(.fullDelete, enabled), revealed: Binding.constant(true), feature: ChatFeature.fullDelete, iconColor: enabled.iconColor) CIChatFeatureView(chat: Chat.sampleData, chatItem: ChatItem.getChatFeatureSample(.fullDelete, enabled), revealed: Binding.constant(true), feature: ChatFeature.fullDelete, iconColor: enabled.iconColor)
} }
} }
@@ -17,6 +17,7 @@ struct CIEventView: View {
.padding(.horizontal, 6) .padding(.horizontal, 6)
.padding(.vertical, 4) .padding(.vertical, 4)
.textSelection(.disabled) .textSelection(.disabled)
.lineLimit(4)
} }
} }
@@ -60,6 +60,7 @@ struct CIFileView: View {
case .rcvInvitation: return true case .rcvInvitation: return true
case .rcvAccepted: return true case .rcvAccepted: return true
case .rcvTransfer: return false case .rcvTransfer: return false
case .rcvAborted: return true
case .rcvComplete: return true case .rcvComplete: return true
case .rcvCancelled: return false case .rcvCancelled: return false
case .rcvError: return false case .rcvError: return false
@@ -69,21 +70,14 @@ struct CIFileView: View {
return false return false
} }
private func fileSizeValid() -> Bool {
if let file = file {
return file.fileSize <= getMaxFileSize(file.fileProtocol)
}
return false
}
private func fileAction() { private func fileAction() {
logger.debug("CIFileView fileAction") logger.debug("CIFileView fileAction")
if let file = file { if let file = file {
switch (file.fileStatus) { switch (file.fileStatus) {
case .rcvInvitation: case .rcvInvitation, .rcvAborted:
if fileSizeValid() { if fileSizeValid(file) {
Task { Task {
logger.debug("CIFileView fileAction - in .rcvInvitation, in Task") logger.debug("CIFileView fileAction - in .rcvInvitation, .rcvAborted, in Task")
if let user = m.currentUser { if let user = m.currentUser {
await receiveFile(user: user, fileId: file.fileId) await receiveFile(user: user, fileId: file.fileId)
} }
@@ -143,7 +137,7 @@ struct CIFileView: View {
case .sndCancelled: fileIcon("doc.fill", innerIcon: "xmark", innerIconSize: 10) case .sndCancelled: fileIcon("doc.fill", innerIcon: "xmark", innerIconSize: 10)
case .sndError: fileIcon("doc.fill", innerIcon: "xmark", innerIconSize: 10) case .sndError: fileIcon("doc.fill", innerIcon: "xmark", innerIconSize: 10)
case .rcvInvitation: case .rcvInvitation:
if fileSizeValid() { if fileSizeValid(file) {
fileIcon("arrow.down.doc.fill", color: .accentColor) fileIcon("arrow.down.doc.fill", color: .accentColor)
} else { } else {
fileIcon("doc.fill", color: .orange, innerIcon: "exclamationmark", innerIconSize: 12) fileIcon("doc.fill", color: .orange, innerIcon: "exclamationmark", innerIconSize: 12)
@@ -155,6 +149,8 @@ struct CIFileView: View {
} else { } else {
progressView() progressView()
} }
case .rcvAborted:
fileIcon("doc.fill", color: .accentColor, innerIcon: "exclamationmark.arrow.circlepath", innerIconSize: 12)
case .rcvComplete: fileIcon("doc.fill") case .rcvComplete: fileIcon("doc.fill")
case .rcvCancelled: fileIcon("doc.fill", innerIcon: "xmark", innerIconSize: 10) case .rcvCancelled: fileIcon("doc.fill", innerIcon: "xmark", innerIconSize: 10)
case .rcvError: fileIcon("doc.fill", innerIcon: "xmark", innerIconSize: 10) case .rcvError: fileIcon("doc.fill", innerIcon: "xmark", innerIconSize: 10)
@@ -201,6 +197,13 @@ struct CIFileView: View {
} }
} }
func fileSizeValid(_ file: CIFile?) -> Bool {
if let file = file {
return file.fileSize <= getMaxFileSize(file.fileProtocol)
}
return false
}
func saveCryptoFile(_ fileSource: CryptoFile) { func saveCryptoFile(_ fileSource: CryptoFile) {
if let cfArgs = fileSource.cryptoArgs { if let cfArgs = fileSource.cryptoArgs {
let url = getAppFilePath(fileSource.filePath) let url = getAppFilePath(fileSource.filePath)
@@ -12,6 +12,7 @@ import SimpleXChat
struct CIGroupInvitationView: View { struct CIGroupInvitationView: View {
@EnvironmentObject var chatModel: ChatModel @EnvironmentObject var chatModel: ChatModel
@Environment(\.colorScheme) var colorScheme @Environment(\.colorScheme) var colorScheme
@ObservedObject var chat: Chat
var chatItem: ChatItem var chatItem: ChatItem
var groupInvitation: CIGroupInvitation var groupInvitation: CIGroupInvitation
var memberRole: GroupMemberRole var memberRole: GroupMemberRole
@@ -20,6 +21,8 @@ struct CIGroupInvitationView: View {
@State private var inProgress = false @State private var inProgress = false
@State private var progressByTimeout = false @State private var progressByTimeout = false
@AppStorage(DEFAULT_SHOW_SENT_VIA_RPOXY) private var showSentViaProxy = false
var body: some View { var body: some View {
let action = !chatItem.chatDir.sent && groupInvitation.status == .pending let action = !chatItem.chatDir.sent && groupInvitation.status == .pending
let v = ZStack(alignment: .bottomTrailing) { let v = ZStack(alignment: .bottomTrailing) {
@@ -37,16 +40,22 @@ struct CIGroupInvitationView: View {
VStack(alignment: .leading, spacing: 2) { VStack(alignment: .leading, spacing: 2) {
groupInvitationText() groupInvitationText()
.overlay(DetermineWidth()) .overlay(DetermineWidth())
Text(chatIncognito ? "Tap to join incognito" : "Tap to join") (
.foregroundColor(inProgress ? .secondary : chatIncognito ? .indigo : .accentColor) Text(chatIncognito ? "Tap to join incognito" : "Tap to join")
.font(.callout) .foregroundColor(inProgress ? .secondary : chatIncognito ? .indigo : .accentColor)
.padding(.trailing, 60) .font(.callout)
.overlay(DetermineWidth()) + Text(" ")
+ ciMetaText(chatItem.meta, chatTTL: nil, encrypted: nil, transparent: true, showStatus: false, showEdited: false, showViaProxy: showSentViaProxy)
)
.overlay(DetermineWidth())
} }
} else { } else {
groupInvitationText() (
.padding(.trailing, 60) groupInvitationText()
.overlay(DetermineWidth()) + Text(" ")
+ ciMetaText(chatItem.meta, chatTTL: nil, encrypted: nil, transparent: true, showStatus: false, showEdited: false, showViaProxy: showSentViaProxy)
)
.overlay(DetermineWidth())
} }
} }
.padding(.bottom, 2) .padding(.bottom, 2)
@@ -56,9 +65,7 @@ struct CIGroupInvitationView: View {
} }
} }
chatItem.timestampText CIMetaView(chat: chat, chatItem: chatItem, showStatus: false, showEdited: false)
.font(.caption)
.foregroundColor(.secondary)
} }
.padding(.horizontal, 12) .padding(.horizontal, 12)
.padding(.vertical, 6) .padding(.vertical, 6)
@@ -100,9 +107,9 @@ struct CIGroupInvitationView: View {
ProfileImage( ProfileImage(
imageStr: groupInvitation.groupProfile.image, imageStr: groupInvitation.groupProfile.image,
iconName: "person.2.circle.fill", iconName: "person.2.circle.fill",
size: 44,
color: color color: color
) )
.frame(width: 44, height: 44)
.padding(.trailing, 4) .padding(.trailing, 4)
VStack(alignment: .leading) { VStack(alignment: .leading) {
let p = groupInvitation.groupProfile let p = groupInvitation.groupProfile
@@ -115,7 +122,7 @@ struct CIGroupInvitationView: View {
} }
} }
private func groupInvitationText() -> some View { private func groupInvitationText() -> Text {
Text(groupInvitationStr()) Text(groupInvitationStr())
.font(.callout) .font(.callout)
} }
@@ -137,8 +144,8 @@ struct CIGroupInvitationView: View {
struct CIGroupInvitationView_Previews: PreviewProvider { struct CIGroupInvitationView_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
Group { Group {
CIGroupInvitationView(chatItem: ChatItem.getGroupInvitationSample(), groupInvitation: CIGroupInvitation.getSample(groupProfile: GroupProfile(displayName: "team", fullName: "team")), memberRole: .admin) CIGroupInvitationView(chat: Chat.sampleData, chatItem: ChatItem.getGroupInvitationSample(), groupInvitation: CIGroupInvitation.getSample(groupProfile: GroupProfile(displayName: "team", fullName: "team")), memberRole: .admin)
CIGroupInvitationView(chatItem: ChatItem.getGroupInvitationSample(), groupInvitation: CIGroupInvitation.getSample(status: .accepted), memberRole: .admin) CIGroupInvitationView(chat: Chat.sampleData, chatItem: ChatItem.getGroupInvitationSample(), groupInvitation: CIGroupInvitation.getSample(status: .accepted), memberRole: .admin)
} }
} }
} }
@@ -17,7 +17,6 @@ struct CIImageView: View {
let maxWidth: CGFloat let maxWidth: CGFloat
@Binding var imgWidth: CGFloat? @Binding var imgWidth: CGFloat?
@State var scrollProxy: ScrollViewProxy? @State var scrollProxy: ScrollViewProxy?
@State var metaColor: Color
@State private var showFullScreenImage = false @State private var showFullScreenImage = false
var body: some View { var body: some View {
@@ -38,7 +37,7 @@ struct CIImageView: View {
.onTapGesture { .onTapGesture {
if let file = file { if let file = file {
switch file.fileStatus { switch file.fileStatus {
case .rcvInvitation: case .rcvInvitation, .rcvAborted:
Task { Task {
if let user = m.currentUser { if let user = m.currentUser {
await receiveFile(user: user, fileId: file.fileId) await receiveFile(user: user, fileId: file.fileId)
@@ -70,14 +69,14 @@ struct CIImageView: View {
} }
private func imageView(_ img: UIImage) -> some View { private func imageView(_ img: UIImage) -> some View {
let w = img.size.width <= img.size.height ? maxWidth * 0.75 : img.imageData == nil ? .infinity : maxWidth let w = img.size.width <= img.size.height ? maxWidth * 0.75 : maxWidth
DispatchQueue.main.async { imgWidth = w } DispatchQueue.main.async { imgWidth = w }
return ZStack(alignment: .topTrailing) { return ZStack(alignment: .topTrailing) {
if img.imageData == nil { if img.imageData == nil {
Image(uiImage: img) Image(uiImage: img)
.resizable() .resizable()
.scaledToFit() .scaledToFit()
.frame(maxWidth: w) .frame(width: w)
} else { } else {
SwiftyGif(image: img) SwiftyGif(image: img)
.frame(width: w, height: w * img.size.height / img.size.width) .frame(width: w, height: w * img.size.height / img.size.width)
@@ -103,6 +102,7 @@ struct CIImageView: View {
case .rcvInvitation: fileIcon("arrow.down", 10, 13) case .rcvInvitation: fileIcon("arrow.down", 10, 13)
case .rcvAccepted: fileIcon("ellipsis", 14, 11) case .rcvAccepted: fileIcon("ellipsis", 14, 11)
case .rcvTransfer: progressView() case .rcvTransfer: progressView()
case .rcvAborted: fileIcon("exclamationmark.arrow.circlepath", 14, 11)
case .rcvCancelled: fileIcon("xmark", 10, 13) case .rcvCancelled: fileIcon("xmark", 10, 13)
case .rcvError: fileIcon("xmark", 10, 13) case .rcvError: fileIcon("xmark", 10, 13)
case .invalid: fileIcon("questionmark", 10, 13) case .invalid: fileIcon("questionmark", 10, 13)
@@ -116,7 +116,7 @@ struct CIImageView: View {
.resizable() .resizable()
.aspectRatio(contentMode: .fit) .aspectRatio(contentMode: .fit)
.frame(width: size, height: size) .frame(width: size, height: size)
.foregroundColor(metaColor) .foregroundColor(.white)
.padding(padding) .padding(padding)
} }
@@ -14,6 +14,10 @@ struct CIMetaView: View {
var chatItem: ChatItem var chatItem: ChatItem
var metaColor = Color.secondary var metaColor = Color.secondary
var paleMetaColor = Color(UIColor.tertiaryLabel) var paleMetaColor = Color(UIColor.tertiaryLabel)
var showStatus = true
var showEdited = true
@AppStorage(DEFAULT_SHOW_SENT_VIA_RPOXY) private var showSentViaProxy = false
var body: some View { var body: some View {
if chatItem.isDeletedContent { if chatItem.isDeletedContent {
@@ -25,24 +29,24 @@ struct CIMetaView: View {
switch meta.itemStatus { switch meta.itemStatus {
case let .sndSent(sndProgress): case let .sndSent(sndProgress):
switch sndProgress { switch sndProgress {
case .complete: ciMetaText(meta, chatTTL: ttl, encrypted: encrypted, color: metaColor, sent: .sent) case .complete: ciMetaText(meta, chatTTL: ttl, encrypted: encrypted, color: metaColor, sent: .sent, showStatus: showStatus, showEdited: showEdited, showViaProxy: showSentViaProxy)
case .partial: ciMetaText(meta, chatTTL: ttl, encrypted: encrypted, color: paleMetaColor, sent: .sent) case .partial: ciMetaText(meta, chatTTL: ttl, encrypted: encrypted, color: paleMetaColor, sent: .sent, showStatus: showStatus, showEdited: showEdited, showViaProxy: showSentViaProxy)
} }
case let .sndRcvd(_, sndProgress): case let .sndRcvd(_, sndProgress):
switch sndProgress { switch sndProgress {
case .complete: case .complete:
ZStack { ZStack {
ciMetaText(meta, chatTTL: ttl, encrypted: encrypted, color: metaColor, sent: .rcvd1) ciMetaText(meta, chatTTL: ttl, encrypted: encrypted, color: metaColor, sent: .rcvd1, showStatus: showStatus, showEdited: showEdited, showViaProxy: showSentViaProxy)
ciMetaText(meta, chatTTL: ttl, encrypted: encrypted, color: metaColor, sent: .rcvd2) ciMetaText(meta, chatTTL: ttl, encrypted: encrypted, color: metaColor, sent: .rcvd2, showStatus: showStatus, showEdited: showEdited, showViaProxy: showSentViaProxy)
} }
case .partial: case .partial:
ZStack { ZStack {
ciMetaText(meta, chatTTL: ttl, encrypted: encrypted, color: paleMetaColor, sent: .rcvd1) ciMetaText(meta, chatTTL: ttl, encrypted: encrypted, color: paleMetaColor, sent: .rcvd1, showStatus: showStatus, showEdited: showEdited, showViaProxy: showSentViaProxy)
ciMetaText(meta, chatTTL: ttl, encrypted: encrypted, color: paleMetaColor, sent: .rcvd2) ciMetaText(meta, chatTTL: ttl, encrypted: encrypted, color: paleMetaColor, sent: .rcvd2, showStatus: showStatus, showEdited: showEdited, showViaProxy: showSentViaProxy)
} }
} }
default: default:
ciMetaText(meta, chatTTL: ttl, encrypted: encrypted, color: metaColor) ciMetaText(meta, chatTTL: ttl, encrypted: encrypted, color: metaColor, showStatus: showStatus, showEdited: showEdited, showViaProxy: showSentViaProxy)
} }
} }
} }
@@ -54,9 +58,19 @@ enum SentCheckmark {
case rcvd2 case rcvd2
} }
func ciMetaText(_ meta: CIMeta, chatTTL: Int?, encrypted: Bool?, color: Color = .clear, transparent: Bool = false, sent: SentCheckmark? = nil) -> Text { func ciMetaText(
_ meta: CIMeta,
chatTTL: Int?,
encrypted: Bool?,
color: Color = .clear,
transparent: Bool = false,
sent: SentCheckmark? = nil,
showStatus: Bool = true,
showEdited: Bool = true,
showViaProxy: Bool
) -> Text {
var r = Text("") var r = Text("")
if meta.itemEdited { if showEdited, meta.itemEdited {
r = r + statusIconText("pencil", color) r = r + statusIconText("pencil", color)
} }
if meta.disappearing { if meta.disappearing {
@@ -67,19 +81,24 @@ func ciMetaText(_ meta: CIMeta, chatTTL: Int?, encrypted: Bool?, color: Color =
} }
r = r + Text(" ") r = r + Text(" ")
} }
if let (icon, statusColor) = meta.statusIcon(color) { if showViaProxy, meta.sentViaProxy == true {
let t = Text(Image(systemName: icon)).font(.caption2) r = r + statusIconText("arrow.forward", color.opacity(0.67)).font(.caption2)
let gap = Text(" ").kerning(-1.25) }
let t1 = t.foregroundColor(transparent ? .clear : statusColor.opacity(0.67)) if showStatus {
switch sent { if let (icon, statusColor) = meta.statusIcon(color) {
case nil: r = r + t1 let t = Text(Image(systemName: icon)).font(.caption2)
case .sent: r = r + t1 + gap let gap = Text(" ").kerning(-1.25)
case .rcvd1: r = r + t.foregroundColor(transparent ? .clear : statusColor.opacity(0.67)) + gap let t1 = t.foregroundColor(transparent ? .clear : statusColor.opacity(0.67))
case .rcvd2: r = r + gap + t1 switch sent {
case nil: r = r + t1
case .sent: r = r + t1 + gap
case .rcvd1: r = r + t.foregroundColor(transparent ? .clear : statusColor.opacity(0.67)) + gap
case .rcvd2: r = r + gap + t1
}
r = r + Text(" ")
} else if !meta.disappearing {
r = r + statusIconText("circlebadge.fill", .clear) + Text(" ")
} }
r = r + Text(" ")
} else if !meta.disappearing {
r = r + statusIconText("circlebadge.fill", .clear) + Text(" ")
} }
if let enc = encrypted { if let enc = encrypted {
r = r + statusIconText(enc ? "lock" : "lock.open", color) + Text(" ") r = r + statusIconText(enc ? "lock" : "lock.open", color) + Text(" ")
@@ -19,6 +19,8 @@ struct CIRcvDecryptionError: View {
var chatItem: ChatItem var chatItem: ChatItem
@State private var alert: CIRcvDecryptionErrorAlert? @State private var alert: CIRcvDecryptionErrorAlert?
@AppStorage(DEFAULT_SHOW_SENT_VIA_RPOXY) private var showSentViaProxy = false
enum CIRcvDecryptionErrorAlert: Identifiable { enum CIRcvDecryptionErrorAlert: Identifiable {
case syncAllowedAlert(_ syncConnection: () -> Void) case syncAllowedAlert(_ syncConnection: () -> Void)
case syncNotSupportedContactAlert case syncNotSupportedContactAlert
@@ -119,7 +121,7 @@ struct CIRcvDecryptionError: View {
.foregroundColor(syncSupported ? .accentColor : .secondary) .foregroundColor(syncSupported ? .accentColor : .secondary)
.font(.callout) .font(.callout)
+ Text(" ") + Text(" ")
+ ciMetaText(chatItem.meta, chatTTL: nil, encrypted: nil, transparent: true) + ciMetaText(chatItem.meta, chatTTL: nil, encrypted: nil, transparent: true, showViaProxy: showSentViaProxy)
) )
} }
.padding(.horizontal, 12) .padding(.horizontal, 12)
@@ -140,7 +142,7 @@ struct CIRcvDecryptionError: View {
.foregroundColor(.red) .foregroundColor(.red)
.italic() .italic()
+ Text(" ") + Text(" ")
+ ciMetaText(chatItem.meta, chatTTL: nil, encrypted: nil, transparent: true) + ciMetaText(chatItem.meta, chatTTL: nil, encrypted: nil, transparent: true, showViaProxy: showSentViaProxy)
} }
.padding(.horizontal, 12) .padding(.horizontal, 12)
CIMetaView(chat: chat, chatItem: chatItem) CIMetaView(chat: chat, chatItem: chatItem)
@@ -69,7 +69,7 @@ struct CIVideoView: View {
.onTapGesture { .onTapGesture {
if let file = file { if let file = file {
switch file.fileStatus { switch file.fileStatus {
case .rcvInvitation: case .rcvInvitation, .rcvAborted:
receiveFileIfValidSize(file: file, receiveFile: receiveFile) receiveFileIfValidSize(file: file, receiveFile: receiveFile)
case .rcvAccepted: case .rcvAccepted:
switch file.fileProtocol { switch file.fileProtocol {
@@ -95,7 +95,7 @@ struct CIVideoView: View {
} }
durationProgress() durationProgress()
} }
if let file = file, case .rcvInvitation = file.fileStatus { if let file = file, showDownloadButton(file.fileStatus) {
Button { Button {
receiveFileIfValidSize(file: file, receiveFile: receiveFile) receiveFileIfValidSize(file: file, receiveFile: receiveFile)
} label: { } label: {
@@ -105,6 +105,14 @@ struct CIVideoView: View {
} }
} }
private func showDownloadButton(_ fileStatus: CIFileStatus) -> Bool {
switch fileStatus {
case .rcvInvitation: true
case .rcvAborted: true
default: false
}
}
private func videoViewEncrypted(_ file: CIFile, _ defaultPreview: UIImage, _ duration: Int) -> some View { private func videoViewEncrypted(_ file: CIFile, _ defaultPreview: UIImage, _ duration: Int) -> some View {
return ZStack(alignment: .topTrailing) { return ZStack(alignment: .topTrailing) {
ZStack(alignment: .center) { ZStack(alignment: .center) {
@@ -126,7 +134,7 @@ struct CIVideoView: View {
if !decryptionInProgress { if !decryptionInProgress {
Button { Button {
decrypt(file: file) { decrypt(file: file) {
if let decrypted = urlDecrypted { if urlDecrypted != nil {
videoPlaying = true videoPlaying = true
player?.play() player?.play()
} }
@@ -243,13 +251,13 @@ struct CIVideoView: View {
} }
private func imageView(_ img: UIImage) -> some View { private func imageView(_ img: UIImage) -> some View {
let w = img.size.width <= img.size.height ? maxWidth * 0.75 : .infinity let w = img.size.width <= img.size.height ? maxWidth * 0.75 : maxWidth
DispatchQueue.main.async { videoWidth = w } DispatchQueue.main.async { videoWidth = w }
return ZStack(alignment: .topTrailing) { return ZStack(alignment: .topTrailing) {
Image(uiImage: img) Image(uiImage: img)
.resizable() .resizable()
.scaledToFit() .scaledToFit()
.frame(maxWidth: w) .frame(width: w)
loadingIndicator() loadingIndicator()
} }
} }
@@ -280,6 +288,7 @@ struct CIVideoView: View {
} else { } else {
progressView() progressView()
} }
case .rcvAborted: fileIcon("exclamationmark.arrow.circlepath", 14, 11)
case .rcvCancelled: fileIcon("xmark", 10, 13) case .rcvCancelled: fileIcon("xmark", 10, 13)
case .rcvError: fileIcon("xmark", 10, 13) case .rcvError: fileIcon("xmark", 10, 13)
case .invalid: fileIcon("questionmark", 10, 13) case .invalid: fileIcon("questionmark", 10, 13)
@@ -318,10 +327,10 @@ struct CIVideoView: View {
} }
// TODO encrypt: where file size is checked? // TODO encrypt: where file size is checked?
private func receiveFileIfValidSize(file: CIFile, receiveFile: @escaping (User, Int64, Bool) async -> Void) { private func receiveFileIfValidSize(file: CIFile, receiveFile: @escaping (User, Int64, Bool, Bool) async -> Void) {
Task { Task {
if let user = m.currentUser { if let user = m.currentUser {
await receiveFile(user, file.fileId, false) await receiveFile(user, file.fileId, false, false)
} }
} }
} }
@@ -139,9 +139,10 @@ struct VoiceMessagePlayer: View {
case .sndComplete: playbackButton() case .sndComplete: playbackButton()
case .sndCancelled: playbackButton() case .sndCancelled: playbackButton()
case .sndError: playbackButton() case .sndError: playbackButton()
case .rcvInvitation: downloadButton(recordingFile) case .rcvInvitation: downloadButton(recordingFile, "play.fill")
case .rcvAccepted: loadingIcon() case .rcvAccepted: loadingIcon()
case .rcvTransfer: loadingIcon() case .rcvTransfer: loadingIcon()
case .rcvAborted: downloadButton(recordingFile, "exclamationmark.arrow.circlepath")
case .rcvComplete: playbackButton() case .rcvComplete: playbackButton()
case .rcvCancelled: playPauseIcon("play.fill", Color(uiColor: .tertiaryLabel)) case .rcvCancelled: playPauseIcon("play.fill", Color(uiColor: .tertiaryLabel))
case .rcvError: playPauseIcon("play.fill", Color(uiColor: .tertiaryLabel)) case .rcvError: playPauseIcon("play.fill", Color(uiColor: .tertiaryLabel))
@@ -217,7 +218,7 @@ struct VoiceMessagePlayer: View {
} }
} }
private func downloadButton(_ recordingFile: CIFile) -> some View { private func downloadButton(_ recordingFile: CIFile, _ icon: String) -> some View {
Button { Button {
Task { Task {
if let user = chatModel.currentUser { if let user = chatModel.currentUser {
@@ -225,7 +226,7 @@ struct VoiceMessagePlayer: View {
} }
} }
} label: { } label: {
playPauseIcon("play.fill") playPauseIcon(icon)
} }
} }
@@ -65,6 +65,8 @@ struct FramedItemView: View {
} }
} }
} }
} else if let itemForwarded = chatItem.meta.itemForwarded {
framedItemHeader(icon: "arrowshape.turn.up.forward", caption: Text(itemForwarded.text(chat.chatInfo.chatType)).italic(), pad: true)
} }
ChatItemContentView(chat: chat, chatItem: chatItem, revealed: $revealed, msgContentView: framedMsgContentView) ChatItemContentView(chat: chat, chatItem: chatItem, revealed: $revealed, msgContentView: framedMsgContentView)
@@ -85,12 +87,17 @@ struct FramedItemView: View {
.cornerRadius(18) .cornerRadius(18)
.onPreferenceChange(DetermineWidth.Key.self) { msgWidth = $0 } .onPreferenceChange(DetermineWidth.Key.self) { msgWidth = $0 }
switch chatItem.meta.itemStatus { if let (title, text) = chatItem.meta.itemStatus.statusInfo {
case .sndErrorAuth: v.onTapGesture {
v.onTapGesture { msgDeliveryError("Most likely this contact has deleted the connection with you.") } AlertManager.shared.showAlert(
case let .sndError(agentError): Alert(
v.onTapGesture { msgDeliveryError("Unexpected error: \(agentError)") } title: Text(title),
default: v message: Text(text)
)
)
}
} else {
v
} }
} }
@@ -108,7 +115,7 @@ struct FramedItemView: View {
} else { } else {
switch (chatItem.content.msgContent) { switch (chatItem.content.msgContent) {
case let .image(text, image): case let .image(text, image):
CIImageView(chatItem: chatItem, image: image, maxWidth: maxWidth, imgWidth: $imgWidth, scrollProxy: scrollProxy, metaColor: metaColor) CIImageView(chatItem: chatItem, image: image, maxWidth: maxWidth, imgWidth: $imgWidth, scrollProxy: scrollProxy)
.overlay(DetermineWidth()) .overlay(DetermineWidth())
if text == "" && !chatItem.meta.isLive { if text == "" && !chatItem.meta.isLive {
Color.clear Color.clear
@@ -155,15 +162,8 @@ struct FramedItemView: View {
} }
} }
} }
private func msgDeliveryError(_ err: LocalizedStringKey) {
AlertManager.shared.showAlertMsg(
title: "Message delivery error",
message: err
)
}
@ViewBuilder func framedItemHeader(icon: String? = nil, caption: Text) -> some View { @ViewBuilder func framedItemHeader(icon: String? = nil, caption: Text, pad: Bool = false) -> some View {
let v = HStack(spacing: 6) { let v = HStack(spacing: 6) {
if let icon = icon { if let icon = icon {
Image(systemName: icon) Image(systemName: icon)
@@ -178,7 +178,7 @@ struct FramedItemView: View {
.foregroundColor(.secondary) .foregroundColor(.secondary)
.padding(.horizontal, 12) .padding(.horizontal, 12)
.padding(.top, 6) .padding(.top, 6)
.padding(.bottom, chatItem.quotedItem == nil ? 6 : 0) // TODO think how to regroup .padding(.bottom, pad || (chatItem.quotedItem == nil && chatItem.meta.itemForwarded == nil) ? 6 : 0)
.overlay(DetermineWidth()) .overlay(DetermineWidth())
.frame(minWidth: msgWidth, alignment: .leading) .frame(minWidth: msgWidth, alignment: .leading)
.background(chatItemFrameContextColor(chatItem, colorScheme)) .background(chatItemFrameContextColor(chatItem, colorScheme))
@@ -246,13 +246,17 @@ struct FramedItemView: View {
Group { Group {
if let sender = qi.getSender(membership()) { if let sender = qi.getSender(membership()) {
VStack(alignment: .leading, spacing: 2) { VStack(alignment: .leading, spacing: 2) {
Text(sender).font(.caption).foregroundColor(.secondary) Text(sender)
.font(.caption)
.foregroundColor(.secondary)
.lineLimit(1)
ciQuotedMsgTextView(qi, lines: 2) ciQuotedMsgTextView(qi, lines: 2)
} }
} else { } else {
ciQuotedMsgTextView(qi, lines: 3) ciQuotedMsgTextView(qi, lines: 3)
} }
} }
.fixedSize(horizontal: false, vertical: true)
.padding(.top, 6) .padding(.top, 6)
.padding(.horizontal, 12) .padding(.horizontal, 12)
} }
@@ -352,9 +356,9 @@ private struct MetaColorPreferenceKey: PreferenceKey {
func onlyImageOrVideo(_ ci: ChatItem) -> Bool { func onlyImageOrVideo(_ ci: ChatItem) -> Bool {
if case let .image(text, _) = ci.content.msgContent { if case let .image(text, _) = ci.content.msgContent {
return ci.meta.itemDeleted == nil && !ci.meta.isLive && ci.quotedItem == nil && text == "" return ci.meta.itemDeleted == nil && !ci.meta.isLive && ci.quotedItem == nil && ci.meta.itemForwarded == nil && text == ""
} else if case let .video(text, _, _) = ci.content.msgContent { } else if case let .video(text, _, _) = ci.content.msgContent {
return ci.meta.itemDeleted == nil && !ci.meta.isLive && ci.quotedItem == nil && text == "" return ci.meta.itemDeleted == nil && !ci.meta.isLive && ci.quotedItem == nil && ci.meta.itemForwarded == nil && text == ""
} }
return false return false
} }
@@ -35,6 +35,8 @@ struct MsgContentView: View {
@State private var typingIdx = 0 @State private var typingIdx = 0
@State private var timer: Timer? @State private var timer: Timer?
@AppStorage(DEFAULT_SHOW_SENT_VIA_RPOXY) private var showSentViaProxy = false
var body: some View { var body: some View {
if meta?.isLive == true { if meta?.isLive == true {
msgContentView() msgContentView()
@@ -81,7 +83,7 @@ struct MsgContentView: View {
} }
private func reserveSpaceForMeta(_ mt: CIMeta) -> Text { private func reserveSpaceForMeta(_ mt: CIMeta) -> Text {
(rightToLeft ? Text("\n") : Text(" ")) + ciMetaText(mt, chatTTL: chat.chatInfo.timedMessagesTTL, encrypted: nil, transparent: true) (rightToLeft ? Text("\n") : Text(" ")) + ciMetaText(mt, chatTTL: chat.chatInfo.timedMessagesTTL, encrypted: nil, transparent: true, showViaProxy: showSentViaProxy)
} }
} }
@@ -0,0 +1,151 @@
//
// ChatItemForwardingView.swift
// SimpleX (iOS)
//
// Created by spaced4ndy on 12.04.2024.
// Copyright © 2024 SimpleX Chat. All rights reserved.
//
import SwiftUI
import SimpleXChat
struct ChatItemForwardingView: View {
@EnvironmentObject var chatModel: ChatModel
@Environment(\.dismiss) var dismiss
var ci: ChatItem
var fromChatInfo: ChatInfo
@Binding var composeState: ComposeState
@State private var searchText: String = ""
@FocusState private var searchFocused
var body: some View {
NavigationView {
forwardListView()
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button("Cancel") {
dismiss()
}
}
ToolbarItem(placement: .principal) {
Text("Forward")
.bold()
}
}
}
}
@ViewBuilder private func forwardListView() -> some View {
VStack(alignment: .leading) {
let chatsToForwardTo = filterChatsToForwardTo()
if !chatsToForwardTo.isEmpty {
ScrollView {
LazyVStack(alignment: .leading, spacing: 8) {
searchFieldView(text: $searchText, focussed: $searchFocused)
.padding(.leading, 2)
let s = searchText.trimmingCharacters(in: .whitespaces).localizedLowercase
let chats = s == "" ? chatsToForwardTo : chatsToForwardTo.filter { filterChatSearched($0, s) }
ForEach(chats) { chat in
Divider()
forwardListNavLinkView(chat)
.disabled(chatModel.deletedChats.contains(chat.chatInfo.id))
}
}
.padding(.horizontal)
.padding(.vertical, 8)
.background(Color(uiColor: .systemBackground))
.cornerRadius(12)
.padding(.horizontal)
}
.background(Color(.systemGroupedBackground))
} else {
emptyList()
}
}
}
private func filterChatsToForwardTo() -> [Chat] {
var filteredChats = chatModel.chats.filter({ canForwardToChat($0) })
if let index = filteredChats.firstIndex(where: { $0.chatInfo.chatType == .local }) {
let privateNotes = filteredChats.remove(at: index)
filteredChats.insert(privateNotes, at: 0)
}
return filteredChats
}
private func filterChatSearched(_ chat: Chat, _ searchStr: String) -> Bool {
let cInfo = chat.chatInfo
return switch cInfo {
case let .direct(contact):
viewNameContains(cInfo, searchStr) ||
contact.profile.displayName.localizedLowercase.contains(searchStr) ||
contact.fullName.localizedLowercase.contains(searchStr)
default:
viewNameContains(cInfo, searchStr)
}
func viewNameContains(_ cInfo: ChatInfo, _ s: String) -> Bool {
cInfo.chatViewName.localizedLowercase.contains(s)
}
}
private func canForwardToChat(_ chat: Chat) -> Bool {
switch chat.chatInfo {
case let .direct(contact): contact.sendMsgEnabled && !contact.nextSendGrpInv
case let .group(groupInfo): groupInfo.sendMsgEnabled
case let .local(noteFolder): noteFolder.sendMsgEnabled
case .contactRequest: false
case .contactConnection: false
case .invalidJSON: false
}
}
private func emptyList() -> some View {
Text("No filtered chats")
.foregroundColor(.secondary)
.frame(maxWidth: .infinity)
}
@ViewBuilder private func forwardListNavLinkView(_ chat: Chat) -> some View {
Button {
dismiss()
if chat.id == fromChatInfo.id {
composeState = ComposeState(
message: composeState.message,
preview: composeState.linkPreview != nil ? composeState.preview : .noPreview,
contextItem: .forwardingItem(chatItem: ci, fromChatInfo: fromChatInfo)
)
} else {
composeState = ComposeState.init(forwardingItem: ci, fromChatInfo: fromChatInfo)
chatModel.chatId = chat.id
}
} label: {
HStack {
ChatInfoImage(chat: chat, size: 30)
.padding(.trailing, 2)
Text(chat.chatInfo.chatViewName)
.foregroundColor(.primary)
.lineLimit(1)
if chat.chatInfo.incognito {
Spacer()
Image(systemName: "theatermasks")
.resizable()
.scaledToFit()
.frame(width: 22, height: 22)
.foregroundColor(.secondary)
}
}
.frame(maxWidth: .infinity, alignment: .leading)
}
}
}
#Preview {
ChatItemForwardingView(
ci: ChatItem.getSample(1, .directSnd, .now, "hello"),
fromChatInfo: .direct(contact: Contact.sampleData),
composeState: Binding.constant(ComposeState(message: "hello"))
)
}
@@ -11,6 +11,7 @@ import SimpleXChat
struct ChatItemInfoView: View { struct ChatItemInfoView: View {
@EnvironmentObject var chatModel: ChatModel @EnvironmentObject var chatModel: ChatModel
@Environment(\.dismiss) var dismiss
@Environment(\.colorScheme) var colorScheme @Environment(\.colorScheme) var colorScheme
var ci: ChatItem var ci: ChatItem
@Binding var chatItemInfo: ChatItemInfo? @Binding var chatItemInfo: ChatItemInfo?
@@ -21,6 +22,7 @@ struct ChatItemInfoView: View {
enum CIInfoTab { enum CIInfoTab {
case history case history
case quote case quote
case forwarded
case delivery case delivery
} }
@@ -68,9 +70,20 @@ struct ChatItemInfoView: View {
if ci.quotedItem != nil { if ci.quotedItem != nil {
numTabs += 1 numTabs += 1
} }
if chatItemInfo?.forwardedFromChatItem != nil {
numTabs += 1
}
return numTabs return numTabs
} }
private var local: Bool {
switch ci.chatDir {
case .localSnd: true
case .localRcv: true
default: false
}
}
@ViewBuilder private func itemInfoView() -> some View { @ViewBuilder private func itemInfoView() -> some View {
if numTabs > 1 { if numTabs > 1 {
TabView(selection: $selection) { TabView(selection: $selection) {
@@ -93,6 +106,13 @@ struct ChatItemInfoView: View {
} }
.tag(CIInfoTab.quote) .tag(CIInfoTab.quote)
} }
if let forwardedFromItem = chatItemInfo?.forwardedFromChatItem {
forwardedFromTab(forwardedFromItem)
.tabItem {
Label(local ? "Saved" : "Forwarded", systemImage: "arrowshape.turn.up.forward")
}
.tag(CIInfoTab.forwarded)
}
} }
.onAppear { .onAppear {
if chatItemInfo?.memberDeliveryStatuses != nil { if chatItemInfo?.memberDeliveryStatuses != nil {
@@ -275,6 +295,74 @@ struct ChatItemInfoView: View {
: Color(uiColor: .tertiarySystemGroupedBackground) : Color(uiColor: .tertiarySystemGroupedBackground)
} }
@ViewBuilder private func forwardedFromTab(_ forwardedFromItem: AChatItem) -> some View {
ScrollView {
VStack(alignment: .leading, spacing: 16) {
details()
Divider().padding(.vertical)
Text(local ? "Saved from" : "Forwarded from")
.font(.title2)
.padding(.bottom, 4)
forwardedFromView(forwardedFromItem)
}
.padding()
}
.frame(maxHeight: .infinity, alignment: .top)
}
private func forwardedFromView(_ forwardedFromItem: AChatItem) -> some View {
VStack(alignment: .leading, spacing: 8) {
Button {
Task {
await MainActor.run {
chatModel.chatId = forwardedFromItem.chatInfo.id
dismiss()
}
}
} label: {
forwardedFromSender(forwardedFromItem)
}
if !local {
Divider().padding(.top, 32)
Text("Recipient(s) can't see who this message is from.")
.font(.caption)
.foregroundColor(.secondary)
}
}
}
@ViewBuilder private func forwardedFromSender(_ forwardedFromItem: AChatItem) -> some View {
HStack {
ChatInfoImage(chat: Chat(chatInfo: forwardedFromItem.chatInfo), size: 48)
.padding(.trailing, 6)
if forwardedFromItem.chatItem.chatDir.sent {
VStack(alignment: .leading) {
Text("you")
.italic()
.foregroundColor(.primary)
Text(forwardedFromItem.chatInfo.chatViewName)
.foregroundColor(.secondary)
.lineLimit(1)
}
} else if case let .groupRcv(groupMember) = forwardedFromItem.chatItem.chatDir {
VStack(alignment: .leading) {
Text(groupMember.chatViewName)
.foregroundColor(.primary)
.lineLimit(1)
Text(forwardedFromItem.chatInfo.chatViewName)
.foregroundColor(.secondary)
.lineLimit(1)
}
} else {
Text(forwardedFromItem.chatInfo.chatViewName)
.foregroundColor(.primary)
.lineLimit(1)
}
}
}
@ViewBuilder private func deliveryTab(_ memberDeliveryStatuses: [MemberDeliveryStatus]) -> some View { @ViewBuilder private func deliveryTab(_ memberDeliveryStatuses: [MemberDeliveryStatus]) -> some View {
ScrollView { ScrollView {
VStack(alignment: .leading, spacing: 16) { VStack(alignment: .leading, spacing: 16) {
@@ -295,7 +383,7 @@ struct ChatItemInfoView: View {
let mss = membersStatuses(memberDeliveryStatuses) let mss = membersStatuses(memberDeliveryStatuses)
if !mss.isEmpty { if !mss.isEmpty {
ForEach(mss, id: \.0.groupMemberId) { memberStatus in ForEach(mss, id: \.0.groupMemberId) { memberStatus in
memberDeliveryStatusView(memberStatus.0, memberStatus.1) memberDeliveryStatusView(memberStatus.0, memberStatus.1, memberStatus.2)
} }
} else { } else {
Text("No delivery information") Text("No delivery information")
@@ -304,24 +392,27 @@ struct ChatItemInfoView: View {
} }
} }
private func membersStatuses(_ memberDeliveryStatuses: [MemberDeliveryStatus]) -> [(GroupMember, CIStatus)] { private func membersStatuses(_ memberDeliveryStatuses: [MemberDeliveryStatus]) -> [(GroupMember, CIStatus, Bool?)] {
memberDeliveryStatuses.compactMap({ mds in memberDeliveryStatuses.compactMap({ mds in
if let mem = chatModel.getGroupMember(mds.groupMemberId) { if let mem = chatModel.getGroupMember(mds.groupMemberId) {
return (mem.wrapped, mds.memberDeliveryStatus) return (mem.wrapped, mds.memberDeliveryStatus, mds.sentViaProxy)
} else { } else {
return nil return nil
} }
}) })
} }
private func memberDeliveryStatusView(_ member: GroupMember, _ status: CIStatus) -> some View { private func memberDeliveryStatusView(_ member: GroupMember, _ status: CIStatus, _ sentViaProxy: Bool?) -> some View {
HStack{ HStack{
ProfileImage(imageStr: member.image) ProfileImage(imageStr: member.image, size: 30)
.frame(width: 30, height: 30)
.padding(.trailing, 2) .padding(.trailing, 2)
Text(member.chatViewName) Text(member.chatViewName)
.lineLimit(1) .lineLimit(1)
Spacer() Spacer()
if sentViaProxy == true {
Image(systemName: "arrow.forward")
.foregroundColor(.secondary).opacity(0.67)
}
let v = Group { let v = Group {
if let (icon, statusColor) = status.statusIcon(Color.secondary) { if let (icon, statusColor) = status.statusIcon(Color.secondary) {
switch status { switch status {
@@ -46,7 +46,7 @@ struct ChatItemView: View {
let ci = chatItem let ci = chatItem
if chatItem.meta.itemDeleted != nil && (!revealed || chatItem.isDeletedContent) { if chatItem.meta.itemDeleted != nil && (!revealed || chatItem.isDeletedContent) {
MarkedDeletedItemView(chat: chat, chatItem: chatItem, revealed: $revealed) MarkedDeletedItemView(chat: chat, chatItem: chatItem, revealed: $revealed)
} else if ci.quotedItem == nil && ci.meta.itemDeleted == nil && !ci.meta.isLive { } else if ci.quotedItem == nil && ci.meta.itemForwarded == nil && ci.meta.itemDeleted == nil && !ci.meta.isLive {
if let mc = ci.content.msgContent, mc.isText && isShortEmoji(ci.content.text) { if let mc = ci.content.msgContent, mc.isText && isShortEmoji(ci.content.text) {
EmojiItemView(chat: chat, chatItem: ci) EmojiItemView(chat: chat, chatItem: ci)
} else if ci.content.text.isEmpty, case let .voice(_, duration) = ci.content.msgContent { } else if ci.content.text.isEmpty, case let .voice(_, duration) = ci.content.msgContent {
@@ -102,9 +102,9 @@ struct ChatItemContentView<Content: View>: View {
case let .rcvChatPreference(feature, allowed, param): case let .rcvChatPreference(feature, allowed, param):
CIFeaturePreferenceView(chat: chat, chatItem: chatItem, feature: feature, allowed: allowed, param: param) CIFeaturePreferenceView(chat: chat, chatItem: chatItem, feature: feature, allowed: allowed, param: param)
case let .sndChatPreference(feature, _, _): case let .sndChatPreference(feature, _, _):
CIChatFeatureView(chatItem: chatItem, revealed: $revealed, feature: feature, icon: feature.icon, iconColor: .secondary) CIChatFeatureView(chat: chat, chatItem: chatItem, revealed: $revealed, feature: feature, icon: feature.icon, iconColor: .secondary)
case let .rcvGroupFeature(feature, preference, _): chatFeatureView(feature, preference.enable.iconColor) case let .rcvGroupFeature(feature, preference, _, role): chatFeatureView(feature, preference.enabled(role, for: chat.chatInfo.groupInfo?.membership).iconColor)
case let .sndGroupFeature(feature, preference, _): chatFeatureView(feature, preference.enable.iconColor) case let .sndGroupFeature(feature, preference, _, role): chatFeatureView(feature, preference.enabled(role, for: chat.chatInfo.groupInfo?.membership).iconColor)
case let .rcvChatFeatureRejected(feature): chatFeatureView(feature, .red) case let .rcvChatFeatureRejected(feature): chatFeatureView(feature, .red)
case let .rcvGroupFeatureRejected(feature): chatFeatureView(feature, .red) case let .rcvGroupFeatureRejected(feature): chatFeatureView(feature, .red)
case .sndModerated: deletedItemView() case .sndModerated: deletedItemView()
@@ -127,7 +127,7 @@ struct ChatItemContentView<Content: View>: View {
} }
private func groupInvitationItemView(_ groupInvitation: CIGroupInvitation, _ memberRole: GroupMemberRole) -> some View { private func groupInvitationItemView(_ groupInvitation: CIGroupInvitation, _ memberRole: GroupMemberRole) -> some View {
CIGroupInvitationView(chatItem: chatItem, groupInvitation: groupInvitation, memberRole: memberRole, chatIncognito: chat.chatInfo.incognito) CIGroupInvitationView(chat: chat, chatItem: chatItem, groupInvitation: groupInvitation, memberRole: memberRole, chatIncognito: chat.chatInfo.incognito)
} }
private func eventItemView() -> some View { private func eventItemView() -> some View {
@@ -149,7 +149,7 @@ struct ChatItemContentView<Content: View>: View {
} }
private func chatFeatureView(_ feature: Feature, _ iconColor: Color) -> some View { private func chatFeatureView(_ feature: Feature, _ iconColor: Color) -> some View {
CIChatFeatureView(chatItem: chatItem, revealed: $revealed, feature: feature, iconColor: iconColor) CIChatFeatureView(chat: chat, chatItem: chatItem, revealed: $revealed, feature: feature, iconColor: iconColor)
} }
private var mergedGroupEventText: Text? { private var mergedGroupEventText: Text? {
+84 -23
View File
@@ -17,6 +17,7 @@ struct ChatView: View {
@Environment(\.colorScheme) var colorScheme @Environment(\.colorScheme) var colorScheme
@Environment(\.dismiss) var dismiss @Environment(\.dismiss) var dismiss
@Environment(\.presentationMode) var presentationMode @Environment(\.presentationMode) var presentationMode
@Environment(\.scenePhase) var scenePhase
@State @ObservedObject var chat: Chat @State @ObservedObject var chat: Chat
@State private var showChatInfoSheet: Bool = false @State private var showChatInfoSheet: Bool = false
@State private var showAddMembersSheet: Bool = false @State private var showAddMembersSheet: Bool = false
@@ -82,7 +83,11 @@ struct ChatView: View {
initChatView() initChatView()
} }
.onChange(of: chatModel.chatId) { cId in .onChange(of: chatModel.chatId) { cId in
if cId != nil { showChatInfoSheet = false
if let cId {
if let c = chatModel.getChat(cId) {
chat = c
}
initChatView() initChatView()
} else { } else {
dismiss() dismiss()
@@ -178,7 +183,7 @@ struct ChatView: View {
.disabled(!contact.ready || !contact.active) .disabled(!contact.ready || !contact.active)
} }
searchButton() searchButton()
toggleNtfsButton(chat) ToggleNtfsButton(chat: chat)
.disabled(!contact.ready || !contact.active) .disabled(!contact.ready || !contact.active)
} label: { } label: {
Image(systemName: "ellipsis") Image(systemName: "ellipsis")
@@ -207,7 +212,7 @@ struct ChatView: View {
} }
Menu { Menu {
searchButton() searchButton()
toggleNtfsButton(chat) ToggleNtfsButton(chat: chat)
} label: { } label: {
Image(systemName: "ellipsis") Image(systemName: "ellipsis")
} }
@@ -234,7 +239,9 @@ struct ChatView: View {
private func initChatView() { private func initChatView() {
let cInfo = chat.chatInfo let cInfo = chat.chatInfo
if case let .direct(contact) = cInfo { // This check prevents the call to apiContactInfo after the app is suspended, and the database is closed.
if case .active = scenePhase,
case let .direct(contact) = cInfo {
Task { Task {
do { do {
let (stats, _) = try await apiContactInfo(chat.chatInfo.apiId) let (stats, _) = try await apiContactInfo(chat.chatInfo.apiId)
@@ -248,7 +255,8 @@ struct ChatView: View {
} }
} }
} }
if chatModel.draftChatId == cInfo.id, let draft = chatModel.draft { if chatModel.draftChatId == cInfo.id && !composeState.forwarding,
let draft = chatModel.draft {
composeState = draft composeState = draft
} }
if chat.chatStats.unreadChat { if chat.chatStats.unreadChat {
@@ -293,7 +301,7 @@ struct ChatView: View {
} }
private func voiceWithoutFrame(_ ci: ChatItem) -> Bool { private func voiceWithoutFrame(_ ci: ChatItem) -> Bool {
ci.content.msgContent?.isVoice == true && ci.content.text.count == 0 && ci.quotedItem == nil ci.content.msgContent?.isVoice == true && ci.content.text.count == 0 && ci.quotedItem == nil && ci.meta.itemForwarded == nil
} }
private func chatItemsList() -> some View { private func chatItemsList() -> some View {
@@ -339,8 +347,8 @@ struct ChatView: View {
.onChange(of: searchText) { _ in .onChange(of: searchText) { _ in
loadChat(chat: chat, search: searchText) loadChat(chat: chat, search: searchText)
} }
.onChange(of: chatModel.chatId) { _ in .onChange(of: chatModel.chatId) { chatId in
if let chatId = chatModel.chatId, let c = chatModel.getChat(chatId) { if let chatId, let c = chatModel.getChat(chatId) {
chat = c chat = c
showChatInfoSheet = false showChatInfoSheet = false
loadChat(chat: c) loadChat(chat: c)
@@ -511,6 +519,7 @@ struct ChatView: View {
chat: chat, chat: chat,
chatItem: ci, chatItem: ci,
maxWidth: maxWidth, maxWidth: maxWidth,
itemWidth: maxWidth,
composeState: $composeState, composeState: $composeState,
selectedMember: $selectedMember, selectedMember: $selectedMember,
chatView: self chatView: self
@@ -523,6 +532,7 @@ struct ChatView: View {
@ObservedObject var chat: Chat @ObservedObject var chat: Chat
var chatItem: ChatItem var chatItem: ChatItem
var maxWidth: CGFloat var maxWidth: CGFloat
@State var itemWidth: CGFloat
@Binding var composeState: ComposeState @Binding var composeState: ComposeState
@Binding var selectedMember: GMember? @Binding var selectedMember: GMember?
var chatView: ChatView var chatView: ChatView
@@ -534,6 +544,7 @@ struct ChatView: View {
@State private var revealed = false @State private var revealed = false
@State private var showChatItemInfoSheet: Bool = false @State private var showChatItemInfoSheet: Bool = false
@State private var chatItemInfo: ChatItemInfo? @State private var chatItemInfo: ChatItemInfo?
@State private var showForwardingSheet: Bool = false
@State private var allowMenu: Bool = true @State private var allowMenu: Bool = true
@@ -557,7 +568,12 @@ struct ChatView: View {
chatItemView(ci, nil, prev) chatItemView(ci, nil, prev)
} }
} else { } else {
chatItemView(chatItem, range, prevItem) // Switch branches just to work around context menu problem when 'revealed' changes but size of item isn't
if revealed {
chatItemView(chatItem, range, prevItem)
} else {
chatItemView(chatItem, range, prevItem)
}
} }
} }
} }
@@ -577,12 +593,12 @@ struct ChatView: View {
Text(memberNames(member, prevMember, memCount)) Text(memberNames(member, prevMember, memCount))
.font(.caption) .font(.caption)
.foregroundStyle(.secondary) .foregroundStyle(.secondary)
.lineLimit(2)
.padding(.leading, memberImageSize + 14) .padding(.leading, memberImageSize + 14)
.padding(.top, 7) .padding(.top, 7)
} }
HStack(alignment: .top, spacing: 8) { HStack(alignment: .top, spacing: 8) {
ProfileImage(imageStr: member.memberProfile.image) ProfileImage(imageStr: member.memberProfile.image, size: memberImageSize)
.frame(width: memberImageSize, height: memberImageSize)
.onTapGesture { .onTapGesture {
if chatView.membersLoaded { if chatView.membersLoaded {
selectedMember = m.getGroupMember(member.groupMemberId) selectedMember = m.getGroupMember(member.groupMemberId)
@@ -646,7 +662,7 @@ struct ChatView: View {
playbackState: $playbackState, playbackState: $playbackState,
playbackTime: $playbackTime playbackTime: $playbackTime
) )
.uiKitContextMenu(menu: uiMenu, allowMenu: $allowMenu) .uiKitContextMenu(hasImageOrVideo: ci.content.msgContent?.isImageOrVideo == true, maxWidth: maxWidth, itemWidth: $itemWidth, menu: uiMenu, allowMenu: $allowMenu)
.accessibilityLabel("") .accessibilityLabel("")
if ci.content.msgContent != nil && (ci.meta.itemDeleted == nil || revealed) && ci.reactions.count > 0 { if ci.content.msgContent != nil && (ci.meta.itemDeleted == nil || revealed) && ci.reactions.count > 0 {
chatItemReactions(ci) chatItemReactions(ci)
@@ -657,7 +673,7 @@ struct ChatView: View {
Button("Delete for me", role: .destructive) { Button("Delete for me", role: .destructive) {
deleteMessage(.cidmInternal) deleteMessage(.cidmInternal)
} }
if let di = deletingItem, di.meta.editable && !di.localNote { if let di = deletingItem, di.meta.deletable && !di.localNote {
Button(broadcastDeleteButtonText, role: .destructive) { Button(broadcastDeleteButtonText, role: .destructive) {
deleteMessage(.cidmBroadcast) deleteMessage(.cidmBroadcast)
} }
@@ -683,6 +699,14 @@ struct ChatView: View {
}) { }) {
ChatItemInfoView(ci: ci, chatItemInfo: $chatItemInfo) ChatItemInfoView(ci: ci, chatItemInfo: $chatItemInfo)
} }
.sheet(isPresented: $showForwardingSheet) {
if #available(iOS 16.0, *) {
ChatItemForwardingView(ci: ci, fromChatInfo: chat.chatInfo, composeState: $composeState)
.presentationDetents([.fraction(0.8)])
} else {
ChatItemForwardingView(ci: ci, fromChatInfo: chat.chatInfo, composeState: $composeState)
}
}
} }
private func showMemberImage(_ member: GroupMember, _ prevItem: ChatItem?) -> Bool { private func showMemberImage(_ member: GroupMember, _ prevItem: ChatItem?) -> Bool {
@@ -761,10 +785,17 @@ struct ChatView: View {
} else { } else {
menu.append(saveFileAction(fileSource)) menu.append(saveFileAction(fileSource))
} }
} else if let file = ci.file, case .rcvInvitation = file.fileStatus, fileSizeValid(file) {
menu.append(downloadFileAction(file))
} }
if ci.meta.editable && !mc.isVoice && !live { if ci.meta.editable && !mc.isVoice && !live {
menu.append(editAction(ci)) menu.append(editAction(ci))
} }
if ci.meta.itemDeleted == nil
&& (ci.file == nil || (fileSource != nil && fileExists))
&& !ci.isLiveDummy && !live {
menu.append(forwardUIAction(ci))
}
if !ci.isLiveDummy { if !ci.isLiveDummy {
menu.append(viewInfoUIAction(ci)) menu.append(viewInfoUIAction(ci))
} }
@@ -797,6 +828,9 @@ struct ChatView: View {
menu.append(deleteUIAction(ci)) menu.append(deleteUIAction(ci))
} else if ci.mergeCategory != nil && ((range?.count ?? 0) > 1 || revealed) { } else if ci.mergeCategory != nil && ((range?.count ?? 0) > 1 || revealed) {
menu.append(revealed ? shrinkUIAction() : expandUIAction()) menu.append(revealed ? shrinkUIAction() : expandUIAction())
menu.append(deleteUIAction(ci))
} else if ci.showLocalDelete {
menu.append(deleteUIAction(ci))
} }
return menu return menu
} }
@@ -816,6 +850,15 @@ struct ChatView: View {
} }
} }
private func forwardUIAction(_ ci: ChatItem) -> UIAction {
UIAction(
title: NSLocalizedString("Forward", comment: "chat item action"),
image: UIImage(systemName: "arrowshape.turn.up.forward")
) { _ in
showForwardingSheet = true
}
}
private func reactionUIMenuPreiOS16(_ rs: [UIAction]) -> UIMenu { private func reactionUIMenuPreiOS16(_ rs: [UIAction]) -> UIMenu {
UIMenu( UIMenu(
title: NSLocalizedString("React…", comment: "chat item menu"), title: NSLocalizedString("React…", comment: "chat item menu"),
@@ -913,7 +956,21 @@ struct ChatView: View {
saveCryptoFile(fileSource) saveCryptoFile(fileSource)
} }
} }
private func downloadFileAction(_ file: CIFile) -> UIAction {
UIAction(
title: NSLocalizedString("Download", comment: "chat item action"),
image: UIImage(systemName: "arrow.down.doc")
) { _ in
Task {
logger.debug("ChatView downloadFileAction, in Task")
if let user = m.currentUser {
await receiveFile(user: user, fileId: file.fileId)
}
}
}
}
private func editAction(_ ci: ChatItem) -> UIAction { private func editAction(_ ci: ChatItem) -> UIAction {
UIAction( UIAction(
title: NSLocalizedString("Edit", comment: "chat item action"), title: NSLocalizedString("Edit", comment: "chat item action"),
@@ -986,7 +1043,7 @@ struct ChatView: View {
image: UIImage(systemName: "trash"), image: UIImage(systemName: "trash"),
attributes: [.destructive] attributes: [.destructive]
) { _ in ) { _ in
if !revealed && ci.meta.itemDeleted != nil, if !revealed,
let currIndex = m.getChatItemIndex(ci), let currIndex = m.getChatItemIndex(ci),
let ciCategory = ci.mergeCategory { let ciCategory = ci.mergeCategory {
let (prevHidden, _) = m.getPrevShownChatItem(currIndex, ciCategory) let (prevHidden, _) = m.getPrevShownChatItem(currIndex, ciCategory)
@@ -1162,14 +1219,18 @@ struct ChatView: View {
} }
} }
@ViewBuilder func toggleNtfsButton(_ chat: Chat) -> some View { struct ToggleNtfsButton: View {
Button { @ObservedObject var chat: Chat
toggleNotifications(chat, enableNtfs: !chat.chatInfo.ntfsEnabled)
} label: { var body: some View {
if chat.chatInfo.ntfsEnabled { Button {
Label("Mute", systemImage: "speaker.slash") toggleNotifications(chat, enableNtfs: !chat.chatInfo.ntfsEnabled)
} else { } label: {
Label("Unmute", systemImage: "speaker.wave.2") if chat.chatInfo.ntfsEnabled {
Label("Mute", systemImage: "speaker.slash")
} else {
Label("Unmute", systemImage: "speaker.wave.2")
}
} }
} }
} }
@@ -23,6 +23,7 @@ enum ComposeContextItem {
case noContextItem case noContextItem
case quotedItem(chatItem: ChatItem) case quotedItem(chatItem: ChatItem)
case editingItem(chatItem: ChatItem) case editingItem(chatItem: ChatItem)
case forwardingItem(chatItem: ChatItem, fromChatInfo: ChatInfo)
} }
enum VoiceMessageRecordingState { enum VoiceMessageRecordingState {
@@ -72,6 +73,13 @@ struct ComposeState {
} }
} }
init(forwardingItem: ChatItem, fromChatInfo: ChatInfo) {
self.message = ""
self.preview = .noPreview
self.contextItem = .forwardingItem(chatItem: forwardingItem, fromChatInfo: fromChatInfo)
self.voiceMessageRecordingState = .noRecording
}
func copy( func copy(
message: String? = nil, message: String? = nil,
liveMessage: LiveMessage? = nil, liveMessage: LiveMessage? = nil,
@@ -102,12 +110,19 @@ struct ComposeState {
} }
} }
var forwarding: Bool {
switch contextItem {
case .forwardingItem: return true
default: return false
}
}
var sendEnabled: Bool { var sendEnabled: Bool {
switch preview { switch preview {
case let .mediaPreviews(media): return !media.isEmpty case let .mediaPreviews(media): return !media.isEmpty
case .voicePreview: return voiceMessageRecordingState == .finished case .voicePreview: return voiceMessageRecordingState == .finished
case .filePreview: return true case .filePreview: return true
default: return !message.isEmpty || liveMessage != nil default: return !message.isEmpty || forwarding || liveMessage != nil
} }
} }
@@ -153,7 +168,7 @@ struct ComposeState {
} }
var attachmentDisabled: Bool { var attachmentDisabled: Bool {
if editing || liveMessage != nil || inProgress { return true } if editing || forwarding || liveMessage != nil || inProgress { return true }
switch preview { switch preview {
case .noPreview: return false case .noPreview: return false
case .linkPreview: return false case .linkPreview: return false
@@ -161,6 +176,16 @@ struct ComposeState {
} }
} }
var attachmentPreview: Bool {
switch preview {
case .noPreview: false
case .linkPreview: false
case let .mediaPreviews(mediaPreviews): !mediaPreviews.isEmpty
case .voicePreview: false
case .filePreview: true
}
}
var empty: Bool { var empty: Bool {
message == "" && noPreview message == "" && noPreview
} }
@@ -234,6 +259,7 @@ struct ComposeView: View {
@Binding var keyboardVisible: Bool @Binding var keyboardVisible: Bool
@State var linkUrl: URL? = nil @State var linkUrl: URL? = nil
@State var hasSimplexLink: Bool = false
@State var prevLinkUrl: URL? = nil @State var prevLinkUrl: URL? = nil
@State var pendingLinkUrl: URL? = nil @State var pendingLinkUrl: URL? = nil
@State var cancelledLinks: Set<String> = [] @State var cancelledLinks: Set<String> = []
@@ -260,6 +286,16 @@ struct ComposeView: View {
if chat.chatInfo.contact?.nextSendGrpInv ?? false { if chat.chatInfo.contact?.nextSendGrpInv ?? false {
ContextInvitingContactMemberView() ContextInvitingContactMemberView()
} }
let simplexLinkProhibited = hasSimplexLink && !chat.groupFeatureEnabled(.simplexLinks)
let fileProhibited = composeState.attachmentPreview && !chat.groupFeatureEnabled(.files)
let voiceProhibited = composeState.voicePreview && !chat.chatInfo.featureEnabled(.voice)
if simplexLinkProhibited {
msgNotAllowedView("SimpleX links not allowed", icon: "link")
} else if fileProhibited {
msgNotAllowedView("Files and media not allowed", icon: "doc")
} else if voiceProhibited {
msgNotAllowedView("Voice messages not allowed", icon: "mic")
}
contextItemView() contextItemView()
switch (composeState.editing, composeState.preview) { switch (composeState.editing, composeState.preview) {
case (true, .filePreview): EmptyView() case (true, .filePreview): EmptyView()
@@ -278,7 +314,7 @@ struct ComposeView: View {
.padding(.bottom, 12) .padding(.bottom, 12)
.padding(.leading, 12) .padding(.leading, 12)
if case let .group(g) = chat.chatInfo, if case let .group(g) = chat.chatInfo,
!g.fullGroupPreferences.files.on { !g.fullGroupPreferences.files.on(for: g.membership) {
b.disabled(true).onTapGesture { b.disabled(true).onTapGesture {
AlertManager.shared.showAlertMsg( AlertManager.shared.showAlertMsg(
title: "Files and media prohibited!", title: "Files and media prohibited!",
@@ -303,6 +339,7 @@ struct ComposeView: View {
}, },
nextSendGrpInv: chat.chatInfo.contact?.nextSendGrpInv ?? false, nextSendGrpInv: chat.chatInfo.contact?.nextSendGrpInv ?? false,
voiceMessageAllowed: chat.chatInfo.featureEnabled(.voice), voiceMessageAllowed: chat.chatInfo.featureEnabled(.voice),
disableSendButton: simplexLinkProhibited || fileProhibited || voiceProhibited,
showEnableVoiceMessagesAlert: chat.chatInfo.showEnableVoiceMessagesAlert, showEnableVoiceMessagesAlert: chat.chatInfo.showEnableVoiceMessagesAlert,
startVoiceMessageRecording: { startVoiceMessageRecording: {
Task { Task {
@@ -337,13 +374,18 @@ struct ComposeView: View {
} }
} }
} }
.onChange(of: composeState.message) { _ in .onChange(of: composeState.message) { msg in
if composeState.linkPreviewAllowed { if composeState.linkPreviewAllowed {
if composeState.message.count > 0 { if msg.count > 0 {
showLinkPreview(composeState.message) showLinkPreview(msg)
} else { } else {
resetLinkPreview() resetLinkPreview()
hasSimplexLink = false
} }
} else if msg.count > 0 && !chat.groupFeatureEnabled(.simplexLinks) {
(_, hasSimplexLink) = parseMessage(msg)
} else {
hasSimplexLink = false
} }
} }
.onChange(of: chat.userCanSend) { canSend in .onChange(of: chat.userCanSend) { canSend in
@@ -610,6 +652,18 @@ struct ComposeView: View {
} }
} }
private func msgNotAllowedView(_ reason: LocalizedStringKey, icon: String) -> some View {
HStack {
Image(systemName: icon).foregroundColor(.secondary)
Text(reason).italic()
}
.padding(12)
.frame(minHeight: 50)
.frame(maxWidth: .infinity, alignment: .leading)
.background(Color(uiColor: .tertiarySystemGroupedBackground))
.padding(.top, 8)
}
@ViewBuilder private func contextItemView() -> some View { @ViewBuilder private func contextItemView() -> some View {
switch composeState.contextItem { switch composeState.contextItem {
case .noContextItem: case .noContextItem:
@@ -628,6 +682,14 @@ struct ComposeView: View {
contextIcon: "pencil", contextIcon: "pencil",
cancelContextItem: { clearState() } cancelContextItem: { clearState() }
) )
case let .forwardingItem(chatItem: forwardedItem, _):
ContextItemView(
chat: chat,
contextItem: forwardedItem,
contextIcon: "arrowshape.turn.up.forward",
cancelContextItem: { composeState = composeState.copy(contextItem: .noContextItem) },
showSender: false
)
} }
} }
@@ -649,6 +711,11 @@ struct ComposeView: View {
} }
if chat.chatInfo.contact?.nextSendGrpInv ?? false { if chat.chatInfo.contact?.nextSendGrpInv ?? false {
await sendMemberContactInvitation() await sendMemberContactInvitation()
} else if case let .forwardingItem(ci, fromChatInfo) = composeState.contextItem {
sent = await forwardItem(ci, fromChatInfo, ttl)
if !composeState.message.isEmpty {
sent = await send(checkLinkPreview(), quoted: sent?.id, live: false, ttl: ttl)
}
} else if case let .editingItem(ci) = composeState.contextItem { } else if case let .editingItem(ci) = composeState.contextItem {
sent = await updateMessage(ci, live: live) sent = await updateMessage(ci, live: live)
} else if let liveMessage = liveMessage, liveMessage.sentMsg != nil { } else if let liveMessage = liveMessage, liveMessage.sentMsg != nil {
@@ -694,7 +761,15 @@ struct ComposeView: View {
} }
} }
} }
await MainActor.run { clearState(live: live) } await MainActor.run {
let wasForwarding = composeState.forwarding
clearState(live: live)
if wasForwarding,
chatModel.draftChatId == chat.chatInfo.id,
let draft = chatModel.draft {
composeState = draft
}
}
return sent return sent
func sending() async { func sending() async {
@@ -815,10 +890,27 @@ struct ComposeView: View {
return nil return nil
} }
func forwardItem(_ forwardedItem: ChatItem, _ fromChatInfo: ChatInfo, _ ttl: Int?) async -> ChatItem? {
if let chatItem = await apiForwardChatItem(
toChatType: chat.chatInfo.chatType,
toChatId: chat.chatInfo.apiId,
fromChatType: fromChatInfo.chatType,
fromChatId: fromChatInfo.apiId,
itemId: forwardedItem.id,
ttl: ttl
) {
await MainActor.run {
chatModel.addChatItem(chat.chatInfo, chatItem)
}
return chatItem
}
return nil
}
func checkLinkPreview() -> MsgContent { func checkLinkPreview() -> MsgContent {
switch (composeState.preview) { switch (composeState.preview) {
case let .linkPreview(linkPreview: linkPreview): case let .linkPreview(linkPreview: linkPreview):
if let url = parseMessage(msgText), if let url = parseMessage(msgText).url,
let linkPreview = linkPreview, let linkPreview = linkPreview,
url == linkPreview.uri { url == linkPreview.uri {
return .link(text: msgText, preview: linkPreview) return .link(text: msgText, preview: linkPreview)
@@ -947,7 +1039,7 @@ struct ComposeView: View {
private func showLinkPreview(_ s: String) { private func showLinkPreview(_ s: String) {
prevLinkUrl = linkUrl prevLinkUrl = linkUrl
linkUrl = parseMessage(s) (linkUrl, hasSimplexLink) = parseMessage(s)
if let url = linkUrl { if let url = linkUrl {
if url != composeState.linkPreview?.uri && url != pendingLinkUrl { if url != composeState.linkPreview?.uri && url != pendingLinkUrl {
pendingLinkUrl = url pendingLinkUrl = url
@@ -964,13 +1056,17 @@ struct ComposeView: View {
} }
} }
private func parseMessage(_ msg: String) -> URL? { private func parseMessage(_ msg: String) -> (url: URL?, hasSimplexLink: Bool) {
let parsedMsg = parseSimpleXMarkdown(msg) guard let parsedMsg = parseSimpleXMarkdown(msg) else { return (nil, false) }
let uri = parsedMsg?.first(where: { ft in let url: URL? = if let uri = parsedMsg.first(where: { ft in
ft.format == .uri && !cancelledLinks.contains(ft.text) && !isSimplexLink(ft.text) ft.format == .uri && !cancelledLinks.contains(ft.text) && !isSimplexLink(ft.text)
}) }) {
if let uri = uri { return URL(string: uri.text) } URL(string: uri.text)
else { return nil } } else {
nil
}
let simplexLink = parsedMsg.contains(where: { ft in ft.format?.isSimplexLink ?? false })
return (url, simplexLink)
} }
private func isSimplexLink(_ link: String) -> Bool { private func isSimplexLink(_ link: String) -> Bool {
@@ -15,6 +15,7 @@ struct ContextItemView: View {
let contextItem: ChatItem let contextItem: ChatItem
let contextIcon: String let contextIcon: String
let cancelContextItem: () -> Void let cancelContextItem: () -> Void
var showSender: Bool = true
var body: some View { var body: some View {
HStack { HStack {
@@ -23,7 +24,7 @@ struct ContextItemView: View {
.aspectRatio(contentMode: .fit) .aspectRatio(contentMode: .fit)
.frame(width: 16, height: 16) .frame(width: 16, height: 16)
.foregroundColor(.secondary) .foregroundColor(.secondary)
if let sender = contextItem.memberDisplayName { if showSender, let sender = contextItem.memberDisplayName {
VStack(alignment: .leading, spacing: 4) { VStack(alignment: .leading, spacing: 4) {
Text(sender).font(.caption).foregroundColor(.secondary) Text(sender).font(.caption).foregroundColor(.secondary)
msgContentView(lines: 2) msgContentView(lines: 2)
@@ -48,14 +49,26 @@ struct ContextItemView: View {
} }
private func msgContentView(lines: Int) -> some View { private func msgContentView(lines: Int) -> some View {
MsgContentView( contextMsgPreview()
chat: chat, .multilineTextAlignment(isRightToLeft(contextItem.text) ? .trailing : .leading)
text: contextItem.text, .lineLimit(lines)
formattedText: contextItem.formattedText, }
showSecrets: false
) private func contextMsgPreview() -> Text {
.multilineTextAlignment(isRightToLeft(contextItem.text) ? .trailing : .leading) return attachment() + messageText(contextItem.text, contextItem.formattedText, nil, preview: true, showSecrets: false)
.lineLimit(lines)
func attachment() -> Text {
switch contextItem.content.msgContent {
case .file: return image("doc.fill")
case .image: return image("photo")
case .voice: return image("play.fill")
default: return Text("")
}
}
func image(_ s: String) -> Text {
Text(Image(systemName: s)).foregroundColor(Color(uiColor: .tertiaryLabel)) + Text(" ")
}
} }
} }
@@ -16,7 +16,6 @@ struct NativeTextEditor: UIViewRepresentable {
@Binding var disableEditing: Bool @Binding var disableEditing: Bool
@Binding var height: CGFloat @Binding var height: CGFloat
@Binding var focused: Bool @Binding var focused: Bool
let alignment: TextAlignment
let onImagesAdded: ([UploadContent]) -> Void let onImagesAdded: ([UploadContent]) -> Void
private let minHeight: CGFloat = 37 private let minHeight: CGFloat = 37
@@ -30,13 +29,16 @@ struct NativeTextEditor: UIViewRepresentable {
func makeUIView(context: Context) -> UITextView { func makeUIView(context: Context) -> UITextView {
let field = CustomUITextField(height: _height) let field = CustomUITextField(height: _height)
field.text = text field.text = text
field.textAlignment = alignment == .leading ? .left : .right field.textAlignment = alignment(text)
field.autocapitalizationType = .sentences field.autocapitalizationType = .sentences
field.setOnTextChangedListener { newText, images in field.setOnTextChangedListener { newText, images in
if !disableEditing { if !disableEditing {
// Speed up the process of updating layout, reduce jumping content on screen
if !isShortEmoji(newText) { updateHeight(field) }
text = newText text = newText
field.textAlignment = alignment(text)
updateFont(field)
// Speed up the process of updating layout, reduce jumping content on screen
updateHeight(field)
self.height = field.frame.size.height
} else { } else {
field.text = text field.text = text
} }
@@ -53,10 +55,12 @@ struct NativeTextEditor: UIViewRepresentable {
} }
func updateUIView(_ field: UITextView, context: Context) { func updateUIView(_ field: UITextView, context: Context) {
field.text = text if field.markedTextRange == nil && field.text != text {
field.textAlignment = alignment == .leading ? .left : .right field.text = text
updateFont(field) field.textAlignment = alignment(text)
updateHeight(field) updateFont(field)
updateHeight(field)
}
} }
private func updateHeight(_ field: UITextView) { private func updateHeight(_ field: UITextView) {
@@ -73,12 +77,19 @@ struct NativeTextEditor: UIViewRepresentable {
} }
private func updateFont(_ field: UITextView) { private func updateFont(_ field: UITextView) {
field.font = isShortEmoji(field.text) let newFont = isShortEmoji(field.text)
? (field.text.count < 4 ? largeEmojiUIFont : mediumEmojiUIFont) ? (field.text.count < 4 ? largeEmojiUIFont : mediumEmojiUIFont)
: UIFont.preferredFont(forTextStyle: .body) : UIFont.preferredFont(forTextStyle: .body)
if field.font != newFont {
field.font = newFont
}
} }
} }
private func alignment(_ text: String) -> NSTextAlignment {
isRightToLeft(text) ? .right : .left
}
private class CustomUITextField: UITextView, UITextViewDelegate { private class CustomUITextField: UITextView, UITextViewDelegate {
var height: Binding<CGFloat> var height: Binding<CGFloat>
var newHeight: CGFloat = 0 var newHeight: CGFloat = 0
@@ -205,7 +216,6 @@ struct NativeTextEditor_Previews: PreviewProvider{
disableEditing: Binding.constant(false), disableEditing: Binding.constant(false),
height: Binding.constant(100), height: Binding.constant(100),
focused: Binding.constant(false), focused: Binding.constant(false),
alignment: TextAlignment.leading,
onImagesAdded: { _ in } onImagesAdded: { _ in }
) )
.fixedSize(horizontal: false, vertical: true) .fixedSize(horizontal: false, vertical: true)
@@ -20,6 +20,7 @@ struct SendMessageView: View {
var nextSendGrpInv: Bool = false var nextSendGrpInv: Bool = false
var showVoiceMessageButton: Bool = true var showVoiceMessageButton: Bool = true
var voiceMessageAllowed: Bool = true var voiceMessageAllowed: Bool = true
var disableSendButton = false
var showEnableVoiceMessagesAlert: ChatInfo.ShowEnableVoiceMessagesAlert = .other var showEnableVoiceMessagesAlert: ChatInfo.ShowEnableVoiceMessagesAlert = .other
var startVoiceMessageRecording: (() -> Void)? = nil var startVoiceMessageRecording: (() -> Void)? = nil
var finishVoiceMessageRecording: (() -> Void)? = nil var finishVoiceMessageRecording: (() -> Void)? = nil
@@ -53,13 +54,11 @@ struct SendMessageView: View {
.padding(.vertical, 8) .padding(.vertical, 8)
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
} else { } else {
let alignment: TextAlignment = isRightToLeft(composeState.message) ? .trailing : .leading
NativeTextEditor( NativeTextEditor(
text: $composeState.message, text: $composeState.message,
disableEditing: $composeState.inProgress, disableEditing: $composeState.inProgress,
height: $teHeight, height: $teHeight,
focused: $keyboardVisible, focused: $keyboardVisible,
alignment: alignment,
onImagesAdded: onMediaAdded onImagesAdded: onMediaAdded
) )
.allowsTightening(false) .allowsTightening(false)
@@ -109,6 +108,7 @@ struct SendMessageView: View {
} else if showVoiceMessageButton } else if showVoiceMessageButton
&& composeState.message.isEmpty && composeState.message.isEmpty
&& !composeState.editing && !composeState.editing
&& !composeState.forwarding
&& composeState.liveMessage == nil && composeState.liveMessage == nil
&& ((composeState.noPreview && vmrs == .noRecording) && ((composeState.noPreview && vmrs == .noRecording)
|| (vmrs == .recording && holdingVMR)) { || (vmrs == .recording && holdingVMR)) {
@@ -184,7 +184,8 @@ struct SendMessageView: View {
!composeState.sendEnabled || !composeState.sendEnabled ||
composeState.inProgress || composeState.inProgress ||
(!voiceMessageAllowed && composeState.voicePreview) || (!voiceMessageAllowed && composeState.voicePreview) ||
composeState.endLiveDisabled composeState.endLiveDisabled ||
disableSendButton
) )
.frame(width: 29, height: 29) .frame(width: 29, height: 29)
.contextMenu{ .contextMenu{
@@ -194,8 +194,7 @@ struct AddGroupMembersViewCommon: View {
} }
} label: { } label: {
HStack{ HStack{
ProfileImage(imageStr: contact.image) ProfileImage(imageStr: contact.image, size: 30)
.frame(width: 30, height: 30)
.padding(.trailing, 2) .padding(.trailing, 2)
Text(ChatInfo.direct(contact: contact).chatViewName) Text(ChatInfo.direct(contact: contact).chatViewName)
.foregroundColor(prohibitedToInviteIncognito ? .secondary : .primary) .foregroundColor(prohibitedToInviteIncognito ? .secondary : .primary)
@@ -62,7 +62,7 @@ struct GroupChatInfoView: View {
NavigationView { NavigationView {
let members = chatModel.groupMembers let members = chatModel.groupMembers
.filter { m in let status = m.wrapped.memberStatus; return status != .memLeft && status != .memRemoved } .filter { m in let status = m.wrapped.memberStatus; return status != .memLeft && status != .memRemoved }
.sorted { $0.displayName.lowercased() < $1.displayName.lowercased() } .sorted { $0.wrapped.memberRole > $1.wrapped.memberRole }
List { List {
groupInfoHeader() groupInfoHeader()
@@ -172,8 +172,7 @@ struct GroupChatInfoView: View {
private func groupInfoHeader() -> some View { private func groupInfoHeader() -> some View {
VStack { VStack {
let cInfo = chat.chatInfo let cInfo = chat.chatInfo
ChatInfoImage(chat: chat, color: Color(uiColor: .tertiarySystemFill)) ChatInfoImage(chat: chat, size: 192, color: Color(uiColor: .tertiarySystemFill))
.frame(width: 192, height: 192)
.padding(.top, 12) .padding(.top, 12)
.padding() .padding()
Text(cInfo.displayName) Text(cInfo.displayName)
@@ -217,8 +216,7 @@ struct GroupChatInfoView: View {
var body: some View { var body: some View {
let member = groupMember.wrapped let member = groupMember.wrapped
let v = HStack{ let v = HStack{
ProfileImage(imageStr: member.image) ProfileImage(imageStr: member.image, size: 38)
.frame(width: 38, height: 38)
.padding(.trailing, 2) .padding(.trailing, 2)
// TODO server connection status // TODO server connection status
VStack(alignment: .leading) { VStack(alignment: .leading) {
@@ -83,7 +83,7 @@ struct GroupMemberInfoView: View {
Section { Section {
if let contactId = member.memberContactId, let chat = knownDirectChat(contactId) { if let contactId = member.memberContactId, let chat = knownDirectChat(contactId) {
knownDirectChatButton(chat) knownDirectChatButton(chat)
} else if groupInfo.fullGroupPreferences.directMessages.on { } else if groupInfo.fullGroupPreferences.directMessages.on(for: groupInfo.membership) {
if let contactId = member.memberContactId { if let contactId = member.memberContactId {
newDirectChatButton(contactId) newDirectChatButton(contactId)
} else if member.activeConn?.peerChatVRange.isCompatibleRange(CREATE_MEMBER_CONTACT_VRANGE) ?? false { } else if member.activeConn?.peerChatVRange.isCompatibleRange(CREATE_MEMBER_CONTACT_VRANGE) ?? false {
@@ -110,7 +110,7 @@ struct GroupMemberInfoView: View {
Label("Share address", systemImage: "square.and.arrow.up") Label("Share address", systemImage: "square.and.arrow.up")
} }
if let contactId = member.memberContactId { if let contactId = member.memberContactId {
if knownDirectChat(contactId) == nil && !groupInfo.fullGroupPreferences.directMessages.on { if knownDirectChat(contactId) == nil && !groupInfo.fullGroupPreferences.directMessages.on(for: groupInfo.membership) {
connectViaAddressButton(contactLink) connectViaAddressButton(contactLink)
} }
} else { } else {
@@ -305,8 +305,7 @@ struct GroupMemberInfoView: View {
private func groupMemberInfoHeader(_ mem: GroupMember) -> some View { private func groupMemberInfoHeader(_ mem: GroupMember) -> some View {
VStack { VStack {
ProfileImage(imageStr: mem.image, color: Color(uiColor: .tertiarySystemFill)) ProfileImage(imageStr: mem.image, size: 192, color: Color(uiColor: .tertiarySystemFill))
.frame(width: 192, height: 192)
.padding(.top, 12) .padding(.top, 12)
.padding() .padding()
if mem.verified { if mem.verified {
@@ -9,6 +9,12 @@
import SwiftUI import SwiftUI
import SimpleXChat import SimpleXChat
private let featureRoles: [(role: GroupMemberRole?, text: LocalizedStringKey)] = [
(nil, "all members"),
(.admin, "admins"),
(.owner, "owners")
]
struct GroupPreferencesView: View { struct GroupPreferencesView: View {
@Environment(\.dismiss) var dismiss: DismissAction @Environment(\.dismiss) var dismiss: DismissAction
@EnvironmentObject var chatModel: ChatModel @EnvironmentObject var chatModel: ChatModel
@@ -24,10 +30,12 @@ struct GroupPreferencesView: View {
List { List {
featureSection(.timedMessages, $preferences.timedMessages.enable) featureSection(.timedMessages, $preferences.timedMessages.enable)
featureSection(.fullDelete, $preferences.fullDelete.enable) featureSection(.fullDelete, $preferences.fullDelete.enable)
featureSection(.directMessages, $preferences.directMessages.enable) featureSection(.directMessages, $preferences.directMessages.enable, $preferences.directMessages.role)
featureSection(.reactions, $preferences.reactions.enable) featureSection(.reactions, $preferences.reactions.enable)
featureSection(.voice, $preferences.voice.enable) featureSection(.voice, $preferences.voice.enable, $preferences.voice.role)
featureSection(.files, $preferences.files.enable) featureSection(.files, $preferences.files.enable, $preferences.files.role)
// TODO enable simplexLinks preference in 5.8
// featureSection(.simplexLinks, $preferences.simplexLinks.enable, $preferences.simplexLinks.role)
featureSection(.history, $preferences.history.enable) featureSection(.history, $preferences.history.enable)
if groupInfo.canEdit { if groupInfo.canEdit {
@@ -64,7 +72,7 @@ struct GroupPreferencesView: View {
} }
} }
private func featureSection(_ feature: GroupFeature, _ enableFeature: Binding<GroupFeatureEnabled>) -> some View { private func featureSection(_ feature: GroupFeature, _ enableFeature: Binding<GroupFeatureEnabled>, _ enableForRole: Binding<GroupMemberRole?>? = nil) -> some View {
Section { Section {
let color: Color = enableFeature.wrappedValue == .on ? .green : .secondary let color: Color = enableFeature.wrappedValue == .on ? .green : .secondary
let icon = enableFeature.wrappedValue == .on ? feature.iconFilled : feature.icon let icon = enableFeature.wrappedValue == .on ? feature.iconFilled : feature.icon
@@ -87,6 +95,16 @@ struct GroupPreferencesView: View {
) )
.frame(height: 36) .frame(height: 36)
} }
if enableFeature.wrappedValue == .on, let enableForRole {
Picker("Enabled for", selection: enableForRole) {
ForEach(featureRoles, id: \.role) { fr in
Text(fr.text)
}
}
.frame(height: 36)
// remove in v5.8
.disabled(true)
}
} else { } else {
settingsRow(icon, color: color) { settingsRow(icon, color: color) {
infoRow(Text(feature.text), enableFeature.wrappedValue.text) infoRow(Text(feature.text), enableFeature.wrappedValue.text)
@@ -94,10 +112,26 @@ struct GroupPreferencesView: View {
if timedOn { if timedOn {
infoRow("Delete after", timeText(preferences.timedMessages.ttl)) infoRow("Delete after", timeText(preferences.timedMessages.ttl))
} }
if enableFeature.wrappedValue == .on, let enableForRole {
HStack {
Text("Enabled for").foregroundColor(.secondary)
Spacer()
Text(
featureRoles.first(where: { fr in fr.role == enableForRole.wrappedValue })?.text
?? "all members"
)
.foregroundColor(.secondary)
}
}
} }
} footer: { } footer: {
Text(feature.enableDescription(enableFeature.wrappedValue, groupInfo.canEdit)) Text(feature.enableDescription(enableFeature.wrappedValue, groupInfo.canEdit))
} }
.onChange(of: enableFeature.wrappedValue) { enabled in
if case .off = enabled {
enableForRole?.wrappedValue = nil
}
}
} }
private func savePreferences() { private func savePreferences() {
@@ -92,7 +92,7 @@ struct ChatListNavLink: View {
.swipeActions(edge: .leading, allowsFullSwipe: true) { .swipeActions(edge: .leading, allowsFullSwipe: true) {
markReadButton() markReadButton()
toggleFavoriteButton() toggleFavoriteButton()
toggleNtfsButton(chat) ToggleNtfsButton(chat: chat)
} }
.swipeActions(edge: .trailing, allowsFullSwipe: true) { .swipeActions(edge: .trailing, allowsFullSwipe: true) {
if !chat.chatItems.isEmpty { if !chat.chatItems.isEmpty {
@@ -181,7 +181,7 @@ struct ChatListNavLink: View {
.swipeActions(edge: .leading, allowsFullSwipe: true) { .swipeActions(edge: .leading, allowsFullSwipe: true) {
markReadButton() markReadButton()
toggleFavoriteButton() toggleFavoriteButton()
toggleNtfsButton(chat) ToggleNtfsButton(chat: chat)
} }
.swipeActions(edge: .trailing, allowsFullSwipe: true) { .swipeActions(edge: .trailing, allowsFullSwipe: true) {
if !chat.chatItems.isEmpty { if !chat.chatItems.isEmpty {
@@ -92,8 +92,7 @@ struct ChatListView: View {
ToolbarItem(placement: .navigationBarLeading) { ToolbarItem(placement: .navigationBarLeading) {
let user = chatModel.currentUser ?? User.sampleData let user = chatModel.currentUser ?? User.sampleData
ZStack(alignment: .topTrailing) { ZStack(alignment: .topTrailing) {
ProfileImage(imageStr: user.image, color: Color(uiColor: .quaternaryLabel)) ProfileImage(imageStr: user.image, size: 32, color: Color(uiColor: .quaternaryLabel))
.frame(width: 32, height: 32)
.padding(.trailing, 4) .padding(.trailing, 4)
let allRead = chatModel.users let allRead = chatModel.users
.filter { u in !u.user.activeUser && !u.user.hidden } .filter { u in !u.user.activeUser && !u.user.hidden }
@@ -23,8 +23,7 @@ struct ChatPreviewView: View {
let cItem = chat.chatItems.last let cItem = chat.chatItems.last
return HStack(spacing: 8) { return HStack(spacing: 8) {
ZStack(alignment: .bottomTrailing) { ZStack(alignment: .bottomTrailing) {
ChatInfoImage(chat: chat) ChatInfoImage(chat: chat, size: 63)
.frame(width: 63, height: 63)
chatPreviewImageOverlayIcon() chatPreviewImageOverlayIcon()
.padding([.bottom, .trailing], 1) .padding([.bottom, .trailing], 1)
} }
@@ -241,14 +240,14 @@ struct ChatPreviewView: View {
private func itemStatusMark(_ cItem: ChatItem) -> Text { private func itemStatusMark(_ cItem: ChatItem) -> Text {
switch cItem.meta.itemStatus { switch cItem.meta.itemStatus {
case .sndErrorAuth: case .sndErrorAuth, .sndError:
return Text(Image(systemName: "multiply")) return Text(Image(systemName: "multiply"))
.font(.caption) .font(.caption)
.foregroundColor(.red) + Text(" ") .foregroundColor(.red) + Text(" ")
case .sndError: case .sndWarning:
return Text(Image(systemName: "exclamationmark.triangle.fill")) return Text(Image(systemName: "exclamationmark.triangle.fill"))
.font(.caption) .font(.caption)
.foregroundColor(.yellow) + Text(" ") .foregroundColor(.orange) + Text(" ")
default: return Text("") default: return Text("")
} }
} }
@@ -16,8 +16,7 @@ struct ContactRequestView: View {
var body: some View { var body: some View {
HStack(spacing: 8) { HStack(spacing: 8) {
ChatInfoImage(chat: chat) ChatInfoImage(chat: chat, size: 63)
.frame(width: 63, height: 63)
.padding(.leading, 4) .padding(.leading, 4)
VStack(alignment: .leading, spacing: 0) { VStack(alignment: .leading, spacing: 0) {
HStack(alignment: .top) { HStack(alignment: .top) {
@@ -12,6 +12,7 @@ private let fillColorLight = Color(uiColor: UIColor(red: 0.99, green: 0.99, blue
struct UserPicker: View { struct UserPicker: View {
@EnvironmentObject var m: ChatModel @EnvironmentObject var m: ChatModel
@Environment(\.colorScheme) var colorScheme @Environment(\.colorScheme) var colorScheme
@Environment(\.scenePhase) var scenePhase
@Binding var showSettings: Bool @Binding var showSettings: Bool
@Binding var showConnectDesktop: Bool @Binding var showConnectDesktop: Bool
@Binding var userPickerVisible: Bool @Binding var userPickerVisible: Bool
@@ -91,7 +92,10 @@ struct UserPicker: View {
.opacity(userPickerVisible ? 1.0 : 0.0) .opacity(userPickerVisible ? 1.0 : 0.0)
.onAppear { .onAppear {
do { do {
m.users = try listUsers() // This check prevents the call of listUsers after the app is suspended, and the database is closed.
if case .active = scenePhase {
m.users = try listUsers()
}
} catch let error { } catch let error {
logger.error("Error loading users \(responseError(error))") logger.error("Error loading users \(responseError(error))")
} }
@@ -123,8 +127,7 @@ struct UserPicker: View {
} }
}, label: { }, label: {
HStack(spacing: 0) { HStack(spacing: 0) {
ProfileImage(imageStr: user.image, color: Color(uiColor: .tertiarySystemFill)) ProfileImage(imageStr: user.image, size: 44, color: Color(uiColor: .tertiarySystemFill))
.frame(width: 44, height: 44)
.padding(.trailing, 12) .padding(.trailing, 12)
Text(user.chatViewName) Text(user.chatViewName)
.fontWeight(user.activeUser ? .medium : .regular) .fontWeight(user.activeUser ? .medium : .regular)
@@ -19,7 +19,6 @@ enum DatabaseAlert: Identifiable {
case chatDeleted case chatDeleted
case deleteLegacyDatabase case deleteLegacyDatabase
case deleteFilesAndMedia case deleteFilesAndMedia
case deleteTempFiles
case setChatItemTTL(ttl: ChatItemTTL) case setChatItemTTL(ttl: ChatItemTTL)
case error(title: LocalizedStringKey, error: String = "") case error(title: LocalizedStringKey, error: String = "")
@@ -34,7 +33,6 @@ enum DatabaseAlert: Identifiable {
case .chatDeleted: return "chatDeleted" case .chatDeleted: return "chatDeleted"
case .deleteLegacyDatabase: return "deleteLegacyDatabase" case .deleteLegacyDatabase: return "deleteLegacyDatabase"
case .deleteFilesAndMedia: return "deleteFilesAndMedia" case .deleteFilesAndMedia: return "deleteFilesAndMedia"
case .deleteTempFiles: return "deleteTempFiles"
case .setChatItemTTL: return "setChatItemTTL" case .setChatItemTTL: return "setChatItemTTL"
case let .error(title, _): return "error \(title)" case let .error(title, _): return "error \(title)"
} }
@@ -51,7 +49,6 @@ struct DatabaseView: View {
@State private var progressIndicator = false @State private var progressIndicator = false
@AppStorage(DEFAULT_CHAT_ARCHIVE_NAME) private var chatArchiveName: String? @AppStorage(DEFAULT_CHAT_ARCHIVE_NAME) private var chatArchiveName: String?
@AppStorage(DEFAULT_CHAT_ARCHIVE_TIME) private var chatArchiveTime: Double = 0 @AppStorage(DEFAULT_CHAT_ARCHIVE_TIME) private var chatArchiveTime: Double = 0
@AppStorage(DEFAULT_DEVELOPER_TOOLS) private var developerTools = false
@State private var dbContainer = dbContainerGroupDefault.get() @State private var dbContainer = dbContainerGroupDefault.get()
@State private var legacyDatabase = hasLegacyDatabase() @State private var legacyDatabase = hasLegacyDatabase()
@State private var useKeychain = storeDBPassphraseGroupDefault.get() @State private var useKeychain = storeDBPassphraseGroupDefault.get()
@@ -194,16 +191,6 @@ struct DatabaseView: View {
} }
} }
} }
if developerTools {
Section {
Button("Delete temporary files", role: .destructive) {
alert = .deleteTempFiles
}
} header: {
Text("Temp files")
}
}
} }
.onAppear { .onAppear {
runChat = m.chatRunning ?? true runChat = m.chatRunning ?? true
@@ -303,15 +290,6 @@ struct DatabaseView: View {
}, },
secondaryButton: .cancel() secondaryButton: .cancel()
) )
case .deleteTempFiles:
return Alert(
title: Text("Delete temporary files?"),
message: Text("This action cannot be undone - all temporary files will be deleted."),
primaryButton: .destructive(Text("Delete")) {
deleteAppTempFiles()
},
secondaryButton: .cancel()
)
case let .setChatItemTTL(ttl): case let .setChatItemTTL(ttl):
return Alert( return Alert(
title: Text("Enable automatic message deletion?"), title: Text("Enable automatic message deletion?"),
@@ -12,6 +12,7 @@ import SimpleXChat
struct ChatInfoImage: View { struct ChatInfoImage: View {
@Environment(\.colorScheme) var colorScheme @Environment(\.colorScheme) var colorScheme
@ObservedObject var chat: Chat @ObservedObject var chat: Chat
var size: CGFloat
var color = Color(uiColor: .tertiarySystemGroupedBackground) var color = Color(uiColor: .tertiarySystemGroupedBackground)
var body: some View { var body: some View {
@@ -28,6 +29,7 @@ struct ChatInfoImage: View {
return ProfileImage( return ProfileImage(
imageStr: chat.chatInfo.image, imageStr: chat.chatInfo.image,
iconName: iconName, iconName: iconName,
size: size,
color: iconColor color: iconColor
) )
} }
@@ -36,8 +38,9 @@ struct ChatInfoImage: View {
struct ChatInfoImage_Previews: PreviewProvider { struct ChatInfoImage_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
ChatInfoImage( ChatInfoImage(
chat: Chat(chatInfo: ChatInfo.sampleData.direct, chatItems: []) chat: Chat(chatInfo: ChatInfo.sampleData.direct, chatItems: []),
, color: Color(red: 0.9, green: 0.9, blue: 0.9) size: 63,
color: Color(red: 0.9, green: 0.9, blue: 0.9)
) )
.previewLayout(.fixed(width: 63, height: 63)) .previewLayout(.fixed(width: 63, height: 63))
} }
+33 -10
View File
@@ -11,28 +11,43 @@ import UIKit
import SwiftUI import SwiftUI
extension View { extension View {
func uiKitContextMenu(menu: Binding<UIMenu>, allowMenu: Binding<Bool>) -> some View { func uiKitContextMenu(hasImageOrVideo: Bool, maxWidth: CGFloat, itemWidth: Binding<CGFloat>, menu: Binding<UIMenu>, allowMenu: Binding<Bool>) -> some View {
self.overlay { Group {
if allowMenu.wrappedValue { if allowMenu.wrappedValue {
self.overlay(Color(uiColor: .systemBackground)).overlay(InteractionView(content: self, menu: menu)) if hasImageOrVideo {
InteractionView(content:
self.environmentObject(ChatModel.shared)
.overlay(DetermineWidthImageVideoItem())
.onPreferenceChange(DetermineWidthImageVideoItem.Key.self) { itemWidth.wrappedValue = $0 == 0 ? maxWidth : $0 }
, maxWidth: maxWidth, itemWidth: itemWidth, menu: menu)
.frame(maxWidth: itemWidth.wrappedValue)
} else {
InteractionView(content: self.environmentObject(ChatModel.shared), maxWidth: maxWidth, itemWidth: itemWidth, menu: menu)
.fixedSize(horizontal: true, vertical: false)
} }
} else {
self
} }
}
} }
} }
private struct InteractionConfig<Content: View> { private class HostingViewHolder: UIView {
let content: Content var contentSize: CGSize = CGSizeMake(0, 0)
let menu: UIMenu override var intrinsicContentSize: CGSize { get { contentSize } }
} }
private struct InteractionView<Content: View>: UIViewRepresentable { struct InteractionView<Content: View>: UIViewRepresentable {
let content: Content let content: Content
var maxWidth: CGFloat
var itemWidth: Binding<CGFloat>
@Binding var menu: UIMenu @Binding var menu: UIMenu
func makeUIView(context: Context) -> UIView { func makeUIView(context: Context) -> UIView {
let view = UIView() let view = HostingViewHolder()
view.backgroundColor = .clear view.backgroundColor = .clear
let hostView = UIHostingController(rootView: content) let hostView = UIHostingController(rootView: content)
view.contentSize = hostView.view.intrinsicContentSize
hostView.view.translatesAutoresizingMaskIntoConstraints = false hostView.view.translatesAutoresizingMaskIntoConstraints = false
let constraints = [ let constraints = [
hostView.view.topAnchor.constraint(equalTo: view.topAnchor), hostView.view.topAnchor.constraint(equalTo: view.topAnchor),
@@ -44,12 +59,20 @@ private struct InteractionView<Content: View>: UIViewRepresentable {
] ]
view.addSubview(hostView.view) view.addSubview(hostView.view)
view.addConstraints(constraints) view.addConstraints(constraints)
view.layer.cornerRadius = 18
hostView.view.layer.cornerRadius = 18
let menuInteraction = UIContextMenuInteraction(delegate: context.coordinator) let menuInteraction = UIContextMenuInteraction(delegate: context.coordinator)
view.addInteraction(menuInteraction) view.addInteraction(menuInteraction)
return view return view
} }
func updateUIView(_ uiView: UIView, context: Context) {} func updateUIView(_ uiView: UIView, context: Context) {
let was = (uiView as! HostingViewHolder).contentSize
(uiView as! HostingViewHolder).contentSize = uiView.subviews[0].sizeThatFits(CGSizeMake(itemWidth.wrappedValue, .infinity))
if was != (uiView as! HostingViewHolder).contentSize {
uiView.invalidateIntrinsicContentSize()
}
}
func makeCoordinator() -> Coordinator { func makeCoordinator() -> Coordinator {
Coordinator(self) Coordinator(self)
@@ -21,6 +21,19 @@ struct DetermineWidth: View {
} }
} }
struct DetermineWidthImageVideoItem: View {
typealias Key = MaximumWidthImageVideoPreferenceKey
var body: some View {
GeometryReader { proxy in
Color.clear
.preference(
key: MaximumWidthImageVideoPreferenceKey.self,
value: proxy.size.width
)
}
}
}
struct MaximumWidthPreferenceKey: PreferenceKey { struct MaximumWidthPreferenceKey: PreferenceKey {
static var defaultValue: CGFloat = 0 static var defaultValue: CGFloat = 0
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) { static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
@@ -28,6 +41,13 @@ struct MaximumWidthPreferenceKey: PreferenceKey {
} }
} }
struct MaximumWidthImageVideoPreferenceKey: PreferenceKey {
static var defaultValue: CGFloat = 0
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
value = max(value, nextValue())
}
}
struct DetermineWidth_Previews: PreviewProvider { struct DetermineWidth_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
DetermineWidth() DetermineWidth()
@@ -9,29 +9,51 @@
import SwiftUI import SwiftUI
import SimpleXChat import SimpleXChat
let defaultProfileImageCorner = 22.5
struct ProfileImage: View { struct ProfileImage: View {
var imageStr: String? = nil var imageStr: String? = nil
var iconName: String = "person.crop.circle.fill" var iconName: String = "person.crop.circle.fill"
var size: CGFloat
var color = Color(uiColor: .tertiarySystemGroupedBackground) var color = Color(uiColor: .tertiarySystemGroupedBackground)
@AppStorage(DEFAULT_PROFILE_IMAGE_CORNER_RADIUS) private var radius = defaultProfileImageCorner
var body: some View { var body: some View {
if let image = imageStr, if let image = imageStr,
let data = Data(base64Encoded: dropImagePrefix(image)), let data = Data(base64Encoded: dropImagePrefix(image)),
let uiImage = UIImage(data: data) { let uiImage = UIImage(data: data) {
Image(uiImage: uiImage) clipProfileImage(Image(uiImage: uiImage), size: size, radius: radius)
.resizable()
.clipShape(Circle())
} else { } else {
Image(systemName: iconName) Image(systemName: iconName)
.resizable() .resizable()
.foregroundColor(color) .foregroundColor(color)
.frame(width: size, height: size)
} }
} }
} }
private let squareToCircleRatio = 0.935
private let radiusFactor = (1 - squareToCircleRatio) / 50
@ViewBuilder func clipProfileImage(_ img: Image, size: CGFloat, radius: Double) -> some View {
let v = img.resizable()
if radius >= 50 {
v.frame(width: size, height: size).clipShape(Circle())
} else if radius <= 0 {
let sz = size * squareToCircleRatio
v.frame(width: sz, height: sz).padding((size - sz) / 2)
} else {
let sz = size * (squareToCircleRatio + radius * radiusFactor)
v.frame(width: sz, height: sz)
.clipShape(RoundedRectangle(cornerRadius: sz * radius / 100, style: .continuous))
.padding((size - sz) / 2)
}
}
struct ProfileImage_Previews: PreviewProvider { struct ProfileImage_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
ProfileImage(imageStr: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAKHGlDQ1BJQ0MgUHJvZmlsZQAASImFVgdUVNcWve9Nb7QZeu9NehtAem/Sq6gMQ28OQxWxgAQjEFFEREARNFQFg1KjiIhiIQgoYA9IEFBisCAq6OQNJNH4//r/zDpz9ttzz7n73ffWmg0A6QCDxYqD+QCIT0hmezlYywQEBsngngEYCAIy0AC6DGYSy8rDwxUg8Xf9d7wbAxC33tHgzvrP3/9nCISFJzEBgIIRTGey2MkILkawT1oyi4tnEUxjI6IQvMLFkauYqxjQQtewwuoaHy8bBNMBwJMZDHYkAERbhJdJZUYic4hhCNZOCItOQDB3vjkzioFwxLsIXhcRl5IOAImrRzs+fivCk7QRrIL0shAcwNUW+tX8yH/tFfrPXgxG5D84Pi6F+dc9ck+HHJ7g641UMSQlQATQBHEgBaQDGcACbLAVYaIRJhx5Dv+9j77aZ4OsZIFtSEc0iARRIBnpt/9qlvfqpGSQBhjImnCEcUU+NtxnujZy4fbqVEiU/wuXdQyA9S0cDqfzC+e2F4DzyLkSB79wyi0A8KoBcL2GmcJOXePQ3C8MIAJeQAOiQArIAxXuWwMMgSmwBHbAGbgDHxAINgMmojceUZUGMkEWyAX54AA4DMpAJTgJ6sAZ0ALawQVwGVwDt8AQGAUPwQSYBi/AAngHliEIwkEUiAqJQtKQIqQO6UJ0yByyg1whLygQCoEioQQoBcqE9kD5UBFUBlVB9dBPUCd0GboBDUP3oUloDnoNfYRRMBmmwZKwEqwF02Er2AX2gTfBkXAinAHnwPvhUrgaPg23wZfhW/AoPAG/gBdRAEVCCaFkURooOsoG5Y4KQkWg2KidqDxUCaoa1YTqQvWj7qAmUPOoD2gsmoqWQWugTdGOaF80E52I3okuQJeh69Bt6D70HfQkegH9GUPBSGDUMSYYJ0wAJhKThsnFlGBqMK2Yq5hRzDTmHRaLFcIqY42wjthAbAx2O7YAewzbjO3BDmOnsIs4HE4Up44zw7njGLhkXC7uKO407hJuBDeNe48n4aXxunh7fBA+AZ+NL8E34LvxI/gZ/DKBj6BIMCG4E8II2wiFhFOELsJtwjRhmchPVCaaEX2IMcQsYimxiXiV+Ij4hkQiyZGMSZ6kaNJuUinpLOk6aZL0gSxAViPbkIPJKeT95FpyD/k++Q2FQlGiWFKCKMmU/ZR6yhXKE8p7HiqPJo8TTxjPLp5ynjaeEZ6XvAReRV4r3s28GbwlvOd4b/PO8xH4lPhs+Bh8O/nK+Tr5xvkW+an8Ovzu/PH8BfwN/Df4ZwVwAkoCdgJhAjkCJwWuCExRUVR5qg2VSd1DPUW9Sp2mYWnKNCdaDC2fdoY2SFsQFBDUF/QTTBcsF7woOCGEElISchKKEyoUahEaE/ooLClsJRwuvE+4SXhEeElEXMRSJFwkT6RZZFTko6iMqJ1orOhB0XbRx2JoMTUxT7E0seNiV8XmxWnipuJM8TzxFvEHErCEmoSXxHaJkxIDEouSUpIOkizJo5JXJOelhKQspWKkiqW6peakqdLm0tHSxdKXpJ/LCMpYycTJlMr0ySzISsg6yqbIVskOyi7LKcv5ymXLNcs9lifK0+Uj5Ivle+UXFKQV3BQyFRoVHigSFOmKUYpHFPsVl5SUlfyV9iq1K80qiyg7KWcoNyo/UqGoWKgkqlSr3FXFqtJVY1WPqQ6pwWoGalFq5Wq31WF1Q/Vo9WPqw+sw64zXJayrXjeuQdaw0kjVaNSY1BTSdNXM1mzXfKmloBWkdVCrX+uztoF2nPYp7Yc6AjrOOtk6XTqvddV0mbrlunf1KHr2erv0OvRe6avrh+sf179nQDVwM9hr0GvwydDIkG3YZDhnpGAUYlRhNE6n0T3oBfTrxhhja+NdxheMP5gYmiSbtJj8YaphGmvaYDq7Xnl9+PpT66fM5MwYZlVmE+Yy5iHmJ8wnLGQtGBbVFk8t5S3DLGssZ6xUrWKsTlu9tNa2Zlu3Wi/ZmNjssOmxRdk62ObZDtoJ2Pnaldk9sZezj7RvtF9wMHDY7tDjiHF0cTzoOO4k6cR0qndacDZy3uHc50J28XYpc3nqqubKdu1yg92c3Q65PdqguCFhQ7s7cHdyP+T+2EPZI9HjZ0+sp4dnueczLx2vTK9+b6r3Fu8G73c+1j6FPg99VXxTfHv9eP2C/er9lvxt/Yv8JwK0AnYE3AoUC4wO7AjCBfkF1QQtbrTbeHjjdLBBcG7w2CblTembbmwW2xy3+eIW3i2MLedCMCH+IQ0hKwx3RjVjMdQptCJ0gWnDPMJ8EWYZVhw2F24WXhQ+E2EWURQxG2kWeShyLsoiqiRqPtomuiz6VYxjTGXMUqx7bG0sJ84/rjkeHx8S35kgkBCb0LdVamv61mGWOiuXNZFokng4cYHtwq5JgpI2JXUk05A/0oEUlZTvUiZTzVPLU9+n+aWdS+dPT0gf2Ka2bd+2mQz7jB+3o7czt/dmymZmZU7usNpRtRPaGbqzd5f8rpxd07sddtdlEbNis37J1s4uyn67x39PV45kzu6cqe8cvmvM5cll547vNd1b+T36++jvB/fp7Tu673NeWN7NfO38kvyVAmbBzR90fij9gbM/Yv9goWHh8QPYAwkHxg5aHKwr4i/KKJo65HaorVimOK/47eEth2+U6JdUHiEeSTkyUepa2nFU4eiBoytlUWWj5dblzRUSFfsqlo6FHRs5bnm8qVKyMr/y44noE/eqHKraqpWqS05iT6aefHbK71T/j/Qf62vEavJrPtUm1E7UedX11RvV1zdINBQ2wo0pjXOng08PnbE909Gk0VTVLNScfxacTTn7/KeQn8ZaXFp6z9HPNZ1XPF/RSm3Na4PatrUttEe1T3QEdgx3Onf2dpl2tf6s+XPtBdkL5RcFLxZ2E7tzujmXMi4t9rB65i9HXp7q3dL78ErAlbt9nn2DV12uXr9mf+1Kv1X/petm1y/cMLnReZN+s/2W4a22AYOB1l8MfmkdNBxsu210u2PIeKhreP1w94jFyOU7tneu3XW6e2t0w+jwmO/YvfHg8Yl7Yfdm78fdf/Ug9cHyw92PMI/yHvM9Lnki8aT6V9VfmycMJy5O2k4OPPV++nCKOfXit6TfVqZznlGelcxIz9TP6s5emLOfG3q+8fn0C9aL5fnc3/l/r3ip8vL8H5Z/DCwELEy/Yr/ivC54I/qm9q3+295Fj8Un7+LfLS/lvRd9X/eB/qH/o//HmeW0FdxK6SfVT12fXT4/4sRzOCwGm7FqBVBIwhERALyuBYASCAB1CPEPG9f8119+BvrK2fyNwVndL5jhvubRVsMQgCakeCFp04OsQ1LJEgAe5NodqT6WANbT+yf/iqQIPd21PXgaAcDJcjivtwJAQHLFgcNZ9uBwPlUgYhHf1z37f7V9g9e8ITewiP88wfWIYET6HPg21nzjV2fybQVcxfrg2/onng/F50lD/ccAAAA4ZVhJZk1NACoAAAAIAAGHaQAEAAAAAQAAABoAAAAAAAKgAgAEAAAAAQAAABigAwAEAAAAAQAAABgAAAAAwf1XlwAAAaNJREFUSA3FlT1LA0EQQBN/gYUYRTksJZVgEbCR/D+7QMr8ABtttBBCsLGzsLG2sxaxED/ie4d77u0dyaE5HHjczn7MzO7M7nU6/yXz+bwLhzCCjTQO+rZhDH3opuNLdRYN4RHe4RIKJ7R34Ro+4AEGSw2mE1iUwT18gpI74WvkGlccu4XNdH0jnYU7cAUacidn37qR23cOxc4aGU0nYUAn7iSWEHkz46w0ocdQu1X6B/AMQZ5o7KfBqNOfwRH8JB7FajGhnmcpKvQe3MEbvILiDm5gPXaCHnZr4vvFGMoEKudKn8YvQIOOe+YzCPop7dwJ3zRfJ7GDuso4YJGRa0yZgg4tUaNXdGrbuZWKKxzYYEJc2xp9AUUjGt8KC2jvgYadF8+10vJyDnNLXwbdiWUZi0fUK01Eoc+AZhCLZVzK4Vq6sDUdz+0dEcbbTTIOJmAyTVhx/WmvrExbv2jtPhWLKodjCtefZiEeZeVZWWSndgwj6fVf3XON8Qwq15++uoqrfYVrow6dGBpCq79ME291jaB0/Q2CPncyht/99MNO/vr9AqW/CGi8sJqbAAAAAElFTkSuQmCC") ProfileImage(imageStr: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAKHGlDQ1BJQ0MgUHJvZmlsZQAASImFVgdUVNcWve9Nb7QZeu9NehtAem/Sq6gMQ28OQxWxgAQjEFFEREARNFQFg1KjiIhiIQgoYA9IEFBisCAq6OQNJNH4//r/zDpz9ttzz7n73ffWmg0A6QCDxYqD+QCIT0hmezlYywQEBsngngEYCAIy0AC6DGYSy8rDwxUg8Xf9d7wbAxC33tHgzvrP3/9nCISFJzEBgIIRTGey2MkILkawT1oyi4tnEUxjI6IQvMLFkauYqxjQQtewwuoaHy8bBNMBwJMZDHYkAERbhJdJZUYic4hhCNZOCItOQDB3vjkzioFwxLsIXhcRl5IOAImrRzs+fivCk7QRrIL0shAcwNUW+tX8yH/tFfrPXgxG5D84Pi6F+dc9ck+HHJ7g641UMSQlQATQBHEgBaQDGcACbLAVYaIRJhx5Dv+9j77aZ4OsZIFtSEc0iARRIBnpt/9qlvfqpGSQBhjImnCEcUU+NtxnujZy4fbqVEiU/wuXdQyA9S0cDqfzC+e2F4DzyLkSB79wyi0A8KoBcL2GmcJOXePQ3C8MIAJeQAOiQArIAxXuWwMMgSmwBHbAGbgDHxAINgMmojceUZUGMkEWyAX54AA4DMpAJTgJ6sAZ0ALawQVwGVwDt8AQGAUPwQSYBi/AAngHliEIwkEUiAqJQtKQIqQO6UJ0yByyg1whLygQCoEioQQoBcqE9kD5UBFUBlVB9dBPUCd0GboBDUP3oUloDnoNfYRRMBmmwZKwEqwF02Er2AX2gTfBkXAinAHnwPvhUrgaPg23wZfhW/AoPAG/gBdRAEVCCaFkURooOsoG5Y4KQkWg2KidqDxUCaoa1YTqQvWj7qAmUPOoD2gsmoqWQWugTdGOaF80E52I3okuQJeh69Bt6D70HfQkegH9GUPBSGDUMSYYJ0wAJhKThsnFlGBqMK2Yq5hRzDTmHRaLFcIqY42wjthAbAx2O7YAewzbjO3BDmOnsIs4HE4Up44zw7njGLhkXC7uKO407hJuBDeNe48n4aXxunh7fBA+AZ+NL8E34LvxI/gZ/DKBj6BIMCG4E8II2wiFhFOELsJtwjRhmchPVCaaEX2IMcQsYimxiXiV+Ij4hkQiyZGMSZ6kaNJuUinpLOk6aZL0gSxAViPbkIPJKeT95FpyD/k++Q2FQlGiWFKCKMmU/ZR6yhXKE8p7HiqPJo8TTxjPLp5ynjaeEZ6XvAReRV4r3s28GbwlvOd4b/PO8xH4lPhs+Bh8O/nK+Tr5xvkW+an8Ovzu/PH8BfwN/Df4ZwVwAkoCdgJhAjkCJwWuCExRUVR5qg2VSd1DPUW9Sp2mYWnKNCdaDC2fdoY2SFsQFBDUF/QTTBcsF7woOCGEElISchKKEyoUahEaE/ooLClsJRwuvE+4SXhEeElEXMRSJFwkT6RZZFTko6iMqJ1orOhB0XbRx2JoMTUxT7E0seNiV8XmxWnipuJM8TzxFvEHErCEmoSXxHaJkxIDEouSUpIOkizJo5JXJOelhKQspWKkiqW6peakqdLm0tHSxdKXpJ/LCMpYycTJlMr0ySzISsg6yqbIVskOyi7LKcv5ymXLNcs9lifK0+Uj5Ivle+UXFKQV3BQyFRoVHigSFOmKUYpHFPsVl5SUlfyV9iq1K80qiyg7KWcoNyo/UqGoWKgkqlSr3FXFqtJVY1WPqQ6pwWoGalFq5Wq31WF1Q/Vo9WPqw+sw64zXJayrXjeuQdaw0kjVaNSY1BTSdNXM1mzXfKmloBWkdVCrX+uztoF2nPYp7Yc6AjrOOtk6XTqvddV0mbrlunf1KHr2erv0OvRe6avrh+sf179nQDVwM9hr0GvwydDIkG3YZDhnpGAUYlRhNE6n0T3oBfTrxhhja+NdxheMP5gYmiSbtJj8YaphGmvaYDq7Xnl9+PpT66fM5MwYZlVmE+Yy5iHmJ8wnLGQtGBbVFk8t5S3DLGssZ6xUrWKsTlu9tNa2Zlu3Wi/ZmNjssOmxRdk62ObZDtoJ2Pnaldk9sZezj7RvtF9wMHDY7tDjiHF0cTzoOO4k6cR0qndacDZy3uHc50J28XYpc3nqqubKdu1yg92c3Q65PdqguCFhQ7s7cHdyP+T+2EPZI9HjZ0+sp4dnueczLx2vTK9+b6r3Fu8G73c+1j6FPg99VXxTfHv9eP2C/er9lvxt/Yv8JwK0AnYE3AoUC4wO7AjCBfkF1QQtbrTbeHjjdLBBcG7w2CblTembbmwW2xy3+eIW3i2MLedCMCH+IQ0hKwx3RjVjMdQptCJ0gWnDPMJ8EWYZVhw2F24WXhQ+E2EWURQxG2kWeShyLsoiqiRqPtomuiz6VYxjTGXMUqx7bG0sJ84/rjkeHx8S35kgkBCb0LdVamv61mGWOiuXNZFokng4cYHtwq5JgpI2JXUk05A/0oEUlZTvUiZTzVPLU9+n+aWdS+dPT0gf2Ka2bd+2mQz7jB+3o7czt/dmymZmZU7usNpRtRPaGbqzd5f8rpxd07sddtdlEbNis37J1s4uyn67x39PV45kzu6cqe8cvmvM5cll547vNd1b+T36++jvB/fp7Tu673NeWN7NfO38kvyVAmbBzR90fij9gbM/Yv9goWHh8QPYAwkHxg5aHKwr4i/KKJo65HaorVimOK/47eEth2+U6JdUHiEeSTkyUepa2nFU4eiBoytlUWWj5dblzRUSFfsqlo6FHRs5bnm8qVKyMr/y44noE/eqHKraqpWqS05iT6aefHbK71T/j/Qf62vEavJrPtUm1E7UedX11RvV1zdINBQ2wo0pjXOng08PnbE909Gk0VTVLNScfxacTTn7/KeQn8ZaXFp6z9HPNZ1XPF/RSm3Na4PatrUttEe1T3QEdgx3Onf2dpl2tf6s+XPtBdkL5RcFLxZ2E7tzujmXMi4t9rB65i9HXp7q3dL78ErAlbt9nn2DV12uXr9mf+1Kv1X/petm1y/cMLnReZN+s/2W4a22AYOB1l8MfmkdNBxsu210u2PIeKhreP1w94jFyOU7tneu3XW6e2t0w+jwmO/YvfHg8Yl7Yfdm78fdf/Ug9cHyw92PMI/yHvM9Lnki8aT6V9VfmycMJy5O2k4OPPV++nCKOfXit6TfVqZznlGelcxIz9TP6s5emLOfG3q+8fn0C9aL5fnc3/l/r3ip8vL8H5Z/DCwELEy/Yr/ivC54I/qm9q3+295Fj8Un7+LfLS/lvRd9X/eB/qH/o//HmeW0FdxK6SfVT12fXT4/4sRzOCwGm7FqBVBIwhERALyuBYASCAB1CPEPG9f8119+BvrK2fyNwVndL5jhvubRVsMQgCakeCFp04OsQ1LJEgAe5NodqT6WANbT+yf/iqQIPd21PXgaAcDJcjivtwJAQHLFgcNZ9uBwPlUgYhHf1z37f7V9g9e8ITewiP88wfWIYET6HPg21nzjV2fybQVcxfrg2/onng/F50lD/ccAAAA4ZVhJZk1NACoAAAAIAAGHaQAEAAAAAQAAABoAAAAAAAKgAgAEAAAAAQAAABigAwAEAAAAAQAAABgAAAAAwf1XlwAAAaNJREFUSA3FlT1LA0EQQBN/gYUYRTksJZVgEbCR/D+7QMr8ABtttBBCsLGzsLG2sxaxED/ie4d77u0dyaE5HHjczn7MzO7M7nU6/yXz+bwLhzCCjTQO+rZhDH3opuNLdRYN4RHe4RIKJ7R34Ro+4AEGSw2mE1iUwT18gpI74WvkGlccu4XNdH0jnYU7cAUacidn37qR23cOxc4aGU0nYUAn7iSWEHkz46w0ocdQu1X6B/AMQZ5o7KfBqNOfwRH8JB7FajGhnmcpKvQe3MEbvILiDm5gPXaCHnZr4vvFGMoEKudKn8YvQIOOe+YzCPop7dwJ3zRfJ7GDuso4YJGRa0yZgg4tUaNXdGrbuZWKKxzYYEJc2xp9AUUjGt8KC2jvgYadF8+10vJyDnNLXwbdiWUZi0fUK01Eoc+AZhCLZVzK4Vq6sDUdz+0dEcbbTTIOJmAyTVhx/WmvrExbv2jtPhWLKodjCtefZiEeZeVZWWSndgwj6fVf3XON8Qwq15++uoqrfYVrow6dGBpCq79ME291jaB0/Q2CPncyht/99MNO/vr9AqW/CGi8sJqbAAAAAElFTkSuQmCC", size: 63)
.previewLayout(.fixed(width: 63, height: 63)) .previewLayout(.fixed(width: 63, height: 63))
.background(.black) .background(.black)
} }
@@ -150,7 +150,7 @@ struct MigrateFromDevice: View {
return Alert( return Alert(
title: Text(title), title: Text(title),
message: Text(text), message: Text(text),
primaryButton: .destructive(Text("Delete")) { primaryButton: .default(Text("Delete")) {
deleteChatAndDismiss() deleteChatAndDismiss()
}, },
secondaryButton: .cancel() secondaryButton: .cancel()
@@ -333,16 +333,16 @@ struct MigrateFromDevice: View {
ZStack { ZStack {
List { List {
Section { Section {
Button(action: { alert = .deleteChat() }) {
settingsRow("trash.fill") {
Text("Delete database from this device").foregroundColor(.accentColor)
}
}
Button(action: { alert = .startChat() }) { Button(action: { alert = .startChat() }) {
settingsRow("play.fill") { settingsRow("play.fill") {
Text("Start chat").foregroundColor(.red) Text("Start chat").foregroundColor(.red)
} }
} }
Button(action: { alert = .deleteChat() }) {
settingsRow("trash.fill") {
Text("Delete database from this device").foregroundColor(.accentColor)
}
}
} header: { } header: {
Text("Migration complete") Text("Migration complete")
} footer: { } footer: {
@@ -448,6 +448,9 @@ struct MigrateToDevice: View {
case .rcvFileError: case .rcvFileError:
alert = .error(title: "Download failed", error: "File was deleted or link is invalid") alert = .error(title: "Download failed", error: "File was deleted or link is invalid")
migrationState = .downloadFailed(totalBytes: totalBytes, link: link, archivePath: archivePath) migrationState = .downloadFailed(totalBytes: totalBytes, link: link, archivePath: archivePath)
case .chatError(_, .error(.noRcvFileUser)):
alert = .error(title: "Download failed", error: "File was deleted or link is invalid")
migrationState = .downloadFailed(totalBytes: totalBytes, link: link, archivePath: archivePath)
default: default:
logger.debug("unsupported event: \(msg.responseType)") logger.debug("unsupported event: \(msg.responseType)")
} }
@@ -70,9 +70,7 @@ struct AddGroupView: View {
ZStack(alignment: .center) { ZStack(alignment: .center) {
ZStack(alignment: .topTrailing) { ZStack(alignment: .topTrailing) {
ProfileImage(imageStr: profile.image, color: Color(uiColor: .secondarySystemGroupedBackground)) ProfileImage(imageStr: profile.image, size: 128, color: Color(uiColor: .secondarySystemGroupedBackground))
.aspectRatio(1, contentMode: .fit)
.frame(maxWidth: 128, maxHeight: 128)
if profile.image != nil { if profile.image != nil {
Button { Button {
profile.image = nil profile.image = nil
@@ -166,8 +166,10 @@ private func createProfile(_ displayName: String, showAlert: (UserProfileAlert)
) )
let m = ChatModel.shared let m = ChatModel.shared
do { do {
AppChatState.shared.set(.active)
m.currentUser = try apiCreateActiveUser(profile) m.currentUser = try apiCreateActiveUser(profile)
if m.users.isEmpty { // .isEmpty check is redundant here, but it makes it clearer what is going on
if m.users.isEmpty || m.users.allSatisfy({ $0.user.hidden }) {
try startChat() try startChat()
withAnimation { withAnimation {
onboardingStageDefault.set(.step3_CreateSimpleXAddress) onboardingStageDefault.set(.step3_CreateSimpleXAddress)
@@ -344,6 +344,68 @@ private let versionDescriptions: [VersionDescription] = [
description: "Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)!" description: "Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)!"
), ),
] ]
),
VersionDescription(
version: "v5.6",
post: URL(string: "https://simplex.chat/blog/20240323-simplex-network-privacy-non-profit-v5-6-quantum-resistant-e2e-encryption-simple-migration.html"),
features: [
FeatureDescription(
icon: "key",
title: "Quantum resistant encryption",
description: "Enable in direct chats (BETA)!"
),
FeatureDescription(
icon: "tray.and.arrow.up",
title: "App data migration",
description: "Migrate to another device via QR code."
),
FeatureDescription(
icon: "phone",
title: "Picture-in-picture calls",
description: "Use the app while in the call."
),
FeatureDescription(
icon: "hand.raised",
title: "Safer groups",
description: "Admins can block a member for all."
),
FeatureDescription(
icon: "character",
title: "Hungarian interface",
description: "Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)!"
),
]
),
VersionDescription(
version: "v5.7",
post: URL(string: "https://simplex.chat/blog/20240426-simplex-legally-binding-transparency-v5-7-better-user-experience.html"),
features: [
FeatureDescription(
icon: "key",
title: "Quantum resistant encryption",
description: "Will be enabled in direct chats!"
),
FeatureDescription(
icon: "arrowshape.turn.up.forward",
title: "Forward and save messages",
description: "Message source remains private."
),
FeatureDescription(
icon: "music.note",
title: "In-call sounds",
description: "When connecting audio and video calls."
),
FeatureDescription(
icon: "person.crop.square",
title: "Shape profile images",
description: "Square, circle, or anything in between."
),
FeatureDescription(
icon: "antenna.radiowaves.left.and.right",
title: "Network management",
description: "More reliable network connection."
)
]
) )
] ]
@@ -51,9 +51,10 @@ struct AdvancedNetworkSettings: View {
} }
.disabled(currentNetCfg == NetCfg.proxyDefaults) .disabled(currentNetCfg == NetCfg.proxyDefaults)
timeoutSettingPicker("TCP connection timeout", selection: $netCfg.tcpConnectTimeout, values: [7_500000, 10_000000, 15_000000, 20_000000, 30_000000, 45_000000], label: secondsLabel) timeoutSettingPicker("TCP connection timeout", selection: $netCfg.tcpConnectTimeout, values: [10_000000, 15_000000, 20_000000, 30_000000, 45_000000, 60_000000, 90_000000], label: secondsLabel)
timeoutSettingPicker("Protocol timeout", selection: $netCfg.tcpTimeout, values: [5_000000, 7_000000, 10_000000, 15_000000, 20_000000, 30_000000], label: secondsLabel) timeoutSettingPicker("Protocol timeout", selection: $netCfg.tcpTimeout, values: [5_000000, 7_000000, 10_000000, 15_000000, 20_000000, 30_000000], label: secondsLabel)
timeoutSettingPicker("Protocol timeout per KB", selection: $netCfg.tcpTimeoutPerKb, values: [15_000, 30_000, 45_000, 60_000, 90_000, 120_000], label: secondsLabel) timeoutSettingPicker("Protocol timeout per KB", selection: $netCfg.tcpTimeoutPerKb, values: [2_500, 5_000, 10_000, 15_000, 20_000, 30_000], label: secondsLabel)
// intSettingPicker("Receiving concurrency", selection: $netCfg.rcvConcurrency, values: [1, 2, 4, 8, 12, 16, 24], label: "")
timeoutSettingPicker("PING interval", selection: $netCfg.smpPingInterval, values: [120_000000, 300_000000, 600_000000, 1200_000000, 2400_000000, 3600_000000], label: secondsLabel) timeoutSettingPicker("PING interval", selection: $netCfg.smpPingInterval, values: [120_000000, 300_000000, 600_000000, 1200_000000, 2400_000000, 3600_000000], label: secondsLabel)
intSettingPicker("PING count", selection: $netCfg.smpPingCount, values: [1, 2, 3, 5, 8], label: "") intSettingPicker("PING count", selection: $netCfg.smpPingCount, values: [1, 2, 3, 5, 8], label: "")
Toggle("Enable TCP keep-alive", isOn: $enableKeepAlive) Toggle("Enable TCP keep-alive", isOn: $enableKeepAlive)
@@ -23,6 +23,7 @@ extension AppSettings {
setNetCfg(val) setNetCfg(val)
} }
if let val = privacyEncryptLocalFiles { privacyEncryptLocalFilesGroupDefault.set(val) } if let val = privacyEncryptLocalFiles { privacyEncryptLocalFilesGroupDefault.set(val) }
if let val = privacyAskToApproveRelays { privacyAskToApproveRelaysGroupDefault.set(val) }
if let val = privacyAcceptImages { if let val = privacyAcceptImages {
privacyAcceptImagesGroupDefault.set(val) privacyAcceptImagesGroupDefault.set(val)
def.setValue(val, forKey: DEFAULT_PRIVACY_ACCEPT_IMAGES) def.setValue(val, forKey: DEFAULT_PRIVACY_ACCEPT_IMAGES)
@@ -50,6 +51,7 @@ extension AppSettings {
var c = AppSettings.defaults var c = AppSettings.defaults
c.networkConfig = getNetCfg() c.networkConfig = getNetCfg()
c.privacyEncryptLocalFiles = privacyEncryptLocalFilesGroupDefault.get() c.privacyEncryptLocalFiles = privacyEncryptLocalFilesGroupDefault.get()
c.privacyAskToApproveRelays = privacyAskToApproveRelaysGroupDefault.get()
c.privacyAcceptImages = privacyAcceptImagesGroupDefault.get() c.privacyAcceptImages = privacyAcceptImagesGroupDefault.get()
c.privacyLinkPreviews = def.bool(forKey: DEFAULT_PRIVACY_LINK_PREVIEWS) c.privacyLinkPreviews = def.bool(forKey: DEFAULT_PRIVACY_LINK_PREVIEWS)
c.privacyShowChatPreviews = def.bool(forKey: DEFAULT_PRIVACY_SHOW_CHAT_PREVIEWS) c.privacyShowChatPreviews = def.bool(forKey: DEFAULT_PRIVACY_SHOW_CHAT_PREVIEWS)
@@ -17,11 +17,14 @@ let interfaceStyleNames: [LocalizedStringKey] = ["System", "Light", "Dark"]
let appSettingsURL = URL(string: UIApplication.openSettingsURLString)! let appSettingsURL = URL(string: UIApplication.openSettingsURLString)!
struct AppearanceSettings: View { struct AppearanceSettings: View {
@EnvironmentObject var m: ChatModel
@Environment(\.colorScheme) var colorScheme
@EnvironmentObject var sceneDelegate: SceneDelegate @EnvironmentObject var sceneDelegate: SceneDelegate
@State private var iconLightTapped = false @State private var iconLightTapped = false
@State private var iconDarkTapped = false @State private var iconDarkTapped = false
@State private var userInterfaceStyle = getUserInterfaceStyleDefault() @State private var userInterfaceStyle = getUserInterfaceStyleDefault()
@State private var uiTintColor = getUIAccentColorDefault() @State private var uiTintColor = getUIAccentColorDefault()
@AppStorage(DEFAULT_PROFILE_IMAGE_CORNER_RADIUS) private var profileImageCornerRadius = defaultProfileImageCorner
var body: some View { var body: some View {
VStack{ VStack{
@@ -44,6 +47,23 @@ struct AppearanceSettings: View {
} }
} }
Section("Profile images") {
HStack(spacing: 16) {
if let img = m.currentUser?.image, img != "" {
ProfileImage(imageStr: img, size: 60)
} else {
clipProfileImage(Image(colorScheme == .light ? "icon-dark" : "icon-light"), size: 60, radius: profileImageCornerRadius)
}
Slider(
value: $profileImageCornerRadius,
in: 0...50,
step: 2.5
)
}
.foregroundColor(.secondary)
}
Section { Section {
Picker("Theme", selection: $userInterfaceStyle) { Picker("Theme", selection: $userInterfaceStyle) {
ForEach(interfaceStyles, id: \.self) { style in ForEach(interfaceStyles, id: \.self) { style in
@@ -93,7 +113,7 @@ struct AppearanceSettings: View {
} }
._onButtonGesture { tapped.wrappedValue = $0 } perform: {} ._onButtonGesture { tapped.wrappedValue = $0 } perform: {}
.overlay(tapped.wrappedValue ? Color.secondary : Color.clear) .overlay(tapped.wrappedValue ? Color.secondary : Color.clear)
.cornerRadius(20) .cornerRadius(13.5)
} }
} }
@@ -12,7 +12,6 @@ import SimpleXChat
struct DeveloperView: View { struct DeveloperView: View {
@AppStorage(DEFAULT_DEVELOPER_TOOLS) private var developerTools = false @AppStorage(DEFAULT_DEVELOPER_TOOLS) private var developerTools = false
@AppStorage(GROUP_DEFAULT_CONFIRM_DB_UPGRADES, store: groupDefaults) private var confirmDatabaseUpgrades = false @AppStorage(GROUP_DEFAULT_CONFIRM_DB_UPGRADES, store: groupDefaults) private var confirmDatabaseUpgrades = false
@AppStorage(GROUP_DEFAULT_PQ_EXPERIMENTAL_ENABLED, store: groupDefaults) private var pqExperimentalEnabled = false
@Environment(\.colorScheme) var colorScheme @Environment(\.colorScheme) var colorScheme
var body: some View { var body: some View {
@@ -43,33 +42,9 @@ struct DeveloperView: View {
} footer: { } footer: {
(developerTools ? Text("Show:") : Text("Hide:")) + Text(" ") + Text("Database IDs and Transport isolation option.") (developerTools ? Text("Show:") : Text("Hide:")) + Text(" ") + Text("Database IDs and Transport isolation option.")
} }
if developerTools {
Section {
settingsRow("key") {
Toggle("Post-quantum E2EE", isOn: $pqExperimentalEnabled)
.onChange(of: pqExperimentalEnabled) {
setPQExperimentalEnabled($0)
}
}
} header: {
Text(String("Experimental"))
} footer: {
Text(String("In this version applies only to new contacts."))
}
}
} }
} }
} }
private func setPQExperimentalEnabled(_ enable: Bool) {
do {
try apiSetPQEncryption(enable)
} catch let error {
let err = responseError(error)
logger.error("apiSetPQEncryption \(err)")
}
}
} }
struct DeveloperView_Previews: PreviewProvider { struct DeveloperView_Previews: PreviewProvider {
@@ -12,24 +12,32 @@ import SimpleXChat
private enum NetworkAlert: Identifiable { private enum NetworkAlert: Identifiable {
case updateOnionHosts(hosts: OnionHosts) case updateOnionHosts(hosts: OnionHosts)
case updateSessionMode(mode: TransportSessionMode) case updateSessionMode(mode: TransportSessionMode)
case updateSMPProxyMode(proxyMode: SMPProxyMode)
case updateSMPProxyFallback(proxyFallback: SMPProxyFallback)
case error(err: String) case error(err: String)
var id: String { var id: String {
switch self { switch self {
case let .updateOnionHosts(hosts): return "updateOnionHosts \(hosts)" case let .updateOnionHosts(hosts): return "updateOnionHosts \(hosts)"
case let .updateSessionMode(mode): return "updateSessionMode \(mode)" case let .updateSessionMode(mode): return "updateSessionMode \(mode)"
case let .updateSMPProxyMode(proxyMode): return "updateSMPProxyMode \(proxyMode)"
case let .updateSMPProxyFallback(proxyFallback): return "updateSMPProxyFallback \(proxyFallback)"
case let .error(err): return "error \(err)" case let .error(err): return "error \(err)"
} }
} }
} }
struct NetworkAndServers: View { struct NetworkAndServers: View {
@EnvironmentObject var m: ChatModel
@AppStorage(DEFAULT_DEVELOPER_TOOLS) private var developerTools = false @AppStorage(DEFAULT_DEVELOPER_TOOLS) private var developerTools = false
@AppStorage(DEFAULT_SHOW_SENT_VIA_RPOXY) private var showSentViaProxy = true
@State private var cfgLoaded = false @State private var cfgLoaded = false
@State private var currentNetCfg = NetCfg.defaults @State private var currentNetCfg = NetCfg.defaults
@State private var netCfg = NetCfg.defaults @State private var netCfg = NetCfg.defaults
@State private var onionHosts: OnionHosts = .no @State private var onionHosts: OnionHosts = .no
@State private var sessionMode: TransportSessionMode = .user @State private var sessionMode: TransportSessionMode = .user
@State private var proxyMode: SMPProxyMode = .never
@State private var proxyFallback: SMPProxyFallback = .allow
@State private var alert: NetworkAlert? @State private var alert: NetworkAlert?
var body: some View { var body: some View {
@@ -74,6 +82,30 @@ struct NetworkAndServers: View {
Text("Using .onion hosts requires compatible VPN provider.") Text("Using .onion hosts requires compatible VPN provider.")
} }
Section {
Picker("Private routing", selection: $proxyMode) {
ForEach(SMPProxyMode.values, id: \.self) { Text($0.text) }
}
.frame(height: 36)
Picker("Allow downgrade", selection: $proxyFallback) {
ForEach(SMPProxyFallback.values, id: \.self) { Text($0.text) }
}
.disabled(proxyMode == .never)
.frame(height: 36)
Toggle("Show message status", isOn: $showSentViaProxy)
} header: {
Text("Private message routing")
} footer: {
VStack(alignment: .leading) {
Text("To protect your IP address, private routing uses your SMP servers to deliver messages.")
if showSentViaProxy {
Text("Show → on messages sent via private routing.")
}
}
}
Section("Calls") { Section("Calls") {
NavigationLink { NavigationLink {
RTCServers() RTCServers()
@@ -82,6 +114,14 @@ struct NetworkAndServers: View {
Text("WebRTC ICE servers") Text("WebRTC ICE servers")
} }
} }
Section("Network connection") {
HStack {
Text(m.networkInfo.networkType.text)
Spacer()
Image(systemName: "circle.fill").foregroundColor(m.networkInfo.online ? .green : .red)
}
}
} }
} }
.onAppear { .onAppear {
@@ -90,14 +130,24 @@ struct NetworkAndServers: View {
currentNetCfg = getNetCfg() currentNetCfg = getNetCfg()
resetNetCfgView() resetNetCfgView()
} }
.onChange(of: onionHosts) { _ in .onChange(of: onionHosts) { hosts in
if onionHosts != OnionHosts(netCfg: currentNetCfg) { if hosts != OnionHosts(netCfg: currentNetCfg) {
alert = .updateOnionHosts(hosts: onionHosts) alert = .updateOnionHosts(hosts: hosts)
} }
} }
.onChange(of: sessionMode) { _ in .onChange(of: sessionMode) { mode in
if sessionMode != netCfg.sessionMode { if mode != netCfg.sessionMode {
alert = .updateSessionMode(mode: sessionMode) alert = .updateSessionMode(mode: mode)
}
}
.onChange(of: proxyMode) { mode in
if mode != netCfg.smpProxyMode {
alert = .updateSMPProxyMode(proxyMode: mode)
}
}
.onChange(of: proxyFallback) { fallbackMode in
if fallbackMode != netCfg.smpProxyFallback {
alert = .updateSMPProxyFallback(proxyFallback: fallbackMode)
} }
} }
.alert(item: $alert) { a in .alert(item: $alert) { a in
@@ -128,6 +178,30 @@ struct NetworkAndServers: View {
resetNetCfgView() resetNetCfgView()
} }
) )
case let .updateSMPProxyMode(proxyMode):
return Alert(
title: Text("Message routing mode"),
message: Text(proxyModeInfo(proxyMode)) + Text("\n") + Text("Updating this setting will re-connect the client to all servers."),
primaryButton: .default(Text("Ok")) {
netCfg.smpProxyMode = proxyMode
saveNetCfg()
},
secondaryButton: .cancel() {
resetNetCfgView()
}
)
case let .updateSMPProxyFallback(proxyFallback):
return Alert(
title: Text("Message routing fallback"),
message: Text(proxyFallbackInfo(proxyFallback)) + Text("\n") + Text("Updating this setting will re-connect the client to all servers."),
primaryButton: .default(Text("Ok")) {
netCfg.smpProxyFallback = proxyFallback
saveNetCfg()
},
secondaryButton: .cancel() {
resetNetCfgView()
}
)
case let .error(err): case let .error(err):
return Alert( return Alert(
title: Text("Error updating settings"), title: Text("Error updating settings"),
@@ -157,6 +231,8 @@ struct NetworkAndServers: View {
netCfg = currentNetCfg netCfg = currentNetCfg
onionHosts = OnionHosts(netCfg: netCfg) onionHosts = OnionHosts(netCfg: netCfg)
sessionMode = netCfg.sessionMode sessionMode = netCfg.sessionMode
proxyMode = netCfg.smpProxyMode
proxyFallback = netCfg.smpProxyFallback
} }
private func onionHostsInfo(_ hosts: OnionHosts) -> LocalizedStringKey { private func onionHostsInfo(_ hosts: OnionHosts) -> LocalizedStringKey {
@@ -173,6 +249,23 @@ struct NetworkAndServers: View {
case .entity: return "A separate TCP connection will be used **for each contact and group member**.\n**Please note**: if you have many connections, your battery and traffic consumption can be substantially higher and some connections may fail." case .entity: return "A separate TCP connection will be used **for each contact and group member**.\n**Please note**: if you have many connections, your battery and traffic consumption can be substantially higher and some connections may fail."
} }
} }
private func proxyModeInfo(_ mode: SMPProxyMode) -> LocalizedStringKey {
switch mode {
case .always: return "Always use private routing."
case .unknown: return "Use private routing with unknown servers."
case .unprotected: return "Use private routing with unknown servers when IP address is not protected."
case .never: return "Do NOT use private routing."
}
}
private func proxyFallbackInfo(_ proxyFallback: SMPProxyFallback) -> LocalizedStringKey {
switch proxyFallback {
case .allow: return "Send messages directly when your or destination server does not support private routing."
case .allowProtected: return "Send messages directly when IP address is protected and your or destination server does not support private routing."
case .prohibit: return "Do NOT send messages directly, even if your or destination server does not support private routing."
}
}
} }
struct NetworkServersView_Previews: PreviewProvider { struct NetworkServersView_Previews: PreviewProvider {
@@ -16,6 +16,7 @@ struct PrivacySettings: View {
@AppStorage(DEFAULT_PRIVACY_SHOW_CHAT_PREVIEWS) private var showChatPreviews = true @AppStorage(DEFAULT_PRIVACY_SHOW_CHAT_PREVIEWS) private var showChatPreviews = true
@AppStorage(DEFAULT_PRIVACY_SAVE_LAST_DRAFT) private var saveLastDraft = true @AppStorage(DEFAULT_PRIVACY_SAVE_LAST_DRAFT) private var saveLastDraft = true
@AppStorage(GROUP_DEFAULT_PRIVACY_ENCRYPT_LOCAL_FILES, store: groupDefaults) private var encryptLocalFiles = true @AppStorage(GROUP_DEFAULT_PRIVACY_ENCRYPT_LOCAL_FILES, store: groupDefaults) private var encryptLocalFiles = true
@AppStorage(GROUP_DEFAULT_PRIVACY_ASK_TO_APPROVE_RELAYS, store: groupDefaults) private var askToApproveRelays = true
@State private var simplexLinkMode = privacySimplexLinkModeDefault.get() @State private var simplexLinkMode = privacySimplexLinkModeDefault.get()
@AppStorage(DEFAULT_PRIVACY_PROTECT_SCREEN) private var protectScreen = false @AppStorage(DEFAULT_PRIVACY_PROTECT_SCREEN) private var protectScreen = false
@AppStorage(DEFAULT_PERFORM_LA) private var prefPerformLA = false @AppStorage(DEFAULT_PERFORM_LA) private var prefPerformLA = false
@@ -64,18 +65,6 @@ struct PrivacySettings: View {
} }
Section { Section {
settingsRow("lock.doc") {
Toggle("Encrypt local files", isOn: $encryptLocalFiles)
.onChange(of: encryptLocalFiles) {
setEncryptLocalFiles($0)
}
}
settingsRow("photo") {
Toggle("Auto-accept images", isOn: $autoAcceptImages)
.onChange(of: autoAcceptImages) {
privacyAcceptImagesGroupDefault.set($0)
}
}
settingsRow("network") { settingsRow("network") {
Toggle("Send link previews", isOn: $useLinkPreviews) Toggle("Send link previews", isOn: $useLinkPreviews)
} }
@@ -108,6 +97,32 @@ struct PrivacySettings: View {
Text("Chats") Text("Chats")
} }
Section {
settingsRow("lock.doc") {
Toggle("Encrypt local files", isOn: $encryptLocalFiles)
.onChange(of: encryptLocalFiles) {
setEncryptLocalFiles($0)
}
}
settingsRow("photo") {
Toggle("Auto-accept images", isOn: $autoAcceptImages)
.onChange(of: autoAcceptImages) {
privacyAcceptImagesGroupDefault.set($0)
}
}
settingsRow("network.badge.shield.half.filled") {
Toggle("Protect IP address", isOn: $askToApproveRelays)
}
} header: {
Text("Files")
} footer: {
if askToApproveRelays {
Text("The app will ask to confirm downloads from unknown file servers (except .onion).")
} else {
Text("Without Tor or VPN, your IP address will be visible to file servers.")
}
}
Section { Section {
settingsRow("person") { settingsRow("person") {
Toggle("Contacts", isOn: $contactReceipts) Toggle("Contacts", isOn: $contactReceipts)
@@ -45,6 +45,7 @@ let DEFAULT_ACCENT_COLOR_RED = "accentColorRed"
let DEFAULT_ACCENT_COLOR_GREEN = "accentColorGreen" let DEFAULT_ACCENT_COLOR_GREEN = "accentColorGreen"
let DEFAULT_ACCENT_COLOR_BLUE = "accentColorBlue" let DEFAULT_ACCENT_COLOR_BLUE = "accentColorBlue"
let DEFAULT_USER_INTERFACE_STYLE = "userInterfaceStyle" let DEFAULT_USER_INTERFACE_STYLE = "userInterfaceStyle"
let DEFAULT_PROFILE_IMAGE_CORNER_RADIUS = "profileImageCornerRadius"
let DEFAULT_CONNECT_VIA_LINK_TAB = "connectViaLinkTab" let DEFAULT_CONNECT_VIA_LINK_TAB = "connectViaLinkTab"
let DEFAULT_LIVE_MESSAGE_ALERT_SHOWN = "liveMessageAlertShown" let DEFAULT_LIVE_MESSAGE_ALERT_SHOWN = "liveMessageAlertShown"
let DEFAULT_SHOW_HIDDEN_PROFILES_NOTICE = "showHiddenProfilesNotice" let DEFAULT_SHOW_HIDDEN_PROFILES_NOTICE = "showHiddenProfilesNotice"
@@ -59,6 +60,7 @@ let DEFAULT_DEVICE_NAME_FOR_REMOTE_ACCESS = "deviceNameForRemoteAccess"
let DEFAULT_CONFIRM_REMOTE_SESSIONS = "confirmRemoteSessions" let DEFAULT_CONFIRM_REMOTE_SESSIONS = "confirmRemoteSessions"
let DEFAULT_CONNECT_REMOTE_VIA_MULTICAST = "connectRemoteViaMulticast" let DEFAULT_CONNECT_REMOTE_VIA_MULTICAST = "connectRemoteViaMulticast"
let DEFAULT_CONNECT_REMOTE_VIA_MULTICAST_AUTO = "connectRemoteViaMulticastAuto" let DEFAULT_CONNECT_REMOTE_VIA_MULTICAST_AUTO = "connectRemoteViaMulticastAuto"
let DEFAULT_SHOW_SENT_VIA_RPOXY = "showSentViaProxy"
let ANDROID_DEFAULT_CALL_ON_LOCK_SCREEN = "androidCallOnLockScreen" let ANDROID_DEFAULT_CALL_ON_LOCK_SCREEN = "androidCallOnLockScreen"
@@ -87,6 +89,7 @@ let appDefaults: [String: Any] = [
DEFAULT_ACCENT_COLOR_GREEN: 0.533, DEFAULT_ACCENT_COLOR_GREEN: 0.533,
DEFAULT_ACCENT_COLOR_BLUE: 1.000, DEFAULT_ACCENT_COLOR_BLUE: 1.000,
DEFAULT_USER_INTERFACE_STYLE: 0, DEFAULT_USER_INTERFACE_STYLE: 0,
DEFAULT_PROFILE_IMAGE_CORNER_RADIUS: defaultProfileImageCorner,
DEFAULT_CONNECT_VIA_LINK_TAB: ConnectViaLinkTab.scan.rawValue, DEFAULT_CONNECT_VIA_LINK_TAB: ConnectViaLinkTab.scan.rawValue,
DEFAULT_LIVE_MESSAGE_ALERT_SHOWN: false, DEFAULT_LIVE_MESSAGE_ALERT_SHOWN: false,
DEFAULT_SHOW_HIDDEN_PROFILES_NOTICE: true, DEFAULT_SHOW_HIDDEN_PROFILES_NOTICE: true,
@@ -97,6 +100,7 @@ let appDefaults: [String: Any] = [
DEFAULT_CONFIRM_REMOTE_SESSIONS: false, DEFAULT_CONFIRM_REMOTE_SESSIONS: false,
DEFAULT_CONNECT_REMOTE_VIA_MULTICAST: true, DEFAULT_CONNECT_REMOTE_VIA_MULTICAST: true,
DEFAULT_CONNECT_REMOTE_VIA_MULTICAST_AUTO: true, DEFAULT_CONNECT_REMOTE_VIA_MULTICAST_AUTO: true,
DEFAULT_SHOW_SENT_VIA_RPOXY: false,
ANDROID_DEFAULT_CALL_ON_LOCK_SCREEN: AppSettingsLockScreenCalls.show.rawValue ANDROID_DEFAULT_CALL_ON_LOCK_SCREEN: AppSettingsLockScreenCalls.show.rawValue
] ]
@@ -425,8 +429,7 @@ struct ProfilePreview: View {
var body: some View { var body: some View {
HStack { HStack {
ProfileImage(imageStr: profileOf.image, color: color) ProfileImage(imageStr: profileOf.image, size: 44, color: color)
.frame(width: 44, height: 44)
.padding(.trailing, 6) .padding(.trailing, 6)
.padding(.vertical, 6) .padding(.vertical, 6)
VStack(alignment: .leading) { VStack(alignment: .leading) {
@@ -188,9 +188,7 @@ struct UserProfile: View {
} }
func profileImageView(_ imageStr: String?) -> some View { func profileImageView(_ imageStr: String?) -> some View {
ProfileImage(imageStr: imageStr) ProfileImage(imageStr: imageStr, size: 192)
.aspectRatio(1, contentMode: .fit)
.frame(maxWidth: 192, maxHeight: 192)
} }
func editImageButton(action: @escaping () -> Void) -> some View { func editImageButton(action: @escaping () -> Void) -> some View {
@@ -276,6 +276,7 @@ struct UserProfilesView: View {
// Deleting the last visible user while having hidden one(s) // Deleting the last visible user while having hidden one(s)
try await deleteUser() try await deleteUser()
try await changeActiveUserAsync_(nil, viewPwd: nil) try await changeActiveUserAsync_(nil, viewPwd: nil)
try? await stopChatAsync()
await MainActor.run { await MainActor.run {
onboardingStageDefault.set(.step1_SimpleXInfo) onboardingStageDefault.set(.step1_SimpleXInfo)
m.onboardingStage = .step1_SimpleXInfo m.onboardingStage = .step1_SimpleXInfo
@@ -308,8 +309,7 @@ struct UserProfilesView: View {
} }
} label: { } label: {
HStack { HStack {
ProfileImage(imageStr: user.image, color: Color(uiColor: .tertiarySystemFill)) ProfileImage(imageStr: user.image, size: 44, color: Color(uiColor: .tertiarySystemFill))
.frame(width: 44, height: 44)
.padding(.vertical, 4) .padding(.vertical, 4)
.padding(.trailing, 12) .padding(.trailing, 12)
Text(user.chatViewName) Text(user.chatViewName)
File diff suppressed because it is too large Load Diff
@@ -107,6 +107,10 @@
<target>%@ připojen</target> <target>%@ připojen</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="%@ downloaded" xml:space="preserve">
<source>%@ downloaded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ is connected!" xml:space="preserve"> <trans-unit id="%@ is connected!" xml:space="preserve">
<source>%@ is connected!</source> <source>%@ is connected!</source>
<target>%@ je připojen!</target> <target>%@ je připojen!</target>
@@ -127,6 +131,10 @@
<target>%@ servery</target> <target>%@ servery</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="%@ uploaded" xml:space="preserve">
<source>%@ uploaded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ wants to connect!" xml:space="preserve"> <trans-unit id="%@ wants to connect!" xml:space="preserve">
<source>%@ wants to connect!</source> <source>%@ wants to connect!</source>
<target>%@ se chce připojit!</target> <target>%@ se chce připojit!</target>
@@ -332,6 +340,10 @@
<target>**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).</target> <target>**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).</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="**Please note**: using the same database on two devices will break the decryption of messages from your connections, as a security protection." xml:space="preserve">
<source>**Please note**: using the same database on two devices will break the decryption of messages from your connections, as a security protection.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="**Please note**: you will NOT be able to recover or change passphrase if you lose it." xml:space="preserve"> <trans-unit id="**Please note**: you will NOT be able to recover or change passphrase if you lose it." xml:space="preserve">
<source>**Please note**: you will NOT be able to recover or change passphrase if you lose it.</source> <source>**Please note**: you will NOT be able to recover or change passphrase if you lose it.</source>
<target>**Upozornění**: Pokud heslo ztratíte, NEBUDETE jej moci obnovit ani změnit.</target> <target>**Upozornění**: Pokud heslo ztratíte, NEBUDETE jej moci obnovit ani změnit.</target>
@@ -347,6 +359,10 @@
<target>**Upozornění**: Okamžitě doručovaná oznámení vyžadují přístupové heslo uložené v Klíčence.</target> <target>**Upozornění**: Okamžitě doručovaná oznámení vyžadují přístupové heslo uložené v Klíčence.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="**Warning**: the archive will be removed." xml:space="preserve">
<source>**Warning**: the archive will be removed.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="**e2e encrypted** audio call" xml:space="preserve"> <trans-unit id="**e2e encrypted** audio call" xml:space="preserve">
<source>**e2e encrypted** audio call</source> <source>**e2e encrypted** audio call</source>
<target>**e2e šifrovaný** audio hovor</target> <target>**e2e šifrovaný** audio hovor</target>
@@ -598,6 +614,10 @@
<target>Změna adresy bude přerušena. Budou použity staré přijímací adresy.</target> <target>Změna adresy bude přerušena. Budou použity staré přijímací adresy.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Admins can block a member for all." xml:space="preserve">
<source>Admins can block a member for all.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Admins can create the links to join groups." xml:space="preserve"> <trans-unit id="Admins can create the links to join groups." xml:space="preserve">
<source>Admins can create the links to join groups.</source> <source>Admins can create the links to join groups.</source>
<target>Správci mohou vytvářet odkazy pro připojení ke skupinám.</target> <target>Správci mohou vytvářet odkazy pro připojení ke skupinám.</target>
@@ -651,6 +671,10 @@
<target>Všechny vaše kontakty zůstanou připojeny. Aktualizace profilu bude odeslána vašim kontaktům.</target> <target>Všechny vaše kontakty zůstanou připojeny. Aktualizace profilu bude odeslána vašim kontaktům.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="All your contacts, conversations and files will be securely encrypted and uploaded in chunks to configured XFTP relays." xml:space="preserve">
<source>All your contacts, conversations and files will be securely encrypted and uploaded in chunks to configured XFTP relays.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow" xml:space="preserve"> <trans-unit id="Allow" xml:space="preserve">
<source>Allow</source> <source>Allow</source>
<target>Povolit</target> <target>Povolit</target>
@@ -696,6 +720,10 @@
<target>Povolit nevratné smazání odeslaných zpráv. (24 hodin)</target> <target>Povolit nevratné smazání odeslaných zpráv. (24 hodin)</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
<source>Allow to send SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send files and media." xml:space="preserve"> <trans-unit id="Allow to send files and media." xml:space="preserve">
<source>Allow to send files and media.</source> <source>Allow to send files and media.</source>
<target>Povolit odesílání souborů a médii.</target> <target>Povolit odesílání souborů a médii.</target>
@@ -774,6 +802,10 @@
<target>Sestavení aplikace: %@</target> <target>Sestavení aplikace: %@</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="App data migration" xml:space="preserve">
<source>App data migration</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="App encrypts new local files (except videos)." xml:space="preserve"> <trans-unit id="App encrypts new local files (except videos)." xml:space="preserve">
<source>App encrypts new local files (except videos).</source> <source>App encrypts new local files (except videos).</source>
<target>Aplikace šifruje nové místní soubory (s výjimkou videí).</target> <target>Aplikace šifruje nové místní soubory (s výjimkou videí).</target>
@@ -809,6 +841,18 @@
<target>Vzhled</target> <target>Vzhled</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Apply" xml:space="preserve">
<source>Apply</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive and upload" xml:space="preserve">
<source>Archive and upload</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archiving database" xml:space="preserve">
<source>Archiving database</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Attach" xml:space="preserve"> <trans-unit id="Attach" xml:space="preserve">
<source>Attach</source> <source>Attach</source>
<target>Připojit</target> <target>Připojit</target>
@@ -989,6 +1033,10 @@
<target>Zrušit</target> <target>Zrušit</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Cancel migration" xml:space="preserve">
<source>Cancel migration</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Cannot access keychain to save database password" xml:space="preserve"> <trans-unit id="Cannot access keychain to save database password" xml:space="preserve">
<source>Cannot access keychain to save database password</source> <source>Cannot access keychain to save database password</source>
<target>Nelze získat přístup ke klíčence pro uložení hesla databáze</target> <target>Nelze získat přístup ke klíčence pro uložení hesla databáze</target>
@@ -999,6 +1047,10 @@
<target>Nelze přijmout soubor</target> <target>Nelze přijmout soubor</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Cellular" xml:space="preserve">
<source>Cellular</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Change" xml:space="preserve"> <trans-unit id="Change" xml:space="preserve">
<source>Change</source> <source>Change</source>
<target>Změnit</target> <target>Změnit</target>
@@ -1089,6 +1141,10 @@
<source>Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat.</source> <source>Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat.</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Chat migrated!" xml:space="preserve">
<source>Chat migrated!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Chat preferences" xml:space="preserve"> <trans-unit id="Chat preferences" xml:space="preserve">
<source>Chat preferences</source> <source>Chat preferences</source>
<target>Předvolby chatu</target> <target>Předvolby chatu</target>
@@ -1109,6 +1165,10 @@
<target>Čínské a Španělské rozhranní</target> <target>Čínské a Španělské rozhranní</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Choose _Migrate from another device_ on the new device and scan QR code." xml:space="preserve">
<source>Choose _Migrate from another device_ on the new device and scan QR code.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Choose file" xml:space="preserve"> <trans-unit id="Choose file" xml:space="preserve">
<source>Choose file</source> <source>Choose file</source>
<target>Vybrat soubor</target> <target>Vybrat soubor</target>
@@ -1178,6 +1238,10 @@
<target>Potvrdit aktualizaci databáze</target> <target>Potvrdit aktualizaci databáze</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Confirm network settings" xml:space="preserve">
<source>Confirm network settings</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirm new passphrase…" xml:space="preserve"> <trans-unit id="Confirm new passphrase…" xml:space="preserve">
<source>Confirm new passphrase…</source> <source>Confirm new passphrase…</source>
<target>Potvrdit novou heslovou frázi…</target> <target>Potvrdit novou heslovou frázi…</target>
@@ -1188,6 +1252,14 @@
<target>Potvrdit heslo</target> <target>Potvrdit heslo</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Confirm that you remember database passphrase to migrate it." xml:space="preserve">
<source>Confirm that you remember database passphrase to migrate it.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirm upload" xml:space="preserve">
<source>Confirm upload</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect" xml:space="preserve"> <trans-unit id="Connect" xml:space="preserve">
<source>Connect</source> <source>Connect</source>
<target>Připojit</target> <target>Připojit</target>
@@ -1428,6 +1500,10 @@ This is your own one-time link!</source>
<target>Vytvořeno na %@</target> <target>Vytvořeno na %@</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Creating archive link" xml:space="preserve">
<source>Creating archive link</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Creating link…" xml:space="preserve"> <trans-unit id="Creating link…" xml:space="preserve">
<source>Creating link…</source> <source>Creating link…</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
@@ -1643,6 +1719,10 @@ This cannot be undone!</source>
<target>Odstranění databáze</target> <target>Odstranění databáze</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Delete database from this device" xml:space="preserve">
<source>Delete database from this device</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete file" xml:space="preserve"> <trans-unit id="Delete file" xml:space="preserve">
<source>Delete file</source> <source>Delete file</source>
<target>Smazat soubor</target> <target>Smazat soubor</target>
@@ -1927,11 +2007,27 @@ This cannot be undone!</source>
<target>Snížit a otevřít chat</target> <target>Snížit a otevřít chat</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Download" xml:space="preserve">
<source>Download</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Download failed" xml:space="preserve">
<source>Download failed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Download file" xml:space="preserve"> <trans-unit id="Download file" xml:space="preserve">
<source>Download file</source> <source>Download file</source>
<target>Stáhnout soubor</target> <target>Stáhnout soubor</target>
<note>server test step</note> <note>server test step</note>
</trans-unit> </trans-unit>
<trans-unit id="Downloading archive" xml:space="preserve">
<source>Downloading archive</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Downloading link details" xml:space="preserve">
<source>Downloading link details</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Duplicate display name!" xml:space="preserve"> <trans-unit id="Duplicate display name!" xml:space="preserve">
<source>Duplicate display name!</source> <source>Duplicate display name!</source>
<target>Duplicitní zobrazované jméno!</target> <target>Duplicitní zobrazované jméno!</target>
@@ -1986,6 +2082,10 @@ This cannot be undone!</source>
<target>Povolit pro všechny</target> <target>Povolit pro všechny</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Enable in direct chats (BETA)!" xml:space="preserve">
<source>Enable in direct chats (BETA)!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enable instant notifications?" xml:space="preserve"> <trans-unit id="Enable instant notifications?" xml:space="preserve">
<source>Enable instant notifications?</source> <source>Enable instant notifications?</source>
<target>Povolit okamžitá oznámení?</target> <target>Povolit okamžitá oznámení?</target>
@@ -2016,6 +2116,10 @@ This cannot be undone!</source>
<target>Povolit sebedestrukční heslo</target> <target>Povolit sebedestrukční heslo</target>
<note>set passcode view</note> <note>set passcode view</note>
</trans-unit> </trans-unit>
<trans-unit id="Enabled for" xml:space="preserve">
<source>Enabled for</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Encrypt" xml:space="preserve"> <trans-unit id="Encrypt" xml:space="preserve">
<source>Encrypt</source> <source>Encrypt</source>
<target>Šifrovat</target> <target>Šifrovat</target>
@@ -2097,6 +2201,10 @@ This cannot be undone!</source>
<source>Enter group name…</source> <source>Enter group name…</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Enter passphrase" xml:space="preserve">
<source>Enter passphrase</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter passphrase…" xml:space="preserve"> <trans-unit id="Enter passphrase…" xml:space="preserve">
<source>Enter passphrase…</source> <source>Enter passphrase…</source>
<target>Zadejte přístupovou frázi…</target> <target>Zadejte přístupovou frázi…</target>
@@ -2244,6 +2352,10 @@ This cannot be undone!</source>
<target>Chyba mazání uživatelského profilu</target> <target>Chyba mazání uživatelského profilu</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Error downloading the archive" xml:space="preserve">
<source>Error downloading the archive</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error enabling delivery receipts!" xml:space="preserve"> <trans-unit id="Error enabling delivery receipts!" xml:space="preserve">
<source>Error enabling delivery receipts!</source> <source>Error enabling delivery receipts!</source>
<target>Chyba povolení potvrzení o doručení!</target> <target>Chyba povolení potvrzení o doručení!</target>
@@ -2318,6 +2430,10 @@ This cannot be undone!</source>
<target>Při ukládání přístupové fráze do klíčenky došlo k chybě</target> <target>Při ukládání přístupové fráze do klíčenky došlo k chybě</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Error saving settings" xml:space="preserve">
<source>Error saving settings</source>
<note>when migrating</note>
</trans-unit>
<trans-unit id="Error saving user password" xml:space="preserve"> <trans-unit id="Error saving user password" xml:space="preserve">
<source>Error saving user password</source> <source>Error saving user password</source>
<target>Chyba ukládání hesla uživatele</target> <target>Chyba ukládání hesla uživatele</target>
@@ -2387,6 +2503,14 @@ This cannot be undone!</source>
<target>Chyba aktualizace soukromí uživatele</target> <target>Chyba aktualizace soukromí uživatele</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Error uploading the archive" xml:space="preserve">
<source>Error uploading the archive</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error verifying passphrase:" xml:space="preserve">
<source>Error verifying passphrase:</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error: " xml:space="preserve"> <trans-unit id="Error: " xml:space="preserve">
<source>Error: </source> <source>Error: </source>
<target>Chyba: </target> <target>Chyba: </target>
@@ -2436,6 +2560,10 @@ This cannot be undone!</source>
<target>Exportovaný archiv databáze.</target> <target>Exportovaný archiv databáze.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Exported file doesn't exist" xml:space="preserve">
<source>Exported file doesn't exist</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Exporting database archive…" xml:space="preserve"> <trans-unit id="Exporting database archive…" xml:space="preserve">
<source>Exporting database archive…</source> <source>Exporting database archive…</source>
<target>Exportuji archiv databáze…</target> <target>Exportuji archiv databáze…</target>
@@ -2495,6 +2623,10 @@ This cannot be undone!</source>
<target>Soubory a média jsou zakázány v této skupině.</target> <target>Soubory a média jsou zakázány v této skupině.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Files and media not allowed" xml:space="preserve">
<source>Files and media not allowed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media prohibited!" xml:space="preserve"> <trans-unit id="Files and media prohibited!" xml:space="preserve">
<source>Files and media prohibited!</source> <source>Files and media prohibited!</source>
<target>Soubory a média jsou zakázány!</target> <target>Soubory a média jsou zakázány!</target>
@@ -2505,6 +2637,14 @@ This cannot be undone!</source>
<target>Filtrovat nepřečtené a oblíbené chaty.</target> <target>Filtrovat nepřečtené a oblíbené chaty.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Finalize migration" xml:space="preserve">
<source>Finalize migration</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Finalize migration on another device." xml:space="preserve">
<source>Finalize migration on another device.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Finally, we have them! 🚀" xml:space="preserve"> <trans-unit id="Finally, we have them! 🚀" xml:space="preserve">
<source>Finally, we have them! 🚀</source> <source>Finally, we have them! 🚀</source>
<target>Konečně je máme! 🚀</target> <target>Konečně je máme! 🚀</target>
@@ -2550,6 +2690,22 @@ This cannot be undone!</source>
<target>Pro konzoli</target> <target>Pro konzoli</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Forward" xml:space="preserve">
<source>Forward</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Forward and save messages" xml:space="preserve">
<source>Forward and save messages</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded" xml:space="preserve">
<source>Forwarded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded from" xml:space="preserve">
<source>Forwarded from</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Found desktop" xml:space="preserve"> <trans-unit id="Found desktop" xml:space="preserve">
<source>Found desktop</source> <source>Found desktop</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
@@ -2656,6 +2812,10 @@ This cannot be undone!</source>
<target>Členové skupiny mohou nevratně mazat odeslané zprávy. (24 hodin)</target> <target>Členové skupiny mohou nevratně mazat odeslané zprávy. (24 hodin)</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Group members can send SimpleX links." xml:space="preserve">
<source>Group members can send SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send direct messages." xml:space="preserve"> <trans-unit id="Group members can send direct messages." xml:space="preserve">
<source>Group members can send direct messages.</source> <source>Group members can send direct messages.</source>
<target>Členové skupiny mohou posílat přímé zprávy.</target> <target>Členové skupiny mohou posílat přímé zprávy.</target>
@@ -2790,6 +2950,10 @@ This cannot be undone!</source>
<target>Jak používat servery</target> <target>Jak používat servery</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Hungarian interface" xml:space="preserve">
<source>Hungarian interface</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="ICE servers (one per line)" xml:space="preserve"> <trans-unit id="ICE servers (one per line)" xml:space="preserve">
<source>ICE servers (one per line)</source> <source>ICE servers (one per line)</source>
<target>Servery ICE (jeden na řádek)</target> <target>Servery ICE (jeden na řádek)</target>
@@ -2855,6 +3019,14 @@ This cannot be undone!</source>
<target>Import databáze</target> <target>Import databáze</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Import failed" xml:space="preserve">
<source>Import failed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Importing archive" xml:space="preserve">
<source>Importing archive</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Improved message delivery" xml:space="preserve"> <trans-unit id="Improved message delivery" xml:space="preserve">
<source>Improved message delivery</source> <source>Improved message delivery</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
@@ -2869,11 +3041,19 @@ This cannot be undone!</source>
<target>Vylepšená konfigurace serveru</target> <target>Vylepšená konfigurace serveru</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="In order to continue, chat should be stopped." xml:space="preserve">
<source>In order to continue, chat should be stopped.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="In reply to" xml:space="preserve"> <trans-unit id="In reply to" xml:space="preserve">
<source>In reply to</source> <source>In reply to</source>
<target>V odpovědi na</target> <target>V odpovědi na</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="In-call sounds" xml:space="preserve">
<source>In-call sounds</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Incognito" xml:space="preserve"> <trans-unit id="Incognito" xml:space="preserve">
<source>Incognito</source> <source>Incognito</source>
<target>Inkognito</target> <target>Inkognito</target>
@@ -2976,6 +3156,10 @@ This cannot be undone!</source>
<source>Invalid link</source> <source>Invalid link</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Invalid migration confirmation" xml:space="preserve">
<source>Invalid migration confirmation</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Invalid name!" xml:space="preserve"> <trans-unit id="Invalid name!" xml:space="preserve">
<source>Invalid name!</source> <source>Invalid name!</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
@@ -3326,11 +3510,19 @@ This is your link for group %@!</source>
<target>Reakce na zprávy jsou v této skupině zakázány.</target> <target>Reakce na zprávy jsou v této skupině zakázány.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Message source remains private." xml:space="preserve">
<source>Message source remains private.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message text" xml:space="preserve"> <trans-unit id="Message text" xml:space="preserve">
<source>Message text</source> <source>Message text</source>
<target>Text zprávy</target> <target>Text zprávy</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Message too large" xml:space="preserve">
<source>Message too large</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Messages" xml:space="preserve"> <trans-unit id="Messages" xml:space="preserve">
<source>Messages</source> <source>Messages</source>
<target>Zprávy</target> <target>Zprávy</target>
@@ -3345,11 +3537,47 @@ This is your link for group %@!</source>
<source>Messages from %@ will be shown!</source> <source>Messages from %@ will be shown!</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Messages, files and calls are protected by **end-to-end encryption** with perfect forward secrecy, repudiation and break-in recovery." xml:space="preserve">
<source>Messages, files and calls are protected by **end-to-end encryption** with perfect forward secrecy, repudiation and break-in recovery.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Messages, files and calls are protected by **quantum resistant e2e encryption** with perfect forward secrecy, repudiation and break-in recovery." xml:space="preserve">
<source>Messages, files and calls are protected by **quantum resistant e2e encryption** with perfect forward secrecy, repudiation and break-in recovery.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Migrate device" xml:space="preserve">
<source>Migrate device</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Migrate from another device" xml:space="preserve">
<source>Migrate from another device</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Migrate here" xml:space="preserve">
<source>Migrate here</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Migrate to another device" xml:space="preserve">
<source>Migrate to another device</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Migrate to another device via QR code." xml:space="preserve">
<source>Migrate to another device via QR code.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Migrating" xml:space="preserve">
<source>Migrating</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Migrating database archive…" xml:space="preserve"> <trans-unit id="Migrating database archive…" xml:space="preserve">
<source>Migrating database archive…</source> <source>Migrating database archive…</source>
<target>Přenášení archivu databáze…</target> <target>Přenášení archivu databáze…</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Migration complete" xml:space="preserve">
<source>Migration complete</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Migration error:" xml:space="preserve"> <trans-unit id="Migration error:" xml:space="preserve">
<source>Migration error:</source> <source>Migration error:</source>
<target>Chyba přenášení:</target> <target>Chyba přenášení:</target>
@@ -3390,6 +3618,10 @@ This is your link for group %@!</source>
<target>Další vylepšení se chystají již brzy!</target> <target>Další vylepšení se chystají již brzy!</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="More reliable network connection." xml:space="preserve">
<source>More reliable network connection.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Most likely this connection is deleted." xml:space="preserve"> <trans-unit id="Most likely this connection is deleted." xml:space="preserve">
<source>Most likely this connection is deleted.</source> <source>Most likely this connection is deleted.</source>
<target>Pravděpodobně je toto spojení smazáno.</target> <target>Pravděpodobně je toto spojení smazáno.</target>
@@ -3425,6 +3657,14 @@ This is your link for group %@!</source>
<target>Síť a servery</target> <target>Síť a servery</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Network connection" xml:space="preserve">
<source>Network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Network management" xml:space="preserve">
<source>Network management</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Network settings" xml:space="preserve"> <trans-unit id="Network settings" xml:space="preserve">
<source>Network settings</source> <source>Network settings</source>
<target>Nastavení sítě</target> <target>Nastavení sítě</target>
@@ -3534,6 +3774,10 @@ This is your link for group %@!</source>
<target>Žádná historie</target> <target>Žádná historie</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="No network connection" xml:space="preserve">
<source>No network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record voice message" xml:space="preserve"> <trans-unit id="No permission to record voice message" xml:space="preserve">
<source>No permission to record voice message</source> <source>No permission to record voice message</source>
<target>Nemáte oprávnění nahrávat hlasové zprávy</target> <target>Nemáte oprávnění nahrávat hlasové zprávy</target>
@@ -3705,6 +3949,10 @@ This is your link for group %@!</source>
<source>Open group</source> <source>Open group</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Open migration to another device" xml:space="preserve">
<source>Open migration to another device</source>
<note>authentication reason</note>
</trans-unit>
<trans-unit id="Open user profiles" xml:space="preserve"> <trans-unit id="Open user profiles" xml:space="preserve">
<source>Open user profiles</source> <source>Open user profiles</source>
<target>Otevřít uživatelské profily</target> <target>Otevřít uživatelské profily</target>
@@ -3719,14 +3967,26 @@ This is your link for group %@!</source>
<source>Opening app…</source> <source>Opening app…</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Or paste archive link" xml:space="preserve">
<source>Or paste archive link</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Or scan QR code" xml:space="preserve"> <trans-unit id="Or scan QR code" xml:space="preserve">
<source>Or scan QR code</source> <source>Or scan QR code</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Or securely share this file link" xml:space="preserve">
<source>Or securely share this file link</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Or show this code" xml:space="preserve"> <trans-unit id="Or show this code" xml:space="preserve">
<source>Or show this code</source> <source>Or show this code</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Other" xml:space="preserve">
<source>Other</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve"> <trans-unit id="PING count" xml:space="preserve">
<source>PING count</source> <source>PING count</source>
<target>Počet PING</target> <target>Počet PING</target>
@@ -3803,6 +4063,10 @@ This is your link for group %@!</source>
<target>Chyba dešifrování</target> <target>Chyba dešifrování</target>
<note>message decrypt error item</note> <note>message decrypt error item</note>
</trans-unit> </trans-unit>
<trans-unit id="Picture-in-picture calls" xml:space="preserve">
<source>Picture-in-picture calls</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Please ask your contact to enable sending voice messages." xml:space="preserve"> <trans-unit id="Please ask your contact to enable sending voice messages." xml:space="preserve">
<source>Please ask your contact to enable sending voice messages.</source> <source>Please ask your contact to enable sending voice messages.</source>
<target>Prosím, požádejte kontaktní osobu, aby umožnila odesílání hlasových zpráv.</target> <target>Prosím, požádejte kontaktní osobu, aby umožnila odesílání hlasových zpráv.</target>
@@ -3823,6 +4087,10 @@ This is your link for group %@!</source>
<target>Zkontrolujte prosím nastavení své i svého kontaktu.</target> <target>Zkontrolujte prosím nastavení své i svého kontaktu.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Please confirm that network settings are correct for this device." xml:space="preserve">
<source>Please confirm that network settings are correct for this device.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Please contact developers.&#10;Error: %@" xml:space="preserve"> <trans-unit id="Please contact developers.&#10;Error: %@" xml:space="preserve">
<source>Please contact developers. <source>Please contact developers.
Error: %@</source> Error: %@</source>
@@ -3927,6 +4195,10 @@ Error: %@</source>
<target>Profilový obrázek</target> <target>Profilový obrázek</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Profile images" xml:space="preserve">
<source>Profile images</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile name" xml:space="preserve"> <trans-unit id="Profile name" xml:space="preserve">
<source>Profile name</source> <source>Profile name</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
@@ -3965,6 +4237,10 @@ Error: %@</source>
<target>Zakázat reakce na zprávy.</target> <target>Zakázat reakce na zprávy.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
<source>Prohibit sending SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending direct messages to members." xml:space="preserve"> <trans-unit id="Prohibit sending direct messages to members." xml:space="preserve">
<source>Prohibit sending direct messages to members.</source> <source>Prohibit sending direct messages to members.</source>
<target>Zakázat odesílání přímých zpráv členům.</target> <target>Zakázat odesílání přímých zpráv členům.</target>
@@ -4010,6 +4286,14 @@ Error: %@</source>
<target>Nabízená oznámení</target> <target>Nabízená oznámení</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Push server" xml:space="preserve">
<source>Push server</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Quantum resistant encryption" xml:space="preserve">
<source>Quantum resistant encryption</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Rate the app" xml:space="preserve"> <trans-unit id="Rate the app" xml:space="preserve">
<source>Rate the app</source> <source>Rate the app</source>
<target>Ohodnoťte aplikaci</target> <target>Ohodnoťte aplikaci</target>
@@ -4084,6 +4368,10 @@ Error: %@</source>
<target>Přijímací adresa bude změněna na jiný server. Změna adresy bude dokončena po připojení odesílatele.</target> <target>Přijímací adresa bude změněna na jiný server. Změna adresy bude dokončena po připojení odesílatele.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Receiving concurrency" xml:space="preserve">
<source>Receiving concurrency</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Receiving file will be stopped." xml:space="preserve"> <trans-unit id="Receiving file will be stopped." xml:space="preserve">
<source>Receiving file will be stopped.</source> <source>Receiving file will be stopped.</source>
<target>Příjem souboru bude zastaven.</target> <target>Příjem souboru bude zastaven.</target>
@@ -4098,6 +4386,10 @@ Error: %@</source>
<source>Recent history and improved [directory bot](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</source> <source>Recent history and improved [directory bot](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Recipient(s) can't see who this message is from." xml:space="preserve">
<source>Recipient(s) can't see who this message is from.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Recipients see updates as you type them." xml:space="preserve"> <trans-unit id="Recipients see updates as you type them." xml:space="preserve">
<source>Recipients see updates as you type them.</source> <source>Recipients see updates as you type them.</source>
<target>Příjemci uvidí aktualizace během jejich psaní.</target> <target>Příjemci uvidí aktualizace během jejich psaní.</target>
@@ -4192,10 +4484,22 @@ Error: %@</source>
<source>Repeat connection request?</source> <source>Repeat connection request?</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Repeat download" xml:space="preserve">
<source>Repeat download</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Repeat import" xml:space="preserve">
<source>Repeat import</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Repeat join request?" xml:space="preserve"> <trans-unit id="Repeat join request?" xml:space="preserve">
<source>Repeat join request?</source> <source>Repeat join request?</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Repeat upload" xml:space="preserve">
<source>Repeat upload</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Reply" xml:space="preserve"> <trans-unit id="Reply" xml:space="preserve">
<source>Reply</source> <source>Reply</source>
<target>Odpověď</target> <target>Odpověď</target>
@@ -4295,6 +4599,10 @@ Error: %@</source>
<target>SMP servery</target> <target>SMP servery</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Safer groups" xml:space="preserve">
<source>Safer groups</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Save" xml:space="preserve"> <trans-unit id="Save" xml:space="preserve">
<source>Save</source> <source>Save</source>
<target>Uložit</target> <target>Uložit</target>
@@ -4375,11 +4683,19 @@ Error: %@</source>
<target>Uložit uvítací zprávu?</target> <target>Uložit uvítací zprávu?</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved" xml:space="preserve">
<source>Saved</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve"> <trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve">
<source>Saved WebRTC ICE servers will be removed</source> <source>Saved WebRTC ICE servers will be removed</source>
<target>Uložené servery WebRTC ICE budou odstraněny</target> <target>Uložené servery WebRTC ICE budou odstraněny</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved from" xml:space="preserve">
<source>Saved from</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved message" xml:space="preserve"> <trans-unit id="Saved message" xml:space="preserve">
<source>Saved message</source> <source>Saved message</source>
<note>message info title</note> <note>message info title</note>
@@ -4654,6 +4970,10 @@ Error: %@</source>
<target>Nastavit heslo</target> <target>Nastavit heslo</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Set passphrase" xml:space="preserve">
<source>Set passphrase</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set passphrase to export" xml:space="preserve"> <trans-unit id="Set passphrase to export" xml:space="preserve">
<source>Set passphrase to export</source> <source>Set passphrase to export</source>
<target>Nastavení přístupové fráze pro export</target> <target>Nastavení přístupové fráze pro export</target>
@@ -4674,6 +4994,10 @@ Error: %@</source>
<target>Nastavení</target> <target>Nastavení</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Shape profile images" xml:space="preserve">
<source>Shape profile images</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Share" xml:space="preserve"> <trans-unit id="Share" xml:space="preserve">
<source>Share</source> <source>Share</source>
<target>Sdílet</target> <target>Sdílet</target>
@@ -4708,6 +5032,10 @@ Error: %@</source>
<target>Sdílet s kontakty</target> <target>Sdílet s kontakty</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Show QR code" xml:space="preserve">
<source>Show QR code</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show calls in phone history" xml:space="preserve"> <trans-unit id="Show calls in phone history" xml:space="preserve">
<source>Show calls in phone history</source> <source>Show calls in phone history</source>
<target>Ukaž hovory v historii telefonu</target> <target>Ukaž hovory v historii telefonu</target>
@@ -4786,6 +5114,14 @@ Error: %@</source>
<trans-unit id="SimpleX links" xml:space="preserve"> <trans-unit id="SimpleX links" xml:space="preserve">
<source>SimpleX links</source> <source>SimpleX links</source>
<target>Odkazy na SimpleX</target> <target>Odkazy na SimpleX</target>
<note>chat feature</note>
</trans-unit>
<trans-unit id="SimpleX links are prohibited in this group." xml:space="preserve">
<source>SimpleX links are prohibited in this group.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="SimpleX links not allowed" xml:space="preserve">
<source>SimpleX links not allowed</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="SimpleX one-time invitation" xml:space="preserve"> <trans-unit id="SimpleX one-time invitation" xml:space="preserve">
@@ -4823,6 +5159,10 @@ Error: %@</source>
<target>Někdo</target> <target>Někdo</target>
<note>notification title</note> <note>notification title</note>
</trans-unit> </trans-unit>
<trans-unit id="Square, circle, or anything in between." xml:space="preserve">
<source>Square, circle, or anything in between.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Start chat" xml:space="preserve"> <trans-unit id="Start chat" xml:space="preserve">
<source>Start chat</source> <source>Start chat</source>
<target>Začít chat</target> <target>Začít chat</target>
@@ -4847,6 +5187,10 @@ Error: %@</source>
<target>Zastavit SimpleX</target> <target>Zastavit SimpleX</target>
<note>authentication reason</note> <note>authentication reason</note>
</trans-unit> </trans-unit>
<trans-unit id="Stop chat" xml:space="preserve">
<source>Stop chat</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Stop chat to enable database actions" xml:space="preserve"> <trans-unit id="Stop chat to enable database actions" xml:space="preserve">
<source>Stop chat to enable database actions</source> <source>Stop chat to enable database actions</source>
<target>Zastavte chat pro povolení akcí databáze</target> <target>Zastavte chat pro povolení akcí databáze</target>
@@ -4887,6 +5231,10 @@ Error: %@</source>
<target>Přestat sdílet adresu?</target> <target>Přestat sdílet adresu?</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Stopping chat" xml:space="preserve">
<source>Stopping chat</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Submit" xml:space="preserve"> <trans-unit id="Submit" xml:space="preserve">
<source>Submit</source> <source>Submit</source>
<target>Odeslat</target> <target>Odeslat</target>
@@ -5129,6 +5477,14 @@ Může se to stát kvůli nějaké chybě, nebo pokud je spojení kompromitován
<target>Tuto akci nelze vzít zpět - váš profil, kontakty, zprávy a soubory budou nenávratně ztraceny.</target> <target>Tuto akci nelze vzít zpět - váš profil, kontakty, zprávy a soubory budou nenávratně ztraceny.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="This chat is protected by end-to-end encryption." xml:space="preserve">
<source>This chat is protected by end-to-end encryption.</source>
<note>E2EE info chat item</note>
</trans-unit>
<trans-unit id="This chat is protected by quantum resistant end-to-end encryption." xml:space="preserve">
<source>This chat is protected by quantum resistant end-to-end encryption.</source>
<note>E2EE info chat item</note>
</trans-unit>
<trans-unit id="This device name" xml:space="preserve"> <trans-unit id="This device name" xml:space="preserve">
<source>This device name</source> <source>This device name</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
@@ -5409,11 +5765,19 @@ Chcete-li se připojit, požádejte svůj kontakt o vytvoření dalšího odkazu
<target>Zvýšit a otevřít chat</target> <target>Zvýšit a otevřít chat</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Upload failed" xml:space="preserve">
<source>Upload failed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Upload file" xml:space="preserve"> <trans-unit id="Upload file" xml:space="preserve">
<source>Upload file</source> <source>Upload file</source>
<target>Nahrát soubor</target> <target>Nahrát soubor</target>
<note>server test step</note> <note>server test step</note>
</trans-unit> </trans-unit>
<trans-unit id="Uploading archive" xml:space="preserve">
<source>Uploading archive</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use .onion hosts" xml:space="preserve"> <trans-unit id="Use .onion hosts" xml:space="preserve">
<source>Use .onion hosts</source> <source>Use .onion hosts</source>
<target>Použít hostitele .onion</target> <target>Použít hostitele .onion</target>
@@ -5462,6 +5826,10 @@ Chcete-li se připojit, požádejte svůj kontakt o vytvoření dalšího odkazu
<target>Použít server</target> <target>Použít server</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Use the app while in the call." xml:space="preserve">
<source>Use the app while in the call.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User profile" xml:space="preserve"> <trans-unit id="User profile" xml:space="preserve">
<source>User profile</source> <source>User profile</source>
<target>Profil uživatele</target> <target>Profil uživatele</target>
@@ -5494,6 +5862,14 @@ Chcete-li se připojit, požádejte svůj kontakt o vytvoření dalšího odkazu
<source>Verify connections</source> <source>Verify connections</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Verify database passphrase" xml:space="preserve">
<source>Verify database passphrase</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify passphrase" xml:space="preserve">
<source>Verify passphrase</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify security code" xml:space="preserve"> <trans-unit id="Verify security code" xml:space="preserve">
<source>Verify security code</source> <source>Verify security code</source>
<target>Ověření bezpečnostního kódu</target> <target>Ověření bezpečnostního kódu</target>
@@ -5552,6 +5928,10 @@ Chcete-li se připojit, požádejte svůj kontakt o vytvoření dalšího odkazu
<target>Hlasové zprávy jsou v této skupině zakázány.</target> <target>Hlasové zprávy jsou v této skupině zakázány.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Voice messages not allowed" xml:space="preserve">
<source>Voice messages not allowed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Voice messages prohibited!" xml:space="preserve"> <trans-unit id="Voice messages prohibited!" xml:space="preserve">
<source>Voice messages prohibited!</source> <source>Voice messages prohibited!</source>
<target>Hlasové zprávy jsou zakázány!</target> <target>Hlasové zprávy jsou zakázány!</target>
@@ -5581,6 +5961,10 @@ Chcete-li se připojit, požádejte svůj kontakt o vytvoření dalšího odkazu
<target>Čekám na video</target> <target>Čekám na video</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Warning: starting chat on multiple devices is not supported and will cause message delivery failures" xml:space="preserve">
<source>Warning: starting chat on multiple devices is not supported and will cause message delivery failures</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Warning: you may lose some data!" xml:space="preserve"> <trans-unit id="Warning: you may lose some data!" xml:space="preserve">
<source>Warning: you may lose some data!</source> <source>Warning: you may lose some data!</source>
<target>Upozornění: můžete ztratit nějaká data!</target> <target>Upozornění: můžete ztratit nějaká data!</target>
@@ -5601,6 +5985,10 @@ Chcete-li se připojit, požádejte svůj kontakt o vytvoření dalšího odkazu
<target>Uvítací zpráva</target> <target>Uvítací zpráva</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Welcome message is too long" xml:space="preserve">
<source>Welcome message is too long</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="What's new" xml:space="preserve"> <trans-unit id="What's new" xml:space="preserve">
<source>What's new</source> <source>What's new</source>
<target>Co je nového</target> <target>Co je nového</target>
@@ -5611,6 +5999,10 @@ Chcete-li se připojit, požádejte svůj kontakt o vytvoření dalšího odkazu
<target>Když je k dispozici</target> <target>Když je k dispozici</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="When connecting audio and video calls." xml:space="preserve">
<source>When connecting audio and video calls.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="When people request to connect, you can accept or reject it." xml:space="preserve"> <trans-unit id="When people request to connect, you can accept or reject it." xml:space="preserve">
<source>When people request to connect, you can accept or reject it.</source> <source>When people request to connect, you can accept or reject it.</source>
<target>Když někdo požádá o připojení, můžete žádost přijmout nebo odmítnout.</target> <target>Když někdo požádá o připojení, můžete žádost přijmout nebo odmítnout.</target>
@@ -5621,6 +6013,18 @@ Chcete-li se připojit, požádejte svůj kontakt o vytvoření dalšího odkazu
<target>Pokud s někým sdílíte inkognito profil, bude tento profil použit pro skupiny, do kterých vás pozve.</target> <target>Pokud s někým sdílíte inkognito profil, bude tento profil použit pro skupiny, do kterých vás pozve.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="WiFi" xml:space="preserve">
<source>WiFi</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Will be enabled in direct chats!" xml:space="preserve">
<source>Will be enabled in direct chats!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Wired ethernet" xml:space="preserve">
<source>Wired ethernet</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="With encrypted files and media." xml:space="preserve"> <trans-unit id="With encrypted files and media." xml:space="preserve">
<source>With encrypted files and media.</source> <source>With encrypted files and media.</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
@@ -5654,6 +6058,10 @@ Chcete-li se připojit, požádejte svůj kontakt o vytvoření dalšího odkazu
<target>Vy</target> <target>Vy</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="You **must not** use the same database on two devices." xml:space="preserve">
<source>You **must not** use the same database on two devices.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You accepted connection" xml:space="preserve"> <trans-unit id="You accepted connection" xml:space="preserve">
<source>You accepted connection</source> <source>You accepted connection</source>
<target>Přijali jste spojení</target> <target>Přijali jste spojení</target>
@@ -5733,6 +6141,10 @@ Repeat join request?</source>
<target>Můžete je povolit později v nastavení Soukromí &amp; Bezpečnosti aplikace</target> <target>Můžete je povolit později v nastavení Soukromí &amp; Bezpečnosti aplikace</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="You can give another try." xml:space="preserve">
<source>You can give another try.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You can hide or mute a user profile - swipe it to the right." xml:space="preserve"> <trans-unit id="You can hide or mute a user profile - swipe it to the right." xml:space="preserve">
<source>You can hide or mute a user profile - swipe it to the right.</source> <source>You can hide or mute a user profile - swipe it to the right.</source>
<target>Profil uživatele můžete skrýt nebo ztlumit - přejeďte prstem doprava.</target> <target>Profil uživatele můžete skrýt nebo ztlumit - přejeďte prstem doprava.</target>
@@ -6076,6 +6488,10 @@ Servery SimpleX nevidí váš profil.</target>
<target>správce</target> <target>správce</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="admins" xml:space="preserve">
<source>admins</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="agreeing encryption for %@…" xml:space="preserve"> <trans-unit id="agreeing encryption for %@…" xml:space="preserve">
<source>agreeing encryption for %@…</source> <source>agreeing encryption for %@…</source>
<target>povoluji šifrování pro %@…</target> <target>povoluji šifrování pro %@…</target>
@@ -6086,6 +6502,10 @@ Servery SimpleX nevidí váš profil.</target>
<target>povoluji šifrování…</target> <target>povoluji šifrování…</target>
<note>chat item text</note> <note>chat item text</note>
</trans-unit> </trans-unit>
<trans-unit id="all members" xml:space="preserve">
<source>all members</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="always" xml:space="preserve"> <trans-unit id="always" xml:space="preserve">
<source>always</source> <source>always</source>
<target>vždy</target> <target>vždy</target>
@@ -6116,7 +6536,7 @@ Servery SimpleX nevidí váš profil.</target>
</trans-unit> </trans-unit>
<trans-unit id="blocked" xml:space="preserve"> <trans-unit id="blocked" xml:space="preserve">
<source>blocked</source> <source>blocked</source>
<note>No comment provided by engineer.</note> <note>marked deleted chat item preview text</note>
</trans-unit> </trans-unit>
<trans-unit id="blocked %@" xml:space="preserve"> <trans-unit id="blocked %@" xml:space="preserve">
<source>blocked %@</source> <source>blocked %@</source>
@@ -6124,7 +6544,7 @@ Servery SimpleX nevidí váš profil.</target>
</trans-unit> </trans-unit>
<trans-unit id="blocked by admin" xml:space="preserve"> <trans-unit id="blocked by admin" xml:space="preserve">
<source>blocked by admin</source> <source>blocked by admin</source>
<note>blocked chat item</note> <note>marked deleted chat item preview text</note>
</trans-unit> </trans-unit>
<trans-unit id="bold" xml:space="preserve"> <trans-unit id="bold" xml:space="preserve">
<source>bold</source> <source>bold</source>
@@ -6408,6 +6828,10 @@ Servery SimpleX nevidí váš profil.</target>
<source>event happened</source> <source>event happened</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="forwarded" xml:space="preserve">
<source>forwarded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="group deleted" xml:space="preserve"> <trans-unit id="group deleted" xml:space="preserve">
<source>group deleted</source> <source>group deleted</source>
<target>skupina smazána</target> <target>skupina smazána</target>
@@ -6550,7 +6974,7 @@ Servery SimpleX nevidí váš profil.</target>
<trans-unit id="moderated by %@" xml:space="preserve"> <trans-unit id="moderated by %@" xml:space="preserve">
<source>moderated by %@</source> <source>moderated by %@</source>
<target>moderovaný %@</target> <target>moderovaný %@</target>
<note>No comment provided by engineer.</note> <note>marked deleted chat item preview text</note>
</trans-unit> </trans-unit>
<trans-unit id="months" xml:space="preserve"> <trans-unit id="months" xml:space="preserve">
<source>months</source> <source>months</source>
@@ -6614,11 +7038,19 @@ Servery SimpleX nevidí váš profil.</target>
<target>vlastník</target> <target>vlastník</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="owners" xml:space="preserve">
<source>owners</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="peer-to-peer" xml:space="preserve"> <trans-unit id="peer-to-peer" xml:space="preserve">
<source>peer-to-peer</source> <source>peer-to-peer</source>
<target>peer-to-peer</target> <target>peer-to-peer</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="quantum resistant e2e encryption" xml:space="preserve">
<source>quantum resistant e2e encryption</source>
<note>chat item text</note>
</trans-unit>
<trans-unit id="received answer…" xml:space="preserve"> <trans-unit id="received answer…" xml:space="preserve">
<source>received answer…</source> <source>received answer…</source>
<target>obdržel odpověď…</target> <target>obdržel odpověď…</target>
@@ -6657,6 +7089,14 @@ Servery SimpleX nevidí váš profil.</target>
<target>odstranil vás</target> <target>odstranil vás</target>
<note>rcv group event chat item</note> <note>rcv group event chat item</note>
</trans-unit> </trans-unit>
<trans-unit id="saved" xml:space="preserve">
<source>saved</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="saved from %@" xml:space="preserve">
<source>saved from %@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="sec" xml:space="preserve"> <trans-unit id="sec" xml:space="preserve">
<source>sec</source> <source>sec</source>
<target>sek</target> <target>sek</target>
@@ -6690,6 +7130,10 @@ Servery SimpleX nevidí váš profil.</target>
<source>set new profile picture</source> <source>set new profile picture</source>
<note>profile update event chat item</note> <note>profile update event chat item</note>
</trans-unit> </trans-unit>
<trans-unit id="standard end-to-end encryption" xml:space="preserve">
<source>standard end-to-end encryption</source>
<note>chat item text</note>
</trans-unit>
<trans-unit id="starting…" xml:space="preserve"> <trans-unit id="starting…" xml:space="preserve">
<source>starting…</source> <source>starting…</source>
<target>začíná…</target> <target>začíná…</target>
@@ -6786,6 +7230,10 @@ Servery SimpleX nevidí váš profil.</target>
<target>ano</target> <target>ano</target>
<note>pref value</note> <note>pref value</note>
</trans-unit> </trans-unit>
<trans-unit id="you" xml:space="preserve">
<source>you</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="you are invited to group" xml:space="preserve"> <trans-unit id="you are invited to group" xml:space="preserve">
<source>you are invited to group</source> <source>you are invited to group</source>
<target>jste pozváni do skupiny</target> <target>jste pozváni do skupiny</target>
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -105,6 +105,10 @@
<source>%@ connected</source> <source>%@ connected</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="%@ downloaded" xml:space="preserve">
<source>%@ downloaded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ is connected!" xml:space="preserve"> <trans-unit id="%@ is connected!" xml:space="preserve">
<source>%@ is connected!</source> <source>%@ is connected!</source>
<target>%@ on yhdistetty!</target> <target>%@ on yhdistetty!</target>
@@ -125,6 +129,10 @@
<target>%@ palvelimet</target> <target>%@ palvelimet</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="%@ uploaded" xml:space="preserve">
<source>%@ uploaded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ wants to connect!" xml:space="preserve"> <trans-unit id="%@ wants to connect!" xml:space="preserve">
<source>%@ wants to connect!</source> <source>%@ wants to connect!</source>
<target>%@ haluaa muodostaa yhteyden!</target> <target>%@ haluaa muodostaa yhteyden!</target>
@@ -330,6 +338,10 @@
<target>**Yksityisin**: älä käytä SimpleX Chat -ilmoituspalvelinta, tarkista viestit ajoittain taustalla (riippuu siitä, kuinka usein käytät sovellusta).</target> <target>**Yksityisin**: älä käytä SimpleX Chat -ilmoituspalvelinta, tarkista viestit ajoittain taustalla (riippuu siitä, kuinka usein käytät sovellusta).</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="**Please note**: using the same database on two devices will break the decryption of messages from your connections, as a security protection." xml:space="preserve">
<source>**Please note**: using the same database on two devices will break the decryption of messages from your connections, as a security protection.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="**Please note**: you will NOT be able to recover or change passphrase if you lose it." xml:space="preserve"> <trans-unit id="**Please note**: you will NOT be able to recover or change passphrase if you lose it." xml:space="preserve">
<source>**Please note**: you will NOT be able to recover or change passphrase if you lose it.</source> <source>**Please note**: you will NOT be able to recover or change passphrase if you lose it.</source>
<target>**Huomaa**: et voi palauttaa tai muuttaa tunnuslausetta, jos kadotat sen.</target> <target>**Huomaa**: et voi palauttaa tai muuttaa tunnuslausetta, jos kadotat sen.</target>
@@ -345,6 +357,10 @@
<target>**Varoitus**: Välittömät push-ilmoitukset vaativat tunnuslauseen, joka on tallennettu Keychainiin.</target> <target>**Varoitus**: Välittömät push-ilmoitukset vaativat tunnuslauseen, joka on tallennettu Keychainiin.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="**Warning**: the archive will be removed." xml:space="preserve">
<source>**Warning**: the archive will be removed.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="**e2e encrypted** audio call" xml:space="preserve"> <trans-unit id="**e2e encrypted** audio call" xml:space="preserve">
<source>**e2e encrypted** audio call</source> <source>**e2e encrypted** audio call</source>
<target>**e2e-salattu** äänipuhelu</target> <target>**e2e-salattu** äänipuhelu</target>
@@ -593,6 +609,10 @@
<target>Osoitteenmuutos keskeytetään. Käytetään vanhaa vastaanotto-osoitetta.</target> <target>Osoitteenmuutos keskeytetään. Käytetään vanhaa vastaanotto-osoitetta.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Admins can block a member for all." xml:space="preserve">
<source>Admins can block a member for all.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Admins can create the links to join groups." xml:space="preserve"> <trans-unit id="Admins can create the links to join groups." xml:space="preserve">
<source>Admins can create the links to join groups.</source> <source>Admins can create the links to join groups.</source>
<target>Ylläpitäjät voivat luoda linkkejä ryhmiin liittymiseen.</target> <target>Ylläpitäjät voivat luoda linkkejä ryhmiin liittymiseen.</target>
@@ -646,6 +666,10 @@
<target>Kaikki kontaktisi pysyvät yhteydessä. Profiilipäivitys lähetetään kontakteillesi.</target> <target>Kaikki kontaktisi pysyvät yhteydessä. Profiilipäivitys lähetetään kontakteillesi.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="All your contacts, conversations and files will be securely encrypted and uploaded in chunks to configured XFTP relays." xml:space="preserve">
<source>All your contacts, conversations and files will be securely encrypted and uploaded in chunks to configured XFTP relays.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow" xml:space="preserve"> <trans-unit id="Allow" xml:space="preserve">
<source>Allow</source> <source>Allow</source>
<target>Salli</target> <target>Salli</target>
@@ -691,6 +715,10 @@
<target>Salli lähetettyjen viestien peruuttamaton poistaminen. (24 tuntia)</target> <target>Salli lähetettyjen viestien peruuttamaton poistaminen. (24 tuntia)</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
<source>Allow to send SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send files and media." xml:space="preserve"> <trans-unit id="Allow to send files and media." xml:space="preserve">
<source>Allow to send files and media.</source> <source>Allow to send files and media.</source>
<target>Salli tiedostojen ja median lähettäminen.</target> <target>Salli tiedostojen ja median lähettäminen.</target>
@@ -769,6 +797,10 @@
<target>Sovellusversio: %@</target> <target>Sovellusversio: %@</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="App data migration" xml:space="preserve">
<source>App data migration</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="App encrypts new local files (except videos)." xml:space="preserve"> <trans-unit id="App encrypts new local files (except videos)." xml:space="preserve">
<source>App encrypts new local files (except videos).</source> <source>App encrypts new local files (except videos).</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
@@ -803,6 +835,18 @@
<target>Ulkonäkö</target> <target>Ulkonäkö</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Apply" xml:space="preserve">
<source>Apply</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive and upload" xml:space="preserve">
<source>Archive and upload</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archiving database" xml:space="preserve">
<source>Archiving database</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Attach" xml:space="preserve"> <trans-unit id="Attach" xml:space="preserve">
<source>Attach</source> <source>Attach</source>
<target>Liitä</target> <target>Liitä</target>
@@ -982,6 +1026,10 @@
<target>Peruuta</target> <target>Peruuta</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Cancel migration" xml:space="preserve">
<source>Cancel migration</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Cannot access keychain to save database password" xml:space="preserve"> <trans-unit id="Cannot access keychain to save database password" xml:space="preserve">
<source>Cannot access keychain to save database password</source> <source>Cannot access keychain to save database password</source>
<target>Ei pääsyä avainnippuun tietokannan salasanan tallentamiseksi</target> <target>Ei pääsyä avainnippuun tietokannan salasanan tallentamiseksi</target>
@@ -992,6 +1040,10 @@
<target>Tiedostoa ei voi vastaanottaa</target> <target>Tiedostoa ei voi vastaanottaa</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Cellular" xml:space="preserve">
<source>Cellular</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Change" xml:space="preserve"> <trans-unit id="Change" xml:space="preserve">
<source>Change</source> <source>Change</source>
<target>Muuta</target> <target>Muuta</target>
@@ -1082,6 +1134,10 @@
<source>Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat.</source> <source>Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat.</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Chat migrated!" xml:space="preserve">
<source>Chat migrated!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Chat preferences" xml:space="preserve"> <trans-unit id="Chat preferences" xml:space="preserve">
<source>Chat preferences</source> <source>Chat preferences</source>
<target>Chat-asetukset</target> <target>Chat-asetukset</target>
@@ -1102,6 +1158,10 @@
<target>Kiinalainen ja espanjalainen käyttöliittymä</target> <target>Kiinalainen ja espanjalainen käyttöliittymä</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Choose _Migrate from another device_ on the new device and scan QR code." xml:space="preserve">
<source>Choose _Migrate from another device_ on the new device and scan QR code.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Choose file" xml:space="preserve"> <trans-unit id="Choose file" xml:space="preserve">
<source>Choose file</source> <source>Choose file</source>
<target>Valitse tiedosto</target> <target>Valitse tiedosto</target>
@@ -1171,6 +1231,10 @@
<target>Vahvista tietokannan päivitykset</target> <target>Vahvista tietokannan päivitykset</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Confirm network settings" xml:space="preserve">
<source>Confirm network settings</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirm new passphrase…" xml:space="preserve"> <trans-unit id="Confirm new passphrase…" xml:space="preserve">
<source>Confirm new passphrase…</source> <source>Confirm new passphrase…</source>
<target>Vahvista uusi tunnuslause…</target> <target>Vahvista uusi tunnuslause…</target>
@@ -1181,6 +1245,14 @@
<target>Vahvista salasana</target> <target>Vahvista salasana</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Confirm that you remember database passphrase to migrate it." xml:space="preserve">
<source>Confirm that you remember database passphrase to migrate it.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirm upload" xml:space="preserve">
<source>Confirm upload</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect" xml:space="preserve"> <trans-unit id="Connect" xml:space="preserve">
<source>Connect</source> <source>Connect</source>
<target>Yhdistä</target> <target>Yhdistä</target>
@@ -1421,6 +1493,10 @@ This is your own one-time link!</source>
<target>Luotu %@</target> <target>Luotu %@</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Creating archive link" xml:space="preserve">
<source>Creating archive link</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Creating link…" xml:space="preserve"> <trans-unit id="Creating link…" xml:space="preserve">
<source>Creating link…</source> <source>Creating link…</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
@@ -1636,6 +1712,10 @@ This cannot be undone!</source>
<target>Poista tietokanta</target> <target>Poista tietokanta</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Delete database from this device" xml:space="preserve">
<source>Delete database from this device</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete file" xml:space="preserve"> <trans-unit id="Delete file" xml:space="preserve">
<source>Delete file</source> <source>Delete file</source>
<target>Poista tiedosto</target> <target>Poista tiedosto</target>
@@ -1920,11 +2000,27 @@ This cannot be undone!</source>
<target>Alenna ja avaa keskustelu</target> <target>Alenna ja avaa keskustelu</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Download" xml:space="preserve">
<source>Download</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Download failed" xml:space="preserve">
<source>Download failed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Download file" xml:space="preserve"> <trans-unit id="Download file" xml:space="preserve">
<source>Download file</source> <source>Download file</source>
<target>Lataa tiedosto</target> <target>Lataa tiedosto</target>
<note>server test step</note> <note>server test step</note>
</trans-unit> </trans-unit>
<trans-unit id="Downloading archive" xml:space="preserve">
<source>Downloading archive</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Downloading link details" xml:space="preserve">
<source>Downloading link details</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Duplicate display name!" xml:space="preserve"> <trans-unit id="Duplicate display name!" xml:space="preserve">
<source>Duplicate display name!</source> <source>Duplicate display name!</source>
<target>Päällekkäinen näyttönimi!</target> <target>Päällekkäinen näyttönimi!</target>
@@ -1979,6 +2075,10 @@ This cannot be undone!</source>
<target>Salli kaikille</target> <target>Salli kaikille</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Enable in direct chats (BETA)!" xml:space="preserve">
<source>Enable in direct chats (BETA)!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enable instant notifications?" xml:space="preserve"> <trans-unit id="Enable instant notifications?" xml:space="preserve">
<source>Enable instant notifications?</source> <source>Enable instant notifications?</source>
<target>Salli välittömät ilmoitukset?</target> <target>Salli välittömät ilmoitukset?</target>
@@ -2009,6 +2109,10 @@ This cannot be undone!</source>
<target>Ota itsetuhoava pääsykoodi käyttöön</target> <target>Ota itsetuhoava pääsykoodi käyttöön</target>
<note>set passcode view</note> <note>set passcode view</note>
</trans-unit> </trans-unit>
<trans-unit id="Enabled for" xml:space="preserve">
<source>Enabled for</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Encrypt" xml:space="preserve"> <trans-unit id="Encrypt" xml:space="preserve">
<source>Encrypt</source> <source>Encrypt</source>
<target>Salaa</target> <target>Salaa</target>
@@ -2089,6 +2193,10 @@ This cannot be undone!</source>
<source>Enter group name…</source> <source>Enter group name…</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Enter passphrase" xml:space="preserve">
<source>Enter passphrase</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter passphrase…" xml:space="preserve"> <trans-unit id="Enter passphrase…" xml:space="preserve">
<source>Enter passphrase…</source> <source>Enter passphrase…</source>
<target>Syötä tunnuslause…</target> <target>Syötä tunnuslause…</target>
@@ -2235,6 +2343,10 @@ This cannot be undone!</source>
<target>Virhe käyttäjäprofiilin poistamisessa</target> <target>Virhe käyttäjäprofiilin poistamisessa</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Error downloading the archive" xml:space="preserve">
<source>Error downloading the archive</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error enabling delivery receipts!" xml:space="preserve"> <trans-unit id="Error enabling delivery receipts!" xml:space="preserve">
<source>Error enabling delivery receipts!</source> <source>Error enabling delivery receipts!</source>
<target>Virhe toimituskuittauksien sallimisessa!</target> <target>Virhe toimituskuittauksien sallimisessa!</target>
@@ -2309,6 +2421,10 @@ This cannot be undone!</source>
<target>Virhe tunnuslauseen tallentamisessa avainnippuun</target> <target>Virhe tunnuslauseen tallentamisessa avainnippuun</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Error saving settings" xml:space="preserve">
<source>Error saving settings</source>
<note>when migrating</note>
</trans-unit>
<trans-unit id="Error saving user password" xml:space="preserve"> <trans-unit id="Error saving user password" xml:space="preserve">
<source>Error saving user password</source> <source>Error saving user password</source>
<target>Virhe käyttäjän salasanan tallentamisessa</target> <target>Virhe käyttäjän salasanan tallentamisessa</target>
@@ -2377,6 +2493,14 @@ This cannot be undone!</source>
<target>Virhe päivitettäessä käyttäjän tietosuojaa</target> <target>Virhe päivitettäessä käyttäjän tietosuojaa</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Error uploading the archive" xml:space="preserve">
<source>Error uploading the archive</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error verifying passphrase:" xml:space="preserve">
<source>Error verifying passphrase:</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error: " xml:space="preserve"> <trans-unit id="Error: " xml:space="preserve">
<source>Error: </source> <source>Error: </source>
<target>Virhe: </target> <target>Virhe: </target>
@@ -2426,6 +2550,10 @@ This cannot be undone!</source>
<target>Viety tietokanta-arkisto.</target> <target>Viety tietokanta-arkisto.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Exported file doesn't exist" xml:space="preserve">
<source>Exported file doesn't exist</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Exporting database archive…" xml:space="preserve"> <trans-unit id="Exporting database archive…" xml:space="preserve">
<source>Exporting database archive…</source> <source>Exporting database archive…</source>
<target>Tietokanta-arkiston vienti…</target> <target>Tietokanta-arkiston vienti…</target>
@@ -2485,6 +2613,10 @@ This cannot be undone!</source>
<target>Tiedostot ja media ovat tässä ryhmässä kiellettyjä.</target> <target>Tiedostot ja media ovat tässä ryhmässä kiellettyjä.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Files and media not allowed" xml:space="preserve">
<source>Files and media not allowed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media prohibited!" xml:space="preserve"> <trans-unit id="Files and media prohibited!" xml:space="preserve">
<source>Files and media prohibited!</source> <source>Files and media prohibited!</source>
<target>Tiedostot ja media kielletty!</target> <target>Tiedostot ja media kielletty!</target>
@@ -2495,6 +2627,14 @@ This cannot be undone!</source>
<target>Suodata lukemattomia- ja suosikkikeskusteluja.</target> <target>Suodata lukemattomia- ja suosikkikeskusteluja.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Finalize migration" xml:space="preserve">
<source>Finalize migration</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Finalize migration on another device." xml:space="preserve">
<source>Finalize migration on another device.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Finally, we have them! 🚀" xml:space="preserve"> <trans-unit id="Finally, we have them! 🚀" xml:space="preserve">
<source>Finally, we have them! 🚀</source> <source>Finally, we have them! 🚀</source>
<target>Vihdoinkin meillä! 🚀</target> <target>Vihdoinkin meillä! 🚀</target>
@@ -2540,6 +2680,22 @@ This cannot be undone!</source>
<target>Konsoliin</target> <target>Konsoliin</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Forward" xml:space="preserve">
<source>Forward</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Forward and save messages" xml:space="preserve">
<source>Forward and save messages</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded" xml:space="preserve">
<source>Forwarded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded from" xml:space="preserve">
<source>Forwarded from</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Found desktop" xml:space="preserve"> <trans-unit id="Found desktop" xml:space="preserve">
<source>Found desktop</source> <source>Found desktop</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
@@ -2646,6 +2802,10 @@ This cannot be undone!</source>
<target>Ryhmän jäsenet voivat poistaa lähetetyt viestit peruuttamattomasti. (24 tuntia)</target> <target>Ryhmän jäsenet voivat poistaa lähetetyt viestit peruuttamattomasti. (24 tuntia)</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Group members can send SimpleX links." xml:space="preserve">
<source>Group members can send SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send direct messages." xml:space="preserve"> <trans-unit id="Group members can send direct messages." xml:space="preserve">
<source>Group members can send direct messages.</source> <source>Group members can send direct messages.</source>
<target>Ryhmän jäsenet voivat lähettää suoraviestejä.</target> <target>Ryhmän jäsenet voivat lähettää suoraviestejä.</target>
@@ -2780,6 +2940,10 @@ This cannot be undone!</source>
<target>Miten käytät palvelimiasi</target> <target>Miten käytät palvelimiasi</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Hungarian interface" xml:space="preserve">
<source>Hungarian interface</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="ICE servers (one per line)" xml:space="preserve"> <trans-unit id="ICE servers (one per line)" xml:space="preserve">
<source>ICE servers (one per line)</source> <source>ICE servers (one per line)</source>
<target>ICE-palvelimet (yksi per rivi)</target> <target>ICE-palvelimet (yksi per rivi)</target>
@@ -2845,6 +3009,14 @@ This cannot be undone!</source>
<target>Tuo tietokanta</target> <target>Tuo tietokanta</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Import failed" xml:space="preserve">
<source>Import failed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Importing archive" xml:space="preserve">
<source>Importing archive</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Improved message delivery" xml:space="preserve"> <trans-unit id="Improved message delivery" xml:space="preserve">
<source>Improved message delivery</source> <source>Improved message delivery</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
@@ -2859,11 +3031,19 @@ This cannot be undone!</source>
<target>Parannettu palvelimen kokoonpano</target> <target>Parannettu palvelimen kokoonpano</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="In order to continue, chat should be stopped." xml:space="preserve">
<source>In order to continue, chat should be stopped.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="In reply to" xml:space="preserve"> <trans-unit id="In reply to" xml:space="preserve">
<source>In reply to</source> <source>In reply to</source>
<target>Vastauksena</target> <target>Vastauksena</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="In-call sounds" xml:space="preserve">
<source>In-call sounds</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Incognito" xml:space="preserve"> <trans-unit id="Incognito" xml:space="preserve">
<source>Incognito</source> <source>Incognito</source>
<target>Incognito</target> <target>Incognito</target>
@@ -2966,6 +3146,10 @@ This cannot be undone!</source>
<source>Invalid link</source> <source>Invalid link</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Invalid migration confirmation" xml:space="preserve">
<source>Invalid migration confirmation</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Invalid name!" xml:space="preserve"> <trans-unit id="Invalid name!" xml:space="preserve">
<source>Invalid name!</source> <source>Invalid name!</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
@@ -3316,11 +3500,19 @@ This is your link for group %@!</source>
<target>Viestireaktiot ovat kiellettyjä tässä ryhmässä.</target> <target>Viestireaktiot ovat kiellettyjä tässä ryhmässä.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Message source remains private." xml:space="preserve">
<source>Message source remains private.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message text" xml:space="preserve"> <trans-unit id="Message text" xml:space="preserve">
<source>Message text</source> <source>Message text</source>
<target>Viestin teksti</target> <target>Viestin teksti</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Message too large" xml:space="preserve">
<source>Message too large</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Messages" xml:space="preserve"> <trans-unit id="Messages" xml:space="preserve">
<source>Messages</source> <source>Messages</source>
<target>Viestit</target> <target>Viestit</target>
@@ -3335,11 +3527,47 @@ This is your link for group %@!</source>
<source>Messages from %@ will be shown!</source> <source>Messages from %@ will be shown!</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Messages, files and calls are protected by **end-to-end encryption** with perfect forward secrecy, repudiation and break-in recovery." xml:space="preserve">
<source>Messages, files and calls are protected by **end-to-end encryption** with perfect forward secrecy, repudiation and break-in recovery.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Messages, files and calls are protected by **quantum resistant e2e encryption** with perfect forward secrecy, repudiation and break-in recovery." xml:space="preserve">
<source>Messages, files and calls are protected by **quantum resistant e2e encryption** with perfect forward secrecy, repudiation and break-in recovery.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Migrate device" xml:space="preserve">
<source>Migrate device</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Migrate from another device" xml:space="preserve">
<source>Migrate from another device</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Migrate here" xml:space="preserve">
<source>Migrate here</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Migrate to another device" xml:space="preserve">
<source>Migrate to another device</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Migrate to another device via QR code." xml:space="preserve">
<source>Migrate to another device via QR code.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Migrating" xml:space="preserve">
<source>Migrating</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Migrating database archive…" xml:space="preserve"> <trans-unit id="Migrating database archive…" xml:space="preserve">
<source>Migrating database archive…</source> <source>Migrating database archive…</source>
<target>Siirretään tietokannan arkistoa…</target> <target>Siirretään tietokannan arkistoa…</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Migration complete" xml:space="preserve">
<source>Migration complete</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Migration error:" xml:space="preserve"> <trans-unit id="Migration error:" xml:space="preserve">
<source>Migration error:</source> <source>Migration error:</source>
<target>Siirtovirhe:</target> <target>Siirtovirhe:</target>
@@ -3380,6 +3608,10 @@ This is your link for group %@!</source>
<target>Lisää parannuksia on tulossa pian!</target> <target>Lisää parannuksia on tulossa pian!</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="More reliable network connection." xml:space="preserve">
<source>More reliable network connection.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Most likely this connection is deleted." xml:space="preserve"> <trans-unit id="Most likely this connection is deleted." xml:space="preserve">
<source>Most likely this connection is deleted.</source> <source>Most likely this connection is deleted.</source>
<target>Todennäköisesti tämä yhteys on poistettu.</target> <target>Todennäköisesti tämä yhteys on poistettu.</target>
@@ -3415,6 +3647,14 @@ This is your link for group %@!</source>
<target>Verkko ja palvelimet</target> <target>Verkko ja palvelimet</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Network connection" xml:space="preserve">
<source>Network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Network management" xml:space="preserve">
<source>Network management</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Network settings" xml:space="preserve"> <trans-unit id="Network settings" xml:space="preserve">
<source>Network settings</source> <source>Network settings</source>
<target>Verkkoasetukset</target> <target>Verkkoasetukset</target>
@@ -3523,6 +3763,10 @@ This is your link for group %@!</source>
<target>Ei historiaa</target> <target>Ei historiaa</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="No network connection" xml:space="preserve">
<source>No network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record voice message" xml:space="preserve"> <trans-unit id="No permission to record voice message" xml:space="preserve">
<source>No permission to record voice message</source> <source>No permission to record voice message</source>
<target>Ei lupaa ääniviestin tallentamiseen</target> <target>Ei lupaa ääniviestin tallentamiseen</target>
@@ -3693,6 +3937,10 @@ This is your link for group %@!</source>
<source>Open group</source> <source>Open group</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Open migration to another device" xml:space="preserve">
<source>Open migration to another device</source>
<note>authentication reason</note>
</trans-unit>
<trans-unit id="Open user profiles" xml:space="preserve"> <trans-unit id="Open user profiles" xml:space="preserve">
<source>Open user profiles</source> <source>Open user profiles</source>
<target>Avaa käyttäjäprofiilit</target> <target>Avaa käyttäjäprofiilit</target>
@@ -3707,14 +3955,26 @@ This is your link for group %@!</source>
<source>Opening app…</source> <source>Opening app…</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Or paste archive link" xml:space="preserve">
<source>Or paste archive link</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Or scan QR code" xml:space="preserve"> <trans-unit id="Or scan QR code" xml:space="preserve">
<source>Or scan QR code</source> <source>Or scan QR code</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Or securely share this file link" xml:space="preserve">
<source>Or securely share this file link</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Or show this code" xml:space="preserve"> <trans-unit id="Or show this code" xml:space="preserve">
<source>Or show this code</source> <source>Or show this code</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Other" xml:space="preserve">
<source>Other</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve"> <trans-unit id="PING count" xml:space="preserve">
<source>PING count</source> <source>PING count</source>
<target>PING-määrä</target> <target>PING-määrä</target>
@@ -3791,6 +4051,10 @@ This is your link for group %@!</source>
<target>Pysyvä salauksen purkuvirhe</target> <target>Pysyvä salauksen purkuvirhe</target>
<note>message decrypt error item</note> <note>message decrypt error item</note>
</trans-unit> </trans-unit>
<trans-unit id="Picture-in-picture calls" xml:space="preserve">
<source>Picture-in-picture calls</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Please ask your contact to enable sending voice messages." xml:space="preserve"> <trans-unit id="Please ask your contact to enable sending voice messages." xml:space="preserve">
<source>Please ask your contact to enable sending voice messages.</source> <source>Please ask your contact to enable sending voice messages.</source>
<target>Pyydä kontaktiasi sallimaan ääniviestien lähettäminen.</target> <target>Pyydä kontaktiasi sallimaan ääniviestien lähettäminen.</target>
@@ -3811,6 +4075,10 @@ This is your link for group %@!</source>
<target>Tarkista omasi ja kontaktin asetukset.</target> <target>Tarkista omasi ja kontaktin asetukset.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Please confirm that network settings are correct for this device." xml:space="preserve">
<source>Please confirm that network settings are correct for this device.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Please contact developers.&#10;Error: %@" xml:space="preserve"> <trans-unit id="Please contact developers.&#10;Error: %@" xml:space="preserve">
<source>Please contact developers. <source>Please contact developers.
Error: %@</source> Error: %@</source>
@@ -3915,6 +4183,10 @@ Error: %@</source>
<target>Profiilikuva</target> <target>Profiilikuva</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Profile images" xml:space="preserve">
<source>Profile images</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile name" xml:space="preserve"> <trans-unit id="Profile name" xml:space="preserve">
<source>Profile name</source> <source>Profile name</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
@@ -3953,6 +4225,10 @@ Error: %@</source>
<target>Estä viestireaktiot.</target> <target>Estä viestireaktiot.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
<source>Prohibit sending SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending direct messages to members." xml:space="preserve"> <trans-unit id="Prohibit sending direct messages to members." xml:space="preserve">
<source>Prohibit sending direct messages to members.</source> <source>Prohibit sending direct messages to members.</source>
<target>Estä suorien viestien lähettäminen jäsenille.</target> <target>Estä suorien viestien lähettäminen jäsenille.</target>
@@ -3998,6 +4274,14 @@ Error: %@</source>
<target>Push-ilmoitukset</target> <target>Push-ilmoitukset</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Push server" xml:space="preserve">
<source>Push server</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Quantum resistant encryption" xml:space="preserve">
<source>Quantum resistant encryption</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Rate the app" xml:space="preserve"> <trans-unit id="Rate the app" xml:space="preserve">
<source>Rate the app</source> <source>Rate the app</source>
<target>Arvioi sovellus</target> <target>Arvioi sovellus</target>
@@ -4072,6 +4356,10 @@ Error: %@</source>
<target>Vastaanotto-osoite vaihdetaan toiseen palvelimeen. Osoitteenmuutos tehdään sen jälkeen, kun lähettäjä tulee verkkoon.</target> <target>Vastaanotto-osoite vaihdetaan toiseen palvelimeen. Osoitteenmuutos tehdään sen jälkeen, kun lähettäjä tulee verkkoon.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Receiving concurrency" xml:space="preserve">
<source>Receiving concurrency</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Receiving file will be stopped." xml:space="preserve"> <trans-unit id="Receiving file will be stopped." xml:space="preserve">
<source>Receiving file will be stopped.</source> <source>Receiving file will be stopped.</source>
<target>Tiedoston vastaanotto pysäytetään.</target> <target>Tiedoston vastaanotto pysäytetään.</target>
@@ -4086,6 +4374,10 @@ Error: %@</source>
<source>Recent history and improved [directory bot](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</source> <source>Recent history and improved [directory bot](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Recipient(s) can't see who this message is from." xml:space="preserve">
<source>Recipient(s) can't see who this message is from.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Recipients see updates as you type them." xml:space="preserve"> <trans-unit id="Recipients see updates as you type them." xml:space="preserve">
<source>Recipients see updates as you type them.</source> <source>Recipients see updates as you type them.</source>
<target>Vastaanottajat näkevät päivitykset, kun kirjoitat niitä.</target> <target>Vastaanottajat näkevät päivitykset, kun kirjoitat niitä.</target>
@@ -4180,10 +4472,22 @@ Error: %@</source>
<source>Repeat connection request?</source> <source>Repeat connection request?</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Repeat download" xml:space="preserve">
<source>Repeat download</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Repeat import" xml:space="preserve">
<source>Repeat import</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Repeat join request?" xml:space="preserve"> <trans-unit id="Repeat join request?" xml:space="preserve">
<source>Repeat join request?</source> <source>Repeat join request?</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Repeat upload" xml:space="preserve">
<source>Repeat upload</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Reply" xml:space="preserve"> <trans-unit id="Reply" xml:space="preserve">
<source>Reply</source> <source>Reply</source>
<target>Vastaa</target> <target>Vastaa</target>
@@ -4283,6 +4587,10 @@ Error: %@</source>
<target>SMP-palvelimet</target> <target>SMP-palvelimet</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Safer groups" xml:space="preserve">
<source>Safer groups</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Save" xml:space="preserve"> <trans-unit id="Save" xml:space="preserve">
<source>Save</source> <source>Save</source>
<target>Tallenna</target> <target>Tallenna</target>
@@ -4363,11 +4671,19 @@ Error: %@</source>
<target>Tallenna tervetuloviesti?</target> <target>Tallenna tervetuloviesti?</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved" xml:space="preserve">
<source>Saved</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve"> <trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve">
<source>Saved WebRTC ICE servers will be removed</source> <source>Saved WebRTC ICE servers will be removed</source>
<target>Tallennetut WebRTC ICE -palvelimet poistetaan</target> <target>Tallennetut WebRTC ICE -palvelimet poistetaan</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved from" xml:space="preserve">
<source>Saved from</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved message" xml:space="preserve"> <trans-unit id="Saved message" xml:space="preserve">
<source>Saved message</source> <source>Saved message</source>
<note>message info title</note> <note>message info title</note>
@@ -4641,6 +4957,10 @@ Error: %@</source>
<target>Aseta pääsykoodi</target> <target>Aseta pääsykoodi</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Set passphrase" xml:space="preserve">
<source>Set passphrase</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set passphrase to export" xml:space="preserve"> <trans-unit id="Set passphrase to export" xml:space="preserve">
<source>Set passphrase to export</source> <source>Set passphrase to export</source>
<target>Aseta tunnuslause vientiä varten</target> <target>Aseta tunnuslause vientiä varten</target>
@@ -4661,6 +4981,10 @@ Error: %@</source>
<target>Asetukset</target> <target>Asetukset</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Shape profile images" xml:space="preserve">
<source>Shape profile images</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Share" xml:space="preserve"> <trans-unit id="Share" xml:space="preserve">
<source>Share</source> <source>Share</source>
<target>Jaa</target> <target>Jaa</target>
@@ -4695,6 +5019,10 @@ Error: %@</source>
<target>Jaa kontaktien kanssa</target> <target>Jaa kontaktien kanssa</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Show QR code" xml:space="preserve">
<source>Show QR code</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show calls in phone history" xml:space="preserve"> <trans-unit id="Show calls in phone history" xml:space="preserve">
<source>Show calls in phone history</source> <source>Show calls in phone history</source>
<target>Näytä puhelut puhelinhistoriassa</target> <target>Näytä puhelut puhelinhistoriassa</target>
@@ -4773,6 +5101,14 @@ Error: %@</source>
<trans-unit id="SimpleX links" xml:space="preserve"> <trans-unit id="SimpleX links" xml:space="preserve">
<source>SimpleX links</source> <source>SimpleX links</source>
<target>SimpleX-linkit</target> <target>SimpleX-linkit</target>
<note>chat feature</note>
</trans-unit>
<trans-unit id="SimpleX links are prohibited in this group." xml:space="preserve">
<source>SimpleX links are prohibited in this group.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="SimpleX links not allowed" xml:space="preserve">
<source>SimpleX links not allowed</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="SimpleX one-time invitation" xml:space="preserve"> <trans-unit id="SimpleX one-time invitation" xml:space="preserve">
@@ -4809,6 +5145,10 @@ Error: %@</source>
<target>Joku</target> <target>Joku</target>
<note>notification title</note> <note>notification title</note>
</trans-unit> </trans-unit>
<trans-unit id="Square, circle, or anything in between." xml:space="preserve">
<source>Square, circle, or anything in between.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Start chat" xml:space="preserve"> <trans-unit id="Start chat" xml:space="preserve">
<source>Start chat</source> <source>Start chat</source>
<target>Aloita keskustelu</target> <target>Aloita keskustelu</target>
@@ -4833,6 +5173,10 @@ Error: %@</source>
<target>Lopeta SimpleX</target> <target>Lopeta SimpleX</target>
<note>authentication reason</note> <note>authentication reason</note>
</trans-unit> </trans-unit>
<trans-unit id="Stop chat" xml:space="preserve">
<source>Stop chat</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Stop chat to enable database actions" xml:space="preserve"> <trans-unit id="Stop chat to enable database actions" xml:space="preserve">
<source>Stop chat to enable database actions</source> <source>Stop chat to enable database actions</source>
<target>Pysäytä keskustelu tietokantatoimien mahdollistamiseksi</target> <target>Pysäytä keskustelu tietokantatoimien mahdollistamiseksi</target>
@@ -4873,6 +5217,10 @@ Error: %@</source>
<target>Lopeta osoitteen jakaminen?</target> <target>Lopeta osoitteen jakaminen?</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Stopping chat" xml:space="preserve">
<source>Stopping chat</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Submit" xml:space="preserve"> <trans-unit id="Submit" xml:space="preserve">
<source>Submit</source> <source>Submit</source>
<target>Lähetä</target> <target>Lähetä</target>
@@ -5115,6 +5463,14 @@ Tämä voi johtua jostain virheestä tai siitä, että yhteys on vaarantunut.</t
<target>Tätä toimintoa ei voi kumota - profiilisi, kontaktisi, viestisi ja tiedostosi poistuvat peruuttamattomasti.</target> <target>Tätä toimintoa ei voi kumota - profiilisi, kontaktisi, viestisi ja tiedostosi poistuvat peruuttamattomasti.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="This chat is protected by end-to-end encryption." xml:space="preserve">
<source>This chat is protected by end-to-end encryption.</source>
<note>E2EE info chat item</note>
</trans-unit>
<trans-unit id="This chat is protected by quantum resistant end-to-end encryption." xml:space="preserve">
<source>This chat is protected by quantum resistant end-to-end encryption.</source>
<note>E2EE info chat item</note>
</trans-unit>
<trans-unit id="This device name" xml:space="preserve"> <trans-unit id="This device name" xml:space="preserve">
<source>This device name</source> <source>This device name</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
@@ -5394,11 +5750,19 @@ Jos haluat muodostaa yhteyden, pyydä kontaktiasi luomaan toinen yhteyslinkki ja
<target>Päivitä ja avaa keskustelu</target> <target>Päivitä ja avaa keskustelu</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Upload failed" xml:space="preserve">
<source>Upload failed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Upload file" xml:space="preserve"> <trans-unit id="Upload file" xml:space="preserve">
<source>Upload file</source> <source>Upload file</source>
<target>Lataa tiedosto</target> <target>Lataa tiedosto</target>
<note>server test step</note> <note>server test step</note>
</trans-unit> </trans-unit>
<trans-unit id="Uploading archive" xml:space="preserve">
<source>Uploading archive</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use .onion hosts" xml:space="preserve"> <trans-unit id="Use .onion hosts" xml:space="preserve">
<source>Use .onion hosts</source> <source>Use .onion hosts</source>
<target>Käytä .onion-isäntiä</target> <target>Käytä .onion-isäntiä</target>
@@ -5447,6 +5811,10 @@ Jos haluat muodostaa yhteyden, pyydä kontaktiasi luomaan toinen yhteyslinkki ja
<target>Käytä palvelinta</target> <target>Käytä palvelinta</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Use the app while in the call." xml:space="preserve">
<source>Use the app while in the call.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User profile" xml:space="preserve"> <trans-unit id="User profile" xml:space="preserve">
<source>User profile</source> <source>User profile</source>
<target>Käyttäjäprofiili</target> <target>Käyttäjäprofiili</target>
@@ -5479,6 +5847,14 @@ Jos haluat muodostaa yhteyden, pyydä kontaktiasi luomaan toinen yhteyslinkki ja
<source>Verify connections</source> <source>Verify connections</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Verify database passphrase" xml:space="preserve">
<source>Verify database passphrase</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify passphrase" xml:space="preserve">
<source>Verify passphrase</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify security code" xml:space="preserve"> <trans-unit id="Verify security code" xml:space="preserve">
<source>Verify security code</source> <source>Verify security code</source>
<target>Tarkista turvakoodi</target> <target>Tarkista turvakoodi</target>
@@ -5537,6 +5913,10 @@ Jos haluat muodostaa yhteyden, pyydä kontaktiasi luomaan toinen yhteyslinkki ja
<target>Ääniviestit ovat kiellettyjä tässä ryhmässä.</target> <target>Ääniviestit ovat kiellettyjä tässä ryhmässä.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Voice messages not allowed" xml:space="preserve">
<source>Voice messages not allowed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Voice messages prohibited!" xml:space="preserve"> <trans-unit id="Voice messages prohibited!" xml:space="preserve">
<source>Voice messages prohibited!</source> <source>Voice messages prohibited!</source>
<target>Ääniviestit kielletty!</target> <target>Ääniviestit kielletty!</target>
@@ -5566,6 +5946,10 @@ Jos haluat muodostaa yhteyden, pyydä kontaktiasi luomaan toinen yhteyslinkki ja
<target>Odottaa videota</target> <target>Odottaa videota</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Warning: starting chat on multiple devices is not supported and will cause message delivery failures" xml:space="preserve">
<source>Warning: starting chat on multiple devices is not supported and will cause message delivery failures</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Warning: you may lose some data!" xml:space="preserve"> <trans-unit id="Warning: you may lose some data!" xml:space="preserve">
<source>Warning: you may lose some data!</source> <source>Warning: you may lose some data!</source>
<target>Varoitus: saatat menettää joitain tietoja!</target> <target>Varoitus: saatat menettää joitain tietoja!</target>
@@ -5586,6 +5970,10 @@ Jos haluat muodostaa yhteyden, pyydä kontaktiasi luomaan toinen yhteyslinkki ja
<target>Tervetuloviesti</target> <target>Tervetuloviesti</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Welcome message is too long" xml:space="preserve">
<source>Welcome message is too long</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="What's new" xml:space="preserve"> <trans-unit id="What's new" xml:space="preserve">
<source>What's new</source> <source>What's new</source>
<target>Uusimmat</target> <target>Uusimmat</target>
@@ -5596,6 +5984,10 @@ Jos haluat muodostaa yhteyden, pyydä kontaktiasi luomaan toinen yhteyslinkki ja
<target>Kun saatavilla</target> <target>Kun saatavilla</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="When connecting audio and video calls." xml:space="preserve">
<source>When connecting audio and video calls.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="When people request to connect, you can accept or reject it." xml:space="preserve"> <trans-unit id="When people request to connect, you can accept or reject it." xml:space="preserve">
<source>When people request to connect, you can accept or reject it.</source> <source>When people request to connect, you can accept or reject it.</source>
<target>Kun ihmiset pyytävät yhteyden muodostamista, voit hyväksyä tai hylätä sen.</target> <target>Kun ihmiset pyytävät yhteyden muodostamista, voit hyväksyä tai hylätä sen.</target>
@@ -5606,6 +5998,18 @@ Jos haluat muodostaa yhteyden, pyydä kontaktiasi luomaan toinen yhteyslinkki ja
<target>Kun jaat inkognitoprofiilin jonkun kanssa, tätä profiilia käytetään ryhmissä, joihin tämä sinut kutsuu.</target> <target>Kun jaat inkognitoprofiilin jonkun kanssa, tätä profiilia käytetään ryhmissä, joihin tämä sinut kutsuu.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="WiFi" xml:space="preserve">
<source>WiFi</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Will be enabled in direct chats!" xml:space="preserve">
<source>Will be enabled in direct chats!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Wired ethernet" xml:space="preserve">
<source>Wired ethernet</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="With encrypted files and media." xml:space="preserve"> <trans-unit id="With encrypted files and media." xml:space="preserve">
<source>With encrypted files and media.</source> <source>With encrypted files and media.</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
@@ -5639,6 +6043,10 @@ Jos haluat muodostaa yhteyden, pyydä kontaktiasi luomaan toinen yhteyslinkki ja
<target>Sinä</target> <target>Sinä</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="You **must not** use the same database on two devices." xml:space="preserve">
<source>You **must not** use the same database on two devices.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You accepted connection" xml:space="preserve"> <trans-unit id="You accepted connection" xml:space="preserve">
<source>You accepted connection</source> <source>You accepted connection</source>
<target>Hyväksyit yhteyden</target> <target>Hyväksyit yhteyden</target>
@@ -5718,6 +6126,10 @@ Repeat join request?</source>
<target>Voit ottaa ne käyttöön myöhemmin sovelluksen Yksityisyys &amp; Turvallisuus -asetuksista.</target> <target>Voit ottaa ne käyttöön myöhemmin sovelluksen Yksityisyys &amp; Turvallisuus -asetuksista.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="You can give another try." xml:space="preserve">
<source>You can give another try.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You can hide or mute a user profile - swipe it to the right." xml:space="preserve"> <trans-unit id="You can hide or mute a user profile - swipe it to the right." xml:space="preserve">
<source>You can hide or mute a user profile - swipe it to the right.</source> <source>You can hide or mute a user profile - swipe it to the right.</source>
<target>Voit piilottaa tai mykistää käyttäjäprofiilin pyyhkäisemällä sitä oikealle.</target> <target>Voit piilottaa tai mykistää käyttäjäprofiilin pyyhkäisemällä sitä oikealle.</target>
@@ -6061,6 +6473,10 @@ SimpleX-palvelimet eivät näe profiiliasi.</target>
<target>ylläpitäjä</target> <target>ylläpitäjä</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="admins" xml:space="preserve">
<source>admins</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="agreeing encryption for %@…" xml:space="preserve"> <trans-unit id="agreeing encryption for %@…" xml:space="preserve">
<source>agreeing encryption for %@…</source> <source>agreeing encryption for %@…</source>
<target>salauksesta sovitaan %@:lle…</target> <target>salauksesta sovitaan %@:lle…</target>
@@ -6071,6 +6487,10 @@ SimpleX-palvelimet eivät näe profiiliasi.</target>
<target>hyväksyy salausta…</target> <target>hyväksyy salausta…</target>
<note>chat item text</note> <note>chat item text</note>
</trans-unit> </trans-unit>
<trans-unit id="all members" xml:space="preserve">
<source>all members</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="always" xml:space="preserve"> <trans-unit id="always" xml:space="preserve">
<source>always</source> <source>always</source>
<target>aina</target> <target>aina</target>
@@ -6101,7 +6521,7 @@ SimpleX-palvelimet eivät näe profiiliasi.</target>
</trans-unit> </trans-unit>
<trans-unit id="blocked" xml:space="preserve"> <trans-unit id="blocked" xml:space="preserve">
<source>blocked</source> <source>blocked</source>
<note>No comment provided by engineer.</note> <note>marked deleted chat item preview text</note>
</trans-unit> </trans-unit>
<trans-unit id="blocked %@" xml:space="preserve"> <trans-unit id="blocked %@" xml:space="preserve">
<source>blocked %@</source> <source>blocked %@</source>
@@ -6109,7 +6529,7 @@ SimpleX-palvelimet eivät näe profiiliasi.</target>
</trans-unit> </trans-unit>
<trans-unit id="blocked by admin" xml:space="preserve"> <trans-unit id="blocked by admin" xml:space="preserve">
<source>blocked by admin</source> <source>blocked by admin</source>
<note>blocked chat item</note> <note>marked deleted chat item preview text</note>
</trans-unit> </trans-unit>
<trans-unit id="bold" xml:space="preserve"> <trans-unit id="bold" xml:space="preserve">
<source>bold</source> <source>bold</source>
@@ -6393,6 +6813,10 @@ SimpleX-palvelimet eivät näe profiiliasi.</target>
<target>tapahtuma tapahtui</target> <target>tapahtuma tapahtui</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="forwarded" xml:space="preserve">
<source>forwarded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="group deleted" xml:space="preserve"> <trans-unit id="group deleted" xml:space="preserve">
<source>group deleted</source> <source>group deleted</source>
<target>ryhmä poistettu</target> <target>ryhmä poistettu</target>
@@ -6535,7 +6959,7 @@ SimpleX-palvelimet eivät näe profiiliasi.</target>
<trans-unit id="moderated by %@" xml:space="preserve"> <trans-unit id="moderated by %@" xml:space="preserve">
<source>moderated by %@</source> <source>moderated by %@</source>
<target>%@ moderoi</target> <target>%@ moderoi</target>
<note>No comment provided by engineer.</note> <note>marked deleted chat item preview text</note>
</trans-unit> </trans-unit>
<trans-unit id="months" xml:space="preserve"> <trans-unit id="months" xml:space="preserve">
<source>months</source> <source>months</source>
@@ -6599,11 +7023,19 @@ SimpleX-palvelimet eivät näe profiiliasi.</target>
<target>omistaja</target> <target>omistaja</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="owners" xml:space="preserve">
<source>owners</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="peer-to-peer" xml:space="preserve"> <trans-unit id="peer-to-peer" xml:space="preserve">
<source>peer-to-peer</source> <source>peer-to-peer</source>
<target>vertais</target> <target>vertais</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="quantum resistant e2e encryption" xml:space="preserve">
<source>quantum resistant e2e encryption</source>
<note>chat item text</note>
</trans-unit>
<trans-unit id="received answer…" xml:space="preserve"> <trans-unit id="received answer…" xml:space="preserve">
<source>received answer…</source> <source>received answer…</source>
<target>vastaus saatu…</target> <target>vastaus saatu…</target>
@@ -6642,6 +7074,14 @@ SimpleX-palvelimet eivät näe profiiliasi.</target>
<target>poisti sinut</target> <target>poisti sinut</target>
<note>rcv group event chat item</note> <note>rcv group event chat item</note>
</trans-unit> </trans-unit>
<trans-unit id="saved" xml:space="preserve">
<source>saved</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="saved from %@" xml:space="preserve">
<source>saved from %@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="sec" xml:space="preserve"> <trans-unit id="sec" xml:space="preserve">
<source>sec</source> <source>sec</source>
<target>sek</target> <target>sek</target>
@@ -6674,6 +7114,10 @@ SimpleX-palvelimet eivät näe profiiliasi.</target>
<source>set new profile picture</source> <source>set new profile picture</source>
<note>profile update event chat item</note> <note>profile update event chat item</note>
</trans-unit> </trans-unit>
<trans-unit id="standard end-to-end encryption" xml:space="preserve">
<source>standard end-to-end encryption</source>
<note>chat item text</note>
</trans-unit>
<trans-unit id="starting…" xml:space="preserve"> <trans-unit id="starting…" xml:space="preserve">
<source>starting…</source> <source>starting…</source>
<target>alkaa…</target> <target>alkaa…</target>
@@ -6770,6 +7214,10 @@ SimpleX-palvelimet eivät näe profiiliasi.</target>
<target>kyllä</target> <target>kyllä</target>
<note>pref value</note> <note>pref value</note>
</trans-unit> </trans-unit>
<trans-unit id="you" xml:space="preserve">
<source>you</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="you are invited to group" xml:space="preserve"> <trans-unit id="you are invited to group" xml:space="preserve">
<source>you are invited to group</source> <source>you are invited to group</source>
<target>sinut on kutsuttu ryhmään</target> <target>sinut on kutsuttu ryhmään</target>
File diff suppressed because it is too large Load Diff
@@ -5311,6 +5311,11 @@ SimpleX servers cannot see your profile.</source>
<target state="translated">ללא היסטוריה</target> <target state="translated">ללא היסטוריה</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="%@ and %@" xml:space="preserve" approved="no">
<source>%@ and %@</source>
<target state="translated">%@ ו-%@</target>
<note>No comment provided by engineer.</note>
</trans-unit>
</body> </body>
</file> </file>
<file original="en.lproj/SimpleX--iOS--InfoPlist.strings" source-language="en" target-language="he" datatype="plaintext"> <file original="en.lproj/SimpleX--iOS--InfoPlist.strings" source-language="en" target-language="he" datatype="plaintext">
@@ -0,0 +1,15 @@
{
"colors" : [
{
"idiom" : "universal",
"locale" : "hu"
}
],
"properties" : {
"localizable" : true
},
"info" : {
"version" : 1,
"author" : "xcode"
}
}
@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,23 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"red" : "0.000",
"alpha" : "1.000",
"blue" : "1.000",
"green" : "0.533"
}
},
"idiom" : "universal"
}
],
"properties" : {
"localizable" : true
},
"info" : {
"version" : 1,
"author" : "xcode"
}
}
@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -0,0 +1,6 @@
/* Bundle display name */
"CFBundleDisplayName" = "SimpleX NSE";
/* Bundle name */
"CFBundleName" = "SimpleX NSE";
/* Copyright (human-readable) */
"NSHumanReadableCopyright" = "Copyright © 2022 SimpleX Chat. All rights reserved.";
@@ -0,0 +1,30 @@
/* No comment provided by engineer. */
"_italic_" = "\\_italic_";
/* No comment provided by engineer. */
"**Add new contact**: to create your one-time QR Code for your contact." = "**Add new contact**: to create your one-time QR Code or link for your contact.";
/* No comment provided by engineer. */
"*bold*" = "\\*bold*";
/* No comment provided by engineer. */
"`a + b`" = "\\`a + b`";
/* No comment provided by engineer. */
"~strike~" = "\\~strike~";
/* call status */
"connecting call" = "connecting call…";
/* No comment provided by engineer. */
"Connecting server…" = "Connecting to server…";
/* No comment provided by engineer. */
"Connecting server… (error: %@)" = "Connecting to server… (error: %@)";
/* rcv group event chat item */
"member connected" = "connected";
/* No comment provided by engineer. */
"No group!" = "Group not found!";
@@ -0,0 +1,12 @@
/* Bundle name */
"CFBundleName" = "SimpleX";
/* Privacy - Camera Usage Description */
"NSCameraUsageDescription" = "SimpleX needs camera access to scan QR codes to connect to other users and for video calls.";
/* Privacy - Face ID Usage Description */
"NSFaceIDUsageDescription" = "SimpleX uses Face ID for local authentication";
/* Privacy - Local Network Usage Description */
"NSLocalNetworkUsageDescription" = "SimpleX uses local network access to allow using user chat profile via desktop app on the same network.";
/* Privacy - Microphone Usage Description */
"NSMicrophoneUsageDescription" = "SimpleX needs microphone access for audio and video calls, and to record voice messages.";
/* Privacy - Photo Library Additions Usage Description */
"NSPhotoLibraryAddUsageDescription" = "SimpleX needs access to Photo Library for saving captured and received media";
@@ -0,0 +1,12 @@
{
"developmentRegion" : "en",
"project" : "SimpleX.xcodeproj",
"targetLocale" : "hu",
"toolInfo" : {
"toolBuildNumber" : "15A240d",
"toolID" : "com.apple.dt.xcode",
"toolName" : "Xcode",
"toolVersion" : "15.0"
},
"version" : "1.0"
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -69,7 +69,7 @@
</trans-unit> </trans-unit>
<trans-unit id="%@ is not verified" xml:space="preserve" approved="no"> <trans-unit id="%@ is not verified" xml:space="preserve" approved="no">
<source>%@ is not verified</source> <source>%@ is not verified</source>
<target state="translated">%@ não foi verificado</target> <target state="translated">%@ não foi verificado(a)</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="%@ is verified" xml:space="preserve" approved="no"> <trans-unit id="%@ is verified" xml:space="preserve" approved="no">
@@ -84,12 +84,12 @@
</trans-unit> </trans-unit>
<trans-unit id="%d days" xml:space="preserve" approved="no"> <trans-unit id="%d days" xml:space="preserve" approved="no">
<source>%d days</source> <source>%d days</source>
<target state="translated">%d dia(s)</target> <target state="translated">%d dias</target>
<note>message ttl</note> <note>message ttl</note>
</trans-unit> </trans-unit>
<trans-unit id="%d hours" xml:space="preserve" approved="no"> <trans-unit id="%d hours" xml:space="preserve" approved="no">
<source>%d hours</source> <source>%d hours</source>
<target state="translated">%d hora(s)</target> <target state="translated">%d horas</target>
<note>message ttl</note> <note>message ttl</note>
</trans-unit> </trans-unit>
<trans-unit id="%d min" xml:space="preserve" approved="no"> <trans-unit id="%d min" xml:space="preserve" approved="no">
@@ -99,7 +99,7 @@
</trans-unit> </trans-unit>
<trans-unit id="%d months" xml:space="preserve" approved="no"> <trans-unit id="%d months" xml:space="preserve" approved="no">
<source>%d months</source> <source>%d months</source>
<target state="translated">%d mês(es)</target> <target state="translated">%d meses</target>
<note>message ttl</note> <note>message ttl</note>
</trans-unit> </trans-unit>
<trans-unit id="%d sec" xml:space="preserve" approved="no"> <trans-unit id="%d sec" xml:space="preserve" approved="no">
@@ -109,7 +109,7 @@
</trans-unit> </trans-unit>
<trans-unit id="%d skipped message(s)" xml:space="preserve" approved="no"> <trans-unit id="%d skipped message(s)" xml:space="preserve" approved="no">
<source>%d skipped message(s)</source> <source>%d skipped message(s)</source>
<target state="translated">%d mensagem(ns) ignorada(s)</target> <target state="translated">%d mensagem(ns) omitida(s)</target>
<note>integrity error chat item</note> <note>integrity error chat item</note>
</trans-unit> </trans-unit>
<trans-unit id="%lld" xml:space="preserve" approved="no"> <trans-unit id="%lld" xml:space="preserve" approved="no">
@@ -5189,6 +5189,51 @@ Isso pode acontecer por causa de algum bug ou quando a conexão está comprometi
<target state="translated">Desaparecerá: %@</target> <target state="translated">Desaparecerá: %@</target>
<note>copied message info</note> <note>copied message info</note>
</trans-unit> </trans-unit>
<trans-unit id="# %@" xml:space="preserve" approved="no">
<source># %@</source>
<target state="translated"># %@</target>
<note>copied message info title, # &lt;title&gt;</note>
</trans-unit>
<trans-unit id="## History" xml:space="preserve" approved="no">
<source>## History</source>
<target state="translated">## Histórico</target>
<note>copied message info</note>
</trans-unit>
<trans-unit id="## In reply to" xml:space="preserve" approved="no">
<source>## In reply to</source>
<target state="translated">## Em resposta a</target>
<note>copied message info</note>
</trans-unit>
<trans-unit id="%@ connected" xml:space="preserve" approved="no">
<source>%@ connected</source>
<target state="translated">%@ conectado(a)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@, %@ and %lld members" xml:space="preserve" approved="no">
<source>%@, %@ and %lld members</source>
<target state="translated">%@, %@ e %lld membros</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ and %@ connected" xml:space="preserve" approved="no">
<source>%@ and %@ connected</source>
<target state="translated">%@ e %@ conectados</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@, %@ and %lld other members connected" xml:space="preserve" approved="no">
<source>%@, %@ and %lld other members connected</source>
<target state="translated">%@, %@ e %lld e outros membros se conectaram</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ and %@" xml:space="preserve" approved="no">
<source>%@ and %@</source>
<target state="translated">%@ e %@</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ at %@:" xml:space="preserve" approved="no">
<source>%1$@ at %2$@:</source>
<target state="translated">%1$@ em %2$@:</target>
<note>copied message info, &lt;sender&gt; at &lt;time&gt;</note>
</trans-unit>
</body> </body>
</file> </file>
<file original="en.lproj/SimpleX--iOS--InfoPlist.strings" source-language="en" target-language="pt-BR" datatype="plaintext"> <file original="en.lproj/SimpleX--iOS--InfoPlist.strings" source-language="en" target-language="pt-BR" datatype="plaintext">
@@ -15,32 +15,39 @@
Available in v5.1</source> Available in v5.1</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id=" " xml:space="preserve"> <trans-unit id=" " xml:space="preserve" approved="no">
<source> </source> <source> </source>
<target state="translated"> </target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id=" " xml:space="preserve"> <trans-unit id=" " xml:space="preserve" approved="no">
<source> </source> <source> </source>
<target state="translated"> </target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id=" " xml:space="preserve"> <trans-unit id=" " xml:space="preserve" approved="no">
<source> </source> <source> </source>
<target state="translated"> </target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id=" (" xml:space="preserve"> <trans-unit id=" (" xml:space="preserve" approved="no">
<source> (</source> <source> (</source>
<target state="translated"> (</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id=" (can be copied)" xml:space="preserve"> <trans-unit id=" (can be copied)" xml:space="preserve" approved="no">
<source> (can be copied)</source> <source> (can be copied)</source>
<target state="translated"> .(pode ser copiado)</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="!1 colored!" xml:space="preserve"> <trans-unit id="!1 colored!" xml:space="preserve" approved="no">
<source>!1 colored!</source> <source>!1 colored!</source>
<target state="translated">!1 colorido!</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="#secret#" xml:space="preserve"> <trans-unit id="#secret#" xml:space="preserve" approved="no">
<source>#secret#</source> <source>#secret#</source>
<target state="translated">#secreto#</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="%@" xml:space="preserve"> <trans-unit id="%@" xml:space="preserve">
@@ -55,48 +62,59 @@ Available in v5.1</source>
<source>%@ / %@</source> <source>%@ / %@</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="%@ is connected!" xml:space="preserve"> <trans-unit id="%@ is connected!" xml:space="preserve" approved="no">
<source>%@ is connected!</source> <source>%@ is connected!</source>
<target state="translated">%@ está conectado!</target>
<note>notification title</note> <note>notification title</note>
</trans-unit> </trans-unit>
<trans-unit id="%@ is not verified" xml:space="preserve"> <trans-unit id="%@ is not verified" xml:space="preserve" approved="no">
<source>%@ is not verified</source> <source>%@ is not verified</source>
<target state="translated">%@ não foi verificado</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="%@ is verified" xml:space="preserve"> <trans-unit id="%@ is verified" xml:space="preserve" approved="no">
<source>%@ is verified</source> <source>%@ is verified</source>
<target state="translated">%@ foi verificado</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="%@ servers" xml:space="preserve"> <trans-unit id="%@ servers" xml:space="preserve" approved="no">
<source>%@ servers</source> <source>%@ servers</source>
<target state="translated">%@ servidores</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="%@ wants to connect!" xml:space="preserve"> <trans-unit id="%@ wants to connect!" xml:space="preserve" approved="no">
<source>%@ wants to connect!</source> <source>%@ wants to connect!</source>
<target state="translated">%@ quer se conectar!</target>
<note>notification title</note> <note>notification title</note>
</trans-unit> </trans-unit>
<trans-unit id="%d days" xml:space="preserve"> <trans-unit id="%d days" xml:space="preserve" approved="no">
<source>%d days</source> <source>%d days</source>
<target state="translated">%d dias</target>
<note>message ttl</note> <note>message ttl</note>
</trans-unit> </trans-unit>
<trans-unit id="%d hours" xml:space="preserve"> <trans-unit id="%d hours" xml:space="preserve" approved="no">
<source>%d hours</source> <source>%d hours</source>
<target state="translated">%d horas</target>
<note>message ttl</note> <note>message ttl</note>
</trans-unit> </trans-unit>
<trans-unit id="%d min" xml:space="preserve"> <trans-unit id="%d min" xml:space="preserve" approved="no">
<source>%d min</source> <source>%d min</source>
<target state="translated">%d minuto</target>
<note>message ttl</note> <note>message ttl</note>
</trans-unit> </trans-unit>
<trans-unit id="%d months" xml:space="preserve"> <trans-unit id="%d months" xml:space="preserve" approved="no">
<source>%d months</source> <source>%d months</source>
<target state="translated">%d meses</target>
<note>message ttl</note> <note>message ttl</note>
</trans-unit> </trans-unit>
<trans-unit id="%d sec" xml:space="preserve"> <trans-unit id="%d sec" xml:space="preserve" approved="no">
<source>%d sec</source> <source>%d sec</source>
<target state="translated">%d segundo</target>
<note>message ttl</note> <note>message ttl</note>
</trans-unit> </trans-unit>
<trans-unit id="%d skipped message(s)" xml:space="preserve"> <trans-unit id="%d skipped message(s)" xml:space="preserve" approved="no">
<source>%d skipped message(s)</source> <source>%d skipped message(s)</source>
<target state="translated">%d mensagem(s) ignorada(s)</target>
<note>integrity error chat item</note> <note>integrity error chat item</note>
</trans-unit> </trans-unit>
<trans-unit id="%lld" xml:space="preserve"> <trans-unit id="%lld" xml:space="preserve">
@@ -107,28 +125,34 @@ Available in v5.1</source>
<source>%lld %@</source> <source>%lld %@</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="%lld contact(s) selected" xml:space="preserve"> <trans-unit id="%lld contact(s) selected" xml:space="preserve" approved="no">
<source>%lld contact(s) selected</source> <source>%lld contact(s) selected</source>
<target state="translated">%lld contato(s) selecionado(s)</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="%lld file(s) with total size of %@" xml:space="preserve"> <trans-unit id="%lld file(s) with total size of %@" xml:space="preserve" approved="no">
<source>%lld file(s) with total size of %@</source> <source>%lld file(s) with total size of %@</source>
<target state="translated">%lld arquivo(s) com tamanho total de %@</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="%lld members" xml:space="preserve"> <trans-unit id="%lld members" xml:space="preserve" approved="no">
<source>%lld members</source> <source>%lld members</source>
<target state="translated">%lld membros</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="%lld minutes" xml:space="preserve"> <trans-unit id="%lld minutes" xml:space="preserve" approved="no">
<source>%lld minutes</source> <source>%lld minutes</source>
<target state="translated">%lld minutos</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="%lld second(s)" xml:space="preserve"> <trans-unit id="%lld second(s)" xml:space="preserve" approved="no">
<source>%lld second(s)</source> <source>%lld second(s)</source>
<target state="translated">%lld segundo(s)</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="%lld seconds" xml:space="preserve"> <trans-unit id="%lld seconds" xml:space="preserve" approved="no">
<source>%lld seconds</source> <source>%lld seconds</source>
<target state="translated">%lld segundos</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="%lldd" xml:space="preserve"> <trans-unit id="%lldd" xml:space="preserve">
@@ -159,12 +183,14 @@ Available in v5.1</source>
<source>%lldw</source> <source>%lldw</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="%u messages failed to decrypt." xml:space="preserve"> <trans-unit id="%u messages failed to decrypt." xml:space="preserve" approved="no">
<source>%u messages failed to decrypt.</source> <source>%u messages failed to decrypt.</source>
<target state="translated">%u mensagens não foram descriptografadas.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="%u messages skipped." xml:space="preserve"> <trans-unit id="%u messages skipped." xml:space="preserve" approved="no">
<source>%u messages skipped.</source> <source>%u messages skipped.</source>
<target state="translated">%u mensagens ignoradas.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="(" xml:space="preserve"> <trans-unit id="(" xml:space="preserve">
@@ -175,48 +201,56 @@ Available in v5.1</source>
<source>)</source> <source>)</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="**Add new contact**: to create your one-time QR Code for your contact." xml:space="preserve"> <trans-unit id="**Add new contact**: to create your one-time QR Code for your contact." xml:space="preserve" approved="no">
<source>**Add new contact**: to create your one-time QR Code or link for your contact.</source> <source>**Add new contact**: to create your one-time QR Code or link for your contact.</source>
<target state="translated">**Adicionar novo contato**: para criar seu QR Code único ou link para seu contato.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="**Create link / QR code** for your contact to use." xml:space="preserve"> <trans-unit id="**Create link / QR code** for your contact to use." xml:space="preserve">
<source>**Create link / QR code** for your contact to use.</source> <source>**Create link / QR code** for your contact to use.</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="**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." xml:space="preserve"> <trans-unit id="**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." xml:space="preserve" approved="no">
<source>**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.</source> <source>**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.</source>
<target state="translated">**Mais privado**: verifique novas mensagens a cada 20 minutos. O token do dispositivo é compartilhado com o servidor SimpleX Chat, mas não com quantos contatos ou mensagens você possui.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="**Most private**: do not use SimpleX Chat notifications server, check messages periodically in the background (depends on how often you use the app)." xml:space="preserve"> <trans-unit id="**Most private**: do not use SimpleX Chat notifications server, check messages periodically in the background (depends on how often you use the app)." xml:space="preserve" approved="no">
<source>**Most private**: do not use SimpleX Chat notifications server, check messages periodically in the background (depends on how often you use the app).</source> <source>**Most private**: do not use SimpleX Chat notifications server, check messages periodically in the background (depends on how often you use the app).</source>
<target state="translated">**Totalmente privado**: não use o servidor de notificações do SimpleX Chat, verifique as mensagens periodicamente em segundo plano (depende da frequência com que você usa o aplicativo).</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="**Paste received link** or open it in the browser and tap **Open in mobile app**." xml:space="preserve"> <trans-unit id="**Paste received link** or open it in the browser and tap **Open in mobile app**." xml:space="preserve">
<source>**Paste received link** or open it in the browser and tap **Open in mobile app**.</source> <source>**Paste received link** or open it in the browser and tap **Open in mobile app**.</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="**Please note**: you will NOT be able to recover or change passphrase if you lose it." xml:space="preserve"> <trans-unit id="**Please note**: you will NOT be able to recover or change passphrase if you lose it." xml:space="preserve" approved="no">
<source>**Please note**: you will NOT be able to recover or change passphrase if you lose it.</source> <source>**Please note**: you will NOT be able to recover or change passphrase if you lose it.</source>
<target state="translated">**Atenção**: Você NÃO poderá recuperar ou alterar a senha caso a perca.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="**Recommended**: device token and notifications are sent to SimpleX Chat notification server, but not the message content, size or who it is from." xml:space="preserve"> <trans-unit id="**Recommended**: device token and notifications are sent to SimpleX Chat notification server, but not the message content, size or who it is from." xml:space="preserve" approved="no">
<source>**Recommended**: device token and notifications are sent to SimpleX Chat notification server, but not the message content, size or who it is from.</source> <source>**Recommended**: device token and notifications are sent to SimpleX Chat notification server, but not the message content, size or who it is from.</source>
<target state="translated">**Recomendado**: O token do dispositivo e as notificações são enviados ao servidor de notificação do SimpleX Chat, mas não o conteúdo, o tamanho da mensagem ou de quem ela é.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="**Scan QR code**: to connect to your contact in person or via video call." xml:space="preserve"> <trans-unit id="**Scan QR code**: to connect to your contact in person or via video call." xml:space="preserve">
<source>**Scan QR code**: to connect to your contact in person or via video call.</source> <source>**Scan QR code**: to connect to your contact in person or via video call.</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="**Warning**: Instant push notifications require passphrase saved in Keychain." xml:space="preserve"> <trans-unit id="**Warning**: Instant push notifications require passphrase saved in Keychain." xml:space="preserve" approved="no">
<source>**Warning**: Instant push notifications require passphrase saved in Keychain.</source> <source>**Warning**: Instant push notifications require passphrase saved in Keychain.</source>
<target state="translated">**Aviso**: As notificações push instantâneas exigem uma senha salva nas Chaves.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="**e2e encrypted** audio call" xml:space="preserve"> <trans-unit id="**e2e encrypted** audio call" xml:space="preserve" approved="no">
<source>**e2e encrypted** audio call</source> <source>**e2e encrypted** audio call</source>
<target state="translated">** Criptografado e2e** chamada de áudio</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="**e2e encrypted** video call" xml:space="preserve"> <trans-unit id="**e2e encrypted** video call" xml:space="preserve" approved="no">
<source>**e2e encrypted** video call</source> <source>**e2e encrypted** video call</source>
<target state="translated">**Criptografado e2e** chamada de vídeo</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="*bold*" xml:space="preserve"> <trans-unit id="*bold*" xml:space="preserve">
@@ -353,144 +387,175 @@ Available in v5.1</source>
<source>All group members will remain connected.</source> <source>All group members will remain connected.</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="All messages will be deleted - this cannot be undone! The messages will be deleted ONLY for you." xml:space="preserve"> <trans-unit id="All messages will be deleted - this cannot be undone! The messages will be deleted ONLY for you." xml:space="preserve" approved="no">
<source>All messages will be deleted - this cannot be undone! The messages will be deleted ONLY for you.</source> <source>All messages will be deleted - this cannot be undone! The messages will be deleted ONLY for you.</source>
<target state="translated">Todas as mensagens serão apagadas isso não pode ser desfeito! As mensagens serão apagadas SOMENTE para você.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="All your contacts will remain connected" xml:space="preserve"> <trans-unit id="All your contacts will remain connected" xml:space="preserve">
<source>All your contacts will remain connected</source> <source>All your contacts will remain connected</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Allow" xml:space="preserve"> <trans-unit id="Allow" xml:space="preserve" approved="no">
<source>Allow</source> <source>Allow</source>
<target state="translated">Permitir</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Allow calls only if your contact allows them." xml:space="preserve"> <trans-unit id="Allow calls only if your contact allows them." xml:space="preserve" approved="no">
<source>Allow calls only if your contact allows them.</source> <source>Allow calls only if your contact allows them.</source>
<target state="translated">Permita chamadas somente se seu contato permitir.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Allow disappearing messages only if your contact allows it to you." xml:space="preserve"> <trans-unit id="Allow disappearing messages only if your contact allows it to you." xml:space="preserve" approved="no">
<source>Allow disappearing messages only if your contact allows it to you.</source> <source>Allow disappearing messages only if your contact allows it to you.</source>
<target state="translated">Permita o desaparecimento de mensagens somente se o seu contato permitir.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Allow irreversible message deletion only if your contact allows it to you." xml:space="preserve"> <trans-unit id="Allow irreversible message deletion only if your contact allows it to you." xml:space="preserve">
<source>Allow irreversible message deletion only if your contact allows it to you.</source> <source>Allow irreversible message deletion only if your contact allows it to you.</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Allow sending direct messages to members." xml:space="preserve"> <trans-unit id="Allow sending direct messages to members." xml:space="preserve" approved="no">
<source>Allow sending direct messages to members.</source> <source>Allow sending direct messages to members.</source>
<target state="translated">Permitir o envio de mensagens diretas aos membros.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Allow sending disappearing messages." xml:space="preserve"> <trans-unit id="Allow sending disappearing messages." xml:space="preserve" approved="no">
<source>Allow sending disappearing messages.</source> <source>Allow sending disappearing messages.</source>
<target state="translated">Permitir o envio de mensagens que desaparecem.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Allow to irreversibly delete sent messages." xml:space="preserve"> <trans-unit id="Allow to irreversibly delete sent messages." xml:space="preserve">
<source>Allow to irreversibly delete sent messages.</source> <source>Allow to irreversibly delete sent messages.</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Allow to send voice messages." xml:space="preserve"> <trans-unit id="Allow to send voice messages." xml:space="preserve" approved="no">
<source>Allow to send voice messages.</source> <source>Allow to send voice messages.</source>
<target state="translated">Permitir enviar mensagens de voz.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Allow voice messages only if your contact allows them." xml:space="preserve"> <trans-unit id="Allow voice messages only if your contact allows them." xml:space="preserve" approved="no">
<source>Allow voice messages only if your contact allows them.</source> <source>Allow voice messages only if your contact allows them.</source>
<target state="translated">Permita mensagens de voz apenas se o seu contato permitir.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Allow voice messages?" xml:space="preserve"> <trans-unit id="Allow voice messages?" xml:space="preserve" approved="no">
<source>Allow voice messages?</source> <source>Allow voice messages?</source>
<target state="translated">Permitir mensagens de voz?</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Allow your contacts to call you." xml:space="preserve"> <trans-unit id="Allow your contacts to call you." xml:space="preserve" approved="no">
<source>Allow your contacts to call you.</source> <source>Allow your contacts to call you.</source>
<target state="translated">Permita que seus contatos liguem para você.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Allow your contacts to irreversibly delete sent messages." xml:space="preserve"> <trans-unit id="Allow your contacts to irreversibly delete sent messages." xml:space="preserve">
<source>Allow your contacts to irreversibly delete sent messages.</source> <source>Allow your contacts to irreversibly delete sent messages.</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Allow your contacts to send disappearing messages." xml:space="preserve"> <trans-unit id="Allow your contacts to send disappearing messages." xml:space="preserve" approved="no">
<source>Allow your contacts to send disappearing messages.</source> <source>Allow your contacts to send disappearing messages.</source>
<target state="translated">Permita que seus contatos enviem mensagens que desaparecem.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Allow your contacts to send voice messages." xml:space="preserve"> <trans-unit id="Allow your contacts to send voice messages." xml:space="preserve" approved="no">
<source>Allow your contacts to send voice messages.</source> <source>Allow your contacts to send voice messages.</source>
<target state="translated">Permita que seus contatos enviem mensagens de voz.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Already connected?" xml:space="preserve"> <trans-unit id="Already connected?" xml:space="preserve" approved="no">
<source>Already connected?</source> <source>Already connected?</source>
<target state="translated">Já conectado?</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Always use relay" xml:space="preserve"> <trans-unit id="Always use relay" xml:space="preserve" approved="no">
<source>Always use relay</source> <source>Always use relay</source>
<target state="translated">Sempre usar retransmissão</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Answer call" xml:space="preserve"> <trans-unit id="Answer call" xml:space="preserve" approved="no">
<source>Answer call</source> <source>Answer call</source>
<target state="translated">Atender chamada</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="App build: %@" xml:space="preserve"> <trans-unit id="App build: %@" xml:space="preserve" approved="no">
<source>App build: %@</source> <source>App build: %@</source>
<target state="translated">Versão do Aplicativo: %@</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="App icon" xml:space="preserve"> <trans-unit id="App icon" xml:space="preserve" approved="no">
<source>App icon</source> <source>App icon</source>
<target state="translated">Ícone do Aplicativo</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="App passcode" xml:space="preserve"> <trans-unit id="App passcode" xml:space="preserve" approved="no">
<source>App passcode</source> <source>App passcode</source>
<target state="translated">Senha do Aplicativo</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="App version" xml:space="preserve"> <trans-unit id="App version" xml:space="preserve" approved="no">
<source>App version</source> <source>App version</source>
<target state="translated">Versão do Aplicativo</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="App version: v%@" xml:space="preserve"> <trans-unit id="App version: v%@" xml:space="preserve" approved="no">
<source>App version: v%@</source> <source>App version: v%@</source>
<target state="translated">Versão do Aplicativo: v%@</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Appearance" xml:space="preserve"> <trans-unit id="Appearance" xml:space="preserve" approved="no">
<source>Appearance</source> <source>Appearance</source>
<target state="translated">Aparência</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Attach" xml:space="preserve"> <trans-unit id="Attach" xml:space="preserve" approved="no">
<source>Attach</source> <source>Attach</source>
<target state="translated">Anexar</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Audio &amp; video calls" xml:space="preserve"> <trans-unit id="Audio &amp; video calls" xml:space="preserve" approved="no">
<source>Audio &amp; video calls</source> <source>Audio &amp; video calls</source>
<target state="translated">Chamadas de áudio e vídeo</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Audio and video calls" xml:space="preserve"> <trans-unit id="Audio and video calls" xml:space="preserve" approved="no">
<source>Audio and video calls</source> <source>Audio and video calls</source>
<target state="translated">Chamadas de áudio e vídeo</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Audio/video calls" xml:space="preserve"> <trans-unit id="Audio/video calls" xml:space="preserve" approved="no">
<source>Audio/video calls</source> <source>Audio/video calls</source>
<target state="translated">Chamadas de áudio/vídeo</target>
<note>chat feature</note> <note>chat feature</note>
</trans-unit> </trans-unit>
<trans-unit id="Audio/video calls are prohibited." xml:space="preserve"> <trans-unit id="Audio/video calls are prohibited." xml:space="preserve" approved="no">
<source>Audio/video calls are prohibited.</source> <source>Audio/video calls are prohibited.</source>
<target state="translated">Chamadas de áudio/vídeo são proibidas.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Authentication cancelled" xml:space="preserve"> <trans-unit id="Authentication cancelled" xml:space="preserve" approved="no">
<source>Authentication cancelled</source> <source>Authentication cancelled</source>
<target state="translated">Autenticação cancelada</target>
<note>PIN entry</note> <note>PIN entry</note>
</trans-unit> </trans-unit>
<trans-unit id="Authentication failed" xml:space="preserve"> <trans-unit id="Authentication failed" xml:space="preserve" approved="no">
<source>Authentication failed</source> <source>Authentication failed</source>
<target state="translated">Falha na autenticação</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Authentication is required before the call is connected, but you may miss calls." xml:space="preserve"> <trans-unit id="Authentication is required before the call is connected, but you may miss calls." xml:space="preserve" approved="no">
<source>Authentication is required before the call is connected, but you may miss calls.</source> <source>Authentication is required before the call is connected, but you may miss calls.</source>
<target state="translated">A autenticação é necessária antes que a chamada seja conectada, mas você pode perder chamadas.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Authentication unavailable" xml:space="preserve"> <trans-unit id="Authentication unavailable" xml:space="preserve" approved="no">
<source>Authentication unavailable</source> <source>Authentication unavailable</source>
<target state="translated">Autenticação indisponível</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Auto-accept contact requests" xml:space="preserve"> <trans-unit id="Auto-accept contact requests" xml:space="preserve" approved="no">
<source>Auto-accept contact requests</source> <source>Auto-accept contact requests</source>
<target state="translated">Aceitar solicitações de contato automaticamente</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Auto-accept images" xml:space="preserve"> <trans-unit id="Auto-accept images" xml:space="preserve">
@@ -545,160 +610,197 @@ Available in v5.1</source>
<source>Can't delete user profile!</source> <source>Can't delete user profile!</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Can't invite contact!" xml:space="preserve"> <trans-unit id="Can't invite contact!" xml:space="preserve" approved="no">
<source>Can't invite contact!</source> <source>Can't invite contact!</source>
<target state="translated">Não é possível convidar contato!</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Can't invite contacts!" xml:space="preserve"> <trans-unit id="Can't invite contacts!" xml:space="preserve" approved="no">
<source>Can't invite contacts!</source> <source>Can't invite contacts!</source>
<target state="translated">Não é possível convidar contatos!</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Cancel" xml:space="preserve"> <trans-unit id="Cancel" xml:space="preserve" approved="no">
<source>Cancel</source> <source>Cancel</source>
<target state="translated">Cancelar</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Cannot access keychain to save database password" xml:space="preserve"> <trans-unit id="Cannot access keychain to save database password" xml:space="preserve" approved="no">
<source>Cannot access keychain to save database password</source> <source>Cannot access keychain to save database password</source>
<target state="translated">Não é possível acessar as chaves para salvar a senha do banco de dados</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Cannot receive file" xml:space="preserve"> <trans-unit id="Cannot receive file" xml:space="preserve" approved="no">
<source>Cannot receive file</source> <source>Cannot receive file</source>
<target state="translated">Não é possível receber o arquivo</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Change" xml:space="preserve"> <trans-unit id="Change" xml:space="preserve" approved="no">
<source>Change</source> <source>Change</source>
<target state="translated">Mudar</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Change passcode" xml:space="preserve"> <trans-unit id="Change passcode" xml:space="preserve">
<source>Change passcode</source> <source>Change passcode</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Change database passphrase?" xml:space="preserve"> <trans-unit id="Change database passphrase?" xml:space="preserve" approved="no">
<source>Change database passphrase?</source> <source>Change database passphrase?</source>
<target state="translated">Alterar a senha do banco de dados?</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Change lock mode" xml:space="preserve"> <trans-unit id="Change lock mode" xml:space="preserve" approved="no">
<source>Change lock mode</source> <source>Change lock mode</source>
<target state="translated">Alterar modo de bloqueio</target>
<note>authentication reason</note> <note>authentication reason</note>
</trans-unit> </trans-unit>
<trans-unit id="Change member role?" xml:space="preserve"> <trans-unit id="Change member role?" xml:space="preserve" approved="no">
<source>Change member role?</source> <source>Change member role?</source>
<target state="translated">Alterar a função do membro?</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Change passcode" xml:space="preserve"> <trans-unit id="Change passcode" xml:space="preserve" approved="no">
<source>Change passcode</source> <source>Change passcode</source>
<target state="translated">Alterar senha</target>
<note>authentication reason</note> <note>authentication reason</note>
</trans-unit> </trans-unit>
<trans-unit id="Change receiving address" xml:space="preserve"> <trans-unit id="Change receiving address" xml:space="preserve" approved="no">
<source>Change receiving address</source> <source>Change receiving address</source>
<target state="translated">Alterar endereço de recebimento</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Change receiving address?" xml:space="preserve"> <trans-unit id="Change receiving address?" xml:space="preserve" approved="no">
<source>Change receiving address?</source> <source>Change receiving address?</source>
<target state="translated">Alterar endereço de recebimento?</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Change role" xml:space="preserve"> <trans-unit id="Change role" xml:space="preserve" approved="no">
<source>Change role</source> <source>Change role</source>
<target state="translated">Mudar função</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Chat archive" xml:space="preserve"> <trans-unit id="Chat archive" xml:space="preserve" approved="no">
<source>Chat archive</source> <source>Chat archive</source>
<target state="translated">Arquivar conversa</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Chat console" xml:space="preserve"> <trans-unit id="Chat console" xml:space="preserve" approved="no">
<source>Chat console</source> <source>Chat console</source>
<target state="translated">Console da conversa</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Chat database" xml:space="preserve"> <trans-unit id="Chat database" xml:space="preserve" approved="no">
<source>Chat database</source> <source>Chat database</source>
<target state="translated">Banco de Dados da conversa</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Chat database deleted" xml:space="preserve"> <trans-unit id="Chat database deleted" xml:space="preserve" approved="no">
<source>Chat database deleted</source> <source>Chat database deleted</source>
<target state="translated">Banco de Dados da conversa apagado</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Chat database imported" xml:space="preserve"> <trans-unit id="Chat database imported" xml:space="preserve" approved="no">
<source>Chat database imported</source> <source>Chat database imported</source>
<target state="translated">Banco de Dados da conversa importado</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Chat is running" xml:space="preserve"> <trans-unit id="Chat is running" xml:space="preserve" approved="no">
<source>Chat is running</source> <source>Chat is running</source>
<target state="translated">A conversa está em execução</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Chat is stopped" xml:space="preserve"> <trans-unit id="Chat is stopped" xml:space="preserve">
<source>Chat is stopped</source> <source>Chat is stopped</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Chat preferences" xml:space="preserve"> <trans-unit id="Chat preferences" xml:space="preserve" approved="no">
<source>Chat preferences</source> <source>Chat preferences</source>
<target state="translated">Preferências da conversa</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Chats" xml:space="preserve"> <trans-unit id="Chats" xml:space="preserve" approved="no">
<source>Chats</source> <source>Chats</source>
<target state="translated">Conversas</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Check server address and try again." xml:space="preserve"> <trans-unit id="Check server address and try again." xml:space="preserve" approved="no">
<source>Check server address and try again.</source> <source>Check server address and try again.</source>
<target state="translated">Verifique o endereço do servidor e tente novamente.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Chinese and Spanish interface" xml:space="preserve"> <trans-unit id="Chinese and Spanish interface" xml:space="preserve" approved="no">
<source>Chinese and Spanish interface</source> <source>Chinese and Spanish interface</source>
<target state="translated">Interface em Chinês e Espanhol</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Choose file" xml:space="preserve"> <trans-unit id="Choose file" xml:space="preserve" approved="no">
<source>Choose file</source> <source>Choose file</source>
<target state="translated">Escolher arquivo</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Choose from library" xml:space="preserve"> <trans-unit id="Choose from library" xml:space="preserve" approved="no">
<source>Choose from library</source> <source>Choose from library</source>
<target state="translated">Escolha da biblioteca</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Clear" xml:space="preserve"> <trans-unit id="Clear" xml:space="preserve" approved="no">
<source>Clear</source> <source>Clear</source>
<target state="translated">Limpar</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Clear conversation" xml:space="preserve"> <trans-unit id="Clear conversation" xml:space="preserve" approved="no">
<source>Clear conversation</source> <source>Clear conversation</source>
<target state="translated">Limpar conversa</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Clear conversation?" xml:space="preserve"> <trans-unit id="Clear conversation?" xml:space="preserve" approved="no">
<source>Clear conversation?</source> <source>Clear conversation?</source>
<target state="translated">Limpar conversa?</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Clear verification" xml:space="preserve"> <trans-unit id="Clear verification" xml:space="preserve" approved="no">
<source>Clear verification</source> <source>Clear verification</source>
<target state="translated">Limpar verificação</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Colors" xml:space="preserve"> <trans-unit id="Colors" xml:space="preserve" approved="no">
<source>Colors</source> <source>Colors</source>
<target state="translated">Cores</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Compare file" xml:space="preserve"> <trans-unit id="Compare file" xml:space="preserve" approved="no">
<source>Compare file</source> <source>Compare file</source>
<target state="translated">Comparar arquivo</target>
<note>server test step</note> <note>server test step</note>
</trans-unit> </trans-unit>
<trans-unit id="Compare security codes with your contacts." xml:space="preserve"> <trans-unit id="Compare security codes with your contacts." xml:space="preserve" approved="no">
<source>Compare security codes with your contacts.</source> <source>Compare security codes with your contacts.</source>
<target state="translated">Compare os códigos de segurança com seus contatos.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Configure ICE servers" xml:space="preserve"> <trans-unit id="Configure ICE servers" xml:space="preserve" approved="no">
<source>Configure ICE servers</source> <source>Configure ICE servers</source>
<target state="translated">Configurar servidores ICE</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Confirm" xml:space="preserve"> <trans-unit id="Confirm" xml:space="preserve" approved="no">
<source>Confirm</source> <source>Confirm</source>
<target state="translated">Confirme</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Confirm Passcode" xml:space="preserve"> <trans-unit id="Confirm Passcode" xml:space="preserve" approved="no">
<source>Confirm Passcode</source> <source>Confirm Passcode</source>
<target state="translated">Confirmar senha</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Confirm database upgrades" xml:space="preserve"> <trans-unit id="Confirm database upgrades" xml:space="preserve" approved="no">
<source>Confirm database upgrades</source> <source>Confirm database upgrades</source>
<target state="translated">Confirmar atualizações do banco de dados</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Confirm new passphrase…" xml:space="preserve"> <trans-unit id="Confirm new passphrase…" xml:space="preserve" approved="no">
<source>Confirm new passphrase…</source> <source>Confirm new passphrase…</source>
<target state="translated">Confirme a nova senha…</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Confirm password" xml:space="preserve"> <trans-unit id="Confirm password" xml:space="preserve">
@@ -4162,6 +4264,282 @@ SimpleX servers cannot see your profile.</source>
<source>\~strike~</source> <source>\~strike~</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="## In reply to" xml:space="preserve" approved="no">
<source>## In reply to</source>
<target state="translated">## Em resposta a</target>
<note>copied message info</note>
</trans-unit>
<trans-unit id="%@ uploaded" xml:space="preserve" approved="no">
<source>%@ uploaded</source>
<target state="translated">%@ enviado</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%d weeks" xml:space="preserve" approved="no">
<source>%d weeks</source>
<target state="translated">%d semanas</target>
<note>time interval</note>
</trans-unit>
<trans-unit id="%lld messages blocked by admin" xml:space="preserve" approved="no">
<source>%lld messages blocked by admin</source>
<target state="translated">%lld mensagens bloqueadas pelo administrador</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%lld new interface languages" xml:space="preserve" approved="no">
<source>%lld new interface languages</source>
<target state="translated">%lld novas interface de idiomas</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="**Add contact**: to create a new invitation link, or connect via a link you received." xml:space="preserve" approved="no">
<source>**Add contact**: to create a new invitation link, or connect via a link you received.</source>
<target state="translated">**Adicionar contato**: para criar um novo link de convite ou conectar-se por meio de um link que você recebeu.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="**Create group**: to create a new group." xml:space="preserve" approved="no">
<source>**Create group**: to create a new group.</source>
<target state="translated">**Criar grupo**: para criar um novo grupo.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="**Please note**: using the same database on two devices will break the decryption of messages from your connections, as a security protection." xml:space="preserve" approved="no">
<source>**Please note**: using the same database on two devices will break the decryption of messages from your connections, as a security protection.</source>
<target state="translated">**Observação**: usar o mesmo banco de dados em dois dispositivos interromperá a descriptografia de mensagens de suas conexões, como proteção de segurança.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="## History" xml:space="preserve" approved="no">
<source>## History</source>
<target state="translated">## Histórico</target>
<note>copied message info</note>
</trans-unit>
<trans-unit id="**Warning**: the archive will be removed." xml:space="preserve" approved="no">
<source>**Warning**: the archive will be removed.</source>
<target state="translated">**Atenção**: O arquivo será removido.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ and %@" xml:space="preserve" approved="no">
<source>%@ and %@</source>
<target state="translated">%@ e %@</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ and %@ connected" xml:space="preserve" approved="no">
<source>%@ and %@ connected</source>
<target state="translated">%@ e %@ conectado</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ at %@:" xml:space="preserve" approved="no">
<source>%1$@ at %2$@:</source>
<target state="translated">%1$@ em %2$@:</target>
<note>copied message info, &lt;sender&gt; at &lt;time&gt;</note>
</trans-unit>
<trans-unit id="%@ connected" xml:space="preserve" approved="no">
<source>%@ connected</source>
<target state="translated">%@ conectado</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@, %@ and %lld members" xml:space="preserve" approved="no">
<source>%@, %@ and %lld members</source>
<target state="translated">%@, %@ e %lld membros</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@, %@ and %lld other members connected" xml:space="preserve" approved="no">
<source>%@, %@ and %lld other members connected</source>
<target state="translated">%@, %@ e %lld outros membros conectados</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%lld group events" xml:space="preserve" approved="no">
<source>%lld group events</source>
<target state="translated">%lld eventos de grupo</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%lld messages marked deleted" xml:space="preserve" approved="no">
<source>%lld messages marked deleted</source>
<target state="translated">%lld mensagens marcadas como excluídas</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%lld messages blocked" xml:space="preserve" approved="no">
<source>%lld messages blocked</source>
<target state="translated">%lld mensagens bloqueadas</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%lld messages moderated by %@" xml:space="preserve" approved="no">
<source>%lld messages moderated by %@</source>
<target state="translated">%lld mensagens moderadas por %@</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(this device v%@)" xml:space="preserve" approved="no">
<source>(this device v%@)</source>
<target state="translated">(este dispositivo v%@)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All data is erased when it is entered." xml:space="preserve" approved="no">
<source>All data is erased when it is entered.</source>
<target state="translated">Todos os dados são apagados quando são inseridos.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow irreversible message deletion only if your contact allows it to you. (24 hours)" xml:space="preserve" approved="no">
<source>Allow irreversible message deletion only if your contact allows it to you. (24 hours)</source>
<target state="translated">Permita a exclusão irreversível de mensagens somente se o seu contato permitir. (24 horas)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Apply" xml:space="preserve" approved="no">
<source>Apply</source>
<target state="translated">Aplicar</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive and upload" xml:space="preserve" approved="no">
<source>Archive and upload</source>
<target state="translated">Arquivar e fazer envio</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All new messages from %@ will be hidden!" xml:space="preserve" approved="no">
<source>All new messages from %@ will be hidden!</source>
<target state="translated">Todas as novas mensagens de %@ ficarão ocultas!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Already connecting!" xml:space="preserve" approved="no">
<source>Already connecting!</source>
<target state="translated">Já conectando!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="App encrypts new local files (except videos)." xml:space="preserve" approved="no">
<source>App encrypts new local files (except videos).</source>
<target state="translated">O aplicativo criptografa novos arquivos locais (exceto vídeos).</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="App passcode is replaced with self-destruct passcode." xml:space="preserve" approved="no">
<source>App passcode is replaced with self-destruct passcode.</source>
<target state="translated">A senha do Aplicativo é substituída pela senha de autodestruição.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve" approved="no">
<source>All your contacts will remain connected.</source>
<target state="translated">Todos os seus contatos permanecerão conectados.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected. Profile update will be sent to your contacts." xml:space="preserve" approved="no">
<source>All your contacts will remain connected. Profile update will be sent to your contacts.</source>
<target state="translated">Todos os seus contatos permanecerão conectados. A atualização do perfil será enviada para seus contatos.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send files and media." xml:space="preserve" approved="no">
<source>Allow to send files and media.</source>
<target state="translated">Permitir o envio de arquivos e mídia.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="App data migration" xml:space="preserve" approved="no">
<source>App data migration</source>
<target state="translated">Migração de dados de aplicativos</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archiving database" xml:space="preserve" approved="no">
<source>Archiving database</source>
<target state="translated">Arquivando banco de dados</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All messages will be deleted - this cannot be undone!" xml:space="preserve" approved="no">
<source>All messages will be deleted - this cannot be undone!</source>
<target state="translated">Todas as mensagens serão apagadas isso não pode ser desfeito!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts, conversations and files will be securely encrypted and uploaded in chunks to configured XFTP relays." xml:space="preserve" approved="no">
<source>All your contacts, conversations and files will be securely encrypted and uploaded in chunks to configured XFTP relays.</source>
<target state="translated">Todos os seus contatos, conversas e arquivos serão criptografados com segurança e enviados em partes para retransmissões XFTP configuradas.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow message reactions only if your contact allows them." xml:space="preserve" approved="no">
<source>Allow message reactions only if your contact allows them.</source>
<target state="translated">Permita reações às mensagens somente se o seu contato permitir.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow message reactions." xml:space="preserve" approved="no">
<source>Allow message reactions.</source>
<target state="translated">Permitir reações às mensagens.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow your contacts to irreversibly delete sent messages. (24 hours)" xml:space="preserve" approved="no">
<source>Allow your contacts to irreversibly delete sent messages. (24 hours)</source>
<target state="translated">Permita que seus contatos apaguem irreversivelmente as mensagens enviadas. (24 horas)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Already joining the group!" xml:space="preserve" approved="no">
<source>Already joining the group!</source>
<target state="translated">Entrando no grupo!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="An empty chat profile with the provided name is created, and the app opens as usual." xml:space="preserve" approved="no">
<source>An empty chat profile with the provided name is created, and the app opens as usual.</source>
<target state="translated">Um perfil de conversa vazio com o nome fornecido é criado e o aplicativo abre normalmente.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Auto-accept" xml:space="preserve" approved="no">
<source>Auto-accept</source>
<target state="translated">Aceitar automaticamente</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow your contacts adding message reactions." xml:space="preserve" approved="no">
<source>Allow your contacts adding message reactions.</source>
<target state="translated">Permita que seus contatos adicionem reações às mensagens.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to irreversibly delete sent messages. (24 hours)" xml:space="preserve" approved="no">
<source>Allow to irreversibly delete sent messages. (24 hours)</source>
<target state="translated">Permitir apagar irreversivelmente as mensagens enviadas. (24 horas)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Choose _Migrate from another device_ on the new device and scan QR code." xml:space="preserve" approved="no">
<source>Choose _Migrate from another device_ on the new device and scan QR code.</source>
<target state="translated">Escolha _Migrar de outro dispositivo_ no novo dispositivo e leia o código QR.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Cancel migration" xml:space="preserve" approved="no">
<source>Cancel migration</source>
<target state="translated">Cancelar migração</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Camera not available" xml:space="preserve" approved="no">
<source>Camera not available</source>
<target state="translated">Câmera não disponível</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Change self-destruct passcode" xml:space="preserve" approved="no">
<source>Change self-destruct passcode</source>
<target state="translated">Alterar a senha de autodestruição</target>
<note>authentication reason
set passcode view</note>
</trans-unit>
<trans-unit id="Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat." xml:space="preserve" approved="no">
<source>Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat.</source>
<target state="translated">A conversa foi interrompida. Se você já usou esse banco de dados em outro dispositivo, deverá transferi-lo de volta antes de iniciar a conversa.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Chat migrated!" xml:space="preserve" approved="no">
<source>Chat migrated!</source>
<target state="translated">Conversa migrada!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Clear private notes?" xml:space="preserve" approved="no">
<source>Clear private notes?</source>
<target state="translated">Limpar notas privadas?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirm network settings" xml:space="preserve" approved="no">
<source>Confirm network settings</source>
<target state="translated">Confirme as configurações de rede</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirm that you remember database passphrase to migrate it." xml:space="preserve" approved="no">
<source>Confirm that you remember database passphrase to migrate it.</source>
<target state="translated">Confirme se você se lembra da senha do banco de dados para migrá-lo.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Change self-destruct mode" xml:space="preserve" approved="no">
<source>Change self-destruct mode</source>
<target state="translated">Alterar modo de autodestruição</target>
<note>authentication reason</note>
</trans-unit>
<trans-unit id="Confirm upload" xml:space="preserve" approved="no">
<source>Confirm upload</source>
<target state="translated">Confirmar envio</target>
<note>No comment provided by engineer.</note>
</trans-unit>
</body> </body>
</file> </file>
<file original="en.lproj/SimpleX--iOS--InfoPlist.strings" source-language="en" target-language="pt" datatype="plaintext"> <file original="en.lproj/SimpleX--iOS--InfoPlist.strings" source-language="en" target-language="pt" datatype="plaintext">
File diff suppressed because it is too large Load Diff
@@ -101,6 +101,10 @@
<source>%@ connected</source> <source>%@ connected</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="%@ downloaded" xml:space="preserve">
<source>%@ downloaded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ is connected!" xml:space="preserve"> <trans-unit id="%@ is connected!" xml:space="preserve">
<source>%@ is connected!</source> <source>%@ is connected!</source>
<target>%@ เชื่อมต่อสำเร็จ!</target> <target>%@ เชื่อมต่อสำเร็จ!</target>
@@ -121,6 +125,10 @@
<target>%@ เซิร์ฟเวอร์</target> <target>%@ เซิร์ฟเวอร์</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="%@ uploaded" xml:space="preserve">
<source>%@ uploaded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ wants to connect!" xml:space="preserve"> <trans-unit id="%@ wants to connect!" xml:space="preserve">
<source>%@ wants to connect!</source> <source>%@ wants to connect!</source>
<target>%@ อยากเชื่อมต่อ!</target> <target>%@ อยากเชื่อมต่อ!</target>
@@ -324,6 +332,10 @@
<target>**ส่วนตัวที่สุด**: ไม่ใช้เซิร์ฟเวอร์การแจ้งเตือนของ SimpleX Chat ตรวจสอบข้อความเป็นระยะในพื้นหลัง (ขึ้นอยู่กับความถี่ที่คุณใช้แอป)</target> <target>**ส่วนตัวที่สุด**: ไม่ใช้เซิร์ฟเวอร์การแจ้งเตือนของ SimpleX Chat ตรวจสอบข้อความเป็นระยะในพื้นหลัง (ขึ้นอยู่กับความถี่ที่คุณใช้แอป)</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="**Please note**: using the same database on two devices will break the decryption of messages from your connections, as a security protection." xml:space="preserve">
<source>**Please note**: using the same database on two devices will break the decryption of messages from your connections, as a security protection.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="**Please note**: you will NOT be able to recover or change passphrase if you lose it." xml:space="preserve"> <trans-unit id="**Please note**: you will NOT be able to recover or change passphrase if you lose it." xml:space="preserve">
<source>**Please note**: you will NOT be able to recover or change passphrase if you lose it.</source> <source>**Please note**: you will NOT be able to recover or change passphrase if you lose it.</source>
<target>**โปรดทราบ**: คุณจะไม่สามารถกู้คืนหรือเปลี่ยนรหัสผ่านได้หากคุณทำรหัสผ่านหาย</target> <target>**โปรดทราบ**: คุณจะไม่สามารถกู้คืนหรือเปลี่ยนรหัสผ่านได้หากคุณทำรหัสผ่านหาย</target>
@@ -339,6 +351,10 @@
<target>**คำเตือน**: การแจ้งเตือนแบบพุชทันทีจำเป็นต้องบันทึกรหัสผ่านไว้ใน Keychain</target> <target>**คำเตือน**: การแจ้งเตือนแบบพุชทันทีจำเป็นต้องบันทึกรหัสผ่านไว้ใน Keychain</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="**Warning**: the archive will be removed." xml:space="preserve">
<source>**Warning**: the archive will be removed.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="**e2e encrypted** audio call" xml:space="preserve"> <trans-unit id="**e2e encrypted** audio call" xml:space="preserve">
<source>**e2e encrypted** audio call</source> <source>**e2e encrypted** audio call</source>
<target>การโทรเสียงแบบ **encrypted จากต้นจนจบ**</target> <target>การโทรเสียงแบบ **encrypted จากต้นจนจบ**</target>
@@ -585,6 +601,10 @@
<target>การเปลี่ยนแปลงที่อยู่จะถูกยกเลิก จะใช้ที่อยู่เก่าของผู้รับ</target> <target>การเปลี่ยนแปลงที่อยู่จะถูกยกเลิก จะใช้ที่อยู่เก่าของผู้รับ</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Admins can block a member for all." xml:space="preserve">
<source>Admins can block a member for all.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Admins can create the links to join groups." xml:space="preserve"> <trans-unit id="Admins can create the links to join groups." xml:space="preserve">
<source>Admins can create the links to join groups.</source> <source>Admins can create the links to join groups.</source>
<target>ผู้ดูแลระบบสามารถสร้างลิงก์เพื่อเข้าร่วมกลุ่มต่างๆได้</target> <target>ผู้ดูแลระบบสามารถสร้างลิงก์เพื่อเข้าร่วมกลุ่มต่างๆได้</target>
@@ -638,6 +658,10 @@
<target>ผู้ติดต่อทั้งหมดของคุณจะยังคงเชื่อมต่ออยู่. ผู้ติดต่อทั้งหมดของคุณจะยังคงเชื่อมต่ออยู่ การอัปเดตโปรไฟล์จะถูกส่งไปยังผู้ติดต่อของคุณ.</target> <target>ผู้ติดต่อทั้งหมดของคุณจะยังคงเชื่อมต่ออยู่. ผู้ติดต่อทั้งหมดของคุณจะยังคงเชื่อมต่ออยู่ การอัปเดตโปรไฟล์จะถูกส่งไปยังผู้ติดต่อของคุณ.</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="All your contacts, conversations and files will be securely encrypted and uploaded in chunks to configured XFTP relays." xml:space="preserve">
<source>All your contacts, conversations and files will be securely encrypted and uploaded in chunks to configured XFTP relays.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow" xml:space="preserve"> <trans-unit id="Allow" xml:space="preserve">
<source>Allow</source> <source>Allow</source>
<target>อนุญาต</target> <target>อนุญาต</target>
@@ -683,6 +707,10 @@
<target>อนุญาตให้ลบข้อความที่ส่งไปแล้วอย่างถาวร</target> <target>อนุญาตให้ลบข้อความที่ส่งไปแล้วอย่างถาวร</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
<source>Allow to send SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send files and media." xml:space="preserve"> <trans-unit id="Allow to send files and media." xml:space="preserve">
<source>Allow to send files and media.</source> <source>Allow to send files and media.</source>
<target>อนุญาตให้ส่งไฟล์และสื่อ</target> <target>อนุญาตให้ส่งไฟล์และสื่อ</target>
@@ -761,6 +789,10 @@
<target>รุ่นแอป: %@</target> <target>รุ่นแอป: %@</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="App data migration" xml:space="preserve">
<source>App data migration</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="App encrypts new local files (except videos)." xml:space="preserve"> <trans-unit id="App encrypts new local files (except videos)." xml:space="preserve">
<source>App encrypts new local files (except videos).</source> <source>App encrypts new local files (except videos).</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
@@ -795,6 +827,18 @@
<target>รูปร่างลักษณะ</target> <target>รูปร่างลักษณะ</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Apply" xml:space="preserve">
<source>Apply</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archive and upload" xml:space="preserve">
<source>Archive and upload</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Archiving database" xml:space="preserve">
<source>Archiving database</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Attach" xml:space="preserve"> <trans-unit id="Attach" xml:space="preserve">
<source>Attach</source> <source>Attach</source>
<target>แนบ</target> <target>แนบ</target>
@@ -974,6 +1018,10 @@
<target>ยกเลิก</target> <target>ยกเลิก</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Cancel migration" xml:space="preserve">
<source>Cancel migration</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Cannot access keychain to save database password" xml:space="preserve"> <trans-unit id="Cannot access keychain to save database password" xml:space="preserve">
<source>Cannot access keychain to save database password</source> <source>Cannot access keychain to save database password</source>
<target>ไม่สามารถเข้าถึง keychain เพื่อบันทึกรหัสผ่านฐานข้อมูล</target> <target>ไม่สามารถเข้าถึง keychain เพื่อบันทึกรหัสผ่านฐานข้อมูล</target>
@@ -984,6 +1032,10 @@
<target>ไม่สามารถรับไฟล์ได้</target> <target>ไม่สามารถรับไฟล์ได้</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Cellular" xml:space="preserve">
<source>Cellular</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Change" xml:space="preserve"> <trans-unit id="Change" xml:space="preserve">
<source>Change</source> <source>Change</source>
<target>เปลี่ยน</target> <target>เปลี่ยน</target>
@@ -1074,6 +1126,10 @@
<source>Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat.</source> <source>Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat.</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Chat migrated!" xml:space="preserve">
<source>Chat migrated!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Chat preferences" xml:space="preserve"> <trans-unit id="Chat preferences" xml:space="preserve">
<source>Chat preferences</source> <source>Chat preferences</source>
<target>ค่ากําหนดในการแชท</target> <target>ค่ากําหนดในการแชท</target>
@@ -1094,6 +1150,10 @@
<target>อินเทอร์เฟซภาษาจีนและสเปน</target> <target>อินเทอร์เฟซภาษาจีนและสเปน</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Choose _Migrate from another device_ on the new device and scan QR code." xml:space="preserve">
<source>Choose _Migrate from another device_ on the new device and scan QR code.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Choose file" xml:space="preserve"> <trans-unit id="Choose file" xml:space="preserve">
<source>Choose file</source> <source>Choose file</source>
<target>เลือกไฟล์</target> <target>เลือกไฟล์</target>
@@ -1163,6 +1223,10 @@
<target>ยืนยันการอัพเกรดฐานข้อมูล</target> <target>ยืนยันการอัพเกรดฐานข้อมูล</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Confirm network settings" xml:space="preserve">
<source>Confirm network settings</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirm new passphrase…" xml:space="preserve"> <trans-unit id="Confirm new passphrase…" xml:space="preserve">
<source>Confirm new passphrase…</source> <source>Confirm new passphrase…</source>
<target>ยืนยันรหัสผ่านใหม่…</target> <target>ยืนยันรหัสผ่านใหม่…</target>
@@ -1173,6 +1237,14 @@
<target>ยืนยันรหัสผ่าน</target> <target>ยืนยันรหัสผ่าน</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Confirm that you remember database passphrase to migrate it." xml:space="preserve">
<source>Confirm that you remember database passphrase to migrate it.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirm upload" xml:space="preserve">
<source>Confirm upload</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect" xml:space="preserve"> <trans-unit id="Connect" xml:space="preserve">
<source>Connect</source> <source>Connect</source>
<target>เชื่อมต่อ</target> <target>เชื่อมต่อ</target>
@@ -1410,6 +1482,10 @@ This is your own one-time link!</source>
<target>สร้างเมื่อ %@</target> <target>สร้างเมื่อ %@</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Creating archive link" xml:space="preserve">
<source>Creating archive link</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Creating link…" xml:space="preserve"> <trans-unit id="Creating link…" xml:space="preserve">
<source>Creating link…</source> <source>Creating link…</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
@@ -1625,6 +1701,10 @@ This cannot be undone!</source>
<target>ลบฐานข้อมูล</target> <target>ลบฐานข้อมูล</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Delete database from this device" xml:space="preserve">
<source>Delete database from this device</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete file" xml:space="preserve"> <trans-unit id="Delete file" xml:space="preserve">
<source>Delete file</source> <source>Delete file</source>
<target>ลบไฟล์</target> <target>ลบไฟล์</target>
@@ -1907,11 +1987,27 @@ This cannot be undone!</source>
<target>ปรับลดรุ่นและเปิดแชท</target> <target>ปรับลดรุ่นและเปิดแชท</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Download" xml:space="preserve">
<source>Download</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Download failed" xml:space="preserve">
<source>Download failed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Download file" xml:space="preserve"> <trans-unit id="Download file" xml:space="preserve">
<source>Download file</source> <source>Download file</source>
<target>ดาวน์โหลดไฟล์</target> <target>ดาวน์โหลดไฟล์</target>
<note>server test step</note> <note>server test step</note>
</trans-unit> </trans-unit>
<trans-unit id="Downloading archive" xml:space="preserve">
<source>Downloading archive</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Downloading link details" xml:space="preserve">
<source>Downloading link details</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Duplicate display name!" xml:space="preserve"> <trans-unit id="Duplicate display name!" xml:space="preserve">
<source>Duplicate display name!</source> <source>Duplicate display name!</source>
<target>ชื่อที่แสดงซ้ำ!</target> <target>ชื่อที่แสดงซ้ำ!</target>
@@ -1966,6 +2062,10 @@ This cannot be undone!</source>
<target>เปิดใช้งานสําหรับทุกคน</target> <target>เปิดใช้งานสําหรับทุกคน</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Enable in direct chats (BETA)!" xml:space="preserve">
<source>Enable in direct chats (BETA)!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enable instant notifications?" xml:space="preserve"> <trans-unit id="Enable instant notifications?" xml:space="preserve">
<source>Enable instant notifications?</source> <source>Enable instant notifications?</source>
<target>เปิดใช้งานการแจ้งเตือนทันที?</target> <target>เปิดใช้งานการแจ้งเตือนทันที?</target>
@@ -1996,6 +2096,10 @@ This cannot be undone!</source>
<target>เปิดใช้งานรหัสผ่านแบบทําลายตัวเอง</target> <target>เปิดใช้งานรหัสผ่านแบบทําลายตัวเอง</target>
<note>set passcode view</note> <note>set passcode view</note>
</trans-unit> </trans-unit>
<trans-unit id="Enabled for" xml:space="preserve">
<source>Enabled for</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Encrypt" xml:space="preserve"> <trans-unit id="Encrypt" xml:space="preserve">
<source>Encrypt</source> <source>Encrypt</source>
<target>Encrypt</target> <target>Encrypt</target>
@@ -2075,6 +2179,10 @@ This cannot be undone!</source>
<source>Enter group name…</source> <source>Enter group name…</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Enter passphrase" xml:space="preserve">
<source>Enter passphrase</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter passphrase…" xml:space="preserve"> <trans-unit id="Enter passphrase…" xml:space="preserve">
<source>Enter passphrase…</source> <source>Enter passphrase…</source>
<target>ใส่รหัสผ่าน</target> <target>ใส่รหัสผ่าน</target>
@@ -2220,6 +2328,10 @@ This cannot be undone!</source>
<target>เกิดข้อผิดพลาดในการลบโปรไฟล์ผู้ใช้</target> <target>เกิดข้อผิดพลาดในการลบโปรไฟล์ผู้ใช้</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Error downloading the archive" xml:space="preserve">
<source>Error downloading the archive</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error enabling delivery receipts!" xml:space="preserve"> <trans-unit id="Error enabling delivery receipts!" xml:space="preserve">
<source>Error enabling delivery receipts!</source> <source>Error enabling delivery receipts!</source>
<target>เกิดข้อผิดพลาดในการเปิดใช้ใบเสร็จการจัดส่ง!</target> <target>เกิดข้อผิดพลาดในการเปิดใช้ใบเสร็จการจัดส่ง!</target>
@@ -2294,6 +2406,10 @@ This cannot be undone!</source>
<target>เกิดข้อผิดพลาดในการบันทึกรหัสผ่านไปยัง keychain</target> <target>เกิดข้อผิดพลาดในการบันทึกรหัสผ่านไปยัง keychain</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Error saving settings" xml:space="preserve">
<source>Error saving settings</source>
<note>when migrating</note>
</trans-unit>
<trans-unit id="Error saving user password" xml:space="preserve"> <trans-unit id="Error saving user password" xml:space="preserve">
<source>Error saving user password</source> <source>Error saving user password</source>
<target>เกิดข้อผิดพลาดในการบันทึกรหัสผ่านผู้ใช้</target> <target>เกิดข้อผิดพลาดในการบันทึกรหัสผ่านผู้ใช้</target>
@@ -2362,6 +2478,14 @@ This cannot be undone!</source>
<target>เกิดข้อผิดพลาดในการอัปเดตข้อมูลส่วนตัวของผู้ใช้</target> <target>เกิดข้อผิดพลาดในการอัปเดตข้อมูลส่วนตัวของผู้ใช้</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Error uploading the archive" xml:space="preserve">
<source>Error uploading the archive</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error verifying passphrase:" xml:space="preserve">
<source>Error verifying passphrase:</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error: " xml:space="preserve"> <trans-unit id="Error: " xml:space="preserve">
<source>Error: </source> <source>Error: </source>
<target>ผิดพลาด: </target> <target>ผิดพลาด: </target>
@@ -2411,6 +2535,10 @@ This cannot be undone!</source>
<target>ที่เก็บถาวรฐานข้อมูลที่ส่งออก</target> <target>ที่เก็บถาวรฐานข้อมูลที่ส่งออก</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Exported file doesn't exist" xml:space="preserve">
<source>Exported file doesn't exist</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Exporting database archive…" xml:space="preserve"> <trans-unit id="Exporting database archive…" xml:space="preserve">
<source>Exporting database archive…</source> <source>Exporting database archive…</source>
<target>กำลังส่งออกที่เก็บถาวรฐานข้อมูล…</target> <target>กำลังส่งออกที่เก็บถาวรฐานข้อมูล…</target>
@@ -2470,6 +2598,10 @@ This cannot be undone!</source>
<target>ไฟล์และสื่อเป็นสิ่งต้องห้ามในกลุ่มนี้</target> <target>ไฟล์และสื่อเป็นสิ่งต้องห้ามในกลุ่มนี้</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Files and media not allowed" xml:space="preserve">
<source>Files and media not allowed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media prohibited!" xml:space="preserve"> <trans-unit id="Files and media prohibited!" xml:space="preserve">
<source>Files and media prohibited!</source> <source>Files and media prohibited!</source>
<target>ไฟล์และสื่อต้องห้าม!</target> <target>ไฟล์และสื่อต้องห้าม!</target>
@@ -2480,6 +2612,14 @@ This cannot be undone!</source>
<target>กรองแชทที่ยังไม่อ่านและแชทโปรด</target> <target>กรองแชทที่ยังไม่อ่านและแชทโปรด</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Finalize migration" xml:space="preserve">
<source>Finalize migration</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Finalize migration on another device." xml:space="preserve">
<source>Finalize migration on another device.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Finally, we have them! 🚀" xml:space="preserve"> <trans-unit id="Finally, we have them! 🚀" xml:space="preserve">
<source>Finally, we have them! 🚀</source> <source>Finally, we have them! 🚀</source>
<target>ในที่สุดเราก็มีแล้ว! 🚀</target> <target>ในที่สุดเราก็มีแล้ว! 🚀</target>
@@ -2525,6 +2665,22 @@ This cannot be undone!</source>
<target>สำหรับคอนโซล</target> <target>สำหรับคอนโซล</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Forward" xml:space="preserve">
<source>Forward</source>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Forward and save messages" xml:space="preserve">
<source>Forward and save messages</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded" xml:space="preserve">
<source>Forwarded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded from" xml:space="preserve">
<source>Forwarded from</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Found desktop" xml:space="preserve"> <trans-unit id="Found desktop" xml:space="preserve">
<source>Found desktop</source> <source>Found desktop</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
@@ -2631,6 +2787,10 @@ This cannot be undone!</source>
<target>สมาชิกกลุ่มสามารถลบข้อความที่ส่งแล้วอย่างถาวร</target> <target>สมาชิกกลุ่มสามารถลบข้อความที่ส่งแล้วอย่างถาวร</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Group members can send SimpleX links." xml:space="preserve">
<source>Group members can send SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send direct messages." xml:space="preserve"> <trans-unit id="Group members can send direct messages." xml:space="preserve">
<source>Group members can send direct messages.</source> <source>Group members can send direct messages.</source>
<target>สมาชิกกลุ่มสามารถส่งข้อความโดยตรงได้</target> <target>สมาชิกกลุ่มสามารถส่งข้อความโดยตรงได้</target>
@@ -2765,6 +2925,10 @@ This cannot be undone!</source>
<target>วิธีใช้เซิร์ฟเวอร์ของคุณ</target> <target>วิธีใช้เซิร์ฟเวอร์ของคุณ</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Hungarian interface" xml:space="preserve">
<source>Hungarian interface</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="ICE servers (one per line)" xml:space="preserve"> <trans-unit id="ICE servers (one per line)" xml:space="preserve">
<source>ICE servers (one per line)</source> <source>ICE servers (one per line)</source>
<target>เซิร์ฟเวอร์ ICE (หนึ่งเครื่องต่อสาย)</target> <target>เซิร์ฟเวอร์ ICE (หนึ่งเครื่องต่อสาย)</target>
@@ -2830,6 +2994,14 @@ This cannot be undone!</source>
<target>นำเข้าฐานข้อมูล</target> <target>นำเข้าฐานข้อมูล</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Import failed" xml:space="preserve">
<source>Import failed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Importing archive" xml:space="preserve">
<source>Importing archive</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Improved message delivery" xml:space="preserve"> <trans-unit id="Improved message delivery" xml:space="preserve">
<source>Improved message delivery</source> <source>Improved message delivery</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
@@ -2844,11 +3016,19 @@ This cannot be undone!</source>
<target>ปรับปรุงการกําหนดค่าเซิร์ฟเวอร์แล้ว</target> <target>ปรับปรุงการกําหนดค่าเซิร์ฟเวอร์แล้ว</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="In order to continue, chat should be stopped." xml:space="preserve">
<source>In order to continue, chat should be stopped.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="In reply to" xml:space="preserve"> <trans-unit id="In reply to" xml:space="preserve">
<source>In reply to</source> <source>In reply to</source>
<target>ในการตอบกลับถึง</target> <target>ในการตอบกลับถึง</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="In-call sounds" xml:space="preserve">
<source>In-call sounds</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Incognito" xml:space="preserve"> <trans-unit id="Incognito" xml:space="preserve">
<source>Incognito</source> <source>Incognito</source>
<target>ไม่ระบุตัวตน</target> <target>ไม่ระบุตัวตน</target>
@@ -2950,6 +3130,10 @@ This cannot be undone!</source>
<source>Invalid link</source> <source>Invalid link</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Invalid migration confirmation" xml:space="preserve">
<source>Invalid migration confirmation</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Invalid name!" xml:space="preserve"> <trans-unit id="Invalid name!" xml:space="preserve">
<source>Invalid name!</source> <source>Invalid name!</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
@@ -3299,11 +3483,19 @@ This is your link for group %@!</source>
<target>ปฏิกิริยาบนข้อความเป็นสิ่งต้องห้ามในกลุ่มนี้</target> <target>ปฏิกิริยาบนข้อความเป็นสิ่งต้องห้ามในกลุ่มนี้</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Message source remains private." xml:space="preserve">
<source>Message source remains private.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message text" xml:space="preserve"> <trans-unit id="Message text" xml:space="preserve">
<source>Message text</source> <source>Message text</source>
<target>ข้อความ</target> <target>ข้อความ</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Message too large" xml:space="preserve">
<source>Message too large</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Messages" xml:space="preserve"> <trans-unit id="Messages" xml:space="preserve">
<source>Messages</source> <source>Messages</source>
<target>ข้อความ</target> <target>ข้อความ</target>
@@ -3318,11 +3510,47 @@ This is your link for group %@!</source>
<source>Messages from %@ will be shown!</source> <source>Messages from %@ will be shown!</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Messages, files and calls are protected by **end-to-end encryption** with perfect forward secrecy, repudiation and break-in recovery." xml:space="preserve">
<source>Messages, files and calls are protected by **end-to-end encryption** with perfect forward secrecy, repudiation and break-in recovery.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Messages, files and calls are protected by **quantum resistant e2e encryption** with perfect forward secrecy, repudiation and break-in recovery." xml:space="preserve">
<source>Messages, files and calls are protected by **quantum resistant e2e encryption** with perfect forward secrecy, repudiation and break-in recovery.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Migrate device" xml:space="preserve">
<source>Migrate device</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Migrate from another device" xml:space="preserve">
<source>Migrate from another device</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Migrate here" xml:space="preserve">
<source>Migrate here</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Migrate to another device" xml:space="preserve">
<source>Migrate to another device</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Migrate to another device via QR code." xml:space="preserve">
<source>Migrate to another device via QR code.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Migrating" xml:space="preserve">
<source>Migrating</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Migrating database archive…" xml:space="preserve"> <trans-unit id="Migrating database archive…" xml:space="preserve">
<source>Migrating database archive…</source> <source>Migrating database archive…</source>
<target>กำลังย้ายข้อมูลที่เก็บถาวรของฐานข้อมูล…</target> <target>กำลังย้ายข้อมูลที่เก็บถาวรของฐานข้อมูล…</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Migration complete" xml:space="preserve">
<source>Migration complete</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Migration error:" xml:space="preserve"> <trans-unit id="Migration error:" xml:space="preserve">
<source>Migration error:</source> <source>Migration error:</source>
<target>ข้อผิดพลาดในการย้ายข้อมูล:</target> <target>ข้อผิดพลาดในการย้ายข้อมูล:</target>
@@ -3363,6 +3591,10 @@ This is your link for group %@!</source>
<target>การปรับปรุงเพิ่มเติมกำลังจะมาเร็ว ๆ นี้!</target> <target>การปรับปรุงเพิ่มเติมกำลังจะมาเร็ว ๆ นี้!</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="More reliable network connection." xml:space="preserve">
<source>More reliable network connection.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Most likely this connection is deleted." xml:space="preserve"> <trans-unit id="Most likely this connection is deleted." xml:space="preserve">
<source>Most likely this connection is deleted.</source> <source>Most likely this connection is deleted.</source>
<note>item status description</note> <note>item status description</note>
@@ -3397,6 +3629,14 @@ This is your link for group %@!</source>
<target>เครือข่ายและเซิร์ฟเวอร์</target> <target>เครือข่ายและเซิร์ฟเวอร์</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Network connection" xml:space="preserve">
<source>Network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Network management" xml:space="preserve">
<source>Network management</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Network settings" xml:space="preserve"> <trans-unit id="Network settings" xml:space="preserve">
<source>Network settings</source> <source>Network settings</source>
<target>การตั้งค่าเครือข่าย</target> <target>การตั้งค่าเครือข่าย</target>
@@ -3504,6 +3744,10 @@ This is your link for group %@!</source>
<target>ไม่มีประวัติ</target> <target>ไม่มีประวัติ</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="No network connection" xml:space="preserve">
<source>No network connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record voice message" xml:space="preserve"> <trans-unit id="No permission to record voice message" xml:space="preserve">
<source>No permission to record voice message</source> <source>No permission to record voice message</source>
<target>ไม่อนุญาตให้บันทึกข้อความเสียง</target> <target>ไม่อนุญาตให้บันทึกข้อความเสียง</target>
@@ -3674,6 +3918,10 @@ This is your link for group %@!</source>
<source>Open group</source> <source>Open group</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Open migration to another device" xml:space="preserve">
<source>Open migration to another device</source>
<note>authentication reason</note>
</trans-unit>
<trans-unit id="Open user profiles" xml:space="preserve"> <trans-unit id="Open user profiles" xml:space="preserve">
<source>Open user profiles</source> <source>Open user profiles</source>
<target>เปิดโปรไฟล์ผู้ใช้</target> <target>เปิดโปรไฟล์ผู้ใช้</target>
@@ -3688,14 +3936,26 @@ This is your link for group %@!</source>
<source>Opening app…</source> <source>Opening app…</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Or paste archive link" xml:space="preserve">
<source>Or paste archive link</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Or scan QR code" xml:space="preserve"> <trans-unit id="Or scan QR code" xml:space="preserve">
<source>Or scan QR code</source> <source>Or scan QR code</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Or securely share this file link" xml:space="preserve">
<source>Or securely share this file link</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Or show this code" xml:space="preserve"> <trans-unit id="Or show this code" xml:space="preserve">
<source>Or show this code</source> <source>Or show this code</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Other" xml:space="preserve">
<source>Other</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve"> <trans-unit id="PING count" xml:space="preserve">
<source>PING count</source> <source>PING count</source>
<target>จํานวน PING</target> <target>จํานวน PING</target>
@@ -3772,6 +4032,10 @@ This is your link for group %@!</source>
<target>ข้อผิดพลาดในการถอดรหัสอย่างถาวร</target> <target>ข้อผิดพลาดในการถอดรหัสอย่างถาวร</target>
<note>message decrypt error item</note> <note>message decrypt error item</note>
</trans-unit> </trans-unit>
<trans-unit id="Picture-in-picture calls" xml:space="preserve">
<source>Picture-in-picture calls</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Please ask your contact to enable sending voice messages." xml:space="preserve"> <trans-unit id="Please ask your contact to enable sending voice messages." xml:space="preserve">
<source>Please ask your contact to enable sending voice messages.</source> <source>Please ask your contact to enable sending voice messages.</source>
<target>โปรดขอให้ผู้ติดต่อของคุณเปิดใช้งานการส่งข้อความเสียง</target> <target>โปรดขอให้ผู้ติดต่อของคุณเปิดใช้งานการส่งข้อความเสียง</target>
@@ -3792,6 +4056,10 @@ This is your link for group %@!</source>
<target>โปรดตรวจสอบความต้องการของคุณและการตั้งค่าผู้ติดต่อ</target> <target>โปรดตรวจสอบความต้องการของคุณและการตั้งค่าผู้ติดต่อ</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Please confirm that network settings are correct for this device." xml:space="preserve">
<source>Please confirm that network settings are correct for this device.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Please contact developers.&#10;Error: %@" xml:space="preserve"> <trans-unit id="Please contact developers.&#10;Error: %@" xml:space="preserve">
<source>Please contact developers. <source>Please contact developers.
Error: %@</source> Error: %@</source>
@@ -3896,6 +4164,10 @@ Error: %@</source>
<target>รูปโปรไฟล์</target> <target>รูปโปรไฟล์</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Profile images" xml:space="preserve">
<source>Profile images</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile name" xml:space="preserve"> <trans-unit id="Profile name" xml:space="preserve">
<source>Profile name</source> <source>Profile name</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
@@ -3934,6 +4206,10 @@ Error: %@</source>
<target>ห้ามแสดงปฏิกิริยาต่อข้อความ</target> <target>ห้ามแสดงปฏิกิริยาต่อข้อความ</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
<source>Prohibit sending SimpleX links.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending direct messages to members." xml:space="preserve"> <trans-unit id="Prohibit sending direct messages to members." xml:space="preserve">
<source>Prohibit sending direct messages to members.</source> <source>Prohibit sending direct messages to members.</source>
<target>ห้ามส่งข้อความโดยตรงถึงสมาชิก</target> <target>ห้ามส่งข้อความโดยตรงถึงสมาชิก</target>
@@ -3979,6 +4255,14 @@ Error: %@</source>
<target>การแจ้งเตือนแบบทันที</target> <target>การแจ้งเตือนแบบทันที</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Push server" xml:space="preserve">
<source>Push server</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Quantum resistant encryption" xml:space="preserve">
<source>Quantum resistant encryption</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Rate the app" xml:space="preserve"> <trans-unit id="Rate the app" xml:space="preserve">
<source>Rate the app</source> <source>Rate the app</source>
<target>ให้คะแนนแอป</target> <target>ให้คะแนนแอป</target>
@@ -4052,6 +4336,10 @@ Error: %@</source>
<target>ที่อยู่ผู้รับจะถูกเปลี่ยนเป็นเซิร์ฟเวอร์อื่น การเปลี่ยนแปลงที่อยู่จะเสร็จสมบูรณ์หลังจากที่ผู้ส่งออนไลน์</target> <target>ที่อยู่ผู้รับจะถูกเปลี่ยนเป็นเซิร์ฟเวอร์อื่น การเปลี่ยนแปลงที่อยู่จะเสร็จสมบูรณ์หลังจากที่ผู้ส่งออนไลน์</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Receiving concurrency" xml:space="preserve">
<source>Receiving concurrency</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Receiving file will be stopped." xml:space="preserve"> <trans-unit id="Receiving file will be stopped." xml:space="preserve">
<source>Receiving file will be stopped.</source> <source>Receiving file will be stopped.</source>
<target>การรับไฟล์จะหยุดลง</target> <target>การรับไฟล์จะหยุดลง</target>
@@ -4066,6 +4354,10 @@ Error: %@</source>
<source>Recent history and improved [directory bot](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</source> <source>Recent history and improved [directory bot](simplex:/contact#/?v=1-4&amp;smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Recipient(s) can't see who this message is from." xml:space="preserve">
<source>Recipient(s) can't see who this message is from.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Recipients see updates as you type them." xml:space="preserve"> <trans-unit id="Recipients see updates as you type them." xml:space="preserve">
<source>Recipients see updates as you type them.</source> <source>Recipients see updates as you type them.</source>
<target>ผู้รับจะเห็นการอัปเดตเมื่อคุณพิมพ์</target> <target>ผู้รับจะเห็นการอัปเดตเมื่อคุณพิมพ์</target>
@@ -4159,10 +4451,22 @@ Error: %@</source>
<source>Repeat connection request?</source> <source>Repeat connection request?</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Repeat download" xml:space="preserve">
<source>Repeat download</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Repeat import" xml:space="preserve">
<source>Repeat import</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Repeat join request?" xml:space="preserve"> <trans-unit id="Repeat join request?" xml:space="preserve">
<source>Repeat join request?</source> <source>Repeat join request?</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Repeat upload" xml:space="preserve">
<source>Repeat upload</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Reply" xml:space="preserve"> <trans-unit id="Reply" xml:space="preserve">
<source>Reply</source> <source>Reply</source>
<target>ตอบ</target> <target>ตอบ</target>
@@ -4262,6 +4566,10 @@ Error: %@</source>
<target>เซิร์ฟเวอร์ SMP</target> <target>เซิร์ฟเวอร์ SMP</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Safer groups" xml:space="preserve">
<source>Safer groups</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Save" xml:space="preserve"> <trans-unit id="Save" xml:space="preserve">
<source>Save</source> <source>Save</source>
<target>บันทึก</target> <target>บันทึก</target>
@@ -4342,11 +4650,19 @@ Error: %@</source>
<target>บันทึกข้อความต้อนรับ?</target> <target>บันทึกข้อความต้อนรับ?</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved" xml:space="preserve">
<source>Saved</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve"> <trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve">
<source>Saved WebRTC ICE servers will be removed</source> <source>Saved WebRTC ICE servers will be removed</source>
<target>เซิร์ฟเวอร์ WebRTC ICE ที่บันทึกไว้จะถูกลบออก</target> <target>เซิร์ฟเวอร์ WebRTC ICE ที่บันทึกไว้จะถูกลบออก</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Saved from" xml:space="preserve">
<source>Saved from</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved message" xml:space="preserve"> <trans-unit id="Saved message" xml:space="preserve">
<source>Saved message</source> <source>Saved message</source>
<note>message info title</note> <note>message info title</note>
@@ -4618,6 +4934,10 @@ Error: %@</source>
<target>ตั้งรหัสผ่าน</target> <target>ตั้งรหัสผ่าน</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Set passphrase" xml:space="preserve">
<source>Set passphrase</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set passphrase to export" xml:space="preserve"> <trans-unit id="Set passphrase to export" xml:space="preserve">
<source>Set passphrase to export</source> <source>Set passphrase to export</source>
<target>ตั้งรหัสผ่านเพื่อส่งออก</target> <target>ตั้งรหัสผ่านเพื่อส่งออก</target>
@@ -4638,6 +4958,10 @@ Error: %@</source>
<target>การตั้งค่า</target> <target>การตั้งค่า</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Shape profile images" xml:space="preserve">
<source>Shape profile images</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Share" xml:space="preserve"> <trans-unit id="Share" xml:space="preserve">
<source>Share</source> <source>Share</source>
<target>แชร์</target> <target>แชร์</target>
@@ -4672,6 +4996,10 @@ Error: %@</source>
<target>แชร์กับผู้ติดต่อ</target> <target>แชร์กับผู้ติดต่อ</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Show QR code" xml:space="preserve">
<source>Show QR code</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show calls in phone history" xml:space="preserve"> <trans-unit id="Show calls in phone history" xml:space="preserve">
<source>Show calls in phone history</source> <source>Show calls in phone history</source>
<target>แสดงการโทรในประวัติการโทร</target> <target>แสดงการโทรในประวัติการโทร</target>
@@ -4749,6 +5077,14 @@ Error: %@</source>
<trans-unit id="SimpleX links" xml:space="preserve"> <trans-unit id="SimpleX links" xml:space="preserve">
<source>SimpleX links</source> <source>SimpleX links</source>
<target>ลิงก์ SimpleX</target> <target>ลิงก์ SimpleX</target>
<note>chat feature</note>
</trans-unit>
<trans-unit id="SimpleX links are prohibited in this group." xml:space="preserve">
<source>SimpleX links are prohibited in this group.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="SimpleX links not allowed" xml:space="preserve">
<source>SimpleX links not allowed</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="SimpleX one-time invitation" xml:space="preserve"> <trans-unit id="SimpleX one-time invitation" xml:space="preserve">
@@ -4784,6 +5120,10 @@ Error: %@</source>
<target>ใครบางคน</target> <target>ใครบางคน</target>
<note>notification title</note> <note>notification title</note>
</trans-unit> </trans-unit>
<trans-unit id="Square, circle, or anything in between." xml:space="preserve">
<source>Square, circle, or anything in between.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Start chat" xml:space="preserve"> <trans-unit id="Start chat" xml:space="preserve">
<source>Start chat</source> <source>Start chat</source>
<target>เริ่มแชท</target> <target>เริ่มแชท</target>
@@ -4808,6 +5148,10 @@ Error: %@</source>
<target>หยุด SimpleX</target> <target>หยุด SimpleX</target>
<note>authentication reason</note> <note>authentication reason</note>
</trans-unit> </trans-unit>
<trans-unit id="Stop chat" xml:space="preserve">
<source>Stop chat</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Stop chat to enable database actions" xml:space="preserve"> <trans-unit id="Stop chat to enable database actions" xml:space="preserve">
<source>Stop chat to enable database actions</source> <source>Stop chat to enable database actions</source>
<target>หยุดการแชทเพื่อเปิดใช้งานการดำเนินการกับฐานข้อมูล</target> <target>หยุดการแชทเพื่อเปิดใช้งานการดำเนินการกับฐานข้อมูล</target>
@@ -4848,6 +5192,10 @@ Error: %@</source>
<target>หยุดแชร์ที่อยู่ไหม?</target> <target>หยุดแชร์ที่อยู่ไหม?</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Stopping chat" xml:space="preserve">
<source>Stopping chat</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Submit" xml:space="preserve"> <trans-unit id="Submit" xml:space="preserve">
<source>Submit</source> <source>Submit</source>
<target>ส่ง</target> <target>ส่ง</target>
@@ -5090,6 +5438,14 @@ It can happen because of some bug or when the connection is compromised.</source
<target>การดำเนินการนี้ไม่สามารถยกเลิกได้ - โปรไฟล์ ผู้ติดต่อ ข้อความ และไฟล์ของคุณจะสูญหายไปอย่างถาวร</target> <target>การดำเนินการนี้ไม่สามารถยกเลิกได้ - โปรไฟล์ ผู้ติดต่อ ข้อความ และไฟล์ของคุณจะสูญหายไปอย่างถาวร</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="This chat is protected by end-to-end encryption." xml:space="preserve">
<source>This chat is protected by end-to-end encryption.</source>
<note>E2EE info chat item</note>
</trans-unit>
<trans-unit id="This chat is protected by quantum resistant end-to-end encryption." xml:space="preserve">
<source>This chat is protected by quantum resistant end-to-end encryption.</source>
<note>E2EE info chat item</note>
</trans-unit>
<trans-unit id="This device name" xml:space="preserve"> <trans-unit id="This device name" xml:space="preserve">
<source>This device name</source> <source>This device name</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
@@ -5368,11 +5724,19 @@ To connect, please ask your contact to create another connection link and check
<target>อัปเกรดและเปิดการแชท</target> <target>อัปเกรดและเปิดการแชท</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Upload failed" xml:space="preserve">
<source>Upload failed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Upload file" xml:space="preserve"> <trans-unit id="Upload file" xml:space="preserve">
<source>Upload file</source> <source>Upload file</source>
<target>อัปโหลดไฟล์</target> <target>อัปโหลดไฟล์</target>
<note>server test step</note> <note>server test step</note>
</trans-unit> </trans-unit>
<trans-unit id="Uploading archive" xml:space="preserve">
<source>Uploading archive</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use .onion hosts" xml:space="preserve"> <trans-unit id="Use .onion hosts" xml:space="preserve">
<source>Use .onion hosts</source> <source>Use .onion hosts</source>
<target>ใช้โฮสต์ .onion</target> <target>ใช้โฮสต์ .onion</target>
@@ -5419,6 +5783,10 @@ To connect, please ask your contact to create another connection link and check
<target>ใช้เซิร์ฟเวอร์</target> <target>ใช้เซิร์ฟเวอร์</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Use the app while in the call." xml:space="preserve">
<source>Use the app while in the call.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="User profile" xml:space="preserve"> <trans-unit id="User profile" xml:space="preserve">
<source>User profile</source> <source>User profile</source>
<target>โปรไฟล์ผู้ใช้</target> <target>โปรไฟล์ผู้ใช้</target>
@@ -5451,6 +5819,14 @@ To connect, please ask your contact to create another connection link and check
<source>Verify connections</source> <source>Verify connections</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Verify database passphrase" xml:space="preserve">
<source>Verify database passphrase</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify passphrase" xml:space="preserve">
<source>Verify passphrase</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify security code" xml:space="preserve"> <trans-unit id="Verify security code" xml:space="preserve">
<source>Verify security code</source> <source>Verify security code</source>
<target>ตรวจสอบรหัสความปลอดภัย</target> <target>ตรวจสอบรหัสความปลอดภัย</target>
@@ -5509,6 +5885,10 @@ To connect, please ask your contact to create another connection link and check
<target>ข้อความเสียงเป็นสิ่งต้องห้ามในกลุ่มนี้</target> <target>ข้อความเสียงเป็นสิ่งต้องห้ามในกลุ่มนี้</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Voice messages not allowed" xml:space="preserve">
<source>Voice messages not allowed</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Voice messages prohibited!" xml:space="preserve"> <trans-unit id="Voice messages prohibited!" xml:space="preserve">
<source>Voice messages prohibited!</source> <source>Voice messages prohibited!</source>
<target>ห้ามข้อความเสียง!</target> <target>ห้ามข้อความเสียง!</target>
@@ -5538,6 +5918,10 @@ To connect, please ask your contact to create another connection link and check
<target>กําลังรอวิดีโอ</target> <target>กําลังรอวิดีโอ</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Warning: starting chat on multiple devices is not supported and will cause message delivery failures" xml:space="preserve">
<source>Warning: starting chat on multiple devices is not supported and will cause message delivery failures</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Warning: you may lose some data!" xml:space="preserve"> <trans-unit id="Warning: you may lose some data!" xml:space="preserve">
<source>Warning: you may lose some data!</source> <source>Warning: you may lose some data!</source>
<target>คำเตือน: คุณอาจสูญเสียข้อมูลบางส่วน!</target> <target>คำเตือน: คุณอาจสูญเสียข้อมูลบางส่วน!</target>
@@ -5558,6 +5942,10 @@ To connect, please ask your contact to create another connection link and check
<target>ข้อความต้อนรับ</target> <target>ข้อความต้อนรับ</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="Welcome message is too long" xml:space="preserve">
<source>Welcome message is too long</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="What's new" xml:space="preserve"> <trans-unit id="What's new" xml:space="preserve">
<source>What's new</source> <source>What's new</source>
<target>มีอะไรใหม่</target> <target>มีอะไรใหม่</target>
@@ -5568,6 +5956,10 @@ To connect, please ask your contact to create another connection link and check
<target>เมื่อพร้อมใช้งาน</target> <target>เมื่อพร้อมใช้งาน</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="When connecting audio and video calls." xml:space="preserve">
<source>When connecting audio and video calls.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="When people request to connect, you can accept or reject it." xml:space="preserve"> <trans-unit id="When people request to connect, you can accept or reject it." xml:space="preserve">
<source>When people request to connect, you can accept or reject it.</source> <source>When people request to connect, you can accept or reject it.</source>
<target>เมื่อมีคนขอเชื่อมต่อ คุณสามารถยอมรับหรือปฏิเสธได้</target> <target>เมื่อมีคนขอเชื่อมต่อ คุณสามารถยอมรับหรือปฏิเสธได้</target>
@@ -5578,6 +5970,18 @@ To connect, please ask your contact to create another connection link and check
<target>เมื่อคุณแชร์โปรไฟล์ที่ไม่ระบุตัวตนกับใครสักคน โปรไฟล์นี้จะใช้สำหรับกลุ่มที่พวกเขาเชิญคุณ</target> <target>เมื่อคุณแชร์โปรไฟล์ที่ไม่ระบุตัวตนกับใครสักคน โปรไฟล์นี้จะใช้สำหรับกลุ่มที่พวกเขาเชิญคุณ</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="WiFi" xml:space="preserve">
<source>WiFi</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Will be enabled in direct chats!" xml:space="preserve">
<source>Will be enabled in direct chats!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Wired ethernet" xml:space="preserve">
<source>Wired ethernet</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="With encrypted files and media." xml:space="preserve"> <trans-unit id="With encrypted files and media." xml:space="preserve">
<source>With encrypted files and media.</source> <source>With encrypted files and media.</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
@@ -5611,6 +6015,10 @@ To connect, please ask your contact to create another connection link and check
<target>คุณ</target> <target>คุณ</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="You **must not** use the same database on two devices." xml:space="preserve">
<source>You **must not** use the same database on two devices.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You accepted connection" xml:space="preserve"> <trans-unit id="You accepted connection" xml:space="preserve">
<source>You accepted connection</source> <source>You accepted connection</source>
<target>คุณยอมรับการเชื่อมต่อ</target> <target>คุณยอมรับการเชื่อมต่อ</target>
@@ -5690,6 +6098,10 @@ Repeat join request?</source>
<target>คุณสามารถเปิดใช้งานได้ในภายหลังผ่านการตั้งค่าความเป็นส่วนตัวและความปลอดภัยของแอป</target> <target>คุณสามารถเปิดใช้งานได้ในภายหลังผ่านการตั้งค่าความเป็นส่วนตัวและความปลอดภัยของแอป</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="You can give another try." xml:space="preserve">
<source>You can give another try.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You can hide or mute a user profile - swipe it to the right." xml:space="preserve"> <trans-unit id="You can hide or mute a user profile - swipe it to the right." xml:space="preserve">
<source>You can hide or mute a user profile - swipe it to the right.</source> <source>You can hide or mute a user profile - swipe it to the right.</source>
<target>คุณสามารถซ่อนหรือปิดเสียงโปรไฟล์ผู้ใช้ - ปัดไปทางขวา</target> <target>คุณสามารถซ่อนหรือปิดเสียงโปรไฟล์ผู้ใช้ - ปัดไปทางขวา</target>
@@ -6031,6 +6443,10 @@ SimpleX servers cannot see your profile.</source>
<target>ผู้ดูแลระบบ</target> <target>ผู้ดูแลระบบ</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="admins" xml:space="preserve">
<source>admins</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="agreeing encryption for %@…" xml:space="preserve"> <trans-unit id="agreeing encryption for %@…" xml:space="preserve">
<source>agreeing encryption for %@…</source> <source>agreeing encryption for %@…</source>
<target>ยอมรับ encryption สำหรับ %@…</target> <target>ยอมรับ encryption สำหรับ %@…</target>
@@ -6041,6 +6457,10 @@ SimpleX servers cannot see your profile.</source>
<target>เห็นด้วยกับการ encryption…</target> <target>เห็นด้วยกับการ encryption…</target>
<note>chat item text</note> <note>chat item text</note>
</trans-unit> </trans-unit>
<trans-unit id="all members" xml:space="preserve">
<source>all members</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="always" xml:space="preserve"> <trans-unit id="always" xml:space="preserve">
<source>always</source> <source>always</source>
<target>เสมอ</target> <target>เสมอ</target>
@@ -6071,7 +6491,7 @@ SimpleX servers cannot see your profile.</source>
</trans-unit> </trans-unit>
<trans-unit id="blocked" xml:space="preserve"> <trans-unit id="blocked" xml:space="preserve">
<source>blocked</source> <source>blocked</source>
<note>No comment provided by engineer.</note> <note>marked deleted chat item preview text</note>
</trans-unit> </trans-unit>
<trans-unit id="blocked %@" xml:space="preserve"> <trans-unit id="blocked %@" xml:space="preserve">
<source>blocked %@</source> <source>blocked %@</source>
@@ -6079,7 +6499,7 @@ SimpleX servers cannot see your profile.</source>
</trans-unit> </trans-unit>
<trans-unit id="blocked by admin" xml:space="preserve"> <trans-unit id="blocked by admin" xml:space="preserve">
<source>blocked by admin</source> <source>blocked by admin</source>
<note>blocked chat item</note> <note>marked deleted chat item preview text</note>
</trans-unit> </trans-unit>
<trans-unit id="bold" xml:space="preserve"> <trans-unit id="bold" xml:space="preserve">
<source>bold</source> <source>bold</source>
@@ -6361,6 +6781,10 @@ SimpleX servers cannot see your profile.</source>
<source>event happened</source> <source>event happened</source>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="forwarded" xml:space="preserve">
<source>forwarded</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="group deleted" xml:space="preserve"> <trans-unit id="group deleted" xml:space="preserve">
<source>group deleted</source> <source>group deleted</source>
<target>ลบกลุ่มแล้ว</target> <target>ลบกลุ่มแล้ว</target>
@@ -6503,7 +6927,7 @@ SimpleX servers cannot see your profile.</source>
<trans-unit id="moderated by %@" xml:space="preserve"> <trans-unit id="moderated by %@" xml:space="preserve">
<source>moderated by %@</source> <source>moderated by %@</source>
<target>กลั่นกรองโดย %@</target> <target>กลั่นกรองโดย %@</target>
<note>No comment provided by engineer.</note> <note>marked deleted chat item preview text</note>
</trans-unit> </trans-unit>
<trans-unit id="months" xml:space="preserve"> <trans-unit id="months" xml:space="preserve">
<source>months</source> <source>months</source>
@@ -6567,11 +6991,19 @@ SimpleX servers cannot see your profile.</source>
<target>เจ้าของ</target> <target>เจ้าของ</target>
<note>member role</note> <note>member role</note>
</trans-unit> </trans-unit>
<trans-unit id="owners" xml:space="preserve">
<source>owners</source>
<note>feature role</note>
</trans-unit>
<trans-unit id="peer-to-peer" xml:space="preserve"> <trans-unit id="peer-to-peer" xml:space="preserve">
<source>peer-to-peer</source> <source>peer-to-peer</source>
<target>เพื่อนต่อเพื่อน</target> <target>เพื่อนต่อเพื่อน</target>
<note>No comment provided by engineer.</note> <note>No comment provided by engineer.</note>
</trans-unit> </trans-unit>
<trans-unit id="quantum resistant e2e encryption" xml:space="preserve">
<source>quantum resistant e2e encryption</source>
<note>chat item text</note>
</trans-unit>
<trans-unit id="received answer…" xml:space="preserve"> <trans-unit id="received answer…" xml:space="preserve">
<source>received answer…</source> <source>received answer…</source>
<target>ได้รับคำตอบ…</target> <target>ได้รับคำตอบ…</target>
@@ -6610,6 +7042,14 @@ SimpleX servers cannot see your profile.</source>
<target>ลบคุณออกแล้ว</target> <target>ลบคุณออกแล้ว</target>
<note>rcv group event chat item</note> <note>rcv group event chat item</note>
</trans-unit> </trans-unit>
<trans-unit id="saved" xml:space="preserve">
<source>saved</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="saved from %@" xml:space="preserve">
<source>saved from %@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="sec" xml:space="preserve"> <trans-unit id="sec" xml:space="preserve">
<source>sec</source> <source>sec</source>
<target>วินาที</target> <target>วินาที</target>
@@ -6642,6 +7082,10 @@ SimpleX servers cannot see your profile.</source>
<source>set new profile picture</source> <source>set new profile picture</source>
<note>profile update event chat item</note> <note>profile update event chat item</note>
</trans-unit> </trans-unit>
<trans-unit id="standard end-to-end encryption" xml:space="preserve">
<source>standard end-to-end encryption</source>
<note>chat item text</note>
</trans-unit>
<trans-unit id="starting…" xml:space="preserve"> <trans-unit id="starting…" xml:space="preserve">
<source>starting…</source> <source>starting…</source>
<target>กำลังเริ่มต้น…</target> <target>กำลังเริ่มต้น…</target>
@@ -6738,6 +7182,10 @@ SimpleX servers cannot see your profile.</source>
<target>ใช่</target> <target>ใช่</target>
<note>pref value</note> <note>pref value</note>
</trans-unit> </trans-unit>
<trans-unit id="you" xml:space="preserve">
<source>you</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="you are invited to group" xml:space="preserve"> <trans-unit id="you are invited to group" xml:space="preserve">
<source>you are invited to group</source> <source>you are invited to group</source>
<target>คุณได้รับเชิญให้เข้าร่วมกลุ่ม</target> <target>คุณได้รับเชิญให้เข้าร่วมกลุ่ม</target>
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,64 +0,0 @@
//
// ConcurrentQueue.swift
// SimpleX NSE
//
// Created by Evgeny on 08/12/2023.
// Copyright © 2023 SimpleX Chat. All rights reserved.
//
import Foundation
struct DequeueElement<T> {
var elementId: UUID?
var task: Task<T?, Never>
}
class ConcurrentQueue<T> {
private var queue: [T] = []
private var queueLock = DispatchQueue(label: "chat.simplex.app.SimpleX-NSE.concurrent-queue.lock.\(UUID())")
private var continuations = [(elementId: UUID, continuation: CheckedContinuation<T?, Never>)]()
func enqueue(_ el: T) {
resumeContinuation(el) { self.queue.append(el) }
}
func frontEnqueue(_ el: T) {
resumeContinuation(el) { self.queue.insert(el, at: 0) }
}
private func resumeContinuation(_ el: T, add: @escaping () -> Void) {
queueLock.sync {
if let (_, cont) = continuations.first {
continuations.remove(at: 0)
cont.resume(returning: el)
} else {
add()
}
}
}
func dequeue() -> DequeueElement<T> {
queueLock.sync {
if queue.isEmpty {
let elementId = UUID()
let task = Task {
await withCheckedContinuation { cont in
continuations.append((elementId, cont))
}
}
return DequeueElement(elementId: elementId, task: task)
} else {
let el = queue.remove(at: 0)
return DequeueElement(task: Task { el })
}
}
}
func cancelDequeue(_ elementId: UUID) {
queueLock.sync {
let cancelled = continuations.filter { $0.elementId == elementId }
continuations.removeAll { $0.elementId == elementId }
cancelled.forEach { $0.continuation.resume(returning: nil) }
}
}
}
+77 -136
View File
@@ -22,110 +22,6 @@ let nseSuspendSchedule: SuspendSchedule = (2, 4)
let fastNSESuspendSchedule: SuspendSchedule = (1, 1) let fastNSESuspendSchedule: SuspendSchedule = (1, 1)
typealias NtfStream = ConcurrentQueue<NSENotification>
// Notifications are delivered via concurrent queues, as they are all received from chat controller in a single loop that
// writes to ConcurrentQueue and when notification is processed, the instance of Notification service extension reads from the queue.
// One queue per connection (entity) is used.
// The concurrent queues allow read cancellation, to ensure that notifications are not lost in case the current thread completes
// before expected notification is read (multiple notifications can be expected, because one notification can be delivered for several messages).
actor PendingNtfs {
static let shared = PendingNtfs()
private var ntfStreams: [String: NtfStream] = [:]
func createStream(_ id: String) async {
logger.debug("NotificationService PendingNtfs.createStream: \(id)")
if ntfStreams[id] == nil {
ntfStreams[id] = ConcurrentQueue()
logger.debug("NotificationService PendingNtfs.createStream: created ConcurrentQueue")
}
}
func readStream(_ id: String, for nse: NotificationService, ntfInfo: NtfMessages) async {
logger.debug("NotificationService PendingNtfs.readStream: \(id) \(ntfInfo.ntfMessages.count)")
if !ntfInfo.user.showNotifications {
nse.setBestAttemptNtf(.empty)
}
if let s = ntfStreams[id] {
logger.debug("NotificationService PendingNtfs.readStream: has stream")
var expected = Set(ntfInfo.ntfMessages.map { $0.msgId })
logger.debug("NotificationService PendingNtfs.readStream: expecting: \(expected)")
var readCancelled = false
var dequeued: DequeueElement<NSENotification>?
nse.cancelRead = {
readCancelled = true
if let elementId = dequeued?.elementId {
s.cancelDequeue(elementId)
}
}
while !readCancelled {
dequeued = s.dequeue()
if let ntf = await dequeued?.task.value {
if readCancelled {
logger.debug("NotificationService PendingNtfs.readStream: read cancelled, put ntf to queue front")
s.frontEnqueue(ntf)
break
} else if case let .msgInfo(info) = ntf {
let found = expected.remove(info.msgId)
if found != nil {
logger.debug("NotificationService PendingNtfs.readStream: msgInfo, last: \(expected.isEmpty)")
if expected.isEmpty { break }
} else if let msgTs = ntfInfo.msgTs, info.msgTs > msgTs {
logger.debug("NotificationService PendingNtfs.readStream: unexpected msgInfo")
s.frontEnqueue(ntf)
break
}
} else if ntfInfo.user.showNotifications {
logger.debug("NotificationService PendingNtfs.readStream: setting best attempt")
nse.setBestAttemptNtf(ntf)
if ntf.isCallInvitation { break }
}
} else {
break
}
}
nse.cancelRead = nil
logger.debug("NotificationService PendingNtfs.readStream: exiting")
}
}
func writeStream(_ id: String, _ ntf: NSENotification) async {
logger.debug("NotificationService PendingNtfs.writeStream: \(id)")
if let s = ntfStreams[id] {
logger.debug("NotificationService PendingNtfs.writeStream: writing ntf")
s.enqueue(ntf)
}
}
}
// The current implementation assumes concurrent notification delivery and uses semaphores
// to process only one notification per connection (entity) at a time.
class NtfStreamSemaphores {
static let shared = NtfStreamSemaphores()
private static let queue = DispatchQueue(label: "chat.simplex.app.SimpleX-NSE.notification-semaphores.lock")
private var semaphores: [String: DispatchSemaphore] = [:]
func waitForStream(_ id: String) {
streamSemaphore(id, value: 0)?.wait()
}
func signalStreamReady(_ id: String) {
streamSemaphore(id, value: 1)?.signal()
}
// this function returns nil if semaphore is just created, so passed value shoud be coordinated with the desired end value of the semaphore
private func streamSemaphore(_ id: String, value: Int) -> DispatchSemaphore? {
NtfStreamSemaphores.queue.sync {
if let s = semaphores[id] {
return s
} else {
semaphores[id] = DispatchSemaphore(value: value)
return nil
}
}
}
}
enum NSENotification { enum NSENotification {
case nse(UNMutableNotificationContent) case nse(UNMutableNotificationContent)
case callkit(RcvCallInvitation) case callkit(RcvCallInvitation)
@@ -149,7 +45,7 @@ class NSEThreads {
static let shared = NSEThreads() static let shared = NSEThreads()
private static let queue = DispatchQueue(label: "chat.simplex.app.SimpleX-NSE.notification-threads.lock") private static let queue = DispatchQueue(label: "chat.simplex.app.SimpleX-NSE.notification-threads.lock")
private var allThreads: Set<UUID> = [] private var allThreads: Set<UUID> = []
private var activeThreads: Set<UUID> = [] private var activeThreads: [(UUID, NotificationService)] = []
func newThread() -> UUID { func newThread() -> UUID {
NSEThreads.queue.sync { NSEThreads.queue.sync {
@@ -158,19 +54,42 @@ class NSEThreads {
} }
} }
func startThread(_ t: UUID) { func startThread(_ t: UUID, _ service: NotificationService) {
NSEThreads.queue.sync { NSEThreads.queue.sync {
if allThreads.contains(t) { if allThreads.contains(t) {
_ = activeThreads.insert(t) activeThreads.append((t, service))
} else { } else {
logger.warning("NotificationService startThread: thread \(t) was removed before it started") logger.warning("NotificationService startThread: thread \(t) was removed before it started")
} }
} }
} }
func processNotification(_ id: ChatId, _ ntf: NSENotification) async -> Void {
var waitTime: Int64 = 5_000_000000
while waitTime > 0 {
if let (_, nse) = rcvEntityThread(id),
nse.shouldProcessNtf && nse.processReceivedNtf(ntf) {
break
} else {
try? await Task.sleep(nanoseconds: 10_000000)
waitTime -= 10_000000
}
}
}
private func rcvEntityThread(_ id: ChatId) -> (UUID, NotificationService)? {
NSEThreads.queue.sync {
activeThreads.first(where: { (_, nse) in nse.receiveEntityId == id })
}
}
func endThread(_ t: UUID) -> Bool { func endThread(_ t: UUID) -> Bool {
NSEThreads.queue.sync { NSEThreads.queue.sync {
let tActive = activeThreads.remove(t) let tActive: UUID? = if let index = activeThreads.firstIndex(where: { $0.0 == t }) {
activeThreads.remove(at: index).0
} else {
nil
}
let t = allThreads.remove(t) let t = allThreads.remove(t)
if tActive != nil && activeThreads.isEmpty { if tActive != nil && activeThreads.isEmpty {
return true return true
@@ -198,8 +117,11 @@ class NotificationService: UNNotificationServiceExtension {
// thread is added to allThreads here - if thread did not start chat, // thread is added to allThreads here - if thread did not start chat,
// chat does not need to be suspended but NSE state still needs to be set to "suspended". // chat does not need to be suspended but NSE state still needs to be set to "suspended".
var threadId: UUID? = NSEThreads.shared.newThread() var threadId: UUID? = NSEThreads.shared.newThread()
var notificationInfo: NtfMessages?
var receiveEntityId: String? var receiveEntityId: String?
var cancelRead: (() -> Void)? var expectedMessages: Set<String> = []
// return true if the message is taken - it prevents sending it to another NotificationService instance for processing
var shouldProcessNtf = false
var appSubscriber: AppSubscriber? var appSubscriber: AppSubscriber?
var returnedSuspension = false var returnedSuspension = false
@@ -265,7 +187,7 @@ class NotificationService: UNNotificationServiceExtension {
// check it here again // check it here again
appStateGroupDefault.get().inactive { appStateGroupDefault.get().inactive {
// thread is added to activeThreads tracking set here - if thread started chat it needs to be suspended // thread is added to activeThreads tracking set here - if thread started chat it needs to be suspended
if let t = threadId { NSEThreads.shared.startThread(t) } if let t = threadId { NSEThreads.shared.startThread(t, self) }
let dbStatus = startChat() let dbStatus = startChat()
if case .ok = dbStatus, if case .ok = dbStatus,
let ntfInfo = apiGetNtfMessage(nonce: nonce, encNtfInfo: encNtfInfo) { let ntfInfo = apiGetNtfMessage(nonce: nonce, encNtfInfo: encNtfInfo) {
@@ -276,17 +198,11 @@ class NotificationService: UNNotificationServiceExtension {
? .nse(createConnectionEventNtf(ntfInfo.user, connEntity)) ? .nse(createConnectionEventNtf(ntfInfo.user, connEntity))
: .empty : .empty
) )
if let id = connEntity.id { if let id = connEntity.id, ntfInfo.msgTs != nil {
notificationInfo = ntfInfo
receiveEntityId = id receiveEntityId = id
NtfStreamSemaphores.shared.waitForStream(id) expectedMessages = Set(ntfInfo.ntfMessages.map { $0.msgId })
if receiveEntityId != nil { shouldProcessNtf = true
Task {
logger.debug("NotificationService: receiveNtfMessages: in Task, connEntity id \(id)")
await PendingNtfs.shared.createStream(id)
await PendingNtfs.shared.readStream(id, for: self, ntfInfo: ntfInfo)
deliverBestAttemptNtf()
}
}
return return
} }
} }
@@ -302,6 +218,38 @@ class NotificationService: UNNotificationServiceExtension {
deliverBestAttemptNtf(urgent: true) deliverBestAttemptNtf(urgent: true)
} }
func processReceivedNtf(_ ntf: NSENotification) -> Bool {
guard let ntfInfo = notificationInfo, let msgTs = ntfInfo.msgTs else { return false }
if !ntfInfo.user.showNotifications {
self.setBestAttemptNtf(.empty)
}
if case let .msgInfo(info) = ntf {
let found = expectedMessages.remove(info.msgId)
if found != nil {
logger.debug("NotificationService processNtf: msgInfo, last: \(self.expectedMessages.isEmpty)")
if expectedMessages.isEmpty {
self.deliverBestAttemptNtf()
}
return true
} else if info.msgTs > msgTs {
logger.debug("NotificationService processNtf: unexpected msgInfo, let other instance to process it, stopping this one")
self.deliverBestAttemptNtf()
return false
} else {
logger.debug("NotificationService processNtf: unknown message, let other instance to process it")
return false
}
} else if ntfInfo.user.showNotifications {
logger.debug("NotificationService processNtf: setting best attempt")
self.setBestAttemptNtf(ntf)
if ntf.isCallInvitation {
self.deliverBestAttemptNtf()
}
return true
}
return false
}
func setBadgeCount() { func setBadgeCount() {
badgeCount = ntfBadgeCountGroupDefault.get() + 1 badgeCount = ntfBadgeCountGroupDefault.get() + 1
ntfBadgeCountGroupDefault.set(badgeCount) ntfBadgeCountGroupDefault.set(badgeCount)
@@ -323,14 +271,9 @@ class NotificationService: UNNotificationServiceExtension {
private func deliverBestAttemptNtf(urgent: Bool = false) { private func deliverBestAttemptNtf(urgent: Bool = false) {
logger.debug("NotificationService.deliverBestAttemptNtf") logger.debug("NotificationService.deliverBestAttemptNtf")
if let cancel = cancelRead { // stop processing other messages
cancelRead = nil shouldProcessNtf = false
cancel()
}
if let id = receiveEntityId {
receiveEntityId = nil
NtfStreamSemaphores.shared.signalStreamReady(id)
}
let suspend: Bool let suspend: Bool
if let t = threadId { if let t = threadId {
threadId = nil threadId = nil
@@ -572,7 +515,7 @@ func chatSuspended() {
} }
// A single loop is used per Notification service extension process to receive and process all messages depending on the NSE state // A single loop is used per Notification service extension process to receive and process all messages depending on the NSE state
// If the extension is not active yet, or suspended/suspending, or the app is running, the notifications will no be received. // If the extension is not active yet, or suspended/suspending, or the app is running, the notifications will not be received.
func receiveMessages() async { func receiveMessages() async {
logger.debug("NotificationService receiveMessages") logger.debug("NotificationService receiveMessages")
while true { while true {
@@ -591,8 +534,7 @@ func receiveMessages() async {
logger.debug("NotificationService receiveMsg: message") logger.debug("NotificationService receiveMsg: message")
if let (id, ntf) = await receivedMsgNtf(msg) { if let (id, ntf) = await receivedMsgNtf(msg) {
logger.debug("NotificationService receiveMsg: notification") logger.debug("NotificationService receiveMsg: notification")
await PendingNtfs.shared.createStream(id) await NSEThreads.shared.processNotification(id, ntf)
await PendingNtfs.shared.writeStream(id, ntf)
} }
} }
} }
@@ -644,9 +586,6 @@ func receivedMsgNtf(_ res: ChatResponse) async -> (String, NSENotification)? {
cleanupDirectFile(aChatItem) cleanupDirectFile(aChatItem)
} }
return nil return nil
case let .sndFileCompleteXFTP(_, aChatItem, _):
cleanupFile(aChatItem)
return nil
case let .callInvitation(invitation): case let .callInvitation(invitation):
// Do not post it without CallKit support, iOS will stop launching the app without showing CallKit // Do not post it without CallKit support, iOS will stop launching the app without showing CallKit
return ( return (
@@ -757,14 +696,16 @@ func apiGetNtfMessage(nonce: String, encNtfInfo: String) -> NtfMessages? {
} }
func apiReceiveFile(fileId: Int64, encrypted: Bool, inline: Bool? = nil) -> AChatItem? { func apiReceiveFile(fileId: Int64, encrypted: Bool, inline: Bool? = nil) -> AChatItem? {
let r = sendSimpleXCmd(.receiveFile(fileId: fileId, encrypted: encrypted, inline: inline)) let userApprovedRelays = !privacyAskToApproveRelaysGroupDefault.get()
let r = sendSimpleXCmd(.receiveFile(fileId: fileId, userApprovedRelays: userApprovedRelays, encrypted: encrypted, inline: inline))
if case let .rcvFileAccepted(_, chatItem) = r { return chatItem } if case let .rcvFileAccepted(_, chatItem) = r { return chatItem }
logger.error("receiveFile error: \(responseError(r))") logger.error("receiveFile error: \(responseError(r))")
return nil return nil
} }
func apiSetFileToReceive(fileId: Int64, encrypted: Bool) { func apiSetFileToReceive(fileId: Int64, encrypted: Bool) {
let r = sendSimpleXCmd(.setFileToReceive(fileId: fileId, encrypted: encrypted)) let userApprovedRelays = !privacyAskToApproveRelaysGroupDefault.get()
let r = sendSimpleXCmd(.setFileToReceive(fileId: fileId, userApprovedRelays: userApprovedRelays, encrypted: encrypted))
if case .cmdOk = r { return } if case .cmdOk = r { return }
logger.error("setFileToReceive error: \(responseError(r))") logger.error("setFileToReceive error: \(responseError(r))")
} }
@@ -0,0 +1,9 @@
/* Bundle display name */
"CFBundleDisplayName" = "SimpleX NSE";
/* Bundle name */
"CFBundleName" = "SimpleX NSE";
/* Copyright (human-readable) */
"NSHumanReadableCopyright" = "Copyright © 2022 SimpleX Chat. Minden jog fenntartva.";
+89 -37
View File
@@ -57,11 +57,6 @@
5C65F343297D45E100B67AF3 /* VersionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C65F341297D3F3600B67AF3 /* VersionView.swift */; }; 5C65F343297D45E100B67AF3 /* VersionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C65F341297D3F3600B67AF3 /* VersionView.swift */; };
5C6BA667289BD954009B8ECC /* DismissSheets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C6BA666289BD954009B8ECC /* DismissSheets.swift */; }; 5C6BA667289BD954009B8ECC /* DismissSheets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C6BA666289BD954009B8ECC /* DismissSheets.swift */; };
5C7031162953C97F00150A12 /* CIFeaturePreferenceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C7031152953C97F00150A12 /* CIFeaturePreferenceView.swift */; }; 5C7031162953C97F00150A12 /* CIFeaturePreferenceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C7031152953C97F00150A12 /* CIFeaturePreferenceView.swift */; };
5C746DB82BA0DA920049D734 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C746DB32BA0DA920049D734 /* libffi.a */; };
5C746DB92BA0DA920049D734 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C746DB42BA0DA920049D734 /* libgmpxx.a */; };
5C746DBA2BA0DA920049D734 /* libHSsimplex-chat-5.6.0.2-CrEKCx0J5BfIirfPSOWUVo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C746DB52BA0DA920049D734 /* libHSsimplex-chat-5.6.0.2-CrEKCx0J5BfIirfPSOWUVo.a */; };
5C746DBB2BA0DA920049D734 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C746DB62BA0DA920049D734 /* libgmp.a */; };
5C746DBC2BA0DA920049D734 /* libHSsimplex-chat-5.6.0.2-CrEKCx0J5BfIirfPSOWUVo-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C746DB72BA0DA920049D734 /* libHSsimplex-chat-5.6.0.2-CrEKCx0J5BfIirfPSOWUVo-ghc9.6.3.a */; };
5C7505A227B65FDB00BE3227 /* CIMetaView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C7505A127B65FDB00BE3227 /* CIMetaView.swift */; }; 5C7505A227B65FDB00BE3227 /* CIMetaView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C7505A127B65FDB00BE3227 /* CIMetaView.swift */; };
5C7505A527B679EE00BE3227 /* NavLinkPlain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C7505A427B679EE00BE3227 /* NavLinkPlain.swift */; }; 5C7505A527B679EE00BE3227 /* NavLinkPlain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C7505A427B679EE00BE3227 /* NavLinkPlain.swift */; };
5C7505A827B6D34800BE3227 /* ChatInfoToolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C7505A727B6D34800BE3227 /* ChatInfoToolbar.swift */; }; 5C7505A827B6D34800BE3227 /* ChatInfoToolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C7505A727B6D34800BE3227 /* ChatInfoToolbar.swift */; };
@@ -81,6 +76,11 @@
5C9CC7AD28C55D7800BEF955 /* DatabaseEncryptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C9CC7AC28C55D7800BEF955 /* DatabaseEncryptionView.swift */; }; 5C9CC7AD28C55D7800BEF955 /* DatabaseEncryptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C9CC7AC28C55D7800BEF955 /* DatabaseEncryptionView.swift */; };
5C9D13A3282187BB00AB8B43 /* WebRTC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C9D13A2282187BB00AB8B43 /* WebRTC.swift */; }; 5C9D13A3282187BB00AB8B43 /* WebRTC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C9D13A2282187BB00AB8B43 /* WebRTC.swift */; };
5C9D811A2AA8727A001D49FD /* CryptoFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C9D81182AA7A4F1001D49FD /* CryptoFile.swift */; }; 5C9D811A2AA8727A001D49FD /* CryptoFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C9D81182AA7A4F1001D49FD /* CryptoFile.swift */; };
5C9F3DD62BFBCDD90003B86B /* libHSsimplex-chat-5.8.0.2-8RkLdmy05dJBsgWrGV50Uf-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C9F3DD12BFBCDD80003B86B /* libHSsimplex-chat-5.8.0.2-8RkLdmy05dJBsgWrGV50Uf-ghc9.6.3.a */; };
5C9F3DD72BFBCDD90003B86B /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C9F3DD22BFBCDD80003B86B /* libffi.a */; };
5C9F3DD82BFBCDD90003B86B /* libHSsimplex-chat-5.8.0.2-8RkLdmy05dJBsgWrGV50Uf.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C9F3DD32BFBCDD80003B86B /* libHSsimplex-chat-5.8.0.2-8RkLdmy05dJBsgWrGV50Uf.a */; };
5C9F3DD92BFBCDD90003B86B /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C9F3DD42BFBCDD90003B86B /* libgmpxx.a */; };
5C9F3DDA2BFBCDD90003B86B /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C9F3DD52BFBCDD90003B86B /* libgmp.a */; };
5C9FD96E27A5D6ED0075386C /* SendMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C9FD96D27A5D6ED0075386C /* SendMessageView.swift */; }; 5C9FD96E27A5D6ED0075386C /* SendMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C9FD96D27A5D6ED0075386C /* SendMessageView.swift */; };
5CA059DC279559F40002BEB4 /* Tests_iOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CA059DB279559F40002BEB4 /* Tests_iOS.swift */; }; 5CA059DC279559F40002BEB4 /* Tests_iOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CA059DB279559F40002BEB4 /* Tests_iOS.swift */; };
5CA059DE279559F40002BEB4 /* Tests_iOSLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CA059DD279559F40002BEB4 /* Tests_iOSLaunchTests.swift */; }; 5CA059DE279559F40002BEB4 /* Tests_iOSLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CA059DD279559F40002BEB4 /* Tests_iOSLaunchTests.swift */; };
@@ -144,7 +144,6 @@
5CEACCED27DEA495000BD591 /* MsgContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CEACCEC27DEA495000BD591 /* MsgContentView.swift */; }; 5CEACCED27DEA495000BD591 /* MsgContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CEACCEC27DEA495000BD591 /* MsgContentView.swift */; };
5CEBD7462A5C0A8F00665FE2 /* KeyboardPadding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CEBD7452A5C0A8F00665FE2 /* KeyboardPadding.swift */; }; 5CEBD7462A5C0A8F00665FE2 /* KeyboardPadding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CEBD7452A5C0A8F00665FE2 /* KeyboardPadding.swift */; };
5CEBD7482A5F115D00665FE2 /* SetDeliveryReceiptsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CEBD7472A5F115D00665FE2 /* SetDeliveryReceiptsView.swift */; }; 5CEBD7482A5F115D00665FE2 /* SetDeliveryReceiptsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CEBD7472A5F115D00665FE2 /* SetDeliveryReceiptsView.swift */; };
5CF9371E2B23429500E1D781 /* ConcurrentQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CF9371D2B23429500E1D781 /* ConcurrentQueue.swift */; };
5CF937202B24DE8C00E1D781 /* SharedFileSubscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CF9371F2B24DE8C00E1D781 /* SharedFileSubscriber.swift */; }; 5CF937202B24DE8C00E1D781 /* SharedFileSubscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CF9371F2B24DE8C00E1D781 /* SharedFileSubscriber.swift */; };
5CF937232B2503D000E1D781 /* NSESubscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CF937212B25034A00E1D781 /* NSESubscriber.swift */; }; 5CF937232B2503D000E1D781 /* NSESubscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CF937212B25034A00E1D781 /* NSESubscriber.swift */; };
5CFA59C42860BC6200863A68 /* MigrateToAppGroupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CFA59C32860BC6200863A68 /* MigrateToAppGroupView.swift */; }; 5CFA59C42860BC6200863A68 /* MigrateToAppGroupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CFA59C32860BC6200863A68 /* MigrateToAppGroupView.swift */; };
@@ -173,6 +172,7 @@
646BB38E283FDB6D001CE359 /* LocalAuthenticationUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 646BB38D283FDB6D001CE359 /* LocalAuthenticationUtils.swift */; }; 646BB38E283FDB6D001CE359 /* LocalAuthenticationUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 646BB38D283FDB6D001CE359 /* LocalAuthenticationUtils.swift */; };
647F090E288EA27B00644C40 /* GroupMemberInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 647F090D288EA27B00644C40 /* GroupMemberInfoView.swift */; }; 647F090E288EA27B00644C40 /* GroupMemberInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 647F090D288EA27B00644C40 /* GroupMemberInfoView.swift */; };
648010AB281ADD15009009B9 /* CIFileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 648010AA281ADD15009009B9 /* CIFileView.swift */; }; 648010AB281ADD15009009B9 /* CIFileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 648010AA281ADD15009009B9 /* CIFileView.swift */; };
648679AB2BC96A74006456E7 /* ChatItemForwardingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 648679AA2BC96A74006456E7 /* ChatItemForwardingView.swift */; };
649BCDA0280460FD00C3A862 /* ComposeImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649BCD9F280460FD00C3A862 /* ComposeImageView.swift */; }; 649BCDA0280460FD00C3A862 /* ComposeImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649BCD9F280460FD00C3A862 /* ComposeImageView.swift */; };
649BCDA22805D6EF00C3A862 /* CIImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649BCDA12805D6EF00C3A862 /* CIImageView.swift */; }; 649BCDA22805D6EF00C3A862 /* CIImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649BCDA12805D6EF00C3A862 /* CIImageView.swift */; };
64AA1C6927EE10C800AC7277 /* ContextItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64AA1C6827EE10C800AC7277 /* ContextItemView.swift */; }; 64AA1C6927EE10C800AC7277 /* ContextItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64AA1C6827EE10C800AC7277 /* ContextItemView.swift */; };
@@ -188,6 +188,9 @@
8C69FE7D2B8C7D2700267E38 /* AppSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C69FE7C2B8C7D2700267E38 /* AppSettings.swift */; }; 8C69FE7D2B8C7D2700267E38 /* AppSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C69FE7C2B8C7D2700267E38 /* AppSettings.swift */; };
8C7D949A2B88952700B7B9E1 /* MigrateToDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C7D94992B88952700B7B9E1 /* MigrateToDevice.swift */; }; 8C7D949A2B88952700B7B9E1 /* MigrateToDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C7D94992B88952700B7B9E1 /* MigrateToDevice.swift */; };
8C7DF3202B7CDB0A00C886D0 /* MigrateFromDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C7DF31F2B7CDB0A00C886D0 /* MigrateFromDevice.swift */; }; 8C7DF3202B7CDB0A00C886D0 /* MigrateFromDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C7DF31F2B7CDB0A00C886D0 /* MigrateFromDevice.swift */; };
8C81482C2BD91CD4002CBEC3 /* AudioDevicePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C81482B2BD91CD4002CBEC3 /* AudioDevicePicker.swift */; };
8CC4ED902BD7B8530078AEE8 /* CallAudioDeviceManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CC4ED8F2BD7B8530078AEE8 /* CallAudioDeviceManager.swift */; };
8CC956EE2BC0041000412A11 /* NetworkObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CC956ED2BC0041000412A11 /* NetworkObserver.swift */; };
D7197A1829AE89660055C05A /* WebRTC in Frameworks */ = {isa = PBXBuildFile; productRef = D7197A1729AE89660055C05A /* WebRTC */; }; D7197A1829AE89660055C05A /* WebRTC in Frameworks */ = {isa = PBXBuildFile; productRef = D7197A1729AE89660055C05A /* WebRTC */; };
D72A9088294BD7A70047C86D /* NativeTextEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D72A9087294BD7A70047C86D /* NativeTextEditor.swift */; }; D72A9088294BD7A70047C86D /* NativeTextEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D72A9087294BD7A70047C86D /* NativeTextEditor.swift */; };
D741547829AF89AF0022400A /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D741547729AF89AF0022400A /* StoreKit.framework */; }; D741547829AF89AF0022400A /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D741547729AF89AF0022400A /* StoreKit.framework */; };
@@ -288,6 +291,9 @@
5C35CFC727B2782E00FB6C6D /* BGManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BGManager.swift; sourceTree = "<group>"; }; 5C35CFC727B2782E00FB6C6D /* BGManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BGManager.swift; sourceTree = "<group>"; };
5C35CFCA27B2E91D00FB6C6D /* NtfManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NtfManager.swift; sourceTree = "<group>"; }; 5C35CFCA27B2E91D00FB6C6D /* NtfManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NtfManager.swift; sourceTree = "<group>"; };
5C36027227F47AD5009F19D9 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; 5C36027227F47AD5009F19D9 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
5C371E4E2BA9AAA200100AD3 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/Localizable.strings; sourceTree = "<group>"; };
5C371E4F2BA9AB6400100AD3 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = "hu.lproj/SimpleX--iOS--InfoPlist.strings"; sourceTree = "<group>"; };
5C371E502BA9AB6400100AD3 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/InfoPlist.strings; sourceTree = "<group>"; };
5C3A88CD27DF50170060F1C2 /* DetermineWidth.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetermineWidth.swift; sourceTree = "<group>"; }; 5C3A88CD27DF50170060F1C2 /* DetermineWidth.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetermineWidth.swift; sourceTree = "<group>"; };
5C3A88D027DF57800060F1C2 /* FramedItemView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FramedItemView.swift; sourceTree = "<group>"; }; 5C3A88D027DF57800060F1C2 /* FramedItemView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FramedItemView.swift; sourceTree = "<group>"; };
5C3CCFCB2AE6BD3100C3F0C3 /* ConnectDesktopView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConnectDesktopView.swift; sourceTree = "<group>"; }; 5C3CCFCB2AE6BD3100C3F0C3 /* ConnectDesktopView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConnectDesktopView.swift; sourceTree = "<group>"; };
@@ -324,11 +330,6 @@
5C6D183229E93FBA00D430B3 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = "pl.lproj/SimpleX--iOS--InfoPlist.strings"; sourceTree = "<group>"; }; 5C6D183229E93FBA00D430B3 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = "pl.lproj/SimpleX--iOS--InfoPlist.strings"; sourceTree = "<group>"; };
5C6D183329E93FBA00D430B3 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/InfoPlist.strings; sourceTree = "<group>"; }; 5C6D183329E93FBA00D430B3 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/InfoPlist.strings; sourceTree = "<group>"; };
5C7031152953C97F00150A12 /* CIFeaturePreferenceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIFeaturePreferenceView.swift; sourceTree = "<group>"; }; 5C7031152953C97F00150A12 /* CIFeaturePreferenceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIFeaturePreferenceView.swift; sourceTree = "<group>"; };
5C746DB32BA0DA920049D734 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
5C746DB42BA0DA920049D734 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
5C746DB52BA0DA920049D734 /* libHSsimplex-chat-5.6.0.2-CrEKCx0J5BfIirfPSOWUVo.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.6.0.2-CrEKCx0J5BfIirfPSOWUVo.a"; sourceTree = "<group>"; };
5C746DB62BA0DA920049D734 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
5C746DB72BA0DA920049D734 /* libHSsimplex-chat-5.6.0.2-CrEKCx0J5BfIirfPSOWUVo-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.6.0.2-CrEKCx0J5BfIirfPSOWUVo-ghc9.6.3.a"; sourceTree = "<group>"; };
5C7505A127B65FDB00BE3227 /* CIMetaView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIMetaView.swift; sourceTree = "<group>"; }; 5C7505A127B65FDB00BE3227 /* CIMetaView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIMetaView.swift; sourceTree = "<group>"; };
5C7505A427B679EE00BE3227 /* NavLinkPlain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavLinkPlain.swift; sourceTree = "<group>"; }; 5C7505A427B679EE00BE3227 /* NavLinkPlain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavLinkPlain.swift; sourceTree = "<group>"; };
5C7505A727B6D34800BE3227 /* ChatInfoToolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatInfoToolbar.swift; sourceTree = "<group>"; }; 5C7505A727B6D34800BE3227 /* ChatInfoToolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatInfoToolbar.swift; sourceTree = "<group>"; };
@@ -353,6 +354,11 @@
5C9CC7AC28C55D7800BEF955 /* DatabaseEncryptionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatabaseEncryptionView.swift; sourceTree = "<group>"; }; 5C9CC7AC28C55D7800BEF955 /* DatabaseEncryptionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatabaseEncryptionView.swift; sourceTree = "<group>"; };
5C9D13A2282187BB00AB8B43 /* WebRTC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebRTC.swift; sourceTree = "<group>"; }; 5C9D13A2282187BB00AB8B43 /* WebRTC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebRTC.swift; sourceTree = "<group>"; };
5C9D81182AA7A4F1001D49FD /* CryptoFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CryptoFile.swift; sourceTree = "<group>"; }; 5C9D81182AA7A4F1001D49FD /* CryptoFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CryptoFile.swift; sourceTree = "<group>"; };
5C9F3DD12BFBCDD80003B86B /* libHSsimplex-chat-5.8.0.2-8RkLdmy05dJBsgWrGV50Uf-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.8.0.2-8RkLdmy05dJBsgWrGV50Uf-ghc9.6.3.a"; sourceTree = "<group>"; };
5C9F3DD22BFBCDD80003B86B /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
5C9F3DD32BFBCDD80003B86B /* libHSsimplex-chat-5.8.0.2-8RkLdmy05dJBsgWrGV50Uf.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.8.0.2-8RkLdmy05dJBsgWrGV50Uf.a"; sourceTree = "<group>"; };
5C9F3DD42BFBCDD90003B86B /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
5C9F3DD52BFBCDD90003B86B /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
5C9FD96A27A56D4D0075386C /* JSON.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSON.swift; sourceTree = "<group>"; }; 5C9FD96A27A56D4D0075386C /* JSON.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSON.swift; sourceTree = "<group>"; };
5C9FD96D27A5D6ED0075386C /* SendMessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendMessageView.swift; sourceTree = "<group>"; }; 5C9FD96D27A5D6ED0075386C /* SendMessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendMessageView.swift; sourceTree = "<group>"; };
5CA059C3279559F40002BEB4 /* SimpleXApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleXApp.swift; sourceTree = "<group>"; }; 5CA059C3279559F40002BEB4 /* SimpleXApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleXApp.swift; sourceTree = "<group>"; };
@@ -434,7 +440,6 @@
5CEACCEC27DEA495000BD591 /* MsgContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MsgContentView.swift; sourceTree = "<group>"; }; 5CEACCEC27DEA495000BD591 /* MsgContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MsgContentView.swift; sourceTree = "<group>"; };
5CEBD7452A5C0A8F00665FE2 /* KeyboardPadding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardPadding.swift; sourceTree = "<group>"; }; 5CEBD7452A5C0A8F00665FE2 /* KeyboardPadding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardPadding.swift; sourceTree = "<group>"; };
5CEBD7472A5F115D00665FE2 /* SetDeliveryReceiptsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetDeliveryReceiptsView.swift; sourceTree = "<group>"; }; 5CEBD7472A5F115D00665FE2 /* SetDeliveryReceiptsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetDeliveryReceiptsView.swift; sourceTree = "<group>"; };
5CF9371D2B23429500E1D781 /* ConcurrentQueue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConcurrentQueue.swift; sourceTree = "<group>"; };
5CF9371F2B24DE8C00E1D781 /* SharedFileSubscriber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedFileSubscriber.swift; sourceTree = "<group>"; }; 5CF9371F2B24DE8C00E1D781 /* SharedFileSubscriber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedFileSubscriber.swift; sourceTree = "<group>"; };
5CF937212B25034A00E1D781 /* NSESubscriber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSESubscriber.swift; sourceTree = "<group>"; }; 5CF937212B25034A00E1D781 /* NSESubscriber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSESubscriber.swift; sourceTree = "<group>"; };
5CFA59C32860BC6200863A68 /* MigrateToAppGroupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrateToAppGroupView.swift; sourceTree = "<group>"; }; 5CFA59C32860BC6200863A68 /* MigrateToAppGroupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrateToAppGroupView.swift; sourceTree = "<group>"; };
@@ -462,6 +467,7 @@
646BB38D283FDB6D001CE359 /* LocalAuthenticationUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalAuthenticationUtils.swift; sourceTree = "<group>"; }; 646BB38D283FDB6D001CE359 /* LocalAuthenticationUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalAuthenticationUtils.swift; sourceTree = "<group>"; };
647F090D288EA27B00644C40 /* GroupMemberInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupMemberInfoView.swift; sourceTree = "<group>"; }; 647F090D288EA27B00644C40 /* GroupMemberInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupMemberInfoView.swift; sourceTree = "<group>"; };
648010AA281ADD15009009B9 /* CIFileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIFileView.swift; sourceTree = "<group>"; }; 648010AA281ADD15009009B9 /* CIFileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIFileView.swift; sourceTree = "<group>"; };
648679AA2BC96A74006456E7 /* ChatItemForwardingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatItemForwardingView.swift; sourceTree = "<group>"; };
6493D667280ED77F007A76FB /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; }; 6493D667280ED77F007A76FB /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
649BCD9F280460FD00C3A862 /* ComposeImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeImageView.swift; sourceTree = "<group>"; }; 649BCD9F280460FD00C3A862 /* ComposeImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeImageView.swift; sourceTree = "<group>"; };
649BCDA12805D6EF00C3A862 /* CIImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIImageView.swift; sourceTree = "<group>"; }; 649BCDA12805D6EF00C3A862 /* CIImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIImageView.swift; sourceTree = "<group>"; };
@@ -479,6 +485,9 @@
8C69FE7C2B8C7D2700267E38 /* AppSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSettings.swift; sourceTree = "<group>"; }; 8C69FE7C2B8C7D2700267E38 /* AppSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSettings.swift; sourceTree = "<group>"; };
8C7D94992B88952700B7B9E1 /* MigrateToDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrateToDevice.swift; sourceTree = "<group>"; }; 8C7D94992B88952700B7B9E1 /* MigrateToDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrateToDevice.swift; sourceTree = "<group>"; };
8C7DF31F2B7CDB0A00C886D0 /* MigrateFromDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrateFromDevice.swift; sourceTree = "<group>"; }; 8C7DF31F2B7CDB0A00C886D0 /* MigrateFromDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrateFromDevice.swift; sourceTree = "<group>"; };
8C81482B2BD91CD4002CBEC3 /* AudioDevicePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioDevicePicker.swift; sourceTree = "<group>"; };
8CC4ED8F2BD7B8530078AEE8 /* CallAudioDeviceManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallAudioDeviceManager.swift; sourceTree = "<group>"; };
8CC956ED2BC0041000412A11 /* NetworkObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkObserver.swift; sourceTree = "<group>"; };
D72A9087294BD7A70047C86D /* NativeTextEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativeTextEditor.swift; sourceTree = "<group>"; }; D72A9087294BD7A70047C86D /* NativeTextEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativeTextEditor.swift; sourceTree = "<group>"; };
D741547729AF89AF0022400A /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.1.sdk/System/Library/Frameworks/StoreKit.framework; sourceTree = DEVELOPER_DIR; }; D741547729AF89AF0022400A /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.1.sdk/System/Library/Frameworks/StoreKit.framework; sourceTree = DEVELOPER_DIR; };
D741547929AF90B00022400A /* PushKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PushKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.1.sdk/System/Library/Frameworks/PushKit.framework; sourceTree = DEVELOPER_DIR; }; D741547929AF90B00022400A /* PushKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PushKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.1.sdk/System/Library/Frameworks/PushKit.framework; sourceTree = DEVELOPER_DIR; };
@@ -520,13 +529,13 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
5C746DB92BA0DA920049D734 /* libgmpxx.a in Frameworks */, 5C9F3DD92BFBCDD90003B86B /* libgmpxx.a in Frameworks */,
5C746DBA2BA0DA920049D734 /* libHSsimplex-chat-5.6.0.2-CrEKCx0J5BfIirfPSOWUVo.a in Frameworks */, 5C9F3DDA2BFBCDD90003B86B /* libgmp.a in Frameworks */,
5C9F3DD82BFBCDD90003B86B /* libHSsimplex-chat-5.8.0.2-8RkLdmy05dJBsgWrGV50Uf.a in Frameworks */,
5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */, 5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */,
5C746DB82BA0DA920049D734 /* libffi.a in Frameworks */, 5C9F3DD62BFBCDD90003B86B /* libHSsimplex-chat-5.8.0.2-8RkLdmy05dJBsgWrGV50Uf-ghc9.6.3.a in Frameworks */,
5C746DBC2BA0DA920049D734 /* libHSsimplex-chat-5.6.0.2-CrEKCx0J5BfIirfPSOWUVo-ghc9.6.3.a in Frameworks */,
5C746DBB2BA0DA920049D734 /* libgmp.a in Frameworks */,
5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */, 5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */,
5C9F3DD72BFBCDD90003B86B /* libffi.a in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -544,6 +553,8 @@
5C55A922283CEDE600C4E99E /* SoundPlayer.swift */, 5C55A922283CEDE600C4E99E /* SoundPlayer.swift */,
18415323A4082FC92887F906 /* WebRTCClient.swift */, 18415323A4082FC92887F906 /* WebRTCClient.swift */,
18415B08031E8FB0F7FC27F9 /* CallViewRenderers.swift */, 18415B08031E8FB0F7FC27F9 /* CallViewRenderers.swift */,
8CC4ED8F2BD7B8530078AEE8 /* CallAudioDeviceManager.swift */,
8C81482B2BD91CD4002CBEC3 /* AudioDevicePicker.swift */,
); );
path = Call; path = Call;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -582,6 +593,7 @@
5CBE6C11294487F7002D9531 /* VerifyCodeView.swift */, 5CBE6C11294487F7002D9531 /* VerifyCodeView.swift */,
5CBE6C132944CC12002D9531 /* ScanCodeView.swift */, 5CBE6C132944CC12002D9531 /* ScanCodeView.swift */,
64C06EB42A0A4A7C00792D4D /* ChatItemInfoView.swift */, 64C06EB42A0A4A7C00792D4D /* ChatItemInfoView.swift */,
648679AA2BC96A74006456E7 /* ChatItemForwardingView.swift */,
); );
path = Chat; path = Chat;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -589,11 +601,11 @@
5C764E5C279C70B7000C6508 /* Libraries */ = { 5C764E5C279C70B7000C6508 /* Libraries */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
5C746DB32BA0DA920049D734 /* libffi.a */, 5C9F3DD22BFBCDD80003B86B /* libffi.a */,
5C746DB62BA0DA920049D734 /* libgmp.a */, 5C9F3DD52BFBCDD90003B86B /* libgmp.a */,
5C746DB42BA0DA920049D734 /* libgmpxx.a */, 5C9F3DD42BFBCDD90003B86B /* libgmpxx.a */,
5C746DB72BA0DA920049D734 /* libHSsimplex-chat-5.6.0.2-CrEKCx0J5BfIirfPSOWUVo-ghc9.6.3.a */, 5C9F3DD12BFBCDD80003B86B /* libHSsimplex-chat-5.8.0.2-8RkLdmy05dJBsgWrGV50Uf-ghc9.6.3.a */,
5C746DB52BA0DA920049D734 /* libHSsimplex-chat-5.6.0.2-CrEKCx0J5BfIirfPSOWUVo.a */, 5C9F3DD32BFBCDD80003B86B /* libHSsimplex-chat-5.8.0.2-8RkLdmy05dJBsgWrGV50Uf.a */,
); );
path = Libraries; path = Libraries;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -622,6 +634,7 @@
5CB346E82869E8BA001FD2EF /* PushEnvironment.swift */, 5CB346E82869E8BA001FD2EF /* PushEnvironment.swift */,
5C93293E2928E0FD0090FFF9 /* AudioRecPlay.swift */, 5C93293E2928E0FD0090FFF9 /* AudioRecPlay.swift */,
5CBD2859295711D700EC2CF4 /* ImageUtils.swift */, 5CBD2859295711D700EC2CF4 /* ImageUtils.swift */,
8CC956ED2BC0041000412A11 /* NetworkObserver.swift */,
); );
path = Model; path = Model;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -797,7 +810,6 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
5CDCAD5128186DE400503DA2 /* SimpleX NSE.entitlements */, 5CDCAD5128186DE400503DA2 /* SimpleX NSE.entitlements */,
5CF9371D2B23429500E1D781 /* ConcurrentQueue.swift */,
5CDCAD472818589900503DA2 /* NotificationService.swift */, 5CDCAD472818589900503DA2 /* NotificationService.swift */,
5CDCAD492818589900503DA2 /* Info.plist */, 5CDCAD492818589900503DA2 /* Info.plist */,
5CB0BA862826CB3A00B3292C /* InfoPlist.strings */, 5CB0BA862826CB3A00B3292C /* InfoPlist.strings */,
@@ -1060,6 +1072,7 @@
uk, uk,
bg, bg,
tr, tr,
hu,
); );
mainGroup = 5CA059BD279559F40002BEB4; mainGroup = 5CA059BD279559F40002BEB4;
packageReferences = ( packageReferences = (
@@ -1157,6 +1170,7 @@
5C10D88828EED12E00E58BF0 /* ContactConnectionInfo.swift in Sources */, 5C10D88828EED12E00E58BF0 /* ContactConnectionInfo.swift in Sources */,
5CBE6C12294487F7002D9531 /* VerifyCodeView.swift in Sources */, 5CBE6C12294487F7002D9531 /* VerifyCodeView.swift in Sources */,
3CDBCF4227FAE51000354CDD /* ComposeLinkView.swift in Sources */, 3CDBCF4227FAE51000354CDD /* ComposeLinkView.swift in Sources */,
648679AB2BC96A74006456E7 /* ChatItemForwardingView.swift in Sources */,
64466DC829FC2B3B00E3D48D /* CreateSimpleXAddress.swift in Sources */, 64466DC829FC2B3B00E3D48D /* CreateSimpleXAddress.swift in Sources */,
3CDBCF4827FF621E00354CDD /* CILinkView.swift in Sources */, 3CDBCF4827FF621E00354CDD /* CILinkView.swift in Sources */,
5C7505A827B6D34800BE3227 /* ChatInfoToolbar.swift in Sources */, 5C7505A827B6D34800BE3227 /* ChatInfoToolbar.swift in Sources */,
@@ -1175,6 +1189,7 @@
5C9A5BDB2871E05400A5B906 /* SetNotificationsMode.swift in Sources */, 5C9A5BDB2871E05400A5B906 /* SetNotificationsMode.swift in Sources */,
5CB0BA8E2827126500B3292C /* OnboardingView.swift in Sources */, 5CB0BA8E2827126500B3292C /* OnboardingView.swift in Sources */,
6442E0BE2880182D00CEC0F9 /* GroupChatInfoView.swift in Sources */, 6442E0BE2880182D00CEC0F9 /* GroupChatInfoView.swift in Sources */,
8CC956EE2BC0041000412A11 /* NetworkObserver.swift in Sources */,
5C2E261227A30FEA00F70299 /* TerminalView.swift in Sources */, 5C2E261227A30FEA00F70299 /* TerminalView.swift in Sources */,
5C9FD96E27A5D6ED0075386C /* SendMessageView.swift in Sources */, 5C9FD96E27A5D6ED0075386C /* SendMessageView.swift in Sources */,
5CA7DFC329302AF000F7FDDE /* AppSheet.swift in Sources */, 5CA7DFC329302AF000F7FDDE /* AppSheet.swift in Sources */,
@@ -1228,6 +1243,7 @@
5CB346E52868AA7F001FD2EF /* SuspendChat.swift in Sources */, 5CB346E52868AA7F001FD2EF /* SuspendChat.swift in Sources */,
5C9C2DA52894777E00CC63B1 /* GroupProfileView.swift in Sources */, 5C9C2DA52894777E00CC63B1 /* GroupProfileView.swift in Sources */,
5CEACCED27DEA495000BD591 /* MsgContentView.swift in Sources */, 5CEACCED27DEA495000BD591 /* MsgContentView.swift in Sources */,
8C81482C2BD91CD4002CBEC3 /* AudioDevicePicker.swift in Sources */,
5CCB939C297EFCB100399E78 /* NavStackCompat.swift in Sources */, 5CCB939C297EFCB100399E78 /* NavStackCompat.swift in Sources */,
5C764E89279CBCB3000C6508 /* ChatModel.swift in Sources */, 5C764E89279CBCB3000C6508 /* ChatModel.swift in Sources */,
5C971E1D27AEBEF600C8A3CE /* ChatInfoView.swift in Sources */, 5C971E1D27AEBEF600C8A3CE /* ChatInfoView.swift in Sources */,
@@ -1257,6 +1273,7 @@
18415B0585EB5A9A0A7CA8CD /* PressedButtonStyle.swift in Sources */, 18415B0585EB5A9A0A7CA8CD /* PressedButtonStyle.swift in Sources */,
1841560FD1CD447955474C1D /* UserProfilesView.swift in Sources */, 1841560FD1CD447955474C1D /* UserProfilesView.swift in Sources */,
64C3B0212A0D359700E19930 /* CustomTimePicker.swift in Sources */, 64C3B0212A0D359700E19930 /* CustomTimePicker.swift in Sources */,
8CC4ED902BD7B8530078AEE8 /* CallAudioDeviceManager.swift in Sources */,
18415C6C56DBCEC2CBBD2F11 /* WebRTCClient.swift in Sources */, 18415C6C56DBCEC2CBBD2F11 /* WebRTCClient.swift in Sources */,
184152CEF68D2336FC2EBCB0 /* CallViewRenderers.swift in Sources */, 184152CEF68D2336FC2EBCB0 /* CallViewRenderers.swift in Sources */,
5CB634AD29E46CF70066AD6B /* LocalAuthView.swift in Sources */, 5CB634AD29E46CF70066AD6B /* LocalAuthView.swift in Sources */,
@@ -1281,7 +1298,6 @@
files = ( files = (
5CDCAD482818589900503DA2 /* NotificationService.swift in Sources */, 5CDCAD482818589900503DA2 /* NotificationService.swift in Sources */,
5CFE0922282EEAF60002594B /* ZoomableScrollView.swift in Sources */, 5CFE0922282EEAF60002594B /* ZoomableScrollView.swift in Sources */,
5CF9371E2B23429500E1D781 /* ConcurrentQueue.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -1351,6 +1367,7 @@
5C636F672AAB3D2400751C84 /* uk */, 5C636F672AAB3D2400751C84 /* uk */,
5C5B67932ABAF56000DA9412 /* bg */, 5C5B67932ABAF56000DA9412 /* bg */,
5C245F3E2B501F13001CC39F /* tr */, 5C245F3E2B501F13001CC39F /* tr */,
5C371E502BA9AB6400100AD3 /* hu */,
); );
name = InfoPlist.strings; name = InfoPlist.strings;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -1374,6 +1391,7 @@
5CE6C7B42AAB1527007F345C /* uk */, 5CE6C7B42AAB1527007F345C /* uk */,
5C5B67912ABAF4B500DA9412 /* bg */, 5C5B67912ABAF4B500DA9412 /* bg */,
5C245F3C2B501E98001CC39F /* tr */, 5C245F3C2B501E98001CC39F /* tr */,
5C371E4E2BA9AAA200100AD3 /* hu */,
); );
name = Localizable.strings; name = Localizable.strings;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -1396,6 +1414,7 @@
5C636F662AAB3D2400751C84 /* uk */, 5C636F662AAB3D2400751C84 /* uk */,
5C5B67922ABAF56000DA9412 /* bg */, 5C5B67922ABAF56000DA9412 /* bg */,
5C245F3D2B501F13001CC39F /* tr */, 5C245F3D2B501F13001CC39F /* tr */,
5C371E4F2BA9AB6400100AD3 /* hu */,
); );
name = "SimpleX--iOS--InfoPlist.strings"; name = "SimpleX--iOS--InfoPlist.strings";
sourceTree = "<group>"; sourceTree = "<group>";
@@ -1438,6 +1457,7 @@
CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = dwarf; DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES; ENABLE_TESTABILITY = YES;
@@ -1499,6 +1519,7 @@
CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO; ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
@@ -1527,12 +1548,16 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES; ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements"; CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 202; CURRENT_PROJECT_VERSION = 218;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T; DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
ENABLE_PREVIEWS = YES; ENABLE_PREVIEWS = YES;
GCC_OPTIMIZATION_LEVEL = s;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = "SimpleX--iOS--Info.plist"; INFOPLIST_FILE = "SimpleX--iOS--Info.plist";
INFOPLIST_KEY_NSCameraUsageDescription = "SimpleX needs camera access to scan QR codes to connect to other users and for video calls."; INFOPLIST_KEY_NSCameraUsageDescription = "SimpleX needs camera access to scan QR codes to connect to other users and for video calls.";
@@ -1551,11 +1576,13 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 5.6; LLVM_LTO = YES_THIN;
MARKETING_VERSION = 5.8;
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app; PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app;
PRODUCT_NAME = SimpleX; PRODUCT_NAME = SimpleX;
SDKROOT = iphoneos; SDKROOT = iphoneos;
SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OPTIMIZATION_LEVEL = "-O";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1; TARGETED_DEVICE_FAMILY = 1;
}; };
@@ -1570,12 +1597,16 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES; ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements"; CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 202; CURRENT_PROJECT_VERSION = 218;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T; DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
ENABLE_PREVIEWS = YES; ENABLE_CODE_COVERAGE = NO;
ENABLE_PREVIEWS = NO;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = "SimpleX--iOS--Info.plist"; INFOPLIST_FILE = "SimpleX--iOS--Info.plist";
INFOPLIST_KEY_NSCameraUsageDescription = "SimpleX needs camera access to scan QR codes to connect to other users and for video calls."; INFOPLIST_KEY_NSCameraUsageDescription = "SimpleX needs camera access to scan QR codes to connect to other users and for video calls.";
@@ -1594,7 +1625,8 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 5.6; LLVM_LTO = YES;
MARKETING_VERSION = 5.8;
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app; PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app;
PRODUCT_NAME = SimpleX; PRODUCT_NAME = SimpleX;
SDKROOT = iphoneos; SDKROOT = iphoneos;
@@ -1650,12 +1682,15 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements"; CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 202; CURRENT_PROJECT_VERSION = 218;
DEVELOPMENT_TEAM = 5NN7GUYB6T; DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
GCC_OPTIMIZATION_LEVEL = s;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = "SimpleX NSE/Info.plist"; INFOPLIST_FILE = "SimpleX NSE/Info.plist";
INFOPLIST_KEY_CFBundleDisplayName = "SimpleX NSE"; INFOPLIST_KEY_CFBundleDisplayName = "SimpleX NSE";
@@ -1666,13 +1701,15 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
"@executable_path/../../Frameworks", "@executable_path/../../Frameworks",
); );
MARKETING_VERSION = 5.6; LLVM_LTO = YES;
MARKETING_VERSION = 5.8;
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-NSE"; PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-NSE";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
SDKROOT = iphoneos; SDKROOT = iphoneos;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Osize";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1; TARGETED_DEVICE_FAMILY = 1;
}; };
@@ -1682,12 +1719,15 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements"; CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 202; CURRENT_PROJECT_VERSION = 218;
DEVELOPMENT_TEAM = 5NN7GUYB6T; DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
ENABLE_CODE_COVERAGE = NO;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = "SimpleX NSE/Info.plist"; INFOPLIST_FILE = "SimpleX NSE/Info.plist";
INFOPLIST_KEY_CFBundleDisplayName = "SimpleX NSE"; INFOPLIST_KEY_CFBundleDisplayName = "SimpleX NSE";
@@ -1698,13 +1738,15 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
"@executable_path/../../Frameworks", "@executable_path/../../Frameworks",
); );
MARKETING_VERSION = 5.6; LLVM_LTO = YES;
MARKETING_VERSION = 5.8;
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-NSE"; PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-NSE";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
SDKROOT = iphoneos; SDKROOT = iphoneos;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Osize";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1; TARGETED_DEVICE_FAMILY = 1;
VALIDATE_PRODUCT = YES; VALIDATE_PRODUCT = YES;
@@ -1716,14 +1758,17 @@
buildSettings = { buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES; APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 202; CURRENT_PROJECT_VERSION = 218;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T; DEVELOPMENT_TEAM = 5NN7GUYB6T;
DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1; DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath"; DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
GCC_OPTIMIZATION_LEVEL = s;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2022 SimpleX Chat. All rights reserved."; INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2022 SimpleX Chat. All rights reserved.";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
@@ -1741,7 +1786,8 @@
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/Libraries/sim", "$(PROJECT_DIR)/Libraries/sim",
); );
MARKETING_VERSION = 5.6; LLVM_LTO = YES;
MARKETING_VERSION = 5.8;
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.SimpleXChat; PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.SimpleXChat;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SDKROOT = iphoneos; SDKROOT = iphoneos;
@@ -1750,6 +1796,7 @@
SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_INCLUDE_PATHS = ""; SWIFT_INCLUDE_PATHS = "";
SWIFT_OBJC_BRIDGING_HEADER = ./SimpleXChat/SimpleX.h; SWIFT_OBJC_BRIDGING_HEADER = ./SimpleXChat/SimpleX.h;
SWIFT_OPTIMIZATION_LEVEL = "-O";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic"; VERSIONING_SYSTEM = "apple-generic";
@@ -1762,14 +1809,17 @@
buildSettings = { buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES; APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 202; CURRENT_PROJECT_VERSION = 218;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T; DEVELOPMENT_TEAM = 5NN7GUYB6T;
DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1; DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath"; DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
ENABLE_CODE_COVERAGE = NO;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2022 SimpleX Chat. All rights reserved."; INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2022 SimpleX Chat. All rights reserved.";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
@@ -1787,7 +1837,8 @@
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/Libraries/sim", "$(PROJECT_DIR)/Libraries/sim",
); );
MARKETING_VERSION = 5.6; LLVM_LTO = YES;
MARKETING_VERSION = 5.8;
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.SimpleXChat; PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.SimpleXChat;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SDKROOT = iphoneos; SDKROOT = iphoneos;
@@ -1796,6 +1847,7 @@
SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_INCLUDE_PATHS = ""; SWIFT_INCLUDE_PATHS = "";
SWIFT_OBJC_BRIDGING_HEADER = ./SimpleXChat/SimpleX.h; SWIFT_OBJC_BRIDGING_HEADER = ./SimpleXChat/SimpleX.h;
SWIFT_OPTIMIZATION_LEVEL = "-O";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES; VALIDATE_PRODUCT = YES;

Some files were not shown because too many files have changed in this diff Show More