Compare commits

..

67 Commits

Author SHA1 Message Date
Evgeny Poberezkin 02dc8a1597 Merge branch 'master' into contacts-ui-feature-branch 2024-07-01 11:30:47 +01:00
Evgeny Poberezkin 5907d8bd0c core: remove legacy agent stats (#4375) 2024-07-01 11:25:27 +01:00
sh 231082860e flatpak: verify app (#4379) 2024-07-01 09:34:38 +01:00
Evgeny Poberezkin 95c4e77075 Merge branch 'master' into contacts-ui-feature-branch 2024-06-30 23:42:48 +01:00
Evgeny Poberezkin c6366cb269 Merge branch 'stable' 2024-06-29 16:53:30 +01:00
sergeyshadok d066c66282 Update XFTP-SERVER.md (#4184)
Systemd itself uses %<something> tokens so %% needs to be used for specifiers

(https://www.freedesktop.org/software/systemd/man/latest/systemd.unit.html)
2024-06-29 16:50:28 +01:00
Evgeny Poberezkin fab3827697 core: fix markdown for trailing / and ) characters in the links (#4357) 2024-06-29 08:41:21 +01:00
Evgeny Poberezkin d8126e0cd0 website: update join team 2024-06-28 19:09:01 +01:00
sh 5baf8789d6 flatpak: add desktop and metainfo (#4366)
* flatpak: add desktop and metainfo

* metainfo: update

* corrections

* ampersand

* shorter

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-06-28 10:09:34 +01:00
Evgeny Poberezkin dd5454f390 Merge branch 'stable' 2024-06-28 00:12:10 +01:00
Evgeny Poberezkin fca098f535 docs: update donation addresses 2024-06-28 00:10:51 +01:00
spaced4ndy fba0478e50 docs: more additions to chat protocol (#4355)
* docs: more additions to chat protocol

* schema wip

* schema

* update diagram

* remove comments

* punctuation

* diagram text

* update threat model

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2024-06-25 08:37:54 +01:00
spaced4ndy d951003191 core: servers summary api (#4319)
* core: servers summary api

* rework

* server known types

* set stats file path

* rename

* local simplexmq

* update

* rfc

* update

* update

* get servers

* compile summary

* remove sort

* rename

* rename, refactor

* refactor attempt

* refactor attempt 2

* refactor

* fix

* fix2

* remove space

* refactor xftp

* update

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2024-06-25 09:51:55 +04:00
spaced4ndy 1af513c548 docs: update chat protocol (#4344) 2024-06-23 20:36:25 +01:00
Evgeny Poberezkin 85dc467f74 5.8.1: ios 225, android 221, desktop 54 2024-06-19 23:41:23 +01:00
spaced4ndy 89e65c2fc1 multiplatform: check preferences before share/forward (#4338) 2024-06-19 18:53:45 +04:00
Evgeny Poberezkin 0fa8d77214 ios: fix search disappearing in forward view (#4337)
* ios: fix search disappearing in forward view

* update

* diff

* refactor

* use List
2024-06-19 12:51:56 +01:00
spaced4ndy 6ba82c8c39 ios: check preferences before forward (#4336)
* ios: check preferences before forward

* rework

* clean up

* shorter message

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2024-06-19 13:49:44 +04:00
Evgeny Poberezkin e19c14b249 ios: update core library to 5.8.1 2024-06-19 10:12:22 +01:00
Evgeny Poberezkin d993381d31 Revert "web: glossary fix (#4298)"
This reverts commit d3274b28ba.
2024-06-18 23:44:58 +01:00
Evgeny Poberezkin 0198c1f110 core: 5.8.1.0 2024-06-18 23:12:27 +01:00
spaced4ndy 6c4c9b172c core: fix markdown check (#4334)
* core: fix markdown

* more tests

* enable tests

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2024-06-18 12:44:33 -07:00
spaced4ndy d9a61af401 core: fix preference application (#4330) 2024-06-18 10:37:45 +04:00
spaced4ndy a58522ef15 core: api to reconnect single server (#4317) 2024-06-17 11:52:55 +04:00
Evgeny Poberezkin bcd510c913 cli: option to confirm up migrations (#4150)
* cli: option to confirm up migrations

* fix test
2024-06-16 20:24:37 -07:00
M. Sarmad Qadeer c4083e00c5 web: update feed (#4255)
* web: update feed

* change date filter in feed.rss
2024-06-16 14:31:36 -07:00
M. Sarmad Qadeer 7cd35b9068 web: design fixes eg: blog titles & link wrap (#4305)
Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2024-06-16 14:22:53 -07:00
M. Sarmad Qadeer d3274b28ba web: glossary fix (#4298) 2024-06-16 08:23:40 -07:00
Narasimha-sc 40bd5dc2da web: update copyright year 2023->2024 (#4297)
* Update copyright year

* Update ar.json

* Update bg.json

* Update cs.json

* Update de.json

* Update es.json

* Update fr.json

* Update hu.json

* Update it.json

* Update ja.json

* Update nl.json

* Update pl.json

* Update pt_BR.json

* Update ru.json
2024-06-16 08:19:43 -07:00
Evgeny Poberezkin 2a18770b96 Merge branch 'master' into contacts-ui-feature-branch 2024-06-11 11:18:39 +01:00
Diogo 1573b7af13 ios: prevented error on desktop in lack of camera permissions (#4306)
* refactor: 💡 moved ScannerInView to separate module

made it more extensible and ready to be reused

* fix: 🐛 prevented error on desktop in lack of camera permissions

right now, connect to desktop functionality was failing if you didn't
accept permissions before jumping to this screen for the first time. In
here I did pick from other sections where cases of no permissions or
unknown permissions were correctly handled and did reuse the same
mechanism

* chore: 🤖 reverted file move

* chore: 🤖 reverted class change

* chore: 🤖 reverted uncessary change

* chore: 🤖 removed leftover
2024-06-11 09:29:53 +04:00
Narasimha-sc a5bf3cbca8 v5.6 -> v5.8 (#4308) 2024-06-10 18:33:27 +01:00
Stanislav Dmitrenko d5529031ee android, desktop: socks proxy toggle enhancements (#4312) 2024-06-10 18:33:10 +01:00
spaced4ndy d244338b13 ui: differentiate remote ctrl errors, better error texts (#4302) 2024-06-10 18:18:05 +04:00
spaced4ndy ce55c84b96 core: differentiate RCP error in view, test (#4310) 2024-06-10 17:58:53 +04:00
spaced4ndy c52f9baefa desktop: close chat view when chat is stopped (#4313) 2024-06-10 13:11:35 +01:00
Stanislav Dmitrenko ea1c5da65d desktop: change thread who responsible for writting settings (#4311) 2024-06-10 13:05:53 +01:00
sh 5695bb9d46 docs: change smp webpage path (#4307) 2024-06-08 15:42:12 +01:00
spaced4ndy 13751d5705 core: update simplexmq (upload chunks after preparation) (#4299) 2024-06-06 16:09:56 +04:00
spaced4ndy 02803b1491 core: fix testXFTPRcvError test 2024-06-05 21:16:04 +04:00
spaced4ndy 222af69a71 multiplatform: file errors (#4289) 2024-06-05 21:03:59 +04:00
spaced4ndy 5e96e1ea2b ios: file errors (#4281) 2024-06-05 21:03:05 +04:00
spaced4ndy 490e8cead8 core: file errors (#4261) 2024-06-05 21:02:13 +04:00
Evgeny Poberezkin f578ee843b core: update simplexmq (remove protocol encodings) (#4272)
* core: update simplexmq (remove protocol encodings)

* nix

* update simplexmq

* update simplexmq
2024-06-05 20:49:01 +04:00
Evgeny Poberezkin cf2eb76cb7 website: update MoneroKon group link 2024-06-05 17:33:52 +01:00
Evgeny Poberezkin 48f9dcab9a blog: update image 2024-06-04 20:03:42 +01:00
Evgeny Poberezkin ac2ef54838 blog: v5.8 announcement (#4275)
* blog: v5.8 announcement

* update

* update

* update readme

* images, preview

* simplify

* spaces
2024-06-04 19:44:29 +01:00
Evgeny Poberezkin 7e269c6b8c android, desktop: enter app logic (#4288)
Co-authored-by: Avently <7953703+avently@users.noreply.github.com>
2024-06-04 15:59:23 +01:00
Stanislav Dmitrenko 3e739924bb android, desktop: prevent duplication of group in UI when creating one (#4284) 2024-06-04 15:59:02 +01:00
Stanislav Dmitrenko 83706b19da android, desktop: removed additional background under chat bubbles (#4287) 2024-06-04 15:58:29 +01:00
Stanislav Dmitrenko 6f19a7a20f android, desktop: fixes swipe to reply when animations were disabled in the OS (#4286) 2024-06-04 15:57:48 +01:00
spaced4ndy a8740cee4b core: fix cancellation of snd files without description (e.g. while being prepared for upload) (#4285) 2024-06-04 16:17:12 +04:00
sh 4000fe383d docs/smp-server: web server pages configuration and statistics update (#4279)
* docs/smp-server: web server pages configuration and statistics update

* update table

* update

* typo

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-06-03 20:29:12 +01:00
Evgeny Poberezkin dfdb3ca4a2 Merge branch 'master' into contacts-ui-feature-branch 2024-06-03 20:12:27 +01:00
Evgeny Poberezkin 75445e604e 5.8: ios 224, android 219, desktop 53 2024-06-03 14:05:59 +01:00
spaced4ndy 0596278e50 docs: flexible user records rfc (#4205) 2024-06-03 14:15:41 +04:00
spaced4ndy bd85b1063e multiplatform: contacts ui (#4214)
* types

* move stuff around

* move more stuff around

* padding

* tabs

* contacts list

* contact nav links, previews

* desktop list, better icon

* info

* refactor

* comments

* chat info buttons

* call buttons

* delete conversation dialogues

* change remember (contacts still don't update)

* contacts page refreshes on update

* delete contact dialogues

* move user picker to bottom left

* group member info buttons

* divider

* center on desktop

* comment

---------

Co-authored-by: Avently <7953703+avently@users.noreply.github.com>
2024-06-03 14:13:22 +04:00
spaced4ndy 55c1200007 Merge branch 'master' into contacts-ui-feature-branch 2024-06-03 12:51:30 +04:00
Stanislav Dmitrenko 7a77775a42 android, desktop: fix member search in group (#4277) 2024-06-03 08:25:08 +01:00
Evgeny Poberezkin dc8d08ec04 website: translations (#4274)
* Added translation using Weblate (Hungarian)

* Added translation using Weblate (Hungarian)

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

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/uk/

* Translated using Weblate (Hungarian)

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/hu/

* 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/

---------

Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: Maksym Lukashenko <livelmaxim@gmail.com>
Co-authored-by: summoner001 <summoner@vivaldi.net>
Co-authored-by: B.O.S.S <BxOxSxS@protonmail.com>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
2024-06-02 19:43:59 +01:00
Evgeny Poberezkin 4ad0e0f65e ui: translations (#4273)
* Translated using Weblate (Italian)

Currently translated at 100.0% (1819 of 1819 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% (1549 of 1549 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% (1819 of 1819 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% (1819 of 1819 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.8% (1547 of 1549 strings)

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

* Translated using Weblate (Ukrainian)

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

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

* Translated using Weblate (Turkish)

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

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

* Translated using Weblate (Turkish)

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

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

* Translated using Weblate (Hungarian)

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

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

* Translated using Weblate (Spanish)

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

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1823 of 1823 strings)

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

* Translated using Weblate (Persian)

Currently translated at 99.9% (1822 of 1823 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% (1819 of 1819 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% (1549 of 1549 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% (1819 of 1819 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% (1819 of 1819 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.8% (1547 of 1549 strings)

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

* Translated using Weblate (Ukrainian)

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

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

* Translated using Weblate (Turkish)

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

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

* Translated using Weblate (Turkish)

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

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

* Translated using Weblate (Hungarian)

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

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

* Translated using Weblate (Spanish)

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

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1823 of 1823 strings)

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

* Translated using Weblate (Persian)

Currently translated at 99.9% (1822 of 1823 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% (1823 of 1823 strings)

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

* Translated using Weblate (Romanian)

Currently translated at 13.0% (237 of 1823 strings)

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

* Translated using Weblate (German)

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

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

* Translated using Weblate (Spanish)

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

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

* Translated using Weblate (Polish)

Currently translated at 99.9% (1822 of 1823 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% (1549 of 1549 strings)

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

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (1823 of 1823 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 100.0% (1823 of 1823 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 17.6% (322 of 1823 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% (1549 of 1549 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% (1549 of 1549 strings)

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

* Translated using Weblate (Japanese)

Currently translated at 96.9% (1767 of 1823 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% (1823 of 1823 strings)

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

* Translated using Weblate (German)

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

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

* import/export localizations

---------

Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: Maksym Lukashenko <livelmaxim@gmail.com>
Co-authored-by: z0rden <kaanpeker196@gmail.com>
Co-authored-by: summoner001 <summoner@vivaldi.net>
Co-authored-by: J R <jr@simplex.chat>
Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com>
Co-authored-by: Ghost of Sparta <makesocialfoss32@keemail.me>
Co-authored-by: khalidbelk <khalid.belkassmi-el-hafi@epitech.eu>
Co-authored-by: Siavash <ciavash@proton.me>
Co-authored-by: Flavian <3zorro.1@gmail.com>
Co-authored-by: No name <CertainBot@users.noreply.hosted.weblate.org>
Co-authored-by: B.O.S.S <BxOxSxS@protonmail.com>
Co-authored-by: Ninja Left <s1lntlwd@proton.me>
Co-authored-by: Miyu Sakatsuki <miyu-sakatsuki@outlook.jp>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
2024-06-02 19:20:46 +01:00
Evgeny Poberezkin d01515e755 blog: Protecting Children's Safety Requires End-to-End Encryption 2024-06-01 21:47:38 +01:00
spaced4ndy 7abcb6a449 Merge branch 'master' into contacts-ui-feature-branch 2024-05-20 18:59:56 +04:00
spaced4ndy a7cc8348fd ios: move Contacts views 2024-05-20 15:54:55 +04:00
spaced4ndy d1b44719f2 Merge branch 'master' into contacts-ui-feature-branch 2024-05-20 10:31:58 +04:00
spaced4ndy 995863d78b ios: contacts UI improvements 2024-05-20 10:22:03 +04:00
spaced4ndy 8f8601eaa4 ios: UI redesign, contacts (#4116)
* ios: chat delete mode api

* redesign wip

* wip

* filter button right of search

* rework navigation (mostly works?)

* remove modifier

* search in bottom bar

* make filter button easier to press

* increase button size

* customizable search position

* reverse chat list wip

* change material

* list going behind toolbars

* increase spacing

* rework wip

* rework, sheets

* more scale effect

* remove search buttons, rework filter button

* remove onboarding buttons

* scan/paste menu

* wip

* contacts wip

* sizes

* remove unnecessary modifier

* contacts navigation wip

* paddings

* rework chat info view approach

* comment

* comment

* verified marker

* comment

* fix list not updating

* delete contact/conversation

* delete via chat list (has bugs)

* comment

* swipe on contact list

* fixes

* buttons wip

* message button to open chat

* buttons disabled

* call buttons work from sheet

* call button from contacts

* fix buttons

* show keyboard attempts

* Revert "show keyboard attempts"

This reverts commit daa50d1aa9.

* comment

* mark contact chat as not deleted when opening from contacts

* move to old view

* dont reverse contacts in one-hand mode

* change icons

* simplify call buttons (revert to make calls from chat view)

* top bar, reduce padding

* increase filter button size

* support for contact cards

* fix some delete conversation bugs

* fix chat not being removed from list on deleting conversation

* add to app settings

* member view buttons

* icons

* remove unused code

* padding

* avatar

* resize avatar

* button

* add open button for deleted contact

* add deletedByUser status

* rework delete actions

* filter button in contacts list

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-05-13 17:04:46 +04:00
188 changed files with 8393 additions and 1513 deletions
+11 -10
View File
@@ -158,20 +158,19 @@ We are prioritizing users privacy and security - it would be impossible without
Our pledge to our users is that SimpleX protocols are and will remain open, and in public domain, - so anybody can build the future implementations of the clients and the servers. We are building SimpleX platform based on the same principles as email and web, but much more private and secure.
Your donations help us raise more funds any amount, even the price of the cup of coffee, would make a big difference for us.
Your donations help us raise more funds - any amount, even the price of the cup of coffee, would make a big difference for us.
It is possible to donate via:
- [GitHub](https://github.com/sponsors/simplex-chat) - it is commission-free for us.
- [OpenCollective](https://opencollective.com/simplex-chat) - it charges a commission, and also accepts donations in crypto-currencies.
- [GitHub](https://github.com/sponsors/simplex-chat) (commission-free) or [OpenCollective](https://opencollective.com/simplex-chat) (~10% commission).
- Bitcoin: bc1qd74rc032ek2knhhr3yjq2ajzc5enz3h4qwnxad
- Monero: 8568eeVjaJ1RQ65ZUn9PRQ8ENtqeX9VVhcCYYhnVLxhV4JtBqw42so2VEUDQZNkFfsH5sXCuV7FN8VhRQ21DkNibTZP57Qt
- Bitcoin: 1bpefFkzuRoMY3ZuBbZNZxycbg7NYPYTG
- BCH: 1bpefFkzuRoMY3ZuBbZNZxycbg7NYPYTG
- BCH: bitcoincash:qq6c8vfvxqrk6rhdysgvkhqc24sggkfsx5nqvdlqcg
- Ethereum: 0xD9ee7Db0AD0dc1Dfa7eD53290199ED06beA04692
- USDT:
- BNB Smart Chain: 0x83fd788f7241a2be61780ea9dc72d2151e6843e2
- Tron: TNnTrKLBmdy2Wn3cAQR98dAVvWhLskQGfW
- Ethereum: 0x83fd788f7241a2be61780ea9dc72d2151e6843e2
- Solana: 43tWFWDczgAcn4Rzwkpqg2mqwnQETSiTwznmCgA2tf1L
- Ethereum: 0xD9ee7Db0AD0dc1Dfa7eD53290199ED06beA04692
- Solana: 7JCf5m3TiHmYKZVr6jCu1KeZVtb9Y1jRMQDU69p5ARnu
- please ask if you want to donate any other coins.
Thank you,
@@ -234,6 +233,8 @@ You can use SimpleX with your own servers and still communicate with people usin
Recent and important updates:
[Jun 4, 2024. SimpleX network: private message routing, v5.8 released with IP address protection and chat themes](./blog/20240604-simplex-chat-v5.8-private-message-routing-chat-themes.md)
[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)
@@ -382,10 +383,10 @@ Please also join [#simplex-devs](https://simplex.chat/contact#/?v=1-2&smp=smp%3A
- ✅ Private notes.
- ✅ Improve sending videos (including encryption of locally stored videos).
- ✅ Post-quantum resistant key exchange in double ratchet protocol.
- ✅ Message delivery relay for senders (to conceal IP address from the recipients' servers and to reduce the traffic).
- 🏗 Improve stability and reduce battery usage.
- 🏗 Improve experience for the new users.
- 🏗 Large groups, communities and public channels.
- 🏗 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.
- SMP queue redundancy and rotation (manual is supported).
- Include optional message into connection request sent via contact address.
+1 -1
View File
@@ -230,7 +230,7 @@ struct ContentView: View {
private func mainView() -> some View {
ZStack(alignment: .top) {
ChatListView(showSettings: $showSettings).privacySensitive(protectScreen)
HomeView(showSettings: $showSettings).privacySensitive(protectScreen)
.onAppear {
requestNtfAuthorization()
// Local Authentication notice is to be shown on next start after onboarding is complete
+84 -6
View File
@@ -744,21 +744,37 @@ func apiConnectContactViaAddress(incognito: Bool, contactId: Int64) async -> (Co
return (nil, alert)
}
func apiDeleteChat(type: ChatType, id: Int64, notify: Bool? = nil) async throws {
func apiDeleteChat(type: ChatType, id: Int64, chatDeleteMode: ChatDeleteMode = .full(notify: true)) async throws {
let chatId = type.rawValue + id.description
DispatchQueue.main.async { ChatModel.shared.deletedChats.insert(chatId) }
defer { DispatchQueue.main.async { ChatModel.shared.deletedChats.remove(chatId) } }
let r = await chatSendCmd(.apiDeleteChat(type: type, id: id, notify: notify), bgTask: false)
let r = await chatSendCmd(.apiDeleteChat(type: type, id: id, chatDeleteMode: chatDeleteMode), bgTask: false)
if case .direct = type, case .contactDeleted = r { return }
if case .contactConnection = type, case .contactConnectionDeleted = r { return }
if case .group = type, case .groupDeletedUser = r { return }
throw r
}
func deleteChat(_ chat: Chat, notify: Bool? = nil) async {
func apiDeleteContact(id: Int64, chatDeleteMode: ChatDeleteMode = .full(notify: true)) async throws -> Contact {
let type: ChatType = .direct
let chatId = type.rawValue + id.description
if case .full = chatDeleteMode {
DispatchQueue.main.async { ChatModel.shared.deletedChats.insert(chatId) }
}
defer {
if case .full = chatDeleteMode {
DispatchQueue.main.async { ChatModel.shared.deletedChats.remove(chatId) }
}
}
let r = await chatSendCmd(.apiDeleteChat(type: type, id: id, chatDeleteMode: chatDeleteMode), bgTask: false)
if case let .contactDeleted(_, contact) = r { return contact }
throw r
}
func deleteChat(_ chat: Chat, chatDeleteMode: ChatDeleteMode = .full(notify: true)) async {
do {
let cInfo = chat.chatInfo
try await apiDeleteChat(type: cInfo.chatType, id: cInfo.apiId, notify: notify)
try await apiDeleteChat(type: cInfo.chatType, id: cInfo.apiId, chatDeleteMode: chatDeleteMode)
DispatchQueue.main.async { ChatModel.shared.removeChat(cInfo.id) }
} catch let error {
logger.error("deleteChat apiDeleteChat error: \(responseError(error))")
@@ -769,6 +785,39 @@ func deleteChat(_ chat: Chat, notify: Bool? = nil) async {
}
}
func deleteChatContact(_ chat: Chat, chatDeleteMode: ChatDeleteMode = .full(notify: true)) async {
do {
let cInfo = chat.chatInfo
let ct = try await apiDeleteContact(id: cInfo.apiId, chatDeleteMode: chatDeleteMode)
DispatchQueue.main.async {
switch chatDeleteMode {
case .full:
ChatModel.shared.removeChat(cInfo.id)
case .entity:
// removeChat forces list update (for ContactsView)
ChatModel.shared.removeChat(cInfo.id)
ChatModel.shared.addChat(Chat(
chatInfo: .direct(contact: ct),
chatItems: chat.chatItems
))
case .messages:
// removeChat forces list update (for ChatListView)
ChatModel.shared.removeChat(cInfo.id)
ChatModel.shared.addChat(Chat(
chatInfo: .direct(contact: ct),
chatItems: []
))
}
}
} catch let error {
logger.error("deleteChatContact apiDeleteContact error: \(responseError(error))")
AlertManager.shared.showAlertMsg(
title: "Error deleting chat!",
message: "Error: \(responseError(error))"
)
}
}
func apiClearChat(type: ChatType, id: Int64) async throws -> ChatInfo {
let r = await chatSendCmd(.apiClearChat(type: type, id: id), bgTask: false)
if case let .chatCleared(_, updatedChatInfo) = r { return updatedChatInfo }
@@ -1655,6 +1704,11 @@ func processReceivedMsg(_ res: ChatResponse) async {
let cItem = aChatItem.chatItem
await MainActor.run {
if active(user) {
if case let .direct(contact) = cInfo, contact.chatDeleted {
var updatedContact = contact
updatedContact.chatDeleted = false
m.updateContact(updatedContact)
}
m.addChatItem(cInfo, cItem)
} else if cItem.isRcvNew && cInfo.ntfsEnabled {
m.increaseUnreadCounter(user: user)
@@ -1826,11 +1880,15 @@ func processReceivedMsg(_ res: ChatResponse) async {
if let aChatItem = aChatItem {
await chatItemSimpleUpdate(user, aChatItem)
}
case let .rcvFileError(user, aChatItem, _):
case let .rcvFileError(user, aChatItem, _, _):
if let aChatItem = aChatItem {
await chatItemSimpleUpdate(user, aChatItem)
Task { cleanupFile(aChatItem) }
}
case let .rcvFileWarning(user, aChatItem, _, _):
if let aChatItem = aChatItem {
await chatItemSimpleUpdate(user, aChatItem)
}
case let .sndFileStart(user, aChatItem, _):
await chatItemSimpleUpdate(user, aChatItem)
case let .sndFileComplete(user, aChatItem, _):
@@ -1852,6 +1910,10 @@ func processReceivedMsg(_ res: ChatResponse) async {
await chatItemSimpleUpdate(user, aChatItem)
Task { cleanupFile(aChatItem) }
}
case let .sndFileWarning(user, aChatItem, _, _):
if let aChatItem = aChatItem {
await chatItemSimpleUpdate(user, aChatItem)
}
case let .callInvitation(invitation):
await MainActor.run {
m.callInvitations[invitation.contact.id] = invitation
@@ -1949,12 +2011,28 @@ func processReceivedMsg(_ res: ChatResponse) async {
let state = UIRemoteCtrlSessionState.connected(remoteCtrl: remoteCtrl, sessionCode: m.remoteCtrlSession?.sessionCode ?? "")
m.remoteCtrlSession = m.remoteCtrlSession?.updateState(state)
}
case .remoteCtrlStopped:
case let .remoteCtrlStopped(_, rcStopReason):
// This delay is needed to cancel the session that fails on network failure,
// e.g. when user did not grant permission to access local network yet.
if let sess = m.remoteCtrlSession {
await MainActor.run {
m.remoteCtrlSession = nil
dismissAllSheets() {
switch rcStopReason {
case .connectionFailed(.errorAgent(.RCP(.identity))):
AlertManager.shared.showAlertMsg(
title: "Connection with desktop stopped",
message: "This link was used with another mobile device, please create a new link on the desktop."
)
default:
AlertManager.shared.showAlert(Alert(
title: Text("Connection with desktop stopped"),
message: Text("Please check that mobile and desktop are connected to the same local network, and that desktop firewall allows the connection.\nPlease share any other issues with the developers."),
primaryButton: .default(Text("Ok")),
secondaryButton: .default(Text("Copy error")) { UIPasteboard.general.string = String(describing: rcStopReason) }
))
}
}
}
if case .connected = sess.sessionState {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
+238 -32
View File
@@ -88,21 +88,36 @@ enum SendReceipts: Identifiable, Hashable {
}
}
enum ContactDeleteMode {
case full
case entity
public func toChatDeleteMode(notify: Bool) -> ChatDeleteMode {
switch self {
case .full: .full(notify: notify)
case .entity: .entity(notify: notify)
}
}
}
struct ChatInfoView: View {
@EnvironmentObject var chatModel: ChatModel
@Environment(\.dismiss) var dismiss: DismissAction
var openedFromChatView: Bool
@ObservedObject var chat: Chat
@State var contact: Contact
@Binding var connectionStats: ConnectionStats?
@Binding var customUserProfile: Profile?
@State var localAlias: String
@Binding var connectionCode: String?
@State private var connectionStats: ConnectionStats? = nil
@State private var customUserProfile: Profile? = nil
@State private var connectionCode: String? = nil
@FocusState private var aliasTextFieldFocused: Bool
@State private var alert: ChatInfoViewAlert? = nil
@State private var showDeleteContactActionSheet = false
@State private var actionSheet: ChatInfoViewActionSheet? = nil
@State private var showConnectContactViaAddressDialog = false
@State private var sendReceipts = SendReceipts.userDefault(true)
@State private var sendReceiptsUserDefault = true
@AppStorage(DEFAULT_DEVELOPER_TOOLS) private var developerTools = false
@AppStorage(DEFAULT_SHOW_DELETE_CONTACT_NOTICE) private var showDeleteContactNotice = true
enum ChatInfoViewAlert: Identifiable {
case clearChatAlert
@@ -110,6 +125,7 @@ struct ChatInfoView: View {
case switchAddressAlert
case abortSwitchAddressAlert
case syncConnectionForceAlert
case deleteContactNotice
case queueInfo(info: String)
case error(title: LocalizedStringKey, error: LocalizedStringKey = "")
@@ -120,12 +136,25 @@ struct ChatInfoView: View {
case .switchAddressAlert: return "switchAddressAlert"
case .abortSwitchAddressAlert: return "abortSwitchAddressAlert"
case .syncConnectionForceAlert: return "syncConnectionForceAlert"
case .deleteContactNotice: return "deleteContactNotice"
case let .queueInfo(info): return "queueInfo \(info)"
case let .error(title, _): return "error \(title)"
}
}
}
enum ChatInfoViewActionSheet: Identifiable {
case deleteContactActionSheet
case confirmDeleteContactActionSheet(contactDeleteMode: ContactDeleteMode)
var id: String {
switch self {
case .deleteContactActionSheet: return "deleteContactActionSheet"
case .confirmDeleteContactActionSheet: return "confirmDeleteContactActionSheet"
}
}
}
var body: some View {
NavigationView {
List {
@@ -142,6 +171,23 @@ struct ChatInfoView: View {
.listRowBackground(Color.clear)
.listRowSeparator(.hidden)
HStack {
if contact.activeConn == nil && contact.profile.contactLink != nil && contact.active {
connectButton()
} else if !contact.active && !contact.chatDeleted {
openButton()
} else {
messageButton()
}
Spacer()
callButton()
Spacer()
videoButton()
}
.padding(.horizontal)
.listRowBackground(Color.clear)
.listRowSeparator(.hidden)
if let customUserProfile = customUserProfile {
Section("Incognito") {
HStack {
@@ -161,9 +207,9 @@ struct ChatInfoView: View {
connStats.ratchetSyncAllowed {
synchronizeConnectionButton()
}
// } else if developerTools {
// synchronizeConnectionButtonForce()
// }
// } else if developerTools {
// synchronizeConnectionButtonForce()
// }
}
.disabled(!contact.ready || !contact.active)
@@ -249,6 +295,23 @@ struct ChatInfoView: View {
sendReceiptsUserDefault = currentUser.sendRcptsContacts
}
sendReceipts = SendReceipts.fromBool(contact.chatSettings.sendRcpts, userDefault: sendReceiptsUserDefault)
Task {
do {
let (stats, profile) = try await apiContactInfo(chat.chatInfo.apiId)
let (ct, code) = try await apiGetContactCode(chat.chatInfo.apiId)
await MainActor.run {
connectionStats = stats
customUserProfile = profile
connectionCode = code
if contact.activeConn?.connectionCode != ct.activeConn?.connectionCode {
chat.chatInfo = .direct(contact: ct)
}
}
} catch let error {
logger.error("apiContactInfo or apiGetContactCode error: \(responseError(error))")
}
}
}
.alert(item: $alert) { alertItem in
switch(alertItem) {
@@ -257,28 +320,47 @@ struct ChatInfoView: View {
case .switchAddressAlert: return switchAddressAlert(switchContactAddress)
case .abortSwitchAddressAlert: return abortSwitchAddressAlert(abortSwitchContactAddress)
case .syncConnectionForceAlert: return syncConnectionForceAlert({ syncContactConnection(force: true) })
case .deleteContactNotice: return deleteContactNotice(contact)
case let .queueInfo(info): return queueInfoAlert(info)
case let .error(title, error): return mkAlert(title: title, message: error)
}
}
.actionSheet(isPresented: $showDeleteContactActionSheet) {
if contact.ready && contact.active {
return ActionSheet(
title: Text("Delete contact?\nThis cannot be undone!"),
buttons: [
.destructive(Text("Delete and notify contact")) { deleteContact(notify: true) },
.destructive(Text("Delete")) { deleteContact(notify: false) },
.cancel()
]
.actionSheet(item: $actionSheet) { sheet in
switch(sheet) {
case .deleteContactActionSheet:
var sheetButtons: [ActionSheet.Button] = []
sheetButtons.append(
.destructive(Text("Delete contact")) { actionSheet = .confirmDeleteContactActionSheet(contactDeleteMode: .full) }
)
} else {
if !contact.chatDeleted {
sheetButtons.append(
.destructive(Text("Delete contact, keep conversation")) { actionSheet = .confirmDeleteContactActionSheet(contactDeleteMode: .entity) }
)
}
sheetButtons.append(.cancel())
return ActionSheet(
title: Text("Delete contact?\nThis cannot be undone!"),
buttons: [
.destructive(Text("Delete")) { deleteContact() },
.cancel()
]
title: Text("Delete contact?"),
buttons: sheetButtons
)
case let .confirmDeleteContactActionSheet(contactDeleteMode):
if contact.ready && contact.active {
return ActionSheet(
title: Text("Notify contact?\nThis cannot be undone!"),
buttons: [
.destructive(Text("Delete and notify contact")) { deleteContact(chatDeleteMode: contactDeleteMode.toChatDeleteMode(notify: true)) },
.destructive(Text("Delete without notification")) { deleteContact(chatDeleteMode: contactDeleteMode.toChatDeleteMode(notify: false)) },
.cancel()
]
)
} else {
return ActionSheet(
title: Text("Confirm contact deletion.\nThis cannot be undone!"),
buttons: [
.destructive(Text("Delete")) { deleteContact(chatDeleteMode: contactDeleteMode.toChatDeleteMode(notify: false)) },
.cancel()
]
)
}
}
}
}
@@ -349,6 +431,83 @@ struct ChatInfoView: View {
}
}
// when contact is a "contact card"
private func connectButton() -> some View {
InfoViewActionButtonLayout(image: "message.fill", title: "connect")
.onTapGesture {
showConnectContactViaAddressDialog = true
}
.confirmationDialog("Connect with \(contact.chatViewName)", isPresented: $showConnectContactViaAddressDialog, titleVisibility: .visible) {
Button("Use current profile") { connectContactViaAddress_(contact, false) }
Button("Use new incognito profile") { connectContactViaAddress_(contact, true) }
}
}
private func connectContactViaAddress_(_ contact: Contact, _ incognito: Bool) {
Task {
let ok = await connectContactViaAddress(contact.contactId, incognito)
if ok {
await MainActor.run {
if openedFromChatView {
dismiss()
} else {
if contact.chatDeleted {
var updatedContact = contact
updatedContact.chatDeleted = false
chatModel.updateContact(updatedContact)
}
chatModel.chatId = chat.id
}
}
}
}
}
private func openButton() -> some View {
InfoViewActionButtonLayout(image: "message.fill", title: "open")
.onTapGesture {
if openedFromChatView {
dismiss()
} else {
chatModel.chatId = chat.id
}
}
}
// TODO show keyboard
private func messageButton() -> some View {
InfoViewActionButtonLayout(image: "message.fill", title: "message")
.onTapGesture {
if openedFromChatView {
dismiss()
} else {
if contact.chatDeleted {
var updatedContact = contact
updatedContact.chatDeleted = false
chatModel.updateContact(updatedContact)
}
chatModel.chatId = chat.id
}
}
.disabled(!contact.sendMsgEnabled)
}
private func callButton() -> some View {
InfoViewActionButtonLayout(image: "phone.fill", title: "call")
.onTapGesture {
CallController.shared.startCall(contact, .audio)
}
.disabled(!contact.ready || !contact.active || !contact.mergedPreferences.calls.enabled.forUser || chatModel.activeCall != nil)
}
private func videoButton() -> some View {
InfoViewActionButtonLayout(image: "video.fill", title: "video")
.onTapGesture {
CallController.shared.startCall(contact, .video)
}
.disabled(!contact.ready || !contact.active || !contact.mergedPreferences.calls.enabled.forUser || chatModel.activeCall != nil)
}
private func verifyCodeButton(_ code: String) -> some View {
NavigationLink {
VerifyCodeView(
@@ -452,9 +611,9 @@ struct ChatInfoView: View {
private func deleteContactButton() -> some View {
Button(role: .destructive) {
showDeleteContactActionSheet = true
actionSheet = .deleteContactActionSheet
} label: {
Label("Delete contact", systemImage: "trash")
Label("Delete contact", systemImage: "person.badge.minus")
.foregroundColor(Color.red)
}
}
@@ -468,17 +627,34 @@ struct ChatInfoView: View {
}
}
private func deleteContact(notify: Bool? = nil) {
private func deleteContact(chatDeleteMode: ChatDeleteMode) {
Task {
do {
try await apiDeleteChat(type: chat.chatInfo.chatType, id: chat.chatInfo.apiId, notify: notify)
let ct = try await apiDeleteContact(id: chat.chatInfo.apiId, chatDeleteMode: chatDeleteMode)
await MainActor.run {
dismiss()
chatModel.chatId = nil
chatModel.removeChat(chat.chatInfo.id)
switch chatDeleteMode {
case .full:
chatModel.removeChat(chat.chatInfo.id)
case .entity:
chatModel.updateContact(ct)
// dismissing sheet when opened from ChatView closes deleteContactNotice alert,
// also it makes less sense to show this alert as user is already in Chats tab
if showDeleteContactNotice && !openedFromChatView {
alert = .deleteContactNotice
}
case .messages:
logger.warning("ChatInfoView deleteContact case .messages should be unreachable")
chatModel.removeChat(chat.chatInfo.id)
chatModel.addChat(Chat(
chatInfo: .direct(contact: ct),
chatItems: []
))
}
}
} catch let error {
logger.error("deleteContactAlert apiDeleteChat error: \(responseError(error))")
logger.error("ChatInfoView deleteContact apiDeleteContact error: \(responseError(error))")
let a = getErrorAlert(error, "Error deleting contact")
await MainActor.run {
alert = .error(title: a.title, error: a.message)
@@ -563,6 +739,38 @@ struct ChatInfoView: View {
}
}
}
private func deleteContactNotice(_ contact: Contact) -> Alert {
return Alert(
title: Text("Contact deleted!"),
message: Text("You can still view conversation with \(contact.displayName) in the Chats tab."),
primaryButton: .default(Text("Don't show again")) {
showDeleteContactNotice = false
},
secondaryButton: .default(Text("Ok"))
)
}
}
struct InfoViewActionButtonLayout: View {
var image: String
var title: LocalizedStringKey
var body: some View {
VStack(spacing: 4) {
Image(systemName: image)
.resizable()
.scaledToFit()
.frame(width: 24, height: 24)
Text(title)
.font(.caption)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.foregroundColor(.accentColor)
.background(Color(.secondarySystemGroupedBackground))
.cornerRadius(12.0)
.frame(width: 90, height: 60)
}
}
func switchAddressAlert(_ switchAddress: @escaping () -> Void) -> Alert {
@@ -611,12 +819,10 @@ func queueInfoAlert(_ info: String) -> Alert {
struct ChatInfoView_Previews: PreviewProvider {
static var previews: some View {
ChatInfoView(
openedFromChatView: true,
chat: Chat(chatInfo: ChatInfo.sampleData.direct, chatItems: []),
contact: Contact.sampleData,
connectionStats: Binding.constant(nil),
customUserProfile: Binding.constant(nil),
localAlias: "",
connectionCode: Binding.constant(nil)
localAlias: ""
)
}
}
@@ -56,14 +56,16 @@ struct CIFileView: View {
case .sndTransfer: return false
case .sndComplete: return true
case .sndCancelled: return false
case .sndError: return false
case .sndError: return true
case .sndWarning: return true
case .rcvInvitation: return true
case .rcvAccepted: return true
case .rcvTransfer: return false
case .rcvAborted: return true
case .rcvComplete: return true
case .rcvCancelled: return false
case .rcvError: return false
case .rcvError: return true
case .rcvWarning: return true
case .invalid: return false
}
}
@@ -108,6 +110,18 @@ struct CIFileView: View {
if let fileSource = getLoadedFileSource(file) {
saveCryptoFile(fileSource)
}
case let .rcvError(rcvFileError):
logger.debug("CIFileView fileAction - in .rcvError")
AlertManager.shared.showAlert(Alert(
title: Text("File error"),
message: Text(rcvFileError.errorInfo)
))
case let .rcvWarning(rcvFileError):
logger.debug("CIFileView fileAction - in .rcvWarning")
AlertManager.shared.showAlert(Alert(
title: Text("Temporary file error"),
message: Text(rcvFileError.errorInfo)
))
case .sndStored:
logger.debug("CIFileView fileAction - in .sndStored")
if file.fileProtocol == .local, let fileSource = getLoadedFileSource(file) {
@@ -118,6 +132,18 @@ struct CIFileView: View {
if let fileSource = getLoadedFileSource(file) {
saveCryptoFile(fileSource)
}
case let .sndError(sndFileError):
logger.debug("CIFileView fileAction - in .sndError")
AlertManager.shared.showAlert(Alert(
title: Text("File error"),
message: Text(sndFileError.errorInfo)
))
case let .sndWarning(sndFileError):
logger.debug("CIFileView fileAction - in .sndWarning")
AlertManager.shared.showAlert(Alert(
title: Text("Temporary file error"),
message: Text(sndFileError.errorInfo)
))
default: break
}
}
@@ -141,6 +167,7 @@ struct CIFileView: View {
case .sndComplete: fileIcon("doc.fill", innerIcon: "checkmark", innerIconSize: 10)
case .sndCancelled: fileIcon("doc.fill", innerIcon: "xmark", innerIconSize: 10)
case .sndError: fileIcon("doc.fill", innerIcon: "xmark", innerIconSize: 10)
case .sndWarning: fileIcon("doc.fill", innerIcon: "exclamationmark.triangle.fill", innerIconSize: 10)
case .rcvInvitation:
if fileSizeValid(file) {
fileIcon("arrow.down.doc.fill", color: .accentColor)
@@ -159,6 +186,7 @@ struct CIFileView: View {
case .rcvComplete: fileIcon("doc.fill")
case .rcvCancelled: fileIcon("doc.fill", innerIcon: "xmark", innerIconSize: 10)
case .rcvError: fileIcon("doc.fill", innerIcon: "xmark", innerIconSize: 10)
case .rcvWarning: fileIcon("doc.fill", innerIcon: "exclamationmark.triangle.fill", innerIconSize: 10)
case .invalid: fileIcon("doc.fill", innerIcon: "questionmark", innerIconSize: 10)
}
} else {
@@ -60,6 +60,26 @@ struct CIImageView: View {
case .rcvTransfer: () // ?
case .rcvComplete: () // ?
case .rcvCancelled: () // TODO
case let .rcvError(rcvFileError):
AlertManager.shared.showAlert(Alert(
title: Text("File error"),
message: Text(rcvFileError.errorInfo)
))
case let .rcvWarning(rcvFileError):
AlertManager.shared.showAlert(Alert(
title: Text("Temporary file error"),
message: Text(rcvFileError.errorInfo)
))
case let .sndError(sndFileError):
AlertManager.shared.showAlert(Alert(
title: Text("File error"),
message: Text(sndFileError.errorInfo)
))
case let .sndWarning(sndFileError):
AlertManager.shared.showAlert(Alert(
title: Text("Temporary file error"),
message: Text(sndFileError.errorInfo)
))
default: ()
}
}
@@ -99,14 +119,16 @@ struct CIImageView: View {
case .sndComplete: fileIcon("checkmark", 10, 13)
case .sndCancelled: fileIcon("xmark", 10, 13)
case .sndError: fileIcon("xmark", 10, 13)
case .sndWarning: fileIcon("exclamationmark.triangle.fill", 10, 13)
case .rcvInvitation: fileIcon("arrow.down", 10, 13)
case .rcvAccepted: fileIcon("ellipsis", 14, 11)
case .rcvTransfer: progressView()
case .rcvAborted: fileIcon("exclamationmark.arrow.circlepath", 14, 11)
case .rcvComplete: EmptyView()
case .rcvCancelled: fileIcon("xmark", 10, 13)
case .rcvError: fileIcon("xmark", 10, 13)
case .rcvWarning: fileIcon("exclamationmark.triangle.fill", 10, 13)
case .invalid: fileIcon("questionmark", 10, 13)
default: EmptyView()
}
}
}
@@ -192,7 +192,7 @@ struct CIVideoView: View {
.disabled(!canBePlayed)
}
}
loadingIndicator()
fileStatusIcon()
}
.onAppear {
addObserver(player, url)
@@ -258,11 +258,11 @@ struct CIVideoView: View {
.resizable()
.scaledToFit()
.frame(width: w)
loadingIndicator()
fileStatusIcon()
}
}
@ViewBuilder private func loadingIndicator() -> some View {
@ViewBuilder private func fileStatusIcon() -> some View {
if let file = chatItem.file {
switch file.fileStatus {
case .sndStored:
@@ -279,7 +279,22 @@ struct CIVideoView: View {
}
case .sndComplete: fileIcon("checkmark", 10, 13)
case .sndCancelled: fileIcon("xmark", 10, 13)
case .sndError: fileIcon("xmark", 10, 13)
case let .sndError(sndFileError):
fileIcon("xmark", 10, 13)
.onTapGesture {
AlertManager.shared.showAlert(Alert(
title: Text("File error"),
message: Text(sndFileError.errorInfo)
))
}
case let .sndWarning(sndFileError):
fileIcon("exclamationmark.triangle.fill", 10, 13)
.onTapGesture {
AlertManager.shared.showAlert(Alert(
title: Text("Temporary file error"),
message: Text(sndFileError.errorInfo)
))
}
case .rcvInvitation: fileIcon("arrow.down", 10, 13)
case .rcvAccepted: fileIcon("ellipsis", 14, 11)
case let .rcvTransfer(rcvProgress, rcvTotal):
@@ -289,10 +304,25 @@ struct CIVideoView: View {
progressView()
}
case .rcvAborted: fileIcon("exclamationmark.arrow.circlepath", 14, 11)
case .rcvComplete: EmptyView()
case .rcvCancelled: fileIcon("xmark", 10, 13)
case .rcvError: fileIcon("xmark", 10, 13)
case let .rcvError(rcvFileError):
fileIcon("xmark", 10, 13)
.onTapGesture {
AlertManager.shared.showAlert(Alert(
title: Text("File error"),
message: Text(rcvFileError.errorInfo)
))
}
case let .rcvWarning(rcvFileError):
fileIcon("exclamationmark.triangle.fill", 10, 13)
.onTapGesture {
AlertManager.shared.showAlert(Alert(
title: Text("Temporary file error"),
message: Text(rcvFileError.errorInfo)
))
}
case .invalid: fileIcon("questionmark", 10, 13)
default: EmptyView()
}
}
}
@@ -134,18 +134,53 @@ struct VoiceMessagePlayer: View {
ZStack {
if let recordingFile = recordingFile {
switch recordingFile.fileStatus {
case .sndStored: playbackButton()
case .sndTransfer: playbackButton()
case .sndStored:
if recordingFile.fileProtocol == .local {
playbackButton()
} else {
loadingIcon()
}
case .sndTransfer: loadingIcon()
case .sndComplete: playbackButton()
case .sndCancelled: playbackButton()
case .sndError: playbackButton()
case let .sndError(sndFileError):
fileStatusIcon("multiply", 14)
.onTapGesture {
AlertManager.shared.showAlert(Alert(
title: Text("File error"),
message: Text(sndFileError.errorInfo)
))
}
case let .sndWarning(sndFileError):
fileStatusIcon("exclamationmark.triangle.fill", 16)
.onTapGesture {
AlertManager.shared.showAlert(Alert(
title: Text("Temporary file error"),
message: Text(sndFileError.errorInfo)
))
}
case .rcvInvitation: downloadButton(recordingFile, "play.fill")
case .rcvAccepted: loadingIcon()
case .rcvTransfer: loadingIcon()
case .rcvAborted: downloadButton(recordingFile, "exclamationmark.arrow.circlepath")
case .rcvComplete: playbackButton()
case .rcvCancelled: playPauseIcon("play.fill", Color(uiColor: .tertiaryLabel))
case .rcvError: playPauseIcon("play.fill", Color(uiColor: .tertiaryLabel))
case let .rcvError(rcvFileError):
fileStatusIcon("multiply", 14)
.onTapGesture {
AlertManager.shared.showAlert(Alert(
title: Text("File error"),
message: Text(rcvFileError.errorInfo)
))
}
case let .rcvWarning(rcvFileError):
fileStatusIcon("exclamationmark.triangle.fill", 16)
.onTapGesture {
AlertManager.shared.showAlert(Alert(
title: Text("Temporary file error"),
message: Text(rcvFileError.errorInfo)
))
}
case .invalid: playPauseIcon("play.fill", Color(uiColor: .tertiaryLabel))
}
} else {
@@ -246,6 +281,17 @@ struct VoiceMessagePlayer: View {
}
}
private func fileStatusIcon(_ image: String, _ size: CGFloat) -> some View {
Image(systemName: image)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: size, height: size)
.foregroundColor(Color(uiColor: .tertiaryLabel))
.frame(width: 56, height: 56)
.background(showBackground ? chatItemFrameColor(chatItem, colorScheme) : .clear)
.clipShape(Circle())
}
private func loadingIcon() -> some View {
ProgressView()
.frame(width: 30, height: 30)
@@ -19,6 +19,9 @@ struct ChatItemForwardingView: View {
@State private var searchText: String = ""
@FocusState private var searchFocused
@State private var alert: SomeAlert?
@State private var hasSimplexLink_: Bool?
private let chatsToForwardTo = filterChatsToForwardTo()
var body: some View {
NavigationView {
@@ -35,47 +38,29 @@ struct ChatItemForwardingView: View {
}
}
}
.alert(item: $alert) { $0.alert }
}
@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))
}
List {
searchFieldView(text: $searchText, focussed: $searchFocused)
.padding(.leading, 2)
let s = searchText.trimmingCharacters(in: .whitespaces).localizedLowercase
let chats = s == "" ? chatsToForwardTo : chatsToForwardTo.filter { foundChat($0, s) }
ForEach(chats) { chat in
forwardListChatView(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 {
private func foundChat(_ chat: Chat, _ searchStr: String) -> Bool {
let cInfo = chat.chatInfo
return switch cInfo {
case let .direct(contact):
@@ -91,42 +76,70 @@ struct ChatItemForwardingView: View {
}
}
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
private func prohibitedByPref(_ chat: Chat) -> Bool {
// preference checks should match checks in compose view
let simplexLinkProhibited = hasSimplexLink && !chat.groupFeatureEnabled(.simplexLinks)
let fileProhibited = (ci.content.msgContent?.isMediaOrFileAttachment ?? false) && !chat.groupFeatureEnabled(.files)
let voiceProhibited = (ci.content.msgContent?.isVoice ?? false) && !chat.chatInfo.featureEnabled(.voice)
return switch chat.chatInfo {
case .direct: voiceProhibited
case .group: simplexLinkProhibited || fileProhibited || voiceProhibited
case .local: false
case .contactRequest: false
case .contactConnection: false
case .invalidJSON: false
}
}
private var hasSimplexLink: Bool {
if let hasSimplexLink_ { return hasSimplexLink_ }
let r =
if let mcText = ci.content.msgContent?.text,
let parsedMsg = parseSimpleXMarkdown(mcText) {
parsedMsgHasSimplexLink(parsedMsg)
} else {
false
}
hasSimplexLink_ = r
return r
}
private func emptyList() -> some View {
Text("No filtered chats")
.foregroundColor(.secondary)
.frame(maxWidth: .infinity)
}
@ViewBuilder private func forwardListNavLinkView(_ chat: Chat) -> some View {
@ViewBuilder private func forwardListChatView(_ chat: Chat) -> some View {
let prohibited = prohibitedByPref(chat)
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)
)
if prohibited {
alert = SomeAlert(
alert: mkAlert(
title: "Cannot forward message",
message: "Selected chat preferences prohibit this message."
),
id: "forward prohibited by preferences"
)
} else {
composeState = ComposeState.init(forwardingItem: ci, fromChatInfo: fromChatInfo)
chatModel.chatId = chat.id
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)
.foregroundColor(prohibited ? .secondary : .primary)
.lineLimit(1)
if chat.chatInfo.incognito {
Spacer()
@@ -142,6 +155,27 @@ struct ChatItemForwardingView: View {
}
}
private func filterChatsToForwardTo() -> [Chat] {
var filteredChats = ChatModel.shared.chats.filter { c in
c.chatInfo.chatType != .local && canForwardToChat(c)
}
if let privateNotes = ChatModel.shared.chats.first(where: { $0.chatInfo.chatType == .local }) {
filteredChats.insert(privateNotes, at: 0)
}
return filteredChats
}
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
}
}
#Preview {
ChatItemForwardingView(
ci: ChatItem.getSample(1, .directSnd, .now, "hello"),
@@ -17,6 +17,8 @@ struct ChatItemInfoView: View {
@Binding var chatItemInfo: ChatItemInfo?
@State private var selection: CIInfoTab = .history
@State private var alert: CIInfoViewAlert? = nil
@State private var messageStatusLimited: Bool = true
@State private var fileStatusLimited: Bool = true
@AppStorage(DEFAULT_DEVELOPER_TOOLS) private var developerTools = false
enum CIInfoTab {
@@ -157,6 +159,35 @@ struct ChatItemInfoView: View {
if developerTools {
infoRow("Database ID", "\(meta.itemId)")
infoRow("Record updated at", localTimestamp(meta.updatedAt))
let msv = infoRow("Message status", ci.meta.itemStatus.id)
Group {
if messageStatusLimited {
msv.lineLimit(1)
} else {
msv
}
}
.onTapGesture {
withAnimation {
messageStatusLimited.toggle()
}
}
if let file = ci.file {
let fsv = infoRow("File status", file.fileStatus.id)
Group {
if fileStatusLimited {
fsv.lineLimit(1)
} else {
fsv
}
}
.onTapGesture {
withAnimation {
fileStatusLimited.toggle()
}
}
}
}
}
}
@@ -473,8 +504,12 @@ struct ChatItemInfoView: View {
if developerTools {
shareText += [
String.localizedStringWithFormat(NSLocalizedString("Database ID: %d", comment: "copied message info"), meta.itemId),
String.localizedStringWithFormat(NSLocalizedString("Record updated at: %@", comment: "copied message info"), localTimestamp(meta.updatedAt))
String.localizedStringWithFormat(NSLocalizedString("Record updated at: %@", comment: "copied message info"), localTimestamp(meta.updatedAt)),
String.localizedStringWithFormat(NSLocalizedString("Message status: %@", comment: "copied message info"), meta.itemStatus.id)
]
if let file = ci.file {
shareText += [String.localizedStringWithFormat(NSLocalizedString("File status: %@", comment: "copied message info"), file.fileStatus.id)]
}
}
if let qi = ci.quotedItem {
shareText += ["", NSLocalizedString("## In reply to", comment: "copied message info")]
+9 -26
View File
@@ -23,9 +23,6 @@ struct ChatView: View {
@State private var showAddMembersSheet: Bool = false
@State private var composeState = ComposeState()
@State private var keyboardVisible = false
@State private var connectionStats: ConnectionStats?
@State private var customUserProfile: Profile?
@State private var connectionCode: String?
@State private var tableView: UITableView?
@State private var loadingItems = false
@State private var firstPage = false
@@ -45,6 +42,7 @@ struct ChatView: View {
var body: some View {
if #available(iOS 16.0, *) {
viewBody
.toolbarBackground(.visible, for: .navigationBar)
.scrollDismissesKeyboard(.immediately)
.keyboardPadding()
} else {
@@ -111,32 +109,17 @@ struct ChatView: View {
ToolbarItem(placement: .principal) {
if case let .direct(contact) = cInfo {
Button {
Task {
do {
let (stats, profile) = try await apiContactInfo(chat.chatInfo.apiId)
let (ct, code) = try await apiGetContactCode(chat.chatInfo.apiId)
await MainActor.run {
connectionStats = stats
customUserProfile = profile
connectionCode = code
if contact.activeConn?.connectionCode != ct.activeConn?.connectionCode {
chat.chatInfo = .direct(contact: ct)
}
}
} catch let error {
logger.error("apiContactInfo or apiGetContactCode error: \(responseError(error))")
}
await MainActor.run { showChatInfoSheet = true }
}
showChatInfoSheet = true
} label: {
ChatInfoToolbar(chat: chat)
}
.appSheet(isPresented: $showChatInfoSheet, onDismiss: {
connectionStats = nil
customUserProfile = nil
connectionCode = nil
}) {
ChatInfoView(chat: chat, contact: contact, connectionStats: $connectionStats, customUserProfile: $customUserProfile, localAlias: chat.chatInfo.localAlias, connectionCode: $connectionCode)
.appSheet(isPresented: $showChatInfoSheet) {
ChatInfoView(
openedFromChatView: true,
chat: chat,
contact: contact,
localAlias: chat.chatInfo.localAlias
)
}
} else if case let .group(groupInfo) = cInfo {
Button {
@@ -286,6 +286,7 @@ struct ComposeView: View {
if chat.chatInfo.contact?.nextSendGrpInv ?? false {
ContextInvitingContactMemberView()
}
// preference checks should match checks in forwarding list
let simplexLinkProhibited = hasSimplexLink && !chat.groupFeatureEnabled(.simplexLinks)
let fileProhibited = composeState.attachmentPreview && !chat.groupFeatureEnabled(.files)
let voiceProhibited = composeState.voicePreview && !chat.chatInfo.featureEnabled(.voice)
@@ -1065,7 +1066,7 @@ struct ComposeView: View {
} else {
nil
}
let simplexLink = parsedMsg.contains(where: { ft in ft.format?.isSimplexLink ?? false })
let simplexLink = parsedMsgHasSimplexLink(parsedMsg)
return (url, simplexLink)
}
@@ -1105,6 +1106,10 @@ struct ComposeView: View {
}
}
func parsedMsgHasSimplexLink(_ parsedMsg: [FormattedText]) -> Bool {
parsedMsg.contains(where: { ft in ft.format?.isSimplexLink ?? false })
}
struct ComposeView_Previews: PreviewProvider {
static var previews: some View {
let chat = Chat(chatInfo: ChatInfo.sampleData.direct, chatItems: [])
@@ -64,10 +64,11 @@ struct GroupMemberInfoView: View {
}
}
private func knownDirectChat(_ contactId: Int64) -> Chat? {
private func knownDirectChat(_ contactId: Int64) -> (Chat, Contact)? {
if let chat = chatModel.getContactChat(contactId),
chat.chatInfo.contact?.directOrUsed == true {
return chat
let contact = chat.chatInfo.contact,
contact.directOrUsed == true {
return (chat, contact)
} else {
return nil
}
@@ -80,18 +81,35 @@ struct GroupMemberInfoView: View {
List {
groupMemberInfoHeader(member)
.listRowBackground(Color.clear)
.listRowSeparator(.hidden)
HStack {
if let contactId = member.memberContactId, let (chat, contact) = knownDirectChat(contactId) {
knownDirectChatButton(chat)
Spacer()
callButton(contact)
Spacer()
videoButton(contact)
} else if groupInfo.fullGroupPreferences.directMessages.on(for: groupInfo.membership) {
if let contactId = member.memberContactId {
newDirectChatButton(contactId)
} else if member.activeConn?.peerChatVRange.isCompatibleRange(CREATE_MEMBER_CONTACT_VRANGE) ?? false {
createMemberContactButton()
}
Spacer()
InfoViewActionButtonLayout(image: "phone.fill", title: "call")
.disabled(true)
Spacer()
InfoViewActionButtonLayout(image: "video.fill", title: "video")
.disabled(true)
}
}
.padding(.horizontal)
.listRowBackground(Color.clear)
.listRowSeparator(.hidden)
if member.memberActive {
Section {
if let contactId = member.memberContactId, let chat = knownDirectChat(contactId) {
knownDirectChatButton(chat)
} else if groupInfo.fullGroupPreferences.directMessages.on(for: groupInfo.membership) {
if let contactId = member.memberContactId {
newDirectChatButton(contactId)
} else if member.activeConn?.peerChatVRange.isCompatibleRange(CREATE_MEMBER_CONTACT_VRANGE) ?? false {
createMemberContactButton()
}
}
if let code = connectionCode { verifyCodeButton(code) }
if let connStats = connectionStats,
connStats.ratchetSyncAllowed {
@@ -264,58 +282,71 @@ struct GroupMemberInfoView: View {
}
func knownDirectChatButton(_ chat: Chat) -> some View {
Button {
dismissAllSheets(animated: true)
DispatchQueue.main.async {
chatModel.chatId = chat.id
}
} label: {
Label("Send direct message", systemImage: "message")
}
}
func newDirectChatButton(_ contactId: Int64) -> some View {
Button {
do {
let chat = try apiGetChat(type: .direct, id: contactId)
chatModel.addChat(chat)
InfoViewActionButtonLayout(image: "message.fill", title: "message")
.onTapGesture {
dismissAllSheets(animated: true)
DispatchQueue.main.async {
chatModel.chatId = chat.id
}
} catch let error {
logger.error("openDirectChatButton apiGetChat error: \(responseError(error))")
}
} label: {
Label("Send direct message", systemImage: "message")
}
}
func newDirectChatButton(_ contactId: Int64) -> some View {
InfoViewActionButtonLayout(image: "message.fill", title: "message")
.onTapGesture {
do {
let chat = try apiGetChat(type: .direct, id: contactId)
chatModel.addChat(chat)
dismissAllSheets(animated: true)
DispatchQueue.main.async {
chatModel.chatId = chat.id
}
} catch let error {
logger.error("openDirectChatButton apiGetChat error: \(responseError(error))")
}
}
}
func createMemberContactButton() -> some View {
Button {
progressIndicator = true
Task {
do {
let memberContact = try await apiCreateMemberContact(groupInfo.apiId, groupMember.groupMemberId)
await MainActor.run {
progressIndicator = false
chatModel.addChat(Chat(chatInfo: .direct(contact: memberContact)))
dismissAllSheets(animated: true)
chatModel.chatId = memberContact.id
chatModel.setContactNetworkStatus(memberContact, .connected)
}
} catch let error {
logger.error("createMemberContactButton apiCreateMemberContact error: \(responseError(error))")
let a = getErrorAlert(error, "Error creating member contact")
await MainActor.run {
progressIndicator = false
alert = .error(title: a.title, error: a.message)
InfoViewActionButtonLayout(image: "message.fill", title: "message")
.onTapGesture {
progressIndicator = true
Task {
do {
let memberContact = try await apiCreateMemberContact(groupInfo.apiId, groupMember.groupMemberId)
await MainActor.run {
progressIndicator = false
chatModel.addChat(Chat(chatInfo: .direct(contact: memberContact)))
dismissAllSheets(animated: true)
chatModel.chatId = memberContact.id
chatModel.setContactNetworkStatus(memberContact, .connected)
}
} catch let error {
logger.error("createMemberContactButton apiCreateMemberContact error: \(responseError(error))")
let a = getErrorAlert(error, "Error creating member contact")
await MainActor.run {
progressIndicator = false
alert = .error(title: a.title, error: a.message)
}
}
}
}
} label: {
Label("Send direct message", systemImage: "message")
}
}
private func callButton(_ contact: Contact) -> some View {
InfoViewActionButtonLayout(image: "phone.fill", title: "call")
.onTapGesture {
CallController.shared.startCall(contact, .audio)
}
.disabled(!contact.ready || !contact.active || !contact.mergedPreferences.calls.enabled.forUser || chatModel.activeCall != nil)
}
private func videoButton(_ contact: Contact) -> some View {
InfoViewActionButtonLayout(image: "video.fill", title: "video")
.onTapGesture {
CallController.shared.startCall(contact, .video)
}
.disabled(!contact.ready || !contact.active || !contact.mergedPreferences.calls.enabled.forUser || chatModel.activeCall != nil)
}
private func groupMemberInfoHeader(_ mem: GroupMember) -> some View {
@@ -63,7 +63,6 @@ struct ChatHelp: View {
struct ChatHelp_Previews: PreviewProvider {
static var previews: some View {
@State var showSettings = false
return ChatHelp(showSettings: $showSettings)
return ChatHelp(showSettings: Binding.constant(false))
}
}
@@ -32,11 +32,25 @@ struct ChatListNavLink: View {
@State private var showJoinGroupDialog = false
@State private var showContactConnectionInfo = false
@State private var showInvalidJSON = false
@State private var showDeleteContactActionSheet = false
@State private var contactNavLinkSheet: ContactNavLinkActionSheet? = nil
@State private var showConnectContactViaAddressDialog = false
@State private var inProgress = false
@State private var progressByTimeout = false
@AppStorage(DEFAULT_SHOW_DELETE_CONVERSATION_NOTICE) private var showDeleteConversationNotice = true
enum ContactNavLinkActionSheet: Identifiable {
case deleteContactActionSheet
case confirmDeleteContactActionSheet
var id: String {
switch self {
case .deleteContactActionSheet: return "deleteContactActionSheet"
case .confirmDeleteContactActionSheet: return "confirmDeleteContactActionSheet"
}
}
}
var body: some View {
Group {
switch chat.chatInfo {
@@ -67,12 +81,12 @@ struct ChatListNavLink: View {
@ViewBuilder private func contactNavLink(_ contact: Contact) -> some View {
Group {
if contact.activeConn == nil && contact.profile.contactLink != nil {
if contact.activeConn == nil && contact.profile.contactLink != nil && contact.active {
ChatPreviewView(chat: chat, progressByTimeout: Binding.constant(false))
.frame(height: rowHeights[dynamicTypeSize])
.swipeActions(edge: .trailing, allowsFullSwipe: true) {
Button {
showDeleteContactActionSheet = true
contactNavLinkSheet = .deleteContactActionSheet
} label: {
Label("Delete", systemImage: "trash")
}
@@ -100,7 +114,7 @@ struct ChatListNavLink: View {
}
Button {
if contact.ready || !contact.active {
showDeleteContactActionSheet = true
contactNavLinkSheet = .deleteContactActionSheet
} else {
AlertManager.shared.showAlert(deletePendingContactAlert(chat, contact))
}
@@ -112,24 +126,53 @@ struct ChatListNavLink: View {
.frame(height: rowHeights[dynamicTypeSize])
}
}
.actionSheet(isPresented: $showDeleteContactActionSheet) {
if contact.ready && contact.active {
return ActionSheet(
title: Text("Delete contact?\nThis cannot be undone!"),
buttons: [
.destructive(Text("Delete and notify contact")) { Task { await deleteChat(chat, notify: true) } },
.destructive(Text("Delete")) { Task { await deleteChat(chat, notify: false) } },
.cancel()
]
)
} else {
return ActionSheet(
title: Text("Delete contact?\nThis cannot be undone!"),
buttons: [
.destructive(Text("Delete")) { Task { await deleteChat(chat) } },
.cancel()
]
)
.actionSheet(item: $contactNavLinkSheet) { sheet in
switch(sheet) {
case .deleteContactActionSheet:
if contact.contactStatus == .deletedByUser {
return ActionSheet(
title: Text("Delete conversation?\nThis cannot be undone!"),
buttons: [
.destructive(Text("Delete conversation")) { Task { await deleteChatContact(chat, chatDeleteMode: .full(notify: false)) } },
.cancel()
]
)
} else {
return ActionSheet(
title: Text("Delete contact?"),
buttons: [
.destructive(Text("Delete contact")) { contactNavLinkSheet = .confirmDeleteContactActionSheet },
.destructive(Text("Only delete conversation")) {
Task {
await deleteChatContact(chat, chatDeleteMode: .messages)
if showDeleteConversationNotice {
AlertManager.shared.showAlert(deleteConversationNotice(contact))
}
}
},
.cancel()
]
)
}
case .confirmDeleteContactActionSheet:
if contact.ready && contact.active {
return ActionSheet(
title: Text("Notify contact?\nThis cannot be undone!"),
buttons: [
.destructive(Text("Delete and notify contact")) { Task { await deleteChatContact(chat, chatDeleteMode: .full(notify: true)) } },
.destructive(Text("Delete without notification")) { Task { await deleteChatContact(chat, chatDeleteMode: .full(notify: false)) } },
.cancel()
]
)
} else {
return ActionSheet(
title: Text("Confirm contact deletion.\nThis cannot be undone!"),
buttons: [
.destructive(Text("Delete")) { Task { await deleteChatContact(chat, chatDeleteMode: .full(notify: false)) } },
.cancel()
]
)
}
}
}
}
@@ -439,6 +482,17 @@ struct ChatListNavLink: View {
)
}
private func deleteConversationNotice(_ contact: Contact) -> Alert {
return Alert(
title: Text("Conversation deleted!"),
message: Text("You can still send messages to \(contact.displayName) from the Contacts tab."),
primaryButton: .default(Text("Don't show again")) {
showDeleteConversationNotice = false
},
secondaryButton: .default(Text("Ok"))
)
}
private func deletePendingContactAlert(_ chat: Chat, _ contact: Contact) -> Alert {
Alert(
title: Text("Delete pending connection"),
+37 -181
View File
@@ -11,16 +11,15 @@ import SimpleXChat
struct ChatListView: View {
@EnvironmentObject var chatModel: ChatModel
@Binding var showSettings: Bool
@State private var searchMode = false
@FocusState private var searchFocussed
@State private var searchText = ""
@State private var searchShowingSimplexLink = false
@State private var searchChatFilteredBySimplexLink: String? = nil
@State private var newChatMenuOption: NewChatMenuOption? = nil
@State private var userPickerVisible = false
@State private var showConnectDesktop = false
@AppStorage(DEFAULT_SHOW_UNREAD_AND_FAVORITES) private var showUnreadAndFavorites = false
@AppStorage(DEFAULT_ONE_HAND_UI) private var oneHandUI = false
var body: some View {
if #available(iOS 16.0, *) {
@@ -31,44 +30,10 @@ struct ChatListView: View {
}
private var viewBody: some View {
ZStack(alignment: .topLeading) {
NavStackCompat(
isActive: Binding(
get: { chatModel.chatId != nil },
set: { _ in }
),
destination: chatView
) {
VStack {
if chatModel.chats.isEmpty {
onboardingButtons()
}
chatListView
}
}
if userPickerVisible {
Rectangle().fill(.white.opacity(0.001)).onTapGesture {
withAnimation {
userPickerVisible.toggle()
}
}
}
UserPicker(
showSettings: $showSettings,
showConnectDesktop: $showConnectDesktop,
userPickerVisible: $userPickerVisible
)
}
.sheet(isPresented: $showConnectDesktop) {
ConnectDesktopView()
}
}
private var chatListView: some View {
VStack {
chatList
}
.onDisappear() { withAnimation { userPickerVisible = false } }
.scaleEffect(x: 1, y: oneHandUI ? -1 : 1, anchor: .center)
.refreshable {
AlertManager.shared.showAlert(Alert(
title: Text("Reconnect servers?"),
@@ -86,58 +51,6 @@ struct ChatListView: View {
))
}
.listStyle(.plain)
.navigationBarTitleDisplayMode(.inline)
.navigationBarHidden(searchMode)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
let user = chatModel.currentUser ?? User.sampleData
ZStack(alignment: .topTrailing) {
ProfileImage(imageStr: user.image, size: 32, color: Color(uiColor: .quaternaryLabel))
.padding(.trailing, 4)
let allRead = chatModel.users
.filter { u in !u.user.activeUser && !u.user.hidden }
.allSatisfy { u in u.unreadCount == 0 }
if !allRead {
unreadBadge(size: 12)
}
}
.onTapGesture {
if chatModel.users.filter({ u in u.user.activeUser || !u.user.hidden }).count > 1 {
withAnimation {
userPickerVisible.toggle()
}
} else {
showSettings = true
}
}
}
ToolbarItem(placement: .principal) {
HStack(spacing: 4) {
Text("Chats")
.font(.headline)
if chatModel.chats.count > 0 {
toggleFilterButton()
}
}
.frame(maxWidth: .infinity, alignment: .center)
}
ToolbarItem(placement: .navigationBarTrailing) {
switch chatModel.chatRunning {
case .some(true): NewChatMenuButton(newChatMenuOption: $newChatMenuOption)
case .some(false): chatStoppedIcon()
case .none: EmptyView()
}
}
}
}
private func toggleFilterButton() -> some View {
Button {
showUnreadAndFavorites = !showUnreadAndFavorites
} label: {
Image(systemName: "line.3.horizontal.decrease.circle" + (showUnreadAndFavorites ? ".fill" : ""))
.foregroundColor(.accentColor)
}
}
@ViewBuilder private var chatList: some View {
@@ -153,11 +66,13 @@ struct ChatListView: View {
searchShowingSimplexLink: $searchShowingSimplexLink,
searchChatFilteredBySimplexLink: $searchChatFilteredBySimplexLink
)
.scaleEffect(x: 1, y: oneHandUI ? -1 : 1, anchor: .center)
.listRowSeparator(.hidden)
.frame(maxWidth: .infinity)
}
ForEach(cs, id: \.viewId) { chat in
ChatListNavLink(chat: chat)
.scaleEffect(x: 1, y: oneHandUI ? -1 : 1, anchor: .center)
.padding(.trailing, -16)
.disabled(chatModel.chatRunning != true || chatModel.deletedChats.contains(chat.chatInfo.id))
}
@@ -171,7 +86,9 @@ struct ChatListView: View {
}
}
if cs.isEmpty && !chatModel.chats.isEmpty {
Text("No filtered chats").foregroundColor(.secondary)
Text("No filtered chats")
.scaleEffect(x: 1, y: oneHandUI ? -1 : 1, anchor: .center)
.foregroundColor(.secondary)
}
}
}
@@ -182,66 +99,24 @@ struct ChatListView: View {
.foregroundColor(.accentColor)
}
private func onboardingButtons() -> some View {
VStack(alignment: .trailing, spacing: 0) {
Path { p in
p.move(to: CGPoint(x: 8, y: 0))
p.addLine(to: CGPoint(x: 16, y: 10))
p.addLine(to: CGPoint(x: 0, y: 10))
p.addLine(to: CGPoint(x: 8, y: 0))
}
.fill(Color.accentColor)
.frame(width: 20, height: 10)
.padding(.trailing, 12)
connectButton("Tap to start a new chat") {
newChatMenuOption = .newContact
}
Spacer()
Text("You have no chats")
.foregroundColor(.secondary)
.frame(maxWidth: .infinity)
}
.padding(.trailing, 6)
.frame(maxHeight: .infinity)
}
private func connectButton(_ label: LocalizedStringKey, action: @escaping () -> Void) -> some View {
Button(action: action) {
Text(label)
.padding(.vertical, 10)
.padding(.horizontal, 20)
}
.background(Color.accentColor)
.foregroundColor(.white)
.clipShape(RoundedRectangle(cornerRadius: 16))
}
@ViewBuilder private func chatView() -> some View {
if let chatId = chatModel.chatId, let chat = chatModel.getChat(chatId) {
ChatView(chat: chat).onAppear {
loadChat(chat: chat)
}
}
}
private func filteredChats() -> [Chat] {
if let linkChatId = searchChatFilteredBySimplexLink {
return chatModel.chats.filter { $0.id == linkChatId }
} else {
let s = searchString()
return s == "" && !showUnreadAndFavorites
? chatModel.chats
? chatModel.chats.filter { chat in !chat.chatInfo.chatDeleted }
: chatModel.chats.filter { chat in
let cInfo = chat.chatInfo
switch cInfo {
case let .direct(contact):
return s == ""
? filtered(chat)
: (viewNameContains(cInfo, s) ||
contact.profile.displayName.localizedLowercase.contains(s) ||
contact.fullName.localizedLowercase.contains(s))
return !contact.chatDeleted && (
s == ""
? filtered(chat)
: (viewNameContains(cInfo, s) ||
contact.profile.displayName.localizedLowercase.contains(s) ||
contact.fullName.localizedLowercase.contains(s))
)
case let .group(gInfo):
return s == ""
? (filtered(chat) || gInfo.membership.memberStatus == .memInvited)
@@ -282,9 +157,9 @@ struct ChatListSearchBar: View {
@Binding var searchShowingSimplexLink: Bool
@Binding var searchChatFilteredBySimplexLink: String?
@State private var ignoreSearchTextChange = false
@State private var showScanCodeSheet = false
@State private var alert: PlanAndConnectAlert?
@State private var sheet: PlanAndConnectActionSheet?
@AppStorage(DEFAULT_SHOW_UNREAD_AND_FAVORITES) private var showUnreadAndFavorites = false
var body: some View {
VStack(spacing: 12) {
@@ -301,26 +176,6 @@ struct ChatListSearchBar: View {
.onTapGesture {
searchText = ""
}
} else if !searchFocussed {
HStack(spacing: 24) {
if m.pasteboardHasStrings {
Image(systemName: "doc")
.onTapGesture {
if let str = UIPasteboard.general.string {
searchText = str
}
}
}
Image(systemName: "qrcode")
.resizable()
.scaledToFit()
.frame(width: 20, height: 20)
.onTapGesture {
showScanCodeSheet = true
}
}
.padding(.trailing, 2)
}
}
.padding(EdgeInsets(top: 7, leading: 7, bottom: 7, trailing: 7))
@@ -335,13 +190,10 @@ struct ChatListSearchBar: View {
searchText = ""
searchFocussed = false
}
} else if m.chats.count > 0 {
toggleFilterButton()
}
}
Divider()
}
.sheet(isPresented: $showScanCodeSheet) {
NewChatView(selection: .connect, showQRCodeScanner: true)
.environment(\EnvironmentValues.refresh as! WritableKeyPath<EnvironmentValues, RefreshAction?>, nil) // fixes .refreshable in ChatListView affecting nested view
}
.onChange(of: searchFocussed) { sf in
withAnimation { searchMode = sf }
@@ -376,6 +228,21 @@ struct ChatListSearchBar: View {
}
}
private func toggleFilterButton() -> some View {
ZStack {
Color.clear
.frame(width: 22, height: 22)
Image(systemName: showUnreadAndFavorites ? "line.3.horizontal.decrease.circle.fill" : "line.3.horizontal.decrease")
.resizable()
.scaledToFit()
.foregroundColor(showUnreadAndFavorites ? .accentColor : .secondary)
.frame(width: showUnreadAndFavorites ? 22 : 16, height: showUnreadAndFavorites ? 22 : 16)
.onTapGesture {
showUnreadAndFavorites = !showUnreadAndFavorites
}
}
}
private func connect(_ link: String) {
planAndConnect(
link,
@@ -389,17 +256,6 @@ struct ChatListSearchBar: View {
}
}
func chatStoppedIcon() -> some View {
Button {
AlertManager.shared.showAlertMsg(
title: "Chat is stopped",
message: "You can start chat via app Settings / Database or by restarting the app"
)
} label: {
Image(systemName: "exclamationmark.octagon.fill").foregroundColor(.red)
}
}
struct ChatListView_Previews: PreviewProvider {
static var previews: some View {
let chatModel = ChatModel()
@@ -419,9 +275,9 @@ struct ChatListView_Previews: PreviewProvider {
]
return Group {
ChatListView(showSettings: Binding.constant(false))
ChatListView()
.environmentObject(chatModel)
ChatListView(showSettings: Binding.constant(false))
ChatListView()
.environmentObject(ChatModel())
}
}
@@ -204,7 +204,7 @@ struct ChatPreviewView: View {
} else {
switch (chat.chatInfo) {
case let .direct(contact):
if contact.activeConn == nil && contact.profile.contactLink != nil {
if contact.activeConn == nil && contact.profile.contactLink != nil && contact.active {
chatPreviewInfoText("Tap to Connect")
.foregroundColor(.accentColor)
} else if !contact.ready && contact.activeConn != nil {
@@ -0,0 +1,210 @@
//
// ContactListNavLink.swift
// SimpleX (iOS)
//
// Created by spaced4ndy on 06.05.2024.
// Copyright © 2024 SimpleX Chat. All rights reserved.
//
import SwiftUI
import SimpleXChat
struct ContactListNavLink: View {
@ObservedObject var chat: Chat
@State private var contactNavLinkSheet: ContactNavLinkActionSheet? = nil
@AppStorage(DEFAULT_SHOW_DELETE_CONTACT_NOTICE) private var showDeleteContactNotice = true
enum ContactNavLinkActionSheet: Identifiable {
case deleteContactActionSheet
case confirmDeleteContactActionSheet(contactDeleteMode: ContactDeleteMode)
var id: String {
switch self {
case .deleteContactActionSheet: return "deleteContactActionSheet"
case .confirmDeleteContactActionSheet: return "confirmDeleteContactActionSheet"
}
}
}
var body: some View {
switch chat.chatInfo {
case let .direct(contact):
NavigationLink {
ChatInfoView(
openedFromChatView: false,
chat: chat,
contact: contact,
localAlias: chat.chatInfo.localAlias
)
} label: {
HStack{
ZStack(alignment: .bottomTrailing) {
ProfileImage(imageStr: contact.image, size: 38)
chatPreviewImageOverlayIcon(contact)
.padding([.bottom, .trailing], 1)
}
.padding(.trailing, 2)
previewTitle(contact)
Spacer()
HStack {
if chat.chatInfo.chatSettings?.favorite ?? false {
Image(systemName: "star.fill")
.resizable()
.scaledToFill()
.frame(width: 18, height: 18)
.padding(.trailing, 1)
.foregroundColor(.secondary.opacity(0.65))
}
if contact.contactConnIncognito {
Image(systemName: "theatermasks")
.resizable()
.scaledToFit()
.frame(width: 22, height: 22)
.foregroundColor(.secondary)
}
}
}
}
.swipeActions(edge: .leading, allowsFullSwipe: true) {
toggleFavoriteButton()
}
.swipeActions(edge: .trailing, allowsFullSwipe: true) {
Button {
contactNavLinkSheet = .deleteContactActionSheet
} label: {
Label("Delete", systemImage: "person.badge.minus")
}
.tint(.red)
}
.actionSheet(item: $contactNavLinkSheet) { sheet in
switch(sheet) {
case .deleteContactActionSheet:
var sheetButtons: [ActionSheet.Button] = []
sheetButtons.append(
.destructive(Text("Delete contact")) { contactNavLinkSheet = .confirmDeleteContactActionSheet(contactDeleteMode: .full) }
)
if !contact.chatDeleted {
sheetButtons.append(
.destructive(Text("Delete contact, keep conversation")) { contactNavLinkSheet = .confirmDeleteContactActionSheet(contactDeleteMode: .entity) }
)
}
sheetButtons.append(.cancel())
return ActionSheet(
title: Text("Delete contact?"),
buttons: sheetButtons
)
case let .confirmDeleteContactActionSheet(contactDeleteMode):
if contact.ready && contact.active {
return ActionSheet(
title: Text("Notify contact?\nThis cannot be undone!"),
buttons: [
.destructive(Text("Delete and notify contact")) {
Task {
await deleteChatContact(chat, chatDeleteMode: contactDeleteMode.toChatDeleteMode(notify: true))
if contactDeleteMode == .entity && showDeleteContactNotice {
AlertManager.shared.showAlert(deleteContactNotice(contact))
}
}
},
.destructive(Text("Delete without notification")) {
Task {
await deleteChatContact(chat, chatDeleteMode: contactDeleteMode.toChatDeleteMode(notify: false))
if contactDeleteMode == .entity && showDeleteContactNotice {
AlertManager.shared.showAlert(deleteContactNotice(contact))
}
}
},
.cancel()
]
)
} else {
return ActionSheet(
title: Text("Confirm contact deletion.\nThis cannot be undone!"),
buttons: [
.destructive(Text("Delete")) {
Task {
await deleteChatContact(chat, chatDeleteMode: contactDeleteMode.toChatDeleteMode(notify: false))
if contactDeleteMode == .entity && showDeleteContactNotice {
AlertManager.shared.showAlert(deleteContactNotice(contact))
}
}
},
.cancel()
]
)
}
}
}
default:
EmptyView()
}
}
@ViewBuilder private func previewTitle(_ contact: Contact) -> some View {
let t = Text(chat.chatInfo.chatViewName)
(
contact.verified == true
? verifiedIcon + t
: t
)
.lineLimit(1)
}
private var verifiedIcon: Text {
(Text(Image(systemName: "checkmark.shield")) + Text(" "))
.foregroundColor(.secondary)
.baselineOffset(1)
.kerning(-2)
}
@ViewBuilder private func chatPreviewImageOverlayIcon(_ contact: Contact) -> some View {
if !contact.active {
inactiveIcon()
} else {
EmptyView()
}
}
private func inactiveIcon() -> some View {
Image(systemName: "multiply.circle.fill")
.foregroundColor(.secondary.opacity(0.65))
.background(Circle().foregroundColor(Color(uiColor: .systemBackground)))
}
private func deleteContactNotice(_ contact: Contact) -> Alert {
return Alert(
title: Text("Contact deleted!"),
message: Text("You can still view conversation with \(contact.displayName) in the Chats tab."),
primaryButton: .default(Text("Don't show again")) {
showDeleteContactNotice = false
},
secondaryButton: .default(Text("Ok"))
)
}
@ViewBuilder private func toggleFavoriteButton() -> some View {
if chat.chatInfo.chatSettings?.favorite == true {
Button {
toggleChatFavorite(chat, favorite: false)
} label: {
Label("Unfav.", systemImage: "star.slash")
}
.tint(.green)
} else {
Button {
toggleChatFavorite(chat, favorite: true)
} label: {
Label("Favorite", systemImage: "star.fill")
}
.tint(.green)
}
}
}
#Preview {
ContactListNavLink(chat: Chat.sampleData)
}
@@ -0,0 +1,199 @@
//
// ContactsView.swift
// SimpleX (iOS)
//
// Created by spaced4ndy on 06.05.2024.
// Copyright © 2024 SimpleX Chat. All rights reserved.
//
import SwiftUI
import SimpleXChat
struct ContactsView: View {
@EnvironmentObject var chatModel: ChatModel
@State private var searchMode = false
@FocusState private var searchFocussed
@State private var searchText = ""
@AppStorage(DEFAULT_SHOW_UNREAD_AND_FAVORITES) private var showUnreadAndFavorites = false
@AppStorage(DEFAULT_ONE_HAND_UI) private var oneHandUI = false
var body: some View {
if #available(iOS 16.0, *) {
viewBody.scrollDismissesKeyboard(.immediately)
} else {
viewBody
}
}
private var viewBody: some View {
VStack {
contactList
}
.scaleEffect(x: 1, y: oneHandUI ? -1 : 1, anchor: .center)
.listStyle(.plain)
}
@ViewBuilder private var contactList: some View {
let contactChats = contactChats()
let filteredContactChats = filteredContactChats(contactChats)
ZStack {
VStack {
List {
if !contactChats.isEmpty {
ContactsSearchBar(
searchMode: $searchMode,
searchFocussed: $searchFocussed,
searchText: $searchText
)
.scaleEffect(x: 1, y: oneHandUI ? -1 : 1, anchor: .center)
.listRowSeparator(.hidden)
.frame(maxWidth: .infinity)
}
ForEach(filteredContactChats, id: \.viewId) { chat in
switch chat.chatInfo {
case let .direct(contact):
ContactListNavLink(chat: chat)
.scaleEffect(x: 1, y: oneHandUI ? -1 : 1, anchor: .center)
.disabled(chatModel.chatRunning != true || chatModel.deletedChats.contains(contact.id))
default:
EmptyView()
}
}
}
}
if filteredContactChats.isEmpty && !contactChats.isEmpty {
Text("No filtered contacts")
.scaleEffect(x: 1, y: oneHandUI ? -1 : 1, anchor: .center)
.foregroundColor(.secondary)
} else if contactChats.isEmpty {
Text("No contacts")
.scaleEffect(x: 1, y: oneHandUI ? -1 : 1, anchor: .center)
.foregroundColor(.secondary)
}
}
}
private func contactChats() -> [Chat] {
return chatModel.chats.filter { chat in
switch chat.chatInfo {
case .direct: true
default: false
}
}
}
private func filteredContactChats(_ contactChats: [Chat]) -> [Chat] {
let s = searchString()
return (
s == "" && !showUnreadAndFavorites
? contactChats.filter { chat in
switch chat.chatInfo {
case let .direct(contact): return contact.contactStatus != .deletedByUser
default: return false
}
}
: contactChats.filter { chat in
switch chat.chatInfo {
case let .direct(contact):
return contact.contactStatus != .deletedByUser && (
s == ""
? (chat.chatInfo.chatSettings?.favorite ?? false)
: (viewNameContains(contact, s) ||
contact.profile.displayName.localizedLowercase.contains(s) ||
contact.fullName.localizedLowercase.contains(s))
)
default: return false
}
}
)
.sorted{ $0.chatInfo.displayName.lowercased() < $1.chatInfo.displayName.lowercased() }
func searchString() -> String {
searchText.trimmingCharacters(in: .whitespaces).localizedLowercase
}
func viewNameContains(_ contact: Contact, _ s: String) -> Bool {
contact.chatViewName.localizedLowercase.contains(s)
}
}
}
struct ContactsSearchBar: View {
@EnvironmentObject var m: ChatModel
@Binding var searchMode: Bool
@FocusState.Binding var searchFocussed: Bool
@Binding var searchText: String
@AppStorage(DEFAULT_SHOW_UNREAD_AND_FAVORITES) private var showUnreadAndFavorites = false
var body: some View {
VStack(spacing: 12) {
HStack(spacing: 12) {
HStack(spacing: 4) {
Image(systemName: "magnifyingglass")
TextField("Search", text: $searchText)
.focused($searchFocussed)
.frame(maxWidth: .infinity)
if !searchText.isEmpty {
Image(systemName: "xmark.circle.fill")
.onTapGesture {
searchText = ""
}
}
}
.padding(EdgeInsets(top: 7, leading: 7, bottom: 7, trailing: 7))
.foregroundColor(.secondary)
.background(Color(.tertiarySystemFill))
.cornerRadius(10.0)
if searchFocussed {
Text("Cancel")
.foregroundColor(.accentColor)
.onTapGesture {
searchText = ""
searchFocussed = false
}
} else if m.chats.count > 0 {
toggleFilterButton()
}
}
}
.onChange(of: searchFocussed) { sf in
withAnimation { searchMode = sf }
}
}
private func toggleFilterButton() -> some View {
ZStack {
Color.clear
.frame(width: 22, height: 22)
Image(systemName: showUnreadAndFavorites ? "line.3.horizontal.decrease.circle.fill" : "line.3.horizontal.decrease")
.resizable()
.scaledToFit()
.foregroundColor(showUnreadAndFavorites ? .accentColor : .secondary)
.frame(width: showUnreadAndFavorites ? 22 : 16, height: showUnreadAndFavorites ? 22 : 16)
.onTapGesture {
showUnreadAndFavorites = !showUnreadAndFavorites
}
}
}
}
struct ContactsView_Previews: PreviewProvider {
static var previews: some View {
let chatModel = ChatModel()
chatModel.chats = [
Chat(
chatInfo: ChatInfo.sampleData.direct,
chatItems: []
)
]
return Group {
ContactsView()
.environmentObject(chatModel)
ContactsView()
.environmentObject(ChatModel())
}
}
}
+229
View File
@@ -0,0 +1,229 @@
//
// HomeView.swift
// SimpleX (iOS)
//
// Created by spaced4ndy on 01.05.2024.
// Copyright © 2024 SimpleX Chat. All rights reserved.
//
import SwiftUI
import SimpleXChat
enum HomeTab {
case contacts
case chats
}
struct HomeView: View {
@EnvironmentObject var chatModel: ChatModel
@Binding var showSettings: Bool
@State private var homeTab: HomeTab = .chats
@State private var userPickerVisible = false
@State private var showConnectDesktop = false
@State private var newChatMenuOption: NewChatMenuOption? = nil
@State private var toolbarHeight: CGFloat = 0
@AppStorage(DEFAULT_ONE_HAND_UI) private var oneHandUI = false
var body: some View {
ZStack(alignment: .bottomLeading) {
NavStackCompat(
isActive: Binding(
get: { chatModel.chatId != nil },
set: { _ in }
),
destination: chatView,
content: homeView
)
if userPickerVisible {
Rectangle().fill(.white.opacity(0.001)).onTapGesture {
withAnimation {
userPickerVisible.toggle()
}
}
}
UserPicker(
showSettings: $showSettings,
showConnectDesktop: $showConnectDesktop,
userPickerVisible: $userPickerVisible
)
}
.sheet(isPresented: $showConnectDesktop) {
ConnectDesktopView()
}
}
@ViewBuilder private func homeView() -> some View {
let v = VStack {
switch homeTab {
case .contacts: withToolbar("Contacts", contactsView)
case .chats: withToolbar("Chats", chatListView)
}
}
.toolbar {
ToolbarItemGroup(placement: .bottomBar) {
settingsButton()
Spacer()
contactsButton()
Spacer()
chatsButton()
Spacer()
newChatButton()
}
}
if #unavailable(iOS 16) {
v
} else if oneHandUI {
v.toolbarBackground(.visible, for: .navigationBar, .bottomBar)
} else {
v.toolbarBackground(.visible, for: .bottomBar)
}
}
func withToolbar<V: View>(_ title: LocalizedStringKey, _ content: () -> V) -> some View {
content()
.navigationBarTitleDisplayMode(oneHandUI ? .inline : .large)
.navigationTitle(title)
}
@ViewBuilder private func settingsButton() -> some View {
let user = chatModel.currentUser ?? User.sampleData
let multiUser = chatModel.users.filter({ u in u.user.activeUser || !u.user.hidden }).count > 1
Button {
if multiUser {
withAnimation {
userPickerVisible.toggle()
}
} else {
showSettings = true
}
} label: {
VStack(spacing: 2) {
ZStack(alignment: .topTrailing) {
ProfileImage(imageStr: user.image, size: 42, color: Color(uiColor: .quaternaryLabel))
.padding(.top, 3)
.padding(.trailing, 3)
let allRead = chatModel.users
.filter { u in !u.user.activeUser && !u.user.hidden }
.allSatisfy { u in u.unreadCount == 0 }
if !allRead {
userUnreadBadge(size: 12)
}
}
}
}
.foregroundColor(.secondary)
}
private func userUnreadBadge(_ text: Text? = Text(" "), size: CGFloat = 18) -> some View {
Circle()
.frame(width: size, height: size)
.foregroundColor(.accentColor)
}
private func contactsButton() -> some View {
Button {
homeTab = .contacts
} label: {
iconLabel(homeTab == .contacts ? "person.crop.circle.fill" : "person.crop.circle", "Contacts")
}
.foregroundColor(.secondary)
}
private func chatsButton() -> some View {
Button {
homeTab = .chats
} label: {
iconLabel(homeTab == .chats ? "message.fill" : "message", "Chats")
}
.foregroundColor(.secondary)
}
@ViewBuilder private func newChatButton() -> some View {
if case .some(false) = chatModel.chatRunning {
chatsStoppedButton()
} else {
Menu {
Button {
newChatMenuOption = .newGroup
} label: {
Text("Create group")
}
Button {
newChatMenuOption = .scanPaste
} label: {
Text("Scan / Paste link")
}
Button {
newChatMenuOption = .newContact
} label: {
Text("Add contact")
}
} label: {
iconLabel("square.and.pencil", "New chat")
}
.sheet(item: $newChatMenuOption) { opt in
switch opt {
case .newContact: NewChatView(selection: .invite)
case .scanPaste: NewChatView(selection: .connect, showQRCodeScanner: true)
case .newGroup: AddGroupView()
}
}
}
}
func chatsStoppedButton() -> some View {
Button {
AlertManager.shared.showAlertMsg(
title: "Chat is stopped",
message: "You can start chat via app Settings / Database or by restarting the app"
)
} label: {
VStack(spacing: 4) {
Image(systemName: "exclamationmark.octagon.fill")
.resizable()
.scaledToFit()
.foregroundColor(.red)
.frame(width: 24, height: 24)
Text("Stopped")
.font(.caption)
.foregroundColor(.secondary)
}
}
}
private func iconLabel(_ image: String, _ title: LocalizedStringKey) -> some View {
VStack(spacing: 2) {
Image(systemName: image)
.resizable()
.scaledToFit()
.frame(width: 24, height: 24)
Text(title)
.font(.caption2)
}
.padding(.top, 3)
}
@ViewBuilder private func contactsView() -> some View {
ContactsView()
}
@ViewBuilder private func chatListView() -> some View {
// TODO reverse scale effect for swipe actions
ChatListView()
}
@ViewBuilder private func chatView() -> some View {
if let chatId = chatModel.chatId, let chat = chatModel.getChat(chatId) {
ChatView(chat: chat).onAppear {
loadChat(chat: chat)
}
}
}
}
#Preview {
HomeView(showSettings: Binding.constant(false))
}
@@ -10,6 +10,7 @@ import SwiftUI
enum NewChatMenuOption: Identifiable {
case newContact
case scanPaste
case newGroup
var id: Self { self }
@@ -25,6 +26,11 @@ struct NewChatMenuButton: View {
} label: {
Text("Add contact")
}
Button {
newChatMenuOption = .scanPaste
} label: {
Text("Scan / Paste link")
}
Button {
newChatMenuOption = .newGroup
} label: {
@@ -39,6 +45,7 @@ struct NewChatMenuButton: View {
.sheet(item: $newChatMenuOption) { opt in
switch opt {
case .newContact: NewChatView(selection: .invite)
case .scanPaste: NewChatView(selection: .connect, showQRCodeScanner: true)
case .newGroup: AddGroupView()
}
}
+12 -15
View File
@@ -11,14 +11,9 @@ import SimpleXChat
import CodeScanner
import AVFoundation
enum SomeAlert: Identifiable {
case someAlert(alert: Alert, id: String)
var id: String {
switch self {
case let .someAlert(_, id): return id
}
}
struct SomeAlert: Identifiable {
var alert: Alert
var id: String
}
private enum NewChatViewAlert: Identifiable {
@@ -142,8 +137,8 @@ struct NewChatView: View {
switch(a) {
case let .planAndConnectAlert(alert):
return planAndConnectAlert(alert, dismiss: true, cleanup: { pastedLink = "" })
case let .newChatSomeAlert(.someAlert(alert, _)):
return alert
case let .newChatSomeAlert(a):
return a.alert
}
}
}
@@ -181,7 +176,7 @@ struct NewChatView: View {
await MainActor.run {
creatingConnReq = false
if let apiAlert = apiAlert {
alert = .newChatSomeAlert(alert: .someAlert(alert: apiAlert, id: "createInvitation error"))
alert = .newChatSomeAlert(alert: SomeAlert(alert: apiAlert, id: "createInvitation error"))
}
}
}
@@ -315,7 +310,7 @@ private struct ConnectView: View {
// showQRCodeScanner = false
connect(pastedLink)
} else {
alert = .newChatSomeAlert(alert: .someAlert(
alert = .newChatSomeAlert(alert: SomeAlert(
alert: mkAlert(title: "Invalid link", message: "The text you pasted is not a SimpleX link."),
id: "pasteLinkView: code is not a SimpleX link"
))
@@ -338,14 +333,14 @@ private struct ConnectView: View {
if strIsSimplexLink(r.string) {
connect(link)
} else {
alert = .newChatSomeAlert(alert: .someAlert(
alert = .newChatSomeAlert(alert: SomeAlert(
alert: mkAlert(title: "Invalid QR code", message: "The code you scanned is not a SimpleX link QR code."),
id: "processQRCode: code is not a SimpleX link"
))
}
case let .failure(e):
logger.error("processQRCode QR code error: \(e.localizedDescription)")
alert = .newChatSomeAlert(alert: .someAlert(
alert = .newChatSomeAlert(alert: SomeAlert(
alert: mkAlert(title: "Invalid QR code", message: "Error scanning code: \(e.localizedDescription)"),
id: "processQRCode: failure"
))
@@ -367,11 +362,12 @@ struct ScannerInView: View {
@Binding var showQRCodeScanner: Bool
let processQRCode: (_ resp: Result<ScanResult, ScanError>) -> Void
@State private var cameraAuthorizationStatus: AVAuthorizationStatus?
var scanMode: ScanMode = .continuous
var body: some View {
Group {
if showQRCodeScanner, case .authorized = cameraAuthorizationStatus {
CodeScannerView(codeTypes: [.qr], scanMode: .continuous, completion: processQRCode)
CodeScannerView(codeTypes: [.qr], scanMode: scanMode, completion: processQRCode)
.aspectRatio(1, contentMode: .fit)
.cornerRadius(12)
.listRowBackground(Color.clear)
@@ -436,6 +432,7 @@ struct ScannerInView: View {
}
}
private func linkTextView(_ link: String) -> some View {
Text(link)
.lineLimit(1)
@@ -181,23 +181,27 @@ struct ConnectDesktopView: View {
}
private func connectingDesktopView(_ session: RemoteCtrlSession, _ rc: RemoteCtrlInfo?) -> some View {
List {
Section("Connecting to desktop") {
ctrlDeviceNameText(session, rc)
ctrlDeviceVersionText(session)
}
ZStack {
List {
Section("Connecting to desktop") {
ctrlDeviceNameText(session, rc)
ctrlDeviceVersionText(session)
}
if let sessCode = session.sessionCode {
Section("Session code") {
sessionCodeText(sessCode)
if let sessCode = session.sessionCode {
Section("Session code") {
sessionCodeText(sessCode)
}
}
Section {
disconnectButton()
}
}
.navigationTitle("Connecting to desktop")
Section {
disconnectButton()
}
ProgressView().scaleEffect(2)
}
.navigationTitle("Connecting to desktop")
}
private func searchingDesktopView() -> some View {
@@ -329,16 +333,10 @@ struct ConnectDesktopView: View {
}
}
}
private func scanDesctopAddressView() -> some View {
Section("Scan QR code from desktop") {
CodeScannerView(codeTypes: [.qr], scanMode: .oncePerCode, completion: processDesktopQRCode)
.aspectRatio(1, contentMode: .fit)
.cornerRadius(12)
.listRowBackground(Color.clear)
.listRowSeparator(.hidden)
.listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
.padding(.horizontal)
ScannerInView(showQRCodeScanner: $showQRCodeScanner, processQRCode: processDesktopQRCode, scanMode: .oncePerCode)
}
}
@@ -44,6 +44,7 @@ extension AppSettings {
if let val = androidCallOnLockScreen { def.setValue(val.rawValue, forKey: ANDROID_DEFAULT_CALL_ON_LOCK_SCREEN) }
if let val = iosCallKitEnabled { callKitEnabledGroupDefault.set(val) }
if let val = iosCallKitCallsInRecents { def.setValue(val, forKey: DEFAULT_CALL_KIT_CALLS_IN_RECENTS) }
if let val = oneHandUI { def.setValue(val, forKey: DEFAULT_ONE_HAND_UI) }
}
public static var current: AppSettings {
@@ -69,6 +70,7 @@ extension AppSettings {
c.androidCallOnLockScreen = AppSettingsLockScreenCalls(rawValue: def.string(forKey: ANDROID_DEFAULT_CALL_ON_LOCK_SCREEN)!)
c.iosCallKitEnabled = callKitEnabledGroupDefault.get()
c.iosCallKitCallsInRecents = def.bool(forKey: DEFAULT_CALL_KIT_CALLS_IN_RECENTS)
c.oneHandUI = def.bool(forKey: DEFAULT_ONE_HAND_UI)
return c
}
}
@@ -25,6 +25,7 @@ struct AppearanceSettings: View {
@State private var userInterfaceStyle = getUserInterfaceStyleDefault()
@State private var uiTintColor = getUIAccentColorDefault()
@AppStorage(DEFAULT_PROFILE_IMAGE_CORNER_RADIUS) private var profileImageCornerRadius = defaultProfileImageCorner
@AppStorage(DEFAULT_ONE_HAND_UI) private var oneHandUI = false
var body: some View {
VStack{
@@ -39,6 +40,12 @@ struct AppearanceSettings: View {
}
}
// Section("Interface") {
// settingsRow("hand.wave") {
// Toggle("One-hand UI", isOn: $oneHandUI)
// }
// }
Section("App icon") {
HStack {
updateAppIcon(image: "icon-light", icon: nil, tapped: $iconLightTapped)
@@ -12,6 +12,7 @@ import SimpleXChat
struct DeveloperView: View {
@AppStorage(DEFAULT_DEVELOPER_TOOLS) private var developerTools = false
@AppStorage(GROUP_DEFAULT_CONFIRM_DB_UPGRADES, store: groupDefaults) private var confirmDatabaseUpgrades = false
@AppStorage(DEFAULT_ONE_HAND_UI) private var oneHandUI = false
@Environment(\.colorScheme) var colorScheme
var body: some View {
@@ -31,9 +32,6 @@ struct DeveloperView: View {
} label: {
settingsRow("terminal") { Text("Chat console") }
}
settingsRow("internaldrive") {
Toggle("Confirm database upgrades", isOn: $confirmDatabaseUpgrades)
}
settingsRow("chevron.left.forwardslash.chevron.right") {
Toggle("Show developer options", isOn: $developerTools)
}
@@ -42,6 +40,19 @@ struct DeveloperView: View {
} footer: {
(developerTools ? Text("Show:") : Text("Hide:")) + Text(" ") + Text("Database IDs and Transport isolation option.")
}
if developerTools {
Section {
settingsRow("internaldrive") {
Toggle("Confirm database upgrades", isOn: $confirmDatabaseUpgrades)
}
settingsRow("hand.wave") {
Toggle("One-hand UI", isOn: $oneHandUI)
}
} header: {
Text("Developer options")
}
}
}
}
}
@@ -46,6 +46,7 @@ let DEFAULT_ACCENT_COLOR_GREEN = "accentColorGreen"
let DEFAULT_ACCENT_COLOR_BLUE = "accentColorBlue"
let DEFAULT_USER_INTERFACE_STYLE = "userInterfaceStyle"
let DEFAULT_PROFILE_IMAGE_CORNER_RADIUS = "profileImageCornerRadius"
let DEFAULT_ONE_HAND_UI = "oneHandUI"
let DEFAULT_CONNECT_VIA_LINK_TAB = "connectViaLinkTab"
let DEFAULT_LIVE_MESSAGE_ALERT_SHOWN = "liveMessageAlertShown"
let DEFAULT_SHOW_HIDDEN_PROFILES_NOTICE = "showHiddenProfilesNotice"
@@ -60,6 +61,8 @@ let DEFAULT_DEVICE_NAME_FOR_REMOTE_ACCESS = "deviceNameForRemoteAccess"
let DEFAULT_CONFIRM_REMOTE_SESSIONS = "confirmRemoteSessions"
let DEFAULT_CONNECT_REMOTE_VIA_MULTICAST = "connectRemoteViaMulticast"
let DEFAULT_CONNECT_REMOTE_VIA_MULTICAST_AUTO = "connectRemoteViaMulticastAuto"
let DEFAULT_SHOW_DELETE_CONVERSATION_NOTICE = "showDeleteConversationNotice"
let DEFAULT_SHOW_DELETE_CONTACT_NOTICE = "showDeleteContactNotice"
let DEFAULT_SHOW_SENT_VIA_RPOXY = "showSentViaProxy"
let ANDROID_DEFAULT_CALL_ON_LOCK_SCREEN = "androidCallOnLockScreen"
@@ -90,6 +93,7 @@ let appDefaults: [String: Any] = [
DEFAULT_ACCENT_COLOR_BLUE: 1.000,
DEFAULT_USER_INTERFACE_STYLE: 0,
DEFAULT_PROFILE_IMAGE_CORNER_RADIUS: defaultProfileImageCorner,
DEFAULT_ONE_HAND_UI: false,
DEFAULT_CONNECT_VIA_LINK_TAB: ConnectViaLinkTab.scan.rawValue,
DEFAULT_LIVE_MESSAGE_ALERT_SHOWN: false,
DEFAULT_SHOW_HIDDEN_PROFILES_NOTICE: true,
@@ -100,6 +104,8 @@ let appDefaults: [String: Any] = [
DEFAULT_CONFIRM_REMOTE_SESSIONS: false,
DEFAULT_CONNECT_REMOTE_VIA_MULTICAST: true,
DEFAULT_CONNECT_REMOTE_VIA_MULTICAST_AUTO: true,
DEFAULT_SHOW_DELETE_CONVERSATION_NOTICE: true,
DEFAULT_SHOW_DELETE_CONTACT_NOTICE: true,
DEFAULT_SHOW_SENT_VIA_RPOXY: false,
ANDROID_DEFAULT_CALL_ON_LOCK_SCREEN: AppSettingsLockScreenCalls.show.rawValue
]
@@ -448,9 +454,8 @@ struct SettingsView_Previews: PreviewProvider {
static var previews: some View {
let chatModel = ChatModel()
chatModel.currentUser = User.sampleData
@State var showSettings = false
return SettingsView(showSettings: $showSettings)
return SettingsView(showSettings: Binding.constant(false))
.environmentObject(chatModel)
}
}
@@ -403,6 +403,6 @@ public func chatPasswordHash(_ pwd: String, _ salt: String) -> String {
struct UserProfilesView_Previews: PreviewProvider {
static var previews: some View {
UserProfilesView(showSettings: Binding.constant(true))
UserProfilesView(showSettings: Binding.constant(false))
}
}
@@ -1717,6 +1717,10 @@ This is your own one-time link!</source>
<target>Базата данни ще бъде мигрирана, когато приложението се рестартира</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Debug delivery" xml:space="preserve">
<source>Debug delivery</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Decentralized" xml:space="preserve">
<source>Decentralized</source>
<target>Децентрализиран</target>
@@ -3684,6 +3688,10 @@ This is your link for group %@!</source>
<target>Чернова на съобщение</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message queue info" xml:space="preserve">
<source>Message queue info</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message reactions" xml:space="preserve">
<source>Message reactions</source>
<target>Реакции на съобщения</target>
@@ -7539,6 +7547,12 @@ SimpleX сървърите не могат да видят вашия профи
<target>изпрати лично съобщение</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="server queue info: %@&#10;&#10;last received msg: %@" xml:space="preserve">
<source>server queue info: %1$@
last received msg: %2$@</source>
<note>queue info</note>
</trans-unit>
<trans-unit id="set new contact address" xml:space="preserve">
<source>set new contact address</source>
<target>зададен нов адрес за контакт</target>
@@ -1647,6 +1647,10 @@ This is your own one-time link!</source>
<target>Databáze bude přenesena po restartu aplikace</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Debug delivery" xml:space="preserve">
<source>Debug delivery</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Decentralized" xml:space="preserve">
<source>Decentralized</source>
<target>Decentralizované</target>
@@ -3541,6 +3545,10 @@ This is your link for group %@!</source>
<target>Návrh zprávy</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message queue info" xml:space="preserve">
<source>Message queue info</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message reactions" xml:space="preserve">
<source>Message reactions</source>
<target>Reakce na zprávy</target>
@@ -7247,6 +7255,12 @@ Servery SimpleX nevidí váš profil.</target>
<target>odeslat přímou zprávu</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="server queue info: %@&#10;&#10;last received msg: %@" xml:space="preserve">
<source>server queue info: %1$@
last received msg: %2$@</source>
<note>queue info</note>
</trans-unit>
<trans-unit id="set new contact address" xml:space="preserve">
<source>set new contact address</source>
<note>profile update event chat item</note>
@@ -715,6 +715,7 @@
</trans-unit>
<trans-unit id="Allow downgrade" xml:space="preserve">
<source>Allow downgrade</source>
<target>Herabstufung erlauben</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">
@@ -814,6 +815,7 @@
</trans-unit>
<trans-unit id="Always use private routing." xml:space="preserve">
<source>Always use private routing.</source>
<target>Sie nutzen immer privates Routing.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Always use relay" xml:space="preserve">
@@ -1098,6 +1100,7 @@
</trans-unit>
<trans-unit id="Capacity exceeded - recipient did not receive previously sent messages." xml:space="preserve">
<source>Capacity exceeded - recipient did not receive previously sent messages.</source>
<target>Kapazität überschritten - der Empfänger hat die zuvor gesendeten Nachrichten nicht empfangen.</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Cellular" xml:space="preserve">
@@ -1298,6 +1301,7 @@
</trans-unit>
<trans-unit id="Confirm files from unknown servers." xml:space="preserve">
<source>Confirm files from unknown servers.</source>
<target>Dateien von unbekannten Servern bestätigen.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirm network settings" xml:space="preserve">
@@ -1717,6 +1721,10 @@ Das ist Ihr eigener Einmal-Link!</target>
<target>Die Datenbank wird beim nächsten Start der App migriert</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Debug delivery" xml:space="preserve">
<source>Debug delivery</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Decentralized" xml:space="preserve">
<source>Decentralized</source>
<target>Dezentral</target>
@@ -1966,6 +1974,7 @@ Das kann nicht rückgängig gemacht werden!</target>
</trans-unit>
<trans-unit id="Destination server error: %@" xml:space="preserve">
<source>Destination server error: %@</source>
<target>Zielserver-Fehler: %@</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Develop" xml:space="preserve">
@@ -2075,15 +2084,17 @@ Das kann nicht rückgängig gemacht werden!</target>
</trans-unit>
<trans-unit id="Do NOT send messages directly, even if your or destination server does not support private routing." xml:space="preserve">
<source>Do NOT send messages directly, even if your or destination server does not support private routing.</source>
<target>Nachrichten werden nicht direkt versendet, selbst wenn Ihr oder der Zielserver kein privates Routing unterstützt.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Do NOT use SimpleX for emergency calls." xml:space="preserve">
<source>Do NOT use SimpleX for emergency calls.</source>
<target>Nutzen Sie SimpleX nicht für Notrufe.</target>
<target>SimpleX NICHT für Notrufe nutzen.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Do NOT use private routing." xml:space="preserve">
<source>Do NOT use private routing.</source>
<target>Sie nutzen KEIN privates Routing.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Do it later" xml:space="preserve">
@@ -2743,6 +2754,7 @@ Das kann nicht rückgängig gemacht werden!</target>
</trans-unit>
<trans-unit id="Files" xml:space="preserve">
<source>Files</source>
<target>Dateien</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files &amp; media" xml:space="preserve">
@@ -2853,11 +2865,15 @@ Das kann nicht rückgängig gemacht werden!</target>
<trans-unit id="Forwarding server: %@&#10;Destination server error: %@" xml:space="preserve">
<source>Forwarding server: %1$@
Destination server error: %2$@</source>
<target>Weiterleitungsserver: %1$@
Zielserver Fehler: %2$@</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Forwarding server: %@&#10;Error: %@" xml:space="preserve">
<source>Forwarding server: %1$@
Error: %2$@</source>
<target>Weiterleitungsserver: %1$@
Fehler: %2$@</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Found desktop" xml:space="preserve">
@@ -3677,6 +3693,7 @@ Das ist Ihr Link für die Gruppe %@!</target>
</trans-unit>
<trans-unit id="Message delivery warning" xml:space="preserve">
<source>Message delivery warning</source>
<target>Warnung bei der Nachrichtenzustellung</target>
<note>item status text</note>
</trans-unit>
<trans-unit id="Message draft" xml:space="preserve">
@@ -3684,6 +3701,10 @@ Das ist Ihr Link für die Gruppe %@!</target>
<target>Nachrichtenentwurf</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message queue info" xml:space="preserve">
<source>Message queue info</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message reactions" xml:space="preserve">
<source>Message reactions</source>
<target>Reaktionen auf Nachrichten</target>
@@ -3701,10 +3722,12 @@ Das ist Ihr Link für die Gruppe %@!</target>
</trans-unit>
<trans-unit id="Message routing fallback" xml:space="preserve">
<source>Message routing fallback</source>
<target>Fallback für das Nachrichten-Routing</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message routing mode" xml:space="preserve">
<source>Message routing mode</source>
<target>Modus für das Nachrichten-Routing</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message source remains private." xml:space="preserve">
@@ -3869,6 +3892,7 @@ Das ist Ihr Link für die Gruppe %@!</target>
</trans-unit>
<trans-unit id="Network issues - message expired after many attempts to send it." xml:space="preserve">
<source>Network issues - message expired after many attempts to send it.</source>
<target>Netzwerk-Fehler - die Nachricht ist nach vielen Sende-Versuchen abgelaufen.</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Network management" xml:space="preserve">
@@ -4414,10 +4438,12 @@ Fehler: %@</target>
</trans-unit>
<trans-unit id="Private message routing" xml:space="preserve">
<source>Private message routing</source>
<target>Privates Nachrichten-Routing</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private message routing 🚀" xml:space="preserve">
<source>Private message routing 🚀</source>
<target>Privates Nachrichten-Routing 🚀</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private notes" xml:space="preserve">
@@ -4427,6 +4453,7 @@ Fehler: %@</target>
</trans-unit>
<trans-unit id="Private routing" xml:space="preserve">
<source>Private routing</source>
<target>Privates Routing</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile and server connections" xml:space="preserve">
@@ -4511,6 +4538,7 @@ Fehler: %@</target>
</trans-unit>
<trans-unit id="Protect IP address" xml:space="preserve">
<source>Protect IP address</source>
<target>IP-Adresse schützen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Protect app screen" xml:space="preserve">
@@ -4521,6 +4549,8 @@ Fehler: %@</target>
<trans-unit id="Protect your IP address from the messaging relays chosen by your contacts.&#10;Enable in *Network &amp; servers* settings." xml:space="preserve">
<source>Protect your IP address from the messaging relays chosen by your contacts.
Enable in *Network &amp; servers* settings.</source>
<target>Schützen Sie Ihre IP-Adresse vor den Nachrichten-Relais , die Ihre Kontakte ausgewählt haben.
Aktivieren Sie es in den *Netzwerk &amp; Server* Einstellungen.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Protect your chat profiles with a password!" xml:space="preserve">
@@ -4865,6 +4895,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Safely receive files" xml:space="preserve">
<source>Safely receive files</source>
<target>Dateien sicher empfangen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Safer groups" xml:space="preserve">
@@ -5094,10 +5125,12 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Send messages directly when IP address is protected and your or destination server does not support private routing." xml:space="preserve">
<source>Send messages directly when IP address is protected and your or destination server does not support private routing.</source>
<target>Nachrichten werden direkt versendet, wenn die IP-Adresse geschützt ist, und Ihr oder der Zielserver kein privates Routing unterstützt.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send messages directly when your or destination server does not support private routing." xml:space="preserve">
<source>Send messages directly when your or destination server does not support private routing.</source>
<target>Nachrichten werden direkt versendet, wenn Ihr oder der Zielserver kein privates Routing unterstützt.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send notifications" xml:space="preserve">
@@ -5207,6 +5240,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Server address is incompatible with network settings." xml:space="preserve">
<source>Server address is incompatible with network settings.</source>
<target>Die Server-Adresse ist nicht mit den Netzwerk-Einstellungen kompatibel.</target>
<note>srv error text.</note>
</trans-unit>
<trans-unit id="Server requires authorization to create queues, check password" xml:space="preserve">
@@ -5226,6 +5260,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Server version is incompatible with network settings." xml:space="preserve">
<source>Server version is incompatible with network settings.</source>
<target>Die Server-Version ist nicht mit den Netzwerk-Einstellungen kompatibel.</target>
<note>srv error text</note>
</trans-unit>
<trans-unit id="Servers" xml:space="preserve">
@@ -5350,6 +5385,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Show message status" xml:space="preserve">
<source>Show message status</source>
<target>Nachrichtenstatus anzeigen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show preview" xml:space="preserve">
@@ -5359,6 +5395,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Show → on messages sent via private routing." xml:space="preserve">
<source>Show → on messages sent via private routing.</source>
<target>Bei Nachrichten, die über privates Routing versendet wurden, → anzeigen.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show:" xml:space="preserve">
@@ -5685,6 +5722,7 @@ Dies kann passieren, wenn es einen Fehler gegeben hat oder die Verbindung kompro
</trans-unit>
<trans-unit id="The app will ask to confirm downloads from unknown file servers (except .onion)." xml:space="preserve">
<source>The app will ask to confirm downloads from unknown file servers (except .onion).</source>
<target>Die App wird eine Bestätigung bei Downloads von unbekannten Datei-Servern anfordern (außer bei .onion).</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="The attempt to change database passphrase was not completed." xml:space="preserve">
@@ -5874,6 +5912,7 @@ Dies kann passieren, wenn es einen Fehler gegeben hat oder die Verbindung kompro
</trans-unit>
<trans-unit id="To protect your IP address, private routing uses your SMP servers to deliver messages." xml:space="preserve">
<source>To protect your IP address, private routing uses your SMP servers to deliver messages.</source>
<target>Zum Schutz Ihrer IP-Adresse, wird für die Nachrichten-Auslieferung privates Routing über Ihre konfigurierten SMP-Server genutzt.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To protect your information, turn on SimpleX Lock.&#10;You will be prompted to complete authentication before this feature is enabled." xml:space="preserve">
@@ -6015,6 +6054,7 @@ Sie werden aufgefordert, die Authentifizierung abzuschließen, bevor diese Funkt
</trans-unit>
<trans-unit id="Unknown servers!" xml:space="preserve">
<source>Unknown servers!</source>
<target>Unbekannte Server!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unless you use iOS call interface, enable Do Not Disturb mode to avoid interruptions." xml:space="preserve">
@@ -6136,7 +6176,7 @@ Bitten Sie Ihren Kontakt darum einen weiteren Verbindungs-Link zu erzeugen, um s
</trans-unit>
<trans-unit id="Use current profile" xml:space="preserve">
<source>Use current profile</source>
<target>Das aktuelle Profil nutzen</target>
<target>Aktuelles Profil nutzen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use for new connections" xml:space="preserve">
@@ -6156,7 +6196,7 @@ Bitten Sie Ihren Kontakt darum einen weiteren Verbindungs-Link zu erzeugen, um s
</trans-unit>
<trans-unit id="Use new incognito profile" xml:space="preserve">
<source>Use new incognito profile</source>
<target>Ein neues Inkognito-Profil nutzen</target>
<target>Neues Inkognito-Profil nutzen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use only local notifications?" xml:space="preserve">
@@ -6166,10 +6206,12 @@ Bitten Sie Ihren Kontakt darum einen weiteren Verbindungs-Link zu erzeugen, um s
</trans-unit>
<trans-unit id="Use private routing with unknown servers when IP address is not protected." xml:space="preserve">
<source>Use private routing with unknown servers when IP address is not protected.</source>
<target>Sie nutzen privates Routing mit unbekannten Servern, wenn Ihre IP-Adresse nicht geschützt ist.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use private routing with unknown servers." xml:space="preserve">
<source>Use private routing with unknown servers.</source>
<target>Sie nutzen privates Routing mit unbekannten Servern.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use server" xml:space="preserve">
@@ -6409,10 +6451,12 @@ Bitten Sie Ihren Kontakt darum einen weiteren Verbindungs-Link zu erzeugen, um s
</trans-unit>
<trans-unit id="Without Tor or VPN, your IP address will be visible to file servers." xml:space="preserve">
<source>Without Tor or VPN, your IP address will be visible to file servers.</source>
<target>Ohne Tor- oder VPN-Nutzung wird Ihre IP-Adresse für Datei-Server sichtbar sein.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Without Tor or VPN, your IP address will be visible to these XFTP relays: %@." xml:space="preserve">
<source>Without Tor or VPN, your IP address will be visible to these XFTP relays: %@.</source>
<target>Ohne Tor- oder VPN-Nutzung wird Ihre IP-Adresse für diese XFTP-Relais sichtbar sein: %@.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Wrong database passphrase" xml:space="preserve">
@@ -6422,6 +6466,7 @@ Bitten Sie Ihren Kontakt darum einen weiteren Verbindungs-Link zu erzeugen, um s
</trans-unit>
<trans-unit id="Wrong key or unknown connection - most likely this connection is deleted." xml:space="preserve">
<source>Wrong key or unknown connection - most likely this connection is deleted.</source>
<target>Falscher Schlüssel oder unbekannte Verbindung - höchstwahrscheinlich ist diese Verbindung gelöscht worden.</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Wrong passphrase!" xml:space="preserve">
@@ -7539,6 +7584,12 @@ SimpleX-Server können Ihr Profil nicht einsehen.</target>
<target>Direktnachricht senden</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="server queue info: %@&#10;&#10;last received msg: %@" xml:space="preserve">
<source>server queue info: %1$@
last received msg: %2$@</source>
<note>queue info</note>
</trans-unit>
<trans-unit id="set new contact address" xml:space="preserve">
<source>set new contact address</source>
<target>Es wurde eine neue Kontaktadresse festgelegt</target>
@@ -7581,6 +7632,7 @@ SimpleX-Server können Ihr Profil nicht einsehen.</target>
</trans-unit>
<trans-unit id="unknown relays" xml:space="preserve">
<source>unknown relays</source>
<target>Unbekannte Relais</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="unknown status" xml:space="preserve">
@@ -7590,6 +7642,7 @@ SimpleX-Server können Ihr Profil nicht einsehen.</target>
</trans-unit>
<trans-unit id="unprotected" xml:space="preserve">
<source>unprotected</source>
<target>Ungeschützt</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="updated group profile" xml:space="preserve">
@@ -7659,6 +7712,7 @@ SimpleX-Server können Ihr Profil nicht einsehen.</target>
</trans-unit>
<trans-unit id="when IP hidden" xml:space="preserve">
<source>when IP hidden</source>
<target>Wenn die IP-Adresse versteckt ist</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="yes" xml:space="preserve">
@@ -7797,7 +7851,7 @@ SimpleX-Server können Ihr Profil nicht einsehen.</target>
</trans-unit>
<trans-unit id="NSHumanReadableCopyright" xml:space="preserve">
<source>Copyright © 2022 SimpleX Chat. All rights reserved.</source>
<target>Copyright © 2022 SimpleX Chat. All rights reserved.</target>
<target>Copyright © 2024 SimpleX Chat. All rights reserved.</target>
<note>Copyright (human-readable)</note>
</trans-unit>
</body>
@@ -1721,6 +1721,11 @@ This is your own one-time link!</target>
<target>Database will be migrated when the app restarts</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Debug delivery" xml:space="preserve">
<source>Debug delivery</source>
<target>Debug delivery</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Decentralized" xml:space="preserve">
<source>Decentralized</source>
<target>Decentralized</target>
@@ -3697,6 +3702,11 @@ This is your link for group %@!</target>
<target>Message draft</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message queue info" xml:space="preserve">
<source>Message queue info</source>
<target>Message queue info</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message reactions" xml:space="preserve">
<source>Message reactions</source>
<target>Message reactions</target>
@@ -7576,6 +7586,15 @@ SimpleX servers cannot see your profile.</target>
<target>send direct message</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="server queue info: %@&#10;&#10;last received msg: %@" xml:space="preserve">
<source>server queue info: %1$@
last received msg: %2$@</source>
<target>server queue info: %1$@
last received msg: %2$@</target>
<note>queue info</note>
</trans-unit>
<trans-unit id="set new contact address" xml:space="preserve">
<source>set new contact address</source>
<target>set new contact address</target>
@@ -715,6 +715,7 @@
</trans-unit>
<trans-unit id="Allow downgrade" xml:space="preserve">
<source>Allow downgrade</source>
<target>Permitir versión anterior</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">
@@ -814,6 +815,7 @@
</trans-unit>
<trans-unit id="Always use private routing." xml:space="preserve">
<source>Always use private routing.</source>
<target>Usar siempre enrutamiento privado.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Always use relay" xml:space="preserve">
@@ -1098,6 +1100,7 @@
</trans-unit>
<trans-unit id="Capacity exceeded - recipient did not receive previously sent messages." xml:space="preserve">
<source>Capacity exceeded - recipient did not receive previously sent messages.</source>
<target>Capacidad excedida - el destinatario no ha recibido los mensajes previos.</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Cellular" xml:space="preserve">
@@ -1298,6 +1301,7 @@
</trans-unit>
<trans-unit id="Confirm files from unknown servers." xml:space="preserve">
<source>Confirm files from unknown servers.</source>
<target>Confirma archivos de servidores desconocidos.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirm network settings" xml:space="preserve">
@@ -1717,6 +1721,10 @@ This is your own one-time link!</source>
<target>La base de datos migrará cuando se reinicie la aplicación</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Debug delivery" xml:space="preserve">
<source>Debug delivery</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Decentralized" xml:space="preserve">
<source>Decentralized</source>
<target>Descentralizada</target>
@@ -1966,6 +1974,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Destination server error: %@" xml:space="preserve">
<source>Destination server error: %@</source>
<target>Error del servidor de destino: %@</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Develop" xml:space="preserve">
@@ -2075,6 +2084,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Do NOT send messages directly, even if your or destination server does not support private routing." xml:space="preserve">
<source>Do NOT send messages directly, even if your or destination server does not support private routing.</source>
<target>NO enviar mensajes directamente incluso si tu servidor o el de destino no soportan enrutamiento privado.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Do NOT use SimpleX for emergency calls." xml:space="preserve">
@@ -2084,6 +2094,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Do NOT use private routing." xml:space="preserve">
<source>Do NOT use private routing.</source>
<target>NO usar enrutamiento privado.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Do it later" xml:space="preserve">
@@ -2743,6 +2754,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Files" xml:space="preserve">
<source>Files</source>
<target>Archivos</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files &amp; media" xml:space="preserve">
@@ -2853,11 +2865,15 @@ This cannot be undone!</source>
<trans-unit id="Forwarding server: %@&#10;Destination server error: %@" xml:space="preserve">
<source>Forwarding server: %1$@
Destination server error: %2$@</source>
<target>Servidor de reenvío: %1$@
Error del servidor de destino: %2$@</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Forwarding server: %@&#10;Error: %@" xml:space="preserve">
<source>Forwarding server: %1$@
Error: %2$@</source>
<target>Servidor de reenvío: %1$@
Error: %2$@</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Found desktop" xml:space="preserve">
@@ -3677,6 +3693,7 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Message delivery warning" xml:space="preserve">
<source>Message delivery warning</source>
<target>Aviso de entrega de mensaje</target>
<note>item status text</note>
</trans-unit>
<trans-unit id="Message draft" xml:space="preserve">
@@ -3684,6 +3701,10 @@ This is your link for group %@!</source>
<target>Borrador de mensaje</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message queue info" xml:space="preserve">
<source>Message queue info</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message reactions" xml:space="preserve">
<source>Message reactions</source>
<target>Reacciones a mensajes</target>
@@ -3701,10 +3722,12 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Message routing fallback" xml:space="preserve">
<source>Message routing fallback</source>
<target>Enrutamiento de mensajes alternativo</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message routing mode" xml:space="preserve">
<source>Message routing mode</source>
<target>Modo de enrutamiento de mensajes</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message source remains private." xml:space="preserve">
@@ -3869,6 +3892,7 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Network issues - message expired after many attempts to send it." xml:space="preserve">
<source>Network issues - message expired after many attempts to send it.</source>
<target>Problema en la red - el mensaje ha expirado tras muchos intentos de envío.</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Network management" xml:space="preserve">
@@ -4414,10 +4438,12 @@ Error: %@</target>
</trans-unit>
<trans-unit id="Private message routing" xml:space="preserve">
<source>Private message routing</source>
<target>Enrutamiento privado de mensajes</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private message routing 🚀" xml:space="preserve">
<source>Private message routing 🚀</source>
<target>Enrutamiento privado de mensajes 🚀</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private notes" xml:space="preserve">
@@ -4427,6 +4453,7 @@ Error: %@</target>
</trans-unit>
<trans-unit id="Private routing" xml:space="preserve">
<source>Private routing</source>
<target>Enrutamiento privado</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile and server connections" xml:space="preserve">
@@ -4511,6 +4538,7 @@ Error: %@</target>
</trans-unit>
<trans-unit id="Protect IP address" xml:space="preserve">
<source>Protect IP address</source>
<target>Proteger dirección IP</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Protect app screen" xml:space="preserve">
@@ -4521,6 +4549,8 @@ Error: %@</target>
<trans-unit id="Protect your IP address from the messaging relays chosen by your contacts.&#10;Enable in *Network &amp; servers* settings." xml:space="preserve">
<source>Protect your IP address from the messaging relays chosen by your contacts.
Enable in *Network &amp; servers* settings.</source>
<target>Protege tu dirección IP de los servidores de retransmisión elegidos por tus contactos.
Actívalo en ajustes de *Servidores y Redes*.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Protect your chat profiles with a password!" xml:space="preserve">
@@ -4695,7 +4725,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Relay server is only used if necessary. Another party can observe your IP address." xml:space="preserve">
<source>Relay server is only used if necessary. Another party can observe your IP address.</source>
<target>El retransmisor sólo se usa en caso de necesidad. Un tercero podría ver tu IP.</target>
<target>El servidor de retransmisión sólo se usa en caso de necesidad. Un tercero podría ver tu IP.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Relay server protects your IP address, but it can observe the duration of the call." xml:space="preserve">
@@ -4865,6 +4895,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Safely receive files" xml:space="preserve">
<source>Safely receive files</source>
<target>Recibe archivos de forma segura</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Safer groups" xml:space="preserve">
@@ -5074,7 +5105,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Send direct message to connect" xml:space="preserve">
<source>Send direct message to connect</source>
<target>Enviar mensaje directo para conectar</target>
<target>Envia un mensaje para conectar</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send disappearing message" xml:space="preserve">
@@ -5094,10 +5125,12 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Send messages directly when IP address is protected and your or destination server does not support private routing." xml:space="preserve">
<source>Send messages directly when IP address is protected and your or destination server does not support private routing.</source>
<target>Enviar mensajes directamente cuando tu dirección IP está protegida y tu servidor o el de destino no admitan enrutamiento privado.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send messages directly when your or destination server does not support private routing." xml:space="preserve">
<source>Send messages directly when your or destination server does not support private routing.</source>
<target>Enviar mensajes directamente cuando tu servidor o el de destino no admitan enrutamiento privado.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send notifications" xml:space="preserve">
@@ -5207,6 +5240,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Server address is incompatible with network settings." xml:space="preserve">
<source>Server address is incompatible with network settings.</source>
<target>La dirección del servidor es incompatible con la configuración de la red.</target>
<note>srv error text.</note>
</trans-unit>
<trans-unit id="Server requires authorization to create queues, check password" xml:space="preserve">
@@ -5226,6 +5260,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Server version is incompatible with network settings." xml:space="preserve">
<source>Server version is incompatible with network settings.</source>
<target>La versión del servidor es incompatible con la configuración de red.</target>
<note>srv error text</note>
</trans-unit>
<trans-unit id="Servers" xml:space="preserve">
@@ -5350,6 +5385,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Show message status" xml:space="preserve">
<source>Show message status</source>
<target>Estado del mensaje</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show preview" xml:space="preserve">
@@ -5359,6 +5395,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Show → on messages sent via private routing." xml:space="preserve">
<source>Show → on messages sent via private routing.</source>
<target>Mostrar → en mensajes con enrutamiento privado.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show:" xml:space="preserve">
@@ -5685,6 +5722,7 @@ Puede ocurrir por algún bug o cuando la conexión está comprometida.</target>
</trans-unit>
<trans-unit id="The app will ask to confirm downloads from unknown file servers (except .onion)." xml:space="preserve">
<source>The app will ask to confirm downloads from unknown file servers (except .onion).</source>
<target>La aplicación pedirá que confirmes las descargas desde servidores de archivos desconocidos (excepto .onion).</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="The attempt to change database passphrase was not completed." xml:space="preserve">
@@ -5874,6 +5912,7 @@ Puede ocurrir por algún bug o cuando la conexión está comprometida.</target>
</trans-unit>
<trans-unit id="To protect your IP address, private routing uses your SMP servers to deliver messages." xml:space="preserve">
<source>To protect your IP address, private routing uses your SMP servers to deliver messages.</source>
<target>Para proteger tu dirección IP, el enrutamiento privado usa tus servidores SMP para enviar mensajes.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To protect your information, turn on SimpleX Lock.&#10;You will be prompted to complete authentication before this feature is enabled." xml:space="preserve">
@@ -6015,6 +6054,7 @@ Se te pedirá que completes la autenticación antes de activar esta función.</t
</trans-unit>
<trans-unit id="Unknown servers!" xml:space="preserve">
<source>Unknown servers!</source>
<target>¡Servidores desconocidos!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unless you use iOS call interface, enable Do Not Disturb mode to avoid interruptions." xml:space="preserve">
@@ -6167,10 +6207,12 @@ Para conectarte, pide a tu contacto que cree otro enlace de conexión y comprueb
</trans-unit>
<trans-unit id="Use private routing with unknown servers when IP address is not protected." xml:space="preserve">
<source>Use private routing with unknown servers when IP address is not protected.</source>
<target>Usar enrutamiento privado con servidores desconocidos cuando la dirección IP no está protegida.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use private routing with unknown servers." xml:space="preserve">
<source>Use private routing with unknown servers.</source>
<target>Usar enrutamiento privado con servidores desconocidos.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use server" xml:space="preserve">
@@ -6410,10 +6452,12 @@ Para conectarte, pide a tu contacto que cree otro enlace de conexión y comprueb
</trans-unit>
<trans-unit id="Without Tor or VPN, your IP address will be visible to file servers." xml:space="preserve">
<source>Without Tor or VPN, your IP address will be visible to file servers.</source>
<target>Sin Tor o VPN, tu dirección IP será visible para los servidores de archivos.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Without Tor or VPN, your IP address will be visible to these XFTP relays: %@." xml:space="preserve">
<source>Without Tor or VPN, your IP address will be visible to these XFTP relays: %@.</source>
<target>Sin Tor o VPN, tu dirección IP será visible para estos servidores XFTP: %@.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Wrong database passphrase" xml:space="preserve">
@@ -6423,6 +6467,7 @@ Para conectarte, pide a tu contacto que cree otro enlace de conexión y comprueb
</trans-unit>
<trans-unit id="Wrong key or unknown connection - most likely this connection is deleted." xml:space="preserve">
<source>Wrong key or unknown connection - most likely this connection is deleted.</source>
<target>Clave incorrecta o conexión desconocida - probablemente esta conexión fue eliminada.</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Wrong passphrase!" xml:space="preserve">
@@ -7540,6 +7585,12 @@ Los servidores de SimpleX no pueden ver tu perfil.</target>
<target>Enviar mensaje directo</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="server queue info: %@&#10;&#10;last received msg: %@" xml:space="preserve">
<source>server queue info: %1$@
last received msg: %2$@</source>
<note>queue info</note>
</trans-unit>
<trans-unit id="set new contact address" xml:space="preserve">
<source>set new contact address</source>
<target>nueva dirección de contacto</target>
@@ -7582,6 +7633,7 @@ Los servidores de SimpleX no pueden ver tu perfil.</target>
</trans-unit>
<trans-unit id="unknown relays" xml:space="preserve">
<source>unknown relays</source>
<target>servidor de retransmisión desconocido</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="unknown status" xml:space="preserve">
@@ -7591,6 +7643,7 @@ Los servidores de SimpleX no pueden ver tu perfil.</target>
</trans-unit>
<trans-unit id="unprotected" xml:space="preserve">
<source>unprotected</source>
<target>desprotegido</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="updated group profile" xml:space="preserve">
@@ -7660,6 +7713,7 @@ Los servidores de SimpleX no pueden ver tu perfil.</target>
</trans-unit>
<trans-unit id="when IP hidden" xml:space="preserve">
<source>when IP hidden</source>
<target>con IP oculta</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="yes" xml:space="preserve">
@@ -1640,6 +1640,10 @@ This is your own one-time link!</source>
<target>Tietokanta siirretään, kun sovellus käynnistyy uudelleen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Debug delivery" xml:space="preserve">
<source>Debug delivery</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Decentralized" xml:space="preserve">
<source>Decentralized</source>
<target>Hajautettu</target>
@@ -3531,6 +3535,10 @@ This is your link for group %@!</source>
<target>Viestiluonnos</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message queue info" xml:space="preserve">
<source>Message queue info</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message reactions" xml:space="preserve">
<source>Message reactions</source>
<target>Viestireaktiot</target>
@@ -7231,6 +7239,12 @@ SimpleX-palvelimet eivät näe profiiliasi.</target>
<source>send direct message</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="server queue info: %@&#10;&#10;last received msg: %@" xml:space="preserve">
<source>server queue info: %1$@
last received msg: %2$@</source>
<note>queue info</note>
</trans-unit>
<trans-unit id="set new contact address" xml:space="preserve">
<source>set new contact address</source>
<note>profile update event chat item</note>
@@ -715,6 +715,7 @@
</trans-unit>
<trans-unit id="Allow downgrade" xml:space="preserve">
<source>Allow downgrade</source>
<target>Autoriser la rétrogradation</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">
@@ -814,6 +815,7 @@
</trans-unit>
<trans-unit id="Always use private routing." xml:space="preserve">
<source>Always use private routing.</source>
<target>Toujours utiliser le routage privé.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Always use relay" xml:space="preserve">
@@ -1098,6 +1100,7 @@
</trans-unit>
<trans-unit id="Capacity exceeded - recipient did not receive previously sent messages." xml:space="preserve">
<source>Capacity exceeded - recipient did not receive previously sent messages.</source>
<target>Capacité dépassée - le destinataire n'a pas pu recevoir les messages envoyés précédemment.</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Cellular" xml:space="preserve">
@@ -1298,6 +1301,7 @@
</trans-unit>
<trans-unit id="Confirm files from unknown servers." xml:space="preserve">
<source>Confirm files from unknown servers.</source>
<target>Confirmer les fichiers provenant de serveurs inconnus.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirm network settings" xml:space="preserve">
@@ -1717,6 +1721,10 @@ Il s'agit de votre propre lien unique !</target>
<target>La base de données sera migrée lors du redémarrage de l'app</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Debug delivery" xml:space="preserve">
<source>Debug delivery</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Decentralized" xml:space="preserve">
<source>Decentralized</source>
<target>Décentralisé</target>
@@ -1966,6 +1974,7 @@ Cette opération ne peut être annulée !</target>
</trans-unit>
<trans-unit id="Destination server error: %@" xml:space="preserve">
<source>Destination server error: %@</source>
<target>Erreur du serveur de destination: %@</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Develop" xml:space="preserve">
@@ -2075,6 +2084,7 @@ Cette opération ne peut être annulée !</target>
</trans-unit>
<trans-unit id="Do NOT send messages directly, even if your or destination server does not support private routing." xml:space="preserve">
<source>Do NOT send messages directly, even if your or destination server does not support private routing.</source>
<target>Ne pas envoyer de messages directement, même si votre serveur ou le serveur de destination ne prend pas en charge le routage privé.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Do NOT use SimpleX for emergency calls." xml:space="preserve">
@@ -2084,6 +2094,7 @@ Cette opération ne peut être annulée !</target>
</trans-unit>
<trans-unit id="Do NOT use private routing." xml:space="preserve">
<source>Do NOT use private routing.</source>
<target>Ne pas utiliser de routage privé.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Do it later" xml:space="preserve">
@@ -2743,6 +2754,7 @@ Cette opération ne peut être annulée !</target>
</trans-unit>
<trans-unit id="Files" xml:space="preserve">
<source>Files</source>
<target>Fichiers</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files &amp; media" xml:space="preserve">
@@ -2853,11 +2865,15 @@ Cette opération ne peut être annulée !</target>
<trans-unit id="Forwarding server: %@&#10;Destination server error: %@" xml:space="preserve">
<source>Forwarding server: %1$@
Destination server error: %2$@</source>
<target>Serveur de transfert: %1$@
Erreur du serveur de destination: %2$@</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Forwarding server: %@&#10;Error: %@" xml:space="preserve">
<source>Forwarding server: %1$@
Error: %2$@</source>
<target>Serveur de transfert: %1$@
Erreur: %2$@</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Found desktop" xml:space="preserve">
@@ -3677,6 +3693,7 @@ Voici votre lien pour le groupe %@ !</target>
</trans-unit>
<trans-unit id="Message delivery warning" xml:space="preserve">
<source>Message delivery warning</source>
<target>Avertissement sur la distribution des messages</target>
<note>item status text</note>
</trans-unit>
<trans-unit id="Message draft" xml:space="preserve">
@@ -3684,6 +3701,10 @@ Voici votre lien pour le groupe %@ !</target>
<target>Brouillon de message</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message queue info" xml:space="preserve">
<source>Message queue info</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message reactions" xml:space="preserve">
<source>Message reactions</source>
<target>Réactions aux messages</target>
@@ -3701,10 +3722,12 @@ Voici votre lien pour le groupe %@ !</target>
</trans-unit>
<trans-unit id="Message routing fallback" xml:space="preserve">
<source>Message routing fallback</source>
<target>Rabattement du routage des messages</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message routing mode" xml:space="preserve">
<source>Message routing mode</source>
<target>Mode de routage des messages</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message source remains private." xml:space="preserve">
@@ -3869,6 +3892,7 @@ Voici votre lien pour le groupe %@ !</target>
</trans-unit>
<trans-unit id="Network issues - message expired after many attempts to send it." xml:space="preserve">
<source>Network issues - message expired after many attempts to send it.</source>
<target>Problèmes de réseau - le message a expiré après plusieurs tentatives d'envoi.</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Network management" xml:space="preserve">
@@ -4414,10 +4438,12 @@ Erreur: %@</target>
</trans-unit>
<trans-unit id="Private message routing" xml:space="preserve">
<source>Private message routing</source>
<target>Routage privé des messages</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private message routing 🚀" xml:space="preserve">
<source>Private message routing 🚀</source>
<target>Routage privé des messages 🚀</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private notes" xml:space="preserve">
@@ -4427,6 +4453,7 @@ Erreur: %@</target>
</trans-unit>
<trans-unit id="Private routing" xml:space="preserve">
<source>Private routing</source>
<target>Routage privé</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile and server connections" xml:space="preserve">
@@ -4511,6 +4538,7 @@ Erreur: %@</target>
</trans-unit>
<trans-unit id="Protect IP address" xml:space="preserve">
<source>Protect IP address</source>
<target>Protéger l'adresse IP</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Protect app screen" xml:space="preserve">
@@ -4521,6 +4549,8 @@ Erreur: %@</target>
<trans-unit id="Protect your IP address from the messaging relays chosen by your contacts.&#10;Enable in *Network &amp; servers* settings." xml:space="preserve">
<source>Protect your IP address from the messaging relays chosen by your contacts.
Enable in *Network &amp; servers* settings.</source>
<target>Protégez votre adresse IP des relais de messagerie choisis par vos contacts.
Activez-le dans les paramètres *Réseau et serveurs*.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Protect your chat profiles with a password!" xml:space="preserve">
@@ -4865,6 +4895,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Safely receive files" xml:space="preserve">
<source>Safely receive files</source>
<target>Réception de fichiers en toute sécurité</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Safer groups" xml:space="preserve">
@@ -5094,10 +5125,12 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Send messages directly when IP address is protected and your or destination server does not support private routing." xml:space="preserve">
<source>Send messages directly when IP address is protected and your or destination server does not support private routing.</source>
<target>Envoyer les messages de manière directe lorsque l'adresse IP est protégée et que votre serveur ou le serveur de destination ne prend pas en charge le routage privé.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send messages directly when your or destination server does not support private routing." xml:space="preserve">
<source>Send messages directly when your or destination server does not support private routing.</source>
<target>Envoyez les messages de manière directe lorsque votre serveur ou le serveur de destination ne prend pas en charge le routage privé.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send notifications" xml:space="preserve">
@@ -5207,6 +5240,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Server address is incompatible with network settings." xml:space="preserve">
<source>Server address is incompatible with network settings.</source>
<target>L'adresse du serveur est incompatible avec les paramètres du réseau.</target>
<note>srv error text.</note>
</trans-unit>
<trans-unit id="Server requires authorization to create queues, check password" xml:space="preserve">
@@ -5226,6 +5260,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Server version is incompatible with network settings." xml:space="preserve">
<source>Server version is incompatible with network settings.</source>
<target>La version du serveur est incompatible avec les paramètres du réseau.</target>
<note>srv error text</note>
</trans-unit>
<trans-unit id="Servers" xml:space="preserve">
@@ -5350,6 +5385,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Show message status" xml:space="preserve">
<source>Show message status</source>
<target>Afficher le statut du message</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show preview" xml:space="preserve">
@@ -5359,6 +5395,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Show → on messages sent via private routing." xml:space="preserve">
<source>Show → on messages sent via private routing.</source>
<target>Afficher → sur les messages envoyés via le routage privé.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show:" xml:space="preserve">
@@ -5685,6 +5722,7 @@ Cela peut se produire en raison d'un bug ou lorsque la connexion est compromise.
</trans-unit>
<trans-unit id="The app will ask to confirm downloads from unknown file servers (except .onion)." xml:space="preserve">
<source>The app will ask to confirm downloads from unknown file servers (except .onion).</source>
<target>L'application demandera de confirmer les téléchargements à partir de serveurs de fichiers inconnus (sauf .onion).</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="The attempt to change database passphrase was not completed." xml:space="preserve">
@@ -5874,6 +5912,7 @@ Cela peut se produire en raison d'un bug ou lorsque la connexion est compromise.
</trans-unit>
<trans-unit id="To protect your IP address, private routing uses your SMP servers to deliver messages." xml:space="preserve">
<source>To protect your IP address, private routing uses your SMP servers to deliver messages.</source>
<target>Pour protéger votre adresse IP, le routage privé utilise vos serveurs SMP pour délivrer les messages.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To protect your information, turn on SimpleX Lock.&#10;You will be prompted to complete authentication before this feature is enabled." xml:space="preserve">
@@ -6015,6 +6054,7 @@ Vous serez invité à confirmer l'authentification avant que cette fonction ne s
</trans-unit>
<trans-unit id="Unknown servers!" xml:space="preserve">
<source>Unknown servers!</source>
<target>Serveurs inconnus!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unless you use iOS call interface, enable Do Not Disturb mode to avoid interruptions." xml:space="preserve">
@@ -6166,10 +6206,12 @@ Pour vous connecter, veuillez demander à votre contact de créer un autre lien
</trans-unit>
<trans-unit id="Use private routing with unknown servers when IP address is not protected." xml:space="preserve">
<source>Use private routing with unknown servers when IP address is not protected.</source>
<target>Utiliser le routage privé avec des serveurs inconnus lorsque l'adresse IP n'est pas protégée.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use private routing with unknown servers." xml:space="preserve">
<source>Use private routing with unknown servers.</source>
<target>Utiliser le routage privé avec des serveurs inconnus.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use server" xml:space="preserve">
@@ -6409,10 +6451,12 @@ Pour vous connecter, veuillez demander à votre contact de créer un autre lien
</trans-unit>
<trans-unit id="Without Tor or VPN, your IP address will be visible to file servers." xml:space="preserve">
<source>Without Tor or VPN, your IP address will be visible to file servers.</source>
<target>Sans Tor ou un VPN, votre adresse IP sera visible par les serveurs de fichiers.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Without Tor or VPN, your IP address will be visible to these XFTP relays: %@." xml:space="preserve">
<source>Without Tor or VPN, your IP address will be visible to these XFTP relays: %@.</source>
<target>Sans Tor ni VPN, votre adresse IP sera visible par ces relais XFTP: %@.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Wrong database passphrase" xml:space="preserve">
@@ -6422,6 +6466,7 @@ Pour vous connecter, veuillez demander à votre contact de créer un autre lien
</trans-unit>
<trans-unit id="Wrong key or unknown connection - most likely this connection is deleted." xml:space="preserve">
<source>Wrong key or unknown connection - most likely this connection is deleted.</source>
<target>Clé erronée ou connexion non identifiée - il est très probable que cette connexion soit supprimée.</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Wrong passphrase!" xml:space="preserve">
@@ -7539,6 +7584,12 @@ Les serveurs SimpleX ne peuvent pas voir votre profil.</target>
<target>envoyer un message direct</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="server queue info: %@&#10;&#10;last received msg: %@" xml:space="preserve">
<source>server queue info: %1$@
last received msg: %2$@</source>
<note>queue info</note>
</trans-unit>
<trans-unit id="set new contact address" xml:space="preserve">
<source>set new contact address</source>
<target>a changé d'adresse de contact</target>
@@ -7581,6 +7632,7 @@ Les serveurs SimpleX ne peuvent pas voir votre profil.</target>
</trans-unit>
<trans-unit id="unknown relays" xml:space="preserve">
<source>unknown relays</source>
<target>relais inconnus</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="unknown status" xml:space="preserve">
@@ -7590,6 +7642,7 @@ Les serveurs SimpleX ne peuvent pas voir votre profil.</target>
</trans-unit>
<trans-unit id="unprotected" xml:space="preserve">
<source>unprotected</source>
<target>non protégé</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="updated group profile" xml:space="preserve">
@@ -7659,6 +7712,7 @@ Les serveurs SimpleX ne peuvent pas voir votre profil.</target>
</trans-unit>
<trans-unit id="when IP hidden" xml:space="preserve">
<source>when IP hidden</source>
<target>lorsque l'IP est masquée</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="yes" xml:space="preserve">
@@ -349,7 +349,7 @@
</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">
<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>**Legprivátabb**: ne használja a SimpleX Chat értesítési szervert, rendszeresen ellenőrizze az üzeneteket a háttérben (attól függően, hogy milyen gyakran használja az alkalmazást).</target>
<target>**Legprivátabb**: ne használja a SimpleX Chat értesítési kiszolgálót, rendszeresen ellenőrizze az üzeneteket a háttérben (attól függően, hogy milyen gyakran használja az alkalmazást).</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">
@@ -364,7 +364,7 @@
</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">
<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>**Javasolt**: az eszköztoken és az értesítések elküldésre kerülnek a SimpleX Chat értesítési szerverre, kivéve az üzenet tartalma, mérete vagy az, hogy kitől származik.</target>
<target>**Javasolt**: az eszköztoken és az értesítések elküldésre kerülnek a SimpleX Chat értesítési kiszolgálóra, kivéve az üzenet tartalma, mérete vagy az, hogy kitől származik.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="**Warning**: Instant push notifications require passphrase saved in Keychain." xml:space="preserve">
@@ -715,6 +715,7 @@
</trans-unit>
<trans-unit id="Allow downgrade" xml:space="preserve">
<source>Allow downgrade</source>
<target>Korábbi verzióra történő visszatérés engedélyezése</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">
@@ -814,6 +815,7 @@
</trans-unit>
<trans-unit id="Always use private routing." xml:space="preserve">
<source>Always use private routing.</source>
<target>Mindig használjon privát útválasztást.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Always use relay" xml:space="preserve">
@@ -1098,6 +1100,7 @@
</trans-unit>
<trans-unit id="Capacity exceeded - recipient did not receive previously sent messages." xml:space="preserve">
<source>Capacity exceeded - recipient did not receive previously sent messages.</source>
<target>Kapacitás túllépés - a címzett nem kapta meg a korábban elküldött üzeneteket.</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Cellular" xml:space="preserve">
@@ -1223,7 +1226,7 @@
</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>
<target>Válassza az _Átköltöztetés egy másik eszközről_ opciót az új eszközön és szkennelje be a QR-kódot.</target>
<target>Válassza az _Átköltöztetés egy másik eszközről_ opciót az új eszközön és olvassa be a QR-kódot.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Choose file" xml:space="preserve">
@@ -1243,17 +1246,17 @@
</trans-unit>
<trans-unit id="Clear conversation" xml:space="preserve">
<source>Clear conversation</source>
<target>Beszélgetés kiürítése</target>
<target>Üzenetek kiürítése</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Clear conversation?" xml:space="preserve">
<source>Clear conversation?</source>
<target>Beszélgetés kiürítése?</target>
<target>Üzenetek kiürítése?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Clear private notes?" xml:space="preserve">
<source>Clear private notes?</source>
<target>Privát jegyzetek törlése?</target>
<target>Privát jegyzetek kiürítése?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Clear verification" xml:space="preserve">
@@ -1298,6 +1301,7 @@
</trans-unit>
<trans-unit id="Confirm files from unknown servers." xml:space="preserve">
<source>Confirm files from unknown servers.</source>
<target>Ismeretlen kiszolgálókról származó fájlok jóváhagyása.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirm network settings" xml:space="preserve">
@@ -1717,6 +1721,10 @@ Ez az egyszer használatos hivatkozása!</target>
<target>Az adatbázis az alkalmazás újraindításakor migrálásra kerül</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Debug delivery" xml:space="preserve">
<source>Debug delivery</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Decentralized" xml:space="preserve">
<source>Decentralized</source>
<target>Decentralizált</target>
@@ -1966,6 +1974,7 @@ Ez a művelet nem vonható vissza!</target>
</trans-unit>
<trans-unit id="Destination server error: %@" xml:space="preserve">
<source>Destination server error: %@</source>
<target>Célkiszolgáló hiba: %@</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Develop" xml:space="preserve">
@@ -2075,6 +2084,7 @@ Ez a művelet nem vonható vissza!</target>
</trans-unit>
<trans-unit id="Do NOT send messages directly, even if your or destination server does not support private routing." xml:space="preserve">
<source>Do NOT send messages directly, even if your or destination server does not support private routing.</source>
<target>Ne küldjön üzeneteket közvetlenül, még akkor sem, ha az ön kiszolgálója vagy a célkiszolgáló nem támogatja a privát útválasztást.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Do NOT use SimpleX for emergency calls." xml:space="preserve">
@@ -2084,6 +2094,7 @@ Ez a művelet nem vonható vissza!</target>
</trans-unit>
<trans-unit id="Do NOT use private routing." xml:space="preserve">
<source>Do NOT use private routing.</source>
<target>Ne használjon privát útválasztást.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Do it later" xml:space="preserve">
@@ -2743,6 +2754,7 @@ Ez a művelet nem vonható vissza!</target>
</trans-unit>
<trans-unit id="Files" xml:space="preserve">
<source>Files</source>
<target>Fájlok</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files &amp; media" xml:space="preserve">
@@ -2853,11 +2865,15 @@ Ez a művelet nem vonható vissza!</target>
<trans-unit id="Forwarding server: %@&#10;Destination server error: %@" xml:space="preserve">
<source>Forwarding server: %1$@
Destination server error: %2$@</source>
<target>Továbbító kiszolgáló: %1$@
Célkiszolgáló hiba:%2$@</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Forwarding server: %@&#10;Error: %@" xml:space="preserve">
<source>Forwarding server: %1$@
Error: %2$@</source>
<target>Továbbító kiszolgáló: %1$@
Hiba: %2$@</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Found desktop" xml:space="preserve">
@@ -3607,7 +3623,7 @@ Ez az ön hivatkozása a(z) %@ csoporthoz!</target>
</trans-unit>
<trans-unit id="Make sure %@ server addresses are in correct format, line separated and are not duplicated (%@)." xml:space="preserve">
<source>Make sure %@ server addresses are in correct format, line separated and are not duplicated (%@).</source>
<target>Győződjön meg arról, hogy a %@ szervercímek megfelelő formátumúak, sorszeparáltak és nem duplikáltak (%@).</target>
<target>Győződjön meg arról, hogy a %@ kiszolgálócímek megfelelő formátumúak, sorszeparáltak és nem duplikáltak (%@).</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Make sure WebRTC ICE server addresses are in correct format, line separated and are not duplicated." xml:space="preserve">
@@ -3627,7 +3643,7 @@ Ez az ön hivatkozása a(z) %@ csoporthoz!</target>
</trans-unit>
<trans-unit id="Mark read" xml:space="preserve">
<source>Mark read</source>
<target>Olvasottként jelölés</target>
<target>Olvasottnak jelölés</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Mark verified" xml:space="preserve">
@@ -3677,6 +3693,7 @@ Ez az ön hivatkozása a(z) %@ csoporthoz!</target>
</trans-unit>
<trans-unit id="Message delivery warning" xml:space="preserve">
<source>Message delivery warning</source>
<target>Üzenet kézbesítési figyelmeztetés</target>
<note>item status text</note>
</trans-unit>
<trans-unit id="Message draft" xml:space="preserve">
@@ -3684,6 +3701,10 @@ Ez az ön hivatkozása a(z) %@ csoporthoz!</target>
<target>Üzenetvázlat</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message queue info" xml:space="preserve">
<source>Message queue info</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message reactions" xml:space="preserve">
<source>Message reactions</source>
<target>Üzenetreakciók</target>
@@ -3701,10 +3722,12 @@ Ez az ön hivatkozása a(z) %@ csoporthoz!</target>
</trans-unit>
<trans-unit id="Message routing fallback" xml:space="preserve">
<source>Message routing fallback</source>
<target>Üzenet útválasztási tartalék</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message routing mode" xml:space="preserve">
<source>Message routing mode</source>
<target>Üzenet útválasztási mód</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message source remains private." xml:space="preserve">
@@ -3739,12 +3762,12 @@ Ez az ön hivatkozása a(z) %@ csoporthoz!</target>
</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>
<target>Az üzeneteket, fájlokat és hívásokat **végpontok közötti titkosítással** és sérülés utáni titkosságvédelemmel, visszautasítással és sérülés utáni helyreállítással védi.</target>
<target>Az üzeneteket, fájlokat és hívásokat **végpontok közötti titkosítással**, sérülés utáni titkosság-védelemmel és -helyreállítással, továbbá visszautasítással védi.</target>
<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>
<target>Az üzeneteket, fájlokat és hívásokat **végpontok közötti kvantumrezisztens titkosítással** és sérülés utáni titkosságvédelemmel, visszautasítással és sérülés utáni helyreállítással védi.</target>
<target>Az üzeneteket, fájlokat és hívásokat **végpontok közötti kvantumrezisztens titkosítással**, sérülés utáni titkosság-védelemmel és -helyreállítással, továbbá visszautasítással védi.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Migrate device" xml:space="preserve">
@@ -3869,6 +3892,7 @@ Ez az ön hivatkozása a(z) %@ csoporthoz!</target>
</trans-unit>
<trans-unit id="Network issues - message expired after many attempts to send it." xml:space="preserve">
<source>Network issues - message expired after many attempts to send it.</source>
<target>Hálózati problémák - az üzenet többszöri elküldési kísérlet után lejárt.</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Network management" xml:space="preserve">
@@ -4414,10 +4438,12 @@ Hiba: %@</target>
</trans-unit>
<trans-unit id="Private message routing" xml:space="preserve">
<source>Private message routing</source>
<target>Privát üzenet útválasztás</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private message routing 🚀" xml:space="preserve">
<source>Private message routing 🚀</source>
<target>Privát üzenet útválasztás 🚀</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private notes" xml:space="preserve">
@@ -4427,6 +4453,7 @@ Hiba: %@</target>
</trans-unit>
<trans-unit id="Private routing" xml:space="preserve">
<source>Private routing</source>
<target>Privát útválasztás</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile and server connections" xml:space="preserve">
@@ -4511,6 +4538,7 @@ Hiba: %@</target>
</trans-unit>
<trans-unit id="Protect IP address" xml:space="preserve">
<source>Protect IP address</source>
<target>Az IP-cím védelme</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Protect app screen" xml:space="preserve">
@@ -4521,6 +4549,8 @@ Hiba: %@</target>
<trans-unit id="Protect your IP address from the messaging relays chosen by your contacts.&#10;Enable in *Network &amp; servers* settings." xml:space="preserve">
<source>Protect your IP address from the messaging relays chosen by your contacts.
Enable in *Network &amp; servers* settings.</source>
<target>Védje IP-címét az ismerősei által kiválasztott üzenetküldő átjátszókkal szemben.
Engedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Protect your chat profiles with a password!" xml:space="preserve">
@@ -4865,6 +4895,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Safely receive files" xml:space="preserve">
<source>Safely receive files</source>
<target>Fájlok biztonságos fogadása</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Safer groups" xml:space="preserve">
@@ -5094,10 +5125,12 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Send messages directly when IP address is protected and your or destination server does not support private routing." xml:space="preserve">
<source>Send messages directly when IP address is protected and your or destination server does not support private routing.</source>
<target>Közvetlen üzenetküldés, ha az IP-cím védett és az ön kiszolgálója vagy a célkiszolgáló nem támogatja a privát útválasztást.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send messages directly when your or destination server does not support private routing." xml:space="preserve">
<source>Send messages directly when your or destination server does not support private routing.</source>
<target>Közvetlen üzenetküldés, ha az ön kiszolgálója vagy a célkiszolgáló nem támogatja a privát útválasztást.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send notifications" xml:space="preserve">
@@ -5207,6 +5240,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Server address is incompatible with network settings." xml:space="preserve">
<source>Server address is incompatible with network settings.</source>
<target>A kiszolgáló címe nem kompatibilis a hálózati beállításokkal.</target>
<note>srv error text.</note>
</trans-unit>
<trans-unit id="Server requires authorization to create queues, check password" xml:space="preserve">
@@ -5226,6 +5260,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Server version is incompatible with network settings." xml:space="preserve">
<source>Server version is incompatible with network settings.</source>
<target>A kiszolgáló verziója nem kompatibilis a hálózati beállításokkal.</target>
<note>srv error text</note>
</trans-unit>
<trans-unit id="Servers" xml:space="preserve">
@@ -5350,6 +5385,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Show message status" xml:space="preserve">
<source>Show message status</source>
<target>Üzenet állapot megjelenítése</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show preview" xml:space="preserve">
@@ -5359,6 +5395,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Show → on messages sent via private routing." xml:space="preserve">
<source>Show → on messages sent via private routing.</source>
<target>Egy „→” jel megjelenítése a privát útválasztáson keresztül küldött üzeneteknél.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show:" xml:space="preserve">
@@ -5685,6 +5722,7 @@ Ez valamilyen hiba, vagy sérült kapcsolat esetén fordulhat elő.</target>
</trans-unit>
<trans-unit id="The app will ask to confirm downloads from unknown file servers (except .onion)." xml:space="preserve">
<source>The app will ask to confirm downloads from unknown file servers (except .onion).</source>
<target>Az alkalmazás kérni fogja az ismeretlen fájlkiszolgálókról (kivéve .onion) történő letöltések megerősítését.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="The attempt to change database passphrase was not completed." xml:space="preserve">
@@ -5874,6 +5912,7 @@ Ez valamilyen hiba, vagy sérült kapcsolat esetén fordulhat elő.</target>
</trans-unit>
<trans-unit id="To protect your IP address, private routing uses your SMP servers to deliver messages." xml:space="preserve">
<source>To protect your IP address, private routing uses your SMP servers to deliver messages.</source>
<target>Az IP-címe védelme érdekében a privát útválasztás az SMP-kiszolgálókat használja az üzenetek kézbesítéséhez.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To protect your information, turn on SimpleX Lock.&#10;You will be prompted to complete authentication before this feature is enabled." xml:space="preserve">
@@ -5900,7 +5939,7 @@ A funkció engedélyezése előtt a rendszer felszólítja a hitelesítés befej
</trans-unit>
<trans-unit id="To verify end-to-end encryption with your contact compare (or scan) the code on your devices." xml:space="preserve">
<source>To verify end-to-end encryption with your contact compare (or scan) the code on your devices.</source>
<target>A végpontok közötti titkosítás ellenőrzéséhez ismerősével hasonlítsa össze (vagy szkennelje be) az eszközén lévő kódot.</target>
<target>A végpontok közötti titkosítás ellenőrzéséhez hasonlítsa össze (vagy olvassa be a QR-kódot) az ismerőse eszközén lévő kóddal.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Toggle incognito when connecting." xml:space="preserve">
@@ -6015,6 +6054,7 @@ A funkció engedélyezése előtt a rendszer felszólítja a hitelesítés befej
</trans-unit>
<trans-unit id="Unknown servers!" xml:space="preserve">
<source>Unknown servers!</source>
<target>Ismeretlen kiszolgálók!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unless you use iOS call interface, enable Do Not Disturb mode to avoid interruptions." xml:space="preserve">
@@ -6091,7 +6131,7 @@ A kapcsolódáshoz kérje meg ismerősét, hogy hozzon létre egy másik kapcsol
</trans-unit>
<trans-unit id="Updating settings will re-connect the client to all servers." xml:space="preserve">
<source>Updating settings will re-connect the client to all servers.</source>
<target>A beállítások frissítése a szerverekhez újra kapcsolódással jár.</target>
<target>A beállítások frissítése a kiszolgálókhoz való újra kapcsolódással jár.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Updating this setting will re-connect the client to all servers." xml:space="preserve">
@@ -6166,10 +6206,12 @@ A kapcsolódáshoz kérje meg ismerősét, hogy hozzon létre egy másik kapcsol
</trans-unit>
<trans-unit id="Use private routing with unknown servers when IP address is not protected." xml:space="preserve">
<source>Use private routing with unknown servers when IP address is not protected.</source>
<target>Privát útválasztás használata ismeretlen kiszolgálókkal, ha az IP-cím nem védett.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use private routing with unknown servers." xml:space="preserve">
<source>Use private routing with unknown servers.</source>
<target>Használjon privát útválasztást ismeretlen kiszolgálókkal.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use server" xml:space="preserve">
@@ -6409,10 +6451,12 @@ A kapcsolódáshoz kérje meg ismerősét, hogy hozzon létre egy másik kapcsol
</trans-unit>
<trans-unit id="Without Tor or VPN, your IP address will be visible to file servers." xml:space="preserve">
<source>Without Tor or VPN, your IP address will be visible to file servers.</source>
<target>Tor vagy VPN nélkül az IP-címe látható lesz a fájlkiszolgálók számára.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Without Tor or VPN, your IP address will be visible to these XFTP relays: %@." xml:space="preserve">
<source>Without Tor or VPN, your IP address will be visible to these XFTP relays: %@.</source>
<target>Tor vagy VPN nélkül az IP-címe látható lesz ezen XFTP átjátszók számára: %@.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Wrong database passphrase" xml:space="preserve">
@@ -6422,6 +6466,7 @@ A kapcsolódáshoz kérje meg ismerősét, hogy hozzon létre egy másik kapcsol
</trans-unit>
<trans-unit id="Wrong key or unknown connection - most likely this connection is deleted." xml:space="preserve">
<source>Wrong key or unknown connection - most likely this connection is deleted.</source>
<target>Rossz kulcs vagy ismeretlen kapcsolat - valószínűleg ez a kapcsolat törlődött.</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Wrong passphrase!" xml:space="preserve">
@@ -6598,7 +6643,7 @@ Csatlakozási kérés megismétlése?</target>
</trans-unit>
<trans-unit id="You control through which server(s) **to receive** the messages, your contacts the servers you use to message them." xml:space="preserve">
<source>You control through which server(s) **to receive** the messages, your contacts the servers you use to message them.</source>
<target>Ön szabályozhatja, hogy mely kiszogál(ók)ón keresztül **kapja** az üzeneteket, az ismerősöket - az üzenetküldéshez használt szervereken.</target>
<target>Ön szabályozhatja, hogy mely kiszogál(ók)ón keresztül **kapja** az üzeneteket, az ismerősöket - az üzenetküldéshez használt kiszolgálókon.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You could not be verified; please try again." xml:space="preserve">
@@ -7539,6 +7584,12 @@ A SimpleX kiszolgálók nem látjhatják profilját.</target>
<target>közvetlen üzenet küldése</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="server queue info: %@&#10;&#10;last received msg: %@" xml:space="preserve">
<source>server queue info: %1$@
last received msg: %2$@</source>
<note>queue info</note>
</trans-unit>
<trans-unit id="set new contact address" xml:space="preserve">
<source>set new contact address</source>
<target>új kapcsolattartási azonosító beállítása</target>
@@ -7581,6 +7632,7 @@ A SimpleX kiszolgálók nem látjhatják profilját.</target>
</trans-unit>
<trans-unit id="unknown relays" xml:space="preserve">
<source>unknown relays</source>
<target>ismeretlen átjátszók</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="unknown status" xml:space="preserve">
@@ -7590,6 +7642,7 @@ A SimpleX kiszolgálók nem látjhatják profilját.</target>
</trans-unit>
<trans-unit id="unprotected" xml:space="preserve">
<source>unprotected</source>
<target>nem védett</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="updated group profile" xml:space="preserve">
@@ -7659,6 +7712,7 @@ A SimpleX kiszolgálók nem látjhatják profilját.</target>
</trans-unit>
<trans-unit id="when IP hidden" xml:space="preserve">
<source>when IP hidden</source>
<target>ha az IP-cím rejtett</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="yes" xml:space="preserve">
@@ -715,6 +715,7 @@
</trans-unit>
<trans-unit id="Allow downgrade" xml:space="preserve">
<source>Allow downgrade</source>
<target>Consenti downgrade</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">
@@ -814,6 +815,7 @@
</trans-unit>
<trans-unit id="Always use private routing." xml:space="preserve">
<source>Always use private routing.</source>
<target>Usa sempre l'instradamento privato.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Always use relay" xml:space="preserve">
@@ -1098,6 +1100,7 @@
</trans-unit>
<trans-unit id="Capacity exceeded - recipient did not receive previously sent messages." xml:space="preserve">
<source>Capacity exceeded - recipient did not receive previously sent messages.</source>
<target>Quota superata - il destinatario non ha ricevuto i messaggi precedentemente inviati.</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Cellular" xml:space="preserve">
@@ -1298,6 +1301,7 @@
</trans-unit>
<trans-unit id="Confirm files from unknown servers." xml:space="preserve">
<source>Confirm files from unknown servers.</source>
<target>Conferma i file da server sconosciuti.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirm network settings" xml:space="preserve">
@@ -1717,6 +1721,10 @@ Questo è il tuo link una tantum!</target>
<target>Il database verrà migrato al riavvio dell'app</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Debug delivery" xml:space="preserve">
<source>Debug delivery</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Decentralized" xml:space="preserve">
<source>Decentralized</source>
<target>Decentralizzato</target>
@@ -1966,6 +1974,7 @@ Non è reversibile!</target>
</trans-unit>
<trans-unit id="Destination server error: %@" xml:space="preserve">
<source>Destination server error: %@</source>
<target>Errore del server di destinazione: %@</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Develop" xml:space="preserve">
@@ -2075,6 +2084,7 @@ Non è reversibile!</target>
</trans-unit>
<trans-unit id="Do NOT send messages directly, even if your or destination server does not support private routing." xml:space="preserve">
<source>Do NOT send messages directly, even if your or destination server does not support private routing.</source>
<target>NON inviare messaggi direttamente, anche se il tuo server o quello di destinazione non supporta l'instradamento privato.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Do NOT use SimpleX for emergency calls." xml:space="preserve">
@@ -2084,6 +2094,7 @@ Non è reversibile!</target>
</trans-unit>
<trans-unit id="Do NOT use private routing." xml:space="preserve">
<source>Do NOT use private routing.</source>
<target>NON usare l'instradamento privato.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Do it later" xml:space="preserve">
@@ -2743,6 +2754,7 @@ Non è reversibile!</target>
</trans-unit>
<trans-unit id="Files" xml:space="preserve">
<source>Files</source>
<target>File</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files &amp; media" xml:space="preserve">
@@ -2853,11 +2865,15 @@ Non è reversibile!</target>
<trans-unit id="Forwarding server: %@&#10;Destination server error: %@" xml:space="preserve">
<source>Forwarding server: %1$@
Destination server error: %2$@</source>
<target>Server di inoltro: %1$@
Errore del server di destinazione: %2$@</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Forwarding server: %@&#10;Error: %@" xml:space="preserve">
<source>Forwarding server: %1$@
Error: %2$@</source>
<target>Server di inoltro: %1$@
Errore: %2$@</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Found desktop" xml:space="preserve">
@@ -3677,6 +3693,7 @@ Questo è il tuo link per il gruppo %@!</target>
</trans-unit>
<trans-unit id="Message delivery warning" xml:space="preserve">
<source>Message delivery warning</source>
<target>Avviso di consegna del messaggio</target>
<note>item status text</note>
</trans-unit>
<trans-unit id="Message draft" xml:space="preserve">
@@ -3684,6 +3701,10 @@ Questo è il tuo link per il gruppo %@!</target>
<target>Bozza dei messaggi</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message queue info" xml:space="preserve">
<source>Message queue info</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message reactions" xml:space="preserve">
<source>Message reactions</source>
<target>Reazioni ai messaggi</target>
@@ -3701,10 +3722,12 @@ Questo è il tuo link per il gruppo %@!</target>
</trans-unit>
<trans-unit id="Message routing fallback" xml:space="preserve">
<source>Message routing fallback</source>
<target>Ripiego instradamento messaggio</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message routing mode" xml:space="preserve">
<source>Message routing mode</source>
<target>Modalità instradamento messaggio</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message source remains private." xml:space="preserve">
@@ -3869,6 +3892,7 @@ Questo è il tuo link per il gruppo %@!</target>
</trans-unit>
<trans-unit id="Network issues - message expired after many attempts to send it." xml:space="preserve">
<source>Network issues - message expired after many attempts to send it.</source>
<target>Problemi di rete - messaggio scaduto dopo molti tentativi di inviarlo.</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Network management" xml:space="preserve">
@@ -4414,10 +4438,12 @@ Errore: %@</target>
</trans-unit>
<trans-unit id="Private message routing" xml:space="preserve">
<source>Private message routing</source>
<target>Instradamento privato messaggi</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private message routing 🚀" xml:space="preserve">
<source>Private message routing 🚀</source>
<target>Instradamento privato dei messaggi 🚀</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private notes" xml:space="preserve">
@@ -4427,6 +4453,7 @@ Errore: %@</target>
</trans-unit>
<trans-unit id="Private routing" xml:space="preserve">
<source>Private routing</source>
<target>Instradamento privato</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile and server connections" xml:space="preserve">
@@ -4511,6 +4538,7 @@ Errore: %@</target>
</trans-unit>
<trans-unit id="Protect IP address" xml:space="preserve">
<source>Protect IP address</source>
<target>Proteggi l'indirizzo IP</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Protect app screen" xml:space="preserve">
@@ -4521,6 +4549,8 @@ Errore: %@</target>
<trans-unit id="Protect your IP address from the messaging relays chosen by your contacts.&#10;Enable in *Network &amp; servers* settings." xml:space="preserve">
<source>Protect your IP address from the messaging relays chosen by your contacts.
Enable in *Network &amp; servers* settings.</source>
<target>Proteggi il tuo indirizzo IP dai relay di messaggistica scelti dai tuoi contatti.
Attivalo nelle impostazioni *Rete e server*.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Protect your chat profiles with a password!" xml:space="preserve">
@@ -4865,6 +4895,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Safely receive files" xml:space="preserve">
<source>Safely receive files</source>
<target>Ricevi i file in sicurezza</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Safer groups" xml:space="preserve">
@@ -5094,10 +5125,12 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Send messages directly when IP address is protected and your or destination server does not support private routing." xml:space="preserve">
<source>Send messages directly when IP address is protected and your or destination server does not support private routing.</source>
<target>Invia messaggi direttamente quando l'indirizzo IP è protetto e il tuo server o quello di destinazione non supporta l'instradamento privato.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send messages directly when your or destination server does not support private routing." xml:space="preserve">
<source>Send messages directly when your or destination server does not support private routing.</source>
<target>Invia messaggi direttamente quando il tuo server o quello di destinazione non supporta l'instradamento privato.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send notifications" xml:space="preserve">
@@ -5207,6 +5240,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Server address is incompatible with network settings." xml:space="preserve">
<source>Server address is incompatible with network settings.</source>
<target>L'indirizzo del server non è compatibile con le impostazioni di rete.</target>
<note>srv error text.</note>
</trans-unit>
<trans-unit id="Server requires authorization to create queues, check password" xml:space="preserve">
@@ -5226,6 +5260,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Server version is incompatible with network settings." xml:space="preserve">
<source>Server version is incompatible with network settings.</source>
<target>La versione del server non è compatibile con le impostazioni di rete.</target>
<note>srv error text</note>
</trans-unit>
<trans-unit id="Servers" xml:space="preserve">
@@ -5350,6 +5385,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Show message status" xml:space="preserve">
<source>Show message status</source>
<target>Mostra stato del messaggio</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show preview" xml:space="preserve">
@@ -5359,6 +5395,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Show → on messages sent via private routing." xml:space="preserve">
<source>Show → on messages sent via private routing.</source>
<target>Mostra → nei messaggi inviati via instradamento privato.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show:" xml:space="preserve">
@@ -5685,6 +5722,7 @@ Può accadere a causa di qualche bug o quando la connessione è compromessa.</ta
</trans-unit>
<trans-unit id="The app will ask to confirm downloads from unknown file servers (except .onion)." xml:space="preserve">
<source>The app will ask to confirm downloads from unknown file servers (except .onion).</source>
<target>L'app chiederà di confermare i download da server di file sconosciuti (eccetto .onion).</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="The attempt to change database passphrase was not completed." xml:space="preserve">
@@ -5874,6 +5912,7 @@ Può accadere a causa di qualche bug o quando la connessione è compromessa.</ta
</trans-unit>
<trans-unit id="To protect your IP address, private routing uses your SMP servers to deliver messages." xml:space="preserve">
<source>To protect your IP address, private routing uses your SMP servers to deliver messages.</source>
<target>Per proteggere il tuo indirizzo IP, l'instradamento privato usa i tuoi server SMP per consegnare i messaggi.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To protect your information, turn on SimpleX Lock.&#10;You will be prompted to complete authentication before this feature is enabled." xml:space="preserve">
@@ -6015,6 +6054,7 @@ Ti verrà chiesto di completare l'autenticazione prima di attivare questa funzio
</trans-unit>
<trans-unit id="Unknown servers!" xml:space="preserve">
<source>Unknown servers!</source>
<target>Server sconosciuti!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unless you use iOS call interface, enable Do Not Disturb mode to avoid interruptions." xml:space="preserve">
@@ -6166,10 +6206,12 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e
</trans-unit>
<trans-unit id="Use private routing with unknown servers when IP address is not protected." xml:space="preserve">
<source>Use private routing with unknown servers when IP address is not protected.</source>
<target>Usa l'instradamento privato con server sconosciuti quando l'indirizzo IP non è protetto.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use private routing with unknown servers." xml:space="preserve">
<source>Use private routing with unknown servers.</source>
<target>Usa l'instradamento privato con server sconosciuti.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use server" xml:space="preserve">
@@ -6409,10 +6451,12 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e
</trans-unit>
<trans-unit id="Without Tor or VPN, your IP address will be visible to file servers." xml:space="preserve">
<source>Without Tor or VPN, your IP address will be visible to file servers.</source>
<target>Senza Tor o VPN, il tuo indirizzo IP sarà visibile ai server di file.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Without Tor or VPN, your IP address will be visible to these XFTP relays: %@." xml:space="preserve">
<source>Without Tor or VPN, your IP address will be visible to these XFTP relays: %@.</source>
<target>Senza Tor o VPN, il tuo indirizzo IP sarà visibile a questi relay XFTP: %@.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Wrong database passphrase" xml:space="preserve">
@@ -6422,6 +6466,7 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e
</trans-unit>
<trans-unit id="Wrong key or unknown connection - most likely this connection is deleted." xml:space="preserve">
<source>Wrong key or unknown connection - most likely this connection is deleted.</source>
<target>Chiave sbagliata o connessione sconosciuta - molto probabilmente questa connessione è stata eliminata.</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Wrong passphrase!" xml:space="preserve">
@@ -7539,6 +7584,12 @@ I server di SimpleX non possono vedere il tuo profilo.</target>
<target>invia messaggio diretto</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="server queue info: %@&#10;&#10;last received msg: %@" xml:space="preserve">
<source>server queue info: %1$@
last received msg: %2$@</source>
<note>queue info</note>
</trans-unit>
<trans-unit id="set new contact address" xml:space="preserve">
<source>set new contact address</source>
<target>impostato nuovo indirizzo di contatto</target>
@@ -7581,6 +7632,7 @@ I server di SimpleX non possono vedere il tuo profilo.</target>
</trans-unit>
<trans-unit id="unknown relays" xml:space="preserve">
<source>unknown relays</source>
<target>relay sconosciuti</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="unknown status" xml:space="preserve">
@@ -7590,6 +7642,7 @@ I server di SimpleX non possono vedere il tuo profilo.</target>
</trans-unit>
<trans-unit id="unprotected" xml:space="preserve">
<source>unprotected</source>
<target>non protetto</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="updated group profile" xml:space="preserve">
@@ -7659,6 +7712,7 @@ I server di SimpleX non possono vedere il tuo profilo.</target>
</trans-unit>
<trans-unit id="when IP hidden" xml:space="preserve">
<source>when IP hidden</source>
<target>quando l'IP è nascosto</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="yes" xml:space="preserve">
@@ -1664,6 +1664,10 @@ This is your own one-time link!</source>
<target>データベースはアプリ再起動時に移行されます</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Debug delivery" xml:space="preserve">
<source>Debug delivery</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Decentralized" xml:space="preserve">
<source>Decentralized</source>
<target>分散型</target>
@@ -3555,6 +3559,10 @@ This is your link for group %@!</source>
<target>メッセージの下書き</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message queue info" xml:space="preserve">
<source>Message queue info</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message reactions" xml:space="preserve">
<source>Message reactions</source>
<target>メッセージへのリアクション</target>
@@ -7249,6 +7257,12 @@ SimpleX サーバーはあなたのプロファイルを参照できません。
<source>send direct message</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="server queue info: %@&#10;&#10;last received msg: %@" xml:space="preserve">
<source>server queue info: %1$@
last received msg: %2$@</source>
<note>queue info</note>
</trans-unit>
<trans-unit id="set new contact address" xml:space="preserve">
<source>set new contact address</source>
<note>profile update event chat item</note>
@@ -715,6 +715,7 @@
</trans-unit>
<trans-unit id="Allow downgrade" xml:space="preserve">
<source>Allow downgrade</source>
<target>Downgraden toestaan</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">
@@ -814,6 +815,7 @@
</trans-unit>
<trans-unit id="Always use private routing." xml:space="preserve">
<source>Always use private routing.</source>
<target>Gebruik altijd privéroutering.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Always use relay" xml:space="preserve">
@@ -1098,6 +1100,7 @@
</trans-unit>
<trans-unit id="Capacity exceeded - recipient did not receive previously sent messages." xml:space="preserve">
<source>Capacity exceeded - recipient did not receive previously sent messages.</source>
<target>Capaciteit overschreden - ontvanger heeft eerder verzonden berichten niet ontvangen.</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Cellular" xml:space="preserve">
@@ -1298,6 +1301,7 @@
</trans-unit>
<trans-unit id="Confirm files from unknown servers." xml:space="preserve">
<source>Confirm files from unknown servers.</source>
<target>Bevestig bestanden van onbekende servers.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirm network settings" xml:space="preserve">
@@ -1717,6 +1721,10 @@ Dit is uw eigen eenmalige link!</target>
<target>De database wordt gemigreerd wanneer de app opnieuw wordt opgestart</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Debug delivery" xml:space="preserve">
<source>Debug delivery</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Decentralized" xml:space="preserve">
<source>Decentralized</source>
<target>Gedecentraliseerd</target>
@@ -1966,6 +1974,7 @@ Dit kan niet ongedaan gemaakt worden!</target>
</trans-unit>
<trans-unit id="Destination server error: %@" xml:space="preserve">
<source>Destination server error: %@</source>
<target>Bestemmingsserverfout: %@</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Develop" xml:space="preserve">
@@ -2075,6 +2084,7 @@ Dit kan niet ongedaan gemaakt worden!</target>
</trans-unit>
<trans-unit id="Do NOT send messages directly, even if your or destination server does not support private routing." xml:space="preserve">
<source>Do NOT send messages directly, even if your or destination server does not support private routing.</source>
<target>Stuur GEEN berichten rechtstreeks, zelfs als uw of de bestemmingsserver geen privéroutering ondersteunt.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Do NOT use SimpleX for emergency calls." xml:space="preserve">
@@ -2084,6 +2094,7 @@ Dit kan niet ongedaan gemaakt worden!</target>
</trans-unit>
<trans-unit id="Do NOT use private routing." xml:space="preserve">
<source>Do NOT use private routing.</source>
<target>Gebruik GEEN privéroutering.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Do it later" xml:space="preserve">
@@ -2743,6 +2754,7 @@ Dit kan niet ongedaan gemaakt worden!</target>
</trans-unit>
<trans-unit id="Files" xml:space="preserve">
<source>Files</source>
<target>Bestanden</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files &amp; media" xml:space="preserve">
@@ -2853,11 +2865,15 @@ Dit kan niet ongedaan gemaakt worden!</target>
<trans-unit id="Forwarding server: %@&#10;Destination server error: %@" xml:space="preserve">
<source>Forwarding server: %1$@
Destination server error: %2$@</source>
<target>Doorstuurserver: %1$@
Bestemmingsserverfout: %2$@</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Forwarding server: %@&#10;Error: %@" xml:space="preserve">
<source>Forwarding server: %1$@
Error: %2$@</source>
<target>Doorstuurserver: %1$@
Fout: %2$@</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Found desktop" xml:space="preserve">
@@ -3677,6 +3693,7 @@ Dit is jouw link voor groep %@!</target>
</trans-unit>
<trans-unit id="Message delivery warning" xml:space="preserve">
<source>Message delivery warning</source>
<target>Waarschuwing voor berichtbezorging</target>
<note>item status text</note>
</trans-unit>
<trans-unit id="Message draft" xml:space="preserve">
@@ -3684,6 +3701,10 @@ Dit is jouw link voor groep %@!</target>
<target>Concept bericht</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message queue info" xml:space="preserve">
<source>Message queue info</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message reactions" xml:space="preserve">
<source>Message reactions</source>
<target>Reacties op berichten</target>
@@ -3701,10 +3722,12 @@ Dit is jouw link voor groep %@!</target>
</trans-unit>
<trans-unit id="Message routing fallback" xml:space="preserve">
<source>Message routing fallback</source>
<target>Terugval op berichtroutering</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message routing mode" xml:space="preserve">
<source>Message routing mode</source>
<target>Berichtrouteringsmodus</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message source remains private." xml:space="preserve">
@@ -3869,6 +3892,7 @@ Dit is jouw link voor groep %@!</target>
</trans-unit>
<trans-unit id="Network issues - message expired after many attempts to send it." xml:space="preserve">
<source>Network issues - message expired after many attempts to send it.</source>
<target>Netwerkproblemen - bericht is verlopen na vele pogingen om het te verzenden.</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Network management" xml:space="preserve">
@@ -4414,10 +4438,12 @@ Fout: %@</target>
</trans-unit>
<trans-unit id="Private message routing" xml:space="preserve">
<source>Private message routing</source>
<target>Routering van privéberichten</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private message routing 🚀" xml:space="preserve">
<source>Private message routing 🚀</source>
<target>Routing van privéberichten🚀</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private notes" xml:space="preserve">
@@ -4427,6 +4453,7 @@ Fout: %@</target>
</trans-unit>
<trans-unit id="Private routing" xml:space="preserve">
<source>Private routing</source>
<target>Privéroutering</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile and server connections" xml:space="preserve">
@@ -4511,6 +4538,7 @@ Fout: %@</target>
</trans-unit>
<trans-unit id="Protect IP address" xml:space="preserve">
<source>Protect IP address</source>
<target>Bescherm het IP-adres</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Protect app screen" xml:space="preserve">
@@ -4521,6 +4549,8 @@ Fout: %@</target>
<trans-unit id="Protect your IP address from the messaging relays chosen by your contacts.&#10;Enable in *Network &amp; servers* settings." xml:space="preserve">
<source>Protect your IP address from the messaging relays chosen by your contacts.
Enable in *Network &amp; servers* settings.</source>
<target>Bescherm uw IP-adres tegen de berichtenrelais die door uw contacten zijn gekozen.
Schakel dit in in *Netwerk en servers*-instellingen.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Protect your chat profiles with a password!" xml:space="preserve">
@@ -4865,6 +4895,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Safely receive files" xml:space="preserve">
<source>Safely receive files</source>
<target>Veilig bestanden ontvangen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Safer groups" xml:space="preserve">
@@ -5094,10 +5125,12 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Send messages directly when IP address is protected and your or destination server does not support private routing." xml:space="preserve">
<source>Send messages directly when IP address is protected and your or destination server does not support private routing.</source>
<target>Stuur berichten rechtstreeks als het IP-adres beschermd is en uw of bestemmingsserver geen privéroutering ondersteunt.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send messages directly when your or destination server does not support private routing." xml:space="preserve">
<source>Send messages directly when your or destination server does not support private routing.</source>
<target>Stuur berichten rechtstreeks wanneer uw of de doelserver geen privéroutering ondersteunt.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send notifications" xml:space="preserve">
@@ -5207,6 +5240,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Server address is incompatible with network settings." xml:space="preserve">
<source>Server address is incompatible with network settings.</source>
<target>Serveradres is niet compatibel met netwerkinstellingen.</target>
<note>srv error text.</note>
</trans-unit>
<trans-unit id="Server requires authorization to create queues, check password" xml:space="preserve">
@@ -5226,6 +5260,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Server version is incompatible with network settings." xml:space="preserve">
<source>Server version is incompatible with network settings.</source>
<target>Serverversie is incompatibel met netwerkinstellingen.</target>
<note>srv error text</note>
</trans-unit>
<trans-unit id="Servers" xml:space="preserve">
@@ -5350,6 +5385,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Show message status" xml:space="preserve">
<source>Show message status</source>
<target>Toon berichtstatus</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show preview" xml:space="preserve">
@@ -5359,6 +5395,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Show → on messages sent via private routing." xml:space="preserve">
<source>Show → on messages sent via private routing.</source>
<target>Toon → bij berichten verzonden via privéroutering.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show:" xml:space="preserve">
@@ -5685,6 +5722,7 @@ Het kan gebeuren vanwege een bug of wanneer de verbinding is aangetast.</target>
</trans-unit>
<trans-unit id="The app will ask to confirm downloads from unknown file servers (except .onion)." xml:space="preserve">
<source>The app will ask to confirm downloads from unknown file servers (except .onion).</source>
<target>De app vraagt om downloads van onbekende bestandsservers (behalve .onion) te bevestigen.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="The attempt to change database passphrase was not completed." xml:space="preserve">
@@ -5874,6 +5912,7 @@ Het kan gebeuren vanwege een bug of wanneer de verbinding is aangetast.</target>
</trans-unit>
<trans-unit id="To protect your IP address, private routing uses your SMP servers to deliver messages." xml:space="preserve">
<source>To protect your IP address, private routing uses your SMP servers to deliver messages.</source>
<target>Om uw IP-adres te beschermen, gebruikt privéroutering uw SMP-servers om berichten te bezorgen.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To protect your information, turn on SimpleX Lock.&#10;You will be prompted to complete authentication before this feature is enabled." xml:space="preserve">
@@ -6015,6 +6054,7 @@ U wordt gevraagd de authenticatie te voltooien voordat deze functie wordt ingesc
</trans-unit>
<trans-unit id="Unknown servers!" xml:space="preserve">
<source>Unknown servers!</source>
<target>Onbekende servers!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unless you use iOS call interface, enable Do Not Disturb mode to avoid interruptions." xml:space="preserve">
@@ -6166,10 +6206,12 @@ Om verbinding te maken, vraagt u uw contact om een andere verbinding link te mak
</trans-unit>
<trans-unit id="Use private routing with unknown servers when IP address is not protected." xml:space="preserve">
<source>Use private routing with unknown servers when IP address is not protected.</source>
<target>Gebruik privéroutering met onbekende servers wanneer het IP-adres niet beveiligd is.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use private routing with unknown servers." xml:space="preserve">
<source>Use private routing with unknown servers.</source>
<target>Gebruik privéroutering met onbekende servers.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use server" xml:space="preserve">
@@ -6409,10 +6451,12 @@ Om verbinding te maken, vraagt u uw contact om een andere verbinding link te mak
</trans-unit>
<trans-unit id="Without Tor or VPN, your IP address will be visible to file servers." xml:space="preserve">
<source>Without Tor or VPN, your IP address will be visible to file servers.</source>
<target>Zonder Tor of VPN is uw IP-adres zichtbaar voor bestandsservers.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Without Tor or VPN, your IP address will be visible to these XFTP relays: %@." xml:space="preserve">
<source>Without Tor or VPN, your IP address will be visible to these XFTP relays: %@.</source>
<target>Zonder Tor of VPN zal uw IP-adres zichtbaar zijn voor deze XFTP-relays: %@.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Wrong database passphrase" xml:space="preserve">
@@ -6422,6 +6466,7 @@ Om verbinding te maken, vraagt u uw contact om een andere verbinding link te mak
</trans-unit>
<trans-unit id="Wrong key or unknown connection - most likely this connection is deleted." xml:space="preserve">
<source>Wrong key or unknown connection - most likely this connection is deleted.</source>
<target>Verkeerde sleutel of onbekende verbinding - hoogstwaarschijnlijk is deze verbinding verwijderd.</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Wrong passphrase!" xml:space="preserve">
@@ -7539,6 +7584,12 @@ SimpleX servers kunnen uw profiel niet zien.</target>
<target>stuur een direct bericht</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="server queue info: %@&#10;&#10;last received msg: %@" xml:space="preserve">
<source>server queue info: %1$@
last received msg: %2$@</source>
<note>queue info</note>
</trans-unit>
<trans-unit id="set new contact address" xml:space="preserve">
<source>set new contact address</source>
<target>nieuw contactadres instellen</target>
@@ -7581,6 +7632,7 @@ SimpleX servers kunnen uw profiel niet zien.</target>
</trans-unit>
<trans-unit id="unknown relays" xml:space="preserve">
<source>unknown relays</source>
<target>onbekende relays</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="unknown status" xml:space="preserve">
@@ -7590,6 +7642,7 @@ SimpleX servers kunnen uw profiel niet zien.</target>
</trans-unit>
<trans-unit id="unprotected" xml:space="preserve">
<source>unprotected</source>
<target>onbeschermd</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="updated group profile" xml:space="preserve">
@@ -7659,6 +7712,7 @@ SimpleX servers kunnen uw profiel niet zien.</target>
</trans-unit>
<trans-unit id="when IP hidden" xml:space="preserve">
<source>when IP hidden</source>
<target>wanneer IP verborgen is</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="yes" xml:space="preserve">
@@ -715,6 +715,7 @@
</trans-unit>
<trans-unit id="Allow downgrade" xml:space="preserve">
<source>Allow downgrade</source>
<target>Zezwól na obniżenie wersji</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">
@@ -814,6 +815,7 @@
</trans-unit>
<trans-unit id="Always use private routing." xml:space="preserve">
<source>Always use private routing.</source>
<target>Zawsze używaj prywatnego trasowania.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Always use relay" xml:space="preserve">
@@ -1098,6 +1100,7 @@
</trans-unit>
<trans-unit id="Capacity exceeded - recipient did not receive previously sent messages." xml:space="preserve">
<source>Capacity exceeded - recipient did not receive previously sent messages.</source>
<target>Przekroczono pojemność - odbiorca nie otrzymał wcześniej wysłanych wiadomości.</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Cellular" xml:space="preserve">
@@ -1298,6 +1301,7 @@
</trans-unit>
<trans-unit id="Confirm files from unknown servers." xml:space="preserve">
<source>Confirm files from unknown servers.</source>
<target>Potwierdzaj pliki z nieznanych serwerów.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirm network settings" xml:space="preserve">
@@ -1717,6 +1721,10 @@ To jest twój jednorazowy link!</target>
<target>Baza danych zostanie zmigrowana po ponownym uruchomieniu aplikacji</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Debug delivery" xml:space="preserve">
<source>Debug delivery</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Decentralized" xml:space="preserve">
<source>Decentralized</source>
<target>Zdecentralizowane</target>
@@ -1966,6 +1974,7 @@ To nie może być cofnięte!</target>
</trans-unit>
<trans-unit id="Destination server error: %@" xml:space="preserve">
<source>Destination server error: %@</source>
<target>Błąd docelowego serwera: %@</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Develop" xml:space="preserve">
@@ -2075,6 +2084,7 @@ To nie może być cofnięte!</target>
</trans-unit>
<trans-unit id="Do NOT send messages directly, even if your or destination server does not support private routing." xml:space="preserve">
<source>Do NOT send messages directly, even if your or destination server does not support private routing.</source>
<target>NIE wysyłaj wiadomości bezpośrednio, nawet jeśli serwer docelowy nie obsługuje prywatnego trasowania.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Do NOT use SimpleX for emergency calls." xml:space="preserve">
@@ -2084,6 +2094,7 @@ To nie może być cofnięte!</target>
</trans-unit>
<trans-unit id="Do NOT use private routing." xml:space="preserve">
<source>Do NOT use private routing.</source>
<target>NIE używaj prywatnego trasowania.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Do it later" xml:space="preserve">
@@ -2743,6 +2754,7 @@ To nie może być cofnięte!</target>
</trans-unit>
<trans-unit id="Files" xml:space="preserve">
<source>Files</source>
<target>Pliki</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files &amp; media" xml:space="preserve">
@@ -2853,11 +2865,15 @@ To nie może być cofnięte!</target>
<trans-unit id="Forwarding server: %@&#10;Destination server error: %@" xml:space="preserve">
<source>Forwarding server: %1$@
Destination server error: %2$@</source>
<target>Serwer przekazujący: %1$@
Błąd serwera docelowego: %2$@</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Forwarding server: %@&#10;Error: %@" xml:space="preserve">
<source>Forwarding server: %1$@
Error: %2$@</source>
<target>Serwer przekazujący: %1$@
Błąd: %2$@</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Found desktop" xml:space="preserve">
@@ -3677,6 +3693,7 @@ To jest twój link do grupy %@!</target>
</trans-unit>
<trans-unit id="Message delivery warning" xml:space="preserve">
<source>Message delivery warning</source>
<target>Ostrzeżenie dostarczenia wiadomości</target>
<note>item status text</note>
</trans-unit>
<trans-unit id="Message draft" xml:space="preserve">
@@ -3684,6 +3701,10 @@ To jest twój link do grupy %@!</target>
<target>Wersja robocza wiadomości</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message queue info" xml:space="preserve">
<source>Message queue info</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message reactions" xml:space="preserve">
<source>Message reactions</source>
<target>Reakcje wiadomości</target>
@@ -3701,10 +3722,12 @@ To jest twój link do grupy %@!</target>
</trans-unit>
<trans-unit id="Message routing fallback" xml:space="preserve">
<source>Message routing fallback</source>
<target>Rezerwowe trasowania wiadomości</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message routing mode" xml:space="preserve">
<source>Message routing mode</source>
<target>Tryb trasowania wiadomości</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message source remains private." xml:space="preserve">
@@ -3869,6 +3892,7 @@ To jest twój link do grupy %@!</target>
</trans-unit>
<trans-unit id="Network issues - message expired after many attempts to send it." xml:space="preserve">
<source>Network issues - message expired after many attempts to send it.</source>
<target>Błąd sieciowy - wiadomość wygasła po wielu próbach wysłania jej.</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Network management" xml:space="preserve">
@@ -4414,10 +4438,12 @@ Błąd: %@</target>
</trans-unit>
<trans-unit id="Private message routing" xml:space="preserve">
<source>Private message routing</source>
<target>Trasowanie prywatnych wiadomości</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private message routing 🚀" xml:space="preserve">
<source>Private message routing 🚀</source>
<target>Trasowanie prywatnych wiadomości🚀</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private notes" xml:space="preserve">
@@ -4427,6 +4453,7 @@ Błąd: %@</target>
</trans-unit>
<trans-unit id="Private routing" xml:space="preserve">
<source>Private routing</source>
<target>Prywatne trasowanie</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile and server connections" xml:space="preserve">
@@ -4511,6 +4538,7 @@ Błąd: %@</target>
</trans-unit>
<trans-unit id="Protect IP address" xml:space="preserve">
<source>Protect IP address</source>
<target>Chroń adres IP</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Protect app screen" xml:space="preserve">
@@ -4521,6 +4549,8 @@ Błąd: %@</target>
<trans-unit id="Protect your IP address from the messaging relays chosen by your contacts.&#10;Enable in *Network &amp; servers* settings." xml:space="preserve">
<source>Protect your IP address from the messaging relays chosen by your contacts.
Enable in *Network &amp; servers* settings.</source>
<target>Chroni Twój adres IP przed przekaźnikami wiadomości wybranych przez Twoje kontakty.
Włącz w ustawianiach *Sieć i serwery* .</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Protect your chat profiles with a password!" xml:space="preserve">
@@ -4865,6 +4895,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Safely receive files" xml:space="preserve">
<source>Safely receive files</source>
<target>Bezpiecznie otrzymuj pliki</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Safer groups" xml:space="preserve">
@@ -5094,10 +5125,12 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Send messages directly when IP address is protected and your or destination server does not support private routing." xml:space="preserve">
<source>Send messages directly when IP address is protected and your or destination server does not support private routing.</source>
<target>Wysyłaj wiadomości bezpośrednio, gdy adres IP jest chroniony i Twój lub docelowy serwer nie obsługuje prywatnego trasowania.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send messages directly when your or destination server does not support private routing." xml:space="preserve">
<source>Send messages directly when your or destination server does not support private routing.</source>
<target>Wysyłaj wiadomości bezpośrednio, gdy Twój lub docelowy serwer nie obsługuje prywatnego trasowania.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send notifications" xml:space="preserve">
@@ -5207,6 +5240,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Server address is incompatible with network settings." xml:space="preserve">
<source>Server address is incompatible with network settings.</source>
<target>Adres serwera jest niekompatybilny z ustawieniami sieciowymi.</target>
<note>srv error text.</note>
</trans-unit>
<trans-unit id="Server requires authorization to create queues, check password" xml:space="preserve">
@@ -5226,6 +5260,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Server version is incompatible with network settings." xml:space="preserve">
<source>Server version is incompatible with network settings.</source>
<target>Wersja serwera jest niekompatybilna z ustawieniami sieciowymi.</target>
<note>srv error text</note>
</trans-unit>
<trans-unit id="Servers" xml:space="preserve">
@@ -5350,6 +5385,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Show message status" xml:space="preserve">
<source>Show message status</source>
<target>Pokaż status wiadomości</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show preview" xml:space="preserve">
@@ -5359,6 +5395,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Show → on messages sent via private routing." xml:space="preserve">
<source>Show → on messages sent via private routing.</source>
<target>Pokaż → na wiadomościach wysłanych przez prywatne trasowanie.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show:" xml:space="preserve">
@@ -5685,6 +5722,7 @@ Może się to zdarzyć z powodu jakiegoś błędu lub gdy połączenie jest skom
</trans-unit>
<trans-unit id="The app will ask to confirm downloads from unknown file servers (except .onion)." xml:space="preserve">
<source>The app will ask to confirm downloads from unknown file servers (except .onion).</source>
<target>Aplikacja zapyta o potwierdzenie pobierania od nieznanych serwerów plików (poza .onion).</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="The attempt to change database passphrase was not completed." xml:space="preserve">
@@ -5874,6 +5912,7 @@ Może się to zdarzyć z powodu jakiegoś błędu lub gdy połączenie jest skom
</trans-unit>
<trans-unit id="To protect your IP address, private routing uses your SMP servers to deliver messages." xml:space="preserve">
<source>To protect your IP address, private routing uses your SMP servers to deliver messages.</source>
<target>Aby chronić Twój adres IP, prywatne trasowanie używa Twoich serwerów SMP, aby dostarczyć wiadomości.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To protect your information, turn on SimpleX Lock.&#10;You will be prompted to complete authentication before this feature is enabled." xml:space="preserve">
@@ -6015,6 +6054,7 @@ Przed włączeniem tej funkcji zostanie wyświetlony monit uwierzytelniania.</ta
</trans-unit>
<trans-unit id="Unknown servers!" xml:space="preserve">
<source>Unknown servers!</source>
<target>Nieznane serwery!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unless you use iOS call interface, enable Do Not Disturb mode to avoid interruptions." xml:space="preserve">
@@ -6166,10 +6206,12 @@ Aby się połączyć, poproś Twój kontakt o utworzenie kolejnego linku połąc
</trans-unit>
<trans-unit id="Use private routing with unknown servers when IP address is not protected." xml:space="preserve">
<source>Use private routing with unknown servers when IP address is not protected.</source>
<target>Używaj prywatnego trasowania z nieznanymi serwerami, gdy adres IP nie jest chroniony.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use private routing with unknown servers." xml:space="preserve">
<source>Use private routing with unknown servers.</source>
<target>Używaj prywatnego trasowania z nieznanymi serwerami.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use server" xml:space="preserve">
@@ -6409,10 +6451,12 @@ Aby się połączyć, poproś Twój kontakt o utworzenie kolejnego linku połąc
</trans-unit>
<trans-unit id="Without Tor or VPN, your IP address will be visible to file servers." xml:space="preserve">
<source>Without Tor or VPN, your IP address will be visible to file servers.</source>
<target>Bez Tor lub VPN, Twój adres IP będzie widoczny do serwerów plików.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Without Tor or VPN, your IP address will be visible to these XFTP relays: %@." xml:space="preserve">
<source>Without Tor or VPN, your IP address will be visible to these XFTP relays: %@.</source>
<target>Bez Tor lub VPN, Twój adres IP będzie widoczny dla tych przekaźników XFTP: %@.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Wrong database passphrase" xml:space="preserve">
@@ -6422,6 +6466,7 @@ Aby się połączyć, poproś Twój kontakt o utworzenie kolejnego linku połąc
</trans-unit>
<trans-unit id="Wrong key or unknown connection - most likely this connection is deleted." xml:space="preserve">
<source>Wrong key or unknown connection - most likely this connection is deleted.</source>
<target>Zły klucz lub nieznane połączenie - najprawdopodobniej to połączenie jest usunięte.</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Wrong passphrase!" xml:space="preserve">
@@ -7539,6 +7584,12 @@ Serwery SimpleX nie mogą zobaczyć Twojego profilu.</target>
<target>wyślij wiadomość bezpośrednią</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="server queue info: %@&#10;&#10;last received msg: %@" xml:space="preserve">
<source>server queue info: %1$@
last received msg: %2$@</source>
<note>queue info</note>
</trans-unit>
<trans-unit id="set new contact address" xml:space="preserve">
<source>set new contact address</source>
<target>ustaw nowy adres kontaktu</target>
@@ -7581,6 +7632,7 @@ Serwery SimpleX nie mogą zobaczyć Twojego profilu.</target>
</trans-unit>
<trans-unit id="unknown relays" xml:space="preserve">
<source>unknown relays</source>
<target>nieznane przekaźniki</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="unknown status" xml:space="preserve">
@@ -7590,6 +7642,7 @@ Serwery SimpleX nie mogą zobaczyć Twojego profilu.</target>
</trans-unit>
<trans-unit id="unprotected" xml:space="preserve">
<source>unprotected</source>
<target>niezabezpieczony</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="updated group profile" xml:space="preserve">
@@ -7659,6 +7712,7 @@ Serwery SimpleX nie mogą zobaczyć Twojego profilu.</target>
</trans-unit>
<trans-unit id="when IP hidden" xml:space="preserve">
<source>when IP hidden</source>
<target>gdy IP ukryty</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="yes" xml:space="preserve">
@@ -715,6 +715,7 @@
</trans-unit>
<trans-unit id="Allow downgrade" xml:space="preserve">
<source>Allow downgrade</source>
<target>Разрешить прямую доставку</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">
@@ -814,6 +815,7 @@
</trans-unit>
<trans-unit id="Always use private routing." xml:space="preserve">
<source>Always use private routing.</source>
<target>Всегда использовать конфиденциальную доставку.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Always use relay" xml:space="preserve">
@@ -1098,6 +1100,7 @@
</trans-unit>
<trans-unit id="Capacity exceeded - recipient did not receive previously sent messages." xml:space="preserve">
<source>Capacity exceeded - recipient did not receive previously sent messages.</source>
<target>Превышено количество сообщений - предыдущие сообщения не доставлены.</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Cellular" xml:space="preserve">
@@ -1298,6 +1301,7 @@
</trans-unit>
<trans-unit id="Confirm files from unknown servers." xml:space="preserve">
<source>Confirm files from unknown servers.</source>
<target>Подтверждать файлы с неизвестных серверов.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirm network settings" xml:space="preserve">
@@ -1717,6 +1721,10 @@ This is your own one-time link!</source>
<target>Данные чата будут мигрированы при перезапуске</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Debug delivery" xml:space="preserve">
<source>Debug delivery</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Decentralized" xml:space="preserve">
<source>Decentralized</source>
<target>Децентрализованный</target>
@@ -1966,6 +1974,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Destination server error: %@" xml:space="preserve">
<source>Destination server error: %@</source>
<target>Ошибка сервера получателя: %@</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Develop" xml:space="preserve">
@@ -2075,6 +2084,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Do NOT send messages directly, even if your or destination server does not support private routing." xml:space="preserve">
<source>Do NOT send messages directly, even if your or destination server does not support private routing.</source>
<target>Не отправлять сообщения напрямую, даже если сервер получателя не поддерживает конфиденциальную доставку.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Do NOT use SimpleX for emergency calls." xml:space="preserve">
@@ -2084,6 +2094,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Do NOT use private routing." xml:space="preserve">
<source>Do NOT use private routing.</source>
<target>Не использовать конфиденциальную доставку.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Do it later" xml:space="preserve">
@@ -2743,6 +2754,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Files" xml:space="preserve">
<source>Files</source>
<target>Файлы</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files &amp; media" xml:space="preserve">
@@ -2853,11 +2865,15 @@ This cannot be undone!</source>
<trans-unit id="Forwarding server: %@&#10;Destination server error: %@" xml:space="preserve">
<source>Forwarding server: %1$@
Destination server error: %2$@</source>
<target>Пересылающий сервер: %1$@
Ошибка сервера получателя: %2$@</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Forwarding server: %@&#10;Error: %@" xml:space="preserve">
<source>Forwarding server: %1$@
Error: %2$@</source>
<target>Пересылающий сервер: %1$@
Ошибка: %2$@</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Found desktop" xml:space="preserve">
@@ -3677,6 +3693,7 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Message delivery warning" xml:space="preserve">
<source>Message delivery warning</source>
<target>Предупреждение доставки сообщения</target>
<note>item status text</note>
</trans-unit>
<trans-unit id="Message draft" xml:space="preserve">
@@ -3684,6 +3701,10 @@ This is your link for group %@!</source>
<target>Черновик сообщения</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message queue info" xml:space="preserve">
<source>Message queue info</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message reactions" xml:space="preserve">
<source>Message reactions</source>
<target>Реакции на сообщения</target>
@@ -3701,10 +3722,12 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Message routing fallback" xml:space="preserve">
<source>Message routing fallback</source>
<target>Прямая доставка сообщений</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message routing mode" xml:space="preserve">
<source>Message routing mode</source>
<target>Режим доставки сообщений</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message source remains private." xml:space="preserve">
@@ -3869,6 +3892,7 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Network issues - message expired after many attempts to send it." xml:space="preserve">
<source>Network issues - message expired after many attempts to send it.</source>
<target>Ошибка сети - сообщение не было отправлено после многократных попыток.</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Network management" xml:space="preserve">
@@ -4414,10 +4438,12 @@ Error: %@</source>
</trans-unit>
<trans-unit id="Private message routing" xml:space="preserve">
<source>Private message routing</source>
<target>Конфиденциальная доставка сообщений</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private message routing 🚀" xml:space="preserve">
<source>Private message routing 🚀</source>
<target>Конфиденциальная доставка сообщений 🚀</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private notes" xml:space="preserve">
@@ -4427,6 +4453,7 @@ Error: %@</source>
</trans-unit>
<trans-unit id="Private routing" xml:space="preserve">
<source>Private routing</source>
<target>Конфиденциальная доставка</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile and server connections" xml:space="preserve">
@@ -4511,6 +4538,7 @@ Error: %@</source>
</trans-unit>
<trans-unit id="Protect IP address" xml:space="preserve">
<source>Protect IP address</source>
<target>Защитить IP адрес</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Protect app screen" xml:space="preserve">
@@ -4521,6 +4549,8 @@ Error: %@</source>
<trans-unit id="Protect your IP address from the messaging relays chosen by your contacts.&#10;Enable in *Network &amp; servers* settings." xml:space="preserve">
<source>Protect your IP address from the messaging relays chosen by your contacts.
Enable in *Network &amp; servers* settings.</source>
<target>Защитите ваш IP адрес от серверов сообщений, выбранных Вашими контактами.
Включите в настройках *Сеть и серверы*.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Protect your chat profiles with a password!" xml:space="preserve">
@@ -4865,6 +4895,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Safely receive files" xml:space="preserve">
<source>Safely receive files</source>
<target>Получайте файлы безопасно</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Safer groups" xml:space="preserve">
@@ -5094,10 +5125,12 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Send messages directly when IP address is protected and your or destination server does not support private routing." xml:space="preserve">
<source>Send messages directly when IP address is protected and your or destination server does not support private routing.</source>
<target>Отправлять сообщения напрямую, когда IP адрес защищен, и Ваш сервер или сервер получателя не поддерживает конфиденциальную доставку.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send messages directly when your or destination server does not support private routing." xml:space="preserve">
<source>Send messages directly when your or destination server does not support private routing.</source>
<target>Отправлять сообщения напрямую, когда Ваш сервер или сервер получателя не поддерживает конфиденциальную доставку.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send notifications" xml:space="preserve">
@@ -5207,6 +5240,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Server address is incompatible with network settings." xml:space="preserve">
<source>Server address is incompatible with network settings.</source>
<target>Адрес сервера несовместим с настройками сети.</target>
<note>srv error text.</note>
</trans-unit>
<trans-unit id="Server requires authorization to create queues, check password" xml:space="preserve">
@@ -5226,6 +5260,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Server version is incompatible with network settings." xml:space="preserve">
<source>Server version is incompatible with network settings.</source>
<target>Версия сервера несовместима с настройками сети.</target>
<note>srv error text</note>
</trans-unit>
<trans-unit id="Servers" xml:space="preserve">
@@ -5350,6 +5385,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Show message status" xml:space="preserve">
<source>Show message status</source>
<target>Показать статус сообщения</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show preview" xml:space="preserve">
@@ -5359,6 +5395,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Show → on messages sent via private routing." xml:space="preserve">
<source>Show → on messages sent via private routing.</source>
<target>Показать → на сообщениях доставленных конфиденциально.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show:" xml:space="preserve">
@@ -5685,6 +5722,7 @@ It can happen because of some bug or when the connection is compromised.</source
</trans-unit>
<trans-unit id="The app will ask to confirm downloads from unknown file servers (except .onion)." xml:space="preserve">
<source>The app will ask to confirm downloads from unknown file servers (except .onion).</source>
<target>Приложение будет запрашивать подтверждение загрузки с неизвестных серверов (за исключением .onion адресов).</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="The attempt to change database passphrase was not completed." xml:space="preserve">
@@ -5874,6 +5912,7 @@ It can happen because of some bug or when the connection is compromised.</source
</trans-unit>
<trans-unit id="To protect your IP address, private routing uses your SMP servers to deliver messages." xml:space="preserve">
<source>To protect your IP address, private routing uses your SMP servers to deliver messages.</source>
<target>Чтобы защитить ваш IP адрес, приложение использует Ваши SMP серверы для конфиденциальной доставки сообщений.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To protect your information, turn on SimpleX Lock.&#10;You will be prompted to complete authentication before this feature is enabled." xml:space="preserve">
@@ -6015,6 +6054,7 @@ You will be prompted to complete authentication before this feature is enabled.<
</trans-unit>
<trans-unit id="Unknown servers!" xml:space="preserve">
<source>Unknown servers!</source>
<target>Неизвестные серверы!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unless you use iOS call interface, enable Do Not Disturb mode to avoid interruptions." xml:space="preserve">
@@ -6166,10 +6206,12 @@ To connect, please ask your contact to create another connection link and check
</trans-unit>
<trans-unit id="Use private routing with unknown servers when IP address is not protected." xml:space="preserve">
<source>Use private routing with unknown servers when IP address is not protected.</source>
<target>Использовать конфиденциальную доставку с неизвестными серверами, когда IP адрес не защищен.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use private routing with unknown servers." xml:space="preserve">
<source>Use private routing with unknown servers.</source>
<target>Использовать конфиденциальную доставку с неизвестными серверами.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use server" xml:space="preserve">
@@ -6409,10 +6451,12 @@ To connect, please ask your contact to create another connection link and check
</trans-unit>
<trans-unit id="Without Tor or VPN, your IP address will be visible to file servers." xml:space="preserve">
<source>Without Tor or VPN, your IP address will be visible to file servers.</source>
<target>Без Тора или ВПН, Ваш IP адрес будет доступен серверам файлов.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Without Tor or VPN, your IP address will be visible to these XFTP relays: %@." xml:space="preserve">
<source>Without Tor or VPN, your IP address will be visible to these XFTP relays: %@.</source>
<target>Без Тора или ВПН, Ваш IP адрес будет доступен этим серверам файлов: %@.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Wrong database passphrase" xml:space="preserve">
@@ -6422,6 +6466,7 @@ To connect, please ask your contact to create another connection link and check
</trans-unit>
<trans-unit id="Wrong key or unknown connection - most likely this connection is deleted." xml:space="preserve">
<source>Wrong key or unknown connection - most likely this connection is deleted.</source>
<target>Неверный ключ или неизвестное соединение - скорее всего, это соединение удалено.</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Wrong passphrase!" xml:space="preserve">
@@ -7539,6 +7584,12 @@ SimpleX серверы не могут получить доступ к Ваше
<target>отправьте сообщение</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="server queue info: %@&#10;&#10;last received msg: %@" xml:space="preserve">
<source>server queue info: %1$@
last received msg: %2$@</source>
<note>queue info</note>
</trans-unit>
<trans-unit id="set new contact address" xml:space="preserve">
<source>set new contact address</source>
<target>установлен новый адрес контакта</target>
@@ -7581,6 +7632,7 @@ SimpleX серверы не могут получить доступ к Ваше
</trans-unit>
<trans-unit id="unknown relays" xml:space="preserve">
<source>unknown relays</source>
<target>неизвестные серверы</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="unknown status" xml:space="preserve">
@@ -7590,6 +7642,7 @@ SimpleX серверы не могут получить доступ к Ваше
</trans-unit>
<trans-unit id="unprotected" xml:space="preserve">
<source>unprotected</source>
<target>незащищённый</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="updated group profile" xml:space="preserve">
@@ -7659,6 +7712,7 @@ SimpleX серверы не могут получить доступ к Ваше
</trans-unit>
<trans-unit id="when IP hidden" xml:space="preserve">
<source>when IP hidden</source>
<target>когда IP защищен</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="yes" xml:space="preserve">
@@ -1629,6 +1629,10 @@ This is your own one-time link!</source>
<target>ระบบจะย้ายฐานข้อมูลเมื่อแอปรีสตาร์ท</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Debug delivery" xml:space="preserve">
<source>Debug delivery</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Decentralized" xml:space="preserve">
<source>Decentralized</source>
<target>กระจายอำนาจแล้ว</target>
@@ -3514,6 +3518,10 @@ This is your link for group %@!</source>
<target>ร่างข้อความ</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message queue info" xml:space="preserve">
<source>Message queue info</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message reactions" xml:space="preserve">
<source>Message reactions</source>
<target>ปฏิกิริยาของข้อความ</target>
@@ -7199,6 +7207,12 @@ SimpleX servers cannot see your profile.</source>
<source>send direct message</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="server queue info: %@&#10;&#10;last received msg: %@" xml:space="preserve">
<source>server queue info: %1$@
last received msg: %2$@</source>
<note>queue info</note>
</trans-unit>
<trans-unit id="set new contact address" xml:space="preserve">
<source>set new contact address</source>
<note>profile update event chat item</note>
@@ -445,7 +445,7 @@
</trans-unit>
<trans-unit id="0s" xml:space="preserve">
<source>0s</source>
<target>0 saniye</target>
<target>0sn</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="1 day" xml:space="preserve">
@@ -695,7 +695,7 @@
</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>
<target>Tüm kişileriniz, sohbetleriniz ve dosyalarınız güvenli bir şekilde şifrelenecek ve parçalar halinde yapılandırılmış XFTP rölelerine yüklenecektir.</target>
<target>Tüm kişileriniz, konuşmalarınız ve dosyalarınız güvenli bir şekilde şifrelenir ve yapılandırılmış XFTP yönlendiricilerine parçalar halinde yüklenir.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow" xml:space="preserve">
@@ -715,6 +715,7 @@
</trans-unit>
<trans-unit id="Allow downgrade" xml:space="preserve">
<source>Allow downgrade</source>
<target>Sürüm düşürmeye izin ver</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">
@@ -734,7 +735,7 @@
</trans-unit>
<trans-unit id="Allow sending direct messages to members." xml:space="preserve">
<source>Allow sending direct messages to members.</source>
<target>Üyelere direkt mesaj göndermeye izin ver.</target>
<target>Üyelere doğrudan mesaj göndermeye izin ver.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow sending disappearing messages." xml:space="preserve">
@@ -814,6 +815,7 @@
</trans-unit>
<trans-unit id="Always use private routing." xml:space="preserve">
<source>Always use private routing.</source>
<target>Her zaman gizli yönlendirme kullan.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Always use relay" xml:space="preserve">
@@ -1098,6 +1100,7 @@
</trans-unit>
<trans-unit id="Capacity exceeded - recipient did not receive previously sent messages." xml:space="preserve">
<source>Capacity exceeded - recipient did not receive previously sent messages.</source>
<target>Kapasite aşıldı - alıcı önceden gönderilen mesajları almadı.</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Cellular" xml:space="preserve">
@@ -1298,6 +1301,7 @@
</trans-unit>
<trans-unit id="Confirm files from unknown servers." xml:space="preserve">
<source>Confirm files from unknown servers.</source>
<target>Bilinmeyen sunuculardan gelen dosyaları onayla.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirm network settings" xml:space="preserve">
@@ -1717,6 +1721,10 @@ Bu senin kendi tek kullanımlık bağlantın!</target>
<target>Uygulama yeniden başlatıldığında veritabanı taşınacaktır</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Debug delivery" xml:space="preserve">
<source>Debug delivery</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Decentralized" xml:space="preserve">
<source>Decentralized</source>
<target>Merkezi Olmayan</target>
@@ -1966,6 +1974,7 @@ Bu geri alınamaz!</target>
</trans-unit>
<trans-unit id="Destination server error: %@" xml:space="preserve">
<source>Destination server error: %@</source>
<target>Hedef sunucu hatası: %@</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Develop" xml:space="preserve">
@@ -2075,6 +2084,7 @@ Bu geri alınamaz!</target>
</trans-unit>
<trans-unit id="Do NOT send messages directly, even if your or destination server does not support private routing." xml:space="preserve">
<source>Do NOT send messages directly, even if your or destination server does not support private routing.</source>
<target>Sizin veya hedef sunucunun özel yönlendirmeyi desteklememesi durumunda bile mesajları doğrudan GÖNDERMEYİN.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Do NOT use SimpleX for emergency calls." xml:space="preserve">
@@ -2084,6 +2094,7 @@ Bu geri alınamaz!</target>
</trans-unit>
<trans-unit id="Do NOT use private routing." xml:space="preserve">
<source>Do NOT use private routing.</source>
<target>Gizli yönlendirmeyi KULLANMA.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Do it later" xml:space="preserve">
@@ -2743,6 +2754,7 @@ Bu geri alınamaz!</target>
</trans-unit>
<trans-unit id="Files" xml:space="preserve">
<source>Files</source>
<target>Dosyalar</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files &amp; media" xml:space="preserve">
@@ -2853,11 +2865,15 @@ Bu geri alınamaz!</target>
<trans-unit id="Forwarding server: %@&#10;Destination server error: %@" xml:space="preserve">
<source>Forwarding server: %1$@
Destination server error: %2$@</source>
<target>Yönlendirme sunucusu: %1$@
Hedef sunucu hatası: %2$@</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Forwarding server: %@&#10;Error: %@" xml:space="preserve">
<source>Forwarding server: %1$@
Error: %2$@</source>
<target>Yönlendirme sunucusu: %1$@
Hata: %2$@</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Found desktop" xml:space="preserve">
@@ -3677,6 +3693,7 @@ Bu senin grup için bağlantın %@!</target>
</trans-unit>
<trans-unit id="Message delivery warning" xml:space="preserve">
<source>Message delivery warning</source>
<target>Mesaj iletimi uyarısı</target>
<note>item status text</note>
</trans-unit>
<trans-unit id="Message draft" xml:space="preserve">
@@ -3684,6 +3701,10 @@ Bu senin grup için bağlantın %@!</target>
<target>Mesaj taslağı</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message queue info" xml:space="preserve">
<source>Message queue info</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message reactions" xml:space="preserve">
<source>Message reactions</source>
<target>Mesaj tepkileri</target>
@@ -3701,10 +3722,12 @@ Bu senin grup için bağlantın %@!</target>
</trans-unit>
<trans-unit id="Message routing fallback" xml:space="preserve">
<source>Message routing fallback</source>
<target>Mesaj yönlendirme yedeklemesi</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message routing mode" xml:space="preserve">
<source>Message routing mode</source>
<target>Mesaj yönlendirme modu</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message source remains private." xml:space="preserve">
@@ -3869,6 +3892,7 @@ Bu senin grup için bağlantın %@!</target>
</trans-unit>
<trans-unit id="Network issues - message expired after many attempts to send it." xml:space="preserve">
<source>Network issues - message expired after many attempts to send it.</source>
<target>Ağ sorunları - birçok gönderme denemesinden sonra mesajın süresi doldu.</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Network management" xml:space="preserve">
@@ -4414,10 +4438,12 @@ Hata: %@</target>
</trans-unit>
<trans-unit id="Private message routing" xml:space="preserve">
<source>Private message routing</source>
<target>Gizli mesaj yönlendirme</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private message routing 🚀" xml:space="preserve">
<source>Private message routing 🚀</source>
<target>Gizli mesaj yönlendirme 🚀</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private notes" xml:space="preserve">
@@ -4427,6 +4453,7 @@ Hata: %@</target>
</trans-unit>
<trans-unit id="Private routing" xml:space="preserve">
<source>Private routing</source>
<target>Gizli yönlendirme</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile and server connections" xml:space="preserve">
@@ -4491,7 +4518,7 @@ Hata: %@</target>
</trans-unit>
<trans-unit id="Prohibit sending direct messages to members." xml:space="preserve">
<source>Prohibit sending direct messages to members.</source>
<target>Geri dönülmez mesaj silme işlemini yasakla.</target>
<target>Üyelere doğrudan mesaj göndermeyi yasakla.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending disappearing messages." xml:space="preserve">
@@ -4511,6 +4538,7 @@ Hata: %@</target>
</trans-unit>
<trans-unit id="Protect IP address" xml:space="preserve">
<source>Protect IP address</source>
<target>IP adresini koru</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Protect app screen" xml:space="preserve">
@@ -4521,6 +4549,8 @@ Hata: %@</target>
<trans-unit id="Protect your IP address from the messaging relays chosen by your contacts.&#10;Enable in *Network &amp; servers* settings." xml:space="preserve">
<source>Protect your IP address from the messaging relays chosen by your contacts.
Enable in *Network &amp; servers* settings.</source>
<target>IP adresinizi kişileriniz tarafından seçilen mesajlaşma yönlendiricilerinden koruyun.
*Ağ ve sunucular* ayarlarında etkinleştirin.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Protect your chat profiles with a password!" xml:space="preserve">
@@ -4695,12 +4725,12 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Relay server is only used if necessary. Another party can observe your IP address." xml:space="preserve">
<source>Relay server is only used if necessary. Another party can observe your IP address.</source>
<target>Aktarma sunucusu yalnızca gerekli olduğunda kullanılır. Başka bir taraf IP adresinizi gözlemleyebilir.</target>
<target>Yönlendirici sunucusu yalnızca gerekli olduğunda kullanılır. Başka bir taraf IP adresinizi gözlemleyebilir.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Relay server protects your IP address, but it can observe the duration of the call." xml:space="preserve">
<source>Relay server protects your IP address, but it can observe the duration of the call.</source>
<target>Aktarıcı sunucu IP adresinizi korur, ancak aramanın süresini gözlemleyebilir.</target>
<target>Yönlendirici sunucu IP adresinizi korur, ancak aramanın süresini gözlemleyebilir.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Remove" xml:space="preserve">
@@ -4865,6 +4895,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Safely receive files" xml:space="preserve">
<source>Safely receive files</source>
<target>Dosyaları güvenle alın</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Safer groups" xml:space="preserve">
@@ -5094,10 +5125,12 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Send messages directly when IP address is protected and your or destination server does not support private routing." xml:space="preserve">
<source>Send messages directly when IP address is protected and your or destination server does not support private routing.</source>
<target>IP adresi korumalı olduğunda ve sizin veya hedef sunucunun özel yönlendirmeyi desteklemediği durumlarda mesajları doğrudan gönderin.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send messages directly when your or destination server does not support private routing." xml:space="preserve">
<source>Send messages directly when your or destination server does not support private routing.</source>
<target>Sizin veya hedef sunucunun özel yönlendirmeyi desteklemediği durumlarda mesajları doğrudan gönderin.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send notifications" xml:space="preserve">
@@ -5207,6 +5240,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Server address is incompatible with network settings." xml:space="preserve">
<source>Server address is incompatible with network settings.</source>
<target>Sunucu adresi ağ ayarlarıyla uyumlu değil.</target>
<note>srv error text.</note>
</trans-unit>
<trans-unit id="Server requires authorization to create queues, check password" xml:space="preserve">
@@ -5226,6 +5260,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Server version is incompatible with network settings." xml:space="preserve">
<source>Server version is incompatible with network settings.</source>
<target>Sunucu sürümü ağ ayarlarıyla uyumlu değil.</target>
<note>srv error text</note>
</trans-unit>
<trans-unit id="Servers" xml:space="preserve">
@@ -5350,6 +5385,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Show message status" xml:space="preserve">
<source>Show message status</source>
<target>Mesaj durumunu göster</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show preview" xml:space="preserve">
@@ -5359,6 +5395,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Show → on messages sent via private routing." xml:space="preserve">
<source>Show → on messages sent via private routing.</source>
<target>Gizli yönlendirme yoluyla gönderilen mesajlarda → işaretini göster.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show:" xml:space="preserve">
@@ -5685,6 +5722,7 @@ Bazı hatalar nedeniyle veya bağlantı tehlikeye girdiğinde meydana gelebilir.
</trans-unit>
<trans-unit id="The app will ask to confirm downloads from unknown file servers (except .onion)." xml:space="preserve">
<source>The app will ask to confirm downloads from unknown file servers (except .onion).</source>
<target>Uygulama bilinmeyen dosya sunucularından indirmeleri onaylamanızı isteyecektir (.onion hariç).</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="The attempt to change database passphrase was not completed." xml:space="preserve">
@@ -5874,6 +5912,7 @@ Bazı hatalar nedeniyle veya bağlantı tehlikeye girdiğinde meydana gelebilir.
</trans-unit>
<trans-unit id="To protect your IP address, private routing uses your SMP servers to deliver messages." xml:space="preserve">
<source>To protect your IP address, private routing uses your SMP servers to deliver messages.</source>
<target>IP adresinizi korumak için,gizli yönlendirme mesajları iletmek için SMP sunucularınızı kullanır.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To protect your information, turn on SimpleX Lock.&#10;You will be prompted to complete authentication before this feature is enabled." xml:space="preserve">
@@ -6015,6 +6054,7 @@ Bu özellik etkinleştirilmeden önce kimlik doğrulamayı tamamlamanız istenec
</trans-unit>
<trans-unit id="Unknown servers!" xml:space="preserve">
<source>Unknown servers!</source>
<target>Bilinmeyen sunucular!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unless you use iOS call interface, enable Do Not Disturb mode to avoid interruptions." xml:space="preserve">
@@ -6166,10 +6206,12 @@ Bağlanmak için lütfen kişinizden başka bir bağlantı oluşturmasını iste
</trans-unit>
<trans-unit id="Use private routing with unknown servers when IP address is not protected." xml:space="preserve">
<source>Use private routing with unknown servers when IP address is not protected.</source>
<target>IP adresi korunmadığında bilinmeyen sunucularla gizli yönlendirme kullan.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use private routing with unknown servers." xml:space="preserve">
<source>Use private routing with unknown servers.</source>
<target>Bilinmeyen sunucularla gizli yönlendirme kullan.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use server" xml:space="preserve">
@@ -6409,10 +6451,12 @@ Bağlanmak için lütfen kişinizden başka bir bağlantı oluşturmasını iste
</trans-unit>
<trans-unit id="Without Tor or VPN, your IP address will be visible to file servers." xml:space="preserve">
<source>Without Tor or VPN, your IP address will be visible to file servers.</source>
<target>Tor veya VPN olmadan, IP adresiniz dosya sunucularına görülebilir.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Without Tor or VPN, your IP address will be visible to these XFTP relays: %@." xml:space="preserve">
<source>Without Tor or VPN, your IP address will be visible to these XFTP relays: %@.</source>
<target>Tor veya VPN olmadan, IP adresiniz bu XFTP aktarıcıları tarafından görülebilir: %@.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Wrong database passphrase" xml:space="preserve">
@@ -6422,6 +6466,7 @@ Bağlanmak için lütfen kişinizden başka bir bağlantı oluşturmasını iste
</trans-unit>
<trans-unit id="Wrong key or unknown connection - most likely this connection is deleted." xml:space="preserve">
<source>Wrong key or unknown connection - most likely this connection is deleted.</source>
<target>Yanlış anahtar veya bilinmeyen bağlantı - büyük olasılıkla bu bağlantı silinmiştir.</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Wrong passphrase!" xml:space="preserve">
@@ -7539,6 +7584,12 @@ SimpleX sunucuları profilinizi göremez.</target>
<target>doğrudan mesaj gönder</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="server queue info: %@&#10;&#10;last received msg: %@" xml:space="preserve">
<source>server queue info: %1$@
last received msg: %2$@</source>
<note>queue info</note>
</trans-unit>
<trans-unit id="set new contact address" xml:space="preserve">
<source>set new contact address</source>
<target>yeni kişi adresi ayarla</target>
@@ -7581,6 +7632,7 @@ SimpleX sunucuları profilinizi göremez.</target>
</trans-unit>
<trans-unit id="unknown relays" xml:space="preserve">
<source>unknown relays</source>
<target>bilinmeyen yönlendiriciler</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="unknown status" xml:space="preserve">
@@ -7590,6 +7642,7 @@ SimpleX sunucuları profilinizi göremez.</target>
</trans-unit>
<trans-unit id="unprotected" xml:space="preserve">
<source>unprotected</source>
<target>korumasız</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="updated group profile" xml:space="preserve">
@@ -7659,6 +7712,7 @@ SimpleX sunucuları profilinizi göremez.</target>
</trans-unit>
<trans-unit id="when IP hidden" xml:space="preserve">
<source>when IP hidden</source>
<target>IP gizliyken</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="yes" xml:space="preserve">
@@ -715,6 +715,7 @@
</trans-unit>
<trans-unit id="Allow downgrade" xml:space="preserve">
<source>Allow downgrade</source>
<target>Дозволити пониження версії</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">
@@ -749,6 +750,7 @@
</trans-unit>
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
<source>Allow to send SimpleX links.</source>
<target>Дозволити надсилати посилання SimpleX.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send files and media." xml:space="preserve">
@@ -813,6 +815,7 @@
</trans-unit>
<trans-unit id="Always use private routing." xml:space="preserve">
<source>Always use private routing.</source>
<target>Завжди використовуйте приватну маршрутизацію.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Always use relay" xml:space="preserve">
@@ -1097,10 +1100,12 @@
</trans-unit>
<trans-unit id="Capacity exceeded - recipient did not receive previously sent messages." xml:space="preserve">
<source>Capacity exceeded - recipient did not receive previously sent messages.</source>
<target>Перевищено ліміт - одержувач не отримав раніше надіслані повідомлення.</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Cellular" xml:space="preserve">
<source>Cellular</source>
<target>Стільниковий</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Change" xml:space="preserve">
@@ -1296,6 +1301,7 @@
</trans-unit>
<trans-unit id="Confirm files from unknown servers." xml:space="preserve">
<source>Confirm files from unknown servers.</source>
<target>Підтвердити файли з невідомих серверів.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Confirm network settings" xml:space="preserve">
@@ -1715,6 +1721,10 @@ This is your own one-time link!</source>
<target>База даних буде перенесена під час перезапуску програми</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Debug delivery" xml:space="preserve">
<source>Debug delivery</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Decentralized" xml:space="preserve">
<source>Decentralized</source>
<target>Децентралізований</target>
@@ -1964,6 +1974,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Destination server error: %@" xml:space="preserve">
<source>Destination server error: %@</source>
<target>Помилка сервера призначення: %@</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Develop" xml:space="preserve">
@@ -2073,6 +2084,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Do NOT send messages directly, even if your or destination server does not support private routing." xml:space="preserve">
<source>Do NOT send messages directly, even if your or destination server does not support private routing.</source>
<target>НЕ надсилайте повідомлення напряму, навіть якщо ваш сервер або сервер призначення не підтримує приватну маршрутизацію.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Do NOT use SimpleX for emergency calls." xml:space="preserve">
@@ -2082,6 +2094,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Do NOT use private routing." xml:space="preserve">
<source>Do NOT use private routing.</source>
<target>НЕ використовуйте приватну маршрутизацію.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Do it later" xml:space="preserve">
@@ -2116,6 +2129,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Download" xml:space="preserve">
<source>Download</source>
<target>Завантажити</target>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Download failed" xml:space="preserve">
@@ -2230,6 +2244,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Enabled for" xml:space="preserve">
<source>Enabled for</source>
<target>Увімкнено для</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Encrypt" xml:space="preserve">
@@ -2739,6 +2754,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Files" xml:space="preserve">
<source>Files</source>
<target>Файли</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files &amp; media" xml:space="preserve">
@@ -2758,6 +2774,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Files and media not allowed" xml:space="preserve">
<source>Files and media not allowed</source>
<target>Файли та медіафайли заборонені</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media prohibited!" xml:space="preserve">
@@ -2827,28 +2844,36 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Forward" xml:space="preserve">
<source>Forward</source>
<target>Пересилання</target>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Forward and save messages" xml:space="preserve">
<source>Forward and save messages</source>
<target>Пересилання та збереження повідомлень</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded" xml:space="preserve">
<source>Forwarded</source>
<target>Переслано</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarded from" xml:space="preserve">
<source>Forwarded from</source>
<target>Переслано з</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Forwarding server: %@&#10;Destination server error: %@" xml:space="preserve">
<source>Forwarding server: %1$@
Destination server error: %2$@</source>
<target>Сервер переадресації: %1$@
Помилка сервера призначення: %2$@</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Forwarding server: %@&#10;Error: %@" xml:space="preserve">
<source>Forwarding server: %1$@
Error: %2$@</source>
<target>Сервер переадресації: %1$@
Помилка: %2$@</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Found desktop" xml:space="preserve">
@@ -2963,6 +2988,7 @@ Error: %2$@</source>
</trans-unit>
<trans-unit id="Group members can send SimpleX links." xml:space="preserve">
<source>Group members can send SimpleX links.</source>
<target>Учасники групи можуть надсилати посилання SimpleX.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send direct messages." xml:space="preserve">
@@ -3207,6 +3233,7 @@ Error: %2$@</source>
</trans-unit>
<trans-unit id="In-call sounds" xml:space="preserve">
<source>In-call sounds</source>
<target>Звуки вхідного дзвінка</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Incognito" xml:space="preserve">
@@ -3666,6 +3693,7 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Message delivery warning" xml:space="preserve">
<source>Message delivery warning</source>
<target>Попередження про доставку повідомлення</target>
<note>item status text</note>
</trans-unit>
<trans-unit id="Message draft" xml:space="preserve">
@@ -3673,6 +3701,10 @@ This is your link for group %@!</source>
<target>Чернетка повідомлення</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message queue info" xml:space="preserve">
<source>Message queue info</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message reactions" xml:space="preserve">
<source>Message reactions</source>
<target>Реакції на повідомлення</target>
@@ -3690,14 +3722,17 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Message routing fallback" xml:space="preserve">
<source>Message routing fallback</source>
<target>Запасний варіант маршрутизації повідомлень</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message routing mode" xml:space="preserve">
<source>Message routing mode</source>
<target>Режим маршрутизації повідомлень</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message source remains private." xml:space="preserve">
<source>Message source remains private.</source>
<target>Джерело повідомлення залишається приватним.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message text" xml:space="preserve">
@@ -3817,6 +3852,7 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="More reliable network connection." xml:space="preserve">
<source>More reliable network connection.</source>
<target>Більш надійне з'єднання з мережею.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Most likely this connection is deleted." xml:space="preserve">
@@ -3851,14 +3887,17 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Network connection" xml:space="preserve">
<source>Network connection</source>
<target>Підключення до мережі</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Network issues - message expired after many attempts to send it." xml:space="preserve">
<source>Network issues - message expired after many attempts to send it.</source>
<target>Проблеми з мережею - термін дії повідомлення закінчився після багатьох спроб надіслати його.</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Network management" xml:space="preserve">
<source>Network management</source>
<target>Керування мережею</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Network settings" xml:space="preserve">
@@ -3973,6 +4012,7 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="No network connection" xml:space="preserve">
<source>No network connection</source>
<target>Немає підключення до мережі</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No permission to record voice message" xml:space="preserve">
@@ -4191,6 +4231,7 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Other" xml:space="preserve">
<source>Other</source>
<target>Інше</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="PING count" xml:space="preserve">
@@ -4397,10 +4438,12 @@ Error: %@</source>
</trans-unit>
<trans-unit id="Private message routing" xml:space="preserve">
<source>Private message routing</source>
<target>Маршрутизація приватних повідомлень</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private message routing 🚀" xml:space="preserve">
<source>Private message routing 🚀</source>
<target>Маршрутизація приватних повідомлень 🚀</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Private notes" xml:space="preserve">
@@ -4410,6 +4453,7 @@ Error: %@</source>
</trans-unit>
<trans-unit id="Private routing" xml:space="preserve">
<source>Private routing</source>
<target>Приватна маршрутизація</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile and server connections" xml:space="preserve">
@@ -4424,6 +4468,7 @@ Error: %@</source>
</trans-unit>
<trans-unit id="Profile images" xml:space="preserve">
<source>Profile images</source>
<target>Зображення профілю</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile name" xml:space="preserve">
@@ -4468,6 +4513,7 @@ Error: %@</source>
</trans-unit>
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
<source>Prohibit sending SimpleX links.</source>
<target>Заборонити надсилання посилань SimpleX.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending direct messages to members." xml:space="preserve">
@@ -4492,6 +4538,7 @@ Error: %@</source>
</trans-unit>
<trans-unit id="Protect IP address" xml:space="preserve">
<source>Protect IP address</source>
<target>Захист IP-адреси</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Protect app screen" xml:space="preserve">
@@ -4502,6 +4549,8 @@ Error: %@</source>
<trans-unit id="Protect your IP address from the messaging relays chosen by your contacts.&#10;Enable in *Network &amp; servers* settings." xml:space="preserve">
<source>Protect your IP address from the messaging relays chosen by your contacts.
Enable in *Network &amp; servers* settings.</source>
<target>Захистіть свою IP-адресу від ретрансляторів повідомлень, обраних вашими контактами.
Увімкніть у налаштуваннях *Мережа та сервери*.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Protect your chat profiles with a password!" xml:space="preserve">
@@ -4626,6 +4675,7 @@ Enable in *Network &amp; servers* settings.</source>
</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>
<target>Одержувач(и) не бачить, від кого це повідомлення.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Recipients see updates as you type them." xml:space="preserve">
@@ -4845,6 +4895,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Safely receive files" xml:space="preserve">
<source>Safely receive files</source>
<target>Безпечне отримання файлів</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Safer groups" xml:space="preserve">
@@ -4934,6 +4985,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Saved" xml:space="preserve">
<source>Saved</source>
<target>Збережено</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve">
@@ -4943,6 +4995,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Saved from" xml:space="preserve">
<source>Saved from</source>
<target>Збережено з</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved message" xml:space="preserve">
@@ -5072,10 +5125,12 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Send messages directly when IP address is protected and your or destination server does not support private routing." xml:space="preserve">
<source>Send messages directly when IP address is protected and your or destination server does not support private routing.</source>
<target>Надсилайте повідомлення напряму, якщо IP-адреса захищена, а ваш сервер або сервер призначення не підтримує приватну маршрутизацію.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send messages directly when your or destination server does not support private routing." xml:space="preserve">
<source>Send messages directly when your or destination server does not support private routing.</source>
<target>Надсилайте повідомлення напряму, якщо ваш сервер або сервер призначення не підтримує приватну маршрутизацію.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Send notifications" xml:space="preserve">
@@ -5185,6 +5240,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Server address is incompatible with network settings." xml:space="preserve">
<source>Server address is incompatible with network settings.</source>
<target>Адреса сервера несумісна з налаштуваннями мережі.</target>
<note>srv error text.</note>
</trans-unit>
<trans-unit id="Server requires authorization to create queues, check password" xml:space="preserve">
@@ -5204,6 +5260,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Server version is incompatible with network settings." xml:space="preserve">
<source>Server version is incompatible with network settings.</source>
<target>Серверна версія несумісна з мережевими налаштуваннями.</target>
<note>srv error text</note>
</trans-unit>
<trans-unit id="Servers" xml:space="preserve">
@@ -5268,6 +5325,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Shape profile images" xml:space="preserve">
<source>Shape profile images</source>
<target>Сформуйте зображення профілю</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Share" xml:space="preserve">
@@ -5327,6 +5385,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Show message status" xml:space="preserve">
<source>Show message status</source>
<target>Показати статус повідомлення</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show preview" xml:space="preserve">
@@ -5336,6 +5395,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Show → on messages sent via private routing." xml:space="preserve">
<source>Show → on messages sent via private routing.</source>
<target>Показувати → у повідомленнях, надісланих через приватну маршрутизацію.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Show:" xml:space="preserve">
@@ -5400,10 +5460,12 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="SimpleX links are prohibited in this group." xml:space="preserve">
<source>SimpleX links are prohibited in this group.</source>
<target>У цій групі заборонені посилання на SimpleX.</target>
<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>
<target>Посилання SimpleX заборонені</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="SimpleX one-time invitation" xml:space="preserve">
@@ -5443,6 +5505,7 @@ Enable in *Network &amp; servers* settings.</source>
</trans-unit>
<trans-unit id="Square, circle, or anything in between." xml:space="preserve">
<source>Square, circle, or anything in between.</source>
<target>Квадрат, коло або щось середнє між ними.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Start chat" xml:space="preserve">
@@ -5659,6 +5722,7 @@ It can happen because of some bug or when the connection is compromised.</source
</trans-unit>
<trans-unit id="The app will ask to confirm downloads from unknown file servers (except .onion)." xml:space="preserve">
<source>The app will ask to confirm downloads from unknown file servers (except .onion).</source>
<target>Програма попросить підтвердити завантаження з невідомих файлових серверів (крім .onion).</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="The attempt to change database passphrase was not completed." xml:space="preserve">
@@ -5848,6 +5912,7 @@ It can happen because of some bug or when the connection is compromised.</source
</trans-unit>
<trans-unit id="To protect your IP address, private routing uses your SMP servers to deliver messages." xml:space="preserve">
<source>To protect your IP address, private routing uses your SMP servers to deliver messages.</source>
<target>Щоб захистити вашу IP-адресу, приватна маршрутизація використовує ваші SMP-сервери для доставки повідомлень.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To protect your information, turn on SimpleX Lock.&#10;You will be prompted to complete authentication before this feature is enabled." xml:space="preserve">
@@ -5989,6 +6054,7 @@ You will be prompted to complete authentication before this feature is enabled.<
</trans-unit>
<trans-unit id="Unknown servers!" xml:space="preserve">
<source>Unknown servers!</source>
<target>Невідомі сервери!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unless you use iOS call interface, enable Do Not Disturb mode to avoid interruptions." xml:space="preserve">
@@ -6140,10 +6206,12 @@ To connect, please ask your contact to create another connection link and check
</trans-unit>
<trans-unit id="Use private routing with unknown servers when IP address is not protected." xml:space="preserve">
<source>Use private routing with unknown servers when IP address is not protected.</source>
<target>Використовуйте приватну маршрутизацію з невідомими серверами, якщо IP-адреса не захищена.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use private routing with unknown servers." xml:space="preserve">
<source>Use private routing with unknown servers.</source>
<target>Використовуйте приватну маршрутизацію з невідомими серверами.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use server" xml:space="preserve">
@@ -6263,6 +6331,7 @@ To connect, please ask your contact to create another connection link and check
</trans-unit>
<trans-unit id="Voice messages not allowed" xml:space="preserve">
<source>Voice messages not allowed</source>
<target>Голосові повідомлення заборонені</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Voice messages prohibited!" xml:space="preserve">
@@ -6337,6 +6406,7 @@ To connect, please ask your contact to create another connection link and check
</trans-unit>
<trans-unit id="When connecting audio and video calls." xml:space="preserve">
<source>When connecting audio and video calls.</source>
<target>При підключенні аудіо та відеодзвінків.</target>
<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">
@@ -6351,14 +6421,17 @@ To connect, please ask your contact to create another connection link and check
</trans-unit>
<trans-unit id="WiFi" xml:space="preserve">
<source>WiFi</source>
<target>WiFi</target>
<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>
<target>Буде ввімкнено в прямих чатах!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Wired ethernet" xml:space="preserve">
<source>Wired ethernet</source>
<target>Дротова мережа Ethernet</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="With encrypted files and media." xml:space="preserve">
@@ -6378,10 +6451,12 @@ To connect, please ask your contact to create another connection link and check
</trans-unit>
<trans-unit id="Without Tor or VPN, your IP address will be visible to file servers." xml:space="preserve">
<source>Without Tor or VPN, your IP address will be visible to file servers.</source>
<target>Без Tor або VPN ваша IP-адреса буде видимою для файлових серверів.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Without Tor or VPN, your IP address will be visible to these XFTP relays: %@." xml:space="preserve">
<source>Without Tor or VPN, your IP address will be visible to these XFTP relays: %@.</source>
<target>Без Tor або VPN ваша IP-адреса буде видимою для цих XFTP-ретрансляторів: %@.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Wrong database passphrase" xml:space="preserve">
@@ -6391,6 +6466,7 @@ To connect, please ask your contact to create another connection link and check
</trans-unit>
<trans-unit id="Wrong key or unknown connection - most likely this connection is deleted." xml:space="preserve">
<source>Wrong key or unknown connection - most likely this connection is deleted.</source>
<target>Неправильний ключ або невідоме з'єднання - швидше за все, це з'єднання видалено.</target>
<note>snd error text</note>
</trans-unit>
<trans-unit id="Wrong passphrase!" xml:space="preserve">
@@ -6858,6 +6934,7 @@ SimpleX servers cannot see your profile.</source>
</trans-unit>
<trans-unit id="admins" xml:space="preserve">
<source>admins</source>
<target>адміністратори</target>
<note>feature role</note>
</trans-unit>
<trans-unit id="agreeing encryption for %@…" xml:space="preserve">
@@ -6872,6 +6949,7 @@ SimpleX servers cannot see your profile.</source>
</trans-unit>
<trans-unit id="all members" xml:space="preserve">
<source>all members</source>
<target>всі учасники</target>
<note>feature role</note>
</trans-unit>
<trans-unit id="always" xml:space="preserve">
@@ -7206,6 +7284,7 @@ SimpleX servers cannot see your profile.</source>
</trans-unit>
<trans-unit id="forwarded" xml:space="preserve">
<source>forwarded</source>
<target>переслано</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="group deleted" xml:space="preserve">
@@ -7417,6 +7496,7 @@ SimpleX servers cannot see your profile.</source>
</trans-unit>
<trans-unit id="owners" xml:space="preserve">
<source>owners</source>
<target>власники</target>
<note>feature role</note>
</trans-unit>
<trans-unit id="peer-to-peer" xml:space="preserve">
@@ -7471,10 +7551,12 @@ SimpleX servers cannot see your profile.</source>
</trans-unit>
<trans-unit id="saved" xml:space="preserve">
<source>saved</source>
<target>збережено</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="saved from %@" xml:space="preserve">
<source>saved from %@</source>
<target>збережено з %@</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="sec" xml:space="preserve">
@@ -7502,6 +7584,12 @@ SimpleX servers cannot see your profile.</source>
<target>надіслати пряме повідомлення</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="server queue info: %@&#10;&#10;last received msg: %@" xml:space="preserve">
<source>server queue info: %1$@
last received msg: %2$@</source>
<note>queue info</note>
</trans-unit>
<trans-unit id="set new contact address" xml:space="preserve">
<source>set new contact address</source>
<target>встановити нову контактну адресу</target>
@@ -7544,6 +7632,7 @@ SimpleX servers cannot see your profile.</source>
</trans-unit>
<trans-unit id="unknown relays" xml:space="preserve">
<source>unknown relays</source>
<target>невідомі реле</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="unknown status" xml:space="preserve">
@@ -7553,6 +7642,7 @@ SimpleX servers cannot see your profile.</source>
</trans-unit>
<trans-unit id="unprotected" xml:space="preserve">
<source>unprotected</source>
<target>незахищені</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="updated group profile" xml:space="preserve">
@@ -7622,6 +7712,7 @@ SimpleX servers cannot see your profile.</source>
</trans-unit>
<trans-unit id="when IP hidden" xml:space="preserve">
<source>when IP hidden</source>
<target>коли IP приховано</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="yes" xml:space="preserve">
@@ -7631,6 +7722,7 @@ SimpleX servers cannot see your profile.</source>
</trans-unit>
<trans-unit id="you" xml:space="preserve">
<source>you</source>
<target>ти</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="you are invited to group" xml:space="preserve">
@@ -1695,6 +1695,10 @@ This is your own one-time link!</source>
<target>应用程序重新启动时将迁移数据库</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Debug delivery" xml:space="preserve">
<source>Debug delivery</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Decentralized" xml:space="preserve">
<source>Decentralized</source>
<target>分散式</target>
@@ -3646,6 +3650,10 @@ This is your link for group %@!</source>
<target>消息草稿</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message queue info" xml:space="preserve">
<source>Message queue info</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message reactions" xml:space="preserve">
<source>Message reactions</source>
<target>消息回应</target>
@@ -7471,6 +7479,12 @@ SimpleX 服务器无法看到您的资料。</target>
<target>发送私信</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="server queue info: %@&#10;&#10;last received msg: %@" xml:space="preserve">
<source>server queue info: %1$@
last received msg: %2$@</source>
<note>queue info</note>
</trans-unit>
<trans-unit id="set new contact address" xml:space="preserve">
<source>set new contact address</source>
<target>设置新的联系地址</target>
@@ -5,5 +5,5 @@
"CFBundleName" = "SimpleX NSE";
/* Copyright (human-readable) */
"NSHumanReadableCopyright" = "Copyright © 2022 SimpleX Chat. All rights reserved.";
"NSHumanReadableCopyright" = "Copyright © 2024 SimpleX Chat. All rights reserved.";
+60 -32
View File
@@ -24,11 +24,6 @@
5C029EAA283942EA004A9677 /* CallController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C029EA9283942EA004A9677 /* CallController.swift */; };
5C05DF532840AA1D00C683F9 /* CallSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C05DF522840AA1D00C683F9 /* CallSettings.swift */; };
5C063D2727A4564100AEC577 /* ChatPreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C063D2627A4564100AEC577 /* ChatPreviewView.swift */; };
5C0EA13B2C0B176B00AD2E5E /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C0EA1362C0B176B00AD2E5E /* libgmp.a */; };
5C0EA13C2C0B176B00AD2E5E /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C0EA1372C0B176B00AD2E5E /* libgmpxx.a */; };
5C0EA13D2C0B176B00AD2E5E /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C0EA1382C0B176B00AD2E5E /* libffi.a */; };
5C0EA13E2C0B176B00AD2E5E /* libHSsimplex-chat-5.8.0.5-Idqi6HXqzzs2zrnyZtMyhc-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C0EA1392C0B176B00AD2E5E /* libHSsimplex-chat-5.8.0.5-Idqi6HXqzzs2zrnyZtMyhc-ghc9.6.3.a */; };
5C0EA13F2C0B176B00AD2E5E /* libHSsimplex-chat-5.8.0.5-Idqi6HXqzzs2zrnyZtMyhc.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C0EA13A2C0B176B00AD2E5E /* libHSsimplex-chat-5.8.0.5-Idqi6HXqzzs2zrnyZtMyhc.a */; };
5C10D88828EED12E00E58BF0 /* ContactConnectionInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C10D88728EED12E00E58BF0 /* ContactConnectionInfo.swift */; };
5C10D88A28F187F300E58BF0 /* FullScreenMediaView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C10D88928F187F300E58BF0 /* FullScreenMediaView.swift */; };
5C116CDC27AABE0400E66D01 /* ContactRequestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C116CDB27AABE0400E66D01 /* ContactRequestView.swift */; };
@@ -155,6 +150,7 @@
6407BA83295DA85D0082BA18 /* CIInvalidJSONView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6407BA82295DA85D0082BA18 /* CIInvalidJSONView.swift */; };
6419EC562AB8BC8B004A607A /* ContextInvitingContactMemberView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6419EC552AB8BC8B004A607A /* ContextInvitingContactMemberView.swift */; };
6419EC582AB97507004A607A /* CIMemberCreatedContactView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6419EC572AB97507004A607A /* CIMemberCreatedContactView.swift */; };
642CE4952BE2651E00AD7757 /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 642CE4942BE2651E00AD7757 /* HomeView.swift */; };
6432857C2925443C00FBE5C8 /* GroupPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6432857B2925443C00FBE5C8 /* GroupPreferencesView.swift */; };
6440CA00288857A10062C672 /* CIEventView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6440C9FF288857A10062C672 /* CIEventView.swift */; };
6440CA03288AECA70062C672 /* AddGroupMembersView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6440CA02288AECA70062C672 /* AddGroupMembersView.swift */; };
@@ -172,9 +168,11 @@
646BB38E283FDB6D001CE359 /* LocalAuthenticationUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 646BB38D283FDB6D001CE359 /* LocalAuthenticationUtils.swift */; };
647F090E288EA27B00644C40 /* GroupMemberInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 647F090D288EA27B00644C40 /* GroupMemberInfoView.swift */; };
648010AB281ADD15009009B9 /* CIFileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 648010AA281ADD15009009B9 /* CIFileView.swift */; };
6485F7C62BE8DB6500FAE413 /* ContactsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6485F7C52BE8DB6500FAE413 /* ContactsView.swift */; };
648679AB2BC96A74006456E7 /* ChatItemForwardingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 648679AA2BC96A74006456E7 /* ChatItemForwardingView.swift */; };
649BCDA0280460FD00C3A862 /* ComposeImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649BCD9F280460FD00C3A862 /* ComposeImageView.swift */; };
649BCDA22805D6EF00C3A862 /* CIImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649BCDA12805D6EF00C3A862 /* CIImageView.swift */; };
64A596452BE90DEC00B69266 /* ContactListNavLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64A596442BE90DEC00B69266 /* ContactListNavLink.swift */; };
64AA1C6927EE10C800AC7277 /* ContextItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64AA1C6827EE10C800AC7277 /* ContextItemView.swift */; };
64AA1C6C27F3537400AC7277 /* DeletedItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64AA1C6B27F3537400AC7277 /* DeletedItemView.swift */; };
64C06EB52A0A4A7C00792D4D /* ChatItemInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64C06EB42A0A4A7C00792D4D /* ChatItemInfoView.swift */; };
@@ -197,6 +195,11 @@
D741547A29AF90B00022400A /* PushKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D741547929AF90B00022400A /* PushKit.framework */; };
D77B92DC2952372200A5A1CC /* SwiftyGif in Frameworks */ = {isa = PBXBuildFile; productRef = D77B92DB2952372200A5A1CC /* SwiftyGif */; };
D7F0E33929964E7E0068AF69 /* LZString in Frameworks */ = {isa = PBXBuildFile; productRef = D7F0E33829964E7E0068AF69 /* LZString */; };
E5D68D3F2C22D78C00CBA347 /* libHSsimplex-chat-5.8.1.0-GEbUSGuGADZH0bnStuks0c.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5D68D3A2C22D78C00CBA347 /* libHSsimplex-chat-5.8.1.0-GEbUSGuGADZH0bnStuks0c.a */; };
E5D68D402C22D78C00CBA347 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5D68D3B2C22D78C00CBA347 /* libffi.a */; };
E5D68D412C22D78C00CBA347 /* libHSsimplex-chat-5.8.1.0-GEbUSGuGADZH0bnStuks0c-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5D68D3C2C22D78C00CBA347 /* libHSsimplex-chat-5.8.1.0-GEbUSGuGADZH0bnStuks0c-ghc9.6.3.a */; };
E5D68D422C22D78C00CBA347 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5D68D3D2C22D78C00CBA347 /* libgmp.a */; };
E5D68D432C22D78C00CBA347 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5D68D3E2C22D78C00CBA347 /* libgmpxx.a */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -273,11 +276,6 @@
5C029EA9283942EA004A9677 /* CallController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallController.swift; sourceTree = "<group>"; };
5C05DF522840AA1D00C683F9 /* CallSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallSettings.swift; sourceTree = "<group>"; };
5C063D2627A4564100AEC577 /* ChatPreviewView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatPreviewView.swift; sourceTree = "<group>"; };
5C0EA1362C0B176B00AD2E5E /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
5C0EA1372C0B176B00AD2E5E /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
5C0EA1382C0B176B00AD2E5E /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
5C0EA1392C0B176B00AD2E5E /* libHSsimplex-chat-5.8.0.5-Idqi6HXqzzs2zrnyZtMyhc-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.8.0.5-Idqi6HXqzzs2zrnyZtMyhc-ghc9.6.3.a"; sourceTree = "<group>"; };
5C0EA13A2C0B176B00AD2E5E /* libHSsimplex-chat-5.8.0.5-Idqi6HXqzzs2zrnyZtMyhc.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.8.0.5-Idqi6HXqzzs2zrnyZtMyhc.a"; sourceTree = "<group>"; };
5C10D88728EED12E00E58BF0 /* ContactConnectionInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactConnectionInfo.swift; sourceTree = "<group>"; };
5C10D88928F187F300E58BF0 /* FullScreenMediaView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullScreenMediaView.swift; sourceTree = "<group>"; };
5C116CDB27AABE0400E66D01 /* ContactRequestView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactRequestView.swift; sourceTree = "<group>"; };
@@ -450,6 +448,7 @@
6407BA82295DA85D0082BA18 /* CIInvalidJSONView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIInvalidJSONView.swift; sourceTree = "<group>"; };
6419EC552AB8BC8B004A607A /* ContextInvitingContactMemberView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextInvitingContactMemberView.swift; sourceTree = "<group>"; };
6419EC572AB97507004A607A /* CIMemberCreatedContactView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIMemberCreatedContactView.swift; sourceTree = "<group>"; };
642CE4942BE2651E00AD7757 /* HomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeView.swift; sourceTree = "<group>"; };
6432857B2925443C00FBE5C8 /* GroupPreferencesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupPreferencesView.swift; sourceTree = "<group>"; };
6440C9FF288857A10062C672 /* CIEventView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIEventView.swift; sourceTree = "<group>"; };
6440CA02288AECA70062C672 /* AddGroupMembersView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddGroupMembersView.swift; sourceTree = "<group>"; };
@@ -467,10 +466,12 @@
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>"; };
648010AA281ADD15009009B9 /* CIFileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIFileView.swift; sourceTree = "<group>"; };
6485F7C52BE8DB6500FAE413 /* ContactsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactsView.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>"; };
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>"; };
64A596442BE90DEC00B69266 /* ContactListNavLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactListNavLink.swift; sourceTree = "<group>"; };
64AA1C6827EE10C800AC7277 /* ContextItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextItemView.swift; sourceTree = "<group>"; };
64AA1C6B27F3537400AC7277 /* DeletedItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeletedItemView.swift; sourceTree = "<group>"; };
64C06EB42A0A4A7C00792D4D /* ChatItemInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatItemInfoView.swift; sourceTree = "<group>"; };
@@ -492,6 +493,11 @@
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; };
D7AA2C3429A936B400737B40 /* MediaEncryption.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; name = MediaEncryption.playground; path = Shared/MediaEncryption.playground; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
E5D68D3A2C22D78C00CBA347 /* libHSsimplex-chat-5.8.1.0-GEbUSGuGADZH0bnStuks0c.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.8.1.0-GEbUSGuGADZH0bnStuks0c.a"; sourceTree = "<group>"; };
E5D68D3B2C22D78C00CBA347 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
E5D68D3C2C22D78C00CBA347 /* libHSsimplex-chat-5.8.1.0-GEbUSGuGADZH0bnStuks0c-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.8.1.0-GEbUSGuGADZH0bnStuks0c-ghc9.6.3.a"; sourceTree = "<group>"; };
E5D68D3D2C22D78C00CBA347 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
E5D68D3E2C22D78C00CBA347 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -529,13 +535,13 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
5C0EA13C2C0B176B00AD2E5E /* libgmpxx.a in Frameworks */,
E5D68D412C22D78C00CBA347 /* libHSsimplex-chat-5.8.1.0-GEbUSGuGADZH0bnStuks0c-ghc9.6.3.a in Frameworks */,
5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */,
5C0EA13B2C0B176B00AD2E5E /* libgmp.a in Frameworks */,
5C0EA13D2C0B176B00AD2E5E /* libffi.a in Frameworks */,
5C0EA13F2C0B176B00AD2E5E /* libHSsimplex-chat-5.8.0.5-Idqi6HXqzzs2zrnyZtMyhc.a in Frameworks */,
5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */,
5C0EA13E2C0B176B00AD2E5E /* libHSsimplex-chat-5.8.0.5-Idqi6HXqzzs2zrnyZtMyhc-ghc9.6.3.a in Frameworks */,
E5D68D3F2C22D78C00CBA347 /* libHSsimplex-chat-5.8.1.0-GEbUSGuGADZH0bnStuks0c.a in Frameworks */,
E5D68D422C22D78C00CBA347 /* libgmp.a in Frameworks */,
E5D68D402C22D78C00CBA347 /* libffi.a in Frameworks */,
E5D68D432C22D78C00CBA347 /* libgmpxx.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -562,11 +568,13 @@
5C2E260D27A30E2400F70299 /* Views */ = {
isa = PBXGroup;
children = (
642CE4932BE2650500AD7757 /* Home */,
5CB0BA8C282711BC00B3292C /* Onboarding */,
3C714775281C080100CB4D4B /* Call */,
5C971E1F27AEBF7000C8A3CE /* Helpers */,
5C5F4AC227A5E9AF00B51EF1 /* Chat */,
5CB9250B27A942F300ACCCDD /* ChatList */,
6485F7C42BE8DB4F00FAE413 /* Contacts */,
5CB924DD27A8622200ACCCDD /* NewChat */,
5CFA59C22860B04D00863A68 /* Database */,
5CB634AB29E46CDB0066AD6B /* LocalAuth */,
@@ -601,11 +609,11 @@
5C764E5C279C70B7000C6508 /* Libraries */ = {
isa = PBXGroup;
children = (
5C0EA1382C0B176B00AD2E5E /* libffi.a */,
5C0EA1362C0B176B00AD2E5E /* libgmp.a */,
5C0EA1372C0B176B00AD2E5E /* libgmpxx.a */,
5C0EA1392C0B176B00AD2E5E /* libHSsimplex-chat-5.8.0.5-Idqi6HXqzzs2zrnyZtMyhc-ghc9.6.3.a */,
5C0EA13A2C0B176B00AD2E5E /* libHSsimplex-chat-5.8.0.5-Idqi6HXqzzs2zrnyZtMyhc.a */,
E5D68D3B2C22D78C00CBA347 /* libffi.a */,
E5D68D3D2C22D78C00CBA347 /* libgmp.a */,
E5D68D3E2C22D78C00CBA347 /* libgmpxx.a */,
E5D68D3C2C22D78C00CBA347 /* libHSsimplex-chat-5.8.1.0-GEbUSGuGADZH0bnStuks0c-ghc9.6.3.a */,
E5D68D3A2C22D78C00CBA347 /* libHSsimplex-chat-5.8.1.0-GEbUSGuGADZH0bnStuks0c.a */,
);
path = Libraries;
sourceTree = "<group>";
@@ -899,6 +907,14 @@
path = Database;
sourceTree = "<group>";
};
642CE4932BE2650500AD7757 /* Home */ = {
isa = PBXGroup;
children = (
642CE4942BE2651E00AD7757 /* HomeView.swift */,
);
path = Home;
sourceTree = "<group>";
};
6440CA01288AEC770062C672 /* Group */ = {
isa = PBXGroup;
children = (
@@ -913,6 +929,15 @@
path = Group;
sourceTree = "<group>";
};
6485F7C42BE8DB4F00FAE413 /* Contacts */ = {
isa = PBXGroup;
children = (
6485F7C52BE8DB6500FAE413 /* ContactsView.swift */,
64A596442BE90DEC00B69266 /* ContactListNavLink.swift */,
);
path = Contacts;
sourceTree = "<group>";
};
8C7D94982B8894D300B7B9E1 /* Migration */ = {
isa = PBXGroup;
children = (
@@ -1148,6 +1173,7 @@
5CB0BA9A2827FD8800B3292C /* HowItWorks.swift in Sources */,
5C13730B28156D2700F43030 /* ContactConnectionView.swift in Sources */,
644EFFE0292CFD7F00525D5B /* CIVoiceView.swift in Sources */,
64A596452BE90DEC00B69266 /* ContactListNavLink.swift in Sources */,
6432857C2925443C00FBE5C8 /* GroupPreferencesView.swift in Sources */,
5C93293129239BED0090FFF9 /* ProtocolServerView.swift in Sources */,
5C9CC7AD28C55D7800BEF955 /* DatabaseEncryptionView.swift in Sources */,
@@ -1168,6 +1194,7 @@
5CB2084F28DA4B4800D024EC /* RTCServers.swift in Sources */,
5CB634AF29E4BB7D0066AD6B /* SetAppPasscodeView.swift in Sources */,
5C10D88828EED12E00E58BF0 /* ContactConnectionInfo.swift in Sources */,
6485F7C62BE8DB6500FAE413 /* ContactsView.swift in Sources */,
5CBE6C12294487F7002D9531 /* VerifyCodeView.swift in Sources */,
3CDBCF4227FAE51000354CDD /* ComposeLinkView.swift in Sources */,
648679AB2BC96A74006456E7 /* ChatItemForwardingView.swift in Sources */,
@@ -1212,6 +1239,7 @@
5CEBD7462A5C0A8F00665FE2 /* KeyboardPadding.swift in Sources */,
5C35CFC827B2782E00FB6C6D /* BGManager.swift in Sources */,
5CB634B129E5EFEA0066AD6B /* PasscodeView.swift in Sources */,
642CE4952BE2651E00AD7757 /* HomeView.swift in Sources */,
8C69FE7D2B8C7D2700267E38 /* AppSettings.swift in Sources */,
5C2E260F27A30FDC00F70299 /* ChatView.swift in Sources */,
5C2E260B27A30CFA00F70299 /* ChatListView.swift in Sources */,
@@ -1552,7 +1580,7 @@
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 223;
CURRENT_PROJECT_VERSION = 225;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
@@ -1577,7 +1605,7 @@
"@executable_path/Frameworks",
);
LLVM_LTO = YES_THIN;
MARKETING_VERSION = 5.8;
MARKETING_VERSION = 5.8.1;
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app;
PRODUCT_NAME = SimpleX;
SDKROOT = iphoneos;
@@ -1601,7 +1629,7 @@
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 223;
CURRENT_PROJECT_VERSION = 225;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
@@ -1626,7 +1654,7 @@
"@executable_path/Frameworks",
);
LLVM_LTO = YES;
MARKETING_VERSION = 5.8;
MARKETING_VERSION = 5.8.1;
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app;
PRODUCT_NAME = SimpleX;
SDKROOT = iphoneos;
@@ -1687,7 +1715,7 @@
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 223;
CURRENT_PROJECT_VERSION = 225;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
GCC_OPTIMIZATION_LEVEL = s;
@@ -1702,7 +1730,7 @@
"@executable_path/../../Frameworks",
);
LLVM_LTO = YES;
MARKETING_VERSION = 5.8;
MARKETING_VERSION = 5.8.1;
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-NSE";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -1724,7 +1752,7 @@
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 223;
CURRENT_PROJECT_VERSION = 225;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
ENABLE_CODE_COVERAGE = NO;
@@ -1739,7 +1767,7 @@
"@executable_path/../../Frameworks",
);
LLVM_LTO = YES;
MARKETING_VERSION = 5.8;
MARKETING_VERSION = 5.8.1;
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-NSE";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -1761,7 +1789,7 @@
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 223;
CURRENT_PROJECT_VERSION = 225;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
DYLIB_COMPATIBILITY_VERSION = 1;
@@ -1787,7 +1815,7 @@
"$(PROJECT_DIR)/Libraries/sim",
);
LLVM_LTO = YES;
MARKETING_VERSION = 5.8;
MARKETING_VERSION = 5.8.1;
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.SimpleXChat;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SDKROOT = iphoneos;
@@ -1812,7 +1840,7 @@
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 223;
CURRENT_PROJECT_VERSION = 225;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
DYLIB_COMPATIBILITY_VERSION = 1;
@@ -1838,7 +1866,7 @@
"$(PROJECT_DIR)/Libraries/sim",
);
LLVM_LTO = YES;
MARKETING_VERSION = 5.8;
MARKETING_VERSION = 5.8.1;
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.SimpleXChat;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SDKROOT = iphoneos;
+33 -16
View File
@@ -99,7 +99,7 @@ public enum ChatCommand {
case apiConnectPlan(userId: Int64, connReq: String)
case apiConnect(userId: Int64, incognito: Bool, connReq: String)
case apiConnectContactViaAddress(userId: Int64, incognito: Bool, contactId: Int64)
case apiDeleteChat(type: ChatType, id: Int64, notify: Bool?)
case apiDeleteChat(type: ChatType, id: Int64, chatDeleteMode: ChatDeleteMode)
case apiClearChat(type: ChatType, id: Int64)
case apiListContacts(userId: Int64)
case apiUpdateProfile(userId: Int64, profile: Profile)
@@ -257,11 +257,7 @@ public enum ChatCommand {
case let .apiConnectPlan(userId, connReq): return "/_connect plan \(userId) \(connReq)"
case let .apiConnect(userId, incognito, connReq): return "/_connect \(userId) incognito=\(onOff(incognito)) \(connReq)"
case let .apiConnectContactViaAddress(userId, incognito, contactId): return "/_connect contact \(userId) incognito=\(onOff(incognito)) \(contactId)"
case let .apiDeleteChat(type, id, notify): if let notify = notify {
return "/_delete \(ref(type, id)) notify=\(onOff(notify))"
} else {
return "/_delete \(ref(type, id))"
}
case let .apiDeleteChat(type, id, chatDeleteMode): return "/_delete \(ref(type, id)) \(chatDeleteMode.cmdString)"
case let .apiClearChat(type, id): return "/_clear chat \(ref(type, id))"
case let .apiListContacts(userId): return "/_contacts \(userId)"
case let .apiUpdateProfile(userId, profile): return "/_profile \(userId) \(encodeJSON(profile))"
@@ -485,10 +481,6 @@ public enum ChatCommand {
return nil
}
private func onOff(_ b: Bool) -> String {
b ? "on" : "off"
}
private func onOffParam(_ param: String, _ b: Bool?) -> String {
if let b = b {
return " \(param)=\(onOff(b))"
@@ -501,6 +493,10 @@ public enum ChatCommand {
}
}
private func onOff(_ b: Bool) -> String {
b ? "on" : "off"
}
public struct APIResponse: Decodable {
var resp: ChatResponse
}
@@ -622,7 +618,8 @@ public enum ChatResponse: Decodable, Error {
case rcvStandaloneFileComplete(user: UserRef, targetPath: String, rcvFileTransfer: RcvFileTransfer)
case rcvFileCancelled(user: UserRef, chatItem_: AChatItem?, rcvFileTransfer: RcvFileTransfer)
case rcvFileSndCancelled(user: UserRef, chatItem: AChatItem, rcvFileTransfer: RcvFileTransfer)
case rcvFileError(user: UserRef, chatItem_: AChatItem?, rcvFileTransfer: RcvFileTransfer)
case rcvFileError(user: UserRef, chatItem_: AChatItem?, agentError: AgentErrorType, rcvFileTransfer: RcvFileTransfer)
case rcvFileWarning(user: UserRef, chatItem_: AChatItem?, agentError: AgentErrorType, rcvFileTransfer: RcvFileTransfer)
// sending file events
case sndFileStart(user: UserRef, chatItem: AChatItem, sndFileTransfer: SndFileTransfer)
case sndFileComplete(user: UserRef, chatItem: AChatItem, sndFileTransfer: SndFileTransfer)
@@ -636,6 +633,7 @@ public enum ChatResponse: Decodable, Error {
case sndStandaloneFileComplete(user: UserRef, fileTransferMeta: FileTransferMeta, rcvURIs: [String])
case sndFileCancelledXFTP(user: UserRef, chatItem_: AChatItem?, fileTransferMeta: FileTransferMeta)
case sndFileError(user: UserRef, chatItem_: AChatItem?, fileTransferMeta: FileTransferMeta, errorMessage: String)
case sndFileWarning(user: UserRef, chatItem_: AChatItem?, fileTransferMeta: FileTransferMeta, errorMessage: String)
// call events
case callInvitation(callInvitation: RcvCallInvitation)
case callOffer(user: UserRef, contact: Contact, callType: CallType, offer: WebRTCSession, sharedKey: String?, askConfirmation: Bool)
@@ -784,6 +782,7 @@ public enum ChatResponse: Decodable, Error {
case .rcvFileCancelled: return "rcvFileCancelled"
case .rcvFileSndCancelled: return "rcvFileSndCancelled"
case .rcvFileError: return "rcvFileError"
case .rcvFileWarning: return "rcvFileWarning"
case .sndFileStart: return "sndFileStart"
case .sndFileComplete: return "sndFileComplete"
case .sndFileCancelled: return "sndFileCancelled"
@@ -796,6 +795,7 @@ public enum ChatResponse: Decodable, Error {
case .sndStandaloneFileComplete: return "sndStandaloneFileComplete"
case .sndFileCancelledXFTP: return "sndFileCancelledXFTP"
case .sndFileError: return "sndFileError"
case .sndFileWarning: return "sndFileWarning"
case .callInvitation: return "callInvitation"
case .callOffer: return "callOffer"
case .callAnswer: return "callAnswer"
@@ -944,7 +944,8 @@ public enum ChatResponse: Decodable, Error {
case let .rcvFileComplete(u, chatItem): return withUser(u, String(describing: chatItem))
case let .rcvFileCancelled(u, chatItem, _): return withUser(u, String(describing: chatItem))
case let .rcvFileSndCancelled(u, chatItem, _): return withUser(u, String(describing: chatItem))
case let .rcvFileError(u, chatItem, _): return withUser(u, String(describing: chatItem))
case let .rcvFileError(u, chatItem, agentError, _): return withUser(u, "agentError: \(String(describing: agentError))\nchatItem: \(String(describing: chatItem))")
case let .rcvFileWarning(u, chatItem, agentError, _): return withUser(u, "agentError: \(String(describing: agentError))\nchatItem: \(String(describing: chatItem))")
case let .sndFileStart(u, chatItem, _): return withUser(u, String(describing: chatItem))
case let .sndFileComplete(u, chatItem, _): return withUser(u, String(describing: chatItem))
case let .sndFileCancelled(u, chatItem, _, _): return withUser(u, String(describing: chatItem))
@@ -957,6 +958,7 @@ public enum ChatResponse: Decodable, Error {
case let .sndStandaloneFileComplete(u, _, rcvURIs): return withUser(u, String(rcvURIs.count))
case let .sndFileCancelledXFTP(u, chatItem, _): return withUser(u, String(describing: chatItem))
case let .sndFileError(u, chatItem, _, err): return withUser(u, "error: \(String(describing: err))\nchatItem: \(String(describing: chatItem))")
case let .sndFileWarning(u, chatItem, _, err): return withUser(u, "error: \(String(describing: err))\nchatItem: \(String(describing: chatItem))")
case let .callInvitation(inv): return String(describing: inv)
case let .callOffer(u, contact, callType, offer, sharedKey, askConfirmation): return withUser(u, "contact: \(contact.id)\ncallType: \(String(describing: callType))\nsharedKey: \(sharedKey ?? "")\naskConfirmation: \(askConfirmation)\noffer: \(String(describing: offer))")
case let .callAnswer(u, contact, answer): return withUser(u, "contact: \(contact.id)\nanswer: \(String(describing: answer))")
@@ -974,7 +976,7 @@ public enum ChatResponse: Decodable, Error {
case let .remoteCtrlConnecting(remoteCtrl_, ctrlAppInfo, appVersion): return "remoteCtrl_:\n\(String(describing: remoteCtrl_))\nctrlAppInfo:\n\(String(describing: ctrlAppInfo))\nappVersion: \(appVersion)"
case let .remoteCtrlSessionCode(remoteCtrl_, sessionCode): return "remoteCtrl_:\n\(String(describing: remoteCtrl_))\nsessionCode: \(sessionCode)"
case let .remoteCtrlConnected(remoteCtrl): return String(describing: remoteCtrl)
case .remoteCtrlStopped: return noDetails
case let .remoteCtrlStopped(rcsState, rcStopReason): return "rcsState: \(String(describing: rcsState))\nrcStopReason: \(String(describing: rcStopReason))"
case let .contactPQEnabled(u, contact, pqEnabled): return withUser(u, "contact: \(String(describing: contact))\npqEnabled: \(pqEnabled)")
case let .versionInfo(versionInfo, chatMigrations, agentMigrations): return "\(String(describing: versionInfo))\n\nchat migrations: \(chatMigrations.map(\.upName))\n\nagent migrations: \(agentMigrations.map(\.upName))"
case .cmdOk: return noDetails
@@ -1004,6 +1006,20 @@ public func chatError(_ chatResponse: ChatResponse) -> ChatErrorType? {
}
}
public enum ChatDeleteMode: Codable {
case full(notify: Bool)
case entity(notify: Bool)
case messages
var cmdString: String {
switch self {
case let .full(notify): "full notify=\(onOff(notify))"
case let .entity(notify): "entity notify=\(onOff(notify))"
case .messages: "messages"
}
}
}
public enum ConnectionPlan: Decodable {
case invitationLink(invitationLinkPlan: InvitationLinkPlan)
case contactAddress(contactAddressPlan: ContactAddressPlan)
@@ -1771,8 +1787,6 @@ public enum ChatErrorType: Decodable {
case fileImageSize(filePath: String)
case fileNotReceived(fileId: Int64)
case fileNotApproved(fileId: Int64, unknownServers: [String])
// case xFTPRcvFile
// case xFTPSndFile
case fallbackToSMPProhibited(fileId: Int64)
case inlineFileProhibited(fileId: Int64)
case invalidQuote
@@ -2067,6 +2081,7 @@ public struct AppSettings: Codable, Equatable {
public var androidCallOnLockScreen: AppSettingsLockScreenCalls? = nil
public var iosCallKitEnabled: Bool? = nil
public var iosCallKitCallsInRecents: Bool? = nil
public var oneHandUI: Bool? = nil
public func prepareForExport() -> AppSettings {
var empty = AppSettings()
@@ -2091,6 +2106,7 @@ public struct AppSettings: Codable, Equatable {
if androidCallOnLockScreen != def.androidCallOnLockScreen { empty.androidCallOnLockScreen = androidCallOnLockScreen }
if iosCallKitEnabled != def.iosCallKitEnabled { empty.iosCallKitEnabled = iosCallKitEnabled }
if iosCallKitCallsInRecents != def.iosCallKitCallsInRecents { empty.iosCallKitCallsInRecents = iosCallKitCallsInRecents }
if oneHandUI != def.oneHandUI { empty.oneHandUI = oneHandUI }
return empty
}
@@ -2115,7 +2131,8 @@ public struct AppSettings: Codable, Equatable {
confirmDBUpgrades: false,
androidCallOnLockScreen: AppSettingsLockScreenCalls.show,
iosCallKitEnabled: true,
iosCallKitCallsInRecents: false
iosCallKitCallsInRecents: false,
oneHandUI: false
)
}
}
+70 -8
View File
@@ -1287,6 +1287,15 @@ public enum ChatInfo: Identifiable, Decodable, NamedChat {
}
}
public var chatDeleted: Bool {
get {
switch self {
case let .direct(contact): return contact.chatDeleted
default: return false
}
}
}
public var sendMsgEnabled: Bool {
get {
switch self {
@@ -1504,6 +1513,7 @@ public struct Contact: Identifiable, Decodable, NamedChat {
var chatTs: Date?
var contactGroupMemberId: Int64?
var contactGrpInvSent: Bool
public var chatDeleted: Bool
public var id: ChatId { get { "@\(contactId)" } }
public var apiId: Int64 { get { contactId } }
@@ -1570,13 +1580,15 @@ public struct Contact: Identifiable, Decodable, NamedChat {
mergedPreferences: ContactUserPreferences.sampleData,
createdAt: .now,
updatedAt: .now,
contactGrpInvSent: false
contactGrpInvSent: false,
chatDeleted: false
)
}
public enum ContactStatus: String, Decodable {
case active = "active"
case deleted = "deleted"
case deletedByUser = "deletedByUser"
}
public struct ContactRef: Decodable, Equatable {
@@ -2728,7 +2740,7 @@ public enum CIStatus: Decodable {
case rcvRead
case invalid(text: String)
var id: String {
public var id: String {
switch self {
case .sndNew: return "sndNew"
case .sndSent: return "sndSent"
@@ -2809,11 +2821,19 @@ public enum SndError: Decodable {
}
}
public enum SrvError: Decodable {
public enum SrvError: Decodable, Equatable {
case host
case version
case other(srvError: String)
var id: String {
switch self {
case .host: return "host"
case .version: return "version"
case let .other(srvError): return "other \(srvError)"
}
}
public var errorInfo: String {
switch self {
case .host: NSLocalizedString("Server address is incompatible with network settings.", comment: "srv error text.")
@@ -3171,6 +3191,7 @@ public struct CIFile: Decodable {
case .sndComplete: return true
case .sndCancelled: return true
case .sndError: return true
case .sndWarning: return true
case .rcvInvitation: return false
case .rcvAccepted: return false
case .rcvTransfer: return false
@@ -3178,6 +3199,7 @@ public struct CIFile: Decodable {
case .rcvCancelled: return false
case .rcvComplete: return true
case .rcvError: return false
case .rcvWarning: return false
case .invalid: return false
}
}
@@ -3196,12 +3218,14 @@ public struct CIFile: Decodable {
}
case .sndCancelled: return nil
case .sndError: return nil
case .sndWarning: return sndCancelAction
case .rcvInvitation: return nil
case .rcvAccepted: return rcvCancelAction
case .rcvTransfer: return rcvCancelAction
case .rcvAborted: return nil
case .rcvCancelled: return nil
case .rcvComplete: return nil
case .rcvWarning: return rcvCancelAction
case .rcvError: return nil
case .invalid: return nil
}
@@ -3310,35 +3334,64 @@ public enum CIFileStatus: Decodable, Equatable {
case sndTransfer(sndProgress: Int64, sndTotal: Int64)
case sndComplete
case sndCancelled
case sndError
case sndError(sndFileError: FileError)
case sndWarning(sndFileError: FileError)
case rcvInvitation
case rcvAccepted
case rcvTransfer(rcvProgress: Int64, rcvTotal: Int64)
case rcvAborted
case rcvComplete
case rcvCancelled
case rcvError
case rcvError(rcvFileError: FileError)
case rcvWarning(rcvFileError: FileError)
case invalid(text: String)
var id: String {
public var id: String {
switch self {
case .sndStored: return "sndStored"
case let .sndTransfer(sndProgress, sndTotal): return "sndTransfer \(sndProgress) \(sndTotal)"
case .sndComplete: return "sndComplete"
case .sndCancelled: return "sndCancelled"
case .sndError: return "sndError"
case let .sndError(sndFileError): return "sndError \(sndFileError)"
case let .sndWarning(sndFileError): return "sndWarning \(sndFileError)"
case .rcvInvitation: return "rcvInvitation"
case .rcvAccepted: return "rcvAccepted"
case let .rcvTransfer(rcvProgress, rcvTotal): return "rcvTransfer \(rcvProgress) \(rcvTotal)"
case .rcvAborted: return "rcvAborted"
case .rcvComplete: return "rcvComplete"
case .rcvCancelled: return "rcvCancelled"
case .rcvError: return "rcvError"
case let .rcvError(rcvFileError): return "rcvError \(rcvFileError)"
case let .rcvWarning(rcvFileError): return "rcvWarning \(rcvFileError)"
case .invalid: return "invalid"
}
}
}
public enum FileError: Decodable, Equatable {
case auth
case noFile
case relay(srvError: SrvError)
case other(fileError: String)
var id: String {
switch self {
case .auth: return "auth"
case .noFile: return "noFile"
case let .relay(srvError): return "relay \(srvError)"
case let .other(fileError): return "other \(fileError)"
}
}
public var errorInfo: String {
switch self {
case .auth: NSLocalizedString("Wrong key or unknown file chunk address - most likely file is deleted.", comment: "file error text")
case .noFile: NSLocalizedString("File not found - most likely file was deleted or cancelled.", comment: "file error text")
case let .relay(srvError): String.localizedStringWithFormat(NSLocalizedString("File server error: %@", comment: "file error text"), srvError.errorInfo)
case let .other(fileError): String.localizedStringWithFormat(NSLocalizedString("Error: %@", comment: "file error text"), fileError)
}
}
}
public enum MsgContent: Equatable {
case text(String)
case link(text: String, preview: LinkPreview)
@@ -3397,6 +3450,15 @@ public enum MsgContent: Equatable {
}
}
public var isMediaOrFileAttachment: Bool {
switch self {
case .image: true
case .video: true
case .file: true
default: false
}
}
var cmdString: String {
"json \(encodeJSON(self))"
}
+114 -3
View File
@@ -449,6 +449,9 @@
/* No comment provided by engineer. */
"Allow disappearing messages only if your contact allows it to you." = "Erlauben Sie verschwindende Nachrichten nur dann, wenn es Ihr Kontakt ebenfalls erlaubt.";
/* No comment provided by engineer. */
"Allow downgrade" = "Herabstufung erlauben";
/* No comment provided by engineer. */
"Allow irreversible message deletion only if your contact allows it to you. (24 hours)" = "Erlauben Sie das unwiederbringliche Löschen von Nachrichten nur dann, wenn es Ihnen Ihr Kontakt ebenfalls erlaubt. (24 Stunden)";
@@ -509,6 +512,9 @@
/* pref value */
"always" = "Immer";
/* No comment provided by engineer. */
"Always use private routing." = "Sie nutzen immer privates Routing.";
/* No comment provided by engineer. */
"Always use relay" = "Über ein Relais verbinden";
@@ -716,6 +722,9 @@
/* No comment provided by engineer. */
"Cannot receive file" = "Datei kann nicht empfangen werden";
/* snd error text */
"Capacity exceeded - recipient did not receive previously sent messages." = "Kapazität überschritten - der Empfänger hat die zuvor gesendeten Nachrichten nicht empfangen.";
/* No comment provided by engineer. */
"Cellular" = "Zellulär";
@@ -852,6 +861,9 @@
/* No comment provided by engineer. */
"Confirm database upgrades" = "Datenbank-Aktualisierungen bestätigen";
/* No comment provided by engineer. */
"Confirm files from unknown servers." = "Dateien von unbekannten Servern bestätigen.";
/* No comment provided by engineer. */
"Confirm network settings" = "Bestätigen Sie die Netzwerkeinstellungen";
@@ -1320,6 +1332,9 @@
/* No comment provided by engineer. */
"Desktop devices" = "Desktop-Geräte";
/* snd error text */
"Destination server error: %@" = "Zielserver-Fehler: %@";
/* No comment provided by engineer. */
"Develop" = "Entwicklung";
@@ -1399,7 +1414,13 @@
"Do not send history to new members." = "Den Nachrichtenverlauf nicht an neue Mitglieder senden.";
/* No comment provided by engineer. */
"Do NOT use SimpleX for emergency calls." = "Nutzen Sie SimpleX nicht für Notrufe.";
"Do NOT send messages directly, even if your or destination server does not support private routing." = "Nachrichten werden nicht direkt versendet, selbst wenn Ihr oder der Zielserver kein privates Routing unterstützt.";
/* No comment provided by engineer. */
"Do NOT use private routing." = "Sie nutzen KEIN privates Routing.";
/* No comment provided by engineer. */
"Do NOT use SimpleX for emergency calls." = "SimpleX NICHT für Notrufe nutzen.";
/* No comment provided by engineer. */
"Don't create address" = "Keine Adresse erstellt";
@@ -1839,6 +1860,9 @@
/* No comment provided by engineer. */
"File: %@" = "Datei: %@";
/* No comment provided by engineer. */
"Files" = "Dateien";
/* No comment provided by engineer. */
"Files & media" = "Dateien & Medien";
@@ -1905,6 +1929,12 @@
/* No comment provided by engineer. */
"Forwarded from" = "Weitergeleitet aus";
/* snd error text */
"Forwarding server: %@\nDestination server error: %@" = "Weiterleitungsserver: %1$@\nZielserver Fehler: %2$@";
/* snd error text */
"Forwarding server: %@\nError: %@" = "Weiterleitungsserver: %1$@\nFehler: %2$@";
/* No comment provided by engineer. */
"Found desktop" = "Gefundener Desktop";
@@ -2460,6 +2490,9 @@
/* No comment provided by engineer. */
"Message delivery receipts!" = "Empfangsbestätigungen für Nachrichten!";
/* item status text */
"Message delivery warning" = "Warnung bei der Nachrichtenzustellung";
/* No comment provided by engineer. */
"Message draft" = "Nachrichtenentwurf";
@@ -2475,6 +2508,12 @@
/* notification */
"message received" = "Nachricht empfangen";
/* No comment provided by engineer. */
"Message routing fallback" = "Fallback für das Nachrichten-Routing";
/* No comment provided by engineer. */
"Message routing mode" = "Modus für das Nachrichten-Routing";
/* No comment provided by engineer. */
"Message source remains private." = "Die Nachrichtenquelle bleibt privat.";
@@ -2586,6 +2625,9 @@
/* No comment provided by engineer. */
"Network connection" = "Netzwerkverbindung";
/* snd error text */
"Network issues - message expired after many attempts to send it." = "Netzwerk-Fehler - die Nachricht ist nach vielen Sende-Versuchen abgelaufen.";
/* No comment provided by engineer. */
"Network management" = "Netzwerk-Verwaltung";
@@ -2948,9 +2990,18 @@
/* No comment provided by engineer. */
"Private filenames" = "Neutrale Dateinamen";
/* No comment provided by engineer. */
"Private message routing" = "Privates Nachrichten-Routing";
/* No comment provided by engineer. */
"Private message routing 🚀" = "Privates Nachrichten-Routing 🚀";
/* name of notes to self */
"Private notes" = "Private Notizen";
/* No comment provided by engineer. */
"Private routing" = "Privates Routing";
/* No comment provided by engineer. */
"Profile and server connections" = "Profil und Serververbindungen";
@@ -3002,9 +3053,15 @@
/* No comment provided by engineer. */
"Protect app screen" = "App-Bildschirm schützen";
/* No comment provided by engineer. */
"Protect IP address" = "IP-Adresse schützen";
/* No comment provided by engineer. */
"Protect your chat profiles with a password!" = "Ihre Chat-Profile mit einem Passwort schützen!";
/* No comment provided by engineer. */
"Protect your IP address from the messaging relays chosen by your contacts.\nEnable in *Network & servers* settings." = "Schützen Sie Ihre IP-Adresse vor den Nachrichten-Relais , die Ihre Kontakte ausgewählt haben.\nAktivieren Sie es in den *Netzwerk & Server* Einstellungen.";
/* No comment provided by engineer. */
"Protocol timeout" = "Protokollzeitüberschreitung";
@@ -3230,6 +3287,9 @@
/* No comment provided by engineer. */
"Run chat" = "Chat starten";
/* No comment provided by engineer. */
"Safely receive files" = "Dateien sicher empfangen";
/* No comment provided by engineer. */
"Safer groups" = "Sicherere Gruppen";
@@ -3386,6 +3446,12 @@
/* No comment provided by engineer. */
"Send live message" = "Live Nachricht senden";
/* No comment provided by engineer. */
"Send messages directly when IP address is protected and your or destination server does not support private routing." = "Nachrichten werden direkt versendet, wenn die IP-Adresse geschützt ist, und Ihr oder der Zielserver kein privates Routing unterstützt.";
/* No comment provided by engineer. */
"Send messages directly when your or destination server does not support private routing." = "Nachrichten werden direkt versendet, wenn Ihr oder der Zielserver kein privates Routing unterstützt.";
/* No comment provided by engineer. */
"Send notifications" = "Benachrichtigungen senden";
@@ -3449,6 +3515,9 @@
/* No comment provided by engineer. */
"Sent messages will be deleted after set time." = "Gesendete Nachrichten werden nach der eingestellten Zeit gelöscht.";
/* srv error text. */
"Server address is incompatible with network settings." = "Die Server-Adresse ist nicht mit den Netzwerk-Einstellungen kompatibel.";
/* server test error */
"Server requires authorization to create queues, check password" = "Um Warteschlangen zu erzeugen benötigt der Server eine Authentifizierung. Bitte überprüfen Sie das Passwort";
@@ -3458,6 +3527,9 @@
/* No comment provided by engineer. */
"Server test failed!" = "Server Test ist fehlgeschlagen!";
/* srv error text */
"Server version is incompatible with network settings." = "Die Server-Version ist nicht mit den Netzwerk-Einstellungen kompatibel.";
/* No comment provided by engineer. */
"Servers" = "Server";
@@ -3524,6 +3596,9 @@
/* No comment provided by engineer. */
"Share with contacts" = "Mit Kontakten teilen";
/* No comment provided by engineer. */
"Show → on messages sent via private routing." = "Bei Nachrichten, die über privates Routing versendet wurden, → anzeigen.";
/* No comment provided by engineer. */
"Show calls in phone history" = "Anrufliste anzeigen";
@@ -3533,6 +3608,9 @@
/* No comment provided by engineer. */
"Show last messages" = "Letzte Nachrichten anzeigen";
/* No comment provided by engineer. */
"Show message status" = "Nachrichtenstatus anzeigen";
/* No comment provided by engineer. */
"Show preview" = "Vorschau anzeigen";
@@ -3740,6 +3818,9 @@
/* No comment provided by engineer. */
"The app can notify you when you receive messages or contact requests - please open settings to enable." = "Wenn sie Nachrichten oder Kontaktanfragen empfangen, kann Sie die App benachrichtigen - Um dies zu aktivieren, öffnen Sie bitte die Einstellungen.";
/* No comment provided by engineer. */
"The app will ask to confirm downloads from unknown file servers (except .onion)." = "Die App wird eine Bestätigung bei Downloads von unbekannten Datei-Servern anfordern (außer bei .onion).";
/* No comment provided by engineer. */
"The attempt to change database passphrase was not completed." = "Die Änderung des Datenbank-Passworts konnte nicht abgeschlossen werden.";
@@ -3860,6 +3941,9 @@
/* No comment provided by engineer. */
"To protect your information, turn on SimpleX Lock.\nYou will be prompted to complete authentication before this feature is enabled." = "Um Ihre Informationen zu schützen, schalten Sie die SimpleX-Sperre ein.\nSie werden aufgefordert, die Authentifizierung abzuschließen, bevor diese Funktion aktiviert wird.";
/* No comment provided by engineer. */
"To protect your IP address, private routing uses your SMP servers to deliver messages." = "Zum Schutz Ihrer IP-Adresse, wird für die Nachrichten-Auslieferung privates Routing über Ihre konfigurierten SMP-Server genutzt.";
/* No comment provided by engineer. */
"To record voice message please grant permission to use Microphone." = "Bitte erlauben Sie die Nutzung des Mikrofons, um Sprachnachrichten aufnehmen zu können.";
@@ -3944,6 +4028,12 @@
/* No comment provided by engineer. */
"Unknown error" = "Unbekannter Fehler";
/* No comment provided by engineer. */
"unknown relays" = "Unbekannte Relais";
/* No comment provided by engineer. */
"Unknown servers!" = "Unbekannte Server!";
/* No comment provided by engineer. */
"unknown status" = "unbekannter Gruppenmitglieds-Status";
@@ -3968,6 +4058,9 @@
/* No comment provided by engineer. */
"Unmute" = "Stummschaltung aufheben";
/* No comment provided by engineer. */
"unprotected" = "Ungeschützt";
/* No comment provided by engineer. */
"Unread" = "Ungelesen";
@@ -4020,7 +4113,7 @@
"Use chat" = "Verwenden Sie Chat";
/* No comment provided by engineer. */
"Use current profile" = "Das aktuelle Profil nutzen";
"Use current profile" = "Aktuelles Profil nutzen";
/* No comment provided by engineer. */
"Use for new connections" = "Für neue Verbindungen nutzen";
@@ -4032,11 +4125,17 @@
"Use iOS call interface" = "iOS Anrufschnittstelle nutzen";
/* No comment provided by engineer. */
"Use new incognito profile" = "Ein neues Inkognito-Profil nutzen";
"Use new incognito profile" = "Neues Inkognito-Profil nutzen";
/* No comment provided by engineer. */
"Use only local notifications?" = "Nur lokale Benachrichtigungen nutzen?";
/* No comment provided by engineer. */
"Use private routing with unknown servers when IP address is not protected." = "Sie nutzen privates Routing mit unbekannten Servern, wenn Ihre IP-Adresse nicht geschützt ist.";
/* No comment provided by engineer. */
"Use private routing with unknown servers." = "Sie nutzen privates Routing mit unbekannten Servern.";
/* No comment provided by engineer. */
"Use server" = "Server nutzen";
@@ -4190,6 +4289,9 @@
/* No comment provided by engineer. */
"When connecting audio and video calls." = "Bei der Verbindung über Audio- und Video-Anrufe.";
/* No comment provided by engineer. */
"when IP hidden" = "Wenn die IP-Adresse versteckt ist";
/* No comment provided by engineer. */
"When people request to connect, you can accept or reject it." = "Wenn Personen eine Verbindung anfordern, können Sie diese annehmen oder ablehnen.";
@@ -4214,9 +4316,18 @@
/* No comment provided by engineer. */
"With reduced battery usage." = "Mit reduziertem Akkuverbrauch.";
/* No comment provided by engineer. */
"Without Tor or VPN, your IP address will be visible to file servers." = "Ohne Tor- oder VPN-Nutzung wird Ihre IP-Adresse für Datei-Server sichtbar sein.";
/* No comment provided by engineer. */
"Without Tor or VPN, your IP address will be visible to these XFTP relays: %@." = "Ohne Tor- oder VPN-Nutzung wird Ihre IP-Adresse für diese XFTP-Relais sichtbar sein: %@.";
/* No comment provided by engineer. */
"Wrong database passphrase" = "Falsches Datenbank-Passwort";
/* snd error text */
"Wrong key or unknown connection - most likely this connection is deleted." = "Falscher Schlüssel oder unbekannte Verbindung - höchstwahrscheinlich ist diese Verbindung gelöscht worden.";
/* No comment provided by engineer. */
"Wrong passphrase!" = "Falsches Passwort!";
+113 -2
View File
@@ -449,6 +449,9 @@
/* No comment provided by engineer. */
"Allow disappearing messages only if your contact allows it to you." = "Se permiten los mensajes temporales pero sólo si tu contacto también los permite para tí.";
/* No comment provided by engineer. */
"Allow downgrade" = "Permitir versión anterior";
/* No comment provided by engineer. */
"Allow irreversible message deletion only if your contact allows it to you. (24 hours)" = "Se permite la eliminación irreversible de mensajes pero sólo si tu contacto también la permite para tí. (24 horas)";
@@ -509,6 +512,9 @@
/* pref value */
"always" = "siempre";
/* No comment provided by engineer. */
"Always use private routing." = "Usar siempre enrutamiento privado.";
/* No comment provided by engineer. */
"Always use relay" = "Usar siempre retransmisor";
@@ -716,6 +722,9 @@
/* No comment provided by engineer. */
"Cannot receive file" = "No se puede recibir el archivo";
/* snd error text */
"Capacity exceeded - recipient did not receive previously sent messages." = "Capacidad excedida - el destinatario no ha recibido los mensajes previos.";
/* No comment provided by engineer. */
"Cellular" = "Móvil";
@@ -852,6 +861,9 @@
/* No comment provided by engineer. */
"Confirm database upgrades" = "Confirmar actualizaciones de la bases de datos";
/* No comment provided by engineer. */
"Confirm files from unknown servers." = "Confirma archivos de servidores desconocidos.";
/* No comment provided by engineer. */
"Confirm network settings" = "Confirmar configuración de red";
@@ -1320,6 +1332,9 @@
/* No comment provided by engineer. */
"Desktop devices" = "Ordenadores";
/* snd error text */
"Destination server error: %@" = "Error del servidor de destino: %@";
/* No comment provided by engineer. */
"Develop" = "Desarrollo";
@@ -1398,6 +1413,12 @@
/* No comment provided by engineer. */
"Do not send history to new members." = "No enviar historial a miembros nuevos.";
/* No comment provided by engineer. */
"Do NOT send messages directly, even if your or destination server does not support private routing." = "NO enviar mensajes directamente incluso si tu servidor o el de destino no soportan enrutamiento privado.";
/* No comment provided by engineer. */
"Do NOT use private routing." = "NO usar enrutamiento privado.";
/* No comment provided by engineer. */
"Do NOT use SimpleX for emergency calls." = "NO uses SimpleX para llamadas de emergencia.";
@@ -1839,6 +1860,9 @@
/* No comment provided by engineer. */
"File: %@" = "Archivo: %@";
/* No comment provided by engineer. */
"Files" = "Archivos";
/* No comment provided by engineer. */
"Files & media" = "Archivos y multimedia";
@@ -1905,6 +1929,12 @@
/* No comment provided by engineer. */
"Forwarded from" = "Reenviado por";
/* snd error text */
"Forwarding server: %@\nDestination server error: %@" = "Servidor de reenvío: %1$@\nError del servidor de destino: %2$@";
/* snd error text */
"Forwarding server: %@\nError: %@" = "Servidor de reenvío: %1$@\nError: %2$@";
/* No comment provided by engineer. */
"Found desktop" = "Ordenador encontrado";
@@ -2460,6 +2490,9 @@
/* No comment provided by engineer. */
"Message delivery receipts!" = "¡Confirmación de entrega de mensajes!";
/* item status text */
"Message delivery warning" = "Aviso de entrega de mensaje";
/* No comment provided by engineer. */
"Message draft" = "Borrador de mensaje";
@@ -2475,6 +2508,12 @@
/* notification */
"message received" = "mensaje recibido";
/* No comment provided by engineer. */
"Message routing fallback" = "Enrutamiento de mensajes alternativo";
/* No comment provided by engineer. */
"Message routing mode" = "Modo de enrutamiento de mensajes";
/* No comment provided by engineer. */
"Message source remains private." = "El autor del mensaje se mantiene privado.";
@@ -2586,6 +2625,9 @@
/* No comment provided by engineer. */
"Network connection" = "Conexión de red";
/* snd error text */
"Network issues - message expired after many attempts to send it." = "Problema en la red - el mensaje ha expirado tras muchos intentos de envío.";
/* No comment provided by engineer. */
"Network management" = "Gestión de la red";
@@ -2948,9 +2990,18 @@
/* No comment provided by engineer. */
"Private filenames" = "Nombres de archivos privados";
/* No comment provided by engineer. */
"Private message routing" = "Enrutamiento privado de mensajes";
/* No comment provided by engineer. */
"Private message routing 🚀" = "Enrutamiento privado de mensajes 🚀";
/* name of notes to self */
"Private notes" = "Notas privadas";
/* No comment provided by engineer. */
"Private routing" = "Enrutamiento privado";
/* No comment provided by engineer. */
"Profile and server connections" = "Datos del perfil y conexiones";
@@ -3002,9 +3053,15 @@
/* No comment provided by engineer. */
"Protect app screen" = "Proteger la pantalla de la aplicación";
/* No comment provided by engineer. */
"Protect IP address" = "Proteger dirección IP";
/* No comment provided by engineer. */
"Protect your chat profiles with a password!" = "¡Protege tus perfiles con contraseña!";
/* No comment provided by engineer. */
"Protect your IP address from the messaging relays chosen by your contacts.\nEnable in *Network & servers* settings." = "Protege tu dirección IP de los servidores de retransmisión elegidos por tus contactos.\nActívalo en ajustes de *Servidores y Redes*.";
/* No comment provided by engineer. */
"Protocol timeout" = "Tiempo de espera del protocolo";
@@ -3117,7 +3174,7 @@
"rejected call" = "llamada rechazada";
/* No comment provided by engineer. */
"Relay server is only used if necessary. Another party can observe your IP address." = "El retransmisor sólo se usa en caso de necesidad. Un tercero podría ver tu IP.";
"Relay server is only used if necessary. Another party can observe your IP address." = "El servidor de retransmisión sólo se usa en caso de necesidad. Un tercero podría ver tu IP.";
/* No comment provided by engineer. */
"Relay server protects your IP address, but it can observe the duration of the call." = "El servidor de retransmisión protege tu IP pero puede ver la duración de la llamada.";
@@ -3230,6 +3287,9 @@
/* No comment provided by engineer. */
"Run chat" = "Ejecutar chat";
/* No comment provided by engineer. */
"Safely receive files" = "Recibe archivos de forma segura";
/* No comment provided by engineer. */
"Safer groups" = "Grupos más seguros";
@@ -3375,7 +3435,7 @@
"Send direct message" = "Enviar mensaje directo";
/* No comment provided by engineer. */
"Send direct message to connect" = "Enviar mensaje directo para conectar";
"Send direct message to connect" = "Envia un mensaje para conectar";
/* No comment provided by engineer. */
"Send disappearing message" = "Enviar mensaje temporal";
@@ -3386,6 +3446,12 @@
/* No comment provided by engineer. */
"Send live message" = "Mensaje en vivo";
/* No comment provided by engineer. */
"Send messages directly when IP address is protected and your or destination server does not support private routing." = "Enviar mensajes directamente cuando tu dirección IP está protegida y tu servidor o el de destino no admitan enrutamiento privado.";
/* No comment provided by engineer. */
"Send messages directly when your or destination server does not support private routing." = "Enviar mensajes directamente cuando tu servidor o el de destino no admitan enrutamiento privado.";
/* No comment provided by engineer. */
"Send notifications" = "Enviar notificaciones";
@@ -3449,6 +3515,9 @@
/* No comment provided by engineer. */
"Sent messages will be deleted after set time." = "Los mensajes enviados se eliminarán una vez transcurrido el tiempo establecido.";
/* srv error text. */
"Server address is incompatible with network settings." = "La dirección del servidor es incompatible con la configuración de la red.";
/* server test error */
"Server requires authorization to create queues, check password" = "El servidor requiere autorización para crear colas, comprueba la contraseña";
@@ -3458,6 +3527,9 @@
/* No comment provided by engineer. */
"Server test failed!" = "¡Error en prueba del servidor!";
/* srv error text */
"Server version is incompatible with network settings." = "La versión del servidor es incompatible con la configuración de red.";
/* No comment provided by engineer. */
"Servers" = "Servidores";
@@ -3524,6 +3596,9 @@
/* No comment provided by engineer. */
"Share with contacts" = "Compartir con contactos";
/* No comment provided by engineer. */
"Show → on messages sent via private routing." = "Mostrar → en mensajes con enrutamiento privado.";
/* No comment provided by engineer. */
"Show calls in phone history" = "Mostrar llamadas en el historial del teléfono";
@@ -3533,6 +3608,9 @@
/* No comment provided by engineer. */
"Show last messages" = "Mostrar último mensaje";
/* No comment provided by engineer. */
"Show message status" = "Estado del mensaje";
/* No comment provided by engineer. */
"Show preview" = "Mostrar vista previa";
@@ -3740,6 +3818,9 @@
/* No comment provided by engineer. */
"The app can notify you when you receive messages or contact requests - please open settings to enable." = "La aplicación puede notificarte cuando recibas mensajes o solicitudes de contacto: por favor, abre la configuración para activarlo.";
/* No comment provided by engineer. */
"The app will ask to confirm downloads from unknown file servers (except .onion)." = "La aplicación pedirá que confirmes las descargas desde servidores de archivos desconocidos (excepto .onion).";
/* No comment provided by engineer. */
"The attempt to change database passphrase was not completed." = "El intento de cambiar la contraseña de la base de datos no se ha completado.";
@@ -3860,6 +3941,9 @@
/* No comment provided by engineer. */
"To protect your information, turn on SimpleX Lock.\nYou will be prompted to complete authentication before this feature is enabled." = "Para proteger tu información, activa el Bloqueo SimpleX.\nSe te pedirá que completes la autenticación antes de activar esta función.";
/* No comment provided by engineer. */
"To protect your IP address, private routing uses your SMP servers to deliver messages." = "Para proteger tu dirección IP, el enrutamiento privado usa tus servidores SMP para enviar mensajes.";
/* No comment provided by engineer. */
"To record voice message please grant permission to use Microphone." = "Para grabar el mensaje de voz concede permiso para usar el micrófono.";
@@ -3944,6 +4028,12 @@
/* No comment provided by engineer. */
"Unknown error" = "Error desconocido";
/* No comment provided by engineer. */
"unknown relays" = "servidor de retransmisión desconocido";
/* No comment provided by engineer. */
"Unknown servers!" = "¡Servidores desconocidos!";
/* No comment provided by engineer. */
"unknown status" = "estado desconocido";
@@ -3968,6 +4058,9 @@
/* No comment provided by engineer. */
"Unmute" = "Activar audio";
/* No comment provided by engineer. */
"unprotected" = "desprotegido";
/* No comment provided by engineer. */
"Unread" = "No leído";
@@ -4037,6 +4130,12 @@
/* No comment provided by engineer. */
"Use only local notifications?" = "¿Usar sólo notificaciones locales?";
/* No comment provided by engineer. */
"Use private routing with unknown servers when IP address is not protected." = "Usar enrutamiento privado con servidores desconocidos cuando la dirección IP no está protegida.";
/* No comment provided by engineer. */
"Use private routing with unknown servers." = "Usar enrutamiento privado con servidores desconocidos.";
/* No comment provided by engineer. */
"Use server" = "Usar servidor";
@@ -4190,6 +4289,9 @@
/* No comment provided by engineer. */
"When connecting audio and video calls." = "Al iniciar llamadas de audio y vídeo.";
/* No comment provided by engineer. */
"when IP hidden" = "con IP oculta";
/* No comment provided by engineer. */
"When people request to connect, you can accept or reject it." = "Cuando alguien solicite conectarse podrás aceptar o rechazar la solicitud.";
@@ -4214,9 +4316,18 @@
/* No comment provided by engineer. */
"With reduced battery usage." = "Con uso reducido de batería.";
/* No comment provided by engineer. */
"Without Tor or VPN, your IP address will be visible to file servers." = "Sin Tor o VPN, tu dirección IP será visible para los servidores de archivos.";
/* No comment provided by engineer. */
"Without Tor or VPN, your IP address will be visible to these XFTP relays: %@." = "Sin Tor o VPN, tu dirección IP será visible para estos servidores XFTP: %@.";
/* No comment provided by engineer. */
"Wrong database passphrase" = "Contraseña de base de datos incorrecta";
/* snd error text */
"Wrong key or unknown connection - most likely this connection is deleted." = "Clave incorrecta o conexión desconocida - probablemente esta conexión fue eliminada.";
/* No comment provided by engineer. */
"Wrong passphrase!" = "¡Contraseña incorrecta!";
+111
View File
@@ -449,6 +449,9 @@
/* No comment provided by engineer. */
"Allow disappearing messages only if your contact allows it to you." = "Autorise les messages éphémères seulement si votre contact vous lautorise.";
/* No comment provided by engineer. */
"Allow downgrade" = "Autoriser la rétrogradation";
/* No comment provided by engineer. */
"Allow irreversible message deletion only if your contact allows it to you. (24 hours)" = "Autoriser la suppression irréversible des messages uniquement si votre contact vous l'autorise. (24 heures)";
@@ -509,6 +512,9 @@
/* pref value */
"always" = "toujours";
/* No comment provided by engineer. */
"Always use private routing." = "Toujours utiliser le routage privé.";
/* No comment provided by engineer. */
"Always use relay" = "Se connecter via relais";
@@ -716,6 +722,9 @@
/* No comment provided by engineer. */
"Cannot receive file" = "Impossible de recevoir le fichier";
/* snd error text */
"Capacity exceeded - recipient did not receive previously sent messages." = "Capacité dépassée - le destinataire n'a pas pu recevoir les messages envoyés précédemment.";
/* No comment provided by engineer. */
"Cellular" = "Cellulaire";
@@ -852,6 +861,9 @@
/* No comment provided by engineer. */
"Confirm database upgrades" = "Confirmer la mise à niveau de la base de données";
/* No comment provided by engineer. */
"Confirm files from unknown servers." = "Confirmer les fichiers provenant de serveurs inconnus.";
/* No comment provided by engineer. */
"Confirm network settings" = "Confirmer les paramètres réseau";
@@ -1320,6 +1332,9 @@
/* No comment provided by engineer. */
"Desktop devices" = "Appareils de bureau";
/* snd error text */
"Destination server error: %@" = "Erreur du serveur de destination: %@";
/* No comment provided by engineer. */
"Develop" = "Développer";
@@ -1398,6 +1413,12 @@
/* No comment provided by engineer. */
"Do not send history to new members." = "Ne pas envoyer d'historique aux nouveaux membres.";
/* No comment provided by engineer. */
"Do NOT send messages directly, even if your or destination server does not support private routing." = "Ne pas envoyer de messages directement, même si votre serveur ou le serveur de destination ne prend pas en charge le routage privé.";
/* No comment provided by engineer. */
"Do NOT use private routing." = "Ne pas utiliser de routage privé.";
/* No comment provided by engineer. */
"Do NOT use SimpleX for emergency calls." = "N'utilisez PAS SimpleX pour les appels d'urgence.";
@@ -1839,6 +1860,9 @@
/* No comment provided by engineer. */
"File: %@" = "Fichier: %@";
/* No comment provided by engineer. */
"Files" = "Fichiers";
/* No comment provided by engineer. */
"Files & media" = "Fichiers & médias";
@@ -1905,6 +1929,12 @@
/* No comment provided by engineer. */
"Forwarded from" = "Transféré depuis";
/* snd error text */
"Forwarding server: %@\nDestination server error: %@" = "Serveur de transfert: %1$@\nErreur du serveur de destination: %2$@";
/* snd error text */
"Forwarding server: %@\nError: %@" = "Serveur de transfert: %1$@\nErreur: %2$@";
/* No comment provided by engineer. */
"Found desktop" = "Bureau trouvé";
@@ -2460,6 +2490,9 @@
/* No comment provided by engineer. */
"Message delivery receipts!" = "Accusés de réception des messages !";
/* item status text */
"Message delivery warning" = "Avertissement sur la distribution des messages";
/* No comment provided by engineer. */
"Message draft" = "Brouillon de message";
@@ -2475,6 +2508,12 @@
/* notification */
"message received" = "message reçu";
/* No comment provided by engineer. */
"Message routing fallback" = "Rabattement du routage des messages";
/* No comment provided by engineer. */
"Message routing mode" = "Mode de routage des messages";
/* No comment provided by engineer. */
"Message source remains private." = "La source du message reste privée.";
@@ -2586,6 +2625,9 @@
/* No comment provided by engineer. */
"Network connection" = "Connexion au réseau";
/* snd error text */
"Network issues - message expired after many attempts to send it." = "Problèmes de réseau - le message a expiré après plusieurs tentatives d'envoi.";
/* No comment provided by engineer. */
"Network management" = "Gestion du réseau";
@@ -2948,9 +2990,18 @@
/* No comment provided by engineer. */
"Private filenames" = "Noms de fichiers privés";
/* No comment provided by engineer. */
"Private message routing" = "Routage privé des messages";
/* No comment provided by engineer. */
"Private message routing 🚀" = "Routage privé des messages 🚀";
/* name of notes to self */
"Private notes" = "Notes privées";
/* No comment provided by engineer. */
"Private routing" = "Routage privé";
/* No comment provided by engineer. */
"Profile and server connections" = "Profil et connexions au serveur";
@@ -3002,9 +3053,15 @@
/* No comment provided by engineer. */
"Protect app screen" = "Protéger l'écran de l'app";
/* No comment provided by engineer. */
"Protect IP address" = "Protéger l'adresse IP";
/* No comment provided by engineer. */
"Protect your chat profiles with a password!" = "Protégez vos profils de chat par un mot de passe !";
/* No comment provided by engineer. */
"Protect your IP address from the messaging relays chosen by your contacts.\nEnable in *Network & servers* settings." = "Protégez votre adresse IP des relais de messagerie choisis par vos contacts.\nActivez-le dans les paramètres *Réseau et serveurs*.";
/* No comment provided by engineer. */
"Protocol timeout" = "Délai du protocole";
@@ -3230,6 +3287,9 @@
/* No comment provided by engineer. */
"Run chat" = "Exécuter le chat";
/* No comment provided by engineer. */
"Safely receive files" = "Réception de fichiers en toute sécurité";
/* No comment provided by engineer. */
"Safer groups" = "Groupes plus sûrs";
@@ -3386,6 +3446,12 @@
/* No comment provided by engineer. */
"Send live message" = "Envoyer un message dynamique";
/* No comment provided by engineer. */
"Send messages directly when IP address is protected and your or destination server does not support private routing." = "Envoyer les messages de manière directe lorsque l'adresse IP est protégée et que votre serveur ou le serveur de destination ne prend pas en charge le routage privé.";
/* No comment provided by engineer. */
"Send messages directly when your or destination server does not support private routing." = "Envoyez les messages de manière directe lorsque votre serveur ou le serveur de destination ne prend pas en charge le routage privé.";
/* No comment provided by engineer. */
"Send notifications" = "Envoi de notifications";
@@ -3449,6 +3515,9 @@
/* No comment provided by engineer. */
"Sent messages will be deleted after set time." = "Les messages envoyés seront supprimés après une durée déterminée.";
/* srv error text. */
"Server address is incompatible with network settings." = "L'adresse du serveur est incompatible avec les paramètres du réseau.";
/* server test error */
"Server requires authorization to create queues, check password" = "Le serveur requiert une autorisation pour créer des files d'attente, vérifiez le mot de passe";
@@ -3458,6 +3527,9 @@
/* No comment provided by engineer. */
"Server test failed!" = "Échec du test du serveur !";
/* srv error text */
"Server version is incompatible with network settings." = "La version du serveur est incompatible avec les paramètres du réseau.";
/* No comment provided by engineer. */
"Servers" = "Serveurs";
@@ -3524,6 +3596,9 @@
/* No comment provided by engineer. */
"Share with contacts" = "Partager avec vos contacts";
/* No comment provided by engineer. */
"Show → on messages sent via private routing." = "Afficher → sur les messages envoyés via le routage privé.";
/* No comment provided by engineer. */
"Show calls in phone history" = "Afficher les appels dans l'historique du téléphone";
@@ -3533,6 +3608,9 @@
/* No comment provided by engineer. */
"Show last messages" = "Voir les derniers messages";
/* No comment provided by engineer. */
"Show message status" = "Afficher le statut du message";
/* No comment provided by engineer. */
"Show preview" = "Afficher l'aperçu";
@@ -3740,6 +3818,9 @@
/* No comment provided by engineer. */
"The app can notify you when you receive messages or contact requests - please open settings to enable." = "L'application peut vous avertir lorsque vous recevez des messages ou des demandes de contact - veuillez ouvrir les paramètres pour les activer.";
/* No comment provided by engineer. */
"The app will ask to confirm downloads from unknown file servers (except .onion)." = "L'application demandera de confirmer les téléchargements à partir de serveurs de fichiers inconnus (sauf .onion).";
/* No comment provided by engineer. */
"The attempt to change database passphrase was not completed." = "La tentative de modification de la phrase secrète de la base de données n'a pas abouti.";
@@ -3860,6 +3941,9 @@
/* No comment provided by engineer. */
"To protect your information, turn on SimpleX Lock.\nYou will be prompted to complete authentication before this feature is enabled." = "Pour protéger vos informations, activez la fonction SimpleX Lock.\nVous serez invité à confirmer l'authentification avant que cette fonction ne soit activée.";
/* No comment provided by engineer. */
"To protect your IP address, private routing uses your SMP servers to deliver messages." = "Pour protéger votre adresse IP, le routage privé utilise vos serveurs SMP pour délivrer les messages.";
/* No comment provided by engineer. */
"To record voice message please grant permission to use Microphone." = "Pour enregistrer un message vocal, veuillez accorder la permission d'utiliser le microphone.";
@@ -3944,6 +4028,12 @@
/* No comment provided by engineer. */
"Unknown error" = "Erreur inconnue";
/* No comment provided by engineer. */
"unknown relays" = "relais inconnus";
/* No comment provided by engineer. */
"Unknown servers!" = "Serveurs inconnus!";
/* No comment provided by engineer. */
"unknown status" = "statut inconnu";
@@ -3968,6 +4058,9 @@
/* No comment provided by engineer. */
"Unmute" = "Démute";
/* No comment provided by engineer. */
"unprotected" = "non protégé";
/* No comment provided by engineer. */
"Unread" = "Non lu";
@@ -4037,6 +4130,12 @@
/* No comment provided by engineer. */
"Use only local notifications?" = "Utilisation de notifications locales uniquement?";
/* No comment provided by engineer. */
"Use private routing with unknown servers when IP address is not protected." = "Utiliser le routage privé avec des serveurs inconnus lorsque l'adresse IP n'est pas protégée.";
/* No comment provided by engineer. */
"Use private routing with unknown servers." = "Utiliser le routage privé avec des serveurs inconnus.";
/* No comment provided by engineer. */
"Use server" = "Utiliser ce serveur";
@@ -4190,6 +4289,9 @@
/* No comment provided by engineer. */
"When connecting audio and video calls." = "Lors des appels audio et vidéo.";
/* No comment provided by engineer. */
"when IP hidden" = "lorsque l'IP est masquée";
/* No comment provided by engineer. */
"When people request to connect, you can accept or reject it." = "Vous pouvez accepter ou refuser les demandes de contacts.";
@@ -4214,9 +4316,18 @@
/* No comment provided by engineer. */
"With reduced battery usage." = "Consommation réduite de la batterie.";
/* No comment provided by engineer. */
"Without Tor or VPN, your IP address will be visible to file servers." = "Sans Tor ou un VPN, votre adresse IP sera visible par les serveurs de fichiers.";
/* No comment provided by engineer. */
"Without Tor or VPN, your IP address will be visible to these XFTP relays: %@." = "Sans Tor ni VPN, votre adresse IP sera visible par ces relais XFTP: %@.";
/* No comment provided by engineer. */
"Wrong database passphrase" = "Mauvaise phrase secrète pour la base de données";
/* snd error text */
"Wrong key or unknown connection - most likely this connection is deleted." = "Clé erronée ou connexion non identifiée - il est très probable que cette connexion soit supprimée.";
/* No comment provided by engineer. */
"Wrong passphrase!" = "Mauvaise phrase secrète !";
+124 -13
View File
@@ -83,7 +83,7 @@
"**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." = "**Privátabb**: 20 percenként ellenőrzi az új üzeneteket. Az eszköztoken megosztásra kerül a SimpleX Chat kiszolgálóval, de az nem, hogy hány ismerőse vagy üzenete van.";
/* No comment provided by engineer. */
"**Most private**: do not use SimpleX Chat notifications server, check messages periodically in the background (depends on how often you use the app)." = "**Legprivátabb**: ne használja a SimpleX Chat értesítési szervert, rendszeresen ellenőrizze az üzeneteket a háttérben (attól függően, hogy milyen gyakran használja az alkalmazást).";
"**Most private**: do not use SimpleX Chat notifications server, check messages periodically in the background (depends on how often you use the app)." = "**Legprivátabb**: ne használja a SimpleX Chat értesítési kiszolgálót, rendszeresen ellenőrizze az üzeneteket a háttérben (attól függően, hogy milyen gyakran használja az alkalmazást).";
/* No comment provided by engineer. */
"**Please note**: using the same database on two devices will break the decryption of messages from your connections, as a security protection." = "**Megjegyzés**: ha két eszközön is ugyanazt az adatbázist használja, akkor biztonsági védelemként megszakítja a kapcsolataiból érkező üzenetek visszafejtését.";
@@ -92,7 +92,7 @@
"**Please note**: you will NOT be able to recover or change passphrase if you lose it." = "**Figyelem**: NEM tudja visszaállítani vagy megváltoztatni jelmondatát, ha elveszíti azt.";
/* No comment provided by engineer. */
"**Recommended**: device token and notifications are sent to SimpleX Chat notification server, but not the message content, size or who it is from." = "**Javasolt**: az eszköztoken és az értesítések elküldésre kerülnek a SimpleX Chat értesítési szerverre, kivéve az üzenet tartalma, mérete vagy az, hogy kitől származik.";
"**Recommended**: device token and notifications are sent to SimpleX Chat notification server, but not the message content, size or who it is from." = "**Javasolt**: az eszköztoken és az értesítések elküldésre kerülnek a SimpleX Chat értesítési kiszolgálóra, kivéve az üzenet tartalma, mérete vagy az, hogy kitől származik.";
/* No comment provided by engineer. */
"**Warning**: Instant push notifications require passphrase saved in Keychain." = "**Figyelmeztetés**: Az azonnali push-értesítésekhez a kulcstárolóban tárolt jelmondat megadása szükséges.";
@@ -449,6 +449,9 @@
/* No comment provided by engineer. */
"Allow disappearing messages only if your contact allows it to you." = "Az eltűnő üzenetek küldése kizárólag abban az esetben van engedélyezve, ha az ismerőse is engedélyezi az ön számára.";
/* No comment provided by engineer. */
"Allow downgrade" = "Korábbi verzióra történő visszatérés engedélyezése";
/* No comment provided by engineer. */
"Allow irreversible message deletion only if your contact allows it to you. (24 hours)" = "Az üzenetek végleges törlése kizárólag abban az esetben van engedélyezve, ha az ismerőse is engedélyezi. (24 óra)";
@@ -509,6 +512,9 @@
/* pref value */
"always" = "mindig";
/* No comment provided by engineer. */
"Always use private routing." = "Mindig használjon privát útválasztást.";
/* No comment provided by engineer. */
"Always use relay" = "Mindig használjon átjátszó kiszolgálót";
@@ -716,6 +722,9 @@
/* No comment provided by engineer. */
"Cannot receive file" = "Nem lehet fogadni a fájlt";
/* snd error text */
"Capacity exceeded - recipient did not receive previously sent messages." = "Kapacitás túllépés - a címzett nem kapta meg a korábban elküldött üzeneteket.";
/* No comment provided by engineer. */
"Cellular" = "Mobilhálózat";
@@ -805,7 +814,7 @@
"Chinese and Spanish interface" = "Kínai és spanyol kezelőfelület";
/* No comment provided by engineer. */
"Choose _Migrate from another device_ on the new device and scan QR code." = "Válassza az _Átköltöztetés egy másik eszközről_ opciót az új eszközön és szkennelje be a QR-kódot.";
"Choose _Migrate from another device_ on the new device and scan QR code." = "Válassza az _Átköltöztetés egy másik eszközről_ opciót az új eszközön és olvassa be a QR-kódot.";
/* No comment provided by engineer. */
"Choose file" = "Fájl kiválasztása";
@@ -817,13 +826,13 @@
"Clear" = "Kiürítés";
/* No comment provided by engineer. */
"Clear conversation" = "Beszélgetés kiürítése";
"Clear conversation" = "Üzenetek kiürítése";
/* No comment provided by engineer. */
"Clear conversation?" = "Beszélgetés kiürítése?";
"Clear conversation?" = "Üzenetek kiürítése?";
/* No comment provided by engineer. */
"Clear private notes?" = "Privát jegyzetek törlése?";
"Clear private notes?" = "Privát jegyzetek kiürítése?";
/* No comment provided by engineer. */
"Clear verification" = "Hitelesítés törlése";
@@ -852,6 +861,9 @@
/* No comment provided by engineer. */
"Confirm database upgrades" = "Adatbázis frissítés megerősítése";
/* No comment provided by engineer. */
"Confirm files from unknown servers." = "Ismeretlen kiszolgálókról származó fájlok jóváhagyása.";
/* No comment provided by engineer. */
"Confirm network settings" = "Hálózati beállítások megerősítése";
@@ -1320,6 +1332,9 @@
/* No comment provided by engineer. */
"Desktop devices" = "Számítógépek";
/* snd error text */
"Destination server error: %@" = "Célkiszolgáló hiba: %@";
/* No comment provided by engineer. */
"Develop" = "Fejlesztés";
@@ -1398,6 +1413,12 @@
/* No comment provided by engineer. */
"Do not send history to new members." = "Az előzmények ne kerüljenek elküldésre az új tagok számára.";
/* No comment provided by engineer. */
"Do NOT send messages directly, even if your or destination server does not support private routing." = "Ne küldjön üzeneteket közvetlenül, még akkor sem, ha az ön kiszolgálója vagy a célkiszolgáló nem támogatja a privát útválasztást.";
/* No comment provided by engineer. */
"Do NOT use private routing." = "Ne használjon privát útválasztást.";
/* No comment provided by engineer. */
"Do NOT use SimpleX for emergency calls." = "NE használja a SimpleX-et segélyhívásokhoz.";
@@ -1839,6 +1860,9 @@
/* No comment provided by engineer. */
"File: %@" = "Fájl: %@";
/* No comment provided by engineer. */
"Files" = "Fájlok";
/* No comment provided by engineer. */
"Files & media" = "Fájlok és média";
@@ -1905,6 +1929,12 @@
/* No comment provided by engineer. */
"Forwarded from" = "Továbbítva innen:";
/* snd error text */
"Forwarding server: %@\nDestination server error: %@" = "Továbbító kiszolgáló: %1$@\nCélkiszolgáló hiba:%2$@";
/* snd error text */
"Forwarding server: %@\nError: %@" = "Továbbító kiszolgáló: %1$@\nHiba: %2$@";
/* No comment provided by engineer. */
"Found desktop" = "Megtalált számítógép";
@@ -2407,7 +2437,7 @@
"Make profile private!" = "Tegye priváttá a profilját!";
/* No comment provided by engineer. */
"Make sure %@ server addresses are in correct format, line separated and are not duplicated (%@)." = "Győződjön meg arról, hogy a %@ szervercímek megfelelő formátumúak, sorszeparáltak és nem duplikáltak (%@).";
"Make sure %@ server addresses are in correct format, line separated and are not duplicated (%@)." = "Győződjön meg arról, hogy a %@ kiszolgálócímek megfelelő formátumúak, sorszeparáltak és nem duplikáltak (%@).";
/* No comment provided by engineer. */
"Make sure WebRTC ICE server addresses are in correct format, line separated and are not duplicated." = "Győződjön meg arról, hogy a WebRTC ICE-kiszolgáló címei megfelelő formátumúak, sorszeparáltak és nem duplikáltak.";
@@ -2419,7 +2449,7 @@
"Mark deleted for everyone" = "Jelölje meg mindenki számára töröltként";
/* No comment provided by engineer. */
"Mark read" = "Olvasottként jelölés";
"Mark read" = "Olvasottnak jelölés";
/* No comment provided by engineer. */
"Mark verified" = "Hitelesítés";
@@ -2460,6 +2490,9 @@
/* No comment provided by engineer. */
"Message delivery receipts!" = "Üzenetkézbesítési bizonylatok!";
/* item status text */
"Message delivery warning" = "Üzenet kézbesítési figyelmeztetés";
/* No comment provided by engineer. */
"Message draft" = "Üzenetvázlat";
@@ -2475,6 +2508,12 @@
/* notification */
"message received" = "üzenet érkezett";
/* No comment provided by engineer. */
"Message routing fallback" = "Üzenet útválasztási tartalék";
/* No comment provided by engineer. */
"Message routing mode" = "Üzenet útválasztási mód";
/* No comment provided by engineer. */
"Message source remains private." = "Az üzenet forrása titokban marad.";
@@ -2494,10 +2533,10 @@
"Messages from %@ will be shown!" = "A(z) %@ által írt üzenetek megjelennek!";
/* No comment provided by engineer. */
"Messages, files and calls are protected by **end-to-end encryption** with perfect forward secrecy, repudiation and break-in recovery." = "Az üzeneteket, fájlokat és hívásokat **végpontok közötti titkosítással** és sérülés utáni titkosságvédelemmel, visszautasítással és sérülés utáni helyreállítással védi.";
"Messages, files and calls are protected by **end-to-end encryption** with perfect forward secrecy, repudiation and break-in recovery." = "Az üzeneteket, fájlokat és hívásokat **végpontok közötti titkosítással**, sérülés utáni titkosság-védelemmel és -helyreállítással, továbbá visszautasítással védi.";
/* No comment provided by engineer. */
"Messages, files and calls are protected by **quantum resistant e2e encryption** with perfect forward secrecy, repudiation and break-in recovery." = "Az üzeneteket, fájlokat és hívásokat **végpontok közötti kvantumrezisztens titkosítással** és sérülés utáni titkosságvédelemmel, visszautasítással és sérülés utáni helyreállítással védi.";
"Messages, files and calls are protected by **quantum resistant e2e encryption** with perfect forward secrecy, repudiation and break-in recovery." = "Az üzeneteket, fájlokat és hívásokat **végpontok közötti kvantumrezisztens titkosítással**, sérülés utáni titkosság-védelemmel és -helyreállítással, továbbá visszautasítással védi.";
/* No comment provided by engineer. */
"Migrate device" = "Eszköz átköltöztetése";
@@ -2586,6 +2625,9 @@
/* No comment provided by engineer. */
"Network connection" = "Internetkapcsolat";
/* snd error text */
"Network issues - message expired after many attempts to send it." = "Hálózati problémák - az üzenet többszöri elküldési kísérlet után lejárt.";
/* No comment provided by engineer. */
"Network management" = "Hálózatkezelés";
@@ -2948,9 +2990,18 @@
/* No comment provided by engineer. */
"Private filenames" = "Privát fájl nevek";
/* No comment provided by engineer. */
"Private message routing" = "Privát üzenet útválasztás";
/* No comment provided by engineer. */
"Private message routing 🚀" = "Privát üzenet útválasztás 🚀";
/* name of notes to self */
"Private notes" = "Privát jegyzetek";
/* No comment provided by engineer. */
"Private routing" = "Privát útválasztás";
/* No comment provided by engineer. */
"Profile and server connections" = "Profil és kiszolgálókapcsolatok";
@@ -3002,9 +3053,15 @@
/* No comment provided by engineer. */
"Protect app screen" = "Alkalmazás képernyőjének védelme";
/* No comment provided by engineer. */
"Protect IP address" = "Az IP-cím védelme";
/* No comment provided by engineer. */
"Protect your chat profiles with a password!" = "Csevegési profiljok védelme jelszóval!";
/* No comment provided by engineer. */
"Protect your IP address from the messaging relays chosen by your contacts.\nEnable in *Network & servers* settings." = "Védje IP-címét az ismerősei által kiválasztott üzenetküldő átjátszókkal szemben.\nEngedélyezze a beállításokban a *Hálózat és kiszolgálók* menüpontban.";
/* No comment provided by engineer. */
"Protocol timeout" = "Protokoll időtúllépés";
@@ -3230,6 +3287,9 @@
/* No comment provided by engineer. */
"Run chat" = "Csevegési szolgáltatás indítása";
/* No comment provided by engineer. */
"Safely receive files" = "Fájlok biztonságos fogadása";
/* No comment provided by engineer. */
"Safer groups" = "Biztonságosabb csoportok";
@@ -3386,6 +3446,12 @@
/* No comment provided by engineer. */
"Send live message" = "Élő üzenet küldése";
/* No comment provided by engineer. */
"Send messages directly when IP address is protected and your or destination server does not support private routing." = "Közvetlen üzenetküldés, ha az IP-cím védett és az ön kiszolgálója vagy a célkiszolgáló nem támogatja a privát útválasztást.";
/* No comment provided by engineer. */
"Send messages directly when your or destination server does not support private routing." = "Közvetlen üzenetküldés, ha az ön kiszolgálója vagy a célkiszolgáló nem támogatja a privát útválasztást.";
/* No comment provided by engineer. */
"Send notifications" = "Értesítések küldése";
@@ -3449,6 +3515,9 @@
/* No comment provided by engineer. */
"Sent messages will be deleted after set time." = "Az elküldött üzenetek törlésre kerülnek a beállított idő után.";
/* srv error text. */
"Server address is incompatible with network settings." = "A kiszolgáló címe nem kompatibilis a hálózati beállításokkal.";
/* server test error */
"Server requires authorization to create queues, check password" = "A kiszolgálónak engedélyre van szüksége a várólisták létrehozásához, ellenőrizze jelszavát";
@@ -3458,6 +3527,9 @@
/* No comment provided by engineer. */
"Server test failed!" = "Sikertelen kiszolgáló-teszt!";
/* srv error text */
"Server version is incompatible with network settings." = "A kiszolgáló verziója nem kompatibilis a hálózati beállításokkal.";
/* No comment provided by engineer. */
"Servers" = "Kiszolgálók";
@@ -3524,6 +3596,9 @@
/* No comment provided by engineer. */
"Share with contacts" = "Megosztás ismerősökkel";
/* No comment provided by engineer. */
"Show → on messages sent via private routing." = "Egy „→” jel megjelenítése a privát útválasztáson keresztül küldött üzeneteknél.";
/* No comment provided by engineer. */
"Show calls in phone history" = "Hívások megjelenítése a híváslistában";
@@ -3533,6 +3608,9 @@
/* No comment provided by engineer. */
"Show last messages" = "Utolsó üzenetek megjelenítése";
/* No comment provided by engineer. */
"Show message status" = "Üzenet állapot megjelenítése";
/* No comment provided by engineer. */
"Show preview" = "Előnézet megjelenítése";
@@ -3740,6 +3818,9 @@
/* No comment provided by engineer. */
"The app can notify you when you receive messages or contact requests - please open settings to enable." = "Az alkalmazás értesíteni fogja, amikor üzeneteket vagy kapcsolatfelvételi kéréseket kap beállítások megnyitása az engedélyezéshez.";
/* No comment provided by engineer. */
"The app will ask to confirm downloads from unknown file servers (except .onion)." = "Az alkalmazás kérni fogja az ismeretlen fájlkiszolgálókról (kivéve .onion) történő letöltések megerősítését.";
/* No comment provided by engineer. */
"The attempt to change database passphrase was not completed." = "Az adatbázis jelmondatának megváltoztatására tett kísérlet nem fejeződött be.";
@@ -3860,6 +3941,9 @@
/* No comment provided by engineer. */
"To protect your information, turn on SimpleX Lock.\nYou will be prompted to complete authentication before this feature is enabled." = "Az adatavédelem érdekében kapcsolja be a SimpleX zárolás funkciót.\nA funkció engedélyezése előtt a rendszer felszólítja a hitelesítés befejezésére.";
/* No comment provided by engineer. */
"To protect your IP address, private routing uses your SMP servers to deliver messages." = "Az IP-címe védelme érdekében a privát útválasztás az SMP-kiszolgálókat használja az üzenetek kézbesítéséhez.";
/* No comment provided by engineer. */
"To record voice message please grant permission to use Microphone." = "Hangüzenet rögzítéséhez adjon engedélyt a mikrofon használathoz.";
@@ -3870,7 +3954,7 @@
"To support instant push notifications the chat database has to be migrated." = "Az azonnali push értesítések támogatásához a csevegési adatbázis migrálása szükséges.";
/* No comment provided by engineer. */
"To verify end-to-end encryption with your contact compare (or scan) the code on your devices." = "A végpontok közötti titkosítás ellenőrzéséhez ismerősével hasonlítsa össze (vagy szkennelje be) az eszközén lévő kódot.";
"To verify end-to-end encryption with your contact compare (or scan) the code on your devices." = "A végpontok közötti titkosítás ellenőrzéséhez hasonlítsa össze (vagy olvassa be a QR-kódot) az ismerőse eszközén lévő kóddal.";
/* No comment provided by engineer. */
"Toggle incognito when connecting." = "Inkognitó mód kapcsolódáskor.";
@@ -3944,6 +4028,12 @@
/* No comment provided by engineer. */
"Unknown error" = "Ismeretlen hiba";
/* No comment provided by engineer. */
"unknown relays" = "ismeretlen átjátszók";
/* No comment provided by engineer. */
"Unknown servers!" = "Ismeretlen kiszolgálók!";
/* No comment provided by engineer. */
"unknown status" = "ismeretlen státusz";
@@ -3968,6 +4058,9 @@
/* No comment provided by engineer. */
"Unmute" = "Némítás feloldása";
/* No comment provided by engineer. */
"unprotected" = "nem védett";
/* No comment provided by engineer. */
"Unread" = "Olvasatlan";
@@ -3996,7 +4089,7 @@
"updated profile" = "frissített profil";
/* No comment provided by engineer. */
"Updating settings will re-connect the client to all servers." = "A beállítások frissítése a szerverekhez újra kapcsolódással jár.";
"Updating settings will re-connect the client to all servers." = "A beállítások frissítése a kiszolgálókhoz való újra kapcsolódással jár.";
/* No comment provided by engineer. */
"Updating this setting will re-connect the client to all servers." = "A beállítás frissítésével a kliens újrakapcsolódik az összes kiszolgálóhoz.";
@@ -4037,6 +4130,12 @@
/* No comment provided by engineer. */
"Use only local notifications?" = "Csak helyi értesítések használata?";
/* No comment provided by engineer. */
"Use private routing with unknown servers when IP address is not protected." = "Privát útválasztás használata ismeretlen kiszolgálókkal, ha az IP-cím nem védett.";
/* No comment provided by engineer. */
"Use private routing with unknown servers." = "Használjon privát útválasztást ismeretlen kiszolgálókkal.";
/* No comment provided by engineer. */
"Use server" = "Kiszolgáló használata";
@@ -4190,6 +4289,9 @@
/* No comment provided by engineer. */
"When connecting audio and video calls." = "Amikor egy bejövő hang- vagy videóhívás érkezik.";
/* No comment provided by engineer. */
"when IP hidden" = "ha az IP-cím rejtett";
/* No comment provided by engineer. */
"When people request to connect, you can accept or reject it." = "Amikor az emberek kapcsolódást kérelmeznek, ön elfogadhatja vagy elutasíthatja azokat.";
@@ -4214,9 +4316,18 @@
/* No comment provided by engineer. */
"With reduced battery usage." = "Csökkentett akkumulátorhasználattal.";
/* No comment provided by engineer. */
"Without Tor or VPN, your IP address will be visible to file servers." = "Tor vagy VPN nélkül az IP-címe látható lesz a fájlkiszolgálók számára.";
/* No comment provided by engineer. */
"Without Tor or VPN, your IP address will be visible to these XFTP relays: %@." = "Tor vagy VPN nélkül az IP-címe látható lesz ezen XFTP átjátszók számára: %@.";
/* No comment provided by engineer. */
"Wrong database passphrase" = "Téves adatbázis jelmondat";
/* snd error text */
"Wrong key or unknown connection - most likely this connection is deleted." = "Rossz kulcs vagy ismeretlen kapcsolat - valószínűleg ez a kapcsolat törlődött.";
/* No comment provided by engineer. */
"Wrong passphrase!" = "Téves jelmondat!";
@@ -4347,7 +4458,7 @@
"you changed role of %@ to %@" = "%1$@ szerepkörét megváltoztatta erre: %@";
/* No comment provided by engineer. */
"You control through which server(s) **to receive** the messages, your contacts the servers you use to message them." = "Ön szabályozhatja, hogy mely kiszogál(ók)ón keresztül **kapja** az üzeneteket, az ismerősöket - az üzenetküldéshez használt szervereken.";
"You control through which server(s) **to receive** the messages, your contacts the servers you use to message them." = "Ön szabályozhatja, hogy mely kiszogál(ók)ón keresztül **kapja** az üzeneteket, az ismerősöket - az üzenetküldéshez használt kiszolgálókon.";
/* No comment provided by engineer. */
"You could not be verified; please try again." = "Nem lehetett ellenőrizni; próbálja meg újra.";
+111
View File
@@ -449,6 +449,9 @@
/* No comment provided by engineer. */
"Allow disappearing messages only if your contact allows it to you." = "Consenti i messaggi a tempo solo se il contatto li consente a te.";
/* No comment provided by engineer. */
"Allow downgrade" = "Consenti downgrade";
/* No comment provided by engineer. */
"Allow irreversible message deletion only if your contact allows it to you. (24 hours)" = "Consenti l'eliminazione irreversibile dei messaggi solo se il contatto la consente a te. (24 ore)";
@@ -509,6 +512,9 @@
/* pref value */
"always" = "sempre";
/* No comment provided by engineer. */
"Always use private routing." = "Usa sempre l'instradamento privato.";
/* No comment provided by engineer. */
"Always use relay" = "Connetti via relay";
@@ -716,6 +722,9 @@
/* No comment provided by engineer. */
"Cannot receive file" = "Impossibile ricevere il file";
/* snd error text */
"Capacity exceeded - recipient did not receive previously sent messages." = "Quota superata - il destinatario non ha ricevuto i messaggi precedentemente inviati.";
/* No comment provided by engineer. */
"Cellular" = "Mobile";
@@ -852,6 +861,9 @@
/* No comment provided by engineer. */
"Confirm database upgrades" = "Conferma aggiornamenti database";
/* No comment provided by engineer. */
"Confirm files from unknown servers." = "Conferma i file da server sconosciuti.";
/* No comment provided by engineer. */
"Confirm network settings" = "Conferma le impostazioni di rete";
@@ -1320,6 +1332,9 @@
/* No comment provided by engineer. */
"Desktop devices" = "Dispositivi desktop";
/* snd error text */
"Destination server error: %@" = "Errore del server di destinazione: %@";
/* No comment provided by engineer. */
"Develop" = "Sviluppa";
@@ -1398,6 +1413,12 @@
/* No comment provided by engineer. */
"Do not send history to new members." = "Non inviare la cronologia ai nuovi membri.";
/* No comment provided by engineer. */
"Do NOT send messages directly, even if your or destination server does not support private routing." = "NON inviare messaggi direttamente, anche se il tuo server o quello di destinazione non supporta l'instradamento privato.";
/* No comment provided by engineer. */
"Do NOT use private routing." = "NON usare l'instradamento privato.";
/* No comment provided by engineer. */
"Do NOT use SimpleX for emergency calls." = "NON usare SimpleX per chiamate di emergenza.";
@@ -1839,6 +1860,9 @@
/* No comment provided by engineer. */
"File: %@" = "File: %@";
/* No comment provided by engineer. */
"Files" = "File";
/* No comment provided by engineer. */
"Files & media" = "File e multimediali";
@@ -1905,6 +1929,12 @@
/* No comment provided by engineer. */
"Forwarded from" = "Inoltrato da";
/* snd error text */
"Forwarding server: %@\nDestination server error: %@" = "Server di inoltro: %1$@\nErrore del server di destinazione: %2$@";
/* snd error text */
"Forwarding server: %@\nError: %@" = "Server di inoltro: %1$@\nErrore: %2$@";
/* No comment provided by engineer. */
"Found desktop" = "Desktop trovato";
@@ -2460,6 +2490,9 @@
/* No comment provided by engineer. */
"Message delivery receipts!" = "Ricevute di consegna dei messaggi!";
/* item status text */
"Message delivery warning" = "Avviso di consegna del messaggio";
/* No comment provided by engineer. */
"Message draft" = "Bozza dei messaggi";
@@ -2475,6 +2508,12 @@
/* notification */
"message received" = "messaggio ricevuto";
/* No comment provided by engineer. */
"Message routing fallback" = "Ripiego instradamento messaggio";
/* No comment provided by engineer. */
"Message routing mode" = "Modalità instradamento messaggio";
/* No comment provided by engineer. */
"Message source remains private." = "La fonte del messaggio resta privata.";
@@ -2586,6 +2625,9 @@
/* No comment provided by engineer. */
"Network connection" = "Connessione di rete";
/* snd error text */
"Network issues - message expired after many attempts to send it." = "Problemi di rete - messaggio scaduto dopo molti tentativi di inviarlo.";
/* No comment provided by engineer. */
"Network management" = "Gestione della rete";
@@ -2948,9 +2990,18 @@
/* No comment provided by engineer. */
"Private filenames" = "Nomi di file privati";
/* No comment provided by engineer. */
"Private message routing" = "Instradamento privato messaggi";
/* No comment provided by engineer. */
"Private message routing 🚀" = "Instradamento privato dei messaggi 🚀";
/* name of notes to self */
"Private notes" = "Note private";
/* No comment provided by engineer. */
"Private routing" = "Instradamento privato";
/* No comment provided by engineer. */
"Profile and server connections" = "Profilo e connessioni al server";
@@ -3002,9 +3053,15 @@
/* No comment provided by engineer. */
"Protect app screen" = "Proteggi la schermata dell'app";
/* No comment provided by engineer. */
"Protect IP address" = "Proteggi l'indirizzo IP";
/* No comment provided by engineer. */
"Protect your chat profiles with a password!" = "Proteggi i tuoi profili di chat con una password!";
/* No comment provided by engineer. */
"Protect your IP address from the messaging relays chosen by your contacts.\nEnable in *Network & servers* settings." = "Proteggi il tuo indirizzo IP dai relay di messaggistica scelti dai tuoi contatti.\nAttivalo nelle impostazioni *Rete e server*.";
/* No comment provided by engineer. */
"Protocol timeout" = "Scadenza del protocollo";
@@ -3230,6 +3287,9 @@
/* No comment provided by engineer. */
"Run chat" = "Avvia chat";
/* No comment provided by engineer. */
"Safely receive files" = "Ricevi i file in sicurezza";
/* No comment provided by engineer. */
"Safer groups" = "Gruppi più sicuri";
@@ -3386,6 +3446,12 @@
/* No comment provided by engineer. */
"Send live message" = "Invia messaggio in diretta";
/* No comment provided by engineer. */
"Send messages directly when IP address is protected and your or destination server does not support private routing." = "Invia messaggi direttamente quando l'indirizzo IP è protetto e il tuo server o quello di destinazione non supporta l'instradamento privato.";
/* No comment provided by engineer. */
"Send messages directly when your or destination server does not support private routing." = "Invia messaggi direttamente quando il tuo server o quello di destinazione non supporta l'instradamento privato.";
/* No comment provided by engineer. */
"Send notifications" = "Invia notifiche";
@@ -3449,6 +3515,9 @@
/* No comment provided by engineer. */
"Sent messages will be deleted after set time." = "I messaggi inviati verranno eliminati dopo il tempo impostato.";
/* srv error text. */
"Server address is incompatible with network settings." = "L'indirizzo del server non è compatibile con le impostazioni di rete.";
/* server test error */
"Server requires authorization to create queues, check password" = "Il server richiede l'autorizzazione di creare code, controlla la password";
@@ -3458,6 +3527,9 @@
/* No comment provided by engineer. */
"Server test failed!" = "Test del server fallito!";
/* srv error text */
"Server version is incompatible with network settings." = "La versione del server non è compatibile con le impostazioni di rete.";
/* No comment provided by engineer. */
"Servers" = "Server";
@@ -3524,6 +3596,9 @@
/* No comment provided by engineer. */
"Share with contacts" = "Condividi con i contatti";
/* No comment provided by engineer. */
"Show → on messages sent via private routing." = "Mostra → nei messaggi inviati via instradamento privato.";
/* No comment provided by engineer. */
"Show calls in phone history" = "Mostra le chiamate nella cronologia del telefono";
@@ -3533,6 +3608,9 @@
/* No comment provided by engineer. */
"Show last messages" = "Mostra ultimi messaggi";
/* No comment provided by engineer. */
"Show message status" = "Mostra stato del messaggio";
/* No comment provided by engineer. */
"Show preview" = "Mostra anteprima";
@@ -3740,6 +3818,9 @@
/* No comment provided by engineer. */
"The app can notify you when you receive messages or contact requests - please open settings to enable." = "L'app può avvisarti quando ricevi messaggi o richieste di contatto: apri le impostazioni per attivare.";
/* No comment provided by engineer. */
"The app will ask to confirm downloads from unknown file servers (except .onion)." = "L'app chiederà di confermare i download da server di file sconosciuti (eccetto .onion).";
/* No comment provided by engineer. */
"The attempt to change database passphrase was not completed." = "Il tentativo di cambiare la password del database non è stato completato.";
@@ -3860,6 +3941,9 @@
/* No comment provided by engineer. */
"To protect your information, turn on SimpleX Lock.\nYou will be prompted to complete authentication before this feature is enabled." = "Per proteggere le tue informazioni, attiva SimpleX Lock.\nTi verrà chiesto di completare l'autenticazione prima di attivare questa funzionalità.";
/* No comment provided by engineer. */
"To protect your IP address, private routing uses your SMP servers to deliver messages." = "Per proteggere il tuo indirizzo IP, l'instradamento privato usa i tuoi server SMP per consegnare i messaggi.";
/* No comment provided by engineer. */
"To record voice message please grant permission to use Microphone." = "Per registrare un messaggio vocale, concedi l'autorizzazione all'uso del microfono.";
@@ -3944,6 +4028,12 @@
/* No comment provided by engineer. */
"Unknown error" = "Errore sconosciuto";
/* No comment provided by engineer. */
"unknown relays" = "relay sconosciuti";
/* No comment provided by engineer. */
"Unknown servers!" = "Server sconosciuti!";
/* No comment provided by engineer. */
"unknown status" = "stato sconosciuto";
@@ -3968,6 +4058,9 @@
/* No comment provided by engineer. */
"Unmute" = "Riattiva notifiche";
/* No comment provided by engineer. */
"unprotected" = "non protetto";
/* No comment provided by engineer. */
"Unread" = "Non letto";
@@ -4037,6 +4130,12 @@
/* No comment provided by engineer. */
"Use only local notifications?" = "Usare solo notifiche locali?";
/* No comment provided by engineer. */
"Use private routing with unknown servers when IP address is not protected." = "Usa l'instradamento privato con server sconosciuti quando l'indirizzo IP non è protetto.";
/* No comment provided by engineer. */
"Use private routing with unknown servers." = "Usa l'instradamento privato con server sconosciuti.";
/* No comment provided by engineer. */
"Use server" = "Usa il server";
@@ -4190,6 +4289,9 @@
/* No comment provided by engineer. */
"When connecting audio and video calls." = "Quando si connettono le chiamate audio e video.";
/* No comment provided by engineer. */
"when IP hidden" = "quando l'IP è nascosto";
/* No comment provided by engineer. */
"When people request to connect, you can accept or reject it." = "Quando le persone chiedono di connettersi, puoi accettare o rifiutare.";
@@ -4214,9 +4316,18 @@
/* No comment provided by engineer. */
"With reduced battery usage." = "Con consumo di batteria ridotto.";
/* No comment provided by engineer. */
"Without Tor or VPN, your IP address will be visible to file servers." = "Senza Tor o VPN, il tuo indirizzo IP sarà visibile ai server di file.";
/* No comment provided by engineer. */
"Without Tor or VPN, your IP address will be visible to these XFTP relays: %@." = "Senza Tor o VPN, il tuo indirizzo IP sarà visibile a questi relay XFTP: %@.";
/* No comment provided by engineer. */
"Wrong database passphrase" = "Password del database sbagliata";
/* snd error text */
"Wrong key or unknown connection - most likely this connection is deleted." = "Chiave sbagliata o connessione sconosciuta - molto probabilmente questa connessione è stata eliminata.";
/* No comment provided by engineer. */
"Wrong passphrase!" = "Password sbagliata!";
+111
View File
@@ -449,6 +449,9 @@
/* No comment provided by engineer. */
"Allow disappearing messages only if your contact allows it to you." = "Sta verdwijnende berichten alleen toe als uw contact dit toestaat.";
/* No comment provided by engineer. */
"Allow downgrade" = "Downgraden toestaan";
/* No comment provided by engineer. */
"Allow irreversible message deletion only if your contact allows it to you. (24 hours)" = "Sta het onomkeerbaar verwijderen van berichten alleen toe als uw contact dit toestaat. (24 uur)";
@@ -509,6 +512,9 @@
/* pref value */
"always" = "altijd";
/* No comment provided by engineer. */
"Always use private routing." = "Gebruik altijd privéroutering.";
/* No comment provided by engineer. */
"Always use relay" = "Altijd relay gebruiken";
@@ -716,6 +722,9 @@
/* No comment provided by engineer. */
"Cannot receive file" = "Kan bestand niet ontvangen";
/* snd error text */
"Capacity exceeded - recipient did not receive previously sent messages." = "Capaciteit overschreden - ontvanger heeft eerder verzonden berichten niet ontvangen.";
/* No comment provided by engineer. */
"Cellular" = "Mobiel";
@@ -852,6 +861,9 @@
/* No comment provided by engineer. */
"Confirm database upgrades" = "Bevestig database upgrades";
/* No comment provided by engineer. */
"Confirm files from unknown servers." = "Bevestig bestanden van onbekende servers.";
/* No comment provided by engineer. */
"Confirm network settings" = "Bevestig netwerk instellingen";
@@ -1320,6 +1332,9 @@
/* No comment provided by engineer. */
"Desktop devices" = "Desktop apparaten";
/* snd error text */
"Destination server error: %@" = "Bestemmingsserverfout: %@";
/* No comment provided by engineer. */
"Develop" = "Ontwikkelen";
@@ -1398,6 +1413,12 @@
/* No comment provided by engineer. */
"Do not send history to new members." = "Stuur geen geschiedenis naar nieuwe leden.";
/* No comment provided by engineer. */
"Do NOT send messages directly, even if your or destination server does not support private routing." = "Stuur GEEN berichten rechtstreeks, zelfs als uw of de bestemmingsserver geen privéroutering ondersteunt.";
/* No comment provided by engineer. */
"Do NOT use private routing." = "Gebruik GEEN privéroutering.";
/* No comment provided by engineer. */
"Do NOT use SimpleX for emergency calls." = "Gebruik SimpleX NIET voor noodoproepen.";
@@ -1839,6 +1860,9 @@
/* No comment provided by engineer. */
"File: %@" = "Bestand: %@";
/* No comment provided by engineer. */
"Files" = "Bestanden";
/* No comment provided by engineer. */
"Files & media" = "Bestanden en media";
@@ -1905,6 +1929,12 @@
/* No comment provided by engineer. */
"Forwarded from" = "Doorgestuurd vanuit";
/* snd error text */
"Forwarding server: %@\nDestination server error: %@" = "Doorstuurserver: %1$@\nBestemmingsserverfout: %2$@";
/* snd error text */
"Forwarding server: %@\nError: %@" = "Doorstuurserver: %1$@\nFout: %2$@";
/* No comment provided by engineer. */
"Found desktop" = "Desktop gevonden";
@@ -2460,6 +2490,9 @@
/* No comment provided by engineer. */
"Message delivery receipts!" = "Ontvangst bevestiging voor berichten!";
/* item status text */
"Message delivery warning" = "Waarschuwing voor berichtbezorging";
/* No comment provided by engineer. */
"Message draft" = "Concept bericht";
@@ -2475,6 +2508,12 @@
/* notification */
"message received" = "bericht ontvangen";
/* No comment provided by engineer. */
"Message routing fallback" = "Terugval op berichtroutering";
/* No comment provided by engineer. */
"Message routing mode" = "Berichtrouteringsmodus";
/* No comment provided by engineer. */
"Message source remains private." = "Berichtbron blijft privé.";
@@ -2586,6 +2625,9 @@
/* No comment provided by engineer. */
"Network connection" = "Netwerkverbinding";
/* snd error text */
"Network issues - message expired after many attempts to send it." = "Netwerkproblemen - bericht is verlopen na vele pogingen om het te verzenden.";
/* No comment provided by engineer. */
"Network management" = "Netwerkbeheer";
@@ -2948,9 +2990,18 @@
/* No comment provided by engineer. */
"Private filenames" = "Privé bestandsnamen";
/* No comment provided by engineer. */
"Private message routing" = "Routering van privéberichten";
/* No comment provided by engineer. */
"Private message routing 🚀" = "Routing van privéberichten🚀";
/* name of notes to self */
"Private notes" = "Privé notities";
/* No comment provided by engineer. */
"Private routing" = "Privéroutering";
/* No comment provided by engineer. */
"Profile and server connections" = "Profiel- en serververbindingen";
@@ -3002,9 +3053,15 @@
/* No comment provided by engineer. */
"Protect app screen" = "App scherm verbergen";
/* No comment provided by engineer. */
"Protect IP address" = "Bescherm het IP-adres";
/* No comment provided by engineer. */
"Protect your chat profiles with a password!" = "Bescherm je chat profielen met een wachtwoord!";
/* No comment provided by engineer. */
"Protect your IP address from the messaging relays chosen by your contacts.\nEnable in *Network & servers* settings." = "Bescherm uw IP-adres tegen de berichtenrelais die door uw contacten zijn gekozen.\nSchakel dit in in *Netwerk en servers*-instellingen.";
/* No comment provided by engineer. */
"Protocol timeout" = "Protocol timeout";
@@ -3230,6 +3287,9 @@
/* No comment provided by engineer. */
"Run chat" = "Chat uitvoeren";
/* No comment provided by engineer. */
"Safely receive files" = "Veilig bestanden ontvangen";
/* No comment provided by engineer. */
"Safer groups" = "Veiligere groepen";
@@ -3386,6 +3446,12 @@
/* No comment provided by engineer. */
"Send live message" = "Stuur een livebericht";
/* No comment provided by engineer. */
"Send messages directly when IP address is protected and your or destination server does not support private routing." = "Stuur berichten rechtstreeks als het IP-adres beschermd is en uw of bestemmingsserver geen privéroutering ondersteunt.";
/* No comment provided by engineer. */
"Send messages directly when your or destination server does not support private routing." = "Stuur berichten rechtstreeks wanneer uw of de doelserver geen privéroutering ondersteunt.";
/* No comment provided by engineer. */
"Send notifications" = "Meldingen verzenden";
@@ -3449,6 +3515,9 @@
/* No comment provided by engineer. */
"Sent messages will be deleted after set time." = "Verzonden berichten worden na ingestelde tijd verwijderd.";
/* srv error text. */
"Server address is incompatible with network settings." = "Serveradres is niet compatibel met netwerkinstellingen.";
/* server test error */
"Server requires authorization to create queues, check password" = "Server vereist autorisatie om wachtrijen te maken, controleer wachtwoord";
@@ -3458,6 +3527,9 @@
/* No comment provided by engineer. */
"Server test failed!" = "Servertest mislukt!";
/* srv error text */
"Server version is incompatible with network settings." = "Serverversie is incompatibel met netwerkinstellingen.";
/* No comment provided by engineer. */
"Servers" = "Servers";
@@ -3524,6 +3596,9 @@
/* No comment provided by engineer. */
"Share with contacts" = "Delen met contacten";
/* No comment provided by engineer. */
"Show → on messages sent via private routing." = "Toon → bij berichten verzonden via privéroutering.";
/* No comment provided by engineer. */
"Show calls in phone history" = "Toon oproepen in de telefoongeschiedenis";
@@ -3533,6 +3608,9 @@
/* No comment provided by engineer. */
"Show last messages" = "Laat laatste berichten zien";
/* No comment provided by engineer. */
"Show message status" = "Toon berichtstatus";
/* No comment provided by engineer. */
"Show preview" = "Toon voorbeeld";
@@ -3740,6 +3818,9 @@
/* No comment provided by engineer. */
"The app can notify you when you receive messages or contact requests - please open settings to enable." = "De app kan u op de hoogte stellen wanneer u berichten of contact verzoeken ontvangt - open de instellingen om dit in te schakelen.";
/* No comment provided by engineer. */
"The app will ask to confirm downloads from unknown file servers (except .onion)." = "De app vraagt om downloads van onbekende bestandsservers (behalve .onion) te bevestigen.";
/* No comment provided by engineer. */
"The attempt to change database passphrase was not completed." = "De poging om het wachtwoord van de database te wijzigen is niet voltooid.";
@@ -3860,6 +3941,9 @@
/* No comment provided by engineer. */
"To protect your information, turn on SimpleX Lock.\nYou will be prompted to complete authentication before this feature is enabled." = "Schakel SimpleX Vergrendelen om uw informatie te beschermen.\nU wordt gevraagd de authenticatie te voltooien voordat deze functie wordt ingeschakeld.";
/* No comment provided by engineer. */
"To protect your IP address, private routing uses your SMP servers to deliver messages." = "Om uw IP-adres te beschermen, gebruikt privéroutering uw SMP-servers om berichten te bezorgen.";
/* No comment provided by engineer. */
"To record voice message please grant permission to use Microphone." = "Geef toestemming om de microfoon te gebruiken om een spraakbericht op te nemen.";
@@ -3944,6 +4028,12 @@
/* No comment provided by engineer. */
"Unknown error" = "Onbekende fout";
/* No comment provided by engineer. */
"unknown relays" = "onbekende relays";
/* No comment provided by engineer. */
"Unknown servers!" = "Onbekende servers!";
/* No comment provided by engineer. */
"unknown status" = "onbekende status";
@@ -3968,6 +4058,9 @@
/* No comment provided by engineer. */
"Unmute" = "Dempen opheffen";
/* No comment provided by engineer. */
"unprotected" = "onbeschermd";
/* No comment provided by engineer. */
"Unread" = "Ongelezen";
@@ -4037,6 +4130,12 @@
/* No comment provided by engineer. */
"Use only local notifications?" = "Alleen lokale meldingen gebruiken?";
/* No comment provided by engineer. */
"Use private routing with unknown servers when IP address is not protected." = "Gebruik privéroutering met onbekende servers wanneer het IP-adres niet beveiligd is.";
/* No comment provided by engineer. */
"Use private routing with unknown servers." = "Gebruik privéroutering met onbekende servers.";
/* No comment provided by engineer. */
"Use server" = "Gebruik server";
@@ -4190,6 +4289,9 @@
/* No comment provided by engineer. */
"When connecting audio and video calls." = "Bij het verbinden van audio- en video-oproepen.";
/* No comment provided by engineer. */
"when IP hidden" = "wanneer IP verborgen is";
/* No comment provided by engineer. */
"When people request to connect, you can accept or reject it." = "Wanneer mensen vragen om verbinding te maken, kunt u dit accepteren of weigeren.";
@@ -4214,9 +4316,18 @@
/* No comment provided by engineer. */
"With reduced battery usage." = "Met verminderd batterijgebruik.";
/* No comment provided by engineer. */
"Without Tor or VPN, your IP address will be visible to file servers." = "Zonder Tor of VPN is uw IP-adres zichtbaar voor bestandsservers.";
/* No comment provided by engineer. */
"Without Tor or VPN, your IP address will be visible to these XFTP relays: %@." = "Zonder Tor of VPN zal uw IP-adres zichtbaar zijn voor deze XFTP-relays: %@.";
/* No comment provided by engineer. */
"Wrong database passphrase" = "Verkeerd wachtwoord voor de database";
/* snd error text */
"Wrong key or unknown connection - most likely this connection is deleted." = "Verkeerde sleutel of onbekende verbinding - hoogstwaarschijnlijk is deze verbinding verwijderd.";
/* No comment provided by engineer. */
"Wrong passphrase!" = "Verkeerd wachtwoord!";
+111
View File
@@ -449,6 +449,9 @@
/* No comment provided by engineer. */
"Allow disappearing messages only if your contact allows it to you." = "Zezwól na znikające wiadomości tylko wtedy, gdy Twój kontakt Ci na to pozwoli.";
/* No comment provided by engineer. */
"Allow downgrade" = "Zezwól na obniżenie wersji";
/* No comment provided by engineer. */
"Allow irreversible message deletion only if your contact allows it to you. (24 hours)" = "Zezwalaj na nieodwracalne usuwanie wiadomości tylko wtedy, gdy Twój kontakt Ci na to pozwoli. (24 godziny)";
@@ -509,6 +512,9 @@
/* pref value */
"always" = "zawsze";
/* No comment provided by engineer. */
"Always use private routing." = "Zawsze używaj prywatnego trasowania.";
/* No comment provided by engineer. */
"Always use relay" = "Zawsze używaj przekaźnika";
@@ -716,6 +722,9 @@
/* No comment provided by engineer. */
"Cannot receive file" = "Nie można odebrać pliku";
/* snd error text */
"Capacity exceeded - recipient did not receive previously sent messages." = "Przekroczono pojemność - odbiorca nie otrzymał wcześniej wysłanych wiadomości.";
/* No comment provided by engineer. */
"Cellular" = "Sieć komórkowa";
@@ -852,6 +861,9 @@
/* No comment provided by engineer. */
"Confirm database upgrades" = "Potwierdź aktualizacje bazy danych";
/* No comment provided by engineer. */
"Confirm files from unknown servers." = "Potwierdzaj pliki z nieznanych serwerów.";
/* No comment provided by engineer. */
"Confirm network settings" = "Potwierdź ustawienia sieciowe";
@@ -1320,6 +1332,9 @@
/* No comment provided by engineer. */
"Desktop devices" = "Urządzenia komputerowe";
/* snd error text */
"Destination server error: %@" = "Błąd docelowego serwera: %@";
/* No comment provided by engineer. */
"Develop" = "Deweloperskie";
@@ -1398,6 +1413,12 @@
/* No comment provided by engineer. */
"Do not send history to new members." = "Nie wysyłaj historii do nowych członków.";
/* No comment provided by engineer. */
"Do NOT send messages directly, even if your or destination server does not support private routing." = "NIE wysyłaj wiadomości bezpośrednio, nawet jeśli serwer docelowy nie obsługuje prywatnego trasowania.";
/* No comment provided by engineer. */
"Do NOT use private routing." = "NIE używaj prywatnego trasowania.";
/* No comment provided by engineer. */
"Do NOT use SimpleX for emergency calls." = "NIE używaj SimpleX do połączeń alarmowych.";
@@ -1839,6 +1860,9 @@
/* No comment provided by engineer. */
"File: %@" = "Plik: %@";
/* No comment provided by engineer. */
"Files" = "Pliki";
/* No comment provided by engineer. */
"Files & media" = "Pliki i media";
@@ -1905,6 +1929,12 @@
/* No comment provided by engineer. */
"Forwarded from" = "Przekazane dalej od";
/* snd error text */
"Forwarding server: %@\nDestination server error: %@" = "Serwer przekazujący: %1$@\nBłąd serwera docelowego: %2$@";
/* snd error text */
"Forwarding server: %@\nError: %@" = "Serwer przekazujący: %1$@\nBłąd: %2$@";
/* No comment provided by engineer. */
"Found desktop" = "Znaleziono komputer";
@@ -2460,6 +2490,9 @@
/* No comment provided by engineer. */
"Message delivery receipts!" = "Potwierdzenia dostarczenia wiadomości!";
/* item status text */
"Message delivery warning" = "Ostrzeżenie dostarczenia wiadomości";
/* No comment provided by engineer. */
"Message draft" = "Wersja robocza wiadomości";
@@ -2475,6 +2508,12 @@
/* notification */
"message received" = "wiadomość otrzymana";
/* No comment provided by engineer. */
"Message routing fallback" = "Rezerwowe trasowania wiadomości";
/* No comment provided by engineer. */
"Message routing mode" = "Tryb trasowania wiadomości";
/* No comment provided by engineer. */
"Message source remains private." = "Źródło wiadomości pozostaje prywatne.";
@@ -2586,6 +2625,9 @@
/* No comment provided by engineer. */
"Network connection" = "Połączenie z siecią";
/* snd error text */
"Network issues - message expired after many attempts to send it." = "Błąd sieciowy - wiadomość wygasła po wielu próbach wysłania jej.";
/* No comment provided by engineer. */
"Network management" = "Zarządzenie sieciowe";
@@ -2948,9 +2990,18 @@
/* No comment provided by engineer. */
"Private filenames" = "Prywatne nazwy plików";
/* No comment provided by engineer. */
"Private message routing" = "Trasowanie prywatnych wiadomości";
/* No comment provided by engineer. */
"Private message routing 🚀" = "Trasowanie prywatnych wiadomości🚀";
/* name of notes to self */
"Private notes" = "Prywatne notatki";
/* No comment provided by engineer. */
"Private routing" = "Prywatne trasowanie";
/* No comment provided by engineer. */
"Profile and server connections" = "Profil i połączenia z serwerem";
@@ -3002,9 +3053,15 @@
/* No comment provided by engineer. */
"Protect app screen" = "Chroń ekran aplikacji";
/* No comment provided by engineer. */
"Protect IP address" = "Chroń adres IP";
/* No comment provided by engineer. */
"Protect your chat profiles with a password!" = "Chroń swoje profile czatu hasłem!";
/* No comment provided by engineer. */
"Protect your IP address from the messaging relays chosen by your contacts.\nEnable in *Network & servers* settings." = "Chroni Twój adres IP przed przekaźnikami wiadomości wybranych przez Twoje kontakty.\nWłącz w ustawianiach *Sieć i serwery* .";
/* No comment provided by engineer. */
"Protocol timeout" = "Limit czasu protokołu";
@@ -3230,6 +3287,9 @@
/* No comment provided by engineer. */
"Run chat" = "Uruchom czat";
/* No comment provided by engineer. */
"Safely receive files" = "Bezpiecznie otrzymuj pliki";
/* No comment provided by engineer. */
"Safer groups" = "Bezpieczniejsze grupy";
@@ -3386,6 +3446,12 @@
/* No comment provided by engineer. */
"Send live message" = "Wyślij wiadomość na żywo";
/* No comment provided by engineer. */
"Send messages directly when IP address is protected and your or destination server does not support private routing." = "Wysyłaj wiadomości bezpośrednio, gdy adres IP jest chroniony i Twój lub docelowy serwer nie obsługuje prywatnego trasowania.";
/* No comment provided by engineer. */
"Send messages directly when your or destination server does not support private routing." = "Wysyłaj wiadomości bezpośrednio, gdy Twój lub docelowy serwer nie obsługuje prywatnego trasowania.";
/* No comment provided by engineer. */
"Send notifications" = "Wyślij powiadomienia";
@@ -3449,6 +3515,9 @@
/* No comment provided by engineer. */
"Sent messages will be deleted after set time." = "Wysłane wiadomości zostaną usunięte po ustawionym czasie.";
/* srv error text. */
"Server address is incompatible with network settings." = "Adres serwera jest niekompatybilny z ustawieniami sieciowymi.";
/* server test error */
"Server requires authorization to create queues, check password" = "Serwer wymaga autoryzacji do tworzenia kolejek, sprawdź hasło";
@@ -3458,6 +3527,9 @@
/* No comment provided by engineer. */
"Server test failed!" = "Test serwera nie powiódł się!";
/* srv error text */
"Server version is incompatible with network settings." = "Wersja serwera jest niekompatybilna z ustawieniami sieciowymi.";
/* No comment provided by engineer. */
"Servers" = "Serwery";
@@ -3524,6 +3596,9 @@
/* No comment provided by engineer. */
"Share with contacts" = "Udostępnij kontaktom";
/* No comment provided by engineer. */
"Show → on messages sent via private routing." = "Pokaż → na wiadomościach wysłanych przez prywatne trasowanie.";
/* No comment provided by engineer. */
"Show calls in phone history" = "Pokaż połączenia w historii telefonu";
@@ -3533,6 +3608,9 @@
/* No comment provided by engineer. */
"Show last messages" = "Pokaż ostatnie wiadomości";
/* No comment provided by engineer. */
"Show message status" = "Pokaż status wiadomości";
/* No comment provided by engineer. */
"Show preview" = "Pokaż podgląd";
@@ -3740,6 +3818,9 @@
/* No comment provided by engineer. */
"The app can notify you when you receive messages or contact requests - please open settings to enable." = "Aplikacja może powiadamiać Cię, gdy otrzymujesz wiadomości lub prośby o kontakt — otwórz ustawienia, aby włączyć.";
/* No comment provided by engineer. */
"The app will ask to confirm downloads from unknown file servers (except .onion)." = "Aplikacja zapyta o potwierdzenie pobierania od nieznanych serwerów plików (poza .onion).";
/* No comment provided by engineer. */
"The attempt to change database passphrase was not completed." = "Próba zmiany hasła bazy danych nie została zakończona.";
@@ -3860,6 +3941,9 @@
/* No comment provided by engineer. */
"To protect your information, turn on SimpleX Lock.\nYou will be prompted to complete authentication before this feature is enabled." = "Aby chronić swoje informacje, włącz funkcję blokady SimpleX.\nPrzed włączeniem tej funkcji zostanie wyświetlony monit uwierzytelniania.";
/* No comment provided by engineer. */
"To protect your IP address, private routing uses your SMP servers to deliver messages." = "Aby chronić Twój adres IP, prywatne trasowanie używa Twoich serwerów SMP, aby dostarczyć wiadomości.";
/* No comment provided by engineer. */
"To record voice message please grant permission to use Microphone." = "Aby nagrać wiadomość głosową należy udzielić zgody na użycie Mikrofonu.";
@@ -3944,6 +4028,12 @@
/* No comment provided by engineer. */
"Unknown error" = "Nieznany błąd";
/* No comment provided by engineer. */
"unknown relays" = "nieznane przekaźniki";
/* No comment provided by engineer. */
"Unknown servers!" = "Nieznane serwery!";
/* No comment provided by engineer. */
"unknown status" = "nieznany status";
@@ -3968,6 +4058,9 @@
/* No comment provided by engineer. */
"Unmute" = "Wyłącz wyciszenie";
/* No comment provided by engineer. */
"unprotected" = "niezabezpieczony";
/* No comment provided by engineer. */
"Unread" = "Nieprzeczytane";
@@ -4037,6 +4130,12 @@
/* No comment provided by engineer. */
"Use only local notifications?" = "Używać tylko lokalnych powiadomień?";
/* No comment provided by engineer. */
"Use private routing with unknown servers when IP address is not protected." = "Używaj prywatnego trasowania z nieznanymi serwerami, gdy adres IP nie jest chroniony.";
/* No comment provided by engineer. */
"Use private routing with unknown servers." = "Używaj prywatnego trasowania z nieznanymi serwerami.";
/* No comment provided by engineer. */
"Use server" = "Użyj serwera";
@@ -4190,6 +4289,9 @@
/* No comment provided by engineer. */
"When connecting audio and video calls." = "Podczas łączenia połączeń audio i wideo.";
/* No comment provided by engineer. */
"when IP hidden" = "gdy IP ukryty";
/* No comment provided by engineer. */
"When people request to connect, you can accept or reject it." = "Kiedy ludzie proszą o połączenie, możesz je zaakceptować lub odrzucić.";
@@ -4214,9 +4316,18 @@
/* No comment provided by engineer. */
"With reduced battery usage." = "Ze zmniejszonym zużyciem baterii.";
/* No comment provided by engineer. */
"Without Tor or VPN, your IP address will be visible to file servers." = "Bez Tor lub VPN, Twój adres IP będzie widoczny do serwerów plików.";
/* No comment provided by engineer. */
"Without Tor or VPN, your IP address will be visible to these XFTP relays: %@." = "Bez Tor lub VPN, Twój adres IP będzie widoczny dla tych przekaźników XFTP: %@.";
/* No comment provided by engineer. */
"Wrong database passphrase" = "Nieprawidłowe hasło bazy danych";
/* snd error text */
"Wrong key or unknown connection - most likely this connection is deleted." = "Zły klucz lub nieznane połączenie - najprawdopodobniej to połączenie jest usunięte.";
/* No comment provided by engineer. */
"Wrong passphrase!" = "Nieprawidłowe hasło!";
+111
View File
@@ -449,6 +449,9 @@
/* No comment provided by engineer. */
"Allow disappearing messages only if your contact allows it to you." = "Разрешить исчезающие сообщения, только если Ваш контакт разрешает их Вам.";
/* No comment provided by engineer. */
"Allow downgrade" = "Разрешить прямую доставку";
/* No comment provided by engineer. */
"Allow irreversible message deletion only if your contact allows it to you. (24 hours)" = "Разрешить необратимое удаление сообщений, только если Ваш контакт разрешает это Вам. (24 часа)";
@@ -509,6 +512,9 @@
/* pref value */
"always" = "всегда";
/* No comment provided by engineer. */
"Always use private routing." = "Всегда использовать конфиденциальную доставку.";
/* No comment provided by engineer. */
"Always use relay" = "Всегда соединяться через relay";
@@ -716,6 +722,9 @@
/* No comment provided by engineer. */
"Cannot receive file" = "Невозможно получить файл";
/* snd error text */
"Capacity exceeded - recipient did not receive previously sent messages." = "Превышено количество сообщений - предыдущие сообщения не доставлены.";
/* No comment provided by engineer. */
"Cellular" = "Мобильная сеть";
@@ -852,6 +861,9 @@
/* No comment provided by engineer. */
"Confirm database upgrades" = "Подтвердить обновление базы данных";
/* No comment provided by engineer. */
"Confirm files from unknown servers." = "Подтверждать файлы с неизвестных серверов.";
/* No comment provided by engineer. */
"Confirm network settings" = "Подтвердите настройки сети";
@@ -1320,6 +1332,9 @@
/* No comment provided by engineer. */
"Desktop devices" = "Компьютеры";
/* snd error text */
"Destination server error: %@" = "Ошибка сервера получателя: %@";
/* No comment provided by engineer. */
"Develop" = "Для разработчиков";
@@ -1398,6 +1413,12 @@
/* No comment provided by engineer. */
"Do not send history to new members." = "Не отправлять историю новым членам.";
/* No comment provided by engineer. */
"Do NOT send messages directly, even if your or destination server does not support private routing." = "Не отправлять сообщения напрямую, даже если сервер получателя не поддерживает конфиденциальную доставку.";
/* No comment provided by engineer. */
"Do NOT use private routing." = "Не использовать конфиденциальную доставку.";
/* No comment provided by engineer. */
"Do NOT use SimpleX for emergency calls." = "Не используйте SimpleX для экстренных звонков.";
@@ -1839,6 +1860,9 @@
/* No comment provided by engineer. */
"File: %@" = "Файл: %@";
/* No comment provided by engineer. */
"Files" = "Файлы";
/* No comment provided by engineer. */
"Files & media" = "Файлы и медиа";
@@ -1905,6 +1929,12 @@
/* No comment provided by engineer. */
"Forwarded from" = "Переслано из";
/* snd error text */
"Forwarding server: %@\nDestination server error: %@" = "Пересылающий сервер: %1$@\nОшибка сервера получателя: %2$@";
/* snd error text */
"Forwarding server: %@\nError: %@" = "Пересылающий сервер: %1$@\nОшибка: %2$@";
/* No comment provided by engineer. */
"Found desktop" = "Компьютер найден";
@@ -2460,6 +2490,9 @@
/* No comment provided by engineer. */
"Message delivery receipts!" = "Отчеты о доставке сообщений!";
/* item status text */
"Message delivery warning" = "Предупреждение доставки сообщения";
/* No comment provided by engineer. */
"Message draft" = "Черновик сообщения";
@@ -2475,6 +2508,12 @@
/* notification */
"message received" = "получено сообщение";
/* No comment provided by engineer. */
"Message routing fallback" = "Прямая доставка сообщений";
/* No comment provided by engineer. */
"Message routing mode" = "Режим доставки сообщений";
/* No comment provided by engineer. */
"Message source remains private." = "Источник сообщения остаётся конфиденциальным.";
@@ -2586,6 +2625,9 @@
/* No comment provided by engineer. */
"Network connection" = "Интернет-соединение";
/* snd error text */
"Network issues - message expired after many attempts to send it." = "Ошибка сети - сообщение не было отправлено после многократных попыток.";
/* No comment provided by engineer. */
"Network management" = "Статус сети";
@@ -2948,9 +2990,18 @@
/* No comment provided by engineer. */
"Private filenames" = "Защищенные имена файлов";
/* No comment provided by engineer. */
"Private message routing" = "Конфиденциальная доставка сообщений";
/* No comment provided by engineer. */
"Private message routing 🚀" = "Конфиденциальная доставка сообщений 🚀";
/* name of notes to self */
"Private notes" = "Личные заметки";
/* No comment provided by engineer. */
"Private routing" = "Конфиденциальная доставка";
/* No comment provided by engineer. */
"Profile and server connections" = "Профиль и соединения на сервере";
@@ -3002,9 +3053,15 @@
/* No comment provided by engineer. */
"Protect app screen" = "Защитить экран приложения";
/* No comment provided by engineer. */
"Protect IP address" = "Защитить IP адрес";
/* No comment provided by engineer. */
"Protect your chat profiles with a password!" = "Защитите Ваши профили чата паролем!";
/* No comment provided by engineer. */
"Protect your IP address from the messaging relays chosen by your contacts.\nEnable in *Network & servers* settings." = "Защитите ваш IP адрес от серверов сообщений, выбранных Вашими контактами.\nВключите в настройках *Сеть и серверы*.";
/* No comment provided by engineer. */
"Protocol timeout" = "Таймаут протокола";
@@ -3230,6 +3287,9 @@
/* No comment provided by engineer. */
"Run chat" = "Запустить chat";
/* No comment provided by engineer. */
"Safely receive files" = "Получайте файлы безопасно";
/* No comment provided by engineer. */
"Safer groups" = "Более безопасные группы";
@@ -3386,6 +3446,12 @@
/* No comment provided by engineer. */
"Send live message" = "Отправить живое сообщение";
/* No comment provided by engineer. */
"Send messages directly when IP address is protected and your or destination server does not support private routing." = "Отправлять сообщения напрямую, когда IP адрес защищен, и Ваш сервер или сервер получателя не поддерживает конфиденциальную доставку.";
/* No comment provided by engineer. */
"Send messages directly when your or destination server does not support private routing." = "Отправлять сообщения напрямую, когда Ваш сервер или сервер получателя не поддерживает конфиденциальную доставку.";
/* No comment provided by engineer. */
"Send notifications" = "Отправлять уведомления";
@@ -3449,6 +3515,9 @@
/* No comment provided by engineer. */
"Sent messages will be deleted after set time." = "Отправленные сообщения будут удалены через заданное время.";
/* srv error text. */
"Server address is incompatible with network settings." = "Адрес сервера несовместим с настройками сети.";
/* server test error */
"Server requires authorization to create queues, check password" = "Сервер требует авторизации для создания очередей, проверьте пароль";
@@ -3458,6 +3527,9 @@
/* No comment provided by engineer. */
"Server test failed!" = "Ошибка теста сервера!";
/* srv error text */
"Server version is incompatible with network settings." = "Версия сервера несовместима с настройками сети.";
/* No comment provided by engineer. */
"Servers" = "Серверы";
@@ -3524,6 +3596,9 @@
/* No comment provided by engineer. */
"Share with contacts" = "Поделиться с контактами";
/* No comment provided by engineer. */
"Show → on messages sent via private routing." = "Показать → на сообщениях доставленных конфиденциально.";
/* No comment provided by engineer. */
"Show calls in phone history" = "Показать звонки в истории телефона";
@@ -3533,6 +3608,9 @@
/* No comment provided by engineer. */
"Show last messages" = "Показывать последние сообщения";
/* No comment provided by engineer. */
"Show message status" = "Показать статус сообщения";
/* No comment provided by engineer. */
"Show preview" = "Показывать уведомления";
@@ -3740,6 +3818,9 @@
/* No comment provided by engineer. */
"The app can notify you when you receive messages or contact requests - please open settings to enable." = "Приложение может посылать Вам уведомления о сообщениях и запросах на соединение - уведомления можно включить в Настройках.";
/* No comment provided by engineer. */
"The app will ask to confirm downloads from unknown file servers (except .onion)." = "Приложение будет запрашивать подтверждение загрузки с неизвестных серверов (за исключением .onion адресов).";
/* No comment provided by engineer. */
"The attempt to change database passphrase was not completed." = "Попытка поменять пароль базы данных не была завершена.";
@@ -3860,6 +3941,9 @@
/* No comment provided by engineer. */
"To protect your information, turn on SimpleX Lock.\nYou will be prompted to complete authentication before this feature is enabled." = "Чтобы защитить Вашу информацию, включите блокировку SimpleX Chat.\nВам будет нужно пройти аутентификацию для включения блокировки.";
/* No comment provided by engineer. */
"To protect your IP address, private routing uses your SMP servers to deliver messages." = "Чтобы защитить ваш IP адрес, приложение использует Ваши SMP серверы для конфиденциальной доставки сообщений.";
/* No comment provided by engineer. */
"To record voice message please grant permission to use Microphone." = "Для записи голосового сообщения, пожалуйста разрешите доступ к микрофону.";
@@ -3944,6 +4028,12 @@
/* No comment provided by engineer. */
"Unknown error" = "Неизвестная ошибка";
/* No comment provided by engineer. */
"unknown relays" = "неизвестные серверы";
/* No comment provided by engineer. */
"Unknown servers!" = "Неизвестные серверы!";
/* No comment provided by engineer. */
"unknown status" = "неизвестный статус";
@@ -3968,6 +4058,9 @@
/* No comment provided by engineer. */
"Unmute" = "Уведомлять";
/* No comment provided by engineer. */
"unprotected" = "незащищённый";
/* No comment provided by engineer. */
"Unread" = "Не прочитано";
@@ -4037,6 +4130,12 @@
/* No comment provided by engineer. */
"Use only local notifications?" = "Использовать только локальные нотификации?";
/* No comment provided by engineer. */
"Use private routing with unknown servers when IP address is not protected." = "Использовать конфиденциальную доставку с неизвестными серверами, когда IP адрес не защищен.";
/* No comment provided by engineer. */
"Use private routing with unknown servers." = "Использовать конфиденциальную доставку с неизвестными серверами.";
/* No comment provided by engineer. */
"Use server" = "Использовать сервер";
@@ -4190,6 +4289,9 @@
/* No comment provided by engineer. */
"When connecting audio and video calls." = "Во время соединения аудио и видео звонков.";
/* No comment provided by engineer. */
"when IP hidden" = "когда IP защищен";
/* No comment provided by engineer. */
"When people request to connect, you can accept or reject it." = "Когда Вы получите запрос на соединение, Вы можете принять или отклонить его.";
@@ -4214,9 +4316,18 @@
/* No comment provided by engineer. */
"With reduced battery usage." = "С уменьшенным потреблением батареи.";
/* No comment provided by engineer. */
"Without Tor or VPN, your IP address will be visible to file servers." = "Без Тора или ВПН, Ваш IP адрес будет доступен серверам файлов.";
/* No comment provided by engineer. */
"Without Tor or VPN, your IP address will be visible to these XFTP relays: %@." = "Без Тора или ВПН, Ваш IP адрес будет доступен этим серверам файлов: %@.";
/* No comment provided by engineer. */
"Wrong database passphrase" = "Неправильный пароль базы данных";
/* snd error text */
"Wrong key or unknown connection - most likely this connection is deleted." = "Неверный ключ или неизвестное соединение - скорее всего, это соединение удалено.";
/* No comment provided by engineer. */
"Wrong passphrase!" = "Неправильный пароль!";
+117 -6
View File
@@ -275,7 +275,7 @@
"0 sec" = "0 saniye";
/* No comment provided by engineer. */
"0s" = "0 saniye";
"0s" = "0sn";
/* time interval */
"1 day" = "1 gün";
@@ -438,7 +438,7 @@
"All your contacts will remain connected. Profile update will be sent to your contacts." = "Tüm kişileriniz bağlı kalacaktır. Profil güncellemesi kişilerinize gönderilecektir.";
/* No comment provided by engineer. */
"All your contacts, conversations and files will be securely encrypted and uploaded in chunks to configured XFTP relays." = "Tüm kişileriniz, sohbetleriniz ve dosyalarınız güvenli bir şekilde şifrelenecek ve parçalar halinde yapılandırılmış XFTP rölelerine yüklenecektir.";
"All your contacts, conversations and files will be securely encrypted and uploaded in chunks to configured XFTP relays." = "Tüm kişileriniz, konuşmalarınız ve dosyalarınız güvenli bir şekilde şifrelenir ve yapılandırılmış XFTP yönlendiricilerine parçalar halinde yüklenir.";
/* No comment provided by engineer. */
"Allow" = "İzin ver";
@@ -449,6 +449,9 @@
/* No comment provided by engineer. */
"Allow disappearing messages only if your contact allows it to you." = "Eğer kişide izin verirse kaybolan mesajlara izin ver.";
/* No comment provided by engineer. */
"Allow downgrade" = "Sürüm düşürmeye izin ver";
/* No comment provided by engineer. */
"Allow irreversible message deletion only if your contact allows it to you. (24 hours)" = "Konuştuğun kişi, kalıcı olarak silinebilen mesajlara izin veriyorsa sen de ver. (24 saat içinde)";
@@ -459,7 +462,7 @@
"Allow message reactions." = "Mesaj tepkilerine izin ver.";
/* No comment provided by engineer. */
"Allow sending direct messages to members." = "Üyelere direkt mesaj göndermeye izin ver.";
"Allow sending direct messages to members." = "Üyelere doğrudan mesaj göndermeye izin ver.";
/* No comment provided by engineer. */
"Allow sending disappearing messages." = "Kendiliğinden yok olan mesajlar göndermeye izin ver.";
@@ -509,6 +512,9 @@
/* pref value */
"always" = "her zaman";
/* No comment provided by engineer. */
"Always use private routing." = "Her zaman gizli yönlendirme kullan.";
/* No comment provided by engineer. */
"Always use relay" = "Her zaman yönlendirici kullan";
@@ -716,6 +722,9 @@
/* No comment provided by engineer. */
"Cannot receive file" = "Dosya alınamıyor";
/* snd error text */
"Capacity exceeded - recipient did not receive previously sent messages." = "Kapasite aşıldı - alıcı önceden gönderilen mesajları almadı.";
/* No comment provided by engineer. */
"Cellular" = "Hücresel Veri";
@@ -852,6 +861,9 @@
/* No comment provided by engineer. */
"Confirm database upgrades" = "Veritabanı geliştirmelerini onayla";
/* No comment provided by engineer. */
"Confirm files from unknown servers." = "Bilinmeyen sunuculardan gelen dosyaları onayla.";
/* No comment provided by engineer. */
"Confirm network settings" = "Ağ ayarlarını onaylayın";
@@ -1320,6 +1332,9 @@
/* No comment provided by engineer. */
"Desktop devices" = "Bilgisayar cihazları";
/* snd error text */
"Destination server error: %@" = "Hedef sunucu hatası: %@";
/* No comment provided by engineer. */
"Develop" = "Geliştir";
@@ -1398,6 +1413,12 @@
/* No comment provided by engineer. */
"Do not send history to new members." = "Yeni üyelere geçmişi gönderme.";
/* No comment provided by engineer. */
"Do NOT send messages directly, even if your or destination server does not support private routing." = "Sizin veya hedef sunucunun özel yönlendirmeyi desteklememesi durumunda bile mesajları doğrudan GÖNDERMEYİN.";
/* No comment provided by engineer. */
"Do NOT use private routing." = "Gizli yönlendirmeyi KULLANMA.";
/* No comment provided by engineer. */
"Do NOT use SimpleX for emergency calls." = "Acil aramalar için SimpleX'i KULLANMAYIN.";
@@ -1839,6 +1860,9 @@
/* No comment provided by engineer. */
"File: %@" = "Dosya: %@";
/* No comment provided by engineer. */
"Files" = "Dosyalar";
/* No comment provided by engineer. */
"Files & media" = "Dosyalar & medya";
@@ -1905,6 +1929,12 @@
/* No comment provided by engineer. */
"Forwarded from" = "Şuradan iletildi";
/* snd error text */
"Forwarding server: %@\nDestination server error: %@" = "Yönlendirme sunucusu: %1$@\nHedef sunucu hatası: %2$@";
/* snd error text */
"Forwarding server: %@\nError: %@" = "Yönlendirme sunucusu: %1$@\nHata: %2$@";
/* No comment provided by engineer. */
"Found desktop" = "Bilgisayar bulundu";
@@ -2460,6 +2490,9 @@
/* No comment provided by engineer. */
"Message delivery receipts!" = "Mesaj alındı bilgisi!";
/* item status text */
"Message delivery warning" = "Mesaj iletimi uyarısı";
/* No comment provided by engineer. */
"Message draft" = "Mesaj taslağı";
@@ -2475,6 +2508,12 @@
/* notification */
"message received" = "mesaj alındı";
/* No comment provided by engineer. */
"Message routing fallback" = "Mesaj yönlendirme yedeklemesi";
/* No comment provided by engineer. */
"Message routing mode" = "Mesaj yönlendirme modu";
/* No comment provided by engineer. */
"Message source remains private." = "Mesaj kaynağı gizli kalır.";
@@ -2586,6 +2625,9 @@
/* No comment provided by engineer. */
"Network connection" = "Ağ bağlantısı";
/* snd error text */
"Network issues - message expired after many attempts to send it." = "Ağ sorunları - birçok gönderme denemesinden sonra mesajın süresi doldu.";
/* No comment provided by engineer. */
"Network management" = "Ağ yönetimi";
@@ -2948,9 +2990,18 @@
/* No comment provided by engineer. */
"Private filenames" = "Gizli dosya adları";
/* No comment provided by engineer. */
"Private message routing" = "Gizli mesaj yönlendirme";
/* No comment provided by engineer. */
"Private message routing 🚀" = "Gizli mesaj yönlendirme 🚀";
/* name of notes to self */
"Private notes" = "Gizli notlar";
/* No comment provided by engineer. */
"Private routing" = "Gizli yönlendirme";
/* No comment provided by engineer. */
"Profile and server connections" = "Profil ve sunucu bağlantıları";
@@ -2985,7 +3036,7 @@
"Prohibit messages reactions." = "Mesajlarda tepkileri yasakla.";
/* No comment provided by engineer. */
"Prohibit sending direct messages to members." = "Geri dönülmez mesaj silme işlemini yasakla.";
"Prohibit sending direct messages to members." = "Üyelere doğrudan mesaj göndermeyi yasakla.";
/* No comment provided by engineer. */
"Prohibit sending disappearing messages." = "Kaybolan mesajların gönderimini yasakla.";
@@ -3002,9 +3053,15 @@
/* No comment provided by engineer. */
"Protect app screen" = "Uygulama ekranını koru";
/* No comment provided by engineer. */
"Protect IP address" = "IP adresini koru";
/* No comment provided by engineer. */
"Protect your chat profiles with a password!" = "Bir parolayla birlikte sohbet profillerini koru!";
/* No comment provided by engineer. */
"Protect your IP address from the messaging relays chosen by your contacts.\nEnable in *Network & servers* settings." = "IP adresinizi kişileriniz tarafından seçilen mesajlaşma yönlendiricilerinden koruyun.\n*Ağ ve sunucular* ayarlarında etkinleştirin.";
/* No comment provided by engineer. */
"Protocol timeout" = "Protokol zaman aşımı";
@@ -3117,10 +3174,10 @@
"rejected call" = "geri çevrilmiş çağrı";
/* No comment provided by engineer. */
"Relay server is only used if necessary. Another party can observe your IP address." = "Aktarma sunucusu yalnızca gerekli olduğunda kullanılır. Başka bir taraf IP adresinizi gözlemleyebilir.";
"Relay server is only used if necessary. Another party can observe your IP address." = "Yönlendirici sunucusu yalnızca gerekli olduğunda kullanılır. Başka bir taraf IP adresinizi gözlemleyebilir.";
/* No comment provided by engineer. */
"Relay server protects your IP address, but it can observe the duration of the call." = "Aktarıcı sunucu IP adresinizi korur, ancak aramanın süresini gözlemleyebilir.";
"Relay server protects your IP address, but it can observe the duration of the call." = "Yönlendirici sunucu IP adresinizi korur, ancak aramanın süresini gözlemleyebilir.";
/* No comment provided by engineer. */
"Remove" = "Sil";
@@ -3230,6 +3287,9 @@
/* No comment provided by engineer. */
"Run chat" = "Sohbeti çalıştır";
/* No comment provided by engineer. */
"Safely receive files" = "Dosyaları güvenle alın";
/* No comment provided by engineer. */
"Safer groups" = "Daha güvenli gruplar";
@@ -3386,6 +3446,12 @@
/* No comment provided by engineer. */
"Send live message" = "Canlı mesaj gönder";
/* No comment provided by engineer. */
"Send messages directly when IP address is protected and your or destination server does not support private routing." = "IP adresi korumalı olduğunda ve sizin veya hedef sunucunun özel yönlendirmeyi desteklemediği durumlarda mesajları doğrudan gönderin.";
/* No comment provided by engineer. */
"Send messages directly when your or destination server does not support private routing." = "Sizin veya hedef sunucunun özel yönlendirmeyi desteklemediği durumlarda mesajları doğrudan gönderin.";
/* No comment provided by engineer. */
"Send notifications" = "Bildirimler gönder";
@@ -3449,6 +3515,9 @@
/* No comment provided by engineer. */
"Sent messages will be deleted after set time." = "Gönderilen mesajlar ayarlanan süreden sonra silinecektir.";
/* srv error text. */
"Server address is incompatible with network settings." = "Sunucu adresi ağ ayarlarıyla uyumlu değil.";
/* server test error */
"Server requires authorization to create queues, check password" = "Sunucunun sıra oluşturması için yetki gereklidir, şifreyi kontrol edin";
@@ -3458,6 +3527,9 @@
/* No comment provided by engineer. */
"Server test failed!" = "Sunucu testinde hata oluştu!";
/* srv error text */
"Server version is incompatible with network settings." = "Sunucu sürümü ağ ayarlarıyla uyumlu değil.";
/* No comment provided by engineer. */
"Servers" = "Sunucular";
@@ -3524,6 +3596,9 @@
/* No comment provided by engineer. */
"Share with contacts" = "Kişilerle paylaş";
/* No comment provided by engineer. */
"Show → on messages sent via private routing." = "Gizli yönlendirme yoluyla gönderilen mesajlarda → işaretini göster.";
/* No comment provided by engineer. */
"Show calls in phone history" = "Telefon geçmişinde aramaları göster";
@@ -3533,6 +3608,9 @@
/* No comment provided by engineer. */
"Show last messages" = "Son mesajları göster";
/* No comment provided by engineer. */
"Show message status" = "Mesaj durumunu göster";
/* No comment provided by engineer. */
"Show preview" = "Ön gösterimi göser";
@@ -3740,6 +3818,9 @@
/* No comment provided by engineer. */
"The app can notify you when you receive messages or contact requests - please open settings to enable." = "Uygulama, mesaj veya iletişim isteği aldığınızda sizi bilgilendirebilir - etkinleştirmek için lütfen ayarları açın.";
/* No comment provided by engineer. */
"The app will ask to confirm downloads from unknown file servers (except .onion)." = "Uygulama bilinmeyen dosya sunucularından indirmeleri onaylamanızı isteyecektir (.onion hariç).";
/* No comment provided by engineer. */
"The attempt to change database passphrase was not completed." = "Veritabanı parolasını değiştirme girişimi tamamlanmadı.";
@@ -3860,6 +3941,9 @@
/* No comment provided by engineer. */
"To protect your information, turn on SimpleX Lock.\nYou will be prompted to complete authentication before this feature is enabled." = "Bilgilerinizi korumak için SimpleX Lock özelliğini açın.\nBu özellik etkinleştirilmeden önce kimlik doğrulamayı tamamlamanız istenecektir.";
/* No comment provided by engineer. */
"To protect your IP address, private routing uses your SMP servers to deliver messages." = "IP adresinizi korumak için,gizli yönlendirme mesajları iletmek için SMP sunucularınızı kullanır.";
/* No comment provided by engineer. */
"To record voice message please grant permission to use Microphone." = "Sesli mesaj kaydetmek için lütfen Mikrofon kullanım izni verin.";
@@ -3944,6 +4028,12 @@
/* No comment provided by engineer. */
"Unknown error" = "Bilinmeyen hata";
/* No comment provided by engineer. */
"unknown relays" = "bilinmeyen yönlendiriciler";
/* No comment provided by engineer. */
"Unknown servers!" = "Bilinmeyen sunucular!";
/* No comment provided by engineer. */
"unknown status" = "bilinmeyen durum";
@@ -3968,6 +4058,9 @@
/* No comment provided by engineer. */
"Unmute" = "Susturmayı kaldır";
/* No comment provided by engineer. */
"unprotected" = "korumasız";
/* No comment provided by engineer. */
"Unread" = "Okunmamış";
@@ -4037,6 +4130,12 @@
/* No comment provided by engineer. */
"Use only local notifications?" = "Sadece yerel bildirimler kullanılsın mı?";
/* No comment provided by engineer. */
"Use private routing with unknown servers when IP address is not protected." = "IP adresi korunmadığında bilinmeyen sunucularla gizli yönlendirme kullan.";
/* No comment provided by engineer. */
"Use private routing with unknown servers." = "Bilinmeyen sunucularla gizli yönlendirme kullan.";
/* No comment provided by engineer. */
"Use server" = "Sunucu kullan";
@@ -4190,6 +4289,9 @@
/* No comment provided by engineer. */
"When connecting audio and video calls." = "Sesli ve görüntülü aramalara bağlanırken.";
/* No comment provided by engineer. */
"when IP hidden" = "IP gizliyken";
/* No comment provided by engineer. */
"When people request to connect, you can accept or reject it." = "İnsanlar bağlantı talebinde bulunduğunda, kabul edebilir veya reddedebilirsiniz.";
@@ -4214,9 +4316,18 @@
/* No comment provided by engineer. */
"With reduced battery usage." = "Azaltılmış pil kullanımı ile birlikte.";
/* No comment provided by engineer. */
"Without Tor or VPN, your IP address will be visible to file servers." = "Tor veya VPN olmadan, IP adresiniz dosya sunucularına görülebilir.";
/* No comment provided by engineer. */
"Without Tor or VPN, your IP address will be visible to these XFTP relays: %@." = "Tor veya VPN olmadan, IP adresiniz bu XFTP aktarıcıları tarafından görülebilir: %@.";
/* No comment provided by engineer. */
"Wrong database passphrase" = "Yanlış veritabanı parolası";
/* snd error text */
"Wrong key or unknown connection - most likely this connection is deleted." = "Yanlış anahtar veya bilinmeyen bağlantı - büyük olasılıkla bu bağlantı silinmiştir.";
/* No comment provided by engineer. */
"Wrong passphrase!" = "Yanlış parola!";
+225
View File
@@ -389,6 +389,9 @@
/* member role */
"admin" = "адмін";
/* feature role */
"admins" = "адміністратори";
/* No comment provided by engineer. */
"Admins can block a member for all." = "Адміністратори можуть заблокувати користувача для всіх.";
@@ -416,6 +419,9 @@
/* No comment provided by engineer. */
"All group members will remain connected." = "Всі учасники групи залишаться на зв'язку.";
/* feature role */
"all members" = "всі учасники";
/* No comment provided by engineer. */
"All messages will be deleted - this cannot be undone!" = "Усі повідомлення будуть видалені - цю дію не можна скасувати!";
@@ -443,6 +449,9 @@
/* No comment provided by engineer. */
"Allow disappearing messages only if your contact allows it to you." = "Дозволяйте зникати повідомленням, тільки якщо контакт дозволяє вам це робити.";
/* No comment provided by engineer. */
"Allow downgrade" = "Дозволити пониження версії";
/* No comment provided by engineer. */
"Allow irreversible message deletion only if your contact allows it to you. (24 hours)" = "Дозволяйте безповоротне видалення повідомлень, тільки якщо контакт дозволяє вам це зробити. (24 години)";
@@ -464,6 +473,9 @@
/* No comment provided by engineer. */
"Allow to send files and media." = "Дозволяє надсилати файли та медіа.";
/* No comment provided by engineer. */
"Allow to send SimpleX links." = "Дозволити надсилати посилання SimpleX.";
/* No comment provided by engineer. */
"Allow to send voice messages." = "Дозволити надсилати голосові повідомлення.";
@@ -500,6 +512,9 @@
/* pref value */
"always" = "завжди";
/* No comment provided by engineer. */
"Always use private routing." = "Завжди використовуйте приватну маршрутизацію.";
/* No comment provided by engineer. */
"Always use relay" = "Завжди використовуйте реле";
@@ -707,6 +722,12 @@
/* No comment provided by engineer. */
"Cannot receive file" = "Не вдається отримати файл";
/* snd error text */
"Capacity exceeded - recipient did not receive previously sent messages." = "Перевищено ліміт - одержувач не отримав раніше надіслані повідомлення.";
/* No comment provided by engineer. */
"Cellular" = "Стільниковий";
/* No comment provided by engineer. */
"Change" = "Зміна";
@@ -840,6 +861,9 @@
/* No comment provided by engineer. */
"Confirm database upgrades" = "Підтвердити оновлення бази даних";
/* No comment provided by engineer. */
"Confirm files from unknown servers." = "Підтвердити файли з невідомих серверів.";
/* No comment provided by engineer. */
"Confirm network settings" = "Підтвердьте налаштування мережі";
@@ -1308,6 +1332,9 @@
/* No comment provided by engineer. */
"Desktop devices" = "Настільні пристрої";
/* snd error text */
"Destination server error: %@" = "Помилка сервера призначення: %@";
/* No comment provided by engineer. */
"Develop" = "Розробник";
@@ -1386,6 +1413,12 @@
/* No comment provided by engineer. */
"Do not send history to new members." = "Не надсилайте історію новим користувачам.";
/* No comment provided by engineer. */
"Do NOT send messages directly, even if your or destination server does not support private routing." = "НЕ надсилайте повідомлення напряму, навіть якщо ваш сервер або сервер призначення не підтримує приватну маршрутизацію.";
/* No comment provided by engineer. */
"Do NOT use private routing." = "НЕ використовуйте приватну маршрутизацію.";
/* No comment provided by engineer. */
"Do NOT use SimpleX for emergency calls." = "НЕ використовуйте SimpleX для екстрених викликів.";
@@ -1401,6 +1434,9 @@
/* No comment provided by engineer. */
"Downgrade and open chat" = "Пониження та відкритий чат";
/* chat item action */
"Download" = "Завантажити";
/* No comment provided by engineer. */
"Download failed" = "Не вдалося завантажити";
@@ -1476,6 +1512,9 @@
/* enabled status */
"enabled" = "увімкнено";
/* No comment provided by engineer. */
"Enabled for" = "Увімкнено для";
/* enabled status */
"enabled for contact" = "увімкнено для контакту";
@@ -1821,6 +1860,9 @@
/* No comment provided by engineer. */
"File: %@" = "Файл: %@";
/* No comment provided by engineer. */
"Files" = "Файли";
/* No comment provided by engineer. */
"Files & media" = "Файли та медіа";
@@ -1830,6 +1872,9 @@
/* No comment provided by engineer. */
"Files and media are prohibited in this group." = "Файли та медіа в цій групі заборонені.";
/* No comment provided by engineer. */
"Files and media not allowed" = "Файли та медіафайли заборонені";
/* No comment provided by engineer. */
"Files and media prohibited!" = "Файли та медіа заборонені!";
@@ -1869,6 +1914,27 @@
/* No comment provided by engineer. */
"For console" = "Для консолі";
/* chat item action */
"Forward" = "Пересилання";
/* No comment provided by engineer. */
"Forward and save messages" = "Пересилання та збереження повідомлень";
/* No comment provided by engineer. */
"forwarded" = "переслано";
/* No comment provided by engineer. */
"Forwarded" = "Переслано";
/* No comment provided by engineer. */
"Forwarded from" = "Переслано з";
/* snd error text */
"Forwarding server: %@\nDestination server error: %@" = "Сервер переадресації: %1$@\nПомилка сервера призначення: %2$@";
/* snd error text */
"Forwarding server: %@\nError: %@" = "Сервер переадресації: %1$@\nПомилка: %2$@";
/* No comment provided by engineer. */
"Found desktop" = "Знайдено робочий стіл";
@@ -1947,6 +2013,9 @@
/* No comment provided by engineer. */
"Group members can send files and media." = "Учасники групи можуть надсилати файли та медіа.";
/* No comment provided by engineer. */
"Group members can send SimpleX links." = "Учасники групи можуть надсилати посилання SimpleX.";
/* No comment provided by engineer. */
"Group members can send voice messages." = "Учасники групи можуть надсилати голосові повідомлення.";
@@ -2088,6 +2157,9 @@
/* No comment provided by engineer. */
"In reply to" = "У відповідь на";
/* No comment provided by engineer. */
"In-call sounds" = "Звуки вхідного дзвінка";
/* No comment provided by engineer. */
"Incognito" = "Інкогніто";
@@ -2418,6 +2490,9 @@
/* No comment provided by engineer. */
"Message delivery receipts!" = "Підтвердження доставки повідомлення!";
/* item status text */
"Message delivery warning" = "Попередження про доставку повідомлення";
/* No comment provided by engineer. */
"Message draft" = "Чернетка повідомлення";
@@ -2433,6 +2508,15 @@
/* notification */
"message received" = "повідомлення отримано";
/* No comment provided by engineer. */
"Message routing fallback" = "Запасний варіант маршрутизації повідомлень";
/* No comment provided by engineer. */
"Message routing mode" = "Режим маршрутизації повідомлень";
/* No comment provided by engineer. */
"Message source remains private." = "Джерело повідомлення залишається приватним.";
/* No comment provided by engineer. */
"Message text" = "Текст повідомлення";
@@ -2517,6 +2601,9 @@
/* No comment provided by engineer. */
"More improvements are coming soon!" = "Незабаром буде ще більше покращень!";
/* No comment provided by engineer. */
"More reliable network connection." = "Більш надійне з'єднання з мережею.";
/* item status description */
"Most likely this connection is deleted." = "Швидше за все, це з'єднання видалено.";
@@ -2535,6 +2622,15 @@
/* No comment provided by engineer. */
"Network & servers" = "Мережа та сервери";
/* No comment provided by engineer. */
"Network connection" = "Підключення до мережі";
/* snd error text */
"Network issues - message expired after many attempts to send it." = "Проблеми з мережею - термін дії повідомлення закінчився після багатьох спроб надіслати його.";
/* No comment provided by engineer. */
"Network management" = "Керування мережею";
/* No comment provided by engineer. */
"Network settings" = "Налаштування мережі";
@@ -2613,6 +2709,9 @@
/* No comment provided by engineer. */
"No history" = "Немає історії";
/* No comment provided by engineer. */
"No network connection" = "Немає підключення до мережі";
/* No comment provided by engineer. */
"No permission to record voice message" = "Немає дозволу на запис голосового повідомлення";
@@ -2759,9 +2858,15 @@
/* No comment provided by engineer. */
"Or show this code" = "Або покажіть цей код";
/* No comment provided by engineer. */
"Other" = "Інше";
/* member role */
"owner" = "власник";
/* feature role */
"owners" = "власники";
/* No comment provided by engineer. */
"Passcode" = "Пароль";
@@ -2885,15 +2990,27 @@
/* No comment provided by engineer. */
"Private filenames" = "Приватні імена файлів";
/* No comment provided by engineer. */
"Private message routing" = "Маршрутизація приватних повідомлень";
/* No comment provided by engineer. */
"Private message routing 🚀" = "Маршрутизація приватних повідомлень 🚀";
/* name of notes to self */
"Private notes" = "Приватні нотатки";
/* No comment provided by engineer. */
"Private routing" = "Приватна маршрутизація";
/* No comment provided by engineer. */
"Profile and server connections" = "З'єднання профілю та сервера";
/* No comment provided by engineer. */
"Profile image" = "Зображення профілю";
/* No comment provided by engineer. */
"Profile images" = "Зображення профілю";
/* No comment provided by engineer. */
"Profile name" = "Назва профілю";
@@ -2927,15 +3044,24 @@
/* No comment provided by engineer. */
"Prohibit sending files and media." = "Заборонити надсилання файлів і медіа.";
/* No comment provided by engineer. */
"Prohibit sending SimpleX links." = "Заборонити надсилання посилань SimpleX.";
/* No comment provided by engineer. */
"Prohibit sending voice messages." = "Заборонити надсилання голосових повідомлень.";
/* No comment provided by engineer. */
"Protect app screen" = "Захистіть екран програми";
/* No comment provided by engineer. */
"Protect IP address" = "Захист IP-адреси";
/* No comment provided by engineer. */
"Protect your chat profiles with a password!" = "Захистіть свої профілі чату паролем!";
/* No comment provided by engineer. */
"Protect your IP address from the messaging relays chosen by your contacts.\nEnable in *Network & servers* settings." = "Захистіть свою IP-адресу від ретрансляторів повідомлень, обраних вашими контактами.\nУвімкніть у налаштуваннях *Мережа та сервери*.";
/* No comment provided by engineer. */
"Protocol timeout" = "Тайм-аут протоколу";
@@ -3014,6 +3140,9 @@
/* No comment provided by engineer. */
"Recent history and improved [directory bot](simplex:/contact#/?v=1-4&smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion)." = "Нещодавня історія та покращення [directory bot](simplex:/contact#/?v=1-4&smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).";
/* No comment provided by engineer. */
"Recipient(s) can't see who this message is from." = "Одержувач(и) не бачить, від кого це повідомлення.";
/* No comment provided by engineer. */
"Recipients see updates as you type them." = "Одержувачі бачать оновлення, коли ви їх вводите.";
@@ -3158,6 +3287,9 @@
/* No comment provided by engineer. */
"Run chat" = "Запустити чат";
/* No comment provided by engineer. */
"Safely receive files" = "Безпечне отримання файлів";
/* No comment provided by engineer. */
"Safer groups" = "Безпечніші групи";
@@ -3209,6 +3341,18 @@
/* No comment provided by engineer. */
"Save welcome message?" = "Зберегти вітальне повідомлення?";
/* No comment provided by engineer. */
"saved" = "збережено";
/* No comment provided by engineer. */
"Saved" = "Збережено";
/* No comment provided by engineer. */
"Saved from" = "Збережено з";
/* No comment provided by engineer. */
"saved from %@" = "збережено з %@";
/* message info title */
"Saved message" = "Збережене повідомлення";
@@ -3302,6 +3446,12 @@
/* No comment provided by engineer. */
"Send live message" = "Надіслати живе повідомлення";
/* No comment provided by engineer. */
"Send messages directly when IP address is protected and your or destination server does not support private routing." = "Надсилайте повідомлення напряму, якщо IP-адреса захищена, а ваш сервер або сервер призначення не підтримує приватну маршрутизацію.";
/* No comment provided by engineer. */
"Send messages directly when your or destination server does not support private routing." = "Надсилайте повідомлення напряму, якщо ваш сервер або сервер призначення не підтримує приватну маршрутизацію.";
/* No comment provided by engineer. */
"Send notifications" = "Надсилати сповіщення";
@@ -3365,6 +3515,9 @@
/* No comment provided by engineer. */
"Sent messages will be deleted after set time." = "Надіслані повідомлення будуть видалені через встановлений час.";
/* srv error text. */
"Server address is incompatible with network settings." = "Адреса сервера несумісна з налаштуваннями мережі.";
/* server test error */
"Server requires authorization to create queues, check password" = "Сервер вимагає авторизації для створення черг, перевірте пароль";
@@ -3374,6 +3527,9 @@
/* No comment provided by engineer. */
"Server test failed!" = "Тест сервера завершився невдало!";
/* srv error text */
"Server version is incompatible with network settings." = "Серверна версія несумісна з мережевими налаштуваннями.";
/* No comment provided by engineer. */
"Servers" = "Сервери";
@@ -3416,6 +3572,9 @@
/* No comment provided by engineer. */
"Settings" = "Налаштування";
/* No comment provided by engineer. */
"Shape profile images" = "Сформуйте зображення профілю";
/* chat item action */
"Share" = "Поділіться";
@@ -3437,6 +3596,9 @@
/* No comment provided by engineer. */
"Share with contacts" = "Поділіться з контактами";
/* No comment provided by engineer. */
"Show → on messages sent via private routing." = "Показувати → у повідомленнях, надісланих через приватну маршрутизацію.";
/* No comment provided by engineer. */
"Show calls in phone history" = "Показувати дзвінки в історії дзвінків";
@@ -3446,6 +3608,9 @@
/* No comment provided by engineer. */
"Show last messages" = "Показати останні повідомлення";
/* No comment provided by engineer. */
"Show message status" = "Показати статус повідомлення";
/* No comment provided by engineer. */
"Show preview" = "Показати попередній перегляд";
@@ -3476,6 +3641,12 @@
/* chat feature */
"SimpleX links" = "Посилання SimpleX";
/* No comment provided by engineer. */
"SimpleX links are prohibited in this group." = "У цій групі заборонені посилання на SimpleX.";
/* No comment provided by engineer. */
"SimpleX links not allowed" = "Посилання SimpleX заборонені";
/* No comment provided by engineer. */
"SimpleX Lock" = "SimpleX Lock";
@@ -3512,6 +3683,9 @@
/* notification title */
"Somebody" = "Хтось";
/* No comment provided by engineer. */
"Square, circle, or anything in between." = "Квадрат, коло або щось середнє між ними.";
/* chat item text */
"standard end-to-end encryption" = "стандартне наскрізне шифрування";
@@ -3644,6 +3818,9 @@
/* No comment provided by engineer. */
"The app can notify you when you receive messages or contact requests - please open settings to enable." = "Додаток може сповіщати вас, коли ви отримуєте повідомлення або запити на контакт - будь ласка, відкрийте налаштування, щоб увімкнути цю функцію.";
/* No comment provided by engineer. */
"The app will ask to confirm downloads from unknown file servers (except .onion)." = "Програма попросить підтвердити завантаження з невідомих файлових серверів (крім .onion).";
/* No comment provided by engineer. */
"The attempt to change database passphrase was not completed." = "Спроба змінити пароль до бази даних не була завершена.";
@@ -3764,6 +3941,9 @@
/* No comment provided by engineer. */
"To protect your information, turn on SimpleX Lock.\nYou will be prompted to complete authentication before this feature is enabled." = "Щоб захистити вашу інформацію, увімкніть SimpleX Lock.\nПеред увімкненням цієї функції вам буде запропоновано пройти автентифікацію.";
/* No comment provided by engineer. */
"To protect your IP address, private routing uses your SMP servers to deliver messages." = "Щоб захистити вашу IP-адресу, приватна маршрутизація використовує ваші SMP-сервери для доставки повідомлень.";
/* No comment provided by engineer. */
"To record voice message please grant permission to use Microphone." = "Щоб записати голосове повідомлення, будь ласка, надайте дозвіл на використання мікрофону.";
@@ -3848,6 +4028,12 @@
/* No comment provided by engineer. */
"Unknown error" = "Невідома помилка";
/* No comment provided by engineer. */
"unknown relays" = "невідомі реле";
/* No comment provided by engineer. */
"Unknown servers!" = "Невідомі сервери!";
/* No comment provided by engineer. */
"unknown status" = "невідомий статус";
@@ -3872,6 +4058,9 @@
/* No comment provided by engineer. */
"Unmute" = "Увімкнути звук";
/* No comment provided by engineer. */
"unprotected" = "незахищені";
/* No comment provided by engineer. */
"Unread" = "Непрочитане";
@@ -3941,6 +4130,12 @@
/* No comment provided by engineer. */
"Use only local notifications?" = "Використовувати лише локальні сповіщення?";
/* No comment provided by engineer. */
"Use private routing with unknown servers when IP address is not protected." = "Використовуйте приватну маршрутизацію з невідомими серверами, якщо IP-адреса не захищена.";
/* No comment provided by engineer. */
"Use private routing with unknown servers." = "Використовуйте приватну маршрутизацію з невідомими серверами.";
/* No comment provided by engineer. */
"Use server" = "Використовувати сервер";
@@ -4037,6 +4232,9 @@
/* No comment provided by engineer. */
"Voice messages are prohibited in this group." = "Голосові повідомлення в цій групі заборонені.";
/* No comment provided by engineer. */
"Voice messages not allowed" = "Голосові повідомлення заборонені";
/* No comment provided by engineer. */
"Voice messages prohibited!" = "Голосові повідомлення заборонені!";
@@ -4088,12 +4286,27 @@
/* No comment provided by engineer. */
"When available" = "За наявності";
/* No comment provided by engineer. */
"When connecting audio and video calls." = "При підключенні аудіо та відеодзвінків.";
/* No comment provided by engineer. */
"when IP hidden" = "коли IP приховано";
/* No comment provided by engineer. */
"When people request to connect, you can accept or reject it." = "Коли люди звертаються із запитом на підключення, ви можете прийняти або відхилити його.";
/* No comment provided by engineer. */
"When you share an incognito profile with somebody, this profile will be used for the groups they invite you to." = "Коли ви ділитеся з кимось своїм профілем інкогніто, цей профіль буде використовуватися для груп, до яких вас запрошують.";
/* No comment provided by engineer. */
"WiFi" = "WiFi";
/* No comment provided by engineer. */
"Will be enabled in direct chats!" = "Буде ввімкнено в прямих чатах!";
/* No comment provided by engineer. */
"Wired ethernet" = "Дротова мережа Ethernet";
/* No comment provided by engineer. */
"With encrypted files and media." = "З зашифрованими файлами та медіа.";
@@ -4103,9 +4316,18 @@
/* No comment provided by engineer. */
"With reduced battery usage." = "З меншим споживанням заряду акумулятора.";
/* No comment provided by engineer. */
"Without Tor or VPN, your IP address will be visible to file servers." = "Без Tor або VPN ваша IP-адреса буде видимою для файлових серверів.";
/* No comment provided by engineer. */
"Without Tor or VPN, your IP address will be visible to these XFTP relays: %@." = "Без Tor або VPN ваша IP-адреса буде видимою для цих XFTP-ретрансляторів: %@.";
/* No comment provided by engineer. */
"Wrong database passphrase" = "Неправильний пароль до бази даних";
/* snd error text */
"Wrong key or unknown connection - most likely this connection is deleted." = "Неправильний ключ або невідоме з'єднання - швидше за все, це з'єднання видалено.";
/* No comment provided by engineer. */
"Wrong passphrase!" = "Неправильний пароль!";
@@ -4115,6 +4337,9 @@
/* pref value */
"yes" = "так";
/* No comment provided by engineer. */
"you" = "ти";
/* No comment provided by engineer. */
"You" = "Ти";
@@ -1,4 +1,4 @@
package chat.simplex.common.views.chatlist
package chat.simplex.common.views.home
import android.app.Activity
import androidx.compose.foundation.*
@@ -4,16 +4,12 @@ import androidx.compose.animation.core.Animatable
import androidx.compose.foundation.*
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.*
import androidx.compose.material.ripple.rememberRipple
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.clipToBounds
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.unit.dp
import chat.simplex.common.views.usersettings.SetDeliveryReceiptsView
@@ -28,6 +24,7 @@ import chat.simplex.common.views.chat.ChatView
import chat.simplex.common.views.chatlist.*
import chat.simplex.common.views.database.DatabaseErrorView
import chat.simplex.common.views.helpers.*
import chat.simplex.common.views.home.*
import chat.simplex.common.views.localauth.VerticalDivider
import chat.simplex.common.views.onboarding.*
import chat.simplex.common.views.usersettings.*
@@ -287,7 +284,7 @@ fun StartPartOfScreen(settingsState: SettingsViewState) {
} else {
val stopped = chatModel.chatRunning.value == false
if (chatModel.sharedContent.value == null)
ChatListView(chatModel, settingsState, AppLock::setPerformLA, stopped)
HomeView(chatModel, settingsState, AppLock::setPerformLA, stopped)
else
ShareListView(chatModel, settingsState, stopped)
}
@@ -779,6 +779,7 @@ interface SomeChat {
val id: ChatId
val apiId: Long
val ready: Boolean
val chatDeleted: Boolean
val sendMsgEnabled: Boolean
val ntfsEnabled: Boolean
val incognito: Boolean
@@ -859,6 +860,7 @@ sealed class ChatInfo: SomeChat, NamedChat {
override val id get() = contact.id
override val apiId get() = contact.apiId
override val ready get() = contact.ready
override val chatDeleted get() = contact.chatDeleted
override val sendMsgEnabled get() = contact.sendMsgEnabled
override val ntfsEnabled get() = contact.ntfsEnabled
override val incognito get() = contact.incognito
@@ -883,6 +885,7 @@ sealed class ChatInfo: SomeChat, NamedChat {
override val id get() = groupInfo.id
override val apiId get() = groupInfo.apiId
override val ready get() = groupInfo.ready
override val chatDeleted get() = groupInfo.chatDeleted
override val sendMsgEnabled get() = groupInfo.sendMsgEnabled
override val ntfsEnabled get() = groupInfo.ntfsEnabled
override val incognito get() = groupInfo.incognito
@@ -907,6 +910,7 @@ sealed class ChatInfo: SomeChat, NamedChat {
override val id get() = noteFolder.id
override val apiId get() = noteFolder.apiId
override val ready get() = noteFolder.ready
override val chatDeleted get() = noteFolder.chatDeleted
override val sendMsgEnabled get() = noteFolder.sendMsgEnabled
override val ntfsEnabled get() = noteFolder.ntfsEnabled
override val incognito get() = noteFolder.incognito
@@ -931,6 +935,7 @@ sealed class ChatInfo: SomeChat, NamedChat {
override val id get() = contactRequest.id
override val apiId get() = contactRequest.apiId
override val ready get() = contactRequest.ready
override val chatDeleted get() = contactRequest.chatDeleted
override val sendMsgEnabled get() = contactRequest.sendMsgEnabled
override val ntfsEnabled get() = contactRequest.ntfsEnabled
override val incognito get() = contactRequest.incognito
@@ -955,6 +960,7 @@ sealed class ChatInfo: SomeChat, NamedChat {
override val id get() = contactConnection.id
override val apiId get() = contactConnection.apiId
override val ready get() = contactConnection.ready
override val chatDeleted get() = contactConnection.chatDeleted
override val sendMsgEnabled get() = contactConnection.sendMsgEnabled
override val ntfsEnabled get() = false
override val incognito get() = contactConnection.incognito
@@ -980,6 +986,7 @@ sealed class ChatInfo: SomeChat, NamedChat {
override val id get() = ""
override val apiId get() = 0L
override val ready get() = false
override val chatDeleted get() = false
override val sendMsgEnabled get() = false
override val ntfsEnabled get() = false
override val incognito get() = false
@@ -1056,6 +1063,7 @@ data class Contact(
val chatTs: Instant?,
val contactGroupMemberId: Long? = null,
val contactGrpInvSent: Boolean,
override val chatDeleted: Boolean,
val uiThemes: ThemeModeOverrides? = null,
): SomeChat, NamedChat {
override val chatType get() = ChatType.Direct
@@ -1129,6 +1137,7 @@ data class Contact(
updatedAt = Clock.System.now(),
chatTs = Clock.System.now(),
contactGrpInvSent = false,
chatDeleted = false,
uiThemes = null,
)
}
@@ -1137,7 +1146,8 @@ data class Contact(
@Serializable
enum class ContactStatus {
@SerialName("active") Active,
@SerialName("deleted") Deleted;
@SerialName("deleted") Deleted,
@SerialName("deletedByUser") DeletedByUser;
}
@Serializable
@@ -1276,6 +1286,7 @@ data class GroupInfo (
override val id get() = "#$groupId"
override val apiId get() = groupId
override val ready get() = membership.memberActive
override val chatDeleted get() = false
override val sendMsgEnabled get() = membership.memberActive
override val ntfsEnabled get() = chatSettings.enableNtfs == MsgFilter.All
override val incognito get() = membership.memberIncognito
@@ -1581,6 +1592,7 @@ class NoteFolder(
override val chatType get() = ChatType.Local
override val id get() = "*$noteFolderId"
override val apiId get() = noteFolderId
override val chatDeleted get() = false
override val ready get() = true
override val sendMsgEnabled get() = true
override val ntfsEnabled get() = false
@@ -1617,6 +1629,7 @@ class UserContactRequest (
override val chatType get() = ChatType.ContactRequest
override val id get() = "<@$contactRequestId"
override val apiId get() = contactRequestId
override val chatDeleted get() = false
override val ready get() = true
override val sendMsgEnabled get() = false
override val ntfsEnabled get() = false
@@ -1656,6 +1669,7 @@ class PendingContactConnection(
override val chatType get() = ChatType.ContactConnection
override val id get () = ":$pccConnId"
override val apiId get() = pccConnId
override val chatDeleted get() = false
override val ready get() = false
override val sendMsgEnabled get() = false
override val ntfsEnabled get() = false
@@ -2660,6 +2674,7 @@ data class CIFile(
is CIFileStatus.SndComplete -> true
is CIFileStatus.SndCancelled -> true
is CIFileStatus.SndError -> true
is CIFileStatus.SndWarning -> true
is CIFileStatus.RcvInvitation -> false
is CIFileStatus.RcvAccepted -> false
is CIFileStatus.RcvTransfer -> false
@@ -2667,6 +2682,7 @@ data class CIFile(
is CIFileStatus.RcvCancelled -> false
is CIFileStatus.RcvComplete -> true
is CIFileStatus.RcvError -> false
is CIFileStatus.RcvWarning -> false
is CIFileStatus.Invalid -> false
}
@@ -2682,6 +2698,7 @@ data class CIFile(
}
is CIFileStatus.SndCancelled -> null
is CIFileStatus.SndError -> null
is CIFileStatus.SndWarning -> sndCancelAction
is CIFileStatus.RcvInvitation -> null
is CIFileStatus.RcvAccepted -> rcvCancelAction
is CIFileStatus.RcvTransfer -> rcvCancelAction
@@ -2689,6 +2706,7 @@ data class CIFile(
is CIFileStatus.RcvCancelled -> null
is CIFileStatus.RcvComplete -> null
is CIFileStatus.RcvError -> null
is CIFileStatus.RcvWarning -> rcvCancelAction
is CIFileStatus.Invalid -> null
}
@@ -2862,14 +2880,16 @@ sealed class CIFileStatus {
@Serializable @SerialName("sndTransfer") class SndTransfer(val sndProgress: Long, val sndTotal: Long): CIFileStatus()
@Serializable @SerialName("sndComplete") object SndComplete: CIFileStatus()
@Serializable @SerialName("sndCancelled") object SndCancelled: CIFileStatus()
@Serializable @SerialName("sndError") object SndError: CIFileStatus()
@Serializable @SerialName("sndError") class SndError(val sndFileError: FileError): CIFileStatus()
@Serializable @SerialName("sndWarning") class SndWarning(val sndFileError: FileError): CIFileStatus()
@Serializable @SerialName("rcvInvitation") object RcvInvitation: CIFileStatus()
@Serializable @SerialName("rcvAccepted") object RcvAccepted: CIFileStatus()
@Serializable @SerialName("rcvTransfer") class RcvTransfer(val rcvProgress: Long, val rcvTotal: Long): CIFileStatus()
@Serializable @SerialName("rcvAborted") object RcvAborted: CIFileStatus()
@Serializable @SerialName("rcvComplete") object RcvComplete: CIFileStatus()
@Serializable @SerialName("rcvCancelled") object RcvCancelled: CIFileStatus()
@Serializable @SerialName("rcvError") object RcvError: CIFileStatus()
@Serializable @SerialName("rcvError") class RcvError(val rcvFileError: FileError): CIFileStatus()
@Serializable @SerialName("rcvWarning") class RcvWarning(val rcvFileError: FileError): CIFileStatus()
@Serializable @SerialName("invalid") class Invalid(val text: String): CIFileStatus()
val sent: Boolean get() = when (this) {
@@ -2878,6 +2898,7 @@ sealed class CIFileStatus {
is SndComplete -> true
is SndCancelled -> true
is SndError -> true
is SndWarning -> true
is RcvInvitation -> false
is RcvAccepted -> false
is RcvTransfer -> false
@@ -2885,10 +2906,26 @@ sealed class CIFileStatus {
is RcvComplete -> false
is RcvCancelled -> false
is RcvError -> false
is RcvWarning -> false
is Invalid -> false
}
}
@Serializable
sealed class FileError {
@Serializable @SerialName("auth") class Auth: FileError()
@Serializable @SerialName("noFile") class NoFile: FileError()
@Serializable @SerialName("relay") class Relay(val srvError: SrvError): FileError()
@Serializable @SerialName("other") class Other(val fileError: String): FileError()
val errorInfo: String get() = when (this) {
is FileError.Auth -> generalGetString(MR.strings.file_error_auth)
is FileError.NoFile -> generalGetString(MR.strings.file_error_no_file)
is FileError.Relay -> generalGetString(MR.strings.file_error_relay).format(srvError.errorInfo)
is FileError.Other -> generalGetString(MR.strings.ci_status_other_error).format(fileError)
}
}
@Suppress("SERIALIZER_TYPE_INCOMPATIBLE")
@Serializable(with = MsgContentSerializer::class)
sealed class MsgContent {
@@ -2902,6 +2939,20 @@ sealed class MsgContent {
@Serializable(with = MsgContentSerializer::class) class MCFile(override val text: String): MsgContent()
@Serializable(with = MsgContentSerializer::class) class MCUnknown(val type: String? = null, override val text: String, val json: JsonElement): MsgContent()
val isVoice: Boolean get() =
when (this) {
is MCVoice -> true
else -> false
}
val isMediaOrFileAttachment: Boolean get() =
when (this) {
is MCImage -> true
is MCVideo -> true
is MCFile -> true
else -> false
}
val cmdString: String get() =
if (this is MCUnknown) "json $json" else "json ${json.encodeToString(this)}"
}
@@ -1,9 +1,18 @@
package chat.simplex.common.model
import SectionItemView
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import chat.simplex.common.views.helpers.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.style.TextAlign
import chat.simplex.common.model.ChatController.getNetCfg
import chat.simplex.common.model.ChatController.setNetCfg
import chat.simplex.common.model.ChatModel.updatingChatsMutex
@@ -12,7 +21,6 @@ import dev.icerock.moko.resources.compose.painterResource
import chat.simplex.common.platform.*
import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.call.*
import chat.simplex.common.views.chat.group.toggleShowMemberMessages
import chat.simplex.common.views.migration.MigrationFileLinkData
import chat.simplex.common.views.onboarding.OnboardingStage
import chat.simplex.common.views.usersettings.*
@@ -20,6 +28,7 @@ import com.charleskorn.kaml.Yaml
import com.charleskorn.kaml.YamlConfiguration
import chat.simplex.res.MR
import com.russhwolf.settings.Settings
import dev.icerock.moko.resources.compose.stringResource
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.sync.withLock
@@ -195,6 +204,8 @@ class AppPreferences {
val desktopWindowState = mkStrPreference(SHARED_PREFS_DESKTOP_WINDOW_STATE, null)
val showDeleteConversationNotice = mkBoolPreference(SHARED_PREFS_SHOW_DELETE_CONVERSATION_NOTICE, true)
val showDeleteContactNotice = mkBoolPreference(SHARED_PREFS_SHOW_DELETE_CONTACT_NOTICE, true)
val showSentViaProxy = mkBoolPreference(SHARED_PREFS_SHOW_SENT_VIA_RPOXY, false)
@@ -371,6 +382,8 @@ class AppPreferences {
private const val SHARED_PREFS_CONNECT_REMOTE_VIA_MULTICAST_AUTO = "ConnectRemoteViaMulticastAuto"
private const val SHARED_PREFS_OFFER_REMOTE_MULTICAST = "OfferRemoteMulticast"
private const val SHARED_PREFS_DESKTOP_WINDOW_STATE = "DesktopWindowState"
private const val SHARED_PREFS_SHOW_DELETE_CONVERSATION_NOTICE = "showDeleteConversationNotice"
private const val SHARED_PREFS_SHOW_DELETE_CONTACT_NOTICE = "showDeleteContactNotice"
private const val SHARED_PREFS_SHOW_SENT_VIA_RPOXY = "showSentViaProxy"
private const val SHARED_PREFS_IOS_CALL_KIT_ENABLED = "iOSCallKitEnabled"
@@ -1099,16 +1112,16 @@ object ChatController {
}
}
suspend fun deleteChat(chat: Chat, notify: Boolean? = null) {
suspend fun deleteChat(chat: Chat, chatDeleteMode: ChatDeleteMode = ChatDeleteMode.Full(notify = true)) {
val cInfo = chat.chatInfo
if (apiDeleteChat(rh = chat.remoteHostId, type = cInfo.chatType, id = cInfo.apiId, notify = notify)) {
if (apiDeleteChat(rh = chat.remoteHostId, type = cInfo.chatType, id = cInfo.apiId, chatDeleteMode = chatDeleteMode)) {
chatModel.removeChat(chat.remoteHostId, cInfo.id)
}
}
suspend fun apiDeleteChat(rh: Long?, type: ChatType, id: Long, notify: Boolean? = null): Boolean {
suspend fun apiDeleteChat(rh: Long?, type: ChatType, id: Long, chatDeleteMode: ChatDeleteMode = ChatDeleteMode.Full(notify = true)): Boolean {
chatModel.deletedChats.value += rh to type.type + id
val r = sendCmd(rh, CC.ApiDeleteChat(type, id, notify))
val r = sendCmd(rh, CC.ApiDeleteChat(type, id, chatDeleteMode))
val success = when {
r is CR.ContactDeleted && type == ChatType.Direct -> true
r is CR.ContactConnectionDeleted && type == ChatType.ContactConnection -> true
@@ -1129,6 +1142,22 @@ object ChatController {
return success
}
suspend fun apiDeleteContact(rh: Long?, id: Long, chatDeleteMode: ChatDeleteMode = ChatDeleteMode.Full(notify = true)): Contact? {
val type = ChatType.Direct
chatModel.deletedChats.value += rh to type.type + id
val r = sendCmd(rh, CC.ApiDeleteChat(type, id, chatDeleteMode))
val contact = when {
r is CR.ContactDeleted -> r.contact
else -> {
val titleId = MR.strings.error_deleting_contact
apiErrorAlert("apiDeleteChat", generalGetString(titleId), r)
null
}
}
chatModel.deletedChats.value -= rh to type.type + id
return contact
}
fun clearChat(chat: Chat, close: (() -> Unit)? = null) {
withBGApi {
val updatedChatInfo = apiClearChat(chat.remoteHostId, chat.chatInfo.chatType, chat.chatInfo.apiId)
@@ -1867,6 +1896,10 @@ object ChatController {
val cInfo = r.chatItem.chatInfo
val cItem = r.chatItem.chatItem
if (active(r.user)) {
if (cInfo is ChatInfo.Direct && cInfo.chatDeleted) {
val updatedContact = cInfo.contact.copy(chatDeleted = false)
chatModel.updateContact(rhId, updatedContact)
}
chatModel.addChatItem(rhId, cInfo, cItem)
} else if (cItem.isRcvNew && cInfo.ntfsEnabled) {
chatModel.increaseUnreadCounter(rhId, r.user)
@@ -2026,6 +2059,11 @@ object ChatController {
cleanupFile(r.chatItem_)
}
}
is CR.RcvFileWarning -> {
if (r.chatItem_ != null) {
chatItemSimpleUpdate(rhId, r.user, r.chatItem_)
}
}
is CR.SndFileStart ->
chatItemSimpleUpdate(rhId, r.user, r.chatItem)
is CR.SndFileComplete -> {
@@ -2052,6 +2090,11 @@ object ChatController {
cleanupFile(r.chatItem_)
}
}
is CR.SndFileWarning -> {
if (r.chatItem_ != null) {
chatItemSimpleUpdate(rhId, r.user, r.chatItem_)
}
}
is CR.CallInvitation -> {
chatModel.callManager.reportNewIncomingCall(r.callInvitation.copy(remoteHostId = rhId))
}
@@ -2184,15 +2227,43 @@ object ChatController {
val sess = chatModel.remoteCtrlSession.value
if (sess != null) {
chatModel.remoteCtrlSession.value = null
ModalManager.fullscreen.closeModals()
fun showAlert(chatError: ChatError) {
AlertManager.shared.showAlertMsg(
generalGetString(MR.strings.remote_ctrl_was_disconnected_title),
if (chatError is ChatError.ChatErrorRemoteCtrl) {
chatError.remoteCtrlError.localizedString
} else {
generalGetString(MR.strings.remote_ctrl_disconnected_with_reason).format(chatError.string)
}
)
when {
r.rcStopReason is RemoteCtrlStopReason.ConnectionFailed
&& r.rcStopReason.chatError is ChatError.ChatErrorAgent
&& r.rcStopReason.chatError.agentError is AgentErrorType.RCP
&& r.rcStopReason.chatError.agentError.rcpErr is RCErrorType.IDENTITY ->
AlertManager.shared.showAlertMsg(
title = generalGetString(MR.strings.remote_ctrl_was_disconnected_title),
text = generalGetString(MR.strings.remote_ctrl_connection_stopped_identity_desc)
)
else ->
AlertManager.shared.showAlertDialogButtonsColumn(
title = generalGetString(MR.strings.remote_ctrl_was_disconnected_title),
text = if (chatError is ChatError.ChatErrorRemoteCtrl) {
chatError.remoteCtrlError.localizedString
} else {
generalGetString(MR.strings.remote_ctrl_connection_stopped_desc)
},
buttons = {
Column {
SectionItemView({
AlertManager.shared.hideAlert()
}) {
Text(stringResource(MR.strings.ok), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.primary)
}
val clipboard = LocalClipboardManager.current
SectionItemView({
clipboard.setText(AnnotatedString(json.encodeToString(r.rcStopReason)))
AlertManager.shared.hideAlert()
}) {
Text(stringResource(MR.strings.copy_error), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.primary)
}
}
}
)
}
}
when (r.rcStopReason) {
is RemoteCtrlStopReason.DiscoveryFailed -> showAlert(r.rcStopReason.chatError)
@@ -2538,7 +2609,7 @@ sealed class CC {
class APIConnectPlan(val userId: Long, val connReq: String): CC()
class APIConnect(val userId: Long, val incognito: Boolean, val connReq: String): CC()
class ApiConnectContactViaAddress(val userId: Long, val incognito: Boolean, val contactId: Long): CC()
class ApiDeleteChat(val type: ChatType, val id: Long, val notify: Boolean?): CC()
class ApiDeleteChat(val type: ChatType, val id: Long, val chatDeleteMode: ChatDeleteMode): CC()
class ApiClearChat(val type: ChatType, val id: Long): CC()
class ApiListContacts(val userId: Long): CC()
class ApiUpdateProfile(val userId: Long, val profile: Profile): CC()
@@ -2685,11 +2756,7 @@ sealed class CC {
is APIConnectPlan -> "/_connect plan $userId $connReq"
is APIConnect -> "/_connect $userId incognito=${onOff(incognito)} $connReq"
is ApiConnectContactViaAddress -> "/_connect contact $userId incognito=${onOff(incognito)} $contactId"
is ApiDeleteChat -> if (notify != null) {
"/_delete ${chatRef(type, id)} notify=${onOff(notify)}"
} else {
"/_delete ${chatRef(type, id)}"
}
is ApiDeleteChat -> "/_delete ${chatRef(type, id)} ${chatDeleteMode.cmdString}"
is ApiClearChat -> "/_clear chat ${chatRef(type, id)}"
is ApiListContacts -> "/_contacts $userId"
is ApiUpdateProfile -> "/_profile $userId ${json.encodeToString(profile)}"
@@ -2902,8 +2969,6 @@ sealed class CC {
null
}
private fun onOff(b: Boolean): String = if (b) "on" else "off"
private fun maybePwd(pwd: String?): String = if (pwd == "" || pwd == null) "" else " " + json.encodeToString(pwd)
companion object {
@@ -2913,6 +2978,8 @@ sealed class CC {
}
}
fun onOff(b: Boolean): String = if (b) "on" else "off"
@Serializable
data class NewUser(
val profile: Profile?,
@@ -4322,6 +4389,7 @@ sealed class CR {
@Serializable @SerialName("rcvFileCancelled") class RcvFileCancelled(val user: UserRef, val chatItem_: AChatItem?, val rcvFileTransfer: RcvFileTransfer): CR()
@Serializable @SerialName("rcvFileSndCancelled") class RcvFileSndCancelled(val user: UserRef, val chatItem: AChatItem, val rcvFileTransfer: RcvFileTransfer): CR()
@Serializable @SerialName("rcvFileError") class RcvFileError(val user: UserRef, val chatItem_: AChatItem?, val agentError: AgentErrorType, val rcvFileTransfer: RcvFileTransfer): CR()
@Serializable @SerialName("rcvFileWarning") class RcvFileWarning(val user: UserRef, val chatItem_: AChatItem?, val agentError: AgentErrorType, val rcvFileTransfer: RcvFileTransfer): CR()
// sending file events
@Serializable @SerialName("sndFileStart") class SndFileStart(val user: UserRef, val chatItem: AChatItem, val sndFileTransfer: SndFileTransfer): CR()
@Serializable @SerialName("sndFileComplete") class SndFileComplete(val user: UserRef, val chatItem: AChatItem, val sndFileTransfer: SndFileTransfer): CR()
@@ -4334,7 +4402,8 @@ sealed class CR {
@Serializable @SerialName("sndFileCompleteXFTP") class SndFileCompleteXFTP(val user: UserRef, val chatItem: AChatItem, val fileTransferMeta: FileTransferMeta): CR()
@Serializable @SerialName("sndStandaloneFileComplete") class SndStandaloneFileComplete(val user: UserRef, val fileTransferMeta: FileTransferMeta, val rcvURIs: List<String>): CR()
@Serializable @SerialName("sndFileCancelledXFTP") class SndFileCancelledXFTP(val user: UserRef, val chatItem_: AChatItem?, val fileTransferMeta: FileTransferMeta): CR()
@Serializable @SerialName("sndFileError") class SndFileError(val user: UserRef, val chatItem_: AChatItem?, val fileTransferMeta: FileTransferMeta): CR()
@Serializable @SerialName("sndFileError") class SndFileError(val user: UserRef, val chatItem_: AChatItem?, val fileTransferMeta: FileTransferMeta, val errorMessage: String): CR()
@Serializable @SerialName("sndFileWarning") class SndFileWarning(val user: UserRef, val chatItem_: AChatItem?, val fileTransferMeta: FileTransferMeta, val errorMessage: String): CR()
// call events
@Serializable @SerialName("callInvitation") class CallInvitation(val callInvitation: RcvCallInvitation): CR()
@Serializable @SerialName("callInvitations") class CallInvitations(val callInvitations: List<RcvCallInvitation>): CR()
@@ -4493,6 +4562,7 @@ sealed class CR {
is RcvFileProgressXFTP -> "rcvFileProgressXFTP"
is SndFileRedirectStartXFTP -> "sndFileRedirectStartXFTP"
is RcvFileError -> "rcvFileError"
is RcvFileWarning -> "rcvFileWarning"
is SndFileStart -> "sndFileStart"
is SndFileComplete -> "sndFileComplete"
is SndFileRcvCancelled -> "sndFileRcvCancelled"
@@ -4502,6 +4572,7 @@ sealed class CR {
is SndStandaloneFileComplete -> "sndStandaloneFileComplete"
is SndFileCancelledXFTP -> "sndFileCancelledXFTP"
is SndFileError -> "sndFileError"
is SndFileWarning -> "sndFileWarning"
is CallInvitations -> "callInvitations"
is CallInvitation -> "callInvitation"
is CallOffer -> "callOffer"
@@ -4652,6 +4723,7 @@ sealed class CR {
is RcvFileProgressXFTP -> withUser(user, "chatItem: ${json.encodeToString(chatItem_)}\nreceivedSize: $receivedSize\ntotalSize: $totalSize")
is RcvStandaloneFileComplete -> withUser(user, targetPath)
is RcvFileError -> withUser(user, "chatItem_: ${json.encodeToString(chatItem_)}\nagentError: ${agentError.string}\nrcvFileTransfer: $rcvFileTransfer")
is RcvFileWarning -> withUser(user, "chatItem_: ${json.encodeToString(chatItem_)}\nagentError: ${agentError.string}\nrcvFileTransfer: $rcvFileTransfer")
is SndFileCancelled -> json.encodeToString(chatItem_)
is SndStandaloneFileCreated -> noDetails()
is SndFileStartXFTP -> withUser(user, json.encodeToString(chatItem))
@@ -4663,7 +4735,8 @@ sealed class CR {
is SndFileCompleteXFTP -> withUser(user, json.encodeToString(chatItem))
is SndStandaloneFileComplete -> withUser(user, rcvURIs.size.toString())
is SndFileCancelledXFTP -> withUser(user, json.encodeToString(chatItem_))
is SndFileError -> withUser(user, json.encodeToString(chatItem_))
is SndFileError -> withUser(user, "errorMessage: ${json.encodeToString(errorMessage)}\nchatItem: ${json.encodeToString(chatItem_)}")
is SndFileWarning -> withUser(user, "errorMessage: ${json.encodeToString(errorMessage)}\nchatItem: ${json.encodeToString(chatItem_)}")
is CallInvitations -> "callInvitations: ${json.encodeToString(callInvitations)}"
is CallInvitation -> "contact: ${callInvitation.contact.id}\ncallType: $callInvitation.callType\nsharedKey: ${callInvitation.sharedKey ?: ""}"
is CallOffer -> withUser(user, "contact: ${contact.id}\ncallType: $callType\nsharedKey: ${sharedKey ?: ""}\naskConfirmation: $askConfirmation\noffer: ${json.encodeToString(offer)}")
@@ -4700,7 +4773,7 @@ sealed class CR {
(if (remoteCtrl_ == null) "null" else json.encodeToString(remoteCtrl_)) +
"\nsessionCode: $sessionCode"
is RemoteCtrlConnected -> json.encodeToString(remoteCtrl)
is RemoteCtrlStopped -> noDetails()
is RemoteCtrlStopped -> "rcsState: $rcsState\nrcsStopReason: $rcStopReason"
is ContactPQAllowed -> withUser(user, "contact: ${contact.id}\npqEncryption: $pqEncryption")
is ContactPQEnabled -> withUser(user, "contact: ${contact.id}\npqEnabled: $pqEnabled")
is VersionInfo -> "version ${json.encodeToString(versionInfo)}\n\n" +
@@ -4728,6 +4801,19 @@ fun chatError(r: CR): ChatErrorType? {
)
}
@Serializable
sealed class ChatDeleteMode {
@Serializable @SerialName("full") class Full(val notify: Boolean): ChatDeleteMode()
@Serializable @SerialName("entity") class Entity(val notify: Boolean): ChatDeleteMode()
@Serializable @SerialName("messages") class Messages: ChatDeleteMode()
val cmdString: String get() = when (this) {
is ChatDeleteMode.Full -> "full notify=${onOff(notify)}"
is ChatDeleteMode.Entity -> "entity notify=${onOff(notify)}"
is ChatDeleteMode.Messages -> "messages"
}
}
@Serializable
sealed class ConnectionPlan {
@Serializable @SerialName("invitationLink") class InvitationLink(val invitationLinkPlan: InvitationLinkPlan): ConnectionPlan()
@@ -4982,8 +5068,6 @@ sealed class ChatErrorType {
is FileImageSize -> "fileImageSize"
is FileNotReceived -> "fileNotReceived"
is FileNotApproved -> "fileNotApproved"
// is XFTPRcvFile -> "xftpRcvFile"
// is XFTPSndFile -> "xftpSndFile"
is FallbackToSMPProhibited -> "fallbackToSMPProhibited"
is InlineFileProhibited -> "inlineFileProhibited"
is InvalidQuote -> "invalidQuote"
@@ -5061,8 +5145,6 @@ sealed class ChatErrorType {
@Serializable @SerialName("fileImageSize") class FileImageSize(val filePath: String): ChatErrorType()
@Serializable @SerialName("fileNotReceived") class FileNotReceived(val fileId: Long): ChatErrorType()
@Serializable @SerialName("fileNotApproved") class FileNotApproved(val fileId: Long, val unknownServers: List<String>): ChatErrorType()
// @Serializable @SerialName("xFTPRcvFile") object XFTPRcvFile: ChatErrorType()
// @Serializable @SerialName("xFTPSndFile") object XFTPSndFile: ChatErrorType()
@Serializable @SerialName("fallbackToSMPProhibited") class FallbackToSMPProhibited(val fileId: Long): ChatErrorType()
@Serializable @SerialName("inlineFileProhibited") class InlineFileProhibited(val fileId: Long): ChatErrorType()
@Serializable @SerialName("invalidQuote") object InvalidQuote: ChatErrorType()
@@ -1,6 +1,7 @@
package chat.simplex.common.platform
import chat.simplex.common.model.*
import chat.simplex.common.model.ChatController.appPrefs
import chat.simplex.common.model.ChatModel.controller
import chat.simplex.common.model.ChatModel.currentUser
import chat.simplex.common.views.helpers.*
@@ -57,6 +58,9 @@ suspend fun initChatController(useKey: String? = null, confirmMigrations: Migrat
try {
if (chatModel.ctrlInitInProgress.value) return
chatModel.ctrlInitInProgress.value = true
if (!appPrefs.storeDBPassphrase.get() && !appPrefs.initialRandomDBPassphrase.get()) {
ksDatabasePassword.remove()
}
val dbKey = useKey ?: DatabaseUtils.useDatabaseKey()
val confirm = confirmMigrations ?: if (appPreferences.developerTools.get() && appPreferences.confirmDBUpgrades.get()) MigrationConfirmation.Error else MigrationConfirmation.YesUp
var migrated: Array<Any> = chatMigrateInit(dbAbsolutePrefixPath, dbKey, MigrationConfirmation.Error.value)
@@ -224,6 +224,8 @@ object ThemeManager {
s.length == 1 -> "#ff$s$s$s$s$s$s"
s.length == 2 -> "#ff$s$s$s"
s.length == 3 -> "#ff$s$s"
s.length == 4 && this.alpha == 0f -> "#0000$s" // 000088ff treated as 88ff
s.length == 4 -> "#ff00$s"
s.length == 6 && this.alpha == 0f -> "#00$s"
s.length == 6 -> "#ff$s"
else -> "#$s"
@@ -12,12 +12,14 @@ import SectionView
import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.*
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.platform.*
import androidx.compose.ui.text.*
import dev.icerock.moko.resources.compose.painterResource
@@ -35,7 +37,8 @@ import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.helpers.*
import chat.simplex.common.views.usersettings.*
import chat.simplex.common.platform.*
import chat.simplex.common.views.chatlist.updateChatSettings
import chat.simplex.common.views.call.CallMediaType
import chat.simplex.common.views.chatlist.*
import chat.simplex.common.views.newchat.*
import chat.simplex.res.MR
import kotlinx.coroutines.delay
@@ -45,9 +48,21 @@ import kotlinx.datetime.Clock
import kotlinx.serialization.encodeToString
import java.io.File
sealed class ContactDeleteMode {
class Full: ContactDeleteMode()
class Entity: ContactDeleteMode()
fun toChatDeleteMode(notify: Boolean): ChatDeleteMode =
when (this) {
is Full -> ChatDeleteMode.Full(notify)
is Entity -> ChatDeleteMode.Entity(notify)
}
}
@Composable
fun ChatInfoView(
chatModel: ChatModel,
openedFromChatView: Boolean,
contact: Contact,
connectionStats: ConnectionStats?,
customUserProfile: Profile?,
@@ -68,6 +83,7 @@ fun ChatInfoView(
val chatRh = chat.remoteHostId
val sendReceipts = remember(contact.id) { mutableStateOf(SendReceipts.fromBool(contact.chatSettings.sendRcpts, currentUser.sendRcptsContacts)) }
ChatInfoLayout(
openedFromChatView = openedFromChatView,
chat,
contact,
currentUser,
@@ -166,7 +182,8 @@ fun ChatInfoView(
)
}
}
}
},
close = close,
)
}
}
@@ -201,53 +218,127 @@ sealed class SendReceipts {
fun deleteContactDialog(chat: Chat, chatModel: ChatModel, close: (() -> Unit)? = null) {
val chatInfo = chat.chatInfo
AlertManager.shared.showAlertDialogButtonsColumn(
title = generalGetString(MR.strings.delete_contact_question),
text = AnnotatedString(generalGetString(MR.strings.delete_contact_all_messages_deleted_cannot_undo_warning)),
buttons = {
Column {
if (chatInfo is ChatInfo.Direct && chatInfo.contact.ready && chatInfo.contact.active) {
// Delete and notify contact
if (chatInfo is ChatInfo.Direct) {
AlertManager.shared.showAlertDialogButtonsColumn(
title = generalGetString(MR.strings.delete_contact_question),
buttons = {
Column {
// Delete contact
SectionItemView({
AlertManager.shared.hideAlert()
deleteContact(chat, chatModel, close, notify = true)
notifyDeleteContactDialog(chat, chatModel, close, contactDeleteMode = ContactDeleteMode.Full())
}) {
Text(generalGetString(MR.strings.delete_and_notify_contact), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.error)
Text(generalGetString(MR.strings.button_delete_contact), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.error)
}
// Delete
if (!chatInfo.contact.chatDeleted) {
// Delete contact, keep conversation
SectionItemView({
AlertManager.shared.hideAlert()
notifyDeleteContactDialog(chat, chatModel, close, contactDeleteMode = ContactDeleteMode.Entity())
}) {
Text(generalGetString(MR.strings.delete_contact_keep_conversation), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.error)
}
}
// Cancel
SectionItemView({
AlertManager.shared.hideAlert()
deleteContact(chat, chatModel, close, notify = false)
}) {
Text(generalGetString(MR.strings.delete_verb), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.error)
Text(stringResource(MR.strings.cancel_verb), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.primary)
}
} else {
// Delete
SectionItemView({
AlertManager.shared.hideAlert()
deleteContact(chat, chatModel, close)
}) {
Text(generalGetString(MR.strings.delete_verb), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.error)
}
}
// Cancel
SectionItemView({
AlertManager.shared.hideAlert()
}) {
Text(stringResource(MR.strings.cancel_verb), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.primary)
}
}
}
)
}
}
fun notifyDeleteContactDialog(
chat: Chat,
chatModel: ChatModel,
close: (() -> Unit)? = null,
contactDeleteMode: ContactDeleteMode = ContactDeleteMode.Full()
) {
val chatInfo = chat.chatInfo
if (chatInfo is ChatInfo.Direct) {
val contactActive = chatInfo.contact.ready && chatInfo.contact.active
AlertManager.shared.showAlertDialogButtonsColumn(
title = if (contactActive) generalGetString(MR.strings.notify_delete_contact_question) else generalGetString(MR.strings.confirm_delete_contact_question),
text = when (contactDeleteMode) {
is ContactDeleteMode.Full -> generalGetString(MR.strings.delete_contact_all_messages_deleted_cannot_undo_warning)
is ContactDeleteMode.Entity -> generalGetString(MR.strings.delete_contact_cannot_undo_warning)
},
buttons = {
Column {
if (contactActive) {
// Delete and notify contact
SectionItemView({
AlertManager.shared.hideAlert()
deleteContact(chat, chatModel, close, chatDeleteMode = contactDeleteMode.toChatDeleteMode(notify = true))
if (contactDeleteMode is ContactDeleteMode.Entity && chatModel.controller.appPrefs.showDeleteContactNotice.get()) {
showDeleteContactNotice(chatInfo.contact)
}
}) {
Text(generalGetString(MR.strings.delete_and_notify_contact), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.error)
}
// Delete without notification
SectionItemView({
AlertManager.shared.hideAlert()
deleteContact(chat, chatModel, close, chatDeleteMode = contactDeleteMode.toChatDeleteMode(notify = false))
if (contactDeleteMode is ContactDeleteMode.Entity && chatModel.controller.appPrefs.showDeleteContactNotice.get()) {
showDeleteContactNotice(chatInfo.contact)
}
}) {
Text(generalGetString(MR.strings.delete_without_notification), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.error)
}
} else {
// Delete
SectionItemView({
AlertManager.shared.hideAlert()
deleteContact(chat, chatModel, close, chatDeleteMode = contactDeleteMode.toChatDeleteMode(notify = false))
if (contactDeleteMode is ContactDeleteMode.Entity && chatModel.controller.appPrefs.showDeleteContactNotice.get()) {
showDeleteContactNotice(chatInfo.contact)
}
}) {
Text(generalGetString(MR.strings.delete_verb), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.error)
}
}
// Cancel
SectionItemView({
AlertManager.shared.hideAlert()
}) {
Text(stringResource(MR.strings.cancel_verb), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.primary)
}
}
}
)
}
}
private fun showDeleteContactNotice(contact: Contact) {
AlertManager.shared.showAlertDialog(
title = generalGetString(MR.strings.contact_deleted),
text = String.format(generalGetString(MR.strings.you_can_still_view_conversation_with_contact), contact.displayName),
confirmText = generalGetString(MR.strings.ok),
dismissText = generalGetString(MR.strings.dont_show_again),
onDismiss = {
chatModel.controller.appPrefs.showDeleteContactNotice.set(false)
},
)
}
fun deleteContact(chat: Chat, chatModel: ChatModel, close: (() -> Unit)?, notify: Boolean? = null) {
fun deleteContact(chat: Chat, chatModel: ChatModel, close: (() -> Unit)?, chatDeleteMode: ChatDeleteMode = ChatDeleteMode.Full(notify = true)) {
val chatInfo = chat.chatInfo
withBGApi {
val chatRh = chat.remoteHostId
val r = chatModel.controller.apiDeleteChat(chatRh, chatInfo.chatType, chatInfo.apiId, notify)
if (r) {
chatModel.removeChat(chatRh, chatInfo.id)
val ct = chatModel.controller.apiDeleteContact(chatRh, chatInfo.apiId, chatDeleteMode)
if (ct != null) {
when (chatDeleteMode) {
is ChatDeleteMode.Full ->
chatModel.removeChat(chatRh, chatInfo.id)
is ChatDeleteMode.Entity ->
chatModel.updateContact(chatRh, ct)
is ChatDeleteMode.Messages ->
chatModel.clearChat(chatRh, ChatInfo.Direct(ct))
}
if (chatModel.chatId.value == chatInfo.id) {
chatModel.chatId.value = null
ModalManager.end.closeModals()
@@ -280,6 +371,7 @@ fun clearNoteFolderDialog(chat: Chat, close: (() -> Unit)? = null) {
@Composable
fun ChatInfoLayout(
openedFromChatView: Boolean,
chat: Chat,
contact: Contact,
currentUser: User,
@@ -300,6 +392,7 @@ fun ChatInfoLayout(
syncContactConnection: () -> Unit,
syncContactConnectionForce: () -> Unit,
verifyClicked: () -> Unit,
close: () -> Unit,
) {
val cStats = connStats.value
val scrollState = rememberScrollState()
@@ -319,7 +412,31 @@ fun ChatInfoLayout(
}
LocalAliasEditor(chat.id, localAlias, updateValue = onLocalAliasChanged)
SectionSpacer()
Row(
Modifier
.fillMaxWidth()
.padding(horizontal = 10.dp),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
if (contact.activeConn == null && contact.profile.contactLink != null && contact.active) {
ConnectButton(openedFromChatView, chat, contact, close)
} else if (!contact.active && !contact.chatDeleted) {
OpenButton(openedFromChatView, chat, contact, close)
} else {
MessageButton(openedFromChatView, chat, contact, close)
}
Spacer(Modifier.width(10.dp))
CallButton(chat, contact)
Spacer(Modifier.width(10.dp))
VideoButton(chat, contact)
}
SectionSpacer()
if (customUserProfile != null) {
SectionView(generalGetString(MR.strings.incognito).uppercase()) {
SectionItemViewSpaceBetween {
@@ -535,6 +652,155 @@ fun LocalAliasEditor(
}
}
// when contact is a "contact card"
@Composable
private fun ConnectButton(openedFromChatView: Boolean, chat: Chat, contact: Contact, close: () -> Unit) {
InfoViewActionButton(
icon = painterResource(MR.images.ic_chat_bubble_filled),
title = generalGetString(MR.strings.info_view_connect_button),
disabled = false,
onClick = {
AlertManager.privacySensitive.showAlertDialogButtonsColumn(
title = String.format(generalGetString(MR.strings.connect_with_contact_name_question), contact.chatViewName),
buttons = {
Column {
SectionItemView({
AlertManager.privacySensitive.hideAlert()
infoConnectContactViaAddress(openedFromChatView, chat, contact, incognito = false, close)
}) {
Text(generalGetString(MR.strings.connect_use_current_profile), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.primary)
}
SectionItemView({
AlertManager.privacySensitive.hideAlert()
infoConnectContactViaAddress(openedFromChatView, chat, contact, incognito = true, close)
}) {
Text(generalGetString(MR.strings.connect_use_new_incognito_profile), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.primary)
}
SectionItemView({
AlertManager.privacySensitive.hideAlert()
}) {
Text(stringResource(MR.strings.cancel_verb), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.primary)
}
}
},
hostDevice = hostDevice(chat.remoteHostId),
)
}
)
}
private fun infoConnectContactViaAddress(openedFromChatView: Boolean, chat: Chat, contact: Contact, incognito: Boolean, close: () -> Unit) {
withBGApi {
val ok = connectContactViaAddress(chatModel, chat.remoteHostId, contact.contactId, incognito = incognito)
if (ok) {
if (openedFromChatView) {
close.invoke()
} else {
if (contact.chatDeleted) {
chatModel.updateContact(chat.remoteHostId, contact.copy(chatDeleted = false))
}
close.invoke()
openDirectChat(chat.remoteHostId, contact.contactId, chatModel)
}
}
}
}
@Composable
private fun OpenButton(openedFromChatView: Boolean, chat: Chat, contact: Contact, close: () -> Unit) {
InfoViewActionButton(
icon = painterResource(MR.images.ic_chat_bubble_filled),
title = generalGetString(MR.strings.info_view_open_button),
disabled = false,
onClick = {
if (openedFromChatView) {
close.invoke()
} else {
close.invoke()
withBGApi {
openDirectChat(chat.remoteHostId, contact.contactId, chatModel)
}
}
}
)
}
@Composable
private fun MessageButton(openedFromChatView: Boolean, chat: Chat, contact: Contact, close: () -> Unit) {
InfoViewActionButton(
icon = painterResource(MR.images.ic_chat_bubble_filled),
title = generalGetString(MR.strings.info_view_message_button),
disabled = !contact.sendMsgEnabled,
onClick = {
if (openedFromChatView) {
close.invoke()
} else {
if (contact.chatDeleted) {
chatModel.updateContact(chat.remoteHostId, contact.copy(chatDeleted = false))
}
close.invoke()
withBGApi {
openDirectChat(chat.remoteHostId, contact.contactId, chatModel)
}
}
}
)
}
@Composable
fun CallButton(chat: Chat, contact: Contact) {
InfoViewActionButton(
icon = painterResource(MR.images.ic_call_filled),
title = generalGetString(MR.strings.info_view_call_button),
disabled = !contact.ready || !contact.active || !contact.mergedPreferences.calls.enabled.forUser || chatModel.activeCall.value != null,
onClick = {
startChatCall(chat, CallMediaType.Audio)
}
)
}
@Composable
fun VideoButton(chat: Chat, contact: Contact) {
InfoViewActionButton(
icon = painterResource(MR.images.ic_videocam_filled),
title = generalGetString(MR.strings.info_view_video_button),
disabled = !contact.ready || !contact.active || !contact.mergedPreferences.calls.enabled.forUser || chatModel.activeCall.value != null,
onClick = {
startChatCall(chat, CallMediaType.Video)
}
)
}
@Composable
fun InfoViewActionButton(icon: Painter, title: String, disabled: Boolean, onClick: () -> Unit) {
Surface(
Modifier
.width(96.dp)
.height(66.dp),
shape = RoundedCornerShape(20.dp),
color = MaterialTheme.colors.secondaryVariant,
) {
val modifier = if (disabled) Modifier else Modifier.clickable { onClick () }
Column(
modifier,
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Icon(
icon,
contentDescription = null,
Modifier.size(26.dp),
tint = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary
)
Text(
title,
style = MaterialTheme.typography.subtitle2.copy(fontWeight = FontWeight.Normal),
color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary
)
}
}
}
@Composable
private fun NetworkStatusRow(networkStatus: NetworkStatus) {
Row(
@@ -823,6 +1089,7 @@ fun queueInfoText(info: Pair<RcvMsgInfo?, QueueInfo>): String {
fun PreviewChatInfoLayout() {
SimpleXTheme {
ChatInfoLayout(
openedFromChatView = false,
chat = Chat(
remoteHostId = null,
chatInfo = ChatInfo.Direct.sampleData,
@@ -847,6 +1114,7 @@ fun PreviewChatInfoLayout() {
syncContactConnection = {},
syncContactConnectionForce = {},
verifyClicked = {},
close = {},
)
}
}
@@ -31,6 +31,7 @@ import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.chatlist.*
import chat.simplex.res.MR
import dev.icerock.moko.resources.ImageResource
import kotlinx.serialization.encodeToString
sealed class CIInfoTab {
class Delivery(val memberDeliveryStatuses: List<MemberDeliveryStatus>): CIInfoTab()
@@ -216,6 +217,27 @@ fun ChatItemInfoView(chatRh: Long?, ci: ChatItem, ciInfo: ChatItemInfo, devTools
}
}
@Composable
fun ExpandableInfoRow(title: String, value: String) {
val expanded = remember { mutableStateOf(false) }
Row(
Modifier
.fillMaxWidth()
.sizeIn(minHeight = 46.dp)
.padding(PaddingValues(horizontal = DEFAULT_PADDING))
.clickable { expanded.value = !expanded.value },
horizontalArrangement = Arrangement.spacedBy(12.dp),
verticalAlignment = Alignment.CenterVertically
) {
Text(title, color = MaterialTheme.colors.onBackground)
if (expanded.value) {
Text(value, color = MaterialTheme.colors.secondary)
} else {
Text(value, color = MaterialTheme.colors.secondary, maxLines = 1)
}
}
}
@Composable
fun Details() {
AppBarTitle(stringResource(if (ci.localNote) MR.strings.saved_message_title else if (sent) MR.strings.sent_message else MR.strings.received_message))
@@ -244,6 +266,10 @@ fun ChatItemInfoView(chatRh: Long?, ci: ChatItem, ciInfo: ChatItemInfo, devTools
if (devTools) {
InfoRow(stringResource(MR.strings.info_row_database_id), ci.meta.itemId.toString())
InfoRow(stringResource(MR.strings.info_row_updated_at), localTimestamp(ci.meta.updatedAt))
ExpandableInfoRow(stringResource(MR.strings.info_row_message_status), jsonShort.encodeToString(ci.meta.itemStatus))
if (ci.file != null) {
ExpandableInfoRow(stringResource(MR.strings.info_row_file_status), jsonShort.encodeToString(ci.file.fileStatus))
}
}
}
}
@@ -531,6 +557,10 @@ fun itemInfoShareText(chatModel: ChatModel, ci: ChatItem, chatItemInfo: ChatItem
if (devTools) {
shareText.add(String.format(generalGetString(MR.strings.share_text_database_id), meta.itemId))
shareText.add(String.format(generalGetString(MR.strings.share_text_updated_at), meta.updatedAt))
shareText.add(String.format(generalGetString(MR.strings.share_text_message_status), jsonShort.encodeToString(ci.meta.itemStatus)))
if (ci.file != null) {
shareText.add(String.format(generalGetString(MR.strings.share_text_file_status), jsonShort.encodeToString(ci.file.fileStatus)))
}
}
val qi = ci.quotedItem
if (qi != null) {
@@ -189,7 +189,7 @@ fun ChatView(chatId: String, chatModel: ChatModel, onComposed: suspend (chatId:
code = chatModel.controller.apiGetContactCode(chatRh, chat.chatInfo.apiId)?.second
preloadedCode = code
}
ChatInfoView(chatModel, (chat.chatInfo as ChatInfo.Direct).contact, contactInfo?.first, contactInfo?.second, chat.chatInfo.localAlias, code, close)
ChatInfoView(chatModel, openedFromChatView = true, (chat.chatInfo as ChatInfo.Direct).contact, contactInfo?.first, contactInfo?.second, chat.chatInfo.localAlias, code, close)
} else if (chat?.chatInfo is ChatInfo.Group) {
var link: Pair<String, GroupMemberRole>? by remember(chat.id) { mutableStateOf(preloadedLink) }
KeyChangeEffect(chat.id) {
@@ -306,18 +306,7 @@ fun ChatView(chatId: String, chatModel: ChatModel, onComposed: suspend (chatId:
onComplete.invoke()
}
},
startCall = out@{ media ->
withBGApi {
val cInfo = chat.chatInfo
if (cInfo is ChatInfo.Direct) {
val contactInfo = chatModel.controller.apiContactInfo(chat.remoteHostId, cInfo.contact.contactId)
val profile = contactInfo?.second ?: chatModel.currentUser.value?.profile?.toProfile() ?: return@withBGApi
chatModel.activeCall.value = Call(remoteHostId = chatRh, contact = cInfo.contact, callState = CallState.WaitCapabilities, localMedia = media, userProfile = profile)
chatModel.showCallView.value = true
chatModel.callCommand.add(WCallCommand.Capabilities(media))
}
}
},
startCall = out@{ media -> startChatCall(chat, media) },
endCall = {
val call = chatModel.activeCall.value
if (call != null) withBGApi { chatModel.callManager.endCall(call) }
@@ -521,6 +510,19 @@ fun ChatView(chatId: String, chatModel: ChatModel, onComposed: suspend (chatId:
}
}
fun startChatCall(chat: Chat, media: CallMediaType) {
withBGApi {
val cInfo = chat.chatInfo
if (cInfo is ChatInfo.Direct) {
val contactInfo = chatModel.controller.apiContactInfo(chat.remoteHostId, cInfo.contact.contactId)
val profile = contactInfo?.second ?: chatModel.currentUser.value?.profile?.toProfile() ?: return@withBGApi
chatModel.activeCall.value = Call(remoteHostId = chat.remoteHostId, contact = cInfo.contact, callState = CallState.WaitCapabilities, localMedia = media, userProfile = profile)
chatModel.showCallView.value = true
chatModel.callCommand.add(WCallCommand.Capabilities(media))
}
}
}
@Composable
fun ChatLayout(
chat: Chat,
@@ -962,17 +964,8 @@ fun BoxWithConstraintsScope.ChatItemsList(
// With default touchSlop when you scroll LazyColumn, you can unintentionally open reply view
LocalViewConfiguration provides LocalViewConfiguration.current.bigTouchSlop()
) {
val dismissState = rememberDismissState(initialValue = DismissValue.Default) { false }
val directions = setOf(DismissDirection.EndToStart)
val swipeableModifier = SwipeToDismissModifier(
state = dismissState,
directions = directions,
swipeDistance = with(LocalDensity.current) { 30.dp.toPx() },
)
val swipedToEnd = (dismissState.overflow.value > 0f && directions.contains(DismissDirection.StartToEnd))
val swipedToStart = (dismissState.overflow.value < 0f && directions.contains(DismissDirection.EndToStart))
if (dismissState.isAnimationRunning && (swipedToStart || swipedToEnd)) {
LaunchedEffect(Unit) {
val dismissState = rememberDismissState(initialValue = DismissValue.Default) {
if (it == DismissValue.DismissedToStart) {
scope.launch {
if ((cItem.content is CIContent.SndMsgContent || cItem.content is CIContent.RcvMsgContent) && chat.chatInfo !is ChatInfo.Local) {
if (composeState.value.editing) {
@@ -983,7 +976,13 @@ fun BoxWithConstraintsScope.ChatItemsList(
}
}
}
false
}
val swipeableModifier = SwipeToDismissModifier(
state = dismissState,
directions = setOf(DismissDirection.EndToStart),
swipeDistance = with(LocalDensity.current) { 30.dp.toPx() },
)
val provider = {
providerForGallery(i, chatModel.chatItems.value, cItem.id) { indexInReversed ->
scope.launch {
@@ -203,7 +203,7 @@ fun GroupChatInfoLayout(
scope.launch { listState.scrollToItem(0) }
}
val searchText = rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue()) }
val filteredMembers = remember(members) { derivedStateOf { members.filter { it.chatViewName.lowercase().contains(searchText.value.text.trim()) } } }
val filteredMembers = remember(members) { derivedStateOf { members.filter { it.chatViewName.lowercase().contains(searchText.value.text.trim().lowercase()) } } }
// LALAL strange scrolling
LazyColumnWithScrollBar(
Modifier
@@ -36,6 +36,7 @@ import chat.simplex.common.views.newchat.*
import chat.simplex.common.views.usersettings.SettingsActionItem
import chat.simplex.common.model.GroupInfo
import chat.simplex.common.platform.*
import chat.simplex.common.views.call.CallMediaType
import chat.simplex.common.views.chatlist.openLoadedChat
import chat.simplex.res.MR
import kotlinx.datetime.Clock
@@ -246,10 +247,10 @@ fun GroupMemberInfoLayout(
verifyClicked: () -> Unit,
) {
val cStats = connStats.value
fun knownDirectChat(contactId: Long): Chat? {
fun knownDirectChat(contactId: Long): Pair<Chat, Contact>? {
val chat = getContactChat(contactId)
return if (chat != null && chat.chatInfo is ChatInfo.Direct && chat.chatInfo.contact.directOrUsed) {
chat
chat to chat.chatInfo.contact
} else {
null
}
@@ -309,17 +310,37 @@ fun GroupMemberInfoLayout(
val contactId = member.memberContactId
Row(
Modifier
.fillMaxWidth()
.padding(horizontal = 10.dp),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
val knownChat = if (contactId != null) knownDirectChat(contactId) else null
if (knownChat != null) {
val (chat, contact) = knownChat
OpenChatButton(onClick = { openDirectChat(contact.contactId) })
Spacer(Modifier.width(10.dp))
CallButton(chat, contact)
Spacer(Modifier.width(10.dp))
VideoButton(chat, contact)
} else if (groupInfo.fullGroupPreferences.directMessages.on(groupInfo.membership)) {
if (contactId != null) {
OpenChatButton(onClick = { openDirectChat(contactId) })
} else {
OpenChatButton(onClick = { createMemberContact() })
}
Spacer(Modifier.width(10.dp))
InfoViewActionButton(painterResource(MR.images.ic_call_filled), generalGetString(MR.strings.info_view_call_button), disabled = true, onClick = {})
Spacer(Modifier.width(10.dp))
InfoViewActionButton(painterResource(MR.images.ic_videocam_filled), generalGetString(MR.strings.info_view_video_button), disabled = true, onClick = {})
}
}
SectionSpacer()
if (member.memberActive) {
SectionView {
if (contactId != null && knownDirectChat(contactId) != null) {
OpenChatButton(onClick = { openDirectChat(contactId) })
} else if (groupInfo.fullGroupPreferences.directMessages.on(groupInfo.membership)) {
if (contactId != null) {
OpenChatButton(onClick = { openDirectChat(contactId) })
} else if (member.activeConn?.peerChatVRange?.isCompatibleRange(CREATE_MEMBER_CONTACT_VRANGE) == true) {
OpenChatButton(onClick = { createMemberContact() })
}
}
if (connectionCode != null) {
VerifyCodeButton(member.verified, verifyClicked)
}
@@ -513,12 +534,11 @@ fun RemoveMemberButton(onClick: () -> Unit) {
@Composable
fun OpenChatButton(onClick: () -> Unit) {
SettingsActionItem(
painterResource(MR.images.ic_chat),
stringResource(MR.strings.button_send_direct_message),
click = onClick,
textColor = MaterialTheme.colors.primary,
iconColor = MaterialTheme.colors.primary,
InfoViewActionButton(
icon = painterResource(MR.images.ic_chat_bubble_filled),
title = generalGetString(MR.strings.info_view_message_button),
disabled = false,
onClick = onClick
)
}
@@ -87,6 +87,26 @@ fun CIFileView(
)
FileProtocol.LOCAL -> {}
}
file.fileStatus is CIFileStatus.RcvError ->
AlertManager.shared.showAlertMsg(
generalGetString(MR.strings.file_error),
file.fileStatus.rcvFileError.errorInfo
)
file.fileStatus is CIFileStatus.RcvWarning ->
AlertManager.shared.showAlertMsg(
generalGetString(MR.strings.temporary_file_error),
file.fileStatus.rcvFileError.errorInfo
)
file.fileStatus is CIFileStatus.SndError ->
AlertManager.shared.showAlertMsg(
generalGetString(MR.strings.file_error),
file.fileStatus.sndFileError.errorInfo
)
file.fileStatus is CIFileStatus.SndWarning ->
AlertManager.shared.showAlertMsg(
generalGetString(MR.strings.temporary_file_error),
file.fileStatus.sndFileError.errorInfo
)
file.forwardingAllowed() -> {
withLongRunningApi(slow = 600_000) {
var filePath = getLoadedFilePath(file)
@@ -157,6 +177,7 @@ fun CIFileView(
is CIFileStatus.SndComplete -> fileIcon(innerIcon = painterResource(MR.images.ic_check_filled))
is CIFileStatus.SndCancelled -> fileIcon(innerIcon = painterResource(MR.images.ic_close))
is CIFileStatus.SndError -> fileIcon(innerIcon = painterResource(MR.images.ic_close))
is CIFileStatus.SndWarning -> fileIcon(innerIcon = painterResource(MR.images.ic_warning_filled))
is CIFileStatus.RcvInvitation ->
if (fileSizeValid(file))
fileIcon(innerIcon = painterResource(MR.images.ic_arrow_downward), color = MaterialTheme.colors.primary)
@@ -174,6 +195,7 @@ fun CIFileView(
is CIFileStatus.RcvComplete -> fileIcon()
is CIFileStatus.RcvCancelled -> fileIcon(innerIcon = painterResource(MR.images.ic_close))
is CIFileStatus.RcvError -> fileIcon(innerIcon = painterResource(MR.images.ic_close))
is CIFileStatus.RcvWarning -> fileIcon(innerIcon = painterResource(MR.images.ic_warning_filled))
is CIFileStatus.Invalid -> fileIcon(innerIcon = painterResource(MR.images.ic_question_mark))
}
} else {
@@ -70,14 +70,16 @@ fun CIImageView(
is CIFileStatus.SndComplete -> fileIcon(painterResource(MR.images.ic_check_filled), MR.strings.icon_descr_image_snd_complete)
is CIFileStatus.SndCancelled -> fileIcon(painterResource(MR.images.ic_close), MR.strings.icon_descr_file)
is CIFileStatus.SndError -> fileIcon(painterResource(MR.images.ic_close), MR.strings.icon_descr_file)
is CIFileStatus.SndWarning -> fileIcon(painterResource(MR.images.ic_warning_filled), MR.strings.icon_descr_file)
is CIFileStatus.RcvInvitation -> fileIcon(painterResource(MR.images.ic_arrow_downward), MR.strings.icon_descr_asked_to_receive)
is CIFileStatus.RcvAccepted -> fileIcon(painterResource(MR.images.ic_more_horiz), MR.strings.icon_descr_waiting_for_image)
is CIFileStatus.RcvTransfer -> progressIndicator()
is CIFileStatus.RcvComplete -> {}
is CIFileStatus.RcvAborted -> fileIcon(painterResource(MR.images.ic_sync_problem), MR.strings.icon_descr_file)
is CIFileStatus.RcvCancelled -> fileIcon(painterResource(MR.images.ic_close), MR.strings.icon_descr_file)
is CIFileStatus.RcvError -> fileIcon(painterResource(MR.images.ic_close), MR.strings.icon_descr_file)
is CIFileStatus.RcvWarning -> fileIcon(painterResource(MR.images.ic_warning_filled), MR.strings.icon_descr_file)
is CIFileStatus.Invalid -> fileIcon(painterResource(MR.images.ic_question_mark), MR.strings.icon_descr_file)
else -> {}
}
}
}
@@ -201,8 +203,8 @@ fun CIImageView(
} else {
imageView(base64ToBitmap(image), onClick = {
if (file != null) {
when (file.fileStatus) {
CIFileStatus.RcvInvitation, CIFileStatus.RcvAborted ->
when {
file.fileStatus is CIFileStatus.RcvInvitation || file.fileStatus is CIFileStatus.RcvAborted ->
if (fileSizeValid()) {
receiveFile(file.fileId)
} else {
@@ -211,7 +213,7 @@ fun CIImageView(
String.format(generalGetString(MR.strings.contact_sent_large_file), formatBytes(getMaxFileSize(file.fileProtocol)))
)
}
CIFileStatus.RcvAccepted ->
file.fileStatus is CIFileStatus.RcvAccepted ->
when (file.fileProtocol) {
FileProtocol.XFTP ->
AlertManager.shared.showAlertMsg(
@@ -225,9 +227,29 @@ fun CIImageView(
)
FileProtocol.LOCAL -> {}
}
CIFileStatus.RcvTransfer(rcvProgress = 7, rcvTotal = 10) -> {} // ?
CIFileStatus.RcvComplete -> {} // ?
CIFileStatus.RcvCancelled -> {} // TODO
file.fileStatus is CIFileStatus.RcvError ->
AlertManager.shared.showAlertMsg(
generalGetString(MR.strings.file_error),
file.fileStatus.rcvFileError.errorInfo
)
file.fileStatus is CIFileStatus.RcvWarning ->
AlertManager.shared.showAlertMsg(
generalGetString(MR.strings.temporary_file_error),
file.fileStatus.rcvFileError.errorInfo
)
file.fileStatus is CIFileStatus.SndError ->
AlertManager.shared.showAlertMsg(
generalGetString(MR.strings.file_error),
file.fileStatus.sndFileError.errorInfo
)
file.fileStatus is CIFileStatus.SndWarning ->
AlertManager.shared.showAlertMsg(
generalGetString(MR.strings.temporary_file_error),
file.fileStatus.sndFileError.errorInfo
)
file.fileStatus is CIFileStatus.RcvTransfer -> {} // ?
file.fileStatus is CIFileStatus.RcvComplete -> {} // ?
file.fileStatus is CIFileStatus.RcvCancelled -> {} // TODO
else -> {}
}
}
@@ -107,7 +107,7 @@ fun CIVideoView(
}
}
}
loadingIndicator(file)
fileStatusIcon(file)
}
}
@@ -339,11 +339,13 @@ private fun progressIndicator() {
}
@Composable
private fun fileIcon(icon: Painter, stringId: StringResource) {
private fun fileIcon(icon: Painter, stringId: StringResource, onClick: (() -> Unit)? = null) {
var modifier = Modifier.fillMaxSize()
modifier = if (onClick != null) { modifier.clickable { onClick() } } else { modifier }
Icon(
icon,
stringResource(stringId),
Modifier.fillMaxSize(),
modifier,
tint = Color.White
)
}
@@ -364,7 +366,7 @@ private fun progressCircle(progress: Long, total: Long) {
}
@Composable
private fun loadingIndicator(file: CIFile?) {
private fun fileStatusIcon(file: CIFile?) {
if (file != null) {
Box(
Modifier
@@ -387,7 +389,28 @@ private fun loadingIndicator(file: CIFile?) {
}
is CIFileStatus.SndComplete -> fileIcon(painterResource(MR.images.ic_check_filled), MR.strings.icon_descr_video_snd_complete)
is CIFileStatus.SndCancelled -> fileIcon(painterResource(MR.images.ic_close), MR.strings.icon_descr_file)
is CIFileStatus.SndError -> fileIcon(painterResource(MR.images.ic_close), MR.strings.icon_descr_file)
is CIFileStatus.SndError ->
fileIcon(
painterResource(MR.images.ic_close),
MR.strings.icon_descr_file,
onClick = {
AlertManager.shared.showAlertMsg(
generalGetString(MR.strings.file_error),
file.fileStatus.sndFileError.errorInfo
)
}
)
is CIFileStatus.SndWarning ->
fileIcon(
painterResource(MR.images.ic_warning_filled),
MR.strings.icon_descr_file,
onClick = {
AlertManager.shared.showAlertMsg(
generalGetString(MR.strings.temporary_file_error),
file.fileStatus.sndFileError.errorInfo
)
}
)
is CIFileStatus.RcvInvitation -> fileIcon(painterResource(MR.images.ic_arrow_downward), MR.strings.icon_descr_video_asked_to_receive)
is CIFileStatus.RcvAccepted -> fileIcon(painterResource(MR.images.ic_more_horiz), MR.strings.icon_descr_waiting_for_video)
is CIFileStatus.RcvTransfer ->
@@ -397,10 +420,31 @@ private fun loadingIndicator(file: CIFile?) {
progressIndicator()
}
is CIFileStatus.RcvAborted -> fileIcon(painterResource(MR.images.ic_sync_problem), MR.strings.icon_descr_file)
is CIFileStatus.RcvComplete -> {}
is CIFileStatus.RcvCancelled -> fileIcon(painterResource(MR.images.ic_close), MR.strings.icon_descr_file)
is CIFileStatus.RcvError -> fileIcon(painterResource(MR.images.ic_close), MR.strings.icon_descr_file)
is CIFileStatus.RcvError ->
fileIcon(
painterResource(MR.images.ic_close),
MR.strings.icon_descr_file,
onClick = {
AlertManager.shared.showAlertMsg(
generalGetString(MR.strings.file_error),
file.fileStatus.rcvFileError.errorInfo
)
}
)
is CIFileStatus.RcvWarning ->
fileIcon(
painterResource(MR.images.ic_warning_filled),
MR.strings.icon_descr_file,
onClick = {
AlertManager.shared.showAlertMsg(
generalGetString(MR.strings.temporary_file_error),
file.fileStatus.rcvFileError.errorInfo
)
}
)
is CIFileStatus.Invalid -> fileIcon(painterResource(MR.images.ic_question_mark), MR.strings.icon_descr_file)
else -> {}
}
}
}
@@ -252,6 +252,81 @@ private fun PlayPauseButton(
}
}
@Composable
private fun PlayablePlayPauseButton(
audioPlaying: Boolean,
sent: Boolean,
hasText: Boolean,
progress: State<Int>,
duration: State<Int>,
strokeWidth: Float,
strokeColor: Color,
error: Boolean,
play: () -> Unit,
pause: () -> Unit,
longClick: () -> Unit,
) {
val angle = 360f * (progress.value.toDouble() / duration.value).toFloat()
if (hasText) {
IconButton({ if (!audioPlaying) play() else pause() }, Modifier.size(56.dp).drawRingModifier(angle, strokeColor, strokeWidth)) {
Icon(
if (audioPlaying) painterResource(MR.images.ic_pause_filled) else painterResource(MR.images.ic_play_arrow_filled),
contentDescription = null,
Modifier.size(36.dp),
tint = MaterialTheme.colors.primary
)
}
} else {
PlayPauseButton(audioPlaying, sent, angle, strokeWidth, strokeColor, true, error, play, pause, longClick = longClick)
}
}
@Composable
private fun VoiceMsgLoadingProgressIndicator() {
Box(
Modifier
.size(56.dp)
.clip(RoundedCornerShape(4.dp)),
contentAlignment = Alignment.Center
) {
ProgressIndicator()
}
}
@Composable
private fun FileStatusIcon(
sent: Boolean,
icon: ImageResource,
longClick: () -> Unit,
onClick: () -> Unit,
) {
val sentColor = MaterialTheme.appColors.sentMessage
val receivedColor = MaterialTheme.appColors.receivedMessage
Surface(
color = if (sent) sentColor else receivedColor,
shape = MaterialTheme.shapes.small.copy(CornerSize(percent = 50)),
contentColor = LocalContentColor.current
) {
Box(
Modifier
.defaultMinSize(minWidth = 56.dp, minHeight = 56.dp)
.combinedClickable(
onClick = onClick,
onLongClick = longClick
)
.onRightClick { longClick() },
contentAlignment = Alignment.Center
) {
Icon(
painterResource(icon),
contentDescription = null,
Modifier.size(36.dp),
tint = MaterialTheme.colors.secondary
)
}
}
}
@Composable
private fun VoiceMsgIndicator(
file: CIFile?,
@@ -268,39 +343,73 @@ private fun VoiceMsgIndicator(
) {
val strokeWidth = with(LocalDensity.current) { 3.dp.toPx() }
val strokeColor = MaterialTheme.colors.primary
if (file != null && file.loaded && progress != null && duration != null) {
val angle = 360f * (progress.value.toDouble() / duration.value).toFloat()
if (hasText) {
IconButton({ if (!audioPlaying) play() else pause() }, Modifier.size(56.dp).drawRingModifier(angle, strokeColor, strokeWidth)) {
Icon(
if (audioPlaying) painterResource(MR.images.ic_pause_filled) else painterResource(MR.images.ic_play_arrow_filled),
contentDescription = null,
Modifier.size(36.dp),
tint = MaterialTheme.colors.primary
)
when {
file?.fileStatus is CIFileStatus.SndStored ->
if (file.fileProtocol == FileProtocol.LOCAL && progress != null && duration != null) {
PlayablePlayPauseButton(audioPlaying, sent, hasText, progress, duration, strokeWidth, strokeColor, error, play, pause, longClick = longClick)
} else {
VoiceMsgLoadingProgressIndicator()
}
} else {
PlayPauseButton(audioPlaying, sent, angle, strokeWidth, strokeColor, true, error, play, pause, longClick = longClick)
}
} else {
if (file?.fileStatus is CIFileStatus.RcvInvitation) {
file?.fileStatus is CIFileStatus.SndTransfer ->
VoiceMsgLoadingProgressIndicator()
file != null && file.fileStatus is CIFileStatus.SndError ->
FileStatusIcon(
sent,
MR.images.ic_close,
longClick,
onClick = {
AlertManager.shared.showAlertMsg(
generalGetString(MR.strings.file_error),
file.fileStatus.sndFileError.errorInfo
)
}
)
file != null && file.fileStatus is CIFileStatus.SndWarning ->
FileStatusIcon(
sent,
MR.images.ic_warning_filled,
longClick,
onClick = {
AlertManager.shared.showAlertMsg(
generalGetString(MR.strings.temporary_file_error),
file.fileStatus.sndFileError.errorInfo
)
}
)
file?.fileStatus is CIFileStatus.RcvInvitation ->
PlayPauseButton(audioPlaying, sent, 0f, strokeWidth, strokeColor, true, error, { receiveFile(file.fileId) }, {}, longClick = longClick)
} else if (file?.fileStatus is CIFileStatus.RcvTransfer
|| file?.fileStatus is CIFileStatus.RcvAccepted
) {
Box(
Modifier
.size(56.dp)
.clip(RoundedCornerShape(4.dp)),
contentAlignment = Alignment.Center
) {
ProgressIndicator()
}
} else if (file?.fileStatus is CIFileStatus.RcvAborted) {
file?.fileStatus is CIFileStatus.RcvTransfer || file?.fileStatus is CIFileStatus.RcvAccepted ->
VoiceMsgLoadingProgressIndicator()
file?.fileStatus is CIFileStatus.RcvAborted ->
PlayPauseButton(audioPlaying, sent, 0f, strokeWidth, strokeColor, true, error, { receiveFile(file.fileId) }, {}, longClick = longClick, icon = MR.images.ic_sync_problem)
} else {
file != null && file.fileStatus is CIFileStatus.RcvError ->
FileStatusIcon(
sent,
MR.images.ic_close,
longClick,
onClick = {
AlertManager.shared.showAlertMsg(
generalGetString(MR.strings.file_error),
file.fileStatus.rcvFileError.errorInfo
)
}
)
file != null && file.fileStatus is CIFileStatus.RcvWarning ->
FileStatusIcon(
sent,
MR.images.ic_warning_filled,
longClick,
onClick = {
AlertManager.shared.showAlertMsg(
generalGetString(MR.strings.temporary_file_error),
file.fileStatus.rcvFileError.errorInfo
)
}
)
file != null && file.loaded && progress != null && duration != null ->
PlayablePlayPauseButton(audioPlaying, sent, hasText, progress, duration, strokeWidth, strokeColor, error, play, pause, longClick = longClick)
else ->
PlayPauseButton(audioPlaying, sent, 0f, strokeWidth, strokeColor, false, false, {}, {}, longClick)
}
}
}
@@ -189,13 +189,6 @@ fun FramedItemView(
val receivedColor = MaterialTheme.appColors.receivedMessage
Box(Modifier
.clip(RoundedCornerShape(18.dp))
.background(
when {
transparentBackground -> Color.Transparent
sent -> MaterialTheme.colors.background
else -> MaterialTheme.colors.background
}
)
.background(
when {
transparentBackground -> Color.Transparent
@@ -172,7 +172,7 @@ fun ChatListNavLinkView(chat: Chat, nextChatSelected: State<Boolean>) {
}
@Composable
private fun ErrorChatListItem() {
fun ErrorChatListItem() {
Box(Modifier.fillMaxWidth().padding(horizontal = 10.dp, vertical = 6.dp)) {
Text(stringResource(MR.strings.error_showing_content), color = MaterialTheme.colors.error, fontStyle = FontStyle.Italic)
}
@@ -407,13 +407,73 @@ fun DeleteContactAction(chat: Chat, chatModel: ChatModel, showMenu: MutableState
stringResource(MR.strings.delete_contact_menu_action),
painterResource(MR.images.ic_delete),
onClick = {
deleteContactDialog(chat, chatModel)
deleteContactConversationDialog(chat, chatModel)
showMenu.value = false
},
color = Color.Red
)
}
fun deleteContactConversationDialog(chat: Chat, chatModel: ChatModel, close: (() -> Unit)? = null) {
val chatInfo = chat.chatInfo
if (chatInfo is ChatInfo.Direct) {
val contactDeletedByUser = chatInfo.contact.contactStatus == ContactStatus.DeletedByUser
AlertManager.shared.showAlertDialogButtonsColumn(
title = if (contactDeletedByUser) generalGetString(MR.strings.delete_conversation_question) else generalGetString(MR.strings.delete_contact_question),
text = if (contactDeletedByUser) generalGetString(MR.strings.delete_conversation_all_messages_deleted_cannot_undo_warning) else null,
buttons = {
Column {
if (contactDeletedByUser) {
// Delete conversation
SectionItemView({
AlertManager.shared.hideAlert()
deleteContact(chat, chatModel, close, chatDeleteMode = ChatDeleteMode.Full(notify = false))
}) {
Text(generalGetString(MR.strings.delete_conversation), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.error)
}
} else {
// Delete contact
SectionItemView({
AlertManager.shared.hideAlert()
notifyDeleteContactDialog(chat, chatModel, close)
}) {
Text(generalGetString(MR.strings.button_delete_contact), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.error)
}
// Only delete conversation
SectionItemView({
AlertManager.shared.hideAlert()
deleteContact(chat, chatModel, close, chatDeleteMode = ChatDeleteMode.Messages())
if (chatModel.controller.appPrefs.showDeleteConversationNotice.get()) {
showDeleteConversationNotice(chatInfo.contact)
}
}) {
Text(generalGetString(MR.strings.only_delete_conversation), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.error)
}
}
// Cancel
SectionItemView({
AlertManager.shared.hideAlert()
}) {
Text(stringResource(MR.strings.cancel_verb), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.primary)
}
}
}
)
}
}
private fun showDeleteConversationNotice(contact: Contact) {
AlertManager.shared.showAlertDialog(
title = generalGetString(MR.strings.conversation_deleted),
text = String.format(generalGetString(MR.strings.you_can_still_send_messages_to_contact), contact.displayName),
confirmText = generalGetString(MR.strings.ok),
dismissText = generalGetString(MR.strings.dont_show_again),
onDismiss = {
chatModel.controller.appPrefs.showDeleteConversationNotice.set(false)
},
)
}
@Composable
fun DeleteGroupAction(chat: Chat, groupInfo: GroupInfo, chatModel: ChatModel, showMenu: MutableState<Boolean>) {
ItemAction(
@@ -3,336 +3,46 @@ package chat.simplex.common.views.chatlist
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.*
import androidx.compose.ui.graphics.*
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.platform.*
import androidx.compose.ui.text.TextRange
import dev.icerock.moko.resources.compose.painterResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.unit.*
import chat.simplex.common.SettingsViewState
import chat.simplex.common.model.*
import chat.simplex.common.model.ChatController.stopRemoteHostAndReloadHosts
import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.helpers.*
import chat.simplex.common.views.onboarding.WhatsNewView
import chat.simplex.common.views.onboarding.shouldShowWhatsNew
import chat.simplex.common.views.usersettings.SettingsView
import chat.simplex.common.platform.*
import chat.simplex.common.views.call.Call
import chat.simplex.common.views.newchat.*
import chat.simplex.res.MR
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import java.net.URI
@Composable
fun ChatListView(chatModel: ChatModel, settingsState: SettingsViewState, setPerformLA: (Boolean) -> Unit, stopped: Boolean) {
val newChatSheetState by rememberSaveable(stateSaver = AnimatedViewState.saver()) { mutableStateOf(MutableStateFlow(AnimatedViewState.GONE)) }
val showNewChatSheet = {
newChatSheetState.value = AnimatedViewState.VISIBLE
}
val hideNewChatSheet: (animated: Boolean) -> Unit = { animated ->
if (animated) newChatSheetState.value = AnimatedViewState.HIDING
else newChatSheetState.value = AnimatedViewState.GONE
}
LaunchedEffect(Unit) {
if (shouldShowWhatsNew(chatModel)) {
delay(1000L)
ModalManager.center.showCustomModal { close -> WhatsNewView(close = close) }
}
}
LaunchedEffect(chatModel.clearOverlays.value) {
if (chatModel.clearOverlays.value && newChatSheetState.value.isVisible()) hideNewChatSheet(false)
}
if (appPlatform.isDesktop) {
KeyChangeEffect(chatModel.chatId.value) {
if (chatModel.chatId.value != null) {
ModalManager.end.closeModalsExceptFirst()
}
AudioPlayer.stop()
VideoPlayerHolder.stopAll()
}
}
val endPadding = if (appPlatform.isDesktop) 56.dp else 0.dp
val searchText = rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue("")) }
val scope = rememberCoroutineScope()
val (userPickerState, scaffoldState ) = settingsState
Scaffold(topBar = { Box(Modifier.padding(end = endPadding)) { ChatListToolbar(searchText, scaffoldState.drawerState, userPickerState, stopped)} },
scaffoldState = scaffoldState,
drawerContent = {
tryOrShowError("Settings", error = { ErrorSettingsView() }) {
SettingsView(chatModel, setPerformLA, scaffoldState.drawerState)
}
},
contentColor = LocalContentColor.current,
drawerContentColor = LocalContentColor.current,
drawerScrimColor = MaterialTheme.colors.onSurface.copy(alpha = if (isInDarkTheme()) 0.16f else 0.32f),
drawerGesturesEnabled = appPlatform.isAndroid,
floatingActionButton = {
if (searchText.value.text.isEmpty() && !chatModel.desktopNoUserNoRemote && chatModel.chatRunning.value == true) {
FloatingActionButton(
onClick = {
if (!stopped) {
if (newChatSheetState.value.isVisible()) hideNewChatSheet(true) else showNewChatSheet()
}
},
Modifier.padding(end = DEFAULT_PADDING - 16.dp + endPadding, bottom = DEFAULT_PADDING - 16.dp),
elevation = FloatingActionButtonDefaults.elevation(
defaultElevation = 0.dp,
pressedElevation = 0.dp,
hoveredElevation = 0.dp,
focusedElevation = 0.dp,
),
backgroundColor = if (!stopped) MaterialTheme.colors.primary else MaterialTheme.colors.secondary,
contentColor = Color.White
) {
Icon(if (!newChatSheetState.collectAsState().value.isVisible()) painterResource(MR.images.ic_edit_filled) else painterResource(MR.images.ic_close), stringResource(MR.strings.add_contact_or_create_group))
}
}
}
) {
Box(Modifier.padding(it).padding(end = endPadding)) {
Box(
modifier = Modifier
.fillMaxSize()
) {
if (!chatModel.desktopNoUserNoRemote) {
ChatList(chatModel, searchText = searchText)
}
if (chatModel.chats.isEmpty() && !chatModel.switchingUsersAndHosts.value && !chatModel.desktopNoUserNoRemote) {
Text(stringResource(
if (chatModel.chatRunning.value == null) MR.strings.loading_chats else MR.strings.you_have_no_chats), Modifier.align(Alignment.Center), color = MaterialTheme.colors.secondary)
if (!stopped && !newChatSheetState.collectAsState().value.isVisible() && chatModel.chatRunning.value == true && searchText.value.text.isEmpty()) {
OnboardingButtons(showNewChatSheet)
}
}
}
}
}
if (searchText.value.text.isEmpty()) {
if (appPlatform.isDesktop) {
val call = remember { chatModel.activeCall }.value
if (call != null) {
ActiveCallInteractiveArea(call, newChatSheetState)
}
}
// TODO disable this button and sheet for the duration of the switch
tryOrShowError("NewChatSheet", error = {}) {
NewChatSheet(chatModel, newChatSheetState, stopped, hideNewChatSheet)
}
}
if (appPlatform.isAndroid) {
tryOrShowError("UserPicker", error = {}) {
UserPicker(chatModel, userPickerState) {
scope.launch { if (scaffoldState.drawerState.isOpen) scaffoldState.drawerState.close() else scaffoldState.drawerState.open() }
userPickerState.value = AnimatedViewState.GONE
}
}
}
}
@Composable
private fun OnboardingButtons(openNewChatSheet: () -> Unit) {
Column(Modifier.fillMaxSize().padding(DEFAULT_PADDING), horizontalAlignment = Alignment.End, verticalArrangement = Arrangement.Bottom) {
ConnectButton(generalGetString(MR.strings.tap_to_start_new_chat), openNewChatSheet)
val color = MaterialTheme.colors.primaryVariant
Canvas(modifier = Modifier.width(40.dp).height(10.dp), onDraw = {
val trianglePath = Path().apply {
moveTo(0.dp.toPx(), 0f)
lineTo(16.dp.toPx(), 0.dp.toPx())
lineTo(8.dp.toPx(), 10.dp.toPx())
lineTo(0.dp.toPx(), 0.dp.toPx())
}
drawPath(
color = color,
path = trianglePath
)
})
Spacer(Modifier.height(62.dp))
}
}
@Composable
private fun ConnectButton(text: String, onClick: () -> Unit) {
Button(
onClick,
shape = RoundedCornerShape(21.dp),
colors = ButtonDefaults.textButtonColors(
backgroundColor = MaterialTheme.colors.primaryVariant
),
elevation = null,
contentPadding = PaddingValues(horizontal = DEFAULT_PADDING, vertical = DEFAULT_PADDING_HALF),
modifier = Modifier.height(42.dp)
) {
Text(text, color = Color.White)
}
}
@Composable
private fun ChatListToolbar(searchInList: State<TextFieldValue>, drawerState: DrawerState, userPickerState: MutableStateFlow<AnimatedViewState>, stopped: Boolean) {
val barButtons = arrayListOf<@Composable RowScope.() -> Unit>()
if (stopped) {
barButtons.add {
IconButton(onClick = {
AlertManager.shared.showAlertMsg(
generalGetString(MR.strings.chat_is_stopped_indication),
generalGetString(MR.strings.you_can_start_chat_via_setting_or_by_restarting_the_app)
)
}) {
Icon(
painterResource(MR.images.ic_report_filled),
generalGetString(MR.strings.chat_is_stopped_indication),
tint = Color.Red,
)
}
}
}
val scope = rememberCoroutineScope()
DefaultTopAppBar(
navigationButton = {
if (chatModel.users.isEmpty() && !chatModel.desktopNoUserNoRemote) {
NavigationButtonMenu { scope.launch { if (drawerState.isOpen) drawerState.close() else drawerState.open() } }
} else {
val users by remember { derivedStateOf { chatModel.users.filter { u -> u.user.activeUser || !u.user.hidden } } }
val allRead = users
.filter { u -> !u.user.activeUser && !u.user.hidden }
.all { u -> u.unreadCount == 0 }
UserProfileButton(chatModel.currentUser.value?.profile?.image, allRead) {
if (users.size == 1 && chatModel.remoteHosts.isEmpty()) {
scope.launch { drawerState.open() }
} else {
userPickerState.value = AnimatedViewState.VISIBLE
}
}
}
},
title = {
Row(verticalAlignment = Alignment.CenterVertically) {
Text(
stringResource(MR.strings.your_chats),
color = MaterialTheme.colors.onBackground,
fontWeight = FontWeight.SemiBold,
)
if (chatModel.chats.size > 0) {
val enabled = remember { derivedStateOf { searchInList.value.text.isEmpty() } }
if (enabled.value) {
ToggleFilterEnabledButton()
} else {
ToggleFilterDisabledButton()
}
}
}
},
onTitleClick = null,
showSearch = false,
onSearchValueChanged = {},
buttons = barButtons
)
Divider(Modifier.padding(top = AppBarHeight))
}
@Composable
fun UserProfileButton(image: String?, allRead: Boolean, onButtonClicked: () -> Unit) {
Row(verticalAlignment = Alignment.CenterVertically) {
IconButton(onClick = onButtonClicked) {
Box {
ProfileImage(
image = image,
size = 37.dp,
color = MaterialTheme.colors.secondaryVariant.mixWith(MaterialTheme.colors.onBackground, 0.97f)
)
if (!allRead) {
unreadBadge()
}
}
}
if (appPlatform.isDesktop) {
val h by remember { chatModel.currentRemoteHost }
if (h != null) {
Spacer(Modifier.width(12.dp))
HostDisconnectButton {
stopRemoteHostAndReloadHosts(h!!, true)
}
}
}
}
}
@Composable
private fun BoxScope.unreadBadge(text: String? = "") {
Text(
text ?: "",
color = MaterialTheme.colors.onPrimary,
fontSize = 6.sp,
modifier = Modifier
.background(MaterialTheme.colors.primary, shape = CircleShape)
.badgeLayout()
.padding(horizontal = 3.dp)
.padding(vertical = 1.dp)
.align(Alignment.TopEnd)
)
}
@Composable
private fun ToggleFilterEnabledButton() {
fun ToggleFilterButton() {
val pref = remember { ChatController.appPrefs.showUnreadAndFavorites }
IconButton(onClick = { pref.set(!pref.get()) }) {
Icon(
painterResource(MR.images.ic_filter_list),
null,
tint = if (pref.state.value) MaterialTheme.colors.background else MaterialTheme.colors.primary,
tint = if (pref.state.value) MaterialTheme.colors.background else MaterialTheme.colors.secondary,
modifier = Modifier
.padding(3.dp)
.background(color = if (pref.state.value) MaterialTheme.colors.primary else Color.Unspecified, shape = RoundedCornerShape(50))
.border(width = 1.dp, color = MaterialTheme.colors.primary, shape = RoundedCornerShape(50))
.border(width = 1.dp, color = if (pref.state.value) MaterialTheme.colors.primary else Color.Unspecified, shape = RoundedCornerShape(50))
.padding(3.dp)
.size(16.dp)
)
}
}
@Composable
private fun ToggleFilterDisabledButton() {
IconButton({}, enabled = false) {
Icon(
painterResource(MR.images.ic_filter_list),
null,
tint = MaterialTheme.colors.secondary,
modifier = Modifier
.padding(3.dp)
.border(width = 1.dp, color = MaterialTheme.colors.secondary, shape = RoundedCornerShape(50))
.padding(3.dp)
.size(16.dp)
)
}
}
@Composable
expect fun ActiveCallInteractiveArea(call: Call, newChatSheetState: MutableStateFlow<AnimatedViewState>)
fun connectIfOpenedViaUri(rhId: Long?, uri: URI, chatModel: ChatModel) {
Log.d(TAG, "connectIfOpenedViaUri: opened via link")
if (chatModel.currentUser.value == null) {
chatModel.appOpenUrl.value = rhId to uri
} else {
withBGApi {
planAndConnect(rhId, uri, incognito = null, close = null)
}
}
}
@Composable
private fun ChatListSearchBar(listState: LazyListState, searchText: MutableState<TextFieldValue>, searchShowingSimplexLink: MutableState<Boolean>, searchChatFilteredBySimplexLink: MutableState<String?>) {
Row(verticalAlignment = Alignment.CenterVertically) {
@@ -359,28 +69,8 @@ private fun ChatListSearchBar(listState: LazyListState, searchText: MutableState
} else {
Row {
val padding = if (appPlatform.isDesktop) 0.dp else 7.dp
val clipboard = LocalClipboardManager.current
val clipboardHasText = remember(focused) { chatModel.clipboardHasText }.value
if (clipboardHasText) {
IconButton(
onClick = { searchText.value = searchText.value.copy(clipboard.getText()?.text ?: return@IconButton) },
Modifier.size(30.dp).desktopPointerHoverIconHand()
) {
Icon(painterResource(MR.images.ic_article), null, tint = MaterialTheme.colors.secondary)
}
}
Spacer(Modifier.width(padding))
IconButton(
onClick = {
val fixedRhId = chatModel.currentRemoteHost.value
ModalManager.center.closeModals()
ModalManager.center.showModalCloseable { close ->
NewChatView(fixedRhId, selection = NewChatOption.CONNECT, showQRCodeScanner = true, close = close)
}
},
Modifier.size(30.dp).desktopPointerHoverIconHand()
) {
Icon(painterResource(MR.images.ic_qr_code), null, tint = MaterialTheme.colors.secondary)
if (chatModel.chats.size > 0) {
ToggleFilterButton()
}
Spacer(Modifier.width(padding))
}
@@ -437,17 +127,10 @@ private fun connect(link: String, searchChatFilteredBySimplexLink: MutableState<
}
}
@Composable
private fun ErrorSettingsView() {
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Text(generalGetString(MR.strings.error_showing_content), color = MaterialTheme.colors.error, fontStyle = FontStyle.Italic)
}
}
private var lazyListState = 0 to 0
@Composable
private fun ChatList(chatModel: ChatModel, searchText: MutableState<TextFieldValue>) {
fun ChatList(chatModel: ChatModel, searchText: MutableState<TextFieldValue>) {
val listState = rememberLazyListState(lazyListState.first, lazyListState.second)
DisposableEffect(Unit) {
onDispose { lazyListState = listState.firstVisibleItemIndex to listState.firstVisibleItemScrollOffset }
@@ -508,17 +191,18 @@ private fun filteredChats(
} else {
val s = if (searchShowingSimplexLink.value) "" else searchText.trim().lowercase()
if (s.isEmpty() && !showUnreadAndFavorites)
chats
chats.filter { chat -> !chat.chatInfo.chatDeleted }
else {
chats.filter { chat ->
when (val cInfo = chat.chatInfo) {
is ChatInfo.Direct -> if (s.isEmpty()) {
chat.id == chatModel.chatId.value || filtered(chat)
} else {
(viewNameContains(cInfo, s) ||
cInfo.contact.profile.displayName.lowercase().contains(s) ||
cInfo.contact.fullName.lowercase().contains(s))
}
is ChatInfo.Direct -> !chat.chatInfo.chatDeleted && (
if (s.isEmpty()) {
chat.id == chatModel.chatId.value || filtered(chat)
} else {
(viewNameContains(cInfo, s) ||
cInfo.contact.profile.displayName.lowercase().contains(s) ||
cInfo.contact.fullName.lowercase().contains(s))
})
is ChatInfo.Group -> if (s.isEmpty()) {
chat.id == chatModel.chatId.value || filtered(chat) || cInfo.groupInfo.membership.memberStatus == GroupMemberStatus.MemInvited
} else {
@@ -198,7 +198,7 @@ fun ChatPreviewView(
} else {
when (cInfo) {
is ChatInfo.Direct ->
if (cInfo.contact.activeConn == null && cInfo.contact.profile.contactLink != null) {
if (cInfo.contact.activeConn == null && cInfo.contact.profile.contactLink != null && cInfo.contact.active) {
Text(stringResource(MR.strings.contact_tap_to_connect), color = MaterialTheme.colors.primary)
} else if (!cInfo.ready && cInfo.contact.activeConn != null) {
if (cInfo.contact.nextSendGrpInv) {
@@ -9,30 +9,55 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import chat.simplex.common.views.helpers.ProfileImage
import chat.simplex.common.model.*
import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.helpers.*
import chat.simplex.res.MR
@Composable
fun ShareListNavLinkView(chat: Chat, chatModel: ChatModel) {
fun ShareListNavLinkView(
chat: Chat,
chatModel: ChatModel,
isMediaOrFileAttachment: Boolean,
isVoice: Boolean,
hasSimplexLink: Boolean
) {
val stopped = chatModel.chatRunning.value == false
when (chat.chatInfo) {
is ChatInfo.Direct ->
is ChatInfo.Direct -> {
val voiceProhibited = isVoice && !chat.chatInfo.featureEnabled(ChatFeature.Voice)
ShareListNavLinkLayout(
chatLinkPreview = { SharePreviewView(chat) },
click = { directChatAction(chat.remoteHostId, chat.chatInfo.contact, chatModel) },
chatLinkPreview = { SharePreviewView(chat, disabled = voiceProhibited) },
click = {
if (voiceProhibited) {
showForwardProhibitedByPrefAlert()
} else {
directChatAction(chat.remoteHostId, chat.chatInfo.contact, chatModel)
}
},
stopped
)
is ChatInfo.Group ->
}
is ChatInfo.Group -> {
val simplexLinkProhibited = hasSimplexLink && !chat.groupFeatureEnabled(GroupFeature.SimplexLinks)
val fileProhibited = isMediaOrFileAttachment && !chat.groupFeatureEnabled(GroupFeature.Files)
val voiceProhibited = isVoice && !chat.chatInfo.featureEnabled(ChatFeature.Voice)
val prohibitedByPref = simplexLinkProhibited || fileProhibited || voiceProhibited
ShareListNavLinkLayout(
chatLinkPreview = { SharePreviewView(chat) },
click = { groupChatAction(chat.remoteHostId, chat.chatInfo.groupInfo, chatModel) },
chatLinkPreview = { SharePreviewView(chat, disabled = prohibitedByPref) },
click = {
if (prohibitedByPref) {
showForwardProhibitedByPrefAlert()
} else {
groupChatAction(chat.remoteHostId, chat.chatInfo.groupInfo, chatModel)
}
},
stopped
)
}
is ChatInfo.Local ->
ShareListNavLinkLayout(
chatLinkPreview = { SharePreviewView(chat) },
chatLinkPreview = { SharePreviewView(chat, disabled = false) },
click = { noteFolderChatAction(chat.remoteHostId, chat.chatInfo.noteFolder) },
stopped
)
@@ -40,6 +65,13 @@ fun ShareListNavLinkView(chat: Chat, chatModel: ChatModel) {
}
}
private fun showForwardProhibitedByPrefAlert() {
AlertManager.shared.showAlertMsg(
title = generalGetString(MR.strings.cannot_share_message_alert_title),
text = generalGetString(MR.strings.cannot_share_message_alert_text),
)
}
@Composable
private fun ShareListNavLinkLayout(
chatLinkPreview: @Composable () -> Unit,
@@ -53,7 +85,7 @@ private fun ShareListNavLinkLayout(
}
@Composable
private fun SharePreviewView(chat: Chat) {
private fun SharePreviewView(chat: Chat, disabled: Boolean) {
Row(
Modifier.fillMaxSize(),
horizontalArrangement = Arrangement.SpaceBetween,
@@ -70,7 +102,7 @@ private fun SharePreviewView(chat: Chat) {
}
Text(
chat.chatInfo.chatViewName, maxLines = 1, overflow = TextOverflow.Ellipsis,
color = if (chat.chatInfo.incognito) Indigo else Color.Unspecified
color = if (disabled) MaterialTheme.colors.secondary else if (chat.chatInfo.incognito) Indigo else Color.Unspecified
)
}
}
@@ -16,6 +16,7 @@ import chat.simplex.common.SettingsViewState
import chat.simplex.common.model.*
import chat.simplex.common.views.helpers.*
import chat.simplex.common.platform.*
import chat.simplex.common.views.home.UserProfileButton
import chat.simplex.res.MR
import kotlinx.coroutines.flow.MutableStateFlow
@@ -31,13 +32,44 @@ fun ShareListView(chatModel: ChatModel, settingsState: SettingsViewState, stoppe
scaffoldState = scaffoldState,
topBar = { Column { ShareListToolbar(chatModel, userPickerState, stopped) { searchInList = it.trim() } } },
) {
val sharedContent = chatModel.sharedContent.value
var isMediaOrFileAttachment = false
var isVoice = false
var hasSimplexLink = false
when (sharedContent) {
is SharedContent.Text ->
hasSimplexLink = hasSimplexLink(sharedContent.text)
is SharedContent.Media -> {
isMediaOrFileAttachment = true
hasSimplexLink = hasSimplexLink(sharedContent.text)
}
is SharedContent.File -> {
isMediaOrFileAttachment = true
hasSimplexLink = hasSimplexLink(sharedContent.text)
}
is SharedContent.Forward -> {
val mc = sharedContent.chatItem.content.msgContent
if (mc != null) {
isMediaOrFileAttachment = mc.isMediaOrFileAttachment
isVoice = mc.isVoice
hasSimplexLink = hasSimplexLink(mc.text)
}
}
null -> {}
}
Box(Modifier.padding(it)) {
Column(
modifier = Modifier
.fillMaxSize()
) {
if (chatModel.chats.isNotEmpty()) {
ShareList(chatModel, search = searchInList)
ShareList(
chatModel,
search = searchInList,
isMediaOrFileAttachment = isMediaOrFileAttachment,
isVoice = isVoice,
hasSimplexLink = hasSimplexLink
)
} else {
EmptyList()
}
@@ -54,6 +86,11 @@ fun ShareListView(chatModel: ChatModel, settingsState: SettingsViewState, stoppe
}
}
private fun hasSimplexLink(msg: String): Boolean {
val parsedMsg = parseToMarkdown(msg) ?: return false
return parsedMsg.any { ft -> ft.format is Format.SimplexLink }
}
@Composable
private fun EmptyList() {
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
@@ -141,7 +178,13 @@ private fun ShareListToolbar(chatModel: ChatModel, userPickerState: MutableState
}
@Composable
private fun ShareList(chatModel: ChatModel, search: String) {
private fun ShareList(
chatModel: ChatModel,
search: String,
isMediaOrFileAttachment: Boolean,
isVoice: Boolean,
hasSimplexLink: Boolean
) {
val chats by remember(search) {
derivedStateOf {
val sorted = chatModel.chats.toList().sortedByDescending { it.chatInfo is ChatInfo.Local }
@@ -156,7 +199,13 @@ private fun ShareList(chatModel: ChatModel, search: String) {
modifier = Modifier.fillMaxWidth()
) {
items(chats) { chat ->
ShareListNavLinkView(chat, chatModel)
ShareListNavLinkView(
chat,
chatModel,
isMediaOrFileAttachment = isMediaOrFileAttachment,
isVoice = isVoice,
hasSimplexLink = hasSimplexLink
)
}
}
}
@@ -153,6 +153,8 @@ fun UserPicker(
) {
Column(
Modifier
.align(Alignment.BottomStart)
.padding(bottom = BottomAppBarHeight)
.widthIn(min = 260.dp)
.width(IntrinsicSize.Min)
.height(IntrinsicSize.Min)
@@ -0,0 +1,104 @@
package chat.simplex.common.views.contacts
import androidx.compose.runtime.*
import androidx.compose.ui.graphics.Color
import dev.icerock.moko.resources.compose.painterResource
import dev.icerock.moko.resources.compose.stringResource
import chat.simplex.common.model.*
import chat.simplex.common.platform.*
import chat.simplex.common.views.chat.*
import chat.simplex.common.views.chat.item.ItemAction
import chat.simplex.common.views.chatlist.*
import chat.simplex.common.views.helpers.*
import chat.simplex.res.MR
import kotlinx.coroutines.delay
@Composable
fun ContactListNavLinkView(chat: Chat, nextChatSelected: State<Boolean>) {
val showMenu = remember { mutableStateOf(false) }
val disabled = chatModel.chatRunning.value == false || chatModel.deletedChats.value.contains(chat.remoteHostId to chat.chatInfo.id)
LaunchedEffect(chat.id) {
showMenu.value = false
delay(500L)
}
val selectedChat = remember(chat.id) { derivedStateOf { chat.id == chatModel.chatId.value } }
val view = LocalMultiplatformView()
when (chat.chatInfo) {
is ChatInfo.Direct -> {
ChatListNavLinkLayout(
chatLinkPreview = {
tryOrShowError("${chat.id}ContactListNavLink", error = { ErrorChatListItem() }) {
ContactPreviewView(chat, disabled)
}
},
click = {
val chatRh = chat.remoteHostId
if (ModalManager.end.hasModalsOpen()) {
ModalManager.end.closeModals()
// return@ChatLayout -- TODO what's this for?
}
hideKeyboard(view)
withBGApi {
var preloadedContactInfo: Pair<ConnectionStats?, Profile?>? = chatModel.controller.apiContactInfo(chatRh, chat.chatInfo.apiId)
var preloadedCode: String? = chatModel.controller.apiGetContactCode(chatRh, chat.chatInfo.apiId)?.second
ModalManager.end.showModalCloseable(true) { close ->
var contactInfo: Pair<ConnectionStats?, Profile?>? by remember { mutableStateOf(preloadedContactInfo) }
var code: String? by remember { mutableStateOf(preloadedCode) }
KeyChangeEffect(chat.id, ChatModel.networkStatuses.toMap()) {
contactInfo = chatModel.controller.apiContactInfo(chatRh, chat.chatInfo.apiId)
preloadedContactInfo = contactInfo
code = chatModel.controller.apiGetContactCode(chatRh, chat.chatInfo.apiId)?.second
preloadedCode = code
}
ChatInfoView(chatModel, openedFromChatView = false, chat.chatInfo.contact, contactInfo?.first, contactInfo?.second, chat.chatInfo.localAlias, code, close)
}
}
},
dropdownMenuItems = {
tryOrShowError("${chat.id}ContactListNavLinkDropdown", error = {}) {
ContactMenuItems(chat, chat.chatInfo.contact, chatModel, showMenu)
}
},
showMenu,
disabled,
selectedChat,
nextChatSelected,
)
}
else -> {}
}
}
@Composable
fun ContactMenuItems(chat: Chat, contact: Contact, chatModel: ChatModel, showMenu: MutableState<Boolean>) {
if (contact.activeConn != null) {
ToggleFavoritesChatAction(chat, chatModel, chat.chatInfo.chatSettings?.favorite == true, showMenu)
}
DeleteContactAction(chat, chatModel, showMenu)
}
@Composable
fun ToggleFavoritesChatAction(chat: Chat, chatModel: ChatModel, favorite: Boolean, showMenu: MutableState<Boolean>) {
ItemAction(
if (favorite) stringResource(MR.strings.unfavorite_chat) else stringResource(MR.strings.favorite_chat),
if (favorite) painterResource(MR.images.ic_star_off) else painterResource(MR.images.ic_star),
onClick = {
toggleChatFavorite(chat, !favorite, chatModel)
showMenu.value = false
}
)
}
@Composable
fun DeleteContactAction(chat: Chat, chatModel: ChatModel, showMenu: MutableState<Boolean>) {
ItemAction(
stringResource(MR.strings.delete_contact_menu_action),
painterResource(MR.images.ic_delete),
onClick = {
deleteContactDialog(chat, chatModel)
showMenu.value = false
},
color = Color.Red
)
}
@@ -0,0 +1,117 @@
package chat.simplex.common.views.contacts
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import dev.icerock.moko.resources.compose.painterResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.*
import chat.simplex.common.views.helpers.*
import chat.simplex.common.model.*
import chat.simplex.common.platform.chatModel
import chat.simplex.common.ui.theme.DEFAULT_SPACE_AFTER_ICON
import chat.simplex.res.MR
@Composable
fun ContactPreviewView(
chat: Chat,
disabled: Boolean,
) {
val cInfo = chat.chatInfo
@Composable
fun inactiveIcon() {
Icon(
painterResource(MR.images.ic_cancel_filled),
stringResource(MR.strings.icon_descr_group_inactive),
Modifier.size(18.dp).background(MaterialTheme.colors.background, CircleShape),
tint = MaterialTheme.colors.secondary
)
}
@Composable
fun chatPreviewImageOverlayIcon() {
when (cInfo) {
is ChatInfo.Direct ->
if (!cInfo.contact.active) {
inactiveIcon()
}
else -> {}
}
}
@Composable
fun VerifiedIcon() {
Icon(painterResource(MR.images.ic_verified_user), null, Modifier.size(19.dp).padding(end = 3.dp, top = 1.dp), tint = MaterialTheme.colors.secondary)
}
@Composable
fun chatPreviewTitle() {
val deleting by remember(disabled, chat.id) { mutableStateOf(chatModel.deletedChats.value.contains(chat.remoteHostId to chat.chatInfo.id)) }
when (cInfo) {
is ChatInfo.Direct ->
Row(verticalAlignment = Alignment.CenterVertically) {
if (cInfo.contact.verified) {
VerifiedIcon()
}
Text(
cInfo.chatViewName,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
color = if (deleting) MaterialTheme.colors.secondary else Color.Unspecified
)
}
else -> {}
}
}
Row(
verticalAlignment = Alignment.CenterVertically
) {
Box(contentAlignment = Alignment.BottomEnd) {
ChatInfoImage(cInfo, size = 42.dp)
Box(Modifier.padding(end = 2.dp, bottom = 2.dp)) {
chatPreviewImageOverlayIcon()
}
}
Spacer(Modifier.width(DEFAULT_SPACE_AFTER_ICON))
Box(modifier = Modifier.weight(10f, fill = true)) {
chatPreviewTitle()
}
Spacer(Modifier.fillMaxWidth().weight(1f))
if (chat.chatInfo.chatSettings?.favorite == true) {
Icon(
painterResource(MR.images.ic_star_filled),
contentDescription = generalGetString(MR.strings.favorite_chat),
tint = MaterialTheme.colors.secondary,
modifier = Modifier
.size(17.dp)
)
if (chat.chatInfo.incognito) {
Spacer(Modifier.width(DEFAULT_SPACE_AFTER_ICON))
}
}
if (chat.chatInfo.incognito) {
Icon(
painterResource(MR.images.ic_theater_comedy),
contentDescription = null,
tint = MaterialTheme.colors.secondary,
modifier = Modifier
.size(21.dp)
)
}
}
}
@@ -0,0 +1,160 @@
package chat.simplex.common.views.contacts
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.*
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.*
import androidx.compose.ui.platform.*
import dev.icerock.moko.resources.compose.painterResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.unit.*
import chat.simplex.common.model.*
import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.helpers.*
import chat.simplex.common.platform.*
import chat.simplex.common.views.chatlist.ToggleFilterButton
import chat.simplex.common.views.home.contactChats
import chat.simplex.res.MR
import kotlinx.coroutines.flow.distinctUntilChanged
@Composable
private fun ContactsSearchBar(listState: LazyListState, searchText: MutableState<TextFieldValue>) {
Row(verticalAlignment = Alignment.CenterVertically) {
val focusRequester = remember { FocusRequester() }
var focused by remember { mutableStateOf(false) }
Icon(painterResource(MR.images.ic_search), null, Modifier.padding(horizontal = DEFAULT_PADDING_HALF), tint = MaterialTheme.colors.secondary)
SearchTextField(
Modifier.weight(1f).onFocusChanged { focused = it.hasFocus }.focusRequester(focusRequester),
placeholder = stringResource(MR.strings.search_verb),
alwaysVisible = true,
searchText = searchText,
trailingContent = null,
) {
searchText.value = searchText.value.copy(it)
}
val hasText = remember { derivedStateOf { searchText.value.text.isNotEmpty() } }
if (hasText.value) {
val hideSearchOnBack: () -> Unit = { searchText.value = TextFieldValue() }
BackHandler(onBack = hideSearchOnBack)
KeyChangeEffect(chatModel.currentRemoteHost.value) {
hideSearchOnBack()
}
} else {
Row {
val padding = if (appPlatform.isDesktop) 0.dp else 7.dp
if (chatModel.chats.size > 0) {
ToggleFilterButton()
}
Spacer(Modifier.width(padding))
}
}
val focusManager = LocalFocusManager.current
val keyboardState = getKeyboardState()
LaunchedEffect(keyboardState.value) {
if (keyboardState.value == KeyboardState.Closed && focused) {
focusManager.clearFocus()
}
}
LaunchedEffect(Unit) {
snapshotFlow { searchText.value.text }
.distinctUntilChanged()
.collect {
if (it.isNotEmpty()) {
focusRequester.requestFocus()
} else if (listState.layoutInfo.totalItemsCount > 0) {
listState.scrollToItem(0)
}
}
}
}
}
private var lazyListState = 0 to 0
@Composable
fun ContactsList(chatModel: ChatModel, searchText: MutableState<TextFieldValue>) {
val listState = rememberLazyListState(lazyListState.first, lazyListState.second)
DisposableEffect(Unit) {
onDispose { lazyListState = listState.firstVisibleItemIndex to listState.firstVisibleItemScrollOffset }
}
val showUnreadAndFavorites = remember { ChatController.appPrefs.showUnreadAndFavorites.state }.value
val allContactChats = remember(chatModel.chats.toList()) { contactChats(chatModel.chats) }
// See "IndexOutOfBoundsException" comment in ChatListView
val filteredContactChats = filteredContactChats(showUnreadAndFavorites, searchText.value.text, allContactChats.toList())
LazyColumnWithScrollBar(
Modifier.fillMaxWidth(),
listState
) {
stickyHeader {
Column(
Modifier
.offset {
val y = if (searchText.value.text.isEmpty()) {
if (listState.firstVisibleItemIndex == 0) -listState.firstVisibleItemScrollOffset else -1000
} else {
0
}
IntOffset(0, y)
}
.background(MaterialTheme.colors.background)
) {
ContactsSearchBar(listState, searchText)
Divider()
}
}
itemsIndexed(filteredContactChats) { index, chat ->
val nextChatSelected = remember(chat.id, filteredContactChats) { derivedStateOf {
chatModel.chatId.value != null && filteredContactChats.getOrNull(index + 1)?.id == chatModel.chatId.value
} }
ContactListNavLinkView(chat, nextChatSelected)
}
}
if (filteredContactChats.isEmpty() && allContactChats.isNotEmpty()) {
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Text(generalGetString(MR.strings.no_filtered_contacts), color = MaterialTheme.colors.secondary)
}
}
}
private fun filteredContactChats(
showUnreadAndFavorites: Boolean,
searchText: String,
contactChats: List<Chat>
): List<Chat> {
val s = searchText.trim().lowercase()
return (
if (s.isEmpty() && !showUnreadAndFavorites)
contactChats.filter { chat ->
when (val cInfo = chat.chatInfo) {
is ChatInfo.Direct -> cInfo.contact.contactStatus != ContactStatus.DeletedByUser
else -> false
}
}
else {
contactChats.filter { chat ->
when (val cInfo = chat.chatInfo) {
is ChatInfo.Direct -> cInfo.contact.contactStatus != ContactStatus.DeletedByUser && (
if (s.isEmpty()) {
chat.id == chatModel.chatId.value ||
(cInfo.chatSettings?.favorite ?: false)
} else {
(viewNameContains(cInfo, s) ||
cInfo.contact.profile.displayName.lowercase().contains(s) ||
cInfo.contact.fullName.lowercase().contains(s))
})
else -> false
}
}
}
).sortedBy { it.chatInfo.displayName.lowercase() }
}
private fun viewNameContains(cInfo: ChatInfo, s: String): Boolean =
cInfo.chatViewName.lowercase().contains(s.lowercase())
@@ -27,6 +27,7 @@ import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.unit.*
import chat.simplex.common.model.*
import chat.simplex.common.model.ChatController.appPrefs
import chat.simplex.common.platform.*
import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.helpers.*
@@ -40,9 +41,8 @@ import kotlin.math.log2
@Composable
fun DatabaseEncryptionView(m: ChatModel, migration: Boolean) {
val progressIndicator = remember { mutableStateOf(false) }
val prefs = m.controller.appPrefs
val useKeychain = remember { mutableStateOf(prefs.storeDBPassphrase.get()) }
val initialRandomDBPassphrase = remember { mutableStateOf(prefs.initialRandomDBPassphrase.get()) }
val useKeychain = remember { mutableStateOf(appPrefs.storeDBPassphrase.get()) }
val initialRandomDBPassphrase = remember { mutableStateOf(appPrefs.initialRandomDBPassphrase.get()) }
val storedKey = remember { val key = DatabaseUtils.ksDatabasePassword.get(); mutableStateOf(key != null && key != "") }
// Do not do rememberSaveable on current key to prevent saving it on disk in clear text
val currentKey = remember { mutableStateOf(if (initialRandomDBPassphrase.value) DatabaseUtils.ksDatabasePassword.get() ?: "" else "") }
@@ -54,7 +54,6 @@ fun DatabaseEncryptionView(m: ChatModel, migration: Boolean) {
) {
DatabaseEncryptionLayout(
useKeychain,
prefs,
m.chatDbEncrypted.value,
currentKey,
newKey,
@@ -65,7 +64,16 @@ fun DatabaseEncryptionView(m: ChatModel, migration: Boolean) {
migration,
onConfirmEncrypt = {
withLongRunningApi {
encryptDatabase(currentKey, newKey, confirmNewKey, initialRandomDBPassphrase, useKeychain, storedKey, progressIndicator, migration)
encryptDatabase(
currentKey = currentKey,
newKey = newKey,
confirmNewKey = confirmNewKey,
initialRandomDBPassphrase = initialRandomDBPassphrase,
useKeychain = useKeychain,
storedKey = storedKey,
progressIndicator = progressIndicator,
migration = migration
)
}
}
)
@@ -89,7 +97,6 @@ fun DatabaseEncryptionView(m: ChatModel, migration: Boolean) {
@Composable
fun DatabaseEncryptionLayout(
useKeychain: MutableState<Boolean>,
prefs: AppPreferences,
chatDbEncrypted: Boolean?,
currentKey: MutableState<String>,
newKey: MutableState<String>,
@@ -119,14 +126,14 @@ fun DatabaseEncryptionLayout(
enabled = (!initialRandomDBPassphrase.value && !progressIndicator.value) || migration
) { checked ->
if (checked) {
setUseKeychain(true, useKeychain, prefs, migration)
setUseKeychain(true, useKeychain, migration)
} else if (storedKey.value && !migration) {
// Don't show in migration process since it will remove the key after successful encryption
removePassphraseAlert {
removePassphraseFromKeyChain(useKeychain, prefs, storedKey, false)
removePassphraseFromKeyChain(useKeychain, storedKey, false)
}
} else {
setUseKeychain(false, useKeychain, prefs, migration)
setUseKeychain(false, useKeychain, migration)
}
}
@@ -272,17 +279,17 @@ fun resetFormAfterEncryption(
m.controller.appPrefs.initialRandomDBPassphrase.set(false)
}
fun setUseKeychain(value: Boolean, useKeychain: MutableState<Boolean>, prefs: AppPreferences, migration: Boolean) {
fun setUseKeychain(value: Boolean, useKeychain: MutableState<Boolean>, migration: Boolean) {
useKeychain.value = value
// Postpone it when migrating to the end of encryption process
if (!migration) {
prefs.storeDBPassphrase.set(value)
appPrefs.storeDBPassphrase.set(value)
}
}
private fun removePassphraseFromKeyChain(useKeychain: MutableState<Boolean>, prefs: AppPreferences, storedKey: MutableState<Boolean>, migration: Boolean) {
private fun removePassphraseFromKeyChain(useKeychain: MutableState<Boolean>, storedKey: MutableState<Boolean>, migration: Boolean) {
DatabaseUtils.ksDatabasePassword.remove()
setUseKeychain(false, useKeychain, prefs, migration)
setUseKeychain(false, useKeychain, migration)
storedKey.value = false
}
@@ -415,15 +422,14 @@ suspend fun encryptDatabase(
migration: Boolean,
): Boolean {
val m = ChatModel
val prefs = ChatController.appPrefs
progressIndicator.value = true
return try {
prefs.encryptionStartedAt.set(Clock.System.now())
appPrefs.encryptionStartedAt.set(Clock.System.now())
if (!m.chatDbChanged.value) {
m.controller.apiSaveAppSettings(AppSettings.current.prepareForExport())
}
val error = m.controller.apiStorageEncryption(currentKey.value, newKey.value)
prefs.encryptionStartedAt.set(null)
appPrefs.encryptionStartedAt.set(null)
val sqliteError = ((error?.chatError as? ChatError.ChatErrorDatabase)?.databaseError as? DatabaseError.ErrorExport)?.sqliteError
when {
sqliteError is SQLiteError.ErrorNotADatabase -> {
@@ -451,8 +457,8 @@ suspend fun encryptDatabase(
resetFormAfterEncryption(m, initialRandomDBPassphrase, currentKey, newKey, confirmNewKey, storedKey, useKeychain.value)
if (useKeychain.value) {
DatabaseUtils.ksDatabasePassword.set(new)
} else if (migration) {
removePassphraseFromKeyChain(useKeychain, prefs, storedKey, true)
} else {
removePassphraseFromKeyChain(useKeychain, storedKey, migration)
}
operationEnded(m, progressIndicator) {
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.database_encrypted))
@@ -523,7 +529,6 @@ fun PreviewDatabaseEncryptionLayout() {
SimpleXTheme {
DatabaseEncryptionLayout(
useKeychain = remember { mutableStateOf(true) },
prefs = AppPreferences(),
chatDbEncrypted = true,
currentKey = remember { mutableStateOf("") },
newKey = remember { mutableStateOf("") },
@@ -448,6 +448,9 @@ private fun stopChat(m: ChatModel, progressIndicator: MutableState<Boolean>? = n
progressIndicator?.value = true
stopChatAsync(m)
platform.androidChatStopped()
// close chat view for desktop
chatModel.chatId.value = null
ModalManager.end.closeModals()
onStop?.invoke()
} catch (e: Error) {
m.chatRunning.value = true
@@ -15,7 +15,7 @@ import chat.simplex.res.MR
@Composable
fun DefaultTopAppBar(
navigationButton: @Composable RowScope.() -> Unit,
navigationButton: (@Composable RowScope.() -> Unit)? = null,
title: (@Composable () -> Unit)?,
onTitleClick: (() -> Unit)? = null,
showSearch: Boolean,
@@ -125,5 +125,6 @@ private fun TopAppBar(
val AppBarHeight = 56.dp
val AppBarHorizontalPadding = 4.dp
val BottomAppBarHeight = 60.dp
private val TitleInsetWithoutIcon = DEFAULT_PADDING - AppBarHorizontalPadding
val TitleInsetWithIcon = 72.dp
@@ -37,7 +37,7 @@ fun SwipeToDismissModifier(
return Modifier.swipeable(
state = state,
anchors = anchors,
thresholds = { _, _ -> FractionalThreshold(0.5f) },
thresholds = { _, _ -> FractionalThreshold(0.99f) },
orientation = Orientation.Horizontal,
reverseDirection = isRtl,
).offset { IntOffset(state.offset.value.roundToInt(), 0) }
@@ -10,7 +10,7 @@ import androidx.compose.ui.unit.*
import chat.simplex.common.model.*
import chat.simplex.common.platform.*
import chat.simplex.common.ui.theme.ThemeOverrides
import chat.simplex.common.views.chatlist.connectIfOpenedViaUri
import chat.simplex.common.views.home.connectIfOpenedViaUri
import chat.simplex.res.MR
import com.charleskorn.kaml.decodeFromStream
import dev.icerock.moko.resources.StringResource
@@ -0,0 +1,372 @@
package chat.simplex.common.views.home
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.*
import androidx.compose.ui.text.font.FontStyle
import dev.icerock.moko.resources.compose.painterResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.unit.*
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import chat.simplex.common.SettingsViewState
import chat.simplex.common.model.*
import chat.simplex.common.model.ChatController.chatModel
import chat.simplex.common.model.ChatController.stopRemoteHostAndReloadHosts
import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.helpers.*
import chat.simplex.common.views.onboarding.WhatsNewView
import chat.simplex.common.views.onboarding.shouldShowWhatsNew
import chat.simplex.common.views.usersettings.SettingsView
import chat.simplex.common.platform.*
import chat.simplex.common.views.call.Call
import chat.simplex.common.views.chatlist.*
import chat.simplex.common.views.contacts.ContactsList
import chat.simplex.common.views.newchat.*
import chat.simplex.res.MR
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.MutableStateFlow
import java.net.URI
sealed class HomeTab {
class Chats: HomeTab()
class Contacts: HomeTab()
}
@Composable
fun HomeView(chatModel: ChatModel, settingsState: SettingsViewState, setPerformLA: (Boolean) -> Unit, stopped: Boolean) {
val homeTab = remember { mutableStateOf<HomeTab>(HomeTab.Chats()) }
val newChatSheetState by rememberSaveable(stateSaver = AnimatedViewState.saver()) { mutableStateOf(MutableStateFlow(AnimatedViewState.GONE)) }
val showNewChatSheet = {
newChatSheetState.value = AnimatedViewState.VISIBLE
}
val hideNewChatSheet: (animated: Boolean) -> Unit = { animated ->
if (animated) newChatSheetState.value = AnimatedViewState.HIDING
else newChatSheetState.value = AnimatedViewState.GONE
}
LaunchedEffect(Unit) {
if (shouldShowWhatsNew(chatModel)) {
delay(1000L)
ModalManager.center.showCustomModal { close -> WhatsNewView(close = close) }
}
}
LaunchedEffect(chatModel.clearOverlays.value) {
if (chatModel.clearOverlays.value && newChatSheetState.value.isVisible()) hideNewChatSheet(false)
}
if (appPlatform.isDesktop) {
KeyChangeEffect(chatModel.chatId.value) {
if (chatModel.chatId.value != null) {
ModalManager.end.closeModalsExceptFirst()
}
AudioPlayer.stop()
VideoPlayerHolder.stopAll()
}
}
val endPadding = if (appPlatform.isDesktop) 56.dp else 0.dp
val searchText = rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue("")) }
val scope = rememberCoroutineScope()
val (userPickerState, scaffoldState ) = settingsState
Scaffold(
topBar = { Box(Modifier.padding(end = endPadding)) { HomeTopBar(homeTab, stopped) } },
bottomBar = { Box(Modifier.padding(end = endPadding)) { HomeBottomBar(scaffoldState.drawerState, userPickerState, homeTab, stopped) } },
scaffoldState = scaffoldState,
drawerContent = {
tryOrShowError("Settings", error = { ErrorSettingsView() }) {
SettingsView(chatModel, setPerformLA, scaffoldState.drawerState)
}
},
contentColor = LocalContentColor.current,
drawerContentColor = LocalContentColor.current,
drawerScrimColor = MaterialTheme.colors.onSurface.copy(alpha = if (isInDarkTheme()) 0.16f else 0.32f),
drawerGesturesEnabled = appPlatform.isAndroid,
floatingActionButton = {
if (searchText.value.text.isEmpty() && !chatModel.desktopNoUserNoRemote && chatModel.chatRunning.value == true) {
FloatingActionButton(
onClick = {
if (!stopped) {
if (newChatSheetState.value.isVisible()) hideNewChatSheet(true) else showNewChatSheet()
}
},
Modifier.padding(end = DEFAULT_PADDING - 16.dp + endPadding, bottom = DEFAULT_PADDING - 16.dp),
elevation = FloatingActionButtonDefaults.elevation(
defaultElevation = 0.dp,
pressedElevation = 0.dp,
hoveredElevation = 0.dp,
focusedElevation = 0.dp,
),
backgroundColor = if (!stopped) MaterialTheme.colors.primary else MaterialTheme.colors.secondary,
contentColor = Color.White
) {
Icon(if (!newChatSheetState.collectAsState().value.isVisible()) painterResource(MR.images.ic_edit_filled) else painterResource(MR.images.ic_close), stringResource(MR.strings.add_contact_or_create_group))
}
}
}
) {
Box(Modifier.padding(it).padding(end = endPadding)) {
when (homeTab.value) {
is HomeTab.Chats -> ChatsView(searchText)
is HomeTab.Contacts -> ContactsView(searchText)
}
}
}
if (searchText.value.text.isEmpty()) {
if (appPlatform.isDesktop) {
val call = remember { chatModel.activeCall }.value
if (call != null) {
ActiveCallInteractiveArea(call, newChatSheetState)
}
}
// TODO disable this button and sheet for the duration of the switch
tryOrShowError("NewChatSheet", error = {}) {
NewChatSheet(chatModel, newChatSheetState, stopped, hideNewChatSheet)
}
}
if (appPlatform.isAndroid) {
tryOrShowError("UserPicker", error = {}) {
UserPicker(chatModel, userPickerState) {
scope.launch { if (scaffoldState.drawerState.isOpen) scaffoldState.drawerState.close() else scaffoldState.drawerState.open() }
userPickerState.value = AnimatedViewState.GONE
}
}
}
}
@Composable
private fun ChatsView(searchText: MutableState<TextFieldValue>) {
Box(
modifier = Modifier
.fillMaxSize()
) {
if (!chatModel.desktopNoUserNoRemote) {
ChatList(chatModel, searchText = searchText)
}
if (chatModel.chats.isEmpty() && !chatModel.switchingUsersAndHosts.value && !chatModel.desktopNoUserNoRemote) {
Text(stringResource(
if (chatModel.chatRunning.value == null) MR.strings.loading_chats else MR.strings.you_have_no_chats),
Modifier.align(Alignment.Center), color = MaterialTheme.colors.secondary
)
}
}
}
@Composable
private fun ContactsView(searchText: MutableState<TextFieldValue>) {
Box(
modifier = Modifier
.fillMaxSize()
) {
if (!chatModel.desktopNoUserNoRemote) {
ContactsList(chatModel, searchText = searchText)
}
if (remember(chatModel.chats.toList()) { contactChats(chatModel.chats) }.isEmpty() && !chatModel.switchingUsersAndHosts.value && !chatModel.desktopNoUserNoRemote) {
Text(stringResource(
if (chatModel.chatRunning.value == null) MR.strings.loading_chats else MR.strings.no_contacts),
Modifier.align(Alignment.Center), color = MaterialTheme.colors.secondary
)
}
}
}
fun contactChats(c: List<Chat>): List<Chat> {
return c.filter { it.chatInfo is ChatInfo.Direct }
}
@Composable
private fun HomeTopBar(homeTab: MutableState<HomeTab>, stopped: Boolean) {
val barButtons = arrayListOf<@Composable RowScope.() -> Unit>()
if (stopped) {
barButtons.add {
IconButton(onClick = {
AlertManager.shared.showAlertMsg(
generalGetString(MR.strings.chat_is_stopped_indication),
generalGetString(MR.strings.you_can_start_chat_via_setting_or_by_restarting_the_app)
)
}) {
Icon(
painterResource(MR.images.ic_report_filled),
generalGetString(MR.strings.chat_is_stopped_indication),
tint = Color.Red,
)
}
}
}
val title = when (homeTab.value) {
is HomeTab.Chats -> stringResource(MR.strings.your_chats)
is HomeTab.Contacts -> stringResource(MR.strings.contacts)
}
DefaultTopAppBar(
title = {
Row(verticalAlignment = Alignment.CenterVertically) {
Text(
title,
color = MaterialTheme.colors.onBackground,
fontWeight = FontWeight.SemiBold,
)
}
},
onTitleClick = null,
showSearch = false,
onSearchValueChanged = {},
buttons = barButtons
)
Divider(Modifier.padding(top = AppBarHeight))
}
@Composable
private fun HomeBottomBar(
drawerState: DrawerState,
userPickerState: MutableStateFlow<AnimatedViewState>,
homeTab: MutableState<HomeTab>,
stopped: Boolean) {
Box(
Modifier
.fillMaxWidth()
.height(BottomAppBarHeight)
.background(MaterialTheme.colors.background.mixWith(MaterialTheme.colors.onBackground, 0.97f))
) {
Divider()
Row(
Modifier
.fillMaxHeight()
.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly,
verticalAlignment = Alignment.CenterVertically,
) {
SettingsButton(drawerState, userPickerState, stopped)
HomeTabButton(
icon = painterResource(if (homeTab.value is HomeTab.Chats) MR.images.ic_chat_bubble_filled else MR.images.ic_chat_bubble),
title = generalGetString(MR.strings.your_chats),
onClick = { homeTab.value = HomeTab.Chats() }
)
HomeTabButton(
icon = if (homeTab.value is HomeTab.Contacts) rememberVectorPainter(AccountCircleFilled) else painterResource(MR.images.ic_account_circle_filled),
title = generalGetString(MR.strings.contacts),
onClick = { homeTab.value = HomeTab.Contacts() }
)
}
}
}
@Composable
fun SettingsButton(drawerState: DrawerState, userPickerState: MutableStateFlow<AnimatedViewState>, stopped: Boolean) {
val scope = rememberCoroutineScope()
if (chatModel.users.isEmpty() && !chatModel.desktopNoUserNoRemote) {
NavigationButtonMenu { scope.launch { if (drawerState.isOpen) drawerState.close() else drawerState.open() } }
} else {
val users by remember { derivedStateOf { chatModel.users.filter { u -> u.user.activeUser || !u.user.hidden } } }
val allRead = users
.filter { u -> !u.user.activeUser && !u.user.hidden }
.all { u -> u.unreadCount == 0 }
UserProfileButton(chatModel.currentUser.value?.profile?.image, allRead) {
if (users.size == 1 && chatModel.remoteHosts.isEmpty()) {
scope.launch { drawerState.open() }
} else {
userPickerState.value = AnimatedViewState.VISIBLE
}
}
}
}
@Composable
fun UserProfileButton(image: String?, allRead: Boolean, onButtonClicked: () -> Unit) {
Row(verticalAlignment = Alignment.CenterVertically) {
IconButton(onClick = onButtonClicked) {
Box {
ProfileImage(
image = image,
size = 56.dp,
color = MaterialTheme.colors.secondaryVariant.mixWith(MaterialTheme.colors.onBackground, 0.97f)
)
if (!allRead) {
unreadBadge()
}
}
}
if (appPlatform.isDesktop) {
val h by remember { chatModel.currentRemoteHost }
if (h != null) {
Spacer(Modifier.width(12.dp))
HostDisconnectButton {
stopRemoteHostAndReloadHosts(h!!, true)
}
}
}
}
}
@Composable
private fun BoxScope.unreadBadge(text: String? = "") {
Text(
text ?: "",
color = MaterialTheme.colors.onPrimary,
fontSize = 6.sp,
modifier = Modifier
.background(MaterialTheme.colors.primary, shape = CircleShape)
.badgeLayout()
.padding(horizontal = 3.dp)
.padding(vertical = 1.dp)
.align(Alignment.TopEnd)
)
}
@Composable
fun HomeTabButton(icon: Painter, title: String, onClick: () -> Unit) {
Surface(
Modifier
.size(56.dp),
shape = RoundedCornerShape(10.dp),
color = Color.Transparent,
) {
Column(
Modifier
.clickable { onClick () },
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Icon(
icon,
contentDescription = null,
Modifier.size(24.dp),
tint = MaterialTheme.colors.secondary
)
Text(
title,
style = MaterialTheme.typography.subtitle2.copy(fontWeight = FontWeight.Normal, fontSize = 12.sp),
color = MaterialTheme.colors.secondary
)
}
}
}
@Composable
expect fun ActiveCallInteractiveArea(call: Call, newChatSheetState: MutableStateFlow<AnimatedViewState>)
fun connectIfOpenedViaUri(rhId: Long?, uri: URI, chatModel: ChatModel) {
Log.d(TAG, "connectIfOpenedViaUri: opened via link")
if (chatModel.currentUser.value == null) {
chatModel.appOpenUrl.value = rhId to uri
} else {
withBGApi {
planAndConnect(rhId, uri, incognito = null, close = null)
}
}
}
@Composable
private fun ErrorSettingsView() {
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Text(generalGetString(MR.strings.error_showing_content), color = MaterialTheme.colors.error, fontStyle = FontStyle.Italic)
}
}
@@ -39,7 +39,7 @@ fun AddGroupView(chatModel: ChatModel, rh: RemoteHostInfo?, close: () -> Unit) {
withBGApi {
val groupInfo = chatModel.controller.apiNewGroup(rhId, incognito, groupProfile)
if (groupInfo != null) {
chatModel.addChat(Chat(remoteHostId = rhId, chatInfo = ChatInfo.Group(groupInfo), chatItems = listOf()))
chatModel.updateGroup(rhId = rhId, groupInfo)
chatModel.chatItems.clear()
chatModel.chatItemStatuses.clear()
chatModel.chatId.value = groupInfo.id
@@ -44,6 +44,11 @@ fun NewChatSheet(chatModel: ChatModel, newChatSheetState: StateFlow<AnimatedView
ModalManager.center.closeModals()
ModalManager.center.showModalCloseable { close -> NewChatView(chatModel.currentRemoteHost.value, NewChatOption.INVITE, close = close) }
},
scanPaste = {
closeNewChatSheet(false)
ModalManager.center.closeModals()
ModalManager.center.showModalCloseable { close -> NewChatView(chatModel.currentRemoteHost.value, NewChatOption.CONNECT, showQRCodeScanner = true, close = close) }
},
createGroup = {
closeNewChatSheet(false)
ModalManager.center.closeModals()
@@ -55,15 +60,17 @@ fun NewChatSheet(chatModel: ChatModel, newChatSheetState: StateFlow<AnimatedView
private val titles = listOf(
MR.strings.add_contact_tab,
MR.strings.scan_paste_link,
MR.strings.create_group_button
)
private val icons = listOf(MR.images.ic_add_link, MR.images.ic_group)
private val icons = listOf(MR.images.ic_add_link, MR.images.ic_qr_code, MR.images.ic_group)
@Composable
private fun NewChatSheetLayout(
newChatSheetState: StateFlow<AnimatedViewState>,
stopped: Boolean,
addContact: () -> Unit,
scanPaste: () -> Unit,
createGroup: () -> Unit,
closeNewChatSheet: (animated: Boolean) -> Unit,
) {
@@ -102,7 +109,7 @@ private fun NewChatSheetLayout(
verticalArrangement = Arrangement.Bottom,
horizontalAlignment = Alignment.End
) {
val actions = remember { listOf(addContact, createGroup) }
val actions = remember { listOf(addContact, scanPaste, createGroup) }
val backgroundColor = if (isInDarkTheme())
blendARGB(MaterialTheme.colors.primary, Color.Black, 0.7F)
else
@@ -145,7 +152,7 @@ private fun NewChatSheetLayout(
}
FloatingActionButton(
onClick = { if (!stopped) closeNewChatSheet(true) },
Modifier.padding(end = DEFAULT_PADDING, bottom = DEFAULT_PADDING),
Modifier.padding(end = DEFAULT_PADDING, bottom = DEFAULT_PADDING + BottomAppBarHeight),
elevation = FloatingActionButtonDefaults.elevation(
defaultElevation = 0.dp,
pressedElevation = 0.dp,
@@ -264,6 +271,7 @@ private fun PreviewNewChatSheet() {
MutableStateFlow(AnimatedViewState.VISIBLE),
stopped = false,
addContact = {},
scanPaste = {},
createGroup = {},
closeNewChatSheet = {},
)
@@ -31,7 +31,6 @@ import kotlinx.coroutines.delay
fun SetupDatabasePassphrase(m: ChatModel) {
val progressIndicator = remember { mutableStateOf(false) }
val prefs = m.controller.appPrefs
val saveInPreferences = remember { mutableStateOf(prefs.storeDBPassphrase.get()) }
val initialRandomDBPassphrase = remember { mutableStateOf(prefs.initialRandomDBPassphrase.get()) }
// Do not do rememberSaveable on current key to prevent saving it on disk in clear text
val currentKey = remember { mutableStateOf(if (initialRandomDBPassphrase.value) DatabaseUtils.ksDatabasePassword.get() ?: "" else "") }
@@ -58,7 +57,16 @@ fun SetupDatabasePassphrase(m: ChatModel) {
prefs.storeDBPassphrase.set(false)
val newKeyValue = newKey.value
val success = encryptDatabase(currentKey, newKey, confirmNewKey, mutableStateOf(true), saveInPreferences, mutableStateOf(true), progressIndicator, false)
val success = encryptDatabase(
currentKey = currentKey,
newKey = newKey,
confirmNewKey = confirmNewKey,
initialRandomDBPassphrase = mutableStateOf(true),
useKeychain = mutableStateOf(false),
storedKey = mutableStateOf(true),
progressIndicator = progressIndicator,
migration = false
)
if (success) {
startChat(newKeyValue)
nextStep()
@@ -15,6 +15,7 @@ import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.snapshots.SnapshotStateList
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalClipboardManager
@@ -166,6 +167,24 @@ private fun ConnectingDesktop(session: RemoteCtrlSession, rc: RemoteCtrlInfo?) {
SectionView {
DisconnectButton(onClick = ::disconnectDesktop)
}
ProgressIndicator()
}
@Composable
private fun ProgressIndicator() {
Box(
Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
CircularProgressIndicator(
Modifier
.padding(horizontal = 2.dp)
.size(30.dp),
color = MaterialTheme.colors.secondary,
strokeWidth = 3.dp
)
}
}
@Composable
@@ -28,6 +28,7 @@ import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import chat.simplex.common.model.*
import chat.simplex.common.model.ChatModel.controller
import chat.simplex.common.platform.*
import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.chat.item.ClickableText
@@ -58,6 +59,8 @@ fun NetworkAndServersView() {
smpProxyFallback = smpProxyFallback,
proxyPort = proxyPort,
toggleSocksProxy = { enable ->
val def = NetCfg.defaults
val proxyDef = NetCfg.proxyDefaults
if (enable) {
AlertManager.shared.showAlertDialog(
title = generalGetString(MR.strings.network_enable_socks),
@@ -65,7 +68,19 @@ fun NetworkAndServersView() {
confirmText = generalGetString(MR.strings.confirm_verb),
onConfirm = {
withBGApi {
val conf = NetCfg.proxyDefaults.withHostPort(chatModel.controller.appPrefs.networkProxyHostPort.get())
var conf = controller.getNetCfg().withHostPort(controller.appPrefs.networkProxyHostPort.get())
if (conf.tcpConnectTimeout == def.tcpConnectTimeout) {
conf = conf.copy(tcpConnectTimeout = proxyDef.tcpConnectTimeout)
}
if (conf.tcpTimeout == def.tcpTimeout) {
conf = conf.copy(tcpTimeout = proxyDef.tcpTimeout)
}
if (conf.tcpTimeoutPerKb == def.tcpTimeoutPerKb) {
conf = conf.copy(tcpTimeoutPerKb = proxyDef.tcpTimeoutPerKb)
}
if (conf.rcvConcurrency == def.rcvConcurrency) {
conf = conf.copy(rcvConcurrency = proxyDef.rcvConcurrency)
}
chatModel.controller.apiSetNetworkConfig(conf)
chatModel.controller.setNetCfg(conf)
networkUseSocksProxy.value = true
@@ -80,7 +95,19 @@ fun NetworkAndServersView() {
confirmText = generalGetString(MR.strings.confirm_verb),
onConfirm = {
withBGApi {
val conf = NetCfg.defaults
var conf = controller.getNetCfg().copy(socksProxy = null)
if (conf.tcpConnectTimeout == proxyDef.tcpConnectTimeout) {
conf = conf.copy(tcpConnectTimeout = def.tcpConnectTimeout)
}
if (conf.tcpTimeout == proxyDef.tcpTimeout) {
conf = conf.copy(tcpTimeout = def.tcpTimeout)
}
if (conf.tcpTimeoutPerKb == proxyDef.tcpTimeoutPerKb) {
conf = conf.copy(tcpTimeoutPerKb = def.tcpTimeoutPerKb)
}
if (conf.rcvConcurrency == proxyDef.rcvConcurrency) {
conf = conf.copy(rcvConcurrency = def.rcvConcurrency)
}
chatModel.controller.apiSetNetworkConfig(conf)
chatModel.controller.setNetCfg(conf)
networkUseSocksProxy.value = false
@@ -1835,4 +1835,25 @@
<string name="chat_theme_apply_to_mode">طبّق لِ</string>
<string name="wallpaper_scale_fill">ملء</string>
<string name="wallpaper_scale">المقياس</string>
<string name="message_queue_info_none">لا شيء</string>
<string name="v5_8_private_routing">توجيه الرسائل الخاصة 🚀</string>
<string name="v5_8_chat_themes_descr">اجعل محادثاتك تبدو مختلفة!</string>
<string name="v5_8_safe_files">تلقي الملفات بأمان</string>
<string name="v5_8_persian_ui">واجهة المستخدم الفارسية</string>
<string name="chat_theme_reset_to_app_theme">إعادة التعيين إلى سمة التطبيق</string>
<string name="theme_destination_app_theme">سمة التطبيق</string>
<string name="v5_8_safe_files_descr">تأكيد الملفات من خوادم غير معروفة.</string>
<string name="chat_theme_reset_to_user_theme">إعادة التعيين إلى سمة المستخدم</string>
<string name="message_queue_info_server_info">معلومات قائمة انتظار الخادم: %1$s
\n
\nآخر رسالة تم استلامها: %2$s</string>
<string name="info_row_debug_delivery">تسليم التصحيح</string>
<string name="message_queue_info">معلومات قائمة انتظار الرسائل</string>
<string name="v5_8_private_routing_descr">احمِ عنوان IP الخاص بك من مُرحلات المُراسلة التي اختارتها جهات الاتصال الخاصة بك.
\nفعّل في إعدادات *الشبكة والخوادم*.</string>
<string name="v5_8_chat_themes">سمات دردشة جديدة</string>
<string name="error_initializing_web_view">حدث خطأ أثناء تهيئة WebView. حدّث نظامك إلى الإصدار الجديد. يُرجى التواصل بالمطورين.
\nError: %s</string>
<string name="v5_8_message_delivery">تحسين تسليم الرسائل</string>
<string name="v5_8_message_delivery_descr">مع انخفاض استخدام البطارية.</string>
</resources>
@@ -271,6 +271,11 @@
<string name="srv_error_host">Server address is incompatible with network settings.</string>
<string name="srv_error_version">Server version is incompatible with network settings.</string>
<!-- CIFileStatus errors -->
<string name="file_error_auth">Wrong key or unknown file chunk address - most likely file is deleted.</string>
<string name="file_error_no_file">File not found - most likely file was deleted or cancelled.</string>
<string name="file_error_relay">File server error: %1$s</string>
<!-- Chat Actions - ChatItemView.kt (and general) -->
<string name="reply_verb">Reply</string>
<string name="share_verb">Share</string>
@@ -331,6 +336,7 @@
<string name="welcome">Welcome!</string>
<string name="this_text_is_available_in_settings">This text is available in settings</string>
<string name="your_chats">Chats</string>
<string name="contacts">Contacts</string>
<string name="contact_connection_pending">connecting…</string>
<string name="member_contact_send_direct_message">send direct message</string>
<string name="group_preview_you_are_invited">you are invited to group</string>
@@ -341,6 +347,8 @@
<string name="you_have_no_chats">You have no chats</string>
<string name="loading_chats">Loading chats…</string>
<string name="no_filtered_chats">No filtered chats</string>
<string name="no_contacts">No contacts</string>
<string name="no_filtered_contacts">No filtered contacts</string>
<string name="contact_tap_to_connect">Tap to Connect</string>
<string name="connect_with_contact_name_question">Connect with %1$s?</string>
<string name="search_or_paste_simplex_link">Search or paste SimpleX link</string>
@@ -353,6 +361,8 @@
<string name="share_image">Share media…</string>
<string name="share_file">Share file…</string>
<string name="forward_message">Forward message…</string>
<string name="cannot_share_message_alert_title">Cannot send message</string>
<string name="cannot_share_message_alert_text">Selected chat preferences prohibit this message.</string>
<!-- ComposeView.kt, helpers -->
<string name="attach">Attach</string>
@@ -408,6 +418,8 @@
<string name="error_saving_file">Error saving file</string>
<string name="loading_remote_file_title">Loading the file </string>
<string name="loading_remote_file_desc">Please, wait while the file is being loaded from the linked mobile</string>
<string name="file_error">File error</string>
<string name="temporary_file_error">Temporary file error</string>
<!-- Voice messages -->
<string name="voice_message">Voice message</string>
@@ -418,10 +430,28 @@
<string name="notifications">Notifications</string>
<!-- Chat Info Actions - ChatInfoView.kt -->
<string name="info_view_connect_button">connect</string>
<string name="info_view_open_button">open</string>
<string name="info_view_message_button">message</string>
<string name="info_view_call_button">call</string>
<string name="info_view_video_button">video</string>
<string name="delete_contact_question">Delete contact?</string>
<string name="delete_contact_all_messages_deleted_cannot_undo_warning">Contact and all messages will be deleted - this cannot be undone!</string>
<string name="delete_contact_cannot_undo_warning">Contact will be deleted - this cannot be undone!</string>
<string name="delete_conversation_question">Delete conversation?</string>
<string name="delete_conversation_all_messages_deleted_cannot_undo_warning">Conversation and all messages will be deleted - this cannot be undone!</string>
<string name="delete_conversation">Delete conversation</string>
<string name="only_delete_conversation">Only delete conversation</string>
<string name="delete_contact_keep_conversation">Delete contact, keep conversation</string>
<string name="notify_delete_contact_question">Notify contact?</string>
<string name="confirm_delete_contact_question">Confirm contact deletion?</string>
<string name="delete_and_notify_contact">Delete and notify contact</string>
<string name="delete_without_notification">Delete without notification</string>
<string name="button_delete_contact">Delete contact</string>
<string name="conversation_deleted">Conversation deleted!</string>
<string name="you_can_still_send_messages_to_contact">You can still send messages to %1$s from the Contacts tab.</string>
<string name="contact_deleted">Contact deleted!</string>
<string name="you_can_still_view_conversation_with_contact">You can still view conversation with %1$s in the Chats tab.</string>
<string name="text_field_set_contact_placeholder">Set contact name…</string>
<string name="icon_descr_server_status_connected">Connected</string>
<string name="icon_descr_server_status_disconnected">Disconnected</string>
@@ -608,6 +638,7 @@
<!-- NewChatView.kt -->
<string name="new_chat">New chat</string>
<string name="add_contact_tab">Add contact</string>
<string name="scan_paste_link">Scan / Paste link</string>
<string name="one_time_link">One-time invitation link</string>
<string name="one_time_link_short">1-time link</string>
<string name="simplex_address">SimpleX address</string>
@@ -1403,6 +1434,8 @@
<string name="info_row_database_id">Database ID</string>
<string name="info_row_debug_delivery">Debug delivery</string>
<string name="info_row_updated_at">Record updated at</string>
<string name="info_row_message_status">Message status</string>
<string name="info_row_file_status">File status</string>
<string name="info_row_sent_at">Sent at</string>
<string name="info_row_created_at">Created at</string>
<string name="info_row_received_at">Received at</string>
@@ -1411,6 +1444,8 @@
<string name="info_row_disappears_at">Disappears at</string>
<string name="share_text_database_id">Database ID: %d</string>
<string name="share_text_updated_at">Record updated at: %s</string>
<string name="share_text_message_status">Message status: %s</string>
<string name="share_text_file_status">File status: %s</string>
<string name="share_text_sent_at">Sent at: %s</string>
<string name="share_text_created_at">Created at: %s</string>
<string name="share_text_received_at">Received at: %s</string>
@@ -1910,6 +1945,9 @@
<string name="remote_ctrl_was_disconnected_title">Connection stopped</string>
<string name="remote_host_disconnected_from"><![CDATA[Disconnected from mobile <b>%s</b> with the reason: %s]]></string>
<string name="remote_ctrl_disconnected_with_reason">Disconnected with the reason: %s</string>
<string name="remote_ctrl_connection_stopped_desc">Please check that mobile and desktop are connected to the same local network, and that desktop firewall allows the connection.\nPlease share any other issues with the developers.</string>
<string name="remote_ctrl_connection_stopped_identity_desc">This link was used with another mobile device, please create a new link on the desktop.</string>
<string name="copy_error">Copy error</string>
<string name="disconnect_desktop_question">Disconnect desktop?</string>
<string name="only_one_device_can_work_at_the_same_time">Only one device can work at the same time</string>
<string name="open_on_mobile_and_scan_qr_code"><![CDATA[Open <i>Use from desktop</i> in mobile app and scan QR code.]]></string>
@@ -825,7 +825,7 @@
<string name="network_option_protocol_timeout">Protokollzeitüberschreitung</string>
<string name="network_option_ping_interval">PING-Intervall</string>
<string name="network_option_enable_tcp_keep_alive">TCP-Keep-Alive aktivieren</string>
<string name="network_options_revert">Zurückkehren</string>
<string name="network_options_revert">Zurücksetzen</string>
<string name="network_options_save">Speichern</string>
<string name="update_network_settings_question">Netzwerkeinstellungen aktualisieren?</string>
<string name="updating_settings_will_reconnect_client_to_all_servers">Die Aktualisierung der Einstellungen wird den Client wieder mit allen Servern verbinden.</string>
@@ -1385,7 +1385,7 @@
<string name="v5_2_favourites_filter_descr">Nach ungelesenen und favorisierten Chats filtern.</string>
<string name="sending_delivery_receipts_will_be_enabled_all_profiles">Das Senden von Empfangsbestätigungen an alle Kontakte in allen sichtbaren Chat-Profilen wird aktiviert.</string>
<string name="receipts_contacts_override_disabled">Das Senden von Bestätigungen an %d Kontakte ist deaktiviert</string>
<string name="receipts_section_description">Diese Einstellungen gelten für Ihr aktuelles Profil</string>
<string name="receipts_section_description">Diese Einstellungen gelten für Ihr aktuelles Chat-Profil</string>
<string name="receipts_section_description_1">Sie können in den Kontakt- und Gruppeneinstellungen überschrieben werden.</string>
<string name="receipts_section_contacts">Kontakte</string>
<string name="receipts_contacts_title_disable">Bestätigungen deaktivieren\?</string>
@@ -1429,8 +1429,8 @@
<string name="connect_via_member_address_alert_desc">An dieses Gruppenmitglied wird eine Verbindungsanfrage gesendet.</string>
<string name="connect_via_member_address_alert_title">Direkt verbinden\?</string>
<string name="connect_via_link_incognito">Inkognito verbinden</string>
<string name="connect_use_current_profile">Das aktuelle Profil nutzen</string>
<string name="connect_use_new_incognito_profile">Ein neues Inkognito-Profil nutzen</string>
<string name="connect_use_current_profile">Aktuelles Chat-Profil nutzen</string>
<string name="connect_use_new_incognito_profile">Neues Inkognito-Profil nutzen</string>
<string name="system_restricted_background_in_call_warn"><![CDATA[Wählen Sie bitte in den App-Einstellungen <b>App-Akkuverbrauch</b> / <b>Unbeschränkt</b> , um Anrufe im Hintergrund zu führen.]]></string>
<string name="paste_the_link_you_received_to_connect_with_your_contact">Fügen Sie den erhaltenen Link ein, um sich mit Ihrem Kontakt zu verbinden…</string>
<string name="connect__a_new_random_profile_will_be_shared">Es wird ein neues Zufallsprofil geteilt.</string>
@@ -1866,22 +1866,22 @@
<string name="network_smp_proxy_mode_never">Nie</string>
<string name="network_smp_proxy_mode_unknown">Unbekannte Relais</string>
<string name="network_smp_proxy_mode_unprotected">Ungeschützt</string>
<string name="network_smp_proxy_mode_unknown_description">Privates Routing mit unbekannten Servern nutzen.</string>
<string name="network_smp_proxy_mode_never_description">Nutzen Sie kein privates Routing.</string>
<string name="network_smp_proxy_mode_unknown_description">Sie nutzen privates Routing mit unbekannten Servern.</string>
<string name="network_smp_proxy_mode_never_description">Sie nutzen KEIN privates Routing.</string>
<string name="update_network_smp_proxy_mode_question">Modus für das Nachrichten-Routing</string>
<string name="network_smp_proxy_fallback_allow">Ja</string>
<string name="network_smp_proxy_fallback_prohibit">Nein</string>
<string name="network_smp_proxy_fallback_allow_protected">Wenn die IP-Adresse versteckt ist</string>
<string name="update_network_smp_proxy_fallback_question">Fallback für das Nachrichten-Routing</string>
<string name="private_routing_show_message_status">Nachrichtenstatus anzeigen</string>
<string name="network_smp_proxy_fallback_allow_downgrade">Herunterstufung erlauben</string>
<string name="network_smp_proxy_mode_always_description">Immer privates Routing nutzen.</string>
<string name="network_smp_proxy_fallback_prohibit_description">Senden Sie keine direkten Nachrichten, selbst wenn Ihr oder der Zielserver kein privates Routing unterstützt.</string>
<string name="network_smp_proxy_fallback_allow_downgrade">Herabstufung erlauben</string>
<string name="network_smp_proxy_mode_always_description">Sie nutzen immer privates Routing.</string>
<string name="network_smp_proxy_fallback_prohibit_description">Nachrichten werden nicht direkt versendet, selbst wenn Ihr oder der Zielserver kein privates Routing unterstützt.</string>
<string name="settings_section_title_private_message_routing">PRIVATES NACHRICHTEN-ROUTING</string>
<string name="network_smp_proxy_fallback_allow_protected_description">Nachrichten direkt versenden, wenn die IP-Adresse geschützt ist und Ihr oder der Zielserver kein privates Routing unterstützt.</string>
<string name="network_smp_proxy_fallback_allow_description">Nachrichten direkt versenden, wenn Ihr oder der Zielserver kein privates Routing unterstützt.</string>
<string name="private_routing_explanation">Für die Auslieferung Ihrer Nachrichten wird privates Routing Ihrer SMP-Server genutzt, um Ihre IP-Adresse zu schützen.</string>
<string name="network_smp_proxy_mode_unprotected_description">Privates Routing mit unbekannten Servern nutzen, wenn die IP-Adresse nicht geschützt ist.</string>
<string name="network_smp_proxy_fallback_allow_protected_description">Nachrichten werden direkt versendet, wenn die IP-Adresse geschützt ist, und Ihr oder der Zielserver kein privates Routing unterstützt.</string>
<string name="network_smp_proxy_fallback_allow_description">Nachrichten werden direkt versendet, wenn Ihr oder der Zielserver kein privates Routing unterstützt.</string>
<string name="private_routing_explanation">Zum Schutz Ihrer IP-Adresse, wird für die Nachrichten-Auslieferung privates Routing über Ihre konfigurierten SMP-Server genutzt.</string>
<string name="network_smp_proxy_mode_unprotected_description">Sie nutzen privates Routing mit unbekannten Servern, wenn Ihre IP-Adresse nicht geschützt ist.</string>
<string name="protect_ip_address">IP-Adresse schützen</string>
<string name="settings_section_title_files">DATEIEN</string>
<string name="app_will_ask_to_confirm_unknown_file_servers">Die App wird bei unbekannten Datei-Servern nach einer Download-Bestätigung fragen (außer bei .onion oder wenn ein SOCKS-Proxy aktiviert ist).</string>
@@ -1918,4 +1918,25 @@
<string name="wallpaper_preview_hello_alice">Guten Nachmittag!</string>
<string name="wallpaper_preview_hello_bob">Guten Morgen!</string>
<string name="dark_mode_colors">Farben für die dunkle Variante</string>
<string name="theme_destination_app_theme">App-Design</string>
<string name="v5_8_persian_ui">Persische Bedienoberfläche</string>
<string name="chat_theme_reset_to_user_theme">Auf das Benutzer-spezifische Design zurücksetzen</string>
<string name="error_initializing_web_view">Fehler bei der Initialisierung von Webview. Aktualisieren Sie Ihr System auf die neue Version. Bitte kontaktieren Sie die Entwickler.
\nFehler: %s</string>
<string name="chat_theme_reset_to_app_theme">Auf das App-Design zurücksetzen</string>
<string name="v5_8_safe_files_descr">Dateien von unbekannten Servern bestätigen.</string>
<string name="v5_8_message_delivery">Verbesserte Zustellung von Nachrichten</string>
<string name="v5_8_chat_themes_descr">Gestalten Sie Ihre Chats unterschiedlich!</string>
<string name="v5_8_chat_themes">Neue Chat-Designs</string>
<string name="v5_8_private_routing">Privates Nachrichten-Routing 🚀</string>
<string name="v5_8_private_routing_descr">Schützen Sie Ihre IP-Adresse vor den Nachrichten-Relais , die Ihr Kontakt ausgewählt hat.
\nAktivieren Sie es in den *Netzwerk &amp; Server* Einstellungen.</string>
<string name="v5_8_safe_files">Dateien sicher empfangen</string>
<string name="v5_8_message_delivery_descr">Mit reduziertem Akkuverbrauch.</string>
<string name="message_queue_info_none">Keine Information</string>
<string name="info_row_debug_delivery">Debugging-Zustellung</string>
<string name="message_queue_info">Nachrichten-Warteschlangen-Information</string>
<string name="message_queue_info_server_info">Server-Warteschlangen-Information: %1$s
\n
\nZuletzt empfangene Nachricht: %2$s</string>
</resources>
@@ -964,7 +964,7 @@
<string name="save_profile_password">Guardar contraseña de perfil</string>
<string name="password_to_show">Contraseña para hacerlo visible</string>
<string name="error_saving_user_password">Error al guardar contraseña de usuario</string>
<string name="relay_server_if_necessary">El retransmisor sólo se usa en caso de necesidad. Un tercero podría ver tu IP.</string>
<string name="relay_server_if_necessary">El servidor de retransmisión sólo se usa en caso de necesidad. Un tercero podría ver tu IP.</string>
<string name="relay_server_protects_ip">El servidor de retransmisión protege tu IP pero puede ver la duración de la llamada.</string>
<string name="enter_password_to_show">Introduce la contraseña</string>
<string name="user_hide">Ocultar</string>
@@ -1769,7 +1769,7 @@
<string name="settings_section_title_profile_images">Forma de los perfiles</string>
<string name="v5_7_shape_profile_images">Dar forma a las imágenes de perfil</string>
<string name="v5_7_shape_profile_images_descr">Cuadrada, circular o cualquier forma intermedia.</string>
<string name="snd_error_quota">Capacidad excedida - el destinatario no ha recibido el mensaje previo.</string>
<string name="snd_error_quota">Capacidad excedida - el destinatario no ha recibido los mensajes previos.</string>
<string name="snd_error_relay">Error del servidor de destino: %1$s</string>
<string name="ci_status_other_error">Error: %1$s</string>
<string name="snd_error_proxy_relay">Servidor de reenvío: %1$s
@@ -1784,13 +1784,13 @@
<string name="update_network_smp_proxy_fallback_question">Enrutamiento de mensajes alternativo</string>
<string name="update_network_smp_proxy_mode_question">Modo de enrutamiento de mensajes</string>
<string name="network_smp_proxy_fallback_prohibit">No</string>
<string name="private_routing_show_message_status">Mostrar estado del mensaje</string>
<string name="private_routing_show_message_status">Estado del mensaje</string>
<string name="network_smp_proxy_mode_unprotected_description">Usar enrutamiento privado con servidores desconocidos cuando la dirección IP no está protegida.</string>
<string name="network_smp_proxy_fallback_allow_protected">Con IP oculta</string>
<string name="network_smp_proxy_fallback_allow">Si</string>
<string name="network_smp_proxy_fallback_allow_description">Enviar los mensajes directamente cuando tu servidor o el de destino no soporten enrutamiento privado</string>
<string name="private_routing_explanation">Para proteger tu dirección IP, el enrutamiento privado usa tu servidor SMP para enviar mensajes.</string>
<string name="network_smp_proxy_fallback_prohibit_description">NO enviar mensajes directos incluso si tu servidor o el de destino no soportan enrutamiento privado.</string>
<string name="network_smp_proxy_fallback_allow_description">Enviar mensajes directamente cuando tu servidor o el de destino no admitan enrutamiento privado.</string>
<string name="private_routing_explanation">Para proteger tu dirección IP, el enrutamiento privado usa tus servidores SMP para enviar mensajes.</string>
<string name="network_smp_proxy_fallback_prohibit_description">NO enviar mensajes directamente incluso si tu servidor o el de destino no soportan enrutamiento privado.</string>
<string name="network_smp_proxy_mode_always">Siempre</string>
<string name="network_smp_proxy_fallback_allow_downgrade">Permitir versión anterior</string>
<string name="network_smp_proxy_mode_always_description">Usar siempre enrutamiento privado.</string>
@@ -1801,8 +1801,8 @@
<string name="network_smp_proxy_mode_unprotected">Desprotegido</string>
<string name="snd_error_auth">Clave incorrecta o conexión desconocida - probablemente esta conexión fue eliminada</string>
<string name="network_smp_proxy_mode_unknown_description">Usar enrutamiento privado con servidores desconocidos.</string>
<string name="network_smp_proxy_fallback_allow_protected_description">Enviar los mensajes directamente cuando tu dirección IP está protegida y tu servidor o el de destino no soporten enrutamiento privado.</string>
<string name="file_not_approved_title">Servidores desconocidos!</string>
<string name="network_smp_proxy_fallback_allow_protected_description">Enviar mensajes directamente cuando tu dirección IP está protegida y tu servidor o el de destino no admitan enrutamiento privado.</string>
<string name="file_not_approved_title">¡Servidores desconocidos!</string>
<string name="file_not_approved_descr">Sin Tor o VPN, tu dirección IP será visible para estos relés XFTP:
\n%1$s.</string>
<string name="protect_ip_address">Proteger dirección IP</string>
@@ -1838,4 +1838,25 @@
<string name="settings_section_title_user_theme">Tema del perfil</string>
<string name="chat_list_always_visible">Listado del chat en ventana nueva</string>
<string name="color_wallpaper_tint">Color imagen de fondo</string>
<string name="message_queue_info_server_info">información cola del servidor: %1$s
\n
\núltimo mensaje recibido: %2$s</string>
<string name="chat_theme_reset_to_app_theme">Restablecer al tema de la app</string>
<string name="v5_8_private_routing">Enrutamiento privado de mensajes 🚀</string>
<string name="v5_8_safe_files">Recibe archivos de forma segura</string>
<string name="v5_8_message_delivery">Mejora del envío de mensajes</string>
<string name="v5_8_message_delivery_descr">Con uso reducido de la batería.</string>
<string name="theme_destination_app_theme">Tema de la app</string>
<string name="v5_8_safe_files_descr">Confirma archivos de servidores desconocidos.</string>
<string name="info_row_debug_delivery">Entrega de debug</string>
<string name="v5_8_chat_themes_descr">¡Cambia el aspecto de tus chats!</string>
<string name="v5_8_chat_themes">Nuevos temas de chat</string>
<string name="message_queue_info">Información cola de mensajes</string>
<string name="message_queue_info_none">ninguno</string>
<string name="v5_8_private_routing_descr">Protege tu dirección IP de los servidores de retransmisión elegidos por tus contactos.
\nActívalo en ajustes de *Servidores y Redes*.</string>
<string name="chat_theme_reset_to_user_theme">Restablecer al tema del usuario</string>
<string name="error_initializing_web_view">Error al inicializar WebView. Actualiza tu sistema a la última versión. Por favor, ponte en contacto con los desarrolladores.
\nError: %s</string>
<string name="v5_8_persian_ui">Interfaz en persa</string>
</resources>
@@ -613,7 +613,7 @@
<string name="disable_onion_hosts_when_not_supported"><![CDATA[<i>استفاده از میزبان‌های onion.</i> را روی «خیر» تنظیم کنید اگر پروکسی SOCKS از آنها پشتیبانی نمی‌کند.]]></string>
<string name="customize_theme_title">سفارشی کردن تم</string>
<string name="app_version_title">نسخه برنامه</string>
<string name="theme_colors_section_title">رنگ‌های تم</string>
<string name="theme_colors_section_title">رنگ‌های رابط کاربری</string>
<string name="core_version">نسخه هسته: v%s</string>
<string name="core_simplexmq_version">simplexmq: v%s (%2s)</string>
<string name="shutdown_alert_desc">اعلان‌ها از کار خواهند افتاد تا زمانی که برنامه را دوباره راه‌اندازی کنید</string>
@@ -1803,4 +1803,54 @@
<string name="without_tor_or_vpn_ip_address_will_be_visible_to_file_servers">بدون تور یا VPN، نشانی IP شما برای سرورهای پرونده قابل رویت خواهد بود.</string>
<string name="file_not_approved_descr">بدون تور یا VPN، نشانی IP شما برای این واسطه‌های XFTP قابل رویت خواهد بود:
\n%1$s.</string>
<string name="message_queue_info_none">هیچ</string>
<string name="v5_8_message_delivery">تحویل پیام بهبود یافته</string>
<string name="v5_8_persian_ui">رابط کاربری فارسی</string>
<string name="v5_8_message_delivery_descr">با استفاده باتری کاهش یافته.</string>
<string name="info_row_debug_delivery">اشکال‌زدایی تحویل</string>
<string name="message_queue_info">اطلاعات صف پیام</string>
<string name="theme_destination_app_theme">تم برنامه</string>
<string name="v5_8_safe_files_descr">تایید پرونده‌ها از سرورهای ناشناخته.</string>
<string name="message_queue_info_server_info">اطلاعات صف سرور: %1$s
\n
\nآخرین پیام دریافتی: %2$s</string>
<string name="chat_list_always_visible">نمایش فهرست گپ در پنجره جدید</string>
<string name="chat_theme_apply_to_dark_mode">حالت تاریک</string>
<string name="theme_black">سیاه</string>
<string name="color_mode">حالت رنگ</string>
<string name="color_mode_dark">تاریک</string>
<string name="dark_mode_colors">رنگ‌های حالت تاریک</string>
<string name="color_mode_light">روشن</string>
<string name="reset_single_color">بازنشاندن رنگ</string>
<string name="color_mode_system">سیستم</string>
<string name="error_initializing_web_view">خطا در مقداردهی اولیه WebView. سیستم خود را به نسخه جدید به روز کنید. لطفا با توسعه‌دهنگان تماس بگیرید.
\nخطا: 9%s</string>
<string name="settings_section_title_chat_colors">رنگ‌های گپ</string>
<string name="settings_section_title_chat_theme">تم گپ</string>
<string name="settings_section_title_user_theme">تم نمایه</string>
<string name="color_wallpaper_background">پس‌زمینه کاغذدیواری</string>
<string name="color_primary_variant2">ابتدایی اضافی ۲</string>
<string name="wallpaper_advanced_settings">تنظیمات پیشرفته</string>
<string name="wallpaper_scale_fill">پر کردن</string>
<string name="wallpaper_scale_fit">گنجاندن</string>
<string name="wallpaper_preview_hello_alice">عصر به خیر!</string>
<string name="wallpaper_preview_hello_bob">صبح به خیر!</string>
<string name="color_received_quote">پاسخ دریافتی</string>
<string name="theme_remove_image">حذف تصویر</string>
<string name="wallpaper_scale_repeat">تکرار</string>
<string name="wallpaper_scale">مقیاس</string>
<string name="color_sent_quote">پاسخ ارسالی</string>
<string name="color_wallpaper_tint">ابتدایی کاغذدیواری</string>
<string name="chat_theme_set_default_theme">تعیین تم پیش‌فرض</string>
<string name="chat_theme_reset_to_app_theme">بازنشاندن به تم برنامه</string>
<string name="chat_theme_reset_to_user_theme">بازنشاندن به تم کاربر</string>
<string name="chat_theme_apply_to_all_modes">تمام حالت‌های رنگ</string>
<string name="chat_theme_apply_to_mode">اعمال بر</string>
<string name="chat_theme_apply_to_light_mode">حالت روشن</string>
<string name="v5_8_private_routing">مسیریابی پیام خصوصی 🚀</string>
<string name="v5_8_chat_themes_descr">ظاهر گپ‌های خود را متمایز کنید!</string>
<string name="v5_8_chat_themes">تم‌های جدید گپ</string>
<string name="v5_8_private_routing_descr">از نشانی IP خود در برابر واسطه‌های پیام‌رسانی انتخاب شده توسط مخاطبانتان محافظت کنید.
\nدر تنظیمات «شبکه و سرورها» فعال کنید.</string>
<string name="v5_8_safe_files">دریافت امن پرونده‌ها</string>
</resources>

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