Compare commits

...

122 Commits

Author SHA1 Message Date
Avently 29857e33e2 multiplatform: init haskell in different thread 2023-11-21 18:47:01 +07:00
Evgeny Poberezkin 47cd7de1ae core: 5.4.0.4 2023-11-21 00:00:29 +00:00
Evgeny Poberezkin 624a3abba2 website: translations (#3412)
* Translated using Weblate (German)

Currently translated at 100.0% (252 of 252 strings)

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

* Translated using Weblate (Arabic)

Currently translated at 100.0% (252 of 252 strings)

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

---------

Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
2023-11-20 22:29:18 +00:00
Evgeny Poberezkin 121985138a ios: export localizations 2023-11-20 22:24:19 +00:00
Evgeny Poberezkin 7f5efd8927 desktop: use correct remote host when creating/connecting via links (#3409) 2023-11-20 20:56:05 +00:00
Evgeny Poberezkin 96d3c9988c Merge pull request #3404 from simplex-chat/ep/core-add-remote-host
desktop: add remote host ID to entities
2023-11-20 17:21:56 +00:00
spaced4ndy f6b786a187 get user index by remote host id 2023-11-20 20:31:35 +04:00
spaced4ndy 11478da6ef Revert "remoteHostId in backend"
This reverts commit 72654caca6.
2023-11-20 19:56:31 +04:00
spaced4ndy 72654caca6 remoteHostId in backend 2023-11-20 19:51:56 +04:00
spaced4ndy 44c88badde remoteHostId in entities kotlin 2023-11-20 16:31:52 +04:00
Evgeny Poberezkin 53a31ec60e core: add remote host ID to entities 2023-11-20 11:51:40 +00:00
spaced4ndy 718436bf55 core: don't read all group members where unnecessary (#3403) 2023-11-20 15:27:15 +04:00
Evgeny Poberezkin 5bbf4d70a1 Merge pull request #3151 from simplex-chat/remote-desktop
use mobile from desktop
2023-11-20 11:12:01 +00:00
Evgeny Poberezkin 970ca3a409 Merge branch 'master' into remote-desktop 2023-11-20 10:35:20 +00:00
Evgeny Poberezkin c536ca7f0f core: add events not sent to connected remote desktop (#3402) 2023-11-20 10:34:24 +00:00
Evgeny Poberezkin 07ef2a0b64 android: remove ACCESS_WIFI_STATE (#3391) 2023-11-20 10:20:31 +00:00
Evgeny Poberezkin 5b7de8f8c1 desktop, android: pass remote host to API from the loaded objects, to prevent race conditions (#3397)
* desktop, android: pass remote host explicitely to API calls

* use remote host ID in model updates

* add remote host to chat console

* add remote host to notifications functions
2023-11-20 10:20:10 +00:00
Alexander Bondarenko 68cbc605be add remote session sequence to prevent stale state updates (#3390)
* add remote session sequence to prevent stale state updates

* remote RHStateKey

* add StateSeq check to controller

* clean up

* simplify

* undo withRemoteXSession API change

* simplify

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-11-20 10:19:00 +00:00
spaced4ndy 3a510eeaf0 core: rename forwarded fields (#3401) 2023-11-20 14:00:55 +04:00
Alexander Bondarenko ba94f76a90 core: fix remote session stuck in Starting after crashed rcConnect (#3399) 2023-11-20 09:33:43 +00:00
spaced4ndy 85e44dcb77 core: split group message forwarding tests (#3400) 2023-11-20 13:05:59 +04:00
Evgeny Poberezkin 2a8d7b8926 core: add commands that will not be forwarded to connected mobile (#3398)
* core: add commands that will not be forwarded to connected mobile

* fail if command that must be executed locally sent to remote host
2023-11-19 20:48:25 +00:00
Evgeny Poberezkin d9031cb209 Merge branch 'master' into remote-desktop 2023-11-19 11:18:08 +00:00
Evgeny Poberezkin bf8457fb40 website: translations (#3396)
* Translated using Weblate (French)

Currently translated at 100.0% (252 of 252 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 100.0% (252 of 252 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (252 of 252 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (252 of 252 strings)

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

* Translated using Weblate (Polish)

Currently translated at 100.0% (252 of 252 strings)

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

* Translated using Weblate (Russian)

Currently translated at 100.0% (252 of 252 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (252 of 252 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 100.0% (252 of 252 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (252 of 252 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (252 of 252 strings)

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

* Translated using Weblate (Polish)

Currently translated at 100.0% (252 of 252 strings)

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

* Translated using Weblate (Russian)

Currently translated at 100.0% (252 of 252 strings)

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

---------

Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: Eric <zxmegaxqug@hldrive.com>
Co-authored-by: B.O.S.S <BxOxSxS@protonmail.com>
Co-authored-by: Timur Bagautdinov <mr.bagautdinov14@gmail.com>
2023-11-19 11:14:09 +00:00
Evgeny Poberezkin 59392b361b ui: translations (#3392)
* Translated using Weblate (Polish)

Currently translated at 97.4% (1400 of 1437 strings)

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

* Translated using Weblate (Chinese (Simplified))

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

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

* Translated using Weblate (Polish)

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

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

* Translated using Weblate (Dutch)

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

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

* Translated using Weblate (French)

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

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

* Translated using Weblate (Italian)

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

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

* Translated using Weblate (Italian)

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

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

* Translated using Weblate (German)

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

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

* Translated using Weblate (German)

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

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

* Translated using Weblate (Chinese (Simplified))

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

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

* Translated using Weblate (Polish)

Currently translated at 100.0% (1439 of 1439 strings)

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

* Translated using Weblate (French)

Currently translated at 100.0% (1439 of 1439 strings)

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

* Translated using Weblate (Italian)

Currently translated at 100.0% (1439 of 1439 strings)

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

* Translated using Weblate (Ukrainian)

Currently translated at 100.0% (1439 of 1439 strings)

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

* update de: Meine -> Ihre

* nl: Gebruiker -> Lid

* nl: gebruiker -> lid 2

* ios, nl: gebruiker -> lid

* ios, nl: gebruiker -> lid 2

* android: fix strings

* ios: export/import localizations

---------

Co-authored-by: B.O.S.S <BxOxSxS@protonmail.com>
Co-authored-by: Eric <zxmegaxqug@hldrive.com>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: Eryk Michalak <gnu.ewm@protonmail.com>
Co-authored-by: Denys Rastiegaiev <daaren@gmail.com>
2023-11-19 11:06:49 +00:00
Stanislav Dmitrenko 8f0538e756 android: UI for remote connections (#3395)
* android: UI for remote connections

* camera permissions

* eol

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-11-19 01:07:42 +00:00
Moritz Angermann b164cc2fa6 nix: fix lib:support for armv7a (#3394) 2023-11-19 00:31:29 +00:00
Evgeny Poberezkin f9e5a56e1a ios: terminate session on network failure, add description for local network access 2023-11-18 22:20:22 +00:00
Evgeny Poberezkin 96e000e3ea ios: add user-defined device name for remote desktop connection 2023-11-18 20:28:55 +00:00
Evgeny Poberezkin ca8833c0c1 desktop: sending and receiving files via connected mobile (#3365)
* desktop: support remote files (WIP)

* working with remote files locally

* better

* working with remote file downloads

* sending files

* fixes of loading files in some situations

* image compression

* constant for remote hosts

* refactor

---------

Co-authored-by: Avently <7953703+avently@users.noreply.github.com>
2023-11-18 20:11:30 +00:00
Evgeny Poberezkin e95d9d0b49 core: rename migration to remote-control, comments (#3393) 2023-11-18 19:18:02 +00:00
Evgeny Poberezkin cc434cda55 Merge branch 'master' into remote-desktop 2023-11-18 18:03:13 +00:00
spaced4ndy c0e8740f50 core: group message forwarding (#3360)
* core: group message forwarding types

* xgrpmemcon

* rework xgrpmemcon to use intros table

* only forward w/t error

* forward msg

* xGrpMsgForward, check integrity outside

* deduplicate group messages

* test

* change error

* item forwarded flag

* intro_chat_protocol_version, bump version

* comment

* highly available client option

* more comments

* notify xgrpmemcon on deduplication

* member vrange

* encoding

* remove MsgForward

* remove import

* exclude files from forwarding

* refactor

* rename to align with protocol

* forward more message types

* add events

* remove unused error, function

* add x.file.cancel, x.info and x.grp.mem.new to forwarded messages

* remove unused x.msg.file.cancel

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-11-18 17:52:01 +00:00
Evgeny Poberezkin 80abc18371 core: update simplexmq (xrcp) 2023-11-18 15:35:06 +00:00
Stanislav Dmitrenko c9a1de6e4b msys2 setup in different place (#3389) 2023-11-17 19:20:44 +00:00
Alexander Bondarenko 42e0400014 core: add remote controller discovery with multicast (#3369)
* draft multicast chat api

* prepare tests

* Plug discovery into chat api

* Add discovery timeout

* post-merge fixes

* rename discovery state to match others

* update for unified invitation

* fix review notices

* rename, remove stack, update simplexmq

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-11-17 18:50:38 +00:00
Stanislav Dmitrenko 79064e149a desktop: enabled smooth scrolling again (#3388) 2023-11-17 18:19:38 +00:00
Stanislav Dmitrenko 84e09f195c desktop (windows): fix build of CLI (#3387) 2023-11-17 18:19:02 +00:00
Evgeny Poberezkin f6c4e969e4 nix: add openssl to simplexmq, swift flag to simplex-chat (#3386)
* nix: add swift flag

* add openssl for simplexmq to nix

* add openssl to android simplemq, try iOS with enableKTLS = false flag

* fix android
2023-11-17 13:28:10 +00:00
Evgeny Poberezkin 86b916c169 Merge branch 'master' into remote-desktop 2023-11-17 13:02:54 +00:00
Alexander Bondarenko cf102da4d3 remote: add test for rejected ca detection and stability (#3382)
* add test for rejected ca detection and stability

* update mq commit
2023-11-17 11:19:33 +00:00
Evgeny Poberezkin d0f3a3d886 rfc: remote UI implementation (#3206) 2023-11-16 21:53:54 +00:00
Evgeny Poberezkin 64f0dbeb61 Merge branch 'master' into remote-desktop 2023-11-16 20:20:04 +00:00
Evgeny Poberezkin 0322b9708b desktop, ios: remote desktop/mobile connection (#3223)
* ui: remote desktop/mobile connection (WIP)

* add startRemoteCtrl and capability (does not work)

* re-add view

* update core library

* iOS connects to CLI

* ios: mobile ui

* multiplatform types

* update lib

* iOS and desktop connected

* fix controllers list on mobile

* remove iOS 16 paste button

* update device name

* connect existing device

* proposed model

* missing function names in exports

* unused

* remote host picker

* update type

* update lib, keep iOS session alive

* better UI

* update network statuses on switching remote/local hosts

* changes

* ios: prevent dismissing sheet/back when session is connected

* changes

* ios: fix back button asking to disconnect when not connected

* iOS: update type

* picker and session code

* multiplatform: update type

* menu fix

* ios: better ux

* desktop: better ux

* ios: options etc

* UI

* desktop: fix RemoteHostStopped event

* ios: open Use from desktop via picker

* desktop: "new mobile device"

* ios: load remote controllers synchronously, update on connect, fix alerts

* titles

* changes

* more changes to ui

* more and more changes in ui

* padding

* ios: show desktop version, handle errors

* fix stopped event

* refresh hosts always

* radical change

* optimization

* change

* ios: stop in progress session when closing window

---------

Co-authored-by: Avently <7953703+avently@users.noreply.github.com>
2023-11-16 16:53:44 +00:00
Alexander Bondarenko c31ae39617 remote: fix circular error handling (#3380) 2023-11-16 14:56:39 +00:00
Alexander Bondarenko 339c3d2be1 Send CRRemote*Stopped on all errors (#3376)
* Send CRRemote*Stopped on all errors

Commands use the same action, made idempotent and don't send events.

* fix tests

* get http2 cancelling back
2023-11-15 17:31:36 +00:00
Alexander Bondarenko a75fce8dfa Fix hostStore path and check before removing (#3375) 2023-11-15 15:57:29 +00:00
Evgeny Poberezkin b71daed3ec core: include session code in all session states (#3374) 2023-11-15 13:17:31 +00:00
Alexander Bondarenko fa9d61caa4 remove host store in deleteRemoteHost (#3373) 2023-11-15 13:09:52 +00:00
Evgeny Poberezkin 3d617bce25 core: test JSON conversion (#3370) 2023-11-14 22:40:15 +00:00
Evgeny Poberezkin d4ba1bbe69 core: update remote host session state (#3371) 2023-11-14 22:27:21 +00:00
Evgeny Poberezkin 0a4920daae core: encrypt stored/loaded remote files (#3366)
* core: encrypt stored/loaded remote files

* simplexmq

* constant
2023-11-14 16:44:12 +00:00
Evgeny Poberezkin 4da1d21c81 Merge branch 'master' into remote-desktop 2023-11-14 14:43:58 +00:00
Evgeny Poberezkin f9df5aa41b Merge branch 'master' into remote-desktop 2023-11-13 20:41:51 +00:00
Evgeny Poberezkin c91625b32a core: update remote host session state, terminate TLS in one more case (#3364)
* core: update remote host session state, terminate TLS in one more case

* name
2023-11-13 20:16:34 +00:00
Alexander Bondarenko 598b6659cc core: better handling of remote errors (#3358)
* Allow ExitCode exceptions to do their job

* Use appropriate error type

* Close TLS server when cancelling connected remote host

* Add timeout errors

* Bump simplexmq

* extract common timeout value
2023-11-13 18:39:41 +00:00
Evgeny Poberezkin 86bc70fa5a Merge branch 'master' into remote-desktop 2023-11-13 14:07:31 +00:00
Evgeny Poberezkin 72b25385ba core: event when new remote host added (#3355) 2023-11-12 21:43:43 +00:00
Evgeny Poberezkin 92e3f576ca core: return controller app info in response when connecting, validate ID key (#3353) 2023-11-12 14:40:49 +00:00
Evgeny Poberezkin 8e3e58cac8 core: update remote controller name (#3352) 2023-11-12 12:40:13 +00:00
Evgeny Poberezkin 8b67ff7a00 core: remote error handling (#3347)
* core: remote error handling

* fix test, show DB errors
2023-11-11 16:03:12 +00:00
Evgeny Poberezkin beb22c6f87 Merge branch 'master' into remote-desktop 2023-11-11 13:53:51 +00:00
Evgeny Poberezkin b1101fbce4 Merge branch 'master' into remote-desktop 2023-11-11 09:49:22 +00:00
Evgeny Poberezkin 97fd6a993e Merge branch 'master' into remote-desktop 2023-11-10 22:22:04 +00:00
Alexander Bondarenko 227007c8f6 add /switch remote host (#3342)
* Add SwitchRemoteHost

* Add message test

* Match remote prefix and the rest of the line

* Move prefix match to utils
2023-11-10 17:49:23 +00:00
Evgeny Poberezkin 02225df274 core: remote control command/response encryption and signing inside TLS (#3339)
* core: remote control command/response encryption inside TLS (except files, no signing)

* sign/verify

* update simplexmq

* fix lazy

* remove RSNone
2023-11-10 16:10:10 +00:00
Alexander Bondarenko f41861c026 core: terminate remote control TLS connection on both sides (#3338)
* handle session setup errors

* add command/async wrapper

* move furniture around

* detect disconnects and force them with closeConnection

* simplify http server log

* close TLS in other cases

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-11-09 22:43:44 +00:00
Alexander Bondarenko 6d4febb669 core: handle remote control session setup errors (#3332)
* handle session setup errors

* add command/async wrapper

* move furniture around
2023-11-09 18:25:05 +00:00
Evgeny Poberezkin 3dd62ab05a core: remove Hello from the app remote protocol (#3336) 2023-11-09 09:37:56 +00:00
Alexander Bondarenko b729144773 core: use xrcp protocol for desktop/mobile connection (#3305)
* WIP: start working on /connect remote ctrl

OOB is broken, requires fixing simplexmq bits.

* WIP: pull CtrlCryptoHandle from xrcp

* place xrcp stubs

* WIP: start switching to RemoteControl.Client types

* fix http2 sha

* fix sha256map.nix

* fix cabal.project

* update RC test

* WIP: add new remote session

* fix compilation

* simplify

* attach HTTP2 server to TLS

* starting host session in controller (WIP)

* more WIP

* compiles

* compiles2

* wip

* pass startRemote' test

* async to poll for events from host, test to send messages fails

* move xrcp handshake test to simplexmq

* detect session stops

* fix connectRemoteCtrl

* use step type

* app info

* WIP: pairing stores

* plug in hello/appInfo/pairings

* negotiate app version

* update simplexmw, remove KEM secrets from DB

* fix file tests

* tone down http2 shutdown errors

* Add stored session test

* bump simplexmq tag

* update simplexmq

* refactor, fix

* removed unused errors

* rename fields, remove unused file

* rename errors

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-11-08 20:13:52 +00:00
Evgeny Poberezkin 3839267f88 Merge branch 'master' into remote-desktop 2023-11-08 13:10:42 +00:00
Evgeny Poberezkin 2776d864a8 Merge branch 'master' into remote-desktop 2023-11-06 11:44:12 +00:00
Evgeny Poberezkin 177112ab18 update simplexmq 2023-11-04 19:04:40 +00:00
Evgeny Poberezkin c2a99987f3 Merge branch 'master' into remote-desktop 2023-11-04 18:54:12 +00:00
Evgeny Poberezkin 0cc26d192d update sha256map.nix 2023-11-02 14:07:51 +00:00
Evgeny Poberezkin 8546c937b2 Merge branch 'master' into remote-desktop 2023-11-02 14:04:10 +00:00
Evgeny Poberezkin 8482dbfd99 core: update remote API commands/events (#3295)
* core: update remote API

* Add session verification event between tls and http2

* roll back char_ '@' parsers

* use more specific parser for verification codes

* cabal.project.local for mac

---------

Co-authored-by: IC Rainbow <aenor.realm@gmail.com>
2023-11-01 19:08:36 +00:00
Evgeny Poberezkin b2f9270452 Merge branch 'master' into remote-desktop 2023-11-01 18:05:51 +00:00
Alexander Bondarenko 02c0cd5619 Cut at attaching http server/client (#3299)
* Cut at attaching http server/client

* switch to xrcp branch
2023-11-01 10:48:58 +00:00
spaced4ndy b1fdc936a6 Merge branch 'master' into remote-desktop 2023-10-30 20:58:39 +04:00
Alexander Bondarenko be44632b0b implement some of the robust discovery rfc (#3283)
* implement robust discovery

* remove qualified

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-10-30 14:00:54 +00:00
Evgeny Poberezkin b48690dee6 Merge branch 'master' into remote-desktop 2023-10-29 19:15:08 +00:00
Evgeny Poberezkin d90da57f12 core: store/get remote files (#3289)
* core: store remote files (wip)

* fix/test store remote file

* get remote file

* get file

* validate remote file metadata before sending to controller

* CLI commands, test

* update store method
2023-10-29 19:06:32 +00:00
Evgeny Poberezkin 9fb2b7fe73 Merge branch 'master' into remote-desktop 2023-10-29 18:05:03 +00:00
Evgeny Poberezkin 16bda26022 core: derive JSON with TH (#3275)
* core: derive JSON with TH

* fix tests

* simplify events

* reduce diff

* fix

* update simplexmq

* update simplexmq
2023-10-26 15:44:50 +01:00
Evgeny Poberezkin 3790752378 Merge branch 'master' into remote-desktop 2023-10-26 00:00:58 +01:00
Alexander Bondarenko cd98fabe43 robust discovery RFC (#3276)
* add new discovery RFC

* update

* update

* update ports

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-10-25 16:39:46 +01:00
Evgeny Poberezkin 6185971827 Merge branch 'master' into remote-desktop 2023-10-24 23:19:49 +01:00
Alexander Bondarenko e1bd6a93af use multicast address for announce (#3241)
* use multicast address for announce

* Add explicit multicast group membership

* join multicast group on a correct side

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-10-23 13:44:04 +01:00
Evgeny Poberezkin 93800268e4 Merge branch 'master' into remote-desktop 2023-10-23 10:04:51 +01:00
Evgeny Poberezkin b5e114d834 Merge branch 'master' into remote-desktop 2023-10-22 13:04:15 +01:00
Alexander Bondarenko 0d1a080a6e remote protocol (#3225)
* draft remote protocol types and external api

* types (it compiles)

* add error

* move remote controller from http to remote host client protocol

* refactor (doesnt compile)

* fix compile

* Connect remote session

* WIP: wire in remote protocol

* add commands and events

* cleanup

* fix desktop shutdown

* prepare for testing remote files

* Add file IO

* update simplexmq to master

with http2 to 4.1.4

* use json transcoder

* update simplexmq

* collapse RemoteHostSession states

* fold RemoteHello back into the protocol command
move http-command-response-http wrapper to protocol

* use sendRemoteCommand with optional attachments
use streaming request/response

* ditch lazy body streaming

* fix formatting

* put body builder/processor closer together

* wrap handleRemoteCommand around sending files

* handle ChatError's too

* remove binary, use 32-bit encoding for JSON bodies

* enable tests

* refactor

* refactor request handling

* return ChatError

* Flatten remote host

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-10-22 09:42:19 +01:00
Evgeny Poberezkin 0444367002 Merge branch 'master' into remote-desktop 2023-10-21 19:07:30 +01:00
Evgeny Poberezkin 92eae012b3 Merge branch 'master' into remote-desktop 2023-10-16 21:38:54 +01:00
Evgeny Poberezkin fc1bba8817 remote: refactor (WIP) (#3222)
* remote: refactor (WIP)

* refactor discoverRemoteCtrls

* refactor processRemoteCommand, storeRemoteFile

* refactor fetchRemoteFile

* refactor startRemoteHost, receiving files

* refactor relayCommand
2023-10-15 14:17:36 +01:00
Evgeny Poberezkin 41b86e07f1 core: update api (#3221) 2023-10-15 00:18:04 +01:00
Evgeny Poberezkin f5e9bd4f8b core: add set display name (#3216)
* core: add set display name

* enable all tests
2023-10-14 13:10:06 +01:00
Evgeny Poberezkin 5e6aaffb09 simplify remote api, add ios api (#3213) 2023-10-13 22:35:30 +01:00
Alexander Bondarenko 193361c09a core: fix remote handshake test (#3209)
* Fix remoteHandshakeTest

Sidesteps some yet to be uncovered bug when
mobile stops its side before the desktop.

* remove ambiguous update warning

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-10-13 18:53:04 +01:00
Evgeny Poberezkin 392447ea33 core: fix test 2023-10-13 17:52:27 +01:00
Evgeny Poberezkin 5d4006f291 Merge branch 'master' into remote-desktop 2023-10-13 17:46:14 +01:00
Alexander Bondarenko fe6c65f75c rfc: remote profile (#3051)
* Add session UX for mobile and desktop

* Resolve some feedback

* Resolve more feedback

Add QR note for desktops.
Add TLS handshake notice.

* Add details
2023-10-12 15:19:19 +01:00
Evgeny Poberezkin 6dca71cc87 Merge branch 'master' into remote-desktop 2023-10-12 11:40:23 +01:00
Alexander Bondarenko adc1f8c983 android, desktop: remote kotlin types (#3200)
* Add remote types to Kotlin

* update response info for chat console

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-10-12 10:58:59 +01:00
Evgeny Poberezkin 73652e4bba Merge branch 'master' into remote-desktop 2023-10-12 10:43:59 +01:00
Evgeny Poberezkin c2a858b06e core: convert single-field to tagged JSON encoding (#3183)
* core: convert single-field to tagged JSON encoding

* rename

* rename

* fixes, test

* refactor
2023-10-11 19:11:01 +01:00
Alexander Bondarenko 6f5ba54f7b core: remote session files (#3189)
* Receiving files on CRRcvFileComplete

* Add remote /fr test

* Add broken startFileTransfer notice

* Sending files with SendFile/SendImage

With tests for SendFile.

* Add APISendMessage handling

* Test file preconditions

No files should be in stores before actual sending.

* Fix mobile paths in storeFile
2023-10-11 09:45:05 +01:00
Evgeny Poberezkin 2b228a893a Merge branch 'master' into remote-desktop 2023-10-09 17:21:47 +01:00
Evgeny Poberezkin 2eb213741c Merge branch 'master' into remote-desktop 2023-10-09 10:35:38 +01:00
Alexander Bondarenko 91561da351 core: http transport for remote session (#3178)
* Wire some of the session endpoints

* Start sending remote commands

* Expand remote controller

- Fix queues for pumping to remote
- Add 3-way test
- WIP: Add TTY wrapper for remote hosts
- Stop remote controller w/o ids to match starting

* Fix view events

* Drop notifications, add message test

* refactor, receive test

* hunt down stray asyncs

* Take discovery sockets in brackets

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-10-07 14:23:24 +01:00
Evgeny Poberezkin 3ac342782b Merge branch 'master' into remote-desktop 2023-10-07 13:05:22 +01:00
Evgeny Poberezkin a273c68596 core: rename migration, pin dependencies 2023-10-05 22:33:48 +01:00
Alexander Bondarenko fc9db9c381 core: add FromJSON instance to ChatResponse (#3129)
* Start adding FromJSON instances to ChatResponse

* progress

* FromJSON instance for ChatResponse compiles

* restore removed encodings

* remove comment

* diff

* update simplexmq, use TH for JSON

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-10-05 19:49:20 +01:00
Evgeny Poberezkin 27e8a81c9f Merge branch 'master' into remote-desktop 2023-10-05 14:15:25 +01:00
Evgeny Poberezkin 7959c75df7 Merge branch 'master' into remote-desktop 2023-10-04 16:37:15 +01:00
Alexander Bondarenko 0bcf5c9c66 Add commands for remote session credentials (#3161)
* Add remote host commands

* Make startRemoteHost async

* Add tests

* Trim randomStorePath to 16 chars

* Add chat command tests

* add view, use view output in test

* enable all tests

* Fix discovery listener host

Must use any, not broadcast on macos.

* Fix missing do

* address, names

* Fix session host flow

* fix test

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-10-04 16:36:10 +01:00
IC Rainbow bf7917bd67 Merge remote-tracking branch 'origin/master' into ab/remote-discover-upd 2023-09-29 18:42:59 +03:00
IC Rainbow 6c0d1b5f15 Notify about handover errors 2023-09-29 16:53:05 +03:00
IC Rainbow af2df8d489 Rewrite remote controller 2023-09-29 15:01:05 +03:00
IC Rainbow cccb3e33fb Plug discovery into remote controller UI 2023-09-27 18:24:38 +03:00
IC Rainbow 77410e5d5e Add remote host discovery 2023-09-27 13:40:19 +03:00
Alexander Bondarenko 3e29c664ac core: remote host/controller types (#3104)
* Start sprinkling ZoneId everywhere

* Draft zone/satellite/host api

* Add zone dispatching

* Add command relaying handler

* Parse commands and begin DB

* Implement discussed things

* Resolve some comments

* Resolve more stuff

* Make bots ignore remoteHostId from queues

* Fix tests and stub more

* Untangle cmd relaying

* Resolve comments

* Add more http2 client funs

* refactor, rename

* rename

* remove empty tests

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-09-27 09:41:02 +01:00
223 changed files with 13179 additions and 2757 deletions
+26 -15
View File
@@ -261,11 +261,36 @@ jobs:
# / Windows
# rm -rf dist-newstyle/src/direct-sq* is here because of the bug in cabal's dependency which prevents second build from finishing
- name: 'Setup MSYS2'
if: startsWith(github.ref, 'refs/tags/v') && matrix.os == 'windows-latest'
uses: msys2/setup-msys2@v2
with:
msystem: ucrt64
update: true
install: >-
git
perl
make
pacboy: >-
toolchain:p
cmake:p
- name: Windows build
id: windows_build
if: matrix.os == 'windows-latest'
shell: bash
shell: msys2 {0}
run: |
export PATH=$PATH:/c/ghcup/bin
scripts/desktop/prepare-openssl-windows.sh
openssl_windows_style_path=$(echo `pwd`/dist-newstyle/openssl-1.1.1w | sed 's#/\([a-zA-Z]\)#\1:#' | sed 's#/#\\#g')
rm cabal.project.local 2>/dev/null || true
echo "ignore-project: False" >> cabal.project.local
echo "package direct-sqlcipher" >> cabal.project.local
echo " flags: +openssl" >> cabal.project.local
echo " extra-include-dirs: $openssl_windows_style_path\include" >> cabal.project.local
echo " extra-lib-dirs: $openssl_windows_style_path" >> cabal.project.local
rm -rf dist-newstyle/src/direct-sq*
sed -i "s/, unix /--, unix /" simplex-chat.cabal
cabal build --enable-tests
@@ -293,20 +318,6 @@ jobs:
body: |
${{ steps.windows_build.outputs.bin_hash }}
- name: 'Setup MSYS2'
if: startsWith(github.ref, 'refs/tags/v') && matrix.os == 'windows-latest'
uses: msys2/setup-msys2@v2
with:
msystem: ucrt64
update: true
install: >-
git
perl
make
pacboy: >-
toolchain:p
cmake:p
- name: Windows build desktop
id: windows_desktop_build
if: startsWith(github.ref, 'refs/tags/v') && matrix.os == 'windows-latest'
+35
View File
@@ -85,6 +85,8 @@ final class ChatModel: ObservableObject {
@Published var activeCall: Call?
@Published var callCommand: WCallCommand?
@Published var showCallView = false
// remote desktop
@Published var remoteCtrlSession: RemoteCtrlSession?
// currently showing QR code
@Published var connReqInv: String?
// audio recording and playback
@@ -110,6 +112,10 @@ final class ChatModel: ObservableObject {
notificationMode == .periodic || ntfEnablePeriodicGroupDefault.get()
}
var activeRemoteCtrl: Bool {
remoteCtrlSession?.active ?? false
}
func getUser(_ userId: Int64) -> User? {
currentUser?.userId == userId
? currentUser
@@ -762,3 +768,32 @@ final class GMember: ObservableObject, Identifiable {
var viewId: String { get { "\(wrapped.id) \(created.timeIntervalSince1970)" } }
static let sampleData = GMember(GroupMember.sampleData)
}
struct RemoteCtrlSession {
var ctrlAppInfo: CtrlAppInfo
var appVersion: String
var sessionState: UIRemoteCtrlSessionState
func updateState(_ state: UIRemoteCtrlSessionState) -> RemoteCtrlSession {
RemoteCtrlSession(ctrlAppInfo: ctrlAppInfo, appVersion: appVersion, sessionState: state)
}
var active: Bool {
if case .connected = sessionState { true } else { false }
}
var sessionCode: String? {
switch sessionState {
case let .pendingConfirmation(_, sessionCode): sessionCode
case let .connected(_, sessionCode): sessionCode
default: nil
}
}
}
enum UIRemoteCtrlSessionState {
case starting
case connecting(remoteCtrl_: RemoteCtrlInfo?)
case pendingConfirmation(remoteCtrl_: RemoteCtrlInfo?, sessionCode: String)
case connected(remoteCtrl: RemoteCtrlInfo, sessionCode: String)
}
+77
View File
@@ -905,6 +905,44 @@ func apiCancelFile(fileId: Int64) async -> AChatItem? {
}
}
func setLocalDeviceName(_ displayName: String) throws {
try sendCommandOkRespSync(.setLocalDeviceName(displayName: displayName))
}
func connectRemoteCtrl(desktopAddress: String) async throws -> (RemoteCtrlInfo?, CtrlAppInfo, String) {
let r = await chatSendCmd(.connectRemoteCtrl(xrcpInvitation: desktopAddress))
if case let .remoteCtrlConnecting(rc_, ctrlAppInfo, v) = r { return (rc_, ctrlAppInfo, v) }
throw r
}
func findKnownRemoteCtrl() async throws {
try await sendCommandOkResp(.findKnownRemoteCtrl)
}
func confirmRemoteCtrl(_ rcId: Int64) async throws {
try await sendCommandOkResp(.confirmRemoteCtrl(remoteCtrlId: rcId))
}
func verifyRemoteCtrlSession(_ sessCode: String) async throws -> RemoteCtrlInfo {
let r = await chatSendCmd(.verifyRemoteCtrlSession(sessionCode: sessCode))
if case let .remoteCtrlConnected(rc) = r { return rc }
throw r
}
func listRemoteCtrls() throws -> [RemoteCtrlInfo] {
let r = chatSendCmdSync(.listRemoteCtrls)
if case let .remoteCtrlList(rcInfo) = r { return rcInfo }
throw r
}
func stopRemoteCtrl() async throws {
try await sendCommandOkResp(.stopRemoteCtrl)
}
func deleteRemoteCtrl(_ rcId: Int64) async throws {
try await sendCommandOkResp(.deleteRemoteCtrl(remoteCtrlId: rcId))
}
func networkErrorAlert(_ r: ChatResponse) -> Alert? {
switch r {
case let .chatCmdError(_, .errorAgent(.BROKER(addr, .TIMEOUT))):
@@ -1033,6 +1071,12 @@ private func sendCommandOkResp(_ cmd: ChatCommand) async throws {
throw r
}
private func sendCommandOkRespSync(_ cmd: ChatCommand) throws {
let r = chatSendCmdSync(cmd)
if case .cmdOk = r { return }
throw r
}
func apiNewGroup(incognito: Bool, groupProfile: GroupProfile) throws -> GroupInfo {
let userId = try currentUserId("apiNewGroup")
let r = chatSendCmdSync(.apiNewGroup(userId: userId, incognito: incognito, groupProfile: groupProfile))
@@ -1670,6 +1714,26 @@ func processReceivedMsg(_ res: ChatResponse) async {
await MainActor.run {
m.updateGroupMemberConnectionStats(groupInfo, member, ratchetSyncProgress.connectionStats)
}
case let .remoteCtrlFound(remoteCtrl):
// TODO multicast
logger.debug("\(String(describing: remoteCtrl))")
case let .remoteCtrlSessionCode(remoteCtrl_, sessionCode):
await MainActor.run {
let state = UIRemoteCtrlSessionState.pendingConfirmation(remoteCtrl_: remoteCtrl_, sessionCode: sessionCode)
m.remoteCtrlSession = m.remoteCtrlSession?.updateState(state)
}
case let .remoteCtrlConnected(remoteCtrl):
// TODO currently it is returned in response to command, so it is redundant
await MainActor.run {
let state = UIRemoteCtrlSessionState.connected(remoteCtrl: remoteCtrl, sessionCode: m.remoteCtrlSession?.sessionCode ?? "")
m.remoteCtrlSession = m.remoteCtrlSession?.updateState(state)
}
case .remoteCtrlStopped:
// 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.
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
switchToLocalSession()
}
default:
logger.debug("unsupported event: \(res.responseType)")
}
@@ -1683,6 +1747,19 @@ func processReceivedMsg(_ res: ChatResponse) async {
}
}
func switchToLocalSession() {
let m = ChatModel.shared
m.remoteCtrlSession = nil
do {
m.users = try listUsers()
try getUserChatData()
let statuses = (try apiGetNetworkStatuses()).map { s in (s.agentConnId, s.networkStatus) }
m.networkStatuses = Dictionary(uniqueKeysWithValues: statuses)
} catch let error {
logger.debug("error updating chat data: \(responseError(error))")
}
}
func active(_ user: any UserLike) -> Bool {
user.userId == ChatModel.shared.currentUser?.id
}
@@ -15,6 +15,7 @@ struct ChatListView: View {
@State private var searchText = ""
@State private var showAddChat = false
@State private var userPickerVisible = false
@State private var showConnectDesktop = false
@AppStorage(DEFAULT_SHOW_UNREAD_AND_FAVORITES) private var showUnreadAndFavorites = false
var body: some View {
@@ -48,7 +49,14 @@ struct ChatListView: View {
}
}
}
UserPicker(showSettings: $showSettings, userPickerVisible: $userPickerVisible)
UserPicker(
showSettings: $showSettings,
showConnectDesktop: $showConnectDesktop,
userPickerVisible: $userPickerVisible
)
}
.sheet(isPresented: $showConnectDesktop) {
ConnectDesktopView()
}
}
@@ -13,6 +13,7 @@ struct UserPicker: View {
@EnvironmentObject var m: ChatModel
@Environment(\.colorScheme) var colorScheme
@Binding var showSettings: Bool
@Binding var showConnectDesktop: Bool
@Binding var userPickerVisible: Bool
@State var scrollViewContentSize: CGSize = .zero
@State var disableScrolling: Bool = true
@@ -62,6 +63,13 @@ struct UserPicker: View {
.simultaneousGesture(DragGesture(minimumDistance: disableScrolling ? 0 : 10000000))
.frame(maxHeight: scrollViewContentSize.height)
menuButton("Use from desktop", icon: "desktopcomputer") {
showConnectDesktop = true
withAnimation {
userPickerVisible.toggle()
}
}
Divider()
menuButton("Settings", icon: "gearshape") {
showSettings = true
withAnimation {
@@ -85,7 +93,7 @@ struct UserPicker: View {
do {
m.users = try listUsers()
} catch let error {
logger.error("Error updating users \(responseError(error))")
logger.error("Error loading users \(responseError(error))")
}
}
}
@@ -144,7 +152,8 @@ struct UserPicker: View {
.overlay(DetermineWidth())
Spacer()
Image(systemName: icon)
// .frame(width: 24, alignment: .center)
.symbolRenderingMode(.monochrome)
.foregroundColor(.secondary)
}
.padding(.horizontal)
.padding(.vertical, 22)
@@ -170,6 +179,7 @@ struct UserPicker_Previews: PreviewProvider {
m.users = [UserInfo.sampleData, UserInfo.sampleData]
return UserPicker(
showSettings: Binding.constant(false),
showConnectDesktop: Binding.constant(false),
userPickerVisible: Binding.constant(true)
)
.environmentObject(m)
@@ -0,0 +1,434 @@
//
// ConnectDesktopView.swift
// SimpleX (iOS)
//
// Created by Evgeny on 13/10/2023.
// Copyright © 2023 SimpleX Chat. All rights reserved.
//
import SwiftUI
import SimpleXChat
import CodeScanner
struct ConnectDesktopView: View {
@EnvironmentObject var m: ChatModel
@Environment(\.dismiss) var dismiss: DismissAction
var viaSettings = false
@AppStorage(DEFAULT_DEVICE_NAME_FOR_REMOTE_ACCESS) private var deviceName = UIDevice.current.name
@AppStorage(DEFAULT_CONFIRM_REMOTE_SESSIONS) private var confirmRemoteSessions = false
@AppStorage(DEFAULT_CONNECT_REMOTE_VIA_MULTICAST) private var connectRemoteViaMulticast = false
@AppStorage(DEFAULT_OFFER_REMOTE_MULTICAST) private var offerRemoteMulticast = true
@AppStorage(DEFAULT_DEVELOPER_TOOLS) private var developerTools = false
@State private var sessionAddress: String = ""
@State private var remoteCtrls: [RemoteCtrlInfo] = []
@State private var alert: ConnectDesktopAlert?
private enum ConnectDesktopAlert: Identifiable {
case unlinkDesktop(rc: RemoteCtrlInfo)
case disconnectDesktop(action: UserDisconnectAction)
case badInvitationError
case badVersionError(version: String?)
case desktopDisconnectedError
case error(title: LocalizedStringKey, error: LocalizedStringKey = "")
var id: String {
switch self {
case let .unlinkDesktop(rc): "unlinkDesktop \(rc.remoteCtrlId)"
case let .disconnectDesktop(action): "disconnectDecktop \(action)"
case .badInvitationError: "badInvitationError"
case let .badVersionError(v): "badVersionError \(v ?? "")"
case .desktopDisconnectedError: "desktopDisconnectedError"
case let .error(title, _): "error \(title)"
}
}
}
private enum UserDisconnectAction: String {
case back
case dismiss // TODO dismiss settings after confirmation
}
var body: some View {
if viaSettings {
viewBody
.modifier(BackButton(label: "Back") {
if m.activeRemoteCtrl {
alert = .disconnectDesktop(action: .back)
} else {
dismiss()
}
})
} else {
NavigationView {
viewBody
}
}
}
var viewBody: some View {
Group {
if let session = m.remoteCtrlSession {
switch session.sessionState {
case .starting: connectingDesktopView(session, nil)
case let .connecting(rc_): connectingDesktopView(session, rc_)
case let .pendingConfirmation(rc_, sessCode):
if confirmRemoteSessions || rc_ == nil {
verifySessionView(session, rc_, sessCode)
} else {
connectingDesktopView(session, rc_).onAppear {
verifyDesktopSessionCode(sessCode)
}
}
case let .connected(rc, _): activeSessionView(session, rc)
}
} else {
connectDesktopView()
}
}
.onAppear {
setDeviceName(deviceName)
updateRemoteCtrls()
}
.onDisappear {
if m.remoteCtrlSession != nil {
disconnectDesktop()
}
}
.onChange(of: deviceName) {
setDeviceName($0)
}
.onChange(of: m.activeRemoteCtrl) {
UIApplication.shared.isIdleTimerDisabled = $0
}
.alert(item: $alert) { a in
switch a {
case let .unlinkDesktop(rc):
Alert(
title: Text("Unlink desktop?"),
primaryButton: .destructive(Text("Unlink")) {
unlinkDesktop(rc)
},
secondaryButton: .cancel()
)
case let .disconnectDesktop(action):
Alert(
title: Text("Disconnect desktop?"),
primaryButton: .destructive(Text("Disconnect")) {
disconnectDesktop(action)
},
secondaryButton: .cancel()
)
case .badInvitationError:
Alert(title: Text("Bad desktop address"))
case let .badVersionError(v):
Alert(
title: Text("Incompatible version"),
message: Text("Desktop app version \(v ?? "") is not compatible with this app.")
)
case .desktopDisconnectedError:
Alert(title: Text("Connection terminated"))
case let .error(title, error):
Alert(title: Text(title), message: Text(error))
}
}
.interactiveDismissDisabled(m.activeRemoteCtrl)
}
private func connectDesktopView() -> some View {
List {
Section("This device name") {
devicesView()
}
scanDesctopAddressView()
if developerTools {
desktopAddressView()
}
}
.navigationTitle("Connect to desktop")
}
private func connectingDesktopView(_ session: RemoteCtrlSession, _ rc: RemoteCtrlInfo?) -> some View {
List {
Section("Connecting to desktop") {
ctrlDeviceNameText(session, rc)
ctrlDeviceVersionText(session)
}
if let sessCode = session.sessionCode {
Section("Session code") {
sessionCodeText(sessCode)
}
}
Section {
disconnectButton()
}
}
.navigationTitle("Connecting to desktop")
}
private func verifySessionView(_ session: RemoteCtrlSession, _ rc: RemoteCtrlInfo?, _ sessCode: String) -> some View {
List {
Section("Connected to desktop") {
ctrlDeviceNameText(session, rc)
ctrlDeviceVersionText(session)
}
Section("Verify code with desktop") {
sessionCodeText(sessCode)
Button {
verifyDesktopSessionCode(sessCode)
} label: {
Label("Confirm", systemImage: "checkmark")
}
}
Section {
disconnectButton()
}
}
.navigationTitle("Verify connection")
}
private func ctrlDeviceNameText(_ session: RemoteCtrlSession, _ rc: RemoteCtrlInfo?) -> Text {
var t = Text(rc?.deviceViewName ?? session.ctrlAppInfo.deviceName)
if (rc == nil) {
t = t + Text(" ") + Text("(new)").italic()
}
return t
}
private func ctrlDeviceVersionText(_ session: RemoteCtrlSession) -> Text {
let v = session.ctrlAppInfo.appVersionRange.maxVersion
var t = Text("v\(v)")
if v != session.appVersion {
t = t + Text(" ") + Text("(this device v\(session.appVersion))").italic()
}
return t
}
private func activeSessionView(_ session: RemoteCtrlSession, _ rc: RemoteCtrlInfo) -> some View {
List {
Section("Connected desktop") {
Text(rc.deviceViewName)
ctrlDeviceVersionText(session)
}
if let sessCode = session.sessionCode {
Section("Session code") {
sessionCodeText(sessCode)
}
}
Section {
disconnectButton()
} footer: {
// This is specific to iOS
Text("Keep the app open to use it from desktop")
}
}
.navigationTitle("Connected to desktop")
}
private func sessionCodeText(_ code: String) -> some View {
Text(code.prefix(23))
}
private func devicesView() -> some View {
Group {
TextField("Enter this device name…", text: $deviceName)
if !remoteCtrls.isEmpty {
NavigationLink {
linkedDesktopsView()
} label: {
Text("Linked desktops")
}
}
}
}
private func scanDesctopAddressView() -> some View {
Section("Scan QR code from desktop") {
CodeScannerView(codeTypes: [.qr], 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)
}
}
private func desktopAddressView() -> some View {
Section("Desktop address") {
if sessionAddress.isEmpty {
Button {
sessionAddress = UIPasteboard.general.string ?? ""
} label: {
Label("Paste desktop address", systemImage: "doc.plaintext")
}
.disabled(!UIPasteboard.general.hasStrings)
} else {
HStack {
Text(sessionAddress).lineLimit(1)
Spacer()
Image(systemName: "multiply.circle.fill")
.foregroundColor(.secondary)
.onTapGesture { sessionAddress = "" }
}
}
Button {
connectDesktopAddress(sessionAddress)
} label: {
Label("Connect to desktop", systemImage: "rectangle.connected.to.line.below")
}
.disabled(sessionAddress.isEmpty)
}
}
private func linkedDesktopsView() -> some View {
List {
Section("Desktop devices") {
ForEach(remoteCtrls, id: \.remoteCtrlId) { rc in
remoteCtrlView(rc)
}
.onDelete { indexSet in
if let i = indexSet.first, i < remoteCtrls.count {
alert = .unlinkDesktop(rc: remoteCtrls[i])
}
}
}
Section("Linked desktop options") {
Toggle("Verify connections", isOn: $confirmRemoteSessions)
Toggle("Discover on network", isOn: $connectRemoteViaMulticast).disabled(true)
}
}
.navigationTitle("Linked desktops")
}
private func remoteCtrlView(_ rc: RemoteCtrlInfo) -> some View {
Text(rc.deviceViewName)
}
private func setDeviceName(_ name: String) {
do {
try setLocalDeviceName(deviceName)
} catch let e {
errorAlert(e)
}
}
private func updateRemoteCtrls() {
do {
remoteCtrls = try listRemoteCtrls()
} catch let e {
errorAlert(e)
}
}
private func processDesktopQRCode(_ resp: Result<ScanResult, ScanError>) {
switch resp {
case let .success(r): connectDesktopAddress(r.string)
case let .failure(e): errorAlert(e)
}
}
private func connectDesktopAddress(_ addr: String) {
Task {
do {
let (rc_, ctrlAppInfo, v) = try await connectRemoteCtrl(desktopAddress: addr)
await MainActor.run {
sessionAddress = ""
m.remoteCtrlSession = RemoteCtrlSession(
ctrlAppInfo: ctrlAppInfo,
appVersion: v,
sessionState: .connecting(remoteCtrl_: rc_)
)
}
} catch let e {
await MainActor.run {
switch e as? ChatResponse {
case .chatCmdError(_, .errorRemoteCtrl(.badInvitation)): alert = .badInvitationError
case .chatCmdError(_, .error(.commandError)): alert = .badInvitationError
case let .chatCmdError(_, .errorRemoteCtrl(.badVersion(v))): alert = .badVersionError(version: v)
case .chatCmdError(_, .errorAgent(.RCP(.version))): alert = .badVersionError(version: nil)
case .chatCmdError(_, .errorAgent(.RCP(.ctrlAuth))): alert = .desktopDisconnectedError
default: errorAlert(e)
}
}
}
}
}
private func verifyDesktopSessionCode(_ sessCode: String) {
Task {
do {
let rc = try await verifyRemoteCtrlSession(sessCode)
await MainActor.run {
m.remoteCtrlSession = m.remoteCtrlSession?.updateState(.connected(remoteCtrl: rc, sessionCode: sessCode))
}
await MainActor.run {
updateRemoteCtrls()
}
} catch let error {
await MainActor.run {
errorAlert(error)
}
}
}
}
private func disconnectButton() -> some View {
Button {
disconnectDesktop()
} label: {
Label("Disconnect", systemImage: "multiply")
}
}
private func disconnectDesktop(_ action: UserDisconnectAction? = nil) {
Task {
do {
try await stopRemoteCtrl()
await MainActor.run {
switchToLocalSession()
switch action {
case .back: dismiss()
case .dismiss: dismiss()
case .none: ()
}
}
} catch let e {
await MainActor.run {
errorAlert(e)
}
}
}
}
private func unlinkDesktop(_ rc: RemoteCtrlInfo) {
Task {
do {
try await deleteRemoteCtrl(rc.remoteCtrlId)
await MainActor.run {
remoteCtrls.removeAll(where: { $0.remoteCtrlId == rc.remoteCtrlId })
}
} catch let e {
await MainActor.run {
errorAlert(e)
}
}
}
}
private func errorAlert(_ error: Error) {
let a = getErrorAlert(error, "Error")
alert = .error(title: a.title, error: a.message)
}
}
#Preview {
ConnectDesktopView()
}
@@ -53,6 +53,10 @@ let DEFAULT_WHATS_NEW_VERSION = "defaultWhatsNewVersion"
let DEFAULT_ONBOARDING_STAGE = "onboardingStage"
let DEFAULT_CUSTOM_DISAPPEARING_MESSAGE_TIME = "customDisappearingMessageTime"
let DEFAULT_SHOW_UNREAD_AND_FAVORITES = "showUnreadAndFavorites"
let DEFAULT_DEVICE_NAME_FOR_REMOTE_ACCESS = "deviceNameForRemoteAccess"
let DEFAULT_CONFIRM_REMOTE_SESSIONS = "confirmRemoteSessions"
let DEFAULT_CONNECT_REMOTE_VIA_MULTICAST = "connectRemoteViaMulticast"
let DEFAULT_OFFER_REMOTE_MULTICAST = "offerRemoteMulticast"
let appDefaults: [String: Any] = [
DEFAULT_SHOW_LA_NOTICE: false,
@@ -85,7 +89,10 @@ let appDefaults: [String: Any] = [
DEFAULT_SHOW_MUTE_PROFILE_ALERT: true,
DEFAULT_ONBOARDING_STAGE: OnboardingStage.onboardingComplete.rawValue,
DEFAULT_CUSTOM_DISAPPEARING_MESSAGE_TIME: 300,
DEFAULT_SHOW_UNREAD_AND_FAVORITES: false
DEFAULT_SHOW_UNREAD_AND_FAVORITES: false,
DEFAULT_CONFIRM_REMOTE_SESSIONS: false,
DEFAULT_CONNECT_REMOTE_VIA_MULTICAST: false,
DEFAULT_OFFER_REMOTE_MULTICAST: true
]
enum SimpleXLinkMode: String, Identifiable {
@@ -178,6 +185,12 @@ struct SettingsView: View {
} label: {
settingsRow("switch.2") { Text("Chat preferences") }
}
NavigationLink {
ConnectDesktopView(viaSettings: true)
} label: {
settingsRow("desktopcomputer") { Text("Use from desktop") }
}
}
.disabled(chatModel.chatRunning != true)
@@ -362,7 +375,9 @@ struct SettingsView: View {
func settingsRow<Content : View>(_ icon: String, color: Color = .secondary, content: @escaping () -> Content) -> some View {
ZStack(alignment: .leading) {
Image(systemName: icon).frame(maxWidth: 24, maxHeight: 24, alignment: .center).foregroundColor(color)
Image(systemName: icon).frame(maxWidth: 24, maxHeight: 24, alignment: .center)
.symbolRenderingMode(.monochrome)
.foregroundColor(color)
content().padding(.leading, indent)
}
}
+4
View File
@@ -18,5 +18,9 @@
<array>
<string>$(AppIdentifierPrefix)chat.simplex.app</string>
</array>
<key>com.apple.developer.networking.multicast</key>
<true/>
<key>com.apple.developer.device-information.user-assigned-device-name</key>
<true/>
</dict>
</plist>
@@ -290,6 +290,14 @@
<target>(</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(new)" xml:space="preserve">
<source>(new)</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(this device v%@)" xml:space="preserve">
<source>(this device v%@)</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=")" xml:space="preserve">
<source>)</source>
<target>)</target>
@@ -858,6 +866,10 @@
<target>Назад</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Bad desktop address" xml:space="preserve">
<source>Bad desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Bad message ID" xml:space="preserve">
<source>Bad message ID</source>
<target>Лошо ID на съобщението</target>
@@ -1151,6 +1163,10 @@
<target>Свързване инкогнито</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to desktop" xml:space="preserve">
<source>Connect to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to yourself?" xml:space="preserve">
<source>Connect to yourself?</source>
<note>No comment provided by engineer.</note>
@@ -1188,6 +1204,14 @@ This is your own one-time link!</source>
<source>Connect with %@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connected desktop" xml:space="preserve">
<source>Connected desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connected to desktop" xml:space="preserve">
<source>Connected to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connecting server…" xml:space="preserve">
<source>Connecting to server…</source>
<target>Свързване със сървъра…</target>
@@ -1198,6 +1222,10 @@ This is your own one-time link!</source>
<target>Свързване със сървър…(грешка: %@)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connecting to desktop" xml:space="preserve">
<source>Connecting to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection" xml:space="preserve">
<source>Connection</source>
<target>Връзка</target>
@@ -1218,6 +1246,10 @@ This is your own one-time link!</source>
<target>Заявката за връзка е изпратена!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection terminated" xml:space="preserve">
<source>Connection terminated</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection timeout" xml:space="preserve">
<source>Connection timeout</source>
<target>Времето на изчакване за установяване на връзката изтече</target>
@@ -1701,6 +1733,18 @@ This cannot be undone!</source>
<target>Описание</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop address" xml:space="preserve">
<source>Desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop app version %@ is not compatible with this app." xml:space="preserve">
<source>Desktop app version %@ is not compatible with this app.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop devices" xml:space="preserve">
<source>Desktop devices</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Develop" xml:space="preserve">
<source>Develop</source>
<target>Разработване</target>
@@ -1791,11 +1835,19 @@ This cannot be undone!</source>
<target>Прекъсни връзката</target>
<note>server test step</note>
</trans-unit>
<trans-unit id="Disconnect desktop?" xml:space="preserve">
<source>Disconnect desktop?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Discover and join groups" xml:space="preserve">
<source>Discover and join groups</source>
<target>Открийте и се присъединете към групи</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Discover on network" xml:space="preserve">
<source>Discover on network</source>
<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>НЕ използвайте SimpleX за спешни повиквания.</target>
@@ -1966,6 +2018,14 @@ This cannot be undone!</source>
<target>Криптирано съобщение: неочаквана грешка</target>
<note>notification</note>
</trans-unit>
<trans-unit id="Encryption re-negotiation error" xml:space="preserve">
<source>Encryption re-negotiation error</source>
<note>message decrypt error item</note>
</trans-unit>
<trans-unit id="Encryption re-negotiation failed." xml:space="preserve">
<source>Encryption re-negotiation failed.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter Passcode" xml:space="preserve">
<source>Enter Passcode</source>
<target>Въведете kодa за достъп</target>
@@ -1995,6 +2055,10 @@ This cannot be undone!</source>
<target>Въведи сървъра ръчно</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter this device name…" xml:space="preserve">
<source>Enter this device name…</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter welcome message…" xml:space="preserve">
<source>Enter welcome message…</source>
<target>Въведи съобщение при посрещане…</target>
@@ -2765,6 +2829,10 @@ This cannot be undone!</source>
<target>Несъвместима версия на базата данни</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Incompatible version" xml:space="preserve">
<source>Incompatible version</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Incorrect passcode" xml:space="preserve">
<source>Incorrect passcode</source>
<target>Неправилен kод за достъп</target>
@@ -2930,6 +2998,10 @@ This is your link for group %@!</source>
<target>Присъединяване към групата</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Keep the app open to use it from desktop" xml:space="preserve">
<source>Keep the app open to use it from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Keep your connections" xml:space="preserve">
<source>Keep your connections</source>
<target>Запазете връзките си</target>
@@ -2990,6 +3062,14 @@ This is your link for group %@!</source>
<target>Ограничения</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Linked desktop options" xml:space="preserve">
<source>Linked desktop options</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Linked desktops" xml:space="preserve">
<source>Linked desktops</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Live message!" xml:space="preserve">
<source>Live message!</source>
<target>Съобщение на живо!</target>
@@ -3557,6 +3637,10 @@ This is your link for group %@!</source>
<target>Постави</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Paste desktop address" xml:space="preserve">
<source>Paste desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Paste image" xml:space="preserve">
<source>Paste image</source>
<target>Постави изображение</target>
@@ -4148,6 +4232,10 @@ This is your link for group %@!</source>
<target>Сканирай QR код</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scan QR code from desktop" xml:space="preserve">
<source>Scan QR code from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scan code" xml:space="preserve">
<source>Scan code</source>
<target>Сканирай код</target>
@@ -4368,6 +4456,10 @@ This is your link for group %@!</source>
<target>Сървъри</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Session code" xml:space="preserve">
<source>Session code</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set 1 day" xml:space="preserve">
<source>Set 1 day</source>
<target>Задай 1 ден</target>
@@ -4864,6 +4956,10 @@ It can happen because of some bug or when the connection is compromised.</source
<target>Това действие не може да бъде отменено - вашият профил, контакти, съобщения и файлове ще бъдат безвъзвратно загубени.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This device name" xml:space="preserve">
<source>This device name</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This group has over %lld members, delivery receipts are not sent." xml:space="preserve">
<source>This group has over %lld members, delivery receipts are not sent.</source>
<target>Тази група има над %lld членове, потвърждения за доставка не се изпращат.</target>
@@ -5053,6 +5149,14 @@ To connect, please ask your contact to create another connection link and check
За да се свържете, моля, помолете вашия контакт да създаде друг линк за връзка и проверете дали имате стабилна мрежова връзка.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlink" xml:space="preserve">
<source>Unlink</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlink desktop?" xml:space="preserve">
<source>Unlink desktop?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlock" xml:space="preserve">
<source>Unlock</source>
<target>Отключи</target>
@@ -5143,6 +5247,10 @@ To connect, please ask your contact to create another connection link and check
<target>Използвай за нови връзки</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use from desktop" xml:space="preserve">
<source>Use from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use iOS call interface" xml:space="preserve">
<source>Use iOS call interface</source>
<target>Използвай интерфейса за повикване на iOS</target>
@@ -5173,11 +5281,23 @@ To connect, please ask your contact to create another connection link and check
<target>Използват се сървърите на SimpleX Chat.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify code with desktop" xml:space="preserve">
<source>Verify code with desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connection" xml:space="preserve">
<source>Verify connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connection security" xml:space="preserve">
<source>Verify connection security</source>
<target>Потвръди сигурността на връзката</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connections" xml:space="preserve">
<source>Verify connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify security code" xml:space="preserve">
<source>Verify security code</source>
<target>Потвръди кода за сигурност</target>
@@ -6348,6 +6468,10 @@ SimpleX сървърите не могат да видят вашия профи
<target>актуализиран профил на групата</target>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="v%@" xml:space="preserve">
<source>v%@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="v%@ (%@)" xml:space="preserve">
<source>v%@ (%@)</source>
<target>v%@ (%@)</target>
@@ -6485,6 +6609,10 @@ SimpleX сървърите не могат да видят вашия профи
<target>SimpleX използва Face ID за локалнa идентификация</target>
<note>Privacy - Face ID Usage Description</note>
</trans-unit>
<trans-unit id="NSLocalNetworkUsageDescription" xml:space="preserve">
<source>SimpleX uses local network access to allow using user chat profile via desktop app on the same network.</source>
<note>Privacy - Local Network Usage Description</note>
</trans-unit>
<trans-unit id="NSMicrophoneUsageDescription" xml:space="preserve">
<source>SimpleX needs microphone access for audio and video calls, and to record voice messages.</source>
<target>SimpleX се нуждае от достъп до микрофона за аудио и видео разговори и за запис на гласови съобщения.</target>
@@ -4,6 +4,8 @@
"NSCameraUsageDescription" = "SimpleX needs camera access to scan QR codes to connect to other users and for video calls.";
/* Privacy - Face ID Usage Description */
"NSFaceIDUsageDescription" = "SimpleX uses Face ID for local authentication";
/* Privacy - Local Network Usage Description */
"NSLocalNetworkUsageDescription" = "SimpleX uses local network access to allow using user chat profile via desktop app on the same network.";
/* Privacy - Microphone Usage Description */
"NSMicrophoneUsageDescription" = "SimpleX needs microphone access for audio and video calls, and to record voice messages.";
/* Privacy - Photo Library Additions Usage Description */
@@ -290,6 +290,14 @@
<target>(</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(new)" xml:space="preserve">
<source>(new)</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(this device v%@)" xml:space="preserve">
<source>(this device v%@)</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=")" xml:space="preserve">
<source>)</source>
<target>)</target>
@@ -858,6 +866,10 @@
<target>Zpět</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Bad desktop address" xml:space="preserve">
<source>Bad desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Bad message ID" xml:space="preserve">
<source>Bad message ID</source>
<target>Špatné ID zprávy</target>
@@ -1151,6 +1163,10 @@
<target>Spojit se inkognito</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to desktop" xml:space="preserve">
<source>Connect to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to yourself?" xml:space="preserve">
<source>Connect to yourself?</source>
<note>No comment provided by engineer.</note>
@@ -1188,6 +1204,14 @@ This is your own one-time link!</source>
<source>Connect with %@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connected desktop" xml:space="preserve">
<source>Connected desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connected to desktop" xml:space="preserve">
<source>Connected to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connecting server…" xml:space="preserve">
<source>Connecting to server…</source>
<target>Připojování k serveru…</target>
@@ -1198,6 +1222,10 @@ This is your own one-time link!</source>
<target>Připojování k serveru... (chyba: %@)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connecting to desktop" xml:space="preserve">
<source>Connecting to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection" xml:space="preserve">
<source>Connection</source>
<target>Připojení</target>
@@ -1218,6 +1246,10 @@ This is your own one-time link!</source>
<target>Požadavek na připojení byl odeslán!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection terminated" xml:space="preserve">
<source>Connection terminated</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection timeout" xml:space="preserve">
<source>Connection timeout</source>
<target>Časový limit připojení</target>
@@ -1701,6 +1733,18 @@ This cannot be undone!</source>
<target>Popis</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop address" xml:space="preserve">
<source>Desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop app version %@ is not compatible with this app." xml:space="preserve">
<source>Desktop app version %@ is not compatible with this app.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop devices" xml:space="preserve">
<source>Desktop devices</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Develop" xml:space="preserve">
<source>Develop</source>
<target>Vyvinout</target>
@@ -1791,11 +1835,19 @@ This cannot be undone!</source>
<target>Odpojit</target>
<note>server test step</note>
</trans-unit>
<trans-unit id="Disconnect desktop?" xml:space="preserve">
<source>Disconnect desktop?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Discover and join groups" xml:space="preserve">
<source>Discover and join groups</source>
<target>Objevte a připojte skupiny</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Discover on network" xml:space="preserve">
<source>Discover on network</source>
<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>NEpoužívejte SimpleX pro tísňová volání.</target>
@@ -1966,6 +2018,14 @@ This cannot be undone!</source>
<target>Šifrovaná zpráva: neočekávaná chyba</target>
<note>notification</note>
</trans-unit>
<trans-unit id="Encryption re-negotiation error" xml:space="preserve">
<source>Encryption re-negotiation error</source>
<note>message decrypt error item</note>
</trans-unit>
<trans-unit id="Encryption re-negotiation failed." xml:space="preserve">
<source>Encryption re-negotiation failed.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter Passcode" xml:space="preserve">
<source>Enter Passcode</source>
<target>Zadat heslo</target>
@@ -1995,6 +2055,10 @@ This cannot be undone!</source>
<target>Zadejte server ručně</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter this device name…" xml:space="preserve">
<source>Enter this device name…</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter welcome message…" xml:space="preserve">
<source>Enter welcome message…</source>
<target>Zadat uvítací zprávu…</target>
@@ -2765,6 +2829,10 @@ This cannot be undone!</source>
<target>Nekompatibilní verze databáze</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Incompatible version" xml:space="preserve">
<source>Incompatible version</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Incorrect passcode" xml:space="preserve">
<source>Incorrect passcode</source>
<target>Nesprávné heslo</target>
@@ -2930,6 +2998,10 @@ This is your link for group %@!</source>
<target>Připojování ke skupině</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Keep the app open to use it from desktop" xml:space="preserve">
<source>Keep the app open to use it from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Keep your connections" xml:space="preserve">
<source>Keep your connections</source>
<target>Zachovat vaše připojení</target>
@@ -2990,6 +3062,14 @@ This is your link for group %@!</source>
<target>Omezení</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Linked desktop options" xml:space="preserve">
<source>Linked desktop options</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Linked desktops" xml:space="preserve">
<source>Linked desktops</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Live message!" xml:space="preserve">
<source>Live message!</source>
<target>Živé zprávy!</target>
@@ -3557,6 +3637,10 @@ This is your link for group %@!</source>
<target>Vložit</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Paste desktop address" xml:space="preserve">
<source>Paste desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Paste image" xml:space="preserve">
<source>Paste image</source>
<target>Vložit obrázek</target>
@@ -4148,6 +4232,10 @@ This is your link for group %@!</source>
<target>Skenovat QR kód</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scan QR code from desktop" xml:space="preserve">
<source>Scan QR code from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scan code" xml:space="preserve">
<source>Scan code</source>
<target>Skenovat kód</target>
@@ -4368,6 +4456,10 @@ This is your link for group %@!</source>
<target>Servery</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Session code" xml:space="preserve">
<source>Session code</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set 1 day" xml:space="preserve">
<source>Set 1 day</source>
<target>Nastavit 1 den</target>
@@ -4864,6 +4956,10 @@ Může se to stát kvůli nějaké chybě, nebo pokud je spojení kompromitován
<target>Tuto akci nelze vzít zpět - váš profil, kontakty, zprávy a soubory budou nenávratně ztraceny.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This device name" xml:space="preserve">
<source>This device name</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This group has over %lld members, delivery receipts are not sent." xml:space="preserve">
<source>This group has over %lld members, delivery receipts are not sent.</source>
<target>Tato skupina má více než %lld členů, potvrzení o doručení nejsou odesílány.</target>
@@ -5053,6 +5149,14 @@ To connect, please ask your contact to create another connection link and check
Chcete-li se připojit, požádejte svůj kontakt o vytvoření dalšího odkazu na připojení a zkontrolujte, zda máte stabilní připojení k síti.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlink" xml:space="preserve">
<source>Unlink</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlink desktop?" xml:space="preserve">
<source>Unlink desktop?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlock" xml:space="preserve">
<source>Unlock</source>
<target>Odemknout</target>
@@ -5143,6 +5247,10 @@ Chcete-li se připojit, požádejte svůj kontakt o vytvoření dalšího odkazu
<target>Použít pro nová připojení</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use from desktop" xml:space="preserve">
<source>Use from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use iOS call interface" xml:space="preserve">
<source>Use iOS call interface</source>
<target>Použít rozhraní volání iOS</target>
@@ -5173,11 +5281,23 @@ Chcete-li se připojit, požádejte svůj kontakt o vytvoření dalšího odkazu
<target>Používat servery SimpleX Chat.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify code with desktop" xml:space="preserve">
<source>Verify code with desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connection" xml:space="preserve">
<source>Verify connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connection security" xml:space="preserve">
<source>Verify connection security</source>
<target>Ověření zabezpečení připojení</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connections" xml:space="preserve">
<source>Verify connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify security code" xml:space="preserve">
<source>Verify security code</source>
<target>Ověření bezpečnostního kódu</target>
@@ -6347,6 +6467,10 @@ Servery SimpleX nevidí váš profil.</target>
<target>aktualizoval profil skupiny</target>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="v%@" xml:space="preserve">
<source>v%@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="v%@ (%@)" xml:space="preserve">
<source>v%@ (%@)</source>
<target>v%@ (%@)</target>
@@ -6484,6 +6608,10 @@ Servery SimpleX nevidí váš profil.</target>
<target>SimpleX používá Face ID pro místní ověřování</target>
<note>Privacy - Face ID Usage Description</note>
</trans-unit>
<trans-unit id="NSLocalNetworkUsageDescription" xml:space="preserve">
<source>SimpleX uses local network access to allow using user chat profile via desktop app on the same network.</source>
<note>Privacy - Local Network Usage Description</note>
</trans-unit>
<trans-unit id="NSMicrophoneUsageDescription" xml:space="preserve">
<source>SimpleX needs microphone access for audio and video calls, and to record voice messages.</source>
<target>SimpleX potřebuje přístup k mikrofonu pro audio a video hovory a pro nahrávání hlasových zpráv.</target>
@@ -4,6 +4,8 @@
"NSCameraUsageDescription" = "SimpleX needs camera access to scan QR codes to connect to other users and for video calls.";
/* Privacy - Face ID Usage Description */
"NSFaceIDUsageDescription" = "SimpleX uses Face ID for local authentication";
/* Privacy - Local Network Usage Description */
"NSLocalNetworkUsageDescription" = "SimpleX uses local network access to allow using user chat profile via desktop app on the same network.";
/* Privacy - Microphone Usage Description */
"NSMicrophoneUsageDescription" = "SimpleX needs microphone access for audio and video calls, and to record voice messages.";
/* Privacy - Photo Library Additions Usage Description */
@@ -89,11 +89,12 @@
</trans-unit>
<trans-unit id="%@ and %@" xml:space="preserve">
<source>%@ and %@</source>
<target>%@ und %@</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ and %@ connected" xml:space="preserve">
<source>%@ and %@ connected</source>
<target>%@ und %@ wurden verbunden</target>
<target>%@ und %@ wurden mit Ihnen verbunden</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ at %@:" xml:space="preserve">
@@ -103,6 +104,7 @@
</trans-unit>
<trans-unit id="%@ connected" xml:space="preserve">
<source>%@ connected</source>
<target>%@ wurde mit Ihnen verbunden</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ is connected!" xml:space="preserve">
@@ -132,11 +134,12 @@
</trans-unit>
<trans-unit id="%@, %@ and %lld members" xml:space="preserve">
<source>%@, %@ and %lld members</source>
<target>%@, %@ und %lld Mitglieder</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@, %@ and %lld other members connected" xml:space="preserve">
<source>%@, %@ and %lld other members connected</source>
<target>%@, %@ und %lld weitere Mitglieder wurden verbunden</target>
<target>%@, %@ und %lld weitere Mitglieder wurden mit Ihnen verbunden</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@:" xml:space="preserve">
@@ -201,6 +204,7 @@
</trans-unit>
<trans-unit id="%lld group events" xml:space="preserve">
<source>%lld group events</source>
<target>%lld Gruppenereignisse</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%lld members" xml:space="preserve">
@@ -210,14 +214,17 @@
</trans-unit>
<trans-unit id="%lld messages blocked" xml:space="preserve">
<source>%lld messages blocked</source>
<target>%lld Nachrichten blockiert</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%lld messages marked deleted" xml:space="preserve">
<source>%lld messages marked deleted</source>
<target>%lld Nachrichten als gelöscht markiert</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%lld messages moderated by %@" xml:space="preserve">
<source>%lld messages moderated by %@</source>
<target>%lld Nachrichten von %@ moderiert</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%lld minutes" xml:space="preserve">
@@ -290,6 +297,14 @@
<target>(</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(new)" xml:space="preserve">
<source>(new)</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(this device v%@)" xml:space="preserve">
<source>(this device v%@)</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=")" xml:space="preserve">
<source>)</source>
<target>)</target>
@@ -394,6 +409,7 @@
</trans-unit>
<trans-unit id="0 sec" xml:space="preserve">
<source>0 sec</source>
<target>0 sek</target>
<note>time to disappear</note>
</trans-unit>
<trans-unit id="0s" xml:space="preserve">
@@ -623,6 +639,7 @@
</trans-unit>
<trans-unit id="All new messages from %@ will be hidden!" xml:space="preserve">
<source>All new messages from %@ will be hidden!</source>
<target>Alle neuen Nachrichten von %@ werden verborgen!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
@@ -732,10 +749,12 @@
</trans-unit>
<trans-unit id="Already connecting!" xml:space="preserve">
<source>Already connecting!</source>
<target>Bereits verbunden!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Already joining the group!" xml:space="preserve">
<source>Already joining the group!</source>
<target>Sie sind bereits Mitglied der Gruppe!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Always use relay" xml:space="preserve">
@@ -858,6 +877,10 @@
<target>Zurück</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Bad desktop address" xml:space="preserve">
<source>Bad desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Bad message ID" xml:space="preserve">
<source>Bad message ID</source>
<target>Falsche Nachrichten-ID</target>
@@ -875,14 +898,17 @@
</trans-unit>
<trans-unit id="Block" xml:space="preserve">
<source>Block</source>
<target>Blockieren</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Block member" xml:space="preserve">
<source>Block member</source>
<target>Mitglied blockieren</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Block member?" xml:space="preserve">
<source>Block member?</source>
<target>Mitglied blockieren?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Both you and your contact can add message reactions." xml:space="preserve">
@@ -1151,22 +1177,32 @@
<target>Inkognito verbinden</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to desktop" xml:space="preserve">
<source>Connect to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to yourself?" xml:space="preserve">
<source>Connect to yourself?</source>
<target>Mit Ihnen selbst verbinden?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to yourself?&#10;This is your own SimpleX address!" xml:space="preserve">
<source>Connect to yourself?
This is your own SimpleX address!</source>
<target>Mit Ihnen selbst verbinden?
Das ist Ihre eigene SimpleX-Adresse!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to yourself?&#10;This is your own one-time link!" xml:space="preserve">
<source>Connect to yourself?
This is your own one-time link!</source>
<target>Mit Ihnen selbst verbinden?
Das ist Ihr eigener Einmal-Link!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect via contact address" xml:space="preserve">
<source>Connect via contact address</source>
<target>Über die Kontakt-Adresse verbinden</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect via link" xml:space="preserve">
@@ -1186,6 +1222,15 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Connect with %@" xml:space="preserve">
<source>Connect with %@</source>
<target>Mit %@ verbinden</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connected desktop" xml:space="preserve">
<source>Connected desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connected to desktop" xml:space="preserve">
<source>Connected to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connecting server…" xml:space="preserve">
@@ -1198,6 +1243,10 @@ This is your own one-time link!</source>
<target>Mit dem Server verbinden… (Fehler: %@)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connecting to desktop" xml:space="preserve">
<source>Connecting to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection" xml:space="preserve">
<source>Connection</source>
<target>Verbindung</target>
@@ -1218,6 +1267,10 @@ This is your own one-time link!</source>
<target>Verbindungsanfrage wurde gesendet!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection terminated" xml:space="preserve">
<source>Connection terminated</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection timeout" xml:space="preserve">
<source>Connection timeout</source>
<target>Verbindungszeitüberschreitung</target>
@@ -1285,6 +1338,7 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Correct name to %@?" xml:space="preserve">
<source>Correct name to %@?</source>
<target>Richtiger Name für %@?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create" xml:space="preserve">
@@ -1309,6 +1363,7 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Create group" xml:space="preserve">
<source>Create group</source>
<target>Gruppe erstellen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create group link" xml:space="preserve">
@@ -1333,6 +1388,7 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Create profile" xml:space="preserve">
<source>Create profile</source>
<target>Profil erstellen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create queue" xml:space="preserve">
@@ -1495,6 +1551,7 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Delete %lld messages?" xml:space="preserve">
<source>Delete %lld messages?</source>
<target>%lld Nachrichten löschen?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete Contact" xml:space="preserve">
@@ -1524,6 +1581,7 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Delete and notify contact" xml:space="preserve">
<source>Delete and notify contact</source>
<target>Kontakt löschen und benachrichtigen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete archive" xml:space="preserve">
@@ -1559,6 +1617,8 @@ This is your own one-time link!</source>
<trans-unit id="Delete contact?&#10;This cannot be undone!" xml:space="preserve">
<source>Delete contact?
This cannot be undone!</source>
<target>Kontakt löschen?
Das kann nicht rückgängig gemacht werden!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete database" xml:space="preserve">
@@ -1701,6 +1761,18 @@ This cannot be undone!</source>
<target>Beschreibung</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop address" xml:space="preserve">
<source>Desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop app version %@ is not compatible with this app." xml:space="preserve">
<source>Desktop app version %@ is not compatible with this app.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop devices" xml:space="preserve">
<source>Desktop devices</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Develop" xml:space="preserve">
<source>Develop</source>
<target>Entwicklung</target>
@@ -1791,11 +1863,19 @@ This cannot be undone!</source>
<target>Trennen</target>
<note>server test step</note>
</trans-unit>
<trans-unit id="Disconnect desktop?" xml:space="preserve">
<source>Disconnect desktop?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Discover and join groups" xml:space="preserve">
<source>Discover and join groups</source>
<target>Gruppen entdecken und ihnen beitreten</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Discover on network" xml:space="preserve">
<source>Discover on network</source>
<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>
@@ -1966,6 +2046,14 @@ This cannot be undone!</source>
<target>Verschlüsselte Nachricht: Unerwarteter Fehler</target>
<note>notification</note>
</trans-unit>
<trans-unit id="Encryption re-negotiation error" xml:space="preserve">
<source>Encryption re-negotiation error</source>
<note>message decrypt error item</note>
</trans-unit>
<trans-unit id="Encryption re-negotiation failed." xml:space="preserve">
<source>Encryption re-negotiation failed.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter Passcode" xml:space="preserve">
<source>Enter Passcode</source>
<target>Zugangscode eingeben</target>
@@ -1978,6 +2066,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Enter group name…" xml:space="preserve">
<source>Enter group name…</source>
<target>Geben Sie den Gruppennamen ein…</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter passphrase…" xml:space="preserve">
@@ -1995,6 +2084,10 @@ This cannot be undone!</source>
<target>Geben Sie den Server manuell ein</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter this device name…" xml:space="preserve">
<source>Enter this device name…</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter welcome message…" xml:space="preserve">
<source>Enter welcome message…</source>
<target>Geben Sie eine Begrüßungsmeldung ein …</target>
@@ -2007,6 +2100,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Enter your name…" xml:space="preserve">
<source>Enter your name…</source>
<target>Geben Sie Ihren Namen ein…</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error" xml:space="preserve">
@@ -2286,6 +2380,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Expand" xml:space="preserve">
<source>Expand</source>
<target>Erweitern</target>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Export database" xml:space="preserve">
@@ -2435,6 +2530,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Fully decentralized visible only to members." xml:space="preserve">
<source>Fully decentralized visible only to members.</source>
<target>Vollständig dezentralisiert nur für Mitglieder sichtbar.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Fully re-implemented - work in background!" xml:space="preserve">
@@ -2459,10 +2555,12 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Group already exists" xml:space="preserve">
<source>Group already exists</source>
<target>Die Gruppe besteht bereits</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group already exists!" xml:space="preserve">
<source>Group already exists!</source>
<target>Die Gruppe besteht bereits!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group display name" xml:space="preserve">
@@ -2765,6 +2863,10 @@ This cannot be undone!</source>
<target>Inkompatible Datenbank-Version</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Incompatible version" xml:space="preserve">
<source>Incompatible version</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Incorrect passcode" xml:space="preserve">
<source>Incorrect passcode</source>
<target>Zugangscode ist falsch</target>
@@ -2814,6 +2916,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Invalid name!" xml:space="preserve">
<source>Invalid name!</source>
<target>Ungültiger Name!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Invalid server address!" xml:space="preserve">
@@ -2884,7 +2987,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="It seems like you are already connected via this link. If it is not the case, there was an error (%@)." xml:space="preserve">
<source>It seems like you are already connected via this link. If it is not the case, there was an error (%@).</source>
<target>Es sieht so aus, dass Sie bereits über diesen Link verbunden sind. Wenn das nicht der Fall, gab es einen Fehler (%@).</target>
<target>Es sieht so aus, als ob Sie bereits über diesen Link verbunden sind. Wenn das nicht der Fall ist, gab es einen Fehler (%@).</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Italian interface" xml:space="preserve">
@@ -2909,6 +3012,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Join group?" xml:space="preserve">
<source>Join group?</source>
<target>Der Gruppe beitreten?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Join incognito" xml:space="preserve">
@@ -2918,11 +3022,14 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Join with current profile" xml:space="preserve">
<source>Join with current profile</source>
<target>Mit dem aktuellen Profil beitreten</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Join your group?&#10;This is your link for group %@!" xml:space="preserve">
<source>Join your group?
This is your link for group %@!</source>
<target>Ihrer Gruppe beitreten?
Das ist Ihr Link für die Gruppe %@!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Joining group" xml:space="preserve">
@@ -2930,6 +3037,10 @@ This is your link for group %@!</source>
<target>Der Gruppe beitreten</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Keep the app open to use it from desktop" xml:space="preserve">
<source>Keep the app open to use it from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Keep your connections" xml:space="preserve">
<source>Keep your connections</source>
<target>Ihre Verbindungen beibehalten</target>
@@ -2990,6 +3101,14 @@ This is your link for group %@!</source>
<target>Einschränkungen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Linked desktop options" xml:space="preserve">
<source>Linked desktop options</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Linked desktops" xml:space="preserve">
<source>Linked desktops</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Live message!" xml:space="preserve">
<source>Live message!</source>
<target>Live Nachricht!</target>
@@ -3142,6 +3261,7 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Messages from %@ will be shown!" xml:space="preserve">
<source>Messages from %@ will be shown!</source>
<target>Die Nachrichten von %@ werden angezeigt!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Migrating database archive…" xml:space="preserve">
@@ -3495,6 +3615,7 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Open group" xml:space="preserve">
<source>Open group</source>
<target>Gruppe öffnen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Open user profiles" xml:space="preserve">
@@ -3557,6 +3678,10 @@ This is your link for group %@!</source>
<target>Einfügen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Paste desktop address" xml:space="preserve">
<source>Paste desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Paste image" xml:space="preserve">
<source>Paste image</source>
<target>Bild einfügen</target>
@@ -3704,10 +3829,12 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Profile name" xml:space="preserve">
<source>Profile name</source>
<target>Profilname</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile name:" xml:space="preserve">
<source>Profile name:</source>
<target>Profilname:</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile password" xml:space="preserve">
@@ -3957,10 +4084,12 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Repeat connection request?" xml:space="preserve">
<source>Repeat connection request?</source>
<target>Verbindungsanfrage wiederholen?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Repeat join request?" xml:space="preserve">
<source>Repeat join request?</source>
<target>Verbindungsanfrage wiederholen?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Reply" xml:space="preserve">
@@ -4148,6 +4277,10 @@ This is your link for group %@!</source>
<target>QR-Code scannen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scan QR code from desktop" xml:space="preserve">
<source>Scan QR code from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scan code" xml:space="preserve">
<source>Scan code</source>
<target>Code scannen</target>
@@ -4368,6 +4501,10 @@ This is your link for group %@!</source>
<target>Server</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Session code" xml:space="preserve">
<source>Session code</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set 1 day" xml:space="preserve">
<source>Set 1 day</source>
<target>Einen Tag festlegen</target>
@@ -4680,6 +4817,7 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Tap to Connect" xml:space="preserve">
<source>Tap to Connect</source>
<target>Zum Verbinden antippen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Tap to activate profile." xml:space="preserve">
@@ -4864,6 +5002,10 @@ Dies kann passieren, wenn es einen Fehler gegeben hat oder die Verbindung kompro
<target>Diese Aktion kann nicht rückgängig gemacht werden! Ihr Profil und Ihre Kontakte, Nachrichten und Dateien gehen unwiderruflich verloren.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This device name" xml:space="preserve">
<source>This device name</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This group has over %lld members, delivery receipts are not sent." xml:space="preserve">
<source>This group has over %lld members, delivery receipts are not sent.</source>
<target>Es werden keine Empfangsbestätigungen gesendet, da diese Gruppe über %lld Mitglieder hat.</target>
@@ -4876,10 +5018,12 @@ Dies kann passieren, wenn es einen Fehler gegeben hat oder die Verbindung kompro
</trans-unit>
<trans-unit id="This is your own SimpleX address!" xml:space="preserve">
<source>This is your own SimpleX address!</source>
<target>Das ist Ihre eigene SimpleX-Adresse!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This is your own one-time link!" xml:space="preserve">
<source>This is your own one-time link!</source>
<target>Das ist Ihr eigener Einmal-Link!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This setting applies to messages in your current chat profile **%@**." xml:space="preserve">
@@ -4926,7 +5070,7 @@ Sie werden aufgefordert, die Authentifizierung abzuschließen, bevor diese Funkt
</trans-unit>
<trans-unit id="To reveal your hidden profile, enter a full password into a search field in **Your chat profiles** page." xml:space="preserve">
<source>To reveal your hidden profile, enter a full password into a search field in **Your chat profiles** page.</source>
<target>Geben Sie ein vollständiges Passwort in das Suchfeld auf der Seite **Meine Chat-Profile** ein, um Ihr verborgenes Profil zu sehen.</target>
<target>Geben Sie ein vollständiges Passwort in das Suchfeld auf der Seite **Ihre Chat-Profile** ein, um Ihr verborgenes Profil zu sehen.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To support instant push notifications the chat database has to be migrated." xml:space="preserve">
@@ -4981,14 +5125,17 @@ Sie werden aufgefordert, die Authentifizierung abzuschließen, bevor diese Funkt
</trans-unit>
<trans-unit id="Unblock" xml:space="preserve">
<source>Unblock</source>
<target>Freigeben</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unblock member" xml:space="preserve">
<source>Unblock member</source>
<target>Mitglied freigeben</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unblock member?" xml:space="preserve">
<source>Unblock member?</source>
<target>Mitglied freigeben?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unexpected error: %@" xml:space="preserve">
@@ -5053,6 +5200,14 @@ To connect, please ask your contact to create another connection link and check
Bitten Sie Ihren Kontakt darum einen weiteren Verbindungs-Link zu erzeugen, um sich neu verbinden zu können und stellen Sie sicher, dass Sie eine stabile Netzwerk-Verbindung haben.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlink" xml:space="preserve">
<source>Unlink</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlink desktop?" xml:space="preserve">
<source>Unlink desktop?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlock" xml:space="preserve">
<source>Unlock</source>
<target>Entsperren</target>
@@ -5143,6 +5298,10 @@ Bitten Sie Ihren Kontakt darum einen weiteren Verbindungs-Link zu erzeugen, um s
<target>Für neue Verbindungen nutzen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use from desktop" xml:space="preserve">
<source>Use from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use iOS call interface" xml:space="preserve">
<source>Use iOS call interface</source>
<target>iOS Anrufschnittstelle nutzen</target>
@@ -5173,11 +5332,23 @@ Bitten Sie Ihren Kontakt darum einen weiteren Verbindungs-Link zu erzeugen, um s
<target>Verwendung von SimpleX-Chat-Servern.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify code with desktop" xml:space="preserve">
<source>Verify code with desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connection" xml:space="preserve">
<source>Verify connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connection security" xml:space="preserve">
<source>Verify connection security</source>
<target>Sicherheit der Verbindung überprüfen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connections" xml:space="preserve">
<source>Verify connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify security code" xml:space="preserve">
<source>Verify security code</source>
<target>Sicherheitscode überprüfen</target>
@@ -5315,7 +5486,7 @@ Bitten Sie Ihren Kontakt darum einen weiteren Verbindungs-Link zu erzeugen, um s
</trans-unit>
<trans-unit id="You" xml:space="preserve">
<source>You</source>
<target>Meine Daten</target>
<target>Ihre Daten</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You accepted connection" xml:space="preserve">
@@ -5340,31 +5511,39 @@ Bitten Sie Ihren Kontakt darum einen weiteren Verbindungs-Link zu erzeugen, um s
</trans-unit>
<trans-unit id="You are already connecting to %@." xml:space="preserve">
<source>You are already connecting to %@.</source>
<target>Sie sind bereits mit %@ verbunden.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You are already connecting via this one-time link!" xml:space="preserve">
<source>You are already connecting via this one-time link!</source>
<target>Sie sind bereits über diesen Einmal-Link verbunden!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You are already in group %@." xml:space="preserve">
<source>You are already in group %@.</source>
<target>Sie sind bereits Mitglied der Gruppe %@.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You are already joining the group %@." xml:space="preserve">
<source>You are already joining the group %@.</source>
<target>Sie sind bereits Mitglied der Gruppe %@.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You are already joining the group via this link!" xml:space="preserve">
<source>You are already joining the group via this link!</source>
<target>Sie sind über diesen Link bereits Mitglied der Gruppe!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You are already joining the group via this link." xml:space="preserve">
<source>You are already joining the group via this link.</source>
<target>Sie sind über diesen Link bereits Mitglied der Gruppe.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You are already joining the group!&#10;Repeat join request?" xml:space="preserve">
<source>You are already joining the group!
Repeat join request?</source>
<target>Sie sind bereits Mitglied dieser Gruppe!
Verbindungsanfrage wiederholen?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You are connected to the server used to receive messages from this contact." xml:space="preserve">
@@ -5464,11 +5643,14 @@ Repeat join request?</source>
</trans-unit>
<trans-unit id="You have already requested connection via this address!" xml:space="preserve">
<source>You have already requested connection via this address!</source>
<target>Sie haben über diese Adresse bereits eine Verbindung beantragt!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You have already requested connection!&#10;Repeat connection request?" xml:space="preserve">
<source>You have already requested connection!
Repeat connection request?</source>
<target>Sie haben bereits ein Verbindungsanfrage beantragt!
Verbindungsanfrage wiederholen?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You have no chats" xml:space="preserve">
@@ -5523,6 +5705,7 @@ Repeat connection request?</source>
</trans-unit>
<trans-unit id="You will be connected when group link host's device is online, please wait or check later!" xml:space="preserve">
<source>You will be connected when group link host's device is online, please wait or check later!</source>
<target>Sie werden verbunden, sobald das Endgerät des Gruppenlink-Hosts online ist. Bitte warten oder schauen Sie später nochmal nach!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You will be connected when your connection request is accepted, please wait or check later!" xml:space="preserve">
@@ -5542,6 +5725,7 @@ Repeat connection request?</source>
</trans-unit>
<trans-unit id="You will connect to all group members." xml:space="preserve">
<source>You will connect to all group members.</source>
<target>Sie werden mit allen Gruppenmitgliedern verbunden.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You will still receive calls and notifications from muted profiles when they are active." xml:space="preserve">
@@ -5586,7 +5770,7 @@ Repeat connection request?</source>
</trans-unit>
<trans-unit id="Your SimpleX address" xml:space="preserve">
<source>Your SimpleX address</source>
<target>Meine SimpleX-Adresse</target>
<target>Ihre SimpleX-Adresse</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your XFTP servers" xml:space="preserve">
@@ -5611,7 +5795,7 @@ Repeat connection request?</source>
</trans-unit>
<trans-unit id="Your chat profiles" xml:space="preserve">
<source>Your chat profiles</source>
<target>Meine Chat-Profile</target>
<target>Ihre Chat-Profile</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your contact needs to be online for the connection to complete.&#10;You can cancel this connection and remove the contact (and try later with a new link)." xml:space="preserve">
@@ -5655,16 +5839,17 @@ Sie können es in den Einstellungen ändern.</target>
</trans-unit>
<trans-unit id="Your preferences" xml:space="preserve">
<source>Your preferences</source>
<target>Meine Präferenzen</target>
<target>Ihre Präferenzen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your privacy" xml:space="preserve">
<source>Your privacy</source>
<target>Meine Privatsphäre</target>
<target>Ihre Privatsphäre</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your profile" xml:space="preserve">
<source>Your profile</source>
<target>Mein Profil</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your profile **%@** will be shared." xml:space="preserve">
@@ -5701,7 +5886,7 @@ SimpleX-Server können Ihr Profil nicht einsehen.</target>
</trans-unit>
<trans-unit id="Your settings" xml:space="preserve">
<source>Your settings</source>
<target>Meine Einstellungen</target>
<target>Ihre Einstellungen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="[Contribute](https://github.com/simplex-chat/simplex-chat#contribute)" xml:space="preserve">
@@ -5761,6 +5946,7 @@ SimpleX-Server können Ihr Profil nicht einsehen.</target>
</trans-unit>
<trans-unit id="and %lld other events" xml:space="preserve">
<source>and %lld other events</source>
<target>und %lld weitere Ereignisse</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="audio call (not e2e encrypted)" xml:space="preserve">
@@ -5780,6 +5966,7 @@ SimpleX-Server können Ihr Profil nicht einsehen.</target>
</trans-unit>
<trans-unit id="blocked" xml:space="preserve">
<source>blocked</source>
<target>blockiert</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="bold" xml:space="preserve">
@@ -5954,6 +6141,7 @@ SimpleX-Server können Ihr Profil nicht einsehen.</target>
</trans-unit>
<trans-unit id="deleted contact" xml:space="preserve">
<source>deleted contact</source>
<target>Gelöschter Kontakt</target>
<note>rcv direct event chat item</note>
</trans-unit>
<trans-unit id="deleted group" xml:space="preserve">
@@ -6348,6 +6536,10 @@ SimpleX-Server können Ihr Profil nicht einsehen.</target>
<target>Aktualisiertes Gruppenprofil</target>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="v%@" xml:space="preserve">
<source>v%@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="v%@ (%@)" xml:space="preserve">
<source>v%@ (%@)</source>
<target>v%@ (%@)</target>
@@ -6485,6 +6677,10 @@ SimpleX-Server können Ihr Profil nicht einsehen.</target>
<target>Face ID wird von SimpleX für die lokale Authentifizierung genutzt</target>
<note>Privacy - Face ID Usage Description</note>
</trans-unit>
<trans-unit id="NSLocalNetworkUsageDescription" xml:space="preserve">
<source>SimpleX uses local network access to allow using user chat profile via desktop app on the same network.</source>
<note>Privacy - Local Network Usage Description</note>
</trans-unit>
<trans-unit id="NSMicrophoneUsageDescription" xml:space="preserve">
<source>SimpleX needs microphone access for audio and video calls, and to record voice messages.</source>
<target>SimpleX benötigt Zugriff auf das Mikrofon, um Audio- und Videoanrufe und die Aufnahme von Sprachnachrichten zu ermöglichen.</target>
@@ -4,6 +4,8 @@
"NSCameraUsageDescription" = "SimpleX needs camera access to scan QR codes to connect to other users and for video calls.";
/* Privacy - Face ID Usage Description */
"NSFaceIDUsageDescription" = "SimpleX uses Face ID for local authentication";
/* Privacy - Local Network Usage Description */
"NSLocalNetworkUsageDescription" = "SimpleX uses local network access to allow using user chat profile via desktop app on the same network.";
/* Privacy - Microphone Usage Description */
"NSMicrophoneUsageDescription" = "SimpleX needs microphone access for audio and video calls, and to record voice messages.";
/* Privacy - Photo Library Additions Usage Description */
@@ -297,6 +297,16 @@
<target>(</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(new)" xml:space="preserve">
<source>(new)</source>
<target>(new)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(this device v%@)" xml:space="preserve">
<source>(this device v%@)</source>
<target>(this device v%@)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=")" xml:space="preserve">
<source>)</source>
<target>)</target>
@@ -869,6 +879,11 @@
<target>Back</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Bad desktop address" xml:space="preserve">
<source>Bad desktop address</source>
<target>Bad desktop address</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Bad message ID" xml:space="preserve">
<source>Bad message ID</source>
<target>Bad message ID</target>
@@ -1165,6 +1180,11 @@
<target>Connect incognito</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to desktop" xml:space="preserve">
<source>Connect to desktop</source>
<target>Connect to desktop</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to yourself?" xml:space="preserve">
<source>Connect to yourself?</source>
<target>Connect to yourself?</target>
@@ -1209,6 +1229,16 @@ This is your own one-time link!</target>
<target>Connect with %@</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connected desktop" xml:space="preserve">
<source>Connected desktop</source>
<target>Connected desktop</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connected to desktop" xml:space="preserve">
<source>Connected to desktop</source>
<target>Connected to desktop</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connecting server…" xml:space="preserve">
<source>Connecting to server…</source>
<target>Connecting to server…</target>
@@ -1219,6 +1249,11 @@ This is your own one-time link!</target>
<target>Connecting to server… (error: %@)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connecting to desktop" xml:space="preserve">
<source>Connecting to desktop</source>
<target>Connecting to desktop</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection" xml:space="preserve">
<source>Connection</source>
<target>Connection</target>
@@ -1239,6 +1274,11 @@ This is your own one-time link!</target>
<target>Connection request sent!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection terminated" xml:space="preserve">
<source>Connection terminated</source>
<target>Connection terminated</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection timeout" xml:space="preserve">
<source>Connection timeout</source>
<target>Connection timeout</target>
@@ -1729,6 +1769,21 @@ This cannot be undone!</target>
<target>Description</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop address" xml:space="preserve">
<source>Desktop address</source>
<target>Desktop address</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop app version %@ is not compatible with this app." xml:space="preserve">
<source>Desktop app version %@ is not compatible with this app.</source>
<target>Desktop app version %@ is not compatible with this app.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop devices" xml:space="preserve">
<source>Desktop devices</source>
<target>Desktop devices</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Develop" xml:space="preserve">
<source>Develop</source>
<target>Develop</target>
@@ -1819,11 +1874,21 @@ This cannot be undone!</target>
<target>Disconnect</target>
<note>server test step</note>
</trans-unit>
<trans-unit id="Disconnect desktop?" xml:space="preserve">
<source>Disconnect desktop?</source>
<target>Disconnect desktop?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Discover and join groups" xml:space="preserve">
<source>Discover and join groups</source>
<target>Discover and join groups</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Discover on network" xml:space="preserve">
<source>Discover on network</source>
<target>Discover on network</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>Do NOT use SimpleX for emergency calls.</target>
@@ -1994,6 +2059,16 @@ This cannot be undone!</target>
<target>Encrypted message: unexpected error</target>
<note>notification</note>
</trans-unit>
<trans-unit id="Encryption re-negotiation error" xml:space="preserve">
<source>Encryption re-negotiation error</source>
<target>Encryption re-negotiation error</target>
<note>message decrypt error item</note>
</trans-unit>
<trans-unit id="Encryption re-negotiation failed." xml:space="preserve">
<source>Encryption re-negotiation failed.</source>
<target>Encryption re-negotiation failed.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter Passcode" xml:space="preserve">
<source>Enter Passcode</source>
<target>Enter Passcode</target>
@@ -2024,6 +2099,11 @@ This cannot be undone!</target>
<target>Enter server manually</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter this device name…" xml:space="preserve">
<source>Enter this device name…</source>
<target>Enter this device name…</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter welcome message…" xml:space="preserve">
<source>Enter welcome message…</source>
<target>Enter welcome message…</target>
@@ -2799,6 +2879,11 @@ This cannot be undone!</target>
<target>Incompatible database version</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Incompatible version" xml:space="preserve">
<source>Incompatible version</source>
<target>Incompatible version</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Incorrect passcode" xml:space="preserve">
<source>Incorrect passcode</source>
<target>Incorrect passcode</target>
@@ -2969,6 +3054,11 @@ This is your link for group %@!</target>
<target>Joining group</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Keep the app open to use it from desktop" xml:space="preserve">
<source>Keep the app open to use it from desktop</source>
<target>Keep the app open to use it from desktop</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Keep your connections" xml:space="preserve">
<source>Keep your connections</source>
<target>Keep your connections</target>
@@ -3029,6 +3119,16 @@ This is your link for group %@!</target>
<target>Limitations</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Linked desktop options" xml:space="preserve">
<source>Linked desktop options</source>
<target>Linked desktop options</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Linked desktops" xml:space="preserve">
<source>Linked desktops</source>
<target>Linked desktops</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Live message!" xml:space="preserve">
<source>Live message!</source>
<target>Live message!</target>
@@ -3598,6 +3698,11 @@ This is your link for group %@!</target>
<target>Paste</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Paste desktop address" xml:space="preserve">
<source>Paste desktop address</source>
<target>Paste desktop address</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Paste image" xml:space="preserve">
<source>Paste image</source>
<target>Paste image</target>
@@ -4193,6 +4298,11 @@ This is your link for group %@!</target>
<target>Scan QR code</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scan QR code from desktop" xml:space="preserve">
<source>Scan QR code from desktop</source>
<target>Scan QR code from desktop</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scan code" xml:space="preserve">
<source>Scan code</source>
<target>Scan code</target>
@@ -4413,6 +4523,11 @@ This is your link for group %@!</target>
<target>Servers</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Session code" xml:space="preserve">
<source>Session code</source>
<target>Session code</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set 1 day" xml:space="preserve">
<source>Set 1 day</source>
<target>Set 1 day</target>
@@ -4910,6 +5025,11 @@ It can happen because of some bug or when the connection is compromised.</target
<target>This action cannot be undone - your profile, contacts, messages and files will be irreversibly lost.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This device name" xml:space="preserve">
<source>This device name</source>
<target>This device name</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This group has over %lld members, delivery receipts are not sent." xml:space="preserve">
<source>This group has over %lld members, delivery receipts are not sent.</source>
<target>This group has over %lld members, delivery receipts are not sent.</target>
@@ -5104,6 +5224,16 @@ To connect, please ask your contact to create another connection link and check
To connect, please ask your contact to create another connection link and check that you have a stable network connection.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlink" xml:space="preserve">
<source>Unlink</source>
<target>Unlink</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlink desktop?" xml:space="preserve">
<source>Unlink desktop?</source>
<target>Unlink desktop?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlock" xml:space="preserve">
<source>Unlock</source>
<target>Unlock</target>
@@ -5194,6 +5324,11 @@ To connect, please ask your contact to create another connection link and check
<target>Use for new connections</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use from desktop" xml:space="preserve">
<source>Use from desktop</source>
<target>Use from desktop</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use iOS call interface" xml:space="preserve">
<source>Use iOS call interface</source>
<target>Use iOS call interface</target>
@@ -5224,11 +5359,26 @@ To connect, please ask your contact to create another connection link and check
<target>Using SimpleX Chat servers.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify code with desktop" xml:space="preserve">
<source>Verify code with desktop</source>
<target>Verify code with desktop</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connection" xml:space="preserve">
<source>Verify connection</source>
<target>Verify connection</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connection security" xml:space="preserve">
<source>Verify connection security</source>
<target>Verify connection security</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connections" xml:space="preserve">
<source>Verify connections</source>
<target>Verify connections</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify security code" xml:space="preserve">
<source>Verify security code</source>
<target>Verify security code</target>
@@ -6416,6 +6566,11 @@ SimpleX servers cannot see your profile.</target>
<target>updated group profile</target>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="v%@" xml:space="preserve">
<source>v%@</source>
<target>v%@</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="v%@ (%@)" xml:space="preserve">
<source>v%@ (%@)</source>
<target>v%@ (%@)</target>
@@ -6553,6 +6708,11 @@ SimpleX servers cannot see your profile.</target>
<target>SimpleX uses Face ID for local authentication</target>
<note>Privacy - Face ID Usage Description</note>
</trans-unit>
<trans-unit id="NSLocalNetworkUsageDescription" xml:space="preserve">
<source>SimpleX uses local network access to allow using user chat profile via desktop app on the same network.</source>
<target>SimpleX uses local network access to allow using user chat profile via desktop app on the same network.</target>
<note>Privacy - Local Network Usage Description</note>
</trans-unit>
<trans-unit id="NSMicrophoneUsageDescription" xml:space="preserve">
<source>SimpleX needs microphone access for audio and video calls, and to record voice messages.</source>
<target>SimpleX needs microphone access for audio and video calls, and to record voice messages.</target>
@@ -4,6 +4,8 @@
"NSCameraUsageDescription" = "SimpleX needs camera access to scan QR codes to connect to other users and for video calls.";
/* Privacy - Face ID Usage Description */
"NSFaceIDUsageDescription" = "SimpleX uses Face ID for local authentication";
/* Privacy - Local Network Usage Description */
"NSLocalNetworkUsageDescription" = "SimpleX uses local network access to allow using user chat profile via desktop app on the same network.";
/* Privacy - Microphone Usage Description */
"NSMicrophoneUsageDescription" = "SimpleX needs microphone access for audio and video calls, and to record voice messages.";
/* Privacy - Photo Library Additions Usage Description */
@@ -290,6 +290,14 @@
<target>(</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(new)" xml:space="preserve">
<source>(new)</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(this device v%@)" xml:space="preserve">
<source>(this device v%@)</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=")" xml:space="preserve">
<source>)</source>
<target>)</target>
@@ -858,6 +866,10 @@
<target>Volver</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Bad desktop address" xml:space="preserve">
<source>Bad desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Bad message ID" xml:space="preserve">
<source>Bad message ID</source>
<target>ID de mensaje incorrecto</target>
@@ -1151,6 +1163,10 @@
<target>Conectar incognito</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to desktop" xml:space="preserve">
<source>Connect to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to yourself?" xml:space="preserve">
<source>Connect to yourself?</source>
<note>No comment provided by engineer.</note>
@@ -1188,6 +1204,14 @@ This is your own one-time link!</source>
<source>Connect with %@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connected desktop" xml:space="preserve">
<source>Connected desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connected to desktop" xml:space="preserve">
<source>Connected to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connecting server…" xml:space="preserve">
<source>Connecting to server…</source>
<target>Conectando con el servidor…</target>
@@ -1198,6 +1222,10 @@ This is your own one-time link!</source>
<target>Conectando con el servidor... (error: %@)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connecting to desktop" xml:space="preserve">
<source>Connecting to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection" xml:space="preserve">
<source>Connection</source>
<target>Conexión</target>
@@ -1218,6 +1246,10 @@ This is your own one-time link!</source>
<target>¡Solicitud de conexión enviada!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection terminated" xml:space="preserve">
<source>Connection terminated</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection timeout" xml:space="preserve">
<source>Connection timeout</source>
<target>Tiempo de conexión expirado</target>
@@ -1701,6 +1733,18 @@ This cannot be undone!</source>
<target>Descripción</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop address" xml:space="preserve">
<source>Desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop app version %@ is not compatible with this app." xml:space="preserve">
<source>Desktop app version %@ is not compatible with this app.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop devices" xml:space="preserve">
<source>Desktop devices</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Develop" xml:space="preserve">
<source>Develop</source>
<target>Desarrollo</target>
@@ -1791,11 +1835,19 @@ This cannot be undone!</source>
<target>Desconectar</target>
<note>server test step</note>
</trans-unit>
<trans-unit id="Disconnect desktop?" xml:space="preserve">
<source>Disconnect desktop?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Discover and join groups" xml:space="preserve">
<source>Discover and join groups</source>
<target>Descubre y únete a grupos</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Discover on network" xml:space="preserve">
<source>Discover on network</source>
<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>NO uses SimpleX para llamadas de emergencia.</target>
@@ -1966,6 +2018,14 @@ This cannot be undone!</source>
<target>Mensaje cifrado: error inesperado</target>
<note>notification</note>
</trans-unit>
<trans-unit id="Encryption re-negotiation error" xml:space="preserve">
<source>Encryption re-negotiation error</source>
<note>message decrypt error item</note>
</trans-unit>
<trans-unit id="Encryption re-negotiation failed." xml:space="preserve">
<source>Encryption re-negotiation failed.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter Passcode" xml:space="preserve">
<source>Enter Passcode</source>
<target>Introduce Código</target>
@@ -1995,6 +2055,10 @@ This cannot be undone!</source>
<target>Introduce el servidor manualmente</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter this device name…" xml:space="preserve">
<source>Enter this device name…</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter welcome message…" xml:space="preserve">
<source>Enter welcome message…</source>
<target>Introduce mensaje de bienvenida…</target>
@@ -2765,6 +2829,10 @@ This cannot be undone!</source>
<target>Versión de base de datos incompatible</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Incompatible version" xml:space="preserve">
<source>Incompatible version</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Incorrect passcode" xml:space="preserve">
<source>Incorrect passcode</source>
<target>Código de acceso incorrecto</target>
@@ -2930,6 +2998,10 @@ This is your link for group %@!</source>
<target>Entrando al grupo</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Keep the app open to use it from desktop" xml:space="preserve">
<source>Keep the app open to use it from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Keep your connections" xml:space="preserve">
<source>Keep your connections</source>
<target>Conserva tus conexiones</target>
@@ -2990,6 +3062,14 @@ This is your link for group %@!</source>
<target>Limitaciones</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Linked desktop options" xml:space="preserve">
<source>Linked desktop options</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Linked desktops" xml:space="preserve">
<source>Linked desktops</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Live message!" xml:space="preserve">
<source>Live message!</source>
<target>¡Mensaje en vivo!</target>
@@ -3557,6 +3637,10 @@ This is your link for group %@!</source>
<target>Pegar</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Paste desktop address" xml:space="preserve">
<source>Paste desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Paste image" xml:space="preserve">
<source>Paste image</source>
<target>Pegar imagen</target>
@@ -4148,6 +4232,10 @@ This is your link for group %@!</source>
<target>Escanear código QR</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scan QR code from desktop" xml:space="preserve">
<source>Scan QR code from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scan code" xml:space="preserve">
<source>Scan code</source>
<target>Escanear código</target>
@@ -4368,6 +4456,10 @@ This is your link for group %@!</source>
<target>Servidores</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Session code" xml:space="preserve">
<source>Session code</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set 1 day" xml:space="preserve">
<source>Set 1 day</source>
<target>Establecer 1 día</target>
@@ -4864,6 +4956,10 @@ Puede ocurrir por algún bug o cuando la conexión está comprometida.</target>
<target>Esta acción no se puede deshacer. Tu perfil, contactos, mensajes y archivos se perderán irreversiblemente.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This device name" xml:space="preserve">
<source>This device name</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This group has over %lld members, delivery receipts are not sent." xml:space="preserve">
<source>This group has over %lld members, delivery receipts are not sent.</source>
<target>Este grupo tiene más de %lld miembros, no se enviarán confirmaciones de entrega.</target>
@@ -5054,6 +5150,14 @@ que este enlace ya se haya usado, podría ser un error. Por favor, notifícalo.
Para conectarte, pide a tu contacto que cree otro enlace de conexión y comprueba que tienes buena conexión de red.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlink" xml:space="preserve">
<source>Unlink</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlink desktop?" xml:space="preserve">
<source>Unlink desktop?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlock" xml:space="preserve">
<source>Unlock</source>
<target>Desbloquear</target>
@@ -5144,6 +5248,10 @@ Para conectarte, pide a tu contacto que cree otro enlace de conexión y comprueb
<target>Usar para conexiones nuevas</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use from desktop" xml:space="preserve">
<source>Use from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use iOS call interface" xml:space="preserve">
<source>Use iOS call interface</source>
<target>Usar interfaz de llamada de iOS</target>
@@ -5174,11 +5282,23 @@ Para conectarte, pide a tu contacto que cree otro enlace de conexión y comprueb
<target>Usar servidores SimpleX Chat.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify code with desktop" xml:space="preserve">
<source>Verify code with desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connection" xml:space="preserve">
<source>Verify connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connection security" xml:space="preserve">
<source>Verify connection security</source>
<target>Comprobar la seguridad de la conexión</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connections" xml:space="preserve">
<source>Verify connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify security code" xml:space="preserve">
<source>Verify security code</source>
<target>Comprobar código de seguridad</target>
@@ -6349,6 +6469,10 @@ Los servidores de SimpleX no pueden ver tu perfil.</target>
<target>ha actualizado el perfil del grupo</target>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="v%@" xml:space="preserve">
<source>v%@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="v%@ (%@)" xml:space="preserve">
<source>v%@ (%@)</source>
<target>v%@ (%@)</target>
@@ -6486,6 +6610,10 @@ Los servidores de SimpleX no pueden ver tu perfil.</target>
<target>SimpleX usa reconocimiento facial para la autenticación local</target>
<note>Privacy - Face ID Usage Description</note>
</trans-unit>
<trans-unit id="NSLocalNetworkUsageDescription" xml:space="preserve">
<source>SimpleX uses local network access to allow using user chat profile via desktop app on the same network.</source>
<note>Privacy - Local Network Usage Description</note>
</trans-unit>
<trans-unit id="NSMicrophoneUsageDescription" xml:space="preserve">
<source>SimpleX needs microphone access for audio and video calls, and to record voice messages.</source>
<target>SimpleX necesita acceso al micrófono para las llamadas de audio, vídeo y para grabar mensajes de voz.</target>
@@ -4,6 +4,8 @@
"NSCameraUsageDescription" = "SimpleX needs camera access to scan QR codes to connect to other users and for video calls.";
/* Privacy - Face ID Usage Description */
"NSFaceIDUsageDescription" = "SimpleX uses Face ID for local authentication";
/* Privacy - Local Network Usage Description */
"NSLocalNetworkUsageDescription" = "SimpleX uses local network access to allow using user chat profile via desktop app on the same network.";
/* Privacy - Microphone Usage Description */
"NSMicrophoneUsageDescription" = "SimpleX needs microphone access for audio and video calls, and to record voice messages.";
/* Privacy - Photo Library Additions Usage Description */
@@ -290,6 +290,14 @@
<target>(</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(new)" xml:space="preserve">
<source>(new)</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(this device v%@)" xml:space="preserve">
<source>(this device v%@)</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=")" xml:space="preserve">
<source>)</source>
<target>)</target>
@@ -854,6 +862,10 @@
<target>Takaisin</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Bad desktop address" xml:space="preserve">
<source>Bad desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Bad message ID" xml:space="preserve">
<source>Bad message ID</source>
<target>Virheellinen viestin tunniste</target>
@@ -1146,6 +1158,10 @@
<target>Yhdistä Incognito</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to desktop" xml:space="preserve">
<source>Connect to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to yourself?" xml:space="preserve">
<source>Connect to yourself?</source>
<note>No comment provided by engineer.</note>
@@ -1183,6 +1199,14 @@ This is your own one-time link!</source>
<source>Connect with %@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connected desktop" xml:space="preserve">
<source>Connected desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connected to desktop" xml:space="preserve">
<source>Connected to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connecting server…" xml:space="preserve">
<source>Connecting to server…</source>
<target>Yhteyden muodostaminen palvelimeen…</target>
@@ -1193,6 +1217,10 @@ This is your own one-time link!</source>
<target>Yhteyden muodostaminen palvelimeen... (virhe: %@)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connecting to desktop" xml:space="preserve">
<source>Connecting to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection" xml:space="preserve">
<source>Connection</source>
<target>Yhteys</target>
@@ -1213,6 +1241,10 @@ This is your own one-time link!</source>
<target>Yhteyspyyntö lähetetty!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection terminated" xml:space="preserve">
<source>Connection terminated</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection timeout" xml:space="preserve">
<source>Connection timeout</source>
<target>Yhteyden aikakatkaisu</target>
@@ -1696,6 +1728,18 @@ This cannot be undone!</source>
<target>Kuvaus</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop address" xml:space="preserve">
<source>Desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop app version %@ is not compatible with this app." xml:space="preserve">
<source>Desktop app version %@ is not compatible with this app.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop devices" xml:space="preserve">
<source>Desktop devices</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Develop" xml:space="preserve">
<source>Develop</source>
<target>Kehitä</target>
@@ -1786,11 +1830,19 @@ This cannot be undone!</source>
<target>Katkaise</target>
<note>server test step</note>
</trans-unit>
<trans-unit id="Disconnect desktop?" xml:space="preserve">
<source>Disconnect desktop?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Discover and join groups" xml:space="preserve">
<source>Discover and join groups</source>
<target>Löydä ryhmiä ja liity niihin</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Discover on network" xml:space="preserve">
<source>Discover on network</source>
<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>Älä käytä SimpleX-sovellusta hätäpuheluihin.</target>
@@ -1960,6 +2012,14 @@ This cannot be undone!</source>
<target>Salattu viesti: odottamaton virhe</target>
<note>notification</note>
</trans-unit>
<trans-unit id="Encryption re-negotiation error" xml:space="preserve">
<source>Encryption re-negotiation error</source>
<note>message decrypt error item</note>
</trans-unit>
<trans-unit id="Encryption re-negotiation failed." xml:space="preserve">
<source>Encryption re-negotiation failed.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter Passcode" xml:space="preserve">
<source>Enter Passcode</source>
<target>Syötä pääsykoodi</target>
@@ -1989,6 +2049,10 @@ This cannot be undone!</source>
<target>Syötä palvelin manuaalisesti</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter this device name…" xml:space="preserve">
<source>Enter this device name…</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter welcome message…" xml:space="preserve">
<source>Enter welcome message…</source>
<target>Kirjoita tervetuloviesti…</target>
@@ -2757,6 +2821,10 @@ This cannot be undone!</source>
<target>Yhteensopimaton tietokantaversio</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Incompatible version" xml:space="preserve">
<source>Incompatible version</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Incorrect passcode" xml:space="preserve">
<source>Incorrect passcode</source>
<target>Väärä pääsykoodi</target>
@@ -2922,6 +2990,10 @@ This is your link for group %@!</source>
<target>Liittyy ryhmään</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Keep the app open to use it from desktop" xml:space="preserve">
<source>Keep the app open to use it from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Keep your connections" xml:space="preserve">
<source>Keep your connections</source>
<target>Pidä kontaktisi</target>
@@ -2982,6 +3054,14 @@ This is your link for group %@!</source>
<target>Rajoitukset</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Linked desktop options" xml:space="preserve">
<source>Linked desktop options</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Linked desktops" xml:space="preserve">
<source>Linked desktops</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Live message!" xml:space="preserve">
<source>Live message!</source>
<target>Live-viesti!</target>
@@ -3547,6 +3627,10 @@ This is your link for group %@!</source>
<target>Liitä</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Paste desktop address" xml:space="preserve">
<source>Paste desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Paste image" xml:space="preserve">
<source>Paste image</source>
<target>Liitä kuva</target>
@@ -4138,6 +4222,10 @@ This is your link for group %@!</source>
<target>Skannaa QR-koodi</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scan QR code from desktop" xml:space="preserve">
<source>Scan QR code from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scan code" xml:space="preserve">
<source>Scan code</source>
<target>Skannaa koodi</target>
@@ -4357,6 +4445,10 @@ This is your link for group %@!</source>
<target>Palvelimet</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Session code" xml:space="preserve">
<source>Session code</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set 1 day" xml:space="preserve">
<source>Set 1 day</source>
<target>Aseta 1 päivä</target>
@@ -4852,6 +4944,10 @@ Tämä voi johtua jostain virheestä tai siitä, että yhteys on vaarantunut.</t
<target>Tätä toimintoa ei voi kumota - profiilisi, kontaktisi, viestisi ja tiedostosi poistuvat peruuttamattomasti.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This device name" xml:space="preserve">
<source>This device name</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This group has over %lld members, delivery receipts are not sent." xml:space="preserve">
<source>This group has over %lld members, delivery receipts are not sent.</source>
<target>Tässä ryhmässä on yli %lld jäsentä, lähetyskuittauksia ei lähetetä.</target>
@@ -5040,6 +5136,14 @@ To connect, please ask your contact to create another connection link and check
Jos haluat muodostaa yhteyden, pyydä kontaktiasi luomaan toinen yhteyslinkki ja tarkista, että verkkoyhteytesi on vakaa.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlink" xml:space="preserve">
<source>Unlink</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlink desktop?" xml:space="preserve">
<source>Unlink desktop?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlock" xml:space="preserve">
<source>Unlock</source>
<target>Avaa</target>
@@ -5130,6 +5234,10 @@ Jos haluat muodostaa yhteyden, pyydä kontaktiasi luomaan toinen yhteyslinkki ja
<target>Käytä uusiin yhteyksiin</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use from desktop" xml:space="preserve">
<source>Use from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use iOS call interface" xml:space="preserve">
<source>Use iOS call interface</source>
<target>Käytä iOS:n puhelujen käyttöliittymää</target>
@@ -5160,11 +5268,23 @@ Jos haluat muodostaa yhteyden, pyydä kontaktiasi luomaan toinen yhteyslinkki ja
<target>Käyttää SimpleX Chat -palvelimia.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify code with desktop" xml:space="preserve">
<source>Verify code with desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connection" xml:space="preserve">
<source>Verify connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connection security" xml:space="preserve">
<source>Verify connection security</source>
<target>Tarkista yhteyden suojaus</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connections" xml:space="preserve">
<source>Verify connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify security code" xml:space="preserve">
<source>Verify security code</source>
<target>Tarkista turvakoodi</target>
@@ -6333,6 +6453,10 @@ SimpleX-palvelimet eivät näe profiiliasi.</target>
<target>päivitetty ryhmäprofiili</target>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="v%@" xml:space="preserve">
<source>v%@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="v%@ (%@)" xml:space="preserve">
<source>v%@ (%@)</source>
<target>v%@ (%@)</target>
@@ -6470,6 +6594,10 @@ SimpleX-palvelimet eivät näe profiiliasi.</target>
<target>SimpleX käyttää Face ID:tä paikalliseen todennukseen</target>
<note>Privacy - Face ID Usage Description</note>
</trans-unit>
<trans-unit id="NSLocalNetworkUsageDescription" xml:space="preserve">
<source>SimpleX uses local network access to allow using user chat profile via desktop app on the same network.</source>
<note>Privacy - Local Network Usage Description</note>
</trans-unit>
<trans-unit id="NSMicrophoneUsageDescription" xml:space="preserve">
<source>SimpleX needs microphone access for audio and video calls, and to record voice messages.</source>
<target>SimpleX tarvitsee mikrofonia ääni- ja videopuheluita ja ääniviestien tallentamista varten.</target>
@@ -4,6 +4,8 @@
"NSCameraUsageDescription" = "SimpleX needs camera access to scan QR codes to connect to other users and for video calls.";
/* Privacy - Face ID Usage Description */
"NSFaceIDUsageDescription" = "SimpleX uses Face ID for local authentication";
/* Privacy - Local Network Usage Description */
"NSLocalNetworkUsageDescription" = "SimpleX uses local network access to allow using user chat profile via desktop app on the same network.";
/* Privacy - Microphone Usage Description */
"NSMicrophoneUsageDescription" = "SimpleX needs microphone access for audio and video calls, and to record voice messages.";
/* Privacy - Photo Library Additions Usage Description */
@@ -89,6 +89,7 @@
</trans-unit>
<trans-unit id="%@ and %@" xml:space="preserve">
<source>%@ and %@</source>
<target>%@ et %@</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ and %@ connected" xml:space="preserve">
@@ -103,6 +104,7 @@
</trans-unit>
<trans-unit id="%@ connected" xml:space="preserve">
<source>%@ connected</source>
<target>%@ connecté(e)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ is connected!" xml:space="preserve">
@@ -132,6 +134,7 @@
</trans-unit>
<trans-unit id="%@, %@ and %lld members" xml:space="preserve">
<source>%@, %@ and %lld members</source>
<target>%@, %@ et %lld membres</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@, %@ and %lld other members connected" xml:space="preserve">
@@ -201,6 +204,7 @@
</trans-unit>
<trans-unit id="%lld group events" xml:space="preserve">
<source>%lld group events</source>
<target>%lld événements de groupe</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%lld members" xml:space="preserve">
@@ -210,14 +214,17 @@
</trans-unit>
<trans-unit id="%lld messages blocked" xml:space="preserve">
<source>%lld messages blocked</source>
<target>%lld messages bloqués</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%lld messages marked deleted" xml:space="preserve">
<source>%lld messages marked deleted</source>
<target>%lld messages marqués comme supprimés</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%lld messages moderated by %@" xml:space="preserve">
<source>%lld messages moderated by %@</source>
<target>%lld messages modérés par %@</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%lld minutes" xml:space="preserve">
@@ -290,6 +297,14 @@
<target>(</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(new)" xml:space="preserve">
<source>(new)</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(this device v%@)" xml:space="preserve">
<source>(this device v%@)</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=")" xml:space="preserve">
<source>)</source>
<target>)</target>
@@ -394,6 +409,7 @@
</trans-unit>
<trans-unit id="0 sec" xml:space="preserve">
<source>0 sec</source>
<target>0 sec</target>
<note>time to disappear</note>
</trans-unit>
<trans-unit id="0s" xml:space="preserve">
@@ -623,6 +639,7 @@
</trans-unit>
<trans-unit id="All new messages from %@ will be hidden!" xml:space="preserve">
<source>All new messages from %@ will be hidden!</source>
<target>Tous les nouveaux messages de %@ seront cachés !</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
@@ -732,10 +749,12 @@
</trans-unit>
<trans-unit id="Already connecting!" xml:space="preserve">
<source>Already connecting!</source>
<target>Déjà en connexion !</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Already joining the group!" xml:space="preserve">
<source>Already joining the group!</source>
<target>Groupe déjà rejoint !</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Always use relay" xml:space="preserve">
@@ -858,6 +877,10 @@
<target>Retour</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Bad desktop address" xml:space="preserve">
<source>Bad desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Bad message ID" xml:space="preserve">
<source>Bad message ID</source>
<target>Mauvais ID de message</target>
@@ -875,14 +898,17 @@
</trans-unit>
<trans-unit id="Block" xml:space="preserve">
<source>Block</source>
<target>Bloquer</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Block member" xml:space="preserve">
<source>Block member</source>
<target>Bloquer ce membre</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Block member?" xml:space="preserve">
<source>Block member?</source>
<target>Bloquer ce membre ?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Both you and your contact can add message reactions." xml:space="preserve">
@@ -1151,22 +1177,32 @@
<target>Se connecter incognito</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to desktop" xml:space="preserve">
<source>Connect to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to yourself?" xml:space="preserve">
<source>Connect to yourself?</source>
<target>Se connecter à soi-même ?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to yourself?&#10;This is your own SimpleX address!" xml:space="preserve">
<source>Connect to yourself?
This is your own SimpleX address!</source>
<target>Se connecter à soi-même ?
C'est votre propre adresse SimpleX !</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to yourself?&#10;This is your own one-time link!" xml:space="preserve">
<source>Connect to yourself?
This is your own one-time link!</source>
<target>Se connecter à soi-même ?
Il s'agit de votre propre lien unique !</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect via contact address" xml:space="preserve">
<source>Connect via contact address</source>
<target>Se connecter via l'adresse de contact</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect via link" xml:space="preserve">
@@ -1186,6 +1222,15 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Connect with %@" xml:space="preserve">
<source>Connect with %@</source>
<target>Se connecter avec %@</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connected desktop" xml:space="preserve">
<source>Connected desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connected to desktop" xml:space="preserve">
<source>Connected to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connecting server…" xml:space="preserve">
@@ -1198,6 +1243,10 @@ This is your own one-time link!</source>
<target>Connexion au serveur… (erreur : %@)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connecting to desktop" xml:space="preserve">
<source>Connecting to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection" xml:space="preserve">
<source>Connection</source>
<target>Connexion</target>
@@ -1218,6 +1267,10 @@ This is your own one-time link!</source>
<target>Demande de connexion envoyée !</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection terminated" xml:space="preserve">
<source>Connection terminated</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection timeout" xml:space="preserve">
<source>Connection timeout</source>
<target>Délai de connexion</target>
@@ -1285,6 +1338,7 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Correct name to %@?" xml:space="preserve">
<source>Correct name to %@?</source>
<target>Corriger le nom pour %@ ?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create" xml:space="preserve">
@@ -1309,6 +1363,7 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Create group" xml:space="preserve">
<source>Create group</source>
<target>Créer un groupe</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create group link" xml:space="preserve">
@@ -1333,6 +1388,7 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Create profile" xml:space="preserve">
<source>Create profile</source>
<target>Créer le profil</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create queue" xml:space="preserve">
@@ -1495,6 +1551,7 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Delete %lld messages?" xml:space="preserve">
<source>Delete %lld messages?</source>
<target>Supprimer %lld messages ?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete Contact" xml:space="preserve">
@@ -1524,6 +1581,7 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Delete and notify contact" xml:space="preserve">
<source>Delete and notify contact</source>
<target>Supprimer et en informer le contact</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete archive" xml:space="preserve">
@@ -1559,6 +1617,8 @@ This is your own one-time link!</source>
<trans-unit id="Delete contact?&#10;This cannot be undone!" xml:space="preserve">
<source>Delete contact?
This cannot be undone!</source>
<target>Supprimer le contact ?
Cette opération ne peut être annulée !</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete database" xml:space="preserve">
@@ -1701,6 +1761,18 @@ This cannot be undone!</source>
<target>Description</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop address" xml:space="preserve">
<source>Desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop app version %@ is not compatible with this app." xml:space="preserve">
<source>Desktop app version %@ is not compatible with this app.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop devices" xml:space="preserve">
<source>Desktop devices</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Develop" xml:space="preserve">
<source>Develop</source>
<target>Développer</target>
@@ -1791,11 +1863,19 @@ This cannot be undone!</source>
<target>Se déconnecter</target>
<note>server test step</note>
</trans-unit>
<trans-unit id="Disconnect desktop?" xml:space="preserve">
<source>Disconnect desktop?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Discover and join groups" xml:space="preserve">
<source>Discover and join groups</source>
<target>Découvrir et rejoindre des groupes</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Discover on network" xml:space="preserve">
<source>Discover on network</source>
<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>N'utilisez PAS SimpleX pour les appels d'urgence.</target>
@@ -1966,6 +2046,14 @@ This cannot be undone!</source>
<target>Message chiffrée: erreur inattendue</target>
<note>notification</note>
</trans-unit>
<trans-unit id="Encryption re-negotiation error" xml:space="preserve">
<source>Encryption re-negotiation error</source>
<note>message decrypt error item</note>
</trans-unit>
<trans-unit id="Encryption re-negotiation failed." xml:space="preserve">
<source>Encryption re-negotiation failed.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter Passcode" xml:space="preserve">
<source>Enter Passcode</source>
<target>Entrer le code d'accès</target>
@@ -1978,6 +2066,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Enter group name…" xml:space="preserve">
<source>Enter group name…</source>
<target>Entrer un nom de groupe…</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter passphrase…" xml:space="preserve">
@@ -1995,6 +2084,10 @@ This cannot be undone!</source>
<target>Entrer un serveur manuellement</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter this device name…" xml:space="preserve">
<source>Enter this device name…</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter welcome message…" xml:space="preserve">
<source>Enter welcome message…</source>
<target>Entrez un message de bienvenue…</target>
@@ -2007,6 +2100,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Enter your name…" xml:space="preserve">
<source>Enter your name…</source>
<target>Entrez votre nom…</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error" xml:space="preserve">
@@ -2286,6 +2380,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Expand" xml:space="preserve">
<source>Expand</source>
<target>Développer</target>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Export database" xml:space="preserve">
@@ -2435,6 +2530,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Fully decentralized visible only to members." xml:space="preserve">
<source>Fully decentralized visible only to members.</source>
<target>Entièrement décentralisé visible que par ses membres.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Fully re-implemented - work in background!" xml:space="preserve">
@@ -2459,10 +2555,12 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Group already exists" xml:space="preserve">
<source>Group already exists</source>
<target>Le groupe existe déjà</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group already exists!" xml:space="preserve">
<source>Group already exists!</source>
<target>Ce groupe existe déjà !</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group display name" xml:space="preserve">
@@ -2765,6 +2863,10 @@ This cannot be undone!</source>
<target>Version de la base de données incompatible</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Incompatible version" xml:space="preserve">
<source>Incompatible version</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Incorrect passcode" xml:space="preserve">
<source>Incorrect passcode</source>
<target>Code d'accès erroné</target>
@@ -2814,6 +2916,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Invalid name!" xml:space="preserve">
<source>Invalid name!</source>
<target>Nom invalide !</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Invalid server address!" xml:space="preserve">
@@ -2909,6 +3012,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Join group?" xml:space="preserve">
<source>Join group?</source>
<target>Rejoindre le groupe ?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Join incognito" xml:space="preserve">
@@ -2918,11 +3022,14 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Join with current profile" xml:space="preserve">
<source>Join with current profile</source>
<target>Rejoindre avec le profil actuel</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Join your group?&#10;This is your link for group %@!" xml:space="preserve">
<source>Join your group?
This is your link for group %@!</source>
<target>Rejoindre votre groupe ?
Voici votre lien pour le groupe %@ !</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Joining group" xml:space="preserve">
@@ -2930,6 +3037,10 @@ This is your link for group %@!</source>
<target>Entrain de rejoindre le groupe</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Keep the app open to use it from desktop" xml:space="preserve">
<source>Keep the app open to use it from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Keep your connections" xml:space="preserve">
<source>Keep your connections</source>
<target>Conserver vos connexions</target>
@@ -2990,6 +3101,14 @@ This is your link for group %@!</source>
<target>Limitations</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Linked desktop options" xml:space="preserve">
<source>Linked desktop options</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Linked desktops" xml:space="preserve">
<source>Linked desktops</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Live message!" xml:space="preserve">
<source>Live message!</source>
<target>Message dynamique !</target>
@@ -3142,6 +3261,7 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Messages from %@ will be shown!" xml:space="preserve">
<source>Messages from %@ will be shown!</source>
<target>Les messages de %@ seront affichés !</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Migrating database archive…" xml:space="preserve">
@@ -3495,6 +3615,7 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Open group" xml:space="preserve">
<source>Open group</source>
<target>Ouvrir le groupe</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Open user profiles" xml:space="preserve">
@@ -3557,6 +3678,10 @@ This is your link for group %@!</source>
<target>Coller</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Paste desktop address" xml:space="preserve">
<source>Paste desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Paste image" xml:space="preserve">
<source>Paste image</source>
<target>Coller l'image</target>
@@ -3704,10 +3829,12 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Profile name" xml:space="preserve">
<source>Profile name</source>
<target>Nom du profil</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile name:" xml:space="preserve">
<source>Profile name:</source>
<target>Nom du profil :</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile password" xml:space="preserve">
@@ -3957,10 +4084,12 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Repeat connection request?" xml:space="preserve">
<source>Repeat connection request?</source>
<target>Répéter la demande de connexion ?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Repeat join request?" xml:space="preserve">
<source>Repeat join request?</source>
<target>Répéter la requête d'adhésion ?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Reply" xml:space="preserve">
@@ -4148,6 +4277,10 @@ This is your link for group %@!</source>
<target>Scanner un code QR</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scan QR code from desktop" xml:space="preserve">
<source>Scan QR code from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scan code" xml:space="preserve">
<source>Scan code</source>
<target>Scanner le code</target>
@@ -4368,6 +4501,10 @@ This is your link for group %@!</source>
<target>Serveurs</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Session code" xml:space="preserve">
<source>Session code</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set 1 day" xml:space="preserve">
<source>Set 1 day</source>
<target>Définir 1 jour</target>
@@ -4680,6 +4817,7 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Tap to Connect" xml:space="preserve">
<source>Tap to Connect</source>
<target>Tapez pour vous connecter</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Tap to activate profile." xml:space="preserve">
@@ -4864,6 +5002,10 @@ Cela peut se produire en raison d'un bug ou lorsque la connexion est compromise.
<target>Cette action ne peut être annulée - votre profil, vos contacts, vos messages et vos fichiers seront irréversiblement perdus.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This device name" xml:space="preserve">
<source>This device name</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This group has over %lld members, delivery receipts are not sent." xml:space="preserve">
<source>This group has over %lld members, delivery receipts are not sent.</source>
<target>Ce groupe compte plus de %lld membres, les accusés de réception ne sont pas envoyés.</target>
@@ -4876,10 +5018,12 @@ Cela peut se produire en raison d'un bug ou lorsque la connexion est compromise.
</trans-unit>
<trans-unit id="This is your own SimpleX address!" xml:space="preserve">
<source>This is your own SimpleX address!</source>
<target>Voici votre propre adresse SimpleX !</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This is your own one-time link!" xml:space="preserve">
<source>This is your own one-time link!</source>
<target>Voici votre propre lien unique !</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This setting applies to messages in your current chat profile **%@**." xml:space="preserve">
@@ -4981,14 +5125,17 @@ Vous serez invité à confirmer l'authentification avant que cette fonction ne s
</trans-unit>
<trans-unit id="Unblock" xml:space="preserve">
<source>Unblock</source>
<target>Débloquer</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unblock member" xml:space="preserve">
<source>Unblock member</source>
<target>Débloquer ce membre</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unblock member?" xml:space="preserve">
<source>Unblock member?</source>
<target>Débloquer ce membre ?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unexpected error: %@" xml:space="preserve">
@@ -5053,6 +5200,14 @@ To connect, please ask your contact to create another connection link and check
Pour vous connecter, veuillez demander à votre contact de créer un autre lien de connexion et vérifiez que vous disposez d'une connexion réseau stable.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlink" xml:space="preserve">
<source>Unlink</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlink desktop?" xml:space="preserve">
<source>Unlink desktop?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlock" xml:space="preserve">
<source>Unlock</source>
<target>Déverrouiller</target>
@@ -5143,6 +5298,10 @@ Pour vous connecter, veuillez demander à votre contact de créer un autre lien
<target>Utiliser pour les nouvelles connexions</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use from desktop" xml:space="preserve">
<source>Use from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use iOS call interface" xml:space="preserve">
<source>Use iOS call interface</source>
<target>Utiliser l'interface d'appel d'iOS</target>
@@ -5173,11 +5332,23 @@ Pour vous connecter, veuillez demander à votre contact de créer un autre lien
<target>Utilisation des serveurs SimpleX Chat.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify code with desktop" xml:space="preserve">
<source>Verify code with desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connection" xml:space="preserve">
<source>Verify connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connection security" xml:space="preserve">
<source>Verify connection security</source>
<target>Vérifier la sécurité de la connexion</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connections" xml:space="preserve">
<source>Verify connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify security code" xml:space="preserve">
<source>Verify security code</source>
<target>Vérifier le code de sécurité</target>
@@ -5340,31 +5511,39 @@ Pour vous connecter, veuillez demander à votre contact de créer un autre lien
</trans-unit>
<trans-unit id="You are already connecting to %@." xml:space="preserve">
<source>You are already connecting to %@.</source>
<target>Vous êtes déjà en train de vous connecter à %@.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You are already connecting via this one-time link!" xml:space="preserve">
<source>You are already connecting via this one-time link!</source>
<target>Vous êtes déjà connecté(e) via ce lien unique !</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You are already in group %@." xml:space="preserve">
<source>You are already in group %@.</source>
<target>Vous êtes déjà dans le groupe %@.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You are already joining the group %@." xml:space="preserve">
<source>You are already joining the group %@.</source>
<target>Vous êtes déjà en train de rejoindre le groupe %@.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You are already joining the group via this link!" xml:space="preserve">
<source>You are already joining the group via this link!</source>
<target>Vous êtes déjà en train de rejoindre le groupe via ce lien !</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You are already joining the group via this link." xml:space="preserve">
<source>You are already joining the group via this link.</source>
<target>Vous êtes déjà en train de rejoindre le groupe via ce lien.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You are already joining the group!&#10;Repeat join request?" xml:space="preserve">
<source>You are already joining the group!
Repeat join request?</source>
<target>Vous êtes déjà membre de ce groupe !
Répéter la demande d'adhésion ?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You are connected to the server used to receive messages from this contact." xml:space="preserve">
@@ -5464,11 +5643,14 @@ Repeat join request?</source>
</trans-unit>
<trans-unit id="You have already requested connection via this address!" xml:space="preserve">
<source>You have already requested connection via this address!</source>
<target>Vous avez déjà demandé une connexion via cette adresse !</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You have already requested connection!&#10;Repeat connection request?" xml:space="preserve">
<source>You have already requested connection!
Repeat connection request?</source>
<target>Vous avez déjà demandé une connexion !
Répéter la demande de connexion ?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You have no chats" xml:space="preserve">
@@ -5523,6 +5705,7 @@ Repeat connection request?</source>
</trans-unit>
<trans-unit id="You will be connected when group link host's device is online, please wait or check later!" xml:space="preserve">
<source>You will be connected when group link host's device is online, please wait or check later!</source>
<target>Vous serez connecté(e) lorsque l'appareil de l'hôte du lien de groupe sera en ligne, veuillez patienter ou vérifier plus tard !</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You will be connected when your connection request is accepted, please wait or check later!" xml:space="preserve">
@@ -5542,6 +5725,7 @@ Repeat connection request?</source>
</trans-unit>
<trans-unit id="You will connect to all group members." xml:space="preserve">
<source>You will connect to all group members.</source>
<target>Vous vous connecterez à tous les membres du groupe.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You will still receive calls and notifications from muted profiles when they are active." xml:space="preserve">
@@ -5665,6 +5849,7 @@ Vous pouvez modifier ce choix dans les Paramètres.</target>
</trans-unit>
<trans-unit id="Your profile" xml:space="preserve">
<source>Your profile</source>
<target>Votre profil</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your profile **%@** will be shared." xml:space="preserve">
@@ -5761,6 +5946,7 @@ Les serveurs SimpleX ne peuvent pas voir votre profil.</target>
</trans-unit>
<trans-unit id="and %lld other events" xml:space="preserve">
<source>and %lld other events</source>
<target>et %lld autres événements</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="audio call (not e2e encrypted)" xml:space="preserve">
@@ -5780,6 +5966,7 @@ Les serveurs SimpleX ne peuvent pas voir votre profil.</target>
</trans-unit>
<trans-unit id="blocked" xml:space="preserve">
<source>blocked</source>
<target>blocké</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="bold" xml:space="preserve">
@@ -5954,6 +6141,7 @@ Les serveurs SimpleX ne peuvent pas voir votre profil.</target>
</trans-unit>
<trans-unit id="deleted contact" xml:space="preserve">
<source>deleted contact</source>
<target>contact supprimé</target>
<note>rcv direct event chat item</note>
</trans-unit>
<trans-unit id="deleted group" xml:space="preserve">
@@ -6348,6 +6536,10 @@ Les serveurs SimpleX ne peuvent pas voir votre profil.</target>
<target>mise à jour du profil de groupe</target>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="v%@" xml:space="preserve">
<source>v%@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="v%@ (%@)" xml:space="preserve">
<source>v%@ (%@)</source>
<target>v%@ (%@)</target>
@@ -6485,6 +6677,10 @@ Les serveurs SimpleX ne peuvent pas voir votre profil.</target>
<target>SimpleGroup not found!X utilise Face ID pour l'authentification locale</target>
<note>Privacy - Face ID Usage Description</note>
</trans-unit>
<trans-unit id="NSLocalNetworkUsageDescription" xml:space="preserve">
<source>SimpleX uses local network access to allow using user chat profile via desktop app on the same network.</source>
<note>Privacy - Local Network Usage Description</note>
</trans-unit>
<trans-unit id="NSMicrophoneUsageDescription" xml:space="preserve">
<source>SimpleX needs microphone access for audio and video calls, and to record voice messages.</source>
<target>SimpleX a besoin d'un accès au microphone pour les appels audio et vidéo ainsi que pour enregistrer des messages vocaux.</target>
@@ -4,6 +4,8 @@
"NSCameraUsageDescription" = "SimpleX needs camera access to scan QR codes to connect to other users and for video calls.";
/* Privacy - Face ID Usage Description */
"NSFaceIDUsageDescription" = "SimpleX uses Face ID for local authentication";
/* Privacy - Local Network Usage Description */
"NSLocalNetworkUsageDescription" = "SimpleX uses local network access to allow using user chat profile via desktop app on the same network.";
/* Privacy - Microphone Usage Description */
"NSMicrophoneUsageDescription" = "SimpleX needs microphone access for audio and video calls, and to record voice messages.";
/* Privacy - Photo Library Additions Usage Description */
@@ -89,6 +89,7 @@
</trans-unit>
<trans-unit id="%@ and %@" xml:space="preserve">
<source>%@ and %@</source>
<target>%@ e %@</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ and %@ connected" xml:space="preserve">
@@ -103,6 +104,7 @@
</trans-unit>
<trans-unit id="%@ connected" xml:space="preserve">
<source>%@ connected</source>
<target>%@ si è connesso/a</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ is connected!" xml:space="preserve">
@@ -132,6 +134,7 @@
</trans-unit>
<trans-unit id="%@, %@ and %lld members" xml:space="preserve">
<source>%@, %@ and %lld members</source>
<target>%@, %@ e %lld membri</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@, %@ and %lld other members connected" xml:space="preserve">
@@ -201,6 +204,7 @@
</trans-unit>
<trans-unit id="%lld group events" xml:space="preserve">
<source>%lld group events</source>
<target>%lld eventi del gruppo</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%lld members" xml:space="preserve">
@@ -210,14 +214,17 @@
</trans-unit>
<trans-unit id="%lld messages blocked" xml:space="preserve">
<source>%lld messages blocked</source>
<target>%lld messaggi bloccati</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%lld messages marked deleted" xml:space="preserve">
<source>%lld messages marked deleted</source>
<target>%lld messaggi contrassegnati eliminati</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%lld messages moderated by %@" xml:space="preserve">
<source>%lld messages moderated by %@</source>
<target>%lld messaggi moderati da %@</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%lld minutes" xml:space="preserve">
@@ -290,6 +297,14 @@
<target>(</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(new)" xml:space="preserve">
<source>(new)</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(this device v%@)" xml:space="preserve">
<source>(this device v%@)</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=")" xml:space="preserve">
<source>)</source>
<target>)</target>
@@ -394,6 +409,7 @@
</trans-unit>
<trans-unit id="0 sec" xml:space="preserve">
<source>0 sec</source>
<target>0 sec</target>
<note>time to disappear</note>
</trans-unit>
<trans-unit id="0s" xml:space="preserve">
@@ -623,6 +639,7 @@
</trans-unit>
<trans-unit id="All new messages from %@ will be hidden!" xml:space="preserve">
<source>All new messages from %@ will be hidden!</source>
<target>Tutti i nuovi messaggi da %@ verrranno nascosti!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
@@ -732,10 +749,12 @@
</trans-unit>
<trans-unit id="Already connecting!" xml:space="preserve">
<source>Already connecting!</source>
<target>Già in connessione!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Already joining the group!" xml:space="preserve">
<source>Already joining the group!</source>
<target>Già in ingresso nel gruppo!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Always use relay" xml:space="preserve">
@@ -858,6 +877,10 @@
<target>Indietro</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Bad desktop address" xml:space="preserve">
<source>Bad desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Bad message ID" xml:space="preserve">
<source>Bad message ID</source>
<target>ID del messaggio errato</target>
@@ -875,14 +898,17 @@
</trans-unit>
<trans-unit id="Block" xml:space="preserve">
<source>Block</source>
<target>Blocca</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Block member" xml:space="preserve">
<source>Block member</source>
<target>Blocca membro</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Block member?" xml:space="preserve">
<source>Block member?</source>
<target>Bloccare il membro?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Both you and your contact can add message reactions." xml:space="preserve">
@@ -1151,22 +1177,32 @@
<target>Connetti in incognito</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to desktop" xml:space="preserve">
<source>Connect to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to yourself?" xml:space="preserve">
<source>Connect to yourself?</source>
<target>Connettersi a te stesso?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to yourself?&#10;This is your own SimpleX address!" xml:space="preserve">
<source>Connect to yourself?
This is your own SimpleX address!</source>
<target>Connettersi a te stesso?
Questo è il tuo indirizzo SimpleX!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to yourself?&#10;This is your own one-time link!" xml:space="preserve">
<source>Connect to yourself?
This is your own one-time link!</source>
<target>Connettersi a te stesso?
Questo è il tuo link una tantum!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect via contact address" xml:space="preserve">
<source>Connect via contact address</source>
<target>Connettere via indirizzo del contatto</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect via link" xml:space="preserve">
@@ -1186,6 +1222,15 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Connect with %@" xml:space="preserve">
<source>Connect with %@</source>
<target>Connettersi con %@</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connected desktop" xml:space="preserve">
<source>Connected desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connected to desktop" xml:space="preserve">
<source>Connected to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connecting server…" xml:space="preserve">
@@ -1198,6 +1243,10 @@ This is your own one-time link!</source>
<target>Connessione al server… (errore: %@)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connecting to desktop" xml:space="preserve">
<source>Connecting to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection" xml:space="preserve">
<source>Connection</source>
<target>Connessione</target>
@@ -1218,6 +1267,10 @@ This is your own one-time link!</source>
<target>Richiesta di connessione inviata!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection terminated" xml:space="preserve">
<source>Connection terminated</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection timeout" xml:space="preserve">
<source>Connection timeout</source>
<target>Connessione scaduta</target>
@@ -1285,6 +1338,7 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Correct name to %@?" xml:space="preserve">
<source>Correct name to %@?</source>
<target>Correggere il nome a %@?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create" xml:space="preserve">
@@ -1309,6 +1363,7 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Create group" xml:space="preserve">
<source>Create group</source>
<target>Crea gruppo</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create group link" xml:space="preserve">
@@ -1333,6 +1388,7 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Create profile" xml:space="preserve">
<source>Create profile</source>
<target>Crea profilo</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create queue" xml:space="preserve">
@@ -1495,6 +1551,7 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Delete %lld messages?" xml:space="preserve">
<source>Delete %lld messages?</source>
<target>Eliminare %lld messaggi?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete Contact" xml:space="preserve">
@@ -1524,6 +1581,7 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Delete and notify contact" xml:space="preserve">
<source>Delete and notify contact</source>
<target>Elimina e avvisa il contatto</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete archive" xml:space="preserve">
@@ -1559,6 +1617,8 @@ This is your own one-time link!</source>
<trans-unit id="Delete contact?&#10;This cannot be undone!" xml:space="preserve">
<source>Delete contact?
This cannot be undone!</source>
<target>Eliminare il contatto?
Non è reversibile!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete database" xml:space="preserve">
@@ -1701,6 +1761,18 @@ This cannot be undone!</source>
<target>Descrizione</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop address" xml:space="preserve">
<source>Desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop app version %@ is not compatible with this app." xml:space="preserve">
<source>Desktop app version %@ is not compatible with this app.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop devices" xml:space="preserve">
<source>Desktop devices</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Develop" xml:space="preserve">
<source>Develop</source>
<target>Sviluppa</target>
@@ -1791,11 +1863,19 @@ This cannot be undone!</source>
<target>Disconnetti</target>
<note>server test step</note>
</trans-unit>
<trans-unit id="Disconnect desktop?" xml:space="preserve">
<source>Disconnect desktop?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Discover and join groups" xml:space="preserve">
<source>Discover and join groups</source>
<target>Scopri ed unisciti ai gruppi</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Discover on network" xml:space="preserve">
<source>Discover on network</source>
<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>NON usare SimpleX per chiamate di emergenza.</target>
@@ -1966,6 +2046,14 @@ This cannot be undone!</source>
<target>Messaggio crittografato: errore imprevisto</target>
<note>notification</note>
</trans-unit>
<trans-unit id="Encryption re-negotiation error" xml:space="preserve">
<source>Encryption re-negotiation error</source>
<note>message decrypt error item</note>
</trans-unit>
<trans-unit id="Encryption re-negotiation failed." xml:space="preserve">
<source>Encryption re-negotiation failed.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter Passcode" xml:space="preserve">
<source>Enter Passcode</source>
<target>Inserisci il codice di accesso</target>
@@ -1978,6 +2066,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Enter group name…" xml:space="preserve">
<source>Enter group name…</source>
<target>Inserisci il nome del gruppo…</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter passphrase…" xml:space="preserve">
@@ -1995,6 +2084,10 @@ This cannot be undone!</source>
<target>Inserisci il server a mano</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter this device name…" xml:space="preserve">
<source>Enter this device name…</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter welcome message…" xml:space="preserve">
<source>Enter welcome message…</source>
<target>Inserisci il messaggio di benvenuto…</target>
@@ -2007,6 +2100,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Enter your name…" xml:space="preserve">
<source>Enter your name…</source>
<target>Inserisci il tuo nome…</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error" xml:space="preserve">
@@ -2286,6 +2380,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Expand" xml:space="preserve">
<source>Expand</source>
<target>Espandi</target>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Export database" xml:space="preserve">
@@ -2435,6 +2530,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Fully decentralized visible only to members." xml:space="preserve">
<source>Fully decentralized visible only to members.</source>
<target>Completamente decentralizzato: visibile solo ai membri.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Fully re-implemented - work in background!" xml:space="preserve">
@@ -2459,10 +2555,12 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Group already exists" xml:space="preserve">
<source>Group already exists</source>
<target>Il gruppo esiste già</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group already exists!" xml:space="preserve">
<source>Group already exists!</source>
<target>Il gruppo esiste già!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group display name" xml:space="preserve">
@@ -2765,6 +2863,10 @@ This cannot be undone!</source>
<target>Versione del database incompatibile</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Incompatible version" xml:space="preserve">
<source>Incompatible version</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Incorrect passcode" xml:space="preserve">
<source>Incorrect passcode</source>
<target>Codice di accesso errato</target>
@@ -2814,6 +2916,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Invalid name!" xml:space="preserve">
<source>Invalid name!</source>
<target>Nome non valido!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Invalid server address!" xml:space="preserve">
@@ -2909,6 +3012,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Join group?" xml:space="preserve">
<source>Join group?</source>
<target>Entrare nel gruppo?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Join incognito" xml:space="preserve">
@@ -2918,11 +3022,14 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Join with current profile" xml:space="preserve">
<source>Join with current profile</source>
<target>Entra con il profilo attuale</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Join your group?&#10;This is your link for group %@!" xml:space="preserve">
<source>Join your group?
This is your link for group %@!</source>
<target>Entrare nel tuo gruppo?
Questo è il tuo link per il gruppo %@!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Joining group" xml:space="preserve">
@@ -2930,6 +3037,10 @@ This is your link for group %@!</source>
<target>Ingresso nel gruppo</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Keep the app open to use it from desktop" xml:space="preserve">
<source>Keep the app open to use it from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Keep your connections" xml:space="preserve">
<source>Keep your connections</source>
<target>Mantieni le tue connessioni</target>
@@ -2990,6 +3101,14 @@ This is your link for group %@!</source>
<target>Limitazioni</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Linked desktop options" xml:space="preserve">
<source>Linked desktop options</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Linked desktops" xml:space="preserve">
<source>Linked desktops</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Live message!" xml:space="preserve">
<source>Live message!</source>
<target>Messaggio in diretta!</target>
@@ -3142,6 +3261,7 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Messages from %@ will be shown!" xml:space="preserve">
<source>Messages from %@ will be shown!</source>
<target>I messaggi da %@ verranno mostrati!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Migrating database archive…" xml:space="preserve">
@@ -3495,6 +3615,7 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Open group" xml:space="preserve">
<source>Open group</source>
<target>Apri gruppo</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Open user profiles" xml:space="preserve">
@@ -3557,6 +3678,10 @@ This is your link for group %@!</source>
<target>Incolla</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Paste desktop address" xml:space="preserve">
<source>Paste desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Paste image" xml:space="preserve">
<source>Paste image</source>
<target>Incolla immagine</target>
@@ -3704,10 +3829,12 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Profile name" xml:space="preserve">
<source>Profile name</source>
<target>Nome del profilo</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile name:" xml:space="preserve">
<source>Profile name:</source>
<target>Nome del profilo:</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile password" xml:space="preserve">
@@ -3957,10 +4084,12 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Repeat connection request?" xml:space="preserve">
<source>Repeat connection request?</source>
<target>Ripetere la richiesta di connessione?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Repeat join request?" xml:space="preserve">
<source>Repeat join request?</source>
<target>Ripetere la richiesta di ingresso?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Reply" xml:space="preserve">
@@ -4148,6 +4277,10 @@ This is your link for group %@!</source>
<target>Scansiona codice QR</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scan QR code from desktop" xml:space="preserve">
<source>Scan QR code from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scan code" xml:space="preserve">
<source>Scan code</source>
<target>Scansiona codice</target>
@@ -4368,6 +4501,10 @@ This is your link for group %@!</source>
<target>Server</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Session code" xml:space="preserve">
<source>Session code</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set 1 day" xml:space="preserve">
<source>Set 1 day</source>
<target>Imposta 1 giorno</target>
@@ -4680,6 +4817,7 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Tap to Connect" xml:space="preserve">
<source>Tap to Connect</source>
<target>Tocca per connettere</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Tap to activate profile." xml:space="preserve">
@@ -4864,6 +5002,10 @@ Può accadere a causa di qualche bug o quando la connessione è compromessa.</ta
<target>Questa azione non può essere annullata: il tuo profilo, i contatti, i messaggi e i file andranno persi in modo irreversibile.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This device name" xml:space="preserve">
<source>This device name</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This group has over %lld members, delivery receipts are not sent." xml:space="preserve">
<source>This group has over %lld members, delivery receipts are not sent.</source>
<target>Questo gruppo ha più di %lld membri, le ricevute di consegna non vengono inviate.</target>
@@ -4876,10 +5018,12 @@ Può accadere a causa di qualche bug o quando la connessione è compromessa.</ta
</trans-unit>
<trans-unit id="This is your own SimpleX address!" xml:space="preserve">
<source>This is your own SimpleX address!</source>
<target>Questo è il tuo indirizzo SimpleX!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This is your own one-time link!" xml:space="preserve">
<source>This is your own one-time link!</source>
<target>Questo è il tuo link una tantum!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This setting applies to messages in your current chat profile **%@**." xml:space="preserve">
@@ -4981,14 +5125,17 @@ Ti verrà chiesto di completare l'autenticazione prima di attivare questa funzio
</trans-unit>
<trans-unit id="Unblock" xml:space="preserve">
<source>Unblock</source>
<target>Sblocca</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unblock member" xml:space="preserve">
<source>Unblock member</source>
<target>Sblocca membro</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unblock member?" xml:space="preserve">
<source>Unblock member?</source>
<target>Sbloccare il membro?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unexpected error: %@" xml:space="preserve">
@@ -5053,6 +5200,14 @@ To connect, please ask your contact to create another connection link and check
Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e controlla di avere una connessione di rete stabile.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlink" xml:space="preserve">
<source>Unlink</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlink desktop?" xml:space="preserve">
<source>Unlink desktop?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlock" xml:space="preserve">
<source>Unlock</source>
<target>Sblocca</target>
@@ -5143,6 +5298,10 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e
<target>Usa per connessioni nuove</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use from desktop" xml:space="preserve">
<source>Use from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use iOS call interface" xml:space="preserve">
<source>Use iOS call interface</source>
<target>Usa interfaccia di chiamata iOS</target>
@@ -5173,11 +5332,23 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e
<target>Utilizzo dei server SimpleX Chat.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify code with desktop" xml:space="preserve">
<source>Verify code with desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connection" xml:space="preserve">
<source>Verify connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connection security" xml:space="preserve">
<source>Verify connection security</source>
<target>Verifica la sicurezza della connessione</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connections" xml:space="preserve">
<source>Verify connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify security code" xml:space="preserve">
<source>Verify security code</source>
<target>Verifica codice di sicurezza</target>
@@ -5340,31 +5511,39 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e
</trans-unit>
<trans-unit id="You are already connecting to %@." xml:space="preserve">
<source>You are already connecting to %@.</source>
<target>Ti stai già connettendo a %@.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You are already connecting via this one-time link!" xml:space="preserve">
<source>You are already connecting via this one-time link!</source>
<target>Ti stai già connettendo tramite questo link una tantum!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You are already in group %@." xml:space="preserve">
<source>You are already in group %@.</source>
<target>Sei già nel gruppo %@.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You are already joining the group %@." xml:space="preserve">
<source>You are already joining the group %@.</source>
<target>Stai già entrando nel gruppo %@.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You are already joining the group via this link!" xml:space="preserve">
<source>You are already joining the group via this link!</source>
<target>Stai già entrando nel gruppo tramite questo link!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You are already joining the group via this link." xml:space="preserve">
<source>You are already joining the group via this link.</source>
<target>Stai già entrando nel gruppo tramite questo link.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You are already joining the group!&#10;Repeat join request?" xml:space="preserve">
<source>You are already joining the group!
Repeat join request?</source>
<target>Stai già entrando nel gruppo!
Ripetere la richiesta di ingresso?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You are connected to the server used to receive messages from this contact." xml:space="preserve">
@@ -5464,11 +5643,14 @@ Repeat join request?</source>
</trans-unit>
<trans-unit id="You have already requested connection via this address!" xml:space="preserve">
<source>You have already requested connection via this address!</source>
<target>Hai già richiesto la connessione tramite questo indirizzo!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You have already requested connection!&#10;Repeat connection request?" xml:space="preserve">
<source>You have already requested connection!
Repeat connection request?</source>
<target>Hai già richiesto la connessione!
Ripetere la richiesta di connessione?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You have no chats" xml:space="preserve">
@@ -5523,6 +5705,7 @@ Repeat connection request?</source>
</trans-unit>
<trans-unit id="You will be connected when group link host's device is online, please wait or check later!" xml:space="preserve">
<source>You will be connected when group link host's device is online, please wait or check later!</source>
<target>Verrai connesso/a quando il dispositivo dell'host del gruppo sarà in linea, attendi o controlla più tardi!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You will be connected when your connection request is accepted, please wait or check later!" xml:space="preserve">
@@ -5542,6 +5725,7 @@ Repeat connection request?</source>
</trans-unit>
<trans-unit id="You will connect to all group members." xml:space="preserve">
<source>You will connect to all group members.</source>
<target>Ti connetterai a tutti i membri del gruppo.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You will still receive calls and notifications from muted profiles when they are active." xml:space="preserve">
@@ -5665,6 +5849,7 @@ Puoi modificarlo nelle impostazioni.</target>
</trans-unit>
<trans-unit id="Your profile" xml:space="preserve">
<source>Your profile</source>
<target>Il tuo profilo</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your profile **%@** will be shared." xml:space="preserve">
@@ -5761,6 +5946,7 @@ I server di SimpleX non possono vedere il tuo profilo.</target>
</trans-unit>
<trans-unit id="and %lld other events" xml:space="preserve">
<source>and %lld other events</source>
<target>e altri %lld eventi</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="audio call (not e2e encrypted)" xml:space="preserve">
@@ -5780,6 +5966,7 @@ I server di SimpleX non possono vedere il tuo profilo.</target>
</trans-unit>
<trans-unit id="blocked" xml:space="preserve">
<source>blocked</source>
<target>bloccato</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="bold" xml:space="preserve">
@@ -5814,7 +6001,7 @@ I server di SimpleX non possono vedere il tuo profilo.</target>
</trans-unit>
<trans-unit id="changed role of %@ to %@" xml:space="preserve">
<source>changed role of %1$@ to %2$@</source>
<target>cambiato il ruolo di %1$@ in %2$@</target>
<target>ha cambiato il ruolo di %1$@ in %2$@</target>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="changed your role to %@" xml:space="preserve">
@@ -5954,6 +6141,7 @@ I server di SimpleX non possono vedere il tuo profilo.</target>
</trans-unit>
<trans-unit id="deleted contact" xml:space="preserve">
<source>deleted contact</source>
<target>contatto eliminato</target>
<note>rcv direct event chat item</note>
</trans-unit>
<trans-unit id="deleted group" xml:space="preserve">
@@ -6348,6 +6536,10 @@ I server di SimpleX non possono vedere il tuo profilo.</target>
<target>profilo del gruppo aggiornato</target>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="v%@" xml:space="preserve">
<source>v%@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="v%@ (%@)" xml:space="preserve">
<source>v%@ (%@)</source>
<target>v%@ (%@)</target>
@@ -6485,6 +6677,10 @@ I server di SimpleX non possono vedere il tuo profilo.</target>
<target>SimpleX usa Face ID per l'autenticazione locale</target>
<note>Privacy - Face ID Usage Description</note>
</trans-unit>
<trans-unit id="NSLocalNetworkUsageDescription" xml:space="preserve">
<source>SimpleX uses local network access to allow using user chat profile via desktop app on the same network.</source>
<note>Privacy - Local Network Usage Description</note>
</trans-unit>
<trans-unit id="NSMicrophoneUsageDescription" xml:space="preserve">
<source>SimpleX needs microphone access for audio and video calls, and to record voice messages.</source>
<target>SimpleX ha bisogno dell'accesso al microfono per le chiamate audio e video e per registrare messaggi vocali.</target>
@@ -4,6 +4,8 @@
"NSCameraUsageDescription" = "SimpleX needs camera access to scan QR codes to connect to other users and for video calls.";
/* Privacy - Face ID Usage Description */
"NSFaceIDUsageDescription" = "SimpleX uses Face ID for local authentication";
/* Privacy - Local Network Usage Description */
"NSLocalNetworkUsageDescription" = "SimpleX uses local network access to allow using user chat profile via desktop app on the same network.";
/* Privacy - Microphone Usage Description */
"NSMicrophoneUsageDescription" = "SimpleX needs microphone access for audio and video calls, and to record voice messages.";
/* Privacy - Photo Library Additions Usage Description */
@@ -290,6 +290,14 @@
<target>(</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(new)" xml:space="preserve">
<source>(new)</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(this device v%@)" xml:space="preserve">
<source>(this device v%@)</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=")" xml:space="preserve">
<source>)</source>
<target>)</target>
@@ -855,6 +863,10 @@
<target>戻る</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Bad desktop address" xml:space="preserve">
<source>Bad desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Bad message ID" xml:space="preserve">
<source>Bad message ID</source>
<target>メッセージ ID が正しくありません</target>
@@ -1148,6 +1160,10 @@
<target>シークレットモードで接続</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to desktop" xml:space="preserve">
<source>Connect to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to yourself?" xml:space="preserve">
<source>Connect to yourself?</source>
<note>No comment provided by engineer.</note>
@@ -1185,6 +1201,14 @@ This is your own one-time link!</source>
<source>Connect with %@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connected desktop" xml:space="preserve">
<source>Connected desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connected to desktop" xml:space="preserve">
<source>Connected to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connecting server…" xml:space="preserve">
<source>Connecting to server…</source>
<target>サーバーに接続中…</target>
@@ -1195,6 +1219,10 @@ This is your own one-time link!</source>
<target>サーバーに接続中… (エラー: %@)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connecting to desktop" xml:space="preserve">
<source>Connecting to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection" xml:space="preserve">
<source>Connection</source>
<target>接続</target>
@@ -1215,6 +1243,10 @@ This is your own one-time link!</source>
<target>接続リクエストを送信しました!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection terminated" xml:space="preserve">
<source>Connection terminated</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection timeout" xml:space="preserve">
<source>Connection timeout</source>
<target>接続タイムアウト</target>
@@ -1698,6 +1730,18 @@ This cannot be undone!</source>
<target>説明</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop address" xml:space="preserve">
<source>Desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop app version %@ is not compatible with this app." xml:space="preserve">
<source>Desktop app version %@ is not compatible with this app.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop devices" xml:space="preserve">
<source>Desktop devices</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Develop" xml:space="preserve">
<source>Develop</source>
<target>開発</target>
@@ -1788,11 +1832,19 @@ This cannot be undone!</source>
<target>切断</target>
<note>server test step</note>
</trans-unit>
<trans-unit id="Disconnect desktop?" xml:space="preserve">
<source>Disconnect desktop?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Discover and join groups" xml:space="preserve">
<source>Discover and join groups</source>
<target>グループを見つけて参加する</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Discover on network" xml:space="preserve">
<source>Discover on network</source>
<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>緊急通報にSimpleXを使用しないでください。</target>
@@ -1963,6 +2015,14 @@ This cannot be undone!</source>
<target>暗号化されたメッセージ : 予期しないエラー</target>
<note>notification</note>
</trans-unit>
<trans-unit id="Encryption re-negotiation error" xml:space="preserve">
<source>Encryption re-negotiation error</source>
<note>message decrypt error item</note>
</trans-unit>
<trans-unit id="Encryption re-negotiation failed." xml:space="preserve">
<source>Encryption re-negotiation failed.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter Passcode" xml:space="preserve">
<source>Enter Passcode</source>
<target>パスコードを入力</target>
@@ -1992,6 +2052,10 @@ This cannot be undone!</source>
<target>サーバを手動で入力</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter this device name…" xml:space="preserve">
<source>Enter this device name…</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter welcome message…" xml:space="preserve">
<source>Enter welcome message…</source>
<target>ウェルカムメッセージを入力してください…</target>
@@ -2760,6 +2824,10 @@ This cannot be undone!</source>
<target>データベースのバージョンと互換性がない</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Incompatible version" xml:space="preserve">
<source>Incompatible version</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Incorrect passcode" xml:space="preserve">
<source>Incorrect passcode</source>
<target>パスコードが正しくありません</target>
@@ -2925,6 +2993,10 @@ This is your link for group %@!</source>
<target>グループに参加</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Keep the app open to use it from desktop" xml:space="preserve">
<source>Keep the app open to use it from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Keep your connections" xml:space="preserve">
<source>Keep your connections</source>
<target>接続を維持</target>
@@ -2985,6 +3057,14 @@ This is your link for group %@!</source>
<target>制限事項</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Linked desktop options" xml:space="preserve">
<source>Linked desktop options</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Linked desktops" xml:space="preserve">
<source>Linked desktops</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Live message!" xml:space="preserve">
<source>Live message!</source>
<target>ライブメッセージ!</target>
@@ -3551,6 +3631,10 @@ This is your link for group %@!</source>
<target>貼り付け</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Paste desktop address" xml:space="preserve">
<source>Paste desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Paste image" xml:space="preserve">
<source>Paste image</source>
<target>画像の貼り付け</target>
@@ -4141,6 +4225,10 @@ This is your link for group %@!</source>
<target>QRコードを読み込む</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scan QR code from desktop" xml:space="preserve">
<source>Scan QR code from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scan code" xml:space="preserve">
<source>Scan code</source>
<target>コードを読み込む</target>
@@ -4353,6 +4441,10 @@ This is your link for group %@!</source>
<target>サーバ</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Session code" xml:space="preserve">
<source>Session code</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set 1 day" xml:space="preserve">
<source>Set 1 day</source>
<target>1日に設定</target>
@@ -4849,6 +4941,10 @@ It can happen because of some bug or when the connection is compromised.</source
<target>あなたのプロフィール、連絡先、メッセージ、ファイルが完全削除されます (※元に戻せません※)。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This device name" xml:space="preserve">
<source>This device name</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This group has over %lld members, delivery receipts are not sent." xml:space="preserve">
<source>This group has over %lld members, delivery receipts are not sent.</source>
<note>No comment provided by engineer.</note>
@@ -5036,6 +5132,14 @@ To connect, please ask your contact to create another connection link and check
接続するには、連絡先に別の接続リンクを作成するよう依頼し、ネットワーク接続が安定していることを確認してください。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlink" xml:space="preserve">
<source>Unlink</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlink desktop?" xml:space="preserve">
<source>Unlink desktop?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlock" xml:space="preserve">
<source>Unlock</source>
<target>ロック解除</target>
@@ -5126,6 +5230,10 @@ To connect, please ask your contact to create another connection link and check
<target>新しい接続に使う</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use from desktop" xml:space="preserve">
<source>Use from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use iOS call interface" xml:space="preserve">
<source>Use iOS call interface</source>
<target>iOS通話インターフェースを使用する</target>
@@ -5156,11 +5264,23 @@ To connect, please ask your contact to create another connection link and check
<target>SimpleX チャット サーバーを使用する。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify code with desktop" xml:space="preserve">
<source>Verify code with desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connection" xml:space="preserve">
<source>Verify connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connection security" xml:space="preserve">
<source>Verify connection security</source>
<target>接続のセキュリティを確認</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connections" xml:space="preserve">
<source>Verify connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify security code" xml:space="preserve">
<source>Verify security code</source>
<target>セキュリティコードを確認</target>
@@ -6329,6 +6449,10 @@ SimpleX サーバーはあなたのプロファイルを参照できません。
<target>グループプロフィールを更新しました</target>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="v%@" xml:space="preserve">
<source>v%@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="v%@ (%@)" xml:space="preserve">
<source>v%@ (%@)</source>
<target>v%@ (%@)</target>
@@ -6466,6 +6590,10 @@ SimpleX サーバーはあなたのプロファイルを参照できません。
<target>SimpleX はローカル認証に Face ID を使用します</target>
<note>Privacy - Face ID Usage Description</note>
</trans-unit>
<trans-unit id="NSLocalNetworkUsageDescription" xml:space="preserve">
<source>SimpleX uses local network access to allow using user chat profile via desktop app on the same network.</source>
<note>Privacy - Local Network Usage Description</note>
</trans-unit>
<trans-unit id="NSMicrophoneUsageDescription" xml:space="preserve">
<source>SimpleX needs microphone access for audio and video calls, and to record voice messages.</source>
<target>SimpleX では、音声通話やビデオ通話、および音声メッセージの録音のためにマイクへのアクセスが必要です。</target>
@@ -4,6 +4,8 @@
"NSCameraUsageDescription" = "SimpleX needs camera access to scan QR codes to connect to other users and for video calls.";
/* Privacy - Face ID Usage Description */
"NSFaceIDUsageDescription" = "SimpleX uses Face ID for local authentication";
/* Privacy - Local Network Usage Description */
"NSLocalNetworkUsageDescription" = "SimpleX uses local network access to allow using user chat profile via desktop app on the same network.";
/* Privacy - Microphone Usage Description */
"NSMicrophoneUsageDescription" = "SimpleX needs microphone access for audio and video calls, and to record voice messages.";
/* Privacy - Photo Library Additions Usage Description */
@@ -89,6 +89,7 @@
</trans-unit>
<trans-unit id="%@ and %@" xml:space="preserve">
<source>%@ and %@</source>
<target>%@ en %@</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ and %@ connected" xml:space="preserve">
@@ -103,6 +104,7 @@
</trans-unit>
<trans-unit id="%@ connected" xml:space="preserve">
<source>%@ connected</source>
<target>%@ verbonden</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ is connected!" xml:space="preserve">
@@ -132,6 +134,7 @@
</trans-unit>
<trans-unit id="%@, %@ and %lld members" xml:space="preserve">
<source>%@, %@ and %lld members</source>
<target>%@, %@ en %lld leden</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@, %@ and %lld other members connected" xml:space="preserve">
@@ -201,6 +204,7 @@
</trans-unit>
<trans-unit id="%lld group events" xml:space="preserve">
<source>%lld group events</source>
<target>%lld groep gebeurtenissen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%lld members" xml:space="preserve">
@@ -210,14 +214,17 @@
</trans-unit>
<trans-unit id="%lld messages blocked" xml:space="preserve">
<source>%lld messages blocked</source>
<target>%lld berichten geblokkeerd</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%lld messages marked deleted" xml:space="preserve">
<source>%lld messages marked deleted</source>
<target>%lld berichten gemarkeerd als verwijderd</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%lld messages moderated by %@" xml:space="preserve">
<source>%lld messages moderated by %@</source>
<target>%lld berichten gemodereerd door %@</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%lld minutes" xml:space="preserve">
@@ -290,6 +297,14 @@
<target>(</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(new)" xml:space="preserve">
<source>(new)</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(this device v%@)" xml:space="preserve">
<source>(this device v%@)</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=")" xml:space="preserve">
<source>)</source>
<target>)</target>
@@ -394,6 +409,7 @@
</trans-unit>
<trans-unit id="0 sec" xml:space="preserve">
<source>0 sec</source>
<target>0 sec</target>
<note>time to disappear</note>
</trans-unit>
<trans-unit id="0s" xml:space="preserve">
@@ -623,6 +639,7 @@
</trans-unit>
<trans-unit id="All new messages from %@ will be hidden!" xml:space="preserve">
<source>All new messages from %@ will be hidden!</source>
<target>Alle nieuwe berichten van %@ worden verborgen!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
@@ -732,10 +749,12 @@
</trans-unit>
<trans-unit id="Already connecting!" xml:space="preserve">
<source>Already connecting!</source>
<target>Al bezig met verbinden!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Already joining the group!" xml:space="preserve">
<source>Already joining the group!</source>
<target>Al lid van de groep!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Always use relay" xml:space="preserve">
@@ -858,6 +877,10 @@
<target>Terug</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Bad desktop address" xml:space="preserve">
<source>Bad desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Bad message ID" xml:space="preserve">
<source>Bad message ID</source>
<target>Onjuiste bericht-ID</target>
@@ -875,14 +898,17 @@
</trans-unit>
<trans-unit id="Block" xml:space="preserve">
<source>Block</source>
<target>Blokkeren</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Block member" xml:space="preserve">
<source>Block member</source>
<target>Lid blokkeren</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Block member?" xml:space="preserve">
<source>Block member?</source>
<target>Lid blokkeren?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Both you and your contact can add message reactions." xml:space="preserve">
@@ -977,7 +1003,7 @@
</trans-unit>
<trans-unit id="Change member role?" xml:space="preserve">
<source>Change member role?</source>
<target>Rol van gebruiker wijzigen?</target>
<target>Rol van lid wijzigen?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Change passcode" xml:space="preserve">
@@ -1151,22 +1177,32 @@
<target>Verbind incognito</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to desktop" xml:space="preserve">
<source>Connect to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to yourself?" xml:space="preserve">
<source>Connect to yourself?</source>
<target>Verbinding maken met jezelf?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to yourself?&#10;This is your own SimpleX address!" xml:space="preserve">
<source>Connect to yourself?
This is your own SimpleX address!</source>
<target>Verbinding maken met jezelf?
Dit is uw eigen SimpleX adres!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to yourself?&#10;This is your own one-time link!" xml:space="preserve">
<source>Connect to yourself?
This is your own one-time link!</source>
<target>Verbinding maken met jezelf?
Dit is uw eigen eenmalige link!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect via contact address" xml:space="preserve">
<source>Connect via contact address</source>
<target>Verbinding maken via contactadres</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect via link" xml:space="preserve">
@@ -1186,6 +1222,15 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Connect with %@" xml:space="preserve">
<source>Connect with %@</source>
<target>Verbonden met %@</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connected desktop" xml:space="preserve">
<source>Connected desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connected to desktop" xml:space="preserve">
<source>Connected to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connecting server…" xml:space="preserve">
@@ -1198,6 +1243,10 @@ This is your own one-time link!</source>
<target>Verbinden met server... (fout: %@)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connecting to desktop" xml:space="preserve">
<source>Connecting to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection" xml:space="preserve">
<source>Connection</source>
<target>Verbinding</target>
@@ -1218,6 +1267,10 @@ This is your own one-time link!</source>
<target>Verbindingsverzoek verzonden!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection terminated" xml:space="preserve">
<source>Connection terminated</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection timeout" xml:space="preserve">
<source>Connection timeout</source>
<target>Timeout verbinding</target>
@@ -1285,6 +1338,7 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Correct name to %@?" xml:space="preserve">
<source>Correct name to %@?</source>
<target>Juiste naam voor %@?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create" xml:space="preserve">
@@ -1309,6 +1363,7 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Create group" xml:space="preserve">
<source>Create group</source>
<target>Groep aanmaken</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create group link" xml:space="preserve">
@@ -1333,6 +1388,7 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Create profile" xml:space="preserve">
<source>Create profile</source>
<target>Maak een profiel aan</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create queue" xml:space="preserve">
@@ -1495,6 +1551,7 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Delete %lld messages?" xml:space="preserve">
<source>Delete %lld messages?</source>
<target>%lld berichten verwijderen?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete Contact" xml:space="preserve">
@@ -1524,6 +1581,7 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Delete and notify contact" xml:space="preserve">
<source>Delete and notify contact</source>
<target>Contact verwijderen en op de hoogte stellen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete archive" xml:space="preserve">
@@ -1559,6 +1617,8 @@ This is your own one-time link!</source>
<trans-unit id="Delete contact?&#10;This cannot be undone!" xml:space="preserve">
<source>Delete contact?
This cannot be undone!</source>
<target>Verwijder contact?
Dit kan niet ongedaan gemaakt worden!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete database" xml:space="preserve">
@@ -1701,6 +1761,18 @@ This cannot be undone!</source>
<target>Beschrijving</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop address" xml:space="preserve">
<source>Desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop app version %@ is not compatible with this app." xml:space="preserve">
<source>Desktop app version %@ is not compatible with this app.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop devices" xml:space="preserve">
<source>Desktop devices</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Develop" xml:space="preserve">
<source>Develop</source>
<target>Ontwikkelen</target>
@@ -1791,11 +1863,19 @@ This cannot be undone!</source>
<target>verbinding verbreken</target>
<note>server test step</note>
</trans-unit>
<trans-unit id="Disconnect desktop?" xml:space="preserve">
<source>Disconnect desktop?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Discover and join groups" xml:space="preserve">
<source>Discover and join groups</source>
<target>Ontdek en sluit je aan bij groepen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Discover on network" xml:space="preserve">
<source>Discover on network</source>
<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>Gebruik SimpleX NIET voor noodoproepen.</target>
@@ -1966,6 +2046,14 @@ This cannot be undone!</source>
<target>Versleuteld bericht: onverwachte fout</target>
<note>notification</note>
</trans-unit>
<trans-unit id="Encryption re-negotiation error" xml:space="preserve">
<source>Encryption re-negotiation error</source>
<note>message decrypt error item</note>
</trans-unit>
<trans-unit id="Encryption re-negotiation failed." xml:space="preserve">
<source>Encryption re-negotiation failed.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter Passcode" xml:space="preserve">
<source>Enter Passcode</source>
<target>Voer toegangscode in</target>
@@ -1978,6 +2066,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Enter group name…" xml:space="preserve">
<source>Enter group name…</source>
<target>Groep naam invoeren…</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter passphrase…" xml:space="preserve">
@@ -1995,6 +2084,10 @@ This cannot be undone!</source>
<target>Voer de server handmatig in</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter this device name…" xml:space="preserve">
<source>Enter this device name…</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter welcome message…" xml:space="preserve">
<source>Enter welcome message…</source>
<target>Welkomst bericht invoeren…</target>
@@ -2007,6 +2100,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Enter your name…" xml:space="preserve">
<source>Enter your name…</source>
<target>Vul uw naam in…</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error" xml:space="preserve">
@@ -2031,7 +2125,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Error adding member(s)" xml:space="preserve">
<source>Error adding member(s)</source>
<target>Fout bij het toevoegen van gebruiker(s)</target>
<target>Fout bij het toevoegen van leden</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error changing address" xml:space="preserve">
@@ -2161,7 +2255,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Error removing member" xml:space="preserve">
<source>Error removing member</source>
<target>Fout bij verwijderen van gebruiker</target>
<target>Fout bij verwijderen van lid</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error saving %@ servers" xml:space="preserve">
@@ -2286,6 +2380,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Expand" xml:space="preserve">
<source>Expand</source>
<target>Uitbreiden</target>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Export database" xml:space="preserve">
@@ -2435,6 +2530,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Fully decentralized visible only to members." xml:space="preserve">
<source>Fully decentralized visible only to members.</source>
<target>Volledig gedecentraliseerd alleen zichtbaar voor leden.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Fully re-implemented - work in background!" xml:space="preserve">
@@ -2459,10 +2555,12 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Group already exists" xml:space="preserve">
<source>Group already exists</source>
<target>Groep bestaat al</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group already exists!" xml:space="preserve">
<source>Group already exists!</source>
<target>Groep bestaat al!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group display name" xml:space="preserve">
@@ -2765,6 +2863,10 @@ This cannot be undone!</source>
<target>Incompatibele database versie</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Incompatible version" xml:space="preserve">
<source>Incompatible version</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Incorrect passcode" xml:space="preserve">
<source>Incorrect passcode</source>
<target>Onjuiste toegangscode</target>
@@ -2814,6 +2916,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Invalid name!" xml:space="preserve">
<source>Invalid name!</source>
<target>Ongeldige naam!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Invalid server address!" xml:space="preserve">
@@ -2909,6 +3012,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Join group?" xml:space="preserve">
<source>Join group?</source>
<target>Deelnemen aan groep?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Join incognito" xml:space="preserve">
@@ -2918,11 +3022,14 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Join with current profile" xml:space="preserve">
<source>Join with current profile</source>
<target>Word lid met huidig profiel</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Join your group?&#10;This is your link for group %@!" xml:space="preserve">
<source>Join your group?
This is your link for group %@!</source>
<target>Sluit u aan bij uw groep?
Dit is jouw link voor groep %@!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Joining group" xml:space="preserve">
@@ -2930,6 +3037,10 @@ This is your link for group %@!</source>
<target>Deel nemen aan groep</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Keep the app open to use it from desktop" xml:space="preserve">
<source>Keep the app open to use it from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Keep your connections" xml:space="preserve">
<source>Keep your connections</source>
<target>Behoud uw verbindingen</target>
@@ -2990,6 +3101,14 @@ This is your link for group %@!</source>
<target>Beperkingen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Linked desktop options" xml:space="preserve">
<source>Linked desktop options</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Linked desktops" xml:space="preserve">
<source>Linked desktops</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Live message!" xml:space="preserve">
<source>Live message!</source>
<target>Live bericht!</target>
@@ -3077,22 +3196,22 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Member" xml:space="preserve">
<source>Member</source>
<target>Gebruiker</target>
<target>Lid</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Member role will be changed to &quot;%@&quot;. All group members will be notified." xml:space="preserve">
<source>Member role will be changed to "%@". All group members will be notified.</source>
<target>De rol van gebruiker wordt gewijzigd in "%@". Alle groepsleden worden op de hoogte gebracht.</target>
<target>De rol van lid wordt gewijzigd in "%@". Alle groepsleden worden op de hoogte gebracht.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Member role will be changed to &quot;%@&quot;. The member will receive a new invitation." xml:space="preserve">
<source>Member role will be changed to "%@". The member will receive a new invitation.</source>
<target>De rol van gebruiker wordt gewijzigd in "%@". Het lid ontvangt een nieuwe uitnodiging.</target>
<target>De rol van lid wordt gewijzigd in "%@". Het lid ontvangt een nieuwe uitnodiging.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Member will be removed from group - this cannot be undone!" xml:space="preserve">
<source>Member will be removed from group - this cannot be undone!</source>
<target>Gebruiker wordt uit de groep verwijderd, dit kan niet ongedaan worden gemaakt!</target>
<target>Lid wordt uit de groep verwijderd, dit kan niet ongedaan worden gemaakt!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message delivery error" xml:space="preserve">
@@ -3142,6 +3261,7 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Messages from %@ will be shown!" xml:space="preserve">
<source>Messages from %@ will be shown!</source>
<target>Berichten van %@ worden getoond!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Migrating database archive…" xml:space="preserve">
@@ -3415,7 +3535,7 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Only group owners can enable files and media." xml:space="preserve">
<source>Only group owners can enable files and media.</source>
<target>Alleen groepseigenaren kunnen bestanden en media inschakelen.</target>
<target>Alleen groep eigenaren kunnen bestanden en media inschakelen.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Only group owners can enable voice messages." xml:space="preserve">
@@ -3495,6 +3615,7 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Open group" xml:space="preserve">
<source>Open group</source>
<target>Open groep</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Open user profiles" xml:space="preserve">
@@ -3557,6 +3678,10 @@ This is your link for group %@!</source>
<target>Plakken</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Paste desktop address" xml:space="preserve">
<source>Paste desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Paste image" xml:space="preserve">
<source>Paste image</source>
<target>Afbeelding plakken</target>
@@ -3704,10 +3829,12 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Profile name" xml:space="preserve">
<source>Profile name</source>
<target>Profielnaam</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile name:" xml:space="preserve">
<source>Profile name:</source>
<target>Profielnaam:</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile password" xml:space="preserve">
@@ -3927,12 +4054,12 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Remove member" xml:space="preserve">
<source>Remove member</source>
<target>Gebruiker verwijderen</target>
<target>Lid verwijderen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Remove member?" xml:space="preserve">
<source>Remove member?</source>
<target>Gebruiker verwijderen?</target>
<target>Lid verwijderen?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Remove passphrase from keychain?" xml:space="preserve">
@@ -3957,10 +4084,12 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Repeat connection request?" xml:space="preserve">
<source>Repeat connection request?</source>
<target>Verbindingsverzoek herhalen?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Repeat join request?" xml:space="preserve">
<source>Repeat join request?</source>
<target>Deelnameverzoek herhalen?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Reply" xml:space="preserve">
@@ -4075,7 +4204,7 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Save and notify group members" xml:space="preserve">
<source>Save and notify group members</source>
<target>Opslaan en Groep leden melden</target>
<target>Opslaan en groep leden melden</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Save and update group profile" xml:space="preserve">
@@ -4148,6 +4277,10 @@ This is your link for group %@!</source>
<target>Scan QR-code</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scan QR code from desktop" xml:space="preserve">
<source>Scan QR code from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scan code" xml:space="preserve">
<source>Scan code</source>
<target>Code scannen</target>
@@ -4368,6 +4501,10 @@ This is your link for group %@!</source>
<target>Servers</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Session code" xml:space="preserve">
<source>Session code</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set 1 day" xml:space="preserve">
<source>Set 1 day</source>
<target>Stel 1 dag in</target>
@@ -4680,6 +4817,7 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Tap to Connect" xml:space="preserve">
<source>Tap to Connect</source>
<target>Tik om verbinding te maken</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Tap to activate profile." xml:space="preserve">
@@ -4689,12 +4827,12 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Tap to join" xml:space="preserve">
<source>Tap to join</source>
<target>Tik om mee te doen</target>
<target>Tik om lid te worden</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Tap to join incognito" xml:space="preserve">
<source>Tap to join incognito</source>
<target>Tik om incognito deel te nemen</target>
<target>Tik om incognito lid te worden</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Tap to start a new chat" xml:space="preserve">
@@ -4864,6 +5002,10 @@ Het kan gebeuren vanwege een bug of wanneer de verbinding is aangetast.</target>
<target>Deze actie kan niet ongedaan worden gemaakt. Uw profiel, contacten, berichten en bestanden gaan onomkeerbaar verloren.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This device name" xml:space="preserve">
<source>This device name</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This group has over %lld members, delivery receipts are not sent." xml:space="preserve">
<source>This group has over %lld members, delivery receipts are not sent.</source>
<target>Deze groep heeft meer dan %lld -leden, ontvangstbevestigingen worden niet verzonden.</target>
@@ -4876,10 +5018,12 @@ Het kan gebeuren vanwege een bug of wanneer de verbinding is aangetast.</target>
</trans-unit>
<trans-unit id="This is your own SimpleX address!" xml:space="preserve">
<source>This is your own SimpleX address!</source>
<target>Dit is uw eigen SimpleX adres!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This is your own one-time link!" xml:space="preserve">
<source>This is your own one-time link!</source>
<target>Dit is uw eigen eenmalige link!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This setting applies to messages in your current chat profile **%@**." xml:space="preserve">
@@ -4981,14 +5125,17 @@ U wordt gevraagd de authenticatie te voltooien voordat deze functie wordt ingesc
</trans-unit>
<trans-unit id="Unblock" xml:space="preserve">
<source>Unblock</source>
<target>Deblokkeren</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unblock member" xml:space="preserve">
<source>Unblock member</source>
<target>Lid deblokkeren</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unblock member?" xml:space="preserve">
<source>Unblock member?</source>
<target>Lid deblokkeren?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unexpected error: %@" xml:space="preserve">
@@ -5053,6 +5200,14 @@ To connect, please ask your contact to create another connection link and check
Om verbinding te maken, vraagt u uw contact om een andere verbinding link te maken en te controleren of u een stabiele netwerkverbinding heeft.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlink" xml:space="preserve">
<source>Unlink</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlink desktop?" xml:space="preserve">
<source>Unlink desktop?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlock" xml:space="preserve">
<source>Unlock</source>
<target>Ontgrendelen</target>
@@ -5143,6 +5298,10 @@ Om verbinding te maken, vraagt u uw contact om een andere verbinding link te mak
<target>Gebruik voor nieuwe verbindingen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use from desktop" xml:space="preserve">
<source>Use from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use iOS call interface" xml:space="preserve">
<source>Use iOS call interface</source>
<target>De iOS-oproepinterface gebruiken</target>
@@ -5173,11 +5332,23 @@ Om verbinding te maken, vraagt u uw contact om een andere verbinding link te mak
<target>SimpleX Chat servers gebruiken.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify code with desktop" xml:space="preserve">
<source>Verify code with desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connection" xml:space="preserve">
<source>Verify connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connection security" xml:space="preserve">
<source>Verify connection security</source>
<target>Controleer de verbindingsbeveiliging</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connections" xml:space="preserve">
<source>Verify connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify security code" xml:space="preserve">
<source>Verify security code</source>
<target>Controleer de beveiligingscode</target>
@@ -5340,31 +5511,39 @@ Om verbinding te maken, vraagt u uw contact om een andere verbinding link te mak
</trans-unit>
<trans-unit id="You are already connecting to %@." xml:space="preserve">
<source>You are already connecting to %@.</source>
<target>U maakt al verbinding met %@.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You are already connecting via this one-time link!" xml:space="preserve">
<source>You are already connecting via this one-time link!</source>
<target>Je maakt al verbinding via deze eenmalige link!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You are already in group %@." xml:space="preserve">
<source>You are already in group %@.</source>
<target>Je zit al in groep %@.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You are already joining the group %@." xml:space="preserve">
<source>You are already joining the group %@.</source>
<target>Je bent al lid van de groep %@.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You are already joining the group via this link!" xml:space="preserve">
<source>You are already joining the group via this link!</source>
<target>Je wordt al lid van de groep via deze link!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You are already joining the group via this link." xml:space="preserve">
<source>You are already joining the group via this link.</source>
<target>Je wordt al lid van de groep via deze link.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You are already joining the group!&#10;Repeat join request?" xml:space="preserve">
<source>You are already joining the group!
Repeat join request?</source>
<target>Je sluit je al aan bij de groep!
Deelnameverzoek herhalen?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You are connected to the server used to receive messages from this contact." xml:space="preserve">
@@ -5464,11 +5643,14 @@ Repeat join request?</source>
</trans-unit>
<trans-unit id="You have already requested connection via this address!" xml:space="preserve">
<source>You have already requested connection via this address!</source>
<target>U heeft al een verbinding aangevraagd via dit adres!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You have already requested connection!&#10;Repeat connection request?" xml:space="preserve">
<source>You have already requested connection!
Repeat connection request?</source>
<target>Je hebt al verbinding aangevraagd!
Verbindingsverzoek herhalen?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You have no chats" xml:space="preserve">
@@ -5523,6 +5705,7 @@ Repeat connection request?</source>
</trans-unit>
<trans-unit id="You will be connected when group link host's device is online, please wait or check later!" xml:space="preserve">
<source>You will be connected when group link host's device is online, please wait or check later!</source>
<target>U wordt verbonden wanneer het apparaat van de groep link host online is. Wacht even of controleer het later opnieuw!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You will be connected when your connection request is accepted, please wait or check later!" xml:space="preserve">
@@ -5542,6 +5725,7 @@ Repeat connection request?</source>
</trans-unit>
<trans-unit id="You will connect to all group members." xml:space="preserve">
<source>You will connect to all group members.</source>
<target>Je maakt verbinding met alle leden.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You will still receive calls and notifications from muted profiles when they are active." xml:space="preserve">
@@ -5665,6 +5849,7 @@ U kunt dit wijzigen in Instellingen.</target>
</trans-unit>
<trans-unit id="Your profile" xml:space="preserve">
<source>Your profile</source>
<target>Jouw profiel</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your profile **%@** will be shared." xml:space="preserve">
@@ -5761,6 +5946,7 @@ SimpleX servers kunnen uw profiel niet zien.</target>
</trans-unit>
<trans-unit id="and %lld other events" xml:space="preserve">
<source>and %lld other events</source>
<target>en %lld andere gebeurtenissen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="audio call (not e2e encrypted)" xml:space="preserve">
@@ -5780,6 +5966,7 @@ SimpleX servers kunnen uw profiel niet zien.</target>
</trans-unit>
<trans-unit id="blocked" xml:space="preserve">
<source>blocked</source>
<target>geblokkeerd</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="bold" xml:space="preserve">
@@ -5954,6 +6141,7 @@ SimpleX servers kunnen uw profiel niet zien.</target>
</trans-unit>
<trans-unit id="deleted contact" xml:space="preserve">
<source>deleted contact</source>
<target>verwijderd contact</target>
<note>rcv direct event chat item</note>
</trans-unit>
<trans-unit id="deleted group" xml:space="preserve">
@@ -6168,7 +6356,7 @@ SimpleX servers kunnen uw profiel niet zien.</target>
</trans-unit>
<trans-unit id="member" xml:space="preserve">
<source>member</source>
<target>gebruiker</target>
<target>lid</target>
<note>member role</note>
</trans-unit>
<trans-unit id="member connected" xml:space="preserve">
@@ -6348,6 +6536,10 @@ SimpleX servers kunnen uw profiel niet zien.</target>
<target>bijgewerkt groep profiel</target>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="v%@" xml:space="preserve">
<source>v%@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="v%@ (%@)" xml:space="preserve">
<source>v%@ (%@)</source>
<target>v%@ (%@)</target>
@@ -6485,6 +6677,10 @@ SimpleX servers kunnen uw profiel niet zien.</target>
<target>SimpleX gebruikt Face-ID voor lokale authenticatie</target>
<note>Privacy - Face ID Usage Description</note>
</trans-unit>
<trans-unit id="NSLocalNetworkUsageDescription" xml:space="preserve">
<source>SimpleX uses local network access to allow using user chat profile via desktop app on the same network.</source>
<note>Privacy - Local Network Usage Description</note>
</trans-unit>
<trans-unit id="NSMicrophoneUsageDescription" xml:space="preserve">
<source>SimpleX needs microphone access for audio and video calls, and to record voice messages.</source>
<target>SimpleX heeft microfoon toegang nodig voor audio en video oproepen en om spraak berichten op te nemen.</target>
@@ -4,6 +4,8 @@
"NSCameraUsageDescription" = "SimpleX needs camera access to scan QR codes to connect to other users and for video calls.";
/* Privacy - Face ID Usage Description */
"NSFaceIDUsageDescription" = "SimpleX uses Face ID for local authentication";
/* Privacy - Local Network Usage Description */
"NSLocalNetworkUsageDescription" = "SimpleX uses local network access to allow using user chat profile via desktop app on the same network.";
/* Privacy - Microphone Usage Description */
"NSMicrophoneUsageDescription" = "SimpleX needs microphone access for audio and video calls, and to record voice messages.";
/* Privacy - Photo Library Additions Usage Description */
@@ -89,6 +89,7 @@
</trans-unit>
<trans-unit id="%@ and %@" xml:space="preserve">
<source>%@ and %@</source>
<target>%@ i %@</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ and %@ connected" xml:space="preserve">
@@ -103,6 +104,7 @@
</trans-unit>
<trans-unit id="%@ connected" xml:space="preserve">
<source>%@ connected</source>
<target>%@ połączony</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@ is connected!" xml:space="preserve">
@@ -132,6 +134,7 @@
</trans-unit>
<trans-unit id="%@, %@ and %lld members" xml:space="preserve">
<source>%@, %@ and %lld members</source>
<target>%@, %@ i %lld członków</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%@, %@ and %lld other members connected" xml:space="preserve">
@@ -201,6 +204,7 @@
</trans-unit>
<trans-unit id="%lld group events" xml:space="preserve">
<source>%lld group events</source>
<target>%lld wydarzeń grupy</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%lld members" xml:space="preserve">
@@ -210,14 +214,17 @@
</trans-unit>
<trans-unit id="%lld messages blocked" xml:space="preserve">
<source>%lld messages blocked</source>
<target>%lld wiadomości zablokowanych</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%lld messages marked deleted" xml:space="preserve">
<source>%lld messages marked deleted</source>
<target>%lld wiadomości oznaczonych do usunięcia</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%lld messages moderated by %@" xml:space="preserve">
<source>%lld messages moderated by %@</source>
<target>%lld wiadomości zmoderowanych przez %@</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="%lld minutes" xml:space="preserve">
@@ -290,6 +297,14 @@
<target>(</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(new)" xml:space="preserve">
<source>(new)</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(this device v%@)" xml:space="preserve">
<source>(this device v%@)</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=")" xml:space="preserve">
<source>)</source>
<target>)</target>
@@ -394,6 +409,7 @@
</trans-unit>
<trans-unit id="0 sec" xml:space="preserve">
<source>0 sec</source>
<target>0 sek</target>
<note>time to disappear</note>
</trans-unit>
<trans-unit id="0s" xml:space="preserve">
@@ -623,6 +639,7 @@
</trans-unit>
<trans-unit id="All new messages from %@ will be hidden!" xml:space="preserve">
<source>All new messages from %@ will be hidden!</source>
<target>Wszystkie nowe wiadomości z %@ zostaną ukryte!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="All your contacts will remain connected." xml:space="preserve">
@@ -732,10 +749,12 @@
</trans-unit>
<trans-unit id="Already connecting!" xml:space="preserve">
<source>Already connecting!</source>
<target>Już połączony!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Already joining the group!" xml:space="preserve">
<source>Already joining the group!</source>
<target>Już dołączono do grupy!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Always use relay" xml:space="preserve">
@@ -858,6 +877,10 @@
<target>Wstecz</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Bad desktop address" xml:space="preserve">
<source>Bad desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Bad message ID" xml:space="preserve">
<source>Bad message ID</source>
<target>Zły identyfikator wiadomości</target>
@@ -875,14 +898,17 @@
</trans-unit>
<trans-unit id="Block" xml:space="preserve">
<source>Block</source>
<target>Zablokuj</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Block member" xml:space="preserve">
<source>Block member</source>
<target>Zablokuj członka</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Block member?" xml:space="preserve">
<source>Block member?</source>
<target>Zablokować członka?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Both you and your contact can add message reactions." xml:space="preserve">
@@ -1151,22 +1177,32 @@
<target>Połącz incognito</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to desktop" xml:space="preserve">
<source>Connect to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to yourself?" xml:space="preserve">
<source>Connect to yourself?</source>
<target>Połączyć się ze sobą?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to yourself?&#10;This is your own SimpleX address!" xml:space="preserve">
<source>Connect to yourself?
This is your own SimpleX address!</source>
<target>Połączyć się ze sobą?
To jest twój własny adres SimpleX!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to yourself?&#10;This is your own one-time link!" xml:space="preserve">
<source>Connect to yourself?
This is your own one-time link!</source>
<target>Połączyć się ze sobą?
To jest twój jednorazowy link!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect via contact address" xml:space="preserve">
<source>Connect via contact address</source>
<target>Połącz przez adres kontaktowy</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect via link" xml:space="preserve">
@@ -1186,6 +1222,15 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Connect with %@" xml:space="preserve">
<source>Connect with %@</source>
<target>Połącz z %@</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connected desktop" xml:space="preserve">
<source>Connected desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connected to desktop" xml:space="preserve">
<source>Connected to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connecting server…" xml:space="preserve">
@@ -1198,6 +1243,10 @@ This is your own one-time link!</source>
<target>Łączenie z serwerem... (błąd: %@)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connecting to desktop" xml:space="preserve">
<source>Connecting to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection" xml:space="preserve">
<source>Connection</source>
<target>Połączenie</target>
@@ -1218,6 +1267,10 @@ This is your own one-time link!</source>
<target>Prośba o połączenie wysłana!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection terminated" xml:space="preserve">
<source>Connection terminated</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection timeout" xml:space="preserve">
<source>Connection timeout</source>
<target>Czas połączenia minął</target>
@@ -1285,6 +1338,7 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Correct name to %@?" xml:space="preserve">
<source>Correct name to %@?</source>
<target>Poprawić imię na %@?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create" xml:space="preserve">
@@ -1309,6 +1363,7 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Create group" xml:space="preserve">
<source>Create group</source>
<target>Utwórz grupę</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create group link" xml:space="preserve">
@@ -1333,6 +1388,7 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Create profile" xml:space="preserve">
<source>Create profile</source>
<target>Utwórz profil</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create queue" xml:space="preserve">
@@ -1495,6 +1551,7 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Delete %lld messages?" xml:space="preserve">
<source>Delete %lld messages?</source>
<target>Usunąć %lld wiadomości?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete Contact" xml:space="preserve">
@@ -1524,6 +1581,7 @@ This is your own one-time link!</source>
</trans-unit>
<trans-unit id="Delete and notify contact" xml:space="preserve">
<source>Delete and notify contact</source>
<target>Usuń i powiadom kontakt</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete archive" xml:space="preserve">
@@ -1559,6 +1617,8 @@ This is your own one-time link!</source>
<trans-unit id="Delete contact?&#10;This cannot be undone!" xml:space="preserve">
<source>Delete contact?
This cannot be undone!</source>
<target>Usunąć kontakt?
To nie może być cofnięte!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete database" xml:space="preserve">
@@ -1701,6 +1761,18 @@ This cannot be undone!</source>
<target>Opis</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop address" xml:space="preserve">
<source>Desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop app version %@ is not compatible with this app." xml:space="preserve">
<source>Desktop app version %@ is not compatible with this app.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop devices" xml:space="preserve">
<source>Desktop devices</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Develop" xml:space="preserve">
<source>Develop</source>
<target>Deweloperskie</target>
@@ -1791,11 +1863,19 @@ This cannot be undone!</source>
<target>Rozłącz</target>
<note>server test step</note>
</trans-unit>
<trans-unit id="Disconnect desktop?" xml:space="preserve">
<source>Disconnect desktop?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Discover and join groups" xml:space="preserve">
<source>Discover and join groups</source>
<target>Odkrywaj i dołączaj do grup</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Discover on network" xml:space="preserve">
<source>Discover on network</source>
<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>NIE używaj SimpleX do połączeń alarmowych.</target>
@@ -1966,6 +2046,14 @@ This cannot be undone!</source>
<target>Zaszyfrowana wiadomość: nieoczekiwany błąd</target>
<note>notification</note>
</trans-unit>
<trans-unit id="Encryption re-negotiation error" xml:space="preserve">
<source>Encryption re-negotiation error</source>
<note>message decrypt error item</note>
</trans-unit>
<trans-unit id="Encryption re-negotiation failed." xml:space="preserve">
<source>Encryption re-negotiation failed.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter Passcode" xml:space="preserve">
<source>Enter Passcode</source>
<target>Wprowadź Pin</target>
@@ -1978,6 +2066,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Enter group name…" xml:space="preserve">
<source>Enter group name…</source>
<target>Wpisz nazwę grupy…</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter passphrase…" xml:space="preserve">
@@ -1995,6 +2084,10 @@ This cannot be undone!</source>
<target>Wprowadź serwer ręcznie</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter this device name…" xml:space="preserve">
<source>Enter this device name…</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter welcome message…" xml:space="preserve">
<source>Enter welcome message…</source>
<target>Wpisz wiadomość powitalną…</target>
@@ -2007,6 +2100,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Enter your name…" xml:space="preserve">
<source>Enter your name…</source>
<target>Wpisz swoją nazwę…</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error" xml:space="preserve">
@@ -2286,6 +2380,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Expand" xml:space="preserve">
<source>Expand</source>
<target>Rozszerz</target>
<note>chat item action</note>
</trans-unit>
<trans-unit id="Export database" xml:space="preserve">
@@ -2435,6 +2530,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Fully decentralized visible only to members." xml:space="preserve">
<source>Fully decentralized visible only to members.</source>
<target>W pełni zdecentralizowana widoczna tylko dla członków.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Fully re-implemented - work in background!" xml:space="preserve">
@@ -2459,10 +2555,12 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Group already exists" xml:space="preserve">
<source>Group already exists</source>
<target>Grupa już istnieje</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group already exists!" xml:space="preserve">
<source>Group already exists!</source>
<target>Grupa już istnieje!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group display name" xml:space="preserve">
@@ -2765,6 +2863,10 @@ This cannot be undone!</source>
<target>Niekompatybilna wersja bazy danych</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Incompatible version" xml:space="preserve">
<source>Incompatible version</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Incorrect passcode" xml:space="preserve">
<source>Incorrect passcode</source>
<target>Nieprawidłowy pin</target>
@@ -2814,6 +2916,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Invalid name!" xml:space="preserve">
<source>Invalid name!</source>
<target>Nieprawidłowa nazwa!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Invalid server address!" xml:space="preserve">
@@ -2909,6 +3012,7 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Join group?" xml:space="preserve">
<source>Join group?</source>
<target>Dołączyć do grupy?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Join incognito" xml:space="preserve">
@@ -2918,11 +3022,14 @@ This cannot be undone!</source>
</trans-unit>
<trans-unit id="Join with current profile" xml:space="preserve">
<source>Join with current profile</source>
<target>Dołącz z obecnym profilem</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Join your group?&#10;This is your link for group %@!" xml:space="preserve">
<source>Join your group?
This is your link for group %@!</source>
<target>Dołączyć do twojej grupy?
To jest twój link do grupy %@!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Joining group" xml:space="preserve">
@@ -2930,6 +3037,10 @@ This is your link for group %@!</source>
<target>Dołączanie do grupy</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Keep the app open to use it from desktop" xml:space="preserve">
<source>Keep the app open to use it from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Keep your connections" xml:space="preserve">
<source>Keep your connections</source>
<target>Zachowaj swoje połączenia</target>
@@ -2990,6 +3101,14 @@ This is your link for group %@!</source>
<target>Ograniczenia</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Linked desktop options" xml:space="preserve">
<source>Linked desktop options</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Linked desktops" xml:space="preserve">
<source>Linked desktops</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Live message!" xml:space="preserve">
<source>Live message!</source>
<target>Wiadomość na żywo!</target>
@@ -3142,6 +3261,7 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Messages from %@ will be shown!" xml:space="preserve">
<source>Messages from %@ will be shown!</source>
<target>Wiadomości od %@ zostaną pokazane!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Migrating database archive…" xml:space="preserve">
@@ -3495,6 +3615,7 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Open group" xml:space="preserve">
<source>Open group</source>
<target>Grupa otwarta</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Open user profiles" xml:space="preserve">
@@ -3557,6 +3678,10 @@ This is your link for group %@!</source>
<target>Wklej</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Paste desktop address" xml:space="preserve">
<source>Paste desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Paste image" xml:space="preserve">
<source>Paste image</source>
<target>Wklej obraz</target>
@@ -3704,10 +3829,12 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Profile name" xml:space="preserve">
<source>Profile name</source>
<target>Nazwa profilu</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile name:" xml:space="preserve">
<source>Profile name:</source>
<target>Nazwa profilu:</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile password" xml:space="preserve">
@@ -3957,10 +4084,12 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Repeat connection request?" xml:space="preserve">
<source>Repeat connection request?</source>
<target>Powtórzyć prośbę połączenia?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Repeat join request?" xml:space="preserve">
<source>Repeat join request?</source>
<target>Powtórzyć prośbę dołączenia?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Reply" xml:space="preserve">
@@ -4148,6 +4277,10 @@ This is your link for group %@!</source>
<target>Zeskanuj kod QR</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scan QR code from desktop" xml:space="preserve">
<source>Scan QR code from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scan code" xml:space="preserve">
<source>Scan code</source>
<target>Zeskanuj kod</target>
@@ -4368,6 +4501,10 @@ This is your link for group %@!</source>
<target>Serwery</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Session code" xml:space="preserve">
<source>Session code</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set 1 day" xml:space="preserve">
<source>Set 1 day</source>
<target>Ustaw 1 dzień</target>
@@ -4680,6 +4817,7 @@ This is your link for group %@!</source>
</trans-unit>
<trans-unit id="Tap to Connect" xml:space="preserve">
<source>Tap to Connect</source>
<target>Dotknij aby połączyć</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Tap to activate profile." xml:space="preserve">
@@ -4864,6 +5002,10 @@ Może się to zdarzyć z powodu jakiegoś błędu lub gdy połączenie jest skom
<target>Tego działania nie można cofnąć - Twój profil, kontakty, wiadomości i pliki zostaną nieodwracalnie utracone.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This device name" xml:space="preserve">
<source>This device name</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This group has over %lld members, delivery receipts are not sent." xml:space="preserve">
<source>This group has over %lld members, delivery receipts are not sent.</source>
<target>Ta grupa ma ponad %lld członków, potwierdzenia dostawy nie są wysyłane.</target>
@@ -4876,10 +5018,12 @@ Może się to zdarzyć z powodu jakiegoś błędu lub gdy połączenie jest skom
</trans-unit>
<trans-unit id="This is your own SimpleX address!" xml:space="preserve">
<source>This is your own SimpleX address!</source>
<target>To jest twój własny adres SimpleX!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This is your own one-time link!" xml:space="preserve">
<source>This is your own one-time link!</source>
<target>To jest twój jednorazowy link!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This setting applies to messages in your current chat profile **%@**." xml:space="preserve">
@@ -4981,14 +5125,17 @@ Przed włączeniem tej funkcji zostanie wyświetlony monit uwierzytelniania.</ta
</trans-unit>
<trans-unit id="Unblock" xml:space="preserve">
<source>Unblock</source>
<target>Odblokuj</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unblock member" xml:space="preserve">
<source>Unblock member</source>
<target>Odblokuj członka</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unblock member?" xml:space="preserve">
<source>Unblock member?</source>
<target>Odblokować członka?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unexpected error: %@" xml:space="preserve">
@@ -5053,6 +5200,14 @@ To connect, please ask your contact to create another connection link and check
Aby się połączyć, poproś Twój kontakt o utworzenie kolejnego linku połączenia i sprawdź, czy masz stabilne połączenie z siecią.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlink" xml:space="preserve">
<source>Unlink</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlink desktop?" xml:space="preserve">
<source>Unlink desktop?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlock" xml:space="preserve">
<source>Unlock</source>
<target>Odblokuj</target>
@@ -5143,6 +5298,10 @@ Aby się połączyć, poproś Twój kontakt o utworzenie kolejnego linku połąc
<target>Użyj dla nowych połączeń</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use from desktop" xml:space="preserve">
<source>Use from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use iOS call interface" xml:space="preserve">
<source>Use iOS call interface</source>
<target>Użyj interfejsu połączeń iOS</target>
@@ -5173,11 +5332,23 @@ Aby się połączyć, poproś Twój kontakt o utworzenie kolejnego linku połąc
<target>Używanie serwerów SimpleX Chat.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify code with desktop" xml:space="preserve">
<source>Verify code with desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connection" xml:space="preserve">
<source>Verify connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connection security" xml:space="preserve">
<source>Verify connection security</source>
<target>Weryfikuj bezpieczeństwo połączenia</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connections" xml:space="preserve">
<source>Verify connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify security code" xml:space="preserve">
<source>Verify security code</source>
<target>Weryfikuj kod bezpieczeństwa</target>
@@ -5340,31 +5511,39 @@ Aby się połączyć, poproś Twój kontakt o utworzenie kolejnego linku połąc
</trans-unit>
<trans-unit id="You are already connecting to %@." xml:space="preserve">
<source>You are already connecting to %@.</source>
<target>Już się łączysz z %@.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You are already connecting via this one-time link!" xml:space="preserve">
<source>You are already connecting via this one-time link!</source>
<target>Już jesteś połączony z tym jednorazowym linkiem!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You are already in group %@." xml:space="preserve">
<source>You are already in group %@.</source>
<target>Już jesteś w grupie %@.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You are already joining the group %@." xml:space="preserve">
<source>You are already joining the group %@.</source>
<target>Już dołączasz do grupy %@.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You are already joining the group via this link!" xml:space="preserve">
<source>You are already joining the group via this link!</source>
<target>Już dołączasz do grupy przez ten link!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You are already joining the group via this link." xml:space="preserve">
<source>You are already joining the group via this link.</source>
<target>Już dołączasz do grupy przez ten link.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You are already joining the group!&#10;Repeat join request?" xml:space="preserve">
<source>You are already joining the group!
Repeat join request?</source>
<target>Już dołączasz do grupy!
Powtórzyć prośbę dołączenia?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You are connected to the server used to receive messages from this contact." xml:space="preserve">
@@ -5464,11 +5643,14 @@ Repeat join request?</source>
</trans-unit>
<trans-unit id="You have already requested connection via this address!" xml:space="preserve">
<source>You have already requested connection via this address!</source>
<target>Już prosiłeś o połączenie na ten adres!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You have already requested connection!&#10;Repeat connection request?" xml:space="preserve">
<source>You have already requested connection!
Repeat connection request?</source>
<target>Już prosiłeś o połączenie!
Powtórzyć prośbę połączenia?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You have no chats" xml:space="preserve">
@@ -5523,6 +5705,7 @@ Repeat connection request?</source>
</trans-unit>
<trans-unit id="You will be connected when group link host's device is online, please wait or check later!" xml:space="preserve">
<source>You will be connected when group link host's device is online, please wait or check later!</source>
<target>Zostaniesz połączony, gdy urządzenie hosta grupy będzie online, proszę czekać lub sprawdzić później!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You will be connected when your connection request is accepted, please wait or check later!" xml:space="preserve">
@@ -5542,6 +5725,7 @@ Repeat connection request?</source>
</trans-unit>
<trans-unit id="You will connect to all group members." xml:space="preserve">
<source>You will connect to all group members.</source>
<target>Zostaniesz połączony ze wszystkimi członkami grupy.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="You will still receive calls and notifications from muted profiles when they are active." xml:space="preserve">
@@ -5665,6 +5849,7 @@ Możesz to zmienić w Ustawieniach.</target>
</trans-unit>
<trans-unit id="Your profile" xml:space="preserve">
<source>Your profile</source>
<target>Twój profil</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your profile **%@** will be shared." xml:space="preserve">
@@ -5761,6 +5946,7 @@ Serwery SimpleX nie mogą zobaczyć Twojego profilu.</target>
</trans-unit>
<trans-unit id="and %lld other events" xml:space="preserve">
<source>and %lld other events</source>
<target>i %lld innych wydarzeń</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="audio call (not e2e encrypted)" xml:space="preserve">
@@ -5780,6 +5966,7 @@ Serwery SimpleX nie mogą zobaczyć Twojego profilu.</target>
</trans-unit>
<trans-unit id="blocked" xml:space="preserve">
<source>blocked</source>
<target>zablokowany</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="bold" xml:space="preserve">
@@ -5954,6 +6141,7 @@ Serwery SimpleX nie mogą zobaczyć Twojego profilu.</target>
</trans-unit>
<trans-unit id="deleted contact" xml:space="preserve">
<source>deleted contact</source>
<target>usunięto kontakt</target>
<note>rcv direct event chat item</note>
</trans-unit>
<trans-unit id="deleted group" xml:space="preserve">
@@ -6348,6 +6536,10 @@ Serwery SimpleX nie mogą zobaczyć Twojego profilu.</target>
<target>zaktualizowano profil grupy</target>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="v%@" xml:space="preserve">
<source>v%@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="v%@ (%@)" xml:space="preserve">
<source>v%@ (%@)</source>
<target>v%@ (%@)</target>
@@ -6485,6 +6677,10 @@ Serwery SimpleX nie mogą zobaczyć Twojego profilu.</target>
<target>SimpleX używa Face ID do lokalnego uwierzytelniania</target>
<note>Privacy - Face ID Usage Description</note>
</trans-unit>
<trans-unit id="NSLocalNetworkUsageDescription" xml:space="preserve">
<source>SimpleX uses local network access to allow using user chat profile via desktop app on the same network.</source>
<note>Privacy - Local Network Usage Description</note>
</trans-unit>
<trans-unit id="NSMicrophoneUsageDescription" xml:space="preserve">
<source>SimpleX needs microphone access for audio and video calls, and to record voice messages.</source>
<target>SimpleX potrzebuje dostępu do mikrofonu, w celu połączeń audio i wideo oraz nagrywania wiadomości głosowych.</target>
@@ -4,6 +4,8 @@
"NSCameraUsageDescription" = "SimpleX needs camera access to scan QR codes to connect to other users and for video calls.";
/* Privacy - Face ID Usage Description */
"NSFaceIDUsageDescription" = "SimpleX uses Face ID for local authentication";
/* Privacy - Local Network Usage Description */
"NSLocalNetworkUsageDescription" = "SimpleX uses local network access to allow using user chat profile via desktop app on the same network.";
/* Privacy - Microphone Usage Description */
"NSMicrophoneUsageDescription" = "SimpleX needs microphone access for audio and video calls, and to record voice messages.";
/* Privacy - Photo Library Additions Usage Description */
@@ -290,6 +290,14 @@
<target>(</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(new)" xml:space="preserve">
<source>(new)</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(this device v%@)" xml:space="preserve">
<source>(this device v%@)</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=")" xml:space="preserve">
<source>)</source>
<target>)</target>
@@ -858,6 +866,10 @@
<target>Назад</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Bad desktop address" xml:space="preserve">
<source>Bad desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Bad message ID" xml:space="preserve">
<source>Bad message ID</source>
<target>Ошибка ID сообщения</target>
@@ -1151,6 +1163,10 @@
<target>Соединиться Инкогнито</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to desktop" xml:space="preserve">
<source>Connect to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to yourself?" xml:space="preserve">
<source>Connect to yourself?</source>
<note>No comment provided by engineer.</note>
@@ -1188,6 +1204,14 @@ This is your own one-time link!</source>
<source>Connect with %@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connected desktop" xml:space="preserve">
<source>Connected desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connected to desktop" xml:space="preserve">
<source>Connected to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connecting server…" xml:space="preserve">
<source>Connecting to server…</source>
<target>Устанавливается соединение с сервером…</target>
@@ -1198,6 +1222,10 @@ This is your own one-time link!</source>
<target>Устанавливается соединение с сервером… (ошибка: %@)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connecting to desktop" xml:space="preserve">
<source>Connecting to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection" xml:space="preserve">
<source>Connection</source>
<target>Соединение</target>
@@ -1218,6 +1246,10 @@ This is your own one-time link!</source>
<target>Запрос на соединение отправлен!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection terminated" xml:space="preserve">
<source>Connection terminated</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection timeout" xml:space="preserve">
<source>Connection timeout</source>
<target>Превышено время соединения</target>
@@ -1701,6 +1733,18 @@ This cannot be undone!</source>
<target>Описание</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop address" xml:space="preserve">
<source>Desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop app version %@ is not compatible with this app." xml:space="preserve">
<source>Desktop app version %@ is not compatible with this app.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop devices" xml:space="preserve">
<source>Desktop devices</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Develop" xml:space="preserve">
<source>Develop</source>
<target>Для разработчиков</target>
@@ -1791,11 +1835,19 @@ This cannot be undone!</source>
<target>Разрыв соединения</target>
<note>server test step</note>
</trans-unit>
<trans-unit id="Disconnect desktop?" xml:space="preserve">
<source>Disconnect desktop?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Discover and join groups" xml:space="preserve">
<source>Discover and join groups</source>
<target>Найдите и вступите в группы</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Discover on network" xml:space="preserve">
<source>Discover on network</source>
<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>Не используйте SimpleX для экстренных звонков.</target>
@@ -1966,6 +2018,14 @@ This cannot be undone!</source>
<target>Зашифрованное сообщение: неожиданная ошибка</target>
<note>notification</note>
</trans-unit>
<trans-unit id="Encryption re-negotiation error" xml:space="preserve">
<source>Encryption re-negotiation error</source>
<note>message decrypt error item</note>
</trans-unit>
<trans-unit id="Encryption re-negotiation failed." xml:space="preserve">
<source>Encryption re-negotiation failed.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter Passcode" xml:space="preserve">
<source>Enter Passcode</source>
<target>Введите Код</target>
@@ -1995,6 +2055,10 @@ This cannot be undone!</source>
<target>Ввести сервер вручную</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter this device name…" xml:space="preserve">
<source>Enter this device name…</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter welcome message…" xml:space="preserve">
<source>Enter welcome message…</source>
<target>Введите приветственное сообщение…</target>
@@ -2763,6 +2827,10 @@ This cannot be undone!</source>
<target>Несовместимая версия базы данных</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Incompatible version" xml:space="preserve">
<source>Incompatible version</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Incorrect passcode" xml:space="preserve">
<source>Incorrect passcode</source>
<target>Неправильный код</target>
@@ -2928,6 +2996,10 @@ This is your link for group %@!</source>
<target>Вступление в группу</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Keep the app open to use it from desktop" xml:space="preserve">
<source>Keep the app open to use it from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Keep your connections" xml:space="preserve">
<source>Keep your connections</source>
<target>Сохраните Ваши соединения</target>
@@ -2988,6 +3060,14 @@ This is your link for group %@!</source>
<target>Ограничения</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Linked desktop options" xml:space="preserve">
<source>Linked desktop options</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Linked desktops" xml:space="preserve">
<source>Linked desktops</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Live message!" xml:space="preserve">
<source>Live message!</source>
<target>Живое сообщение!</target>
@@ -3554,6 +3634,10 @@ This is your link for group %@!</source>
<target>Вставить</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Paste desktop address" xml:space="preserve">
<source>Paste desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Paste image" xml:space="preserve">
<source>Paste image</source>
<target>Вставить изображение</target>
@@ -4145,6 +4229,10 @@ This is your link for group %@!</source>
<target>Сканировать QR код</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scan QR code from desktop" xml:space="preserve">
<source>Scan QR code from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scan code" xml:space="preserve">
<source>Scan code</source>
<target>Сканировать код</target>
@@ -4364,6 +4452,10 @@ This is your link for group %@!</source>
<target>Серверы</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Session code" xml:space="preserve">
<source>Session code</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set 1 day" xml:space="preserve">
<source>Set 1 day</source>
<target>Установить 1 день</target>
@@ -4860,6 +4952,10 @@ It can happen because of some bug or when the connection is compromised.</source
<target>Это действие нельзя отменить — Ваш профиль, контакты, сообщения и файлы будут безвозвратно утеряны.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This device name" xml:space="preserve">
<source>This device name</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This group has over %lld members, delivery receipts are not sent." xml:space="preserve">
<source>This group has over %lld members, delivery receipts are not sent.</source>
<target>В группе более %lld членов, отчёты о доставке выключены.</target>
@@ -5049,6 +5145,14 @@ To connect, please ask your contact to create another connection link and check
Чтобы установить соединение, попросите Ваш контакт создать еще одну ссылку и проверьте Ваше соединение с сетью.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlink" xml:space="preserve">
<source>Unlink</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlink desktop?" xml:space="preserve">
<source>Unlink desktop?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlock" xml:space="preserve">
<source>Unlock</source>
<target>Разблокировать</target>
@@ -5139,6 +5243,10 @@ To connect, please ask your contact to create another connection link and check
<target>Использовать для новых соединений</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use from desktop" xml:space="preserve">
<source>Use from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use iOS call interface" xml:space="preserve">
<source>Use iOS call interface</source>
<target>Использовать интерфейс iOS для звонков</target>
@@ -5169,11 +5277,23 @@ To connect, please ask your contact to create another connection link and check
<target>Используются серверы, предоставленные SimpleX Chat.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify code with desktop" xml:space="preserve">
<source>Verify code with desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connection" xml:space="preserve">
<source>Verify connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connection security" xml:space="preserve">
<source>Verify connection security</source>
<target>Проверить безопасность соединения</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connections" xml:space="preserve">
<source>Verify connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify security code" xml:space="preserve">
<source>Verify security code</source>
<target>Подтвердить код безопасности</target>
@@ -6342,6 +6462,10 @@ SimpleX серверы не могут получить доступ к Ваше
<target>обновил(а) профиль группы</target>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="v%@" xml:space="preserve">
<source>v%@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="v%@ (%@)" xml:space="preserve">
<source>v%@ (%@)</source>
<target>v%@ (%@)</target>
@@ -6479,6 +6603,10 @@ SimpleX серверы не могут получить доступ к Ваше
<target>SimpleX использует Face ID для аутентификации</target>
<note>Privacy - Face ID Usage Description</note>
</trans-unit>
<trans-unit id="NSLocalNetworkUsageDescription" xml:space="preserve">
<source>SimpleX uses local network access to allow using user chat profile via desktop app on the same network.</source>
<note>Privacy - Local Network Usage Description</note>
</trans-unit>
<trans-unit id="NSMicrophoneUsageDescription" xml:space="preserve">
<source>SimpleX needs microphone access for audio and video calls, and to record voice messages.</source>
<target>SimpleX использует микрофон для аудио и видео звонков, и для записи голосовых сообщений.</target>
@@ -4,6 +4,8 @@
"NSCameraUsageDescription" = "SimpleX needs camera access to scan QR codes to connect to other users and for video calls.";
/* Privacy - Face ID Usage Description */
"NSFaceIDUsageDescription" = "SimpleX uses Face ID for local authentication";
/* Privacy - Local Network Usage Description */
"NSLocalNetworkUsageDescription" = "SimpleX uses local network access to allow using user chat profile via desktop app on the same network.";
/* Privacy - Microphone Usage Description */
"NSMicrophoneUsageDescription" = "SimpleX needs microphone access for audio and video calls, and to record voice messages.";
/* Privacy - Photo Library Additions Usage Description */
@@ -284,6 +284,14 @@
<target>(</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(new)" xml:space="preserve">
<source>(new)</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(this device v%@)" xml:space="preserve">
<source>(this device v%@)</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=")" xml:space="preserve">
<source>)</source>
<target>)</target>
@@ -846,6 +854,10 @@
<target>กลับ</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Bad desktop address" xml:space="preserve">
<source>Bad desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Bad message ID" xml:space="preserve">
<source>Bad message ID</source>
<target>ID ข้อความที่ไม่ดี</target>
@@ -1137,6 +1149,10 @@
<source>Connect incognito</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to desktop" xml:space="preserve">
<source>Connect to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to yourself?" xml:space="preserve">
<source>Connect to yourself?</source>
<note>No comment provided by engineer.</note>
@@ -1173,6 +1189,14 @@ This is your own one-time link!</source>
<source>Connect with %@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connected desktop" xml:space="preserve">
<source>Connected desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connected to desktop" xml:space="preserve">
<source>Connected to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connecting server…" xml:space="preserve">
<source>Connecting to server…</source>
<target>กำลังเชื่อมต่อกับเซิร์ฟเวอร์…</target>
@@ -1183,6 +1207,10 @@ This is your own one-time link!</source>
<target>กำลังเชื่อมต่อกับเซิร์ฟเวอร์... (ข้อผิดพลาด: %@)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connecting to desktop" xml:space="preserve">
<source>Connecting to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection" xml:space="preserve">
<source>Connection</source>
<target>การเชื่อมต่อ</target>
@@ -1203,6 +1231,10 @@ This is your own one-time link!</source>
<target>ส่งคําขอเชื่อมต่อแล้ว!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection terminated" xml:space="preserve">
<source>Connection terminated</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection timeout" xml:space="preserve">
<source>Connection timeout</source>
<target>หมดเวลาการเชื่อมต่อ</target>
@@ -1684,6 +1716,18 @@ This cannot be undone!</source>
<target>คำอธิบาย</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop address" xml:space="preserve">
<source>Desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop app version %@ is not compatible with this app." xml:space="preserve">
<source>Desktop app version %@ is not compatible with this app.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop devices" xml:space="preserve">
<source>Desktop devices</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Develop" xml:space="preserve">
<source>Develop</source>
<target>พัฒนา</target>
@@ -1774,10 +1818,18 @@ This cannot be undone!</source>
<target>ตัดการเชื่อมต่อ</target>
<note>server test step</note>
</trans-unit>
<trans-unit id="Disconnect desktop?" xml:space="preserve">
<source>Disconnect desktop?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Discover and join groups" xml:space="preserve">
<source>Discover and join groups</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Discover on network" xml:space="preserve">
<source>Discover on network</source>
<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>อย่าใช้ SimpleX สําหรับการโทรฉุกเฉิน</target>
@@ -1946,6 +1998,14 @@ This cannot be undone!</source>
<target>ข้อความที่ encrypt: ข้อผิดพลาดที่ไม่คาดคิด</target>
<note>notification</note>
</trans-unit>
<trans-unit id="Encryption re-negotiation error" xml:space="preserve">
<source>Encryption re-negotiation error</source>
<note>message decrypt error item</note>
</trans-unit>
<trans-unit id="Encryption re-negotiation failed." xml:space="preserve">
<source>Encryption re-negotiation failed.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter Passcode" xml:space="preserve">
<source>Enter Passcode</source>
<target>ใส่รหัสผ่าน</target>
@@ -1975,6 +2035,10 @@ This cannot be undone!</source>
<target>ใส่เซิร์ฟเวอร์ด้วยตนเอง</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter this device name…" xml:space="preserve">
<source>Enter this device name…</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter welcome message…" xml:space="preserve">
<source>Enter welcome message…</source>
<target>ใส่ข้อความต้อนรับ…</target>
@@ -2741,6 +2805,10 @@ This cannot be undone!</source>
<target>เวอร์ชันฐานข้อมูลที่เข้ากันไม่ได้</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Incompatible version" xml:space="preserve">
<source>Incompatible version</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Incorrect passcode" xml:space="preserve">
<source>Incorrect passcode</source>
<target>รหัสผ่านไม่ถูกต้อง</target>
@@ -2905,6 +2973,10 @@ This is your link for group %@!</source>
<target>กำลังจะเข้าร่วมกลุ่ม</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Keep the app open to use it from desktop" xml:space="preserve">
<source>Keep the app open to use it from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Keep your connections" xml:space="preserve">
<source>Keep your connections</source>
<target>รักษาการเชื่อมต่อของคุณ</target>
@@ -2965,6 +3037,14 @@ This is your link for group %@!</source>
<target>ข้อจำกัด</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Linked desktop options" xml:space="preserve">
<source>Linked desktop options</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Linked desktops" xml:space="preserve">
<source>Linked desktops</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Live message!" xml:space="preserve">
<source>Live message!</source>
<target>ข้อความสด!</target>
@@ -3528,6 +3608,10 @@ This is your link for group %@!</source>
<target>แปะ</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Paste desktop address" xml:space="preserve">
<source>Paste desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Paste image" xml:space="preserve">
<source>Paste image</source>
<target>แปะภาพ</target>
@@ -4116,6 +4200,10 @@ This is your link for group %@!</source>
<target>สแกนคิวอาร์โค้ด</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scan QR code from desktop" xml:space="preserve">
<source>Scan QR code from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scan code" xml:space="preserve">
<source>Scan code</source>
<target>สแกนรหัส</target>
@@ -4333,6 +4421,10 @@ This is your link for group %@!</source>
<target>เซิร์ฟเวอร์</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Session code" xml:space="preserve">
<source>Session code</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set 1 day" xml:space="preserve">
<source>Set 1 day</source>
<target>ตั้ง 1 วัน</target>
@@ -4826,6 +4918,10 @@ It can happen because of some bug or when the connection is compromised.</source
<target>การดำเนินการนี้ไม่สามารถยกเลิกได้ - โปรไฟล์ ผู้ติดต่อ ข้อความ และไฟล์ของคุณจะสูญหายไปอย่างถาวร</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This device name" xml:space="preserve">
<source>This device name</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This group has over %lld members, delivery receipts are not sent." xml:space="preserve">
<source>This group has over %lld members, delivery receipts are not sent.</source>
<note>No comment provided by engineer.</note>
@@ -5013,6 +5109,14 @@ To connect, please ask your contact to create another connection link and check
ในการเชื่อมต่อ โปรดขอให้ผู้ติดต่อของคุณสร้างลิงก์การเชื่อมต่ออื่น และตรวจสอบว่าคุณมีการเชื่อมต่อเครือข่ายที่เสถียร</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlink" xml:space="preserve">
<source>Unlink</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlink desktop?" xml:space="preserve">
<source>Unlink desktop?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlock" xml:space="preserve">
<source>Unlock</source>
<target>ปลดล็อค</target>
@@ -5102,6 +5206,10 @@ To connect, please ask your contact to create another connection link and check
<target>ใช้สำหรับการเชื่อมต่อใหม่</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use from desktop" xml:space="preserve">
<source>Use from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use iOS call interface" xml:space="preserve">
<source>Use iOS call interface</source>
<target>ใช้อินเทอร์เฟซการโทร iOS</target>
@@ -5131,11 +5239,23 @@ To connect, please ask your contact to create another connection link and check
<target>กำลังใช้เซิร์ฟเวอร์ SimpleX Chat อยู่</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify code with desktop" xml:space="preserve">
<source>Verify code with desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connection" xml:space="preserve">
<source>Verify connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connection security" xml:space="preserve">
<source>Verify connection security</source>
<target>ตรวจสอบความปลอดภัยในการเชื่อมต่อ</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connections" xml:space="preserve">
<source>Verify connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify security code" xml:space="preserve">
<source>Verify security code</source>
<target>ตรวจสอบรหัสความปลอดภัย</target>
@@ -6300,6 +6420,10 @@ SimpleX servers cannot see your profile.</source>
<target>อัปเดตโปรไฟล์กลุ่มแล้ว</target>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="v%@" xml:space="preserve">
<source>v%@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="v%@ (%@)" xml:space="preserve">
<source>v%@ (%@)</source>
<target>v%@ (%@)</target>
@@ -6437,6 +6561,10 @@ SimpleX servers cannot see your profile.</source>
<target>SimpleX ใช้ Face ID สำหรับการรับรองความถูกต้องในเครื่อง</target>
<note>Privacy - Face ID Usage Description</note>
</trans-unit>
<trans-unit id="NSLocalNetworkUsageDescription" xml:space="preserve">
<source>SimpleX uses local network access to allow using user chat profile via desktop app on the same network.</source>
<note>Privacy - Local Network Usage Description</note>
</trans-unit>
<trans-unit id="NSMicrophoneUsageDescription" xml:space="preserve">
<source>SimpleX needs microphone access for audio and video calls, and to record voice messages.</source>
<target>SimpleX ต้องการการเข้าถึงไมโครโฟนสำหรับการโทรด้วยเสียงและวิดีโอ และเพื่อบันทึกข้อความเสียง</target>
@@ -4,6 +4,8 @@
"NSCameraUsageDescription" = "SimpleX needs camera access to scan QR codes to connect to other users and for video calls.";
/* Privacy - Face ID Usage Description */
"NSFaceIDUsageDescription" = "SimpleX uses Face ID for local authentication";
/* Privacy - Local Network Usage Description */
"NSLocalNetworkUsageDescription" = "SimpleX uses local network access to allow using user chat profile via desktop app on the same network.";
/* Privacy - Microphone Usage Description */
"NSMicrophoneUsageDescription" = "SimpleX needs microphone access for audio and video calls, and to record voice messages.";
/* Privacy - Photo Library Additions Usage Description */
@@ -289,6 +289,14 @@
<target>(</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(new)" xml:space="preserve">
<source>(new)</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(this device v%@)" xml:space="preserve">
<source>(this device v%@)</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=")" xml:space="preserve">
<source>)</source>
<target>)</target>
@@ -853,6 +861,10 @@
<target>Назад</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Bad desktop address" xml:space="preserve">
<source>Bad desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Bad message ID" xml:space="preserve">
<source>Bad message ID</source>
<target>Неправильний ідентифікатор повідомлення</target>
@@ -1145,6 +1157,10 @@
<target>Підключайтеся інкогніто</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to desktop" xml:space="preserve">
<source>Connect to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to yourself?" xml:space="preserve">
<source>Connect to yourself?</source>
<note>No comment provided by engineer.</note>
@@ -1182,6 +1198,14 @@ This is your own one-time link!</source>
<source>Connect with %@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connected desktop" xml:space="preserve">
<source>Connected desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connected to desktop" xml:space="preserve">
<source>Connected to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connecting server…" xml:space="preserve">
<source>Connecting to server…</source>
<target>Підключення до сервера…</target>
@@ -1192,6 +1216,10 @@ This is your own one-time link!</source>
<target>Підключення до сервера... (помилка: %@)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connecting to desktop" xml:space="preserve">
<source>Connecting to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection" xml:space="preserve">
<source>Connection</source>
<target>Підключення</target>
@@ -1212,6 +1240,10 @@ This is your own one-time link!</source>
<target>Запит на підключення відправлено!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection terminated" xml:space="preserve">
<source>Connection terminated</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection timeout" xml:space="preserve">
<source>Connection timeout</source>
<target>Тайм-аут з'єднання</target>
@@ -1694,6 +1726,18 @@ This cannot be undone!</source>
<target>Опис</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop address" xml:space="preserve">
<source>Desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop app version %@ is not compatible with this app." xml:space="preserve">
<source>Desktop app version %@ is not compatible with this app.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop devices" xml:space="preserve">
<source>Desktop devices</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Develop" xml:space="preserve">
<source>Develop</source>
<target>Розробник</target>
@@ -1784,10 +1828,18 @@ This cannot be undone!</source>
<target>Від'єднати</target>
<note>server test step</note>
</trans-unit>
<trans-unit id="Disconnect desktop?" xml:space="preserve">
<source>Disconnect desktop?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Discover and join groups" xml:space="preserve">
<source>Discover and join groups</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Discover on network" xml:space="preserve">
<source>Discover on network</source>
<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>НЕ використовуйте SimpleX для екстрених викликів.</target>
@@ -1956,6 +2008,14 @@ This cannot be undone!</source>
<target>Зашифроване повідомлення: несподівана помилка</target>
<note>notification</note>
</trans-unit>
<trans-unit id="Encryption re-negotiation error" xml:space="preserve">
<source>Encryption re-negotiation error</source>
<note>message decrypt error item</note>
</trans-unit>
<trans-unit id="Encryption re-negotiation failed." xml:space="preserve">
<source>Encryption re-negotiation failed.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter Passcode" xml:space="preserve">
<source>Enter Passcode</source>
<target>Введіть пароль</target>
@@ -1985,6 +2045,10 @@ This cannot be undone!</source>
<target>Увійдіть на сервер вручну</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter this device name…" xml:space="preserve">
<source>Enter this device name…</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter welcome message…" xml:space="preserve">
<source>Enter welcome message…</source>
<target>Введіть вітальне повідомлення…</target>
@@ -2752,6 +2816,10 @@ This cannot be undone!</source>
<target>Несумісна версія бази даних</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Incompatible version" xml:space="preserve">
<source>Incompatible version</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Incorrect passcode" xml:space="preserve">
<source>Incorrect passcode</source>
<target>Неправильний пароль</target>
@@ -2917,6 +2985,10 @@ This is your link for group %@!</source>
<target>Приєднання до групи</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Keep the app open to use it from desktop" xml:space="preserve">
<source>Keep the app open to use it from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Keep your connections" xml:space="preserve">
<source>Keep your connections</source>
<target>Зберігайте свої зв'язки</target>
@@ -2977,6 +3049,14 @@ This is your link for group %@!</source>
<target>Обмеження</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Linked desktop options" xml:space="preserve">
<source>Linked desktop options</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Linked desktops" xml:space="preserve">
<source>Linked desktops</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Live message!" xml:space="preserve">
<source>Live message!</source>
<target>Живе повідомлення!</target>
@@ -3542,6 +3622,10 @@ This is your link for group %@!</source>
<target>Вставити</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Paste desktop address" xml:space="preserve">
<source>Paste desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Paste image" xml:space="preserve">
<source>Paste image</source>
<target>Вставити зображення</target>
@@ -4133,6 +4217,10 @@ This is your link for group %@!</source>
<target>Відскануйте QR-код</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scan QR code from desktop" xml:space="preserve">
<source>Scan QR code from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scan code" xml:space="preserve">
<source>Scan code</source>
<target>Сканувати код</target>
@@ -4352,6 +4440,10 @@ This is your link for group %@!</source>
<target>Сервери</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Session code" xml:space="preserve">
<source>Session code</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set 1 day" xml:space="preserve">
<source>Set 1 day</source>
<target>Встановити 1 день</target>
@@ -4847,6 +4939,10 @@ It can happen because of some bug or when the connection is compromised.</source
<target>Цю дію неможливо скасувати - ваш профіль, контакти, повідомлення та файли будуть безповоротно втрачені.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This device name" xml:space="preserve">
<source>This device name</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This group has over %lld members, delivery receipts are not sent." xml:space="preserve">
<source>This group has over %lld members, delivery receipts are not sent.</source>
<target>У цій групі більше %lld учасників, підтвердження доставки не надсилаються.</target>
@@ -5035,6 +5131,14 @@ To connect, please ask your contact to create another connection link and check
Щоб підключитися, попросіть вашого контакта створити інше посилання і перевірте, чи маєте ви стабільне з'єднання з мережею.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlink" xml:space="preserve">
<source>Unlink</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlink desktop?" xml:space="preserve">
<source>Unlink desktop?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlock" xml:space="preserve">
<source>Unlock</source>
<target>Розблокувати</target>
@@ -5125,6 +5229,10 @@ To connect, please ask your contact to create another connection link and check
<target>Використовуйте для нових з'єднань</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use from desktop" xml:space="preserve">
<source>Use from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use iOS call interface" xml:space="preserve">
<source>Use iOS call interface</source>
<target>Використовуйте інтерфейс виклику iOS</target>
@@ -5155,11 +5263,23 @@ To connect, please ask your contact to create another connection link and check
<target>Використання серверів SimpleX Chat.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify code with desktop" xml:space="preserve">
<source>Verify code with desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connection" xml:space="preserve">
<source>Verify connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connection security" xml:space="preserve">
<source>Verify connection security</source>
<target>Перевірте безпеку з'єднання</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connections" xml:space="preserve">
<source>Verify connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify security code" xml:space="preserve">
<source>Verify security code</source>
<target>Підтвердіть код безпеки</target>
@@ -6328,6 +6448,10 @@ SimpleX servers cannot see your profile.</source>
<target>оновлений профіль групи</target>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="v%@" xml:space="preserve">
<source>v%@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="v%@ (%@)" xml:space="preserve">
<source>v%@ (%@)</source>
<target>v%@ (%@)</target>
@@ -6465,6 +6589,10 @@ SimpleX servers cannot see your profile.</source>
<target>SimpleX використовує Face ID для локальної автентифікації</target>
<note>Privacy - Face ID Usage Description</note>
</trans-unit>
<trans-unit id="NSLocalNetworkUsageDescription" xml:space="preserve">
<source>SimpleX uses local network access to allow using user chat profile via desktop app on the same network.</source>
<note>Privacy - Local Network Usage Description</note>
</trans-unit>
<trans-unit id="NSMicrophoneUsageDescription" xml:space="preserve">
<source>SimpleX needs microphone access for audio and video calls, and to record voice messages.</source>
<target>SimpleX потребує доступу до мікрофона для аудіо та відео дзвінків, а також для запису голосових повідомлень.</target>
@@ -4,6 +4,8 @@
"NSCameraUsageDescription" = "SimpleX needs camera access to scan QR codes to connect to other users and for video calls.";
/* Privacy - Face ID Usage Description */
"NSFaceIDUsageDescription" = "SimpleX uses Face ID for local authentication";
/* Privacy - Local Network Usage Description */
"NSLocalNetworkUsageDescription" = "SimpleX uses local network access to allow using user chat profile via desktop app on the same network.";
/* Privacy - Microphone Usage Description */
"NSMicrophoneUsageDescription" = "SimpleX needs microphone access for audio and video calls, and to record voice messages.";
/* Privacy - Photo Library Additions Usage Description */
@@ -290,6 +290,14 @@
<target>(</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(new)" xml:space="preserve">
<source>(new)</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="(this device v%@)" xml:space="preserve">
<source>(this device v%@)</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=")" xml:space="preserve">
<source>)</source>
<target>)</target>
@@ -858,6 +866,10 @@
<target>返回</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Bad desktop address" xml:space="preserve">
<source>Bad desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Bad message ID" xml:space="preserve">
<source>Bad message ID</source>
<target>错误消息 ID</target>
@@ -1151,6 +1163,10 @@
<target>在隐身状态下连接</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to desktop" xml:space="preserve">
<source>Connect to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connect to yourself?" xml:space="preserve">
<source>Connect to yourself?</source>
<note>No comment provided by engineer.</note>
@@ -1188,6 +1204,14 @@ This is your own one-time link!</source>
<source>Connect with %@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connected desktop" xml:space="preserve">
<source>Connected desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connected to desktop" xml:space="preserve">
<source>Connected to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connecting server…" xml:space="preserve">
<source>Connecting to server…</source>
<target>连接服务器中……</target>
@@ -1198,6 +1222,10 @@ This is your own one-time link!</source>
<target>连接服务器中……(错误:%@</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connecting to desktop" xml:space="preserve">
<source>Connecting to desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection" xml:space="preserve">
<source>Connection</source>
<target>连接</target>
@@ -1218,6 +1246,10 @@ This is your own one-time link!</source>
<target>已发送连接请求!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection terminated" xml:space="preserve">
<source>Connection terminated</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Connection timeout" xml:space="preserve">
<source>Connection timeout</source>
<target>连接超时</target>
@@ -1701,6 +1733,18 @@ This cannot be undone!</source>
<target>描述</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop address" xml:space="preserve">
<source>Desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop app version %@ is not compatible with this app." xml:space="preserve">
<source>Desktop app version %@ is not compatible with this app.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Desktop devices" xml:space="preserve">
<source>Desktop devices</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Develop" xml:space="preserve">
<source>Develop</source>
<target>开发</target>
@@ -1791,11 +1835,19 @@ This cannot be undone!</source>
<target>断开连接</target>
<note>server test step</note>
</trans-unit>
<trans-unit id="Disconnect desktop?" xml:space="preserve">
<source>Disconnect desktop?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Discover and join groups" xml:space="preserve">
<source>Discover and join groups</source>
<target>发现和加入群组</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Discover on network" xml:space="preserve">
<source>Discover on network</source>
<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>请勿使用 SimpleX 进行紧急通话。</target>
@@ -1966,6 +2018,14 @@ This cannot be undone!</source>
<target>加密消息:意外错误</target>
<note>notification</note>
</trans-unit>
<trans-unit id="Encryption re-negotiation error" xml:space="preserve">
<source>Encryption re-negotiation error</source>
<note>message decrypt error item</note>
</trans-unit>
<trans-unit id="Encryption re-negotiation failed." xml:space="preserve">
<source>Encryption re-negotiation failed.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter Passcode" xml:space="preserve">
<source>Enter Passcode</source>
<target>输入密码</target>
@@ -1995,6 +2055,10 @@ This cannot be undone!</source>
<target>手动输入服务器</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter this device name…" xml:space="preserve">
<source>Enter this device name…</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Enter welcome message…" xml:space="preserve">
<source>Enter welcome message…</source>
<target>输入欢迎消息……</target>
@@ -2765,6 +2829,10 @@ This cannot be undone!</source>
<target>数据库版本不兼容</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Incompatible version" xml:space="preserve">
<source>Incompatible version</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Incorrect passcode" xml:space="preserve">
<source>Incorrect passcode</source>
<target>密码错误</target>
@@ -2930,6 +2998,10 @@ This is your link for group %@!</source>
<target>加入群组中</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Keep the app open to use it from desktop" xml:space="preserve">
<source>Keep the app open to use it from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Keep your connections" xml:space="preserve">
<source>Keep your connections</source>
<target>保持连接</target>
@@ -2990,6 +3062,14 @@ This is your link for group %@!</source>
<target>限制</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Linked desktop options" xml:space="preserve">
<source>Linked desktop options</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Linked desktops" xml:space="preserve">
<source>Linked desktops</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Live message!" xml:space="preserve">
<source>Live message!</source>
<target>实时消息!</target>
@@ -3557,6 +3637,10 @@ This is your link for group %@!</source>
<target>粘贴</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Paste desktop address" xml:space="preserve">
<source>Paste desktop address</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Paste image" xml:space="preserve">
<source>Paste image</source>
<target>粘贴图片</target>
@@ -4148,6 +4232,10 @@ This is your link for group %@!</source>
<target>扫描二维码</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scan QR code from desktop" xml:space="preserve">
<source>Scan QR code from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scan code" xml:space="preserve">
<source>Scan code</source>
<target>扫码</target>
@@ -4368,6 +4456,10 @@ This is your link for group %@!</source>
<target>服务器</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Session code" xml:space="preserve">
<source>Session code</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Set 1 day" xml:space="preserve">
<source>Set 1 day</source>
<target>设定1天</target>
@@ -4864,6 +4956,10 @@ It can happen because of some bug or when the connection is compromised.</source
<target>此操作无法撤消——您的个人资料、联系人、消息和文件将不可撤回地丢失。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This device name" xml:space="preserve">
<source>This device name</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="This group has over %lld members, delivery receipts are not sent." xml:space="preserve">
<source>This group has over %lld members, delivery receipts are not sent.</source>
<target>该组有超过 %lld 个成员,不发送送货单。</target>
@@ -5053,6 +5149,14 @@ To connect, please ask your contact to create another connection link and check
如果要连接,请让您的联系人创建另一个连接链接,并检查您的网络连接是否稳定。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlink" xml:space="preserve">
<source>Unlink</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlink desktop?" xml:space="preserve">
<source>Unlink desktop?</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unlock" xml:space="preserve">
<source>Unlock</source>
<target>解锁</target>
@@ -5143,6 +5247,10 @@ To connect, please ask your contact to create another connection link and check
<target>用于新连接</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use from desktop" xml:space="preserve">
<source>Use from desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Use iOS call interface" xml:space="preserve">
<source>Use iOS call interface</source>
<target>使用 iOS 通话界面</target>
@@ -5173,11 +5281,23 @@ To connect, please ask your contact to create another connection link and check
<target>使用 SimpleX Chat 服务器。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify code with desktop" xml:space="preserve">
<source>Verify code with desktop</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connection" xml:space="preserve">
<source>Verify connection</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connection security" xml:space="preserve">
<source>Verify connection security</source>
<target>验证连接安全</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify connections" xml:space="preserve">
<source>Verify connections</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Verify security code" xml:space="preserve">
<source>Verify security code</source>
<target>验证安全码</target>
@@ -6348,6 +6468,10 @@ SimpleX 服务器无法看到您的资料。</target>
<target>已更新的群组资料</target>
<note>rcv group event chat item</note>
</trans-unit>
<trans-unit id="v%@" xml:space="preserve">
<source>v%@</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="v%@ (%@)" xml:space="preserve">
<source>v%@ (%@)</source>
<target>v%@ (%@)</target>
@@ -6485,6 +6609,10 @@ SimpleX 服务器无法看到您的资料。</target>
<target>SimpleX 使用Face ID进行本地身份验证</target>
<note>Privacy - Face ID Usage Description</note>
</trans-unit>
<trans-unit id="NSLocalNetworkUsageDescription" xml:space="preserve">
<source>SimpleX uses local network access to allow using user chat profile via desktop app on the same network.</source>
<note>Privacy - Local Network Usage Description</note>
</trans-unit>
<trans-unit id="NSMicrophoneUsageDescription" xml:space="preserve">
<source>SimpleX needs microphone access for audio and video calls, and to record voice messages.</source>
<target>SimpleX 需要麦克风访问权限才能进行音频和视频通话,以及录制语音消息。</target>
@@ -4,6 +4,8 @@
"NSCameraUsageDescription" = "SimpleX needs camera access to scan QR codes to connect to other users and for video calls.";
/* Privacy - Face ID Usage Description */
"NSFaceIDUsageDescription" = "SimpleX uses Face ID for local authentication";
/* Privacy - Local Network Usage Description */
"NSLocalNetworkUsageDescription" = "SimpleX uses local network access to allow using user chat profile via desktop app on the same network.";
/* Privacy - Microphone Usage Description */
"NSMicrophoneUsageDescription" = "SimpleX needs microphone access for audio and video calls, and to record voice messages.";
/* Privacy - Photo Library Additions Usage Description */
+34 -20
View File
@@ -39,6 +39,7 @@
5C36027327F47AD5009F19D9 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C36027227F47AD5009F19D9 /* AppDelegate.swift */; };
5C3A88CE27DF50170060F1C2 /* DetermineWidth.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C3A88CD27DF50170060F1C2 /* DetermineWidth.swift */; };
5C3A88D127DF57800060F1C2 /* FramedItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C3A88D027DF57800060F1C2 /* FramedItemView.swift */; };
5C3CCFCC2AE6BD3100C3F0C3 /* ConnectDesktopView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C3CCFCB2AE6BD3100C3F0C3 /* ConnectDesktopView.swift */; };
5C3F1D562842B68D00EC8A82 /* IntegrityErrorItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C3F1D552842B68D00EC8A82 /* IntegrityErrorItemView.swift */; };
5C3F1D58284363C400EC8A82 /* PrivacySettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C3F1D57284363C400EC8A82 /* PrivacySettings.swift */; };
5C4B3B0A285FB130003915F2 /* DatabaseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C4B3B09285FB130003915F2 /* DatabaseView.swift */; };
@@ -117,6 +118,11 @@
5CCB939C297EFCB100399E78 /* NavStackCompat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CCB939B297EFCB100399E78 /* NavStackCompat.swift */; };
5CCD403427A5F6DF00368C90 /* AddContactView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CCD403327A5F6DF00368C90 /* AddContactView.swift */; };
5CCD403727A5F9A200368C90 /* ScanToConnectView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CCD403627A5F9A200368C90 /* ScanToConnectView.swift */; };
5CDA5A2D2B04FE2D00A71D61 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CDA5A282B04FE2D00A71D61 /* libgmp.a */; };
5CDA5A2E2B04FE2D00A71D61 /* libHSsimplex-chat-5.4.0.3-rODxCBVsb2BkD1fnTAqXL-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CDA5A292B04FE2D00A71D61 /* libHSsimplex-chat-5.4.0.3-rODxCBVsb2BkD1fnTAqXL-ghc9.6.3.a */; };
5CDA5A2F2B04FE2D00A71D61 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CDA5A2A2B04FE2D00A71D61 /* libffi.a */; };
5CDA5A302B04FE2D00A71D61 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CDA5A2B2B04FE2D00A71D61 /* libgmpxx.a */; };
5CDA5A312B04FE2D00A71D61 /* libHSsimplex-chat-5.4.0.3-rODxCBVsb2BkD1fnTAqXL.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CDA5A2C2B04FE2D00A71D61 /* libHSsimplex-chat-5.4.0.3-rODxCBVsb2BkD1fnTAqXL.a */; };
5CDCAD482818589900503DA2 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CDCAD472818589900503DA2 /* NotificationService.swift */; };
5CE2BA702845308900EC33A6 /* SimpleXChat.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CE2BA682845308900EC33A6 /* SimpleXChat.framework */; };
5CE2BA712845308900EC33A6 /* SimpleXChat.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 5CE2BA682845308900EC33A6 /* SimpleXChat.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
@@ -142,11 +148,6 @@
5CEACCED27DEA495000BD591 /* MsgContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CEACCEC27DEA495000BD591 /* MsgContentView.swift */; };
5CEBD7462A5C0A8F00665FE2 /* KeyboardPadding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CEBD7452A5C0A8F00665FE2 /* KeyboardPadding.swift */; };
5CEBD7482A5F115D00665FE2 /* SetDeliveryReceiptsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CEBD7472A5F115D00665FE2 /* SetDeliveryReceiptsView.swift */; };
5CF4DF772AFF8D4E007893ED /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CF4DF722AFF8D4D007893ED /* libffi.a */; };
5CF4DF782AFF8D4E007893ED /* libHSsimplex-chat-5.4.0.3-EnhmkSQK6HvJ11g1uZERg8-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CF4DF732AFF8D4D007893ED /* libHSsimplex-chat-5.4.0.3-EnhmkSQK6HvJ11g1uZERg8-ghc9.6.3.a */; };
5CF4DF792AFF8D4E007893ED /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CF4DF742AFF8D4D007893ED /* libgmpxx.a */; };
5CF4DF7A2AFF8D4E007893ED /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CF4DF752AFF8D4E007893ED /* libgmp.a */; };
5CF4DF7B2AFF8D4E007893ED /* libHSsimplex-chat-5.4.0.3-EnhmkSQK6HvJ11g1uZERg8.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CF4DF762AFF8D4E007893ED /* libHSsimplex-chat-5.4.0.3-EnhmkSQK6HvJ11g1uZERg8.a */; };
5CFA59C42860BC6200863A68 /* MigrateToAppGroupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CFA59C32860BC6200863A68 /* MigrateToAppGroupView.swift */; };
5CFA59D12864782E00863A68 /* ChatArchiveView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CFA59CF286477B400863A68 /* ChatArchiveView.swift */; };
5CFE0921282EEAF60002594B /* ZoomableScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CFE0920282EEAF60002594B /* ZoomableScrollView.swift */; };
@@ -282,6 +283,7 @@
5C36027227F47AD5009F19D9 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
5C3A88CD27DF50170060F1C2 /* DetermineWidth.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetermineWidth.swift; sourceTree = "<group>"; };
5C3A88D027DF57800060F1C2 /* FramedItemView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FramedItemView.swift; sourceTree = "<group>"; };
5C3CCFCB2AE6BD3100C3F0C3 /* ConnectDesktopView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConnectDesktopView.swift; sourceTree = "<group>"; };
5C3F1D552842B68D00EC8A82 /* IntegrityErrorItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntegrityErrorItemView.swift; sourceTree = "<group>"; };
5C3F1D57284363C400EC8A82 /* PrivacySettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacySettings.swift; sourceTree = "<group>"; };
5C422A7C27A9A6FA0097A1E1 /* SimpleX (iOS).entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "SimpleX (iOS).entitlements"; sourceTree = "<group>"; };
@@ -397,6 +399,11 @@
5CCB939B297EFCB100399E78 /* NavStackCompat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavStackCompat.swift; sourceTree = "<group>"; };
5CCD403327A5F6DF00368C90 /* AddContactView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddContactView.swift; sourceTree = "<group>"; };
5CCD403627A5F9A200368C90 /* ScanToConnectView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanToConnectView.swift; sourceTree = "<group>"; };
5CDA5A282B04FE2D00A71D61 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
5CDA5A292B04FE2D00A71D61 /* libHSsimplex-chat-5.4.0.3-rODxCBVsb2BkD1fnTAqXL-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.4.0.3-rODxCBVsb2BkD1fnTAqXL-ghc9.6.3.a"; sourceTree = "<group>"; };
5CDA5A2A2B04FE2D00A71D61 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
5CDA5A2B2B04FE2D00A71D61 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
5CDA5A2C2B04FE2D00A71D61 /* libHSsimplex-chat-5.4.0.3-rODxCBVsb2BkD1fnTAqXL.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.4.0.3-rODxCBVsb2BkD1fnTAqXL.a"; sourceTree = "<group>"; };
5CDCAD452818589900503DA2 /* SimpleX NSE.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "SimpleX NSE.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
5CDCAD472818589900503DA2 /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = "<group>"; };
5CDCAD492818589900503DA2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@@ -423,11 +430,6 @@
5CEACCEC27DEA495000BD591 /* MsgContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MsgContentView.swift; sourceTree = "<group>"; };
5CEBD7452A5C0A8F00665FE2 /* KeyboardPadding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardPadding.swift; sourceTree = "<group>"; };
5CEBD7472A5F115D00665FE2 /* SetDeliveryReceiptsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetDeliveryReceiptsView.swift; sourceTree = "<group>"; };
5CF4DF722AFF8D4D007893ED /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
5CF4DF732AFF8D4D007893ED /* libHSsimplex-chat-5.4.0.3-EnhmkSQK6HvJ11g1uZERg8-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.4.0.3-EnhmkSQK6HvJ11g1uZERg8-ghc9.6.3.a"; sourceTree = "<group>"; };
5CF4DF742AFF8D4D007893ED /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
5CF4DF752AFF8D4E007893ED /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
5CF4DF762AFF8D4E007893ED /* libHSsimplex-chat-5.4.0.3-EnhmkSQK6HvJ11g1uZERg8.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.4.0.3-EnhmkSQK6HvJ11g1uZERg8.a"; sourceTree = "<group>"; };
5CFA59C32860BC6200863A68 /* MigrateToAppGroupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrateToAppGroupView.swift; sourceTree = "<group>"; };
5CFA59CF286477B400863A68 /* ChatArchiveView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatArchiveView.swift; sourceTree = "<group>"; };
5CFE0920282EEAF60002594B /* ZoomableScrollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ZoomableScrollView.swift; path = Shared/Views/ZoomableScrollView.swift; sourceTree = SOURCE_ROOT; };
@@ -505,13 +507,13 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
5CDA5A302B04FE2D00A71D61 /* libgmpxx.a in Frameworks */,
5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */,
5CF4DF792AFF8D4E007893ED /* libgmpxx.a in Frameworks */,
5CF4DF772AFF8D4E007893ED /* libffi.a in Frameworks */,
5CDA5A2D2B04FE2D00A71D61 /* libgmp.a in Frameworks */,
5CDA5A2E2B04FE2D00A71D61 /* libHSsimplex-chat-5.4.0.3-rODxCBVsb2BkD1fnTAqXL-ghc9.6.3.a in Frameworks */,
5CDA5A2F2B04FE2D00A71D61 /* libffi.a in Frameworks */,
5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */,
5CF4DF7A2AFF8D4E007893ED /* libgmp.a in Frameworks */,
5CF4DF7B2AFF8D4E007893ED /* libHSsimplex-chat-5.4.0.3-EnhmkSQK6HvJ11g1uZERg8.a in Frameworks */,
5CF4DF782AFF8D4E007893ED /* libHSsimplex-chat-5.4.0.3-EnhmkSQK6HvJ11g1uZERg8-ghc9.6.3.a in Frameworks */,
5CDA5A312B04FE2D00A71D61 /* libHSsimplex-chat-5.4.0.3-rODxCBVsb2BkD1fnTAqXL.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -544,6 +546,7 @@
5CB924DD27A8622200ACCCDD /* NewChat */,
5CFA59C22860B04D00863A68 /* Database */,
5CB634AB29E46CDB0066AD6B /* LocalAuth */,
5CA8D01B2AD9B076001FD661 /* RemoteAccess */,
5CB924DF27A8678B00ACCCDD /* UserSettings */,
5C2E261127A30FEA00F70299 /* TerminalView.swift */,
);
@@ -572,11 +575,11 @@
5C764E5C279C70B7000C6508 /* Libraries */ = {
isa = PBXGroup;
children = (
5CF4DF722AFF8D4D007893ED /* libffi.a */,
5CF4DF752AFF8D4E007893ED /* libgmp.a */,
5CF4DF742AFF8D4D007893ED /* libgmpxx.a */,
5CF4DF732AFF8D4D007893ED /* libHSsimplex-chat-5.4.0.3-EnhmkSQK6HvJ11g1uZERg8-ghc9.6.3.a */,
5CF4DF762AFF8D4E007893ED /* libHSsimplex-chat-5.4.0.3-EnhmkSQK6HvJ11g1uZERg8.a */,
5CDA5A2A2B04FE2D00A71D61 /* libffi.a */,
5CDA5A282B04FE2D00A71D61 /* libgmp.a */,
5CDA5A2B2B04FE2D00A71D61 /* libgmpxx.a */,
5CDA5A292B04FE2D00A71D61 /* libHSsimplex-chat-5.4.0.3-rODxCBVsb2BkD1fnTAqXL-ghc9.6.3.a */,
5CDA5A2C2B04FE2D00A71D61 /* libHSsimplex-chat-5.4.0.3-rODxCBVsb2BkD1fnTAqXL.a */,
);
path = Libraries;
sourceTree = "<group>";
@@ -684,6 +687,14 @@
path = "Tests iOS";
sourceTree = "<group>";
};
5CA8D01B2AD9B076001FD661 /* RemoteAccess */ = {
isa = PBXGroup;
children = (
5C3CCFCB2AE6BD3100C3F0C3 /* ConnectDesktopView.swift */,
);
path = RemoteAccess;
sourceTree = "<group>";
};
5CB0BA8C282711BC00B3292C /* Onboarding */ = {
isa = PBXGroup;
children = (
@@ -1170,6 +1181,7 @@
6454036F2822A9750090DDFF /* ComposeFileView.swift in Sources */,
5C5DB70E289ABDD200730FFF /* AppearanceSettings.swift in Sources */,
5C5F2B6D27EBC3FE006A9D5F /* ImagePicker.swift in Sources */,
5C3CCFCC2AE6BD3100C3F0C3 /* ConnectDesktopView.swift in Sources */,
5C9C2DA92899DA6F00CC63B1 /* NetworkAndServers.swift in Sources */,
5C6BA667289BD954009B8ECC /* DismissSheets.swift in Sources */,
5C577F7D27C83AA10006112D /* MarkdownHelp.swift in Sources */,
@@ -1490,6 +1502,7 @@
INFOPLIST_FILE = "SimpleX--iOS--Info.plist";
INFOPLIST_KEY_NSCameraUsageDescription = "SimpleX needs camera access to scan QR codes to connect to other users and for video calls.";
INFOPLIST_KEY_NSFaceIDUsageDescription = "SimpleX uses Face ID for local authentication";
INFOPLIST_KEY_NSLocalNetworkUsageDescription = "SimpleX uses local network access to allow using user chat profile via desktop app on the same network.";
INFOPLIST_KEY_NSMicrophoneUsageDescription = "SimpleX needs microphone access for audio and video calls, and to record voice messages.";
INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "SimpleX needs access to Photo Library for saving captured and received media";
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
@@ -1532,6 +1545,7 @@
INFOPLIST_FILE = "SimpleX--iOS--Info.plist";
INFOPLIST_KEY_NSCameraUsageDescription = "SimpleX needs camera access to scan QR codes to connect to other users and for video calls.";
INFOPLIST_KEY_NSFaceIDUsageDescription = "SimpleX uses Face ID for local authentication";
INFOPLIST_KEY_NSLocalNetworkUsageDescription = "SimpleX uses local network access to allow using user chat profile via desktop app on the same network.";
INFOPLIST_KEY_NSMicrophoneUsageDescription = "SimpleX needs microphone access for audio and video calls, and to record voice messages.";
INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "SimpleX needs access to Photo Library for saving captured and received media";
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
+102
View File
@@ -120,6 +120,16 @@ public enum ChatCommand {
case receiveFile(fileId: Int64, encrypted: Bool?, inline: Bool?)
case setFileToReceive(fileId: Int64, encrypted: Bool?)
case cancelFile(fileId: Int64)
// remote desktop commands
case setLocalDeviceName(displayName: String)
case connectRemoteCtrl(xrcpInvitation: String)
case findKnownRemoteCtrl
case confirmRemoteCtrl(remoteCtrlId: Int64)
case verifyRemoteCtrlSession(sessionCode: String)
case listRemoteCtrls
case stopRemoteCtrl
case deleteRemoteCtrl(remoteCtrlId: Int64)
// misc
case showVersion
case string(String)
@@ -260,6 +270,14 @@ public enum ChatCommand {
case let .receiveFile(fileId, encrypt, inline): return "/freceive \(fileId)\(onOffParam("encrypt", encrypt))\(onOffParam("inline", inline))"
case let .setFileToReceive(fileId, encrypt): return "/_set_file_to_receive \(fileId)\(onOffParam("encrypt", encrypt))"
case let .cancelFile(fileId): return "/fcancel \(fileId)"
case let .setLocalDeviceName(displayName): return "/set device name \(displayName)"
case let .connectRemoteCtrl(xrcpInv): return "/connect remote ctrl \(xrcpInv)"
case .findKnownRemoteCtrl: return "/find remote ctrl"
case let .confirmRemoteCtrl(rcId): return "/confirm remote ctrl \(rcId)"
case let .verifyRemoteCtrlSession(sessCode): return "/verify remote ctrl \(sessCode)"
case .listRemoteCtrls: return "/list remote ctrls"
case .stopRemoteCtrl: return "/stop remote ctrl"
case let .deleteRemoteCtrl(rcId): return "/delete remote ctrl \(rcId)"
case .showVersion: return "/version"
case let .string(str): return str
}
@@ -375,6 +393,14 @@ public enum ChatCommand {
case .receiveFile: return "receiveFile"
case .setFileToReceive: return "setFileToReceive"
case .cancelFile: return "cancelFile"
case .setLocalDeviceName: return "setLocalDeviceName"
case .connectRemoteCtrl: return "connectRemoteCtrl"
case .findKnownRemoteCtrl: return "findKnownRemoteCtrl"
case .confirmRemoteCtrl: return "confirmRemoteCtrl"
case .verifyRemoteCtrlSession: return "verifyRemoteCtrlSession"
case .listRemoteCtrls: return "listRemoteCtrls"
case .stopRemoteCtrl: return "stopRemoteCtrl"
case .deleteRemoteCtrl: return "deleteRemoteCtrl"
case .showVersion: return "showVersion"
case .string: return "console command"
}
@@ -581,6 +607,14 @@ public enum ChatResponse: Decodable, Error {
case ntfMessages(user_: User?, connEntity: ConnectionEntity?, msgTs: Date?, ntfMessages: [NtfMsgInfo])
case newContactConnection(user: UserRef, connection: PendingContactConnection)
case contactConnectionDeleted(user: UserRef, connection: PendingContactConnection)
// remote desktop responses/events
case remoteCtrlList(remoteCtrls: [RemoteCtrlInfo])
case remoteCtrlFound(remoteCtrl: RemoteCtrlInfo)
case remoteCtrlConnecting(remoteCtrl_: RemoteCtrlInfo?, ctrlAppInfo: CtrlAppInfo, appVersion: String)
case remoteCtrlSessionCode(remoteCtrl_: RemoteCtrlInfo?, sessionCode: String)
case remoteCtrlConnected(remoteCtrl: RemoteCtrlInfo)
case remoteCtrlStopped
// misc
case versionInfo(versionInfo: CoreVersionInfo, chatMigrations: [UpMigration], agentMigrations: [UpMigration])
case cmdOk(user: UserRef?)
case chatCmdError(user_: UserRef?, chatError: ChatError)
@@ -720,6 +754,12 @@ public enum ChatResponse: Decodable, Error {
case .ntfMessages: return "ntfMessages"
case .newContactConnection: return "newContactConnection"
case .contactConnectionDeleted: return "contactConnectionDeleted"
case .remoteCtrlList: return "remoteCtrlList"
case .remoteCtrlFound: return "remoteCtrlFound"
case .remoteCtrlConnecting: return "remoteCtrlConnecting"
case .remoteCtrlSessionCode: return "remoteCtrlSessionCode"
case .remoteCtrlConnected: return "remoteCtrlConnected"
case .remoteCtrlStopped: return "remoteCtrlStopped"
case .versionInfo: return "versionInfo"
case .cmdOk: return "cmdOk"
case .chatCmdError: return "chatCmdError"
@@ -862,6 +902,12 @@ public enum ChatResponse: Decodable, Error {
case let .ntfMessages(u, connEntity, msgTs, ntfMessages): return withUser(u, "connEntity: \(String(describing: connEntity))\nmsgTs: \(String(describing: msgTs))\nntfMessages: \(String(describing: ntfMessages))")
case let .newContactConnection(u, connection): return withUser(u, String(describing: connection))
case let .contactConnectionDeleted(u, connection): return withUser(u, String(describing: connection))
case let .remoteCtrlList(remoteCtrls): return String(describing: remoteCtrls)
case let .remoteCtrlFound(remoteCtrl): return String(describing: remoteCtrl)
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 .versionInfo(versionInfo, chatMigrations, agentMigrations): return "\(String(describing: versionInfo))\n\nchat migrations: \(chatMigrations.map(\.upName))\n\nagent migrations: \(agentMigrations.map(\.upName))"
case .cmdOk: return noDetails
case let .chatCmdError(u, chatError): return withUser(u, String(describing: chatError))
@@ -1488,6 +1534,33 @@ public enum NotificationPreviewMode: String, SelectableItem {
public static var values: [NotificationPreviewMode] = [.message, .contact, .hidden]
}
public struct RemoteCtrlInfo: Decodable {
public var remoteCtrlId: Int64
public var ctrlDeviceName: String
public var sessionState: RemoteCtrlSessionState?
public var deviceViewName: String {
ctrlDeviceName == "" ? "\(remoteCtrlId)" : ctrlDeviceName
}
}
public enum RemoteCtrlSessionState: Decodable {
case starting
case connecting
case pendingConfirmation(sessionCode: String)
case connected(sessionCode: String)
}
public struct CtrlAppInfo: Decodable {
public var appVersionRange: AppVersionRange
public var deviceName: String
}
public struct AppVersionRange: Decodable {
public var minVersion: String
public var maxVersion: String
}
public struct CoreVersionInfo: Decodable {
public var version: String
public var simplexmqVersion: String
@@ -1515,6 +1588,7 @@ public enum ChatError: Decodable {
case errorAgent(agentError: AgentErrorType)
case errorStore(storeError: StoreError)
case errorDatabase(databaseError: DatabaseError)
case errorRemoteCtrl(remoteCtrlError: RemoteCtrlError)
case invalidJSON(json: String)
}
@@ -1674,6 +1748,7 @@ public enum AgentErrorType: Decodable {
case SMP(smpErr: ProtocolErrorType)
case NTF(ntfErr: ProtocolErrorType)
case XFTP(xftpErr: XFTPErrorType)
case RCP(rcpErr: RCErrorType)
case BROKER(brokerAddress: String, brokerErr: BrokerErrorType)
case AGENT(agentErr: SMPAgentError)
case INTERNAL(internalErr: String)
@@ -1731,6 +1806,22 @@ public enum XFTPErrorType: Decodable {
case INTERNAL
}
public enum RCErrorType: Decodable {
case `internal`(internalErr: String)
case identity
case noLocalAddress
case tlsStartFailed
case exception(exception: String)
case ctrlAuth
case ctrlNotFound
case ctrlError(ctrlErr: String)
case version
case encrypt
case decrypt
case blockSize
case syntax(syntaxErr: String)
}
public enum ProtocolCommandError: Decodable {
case UNKNOWN
case SYNTAX
@@ -1766,3 +1857,14 @@ public enum ArchiveError: Decodable {
case `import`(chatError: ChatError)
case importFile(file: String, chatError: ChatError)
}
public enum RemoteCtrlError: Decodable {
case inactive
case badState
case busy
case timeout
case disconnected(remoteCtrlId: Int64, reason: String)
case badInvitation
case badVersion(appVersion: String)
// case protocolError(protocolError: RemoteProtocolError)
}
+196 -10
View File
@@ -119,11 +119,17 @@
"%@ %@" = "%@ %@";
/* No comment provided by engineer. */
"%@ and %@ connected" = "%@ und %@ wurden verbunden";
"%@ and %@" = "%@ und %@";
/* No comment provided by engineer. */
"%@ and %@ connected" = "%@ und %@ wurden mit Ihnen verbunden";
/* copied message info, <sender> at <time> */
"%@ at %@:" = "%1$@ an %2$@:";
/* No comment provided by engineer. */
"%@ connected" = "%@ wurde mit Ihnen verbunden";
/* notification title */
"%@ is connected!" = "%@ ist mit Ihnen verbunden!";
@@ -140,7 +146,10 @@
"%@ wants to connect!" = "%@ will sich mit Ihnen verbinden!";
/* No comment provided by engineer. */
"%@, %@ and %lld other members connected" = "%@, %@ und %lld weitere Mitglieder wurden verbunden";
"%@, %@ and %lld members" = "%@, %@ und %lld Mitglieder";
/* No comment provided by engineer. */
"%@, %@ and %lld other members connected" = "%@, %@ und %lld weitere Mitglieder wurden mit Ihnen verbunden";
/* copied message info */
"%@:" = "%@:";
@@ -178,9 +187,21 @@
/* No comment provided by engineer. */
"%lld file(s) with total size of %@" = "%lld Datei(en) mit einem Gesamtspeicherverbrauch von %@";
/* No comment provided by engineer. */
"%lld group events" = "%lld Gruppenereignisse";
/* No comment provided by engineer. */
"%lld members" = "%lld Mitglieder";
/* No comment provided by engineer. */
"%lld messages blocked" = "%lld Nachrichten blockiert";
/* No comment provided by engineer. */
"%lld messages marked deleted" = "%lld Nachrichten als gelöscht markiert";
/* No comment provided by engineer. */
"%lld messages moderated by %@" = "%lld Nachrichten von %@ moderiert";
/* No comment provided by engineer. */
"%lld minutes" = "%lld Minuten";
@@ -229,6 +250,9 @@
/* No comment provided by engineer. */
"~strike~" = "\\~durchstreichen~";
/* time to disappear */
"0 sec" = "0 sek";
/* No comment provided by engineer. */
"0s" = "0s";
@@ -371,6 +395,9 @@
/* No comment provided by engineer. */
"All messages will be deleted - this cannot be undone! The messages will be deleted ONLY for you." = "Alle Nachrichten werden gelöscht - dies kann nicht rückgängig gemacht werden! Die Nachrichten werden NUR bei Ihnen gelöscht.";
/* No comment provided by engineer. */
"All new messages from %@ will be hidden!" = "Alle neuen Nachrichten von %@ werden verborgen!";
/* No comment provided by engineer. */
"All your contacts will remain connected." = "Alle Ihre Kontakte bleiben verbunden.";
@@ -434,6 +461,12 @@
/* No comment provided by engineer. */
"Already connected?" = "Sind Sie bereits verbunden?";
/* No comment provided by engineer. */
"Already connecting!" = "Bereits verbunden!";
/* No comment provided by engineer. */
"Already joining the group!" = "Sie sind bereits Mitglied der Gruppe!";
/* pref value */
"always" = "Immer";
@@ -443,6 +476,9 @@
/* No comment provided by engineer. */
"An empty chat profile with the provided name is created, and the app opens as usual." = "Es wurde ein leeres Chat-Profil mit dem eingegebenen Namen erstellt und die App öffnet wie gewohnt.";
/* No comment provided by engineer. */
"and %lld other events" = "und %lld weitere Ereignisse";
/* No comment provided by engineer. */
"Answer call" = "Anruf annehmen";
@@ -527,6 +563,18 @@
/* No comment provided by engineer. */
"Better messages" = "Verbesserungen bei Nachrichten";
/* No comment provided by engineer. */
"Block" = "Blockieren";
/* No comment provided by engineer. */
"Block member" = "Mitglied blockieren";
/* No comment provided by engineer. */
"Block member?" = "Mitglied blockieren?";
/* No comment provided by engineer. */
"blocked" = "blockiert";
/* No comment provided by engineer. */
"bold" = "fett";
@@ -726,6 +774,18 @@
/* No comment provided by engineer. */
"connect to SimpleX Chat developers." = "Mit den SimpleX Chat-Entwicklern verbinden.";
/* No comment provided by engineer. */
"Connect to yourself?" = "Mit Ihnen selbst verbinden?";
/* No comment provided by engineer. */
"Connect to yourself?\nThis is your own one-time link!" = "Mit Ihnen selbst verbinden?\nDas ist Ihr eigener Einmal-Link!";
/* No comment provided by engineer. */
"Connect to yourself?\nThis is your own SimpleX address!" = "Mit Ihnen selbst verbinden?\nDas ist Ihre eigene SimpleX-Adresse!";
/* No comment provided by engineer. */
"Connect via contact address" = "Über die Kontakt-Adresse verbinden";
/* No comment provided by engineer. */
"Connect via link" = "Über einen Link verbinden";
@@ -735,6 +795,9 @@
/* No comment provided by engineer. */
"Connect via one-time link" = "Über einen Einmal-Link verbinden";
/* No comment provided by engineer. */
"Connect with %@" = "Mit %@ verbinden";
/* No comment provided by engineer. */
"connected" = "Verbunden";
@@ -831,6 +894,9 @@
/* No comment provided by engineer. */
"Core version: v%@" = "Core Version: v%@";
/* No comment provided by engineer. */
"Correct name to %@?" = "Richtiger Name für %@?";
/* No comment provided by engineer. */
"Create" = "Erstellen";
@@ -840,6 +906,9 @@
/* server test step */
"Create file" = "Datei erstellen";
/* No comment provided by engineer. */
"Create group" = "Gruppe erstellen";
/* No comment provided by engineer. */
"Create group link" = "Gruppenlink erstellen";
@@ -852,6 +921,9 @@
/* No comment provided by engineer. */
"Create one-time invitation link" = "Einmal-Einladungslink erstellen";
/* No comment provided by engineer. */
"Create profile" = "Profil erstellen";
/* server test step */
"Create queue" = "Erzeuge Warteschlange";
@@ -966,6 +1038,9 @@
/* chat item action */
"Delete" = "Löschen";
/* No comment provided by engineer. */
"Delete %lld messages?" = "%lld Nachrichten löschen?";
/* No comment provided by engineer. */
"Delete address" = "Adresse löschen";
@@ -978,6 +1053,9 @@
/* No comment provided by engineer. */
"Delete all files" = "Alle Dateien löschen";
/* No comment provided by engineer. */
"Delete and notify contact" = "Kontakt löschen und benachrichtigen";
/* No comment provided by engineer. */
"Delete archive" = "Archiv löschen";
@@ -999,6 +1077,9 @@
/* No comment provided by engineer. */
"Delete Contact" = "Kontakt löschen";
/* No comment provided by engineer. */
"Delete contact?\nThis cannot be undone!" = "Kontakt löschen?\nDas kann nicht rückgängig gemacht werden!";
/* No comment provided by engineer. */
"Delete database" = "Datenbank löschen";
@@ -1074,6 +1155,9 @@
/* copied message info */
"Deleted at: %@" = "Gelöscht um: %@";
/* rcv direct event chat item */
"deleted contact" = "Gelöschter Kontakt";
/* rcv group event chat item */
"deleted group" = "Gruppe gelöscht";
@@ -1305,6 +1389,9 @@
/* No comment provided by engineer. */
"Enter correct passphrase." = "Geben Sie das korrekte Passwort ein.";
/* No comment provided by engineer. */
"Enter group name…" = "Geben Sie den Gruppennamen ein…";
/* No comment provided by engineer. */
"Enter Passcode" = "Zugangscode eingeben";
@@ -1323,6 +1410,9 @@
/* placeholder */
"Enter welcome message… (optional)" = "Geben Sie eine Begrüßungsmeldung ein … (optional)";
/* No comment provided by engineer. */
"Enter your name…" = "Geben Sie Ihren Namen ein…";
/* No comment provided by engineer. */
"error" = "Fehler";
@@ -1494,6 +1584,9 @@
/* No comment provided by engineer. */
"Exit without saving" = "Beenden ohne Speichern";
/* chat item action */
"Expand" = "Erweitern";
/* No comment provided by engineer. */
"Export database" = "Datenbank exportieren";
@@ -1581,6 +1674,9 @@
/* No comment provided by engineer. */
"Full name:" = "Vollständiger Name:";
/* No comment provided by engineer. */
"Fully decentralized visible only to members." = "Vollständig dezentralisiert nur für Mitglieder sichtbar.";
/* No comment provided by engineer. */
"Fully re-implemented - work in background!" = "Komplett neu umgesetzt - arbeitet nun im Hintergrund!";
@@ -1593,6 +1689,12 @@
/* No comment provided by engineer. */
"Group" = "Gruppe";
/* No comment provided by engineer. */
"Group already exists" = "Die Gruppe besteht bereits";
/* No comment provided by engineer. */
"Group already exists!" = "Die Gruppe besteht bereits!";
/* No comment provided by engineer. */
"group deleted" = "Gruppe gelöscht";
@@ -1830,6 +1932,9 @@
/* invalid chat item */
"invalid data" = "Ungültige Daten";
/* No comment provided by engineer. */
"Invalid name!" = "Ungültiger Name!";
/* No comment provided by engineer. */
"Invalid server address!" = "Ungültige Serveradresse!";
@@ -1888,7 +1993,7 @@
"It can happen when:\n1. The messages expired in the sending client after 2 days or on the server after 30 days.\n2. Message decryption failed, because you or your contact used old database backup.\n3. The connection was compromised." = "Dies kann unter folgenden Umständen passieren:\n1. Die Nachrichten verfallen auf dem sendenden Client-System nach 2 Tagen oder auf dem Server nach 30 Tagen.\n2. Die Nachrichten-Entschlüsselung ist fehlgeschlagen, da von Ihnen oder Ihrem Kontakt ein altes Datenbank-Backup genutzt wurde.\n3. Die Verbindung wurde kompromittiert.";
/* No comment provided by engineer. */
"It seems like you are already connected via this link. If it is not the case, there was an error (%@)." = "Es sieht so aus, dass Sie bereits über diesen Link verbunden sind. Wenn das nicht der Fall, gab es einen Fehler (%@).";
"It seems like you are already connected via this link. If it is not the case, there was an error (%@)." = "Es sieht so aus, als ob Sie bereits über diesen Link verbunden sind. Wenn das nicht der Fall ist, gab es einen Fehler (%@).";
/* No comment provided by engineer. */
"Italian interface" = "Italienische Bedienoberfläche";
@@ -1908,9 +2013,18 @@
/* No comment provided by engineer. */
"Join group" = "Treten Sie der Gruppe bei";
/* No comment provided by engineer. */
"Join group?" = "Der Gruppe beitreten?";
/* No comment provided by engineer. */
"Join incognito" = "Inkognito beitreten";
/* No comment provided by engineer. */
"Join with current profile" = "Mit dem aktuellen Profil beitreten";
/* No comment provided by engineer. */
"Join your group?\nThis is your link for group %@!" = "Ihrer Gruppe beitreten?\nDas ist Ihr Link für die Gruppe %@!";
/* No comment provided by engineer. */
"Joining group" = "Der Gruppe beitreten";
@@ -2055,6 +2169,9 @@
/* No comment provided by engineer. */
"Messages & files" = "Nachrichten";
/* No comment provided by engineer. */
"Messages from %@ will be shown!" = "Die Nachrichten von %@ werden angezeigt!";
/* No comment provided by engineer. */
"Migrating database archive…" = "Datenbank-Archiv wird migriert…";
@@ -2306,6 +2423,9 @@
/* authentication reason */
"Open chat console" = "Chat-Konsole öffnen";
/* No comment provided by engineer. */
"Open group" = "Gruppe öffnen";
/* No comment provided by engineer. */
"Open Settings" = "Geräte-Einstellungen öffnen";
@@ -2438,6 +2558,12 @@
/* No comment provided by engineer. */
"Profile image" = "Profilbild";
/* No comment provided by engineer. */
"Profile name" = "Profilname";
/* No comment provided by engineer. */
"Profile name:" = "Profilname:";
/* No comment provided by engineer. */
"Profile password" = "Passwort für Profil";
@@ -2603,6 +2729,12 @@
/* No comment provided by engineer. */
"Renegotiate encryption?" = "Verschlüsselung neu aushandeln?";
/* No comment provided by engineer. */
"Repeat connection request?" = "Verbindungsanfrage wiederholen?";
/* No comment provided by engineer. */
"Repeat join request?" = "Verbindungsanfrage wiederholen?";
/* chat item action */
"Reply" = "Antwort";
@@ -3044,6 +3176,9 @@
/* No comment provided by engineer. */
"Tap to activate profile." = "Tippen Sie auf das Profil um es zu aktivieren.";
/* No comment provided by engineer. */
"Tap to Connect" = "Zum Verbinden antippen";
/* No comment provided by engineer. */
"Tap to join" = "Zum Beitreten tippen";
@@ -3170,6 +3305,12 @@
/* No comment provided by engineer. */
"This group no longer exists." = "Diese Gruppe existiert nicht mehr.";
/* No comment provided by engineer. */
"This is your own one-time link!" = "Das ist Ihr eigener Einmal-Link!";
/* No comment provided by engineer. */
"This is your own SimpleX address!" = "Das ist Ihre eigene SimpleX-Adresse!";
/* No comment provided by engineer. */
"This setting applies to messages in your current chat profile **%@**." = "Diese Einstellung gilt für Nachrichten in Ihrem aktuellen Chat-Profil **%@**.";
@@ -3195,7 +3336,7 @@
"To record voice message please grant permission to use Microphone." = "Bitte erlauben Sie die Nutzung des Mikrofons, um Sprachnachrichten aufnehmen zu können.";
/* No comment provided by engineer. */
"To reveal your hidden profile, enter a full password into a search field in **Your chat profiles** page." = "Geben Sie ein vollständiges Passwort in das Suchfeld auf der Seite **Meine Chat-Profile** ein, um Ihr verborgenes Profil zu sehen.";
"To reveal your hidden profile, enter a full password into a search field in **Your chat profiles** page." = "Geben Sie ein vollständiges Passwort in das Suchfeld auf der Seite **Ihre Chat-Profile** ein, um Ihr verborgenes Profil zu sehen.";
/* No comment provided by engineer. */
"To support instant push notifications the chat database has to be migrated." = "Um sofortige Push-Benachrichtigungen zu unterstützen, muss die Chat-Datenbank migriert werden.";
@@ -3227,6 +3368,15 @@
/* No comment provided by engineer. */
"Unable to record voice message" = "Die Aufnahme einer Sprachnachricht ist nicht möglich";
/* No comment provided by engineer. */
"Unblock" = "Freigeben";
/* No comment provided by engineer. */
"Unblock member" = "Mitglied freigeben";
/* No comment provided by engineer. */
"Unblock member?" = "Mitglied freigeben?";
/* item status description */
"Unexpected error: %@" = "Unerwarteter Fehler: %@";
@@ -3459,7 +3609,7 @@
"yes" = "Ja";
/* No comment provided by engineer. */
"You" = "Meine Daten";
"You" = "Ihre Daten";
/* No comment provided by engineer. */
"You accepted connection" = "Sie haben die Verbindung akzeptiert";
@@ -3473,6 +3623,27 @@
/* No comment provided by engineer. */
"You are already connected to %@." = "Sie sind bereits mit %@ verbunden.";
/* No comment provided by engineer. */
"You are already connecting to %@." = "Sie sind bereits mit %@ verbunden.";
/* No comment provided by engineer. */
"You are already connecting via this one-time link!" = "Sie sind bereits über diesen Einmal-Link verbunden!";
/* No comment provided by engineer. */
"You are already in group %@." = "Sie sind bereits Mitglied der Gruppe %@.";
/* No comment provided by engineer. */
"You are already joining the group %@." = "Sie sind bereits Mitglied der Gruppe %@.";
/* No comment provided by engineer. */
"You are already joining the group via this link!" = "Sie sind über diesen Link bereits Mitglied der Gruppe!";
/* No comment provided by engineer. */
"You are already joining the group via this link." = "Sie sind über diesen Link bereits Mitglied der Gruppe.";
/* No comment provided by engineer. */
"You are already joining the group!\nRepeat join request?" = "Sie sind bereits Mitglied dieser Gruppe!\nVerbindungsanfrage wiederholen?";
/* No comment provided by engineer. */
"You are connected to the server used to receive messages from this contact." = "Sie sind mit dem Server verbunden, der für den Empfang von Nachrichten mit diesem Kontakt genutzt wird.";
@@ -3548,6 +3719,12 @@
/* No comment provided by engineer. */
"You could not be verified; please try again." = "Sie konnten nicht überprüft werden; bitte versuchen Sie es erneut.";
/* No comment provided by engineer. */
"You have already requested connection via this address!" = "Sie haben über diese Adresse bereits eine Verbindung beantragt!";
/* No comment provided by engineer. */
"You have already requested connection!\nRepeat connection request?" = "Sie haben bereits ein Verbindungsanfrage beantragt!\nVerbindungsanfrage wiederholen?";
/* No comment provided by engineer. */
"You have no chats" = "Sie haben keine Chats";
@@ -3590,6 +3767,9 @@
/* No comment provided by engineer. */
"You will be connected to group when the group host's device is online, please wait or check later!" = "Sie werden mit der Gruppe verbunden, sobald das Endgerät des Gruppen-Hosts online ist. Bitte warten oder schauen Sie später nochmal nach!";
/* No comment provided by engineer. */
"You will be connected when group link host's device is online, please wait or check later!" = "Sie werden verbunden, sobald das Endgerät des Gruppenlink-Hosts online ist. Bitte warten oder schauen Sie später nochmal nach!";
/* No comment provided by engineer. */
"You will be connected when your connection request is accepted, please wait or check later!" = "Sie werden verbunden, sobald Ihre Verbindungsanfrage akzeptiert wird. Bitte warten oder schauen Sie später nochmal nach!";
@@ -3599,6 +3779,9 @@
/* No comment provided by engineer. */
"You will be required to authenticate when you start or resume the app after 30 seconds in background." = "Sie müssen sich authentifizieren, wenn Sie die im Hintergrund befindliche App nach 30 Sekunden starten oder fortsetzen.";
/* No comment provided by engineer. */
"You will connect to all group members." = "Sie werden mit allen Gruppenmitgliedern verbunden.";
/* No comment provided by engineer. */
"You will still receive calls and notifications from muted profiles when they are active." = "Sie können Anrufe und Benachrichtigungen auch von stummgeschalteten Profilen empfangen, solange diese aktiv sind.";
@@ -3630,7 +3813,7 @@
"Your chat database is not encrypted - set passphrase to encrypt it." = "Ihre Chat-Datenbank ist nicht verschlüsselt. Bitte legen Sie ein Passwort fest, um sie zu schützen.";
/* No comment provided by engineer. */
"Your chat profiles" = "Meine Chat-Profile";
"Your chat profiles" = "Ihre Chat-Profile";
/* No comment provided by engineer. */
"Your contact needs to be online for the connection to complete.\nYou can cancel this connection and remove the contact (and try later with a new link)." = "Damit die Verbindung hergestellt werden kann, muss Ihr Kontakt online sein.\nSie können diese Verbindung abbrechen und den Kontakt entfernen (und es später nochmals mit einem neuen Link versuchen).";
@@ -3657,10 +3840,13 @@
"Your ICE servers" = "Ihre ICE-Server";
/* No comment provided by engineer. */
"Your preferences" = "Meine Präferenzen";
"Your preferences" = "Ihre Präferenzen";
/* No comment provided by engineer. */
"Your privacy" = "Meine Privatsphäre";
"Your privacy" = "Ihre Privatsphäre";
/* No comment provided by engineer. */
"Your profile" = "Mein Profil";
/* No comment provided by engineer. */
"Your profile **%@** will be shared." = "Ihr Profil **%@** wird geteilt.";
@@ -3681,10 +3867,10 @@
"Your server address" = "Ihre Serveradresse";
/* No comment provided by engineer. */
"Your settings" = "Meine Einstellungen";
"Your settings" = "Ihre Einstellungen";
/* No comment provided by engineer. */
"Your SimpleX address" = "Meine SimpleX-Adresse";
"Your SimpleX address" = "Ihre SimpleX-Adresse";
/* No comment provided by engineer. */
"Your SMP servers" = "Ihre SMP-Server";
+186
View File
@@ -118,12 +118,18 @@
/* No comment provided by engineer. */
"%@ %@" = "%@ %@";
/* No comment provided by engineer. */
"%@ and %@" = "%@ et %@";
/* No comment provided by engineer. */
"%@ and %@ connected" = "%@ et %@ sont connecté.es";
/* copied message info, <sender> at <time> */
"%@ at %@:" = "%1$@ à %2$@:";
/* No comment provided by engineer. */
"%@ connected" = "%@ connecté(e)";
/* notification title */
"%@ is connected!" = "%@ est connecté·e !";
@@ -139,6 +145,9 @@
/* notification title */
"%@ wants to connect!" = "%@ veut se connecter !";
/* No comment provided by engineer. */
"%@, %@ and %lld members" = "%@, %@ et %lld membres";
/* No comment provided by engineer. */
"%@, %@ and %lld other members connected" = "%@, %@ et %lld autres membres sont connectés";
@@ -178,9 +187,21 @@
/* No comment provided by engineer. */
"%lld file(s) with total size of %@" = "%lld fichier·s pour une taille totale de %@";
/* No comment provided by engineer. */
"%lld group events" = "%lld événements de groupe";
/* No comment provided by engineer. */
"%lld members" = "%lld membres";
/* No comment provided by engineer. */
"%lld messages blocked" = "%lld messages bloqués";
/* No comment provided by engineer. */
"%lld messages marked deleted" = "%lld messages marqués comme supprimés";
/* No comment provided by engineer. */
"%lld messages moderated by %@" = "%lld messages modérés par %@";
/* No comment provided by engineer. */
"%lld minutes" = "%lld minutes";
@@ -229,6 +250,9 @@
/* No comment provided by engineer. */
"~strike~" = "\\~barré~";
/* time to disappear */
"0 sec" = "0 sec";
/* No comment provided by engineer. */
"0s" = "0s";
@@ -371,6 +395,9 @@
/* No comment provided by engineer. */
"All messages will be deleted - this cannot be undone! The messages will be deleted ONLY for you." = "Tous les messages seront supprimés - impossible de revenir en arrière ! Les messages seront supprimés UNIQUEMENT pour vous.";
/* No comment provided by engineer. */
"All new messages from %@ will be hidden!" = "Tous les nouveaux messages de %@ seront cachés !";
/* No comment provided by engineer. */
"All your contacts will remain connected." = "Tous vos contacts resteront connectés.";
@@ -434,6 +461,12 @@
/* No comment provided by engineer. */
"Already connected?" = "Déjà connecté ?";
/* No comment provided by engineer. */
"Already connecting!" = "Déjà en connexion !";
/* No comment provided by engineer. */
"Already joining the group!" = "Groupe déjà rejoint !";
/* pref value */
"always" = "toujours";
@@ -443,6 +476,9 @@
/* No comment provided by engineer. */
"An empty chat profile with the provided name is created, and the app opens as usual." = "Un profil de chat vierge portant le nom fourni est créé et l'application s'ouvre normalement.";
/* No comment provided by engineer. */
"and %lld other events" = "et %lld autres événements";
/* No comment provided by engineer. */
"Answer call" = "Répondre à l'appel";
@@ -527,6 +563,18 @@
/* No comment provided by engineer. */
"Better messages" = "Meilleurs messages";
/* No comment provided by engineer. */
"Block" = "Bloquer";
/* No comment provided by engineer. */
"Block member" = "Bloquer ce membre";
/* No comment provided by engineer. */
"Block member?" = "Bloquer ce membre ?";
/* No comment provided by engineer. */
"blocked" = "blocké";
/* No comment provided by engineer. */
"bold" = "gras";
@@ -726,6 +774,18 @@
/* No comment provided by engineer. */
"connect to SimpleX Chat developers." = "se connecter aux developpeurs de SimpleX Chat.";
/* No comment provided by engineer. */
"Connect to yourself?" = "Se connecter à soi-même ?";
/* No comment provided by engineer. */
"Connect to yourself?\nThis is your own one-time link!" = "Se connecter à soi-même ?\nIl s'agit de votre propre lien unique !";
/* No comment provided by engineer. */
"Connect to yourself?\nThis is your own SimpleX address!" = "Se connecter à soi-même ?\nC'est votre propre adresse SimpleX !";
/* No comment provided by engineer. */
"Connect via contact address" = "Se connecter via l'adresse de contact";
/* No comment provided by engineer. */
"Connect via link" = "Se connecter via un lien";
@@ -735,6 +795,9 @@
/* No comment provided by engineer. */
"Connect via one-time link" = "Se connecter via un lien unique";
/* No comment provided by engineer. */
"Connect with %@" = "Se connecter avec %@";
/* No comment provided by engineer. */
"connected" = "connecté";
@@ -831,6 +894,9 @@
/* No comment provided by engineer. */
"Core version: v%@" = "Version du cœur : v%@";
/* No comment provided by engineer. */
"Correct name to %@?" = "Corriger le nom pour %@ ?";
/* No comment provided by engineer. */
"Create" = "Créer";
@@ -840,6 +906,9 @@
/* server test step */
"Create file" = "Créer un fichier";
/* No comment provided by engineer. */
"Create group" = "Créer un groupe";
/* No comment provided by engineer. */
"Create group link" = "Créer un lien de groupe";
@@ -852,6 +921,9 @@
/* No comment provided by engineer. */
"Create one-time invitation link" = "Créer un lien d'invitation unique";
/* No comment provided by engineer. */
"Create profile" = "Créer le profil";
/* server test step */
"Create queue" = "Créer une file d'attente";
@@ -966,6 +1038,9 @@
/* chat item action */
"Delete" = "Supprimer";
/* No comment provided by engineer. */
"Delete %lld messages?" = "Supprimer %lld messages ?";
/* No comment provided by engineer. */
"Delete address" = "Supprimer l'adresse";
@@ -978,6 +1053,9 @@
/* No comment provided by engineer. */
"Delete all files" = "Effacer tous les fichiers";
/* No comment provided by engineer. */
"Delete and notify contact" = "Supprimer et en informer le contact";
/* No comment provided by engineer. */
"Delete archive" = "Supprimer l'archive";
@@ -999,6 +1077,9 @@
/* No comment provided by engineer. */
"Delete Contact" = "Supprimer le contact";
/* No comment provided by engineer. */
"Delete contact?\nThis cannot be undone!" = "Supprimer le contact ?\nCette opération ne peut être annulée !";
/* No comment provided by engineer. */
"Delete database" = "Supprimer la base de données";
@@ -1074,6 +1155,9 @@
/* copied message info */
"Deleted at: %@" = "Supprimé à : %@";
/* rcv direct event chat item */
"deleted contact" = "contact supprimé";
/* rcv group event chat item */
"deleted group" = "groupe supprimé";
@@ -1305,6 +1389,9 @@
/* No comment provided by engineer. */
"Enter correct passphrase." = "Entrez la phrase secrète correcte.";
/* No comment provided by engineer. */
"Enter group name…" = "Entrer un nom de groupe…";
/* No comment provided by engineer. */
"Enter Passcode" = "Entrer le code d'accès";
@@ -1323,6 +1410,9 @@
/* placeholder */
"Enter welcome message… (optional)" = "Entrez un message de bienvenue… (facultatif)";
/* No comment provided by engineer. */
"Enter your name…" = "Entrez votre nom…";
/* No comment provided by engineer. */
"error" = "erreur";
@@ -1494,6 +1584,9 @@
/* No comment provided by engineer. */
"Exit without saving" = "Quitter sans sauvegarder";
/* chat item action */
"Expand" = "Développer";
/* No comment provided by engineer. */
"Export database" = "Exporter la base de données";
@@ -1581,6 +1674,9 @@
/* No comment provided by engineer. */
"Full name:" = "Nom complet :";
/* No comment provided by engineer. */
"Fully decentralized visible only to members." = "Entièrement décentralisé visible que par ses membres.";
/* No comment provided by engineer. */
"Fully re-implemented - work in background!" = "Entièrement réimplémenté - fonctionne en arrière-plan !";
@@ -1593,6 +1689,12 @@
/* No comment provided by engineer. */
"Group" = "Groupe";
/* No comment provided by engineer. */
"Group already exists" = "Le groupe existe déjà";
/* No comment provided by engineer. */
"Group already exists!" = "Ce groupe existe déjà !";
/* No comment provided by engineer. */
"group deleted" = "groupe supprimé";
@@ -1830,6 +1932,9 @@
/* invalid chat item */
"invalid data" = "données invalides";
/* No comment provided by engineer. */
"Invalid name!" = "Nom invalide !";
/* No comment provided by engineer. */
"Invalid server address!" = "Adresse de serveur invalide !";
@@ -1908,9 +2013,18 @@
/* No comment provided by engineer. */
"Join group" = "Rejoindre le groupe";
/* No comment provided by engineer. */
"Join group?" = "Rejoindre le groupe ?";
/* No comment provided by engineer. */
"Join incognito" = "Rejoindre en incognito";
/* No comment provided by engineer. */
"Join with current profile" = "Rejoindre avec le profil actuel";
/* No comment provided by engineer. */
"Join your group?\nThis is your link for group %@!" = "Rejoindre votre groupe ?\nVoici votre lien pour le groupe %@ !";
/* No comment provided by engineer. */
"Joining group" = "Entrain de rejoindre le groupe";
@@ -2055,6 +2169,9 @@
/* No comment provided by engineer. */
"Messages & files" = "Messages";
/* No comment provided by engineer. */
"Messages from %@ will be shown!" = "Les messages de %@ seront affichés !";
/* No comment provided by engineer. */
"Migrating database archive…" = "Migration de l'archive de la base de données…";
@@ -2306,6 +2423,9 @@
/* authentication reason */
"Open chat console" = "Ouvrir la console du chat";
/* No comment provided by engineer. */
"Open group" = "Ouvrir le groupe";
/* No comment provided by engineer. */
"Open Settings" = "Ouvrir les Paramètres";
@@ -2438,6 +2558,12 @@
/* No comment provided by engineer. */
"Profile image" = "Image de profil";
/* No comment provided by engineer. */
"Profile name" = "Nom du profil";
/* No comment provided by engineer. */
"Profile name:" = "Nom du profil :";
/* No comment provided by engineer. */
"Profile password" = "Mot de passe de profil";
@@ -2603,6 +2729,12 @@
/* No comment provided by engineer. */
"Renegotiate encryption?" = "Renégocier le chiffrement?";
/* No comment provided by engineer. */
"Repeat connection request?" = "Répéter la demande de connexion ?";
/* No comment provided by engineer. */
"Repeat join request?" = "Répéter la requête d'adhésion ?";
/* chat item action */
"Reply" = "Répondre";
@@ -3044,6 +3176,9 @@
/* No comment provided by engineer. */
"Tap to activate profile." = "Appuyez pour activer un profil.";
/* No comment provided by engineer. */
"Tap to Connect" = "Tapez pour vous connecter";
/* No comment provided by engineer. */
"Tap to join" = "Appuyez pour rejoindre";
@@ -3170,6 +3305,12 @@
/* No comment provided by engineer. */
"This group no longer exists." = "Ce groupe n'existe plus.";
/* No comment provided by engineer. */
"This is your own one-time link!" = "Voici votre propre lien unique !";
/* No comment provided by engineer. */
"This is your own SimpleX address!" = "Voici votre propre adresse SimpleX !";
/* No comment provided by engineer. */
"This setting applies to messages in your current chat profile **%@**." = "Ce paramètre s'applique aux messages de votre profil de chat actuel **%@**.";
@@ -3227,6 +3368,15 @@
/* No comment provided by engineer. */
"Unable to record voice message" = "Impossible d'enregistrer un message vocal";
/* No comment provided by engineer. */
"Unblock" = "Débloquer";
/* No comment provided by engineer. */
"Unblock member" = "Débloquer ce membre";
/* No comment provided by engineer. */
"Unblock member?" = "Débloquer ce membre ?";
/* item status description */
"Unexpected error: %@" = "Erreur inattendue: %@";
@@ -3473,6 +3623,27 @@
/* No comment provided by engineer. */
"You are already connected to %@." = "Vous êtes déjà connecté·e à %@ via ce lien.";
/* No comment provided by engineer. */
"You are already connecting to %@." = "Vous êtes déjà en train de vous connecter à %@.";
/* No comment provided by engineer. */
"You are already connecting via this one-time link!" = "Vous êtes déjà connecté(e) via ce lien unique !";
/* No comment provided by engineer. */
"You are already in group %@." = "Vous êtes déjà dans le groupe %@.";
/* No comment provided by engineer. */
"You are already joining the group %@." = "Vous êtes déjà en train de rejoindre le groupe %@.";
/* No comment provided by engineer. */
"You are already joining the group via this link!" = "Vous êtes déjà en train de rejoindre le groupe via ce lien !";
/* No comment provided by engineer. */
"You are already joining the group via this link." = "Vous êtes déjà en train de rejoindre le groupe via ce lien.";
/* No comment provided by engineer. */
"You are already joining the group!\nRepeat join request?" = "Vous êtes déjà membre de ce groupe !\nRépéter la demande d'adhésion ?";
/* No comment provided by engineer. */
"You are connected to the server used to receive messages from this contact." = "Vous êtes connecté·e au serveur utilisé pour recevoir les messages de ce contact.";
@@ -3548,6 +3719,12 @@
/* No comment provided by engineer. */
"You could not be verified; please try again." = "Vous n'avez pas pu être vérifié·e; veuillez réessayer.";
/* No comment provided by engineer. */
"You have already requested connection via this address!" = "Vous avez déjà demandé une connexion via cette adresse !";
/* No comment provided by engineer. */
"You have already requested connection!\nRepeat connection request?" = "Vous avez déjà demandé une connexion !\nRépéter la demande de connexion ?";
/* No comment provided by engineer. */
"You have no chats" = "Vous n'avez aucune discussion";
@@ -3590,6 +3767,9 @@
/* No comment provided by engineer. */
"You will be connected to group when the group host's device is online, please wait or check later!" = "Vous serez connecté·e au groupe lorsque l'appareil de l'hôte sera en ligne, veuillez attendre ou vérifier plus tard !";
/* No comment provided by engineer. */
"You will be connected when group link host's device is online, please wait or check later!" = "Vous serez connecté(e) lorsque l'appareil de l'hôte du lien de groupe sera en ligne, veuillez patienter ou vérifier plus tard !";
/* No comment provided by engineer. */
"You will be connected when your connection request is accepted, please wait or check later!" = "Vous serez connecté·e lorsque votre demande de connexion sera acceptée, veuillez attendre ou vérifier plus tard !";
@@ -3599,6 +3779,9 @@
/* No comment provided by engineer. */
"You will be required to authenticate when you start or resume the app after 30 seconds in background." = "Il vous sera demandé de vous authentifier lorsque vous démarrez ou reprenez l'application après 30 secondes en arrière-plan.";
/* No comment provided by engineer. */
"You will connect to all group members." = "Vous vous connecterez à tous les membres du groupe.";
/* No comment provided by engineer. */
"You will still receive calls and notifications from muted profiles when they are active." = "Vous continuerez à recevoir des appels et des notifications des profils mis en sourdine lorsqu'ils sont actifs.";
@@ -3662,6 +3845,9 @@
/* No comment provided by engineer. */
"Your privacy" = "Votre vie privée";
/* No comment provided by engineer. */
"Your profile" = "Votre profil";
/* No comment provided by engineer. */
"Your profile **%@** will be shared." = "Votre profil **%@** sera partagé.";
+187 -1
View File
@@ -118,12 +118,18 @@
/* No comment provided by engineer. */
"%@ %@" = "%@ %@";
/* No comment provided by engineer. */
"%@ and %@" = "%@ e %@";
/* No comment provided by engineer. */
"%@ and %@ connected" = "%@ e %@ sono connessi/e";
/* copied message info, <sender> at <time> */
"%@ at %@:" = "%1$@ alle %2$@:";
/* No comment provided by engineer. */
"%@ connected" = "%@ si è connesso/a";
/* notification title */
"%@ is connected!" = "%@ è connesso/a!";
@@ -139,6 +145,9 @@
/* notification title */
"%@ wants to connect!" = "%@ si vuole connettere!";
/* No comment provided by engineer. */
"%@, %@ and %lld members" = "%@, %@ e %lld membri";
/* No comment provided by engineer. */
"%@, %@ and %lld other members connected" = "%@, %@ e altri %lld membri sono connessi";
@@ -178,9 +187,21 @@
/* No comment provided by engineer. */
"%lld file(s) with total size of %@" = "%lld file con dimensione totale di %@";
/* No comment provided by engineer. */
"%lld group events" = "%lld eventi del gruppo";
/* No comment provided by engineer. */
"%lld members" = "%lld membri";
/* No comment provided by engineer. */
"%lld messages blocked" = "%lld messaggi bloccati";
/* No comment provided by engineer. */
"%lld messages marked deleted" = "%lld messaggi contrassegnati eliminati";
/* No comment provided by engineer. */
"%lld messages moderated by %@" = "%lld messaggi moderati da %@";
/* No comment provided by engineer. */
"%lld minutes" = "%lld minuti";
@@ -229,6 +250,9 @@
/* No comment provided by engineer. */
"~strike~" = "\\~barrato~";
/* time to disappear */
"0 sec" = "0 sec";
/* No comment provided by engineer. */
"0s" = "0s";
@@ -371,6 +395,9 @@
/* No comment provided by engineer. */
"All messages will be deleted - this cannot be undone! The messages will be deleted ONLY for you." = "Tutti i messaggi verranno eliminati, non è reversibile! I messaggi verranno eliminati SOLO per te.";
/* No comment provided by engineer. */
"All new messages from %@ will be hidden!" = "Tutti i nuovi messaggi da %@ verrranno nascosti!";
/* No comment provided by engineer. */
"All your contacts will remain connected." = "Tutti i tuoi contatti resteranno connessi.";
@@ -434,6 +461,12 @@
/* No comment provided by engineer. */
"Already connected?" = "Già connesso/a?";
/* No comment provided by engineer. */
"Already connecting!" = "Già in connessione!";
/* No comment provided by engineer. */
"Already joining the group!" = "Già in ingresso nel gruppo!";
/* pref value */
"always" = "sempre";
@@ -443,6 +476,9 @@
/* No comment provided by engineer. */
"An empty chat profile with the provided name is created, and the app opens as usual." = "Viene creato un profilo di chat vuoto con il nome scelto e l'app si apre come al solito.";
/* No comment provided by engineer. */
"and %lld other events" = "e altri %lld eventi";
/* No comment provided by engineer. */
"Answer call" = "Rispondi alla chiamata";
@@ -527,6 +563,18 @@
/* No comment provided by engineer. */
"Better messages" = "Messaggi migliorati";
/* No comment provided by engineer. */
"Block" = "Blocca";
/* No comment provided by engineer. */
"Block member" = "Blocca membro";
/* No comment provided by engineer. */
"Block member?" = "Bloccare il membro?";
/* No comment provided by engineer. */
"blocked" = "bloccato";
/* No comment provided by engineer. */
"bold" = "grassetto";
@@ -622,7 +670,7 @@
"changed address for you" = "indirizzo cambiato per te";
/* rcv group event chat item */
"changed role of %@ to %@" = "cambiato il ruolo di %1$@ in %2$@";
"changed role of %@ to %@" = "ha cambiato il ruolo di %1$@ in %2$@";
/* rcv group event chat item */
"changed your role to %@" = "cambiato il tuo ruolo in %@";
@@ -726,6 +774,18 @@
/* No comment provided by engineer. */
"connect to SimpleX Chat developers." = "connettiti agli sviluppatori di SimpleX Chat.";
/* No comment provided by engineer. */
"Connect to yourself?" = "Connettersi a te stesso?";
/* No comment provided by engineer. */
"Connect to yourself?\nThis is your own one-time link!" = "Connettersi a te stesso?\nQuesto è il tuo link una tantum!";
/* No comment provided by engineer. */
"Connect to yourself?\nThis is your own SimpleX address!" = "Connettersi a te stesso?\nQuesto è il tuo indirizzo SimpleX!";
/* No comment provided by engineer. */
"Connect via contact address" = "Connettere via indirizzo del contatto";
/* No comment provided by engineer. */
"Connect via link" = "Connetti via link";
@@ -735,6 +795,9 @@
/* No comment provided by engineer. */
"Connect via one-time link" = "Connetti via link una tantum";
/* No comment provided by engineer. */
"Connect with %@" = "Connettersi con %@";
/* No comment provided by engineer. */
"connected" = "connesso/a";
@@ -831,6 +894,9 @@
/* No comment provided by engineer. */
"Core version: v%@" = "Versione core: v%@";
/* No comment provided by engineer. */
"Correct name to %@?" = "Correggere il nome a %@?";
/* No comment provided by engineer. */
"Create" = "Crea";
@@ -840,6 +906,9 @@
/* server test step */
"Create file" = "Crea file";
/* No comment provided by engineer. */
"Create group" = "Crea gruppo";
/* No comment provided by engineer. */
"Create group link" = "Crea link del gruppo";
@@ -852,6 +921,9 @@
/* No comment provided by engineer. */
"Create one-time invitation link" = "Crea link di invito una tantum";
/* No comment provided by engineer. */
"Create profile" = "Crea profilo";
/* server test step */
"Create queue" = "Crea coda";
@@ -966,6 +1038,9 @@
/* chat item action */
"Delete" = "Elimina";
/* No comment provided by engineer. */
"Delete %lld messages?" = "Eliminare %lld messaggi?";
/* No comment provided by engineer. */
"Delete address" = "Elimina indirizzo";
@@ -978,6 +1053,9 @@
/* No comment provided by engineer. */
"Delete all files" = "Elimina tutti i file";
/* No comment provided by engineer. */
"Delete and notify contact" = "Elimina e avvisa il contatto";
/* No comment provided by engineer. */
"Delete archive" = "Elimina archivio";
@@ -999,6 +1077,9 @@
/* No comment provided by engineer. */
"Delete Contact" = "Elimina contatto";
/* No comment provided by engineer. */
"Delete contact?\nThis cannot be undone!" = "Eliminare il contatto?\nNon è reversibile!";
/* No comment provided by engineer. */
"Delete database" = "Elimina database";
@@ -1074,6 +1155,9 @@
/* copied message info */
"Deleted at: %@" = "Eliminato il: %@";
/* rcv direct event chat item */
"deleted contact" = "contatto eliminato";
/* rcv group event chat item */
"deleted group" = "gruppo eliminato";
@@ -1305,6 +1389,9 @@
/* No comment provided by engineer. */
"Enter correct passphrase." = "Inserisci la password giusta.";
/* No comment provided by engineer. */
"Enter group name…" = "Inserisci il nome del gruppo…";
/* No comment provided by engineer. */
"Enter Passcode" = "Inserisci il codice di accesso";
@@ -1323,6 +1410,9 @@
/* placeholder */
"Enter welcome message… (optional)" = "Inserisci il messaggio di benvenuto… (facoltativo)";
/* No comment provided by engineer. */
"Enter your name…" = "Inserisci il tuo nome…";
/* No comment provided by engineer. */
"error" = "errore";
@@ -1494,6 +1584,9 @@
/* No comment provided by engineer. */
"Exit without saving" = "Esci senza salvare";
/* chat item action */
"Expand" = "Espandi";
/* No comment provided by engineer. */
"Export database" = "Esporta database";
@@ -1581,6 +1674,9 @@
/* No comment provided by engineer. */
"Full name:" = "Nome completo:";
/* No comment provided by engineer. */
"Fully decentralized visible only to members." = "Completamente decentralizzato: visibile solo ai membri.";
/* No comment provided by engineer. */
"Fully re-implemented - work in background!" = "Completamente reimplementato - funziona in secondo piano!";
@@ -1593,6 +1689,12 @@
/* No comment provided by engineer. */
"Group" = "Gruppo";
/* No comment provided by engineer. */
"Group already exists" = "Il gruppo esiste già";
/* No comment provided by engineer. */
"Group already exists!" = "Il gruppo esiste già!";
/* No comment provided by engineer. */
"group deleted" = "gruppo eliminato";
@@ -1830,6 +1932,9 @@
/* invalid chat item */
"invalid data" = "dati non validi";
/* No comment provided by engineer. */
"Invalid name!" = "Nome non valido!";
/* No comment provided by engineer. */
"Invalid server address!" = "Indirizzo del server non valido!";
@@ -1908,9 +2013,18 @@
/* No comment provided by engineer. */
"Join group" = "Entra nel gruppo";
/* No comment provided by engineer. */
"Join group?" = "Entrare nel gruppo?";
/* No comment provided by engineer. */
"Join incognito" = "Entra in incognito";
/* No comment provided by engineer. */
"Join with current profile" = "Entra con il profilo attuale";
/* No comment provided by engineer. */
"Join your group?\nThis is your link for group %@!" = "Entrare nel tuo gruppo?\nQuesto è il tuo link per il gruppo %@!";
/* No comment provided by engineer. */
"Joining group" = "Ingresso nel gruppo";
@@ -2055,6 +2169,9 @@
/* No comment provided by engineer. */
"Messages & files" = "Messaggi";
/* No comment provided by engineer. */
"Messages from %@ will be shown!" = "I messaggi da %@ verranno mostrati!";
/* No comment provided by engineer. */
"Migrating database archive…" = "Migrazione archivio del database…";
@@ -2306,6 +2423,9 @@
/* authentication reason */
"Open chat console" = "Apri la console della chat";
/* No comment provided by engineer. */
"Open group" = "Apri gruppo";
/* No comment provided by engineer. */
"Open Settings" = "Apri le impostazioni";
@@ -2438,6 +2558,12 @@
/* No comment provided by engineer. */
"Profile image" = "Immagine del profilo";
/* No comment provided by engineer. */
"Profile name" = "Nome del profilo";
/* No comment provided by engineer. */
"Profile name:" = "Nome del profilo:";
/* No comment provided by engineer. */
"Profile password" = "Password del profilo";
@@ -2603,6 +2729,12 @@
/* No comment provided by engineer. */
"Renegotiate encryption?" = "Rinegoziare la crittografia?";
/* No comment provided by engineer. */
"Repeat connection request?" = "Ripetere la richiesta di connessione?";
/* No comment provided by engineer. */
"Repeat join request?" = "Ripetere la richiesta di ingresso?";
/* chat item action */
"Reply" = "Rispondi";
@@ -3044,6 +3176,9 @@
/* No comment provided by engineer. */
"Tap to activate profile." = "Tocca per attivare il profilo.";
/* No comment provided by engineer. */
"Tap to Connect" = "Tocca per connettere";
/* No comment provided by engineer. */
"Tap to join" = "Tocca per entrare";
@@ -3170,6 +3305,12 @@
/* No comment provided by engineer. */
"This group no longer exists." = "Questo gruppo non esiste più.";
/* No comment provided by engineer. */
"This is your own one-time link!" = "Questo è il tuo link una tantum!";
/* No comment provided by engineer. */
"This is your own SimpleX address!" = "Questo è il tuo indirizzo SimpleX!";
/* No comment provided by engineer. */
"This setting applies to messages in your current chat profile **%@**." = "Questa impostazione si applica ai messaggi del profilo di chat attuale **%@**.";
@@ -3227,6 +3368,15 @@
/* No comment provided by engineer. */
"Unable to record voice message" = "Impossibile registrare il messaggio vocale";
/* No comment provided by engineer. */
"Unblock" = "Sblocca";
/* No comment provided by engineer. */
"Unblock member" = "Sblocca membro";
/* No comment provided by engineer. */
"Unblock member?" = "Sbloccare il membro?";
/* item status description */
"Unexpected error: %@" = "Errore imprevisto: % @";
@@ -3473,6 +3623,27 @@
/* No comment provided by engineer. */
"You are already connected to %@." = "Sei già connesso/a a %@.";
/* No comment provided by engineer. */
"You are already connecting to %@." = "Ti stai già connettendo a %@.";
/* No comment provided by engineer. */
"You are already connecting via this one-time link!" = "Ti stai già connettendo tramite questo link una tantum!";
/* No comment provided by engineer. */
"You are already in group %@." = "Sei già nel gruppo %@.";
/* No comment provided by engineer. */
"You are already joining the group %@." = "Stai già entrando nel gruppo %@.";
/* No comment provided by engineer. */
"You are already joining the group via this link!" = "Stai già entrando nel gruppo tramite questo link!";
/* No comment provided by engineer. */
"You are already joining the group via this link." = "Stai già entrando nel gruppo tramite questo link.";
/* No comment provided by engineer. */
"You are already joining the group!\nRepeat join request?" = "Stai già entrando nel gruppo!\nRipetere la richiesta di ingresso?";
/* No comment provided by engineer. */
"You are connected to the server used to receive messages from this contact." = "Sei connesso/a al server usato per ricevere messaggi da questo contatto.";
@@ -3548,6 +3719,12 @@
/* No comment provided by engineer. */
"You could not be verified; please try again." = "Non è stato possibile verificarti, riprova.";
/* No comment provided by engineer. */
"You have already requested connection via this address!" = "Hai già richiesto la connessione tramite questo indirizzo!";
/* No comment provided by engineer. */
"You have already requested connection!\nRepeat connection request?" = "Hai già richiesto la connessione!\nRipetere la richiesta di connessione?";
/* No comment provided by engineer. */
"You have no chats" = "Non hai chat";
@@ -3590,6 +3767,9 @@
/* No comment provided by engineer. */
"You will be connected to group when the group host's device is online, please wait or check later!" = "Verrai connesso/a al gruppo quando il dispositivo dell'host del gruppo sarà in linea, attendi o controlla più tardi!";
/* No comment provided by engineer. */
"You will be connected when group link host's device is online, please wait or check later!" = "Verrai connesso/a quando il dispositivo dell'host del gruppo sarà in linea, attendi o controlla più tardi!";
/* No comment provided by engineer. */
"You will be connected when your connection request is accepted, please wait or check later!" = "Verrai connesso/a quando la tua richiesta di connessione verrà accettata, attendi o controlla più tardi!";
@@ -3599,6 +3779,9 @@
/* No comment provided by engineer. */
"You will be required to authenticate when you start or resume the app after 30 seconds in background." = "Dovrai autenticarti quando avvii o riapri l'app dopo 30 secondi in secondo piano.";
/* No comment provided by engineer. */
"You will connect to all group members." = "Ti connetterai a tutti i membri del gruppo.";
/* No comment provided by engineer. */
"You will still receive calls and notifications from muted profiles when they are active." = "Continuerai a ricevere chiamate e notifiche da profili silenziati quando sono attivi.";
@@ -3662,6 +3845,9 @@
/* No comment provided by engineer. */
"Your privacy" = "La tua privacy";
/* No comment provided by engineer. */
"Your profile" = "Il tuo profilo";
/* No comment provided by engineer. */
"Your profile **%@** will be shared." = "Il tuo profilo **%@** verrà condiviso.";
+200 -14
View File
@@ -118,12 +118,18 @@
/* No comment provided by engineer. */
"%@ %@" = "%@ %@";
/* No comment provided by engineer. */
"%@ and %@" = "%@ en %@";
/* No comment provided by engineer. */
"%@ and %@ connected" = "%@ en %@ verbonden";
/* copied message info, <sender> at <time> */
"%@ at %@:" = "%1$@ bij %2$@:";
/* No comment provided by engineer. */
"%@ connected" = "%@ verbonden";
/* notification title */
"%@ is connected!" = "%@ is verbonden!";
@@ -139,6 +145,9 @@
/* notification title */
"%@ wants to connect!" = "%@ wil verbinding maken!";
/* No comment provided by engineer. */
"%@, %@ and %lld members" = "%@, %@ en %lld leden";
/* No comment provided by engineer. */
"%@, %@ and %lld other members connected" = "%@, %@ en %lld andere leden hebben verbinding gemaakt";
@@ -178,9 +187,21 @@
/* No comment provided by engineer. */
"%lld file(s) with total size of %@" = "%lld bestand(en) met een totale grootte van %@";
/* No comment provided by engineer. */
"%lld group events" = "%lld groep gebeurtenissen";
/* No comment provided by engineer. */
"%lld members" = "%lld leden";
/* No comment provided by engineer. */
"%lld messages blocked" = "%lld berichten geblokkeerd";
/* No comment provided by engineer. */
"%lld messages marked deleted" = "%lld berichten gemarkeerd als verwijderd";
/* No comment provided by engineer. */
"%lld messages moderated by %@" = "%lld berichten gemodereerd door %@";
/* No comment provided by engineer. */
"%lld minutes" = "%lld minuten";
@@ -229,6 +250,9 @@
/* No comment provided by engineer. */
"~strike~" = "\\~staking~";
/* time to disappear */
"0 sec" = "0 sec";
/* No comment provided by engineer. */
"0s" = "0s";
@@ -371,6 +395,9 @@
/* No comment provided by engineer. */
"All messages will be deleted - this cannot be undone! The messages will be deleted ONLY for you." = "Alle berichten worden verwijderd, dit kan niet ongedaan worden gemaakt! De berichten worden ALLEEN voor jou verwijderd.";
/* No comment provided by engineer. */
"All new messages from %@ will be hidden!" = "Alle nieuwe berichten van %@ worden verborgen!";
/* No comment provided by engineer. */
"All your contacts will remain connected." = "Al uw contacten blijven verbonden.";
@@ -434,6 +461,12 @@
/* No comment provided by engineer. */
"Already connected?" = "Al verbonden?";
/* No comment provided by engineer. */
"Already connecting!" = "Al bezig met verbinden!";
/* No comment provided by engineer. */
"Already joining the group!" = "Al lid van de groep!";
/* pref value */
"always" = "altijd";
@@ -443,6 +476,9 @@
/* No comment provided by engineer. */
"An empty chat profile with the provided name is created, and the app opens as usual." = "Er wordt een leeg chatprofiel met de opgegeven naam gemaakt en de app wordt zoals gewoonlijk geopend.";
/* No comment provided by engineer. */
"and %lld other events" = "en %lld andere gebeurtenissen";
/* No comment provided by engineer. */
"Answer call" = "Beantwoord oproep";
@@ -527,6 +563,18 @@
/* No comment provided by engineer. */
"Better messages" = "Betere berichten";
/* No comment provided by engineer. */
"Block" = "Blokkeren";
/* No comment provided by engineer. */
"Block member" = "Lid blokkeren";
/* No comment provided by engineer. */
"Block member?" = "Lid blokkeren?";
/* No comment provided by engineer. */
"blocked" = "geblokkeerd";
/* No comment provided by engineer. */
"bold" = "vetgedrukt";
@@ -597,7 +645,7 @@
"Change lock mode" = "Wijzig de vergrendelings modus";
/* No comment provided by engineer. */
"Change member role?" = "Rol van gebruiker wijzigen?";
"Change member role?" = "Rol van lid wijzigen?";
/* authentication reason */
"Change passcode" = "Toegangscode wijzigen";
@@ -726,6 +774,18 @@
/* No comment provided by engineer. */
"connect to SimpleX Chat developers." = "maak verbinding met SimpleX Chat-ontwikkelaars.";
/* No comment provided by engineer. */
"Connect to yourself?" = "Verbinding maken met jezelf?";
/* No comment provided by engineer. */
"Connect to yourself?\nThis is your own one-time link!" = "Verbinding maken met jezelf?\nDit is uw eigen eenmalige link!";
/* No comment provided by engineer. */
"Connect to yourself?\nThis is your own SimpleX address!" = "Verbinding maken met jezelf?\nDit is uw eigen SimpleX adres!";
/* No comment provided by engineer. */
"Connect via contact address" = "Verbinding maken via contactadres";
/* No comment provided by engineer. */
"Connect via link" = "Maak verbinding via link";
@@ -735,6 +795,9 @@
/* No comment provided by engineer. */
"Connect via one-time link" = "Verbinden via een eenmalige link?";
/* No comment provided by engineer. */
"Connect with %@" = "Verbonden met %@";
/* No comment provided by engineer. */
"connected" = "verbonden";
@@ -831,6 +894,9 @@
/* No comment provided by engineer. */
"Core version: v%@" = "Core versie: v% @";
/* No comment provided by engineer. */
"Correct name to %@?" = "Juiste naam voor %@?";
/* No comment provided by engineer. */
"Create" = "Maak";
@@ -840,6 +906,9 @@
/* server test step */
"Create file" = "Bestand maken";
/* No comment provided by engineer. */
"Create group" = "Groep aanmaken";
/* No comment provided by engineer. */
"Create group link" = "Groep link maken";
@@ -852,6 +921,9 @@
/* No comment provided by engineer. */
"Create one-time invitation link" = "Maak een eenmalige uitnodiging link";
/* No comment provided by engineer. */
"Create profile" = "Maak een profiel aan";
/* server test step */
"Create queue" = "Maak een wachtrij";
@@ -966,6 +1038,9 @@
/* chat item action */
"Delete" = "Verwijderen";
/* No comment provided by engineer. */
"Delete %lld messages?" = "%lld berichten verwijderen?";
/* No comment provided by engineer. */
"Delete address" = "Adres verwijderen";
@@ -978,6 +1053,9 @@
/* No comment provided by engineer. */
"Delete all files" = "Verwijder alle bestanden";
/* No comment provided by engineer. */
"Delete and notify contact" = "Contact verwijderen en op de hoogte stellen";
/* No comment provided by engineer. */
"Delete archive" = "Archief verwijderen";
@@ -999,6 +1077,9 @@
/* No comment provided by engineer. */
"Delete Contact" = "Verwijder contact";
/* No comment provided by engineer. */
"Delete contact?\nThis cannot be undone!" = "Verwijder contact?\nDit kan niet ongedaan gemaakt worden!";
/* No comment provided by engineer. */
"Delete database" = "Database verwijderen";
@@ -1074,6 +1155,9 @@
/* copied message info */
"Deleted at: %@" = "Verwijderd om: %@";
/* rcv direct event chat item */
"deleted contact" = "verwijderd contact";
/* rcv group event chat item */
"deleted group" = "verwijderde groep";
@@ -1305,6 +1389,9 @@
/* No comment provided by engineer. */
"Enter correct passphrase." = "Voer het juiste wachtwoord in.";
/* No comment provided by engineer. */
"Enter group name…" = "Groep naam invoeren…";
/* No comment provided by engineer. */
"Enter Passcode" = "Voer toegangscode in";
@@ -1323,6 +1410,9 @@
/* placeholder */
"Enter welcome message… (optional)" = "Voer welkomst bericht in... (optioneel)";
/* No comment provided by engineer. */
"Enter your name…" = "Vul uw naam in…";
/* No comment provided by engineer. */
"error" = "fout";
@@ -1339,7 +1429,7 @@
"Error accessing database file" = "Fout bij toegang tot database bestand";
/* No comment provided by engineer. */
"Error adding member(s)" = "Fout bij het toevoegen van gebruiker(s)";
"Error adding member(s)" = "Fout bij het toevoegen van leden";
/* No comment provided by engineer. */
"Error changing address" = "Fout bij wijzigen van adres";
@@ -1417,7 +1507,7 @@
"Error receiving file" = "Fout bij ontvangen van bestand";
/* No comment provided by engineer. */
"Error removing member" = "Fout bij verwijderen van gebruiker";
"Error removing member" = "Fout bij verwijderen van lid";
/* No comment provided by engineer. */
"Error saving %@ servers" = "Fout bij opslaan van %@ servers";
@@ -1494,6 +1584,9 @@
/* No comment provided by engineer. */
"Exit without saving" = "Afsluiten zonder opslaan";
/* chat item action */
"Expand" = "Uitbreiden";
/* No comment provided by engineer. */
"Export database" = "Database exporteren";
@@ -1581,6 +1674,9 @@
/* No comment provided by engineer. */
"Full name:" = "Volledige naam:";
/* No comment provided by engineer. */
"Fully decentralized visible only to members." = "Volledig gedecentraliseerd alleen zichtbaar voor leden.";
/* No comment provided by engineer. */
"Fully re-implemented - work in background!" = "Volledig opnieuw geïmplementeerd - werk op de achtergrond!";
@@ -1593,6 +1689,12 @@
/* No comment provided by engineer. */
"Group" = "Groep";
/* No comment provided by engineer. */
"Group already exists" = "Groep bestaat al";
/* No comment provided by engineer. */
"Group already exists!" = "Groep bestaat al!";
/* No comment provided by engineer. */
"group deleted" = "groep verwijderd";
@@ -1830,6 +1932,9 @@
/* invalid chat item */
"invalid data" = "ongeldige gegevens";
/* No comment provided by engineer. */
"Invalid name!" = "Ongeldige naam!";
/* No comment provided by engineer. */
"Invalid server address!" = "Ongeldig server adres!";
@@ -1908,9 +2013,18 @@
/* No comment provided by engineer. */
"Join group" = "Word lid van groep";
/* No comment provided by engineer. */
"Join group?" = "Deelnemen aan groep?";
/* No comment provided by engineer. */
"Join incognito" = "Doe incognito mee";
/* No comment provided by engineer. */
"Join with current profile" = "Word lid met huidig profiel";
/* No comment provided by engineer. */
"Join your group?\nThis is your link for group %@!" = "Sluit u aan bij uw groep?\nDit is jouw link voor groep %@!";
/* No comment provided by engineer. */
"Joining group" = "Deel nemen aan groep";
@@ -2008,22 +2122,22 @@
"Max 30 seconds, received instantly." = "Max 30 seconden, direct ontvangen.";
/* member role */
"member" = "gebruiker";
"member" = "lid";
/* No comment provided by engineer. */
"Member" = "Gebruiker";
"Member" = "Lid";
/* rcv group event chat item */
"member connected" = "is toegetreden";
/* No comment provided by engineer. */
"Member role will be changed to \"%@\". All group members will be notified." = "De rol van gebruiker wordt gewijzigd in \"%@\". Alle groepsleden worden op de hoogte gebracht.";
"Member role will be changed to \"%@\". All group members will be notified." = "De rol van lid wordt gewijzigd in \"%@\". Alle groepsleden worden op de hoogte gebracht.";
/* No comment provided by engineer. */
"Member role will be changed to \"%@\". The member will receive a new invitation." = "De rol van gebruiker wordt gewijzigd in \"%@\". Het lid ontvangt een nieuwe uitnodiging.";
"Member role will be changed to \"%@\". The member will receive a new invitation." = "De rol van lid wordt gewijzigd in \"%@\". Het lid ontvangt een nieuwe uitnodiging.";
/* No comment provided by engineer. */
"Member will be removed from group - this cannot be undone!" = "Gebruiker wordt uit de groep verwijderd, dit kan niet ongedaan worden gemaakt!";
"Member will be removed from group - this cannot be undone!" = "Lid wordt uit de groep verwijderd, dit kan niet ongedaan worden gemaakt!";
/* item status text */
"Message delivery error" = "Fout bij bezorging van bericht";
@@ -2055,6 +2169,9 @@
/* No comment provided by engineer. */
"Messages & files" = "Berichten";
/* No comment provided by engineer. */
"Messages from %@ will be shown!" = "Berichten van %@ worden getoond!";
/* No comment provided by engineer. */
"Migrating database archive…" = "Database archief migreren…";
@@ -2262,7 +2379,7 @@
"Only group owners can change group preferences." = "Alleen groep eigenaren kunnen groep voorkeuren wijzigen.";
/* No comment provided by engineer. */
"Only group owners can enable files and media." = "Alleen groepseigenaren kunnen bestanden en media inschakelen.";
"Only group owners can enable files and media." = "Alleen groep eigenaren kunnen bestanden en media inschakelen.";
/* No comment provided by engineer. */
"Only group owners can enable voice messages." = "Alleen groep eigenaren kunnen spraak berichten inschakelen.";
@@ -2306,6 +2423,9 @@
/* authentication reason */
"Open chat console" = "Chat console openen";
/* No comment provided by engineer. */
"Open group" = "Open groep";
/* No comment provided by engineer. */
"Open Settings" = "Open instellingen";
@@ -2438,6 +2558,12 @@
/* No comment provided by engineer. */
"Profile image" = "profielfoto";
/* No comment provided by engineer. */
"Profile name" = "Profielnaam";
/* No comment provided by engineer. */
"Profile name:" = "Profielnaam:";
/* No comment provided by engineer. */
"Profile password" = "Profiel wachtwoord";
@@ -2577,10 +2703,10 @@
"Remove" = "Verwijderen";
/* No comment provided by engineer. */
"Remove member" = "Gebruiker verwijderen";
"Remove member" = "Lid verwijderen";
/* No comment provided by engineer. */
"Remove member?" = "Gebruiker verwijderen?";
"Remove member?" = "Lid verwijderen?";
/* No comment provided by engineer. */
"Remove passphrase from keychain?" = "Wachtwoord van de keychain verwijderen?";
@@ -2603,6 +2729,12 @@
/* No comment provided by engineer. */
"Renegotiate encryption?" = "Heronderhandelen over versleuteling?";
/* No comment provided by engineer. */
"Repeat connection request?" = "Verbindingsverzoek herhalen?";
/* No comment provided by engineer. */
"Repeat join request?" = "Deelnameverzoek herhalen?";
/* chat item action */
"Reply" = "Antwoord";
@@ -2667,7 +2799,7 @@
"Save and notify contact" = "Opslaan en Contact melden";
/* No comment provided by engineer. */
"Save and notify group members" = "Opslaan en Groep leden melden";
"Save and notify group members" = "Opslaan en groep leden melden";
/* No comment provided by engineer. */
"Save and update group profile" = "Groep profiel opslaan en bijwerken";
@@ -3045,10 +3177,13 @@
"Tap to activate profile." = "Tik om profiel te activeren.";
/* No comment provided by engineer. */
"Tap to join" = "Tik om mee te doen";
"Tap to Connect" = "Tik om verbinding te maken";
/* No comment provided by engineer. */
"Tap to join incognito" = "Tik om incognito deel te nemen";
"Tap to join" = "Tik om lid te worden";
/* No comment provided by engineer. */
"Tap to join incognito" = "Tik om incognito lid te worden";
/* No comment provided by engineer. */
"Tap to start a new chat" = "Tik om een nieuw gesprek te starten";
@@ -3170,6 +3305,12 @@
/* No comment provided by engineer. */
"This group no longer exists." = "Deze groep bestaat niet meer.";
/* No comment provided by engineer. */
"This is your own one-time link!" = "Dit is uw eigen eenmalige link!";
/* No comment provided by engineer. */
"This is your own SimpleX address!" = "Dit is uw eigen SimpleX adres!";
/* No comment provided by engineer. */
"This setting applies to messages in your current chat profile **%@**." = "Deze instelling is van toepassing op berichten in je huidige chat profiel **%@**.";
@@ -3227,6 +3368,15 @@
/* No comment provided by engineer. */
"Unable to record voice message" = "Kan spraakbericht niet opnemen";
/* No comment provided by engineer. */
"Unblock" = "Deblokkeren";
/* No comment provided by engineer. */
"Unblock member" = "Lid deblokkeren";
/* No comment provided by engineer. */
"Unblock member?" = "Lid deblokkeren?";
/* item status description */
"Unexpected error: %@" = "Onverwachte fout: %@";
@@ -3473,6 +3623,27 @@
/* No comment provided by engineer. */
"You are already connected to %@." = "U bent al verbonden met %@.";
/* No comment provided by engineer. */
"You are already connecting to %@." = "U maakt al verbinding met %@.";
/* No comment provided by engineer. */
"You are already connecting via this one-time link!" = "Je maakt al verbinding via deze eenmalige link!";
/* No comment provided by engineer. */
"You are already in group %@." = "Je zit al in groep %@.";
/* No comment provided by engineer. */
"You are already joining the group %@." = "Je bent al lid van de groep %@.";
/* No comment provided by engineer. */
"You are already joining the group via this link!" = "Je wordt al lid van de groep via deze link!";
/* No comment provided by engineer. */
"You are already joining the group via this link." = "Je wordt al lid van de groep via deze link.";
/* No comment provided by engineer. */
"You are already joining the group!\nRepeat join request?" = "Je sluit je al aan bij de groep!\nDeelnameverzoek herhalen?";
/* No comment provided by engineer. */
"You are connected to the server used to receive messages from this contact." = "U bent verbonden met de server die wordt gebruikt om berichten van dit contact te ontvangen.";
@@ -3548,6 +3719,12 @@
/* No comment provided by engineer. */
"You could not be verified; please try again." = "U kon niet worden geverifieerd; probeer het opnieuw.";
/* No comment provided by engineer. */
"You have already requested connection via this address!" = "U heeft al een verbinding aangevraagd via dit adres!";
/* No comment provided by engineer. */
"You have already requested connection!\nRepeat connection request?" = "Je hebt al verbinding aangevraagd!\nVerbindingsverzoek herhalen?";
/* No comment provided by engineer. */
"You have no chats" = "Je hebt geen gesprekken";
@@ -3590,6 +3767,9 @@
/* No comment provided by engineer. */
"You will be connected to group when the group host's device is online, please wait or check later!" = "Je wordt verbonden met de groep wanneer het apparaat van de groep host online is, even geduld a.u.b. of controleer het later!";
/* No comment provided by engineer. */
"You will be connected when group link host's device is online, please wait or check later!" = "U wordt verbonden wanneer het apparaat van de groep link host online is. Wacht even of controleer het later opnieuw!";
/* No comment provided by engineer. */
"You will be connected when your connection request is accepted, please wait or check later!" = "U wordt verbonden wanneer uw verbindingsverzoek wordt geaccepteerd, even geduld a.u.b. of controleer later!";
@@ -3599,6 +3779,9 @@
/* No comment provided by engineer. */
"You will be required to authenticate when you start or resume the app after 30 seconds in background." = "U moet zich authenticeren wanneer u de app na 30 seconden op de achtergrond start of hervat.";
/* No comment provided by engineer. */
"You will connect to all group members." = "Je maakt verbinding met alle leden.";
/* No comment provided by engineer. */
"You will still receive calls and notifications from muted profiles when they are active." = "U ontvangt nog steeds oproepen en meldingen van gedempte profielen wanneer deze actief zijn.";
@@ -3662,6 +3845,9 @@
/* No comment provided by engineer. */
"Your privacy" = "Uw privacy";
/* No comment provided by engineer. */
"Your profile" = "Jouw profiel";
/* No comment provided by engineer. */
"Your profile **%@** will be shared." = "Uw profiel **%@** wordt gedeeld.";
+186
View File
@@ -118,12 +118,18 @@
/* No comment provided by engineer. */
"%@ %@" = "%@ %@";
/* No comment provided by engineer. */
"%@ and %@" = "%@ i %@";
/* No comment provided by engineer. */
"%@ and %@ connected" = "%@ i %@ połączeni";
/* copied message info, <sender> at <time> */
"%@ at %@:" = "%1$@ o %2$@:";
/* No comment provided by engineer. */
"%@ connected" = "%@ połączony";
/* notification title */
"%@ is connected!" = "%@ jest połączony!";
@@ -139,6 +145,9 @@
/* notification title */
"%@ wants to connect!" = "%@ chce się połączyć!";
/* No comment provided by engineer. */
"%@, %@ and %lld members" = "%@, %@ i %lld członków";
/* No comment provided by engineer. */
"%@, %@ and %lld other members connected" = "%@, %@ i %lld innych członków połączeni";
@@ -178,9 +187,21 @@
/* No comment provided by engineer. */
"%lld file(s) with total size of %@" = "%lld plik(i) o całkowitym rozmiarze %@";
/* No comment provided by engineer. */
"%lld group events" = "%lld wydarzeń grupy";
/* No comment provided by engineer. */
"%lld members" = "%lld członków";
/* No comment provided by engineer. */
"%lld messages blocked" = "%lld wiadomości zablokowanych";
/* No comment provided by engineer. */
"%lld messages marked deleted" = "%lld wiadomości oznaczonych do usunięcia";
/* No comment provided by engineer. */
"%lld messages moderated by %@" = "%lld wiadomości zmoderowanych przez %@";
/* No comment provided by engineer. */
"%lld minutes" = "%lld minut";
@@ -229,6 +250,9 @@
/* No comment provided by engineer. */
"~strike~" = "\\~strajk~";
/* time to disappear */
"0 sec" = "0 sek";
/* No comment provided by engineer. */
"0s" = "0s";
@@ -371,6 +395,9 @@
/* No comment provided by engineer. */
"All messages will be deleted - this cannot be undone! The messages will be deleted ONLY for you." = "Wszystkie wiadomości zostaną usunięte - nie można tego cofnąć! Wiadomości zostaną usunięte TYLKO dla Ciebie.";
/* No comment provided by engineer. */
"All new messages from %@ will be hidden!" = "Wszystkie nowe wiadomości z %@ zostaną ukryte!";
/* No comment provided by engineer. */
"All your contacts will remain connected." = "Wszystkie Twoje kontakty pozostaną połączone.";
@@ -434,6 +461,12 @@
/* No comment provided by engineer. */
"Already connected?" = "Już połączony?";
/* No comment provided by engineer. */
"Already connecting!" = "Już połączony!";
/* No comment provided by engineer. */
"Already joining the group!" = "Już dołączono do grupy!";
/* pref value */
"always" = "zawsze";
@@ -443,6 +476,9 @@
/* No comment provided by engineer. */
"An empty chat profile with the provided name is created, and the app opens as usual." = "Tworzony jest pusty profil czatu o podanej nazwie, a aplikacja otwiera się jak zwykle.";
/* No comment provided by engineer. */
"and %lld other events" = "i %lld innych wydarzeń";
/* No comment provided by engineer. */
"Answer call" = "Odbierz połączenie";
@@ -527,6 +563,18 @@
/* No comment provided by engineer. */
"Better messages" = "Lepsze wiadomości";
/* No comment provided by engineer. */
"Block" = "Zablokuj";
/* No comment provided by engineer. */
"Block member" = "Zablokuj członka";
/* No comment provided by engineer. */
"Block member?" = "Zablokować członka?";
/* No comment provided by engineer. */
"blocked" = "zablokowany";
/* No comment provided by engineer. */
"bold" = "pogrubiona";
@@ -726,6 +774,18 @@
/* No comment provided by engineer. */
"connect to SimpleX Chat developers." = "połącz się z deweloperami SimpleX Chat.";
/* No comment provided by engineer. */
"Connect to yourself?" = "Połączyć się ze sobą?";
/* No comment provided by engineer. */
"Connect to yourself?\nThis is your own one-time link!" = "Połączyć się ze sobą?\nTo jest twój jednorazowy link!";
/* No comment provided by engineer. */
"Connect to yourself?\nThis is your own SimpleX address!" = "Połączyć się ze sobą?\nTo jest twój własny adres SimpleX!";
/* No comment provided by engineer. */
"Connect via contact address" = "Połącz przez adres kontaktowy";
/* No comment provided by engineer. */
"Connect via link" = "Połącz się przez link";
@@ -735,6 +795,9 @@
/* No comment provided by engineer. */
"Connect via one-time link" = "Połącz przez jednorazowy link";
/* No comment provided by engineer. */
"Connect with %@" = "Połącz z %@";
/* No comment provided by engineer. */
"connected" = "połączony";
@@ -831,6 +894,9 @@
/* No comment provided by engineer. */
"Core version: v%@" = "Wersja rdzenia: v%@";
/* No comment provided by engineer. */
"Correct name to %@?" = "Poprawić imię na %@?";
/* No comment provided by engineer. */
"Create" = "Utwórz";
@@ -840,6 +906,9 @@
/* server test step */
"Create file" = "Utwórz plik";
/* No comment provided by engineer. */
"Create group" = "Utwórz grupę";
/* No comment provided by engineer. */
"Create group link" = "Utwórz link do grupy";
@@ -852,6 +921,9 @@
/* No comment provided by engineer. */
"Create one-time invitation link" = "Utwórz jednorazowy link do zaproszenia";
/* No comment provided by engineer. */
"Create profile" = "Utwórz profil";
/* server test step */
"Create queue" = "Utwórz kolejkę";
@@ -966,6 +1038,9 @@
/* chat item action */
"Delete" = "Usuń";
/* No comment provided by engineer. */
"Delete %lld messages?" = "Usunąć %lld wiadomości?";
/* No comment provided by engineer. */
"Delete address" = "Usuń adres";
@@ -978,6 +1053,9 @@
/* No comment provided by engineer. */
"Delete all files" = "Usuń wszystkie pliki";
/* No comment provided by engineer. */
"Delete and notify contact" = "Usuń i powiadom kontakt";
/* No comment provided by engineer. */
"Delete archive" = "Usuń archiwum";
@@ -999,6 +1077,9 @@
/* No comment provided by engineer. */
"Delete Contact" = "Usuń Kontakt";
/* No comment provided by engineer. */
"Delete contact?\nThis cannot be undone!" = "Usunąć kontakt?\nTo nie może być cofnięte!";
/* No comment provided by engineer. */
"Delete database" = "Usuń bazę danych";
@@ -1074,6 +1155,9 @@
/* copied message info */
"Deleted at: %@" = "Usunięto o: %@";
/* rcv direct event chat item */
"deleted contact" = "usunięto kontakt";
/* rcv group event chat item */
"deleted group" = "usunięta grupa";
@@ -1305,6 +1389,9 @@
/* No comment provided by engineer. */
"Enter correct passphrase." = "Wprowadź poprawne hasło.";
/* No comment provided by engineer. */
"Enter group name…" = "Wpisz nazwę grupy…";
/* No comment provided by engineer. */
"Enter Passcode" = "Wprowadź Pin";
@@ -1323,6 +1410,9 @@
/* placeholder */
"Enter welcome message… (optional)" = "Wpisz wiadomość powitalną… (opcjonalne)";
/* No comment provided by engineer. */
"Enter your name…" = "Wpisz swoją nazwę…";
/* No comment provided by engineer. */
"error" = "błąd";
@@ -1494,6 +1584,9 @@
/* No comment provided by engineer. */
"Exit without saving" = "Wyjdź bez zapisywania";
/* chat item action */
"Expand" = "Rozszerz";
/* No comment provided by engineer. */
"Export database" = "Eksportuj bazę danych";
@@ -1581,6 +1674,9 @@
/* No comment provided by engineer. */
"Full name:" = "Pełna nazwa:";
/* No comment provided by engineer. */
"Fully decentralized visible only to members." = "W pełni zdecentralizowana widoczna tylko dla członków.";
/* No comment provided by engineer. */
"Fully re-implemented - work in background!" = "W pełni ponownie zaimplementowany - praca w tle!";
@@ -1593,6 +1689,12 @@
/* No comment provided by engineer. */
"Group" = "Grupa";
/* No comment provided by engineer. */
"Group already exists" = "Grupa już istnieje";
/* No comment provided by engineer. */
"Group already exists!" = "Grupa już istnieje!";
/* No comment provided by engineer. */
"group deleted" = "grupa usunięta";
@@ -1830,6 +1932,9 @@
/* invalid chat item */
"invalid data" = "nieprawidłowe dane";
/* No comment provided by engineer. */
"Invalid name!" = "Nieprawidłowa nazwa!";
/* No comment provided by engineer. */
"Invalid server address!" = "Nieprawidłowy adres serwera!";
@@ -1908,9 +2013,18 @@
/* No comment provided by engineer. */
"Join group" = "Dołącz do grupy";
/* No comment provided by engineer. */
"Join group?" = "Dołączyć do grupy?";
/* No comment provided by engineer. */
"Join incognito" = "Dołącz incognito";
/* No comment provided by engineer. */
"Join with current profile" = "Dołącz z obecnym profilem";
/* No comment provided by engineer. */
"Join your group?\nThis is your link for group %@!" = "Dołączyć do twojej grupy?\nTo jest twój link do grupy %@!";
/* No comment provided by engineer. */
"Joining group" = "Dołączanie do grupy";
@@ -2055,6 +2169,9 @@
/* No comment provided by engineer. */
"Messages & files" = "Wiadomości i pliki";
/* No comment provided by engineer. */
"Messages from %@ will be shown!" = "Wiadomości od %@ zostaną pokazane!";
/* No comment provided by engineer. */
"Migrating database archive…" = "Migrowanie archiwum bazy danych…";
@@ -2306,6 +2423,9 @@
/* authentication reason */
"Open chat console" = "Otwórz konsolę czatu";
/* No comment provided by engineer. */
"Open group" = "Grupa otwarta";
/* No comment provided by engineer. */
"Open Settings" = "Otwórz Ustawienia";
@@ -2438,6 +2558,12 @@
/* No comment provided by engineer. */
"Profile image" = "Zdjęcie profilowe";
/* No comment provided by engineer. */
"Profile name" = "Nazwa profilu";
/* No comment provided by engineer. */
"Profile name:" = "Nazwa profilu:";
/* No comment provided by engineer. */
"Profile password" = "Hasło profilu";
@@ -2603,6 +2729,12 @@
/* No comment provided by engineer. */
"Renegotiate encryption?" = "Renegocjować szyfrowanie?";
/* No comment provided by engineer. */
"Repeat connection request?" = "Powtórzyć prośbę połączenia?";
/* No comment provided by engineer. */
"Repeat join request?" = "Powtórzyć prośbę dołączenia?";
/* chat item action */
"Reply" = "Odpowiedz";
@@ -3044,6 +3176,9 @@
/* No comment provided by engineer. */
"Tap to activate profile." = "Dotknij, aby aktywować profil.";
/* No comment provided by engineer. */
"Tap to Connect" = "Dotknij aby połączyć";
/* No comment provided by engineer. */
"Tap to join" = "Dotknij, aby dołączyć";
@@ -3170,6 +3305,12 @@
/* No comment provided by engineer. */
"This group no longer exists." = "Ta grupa już nie istnieje.";
/* No comment provided by engineer. */
"This is your own one-time link!" = "To jest twój jednorazowy link!";
/* No comment provided by engineer. */
"This is your own SimpleX address!" = "To jest twój własny adres SimpleX!";
/* No comment provided by engineer. */
"This setting applies to messages in your current chat profile **%@**." = "To ustawienie dotyczy wiadomości Twojego bieżącego profilu czatu **%@**.";
@@ -3227,6 +3368,15 @@
/* No comment provided by engineer. */
"Unable to record voice message" = "Nie można nagrać wiadomości głosowej";
/* No comment provided by engineer. */
"Unblock" = "Odblokuj";
/* No comment provided by engineer. */
"Unblock member" = "Odblokuj członka";
/* No comment provided by engineer. */
"Unblock member?" = "Odblokować członka?";
/* item status description */
"Unexpected error: %@" = "Nieoczekiwany błąd: %@";
@@ -3473,6 +3623,27 @@
/* No comment provided by engineer. */
"You are already connected to %@." = "Jesteś już połączony z %@.";
/* No comment provided by engineer. */
"You are already connecting to %@." = "Już się łączysz z %@.";
/* No comment provided by engineer. */
"You are already connecting via this one-time link!" = "Już jesteś połączony z tym jednorazowym linkiem!";
/* No comment provided by engineer. */
"You are already in group %@." = "Już jesteś w grupie %@.";
/* No comment provided by engineer. */
"You are already joining the group %@." = "Już dołączasz do grupy %@.";
/* No comment provided by engineer. */
"You are already joining the group via this link!" = "Już dołączasz do grupy przez ten link!";
/* No comment provided by engineer. */
"You are already joining the group via this link." = "Już dołączasz do grupy przez ten link.";
/* No comment provided by engineer. */
"You are already joining the group!\nRepeat join request?" = "Już dołączasz do grupy!\nPowtórzyć prośbę dołączenia?";
/* No comment provided by engineer. */
"You are connected to the server used to receive messages from this contact." = "Jesteś połączony z serwerem używanym do odbierania wiadomości od tego kontaktu.";
@@ -3548,6 +3719,12 @@
/* No comment provided by engineer. */
"You could not be verified; please try again." = "Nie można zweryfikować użytkownika; proszę spróbować ponownie.";
/* No comment provided by engineer. */
"You have already requested connection via this address!" = "Już prosiłeś o połączenie na ten adres!";
/* No comment provided by engineer. */
"You have already requested connection!\nRepeat connection request?" = "Już prosiłeś o połączenie!\nPowtórzyć prośbę połączenia?";
/* No comment provided by engineer. */
"You have no chats" = "Nie masz czatów";
@@ -3590,6 +3767,9 @@
/* No comment provided by engineer. */
"You will be connected to group when the group host's device is online, please wait or check later!" = "Zostaniesz połączony do grupy, gdy urządzenie gospodarza grupy będzie online, proszę czekać lub sprawdzić później!";
/* No comment provided by engineer. */
"You will be connected when group link host's device is online, please wait or check later!" = "Zostaniesz połączony, gdy urządzenie hosta grupy będzie online, proszę czekać lub sprawdzić później!";
/* No comment provided by engineer. */
"You will be connected when your connection request is accepted, please wait or check later!" = "Zostaniesz połączony, gdy Twoje żądanie połączenia zostanie zaakceptowane, proszę czekać lub sprawdzić później!";
@@ -3599,6 +3779,9 @@
/* No comment provided by engineer. */
"You will be required to authenticate when you start or resume the app after 30 seconds in background." = "Uwierzytelnienie będzie wymagane przy uruchamianiu lub wznawianiu aplikacji po 30 sekundach w tle.";
/* No comment provided by engineer. */
"You will connect to all group members." = "Zostaniesz połączony ze wszystkimi członkami grupy.";
/* No comment provided by engineer. */
"You will still receive calls and notifications from muted profiles when they are active." = "Nadal będziesz otrzymywać połączenia i powiadomienia z wyciszonych profili, gdy są one aktywne.";
@@ -3662,6 +3845,9 @@
/* No comment provided by engineer. */
"Your privacy" = "Twoja prywatność";
/* No comment provided by engineer. */
"Your profile" = "Twój profil";
/* No comment provided by engineer. */
"Your profile **%@** will be shared." = "Twój profil **%@** zostanie udostępniony.";
@@ -15,7 +15,6 @@
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
@@ -126,7 +126,7 @@ fun processIntent(intent: Intent?) {
when (intent?.action) {
"android.intent.action.VIEW" -> {
val uri = intent.data
if (uri != null) connectIfOpenedViaUri(uri.toURI(), ChatModel)
if (uri != null) connectIfOpenedViaUri(chatModel.remoteHostId, uri.toURI(), ChatModel)
}
}
}
@@ -57,7 +57,7 @@ class SimplexApp: Application(), LifecycleEventObserver {
updatingChatsMutex.withLock {
kotlin.runCatching {
val currentUserId = chatModel.currentUser.value?.userId
val chats = ArrayList(chatController.apiGetChats())
val chats = ArrayList(chatController.apiGetChats(chatModel.remoteHostId))
/** Active user can be changed in background while [ChatController.apiGetChats] is executing */
if (chatModel.currentUser.value?.userId == currentUserId) {
val currentChatId = chatModel.chatId.value
@@ -231,6 +231,7 @@ fun PreviewIncomingCallLockScreenAlert() {
) {
IncomingCallLockScreenAlertLayout(
invitation = RcvCallInvitation(
remoteHostId = null,
user = User.sampleData,
contact = Contact.sampleData,
callType = CallType(media = CallMediaType.Audio, capabilities = CallCapabilities(encryption = false)),
@@ -16,6 +16,8 @@ import kotlin.random.Random
actual val appPlatform = AppPlatform.ANDROID
actual val deviceName = android.os.Build.MODEL
var isAppOnForeground: Boolean = false
@Suppress("ConstantLocale")
@@ -66,5 +68,12 @@ fun initHaskell() {
s.acquire()
pipeStdOutToSocket(socketName)
initHS()
var inited = false
thread(name = "initHs", isDaemon = true) {
initHS()
inited = true
}
while (!inited) {
Thread.sleep(2)
}
}
@@ -23,6 +23,8 @@ actual val agentDatabaseFileName: String = "files_agent.db"
actual val databaseExportDir: File = androidAppContext.cacheDir
actual val remoteHostsDir: File = File(tmpDir.absolutePath + File.separator + "remote_hosts")
actual fun desktopOpenDatabaseDir() {}
@Composable
@@ -38,7 +38,7 @@ actual class RecorderNative: RecorderInterface {
rec.setAudioSamplingRate(16000)
rec.setAudioEncodingBitRate(32000)
rec.setMaxDuration(MAX_VOICE_MILLIS_FOR_SENDING)
val fileToSave = File.createTempFile(generateNewFileName("voice", "${RecorderInterface.extension}_"), ".tmp", tmpDir)
val fileToSave = File.createTempFile(generateNewFileName("voice", "${RecorderInterface.extension}_", tmpDir), ".tmp", tmpDir)
fileToSave.deleteOnExit()
val path = fileToSave.absolutePath
filePath = path
@@ -115,22 +115,23 @@ actual fun ActiveCallView() {
val call = chatModel.activeCall.value
if (call != null) {
Log.d(TAG, "has active call $call")
val callRh = call.remoteHostId
when (val r = apiMsg.resp) {
is WCallResponse.Capabilities -> withBGApi {
val callType = CallType(call.localMedia, r.capabilities)
chatModel.controller.apiSendCallInvitation(call.contact, callType)
chatModel.controller.apiSendCallInvitation(callRh, call.contact, callType)
chatModel.activeCall.value = call.copy(callState = CallState.InvitationSent, localCapabilities = r.capabilities)
}
is WCallResponse.Offer -> withBGApi {
chatModel.controller.apiSendCallOffer(call.contact, r.offer, r.iceCandidates, call.localMedia, r.capabilities)
chatModel.controller.apiSendCallOffer(callRh, call.contact, r.offer, r.iceCandidates, call.localMedia, r.capabilities)
chatModel.activeCall.value = call.copy(callState = CallState.OfferSent, localCapabilities = r.capabilities)
}
is WCallResponse.Answer -> withBGApi {
chatModel.controller.apiSendCallAnswer(call.contact, r.answer, r.iceCandidates)
chatModel.controller.apiSendCallAnswer(callRh, call.contact, r.answer, r.iceCandidates)
chatModel.activeCall.value = call.copy(callState = CallState.Negotiated)
}
is WCallResponse.Ice -> withBGApi {
chatModel.controller.apiSendCallExtraInfo(call.contact, r.iceCandidates)
chatModel.controller.apiSendCallExtraInfo(callRh, call.contact, r.iceCandidates)
}
is WCallResponse.Connection ->
try {
@@ -139,7 +140,7 @@ actual fun ActiveCallView() {
chatModel.activeCall.value = call.copy(callState = CallState.Connected, connectedAt = Clock.System.now())
setCallSound(call.soundSpeaker, audioViaBluetooth)
}
withBGApi { chatModel.controller.apiCallStatus(call.contact, callStatus) }
withBGApi { chatModel.controller.apiCallStatus(callRh, call.contact, callStatus) }
} catch (e: Error) {
Log.d(TAG,"call status ${r.state.connectionState} not used")
}
@@ -578,6 +579,7 @@ fun PreviewActiveCallOverlayVideo() {
SimpleXTheme {
ActiveCallOverlayLayout(
call = Call(
remoteHostId = null,
contact = Contact.sampleData,
callState = CallState.Negotiated,
localMedia = CallMediaType.Video,
@@ -603,6 +605,7 @@ fun PreviewActiveCallOverlayAudio() {
SimpleXTheme {
ActiveCallOverlayLayout(
call = Call(
remoteHostId = null,
contact = Contact.sampleData,
callState = CallState.Negotiated,
localMedia = CallMediaType.Audio,
@@ -1,16 +0,0 @@
package chat.simplex.common.views.chat
import android.Manifest
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import chat.simplex.common.views.chat.ScanCodeLayout
import com.google.accompanist.permissions.rememberPermissionState
@Composable
actual fun ScanCodeView(verifyCode: (String?, cb: (Boolean) -> Unit) -> Unit, close: () -> Unit) {
val cameraPermissionState = rememberPermissionState(permission = Manifest.permission.CAMERA)
LaunchedEffect(Unit) {
cameraPermissionState.launchPermissionRequest()
}
ScanCodeLayout(verifyCode, close)
}
@@ -167,7 +167,7 @@ actual fun getAppFileUri(fileName: String): URI =
FileProvider.getUriForFile(androidAppContext, "$APPLICATION_ID.provider", if (File(fileName).isAbsolute) File(fileName) else File(getAppFilePath(fileName))).toURI()
// https://developer.android.com/training/data-storage/shared/documents-files#bitmap
actual fun getLoadedImage(file: CIFile?): Pair<ImageBitmap, ByteArray>? {
actual suspend fun getLoadedImage(file: CIFile?): Pair<ImageBitmap, ByteArray>? {
val filePath = getLoadedFilePath(file)
return if (filePath != null && file != null) {
try {
@@ -295,7 +295,7 @@ actual suspend fun saveTempImageUncompressed(image: ImageBitmap, asPng: Boolean)
return try {
val ext = if (asPng) "png" else "jpg"
tmpDir.mkdir()
return File(tmpDir.absolutePath + File.separator + generateNewFileName("IMG", ext)).apply {
return File(tmpDir.absolutePath + File.separator + generateNewFileName("IMG", ext, tmpDir)).apply {
outputStream().use { out ->
image.asAndroidBitmap().compress(if (asPng) Bitmap.CompressFormat.PNG else Bitmap.CompressFormat.JPEG, 85, out)
out.flush()
@@ -9,10 +9,12 @@ import dev.icerock.moko.resources.compose.painterResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.unit.sp
import chat.simplex.common.model.ChatModel
import chat.simplex.common.model.RemoteHostInfo
import chat.simplex.res.MR
@Composable
actual fun ConnectViaLinkView(m: ChatModel, close: () -> Unit) {
actual fun ConnectViaLinkView(m: ChatModel, rh: RemoteHostInfo?, close: () -> Unit) {
// TODO this should close if remote host changes in model
val selection = remember {
mutableStateOf(
runCatching { ConnectViaLinkTab.valueOf(m.controller.appPrefs.connectViaLinkTab.get()!!) }.getOrDefault(ConnectViaLinkTab.SCAN)
@@ -31,10 +33,10 @@ actual fun ConnectViaLinkView(m: ChatModel, close: () -> Unit) {
Column(Modifier.weight(1f)) {
when (selection.value) {
ConnectViaLinkTab.SCAN -> {
ScanToConnectView(m, close)
ScanToConnectView(m, rh, close)
}
ConnectViaLinkTab.PASTE -> {
PasteToConnectView(m, close)
PasteToConnectView(m, rh, close)
}
}
}
@@ -1,5 +1,6 @@
package chat.simplex.common.views.newchat
import android.Manifest
import android.annotation.SuppressLint
import android.util.Log
import android.view.ViewGroup
@@ -19,6 +20,7 @@ import boofcv.android.ConvertCameraImage
import boofcv.factory.fiducial.FactoryFiducial
import boofcv.struct.image.GrayU8
import chat.simplex.common.platform.TAG
import com.google.accompanist.permissions.rememberPermissionState
import com.google.common.util.concurrent.ListenableFuture
import java.util.concurrent.*
@@ -26,6 +28,10 @@ import java.util.concurrent.*
@Composable
actual fun QRCodeScanner(onBarcode: (String) -> Unit) {
val cameraPermissionState = rememberPermissionState(permission = Manifest.permission.CAMERA)
LaunchedEffect(Unit) {
cameraPermissionState.launchPermissionRequest()
}
val context = LocalContext.current
val lifecycleOwner = LocalLifecycleOwner.current
var preview by remember { mutableStateOf<Preview?>(null) }
@@ -4,16 +4,18 @@ import android.Manifest
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import chat.simplex.common.model.ChatModel
import chat.simplex.common.model.RemoteHostInfo
import com.google.accompanist.permissions.rememberPermissionState
@Composable
actual fun ScanToConnectView(chatModel: ChatModel, close: () -> Unit) {
actual fun ScanToConnectView(chatModel: ChatModel, rh: RemoteHostInfo?, close: () -> Unit) {
val cameraPermissionState = rememberPermissionState(permission = Manifest.permission.CAMERA)
LaunchedEffect(Unit) {
cameraPermissionState.launchPermissionRequest()
}
ConnectContactLayout(
chatModel = chatModel,
rh = rh,
incognitoPref = chatModel.controller.appPrefs.incognito,
close = close
)
@@ -7,10 +7,10 @@ import chat.simplex.common.model.ServerCfg
import com.google.accompanist.permissions.rememberPermissionState
@Composable
actual fun ScanProtocolServer(onNext: (ServerCfg) -> Unit) {
actual fun ScanProtocolServer(rhId: Long?, onNext: (ServerCfg) -> Unit) {
val cameraPermissionState = rememberPermissionState(permission = Manifest.permission.CAMERA)
LaunchedEffect(Unit) {
cameraPermissionState.launchPermissionRequest()
}
ScanProtocolServerLayout(onNext)
ScanProtocolServerLayout(rhId, onNext)
}
@@ -41,6 +41,7 @@ typedef long* chat_ctrl;
extern char *chat_migrate_init(const char *path, const char *key, const char *confirm, chat_ctrl *ctrl);
extern char *chat_send_cmd(chat_ctrl ctrl, const char *cmd);
extern char *chat_send_remote_cmd(chat_ctrl ctrl, const int rhId, const char *cmd);
extern char *chat_recv_msg(chat_ctrl ctrl); // deprecated
extern char *chat_recv_msg_wait(chat_ctrl ctrl, const int wait);
extern char *chat_parse_markdown(const char *str);
@@ -86,6 +87,14 @@ Java_chat_simplex_common_platform_CoreKt_chatSendCmd(JNIEnv *env, __unused jclas
return res;
}
JNIEXPORT jstring JNICALL
Java_chat_simplex_common_platform_CoreKt_chatSendRemoteCmd(JNIEnv *env, __unused jclass clazz, jlong controller, jint rhId, jstring msg) {
const char *_msg = (*env)->GetStringUTFChars(env, msg, JNI_FALSE);
jstring res = (*env)->NewStringUTF(env, chat_send_remote_cmd((void*)controller, rhId, _msg));
(*env)->ReleaseStringUTFChars(env, msg, _msg);
return res;
}
JNIEXPORT jstring JNICALL
Java_chat_simplex_common_platform_CoreKt_chatRecvMsg(JNIEnv *env, __unused jclass clazz, jlong controller) {
return (*env)->NewStringUTF(env, chat_recv_msg((void*)controller));
@@ -16,6 +16,7 @@ typedef long* chat_ctrl;
extern char *chat_migrate_init(const char *path, const char *key, const char *confirm, chat_ctrl *ctrl);
extern char *chat_send_cmd(chat_ctrl ctrl, const char *cmd);
extern char *chat_send_remote_cmd(chat_ctrl ctrl, const int rhId, const char *cmd);
extern char *chat_recv_msg(chat_ctrl ctrl); // deprecated
extern char *chat_recv_msg_wait(chat_ctrl ctrl, const int wait);
extern char *chat_parse_markdown(const char *str);
@@ -98,6 +99,14 @@ Java_chat_simplex_common_platform_CoreKt_chatSendCmd(JNIEnv *env, jclass clazz,
return res;
}
JNIEXPORT jstring JNICALL
Java_chat_simplex_common_platform_CoreKt_chatSendRemoteCmd(JNIEnv *env, jclass clazz, jlong controller, jint rhId, jstring msg) {
const char *_msg = encode_to_utf8_chars(env, msg);
jstring res = decode_to_utf8_string(env, chat_send_remote_cmd((void*)controller, rhId, _msg));
(*env)->ReleaseStringUTFChars(env, msg, _msg);
return res;
}
JNIEXPORT jstring JNICALL
Java_chat_simplex_common_platform_CoreKt_chatRecvMsg(JNIEnv *env, jclass clazz, jlong controller) {
return decode_to_utf8_string(env, chat_recv_msg((void*)controller));
@@ -38,7 +38,7 @@ import kotlinx.coroutines.flow.*
data class SettingsViewState(
val userPickerState: MutableStateFlow<AnimatedViewState>,
val scaffoldState: ScaffoldState,
val switchingUsers: MutableState<Boolean>
val switchingUsersAndHosts: MutableState<Boolean>
)
@Composable
@@ -121,8 +121,8 @@ fun MainScreen() {
showAdvertiseLAAlert = true
val userPickerState by rememberSaveable(stateSaver = AnimatedViewState.saver()) { mutableStateOf(MutableStateFlow(AnimatedViewState.GONE)) }
val scaffoldState = rememberScaffoldState()
val switchingUsers = rememberSaveable { mutableStateOf(false) }
val settingsState = remember { SettingsViewState(userPickerState, scaffoldState, switchingUsers) }
val switchingUsersAndHosts = rememberSaveable { mutableStateOf(false) }
val settingsState = remember { SettingsViewState(userPickerState, scaffoldState, switchingUsersAndHosts) }
if (appPlatform.isAndroid) {
AndroidScreen(settingsState)
} else {
@@ -138,7 +138,7 @@ fun MainScreen() {
}
onboarding == OnboardingStage.Step2_CreateProfile -> CreateFirstProfile(chatModel) {}
onboarding == OnboardingStage.Step2_5_SetupDatabasePassphrase -> SetupDatabasePassphrase(chatModel)
onboarding == OnboardingStage.Step3_CreateSimpleXAddress -> CreateSimpleXAddress(chatModel)
onboarding == OnboardingStage.Step3_CreateSimpleXAddress -> CreateSimpleXAddress(chatModel, null)
onboarding == OnboardingStage.Step4_SetNotificationsMode -> SetNotificationsMode(chatModel)
}
if (appPlatform.isAndroid) {
@@ -298,7 +298,7 @@ fun DesktopScreen(settingsState: SettingsViewState) {
EndPartOfScreen()
}
}
val (userPickerState, scaffoldState, switchingUsers ) = settingsState
val (userPickerState, scaffoldState, switchingUsersAndHosts ) = settingsState
val scope = rememberCoroutineScope()
if (scaffoldState.drawerState.isOpen) {
Box(
@@ -312,8 +312,9 @@ fun DesktopScreen(settingsState: SettingsViewState) {
)
}
VerticalDivider(Modifier.padding(start = DEFAULT_START_MODAL_WIDTH))
UserPicker(chatModel, userPickerState, switchingUsers) {
UserPicker(chatModel, userPickerState, switchingUsersAndHosts) {
scope.launch { if (scaffoldState.drawerState.isOpen) scaffoldState.drawerState.close() else scaffoldState.drawerState.open() }
userPickerState.value = AnimatedViewState.GONE
}
ModalManager.fullscreen.showInView()
}
@@ -1,7 +1,8 @@
package chat.simplex.common.model
import androidx.compose.material.MaterialTheme
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.runtime.snapshots.SnapshotStateList
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.font.*
@@ -26,6 +27,7 @@ import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.*
import java.io.File
import java.net.URI
import java.net.URLDecoder
import java.time.format.DateTimeFormatter
import java.time.format.FormatStyle
import java.util.*
@@ -106,6 +108,13 @@ object ChatModel {
var updatingChatsMutex: Mutex = Mutex()
// remote controller
val remoteHosts = mutableStateListOf<RemoteHostInfo>()
val currentRemoteHost = mutableStateOf<RemoteHostInfo?>(null)
val remoteHostId: Long? get() = currentRemoteHost?.value?.remoteHostId
val newRemoteHostPairing = mutableStateOf<Pair<RemoteHostInfo?, RemoteHostSessionState>?>(null)
val remoteCtrlSession = mutableStateOf<RemoteCtrlSession?>(null)
fun getUser(userId: Long): User? = if (currentUser.value?.userId == userId) {
currentUser.value
} else {
@@ -113,7 +122,7 @@ object ChatModel {
}
private fun getUserIndex(user: User): Int =
users.indexOfFirst { it.user.userId == user.userId }
users.indexOfFirst { it.user.userId == user.userId && it.user.remoteHostId == user.remoteHostId }
fun updateUser(user: User) {
val i = getUserIndex(user)
@@ -133,16 +142,17 @@ object ChatModel {
}
// toList() here is to prevent ConcurrentModificationException that is rarely happens but happens
fun hasChat(id: String): Boolean = chats.toList().firstOrNull { it.id == id } != null
fun hasChat(rhId: Long?, id: String): Boolean = chats.toList().firstOrNull { it.id == id && it.remoteHostId == rhId } != null
// TODO pass rhId?
fun getChat(id: String): Chat? = chats.toList().firstOrNull { it.id == id }
fun getContactChat(contactId: Long): Chat? = chats.toList().firstOrNull { it.chatInfo is ChatInfo.Direct && it.chatInfo.apiId == contactId }
fun getGroupChat(groupId: Long): Chat? = chats.toList().firstOrNull { it.chatInfo is ChatInfo.Group && it.chatInfo.apiId == groupId }
fun getGroupMember(groupMemberId: Long): GroupMember? = groupMembers.firstOrNull { it.groupMemberId == groupMemberId }
private fun getChatIndex(id: String): Int = chats.toList().indexOfFirst { it.id == id }
private fun getChatIndex(rhId: Long?, id: String): Int = chats.toList().indexOfFirst { it.id == id && it.remoteHostId == rhId }
fun addChat(chat: Chat) = chats.add(index = 0, chat)
fun updateChatInfo(cInfo: ChatInfo) {
val i = getChatIndex(cInfo.id)
fun updateChatInfo(rhId: Long?, cInfo: ChatInfo) {
val i = getChatIndex(rhId, cInfo.id)
if (i >= 0) {
val currentCInfo = chats[i].chatInfo
var newCInfo = cInfo
@@ -164,23 +174,23 @@ object ChatModel {
}
}
fun updateContactConnection(contactConnection: PendingContactConnection) = updateChat(ChatInfo.ContactConnection(contactConnection))
fun updateContactConnection(rhId: Long?, contactConnection: PendingContactConnection) = updateChat(rhId, ChatInfo.ContactConnection(contactConnection))
fun updateContact(contact: Contact) = updateChat(ChatInfo.Direct(contact), addMissing = contact.directOrUsed)
fun updateContact(rhId: Long?, contact: Contact) = updateChat(rhId, ChatInfo.Direct(contact), addMissing = contact.directOrUsed)
fun updateContactConnectionStats(contact: Contact, connectionStats: ConnectionStats) {
fun updateContactConnectionStats(rhId: Long?, contact: Contact, connectionStats: ConnectionStats) {
val updatedConn = contact.activeConn?.copy(connectionStats = connectionStats)
val updatedContact = contact.copy(activeConn = updatedConn)
updateContact(updatedContact)
updateContact(rhId, updatedContact)
}
fun updateGroup(groupInfo: GroupInfo) = updateChat(ChatInfo.Group(groupInfo))
fun updateGroup(rhId: Long?, groupInfo: GroupInfo) = updateChat(rhId, ChatInfo.Group(groupInfo))
private fun updateChat(cInfo: ChatInfo, addMissing: Boolean = true) {
if (hasChat(cInfo.id)) {
updateChatInfo(cInfo)
private fun updateChat(rhId: Long?, cInfo: ChatInfo, addMissing: Boolean = true) {
if (hasChat(rhId, cInfo.id)) {
updateChatInfo(rhId, cInfo)
} else if (addMissing) {
addChat(Chat(chatInfo = cInfo, chatItems = arrayListOf()))
addChat(Chat(remoteHostId = rhId, chatInfo = cInfo, chatItems = arrayListOf()))
}
}
@@ -195,8 +205,8 @@ object ChatModel {
}
}
fun replaceChat(id: String, chat: Chat) {
val i = getChatIndex(id)
fun replaceChat(rhId: Long?, id: String, chat: Chat) {
val i = getChatIndex(rhId, id)
if (i >= 0) {
chats[i] = chat
} else {
@@ -205,9 +215,9 @@ object ChatModel {
}
}
suspend fun addChatItem(cInfo: ChatInfo, cItem: ChatItem) = updatingChatsMutex.withLock {
suspend fun addChatItem(rhId: Long?, cInfo: ChatInfo, cItem: ChatItem) = updatingChatsMutex.withLock {
// update previews
val i = getChatIndex(cInfo.id)
val i = getChatIndex(rhId, cInfo.id)
val chat: Chat
if (i >= 0) {
chat = chats[i]
@@ -216,7 +226,7 @@ object ChatModel {
chatStats =
if (cItem.meta.itemStatus is CIStatus.RcvNew) {
val minUnreadId = if(chat.chatStats.minUnreadItemId == 0L) cItem.id else chat.chatStats.minUnreadItemId
increaseUnreadCounter(currentUser.value!!)
increaseUnreadCounter(rhId, currentUser.value!!)
chat.chatStats.copy(unreadCount = chat.chatStats.unreadCount + 1, minUnreadItemId = minUnreadId)
}
else
@@ -226,7 +236,7 @@ object ChatModel {
popChat_(i)
}
} else {
addChat(Chat(chatInfo = cInfo, chatItems = arrayListOf(cItem)))
addChat(Chat(remoteHostId = rhId, chatInfo = cInfo, chatItems = arrayListOf(cItem)))
}
Log.d(TAG, "TODOCHAT: addChatItem: adding to chat ${chatId.value} from ${cInfo.id} ${cItem.id}, size ${chatItems.size}")
withContext(Dispatchers.Main) {
@@ -246,9 +256,9 @@ object ChatModel {
}
}
suspend fun upsertChatItem(cInfo: ChatInfo, cItem: ChatItem): Boolean = updatingChatsMutex.withLock {
suspend fun upsertChatItem(rhId: Long?, cInfo: ChatInfo, cItem: ChatItem): Boolean = updatingChatsMutex.withLock {
// update previews
val i = getChatIndex(cInfo.id)
val i = getChatIndex(rhId, cInfo.id)
val chat: Chat
val res: Boolean
if (i >= 0) {
@@ -258,12 +268,12 @@ object ChatModel {
chats[i] = chat.copy(chatItems = arrayListOf(cItem))
if (pItem.isRcvNew && !cItem.isRcvNew) {
// status changed from New to Read, update counter
decreaseCounterInChat(cInfo.id)
decreaseCounterInChat(rhId, cInfo.id)
}
}
res = false
} else {
addChat(Chat(chatInfo = cInfo, chatItems = arrayListOf(cItem)))
addChat(Chat(remoteHostId = rhId, chatInfo = cInfo, chatItems = arrayListOf(cItem)))
res = true
}
Log.d(TAG, "TODOCHAT: upsertChatItem: upserting to chat ${chatId.value} from ${cInfo.id} ${cItem.id}, size ${chatItems.size}")
@@ -305,12 +315,12 @@ object ChatModel {
}
}
fun removeChatItem(cInfo: ChatInfo, cItem: ChatItem) {
fun removeChatItem(rhId: Long?, cInfo: ChatInfo, cItem: ChatItem) {
if (cItem.isRcvNew) {
decreaseCounterInChat(cInfo.id)
decreaseCounterInChat(rhId, cInfo.id)
}
// update previews
val i = getChatIndex(cInfo.id)
val i = getChatIndex(rhId, cInfo.id)
val chat: Chat
if (i >= 0) {
chat = chats[i]
@@ -329,11 +339,11 @@ object ChatModel {
}
}
fun clearChat(cInfo: ChatInfo) {
fun clearChat(rhId: Long?, cInfo: ChatInfo) {
// clear preview
val i = getChatIndex(cInfo.id)
val i = getChatIndex(rhId, cInfo.id)
if (i >= 0) {
decreaseUnreadCounter(currentUser.value!!, chats[i].chatStats.unreadCount)
decreaseUnreadCounter(rhId, currentUser.value!!, chats[i].chatStats.unreadCount)
chats[i] = chats[i].copy(chatItems = arrayListOf(), chatStats = Chat.ChatStats(), chatInfo = cInfo)
}
// clear current chat
@@ -343,15 +353,15 @@ object ChatModel {
}
}
fun updateCurrentUser(newProfile: Profile, preferences: FullChatPreferences? = null) {
fun updateCurrentUser(rhId: Long?, newProfile: Profile, preferences: FullChatPreferences? = null) {
val current = currentUser.value ?: return
val updated = current.copy(
profile = newProfile.toLocalProfile(current.profile.profileId),
fullPreferences = preferences ?: current.fullPreferences
)
val indexInUsers = users.indexOfFirst { it.user.userId == current.userId }
if (indexInUsers != -1) {
users[indexInUsers] = UserInfo(updated, users[indexInUsers].unreadCount)
val i = users.indexOfFirst { it.user.userId == current.userId && it.user.remoteHostId == rhId }
if (i != -1) {
users[i] = users[i].copy(user = updated)
}
currentUser.value = updated
}
@@ -370,16 +380,17 @@ object ChatModel {
}
}
fun markChatItemsRead(cInfo: ChatInfo, range: CC.ItemRange? = null, unreadCountAfter: Int? = null) {
val markedRead = markItemsReadInCurrentChat(cInfo, range)
fun markChatItemsRead(chat: Chat, range: CC.ItemRange? = null, unreadCountAfter: Int? = null) {
val cInfo = chat.chatInfo
val markedRead = markItemsReadInCurrentChat(chat, range)
// update preview
val chatIdx = getChatIndex(cInfo.id)
val chatIdx = getChatIndex(chat.remoteHostId, cInfo.id)
if (chatIdx >= 0) {
val chat = chats[chatIdx]
val lastId = chat.chatItems.lastOrNull()?.id
if (lastId != null) {
val unreadCount = unreadCountAfter ?: if (range != null) chat.chatStats.unreadCount - markedRead else 0
decreaseUnreadCounter(currentUser.value!!, chat.chatStats.unreadCount - unreadCount)
decreaseUnreadCounter(chat.remoteHostId, currentUser.value!!, chat.chatStats.unreadCount - unreadCount)
chats[chatIdx] = chat.copy(
chatStats = chat.chatStats.copy(
unreadCount = unreadCount,
@@ -391,7 +402,8 @@ object ChatModel {
}
}
private fun markItemsReadInCurrentChat(cInfo: ChatInfo, range: CC.ItemRange? = null): Int {
private fun markItemsReadInCurrentChat(chat: Chat, range: CC.ItemRange? = null): Int {
val cInfo = chat.chatInfo
var markedRead = 0
if (chatId.value == cInfo.id) {
var i = 0
@@ -415,13 +427,13 @@ object ChatModel {
return markedRead
}
private fun decreaseCounterInChat(chatId: ChatId) {
val chatIndex = getChatIndex(chatId)
private fun decreaseCounterInChat(rhId: Long?, chatId: ChatId) {
val chatIndex = getChatIndex(rhId, chatId)
if (chatIndex == -1) return
val chat = chats[chatIndex]
val unreadCount = kotlin.math.max(chat.chatStats.unreadCount - 1, 0)
decreaseUnreadCounter(currentUser.value!!, chat.chatStats.unreadCount - unreadCount)
decreaseUnreadCounter(rhId, currentUser.value!!, chat.chatStats.unreadCount - unreadCount)
chats[chatIndex] = chat.copy(
chatStats = chat.chatStats.copy(
unreadCount = unreadCount,
@@ -429,18 +441,18 @@ object ChatModel {
)
}
fun increaseUnreadCounter(user: UserLike) {
changeUnreadCounter(user, 1)
fun increaseUnreadCounter(rhId: Long?, user: UserLike) {
changeUnreadCounter(rhId, user, 1)
}
fun decreaseUnreadCounter(user: UserLike, by: Int = 1) {
changeUnreadCounter(user, -by)
fun decreaseUnreadCounter(rhId: Long?, user: UserLike, by: Int = 1) {
changeUnreadCounter(rhId, user, -by)
}
private fun changeUnreadCounter(user: UserLike, by: Int) {
val i = users.indexOfFirst { it.user.userId == user.userId }
private fun changeUnreadCounter(rhId: Long?, user: UserLike, by: Int) {
val i = users.indexOfFirst { it.user.userId == user.userId && it.user.remoteHostId == rhId }
if (i != -1) {
users[i] = UserInfo(users[i].user, users[i].unreadCount + by)
users[i] = users[i].copy(unreadCount = users[i].unreadCount + by)
}
}
@@ -536,14 +548,14 @@ object ChatModel {
}
}
fun removeChat(id: String) {
chats.removeAll { it.id == id }
fun removeChat(rhId: Long?, id: String) {
chats.removeAll { it.id == id && it.remoteHostId == rhId }
}
fun upsertGroupMember(groupInfo: GroupInfo, member: GroupMember): Boolean {
fun upsertGroupMember(rhId: Long?, groupInfo: GroupInfo, member: GroupMember): Boolean {
// user member was updated
if (groupInfo.membership.groupMemberId == member.groupMemberId) {
updateGroup(groupInfo)
updateGroup(rhId, groupInfo)
return false
}
// update current chat
@@ -561,12 +573,12 @@ object ChatModel {
}
}
fun updateGroupMemberConnectionStats(groupInfo: GroupInfo, member: GroupMember, connectionStats: ConnectionStats) {
fun updateGroupMemberConnectionStats(rhId: Long?, groupInfo: GroupInfo, member: GroupMember, connectionStats: ConnectionStats) {
val memberConn = member.activeConn
if (memberConn != null) {
val updatedConn = memberConn.copy(connectionStats = connectionStats)
val updatedMember = member.copy(activeConn = updatedConn)
upsertGroupMember(groupInfo, updatedMember)
upsertGroupMember(rhId, groupInfo, updatedMember)
}
}
@@ -591,6 +603,8 @@ object ChatModel {
}
terminalItems.add(item)
}
fun connectedToRemote(): Boolean = currentRemoteHost.value != null || remoteCtrlSession.value?.active == true
}
enum class ChatType(val type: String) {
@@ -602,6 +616,7 @@ enum class ChatType(val type: String) {
@Serializable
data class User(
val remoteHostId: Long?,
override val userId: Long,
val userContactId: Long,
val localDisplayName: String,
@@ -624,6 +639,7 @@ data class User(
companion object {
val sampleData = User(
remoteHostId = null,
userId = 1,
userContactId = 1,
localDisplayName = "alice",
@@ -700,10 +716,11 @@ interface SomeChat {
}
@Serializable @Stable
data class Chat (
data class Chat(
val remoteHostId: Long?,
val chatInfo: ChatInfo,
val chatItems: List<ChatItem>,
val chatStats: ChatStats = ChatStats(),
val chatStats: ChatStats = ChatStats()
) {
val userCanSend: Boolean
get() = when (chatInfo) {
@@ -733,6 +750,7 @@ data class Chat (
companion object {
val sampleData = Chat(
remoteHostId = null,
chatInfo = ChatInfo.Direct.sampleData,
chatItems = arrayListOf(ChatItem.getSampleData())
)
@@ -2219,7 +2237,7 @@ enum class MREmojiChar(val value: String) {
}
@Serializable
class CIFile(
data class CIFile(
val fileId: Long,
val fileName: String,
val fileSize: Long,
@@ -2263,6 +2281,39 @@ class CIFile(
is CIFileStatus.Invalid -> null
}
/**
* DO NOT CALL this function in compose scope, [LaunchedEffect], [DisposableEffect] and so on. Only with [withBGApi] or [runBlocking].
* Otherwise, it will be canceled when moving to another screen/item/view, etc
* */
suspend fun loadRemoteFile(allowToShowAlert: Boolean): Boolean {
val rh = chatModel.currentRemoteHost.value
val user = chatModel.currentUser.value
if (rh == null || user == null || fileSource == null || !loaded) return false
if (getLoadedFilePath(this) != null) return true
if (cachedRemoteFileRequests.contains(fileSource)) return false
val rf = RemoteFile(
userId = user.userId,
fileId = fileId,
sent = fileStatus.sent,
fileSource = fileSource
)
cachedRemoteFileRequests.add(fileSource)
val showAlert = fileSize > 5_000_000 && allowToShowAlert
if (showAlert) {
AlertManager.shared.showAlertMsgWithProgress(
title = generalGetString(MR.strings.loading_remote_file_title),
text = generalGetString(MR.strings.loading_remote_file_desc)
)
}
val res = chatModel.controller.getRemoteFile(rh.remoteHostId, rf)
cachedRemoteFileRequests.remove(fileSource)
if (showAlert) {
AlertManager.shared.hideAlert()
}
return res
}
companion object {
fun getSample(
fileId: Long = 1,
@@ -2272,6 +2323,8 @@ class CIFile(
fileStatus: CIFileStatus = CIFileStatus.RcvComplete
): CIFile =
CIFile(fileId = fileId, fileName = fileName, fileSize = fileSize, fileSource = if (filePath == null) null else CryptoFile.plain(filePath), fileStatus = fileStatus, fileProtocol = FileProtocol.XFTP)
val cachedRemoteFileRequests = SnapshotStateList<CryptoFile>()
}
}
@@ -2303,6 +2356,8 @@ data class CryptoFile(
companion object {
fun plain(f: String): CryptoFile = CryptoFile(f, null)
fun desktopPlain(f: URI): CryptoFile = CryptoFile(URLDecoder.decode(f.rawPath, "UTF-8"), null)
}
}
@@ -2365,6 +2420,21 @@ sealed class CIFileStatus {
@Serializable @SerialName("rcvCancelled") object RcvCancelled: CIFileStatus()
@Serializable @SerialName("rcvError") object RcvError: CIFileStatus()
@Serializable @SerialName("invalid") class Invalid(val text: String): CIFileStatus()
val sent: Boolean get() = when (this) {
is SndStored -> true
is SndTransfer -> true
is SndComplete -> true
is SndCancelled -> true
is SndError -> true
is RcvInvitation -> false
is RcvAccepted -> false
is RcvTransfer -> false
is RcvComplete -> false
is RcvCancelled -> false
is RcvError -> false
is Invalid -> false
}
}
@Suppress("SERIALIZER_TYPE_INCOMPATIBLE")
@@ -2843,3 +2913,34 @@ enum class NotificationPreviewMode {
val default: NotificationPreviewMode = MESSAGE
}
}
data class RemoteCtrlSession(
val ctrlAppInfo: CtrlAppInfo,
val appVersion: String,
val sessionState: UIRemoteCtrlSessionState
) {
val active: Boolean
get () = sessionState is UIRemoteCtrlSessionState.Connected
val sessionCode: String?
get() = when (val s = sessionState) {
is UIRemoteCtrlSessionState.PendingConfirmation -> s.sessionCode
is UIRemoteCtrlSessionState.Connected -> s.sessionCode
else -> null
}
}
@Serializable
sealed class RemoteCtrlSessionState {
@Serializable @SerialName("starting") object Starting: RemoteCtrlSessionState()
@Serializable @SerialName("connecting") object Connecting: RemoteCtrlSessionState()
@Serializable @SerialName("pendingConfirmation") data class PendingConfirmation(val sessionCode: String): RemoteCtrlSessionState()
@Serializable @SerialName("connected") data class Connected(val sessionCode: String): RemoteCtrlSessionState()
}
sealed class UIRemoteCtrlSessionState {
@Serializable @SerialName("starting") object Starting: UIRemoteCtrlSessionState()
@Serializable @SerialName("connecting") data class Connecting(val remoteCtrl_: RemoteCtrlInfo? = null): UIRemoteCtrlSessionState()
@Serializable @SerialName("pendingConfirmation") data class PendingConfirmation(val remoteCtrl_: RemoteCtrlInfo? = null, val sessionCode: String): UIRemoteCtrlSessionState()
@Serializable @SerialName("connected") data class Connected(val remoteCtrl: RemoteCtrlInfo, val sessionCode: String): UIRemoteCtrlSessionState()
}
@@ -18,6 +18,8 @@ enum class AppPlatform {
expect val appPlatform: AppPlatform
expect val deviceName: String
val appVersionInfo: Pair<String, Int?> = if (appPlatform == AppPlatform.ANDROID)
BuildConfigCommon.ANDROID_VERSION_NAME to BuildConfigCommon.ANDROID_VERSION_CODE
else
@@ -15,6 +15,7 @@ external fun pipeStdOutToSocket(socketName: String) : Int
typealias ChatCtrl = Long
external fun chatMigrateInit(dbPath: String, dbKey: String, confirm: String): Array<Any>
external fun chatSendCmd(ctrl: ChatCtrl, msg: String): String
external fun chatSendRemoteCmd(ctrl: ChatCtrl, rhId: Int, msg: String): String
external fun chatRecvMsg(ctrl: ChatCtrl): String
external fun chatRecvMsgWait(ctrl: ChatCtrl, timeout: Int): String
external fun chatParseMarkdown(str: String): String
@@ -52,7 +53,7 @@ suspend fun initChatController(useKey: String? = null, confirmMigrations: Migrat
} else if (startChat) {
// If we migrated successfully means previous re-encryption process on database level finished successfully too
if (appPreferences.encryptionStartedAt.get() != null) appPreferences.encryptionStartedAt.set(null)
val user = chatController.apiGetActiveUser()
val user = chatController.apiGetActiveUser(null)
if (user == null) {
chatModel.controller.appPrefs.onboardingStage.set(OnboardingStage.Step1_SimpleXInfo)
chatModel.controller.appPrefs.privacyDeliveryReceiptsSet.set(true)
@@ -24,6 +24,8 @@ expect val agentDatabaseFileName: String
* */
expect val databaseExportDir: File
expect val remoteHostsDir: File
expect fun desktopOpenDatabaseDir()
fun copyFileToFile(from: File, to: URI, finally: () -> Unit) {
@@ -59,14 +61,20 @@ fun copyBytesToFile(bytes: ByteArrayInputStream, to: URI, finally: () -> Unit) {
}
fun getAppFilePath(fileName: String): String {
return appFilesDir.absolutePath + File.separator + fileName
val rh = chatModel.currentRemoteHost.value
val s = File.separator
return if (rh == null) {
appFilesDir.absolutePath + s + fileName
} else {
remoteHostsDir.absolutePath + s + rh.storePath + s + "simplex_v1_files" + s + fileName
}
}
fun getLoadedFilePath(file: CIFile?): String? {
val f = file?.fileSource?.filePath
return if (f != null && file.loaded) {
val filePath = getAppFilePath(f)
if (File(filePath).exists()) filePath else null
if (fileReady(file, filePath)) filePath else null
} else {
null
}
@@ -76,12 +84,17 @@ fun getLoadedFileSource(file: CIFile?): CryptoFile? {
val f = file?.fileSource?.filePath
return if (f != null && file.loaded) {
val filePath = getAppFilePath(f)
if (File(filePath).exists()) file.fileSource else null
if (fileReady(file, filePath)) file.fileSource else null
} else {
null
}
}
private fun fileReady(file: CIFile, filePath: String) =
File(filePath).exists() &&
!CIFile.cachedRemoteFileRequests.contains(file.fileSource)
&& File(filePath).length() >= file.fileSize
/**
* [rememberedValue] is used in `remember(rememberedValue)`. So when the value changes, file saver will update a callback function
* */
@@ -49,7 +49,8 @@ abstract class NtfManager {
null
}
val apiId = chatId.replace("<@", "").toLongOrNull() ?: return
acceptContactRequest(incognito, apiId, cInfo, isCurrentUser, ChatModel)
// TODO include remote host in notification
acceptContactRequest(null, incognito, apiId, cInfo, isCurrentUser, ChatModel)
cancelNotificationsForChat(chatId)
}
@@ -57,11 +58,12 @@ abstract class NtfManager {
withBGApi {
awaitChatStartedIfNeeded(chatModel)
if (userId != null && userId != chatModel.currentUser.value?.userId && chatModel.currentUser.value != null) {
chatModel.controller.changeActiveUser(userId, null)
// TODO include remote host ID in desktop notifications?
chatModel.controller.changeActiveUser(null, userId, null)
}
val cInfo = chatModel.getChat(chatId)?.chatInfo
chatModel.clearOverlays.value = true
if (cInfo != null && (cInfo is ChatInfo.Direct || cInfo is ChatInfo.Group)) openChat(cInfo, chatModel)
if (cInfo != null && (cInfo is ChatInfo.Direct || cInfo is ChatInfo.Group)) openChat(null, cInfo, chatModel)
}
}
@@ -69,7 +71,8 @@ abstract class NtfManager {
withBGApi {
awaitChatStartedIfNeeded(chatModel)
if (userId != null && userId != chatModel.currentUser.value?.userId && chatModel.currentUser.value != null) {
chatModel.controller.changeActiveUser(userId, null)
// TODO include remote host ID in desktop notifications?
chatModel.controller.changeActiveUser(null, userId, null)
}
chatModel.chatId.value = null
chatModel.clearOverlays.value = true
@@ -47,13 +47,14 @@ private fun sendCommand(chatModel: ChatModel, composeState: MutableState<Compose
val s = composeState.value.message
if (s.startsWith("/sql") && (!prefPerformLA || !developerTools)) {
val resp = CR.ChatCmdError(null, ChatError.ChatErrorChat(ChatErrorType.CommandError("Failed reading: empty")))
chatModel.addTerminalItem(TerminalItem.cmd(CC.Console(s)))
chatModel.addTerminalItem(TerminalItem.resp(resp))
chatModel.addTerminalItem(TerminalItem.cmd(null, CC.Console(s)))
chatModel.addTerminalItem(TerminalItem.resp(null, resp))
composeState.value = ComposeState(useLinkPreviews = false)
} else {
withApi {
// show "in progress"
chatModel.controller.sendCmd(CC.Console(s))
// TODO show active remote host in chat console?
chatModel.controller.sendCmd(chatModel.remoteHostId, CC.Console(s))
composeState.value = ComposeState(useLinkPreviews = false)
// hide "in progress"
}
@@ -139,8 +140,10 @@ fun TerminalLog(terminalItems: List<TerminalItem>) {
val clipboard = LocalClipboardManager.current
LazyColumn(state = listState, reverseLayout = true) {
items(reversedTerminalItems) { item ->
val rhId = item.remoteHostId
val rhIdStr = if (rhId == null) "" else "$rhId "
Text(
"${item.date.toString().subSequence(11, 19)} ${item.label}",
"$rhIdStr${item.date.toString().subSequence(11, 19)} ${item.label}",
style = TextStyle(fontFamily = FontFamily.Monospace, fontSize = 18.sp, color = MaterialTheme.colors.primary),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
@@ -170,18 +170,19 @@ fun CreateFirstProfile(chatModel: ChatModel, close: () -> Unit) {
fun createProfileInProfiles(chatModel: ChatModel, displayName: String, close: () -> Unit) {
withApi {
val rhId = chatModel.remoteHostId
val user = chatModel.controller.apiCreateActiveUser(
Profile(displayName.trim(), "", null)
rhId, Profile(displayName.trim(), "", null)
) ?: return@withApi
chatModel.currentUser.value = user
if (chatModel.users.isEmpty()) {
chatModel.controller.startChat(user)
chatModel.controller.appPrefs.onboardingStage.set(OnboardingStage.Step3_CreateSimpleXAddress)
} else {
val users = chatModel.controller.listUsers()
val users = chatModel.controller.listUsers(rhId)
chatModel.users.clear()
chatModel.users.addAll(users)
chatModel.controller.getUserChatData()
chatModel.controller.getUserChatData(rhId)
close()
}
}
@@ -190,7 +191,7 @@ fun createProfileInProfiles(chatModel: ChatModel, displayName: String, close: ()
fun createProfileOnboarding(chatModel: ChatModel, displayName: String, close: () -> Unit) {
withApi {
chatModel.controller.apiCreateActiveUser(
Profile(displayName.trim(), "", null)
null, Profile(displayName.trim(), "", null)
) ?: return@withApi
val onboardingStage = chatModel.controller.appPrefs.onboardingStage
if (chatModel.users.isEmpty()) {
@@ -43,6 +43,7 @@ class CallManager(val chatModel: ChatModel) {
private fun justAcceptIncomingCall(invitation: RcvCallInvitation) {
with (chatModel) {
activeCall.value = Call(
remoteHostId = invitation.remoteHostId,
contact = invitation.contact,
callState = CallState.InvitationAccepted,
localMedia = invitation.callType.media,
@@ -76,7 +77,7 @@ class CallManager(val chatModel: ChatModel) {
Log.d(TAG, "CallManager.endCall: ending call...")
callCommand.add(WCallCommand.End)
showCallView.value = false
controller.apiEndCall(call.contact)
controller.apiEndCall(call.remoteHostId, call.contact)
activeCall.value = null
}
}
@@ -90,7 +91,7 @@ class CallManager(val chatModel: ChatModel) {
ntfManager.cancelCallNotification()
}
withApi {
if (!controller.apiRejectCall(invitation.contact)) {
if (!controller.apiRejectCall(invitation.remoteHostId, invitation.contact)) {
Log.e(TAG, "apiRejectCall error")
}
}
@@ -106,6 +106,7 @@ fun PreviewIncomingCallAlertLayout() {
SimpleXTheme {
IncomingCallAlertLayout(
invitation = RcvCallInvitation(
remoteHostId = null,
user = User.sampleData,
contact = Contact.sampleData,
callType = CallType(media = CallMediaType.Audio, capabilities = CallCapabilities(encryption = false)),
@@ -11,6 +11,7 @@ import java.util.*
import kotlin.collections.ArrayList
data class Call(
val remoteHostId: Long?,
val contact: Contact,
val callState: CallState,
val localMedia: CallMediaType,
@@ -95,7 +96,14 @@ sealed class WCallResponse {
@Serializable data class WebRTCSession(val rtcSession: String, val rtcIceCandidates: String)
@Serializable data class WebRTCExtraInfo(val rtcIceCandidates: String)
@Serializable data class CallType(val media: CallMediaType, val capabilities: CallCapabilities)
@Serializable data class RcvCallInvitation(val user: User, val contact: Contact, val callType: CallType, val sharedKey: String? = null, val callTs: Instant) {
@Serializable data class RcvCallInvitation(
val remoteHostId: Long?,
val user: User,
val contact: Contact,
val callType: CallType,
val sharedKey: String? = null,
val callTs: Instant
) {
val callTypeText: String get() = generalGetString(when(callType.media) {
CallMediaType.Video -> if (sharedKey == null) MR.strings.video_call_no_encryption else MR.strings.encrypted_video_call
CallMediaType.Audio -> if (sharedKey == null) MR.strings.audio_call_no_encryption else MR.strings.encrypted_audio_call
@@ -61,6 +61,7 @@ fun ChatInfoView(
val contactNetworkStatus = remember(chatModel.networkStatuses.toMap(), contact) {
mutableStateOf(chatModel.contactNetworkStatus(contact))
}
val chatRh = chat.remoteHostId
val sendReceipts = remember(contact.id) { mutableStateOf(SendReceipts.fromBool(contact.chatSettings.sendRcpts, currentUser.sendRcptsContacts)) }
ChatInfoLayout(
chat,
@@ -81,25 +82,25 @@ fun ChatInfoView(
connectionCode,
developerTools,
onLocalAliasChanged = {
setContactAlias(chat.chatInfo.apiId, it, chatModel)
setContactAlias(chat, it, chatModel)
},
openPreferences = {
ModalManager.end.showCustomModal { close ->
val user = chatModel.currentUser.value
if (user != null) {
ContactPreferencesView(chatModel, user, contact.contactId, close)
ContactPreferencesView(chatModel, user, chatRh, contact.contactId, close)
}
}
},
deleteContact = { deleteContactDialog(chat.chatInfo, chatModel, close) },
clearChat = { clearChatDialog(chat.chatInfo, chatModel, close) },
deleteContact = { deleteContactDialog(chat, chatModel, close) },
clearChat = { clearChatDialog(chat, chatModel, close) },
switchContactAddress = {
showSwitchAddressAlert(switchAddress = {
withApi {
val cStats = chatModel.controller.apiSwitchContact(contact.contactId)
val cStats = chatModel.controller.apiSwitchContact(chatRh, contact.contactId)
connStats.value = cStats
if (cStats != null) {
chatModel.updateContactConnectionStats(contact, cStats)
chatModel.updateContactConnectionStats(chatRh, contact, cStats)
}
close.invoke()
}
@@ -108,20 +109,20 @@ fun ChatInfoView(
abortSwitchContactAddress = {
showAbortSwitchAddressAlert(abortSwitchAddress = {
withApi {
val cStats = chatModel.controller.apiAbortSwitchContact(contact.contactId)
val cStats = chatModel.controller.apiAbortSwitchContact(chatRh, contact.contactId)
connStats.value = cStats
if (cStats != null) {
chatModel.updateContactConnectionStats(contact, cStats)
chatModel.updateContactConnectionStats(chatRh, contact, cStats)
}
}
})
},
syncContactConnection = {
withApi {
val cStats = chatModel.controller.apiSyncContactRatchet(contact.contactId, force = false)
val cStats = chatModel.controller.apiSyncContactRatchet(chatRh, contact.contactId, force = false)
connStats.value = cStats
if (cStats != null) {
chatModel.updateContactConnectionStats(contact, cStats)
chatModel.updateContactConnectionStats(chatRh, contact, cStats)
}
close.invoke()
}
@@ -129,10 +130,10 @@ fun ChatInfoView(
syncContactConnectionForce = {
showSyncConnectionForceAlert(syncConnectionForce = {
withApi {
val cStats = chatModel.controller.apiSyncContactRatchet(contact.contactId, force = true)
val cStats = chatModel.controller.apiSyncContactRatchet(chatRh, contact.contactId, force = true)
connStats.value = cStats
if (cStats != null) {
chatModel.updateContactConnectionStats(contact, cStats)
chatModel.updateContactConnectionStats(chatRh, contact, cStats)
}
close.invoke()
}
@@ -146,9 +147,10 @@ fun ChatInfoView(
connectionCode,
ct.verified,
verify = { code ->
chatModel.controller.apiVerifyContact(ct.contactId, code)?.let { r ->
chatModel.controller.apiVerifyContact(chatRh, ct.contactId, code)?.let { r ->
val (verified, existingCode) = r
chatModel.updateContact(
chatRh,
ct.copy(
activeConn = ct.activeConn?.copy(
connectionCode = if (verified) SecurityCode(existingCode, Clock.System.now()) else null
@@ -195,7 +197,8 @@ sealed class SendReceipts {
}
}
fun deleteContactDialog(chatInfo: ChatInfo, chatModel: ChatModel, close: (() -> Unit)? = null) {
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)),
@@ -206,7 +209,7 @@ fun deleteContactDialog(chatInfo: ChatInfo, chatModel: ChatModel, close: (() ->
SectionItemView({
AlertManager.shared.hideAlert()
withApi {
deleteContact(chatInfo, chatModel, close, notify = true)
deleteContact(chat, chatModel, close, notify = true)
}
}) {
Text(generalGetString(MR.strings.delete_and_notify_contact), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.error)
@@ -215,7 +218,7 @@ fun deleteContactDialog(chatInfo: ChatInfo, chatModel: ChatModel, close: (() ->
SectionItemView({
AlertManager.shared.hideAlert()
withApi {
deleteContact(chatInfo, chatModel, close, notify = false)
deleteContact(chat, chatModel, close, notify = false)
}
}) {
Text(generalGetString(MR.strings.delete_verb), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.error)
@@ -225,7 +228,7 @@ fun deleteContactDialog(chatInfo: ChatInfo, chatModel: ChatModel, close: (() ->
SectionItemView({
AlertManager.shared.hideAlert()
withApi {
deleteContact(chatInfo, chatModel, close)
deleteContact(chat, chatModel, close)
}
}) {
Text(generalGetString(MR.strings.delete_verb), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.error)
@@ -242,11 +245,13 @@ fun deleteContactDialog(chatInfo: ChatInfo, chatModel: ChatModel, close: (() ->
)
}
fun deleteContact(chatInfo: ChatInfo, chatModel: ChatModel, close: (() -> Unit)?, notify: Boolean? = null) {
fun deleteContact(chat: Chat, chatModel: ChatModel, close: (() -> Unit)?, notify: Boolean? = null) {
val chatInfo = chat.chatInfo
withApi {
val r = chatModel.controller.apiDeleteChat(chatInfo.chatType, chatInfo.apiId, notify)
val chatRh = chat.remoteHostId
val r = chatModel.controller.apiDeleteChat(chatRh, chatInfo.chatType, chatInfo.apiId, notify)
if (r) {
chatModel.removeChat(chatInfo.id)
chatModel.removeChat(chatRh, chatInfo.id)
if (chatModel.chatId.value == chatInfo.id) {
chatModel.chatId.value = null
ModalManager.end.closeModals()
@@ -257,16 +262,18 @@ fun deleteContact(chatInfo: ChatInfo, chatModel: ChatModel, close: (() -> Unit)?
}
}
fun clearChatDialog(chatInfo: ChatInfo, chatModel: ChatModel, close: (() -> Unit)? = null) {
fun clearChatDialog(chat: Chat, chatModel: ChatModel, close: (() -> Unit)? = null) {
val chatInfo = chat.chatInfo
AlertManager.shared.showAlertDialog(
title = generalGetString(MR.strings.clear_chat_question),
text = generalGetString(MR.strings.clear_chat_warning),
confirmText = generalGetString(MR.strings.clear_verb),
onConfirm = {
withApi {
val updatedChatInfo = chatModel.controller.apiClearChat(chatInfo.chatType, chatInfo.apiId)
val chatRh = chat.remoteHostId
val updatedChatInfo = chatModel.controller.apiClearChat(chatRh, chatInfo.chatType, chatInfo.apiId)
if (updatedChatInfo != null) {
chatModel.clearChat(updatedChatInfo)
chatModel.clearChat(chatRh, updatedChatInfo)
ntfManager.cancelNotificationsForChat(chatInfo.id)
close?.invoke()
}
@@ -669,9 +676,10 @@ fun ShareAddressButton(onClick: () -> Unit) {
)
}
private fun setContactAlias(contactApiId: Long, localAlias: String, chatModel: ChatModel) = withApi {
chatModel.controller.apiSetContactAlias(contactApiId, localAlias)?.let {
chatModel.updateContact(it)
private fun setContactAlias(chat: Chat, localAlias: String, chatModel: ChatModel) = withApi {
val chatRh = chat.remoteHostId
chatModel.controller.apiSetContactAlias(chatRh, chat.chatInfo.apiId, localAlias)?.let {
chatModel.updateContact(chatRh, it)
}
}
@@ -710,6 +718,7 @@ fun PreviewChatInfoLayout() {
SimpleXTheme {
ChatInfoLayout(
chat = Chat(
remoteHostId = null,
chatInfo = ChatInfo.Direct.sampleData,
chatItems = arrayListOf()
),
@@ -100,11 +100,12 @@ fun ChatView(chatId: String, chatModel: ChatModel, onComposed: suspend (chatId:
}
}
val view = LocalMultiplatformView()
if (activeChat.value == null || user == null) {
val chat = activeChat.value
if (chat == null || user == null) {
chatModel.chatId.value = null
ModalManager.end.closeModals()
} else {
val chat = activeChat.value!!
val chatRh = chat.remoteHostId
// We need to have real unreadCount value for displaying it inside top right button
// Having activeChat reloaded on every change in it is inefficient (UI lags)
val unreadCount = remember {
@@ -166,11 +167,11 @@ fun ChatView(chatId: String, chatModel: ChatModel, onComposed: suspend (chatId:
var preloadedCode: String? = null
var preloadedLink: Pair<String, GroupMemberRole>? = null
if (chat.chatInfo is ChatInfo.Direct) {
preloadedContactInfo = chatModel.controller.apiContactInfo(chat.chatInfo.apiId)
preloadedCode = chatModel.controller.apiGetContactCode(chat.chatInfo.apiId)?.second
preloadedContactInfo = chatModel.controller.apiContactInfo(chatRh, chat.chatInfo.apiId)
preloadedCode = chatModel.controller.apiGetContactCode(chatRh, chat.chatInfo.apiId)?.second
} else if (chat.chatInfo is ChatInfo.Group) {
setGroupMembers(chat.chatInfo.groupInfo, chatModel)
preloadedLink = chatModel.controller.apiGetGroupLink(chat.chatInfo.groupInfo.groupId)
setGroupMembers(chatRh, chat.chatInfo.groupInfo, chatModel)
preloadedLink = chatModel.controller.apiGetGroupLink(chatRh, chat.chatInfo.groupInfo.groupId)
}
ModalManager.end.showModalCloseable(true) { close ->
val chat = remember { activeChat }.value
@@ -178,20 +179,20 @@ fun ChatView(chatId: String, chatModel: ChatModel, onComposed: suspend (chatId:
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(chat.chatInfo.apiId)
contactInfo = chatModel.controller.apiContactInfo(chatRh, chat.chatInfo.apiId)
preloadedContactInfo = contactInfo
code = chatModel.controller.apiGetContactCode(chat.chatInfo.apiId)?.second
code = chatModel.controller.apiGetContactCode(chatRh, chat.chatInfo.apiId)?.second
preloadedCode = code
}
ChatInfoView(chatModel, (chat.chatInfo as ChatInfo.Direct).contact, contactInfo?.first, contactInfo?.second, chat.chatInfo.localAlias, code, close)
} else if (chat?.chatInfo is ChatInfo.Group) {
var link: Pair<String, GroupMemberRole>? by remember(chat.id) { mutableStateOf(preloadedLink) }
KeyChangeEffect(chat.id) {
setGroupMembers((chat.chatInfo as ChatInfo.Group).groupInfo, chatModel)
link = chatModel.controller.apiGetGroupLink(chat.chatInfo.groupInfo.groupId)
setGroupMembers(chatRh, (chat.chatInfo as ChatInfo.Group).groupInfo, chatModel)
link = chatModel.controller.apiGetGroupLink(chatRh, chat.chatInfo.groupInfo.groupId)
preloadedLink = link
}
GroupChatInfoView(chatModel, link?.first, link?.second, {
GroupChatInfoView(chatModel, chatRh, chat.id, link?.first, link?.second, {
link = it
preloadedLink = it
}, close)
@@ -202,19 +203,19 @@ fun ChatView(chatId: String, chatModel: ChatModel, onComposed: suspend (chatId:
showMemberInfo = { groupInfo: GroupInfo, member: GroupMember ->
hideKeyboard(view)
withApi {
val r = chatModel.controller.apiGroupMemberInfo(groupInfo.groupId, member.groupMemberId)
val r = chatModel.controller.apiGroupMemberInfo(chatRh, groupInfo.groupId, member.groupMemberId)
val stats = r?.second
val (_, code) = if (member.memberActive) {
val memCode = chatModel.controller.apiGetGroupMemberCode(groupInfo.apiId, member.groupMemberId)
val memCode = chatModel.controller.apiGetGroupMemberCode(chatRh, groupInfo.apiId, member.groupMemberId)
member to memCode?.second
} else {
member to null
}
setGroupMembers(groupInfo, chatModel)
setGroupMembers(chatRh, groupInfo, chatModel)
ModalManager.end.closeModals()
ModalManager.end.showModalCloseable(true) { close ->
remember { derivedStateOf { chatModel.getGroupMember(member.groupMemberId) } }.value?.let { mem ->
GroupMemberInfoView(groupInfo, mem, stats, code, chatModel, close, close)
GroupMemberInfoView(chatRh, groupInfo, mem, stats, code, chatModel, close, close)
}
}
}
@@ -225,7 +226,7 @@ fun ChatView(chatId: String, chatModel: ChatModel, onComposed: suspend (chatId:
if (c != null && firstId != null) {
withApi {
Log.d(TAG, "TODOCHAT: loadPrevMessages: loading for ${c.id}, current chatId ${ChatModel.chatId.value}, size was ${ChatModel.chatItems.size}")
apiLoadPrevMessages(c.chatInfo, chatModel, firstId, searchText.value)
apiLoadPrevMessages(c, chatModel, firstId, searchText.value)
Log.d(TAG, "TODOCHAT: loadPrevMessages: loaded for ${c.id}, current chatId ${ChatModel.chatId.value}, size now ${ChatModel.chatItems.size}")
}
}
@@ -241,6 +242,7 @@ fun ChatView(chatId: String, chatModel: ChatModel, onComposed: suspend (chatId:
val toChatItem: ChatItem?
if (mode == CIDeleteMode.cidmBroadcast && groupInfo != null && groupMember != null) {
val r = chatModel.controller.apiDeleteMemberChatItem(
chatRh,
groupId = groupInfo.groupId,
groupMemberId = groupMember.groupMemberId,
itemId = itemId
@@ -249,6 +251,7 @@ fun ChatView(chatId: String, chatModel: ChatModel, onComposed: suspend (chatId:
toChatItem = r?.second
} else {
val r = chatModel.controller.apiDeleteChatItem(
chatRh,
type = cInfo.chatType,
id = cInfo.apiId,
itemId = itemId,
@@ -258,9 +261,9 @@ fun ChatView(chatId: String, chatModel: ChatModel, onComposed: suspend (chatId:
toChatItem = r?.toChatItem?.chatItem
}
if (toChatItem == null && deletedChatItem != null) {
chatModel.removeChatItem(cInfo, deletedChatItem)
chatModel.removeChatItem(chatRh, cInfo, deletedChatItem)
} else if (toChatItem != null) {
chatModel.upsertChatItem(cInfo, toChatItem)
chatModel.upsertChatItem(chatRh, cInfo, toChatItem)
}
}
},
@@ -271,27 +274,27 @@ fun ChatView(chatId: String, chatModel: ChatModel, onComposed: suspend (chatId:
val deletedItems: ArrayList<ChatItem> = arrayListOf()
for (itemId in itemIds) {
val di = chatModel.controller.apiDeleteChatItem(
chatInfo.chatType, chatInfo.apiId, itemId, CIDeleteMode.cidmInternal
chatRh, chatInfo.chatType, chatInfo.apiId, itemId, CIDeleteMode.cidmInternal
)?.deletedChatItem?.chatItem
if (di != null) {
deletedItems.add(di)
}
}
for (di in deletedItems) {
chatModel.removeChatItem(chatInfo, di)
chatModel.removeChatItem(chatRh, chatInfo, di)
}
}
}
},
receiveFile = { fileId, encrypted ->
withApi { chatModel.controller.receiveFile(user, fileId, encrypted) }
withApi { chatModel.controller.receiveFile(chatRh, user, fileId, encrypted) }
},
cancelFile = { fileId ->
withApi { chatModel.controller.cancelFile(user, fileId) }
withApi { chatModel.controller.cancelFile(chatRh, user, fileId) }
},
joinGroup = { groupId, onComplete ->
withApi {
chatModel.controller.apiJoinGroup(groupId)
chatModel.controller.apiJoinGroup(chatRh, groupId)
onComplete.invoke()
}
},
@@ -299,7 +302,7 @@ fun ChatView(chatId: String, chatModel: ChatModel, onComposed: suspend (chatId:
withBGApi {
val cInfo = chat.chatInfo
if (cInfo is ChatInfo.Direct) {
chatModel.activeCall.value = Call(contact = cInfo.contact, callState = CallState.WaitCapabilities, localMedia = media)
chatModel.activeCall.value = Call(remoteHostId = chatRh, contact = cInfo.contact, callState = CallState.WaitCapabilities, localMedia = media)
chatModel.showCallView.value = true
chatModel.callCommand.add(WCallCommand.Capabilities(media))
}
@@ -320,48 +323,48 @@ fun ChatView(chatId: String, chatModel: ChatModel, onComposed: suspend (chatId:
},
acceptFeature = { contact, feature, param ->
withApi {
chatModel.controller.allowFeatureToContact(contact, feature, param)
chatModel.controller.allowFeatureToContact(chatRh, contact, feature, param)
}
},
openDirectChat = { contactId ->
withApi {
openDirectChat(contactId, chatModel)
openDirectChat(chatRh, contactId, chatModel)
}
},
updateContactStats = { contact ->
withApi {
val r = chatModel.controller.apiContactInfo(chat.chatInfo.apiId)
val r = chatModel.controller.apiContactInfo(chatRh, chat.chatInfo.apiId)
if (r != null) {
val contactStats = r.first
if (contactStats != null)
chatModel.updateContactConnectionStats(contact, contactStats)
chatModel.updateContactConnectionStats(chatRh, contact, contactStats)
}
}
},
updateMemberStats = { groupInfo, member ->
withApi {
val r = chatModel.controller.apiGroupMemberInfo(groupInfo.groupId, member.groupMemberId)
val r = chatModel.controller.apiGroupMemberInfo(chatRh, groupInfo.groupId, member.groupMemberId)
if (r != null) {
val memStats = r.second
if (memStats != null) {
chatModel.updateGroupMemberConnectionStats(groupInfo, r.first, memStats)
chatModel.updateGroupMemberConnectionStats(chatRh, groupInfo, r.first, memStats)
}
}
}
},
syncContactConnection = { contact ->
withApi {
val cStats = chatModel.controller.apiSyncContactRatchet(contact.contactId, force = false)
val cStats = chatModel.controller.apiSyncContactRatchet(chatRh, contact.contactId, force = false)
if (cStats != null) {
chatModel.updateContactConnectionStats(contact, cStats)
chatModel.updateContactConnectionStats(chatRh, contact, cStats)
}
}
},
syncMemberConnection = { groupInfo, member ->
withApi {
val r = chatModel.controller.apiSyncGroupMemberRatchet(groupInfo.apiId, member.groupMemberId, force = false)
val r = chatModel.controller.apiSyncGroupMemberRatchet(chatRh, groupInfo.apiId, member.groupMemberId, force = false)
if (r != null) {
chatModel.updateGroupMemberConnectionStats(groupInfo, r.first, r.second)
chatModel.updateGroupMemberConnectionStats(chatRh, groupInfo, r.first, r.second)
}
}
},
@@ -374,6 +377,7 @@ fun ChatView(chatId: String, chatModel: ChatModel, onComposed: suspend (chatId:
setReaction = { cInfo, cItem, add, reaction ->
withApi {
val updatedCI = chatModel.controller.apiChatItemReaction(
rh = chatRh,
type = cInfo.chatType,
id = cInfo.apiId,
itemId = cItem.id,
@@ -387,10 +391,10 @@ fun ChatView(chatId: String, chatModel: ChatModel, onComposed: suspend (chatId:
},
showItemDetails = { cInfo, cItem ->
withApi {
val ciInfo = chatModel.controller.apiGetChatItemInfo(cInfo.chatType, cInfo.apiId, cItem.id)
val ciInfo = chatModel.controller.apiGetChatItemInfo(chatRh, cInfo.chatType, cInfo.apiId, cItem.id)
if (ciInfo != null) {
if (chat.chatInfo is ChatInfo.Group) {
setGroupMembers(chat.chatInfo.groupInfo, chatModel)
setGroupMembers(chatRh, chat.chatInfo.groupInfo, chatModel)
}
ModalManager.end.closeModals()
ModalManager.end.showModal(endButtons = { ShareButton {
@@ -404,28 +408,29 @@ fun ChatView(chatId: String, chatModel: ChatModel, onComposed: suspend (chatId:
addMembers = { groupInfo ->
hideKeyboard(view)
withApi {
setGroupMembers(groupInfo, chatModel)
setGroupMembers(chatRh, groupInfo, chatModel)
ModalManager.end.closeModals()
ModalManager.end.showModalCloseable(true) { close ->
AddGroupMembersView(groupInfo, false, chatModel, close)
AddGroupMembersView(chatRh, groupInfo, false, chatModel, close)
}
}
},
openGroupLink = { groupInfo ->
hideKeyboard(view)
withApi {
val link = chatModel.controller.apiGetGroupLink(groupInfo.groupId)
val link = chatModel.controller.apiGetGroupLink(chatRh, groupInfo.groupId)
ModalManager.end.closeModals()
ModalManager.end.showModalCloseable(true) {
GroupLinkView(chatModel, groupInfo, link?.first, link?.second, onGroupLinkUpdated = null)
GroupLinkView(chatModel, chatRh, groupInfo, link?.first, link?.second, onGroupLinkUpdated = null)
}
}
},
markRead = { range, unreadCountAfter ->
chatModel.markChatItemsRead(chat.chatInfo, range, unreadCountAfter)
chatModel.markChatItemsRead(chat, range, unreadCountAfter)
ntfManager.cancelNotificationsForChat(chat.id)
withBGApi {
chatModel.controller.apiChatRead(
chatRh,
chat.chatInfo.chatType,
chat.chatInfo.apiId,
range
@@ -437,7 +442,7 @@ fun ChatView(chatId: String, chatModel: ChatModel, onComposed: suspend (chatId:
if (searchText.value == value) return@ChatLayout
val c = chatModel.getChat(chat.chatInfo.id) ?: return@ChatLayout
withApi {
apiFindMessages(c.chatInfo, chatModel, value)
apiFindMessages(c, chatModel, value)
searchText.value = value
}
},
@@ -498,6 +503,7 @@ fun ChatLayout(
enabled = !attachmentDisabled.value && rememberUpdatedState(chat.userCanSend).value,
onFiles = { paths -> composeState.onFilesAttached(paths.map { URI.create(it) }) },
onImage = {
// TODO: file is not saved anywhere?!
val tmpFile = File.createTempFile("image", ".bmp", tmpDir)
tmpFile.deleteOnExit()
chatModel.filesToDelete.add(tmpFile)
@@ -1252,14 +1258,16 @@ private fun markUnreadChatAsRead(activeChat: MutableState<Chat?>, chatModel: Cha
val chat = activeChat.value
if (chat?.chatStats?.unreadChat != true) return
withApi {
val chatRh = chat.remoteHostId
val success = chatModel.controller.apiChatUnread(
chatRh,
chat.chatInfo.chatType,
chat.chatInfo.apiId,
false
)
if (success && chat.id == activeChat.value?.id) {
activeChat.value = chat.copy(chatStats = chat.chatStats.copy(unreadChat = false))
chatModel.replaceChat(chat.id, activeChat.value!!)
chatModel.replaceChat(chatRh, chat.id, activeChat.value!!)
}
}
}
@@ -1299,7 +1307,7 @@ private fun providerForGallery(
scrollTo: (Int) -> Unit
): ImageGalleryProvider {
fun canShowMedia(item: ChatItem): Boolean =
(item.content.msgContent is MsgContent.MCImage || item.content.msgContent is MsgContent.MCVideo) && (item.file?.loaded == true && getLoadedFilePath(item.file) != null)
(item.content.msgContent is MsgContent.MCImage || item.content.msgContent is MsgContent.MCVideo) && (item.file?.loaded == true && (getLoadedFilePath(item.file) != null || chatModel.connectedToRemote()))
fun item(skipInternalIndex: Int, initialChatId: Long): Pair<Int, ChatItem>? {
var processedInternalIndex = -skipInternalIndex.sign
@@ -1326,7 +1334,7 @@ private fun providerForGallery(
val item = item(internalIndex, initialChatId)?.second ?: return null
return when (item.content.msgContent) {
is MsgContent.MCImage -> {
val res = getLoadedImage(item.file)
val res = runBlocking { getLoadedImage(item.file) }
val filePath = getLoadedFilePath(item.file)
if (res != null && filePath != null) {
val (imageBitmap: ImageBitmap, data: ByteArray) = res
@@ -1334,7 +1342,7 @@ private fun providerForGallery(
} else null
}
is MsgContent.MCVideo -> {
val filePath = getLoadedFilePath(item.file)
val filePath = if (chatModel.connectedToRemote() && item.file?.loaded == true) getAppFilePath(item.file.fileName) else getLoadedFilePath(item.file)
if (filePath != null) {
val uri = getAppFileUri(filePath.substringAfterLast(File.separator))
ProviderMedia.Video(uri, (item.content.msgContent as MsgContent.MCVideo).image)
@@ -1410,6 +1418,7 @@ fun PreviewChatLayout() {
val searchValue = remember { mutableStateOf("") }
ChatLayout(
chat = Chat(
remoteHostId = null,
chatInfo = ChatInfo.Direct.sampleData,
chatItems = chatItems,
chatStats = Chat.ChatStats()
@@ -1482,6 +1491,7 @@ fun PreviewGroupChatLayout() {
val searchValue = remember { mutableStateOf("") }
ChatLayout(
chat = Chat(
remoteHostId = null,
chatInfo = ChatInfo.Group.sampleData,
chatItems = chatItems,
chatStats = Chat.ChatStats()
@@ -15,6 +15,8 @@ import dev.icerock.moko.resources.compose.painterResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.unit.dp
import chat.simplex.common.model.*
import chat.simplex.common.model.ChatModel.controller
import chat.simplex.common.model.ChatModel.filesToDelete
import chat.simplex.common.platform.*
import chat.simplex.common.ui.theme.Indigo
import chat.simplex.common.ui.theme.isSystemInDarkTheme
@@ -349,8 +351,10 @@ fun ComposeView(
}
}
suspend fun send(cInfo: ChatInfo, mc: MsgContent, quoted: Long?, file: CryptoFile? = null, live: Boolean = false, ttl: Int?): ChatItem? {
suspend fun send(chat: Chat, mc: MsgContent, quoted: Long?, file: CryptoFile? = null, live: Boolean = false, ttl: Int?): ChatItem? {
val cInfo = chat.chatInfo
val aChatItem = chatModel.controller.apiSendMessage(
rh = chat.remoteHostId,
type = cInfo.chatType,
id = cInfo.apiId,
file = file,
@@ -360,7 +364,7 @@ fun ComposeView(
ttl = ttl
)
if (aChatItem != null) {
chatModel.addChatItem(cInfo, aChatItem.chatItem)
chatModel.addChatItem(chat.remoteHostId, cInfo, aChatItem.chatItem)
return aChatItem.chatItem
}
if (file != null) removeFile(file.filePath)
@@ -407,23 +411,25 @@ fun ComposeView(
suspend fun sendMemberContactInvitation() {
val mc = checkLinkPreview()
val contact = chatModel.controller.apiSendMemberContactInvitation(chat.chatInfo.apiId, mc)
val contact = chatModel.controller.apiSendMemberContactInvitation(chat.remoteHostId, chat.chatInfo.apiId, mc)
if (contact != null) {
chatModel.updateContact(contact)
chatModel.updateContact(chat.remoteHostId, contact)
}
}
suspend fun updateMessage(ei: ChatItem, cInfo: ChatInfo, live: Boolean): ChatItem? {
suspend fun updateMessage(ei: ChatItem, chat: Chat, live: Boolean): ChatItem? {
val cInfo = chat.chatInfo
val oldMsgContent = ei.content.msgContent
if (oldMsgContent != null) {
val updatedItem = chatModel.controller.apiUpdateChatItem(
rh = chat.remoteHostId,
type = cInfo.chatType,
id = cInfo.apiId,
itemId = ei.meta.itemId,
mc = updateMsgContent(oldMsgContent),
live = live
)
if (updatedItem != null) chatModel.upsertChatItem(cInfo, updatedItem.chatItem)
if (updatedItem != null) chatModel.upsertChatItem(chat.remoteHostId, cInfo, updatedItem.chatItem)
return updatedItem?.chatItem
}
return null
@@ -441,21 +447,29 @@ fun ComposeView(
sent = null
} else if (cs.contextItem is ComposeContextItem.EditingItem) {
val ei = cs.contextItem.chatItem
sent = updateMessage(ei, cInfo, live)
sent = updateMessage(ei, chat, live)
} else if (liveMessage != null && liveMessage.sent) {
sent = updateMessage(liveMessage.chatItem, cInfo, live)
sent = updateMessage(liveMessage.chatItem, chat, live)
} else {
val msgs: ArrayList<MsgContent> = ArrayList()
val files: ArrayList<CryptoFile> = ArrayList()
val remoteHost = chatModel.currentRemoteHost.value
when (val preview = cs.preview) {
ComposePreview.NoPreview -> msgs.add(MsgContent.MCText(msgText))
is ComposePreview.CLinkPreview -> msgs.add(checkLinkPreview())
is ComposePreview.MediaPreview -> {
preview.content.forEachIndexed { index, it ->
val encrypted = chatController.appPrefs.privacyEncryptLocalFiles.get()
val file = when (it) {
is UploadContent.SimpleImage -> saveImage(it.uri, encrypted = chatController.appPrefs.privacyEncryptLocalFiles.get())
is UploadContent.AnimatedImage -> saveAnimImage(it.uri, encrypted = chatController.appPrefs.privacyEncryptLocalFiles.get())
is UploadContent.Video -> saveFileFromUri(it.uri, encrypted = false)
is UploadContent.SimpleImage ->
if (remoteHost == null) saveImage(it.uri, encrypted = encrypted)
else desktopSaveImageInTmp(it.uri)
is UploadContent.AnimatedImage ->
if (remoteHost == null) saveAnimImage(it.uri, encrypted = encrypted)
else CryptoFile.desktopPlain(it.uri)
is UploadContent.Video ->
if (remoteHost == null) saveFileFromUri(it.uri, encrypted = false)
else CryptoFile.desktopPlain(it.uri)
}
if (file != null) {
files.add(file)
@@ -470,22 +484,32 @@ fun ComposeView(
is ComposePreview.VoicePreview -> {
val tmpFile = File(preview.voice)
AudioPlayer.stop(tmpFile.absolutePath)
val actualFile = File(getAppFilePath(tmpFile.name.replaceAfter(RecorderInterface.extension, "")))
files.add(withContext(Dispatchers.IO) {
if (chatController.appPrefs.privacyEncryptLocalFiles.get()) {
val args = encryptCryptoFile(tmpFile.absolutePath, actualFile.absolutePath)
tmpFile.delete()
CryptoFile(actualFile.name, args)
} else {
Files.move(tmpFile.toPath(), actualFile.toPath())
CryptoFile.plain(actualFile.name)
}
})
deleteUnusedFiles()
if (remoteHost == null) {
val actualFile = File(getAppFilePath(tmpFile.name.replaceAfter(RecorderInterface.extension, "")))
files.add(withContext(Dispatchers.IO) {
if (chatController.appPrefs.privacyEncryptLocalFiles.get()) {
val args = encryptCryptoFile(tmpFile.absolutePath, actualFile.absolutePath)
tmpFile.delete()
CryptoFile(actualFile.name, args)
} else {
Files.move(tmpFile.toPath(), actualFile.toPath())
CryptoFile.plain(actualFile.name)
}
})
deleteUnusedFiles()
} else {
files.add(CryptoFile.plain(tmpFile.absolutePath))
// It will be deleted on JVM shutdown or next start (if the app crashes unexpectedly)
filesToDelete.remove(tmpFile)
}
msgs.add(MsgContent.MCVoice(if (msgs.isEmpty()) msgText else "", preview.durationMs / 1000))
}
is ComposePreview.FilePreview -> {
val file = saveFileFromUri(preview.uri, encrypted = chatController.appPrefs.privacyEncryptLocalFiles.get())
val file = if (remoteHost == null) {
saveFileFromUri(preview.uri, encrypted = chatController.appPrefs.privacyEncryptLocalFiles.get())
} else {
CryptoFile.desktopPlain(preview.uri)
}
if (file != null) {
files.add((file))
msgs.add(MsgContent.MCFile(if (msgs.isEmpty()) msgText else ""))
@@ -499,7 +523,15 @@ fun ComposeView(
sent = null
msgs.forEachIndexed { index, content ->
if (index > 0) delay(100)
sent = send(cInfo, content, if (index == 0) quotedItemId else null, files.getOrNull(index),
var file = files.getOrNull(index)
if (remoteHost != null && file != null) {
file = controller.storeRemoteFile(
rhId = remoteHost.remoteHostId,
storeEncrypted = if (content is MsgContent.MCVideo) false else null,
localPath = file.filePath
)
}
sent = send(chat, content, if (index == 0) quotedItemId else null, file,
live = if (content !is MsgContent.MCVoice && index == msgs.lastIndex) live else false,
ttl = ttl
)
@@ -509,7 +541,7 @@ fun ComposeView(
cs.preview is ComposePreview.FilePreview ||
cs.preview is ComposePreview.VoicePreview)
) {
sent = send(cInfo, MsgContent.MCText(msgText), quotedItemId, null, live, ttl)
sent = send(chat, MsgContent.MCText(msgText), quotedItemId, null, live, ttl)
}
}
clearState(live)
@@ -544,7 +576,7 @@ fun ComposeView(
fun allowVoiceToContact() {
val contact = (chat.chatInfo as ChatInfo.Direct?)?.contact ?: return
withApi {
chatModel.controller.allowFeatureToContact(contact, ChatFeature.Voice)
chatModel.controller.allowFeatureToContact(chat.remoteHostId, contact, ChatFeature.Voice)
}
}
@@ -25,6 +25,7 @@ import chat.simplex.res.MR
fun ContactPreferencesView(
m: ChatModel,
user: User,
rhId: Long?,
contactId: Long,
close: () -> Unit,
) {
@@ -36,9 +37,9 @@ fun ContactPreferencesView(
fun savePrefs(afterSave: () -> Unit = {}) {
withApi {
val prefs = contactFeaturesAllowedToPrefs(featuresAllowed)
val toContact = m.controller.apiSetContactPrefs(ct.contactId, prefs)
val toContact = m.controller.apiSetContactPrefs(rhId, ct.contactId, prefs)
if (toContact != null) {
m.updateContact(toContact)
m.updateContact(rhId, toContact)
currentFeaturesAllowed = featuresAllowed
}
afterSave()
@@ -11,10 +11,7 @@ import chat.simplex.res.MR
import dev.icerock.moko.resources.compose.stringResource
@Composable
expect fun ScanCodeView(verifyCode: (String?, cb: (Boolean) -> Unit) -> Unit, close: () -> Unit)
@Composable
fun ScanCodeLayout(verifyCode: (String?, cb: (Boolean) -> Unit) -> Unit, close: () -> Unit) {
fun ScanCodeView(verifyCode: (String?, cb: (Boolean) -> Unit) -> Unit, close: () -> Unit) {
Column(
Modifier
.fillMaxSize()
@@ -33,7 +33,7 @@ import chat.simplex.common.platform.*
import chat.simplex.res.MR
@Composable
fun AddGroupMembersView(groupInfo: GroupInfo, creatingGroup: Boolean = false, chatModel: ChatModel, close: () -> Unit) {
fun AddGroupMembersView(rhId: Long?, groupInfo: GroupInfo, creatingGroup: Boolean = false, chatModel: ChatModel, close: () -> Unit) {
val selectedContacts = remember { mutableStateListOf<Long>() }
val selectedRole = remember { mutableStateOf(GroupMemberRole.Member) }
var allowModifyMembers by remember { mutableStateOf(true) }
@@ -49,16 +49,16 @@ fun AddGroupMembersView(groupInfo: GroupInfo, creatingGroup: Boolean = false, ch
searchText,
openPreferences = {
ModalManager.end.showCustomModal { close ->
GroupPreferencesView(chatModel, groupInfo.id, close)
GroupPreferencesView(chatModel, rhId, groupInfo.id, close)
}
},
inviteMembers = {
allowModifyMembers = false
withApi {
for (contactId in selectedContacts) {
val member = chatModel.controller.apiAddMember(groupInfo.groupId, contactId, selectedRole.value)
val member = chatModel.controller.apiAddMember(rhId, groupInfo.groupId, contactId, selectedRole.value)
if (member != null) {
chatModel.upsertGroupMember(groupInfo, member)
chatModel.upsertGroupMember(rhId, groupInfo, member)
} else {
break
}
@@ -41,9 +41,10 @@ import kotlinx.coroutines.launch
const val SMALL_GROUPS_RCPS_MEM_LIMIT: Int = 20
@Composable
fun GroupChatInfoView(chatModel: ChatModel, groupLink: String?, groupLinkMemberRole: GroupMemberRole?, onGroupLinkUpdated: (Pair<String, GroupMemberRole>?) -> Unit, close: () -> Unit) {
fun GroupChatInfoView(chatModel: ChatModel, rhId: Long?, chatId: String, groupLink: String?, groupLinkMemberRole: GroupMemberRole?, onGroupLinkUpdated: (Pair<String, GroupMemberRole>?) -> Unit, close: () -> Unit) {
BackHandler(onBack = close)
val chat = chatModel.chats.firstOrNull { it.id == chatModel.chatId.value }
// TODO derivedStateOf?
val chat = chatModel.chats.firstOrNull { ch -> ch.id == chatId && ch.remoteHostId == rhId }
val currentUser = chatModel.currentUser.value
val developerTools = chatModel.controller.appPrefs.developerTools.get()
if (chat != null && chat.chatInfo is ChatInfo.Group && currentUser != null) {
@@ -68,25 +69,25 @@ fun GroupChatInfoView(chatModel: ChatModel, groupLink: String?, groupLinkMemberR
groupLink,
addMembers = {
withApi {
setGroupMembers(groupInfo, chatModel)
setGroupMembers(rhId, groupInfo, chatModel)
ModalManager.end.showModalCloseable(true) { close ->
AddGroupMembersView(groupInfo, false, chatModel, close)
AddGroupMembersView(rhId, groupInfo, false, chatModel, close)
}
}
},
showMemberInfo = { member ->
withApi {
val r = chatModel.controller.apiGroupMemberInfo(groupInfo.groupId, member.groupMemberId)
val r = chatModel.controller.apiGroupMemberInfo(rhId, groupInfo.groupId, member.groupMemberId)
val stats = r?.second
val (_, code) = if (member.memberActive) {
val memCode = chatModel.controller.apiGetGroupMemberCode(groupInfo.apiId, member.groupMemberId)
val memCode = chatModel.controller.apiGetGroupMemberCode(rhId, groupInfo.apiId, member.groupMemberId)
member to memCode?.second
} else {
member to null
}
ModalManager.end.showModalCloseable(true) { closeCurrent ->
remember { derivedStateOf { chatModel.getGroupMember(member.groupMemberId) } }.value?.let { mem ->
GroupMemberInfoView(groupInfo, mem, stats, code, chatModel, closeCurrent) {
GroupMemberInfoView(rhId, groupInfo, mem, stats, code, chatModel, closeCurrent) {
closeCurrent()
close()
}
@@ -95,31 +96,33 @@ fun GroupChatInfoView(chatModel: ChatModel, groupLink: String?, groupLinkMemberR
}
},
editGroupProfile = {
ModalManager.end.showCustomModal { close -> GroupProfileView(groupInfo, chatModel, close) }
ModalManager.end.showCustomModal { close -> GroupProfileView(rhId, groupInfo, chatModel, close) }
},
addOrEditWelcomeMessage = {
ModalManager.end.showCustomModal { close -> GroupWelcomeView(chatModel, groupInfo, close) }
ModalManager.end.showCustomModal { close -> GroupWelcomeView(chatModel, rhId, groupInfo, close) }
},
openPreferences = {
ModalManager.end.showCustomModal { close ->
GroupPreferencesView(
chatModel,
rhId,
chat.id,
close
)
}
},
deleteGroup = { deleteGroupDialog(chat.chatInfo, groupInfo, chatModel, close) },
clearChat = { clearChatDialog(chat.chatInfo, chatModel, close) },
leaveGroup = { leaveGroupDialog(groupInfo, chatModel, close) },
deleteGroup = { deleteGroupDialog(chat, groupInfo, chatModel, close) },
clearChat = { clearChatDialog(chat, chatModel, close) },
leaveGroup = { leaveGroupDialog(rhId, groupInfo, chatModel, close) },
manageGroupLink = {
ModalManager.end.showModal { GroupLinkView(chatModel, groupInfo, groupLink, groupLinkMemberRole, onGroupLinkUpdated) }
ModalManager.end.showModal { GroupLinkView(chatModel, rhId, groupInfo, groupLink, groupLinkMemberRole, onGroupLinkUpdated) }
}
)
}
}
fun deleteGroupDialog(chatInfo: ChatInfo, groupInfo: GroupInfo, chatModel: ChatModel, close: (() -> Unit)? = null) {
fun deleteGroupDialog(chat: Chat, groupInfo: GroupInfo, chatModel: ChatModel, close: (() -> Unit)? = null) {
val chatInfo = chat.chatInfo
val alertTextKey =
if (groupInfo.membership.memberCurrent) MR.strings.delete_group_for_all_members_cannot_undo_warning
else MR.strings.delete_group_for_self_cannot_undo_warning
@@ -129,9 +132,9 @@ fun deleteGroupDialog(chatInfo: ChatInfo, groupInfo: GroupInfo, chatModel: ChatM
confirmText = generalGetString(MR.strings.delete_verb),
onConfirm = {
withApi {
val r = chatModel.controller.apiDeleteChat(chatInfo.chatType, chatInfo.apiId)
val r = chatModel.controller.apiDeleteChat(chat.remoteHostId, chatInfo.chatType, chatInfo.apiId)
if (r) {
chatModel.removeChat(chatInfo.id)
chatModel.removeChat(chat.remoteHostId, chatInfo.id)
if (chatModel.chatId.value == chatInfo.id) {
chatModel.chatId.value = null
ModalManager.end.closeModals()
@@ -145,14 +148,14 @@ fun deleteGroupDialog(chatInfo: ChatInfo, groupInfo: GroupInfo, chatModel: ChatM
)
}
fun leaveGroupDialog(groupInfo: GroupInfo, chatModel: ChatModel, close: (() -> Unit)? = null) {
fun leaveGroupDialog(rhId: Long?, groupInfo: GroupInfo, chatModel: ChatModel, close: (() -> Unit)? = null) {
AlertManager.shared.showAlertDialog(
title = generalGetString(MR.strings.leave_group_question),
text = generalGetString(MR.strings.you_will_stop_receiving_messages_from_this_group_chat_history_will_be_preserved),
confirmText = generalGetString(MR.strings.leave_group_button),
onConfirm = {
withApi {
chatModel.controller.leaveGroup(groupInfo.groupId)
chatModel.controller.leaveGroup(rhId, groupInfo.groupId)
close?.invoke()
}
},
@@ -160,16 +163,16 @@ fun leaveGroupDialog(groupInfo: GroupInfo, chatModel: ChatModel, close: (() -> U
)
}
private fun removeMemberAlert(groupInfo: GroupInfo, mem: GroupMember) {
private fun removeMemberAlert(rhId: Long?, groupInfo: GroupInfo, mem: GroupMember) {
AlertManager.shared.showAlertDialog(
title = generalGetString(MR.strings.button_remove_member_question),
text = generalGetString(MR.strings.member_will_be_removed_from_group_cannot_be_undone),
confirmText = generalGetString(MR.strings.remove_member_confirmation),
onConfirm = {
withApi {
val updatedMember = chatModel.controller.apiRemoveMember(groupInfo.groupId, mem.groupMemberId)
val updatedMember = chatModel.controller.apiRemoveMember(rhId, groupInfo.groupId, mem.groupMemberId)
if (updatedMember != null) {
chatModel.upsertGroupMember(groupInfo, updatedMember)
chatModel.upsertGroupMember(rhId, groupInfo, updatedMember)
}
}
},
@@ -260,7 +263,7 @@ fun GroupChatInfoLayout(
Divider()
val showMenu = remember { mutableStateOf(false) }
SectionItemViewLongClickable({ showMemberInfo(member) }, { showMenu.value = true }, minHeight = 54.dp) {
DropDownMenuForMember(member, groupInfo, showMenu)
DropDownMenuForMember(chat.remoteHostId, member, groupInfo, showMenu)
MemberRow(member, onClick = { showMemberInfo(member) })
}
}
@@ -413,22 +416,22 @@ private fun MemberVerifiedShield() {
}
@Composable
private fun DropDownMenuForMember(member: GroupMember, groupInfo: GroupInfo, showMenu: MutableState<Boolean>) {
private fun DropDownMenuForMember(rhId: Long?, member: GroupMember, groupInfo: GroupInfo, showMenu: MutableState<Boolean>) {
DefaultDropdownMenu(showMenu) {
if (member.canBeRemoved(groupInfo)) {
ItemAction(stringResource(MR.strings.remove_member_button), painterResource(MR.images.ic_delete), color = MaterialTheme.colors.error, onClick = {
removeMemberAlert(groupInfo, member)
removeMemberAlert(rhId, groupInfo, member)
showMenu.value = false
})
}
if (member.memberSettings.showMessages) {
ItemAction(stringResource(MR.strings.block_member_button), painterResource(MR.images.ic_back_hand), color = MaterialTheme.colors.error, onClick = {
blockMemberAlert(groupInfo, member)
blockMemberAlert(rhId, groupInfo, member)
showMenu.value = false
})
} else {
ItemAction(stringResource(MR.strings.unblock_member_button), painterResource(MR.images.ic_do_not_touch), onClick = {
unblockMemberAlert(groupInfo, member)
unblockMemberAlert(rhId, groupInfo, member)
showMenu.value = false
})
}
@@ -521,6 +524,7 @@ fun PreviewGroupChatInfoLayout() {
SimpleXTheme {
GroupChatInfoLayout(
chat = Chat(
remoteHostId = null,
chatInfo = ChatInfo.Direct.sampleData,
chatItems = arrayListOf()
),
@@ -25,6 +25,7 @@ import chat.simplex.res.MR
@Composable
fun GroupLinkView(
chatModel: ChatModel,
rhId: Long?,
groupInfo: GroupInfo,
connReqContact: String?,
memberRole: GroupMemberRole?,
@@ -38,7 +39,7 @@ fun GroupLinkView(
fun createLink() {
creatingLink = true
withApi {
val link = chatModel.controller.apiCreateGroupLink(groupInfo.groupId)
val link = chatModel.controller.apiCreateGroupLink(rhId, groupInfo.groupId)
if (link != null) {
groupLink = link.first
groupLinkMemberRole.value = link.second
@@ -62,7 +63,7 @@ fun GroupLinkView(
val role = groupLinkMemberRole.value
if (role != null) {
withBGApi {
val link = chatModel.controller.apiGroupLinkMemberRole(groupInfo.groupId, role)
val link = chatModel.controller.apiGroupLinkMemberRole(rhId, groupInfo.groupId, role)
if (link != null) {
groupLink = link.first
groupLinkMemberRole.value = link.second
@@ -78,7 +79,7 @@ fun GroupLinkView(
confirmText = generalGetString(MR.strings.delete_verb),
onConfirm = {
withApi {
val r = chatModel.controller.apiDeleteGroupLink(groupInfo.groupId)
val r = chatModel.controller.apiDeleteGroupLink(rhId, groupInfo.groupId)
if (r) {
groupLink = null
onGroupLinkUpdated?.invoke(null)
@@ -40,6 +40,7 @@ import kotlinx.datetime.Clock
@Composable
fun GroupMemberInfoView(
rhId: Long?,
groupInfo: GroupInfo,
member: GroupMember,
connectionStats: ConnectionStats?,
@@ -49,7 +50,7 @@ fun GroupMemberInfoView(
closeAll: () -> Unit, // Close all open windows up to ChatView
) {
BackHandler(onBack = close)
val chat = chatModel.chats.firstOrNull { it.id == chatModel.chatId.value }
val chat = chatModel.chats.firstOrNull { ch -> ch.id == chatModel.chatId.value && ch.remoteHostId == rhId }
val connStats = remember { mutableStateOf(connectionStats) }
val developerTools = chatModel.controller.appPrefs.developerTools.get()
var progressIndicator by remember { mutableStateOf(false) }
@@ -66,7 +67,7 @@ fun GroupMemberInfoView(
getContactChat = { chatModel.getContactChat(it) },
openDirectChat = {
withApi {
val c = chatModel.controller.apiGetChat(ChatType.Direct, it)
val c = chatModel.controller.apiGetChat(rhId, ChatType.Direct, it)
if (c != null) {
if (chatModel.getContactChat(it) == null) {
chatModel.addChat(c)
@@ -82,9 +83,9 @@ fun GroupMemberInfoView(
createMemberContact = {
withApi {
progressIndicator = true
val memberContact = chatModel.controller.apiCreateMemberContact(groupInfo.apiId, member.groupMemberId)
val memberContact = chatModel.controller.apiCreateMemberContact(rhId, groupInfo.apiId, member.groupMemberId)
if (memberContact != null) {
val memberChat = Chat(ChatInfo.Direct(memberContact), chatItems = arrayListOf())
val memberChat = Chat(remoteHostId = rhId, ChatInfo.Direct(memberContact), chatItems = arrayListOf())
chatModel.addChat(memberChat)
openLoadedChat(memberChat, chatModel)
closeAll()
@@ -94,11 +95,11 @@ fun GroupMemberInfoView(
}
},
connectViaAddress = { connReqUri ->
connectViaMemberAddressAlert(connReqUri)
connectViaMemberAddressAlert(rhId, connReqUri)
},
blockMember = { blockMemberAlert(groupInfo, member) },
unblockMember = { unblockMemberAlert(groupInfo, member) },
removeMember = { removeMemberDialog(groupInfo, member, chatModel, close) },
blockMember = { blockMemberAlert(rhId, groupInfo, member) },
unblockMember = { unblockMemberAlert(rhId, groupInfo, member) },
removeMember = { removeMemberDialog(rhId, groupInfo, member, chatModel, close) },
onRoleSelected = {
if (it == newRole.value) return@GroupMemberInfoLayout
val prevValue = newRole.value
@@ -108,8 +109,8 @@ fun GroupMemberInfoView(
}) {
withApi {
kotlin.runCatching {
val mem = chatModel.controller.apiMemberRole(groupInfo.groupId, member.groupMemberId, it)
chatModel.upsertGroupMember(groupInfo, mem)
val mem = chatModel.controller.apiMemberRole(rhId, groupInfo.groupId, member.groupMemberId, it)
chatModel.upsertGroupMember(rhId, groupInfo, mem)
}.onFailure {
newRole.value = prevValue
}
@@ -119,10 +120,10 @@ fun GroupMemberInfoView(
switchMemberAddress = {
showSwitchAddressAlert(switchAddress = {
withApi {
val r = chatModel.controller.apiSwitchGroupMember(groupInfo.apiId, member.groupMemberId)
val r = chatModel.controller.apiSwitchGroupMember(rhId, groupInfo.apiId, member.groupMemberId)
if (r != null) {
connStats.value = r.second
chatModel.updateGroupMemberConnectionStats(groupInfo, r.first, r.second)
chatModel.updateGroupMemberConnectionStats(rhId, groupInfo, r.first, r.second)
close.invoke()
}
}
@@ -131,10 +132,10 @@ fun GroupMemberInfoView(
abortSwitchMemberAddress = {
showAbortSwitchAddressAlert(abortSwitchAddress = {
withApi {
val r = chatModel.controller.apiAbortSwitchGroupMember(groupInfo.apiId, member.groupMemberId)
val r = chatModel.controller.apiAbortSwitchGroupMember(rhId, groupInfo.apiId, member.groupMemberId)
if (r != null) {
connStats.value = r.second
chatModel.updateGroupMemberConnectionStats(groupInfo, r.first, r.second)
chatModel.updateGroupMemberConnectionStats(rhId, groupInfo, r.first, r.second)
close.invoke()
}
}
@@ -142,10 +143,10 @@ fun GroupMemberInfoView(
},
syncMemberConnection = {
withApi {
val r = chatModel.controller.apiSyncGroupMemberRatchet(groupInfo.apiId, member.groupMemberId, force = false)
val r = chatModel.controller.apiSyncGroupMemberRatchet(rhId, groupInfo.apiId, member.groupMemberId, force = false)
if (r != null) {
connStats.value = r.second
chatModel.updateGroupMemberConnectionStats(groupInfo, r.first, r.second)
chatModel.updateGroupMemberConnectionStats(rhId, groupInfo, r.first, r.second)
close.invoke()
}
}
@@ -153,10 +154,10 @@ fun GroupMemberInfoView(
syncMemberConnectionForce = {
showSyncConnectionForceAlert(syncConnectionForce = {
withApi {
val r = chatModel.controller.apiSyncGroupMemberRatchet(groupInfo.apiId, member.groupMemberId, force = true)
val r = chatModel.controller.apiSyncGroupMemberRatchet(rhId, groupInfo.apiId, member.groupMemberId, force = true)
if (r != null) {
connStats.value = r.second
chatModel.updateGroupMemberConnectionStats(groupInfo, r.first, r.second)
chatModel.updateGroupMemberConnectionStats(rhId, groupInfo, r.first, r.second)
close.invoke()
}
}
@@ -170,9 +171,10 @@ fun GroupMemberInfoView(
connectionCode,
mem.verified,
verify = { code ->
chatModel.controller.apiVerifyGroupMember(mem.groupId, mem.groupMemberId, code)?.let { r ->
chatModel.controller.apiVerifyGroupMember(rhId, mem.groupId, mem.groupMemberId, code)?.let { r ->
val (verified, existingCode) = r
chatModel.upsertGroupMember(
rhId,
groupInfo,
mem.copy(
activeConn = mem.activeConn?.copy(
@@ -196,16 +198,16 @@ fun GroupMemberInfoView(
}
}
fun removeMemberDialog(groupInfo: GroupInfo, member: GroupMember, chatModel: ChatModel, close: (() -> Unit)? = null) {
fun removeMemberDialog(rhId: Long?, groupInfo: GroupInfo, member: GroupMember, chatModel: ChatModel, close: (() -> Unit)? = null) {
AlertManager.shared.showAlertDialog(
title = generalGetString(MR.strings.button_remove_member),
text = generalGetString(MR.strings.member_will_be_removed_from_group_cannot_be_undone),
confirmText = generalGetString(MR.strings.remove_member_confirmation),
onConfirm = {
withApi {
val removedMember = chatModel.controller.apiRemoveMember(member.groupId, member.groupMemberId)
val removedMember = chatModel.controller.apiRemoveMember(rhId, member.groupId, member.groupMemberId)
if (removedMember != null) {
chatModel.upsertGroupMember(groupInfo, removedMember)
chatModel.upsertGroupMember(rhId, groupInfo, removedMember)
}
close?.invoke()
}
@@ -500,11 +502,11 @@ private fun updateMemberRoleDialog(
)
}
fun connectViaMemberAddressAlert(connReqUri: String) {
fun connectViaMemberAddressAlert(rhId: Long?, connReqUri: String) {
try {
val uri = URI(connReqUri)
withApi {
planAndConnect(chatModel, uri, incognito = null, close = { ModalManager.closeAllModalsEverywhere() })
planAndConnect(chatModel, rhId, uri, incognito = null, close = { ModalManager.closeAllModalsEverywhere() })
}
} catch (e: RuntimeException) {
AlertManager.shared.showAlertMsg(
@@ -514,39 +516,39 @@ fun connectViaMemberAddressAlert(connReqUri: String) {
}
}
fun blockMemberAlert(gInfo: GroupInfo, mem: GroupMember) {
fun blockMemberAlert(rhId: Long?, gInfo: GroupInfo, mem: GroupMember) {
AlertManager.shared.showAlertDialog(
title = generalGetString(MR.strings.block_member_question),
text = generalGetString(MR.strings.block_member_desc).format(mem.chatViewName),
confirmText = generalGetString(MR.strings.block_member_confirmation),
onConfirm = {
toggleShowMemberMessages(gInfo, mem, false)
toggleShowMemberMessages(rhId, gInfo, mem, false)
},
destructive = true,
)
}
fun unblockMemberAlert(gInfo: GroupInfo, mem: GroupMember) {
fun unblockMemberAlert(rhId: Long?, gInfo: GroupInfo, mem: GroupMember) {
AlertManager.shared.showAlertDialog(
title = generalGetString(MR.strings.unblock_member_question),
text = generalGetString(MR.strings.unblock_member_desc).format(mem.chatViewName),
confirmText = generalGetString(MR.strings.unblock_member_confirmation),
onConfirm = {
toggleShowMemberMessages(gInfo, mem, true)
toggleShowMemberMessages(rhId, gInfo, mem, true)
},
)
}
fun toggleShowMemberMessages(gInfo: GroupInfo, member: GroupMember, showMessages: Boolean) {
fun toggleShowMemberMessages(rhId: Long?, gInfo: GroupInfo, member: GroupMember, showMessages: Boolean) {
val updatedMemberSettings = member.memberSettings.copy(showMessages = showMessages)
updateMemberSettings(gInfo, member, updatedMemberSettings)
updateMemberSettings(rhId, gInfo, member, updatedMemberSettings)
}
fun updateMemberSettings(gInfo: GroupInfo, member: GroupMember, memberSettings: GroupMemberSettings) {
fun updateMemberSettings(rhId: Long?, gInfo: GroupInfo, member: GroupMember, memberSettings: GroupMemberSettings) {
withBGApi {
val success = ChatController.apiSetMemberSettings(gInfo.groupId, member.groupMemberId, memberSettings)
val success = ChatController.apiSetMemberSettings(rhId, gInfo.groupId, member.groupMemberId, memberSettings)
if (success) {
ChatModel.upsertGroupMember(gInfo, member.copy(memberSettings = memberSettings))
ChatModel.upsertGroupMember(rhId, gInfo, member.copy(memberSettings = memberSettings))
}
}
}
@@ -21,8 +21,12 @@ import chat.simplex.common.model.*
import chat.simplex.res.MR
@Composable
fun GroupPreferencesView(m: ChatModel, chatId: String, close: () -> Unit,) {
val groupInfo = remember { derivedStateOf { (m.getChat(chatId)?.chatInfo as? ChatInfo.Group)?.groupInfo } }
fun GroupPreferencesView(m: ChatModel, rhId: Long?, chatId: String, close: () -> Unit,) {
val groupInfo = remember { derivedStateOf {
val ch = m.getChat(chatId)
val g = (ch?.chatInfo as? ChatInfo.Group)?.groupInfo
if (g == null || ch?.remoteHostId != rhId) null else g
}}
val gInfo = groupInfo.value ?: return
var preferences by rememberSaveable(gInfo, stateSaver = serializableSaver()) { mutableStateOf(gInfo.fullGroupPreferences) }
var currentPreferences by rememberSaveable(gInfo, stateSaver = serializableSaver()) { mutableStateOf(preferences) }
@@ -30,9 +34,9 @@ fun GroupPreferencesView(m: ChatModel, chatId: String, close: () -> Unit,) {
fun savePrefs(afterSave: () -> Unit = {}) {
withApi {
val gp = gInfo.groupProfile.copy(groupPreferences = preferences.toGroupPreferences())
val g = m.controller.apiUpdateGroup(gInfo.groupId, gp)
val g = m.controller.apiUpdateGroup(rhId, gInfo.groupId, gp)
if (g != null) {
m.updateGroup(g)
m.updateGroup(rhId, g)
currentPreferences = preferences
}
afterSave()
@@ -30,15 +30,15 @@ import kotlinx.coroutines.launch
import java.net.URI
@Composable
fun GroupProfileView(groupInfo: GroupInfo, chatModel: ChatModel, close: () -> Unit) {
fun GroupProfileView(rhId: Long?, groupInfo: GroupInfo, chatModel: ChatModel, close: () -> Unit) {
GroupProfileLayout(
close = close,
groupProfile = groupInfo.groupProfile,
saveProfile = { p ->
withApi {
val gInfo = chatModel.controller.apiUpdateGroup(groupInfo.groupId, p)
val gInfo = chatModel.controller.apiUpdateGroup(rhId, groupInfo.groupId, p)
if (gInfo != null) {
chatModel.updateGroup(gInfo)
chatModel.updateGroup(rhId, gInfo)
close.invoke()
}
}
@@ -30,7 +30,7 @@ import chat.simplex.res.MR
import kotlinx.coroutines.delay
@Composable
fun GroupWelcomeView(m: ChatModel, groupInfo: GroupInfo, close: () -> Unit) {
fun GroupWelcomeView(m: ChatModel, rhId: Long?, groupInfo: GroupInfo, close: () -> Unit) {
var gInfo by remember { mutableStateOf(groupInfo) }
val welcomeText = remember { mutableStateOf(gInfo.groupProfile.description ?: "") }
@@ -41,10 +41,10 @@ fun GroupWelcomeView(m: ChatModel, groupInfo: GroupInfo, close: () -> Unit) {
welcome = null
}
val groupProfileUpdated = gInfo.groupProfile.copy(description = welcome)
val res = m.controller.apiUpdateGroup(gInfo.groupId, groupProfileUpdated)
val res = m.controller.apiUpdateGroup(rhId, gInfo.groupId, groupProfileUpdated)
if (res != null) {
gInfo = res
m.updateGroup(res)
m.updateGroup(rhId, res)
welcomeText.value = welcome ?: ""
}
afterSave()
@@ -94,13 +94,19 @@ fun CIFileView(
)
}
is CIFileStatus.RcvComplete -> {
val filePath = getLoadedFilePath(file)
if (filePath != null) {
withApi {
saveFileLauncher.launch(file.fileName)
withBGApi {
var filePath = getLoadedFilePath(file)
if (chatModel.connectedToRemote() && filePath == null) {
file.loadRemoteFile(true)
filePath = getLoadedFilePath(file)
}
if (filePath != null) {
withApi {
saveFileLauncher.launch(file.fileName)
}
} else {
showToast(generalGetString(MR.strings.file_not_found))
}
} else {
showToast(generalGetString(MR.strings.file_not_found))
}
}
else -> {}
@@ -22,6 +22,9 @@ import chat.simplex.common.platform.*
import chat.simplex.common.ui.theme.DEFAULT_MAX_IMAGE_WIDTH
import chat.simplex.res.MR
import dev.icerock.moko.resources.StringResource
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.runBlocking
import java.io.File
import java.net.URI
@@ -134,7 +137,7 @@ fun CIImageView(
return false
}
fun imageAndFilePath(file: CIFile?): Triple<ImageBitmap, ByteArray, String>? {
suspend fun imageAndFilePath(file: CIFile?): Triple<ImageBitmap, ByteArray, String>? {
val res = getLoadedImage(file)
if (res != null) {
val (imageBitmap: ImageBitmap, data: ByteArray) = res
@@ -148,9 +151,23 @@ fun CIImageView(
Modifier.layoutId(CHAT_IMAGE_LAYOUT_ID),
contentAlignment = Alignment.TopEnd
) {
val res = remember(file) { imageAndFilePath(file) }
if (res != null) {
val (imageBitmap, data, _) = res
val res: MutableState<Triple<ImageBitmap, ByteArray, String>?> = remember {
mutableStateOf(
if (chatModel.connectedToRemote()) null else runBlocking { imageAndFilePath(file) }
)
}
if (chatModel.connectedToRemote()) {
LaunchedEffect(file, CIFile.cachedRemoteFileRequests.toList()) {
withBGApi {
if (res.value == null || res.value!!.third != getLoadedFilePath(file)) {
res.value = imageAndFilePath(file)
}
}
}
}
val loaded = res.value
if (loaded != null) {
val (imageBitmap, data, _) = loaded
SimpleAndAnimatedImageView(data, imageBitmap, file, imageProvider, @Composable { painter, onClick -> ImageView(painter, onClick) })
} else {
imageView(base64ToBitmap(image), onClick = {
@@ -21,6 +21,7 @@ import chat.simplex.common.views.helpers.*
import chat.simplex.common.model.*
import chat.simplex.common.platform.*
import dev.icerock.moko.resources.StringResource
import kotlinx.coroutines.flow.*
import java.io.File
import java.net.URI
@@ -37,10 +38,21 @@ fun CIVideoView(
Modifier.layoutId(CHAT_IMAGE_LAYOUT_ID),
contentAlignment = Alignment.TopEnd
) {
val filePath = remember(file) { getLoadedFilePath(file) }
val preview = remember(image) { base64ToBitmap(image) }
if (file != null && filePath != null) {
val uri = remember(filePath) { getAppFileUri(filePath.substringAfterLast(File.separator)) }
val filePath = remember(file, CIFile.cachedRemoteFileRequests.toList()) { mutableStateOf(getLoadedFilePath(file)) }
if (chatModel.connectedToRemote()) {
LaunchedEffect(file) {
withBGApi {
if (file != null && file.loaded && getLoadedFilePath(file) == null) {
file.loadRemoteFile(false)
filePath.value = getLoadedFilePath(file)
}
}
}
}
val f = filePath.value
if (file != null && f != null) {
val uri = remember(filePath) { getAppFileUri(f.substringAfterLast(File.separator)) }
val view = LocalMultiplatformView()
VideoView(uri, file, preview, duration * 1000L, showMenu, onClick = {
hideKeyboard(view)
@@ -22,7 +22,7 @@ import chat.simplex.common.views.helpers.*
import chat.simplex.common.model.*
import chat.simplex.common.platform.*
import chat.simplex.res.MR
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.*
// TODO refactor https://github.com/simplex-chat/simplex-chat/pull/1451#discussion_r1033429901
@@ -44,16 +44,25 @@ fun CIVoiceView(
) {
if (file != null) {
val f = file.fileSource?.filePath
val fileSource = remember(f, file.fileStatus) { getLoadedFileSource(file) }
val fileSource = remember(f, file.fileStatus, CIFile.cachedRemoteFileRequests.toList()) { mutableStateOf(getLoadedFileSource(file)) }
var brokenAudio by rememberSaveable(f) { mutableStateOf(false) }
val audioPlaying = rememberSaveable(f) { mutableStateOf(false) }
val progress = rememberSaveable(f) { mutableStateOf(0) }
val duration = rememberSaveable(f) { mutableStateOf(providedDurationSec * 1000) }
val play = {
if (fileSource != null) {
AudioPlayer.play(fileSource, audioPlaying, progress, duration, true)
brokenAudio = !audioPlaying.value
val play: () -> Unit = {
val playIfExists = {
if (fileSource.value != null) {
AudioPlayer.play(fileSource.value!!, audioPlaying, progress, duration, true)
brokenAudio = !audioPlaying.value
}
}
if (chatModel.connectedToRemote() && fileSource.value == null) {
withBGApi {
file.loadRemoteFile(true)
fileSource.value = getLoadedFileSource(file)
playIfExists()
}
} else playIfExists()
}
val pause = {
AudioPlayer.pause(audioPlaying, progress)
@@ -68,7 +77,7 @@ fun CIVoiceView(
}
}
VoiceLayout(file, ci, text, audioPlaying, progress, duration, brokenAudio, sent, hasText, timedMessagesTTL, play, pause, longClick, receiveFile) {
AudioPlayer.seekTo(it, progress, fileSource?.filePath)
AudioPlayer.seekTo(it, progress, fileSource.value?.filePath)
}
} else {
VoiceMsgIndicator(null, false, sent, hasText, null, null, false, {}, {}, longClick, receiveFile)
@@ -194,19 +194,34 @@ fun ChatItemView(
})
}
val clipboard = LocalClipboardManager.current
ItemAction(stringResource(MR.strings.share_verb), painterResource(MR.images.ic_share), onClick = {
val fileSource = getLoadedFileSource(cItem.file)
when {
fileSource != null -> shareFile(cItem.text, fileSource)
else -> clipboard.shareText(cItem.content.text)
}
showMenu.value = false
})
ItemAction(stringResource(MR.strings.copy_verb), painterResource(MR.images.ic_content_copy), onClick = {
copyItemToClipboard(cItem, clipboard)
showMenu.value = false
})
if ((cItem.content.msgContent is MsgContent.MCImage || cItem.content.msgContent is MsgContent.MCVideo || cItem.content.msgContent is MsgContent.MCFile || cItem.content.msgContent is MsgContent.MCVoice) && getLoadedFilePath(cItem.file) != null) {
val cachedRemoteReqs = remember { CIFile.cachedRemoteFileRequests }
val copyAndShareAllowed = cItem.file == null || !chatModel.connectedToRemote() || getLoadedFilePath(cItem.file) != null || !cachedRemoteReqs.contains(cItem.file.fileSource)
if (copyAndShareAllowed) {
ItemAction(stringResource(MR.strings.share_verb), painterResource(MR.images.ic_share), onClick = {
var fileSource = getLoadedFileSource(cItem.file)
val shareIfExists = {
when (val f = fileSource) {
null -> clipboard.shareText(cItem.content.text)
else -> shareFile(cItem.text, f)
}
showMenu.value = false
}
if (chatModel.connectedToRemote() && fileSource == null) {
withBGApi {
cItem.file?.loadRemoteFile(true)
fileSource = getLoadedFileSource(cItem.file)
shareIfExists()
}
} else shareIfExists()
})
}
if (copyAndShareAllowed) {
ItemAction(stringResource(MR.strings.copy_verb), painterResource(MR.images.ic_content_copy), onClick = {
copyItemToClipboard(cItem, clipboard)
showMenu.value = false
})
}
if ((cItem.content.msgContent is MsgContent.MCImage || cItem.content.msgContent is MsgContent.MCVideo || cItem.content.msgContent is MsgContent.MCFile || cItem.content.msgContent is MsgContent.MCVoice) && (getLoadedFilePath(cItem.file) != null || (chatModel.connectedToRemote() && !cachedRemoteReqs.contains(cItem.file?.fileSource)))) {
SaveContentItemAction(cItem, saveFileLauncher, showMenu)
}
if (cItem.meta.editable && cItem.content.msgContent !is MsgContent.MCVoice && !live) {
@@ -590,7 +605,7 @@ private fun ShrinkItemAction(revealed: MutableState<Boolean>, showMenu: MutableS
}
@Composable
fun ItemAction(text: String, icon: Painter, onClick: () -> Unit, color: Color = Color.Unspecified) {
fun ItemAction(text: String, icon: Painter, color: Color = Color.Unspecified, onClick: () -> Unit) {
val finalColor = if (color == Color.Unspecified) {
if (isInDarkTheme()) MenuTextColorDark else Color.Black
} else color
@@ -62,7 +62,7 @@ fun ChatListNavLinkView(chat: Chat, chatModel: ChatModel) {
val contactNetworkStatus = chatModel.contactNetworkStatus(chat.chatInfo.contact)
ChatListNavLinkLayout(
chatLinkPreview = { ChatPreviewView(chat, showChatPreviews, chatModel.draft.value, chatModel.draftChatId.value, chatModel.currentUser.value?.profile?.displayName, contactNetworkStatus, stopped, linkMode, inProgress = false, progressByTimeout = false) },
click = { directChatAction(chat.chatInfo.contact, chatModel) },
click = { directChatAction(chat.remoteHostId, chat.chatInfo.contact, chatModel) },
dropdownMenuItems = { ContactMenuItems(chat, chat.chatInfo.contact, chatModel, showMenu, showMarkRead) },
showMenu,
stopped,
@@ -72,7 +72,7 @@ fun ChatListNavLinkView(chat: Chat, chatModel: ChatModel) {
is ChatInfo.Group ->
ChatListNavLinkLayout(
chatLinkPreview = { ChatPreviewView(chat, showChatPreviews, chatModel.draft.value, chatModel.draftChatId.value, chatModel.currentUser.value?.profile?.displayName, null, stopped, linkMode, inProgress.value, progressByTimeout) },
click = { if (!inProgress.value) groupChatAction(chat.chatInfo.groupInfo, chatModel, inProgress) },
click = { if (!inProgress.value) groupChatAction(chat.remoteHostId, chat.chatInfo.groupInfo, chatModel, inProgress) },
dropdownMenuItems = { GroupMenuItems(chat, chat.chatInfo.groupInfo, chatModel, showMenu, inProgress, showMarkRead) },
showMenu,
stopped,
@@ -81,8 +81,8 @@ fun ChatListNavLinkView(chat: Chat, chatModel: ChatModel) {
is ChatInfo.ContactRequest ->
ChatListNavLinkLayout(
chatLinkPreview = { ContactRequestView(chat.chatInfo) },
click = { contactRequestAlertDialog(chat.chatInfo, chatModel) },
dropdownMenuItems = { ContactRequestMenuItems(chat.chatInfo, chatModel, showMenu) },
click = { contactRequestAlertDialog(chat.remoteHostId, chat.chatInfo, chatModel) },
dropdownMenuItems = { ContactRequestMenuItems(chat.remoteHostId, chat.chatInfo, chatModel, showMenu) },
showMenu,
stopped,
selectedChat
@@ -94,10 +94,10 @@ fun ChatListNavLinkView(chat: Chat, chatModel: ChatModel) {
ModalManager.center.closeModals()
ModalManager.end.closeModals()
ModalManager.center.showModalCloseable(true, showClose = appPlatform.isAndroid) { close ->
ContactConnectionInfoView(chatModel, chat.chatInfo.contactConnection.connReqInv, chat.chatInfo.contactConnection, false, close)
ContactConnectionInfoView(chatModel, chat.remoteHostId, chat.chatInfo.contactConnection.connReqInv, chat.chatInfo.contactConnection, false, close)
}
},
dropdownMenuItems = { ContactConnectionMenuItems(chat.chatInfo, chatModel, showMenu) },
dropdownMenuItems = { ContactConnectionMenuItems(chat.remoteHostId, chat.chatInfo, chatModel, showMenu) },
showMenu,
stopped,
selectedChat
@@ -119,38 +119,38 @@ fun ChatListNavLinkView(chat: Chat, chatModel: ChatModel) {
}
}
fun directChatAction(contact: Contact, chatModel: ChatModel) {
fun directChatAction(rhId: Long?, contact: Contact, chatModel: ChatModel) {
when {
contact.activeConn == null && contact.profile.contactLink != null -> askCurrentOrIncognitoProfileConnectContactViaAddress(chatModel, contact, close = null, openChat = true)
else -> withBGApi { openChat(ChatInfo.Direct(contact), chatModel) }
contact.activeConn == null && contact.profile.contactLink != null -> askCurrentOrIncognitoProfileConnectContactViaAddress(chatModel, rhId, contact, close = null, openChat = true)
else -> withBGApi { openChat(rhId, ChatInfo.Direct(contact), chatModel) }
}
}
fun groupChatAction(groupInfo: GroupInfo, chatModel: ChatModel, inProgress: MutableState<Boolean>? = null) {
fun groupChatAction(rhId: Long?, groupInfo: GroupInfo, chatModel: ChatModel, inProgress: MutableState<Boolean>? = null) {
when (groupInfo.membership.memberStatus) {
GroupMemberStatus.MemInvited -> acceptGroupInvitationAlertDialog(groupInfo, chatModel, inProgress)
GroupMemberStatus.MemInvited -> acceptGroupInvitationAlertDialog(rhId, groupInfo, chatModel, inProgress)
GroupMemberStatus.MemAccepted -> groupInvitationAcceptedAlert()
else -> withBGApi { openChat(ChatInfo.Group(groupInfo), chatModel) }
else -> withBGApi { openChat(rhId, ChatInfo.Group(groupInfo), chatModel) }
}
}
suspend fun openDirectChat(contactId: Long, chatModel: ChatModel) {
val chat = chatModel.controller.apiGetChat(ChatType.Direct, contactId)
suspend fun openDirectChat(rhId: Long?, contactId: Long, chatModel: ChatModel) {
val chat = chatModel.controller.apiGetChat(rhId, ChatType.Direct, contactId)
if (chat != null) {
openLoadedChat(chat, chatModel)
}
}
suspend fun openGroupChat(groupId: Long, chatModel: ChatModel) {
val chat = chatModel.controller.apiGetChat(ChatType.Group, groupId)
suspend fun openGroupChat(rhId: Long?, groupId: Long, chatModel: ChatModel) {
val chat = chatModel.controller.apiGetChat(rhId, ChatType.Group, groupId)
if (chat != null) {
openLoadedChat(chat, chatModel)
}
}
suspend fun openChat(chatInfo: ChatInfo, chatModel: ChatModel) {
suspend fun openChat(rhId: Long?, chatInfo: ChatInfo, chatModel: ChatModel) {
Log.d(TAG, "TODOCHAT: openChat: opening ${chatInfo.id}, current chatId ${ChatModel.chatId.value}, size ${ChatModel.chatItems.size}")
val chat = chatModel.controller.apiGetChat(chatInfo.chatType, chatInfo.apiId)
val chat = chatModel.controller.apiGetChat(rhId, chatInfo.chatType, chatInfo.apiId)
if (chat != null) {
openLoadedChat(chat, chatModel)
Log.d(TAG, "TODOCHAT: openChat: opened ${chatInfo.id}, current chatId ${ChatModel.chatId.value}, size ${ChatModel.chatItems.size}")
@@ -164,22 +164,24 @@ fun openLoadedChat(chat: Chat, chatModel: ChatModel) {
chatModel.chatId.value = chat.chatInfo.id
}
suspend fun apiLoadPrevMessages(chatInfo: ChatInfo, chatModel: ChatModel, beforeChatItemId: Long, search: String) {
suspend fun apiLoadPrevMessages(ch: Chat, chatModel: ChatModel, beforeChatItemId: Long, search: String) {
val chatInfo = ch.chatInfo
val pagination = ChatPagination.Before(beforeChatItemId, ChatPagination.PRELOAD_COUNT)
val chat = chatModel.controller.apiGetChat(chatInfo.chatType, chatInfo.apiId, pagination, search) ?: return
val chat = chatModel.controller.apiGetChat(ch.remoteHostId, chatInfo.chatType, chatInfo.apiId, pagination, search) ?: return
if (chatModel.chatId.value != chat.id) return
chatModel.chatItems.addAll(0, chat.chatItems)
}
suspend fun apiFindMessages(chatInfo: ChatInfo, chatModel: ChatModel, search: String) {
val chat = chatModel.controller.apiGetChat(chatInfo.chatType, chatInfo.apiId, search = search) ?: return
suspend fun apiFindMessages(ch: Chat, chatModel: ChatModel, search: String) {
val chatInfo = ch.chatInfo
val chat = chatModel.controller.apiGetChat(ch.remoteHostId, chatInfo.chatType, chatInfo.apiId, search = search) ?: return
if (chatModel.chatId.value != chat.id) return
chatModel.chatItems.clear()
chatModel.chatItems.addAll(0, chat.chatItems)
}
suspend fun setGroupMembers(groupInfo: GroupInfo, chatModel: ChatModel) {
val groupMembers = chatModel.controller.apiListMembers(groupInfo.groupId)
suspend fun setGroupMembers(rhId: Long?, groupInfo: GroupInfo, chatModel: ChatModel) {
val groupMembers = chatModel.controller.apiListMembers(rhId, groupInfo.groupId)
val currentMembers = chatModel.groupMembers
val newMembers = groupMembers.map { newMember ->
val currentMember = currentMembers.find { it.id == newMember.id }
@@ -230,7 +232,7 @@ fun GroupMenuItems(
}
GroupMemberStatus.MemAccepted -> {
if (groupInfo.membership.memberCurrent) {
LeaveGroupAction(groupInfo, chatModel, showMenu)
LeaveGroupAction(chat.remoteHostId, groupInfo, chatModel, showMenu)
}
if (groupInfo.canDelete) {
DeleteGroupAction(chat, groupInfo, chatModel, showMenu)
@@ -246,7 +248,7 @@ fun GroupMenuItems(
ToggleNotificationsChatAction(chat, chatModel, chat.chatInfo.ntfsEnabled, showMenu)
ClearChatAction(chat, chatModel, showMenu)
if (groupInfo.membership.memberCurrent) {
LeaveGroupAction(groupInfo, chatModel, showMenu)
LeaveGroupAction(chat.remoteHostId, groupInfo, chatModel, showMenu)
}
if (groupInfo.canDelete) {
DeleteGroupAction(chat, groupInfo, chatModel, showMenu)
@@ -310,7 +312,7 @@ fun ClearChatAction(chat: Chat, chatModel: ChatModel, showMenu: MutableState<Boo
stringResource(MR.strings.clear_chat_menu_action),
painterResource(MR.images.ic_settings_backup_restore),
onClick = {
clearChatDialog(chat.chatInfo, chatModel)
clearChatDialog(chat, chatModel)
showMenu.value = false
},
color = WarningOrange
@@ -323,7 +325,7 @@ fun DeleteContactAction(chat: Chat, chatModel: ChatModel, showMenu: MutableState
stringResource(MR.strings.delete_contact_menu_action),
painterResource(MR.images.ic_delete),
onClick = {
deleteContactDialog(chat.chatInfo, chatModel)
deleteContactDialog(chat, chatModel)
showMenu.value = false
},
color = Color.Red
@@ -336,7 +338,7 @@ fun DeleteGroupAction(chat: Chat, groupInfo: GroupInfo, chatModel: ChatModel, sh
stringResource(MR.strings.delete_group_menu_action),
painterResource(MR.images.ic_delete),
onClick = {
deleteGroupDialog(chat.chatInfo, groupInfo, chatModel)
deleteGroupDialog(chat, groupInfo, chatModel)
showMenu.value = false
},
color = Color.Red
@@ -354,7 +356,7 @@ fun JoinGroupAction(
val joinGroup: () -> Unit = {
withApi {
inProgress.value = true
chatModel.controller.apiJoinGroup(groupInfo.groupId)
chatModel.controller.apiJoinGroup(chat.remoteHostId, groupInfo.groupId)
inProgress.value = false
}
}
@@ -370,12 +372,12 @@ fun JoinGroupAction(
}
@Composable
fun LeaveGroupAction(groupInfo: GroupInfo, chatModel: ChatModel, showMenu: MutableState<Boolean>) {
fun LeaveGroupAction(rhId: Long?, groupInfo: GroupInfo, chatModel: ChatModel, showMenu: MutableState<Boolean>) {
ItemAction(
stringResource(MR.strings.leave_group_button),
painterResource(MR.images.ic_logout),
onClick = {
leaveGroupDialog(groupInfo, chatModel)
leaveGroupDialog(rhId, groupInfo, chatModel)
showMenu.value = false
},
color = Color.Red
@@ -383,13 +385,13 @@ fun LeaveGroupAction(groupInfo: GroupInfo, chatModel: ChatModel, showMenu: Mutab
}
@Composable
fun ContactRequestMenuItems(chatInfo: ChatInfo.ContactRequest, chatModel: ChatModel, showMenu: MutableState<Boolean>) {
fun ContactRequestMenuItems(rhId: Long?, chatInfo: ChatInfo.ContactRequest, chatModel: ChatModel, showMenu: MutableState<Boolean>) {
ItemAction(
stringResource(MR.strings.accept_contact_button),
painterResource(MR.images.ic_check),
color = MaterialTheme.colors.onBackground,
onClick = {
acceptContactRequest(incognito = false, chatInfo.apiId, chatInfo, true, chatModel)
acceptContactRequest(rhId, incognito = false, chatInfo.apiId, chatInfo, true, chatModel)
showMenu.value = false
}
)
@@ -398,7 +400,7 @@ fun ContactRequestMenuItems(chatInfo: ChatInfo.ContactRequest, chatModel: ChatMo
painterResource(MR.images.ic_theater_comedy),
color = MaterialTheme.colors.onBackground,
onClick = {
acceptContactRequest(incognito = true, chatInfo.apiId, chatInfo, true, chatModel)
acceptContactRequest(rhId, incognito = true, chatInfo.apiId, chatInfo, true, chatModel)
showMenu.value = false
}
)
@@ -406,7 +408,7 @@ fun ContactRequestMenuItems(chatInfo: ChatInfo.ContactRequest, chatModel: ChatMo
stringResource(MR.strings.reject_contact_button),
painterResource(MR.images.ic_close),
onClick = {
rejectContactRequest(chatInfo, chatModel)
rejectContactRequest(rhId, chatInfo, chatModel)
showMenu.value = false
},
color = Color.Red
@@ -414,7 +416,7 @@ fun ContactRequestMenuItems(chatInfo: ChatInfo.ContactRequest, chatModel: ChatMo
}
@Composable
fun ContactConnectionMenuItems(chatInfo: ChatInfo.ContactConnection, chatModel: ChatModel, showMenu: MutableState<Boolean>) {
fun ContactConnectionMenuItems(rhId: Long?, chatInfo: ChatInfo.ContactConnection, chatModel: ChatModel, showMenu: MutableState<Boolean>) {
ItemAction(
stringResource(MR.strings.set_contact_name),
painterResource(MR.images.ic_edit),
@@ -422,7 +424,7 @@ fun ContactConnectionMenuItems(chatInfo: ChatInfo.ContactConnection, chatModel:
ModalManager.center.closeModals()
ModalManager.end.closeModals()
ModalManager.center.showModalCloseable(true, showClose = appPlatform.isAndroid) { close ->
ContactConnectionInfoView(chatModel, chatInfo.contactConnection.connReqInv, chatInfo.contactConnection, true, close)
ContactConnectionInfoView(chatModel, rhId, chatInfo.contactConnection.connReqInv, chatInfo.contactConnection, true, close)
}
showMenu.value = false
},
@@ -431,7 +433,7 @@ fun ContactConnectionMenuItems(chatInfo: ChatInfo.ContactConnection, chatModel:
stringResource(MR.strings.delete_verb),
painterResource(MR.images.ic_delete),
onClick = {
deleteContactConnectionAlert(chatInfo.contactConnection, chatModel) {
deleteContactConnectionAlert(rhId, chatInfo.contactConnection, chatModel) {
if (chatModel.chatId.value == null) {
ModalManager.center.closeModals()
ModalManager.end.closeModals()
@@ -471,8 +473,9 @@ fun markChatRead(c: Chat, chatModel: ChatModel) {
withApi {
if (chat.chatStats.unreadCount > 0) {
val minUnreadItemId = chat.chatStats.minUnreadItemId
chatModel.markChatItemsRead(chat.chatInfo)
chatModel.markChatItemsRead(chat)
chatModel.controller.apiChatRead(
chat.remoteHostId,
chat.chatInfo.chatType,
chat.chatInfo.apiId,
CC.ItemRange(minUnreadItemId, chat.chatItems.last().id)
@@ -481,12 +484,13 @@ fun markChatRead(c: Chat, chatModel: ChatModel) {
}
if (chat.chatStats.unreadChat) {
val success = chatModel.controller.apiChatUnread(
chat.remoteHostId,
chat.chatInfo.chatType,
chat.chatInfo.apiId,
false
)
if (success) {
chatModel.replaceChat(chat.id, chat.copy(chatStats = chat.chatStats.copy(unreadChat = false)))
chatModel.replaceChat(chat.remoteHostId, chat.id, chat.copy(chatStats = chat.chatStats.copy(unreadChat = false)))
}
}
}
@@ -498,17 +502,18 @@ fun markChatUnread(chat: Chat, chatModel: ChatModel) {
withApi {
val success = chatModel.controller.apiChatUnread(
chat.remoteHostId,
chat.chatInfo.chatType,
chat.chatInfo.apiId,
true
)
if (success) {
chatModel.replaceChat(chat.id, chat.copy(chatStats = chat.chatStats.copy(unreadChat = true)))
chatModel.replaceChat(chat.remoteHostId, chat.id, chat.copy(chatStats = chat.chatStats.copy(unreadChat = true)))
}
}
}
fun contactRequestAlertDialog(contactRequest: ChatInfo.ContactRequest, chatModel: ChatModel) {
fun contactRequestAlertDialog(rhId: Long?, contactRequest: ChatInfo.ContactRequest, chatModel: ChatModel) {
AlertManager.shared.showAlertDialogButtonsColumn(
title = generalGetString(MR.strings.accept_connection_request__question),
text = AnnotatedString(generalGetString(MR.strings.if_you_choose_to_reject_the_sender_will_not_be_notified)),
@@ -516,19 +521,19 @@ fun contactRequestAlertDialog(contactRequest: ChatInfo.ContactRequest, chatModel
Column {
SectionItemView({
AlertManager.shared.hideAlert()
acceptContactRequest(incognito = false, contactRequest.apiId, contactRequest, true, chatModel)
acceptContactRequest(rhId, incognito = false, contactRequest.apiId, contactRequest, true, chatModel)
}) {
Text(generalGetString(MR.strings.accept_contact_button), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.primary)
}
SectionItemView({
AlertManager.shared.hideAlert()
acceptContactRequest(incognito = true, contactRequest.apiId, contactRequest, true, chatModel)
acceptContactRequest(rhId, incognito = true, contactRequest.apiId, contactRequest, true, chatModel)
}) {
Text(generalGetString(MR.strings.accept_contact_incognito_button), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.primary)
}
SectionItemView({
AlertManager.shared.hideAlert()
rejectContactRequest(contactRequest, chatModel)
rejectContactRequest(rhId, contactRequest, chatModel)
}) {
Text(generalGetString(MR.strings.reject_contact_button), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = Color.Red)
}
@@ -537,24 +542,24 @@ fun contactRequestAlertDialog(contactRequest: ChatInfo.ContactRequest, chatModel
)
}
fun acceptContactRequest(incognito: Boolean, apiId: Long, contactRequest: ChatInfo.ContactRequest?, isCurrentUser: Boolean, chatModel: ChatModel) {
fun acceptContactRequest(rhId: Long?, incognito: Boolean, apiId: Long, contactRequest: ChatInfo.ContactRequest?, isCurrentUser: Boolean, chatModel: ChatModel) {
withApi {
val contact = chatModel.controller.apiAcceptContactRequest(incognito, apiId)
val contact = chatModel.controller.apiAcceptContactRequest(rhId, incognito, apiId)
if (contact != null && isCurrentUser && contactRequest != null) {
val chat = Chat(ChatInfo.Direct(contact), listOf())
chatModel.replaceChat(contactRequest.id, chat)
val chat = Chat(remoteHostId = rhId, ChatInfo.Direct(contact), listOf())
chatModel.replaceChat(rhId, contactRequest.id, chat)
}
}
}
fun rejectContactRequest(contactRequest: ChatInfo.ContactRequest, chatModel: ChatModel) {
fun rejectContactRequest(rhId: Long?, contactRequest: ChatInfo.ContactRequest, chatModel: ChatModel) {
withApi {
chatModel.controller.apiRejectContactRequest(contactRequest.apiId)
chatModel.removeChat(contactRequest.id)
chatModel.controller.apiRejectContactRequest(rhId, contactRequest.apiId)
chatModel.removeChat(rhId, contactRequest.id)
}
}
fun deleteContactConnectionAlert(connection: PendingContactConnection, chatModel: ChatModel, onSuccess: () -> Unit) {
fun deleteContactConnectionAlert(rhId: Long?, connection: PendingContactConnection, chatModel: ChatModel, onSuccess: () -> Unit) {
AlertManager.shared.showAlertDialog(
title = generalGetString(MR.strings.delete_pending_connection__question),
text = generalGetString(
@@ -565,8 +570,8 @@ fun deleteContactConnectionAlert(connection: PendingContactConnection, chatModel
onConfirm = {
withApi {
AlertManager.shared.hideAlert()
if (chatModel.controller.apiDeleteChat(ChatType.ContactConnection, connection.apiId)) {
chatModel.removeChat(connection.id)
if (chatModel.controller.apiDeleteChat(rhId, ChatType.ContactConnection, connection.apiId)) {
chatModel.removeChat(rhId, connection.id)
onSuccess()
}
}
@@ -575,16 +580,17 @@ fun deleteContactConnectionAlert(connection: PendingContactConnection, chatModel
)
}
fun pendingContactAlertDialog(chatInfo: ChatInfo, chatModel: ChatModel) {
// TODO why is it not used
fun pendingContactAlertDialog(rhId: Long?, chatInfo: ChatInfo, chatModel: ChatModel) {
AlertManager.shared.showAlertDialog(
title = generalGetString(MR.strings.alert_title_contact_connection_pending),
text = generalGetString(MR.strings.alert_text_connection_pending_they_need_to_be_online_can_delete_and_retry),
confirmText = generalGetString(MR.strings.button_delete_contact),
onConfirm = {
withApi {
val r = chatModel.controller.apiDeleteChat(chatInfo.chatType, chatInfo.apiId)
val r = chatModel.controller.apiDeleteChat(rhId, chatInfo.chatType, chatInfo.apiId)
if (r) {
chatModel.removeChat(chatInfo.id)
chatModel.removeChat(rhId, chatInfo.id)
if (chatModel.chatId.value == chatInfo.id) {
chatModel.chatId.value = null
ModalManager.end.closeModals()
@@ -599,6 +605,7 @@ fun pendingContactAlertDialog(chatInfo: ChatInfo, chatModel: ChatModel) {
fun askCurrentOrIncognitoProfileConnectContactViaAddress(
chatModel: ChatModel,
rhId: Long?,
contact: Contact,
close: (() -> Unit)?,
openChat: Boolean
@@ -611,9 +618,9 @@ fun askCurrentOrIncognitoProfileConnectContactViaAddress(
AlertManager.shared.hideAlert()
withApi {
close?.invoke()
val ok = connectContactViaAddress(chatModel, contact.contactId, incognito = false)
val ok = connectContactViaAddress(chatModel, rhId, contact.contactId, incognito = false)
if (ok && openChat) {
openDirectChat(contact.contactId, chatModel)
openDirectChat(rhId, contact.contactId, chatModel)
}
}
}) {
@@ -623,9 +630,9 @@ fun askCurrentOrIncognitoProfileConnectContactViaAddress(
AlertManager.shared.hideAlert()
withApi {
close?.invoke()
val ok = connectContactViaAddress(chatModel, contact.contactId, incognito = true)
val ok = connectContactViaAddress(chatModel, rhId, contact.contactId, incognito = true)
if (ok && openChat) {
openDirectChat(contact.contactId, chatModel)
openDirectChat(rhId, contact.contactId, chatModel)
}
}
}) {
@@ -641,10 +648,10 @@ fun askCurrentOrIncognitoProfileConnectContactViaAddress(
)
}
suspend fun connectContactViaAddress(chatModel: ChatModel, contactId: Long, incognito: Boolean): Boolean {
val contact = chatModel.controller.apiConnectContactViaAddress(incognito, contactId)
suspend fun connectContactViaAddress(chatModel: ChatModel, rhId: Long?, contactId: Long, incognito: Boolean): Boolean {
val contact = chatModel.controller.apiConnectContactViaAddress(rhId, incognito, contactId)
if (contact != null) {
chatModel.updateContact(contact)
chatModel.updateContact(rhId, contact)
AlertManager.shared.showAlertMsg(
title = generalGetString(MR.strings.connection_request_sent),
text = generalGetString(MR.strings.you_will_be_connected_when_your_connection_request_is_accepted)
@@ -654,7 +661,7 @@ suspend fun connectContactViaAddress(chatModel: ChatModel, contactId: Long, inco
return false
}
fun acceptGroupInvitationAlertDialog(groupInfo: GroupInfo, chatModel: ChatModel, inProgress: MutableState<Boolean>? = null) {
fun acceptGroupInvitationAlertDialog(rhId: Long?, groupInfo: GroupInfo, chatModel: ChatModel, inProgress: MutableState<Boolean>? = null) {
AlertManager.shared.showAlertDialog(
title = generalGetString(MR.strings.join_group_question),
text = generalGetString(MR.strings.you_are_invited_to_group_join_to_connect_with_group_members),
@@ -662,12 +669,12 @@ fun acceptGroupInvitationAlertDialog(groupInfo: GroupInfo, chatModel: ChatModel,
onConfirm = {
withApi {
inProgress?.value = true
chatModel.controller.apiJoinGroup(groupInfo.groupId)
chatModel.controller.apiJoinGroup(rhId, groupInfo.groupId)
inProgress?.value = false
}
},
dismissText = generalGetString(MR.strings.delete_verb),
onDismiss = { deleteGroup(groupInfo, chatModel) }
onDismiss = { deleteGroup(rhId, groupInfo, chatModel) }
)
}
@@ -679,11 +686,11 @@ fun cantInviteIncognitoAlert() {
)
}
fun deleteGroup(groupInfo: GroupInfo, chatModel: ChatModel) {
fun deleteGroup(rhId: Long?, groupInfo: GroupInfo, chatModel: ChatModel) {
withApi {
val r = chatModel.controller.apiDeleteChat(ChatType.Group, groupInfo.apiId)
val r = chatModel.controller.apiDeleteChat(rhId, ChatType.Group, groupInfo.apiId)
if (r) {
chatModel.removeChat(groupInfo.id)
chatModel.removeChat(rhId, groupInfo.id)
if (chatModel.chatId.value == groupInfo.id) {
chatModel.chatId.value = null
ModalManager.end.closeModals()
@@ -723,15 +730,15 @@ fun updateChatSettings(chat: Chat, chatSettings: ChatSettings, chatModel: ChatMo
withApi {
val res = when (newChatInfo) {
is ChatInfo.Direct -> with(newChatInfo) {
chatModel.controller.apiSetSettings(chatType, apiId, contact.chatSettings)
chatModel.controller.apiSetSettings(chat.remoteHostId, chatType, apiId, contact.chatSettings)
}
is ChatInfo.Group -> with(newChatInfo) {
chatModel.controller.apiSetSettings(chatType, apiId, groupInfo.chatSettings)
chatModel.controller.apiSetSettings(chat.remoteHostId, chatType, apiId, groupInfo.chatSettings)
}
else -> false
}
if (res && newChatInfo != null) {
chatModel.updateChatInfo(newChatInfo)
chatModel.updateChatInfo(chat.remoteHostId, newChatInfo)
if (chatSettings.enableNtfs != MsgFilter.All) {
ntfManager.cancelNotificationsForChat(chat.id)
}
@@ -765,6 +772,7 @@ fun PreviewChatListNavLinkDirect() {
chatLinkPreview = {
ChatPreviewView(
chat = Chat(
remoteHostId = null,
chatInfo = ChatInfo.Direct.sampleData,
chatItems = listOf(
ChatItem.getSampleData(
@@ -808,6 +816,7 @@ fun PreviewChatListNavLinkGroup() {
chatLinkPreview = {
ChatPreviewView(
Chat(
remoteHostId = null,
chatInfo = ChatInfo.Group.sampleData,
chatItems = listOf(
ChatItem.getSampleData(
@@ -1,6 +1,5 @@
package chat.simplex.common.views.chatlist
import SectionItemView
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.*
@@ -9,30 +8,22 @@ import androidx.compose.foundation.shape.RoundedCornerShape
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.draw.clip
import androidx.compose.ui.graphics.*
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.text.AnnotatedString
import dev.icerock.moko.resources.compose.painterResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
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.views.usersettings.simplexTeamUri
import chat.simplex.common.platform.*
import chat.simplex.common.views.call.Call
import chat.simplex.common.views.call.CallMediaType
import chat.simplex.common.views.chat.item.ItemAction
import chat.simplex.common.views.newchat.*
import chat.simplex.res.MR
import kotlinx.coroutines.*
@@ -62,7 +53,7 @@ fun ChatListView(chatModel: ChatModel, settingsState: SettingsViewState, setPerf
val url = chatModel.appOpenUrl.value
if (url != null) {
chatModel.appOpenUrl.value = null
connectIfOpenedViaUri(url, chatModel)
connectIfOpenedViaUri(chatModel.remoteHostId, url, chatModel)
}
}
if (appPlatform.isDesktop) {
@@ -77,7 +68,7 @@ fun ChatListView(chatModel: ChatModel, settingsState: SettingsViewState, setPerf
val endPadding = if (appPlatform.isDesktop) 56.dp else 0.dp
var searchInList by rememberSaveable { mutableStateOf("") }
val scope = rememberCoroutineScope()
val (userPickerState, scaffoldState, switchingUsers ) = settingsState
val (userPickerState, scaffoldState, switchingUsersAndHosts ) = settingsState
Scaffold(topBar = { Box(Modifier.padding(end = endPadding)) { ChatListToolbar(chatModel, scaffoldState.drawerState, userPickerState, stopped) { searchInList = it.trim() } } },
scaffoldState = scaffoldState,
drawerContent = { SettingsView(chatModel, setPerformLA, scaffoldState.drawerState) },
@@ -113,7 +104,7 @@ fun ChatListView(chatModel: ChatModel, settingsState: SettingsViewState, setPerf
) {
if (chatModel.chats.isNotEmpty()) {
ChatList(chatModel, search = searchInList)
} else if (!switchingUsers.value) {
} else if (!switchingUsersAndHosts.value) {
Box(Modifier.fillMaxSize()) {
if (!stopped && !newChatSheetState.collectAsState().value.isVisible()) {
OnboardingButtons(showNewChatSheet)
@@ -126,14 +117,16 @@ fun ChatListView(chatModel: ChatModel, settingsState: SettingsViewState, setPerf
}
if (searchInList.isEmpty()) {
DesktopActiveCallOverlayLayout(newChatSheetState)
// TODO disable this button and sheet for the duration of the switch
NewChatSheet(chatModel, newChatSheetState, stopped, hideNewChatSheet)
}
if (appPlatform.isAndroid) {
UserPicker(chatModel, userPickerState, switchingUsers) {
UserPicker(chatModel, userPickerState, switchingUsersAndHosts) {
scope.launch { if (scaffoldState.drawerState.isOpen) scaffoldState.drawerState.close() else scaffoldState.drawerState.open() }
userPickerState.value = AnimatedViewState.GONE
}
}
if (switchingUsers.value) {
if (switchingUsersAndHosts.value) {
Box(
Modifier.fillMaxSize().clickable(enabled = false, onClick = {}),
contentAlignment = Alignment.Center
@@ -224,7 +217,7 @@ private fun ChatListToolbar(chatModel: ChatModel, drawerState: DrawerState, user
.filter { u -> !u.user.activeUser && !u.user.hidden }
.all { u -> u.unreadCount == 0 }
UserProfileButton(chatModel.currentUser.value?.profile?.image, allRead) {
if (users.size == 1) {
if (users.size == 1 && chatModel.remoteHosts.isEmpty()) {
scope.launch { drawerState.open() }
} else {
userPickerState.value = AnimatedViewState.VISIBLE
@@ -254,14 +247,25 @@ private fun ChatListToolbar(chatModel: ChatModel, drawerState: DrawerState, user
@Composable
fun UserProfileButton(image: String?, allRead: Boolean, onButtonClicked: () -> Unit) {
IconButton(onClick = onButtonClicked) {
Box {
ProfileImage(
image = image,
size = 37.dp
)
if (!allRead) {
unreadBadge()
Row(verticalAlignment = Alignment.CenterVertically) {
IconButton(onClick = onButtonClicked) {
Box {
ProfileImage(
image = image,
size = 37.dp
)
if (!allRead) {
unreadBadge()
}
}
}
if (appPlatform.isDesktop) {
val h by remember { chatModel.currentRemoteHost }
if (h != null) {
Spacer(Modifier.width(12.dp))
HostDisconnectButton {
stopRemoteHostAndReloadHosts(h!!, true)
}
}
}
}
@@ -314,13 +318,13 @@ private fun ProgressIndicator() {
@Composable
expect fun DesktopActiveCallOverlayLayout(newChatSheetState: MutableStateFlow<AnimatedViewState>)
fun connectIfOpenedViaUri(uri: URI, chatModel: ChatModel) {
fun connectIfOpenedViaUri(rhId: Long?, uri: URI, chatModel: ChatModel) {
Log.d(TAG, "connectIfOpenedViaUri: opened via link")
if (chatModel.currentUser.value == null) {
chatModel.appOpenUrl.value = uri
} else {
withApi {
planAndConnect(chatModel, uri, incognito = null, close = null)
planAndConnect(chatModel, rhId, uri, incognito = null, close = null)
}
}
}
@@ -20,13 +20,13 @@ fun ShareListNavLinkView(chat: Chat, chatModel: ChatModel) {
is ChatInfo.Direct ->
ShareListNavLinkLayout(
chatLinkPreview = { SharePreviewView(chat) },
click = { directChatAction(chat.chatInfo.contact, chatModel) },
click = { directChatAction(chat.remoteHostId, chat.chatInfo.contact, chatModel) },
stopped
)
is ChatInfo.Group ->
ShareListNavLinkLayout(
chatLinkPreview = { SharePreviewView(chat) },
click = { groupChatAction(chat.chatInfo.groupInfo, chatModel) },
click = { groupChatAction(chat.remoteHostId, chat.chatInfo.groupInfo, chatModel) },
stopped
)
is ChatInfo.ContactRequest, is ChatInfo.ContactConnection, is ChatInfo.InvalidJSON -> {}
@@ -26,7 +26,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
@Composable
fun ShareListView(chatModel: ChatModel, settingsState: SettingsViewState, stopped: Boolean) {
var searchInList by rememberSaveable { mutableStateOf("") }
val (userPickerState, scaffoldState, switchingUsers) = settingsState
val (userPickerState, scaffoldState, switchingUsersAndHosts) = settingsState
val endPadding = if (appPlatform.isDesktop) 56.dp else 0.dp
Scaffold(
Modifier.padding(end = endPadding),
@@ -47,8 +47,9 @@ fun ShareListView(chatModel: ChatModel, settingsState: SettingsViewState, stoppe
}
}
if (appPlatform.isAndroid) {
UserPicker(chatModel, userPickerState, switchingUsers, showSettings = false, showCancel = true, cancelClicked = {
UserPicker(chatModel, userPickerState, switchingUsersAndHosts, showSettings = false, showCancel = true, cancelClicked = {
chatModel.sharedContent.value = null
userPickerState.value = AnimatedViewState.GONE
})
}
}
@@ -72,7 +73,7 @@ private fun ShareListToolbar(chatModel: ChatModel, userPickerState: MutableState
val navButton: @Composable RowScope.() -> Unit = {
when {
showSearch -> NavigationButtonBack(hideSearchOnBack)
users.size > 1 -> {
users.size > 1 || chatModel.remoteHosts.isNotEmpty() -> {
val allRead = users
.filter { u -> !u.user.activeUser && !u.user.hidden }
.all { u -> u.unreadCount == 0 }
@@ -4,10 +4,12 @@ import SectionItemView
import androidx.compose.animation.core.*
import androidx.compose.foundation.*
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsHoveredAsState
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.*
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.*
import androidx.compose.ui.draw.*
import androidx.compose.ui.graphics.Color
@@ -18,12 +20,16 @@ import androidx.compose.ui.text.capitalize
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.intl.Locale
import androidx.compose.ui.unit.*
import chat.simplex.common.model.*
import chat.simplex.common.model.ChatController.stopRemoteHostAndReloadHosts
import chat.simplex.common.model.ChatModel.controller
import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.helpers.*
import chat.simplex.common.model.ChatModel
import chat.simplex.common.model.User
import chat.simplex.common.platform.*
import chat.simplex.common.views.remote.ConnectDesktopView
import chat.simplex.common.views.remote.connectMobileDevice
import chat.simplex.res.MR
import dev.icerock.moko.resources.compose.stringResource
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
@@ -33,10 +39,11 @@ import kotlin.math.roundToInt
fun UserPicker(
chatModel: ChatModel,
userPickerState: MutableStateFlow<AnimatedViewState>,
switchingUsers: MutableState<Boolean>,
switchingUsersAndHosts: MutableState<Boolean>,
showSettings: Boolean = true,
showCancel: Boolean = false,
cancelClicked: () -> Unit = {},
useFromDesktopClicked: () -> Unit = {},
settingsClicked: () -> Unit = {},
) {
val scope = rememberCoroutineScope()
@@ -53,6 +60,12 @@ fun UserPicker(
.sortedByDescending { it.user.activeUser }
}
}
val remoteHosts by remember {
derivedStateOf {
chatModel.remoteHosts
.sortedBy { it.hostDeviceName }
}
}
val animatedFloat = remember { Animatable(if (newChat.isVisible()) 0f else 1f) }
LaunchedEffect(Unit) {
launch {
@@ -71,7 +84,7 @@ fun UserPicker(
.filter { it }
.collect {
try {
val updatedUsers = chatModel.controller.listUsers().sortedByDescending { it.user.activeUser }
val updatedUsers = chatModel.controller.listUsers(chatModel.remoteHostId).sortedByDescending { it.user.activeUser }
var same = users.size == updatedUsers.size
if (same) {
for (i in 0 until minOf(users.size, updatedUsers.size)) {
@@ -90,8 +103,42 @@ fun UserPicker(
} catch (e: Exception) {
Log.e(TAG, "Error updating users ${e.stackTraceToString()}")
}
if (!appPlatform.isDesktop) return@collect
try {
val updatedHosts = chatModel.controller.listRemoteHosts()?.sortedBy { it.hostDeviceName } ?: emptyList()
if (remoteHosts != updatedHosts) {
chatModel.remoteHosts.clear()
chatModel.remoteHosts.addAll(updatedHosts)
}
} catch (e: Exception) {
Log.e(TAG, "Error updating remote hosts ${e.stackTraceToString()}")
}
}
}
LaunchedEffect(Unit) {
controller.reloadRemoteHosts()
}
val UsersView: @Composable ColumnScope.() -> Unit = {
users.forEach { u ->
UserProfilePickerItem(u.user, u.unreadCount, openSettings = settingsClicked) {
userPickerState.value = AnimatedViewState.HIDING
if (!u.user.activeUser) {
scope.launch {
val job = launch {
delay(500)
switchingUsersAndHosts.value = true
}
ModalManager.closeAllModalsEverywhere()
chatModel.controller.changeActiveUser(u.user.remoteHostId, u.user.userId, null)
job.cancel()
switchingUsersAndHosts.value = false
}
}
}
Divider(Modifier.requiredHeight(1.dp))
if (u.user.activeUser) Divider(Modifier.requiredHeight(0.5.dp))
}
}
val xOffset = with(LocalDensity.current) { 10.dp.roundToPx() }
val maxWidth = with(LocalDensity.current) { windowWidth() * density }
Box(Modifier
@@ -113,48 +160,72 @@ fun UserPicker(
.background(MaterialTheme.colors.surface, RoundedCornerShape(corner = CornerSize(25.dp)))
.clip(RoundedCornerShape(corner = CornerSize(25.dp)))
) {
val currentRemoteHost = remember { chatModel.currentRemoteHost }.value
Column(Modifier.weight(1f).verticalScroll(rememberScrollState())) {
users.forEach { u ->
UserProfilePickerItem(u.user, u.unreadCount, PaddingValues(start = DEFAULT_PADDING_HALF, end = DEFAULT_PADDING), openSettings = {
settingsClicked()
userPickerState.value = AnimatedViewState.GONE
}) {
userPickerState.value = AnimatedViewState.HIDING
if (!u.user.activeUser) {
scope.launch {
val job = launch {
delay(500)
switchingUsers.value = true
}
ModalManager.closeAllModalsEverywhere()
chatModel.controller.changeActiveUser(u.user.userId, null)
job.cancel()
switchingUsers.value = false
}
if (remoteHosts.isNotEmpty()) {
if (currentRemoteHost == null) {
LocalDevicePickerItem(true) {
userPickerState.value = AnimatedViewState.HIDING
switchToLocalDevice()
}
Divider(Modifier.requiredHeight(1.dp))
} else {
val connecting = rememberSaveable { mutableStateOf(false) }
RemoteHostPickerItem(currentRemoteHost,
actionButtonClick = {
userPickerState.value = AnimatedViewState.HIDING
stopRemoteHostAndReloadHosts(currentRemoteHost, true)
}) {
userPickerState.value = AnimatedViewState.HIDING
switchToRemoteHost(currentRemoteHost, switchingUsersAndHosts, connecting)
}
Divider(Modifier.requiredHeight(1.dp))
}
}
UsersView()
if (remoteHosts.isNotEmpty() && currentRemoteHost != null) {
LocalDevicePickerItem(false) {
userPickerState.value = AnimatedViewState.HIDING
switchToLocalDevice()
}
Divider(Modifier.requiredHeight(1.dp))
if (u.user.activeUser) Divider(Modifier.requiredHeight(0.5.dp))
}
remoteHosts.filter { !it.activeHost }.forEach { h ->
val connecting = rememberSaveable { mutableStateOf(false) }
RemoteHostPickerItem(h,
actionButtonClick = {
userPickerState.value = AnimatedViewState.HIDING
stopRemoteHostAndReloadHosts(h, false)
}) {
userPickerState.value = AnimatedViewState.HIDING
switchToRemoteHost(h, switchingUsersAndHosts, connecting)
}
Divider(Modifier.requiredHeight(1.dp))
}
}
if (appPlatform.isAndroid) {
UseFromDesktopPickerItem {
ModalManager.start.showCustomModal { close ->
ConnectDesktopView(close)
}
userPickerState.value = AnimatedViewState.GONE
}
Divider(Modifier.requiredHeight(1.dp))
}
if (showSettings) {
SettingsPickerItem {
settingsClicked()
userPickerState.value = AnimatedViewState.GONE
}
SettingsPickerItem(settingsClicked)
}
if (showCancel) {
CancelPickerItem {
cancelClicked()
userPickerState.value = AnimatedViewState.GONE
}
CancelPickerItem(cancelClicked)
}
}
}
}
@Composable
fun UserProfilePickerItem(u: User, unreadCount: Int = 0, padding: PaddingValues = PaddingValues(start = DEFAULT_PADDING_HALF, end = DEFAULT_PADDING), onLongClick: () -> Unit = {}, openSettings: () -> Unit = {}, onClick: () -> Unit) {
fun UserProfilePickerItem(u: User, unreadCount: Int = 0, onLongClick: () -> Unit = {}, openSettings: () -> Unit = {}, onClick: () -> Unit) {
Row(
Modifier
.fillMaxWidth()
@@ -166,7 +237,7 @@ fun UserProfilePickerItem(u: User, unreadCount: Int = 0, padding: PaddingValues
indication = if (!u.activeUser) LocalIndication.current else null
)
.onRightClick { onLongClick() }
.padding(padding),
.padding(start = DEFAULT_PADDING_HALF, end = DEFAULT_PADDING),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
@@ -219,16 +290,107 @@ fun UserProfileRow(u: User) {
}
}
@Composable
fun RemoteHostPickerItem(h: RemoteHostInfo, onLongClick: () -> Unit = {}, actionButtonClick: () -> Unit = {}, onClick: () -> Unit) {
Row(
Modifier
.fillMaxWidth()
.background(color = if (h.activeHost) MaterialTheme.colors.surface.mixWith(MaterialTheme.colors.onBackground, 0.95f) else Color.Unspecified)
.sizeIn(minHeight = 46.dp)
.combinedClickable(
onClick = onClick,
onLongClick = onLongClick
)
.onRightClick { onLongClick() }
.padding(start = DEFAULT_PADDING_HALF, end = DEFAULT_PADDING),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
RemoteHostRow(h)
if (h.sessionState is RemoteHostSessionState.Connected) {
HostDisconnectButton(actionButtonClick)
} else {
Box(Modifier.size(20.dp))
}
}
}
@Composable
fun RemoteHostRow(h: RemoteHostInfo) {
Row(
Modifier
.widthIn(max = windowWidth() * 0.7f)
.padding(start = 17.dp),
verticalAlignment = Alignment.CenterVertically
) {
Icon(painterResource(MR.images.ic_smartphone_300), h.hostDeviceName, Modifier.size(20.dp), tint = MaterialTheme.colors.onBackground)
Text(
h.hostDeviceName,
modifier = Modifier.padding(start = 26.dp, end = 8.dp),
color = if (h.activeHost) MaterialTheme.colors.onBackground else if (isInDarkTheme()) MenuTextColorDark else Color.Black,
fontSize = 14.sp,
)
}
}
@Composable
fun LocalDevicePickerItem(active: Boolean, onLongClick: () -> Unit = {}, onClick: () -> Unit) {
Row(
Modifier
.fillMaxWidth()
.background(color = if (active) MaterialTheme.colors.surface.mixWith(MaterialTheme.colors.onBackground, 0.95f) else Color.Unspecified)
.sizeIn(minHeight = 46.dp)
.combinedClickable(
onClick = if (active) {{}} else onClick,
onLongClick = onLongClick,
interactionSource = remember { MutableInteractionSource() },
indication = if (!active) LocalIndication.current else null
)
.onRightClick { onLongClick() }
.padding(start = DEFAULT_PADDING_HALF, end = DEFAULT_PADDING),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
LocalDeviceRow(active)
Box(Modifier.size(20.dp))
}
}
@Composable
fun LocalDeviceRow(active: Boolean) {
Row(
Modifier
.widthIn(max = windowWidth() * 0.7f)
.padding(start = 17.dp, end = DEFAULT_PADDING),
verticalAlignment = Alignment.CenterVertically
) {
Icon(painterResource(MR.images.ic_desktop), stringResource(MR.strings.this_device), Modifier.size(20.dp), tint = MaterialTheme.colors.onBackground)
Text(
stringResource(MR.strings.this_device),
modifier = Modifier.padding(start = 26.dp, end = 8.dp),
color = if (active) MaterialTheme.colors.onBackground else if (isInDarkTheme()) MenuTextColorDark else Color.Black,
fontSize = 14.sp,
)
}
}
@Composable
private fun UseFromDesktopPickerItem(onClick: () -> Unit) {
SectionItemView(onClick, padding = PaddingValues(start = DEFAULT_PADDING + 7.dp, end = DEFAULT_PADDING), minHeight = 68.dp) {
val text = generalGetString(MR.strings.settings_section_title_use_from_desktop).lowercase().capitalize(Locale.current)
Icon(painterResource(MR.images.ic_desktop), text, Modifier.size(20.dp), tint = MaterialTheme.colors.onBackground)
Spacer(Modifier.width(DEFAULT_PADDING + 6.dp))
Text(text, color = if (isInDarkTheme()) MenuTextColorDark else Color.Black)
}
}
@Composable
private fun SettingsPickerItem(onClick: () -> Unit) {
SectionItemView(onClick, padding = PaddingValues(start = DEFAULT_PADDING + 7.dp, end = DEFAULT_PADDING), minHeight = 68.dp) {
val text = generalGetString(MR.strings.settings_section_title_settings).lowercase().capitalize(Locale.current)
Icon(painterResource(MR.images.ic_settings), text, Modifier.size(20.dp), tint = MaterialTheme.colors.onBackground)
Spacer(Modifier.width(DEFAULT_PADDING + 6.dp))
Text(
text,
color = if (isInDarkTheme()) MenuTextColorDark else Color.Black,
)
Text(text, color = if (isInDarkTheme()) MenuTextColorDark else Color.Black)
}
}
@@ -238,9 +400,47 @@ private fun CancelPickerItem(onClick: () -> Unit) {
val text = generalGetString(MR.strings.cancel_verb)
Icon(painterResource(MR.images.ic_close), text, Modifier.size(20.dp), tint = MaterialTheme.colors.onBackground)
Spacer(Modifier.width(DEFAULT_PADDING + 6.dp))
Text(
text,
color = if (isInDarkTheme()) MenuTextColorDark else Color.Black,
Text(text, color = if (isInDarkTheme()) MenuTextColorDark else Color.Black)
}
}
@Composable
fun HostDisconnectButton(onClick: (() -> Unit)?) {
val interactionSource = remember { MutableInteractionSource() }
val hovered = interactionSource.collectIsHoveredAsState().value
IconButton(onClick ?: {}, Modifier.requiredSize(20.dp), enabled = onClick != null) {
Icon(
painterResource(if (onClick == null) MR.images.ic_desktop else if (hovered) MR.images.ic_wifi_off else MR.images.ic_wifi),
null,
Modifier.size(20.dp).hoverable(interactionSource),
tint = if (hovered && onClick != null) WarningOrange else MaterialTheme.colors.onBackground
)
}
}
private fun switchToLocalDevice() {
withBGApi {
chatController.switchUIRemoteHost(null)
}
}
private fun switchToRemoteHost(h: RemoteHostInfo, switchingUsersAndHosts: MutableState<Boolean>, connecting: MutableState<Boolean>) {
if (!h.activeHost()) {
withBGApi {
val job = launch {
delay(500)
switchingUsersAndHosts.value = true
}
ModalManager.closeAllModalsEverywhere()
if (h.sessionState != null) {
chatModel.controller.switchUIRemoteHost(h.remoteHostId)
} else {
connectMobileDevice(h, connecting)
}
job.cancel()
switchingUsersAndHosts.value = false
}
} else {
connectMobileDevice(h, connecting)
}
}
@@ -65,6 +65,8 @@ fun DatabaseView(
Box(
Modifier.fillMaxSize(),
) {
val user = m.currentUser.value
val rhId = user?.remoteHostId
DatabaseLayout(
progressIndicator.value,
remember { m.chatRunning }.value != false,
@@ -80,7 +82,7 @@ fun DatabaseView(
chatLastStart,
appFilesCountAndSize,
chatItemTTL,
m.currentUser.value,
user,
m.users,
startChat = { startChat(m, chatLastStart, m.chatDbChanged) },
stopChatAlert = { stopChatAlert(m) },
@@ -91,9 +93,9 @@ fun DatabaseView(
val oldValue = chatItemTTL.value
chatItemTTL.value = it
if (it < oldValue) {
setChatItemTTLAlert(m, chatItemTTL, progressIndicator, appFilesCountAndSize)
setChatItemTTLAlert(m, rhId, chatItemTTL, progressIndicator, appFilesCountAndSize)
} else if (it != oldValue) {
setCiTTL(m, chatItemTTL, progressIndicator, appFilesCountAndSize)
setCiTTL(m, rhId, chatItemTTL, progressIndicator, appFilesCountAndSize)
}
},
showSettingsModal
@@ -265,7 +267,7 @@ fun DatabaseLayout(
}
private fun setChatItemTTLAlert(
m: ChatModel, selectedChatItemTTL: MutableState<ChatItemTTL>,
m: ChatModel, rhId: Long?, selectedChatItemTTL: MutableState<ChatItemTTL>,
progressIndicator: MutableState<Boolean>,
appFilesCountAndSize: MutableState<Pair<Int, Long>>,
) {
@@ -273,7 +275,7 @@ private fun setChatItemTTLAlert(
title = generalGetString(MR.strings.enable_automatic_deletion_question),
text = generalGetString(MR.strings.enable_automatic_deletion_message),
confirmText = generalGetString(MR.strings.delete_messages),
onConfirm = { setCiTTL(m, selectedChatItemTTL, progressIndicator, appFilesCountAndSize) },
onConfirm = { setCiTTL(m, rhId, selectedChatItemTTL, progressIndicator, appFilesCountAndSize) },
onDismiss = { selectedChatItemTTL.value = m.chatItemTTL.value },
destructive = true,
)
@@ -592,6 +594,7 @@ private fun deleteChat(m: ChatModel, progressIndicator: MutableState<Boolean>) {
private fun setCiTTL(
m: ChatModel,
rhId: Long?,
chatItemTTL: MutableState<ChatItemTTL>,
progressIndicator: MutableState<Boolean>,
appFilesCountAndSize: MutableState<Pair<Int, Long>>,
@@ -600,7 +603,7 @@ private fun setCiTTL(
progressIndicator.value = true
withApi {
try {
m.controller.setChatItemTTL(chatItemTTL.value)
m.controller.setChatItemTTL(rhId, chatItemTTL.value)
// Update model on success
m.chatItemTTL.value = chatItemTTL.value
afterSetCiTTL(m, progressIndicator, appFilesCountAndSize)
@@ -623,7 +626,8 @@ private fun afterSetCiTTL(
withApi {
try {
updatingChatsMutex.withLock {
val chats = m.controller.apiGetChats()
// this is using current remote host on purpose - if it changes during update, it will load correct chats
val chats = m.controller.apiGetChats(m.remoteHostId)
m.updateChats(chats)
}
} catch (e: Exception) {
@@ -188,6 +188,25 @@ class AlertManager {
)
}
}
fun showAlertMsgWithProgress(
title: String,
text: String? = null
) {
showAlert {
AlertDialog(
onDismissRequest = this::hideAlert,
title = alertTitle(title),
text = alertText(text),
buttons = {
Box(Modifier.fillMaxWidth().height(72.dp).padding(bottom = DEFAULT_PADDING * 2), contentAlignment = Alignment.Center) {
CircularProgressIndicator(Modifier.size(36.dp).padding(4.dp), color = MaterialTheme.colors.secondary, strokeWidth = 3.dp)
}
}
)
}
}
fun showAlertMsg(
title: StringResource,
text: StringResource? = null,
@@ -12,6 +12,7 @@ import chat.simplex.common.model.ChatModel
import chat.simplex.common.platform.*
import chat.simplex.common.ui.theme.*
import java.util.concurrent.atomic.AtomicBoolean
import kotlin.math.min
@Composable
fun ModalView(
@@ -86,7 +87,7 @@ class ModalManager(private val placement: ModalPlacement? = null) {
fun closeModal() {
if (modalViews.isNotEmpty()) {
if (modalViews.lastOrNull()?.first == false) modalViews.removeAt(modalViews.lastIndex)
else runAtomically { toRemove.add(modalViews.lastIndex - toRemove.size) }
else runAtomically { toRemove.add(modalViews.lastIndex - min(toRemove.size, modalViews.lastIndex)) }
}
modalCount.value = modalViews.size - toRemove.size
}
@@ -52,6 +52,14 @@ fun annotatedStringResource(id: StringResource): AnnotatedString {
}
}
@Composable
fun annotatedStringResource(id: StringResource, vararg args: Any?): AnnotatedString {
val density = LocalDensity.current
return remember(id) {
escapedHtmlToAnnotatedString(id.localized().format(args), density)
}
}
// maximum image file size to be auto-accepted
const val MAX_IMAGE_SIZE: Long = 261_120 // 255KB
const val MAX_IMAGE_SIZE_AUTO_RCV: Long = MAX_IMAGE_SIZE * 2
@@ -67,7 +75,7 @@ const val MAX_FILE_SIZE_XFTP: Long = 1_073_741_824 // 1GB
expect fun getAppFileUri(fileName: String): URI
// https://developer.android.com/training/data-storage/shared/documents-files#bitmap
expect fun getLoadedImage(file: CIFile?): Pair<ImageBitmap, ByteArray>?
expect suspend fun getLoadedImage(file: CIFile?): Pair<ImageBitmap, ByteArray>?
expect fun getFileName(uri: URI): String?
@@ -106,7 +114,7 @@ fun saveImage(image: ImageBitmap, encrypted: Boolean): CryptoFile? {
return try {
val ext = if (image.hasAlpha()) "png" else "jpg"
val dataResized = resizeImageToDataSize(image, ext == "png", maxDataSize = MAX_IMAGE_SIZE)
val destFileName = generateNewFileName("IMG", ext)
val destFileName = generateNewFileName("IMG", ext, File(getAppFilePath("")))
val destFile = File(getAppFilePath(destFileName))
if (encrypted) {
val args = writeCryptoFile(destFile.absolutePath, dataResized.toByteArray())
@@ -124,6 +132,24 @@ fun saveImage(image: ImageBitmap, encrypted: Boolean): CryptoFile? {
}
}
fun desktopSaveImageInTmp(uri: URI): CryptoFile? {
val image = getBitmapFromUri(uri) ?: return null
return try {
val ext = if (image.hasAlpha()) "png" else "jpg"
val dataResized = resizeImageToDataSize(image, ext == "png", maxDataSize = MAX_IMAGE_SIZE)
val destFileName = generateNewFileName("IMG", ext, tmpDir)
val destFile = File(tmpDir, destFileName)
val output = FileOutputStream(destFile)
dataResized.writeTo(output)
output.flush()
output.close()
CryptoFile.plain(destFile.absolutePath)
} catch (e: Exception) {
Log.e(TAG, "Util.kt desktopSaveImageInTmp error: ${e.stackTraceToString()}")
null
}
}
fun saveAnimImage(uri: URI, encrypted: Boolean): CryptoFile? {
return try {
val filename = getFileName(uri)?.lowercase()
@@ -134,7 +160,7 @@ fun saveAnimImage(uri: URI, encrypted: Boolean): CryptoFile? {
}
// Just in case the image has a strange extension
if (ext.length < 3 || ext.length > 4) ext = "gif"
val destFileName = generateNewFileName("IMG", ext)
val destFileName = generateNewFileName("IMG", ext, File(getAppFilePath("")))
val destFile = File(getAppFilePath(destFileName))
if (encrypted) {
val args = writeCryptoFile(destFile.absolutePath, uri.inputStream()?.readBytes() ?: return null)
@@ -156,7 +182,7 @@ fun saveFileFromUri(uri: URI, encrypted: Boolean, withAlertOnException: Boolean
val inputStream = uri.inputStream()
val fileToSave = getFileName(uri)
return if (inputStream != null && fileToSave != null) {
val destFileName = uniqueCombine(fileToSave)
val destFileName = uniqueCombine(fileToSave, File(getAppFilePath("")))
val destFile = File(getAppFilePath(destFileName))
if (encrypted) {
createTmpFileAndDelete { tmpFile ->
@@ -193,21 +219,21 @@ fun <T> createTmpFileAndDelete(onCreated: (File) -> T): T {
}
}
fun generateNewFileName(prefix: String, ext: String): String {
fun generateNewFileName(prefix: String, ext: String, dir: File): String {
val sdf = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US)
sdf.timeZone = TimeZone.getTimeZone("GMT")
val timestamp = sdf.format(Date())
return uniqueCombine("${prefix}_$timestamp.$ext")
return uniqueCombine("${prefix}_$timestamp.$ext", dir)
}
fun uniqueCombine(fileName: String): String {
fun uniqueCombine(fileName: String, dir: File): String {
val orig = File(fileName)
val name = orig.nameWithoutExtension
val ext = orig.extension
fun tryCombine(n: Int): String {
val suffix = if (n == 0) "" else "_$n"
val f = "$name$suffix.$ext"
return if (File(getAppFilePath(f)).exists()) tryCombine(n + 1) else f
return if (File(dir, f).exists()) tryCombine(n + 1) else f
}
return tryCombine(0)
}
@@ -347,7 +373,7 @@ inline fun <reified T> serializableSaver(): Saver<T, *> = Saver(
fun UriHandler.openVerifiedSimplexUri(uri: String) {
val URI = try { URI.create(uri) } catch (e: Exception) { null }
if (URI != null) {
connectIfOpenedViaUri(URI, ChatModel)
connectIfOpenedViaUri(chatModel.remoteHostId, URI, ChatModel)
}
}
@@ -63,7 +63,7 @@ private fun deleteStorageAndRestart(m: ChatModel, password: String, completed: (
if (!displayName.isNullOrEmpty()) {
profile = Profile(displayName = displayName, fullName = "")
}
val createdUser = m.controller.apiCreateActiveUser(profile, pastTimestamp = true)
val createdUser = m.controller.apiCreateActiveUser(null, profile, pastTimestamp = true)
m.currentUser.value = createdUser
m.controller.appPrefs.onboardingStage.set(OnboardingStage.OnboardingComplete)
if (createdUser != null) {

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