Compare commits

...

38 Commits

Author SHA1 Message Date
JRoberts 6f68840b3a 4.5.2: ios 125, Android 100 2023-02-10 11:43:14 +04:00
JRoberts 2eef858db1 ios: update core library 2023-02-10 11:10:35 +04:00
Evgeny Poberezkin 434315fb08 Merge branch 'stable' 2023-02-09 20:53:05 +00:00
Evgeny Poberezkin 9b495e576c readme: update groups 2023-02-09 20:52:44 +00:00
JRoberts 5405f44f54 core: 4.5.2.0 2023-02-09 16:34:44 +04:00
Stanislav Dmitrenko 53b05974c9 android: limit width + height in chat item view (#1920) 2023-02-09 12:00:33 +00:00
JRoberts 3530022152 ios, android: moderated item content types, CIDeleted type (#1919) 2023-02-09 15:10:35 +04:00
Stanislav Dmitrenko dc6bab7ae6 android: fixed broken autoscroll when a new message is coming (#1917)
* android: fixed broken autoscroll when a new message is coming

* spelling
2023-02-08 23:10:56 +00:00
Stanislav Dmitrenko c9b4ce457e android: prevent race when opening chat (#1914)
* android: prevent race when opening chat

* different way of doing things

* change

* change
2023-02-08 19:25:51 +00:00
JRoberts bd3325a889 core: show/keep message as moderated for moderator (#1916) 2023-02-08 22:29:36 +04:00
JRoberts 9e347484eb core: avoid using wickAckMessage handler on messages leading to connection deletion (#1915) 2023-02-08 21:23:53 +04:00
ishi_sama 894af0602d docs: french (#1905)
* Lang subfolder ; SERVER_fr.md ; fix minor typos

* fix the fix

* fix img src

* CONTRIBUTING_fr

* SQL_fr ; fix rev date

* WEBRTC_fr.md ; rev date

* CLI_fr ; rev date

* fix table content link and sum img src

* fix

* fixing the fix

am i dumb?

* polishing...

* README_fr.md (save)

* Update README_fr.md

* README_fr ; starting SIMPLEX_FR ; link fix

* update README (en+fr)

* Blog README_fr ; translators link

* typo

* SIMPLEX_fr ; fixes

* last fixes

* rename folder

* rename files/links

* update line

* remove ...

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-02-08 14:03:52 +00:00
Stanislav Dmitrenko aa6011a196 android: prevent race when changing active user (#1913) 2023-02-08 13:21:55 +00:00
Stanislav Dmitrenko f24035a99d android: prevent showing system alert after start (Android 13+) (#1909)
* android: prevent showing system alert after start (Android 13+)

* refactor

* added comments and renamed function

* rename

* rename

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-02-08 10:48:19 +00:00
Stanislav Dmitrenko c006b8150f ios: ask permission to open profiles (#1910) 2023-02-08 10:39:41 +00:00
Evgeny Poberezkin 9e4499de6d core: allow admins/owners delete member messages (#1869)
* core: allow admins/owners delete member messages

* allow message deletion to admins/owners

* deleted by types, schema

* check role

* fix test, view

* view, tests

* comment

* test timed deletion events

* refactor

* refactor

* refactor

---------

Co-authored-by: JRoberts <8711996+jr-simplex@users.noreply.github.com>
2023-02-08 11:08:53 +04:00
Evgeny Poberezkin a018e4a581 docs: translation guide (#1911)
* docs: translations

* add doc

* add images, corrections

* spellcheck

* link to translation guide from readme

* change image

* images
2023-02-07 21:57:51 +00:00
Stanislav Dmitrenko d29fd93ea7 docs: view files from private data directory of Android app (#1907)
* docs: view files from private data directory of Android app

* naming

* spelling

* spelling

* change
2023-02-07 15:17:10 +00:00
Stanislav Dmitrenko b30c7af3a3 mobile: including fully localized languages only (#1908)
* mobile: including fully localized languages only

* better place for code

* ios: including fully localized languages only

* Revert "ios: including fully localized languages only"

This reverts commit 42a0334d83.
2023-02-07 15:16:34 +00:00
Stanislav Dmitrenko 2798671d22 android: show alert when decode exception happens (#1906) 2023-02-07 12:08:54 +00:00
Stanislav Dmitrenko 0339b399f7 ios: don't go back when system alert appears (#1903) 2023-02-06 16:33:45 +00:00
Stanislav Dmitrenko d048962959 ios: Fixed screenshot size (#1902) 2023-02-06 16:00:29 +00:00
Stanislav Dmitrenko 4af91c4cae android: fixed size for exported QR code (#1901)
* android: fixed size for exported QR code

* border

* automatic version

* modifier

* make image instead of screenshot

* code folding

* don't use deprecated method

* function refactor

* dropped unneeded variable
2023-02-06 15:34:49 +00:00
Stanislav Dmitrenko 8a445ece90 ios: colored and clickable qr code with logo (#1885)
* ios: colored and clickable qr code with logo

* size of circle

* same padding as in android

* add padding to logo

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-02-06 08:45:56 +00:00
Stanislav Dmitrenko 5082f5b4a4 android: colored and clickable qr code with logo (#1884)
* android: colored and clickable qr code with logo

* save qr code as jpg for better quality

* bigger logo

* bigger logo (0.16f), low error correction (QR scans ok with up to 0.26f circle size)

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-02-06 08:45:40 +00:00
Evgeny Poberezkin c8fae0ec43 blog: typo 2023-02-05 23:46:42 +00:00
Evgeny Poberezkin d9a8d333f7 4.5.1: Android 99, iOS 124 2023-02-05 23:37:58 +00:00
Evgeny Poberezkin 73f8c543e3 translations (#1900)
* Translated using Weblate (Czech)

Currently translated at 100.0% (954 of 954 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 26.7% (255 of 954 strings)

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

* Translated using Weblate (French)

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

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

* Translated using Weblate (Japanese)

Currently translated at 8.5% (82 of 954 strings)

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

* Translated using Weblate (Chinese (Simplified))

Currently translated at 24.4% (219 of 895 strings)

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

* Translated using Weblate (Chinese (Traditional))

Currently translated at 1.8% (18 of 954 strings)

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

* Translated using Weblate (Dutch)

Currently translated at 56.4% (538 of 953 strings)

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

* Translated using Weblate (Czech)

Currently translated at 1.6% (15 of 891 strings)

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

* Added translation using Weblate (Croatian)

* Added translation using Weblate (Croatian)

* Translated using Weblate (Dutch)

Currently translated at 63.6% (607 of 953 strings)

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

* Translated using Weblate (Czech)

Currently translated at 99.6% (950 of 953 strings)

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

* Translated using Weblate (Czech)

Currently translated at 66.1% (589 of 891 strings)

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

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

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

* ios: import localizations

* ios: export localizations

---------

Co-authored-by: zenobit <zen@osowoso.xyz>
Co-authored-by: xqhjay <137847720@qq.com>
Co-authored-by: Ophiushi <Ophiushi@users.noreply.hosted.weblate.org>
Co-authored-by: tomato potato <4ryo49@protonmail.com>
Co-authored-by: Albert Bob <vicdorke@gmail.com>
Co-authored-by: Bdd55oo <giggzuv9z.eofjx@aleeas.com>
Co-authored-by: John m <jvanmanen@gmail.com>
Co-authored-by: Mehmed <pajazetovicmeho@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
2023-02-05 22:36:52 +00:00
Evgeny Poberezkin 14945a9296 ios: update core library 2023-02-05 22:30:03 +00:00
Evgeny Poberezkin 155ffd16ec core: 4.5.1.0 2023-02-05 22:06:27 +00:00
sh 1eb1e52912 call.ts: include udp stun/turn (#1892)
* call.ts: include udp stun/turn

* update JS

* show protocol, support TURNS

* mobile: add turn via UDP, remove protocol from view

* remove enums for protocol strings in ICE candidates

* 0.2.3

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
2023-02-05 21:57:50 +00:00
Evgeny Poberezkin af173ee5c4 blog: v4.5 (#1886)
* blog: v4.5

* update post, images

* update readme, post
2023-02-05 13:53:41 +00:00
Evgeny Poberezkin 06a2f7e4da mobile: remove option "transfer images faster" (#1891) 2023-02-05 11:25:31 +00:00
Evgeny Poberezkin 958299784d core: update simplexmq (more strict transport host parser 2023-02-04 23:31:01 +00:00
Evgeny Poberezkin 49b6979ff0 core: update simplexmq (not to fail batch subscriptions), terminal: log contact errors with -c option (#1890) 2023-02-04 23:13:20 +00:00
Evgeny Poberezkin 3c493db613 mobile: use TCP for ICE requests of WebRTC calls (#1888)
* ios: support query string parameters in ICE server addresses

* android: support query params in ICE server address, add transport=TCP to default servers
2023-02-04 15:44:39 +00:00
Evgeny Poberezkin 86cc85b3a5 mobile: change default of "transfer images faster/inline" to off, mark as BETA (#1889)
* mobile: change default of "transfer images faster/inline" to off, mark as BETA

* ios: import localizations
2023-02-04 15:19:12 +00:00
Evgeny Poberezkin 0427d2e578 core: prevent failure to acknowledge a group message in case its parsing or saving fails (potential cause for stuck delivery) (#1887) 2023-02-04 12:25:11 +00:00
118 changed files with 8042 additions and 1323 deletions
+27 -23
View File
@@ -1,3 +1,5 @@
| Updated 07.02.2023 | Languages: EN, [FR](/docs/lang/fr/README.md) |
<img src="images/simplex-chat-logo.svg" alt="SimpleX logo" width="100%">
# SimpleX - the first messaging platform that has no user identifiers of any kind - 100% private by design!
@@ -76,16 +78,18 @@ You can use SimpleX with your own servers and still communicate with people usin
## Frequently asked questions
1. _How SimpleX can deliver messages without any user identifiers?_ See [v2 release annoucement](./blog/20220511-simplex-chat-v2-images-files.md#the-first-messaging-platform-without-user-identifiers) explaining how SimpleX works.
1. _How SimpleX can deliver messages without any user identifiers?_ See [v2 release announcement](./blog/20220511-simplex-chat-v2-images-files.md#the-first-messaging-platform-without-user-identifiers) explaining how SimpleX works.
2. _Why should I not just use Signal?_ Signal is a centralised platform that uses phone numbers to identify its users and their contacts. It means that while the content of your messages on Signal is protected with robust end-to-end encryption, there is a large amount of meta-data visible to Signal - who you talk with and when.
2. _Why should I not just use Signal?_ Signal is a centralized platform that uses phone numbers to identify its users and their contacts. It means that while the content of your messages on Signal is protected with robust end-to-end encryption, there is a large amount of meta-data visible to Signal - who you talk with and when.
3. _How is it different from Matrix, Session, Ricochet, Cwtch, etc., that also don't require user identites?_ Although these platforms do not require a _real identity_, they do rely on anonymous user identities to deliver messages it can be, for example, an identity key or a random number. Using a persistent user identity, even anonymous, creates a risk that user's connection graph becomes known to the observers and/or service providers, and it can lead to de-anonymizing some users. If the same user profile is used to connect to two different people via any messenger other than SimpleX, these two people can confirm if they are connected to the same person - they would use the same user identifier in the messages. With SimpleX there is no meta-data in common between your conversations with different contacts - the quality that no other messaging platform has.
3. _How is it different from Matrix, Session, Ricochet, Cwtch, etc., that also don't require user identities?_ Although these platforms do not require a _real identity_, they do rely on anonymous user identities to deliver messages it can be, for example, an identity key or a random number. Using a persistent user identity, even anonymous, creates a risk that user's connection graph becomes known to the observers and/or service providers, and it can lead to de-anonymizing some users. If the same user profile is used to connect to two different people via any messenger other than SimpleX, these two people can confirm if they are connected to the same person - they would use the same user identifier in the messages. With SimpleX there is no meta-data in common between your conversations with different contacts - the quality that no other messaging platform has.
## News and updates
Recent updates:
[Feb 04, 2023. v4.5 released - with multiple user profiles, message draft, transport isolation and Italian interface](./blog/20230204-simplex-chat-v4-5-user-chat-profiles.md).
[Jan 03, 2023. v4.4 released - with disappearing messages, "live" messages, connection security verifications, GIFs and stickers and with French interface language](./blog/20230103-simplex-chat-v4.4-disappearing-messages.md).
[Dec 06, 2022. November reviews and v4.3 released - with instant voice messages, irreversible deletion of sent messages and improved server configuration](./blog/20221206-simplex-chat-v4.3-voice-messages.md).
@@ -94,8 +98,6 @@ Recent updates:
[Sep 28, 2022. v4.0: encrypted local chat database and many other changes](./blog/20220928-simplex-chat-v4-encrypted-database.md).
[Sep 1, 2022. v3.2: incognito mode, support .onion server hostnames, setting contact names, changing color scheme, etc. Implementation audit is arranged for October!](./blog/20220901-simplex-chat-v3.2-incognito-mode.md).
[All updates](./blog)
## Make a private connection
@@ -138,7 +140,7 @@ SimpleX Chat is a work in progress we are releasing improvements as they are
What is already implemented:
1. Instead of user profile identifiers used by all other platforms, even the most private ones, SimpleX uses pairwise per-queue identifiers (2 addresses for each unidirectional message queue, with an optional 3rd address for push notificaitons on iOS, 2 queues in each connection between the users). It makes observing the network graph on the application level more difficult, as for `n` users there can be up to `n * (n-1)` message queues.
1. Instead of user profile identifiers used by all other platforms, even the most private ones, SimpleX uses pairwise per-queue identifiers (2 addresses for each unidirectional message queue, with an optional 3rd address for push notifications on iOS, 2 queues in each connection between the users). It makes observing the network graph on the application level more difficult, as for `n` users there can be up to `n * (n-1)` message queues.
2. End-to-end encryption in each message queue using [NaCl cryptobox](https://nacl.cr.yp.to/box.html). This is added to allow redundancy in the future (passing each message via several servers), to avoid having the same ciphertext in different queues (that would only be visible to the attacker if TLS is compromised). The encryption keys used for this encryption are not rotated, instead we are planning to rotate the queues. Curve25519 keys are used for key negotiation.
3. [Double ratchet](https://signal.org/docs/specifications/doubleratchet/) end-to-end encryption in each conversation between two users (or group members). This is the same algorithm that is used in Signal and many other messaging apps; it provides OTR messaging with forward secrecy (each message is encrypted by its own ephemeral key), break-in recovery (the keys are frequently re-negotiated as part of the message exchange). Two pairs of Curve448 keys are used for the initial key agreement, initiating party passes these keys via the connection link, accepting side - in the header of the confirmation message.
4. Additional layer of encryption using NaCL cryptobox for the messages delivered from the server to the recipient. This layer avoids having any ciphertext in common between sent and received traffic of the server inside TLS (and there are no identifiers in common as well).
@@ -148,10 +150,11 @@ What is already implemented:
8. To protect against replay attacks SimpleX servers require [tlsunique channel binding](https://www.rfc-editor.org/rfc/rfc5929.html) as session ID in each client command signed with per-queue ephemeral key.
9. To protect your IP address all SimpleX Chat clients support accessing messaging servers via Tor - see [v3.1 release announcement](./blog/20220808-simplex-chat-v3.1-chat-groups.md) for more details.
10. Local database encryption with passphrase - your contacts, groups and all sent and received messages are stored encrypted. If you used SimpleX Chat before v4.0 you need to enable the encryption via the app settings.
11. Transport isolation - different TCP connections and Tor circuits are used for traffic of different user profiles, optionally - for different contacts and group member connections.
We plan to add soon:
1. Message queue rotation. Currently the queues created between two users are used until the contact is deleted, providing a long-term pairwise identifiers of the conversation. We are planning to add queue rotation to make these identifiers temporary and rotate based on some schedule TBC (e.g., every X messages, or every X hours/days).
1. Automatic message queue rotation. Currently the queues created between two users are used until the queue is manually changed by the user or contact is deleted. We are planning to add automatic queue rotation to make these identifiers temporary and rotate based on some schedule TBC (e.g., every X messages, or every X hours/days).
2. Local files encryption. Currently the images and files you send and receive are stored in the app unencrypted, you can delete them via `Settings / Database passphrase & export`.
3. Message "mixing" - adding latency to message delivery, to protect against traffic correlation by message time.
@@ -161,7 +164,7 @@ You can:
- use SimpleX Chat library to integrate chat functionality into your mobile apps.
- create chat bots and services in Haskell - see [simple](./apps/simplex-bot/) and more [advanced chat bot example](./apps/simplex-bot-advanced/).
- create chat bots and services in any language running SimpleX Chat terminal CLI as a local WebSocket server. See [TypeScript SimpleX Chat client](./packages/simplex-chat-client/) and [JavaScipt chat bot example](./packages/simplex-chat-client/typescript/examples/squaring-bot.js).
- create chat bots and services in any language running SimpleX Chat terminal CLI as a local WebSocket server. See [TypeScript SimpleX Chat client](./packages/simplex-chat-client/) and [JavaScript chat bot example](./packages/simplex-chat-client/typescript/examples/squaring-bot.js).
- run [simplex-chat terminal CLI](./docs/CLI.md) to execute individual chat commands, e.g. to send messages as part of shell script execution.
If you are considering developing with SimpleX platform please get in touch for any advice and support.
@@ -196,16 +199,19 @@ If you are considering developing with SimpleX platform please get in touch for
- ✅ Disappearing messages (with recipient opt-in per-contact).
- ✅ "Live" messages.
- ✅ Contact verification via a separate out-of-band channel.
- 🏗 Multiple user profiles in the same chat database.
- 🏗 Optionally avoid re-using the same TCP session for multiple connections.
- Multiple user profiles in the same chat database.
- Optionally avoid re-using the same TCP session for multiple connections.
- ✅ Preserve message drafts.
- 🏗 File server to optimize for efficient and private sending of large files.
- 🏗 Improved audio & video calls.
- 🏗 SMP queue redundancy and rotation (manual is supported).
- 🏗 Reduced battery and traffic usage in large groups.
- 🏗 Preserve message drafts.
- 🏗 Support older Android OS and 32-bit CPUs.
- Ephemeral/disappearing/OTR conversations with the existing contacts.
- Access password/pin (with optional alternative access password).
- Local app files encryption.
- Video messages.
- Improved navigation and search in the conversation (expand and scroll to quoted message, scroll to search results, etc.).
- Message delivery confirmation (with sender opt-in or opt-out per contact, TBC).
- Feeds/broadcasts.
- Web widgets for custom interactivity in the chats.
@@ -215,15 +221,13 @@ If you are considering developing with SimpleX platform please get in touch for
- Privacy-preserving identity server for optional DNS-based contact/group addresses to simplify connection and discovery, but not used to deliver messages:
- keep all your contacts and groups even if you lose the domain.
- the server doesn't have information about your contacts and groups.
- Channels server for large groups and broadcast channels.
- Hosting server for large groups, communities and public channels.
- Message delivery relay for senders (to conceal IP address from the recipients' servers and to reduce the traffic).
- High capacity multi-node SMP relays.
## Join a user group
You can join a general English-speaking group: [#SimpleX-Group](https://simplex.chat/contact#/?v=1-2&smp=smp%3A%2F%2Fhpq7_4gGJiilmz5Rf-CswuU5kZGkm_zOIooSw6yALRg%3D%40smp5.simplex.im%2FcIS0gu1h0Y8pZpQkDaSz7HZGSHcKpMB9%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAKzzWAJYrVt1zdgRp4pD3FBst6eK7233DJeNElENLJRA%253D%26srv%3Djjbyvoemxysm7qxap7m5d5m35jzv5qq6gnlv7s4rsn7tdwwmuqciwpid.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%228mazMhefXoM5HxWBfZnvwQ%3D%3D%22%7D). Just bear in mind that it has ~300 members now, and that it is fully decentralized, so sending a message and connecting to all members in this group will take some time, only join it if you:
- want to see how larger groups work.
- traffic is not a concern (sending each message is ~5mb).
You can also join a new and smaller English-speaking group if you want to ask questions without too much traffic: [#SimpleX-Group-2](https://simplex.chat/contact#/?v=1-2&smp=smp%3A%2F%2Fhpq7_4gGJiilmz5Rf-CswuU5kZGkm_zOIooSw6yALRg%3D%40smp5.simplex.im%2FQP8zaGjjmlXV-ix_Er4JgJ0lNPYGS1KX%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEApAgBkRZ3x12ayZ7sHrjHQWNMvqzZpWUgM_fFCUdLXwo%253D%26srv%3Djjbyvoemxysm7qxap7m5d5m35jzv5qq6gnlv7s4rsn7tdwwmuqciwpid.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22xWpPXEZZsQp_F7vwAcAYDw%3D%3D%22%7D)
You can join an English-speaking group if you want to ask any questions: [#SimpleX-Group-2](https://simplex.chat/contact#/?v=1-2&smp=smp%3A%2F%2Fhpq7_4gGJiilmz5Rf-CswuU5kZGkm_zOIooSw6yALRg%3D%40smp5.simplex.im%2FQP8zaGjjmlXV-ix_Er4JgJ0lNPYGS1KX%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEApAgBkRZ3x12ayZ7sHrjHQWNMvqzZpWUgM_fFCUdLXwo%253D%26srv%3Djjbyvoemxysm7qxap7m5d5m35jzv5qq6gnlv7s4rsn7tdwwmuqciwpid.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22xWpPXEZZsQp_F7vwAcAYDw%3D%3D%22%7D)
There are also several groups in languages other than English, that we have the apps interface translated into. These groups are for testing, and asking questions to other SimpleX Chat users. We do not always answer questions there, so please ask them in one of the English-speaking groups.
@@ -242,13 +246,13 @@ Thanks to our users and [Weblate](https://hosted.weblate.org/engage/simplex-chat
Current interface languages:
English (development language)
German: [@mlanp](https://github.com/mlanp)
French: link to be added
Italian: [@unbranched](https://github.com/unbranched)
Russian: project team
- English (development language)
- German: [@mlanp](https://github.com/mlanp)
- French: [@ishi_sama](https://github.com/ishi-sama)
- Italian: [@unbranched](https://github.com/unbranched)
- Russian: project team
Languages in progress: Chinese, Hindi, Japanese, Dutch and [many others](https://hosted.weblate.org/projects/simplex-chat/#languages). We will be adding more languages as some of the already added are completed please suggest new languages and get in touch with us!
Languages in progress: Chinese, Hindi, Czech, Japanese, Dutch and [many others](https://hosted.weblate.org/projects/simplex-chat/#languages). We will be adding more languages as some of the already added are completed please suggest new languages, review the [translation guide](./docs/TRANSLATIONS.md) and get in touch with us!
## Contribute
+7 -2
View File
@@ -11,8 +11,8 @@ android {
applicationId "chat.simplex.app"
minSdk 29
targetSdk 32
versionCode 98
versionName "4.5"
versionCode 100
versionName "4.5.2"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
ndk {
@@ -76,6 +76,11 @@ android {
}
jniLibs.useLegacyPackaging = compression_level != "0"
}
def isRelease = gradle.getStartParameter().taskNames.find({ it.toLowerCase().contains("release") }) != null
if (isRelease) {
// Comma separated list of languages that will be included in the apk
android.defaultConfig.resConfigs("en", "ru", "de", "fr", "it")
}
}
dependencies {
+2 -1
View File
@@ -26,7 +26,8 @@ let answerTimeout = 30000;
const processCommand = (function () {
const defaultIceServers = [
{ urls: ["stun:stun.simplex.im:443"] },
{ urls: ["turn:turn.simplex.im:443"], username: "private", credential: "yleob6AVkiNI87hpR94Z" },
{ urls: ["turn:turn.simplex.im:443?transport=udp"], username: "private", credential: "yleob6AVkiNI87hpR94Z" },
{ urls: ["turn:turn.simplex.im:443?transport=tcp"], username: "private", credential: "yleob6AVkiNI87hpR94Z" },
];
function getCallConfig(encodedInsertableStreams, iceServers, relay) {
return {
@@ -101,8 +101,19 @@ class SimplexApp: Application(), LifecycleEventObserver {
isAppOnForeground = true
if (chatModel.chatRunning.value == true) {
kotlin.runCatching {
val chats = chatController.apiGetChats()
chatModel.updateChats(chats)
val currentUserId = chatModel.currentUser.value?.userId
val chats = ArrayList(chatController.apiGetChats())
/** Active user can be changed in background while [ChatController.apiGetChats] is executing */
if (chatModel.currentUser.value?.userId == currentUserId) {
val currentChatId = chatModel.chatId.value
val oldStats = if (currentChatId != null) chatModel.getChat(currentChatId)?.chatStats else null
if (oldStats != null) {
val indexOfCurrentChat = chats.indexOfFirst { it.id == currentChatId }
/** Pass old chatStats because unreadCounter can be changed already while [ChatController.apiGetChats] is executing */
if (indexOfCurrentChat >= 0) chats[indexOfCurrentChat] = chats[indexOfCurrentChat].copy(chatStats = oldStats)
}
chatModel.updateChats(chats)
}
}.onFailure { Log.e(TAG, it.stackTraceToString()) }
}
}
@@ -1257,6 +1257,8 @@ data class ChatItem (
is CIContent.SndGroupFeature -> showNtfDir
is CIContent.RcvChatFeatureRejected -> showNtfDir
is CIContent.RcvGroupFeatureRejected -> showNtfDir
is CIContent.SndModerated -> true
is CIContent.RcvModerated -> true
is CIContent.InvalidJSON -> false
}
@@ -1271,14 +1273,14 @@ data class ChatItem (
status: CIStatus = CIStatus.SndNew(),
quotedItem: CIQuote? = null,
file: CIFile? = null,
itemDeleted: Boolean = false,
itemDeleted: CIDeleted? = null,
itemEdited: Boolean = false,
itemTimed: CITimed? = null,
editable: Boolean = true
) =
ChatItem(
chatDir = dir,
meta = CIMeta.getSample(id, ts, text, status, itemDeleted, itemEdited, null, editable),
meta = CIMeta.getSample(id, ts, text, status, itemDeleted, itemEdited, itemTimed, editable),
content = CIContent.SndMsgContent(msgContent = MsgContent.MCText(text)),
quotedItem = quotedItem,
file = file
@@ -1293,7 +1295,7 @@ data class ChatItem (
) =
ChatItem(
chatDir = CIDirection.DirectRcv(),
meta = CIMeta.getSample(id, Clock.System.now(), text, CIStatus.RcvRead(), itemDeleted = false, itemEdited = false, editable = false),
meta = CIMeta.getSample(id, Clock.System.now(), text, CIStatus.RcvRead()),
content = CIContent.RcvMsgContent(msgContent = MsgContent.MCFile(text)),
quotedItem = null,
file = CIFile.getSample(fileName = fileName, fileSize = fileSize, fileStatus = fileStatus)
@@ -1308,7 +1310,7 @@ data class ChatItem (
) =
ChatItem(
chatDir = dir,
meta = CIMeta.getSample(id, ts, text, status, itemDeleted = false, itemEdited = false, editable = false),
meta = CIMeta.getSample(id, ts, text, status),
content = CIContent.RcvDeleted(deleteMode = CIDeleteMode.cidmBroadcast),
quotedItem = null,
file = null
@@ -1317,7 +1319,7 @@ data class ChatItem (
fun getGroupInvitationSample(status: CIGroupInvitationStatus = CIGroupInvitationStatus.Pending) =
ChatItem(
chatDir = CIDirection.DirectRcv(),
meta = CIMeta.getSample(1, Clock.System.now(), "received invitation to join group team as admin", CIStatus.RcvRead(), itemDeleted = false, itemEdited = false, editable = false),
meta = CIMeta.getSample(1, Clock.System.now(), "received invitation to join group team as admin", CIStatus.RcvRead()),
content = CIContent.RcvGroupInvitation(groupInvitation = CIGroupInvitation.getSample(status = status), memberRole = GroupMemberRole.Admin),
quotedItem = null,
file = null
@@ -1326,7 +1328,7 @@ data class ChatItem (
fun getGroupEventSample() =
ChatItem(
chatDir = CIDirection.DirectRcv(),
meta = CIMeta.getSample(1, Clock.System.now(), "group event text", CIStatus.RcvRead(), itemDeleted = false, itemEdited = false, editable = false),
meta = CIMeta.getSample(1, Clock.System.now(), "group event text", CIStatus.RcvRead()),
content = CIContent.RcvGroupEventContent(rcvGroupEvent = RcvGroupEvent.MemberAdded(groupMemberId = 1, profile = Profile.sampleData)),
quotedItem = null,
file = null
@@ -1336,7 +1338,7 @@ data class ChatItem (
val content = CIContent.RcvChatFeature(feature = feature, enabled = enabled, param = null)
return ChatItem(
chatDir = CIDirection.DirectRcv(),
meta = CIMeta.getSample(1, Clock.System.now(), content.text, CIStatus.RcvRead(), itemDeleted = false, itemEdited = false, editable = false),
meta = CIMeta.getSample(1, Clock.System.now(), content.text, CIStatus.RcvRead()),
content = content,
quotedItem = null,
file = null
@@ -1356,7 +1358,7 @@ data class ChatItem (
itemStatus = CIStatus.RcvRead(),
createdAt = Clock.System.now(),
updatedAt = Clock.System.now(),
itemDeleted = false,
itemDeleted = null,
itemEdited = false,
itemTimed = null,
itemLive = false,
@@ -1376,7 +1378,7 @@ data class ChatItem (
itemStatus = CIStatus.RcvRead(),
createdAt = Clock.System.now(),
updatedAt = Clock.System.now(),
itemDeleted = false,
itemDeleted = null,
itemEdited = false,
itemTimed = null,
itemLive = true,
@@ -1421,7 +1423,7 @@ data class CIMeta (
val itemStatus: CIStatus,
val createdAt: Instant,
val updatedAt: Instant,
val itemDeleted: Boolean,
val itemDeleted: CIDeleted?,
val itemEdited: Boolean,
val itemTimed: CITimed?,
val itemLive: Boolean?,
@@ -1446,7 +1448,7 @@ data class CIMeta (
companion object {
fun getSample(
id: Long, ts: Instant, text: String, status: CIStatus = CIStatus.SndNew(),
itemDeleted: Boolean = false, itemEdited: Boolean = false, itemTimed: CITimed? = null, itemLive: Boolean = false, editable: Boolean = true
itemDeleted: CIDeleted? = null, itemEdited: Boolean = false, itemTimed: CITimed? = null, itemLive: Boolean = false, editable: Boolean = true
): CIMeta =
CIMeta(
itemId = id,
@@ -1471,7 +1473,7 @@ data class CIMeta (
itemStatus = CIStatus.SndNew(),
createdAt = Clock.System.now(),
updatedAt = Clock.System.now(),
itemDeleted = false,
itemDeleted = null,
itemEdited = false,
itemTimed = null,
itemLive = false,
@@ -1506,6 +1508,12 @@ sealed class CIStatus {
@Serializable @SerialName("rcvRead") class RcvRead: CIStatus()
}
@Serializable
sealed class CIDeleted {
@Serializable @SerialName("deleted") class Deleted: CIDeleted()
@Serializable @SerialName("moderated") class Moderated(val byGroupMember: GroupMember): CIDeleted()
}
@Serializable
enum class CIDeleteMode(val deleteMode: String) {
@SerialName("internal") cidmInternal("internal"),
@@ -1541,6 +1549,8 @@ sealed class CIContent: ItemContent {
@Serializable @SerialName("sndGroupFeature") class SndGroupFeature(val groupFeature: GroupFeature, val preference: GroupPreference, val param: Int? = null): CIContent() { override val msgContent: MsgContent? get() = null }
@Serializable @SerialName("rcvChatFeatureRejected") class RcvChatFeatureRejected(val feature: ChatFeature): CIContent() { override val msgContent: MsgContent? get() = null }
@Serializable @SerialName("rcvGroupFeatureRejected") class RcvGroupFeatureRejected(val groupFeature: GroupFeature): CIContent() { override val msgContent: MsgContent? get() = null }
@Serializable @SerialName("sndModerated") object SndModerated: CIContent() { override val msgContent: MsgContent? get() = null }
@Serializable @SerialName("rcvModerated") object RcvModerated: CIContent() { override val msgContent: MsgContent? get() = null }
@Serializable @SerialName("invalidJSON") data class InvalidJSON(val json: String): CIContent() { override val msgContent: MsgContent? get() = null }
override val text: String get() = when (this) {
@@ -1565,6 +1575,8 @@ sealed class CIContent: ItemContent {
is SndGroupFeature -> featureText(groupFeature, preference.enable.text, param)
is RcvChatFeatureRejected -> "${feature.text}: ${generalGetString(R.string.feature_received_prohibited)}"
is RcvGroupFeatureRejected -> "${groupFeature.text}: ${generalGetString(R.string.feature_received_prohibited)}"
is SndModerated -> generalGetString(R.string.moderated_description)
is RcvModerated -> generalGetString(R.string.moderated_description)
is InvalidJSON -> "invalid data"
}
@@ -44,11 +44,7 @@ class NtfManager(val context: Context, private val appPreferences: AppPreference
private val msgNtfTimeoutMs = 30000L
init {
manager.createNotificationChannel(NotificationChannel(MessageChannel, generalGetString(R.string.ntf_channel_messages), NotificationManager.IMPORTANCE_HIGH))
manager.createNotificationChannel(callNotificationChannel(CallChannel, generalGetString(R.string.ntf_channel_calls)))
// Remove old channels since they can't be edited
manager.deleteNotificationChannel("chat.simplex.app.CALL_NOTIFICATION")
manager.deleteNotificationChannel("chat.simplex.app.LOCK_SCREEN_CALL_NOTIFICATION")
if (manager.areNotificationsEnabled()) createNtfChannelsMaybeShowAlert()
}
enum class NotificationAction {
@@ -156,7 +152,7 @@ class NtfManager(val context: Context, private val appPreferences: AppPreference
.setGroup(MessageGroup)
.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_CHILDREN)
.setGroupSummary(true)
.setContentIntent(chatPendingIntent(ShowChatsAction, user.userId))
.setContentIntent(chatPendingIntent(ShowChatsAction, null))
.build()
with(NotificationManagerCompat.from(context)) {
@@ -250,7 +246,7 @@ class NtfManager(val context: Context, private val appPreferences: AppPreference
}
}
private fun chatPendingIntent(intentAction: String, userId: Long, chatId: String? = null, broadcast: Boolean = false): PendingIntent {
private fun chatPendingIntent(intentAction: String, userId: Long?, chatId: String? = null, broadcast: Boolean = false): PendingIntent {
Log.d(TAG, "chatPendingIntent for $intentAction")
val uniqueInt = (System.currentTimeMillis() and 0xfffffff).toInt()
var intent = Intent(context, if (!broadcast) MainActivity::class.java else NtfActionReceiver::class.java)
@@ -268,6 +264,21 @@ class NtfManager(val context: Context, private val appPreferences: AppPreference
}
}
/**
* This function creates notifications channels. On Android 13+ calling it for the first time will trigger system alert,
* The alert asks a user to allow or disallow to show notifications for the app. That's why it should be called only when the user
* already saw such alert or when you want to trigger showing the alert.
* On the first app launch the channels will be created after user profile is created. Subsequent calls will create new channels and delete
* old ones if needed
* */
fun createNtfChannelsMaybeShowAlert() {
manager.createNotificationChannel(NotificationChannel(MessageChannel, generalGetString(R.string.ntf_channel_messages), NotificationManager.IMPORTANCE_HIGH))
manager.createNotificationChannel(callNotificationChannel(CallChannel, generalGetString(R.string.ntf_channel_calls)))
// Remove old channels since they can't be edited
manager.deleteNotificationChannel("chat.simplex.app.CALL_NOTIFICATION")
manager.deleteNotificationChannel("chat.simplex.app.LOCK_SCREEN_CALL_NOTIFICATION")
}
/**
* Processes every action specified by [NotificationCompat.Builder.addAction] that comes with [NotificationAction]
* and [ChatInfo.id] as [ChatIdKey] in extra
@@ -88,7 +88,6 @@ class AppPreferences(val context: Context) {
val webrtcIceServers = mkStrPreference(SHARED_PREFS_WEBRTC_ICE_SERVERS, null)
val privacyProtectScreen = mkBoolPreference(SHARED_PREFS_PRIVACY_PROTECT_SCREEN, true)
val privacyAcceptImages = mkBoolPreference(SHARED_PREFS_PRIVACY_ACCEPT_IMAGES, true)
val privacyTransferImagesInline = mkBoolPreference(SHARED_PREFS_PRIVACY_TRANSFER_IMAGES_INLINE, true)
val privacyLinkPreviews = mkBoolPreference(SHARED_PREFS_PRIVACY_LINK_PREVIEWS, true)
private val _simplexLinkMode = mkStrPreference(SHARED_PREFS_PRIVACY_SIMPLEX_LINK_MODE, SimplexLinkMode.default.name)
val simplexLinkMode: SharedPreference<SimplexLinkMode> = SharedPreference(
@@ -935,7 +934,7 @@ open class ChatController(var ctrl: ChatCtrl?, val ntfManager: NtfManager, val a
return false
}
suspend fun apiReceiveFile(fileId: Long, inline: Boolean): AChatItem? {
suspend fun apiReceiveFile(fileId: Long, inline: Boolean? = null): AChatItem? {
val r = sendCmd(CC.ReceiveFile(fileId, inline))
return when (r) {
is CR.RcvFileAccepted -> r.chatItem
@@ -1424,8 +1423,7 @@ open class ChatController(var ctrl: ChatCtrl?, val ntfManager: NtfManager, val a
}
suspend fun receiveFile(user: User, fileId: Long) {
val inline = appPrefs.privacyTransferImagesInline.get()
val chatItem = apiReceiveFile(fileId, inline)
val chatItem = apiReceiveFile(fileId)
if (chatItem != null) {
chatItemSimpleUpdate(user, chatItem)
}
@@ -1798,7 +1796,7 @@ sealed class CC {
class ApiRejectContact(val contactReqId: Long): CC()
class ApiChatRead(val type: ChatType, val id: Long, val range: ItemRange): CC()
class ApiChatUnread(val type: ChatType, val id: Long, val unreadChat: Boolean): CC()
class ReceiveFile(val fileId: Long, val inline: Boolean): CC()
class ReceiveFile(val fileId: Long, val inline: Boolean?): CC()
class ShowVersion(): CC()
val cmdString: String get() = when (this) {
@@ -1873,7 +1871,7 @@ sealed class CC {
is ApiCallStatus -> "/_call status @${contact.apiId} ${callStatus.value}"
is ApiChatRead -> "/_read chat ${chatRef(type, id)} from=${range.from} to=${range.to}"
is ApiChatUnread -> "/_unread chat ${chatRef(type, id)} ${onOff(unreadChat)}"
is ReceiveFile -> "/freceive $fileId inline=${onOff(inline)}"
is ReceiveFile -> if (inline == null) "/freceive $fileId" else "/freceive $fileId inline=${onOff(inline)}"
is ShowVersion -> "/version"
}
@@ -21,8 +21,8 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.KeyboardCapitalization
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import chat.simplex.app.*
import chat.simplex.app.R
import chat.simplex.app.SimplexService
import chat.simplex.app.model.ChatModel
import chat.simplex.app.model.Profile
import chat.simplex.app.ui.theme.*
@@ -116,6 +116,7 @@ fun createProfile(chatModel: ChatModel, displayName: String, fullName: String, c
if (chatModel.users.isEmpty()) {
chatModel.controller.startChat(user)
chatModel.onboardingStage.value = OnboardingStage.Step3_SetNotificationsMode
SimplexApp.context.chatModel.controller.ntfManager.createNtfChannelsMaybeShowAlert()
} else {
val users = chatModel.controller.listUsers()
chatModel.users.clear()
@@ -297,10 +297,10 @@ fun CallInfoView(call: Call, alignment: Alignment.Horizontal) {
InfoText(call.contact.chatViewName, style = MaterialTheme.typography.h2)
InfoText(call.callState.text)
val connInfo =
if (call.connectionInfo == null) ""
else " (${call.connectionInfo.text})"
InfoText(call.encryptionStatus + connInfo)
val connInfo = call.connectionInfo
// val connInfoText = if (connInfo == null) "" else " (${connInfo.text}, ${connInfo.protocolText})"
val connInfoText = if (connInfo == null) "" else " (${connInfo.text})"
InfoText(call.encryptionStatus + connInfoText)
}
}
@@ -480,7 +480,10 @@ fun PreviewActiveCallOverlayVideo() {
callState = CallState.Negotiated,
localMedia = CallMediaType.Video,
peerMedia = CallMediaType.Video,
connectionInfo = ConnectionInfo(RTCIceCandidate(RTCIceCandidateType.Host), RTCIceCandidate(RTCIceCandidateType.Host))
connectionInfo = ConnectionInfo(
RTCIceCandidate(RTCIceCandidateType.Host, "tcp", null),
RTCIceCandidate(RTCIceCandidateType.Host, "tcp", null)
)
),
dismiss = {},
toggleAudio = {},
@@ -501,7 +504,10 @@ fun PreviewActiveCallOverlayAudio() {
callState = CallState.Negotiated,
localMedia = CallMediaType.Audio,
peerMedia = CallMediaType.Audio,
connectionInfo = ConnectionInfo(RTCIceCandidate(RTCIceCandidateType.Host), RTCIceCandidate(RTCIceCandidateType.Host))
connectionInfo = ConnectionInfo(
RTCIceCandidate(RTCIceCandidateType.Host, "udp", null),
RTCIceCandidate(RTCIceCandidateType.Host, "udp", null)
)
),
dismiss = {},
toggleAudio = {},
@@ -1,9 +1,10 @@
package chat.simplex.app.views.call
import android.util.Log
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import chat.simplex.app.R
import chat.simplex.app.SimplexApp
import androidx.compose.ui.text.toUpperCase
import chat.simplex.app.*
import chat.simplex.app.model.Contact
import chat.simplex.app.model.User
import chat.simplex.app.views.helpers.generalGetString
@@ -11,6 +12,8 @@ import kotlinx.datetime.Instant
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import java.net.URI
import java.util.*
import kotlin.collections.ArrayList
data class Call(
val contact: Contact,
@@ -106,17 +109,30 @@ sealed class WCallResponse {
}
@Serializable data class CallCapabilities(val encryption: Boolean)
@Serializable data class ConnectionInfo(private val localCandidate: RTCIceCandidate?, private val remoteCandidate: RTCIceCandidate?) {
val text: String @Composable get() = when {
localCandidate?.candidateType == RTCIceCandidateType.Host && remoteCandidate?.candidateType == RTCIceCandidateType.Host ->
stringResource(R.string.call_connection_peer_to_peer)
localCandidate?.candidateType == RTCIceCandidateType.Relay && remoteCandidate?.candidateType == RTCIceCandidateType.Relay ->
stringResource(R.string.call_connection_via_relay)
else ->
"${localCandidate?.candidateType?.value ?: "unknown"} / ${remoteCandidate?.candidateType?.value ?: "unknown"}"
val text: String @Composable get() {
val local = localCandidate?.candidateType
val remote = remoteCandidate?.candidateType
return when {
local == RTCIceCandidateType.Host && remote == RTCIceCandidateType.Host ->
stringResource(R.string.call_connection_peer_to_peer)
local == RTCIceCandidateType.Relay && remote == RTCIceCandidateType.Relay ->
stringResource(R.string.call_connection_via_relay)
else ->
"${local?.value ?: "unknown"} / ${remote?.value ?: "unknown"}"
}
}
val protocolText: String get() {
val local = localCandidate?.protocol?.uppercase(Locale.ROOT) ?: "unknown"
val localRelay = localCandidate?.relayProtocol?.uppercase(Locale.ROOT) ?: "unknown"
val remote = remoteCandidate?.protocol?.uppercase(Locale.ROOT) ?: "unknown"
val localText = if (localRelay == local || localCandidate?.relayProtocol == null) local else "$local ($localRelay)"
return if (local == remote) localText else "$localText / $remote"
}
}
// https://developer.mozilla.org/en-US/docs/Web/API/RTCIceCandidate
@Serializable data class RTCIceCandidate(val candidateType: RTCIceCandidateType?)
@Serializable data class RTCIceCandidate(val candidateType: RTCIceCandidateType?, val protocol: String?, val relayProtocol: String?)
// https://developer.mozilla.org/en-US/docs/Web/API/RTCIceServer
@Serializable data class RTCIceServer(val urls: List<String>, val username: String? = null, val credential: String? = null)
@@ -159,20 +175,22 @@ data class ConnectionState(
)
// the servers are expected in this format:
// stun:stun.simplex.im:443
// turn:private:yleob6AVkiNI87hpR94Z@turn.simplex.im:443
// stun:stun.simplex.im:443?transport=tcp
// turn:private:yleob6AVkiNI87hpR94Z@turn.simplex.im:443?transport=tcp
fun parseRTCIceServer(str: String): RTCIceServer? {
var s = replaceScheme(str, "stun:")
s = replaceScheme(s, "turn:")
s = replaceScheme(s, "turns:")
val u = runCatching { URI(s) }.getOrNull()
if (u != null) {
val scheme = u.scheme
val host = u.host
val port = u.port
if (u.path == "" && (scheme == "stun" || scheme == "turn")) {
if (u.path == "" && (scheme == "stun" || scheme == "turn" || scheme == "turns")) {
val userInfo = u.userInfo?.split(":")
val query = if (u.query == null || u.query == "") "" else "?${u.query}"
return RTCIceServer(
urls = listOf("$scheme:$host:$port"),
urls = listOf("$scheme:$host:$port$query"),
username = userInfo?.getOrNull(0),
credential = userInfo?.getOrNull(1)
)
@@ -674,10 +674,18 @@ private fun ScrollToBottom(chatId: ChatId, listState: LazyListState, chatItems:
.distinctUntilChanged()
.filter { listState.layoutInfo.visibleItemsInfo.firstOrNull()?.key != it }
.collect {
if (listState.firstVisibleItemIndex == 0) {
listState.animateScrollToItem(0)
} else {
listState.animateScrollBy(scrollDistance)
try {
if (listState.firstVisibleItemIndex == 0) {
listState.animateScrollToItem(0)
} else {
listState.animateScrollBy(scrollDistance)
}
} catch (e: CancellationException) {
/**
* When you tap and hold a finger on a lazy column with chatItems, and then you receive a message,
* this coroutine will be canceled with the message "Current mutation had a higher priority" because of animatedScroll.
* Which breaks auto-scrolling to bottom. So just ignoring the exception
* */
}
}
}
@@ -174,14 +174,14 @@ fun CIFileView(
class ChatItemProvider: PreviewParameterProvider<ChatItem> {
private val sentFile = ChatItem(
chatDir = CIDirection.DirectSnd(),
meta = CIMeta.getSample(1, Clock.System.now(), "", CIStatus.SndSent(), itemDeleted = false, itemEdited = true, editable = false),
meta = CIMeta.getSample(1, Clock.System.now(), "", CIStatus.SndSent(), itemEdited = true),
content = CIContent.SndMsgContent(msgContent = MsgContent.MCFile("")),
quotedItem = null,
file = CIFile.getSample(fileStatus = CIFileStatus.SndComplete)
)
private val fileChatItemWtFile = ChatItem(
chatDir = CIDirection.DirectRcv(),
meta = CIMeta.getSample(1, Clock.System.now(), "", CIStatus.RcvRead(), itemDeleted = false, itemEdited = false, editable = false),
meta = CIMeta.getSample(1, Clock.System.now(), "", CIStatus.RcvRead(), ),
content = CIContent.RcvMsgContent(msgContent = MsgContent.MCFile("")),
quotedItem = null,
file = null
@@ -98,7 +98,7 @@ fun ChatItemView(
onDismissRequest = { showMenu.value = false },
Modifier.width(220.dp)
) {
if (!cItem.meta.itemDeleted && !live) {
if (cItem.meta.itemDeleted == null && !live) {
ItemAction(stringResource(R.string.reply_verb), Icons.Outlined.Reply, onClick = {
if (composeState.value.editing) {
composeState.value = ComposeState(contextItem = ComposeContextItem.QuotedItem(cItem), useLinkPreviews = useLinkPreviews)
@@ -140,7 +140,7 @@ fun ChatItemView(
showMenu.value = false
})
}
if (cItem.meta.itemDeleted && revealed.value) {
if (cItem.meta.itemDeleted != null && revealed.value) {
ItemAction(
stringResource(R.string.hide_verb),
Icons.Outlined.VisibilityOff,
@@ -178,10 +178,10 @@ fun ChatItemView(
@Composable
fun ContentItem() {
val mc = cItem.content.msgContent
if (cItem.meta.itemDeleted && !revealed.value) {
if (cItem.meta.itemDeleted != null && !revealed.value) {
MarkedDeletedItemView(cItem, cInfo.timedMessagesTTL, showMember = showMember)
MarkedDeletedItemDropdownMenu()
} else if (cItem.quotedItem == null && !cItem.meta.itemDeleted && !cItem.meta.isLive) {
} else if (cItem.quotedItem == null && cItem.meta.itemDeleted == null && !cItem.meta.isLive) {
if (mc is MsgContent.MCText && isShortEmoji(cItem.content.text)) {
EmojiItemView(cItem, cInfo.timedMessagesTTL)
MsgContentItemDropdownMenu()
@@ -238,6 +238,8 @@ fun ChatItemView(
is CIContent.SndGroupFeature -> CIChatFeatureView(cItem, c.groupFeature, c.preference.enable.iconColor)
is CIContent.RcvChatFeatureRejected -> CIChatFeatureView(cItem, c.feature, Color.Red)
is CIContent.RcvGroupFeatureRejected -> CIChatFeatureView(cItem, c.groupFeature, Color.Red)
is CIContent.SndModerated -> DeletedItem()
is CIContent.RcvModerated -> DeletedItem()
is CIContent.InvalidJSON -> CIInvalidJSONView(c.json)
}
}
@@ -1,8 +1,7 @@
package chat.simplex.app.views.chat.item
import android.content.res.Configuration
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.*
import androidx.compose.runtime.Composable
@@ -19,9 +18,10 @@ import chat.simplex.app.ui.theme.SimpleXTheme
@Composable
fun DeletedItemView(ci: ChatItem, timedMessagesTTL: Int?, showMember: Boolean = false) {
val sent = ci.chatDir.sent
Surface(
shape = RoundedCornerShape(18.dp),
color = ReceivedColorLight,
color = if (sent) SentColorLight else ReceivedColorLight,
) {
Row(
Modifier.padding(horizontal = 12.dp, vertical = 6.dp),
@@ -165,7 +165,7 @@ fun FramedItemView(
Box(contentAlignment = Alignment.BottomEnd) {
Column(Modifier.width(IntrinsicSize.Max)) {
PriorityLayout(Modifier, CHAT_IMAGE_LAYOUT_ID) {
if (ci.meta.itemDeleted) {
if (ci.meta.itemDeleted != null) {
FramedItemHeader(stringResource(R.string.marked_deleted_description), true, Icons.Outlined.Delete)
} else if (ci.meta.isLive) {
FramedItemHeader(stringResource(R.string.live), false)
@@ -242,7 +242,12 @@ fun CIMarkdownText(
}
const val CHAT_IMAGE_LAYOUT_ID = "chatImage"
const val MAX_SAFE_WIDTH_HEIGHT = 100_000
/**
* Equal to [androidx.compose.ui.unit.Constraints.MaxFocusMask], which is 0x3FFFF - 1
* Other values make a crash `java.lang.IllegalArgumentException: Can't represent a width of 123456 and height of 9909 in Constraints`
* See [androidx.compose.ui.unit.Constraints.createConstraints]
* */
const val MAX_SAFE_WIDTH = 0x3FFFF - 1
@Composable
fun PriorityLayout(
@@ -250,6 +255,17 @@ fun PriorityLayout(
priorityLayoutId: String,
content: @Composable () -> Unit
) {
/**
* Limiting max value for height + width in order to not crash the app, see [androidx.compose.ui.unit.Constraints.createConstraints]
* */
fun maxSafeHeight(width: Int) = when { // width bits + height bits should be <= 31
width < 0x1FFF /*MaxNonFocusMask*/ -> 0x3FFFF - 1 /* MaxFocusMask */ // 13 bits width + 18 bits height
width < 0x7FFF /*MinNonFocusMask*/ -> 0xFFFF - 1 /* MinFocusMask */ // 15 bits width + 16 bits height
width < 0xFFFF /*MinFocusMask*/ -> 0x7FFF - 1 /* MinFocusMask */ // 16 bits width + 15 bits height
width < 0x3FFFF /*MaxFocusMask*/ -> 0x1FFF - 1 /* MaxNonFocusMask */ // 18 bits width + 13 bits height
else -> 0x1FFF // shouldn't happen since width is limited already
}
Layout(
content = content,
modifier = modifier
@@ -261,15 +277,11 @@ fun PriorityLayout(
if (it.layoutId == priorityLayoutId)
imagePlaceable!!
else
it.measure(constraints.copy(maxWidth = imagePlaceable?.width ?: min(MAX_SAFE_WIDTH_HEIGHT, constraints.maxWidth))) }
/**
* Limit width for every other element to width of important element and height for a sum of all elements.
*
* min(MAX_SAFE_WIDTH_HEIGHT, ...) is here because of exception (related to width of long text):
* java.lang.IllegalArgumentException: Can't represent a size of 324314 in Constraints
* at androidx.compose.ui.unit.Constraints$Companion.bitsNeedForSize(Constraints.kt:403)
* */
layout(imagePlaceable?.measuredWidth ?: min(MAX_SAFE_WIDTH_HEIGHT, placeables.maxOf { it.width }), min(MAX_SAFE_WIDTH_HEIGHT, placeables.sumOf { it.height })) {
it.measure(constraints.copy(maxWidth = imagePlaceable?.width ?: min(MAX_SAFE_WIDTH, constraints.maxWidth))) }
// Limit width for every other element to width of important element and height for a sum of all elements.
val width = imagePlaceable?.measuredWidth ?: min(MAX_SAFE_WIDTH, placeables.maxOf { it.width })
val height = minOf(maxSafeHeight(width), placeables.sumOf { it.height })
layout(width, height) {
var y = 0
placeables.forEach {
it.place(0, y)
@@ -14,6 +14,7 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import chat.simplex.app.R
import chat.simplex.app.model.CIDeleted
import chat.simplex.app.model.ChatItem
import chat.simplex.app.ui.theme.HighOrLowlight
import chat.simplex.app.ui.theme.SimpleXTheme
@@ -51,7 +52,7 @@ fun MarkedDeletedItemView(ci: ChatItem, timedMessagesTTL: Int?, showMember: Bool
fun PreviewMarkedDeletedItemView() {
SimpleXTheme {
DeletedItemView(
ChatItem.getSampleData(itemDeleted = true),
ChatItem.getSampleData(itemDeleted = CIDeleted.Deleted()),
null
)
}
@@ -145,12 +145,12 @@ fun ChatPreviewView(
if (ci != null) {
val (text: CharSequence, inlineTextContent) = when {
chatModelDraftChatId == chat.id && chatModelDraft != null -> remember(chatModelDraft) { messageDraft(chatModelDraft) }
!ci.meta.itemDeleted -> ci.text to null
ci.meta.itemDeleted == null -> ci.text to null
else -> generalGetString(R.string.marked_deleted_description) to null
}
val formattedText = when {
chatModelDraftChatId == chat.id && chatModelDraft != null -> null
!ci.meta.itemDeleted -> ci.formattedText
ci.meta.itemDeleted == null -> ci.formattedText
else -> null
}
MarkdownText(
@@ -6,6 +6,7 @@ import android.content.*
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
import android.content.pm.PackageManager
import android.graphics.*
import android.graphics.ImageDecoder.DecodeException
import android.net.Uri
import android.provider.MediaStore
import android.util.Base64
@@ -205,21 +206,22 @@ fun GetImageBottomSheet(
val processPickedImage = { uri: Uri? ->
if (uri != null) {
val source = ImageDecoder.createSource(context.contentResolver, uri)
val bitmap = ImageDecoder.decodeBitmap(source)
imageBitmap.value = uri
onImageChange(bitmap)
}
}
val galleryLauncher = rememberLauncherForActivityResult(contract = PickFromGallery()) { processPickedImage(it) }
val galleryLauncherFallback = rememberGetContentLauncher { processPickedImage(it) }
val cameraLauncher = rememberCameraLauncher { uri: Uri? ->
if (uri != null) {
imageBitmap.value = uri
val source = ImageDecoder.createSource(SimplexApp.context.contentResolver, uri)
val bitmap = ImageDecoder.decodeBitmap(source)
onImageChange(bitmap)
try {
val bitmap = ImageDecoder.decodeBitmap(source)
imageBitmap.value = uri
onImageChange(bitmap)
} catch (e: DecodeException) {
Log.e(TAG, "Unable to decode the image: ${e.stackTraceToString()}")
AlertManager.shared.showAlertMsg(
title = generalGetString(R.string.image_decoding_exception_title),
text = generalGetString(R.string.image_decoding_exception_desc)
)
}
}
}
val galleryLauncher = rememberLauncherForActivityResult(contract = PickFromGallery(), processPickedImage)
val galleryLauncherFallback = rememberGetContentLauncher(processPickedImage)
val cameraLauncher = rememberCameraLauncher(processPickedImage)
val permissionLauncher = rememberPermissionLauncher { isGranted: Boolean ->
if (isGranted) {
cameraLauncher.launchWithFallback()
@@ -1,5 +1,6 @@
package chat.simplex.app.views.helpers
import android.app.Application
import android.content.Context
import android.content.res.Resources
import android.graphics.*
@@ -374,6 +375,24 @@ fun saveAnimImage(context: Context, uri: Uri): String? {
}
}
fun saveTempImageUncompressed(image: Bitmap, asPng: Boolean): File? {
return try {
val ext = if (asPng) "png" else "jpg"
val tmpDir = SimplexApp.context.getDir("temp", Application.MODE_PRIVATE)
return File(tmpDir.absolutePath + File.separator + generateNewFileName(SimplexApp.context, "IMG", ext)).apply {
outputStream().use { out ->
image.compress(if (asPng) Bitmap.CompressFormat.PNG else Bitmap.CompressFormat.JPEG, 85, out)
out.flush()
}
deleteOnExit()
SimplexApp.context.chatModel.filesToDelete.add(this)
}
} catch (e: Exception) {
Log.e(TAG, "Util.kt saveTempImageUncompressed error: ${e.message}")
null
}
}
fun saveFileFromUri(context: Context, uri: Uri): String? {
return try {
val inputStream = context.contentResolver.openInputStream(uri)
@@ -1,32 +1,100 @@
package chat.simplex.app.views.newchat
import android.graphics.Bitmap
import androidx.compose.foundation.Image
import androidx.compose.runtime.Composable
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.graphics.*
import androidx.compose.ui.platform.*
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import boofcv.alg.fiducial.qrcode.QrCodeEncoder
import boofcv.alg.fiducial.qrcode.QrCodeGeneratorImage
import androidx.core.graphics.*
import androidx.core.graphics.drawable.toBitmap
import boofcv.alg.drawing.FiducialImageEngine
import boofcv.alg.fiducial.qrcode.*
import boofcv.android.ConvertBitmap
import chat.simplex.app.R
import chat.simplex.app.SimplexApp
import chat.simplex.app.ui.theme.SimpleXTheme
import chat.simplex.app.views.helpers.*
import kotlinx.coroutines.launch
@Composable
fun QRCode(connReq: String, modifier: Modifier = Modifier) {
Image(
bitmap = qrCodeBitmap(connReq, 1024).asImageBitmap(),
contentDescription = stringResource(R.string.image_descr_qr_code),
modifier = modifier
)
fun QRCode(
connReq: String,
modifier: Modifier = Modifier,
tintColor: Color = Color(0xff062d56),
withLogo: Boolean = true
) {
val context = LocalContext.current
val scope = rememberCoroutineScope()
BoxWithConstraints {
val maxWidthInPx = with(LocalDensity.current) { maxWidth.roundToPx() }
val qr = remember(maxWidthInPx, connReq, tintColor, withLogo) {
qrCodeBitmap(connReq, maxWidthInPx).replaceColor(Color.Black.toArgb(), tintColor.toArgb())
.let { if (withLogo) it.addLogo() else it }
.asImageBitmap()
}
Image(
bitmap = qr,
contentDescription = stringResource(R.string.image_descr_qr_code),
modifier
.clickable {
scope.launch {
val image = qrCodeBitmap(connReq, 1024).replaceColor(Color.Black.toArgb(), tintColor.toArgb())
.let { if (withLogo) it.addLogo() else it }
val file = saveTempImageUncompressed(image, false)
if (file != null) {
shareFile(context, "", file.absolutePath)
}
}
}
)
}
}
fun qrCodeBitmap(content: String, size: Int): Bitmap {
val qrCode = QrCodeEncoder().addAutomatic(content).fixate()
val renderer = QrCodeGeneratorImage(5)
fun qrCodeBitmap(content: String, size: Int = 1024): Bitmap {
val qrCode = QrCodeEncoder().addAutomatic(content).setError(QrCode.ErrorLevel.L).fixate()
/** See [QrCodeGeneratorImage.initialize] and [FiducialImageEngine.configure] for size calculation */
val numModules = QrCode.totalModules(qrCode.version)
val borderModule = 1
// val calculatedFinalWidth = (pixelsPerModule * numModules) + 2 * (borderModule * pixelsPerModule)
// size = (x * numModules) + 2 * (borderModule * x)
// size / x = numModules + 2 * borderModule
// x = size / (numModules + 2 * borderModule)
val pixelsPerModule = size / (numModules + 2 * borderModule)
// + 1 to make it with better quality
val renderer = QrCodeGeneratorImage(pixelsPerModule + 1)
renderer.borderModule = borderModule
renderer.render(qrCode)
return ConvertBitmap.grayToBitmap(renderer.gray, Bitmap.Config.RGB_565)
return ConvertBitmap.grayToBitmap(renderer.gray, Bitmap.Config.RGB_565).scale(size, size)
}
fun Bitmap.replaceColor(from: Int, to: Int): Bitmap {
val pixels = IntArray(width * height)
getPixels(pixels, 0, width, 0, 0, width, height)
var i = 0
while (i < pixels.size) {
if (pixels[i] == from) {
pixels[i] = to
}
i++
}
setPixels(pixels, 0, width, 0, 0, width, height)
return this
}
fun Bitmap.addLogo(): Bitmap = applyCanvas {
val radius = (width * 0.16f) / 2
val paint = android.graphics.Paint()
paint.color = android.graphics.Color.WHITE
drawCircle(width / 2f, height / 2f, radius, paint)
val logo = SimplexApp.context.resources.getDrawable(R.mipmap.icon_foreground, null).toBitmap()
val logoSize = (width * 0.24).toInt()
translate((width - logoSize) / 2f, (height - logoSize) / 2f)
drawBitmap(logo, null, android.graphics.Rect(0, 0, logoSize, logoSize), null)
}
@Preview
@@ -51,8 +51,6 @@ fun PrivacySettingsView(
SectionView(stringResource(R.string.settings_section_title_chats)) {
SettingsPreferenceItem(Icons.Outlined.Image, stringResource(R.string.auto_accept_images), chatModel.controller.appPrefs.privacyAcceptImages)
SectionDivider()
SettingsPreferenceItem(Icons.Outlined.ImageAspectRatio, stringResource(R.string.transfer_images_faster), chatModel.controller.appPrefs.privacyTransferImagesInline)
SectionDivider()
SettingsPreferenceItem(Icons.Outlined.TravelExplore, stringResource(R.string.send_link_previews), chatModel.controller.appPrefs.privacyLinkPreviews)
SectionDivider()
SectionItemView { SimpleXLinkOptions(chatModel.simplexLinkMode, onSelected = {
@@ -24,6 +24,7 @@ fun VersionInfoView(info: CoreVersionInfo) {
Text(String.format(stringResource(R.string.app_version_code), BuildConfig.VERSION_CODE))
Text(String.format(stringResource(R.string.core_version), info.version))
Text(String.format(stringResource(R.string.core_build_timestamp), info.buildTimestamp))
Text(String.format(stringResource(R.string.core_simplexmq_version), info.simplexmqVersion, info.simplexmqCommit.substring(startIndex = 0, endIndex = 7)))
val simplexmqCommit = if (info.simplexmqCommit.length >= 7) info.simplexmqCommit.substring(startIndex = 0, endIndex = 7) else info.simplexmqCommit
Text(String.format(stringResource(R.string.core_simplexmq_version), info.simplexmqVersion, simplexmqCommit))
}
}
@@ -17,7 +17,7 @@
<string name="accept_requests">Přijímat žádosti</string>
<string name="allow_verb">Povolit</string>
<string name="allow_voice_messages_question">Povolit hlasové zprávy\?</string>
<string name="about_simplex">O Simplex</string>
<string name="about_simplex">O SimpleX</string>
<string name="a_plus_b">a + b</string>
<string name="accept_call_on_lock_screen">Přijmout</string>
<string name="chat_item_ttl_day">1 den</string>
@@ -131,8 +131,8 @@
<string name="contact_already_exists">Kontakt již existuje</string>
<string name="you_are_already_connected_to_vName_via_this_link">Jste již připojeni k <xliff:g id="contactName" example="Alice">%1$s!</xliff:g>.</string>
<string name="invalid_connection_link">Neplatný odkaz na spojení</string>
<string name="error_accepting_contact_request">Error accepting contact request</string>
<string name="error_changing_address">Error changing address</string>
<string name="error_accepting_contact_request">Chyba příjmu požadavku od kontaktu</string>
<string name="error_changing_address">Chuba změny adresy</string>
<string name="settings_notifications_mode_title">Služba oznamování</string>
<string name="notifications_mode_service_desc">Služba na pozadí je spuštěna vždy - oznámení se zobrazí, jakmile jsou zprávy k dispozici.</string>
<string name="notification_preview_mode_message">Text zprávy</string>
@@ -171,32 +171,32 @@
<string name="icon_descr_server_status_error">Chyba</string>
<string name="switch_receiving_address_desc">Tato funkce je experimentální! Bude fungovat pouze v případě, že druhý klient má nainstalovanou verzi 4.2. Po dokončení změny adresy by se měla v konverzaci zobrazit zpráva - zkontrolujte, zda můžete od tohoto kontaktu (nebo člena skupiny) stále přijímat zprávy.</string>
<string name="switch_receiving_address_question">Přepnout přijímací adresu\?</string>
<string name="send_verb">Send</string>
<string name="send_verb">Poslat</string>
<string name="you_need_to_allow_to_send_voice">Abyste mohli odesílat hlasové zprávy, musíte je povolit svému kontaktu.</string>
<string name="icon_descr_cancel_live_message">Cancel live message</string>
<string name="back">Back</string>
<string name="cancel_verb">Cancel</string>
<string name="reset_verb">Reset</string>
<string name="icon_descr_cancel_live_message">Zrušit živou zprávu</string>
<string name="back">Zpět</string>
<string name="cancel_verb">Zrušit</string>
<string name="reset_verb">Obnovit</string>
<string name="ok">OK</string>
<string name="no_details">no details</string>
<string name="add_contact">One-time invitation link</string>
<string name="copied">Copied to clipboard</string>
<string name="add_contact_or_create_group">Start new chat</string>
<string name="create_group">Create secret group</string>
<string name="to_share_with_your_contact">(to share with your contact)</string>
<string name="only_stored_on_members_devices">(only stored by group members)</string>
<string name="toast_permission_denied">Permission Denied!</string>
<string name="use_camera_button">Use Camera</string>
<string name="from_gallery_button">From Gallery</string>
<string name="choose_file">Choose file</string>
<string name="to_start_a_new_chat_help_header">To start a new chat</string>
<string name="chat_help_tap_button">Tap button</string>
<string name="above_then_preposition_continuation">above, then:</string>
<string name="add_new_contact_to_create_one_time_QR_code"><b>Add new contact</b>: to create your one-time QR Code for your contact.</string>
<string name="scan_QR_code_to_connect_to_contact_who_shows_QR_code"><b>Scan QR code</b>: to connect to your contact who shows QR code to you.</string>
<string name="no_details">bez podrobností</string>
<string name="add_contact">Jednorázový zvací odkaz</string>
<string name="copied">Zkopírováno do schránky</string>
<string name="add_contact_or_create_group">Začít novou konverzaci</string>
<string name="create_group">Vytvořit tajnou skupinu</string>
<string name="to_share_with_your_contact">(sdílet s kontaktem)</string>
<string name="only_stored_on_members_devices">(uloženo pouze členy skupiny)</string>
<string name="toast_permission_denied">Oprávnění zamítnuto!</string>
<string name="use_camera_button">Použít fotoaparát</string>
<string name="from_gallery_button">Z Galerie</string>
<string name="choose_file">Vybrat soubor</string>
<string name="to_start_a_new_chat_help_header">Pro zahájení nové konverzace</string>
<string name="chat_help_tap_button">Klepněte na tlačítko</string>
<string name="above_then_preposition_continuation">nad, potom:</string>
<string name="add_new_contact_to_create_one_time_QR_code"><b>Přidat nový kontakt</b>: vytvořit jednorázový kód QR.</string>
<string name="scan_QR_code_to_connect_to_contact_who_shows_QR_code"><b>Skenovat QR kód</b>: připojení ke kontaktu, který vám ukáže QR kód.</string>
<string name="desktop_scan_QR_code_from_app_via_scan_QR_code">💻 desktop: scan displayed QR code from the app, via <b>Scan QR code</b>.</string>
<string name="clear_chat_question">Clear chat\?</string>
<string name="clear_verb">Clear</string>
<string name="clear_chat_question">Vyčistit konverzaci\?</string>
<string name="clear_verb">Čistý</string>
<string name="mark_read">Označit přečtení</string>
<string name="mark_unread">Označit jako nepřečtené</string>
<string name="mute_chat">Ztlumit</string>
@@ -210,10 +210,9 @@
<string name="you_will_be_connected_when_group_host_device_is_online">Ke skupině budete připojeni, až bude zařízení hostitele skupiny online, vyčkejte prosím nebo se podívejte později!</string>
<string name="you_will_be_connected_when_your_connection_request_is_accepted">Budete připojeni, jakmile bude vaše žádost o připojení přijata, vyčkejte prosím nebo se podívejte později!</string>
<string name="connection_request_sent">Požadavek na připojení byl odeslán!</string>
<string name="paste_connection_link_below_to_connect">Paste the link you received into the box below to connect with your contact.</string>
<string name="your_profile_will_be_sent">Váš profil v chatu bude odeslán vašemu kontaktu</string>
<string name="create_one_time_link">Create one-time invitation link</string>
<string name="one_time_link">One-time invitation link</string>
<string name="create_one_time_link">Vytvořit jednorázovou pozvánku</string>
<string name="one_time_link">Vytvořit jednorázový zvací odkaz</string>
<string name="security_code">Bezpečnostní kód</string>
<string name="is_verified">\"%s je ověřeno</string>
<string name="chat_console">Konzola pro chat</string>
@@ -235,13 +234,13 @@
<string name="network_enable_socks">Použít proxy server SOCKS\?</string>
<string name="network_disable_socks">Použít přímé připojení k internetu\?</string>
<string name="network_use_onion_hosts_no">Ne</string>
<string name="network_use_onion_hosts_no_desc_in_alert">Cibuloví hostitelé nebudou použiti.</string>
<string name="network_use_onion_hosts_no_desc_in_alert">Onion hostitelé nebudou použiti.</string>
<string name="network_session_mode_user">Profil chatu</string>
<string name="network_session_mode_entity">Connection</string>
<string name="network_session_mode_entity">Připojení</string>
<string name="core_simplexmq_version">simplexmq: v%s (%2s)</string>
<string name="create_address">Create address</string>
<string name="accept_automatically">Automatically</string>
<string name="section_title_welcome_message">WELCOME MESSAGE</string>
<string name="create_address">Vytvořit adresu</string>
<string name="accept_automatically">Automaticky</string>
<string name="section_title_welcome_message">UVÍTACÍ ZPRÁVA</string>
<string name="save_and_notify_group_members">Uložit a upozornit členy skupiny</string>
<string name="exit_without_saving">Ukončit bez uložení</string>
<string name="the_messaging_and_app_platform_protecting_your_privacy_and_security">Platforma pro zasílání zpráv a aplikace chránící vaše soukromí a bezpečnost.</string>
@@ -253,9 +252,9 @@
<string name="decentralized">Decentralizované</string>
<string name="how_it_works">Jak to funguje</string>
<string name="how_simplex_works">Jak funguje <xliff:g id="appName">SimpleX</xliff:g></string>
<string name="only_client_devices_store_contacts_groups_e2e_encrypted_messages">Only client devices store user profiles, contacts, groups, and messages sent with <b>2-layer end-to-end encryption</b>.</string>
<string name="onboarding_notifications_mode_title">Private notifications</string>
<string name="onboarding_notifications_mode_periodic">Periodic</string>
<string name="only_client_devices_store_contacts_groups_e2e_encrypted_messages">Pouze klientská zařízení ukládají uživatelské profily, kontakty, skupiny a zprávy odesílané pomocí <b>2vrstvého end-to-end šifrování</b>.</string>
<string name="onboarding_notifications_mode_title">Soukromá oznámení</string>
<string name="onboarding_notifications_mode_periodic">Pravidelný</string>
<string name="ignore">Ignorovat</string>
<string name="call_already_ended">Hovor již skončil!</string>
<string name="icon_descr_video_call">videohovor</string>
@@ -265,7 +264,6 @@
<string name="open_simplex_chat_to_accept_call">Otevřete <xliff:g id="appNameFull">SimpleX Chat</xliff:g> pro přijetí hovoru</string>
<string name="allow_accepting_calls_from_lock_screen">Povolte volání ze zamčené obrazovky prostřednictvím Nastavení.</string>
<string name="open_verb">Otevřete stránku</string>
<string name="status_e2e_encrypted">e2e encrypted</string>
<string name="icon_descr_audio_on">Zvuk zapnut</string>
<string name="icon_descr_speaker_off">Reproduktor vypnut</string>
<string name="icon_descr_speaker_on">Zapnutý reproduktor</string>
@@ -295,16 +293,16 @@
<string name="files_and_media_section">Soubory a média</string>
<string name="delete_files_and_media_question">Smazat soubory a média\?</string>
<string name="delete_messages">Odstranění zpráv</string>
<string name="remove_passphrase_from_keychain">Remove passphrase from Keystore\?</string>
<string name="notifications_will_be_hidden">Notifications will be delivered only until the app stops!</string>
<string name="remove_passphrase">Remove</string>
<string name="update_database">Update</string>
<string name="current_passphrase">Current passphrase…</string>
<string name="update_database_passphrase">Update database passphrase</string>
<string name="enter_correct_current_passphrase">Please enter correct current passphrase.</string>
<string name="database_is_not_encrypted">Your chat database is not encrypted - set passphrase to protect it.</string>
<string name="keychain_is_storing_securely">Android Keystore is used to securely store passphrase - it allows notification service to work.</string>
<string name="impossible_to_recover_passphrase"><b>Please note</b>: you will NOT be able to recover or change passphrase if you lose it.</string>
<string name="remove_passphrase_from_keychain">Odstranit přístupovou frázi z úložiště klíčů\?</string>
<string name="notifications_will_be_hidden">Oznámení budou doručována pouze do doby, než se aplikace zastaví!</string>
<string name="remove_passphrase">Odstranit</string>
<string name="update_database">Aktualizovat</string>
<string name="current_passphrase">Aktuální přístupová fráze…</string>
<string name="update_database_passphrase">Aktualizovat přístupovou frázi databáze</string>
<string name="enter_correct_current_passphrase">Zadejte prosím správnou aktuální přístupovou frázi.</string>
<string name="database_is_not_encrypted">Váš databáze konverzace není zašifrována - nastavte přístupovou frázi pro její ochranu.</string>
<string name="keychain_is_storing_securely">K bezpečnému uložení heslové fráze slouží úložiště klíčů Android - umožňuje fungování služby oznámení.</string>
<string name="impossible_to_recover_passphrase"><b>Upozornění</b>: pokud přístupovou frázi ztratíte, NEBUDE možné ji obnovit ani změnit.</string>
<string name="database_will_be_encrypted_and_passphrase_stored">Databáze bude zašifrována a přístupová fráze bude uložena v úložišti klíčů.</string>
<string name="store_passphrase_securely">Heslo uložte bezpečně, v případě jeho ztráty jej NEBUDE možné změnit.</string>
<string name="file_with_path">Soubor: %s</string>
@@ -330,10 +328,10 @@
<string name="icon_descr_expand_role">Rozšířit výběr rolí</string>
<string name="invite_prohibited">Nelze pozvat kontakt!</string>
<string name="failed_to_create_user_duplicate_desc">Již máte profil chatu se stejným zobrazovacím názvem. Zvolte prosím jiné jméno.</string>
<string name="smp_server_test_create_queue">Create queue</string>
<string name="smp_server_test_secure_queue">Secure queue</string>
<string name="service_notifications">Instant notifications!</string>
<string name="it_can_disabled_via_settings_notifications_still_shown"><b>It can be disabled via settings</b> notifications will still be shown while the app is running.</string>
<string name="smp_server_test_create_queue">Vytvořit frontu</string>
<string name="smp_server_test_secure_queue">Zabezpečit frontu</string>
<string name="service_notifications">Okamžitá oznámení!</string>
<string name="it_can_disabled_via_settings_notifications_still_shown"><b>V nastavení ji lze vypnout</b> - oznámení se budou zobrazovat pokud aplikace běží.</string>
<string name="turn_off_battery_optimization">Chcete-li ji používat, <b>vypněte optimalizaci baterie</b> pro <xliff:g id="appName">SimpleX</xliff:g> v dalším dialogu. V opačném případě budou oznámení vypnuta.</string>
<string name="periodic_notifications_desc">Aplikace pravidelně načítá nové zprávy - denně spotřebuje několik procent baterie. Aplikace nepoužívá push oznámení - data ze zařízení nejsou odesílána na servery.</string>
<string name="enter_passphrase_notification_title">Je vyžadována přístupová fráze</string>
@@ -344,8 +342,7 @@
<string name="notification_preview_new_message">nová zpráva</string>
<string name="notification_new_contact_request">Žádost o nový kontakt</string>
<string name="delete_message_cannot_be_undone_warning">Zpráva bude smazána - nelze to vzít zpět!</string>
<string name="confirm_verb">Confirm</string>
<string name="share_invitation_link">Share invitation link</string>
<string name="confirm_verb">Potvrdit</string>
<string name="send_us_an_email">Pošlete nám e-mail</string>
<string name="chat_lock">Zámek SimpleX</string>
<string name="install_simplex_chat_for_terminal">Instalace <xliff:g id="appNameFull">SimpleX Chat</xliff:g> pro terminál</string>
@@ -362,7 +359,7 @@
<string name="people_can_connect_only_via_links_you_share">Lidé se s vámi mohou spojit pouze prostřednictvím odkazů, které sdílíte.</string>
<string name="integrity_msg_bad_hash">špatný hash zprávy</string>
<string name="chat_database_imported">Importovaná databáze chatu</string>
<string name="new_passphrase">New passphrase…</string>
<string name="new_passphrase">Nová přístupová fráze…</string>
<string name="save_passphrase_and_open_chat">Uložte heslo a otevřete chat</string>
<string name="chat_archive_section">ARCHIV CHATU</string>
<string name="no_contacts_selected">Nebyl vybrán žádný kontakt</string>
@@ -372,16 +369,16 @@
<string name="updating_settings_will_reconnect_client_to_all_servers">Aktualizací nastavení se klient znovu připojí ke všem serverům.</string>
<string name="accept_feature_set_1_day">Nastavit 1 den</string>
<string name="connection_error_auth">Chyba spojení (AUTH)</string>
<string name="sender_may_have_deleted_the_connection_request">Sender may have deleted the connection request.</string>
<string name="error_smp_test_server_auth">Server requires authorization to create queues, check password</string>
<string name="smp_server_test_delete_queue">Delete queue</string>
<string name="sender_may_have_deleted_the_connection_request">Odesílatel možná smazal požadavek připojení</string>
<string name="error_smp_test_server_auth">Server vyžaduje autorizaci pro vytváření front, zkontrolujte heslo</string>
<string name="smp_server_test_delete_queue">Odstranit frontu</string>
<string name="delete_group_menu_action">Smazat</string>
<string name="delete_pending_connection__question">Smazat čekající připojení\?</string>
<string name="icon_descr_settings">Nastavení</string>
<string name="image_descr_qr_code">QR kód</string>
<string name="show_QR_code_for_your_contact_to_scan_from_the_app__multiline">Váš kontakt může z aplikace naskenovat QR kód.</string>
<string name="if_you_cannot_meet_in_person_show_QR_in_video_call_or_via_another_channel">If you can\'t meet in person, <b>show QR code in the video call</b>, or share the link.</string>
<string name="scan_code">Scan code</string>
<string name="if_you_cannot_meet_in_person_show_QR_in_video_call_or_via_another_channel">Pokud se nemůžete setkat osobně, ukažte <b>ve videohovoru QR kód</b> nebo sdílejte odkaz.</string>
<string name="scan_code">Skenovat kód</string>
<string name="incorrect_code">Nesprávný bezpečnostní kód!</string>
<string name="scan_code_from_contacts_app">Naskenujte bezpečnostní kód z aplikace vašeho kontaktu.</string>
<string name="mark_code_verified">Označit jako ověřený</string>
@@ -394,15 +391,15 @@
<string name="chat_with_the_founder">Zasílání otázek a nápadů</string>
<string name="smp_servers_test_server">Testovací server</string>
<string name="enter_one_ICE_server_per_line">Servery ICE (jeden na řádek)</string>
<string name="network_use_onion_hosts_required_desc">Pro připojení budou vyžadováni cibuloví hostitelé.</string>
<string name="update_network_session_mode_question">Update transport isolation mode\?</string>
<string name="network_use_onion_hosts_required_desc">Pro připojení budou vyžadováni Onion hostitelé.</string>
<string name="update_network_session_mode_question">Aktualizovat režim izolace\?</string>
<string name="app_version_code">Sestavení aplikace: %s</string>
<string name="you_can_share_your_address_anybody_will_be_able_to_connect">You can share your address as a link or as a QR code - anybody will be able to connect to you. You won\'t lose your contacts if you later delete it.</string>
<string name="share_link">Share link</string>
<string name="delete_address">Delete address</string>
<string name="full_name__field">Full name:</string>
<string name="you_can_share_your_address_anybody_will_be_able_to_connect">Můžete sdílet svou adresu jako odkaz nebo jako QR kód - kdokoli se k vám bude moci připojit. O své kontakty nepřijdete, pokud ji později smažete.</string>
<string name="share_link">Sdílet odkaz</string>
<string name="delete_address">Odstranit adresu</string>
<string name="full_name__field">Celé jméno:</string>
<string name="your_current_profile">Váš současný profil</string>
<string name="to_preserve_privacy_simplex_has_background_service_instead_of_push_notifications_it_uses_a_few_pc_battery">To preserve your privacy, instead of push notifications the app has a <b><xliff:g id="appName">SimpleX</xliff:g> background service</b> it uses a few percent of the battery per day.</string>
<string name="to_preserve_privacy_simplex_has_background_service_instead_of_push_notifications_it_uses_a_few_pc_battery">Pro zachování soukromí má aplikace místo push oznámení <b><xliff:g id="appName">SimpleX</xliff:g> službu na pozadí</b> - denně spotřebuje několik procent baterie.</string>
<string name="periodic_notifications">Pravidelná oznámení</string>
<string name="simplex_service_notification_title"><xliff:g id="appNameFull">SimpleX Chat</xliff:g> služba</string>
<string name="simplex_service_notification_text">Příjem zpráv…</string>
@@ -440,11 +437,11 @@
<string name="view_security_code">Zobrazení bezpečnostního kódu</string>
<string name="icon_descr_record_voice_message">Nahrát hlasovou zprávu</string>
<string name="voice_messages_prohibited">Hlasové zprávy jsou zakázány!</string>
<string name="ask_your_contact_to_enable_voice">Please ask your contact to enable sending voice messages.</string>
<string name="send_live_message_desc">Send a live message - it will update for the recipient(s) as you type it</string>
<string name="share_one_time_link">Create one-time invitation link</string>
<string name="scan_QR_code">Scan QR code</string>
<string name="connect_via_link_or_qr_from_clipboard_or_in_person">(scan or paste from clipboard)</string>
<string name="ask_your_contact_to_enable_voice">Prosím, požádejte kontaktní osobu, aby umožnila odesílání hlasových zpráv.</string>
<string name="send_live_message_desc">Poslat živou zprávu - zpráva se bude aktualizovat pro příjemce během psaní.</string>
<string name="share_one_time_link">Vytvořit jednorázovou pozvánku</string>
<string name="scan_QR_code">Skenovat QR kód</string>
<string name="connect_via_link_or_qr_from_clipboard_or_in_person">( skenovat nebo vložit ze schránky)</string>
<string name="edit_image">Upravit obrázek</string>
<string name="delete_image">Smazat obrázek</string>
<string name="callstatus_error">chyba volání</string>
@@ -467,10 +464,9 @@
<string name="privacy_and_security">Ochrana osobních údajů a zabezpečení</string>
<string name="your_privacy">Vaše soukromí</string>
<string name="protect_app_screen">Ochrana obrazovky aplikace</string>
<string name="transfer_images_faster">Rychlejší přenos obrázků</string>
<string name="send_link_previews">Odesílání náhledů odkazů</string>
<string name="full_backup">Zálohování dat aplikace</string>
<string name="confirm_new_passphrase">Confirm new passphrase</string>
<string name="confirm_new_passphrase">Potvrdit novou heslovou frázi</string>
<string name="error_with_info">Chyba: %s</string>
<string name="leave_group_question">Opustit skupinu\?</string>
<string name="icon_descr_group_inactive">Skupina je neaktivní</string>
@@ -516,10 +512,10 @@
<string name="marked_deleted_description">označeno jako smazáno</string>
<string name="sending_files_not_yet_supported">Odesílání souborů zatím není podporováno</string>
<string name="receiving_files_not_yet_supported">přijímání souborů zatím není podporováno</string>
<string name="sender_you_pronoun">you</string>
<string name="sender_you_pronoun">ty</string>
<string name="unknown_message_format">neznámý formát zprávy</string>
<string name="invalid_message_format">neplatný formát zprávy</string>
<string name="live">LIVE</string>
<string name="live">ŽIVĚ</string>
<string name="description_via_group_link_incognito">inkognito přes skupinový odkaz</string>
<string name="ensure_smp_server_address_are_correct_format_and_unique">Ujistěte se, že adresy serverů SMP jsou ve správném formátu, oddělené na řádcích a nejsou duplicitní.</string>
<string name="failed_to_create_user_title">Chyba při vytváření profilu!</string>
@@ -532,17 +528,17 @@
<string name="error_creating_address">Chyba při vytváření adresy</string>
<string name="please_check_correct_link_and_maybe_ask_for_a_new_one">Zkontrolujte, zda jste použili správný odkaz, nebo požádejte kontakt, aby vám poslal jiný.</string>
<string name="connection_error_auth_desc">Pokud váš kontakt spojení nesmazal nebo tento odkaz již byl použit, může se jednat o chybu - nahlaste ji prosím. Chcete-li se připojit, požádejte prosím svůj kontakt o vytvoření jiného odkazu pro připojení a zkontrolujte, zda máte stabilní připojení k síti.</string>
<string name="error_deleting_contact">Error deleting contact</string>
<string name="error_deleting_group">Error deleting group</string>
<string name="error_deleting_contact_request">Error deleting contact request</string>
<string name="error_deleting_pending_contact_connection">Error deleting pending contact connection</string>
<string name="error_smp_test_failed_at_step">Test failed at step %s.</string>
<string name="error_smp_test_certificate">Possibly, certificate fingerprint in server address is incorrect</string>
<string name="smp_server_test_connect">Connect</string>
<string name="smp_server_test_disconnect">Disconnect</string>
<string name="error_deleting_user">Error deleting user profile</string>
<string name="icon_descr_instant_notifications">Instant notifications</string>
<string name="service_notifications_disabled">Instant notifications are disabled!</string>
<string name="error_deleting_contact">Chyba mazání kontaktu</string>
<string name="error_deleting_group">Chyba mazání skupiny</string>
<string name="error_deleting_contact_request">Chyba mazání žádosti kontaktu</string>
<string name="error_deleting_pending_contact_connection">Chyba mazání probíhajícího připojení kontaktu</string>
<string name="error_smp_test_failed_at_step">Test selhal v kroku %s.</string>
<string name="error_smp_test_certificate">Je možné, že otisk certifikátu v adrese serveru je nesprávný.</string>
<string name="smp_server_test_connect">Připojit</string>
<string name="smp_server_test_disconnect">Odpojit</string>
<string name="error_deleting_user">Chyba mazání uživatelského profilu</string>
<string name="icon_descr_instant_notifications">Okamžitá oznámení</string>
<string name="service_notifications_disabled">Okamžitá oznámení jsou vypnutá!</string>
<string name="turning_off_service_and_periodic">Je aktivní optimalizace baterie, která vypíná službu na pozadí a pravidelné požadavky na nové zprávy. Můžete je znovu povolit prostřednictvím nastavení.</string>
<string name="periodic_notifications_disabled">Pravidelná oznámení jsou vypnuta!</string>
<string name="database_initialization_error_desc">Databáze nefunguje správně. Klepnutím na se dozvíte více</string>
@@ -570,7 +566,7 @@
<string name="group_connection_pending">připojuje se…</string>
<string name="tap_to_start_new_chat">Klepnutím na zahájíte nový chat</string>
<string name="chat_with_developers">Chatujte s vývojáři</string>
<string name="you_have_no_chats">Nemáte žádné chaty</string>
<string name="you_have_no_chats">Nemáte žádné konverzace</string>
<string name="icon_descr_cancel_image_preview">Zrušit náhled obrázku</string>
<string name="share_message">Sdílet zprávu…</string>
<string name="share_image">Sdílet obrázek…</string>
@@ -582,19 +578,19 @@
<string name="icon_descr_server_status_pending">Čeká na vyřízení</string>
<string name="verify_security_code">Ověření bezpečnostního kódu</string>
<string name="icon_descr_send_message">Odeslat zprávu</string>
<string name="only_group_owners_can_enable_voice">Only group owners can enable voice messages.</string>
<string name="send_live_message">Send live message</string>
<string name="live_message">Live message!</string>
<string name="connect_via_link_or_qr">Connect via link / QR code</string>
<string name="thank_you_for_installing_simplex">Thank you for installing <xliff:g id="appNameFull">SimpleX Chat</xliff:g>!</string>
<string name="you_can_connect_to_simplex_chat_founder">You can <font color="#0088ff">connect to <xliff:g id="appNameFull">SimpleX Chat</xliff:g> developers to ask any questions and to receive updates</font>.</string>
<string name="to_connect_via_link_title">To connect via link</string>
<string name="if_you_received_simplex_invitation_link_you_can_open_in_browser">If you received <xliff:g id="appName">SimpleX Chat</xliff:g> invitation link, you can open it in your browser:</string>
<string name="if_you_choose_to_reject_the_sender_will_not_be_notified">If you choose to reject sender will NOT be notified.</string>
<string name="mobile_tap_open_in_mobile_app_then_tap_connect_in_app">📱 mobile: tap <b>Open in mobile app</b>, then tap <b>Connect</b> in the app.</string>
<string name="reject_contact_button">Reject</string>
<string name="clear_chat_button">Clear chat</string>
<string name="clear_chat_menu_action">Clear</string>
<string name="only_group_owners_can_enable_voice">Pouze majitelé skupin mohou povolit zasílání hlasových zpráv.</string>
<string name="send_live_message">Odeslat živou zprávu</string>
<string name="live_message">Živé zprávy!</string>
<string name="connect_via_link_or_qr">Připojit se prostřednictvím odkazu / QR kódu</string>
<string name="thank_you_for_installing_simplex">Děkujeme za instalaci <xliff:g id="appNameFull">SimpleX Chat</xliff:g>!</string>
<string name="you_can_connect_to_simplex_chat_founder">Můžete se <font color="#0088ff">připojit k <xliff:g id="appNameFull">SimpleX Chat</xliff:g> vývojářům a položit jim případné dotazy a získat aktualizace</font>.</string>
<string name="to_connect_via_link_title">K připojení prostřednictvím odkazu</string>
<string name="if_you_received_simplex_invitation_link_you_can_open_in_browser">Pokud jste dostal <xliff:g id="appName">SimpleX Chat</xliff:g> zvací odkaz, Můžete ho otevřít v prohlížeči:</string>
<string name="if_you_choose_to_reject_the_sender_will_not_be_notified">Pokud zvolíte odmítnutí, odesílatel NEBUDE upozorněn.</string>
<string name="mobile_tap_open_in_mobile_app_then_tap_connect_in_app">📱 mobilní telefon: tap <b>Otevřete v mobil aplikaci</b>, potom klikněte <b>Připojit</b>.</string>
<string name="reject_contact_button">Odmítnout</string>
<string name="clear_chat_button">Čistá konverzace</string>
<string name="clear_chat_menu_action">Čistý</string>
<string name="delete_contact_menu_action">Smazat</string>
<string name="set_contact_name">Nastavit jméno kontaktu</string>
<string name="you_accepted_connection">Přijali jste spojení</string>
@@ -614,12 +610,12 @@
<string name="this_QR_code_is_not_a_link">Tento QR kód není odkaz!</string>
<string name="invalid_contact_link">Neplatný odkaz!</string>
<string name="this_link_is_not_a_valid_connection_link">Tento odkaz není platným odkazem pro připojení!</string>
<string name="if_you_cannot_meet_in_person_scan_QR_in_video_call_or_ask_for_invitation_link">If you cannot meet in person, you can <b>scan QR code in the video call</b>, or your contact can share an invitation link.</string>
<string name="connect_via_link">Connect via link</string>
<string name="connect_button">Connect</string>
<string name="paste_button">Paste</string>
<string name="this_string_is_not_a_connection_link">This string is not a connection link!</string>
<string name="you_can_also_connect_by_clicking_the_link">You can also connect by clicking the link. If it opens in the browser, click <b>Open in mobile app</b> button.</string>
<string name="if_you_cannot_meet_in_person_scan_QR_in_video_call_or_ask_for_invitation_link">Pokud se nemůžete setkat osobně, můžete <b>skenovat QR kód ve videohovoru</b> nebo může váš kontakt sdílet pozvánku.</string>
<string name="connect_via_link">Připojte se prostřednictvím odkazu</string>
<string name="connect_button">Připojit</string>
<string name="paste_button">Vložit</string>
<string name="this_string_is_not_a_connection_link">Tento řetězec není odkazem na připojení!</string>
<string name="you_can_also_connect_by_clicking_the_link">Můžete se také připojit kliknutím na odkaz. Pokud se otevře v prohlížeči, klikněte na tlačítko <b>Otevřít v mobil aplikaci</b>.</string>
<string name="is_not_verified">\"%s není ověřeno</string>
<string name="how_to_use_simplex_chat">Jak ji používat</string>
<string name="markdown_help">Nápověda k markdown</string>
@@ -644,23 +640,22 @@
<string name="network_use_onion_hosts">Použít hostitele .onion</string>
<string name="network_use_onion_hosts_prefer">Když je k dispozici</string>
<string name="network_use_onion_hosts_required">Povinné</string>
<string name="network_use_onion_hosts_prefer_desc">Onion hosts se použijí, pokud jsou k dispozici.</string>
<string name="network_use_onion_hosts_prefer_desc">Onion hostitelé se použijí, pokud jsou k dispozici.</string>
<string name="network_use_onion_hosts_no_desc">Onion hostitelé nebudou použiti.</string>
<string name="network_use_onion_hosts_prefer_desc_in_alert">Cibuloví hostitelé budou použiti, pokud budou k dispozici.</string>
<string name="network_use_onion_hosts_required_desc_in_alert">Pro připojení budou vyžadováni cibuloví hostitelé.</string>
<string name="network_use_onion_hosts_prefer_desc_in_alert">Onion hostitelé budou použiti, pokud budou k dispozici.</string>
<string name="network_use_onion_hosts_required_desc_in_alert">Pro připojení budou vyžadováni Onion hostitelé.</string>
<string name="network_session_mode_transport_isolation">Izolace přenosu</string>
<string name="network_session_mode_user_description">A separate TCP connection (and SOCKS credential) will be used <b>for each chat profile you have in the app</b>.</string>
<string name="network_session_mode_entity_description">A separate TCP connection (and SOCKS credential) will be used <b>for each contact and group member</b>.
\n<b>Please note</b>: if you have many connections, your battery and traffic consumption can be substantially higher and some connections may fail.</string>
<string name="appearance_settings">Appearance</string>
<string name="app_version_title">App version</string>
<string name="app_version_name">App version: v%s</string>
<string name="core_version">Core version: v%s</string>
<string name="core_build_timestamp">Core built at: %s</string>
<string name="delete_address__question">Delete address\?</string>
<string name="all_your_contacts_will_remain_connected">All your contacts will remain connected.</string>
<string name="contact_requests">Contact requests</string>
<string name="display_name__field">Display name:</string>
<string name="network_session_mode_entity_description">Oddělit TCP připojení (a SOCKS pověření) bude použito <b>pro všechny kontakty a členy skupin</b>. <b>Upozornění</b>: Pokud máte mnoho připojení, může být spotřeba baterie a provoz podstatně vyšší a některá připojení mohou selhat.</string>
<string name="appearance_settings">Vzhled</string>
<string name="app_version_title">Verze aplikace</string>
<string name="app_version_name">Verze aplikace: v%s</string>
<string name="core_version">Verze jádra: v%s</string>
<string name="core_build_timestamp">Jádro sestaveno na: %s</string>
<string name="delete_address__question">Smazat adresu\?</string>
<string name="all_your_contacts_will_remain_connected">Všechny vaše kontakty zůstanou připojeny.</string>
<string name="contact_requests">Žádosti o kontakt</string>
<string name="display_name__field">Zobrazované jméno:</string>
<string name="your_profile_is_stored_on_device_and_shared_only_with_contacts_simplex_cannot_see_it">Váš profil je uložen v zařízení a je sdílen pouze s vašimi kontakty. <xliff:g id="appName">SimpleX</xliff:g> servery váš profil nevidí.</string>
<string name="save_preferences_question">Uložit předvolby\?</string>
<string name="save_and_notify_contact">Uložit a upozornit kontakt</string>
@@ -688,17 +683,17 @@
<string name="privacy_redefined">Nové vymezení soukromí</string>
<string name="first_platform_without_user_ids">1. Platforma bez identifikátorů uživatelů - soukromá už od záměru.</string>
<string name="immune_to_spam_and_abuse">Odolná vůči spamu a zneužití</string>
<string name="to_protect_privacy_simplex_has_ids_for_queues">To protect privacy, instead of user IDs used by all other platforms, <xliff:g id="appName">SimpleX</xliff:g> has identifiers for message queues, separate for each of your contacts.</string>
<string name="many_people_asked_how_can_it_deliver">Mnoho lidí se ptalo: <i>if <xliff:g id="appName">SimpleX</xliff:g> has no user identifiers, how can it deliver messages\?</i></string>
<string name="you_control_servers_to_receive_your_contacts_to_send">You control through which server(s) <b>to receive</b> the messages, your contacts the servers you use to message them.</string>
<string name="read_more_in_github">Read more in our GitHub repository.</string>
<string name="read_more_in_github_with_link">Read more in our <font color="#0088ff">GitHub repository</font>.</string>
<string name="use_chat">Use chat</string>
<string name="onboarding_notifications_mode_subtitle">It can be changed later via settings.</string>
<string name="onboarding_notifications_mode_off">When app is running</string>
<string name="onboarding_notifications_mode_service">Instant</string>
<string name="onboarding_notifications_mode_off_desc"><b>Best for battery</b>. You will receive notifications only when the app is running, background service will NOT be used.</string>
<string name="onboarding_notifications_mode_periodic_desc"><b>Good for battery</b>. Background service checks for new messages every 10 minutes. You may miss calls and urgent messages.</string>
<string name="to_protect_privacy_simplex_has_ids_for_queues">K ochraně soukromí, místo uživatelských ID používaných všemi ostatními platformami, <xliff:g id="appName">SimpleX</xliff:g> identifikátory pro fronty zpráv, zvlášť pro každý z vašich kontaktů.</string>
<string name="many_people_asked_how_can_it_deliver">Mnoho lidí se ptalo: <i>if <xliff:g id="appName">SimpleX</xliff:g> nemá žádné identifikátory uživatelů, jak může doručovat zprávy\?</i></string>
<string name="you_control_servers_to_receive_your_contacts_to_send">Vy kontrolujete přez který server(y) <b>přijímat</b> zprávy, vaše kontakty - servery které používáte pro konverzaci.</string>
<string name="read_more_in_github">Další informace najdete v našem repozitáři GitHub.</string>
<string name="read_more_in_github_with_link">Další informace najdete v našem <font color="#0088ff">úložišti GitHub</font>.</string>
<string name="use_chat">Konverzovat</string>
<string name="onboarding_notifications_mode_subtitle">Lze změnit později v nastavení.</string>
<string name="onboarding_notifications_mode_off">Když je aplikace spuštěná</string>
<string name="onboarding_notifications_mode_service">Okamžitý</string>
<string name="onboarding_notifications_mode_off_desc"><b>Nejlepší pro baterii</b>. Budete přijímat oznámení pouze když aplikace běží, služba na pozadí NEBUDE použita.</string>
<string name="onboarding_notifications_mode_periodic_desc">&lt;Dobré pro baterii&lt;/b&gt;. Služba na pozadí kontroluje nové zprávy každých 10 minut. Můžete zmeškat hovory a naléhavé zprávy.</string>
<string name="onboarding_notifications_mode_service_desc"><b>Využívá více baterie</b>! Služba na pozadí je spuštěna vždy - oznámení se zobrazí, jakmile jsou zprávy k dispozici.</string>
<string name="paste_the_link_you_received">Vložení přijatého odkazu</string>
<string name="incoming_video_call">Příchozí videohovor</string>
@@ -752,7 +747,7 @@
<string name="delete_files_and_media_all">Odstranit všechny soubory</string>
<string name="delete_files_and_media_desc">Tuto akci nelze vrátit zpět - všechny přijaté a odeslané soubory a média budou smazány. Obrázky s nízkým rozlišením zůstanou zachovány.</string>
<string name="no_received_app_files">Žádné přijaté ani odeslané soubory</string>
<string name="total_files_count_and_size">%d souborů s celkovou velikostí %s</string>
<string name="total_files_count_and_size">%d soubor(ů) s celkovou velikostí %s</string>
<string name="chat_item_ttl_none">nikdy</string>
<string name="chat_item_ttl_seconds">\"%s vteřin(y)</string>
<string name="messages_section_title">Zprávy</string>
@@ -760,16 +755,16 @@
<string name="delete_messages_after">Smazat zprávy po</string>
<string name="enable_automatic_deletion_question">Povolit automatické mazání zpráv\?</string>
<string name="enable_automatic_deletion_message">Tuto akci nelze vzít zpět - zprávy odeslané a přijaté dříve, než bylo zvoleno, budou smazány. Může to trvat několik minut.</string>
<string name="error_changing_message_deletion">Error changing setting</string>
<string name="save_passphrase_in_keychain">Save passphrase in Keystore</string>
<string name="database_encrypted">Database encrypted!</string>
<string name="error_encrypting_database">Error encrypting database</string>
<string name="encrypt_database">Encrypt</string>
<string name="encrypted_with_random_passphrase">Database is encrypted using a random passphrase, you can change it.</string>
<string name="keychain_allows_to_receive_ntfs">Android Keystore will be used to securely store passphrase after you restart the app or change passphrase - it will allow receiving notifications.</string>
<string name="you_have_to_enter_passphrase_every_time">You have to enter passphrase every time the app starts - it is not stored on the device.</string>
<string name="encrypt_database_question">Encrypt database\?</string>
<string name="change_database_passphrase_question">Change database passphrase\?</string>
<string name="error_changing_message_deletion">Chyba změny nastavení</string>
<string name="save_passphrase_in_keychain">Uložit přístupovou frázi do úložiště klíčů</string>
<string name="database_encrypted">Databáze zašifrována!</string>
<string name="error_encrypting_database">Chyba šifrování databáze</string>
<string name="encrypt_database">Šifrovat</string>
<string name="encrypted_with_random_passphrase">Databáze je zašifrována pomocí náhodné přístupové fráze, můžete ji změnit.</string>
<string name="keychain_allows_to_receive_ntfs">K bezpečnému uložení přístupové fráze se použije úložiště klíčů Android, po restartování aplikace nebo změně přístupové fráze - umožní přijímání oznámení.</string>
<string name="you_have_to_enter_passphrase_every_time">Musíte zadat přístupovou frázi při každém spuštění aplikace - není uložena v zařízení.</string>
<string name="encrypt_database_question">Šifrovat databázi\?</string>
<string name="change_database_passphrase_question">Změnit přístupovou frázi databáze\?</string>
<string name="database_will_be_encrypted">Databáze bude zašifrována.</string>
<string name="database_encryption_will_be_updated">Šifrovací heslová fráze databáze bude aktualizována a uložena do úložiště klíčů.</string>
<string name="database_passphrase_will_be_updated">Šifrovací heslová fráze databáze bude aktualizována.</string>
@@ -835,10 +830,10 @@
<string name="group_member_status_intro_invitation">připojení (pozvánka na představení)</string>
<string name="group_member_status_accepted">připojení (přijato)</string>
<string name="group_member_status_announced">připojení (oznámeno)</string>
<string name="group_member_status_connected">connected</string>
<string name="group_member_status_connected">připojen</string>
<string name="group_member_status_complete">kompletní</string>
<string name="group_member_status_creator">tvůrce</string>
<string name="group_member_status_connecting">connecting</string>
<string name="group_member_status_connecting">připojování</string>
<string name="no_contacts_to_add">Žádné kontakty k přidání</string>
<string name="new_member_role">Nová role člena</string>
<string name="invite_to_group_button">Pozvat do skupiny</string>
@@ -559,7 +559,6 @@
<string name="your_privacy">Meine Privatsphäre</string>
<string name="protect_app_screen">App-Bildschirm schützen</string>
<string name="auto_accept_images">Bilder automatisch akzeptieren</string>
<string name="transfer_images_faster">Bilder schneller übertragen</string>
<string name="send_link_previews">Link-Vorschau senden</string>
<string name="full_backup">App-Datensicherung</string>
<!-- Settings sections -->
@@ -623,7 +623,6 @@
<string name="privacy_and_security">Vie privée et sécurité</string>
<string name="protect_app_screen">Protéger l\'écran de l\'app</string>
<string name="auto_accept_images">Images auto-acceptées</string>
<string name="transfer_images_faster">Transfert d\'images plus rapide</string>
<string name="full_backup">Sauvegarde des données de l\'app</string>
<string name="settings_section_title_you">VOUS</string>
<string name="settings_section_title_help">AIDE</string>
@@ -953,4 +952,18 @@
<string name="failed_to_create_user_title">Erreur lors de la création du profil !</string>
<string name="failed_to_create_user_duplicate_desc">Vous avez déjà un profil de chat avec ce même nom affiché. Veuillez choisir un autre nom.</string>
<string name="failed_to_create_user_duplicate_title">Nom d\'affichage en double !</string>
<string name="v4_4_french_interface">Interface en français</string>
<string name="v4_5_transport_isolation_descr">Par profil de chat (par défaut) ou par connexion (BETA).</string>
<string name="v4_5_italian_interface">Interface en italien</string>
<string name="v4_5_message_draft">Brouillon de message</string>
<string name="v4_5_reduced_battery_usage_descr">Plus d\'améliorations à venir !</string>
<string name="v4_5_multiple_chat_profiles">Différents profils de chat</string>
<string name="v4_5_message_draft_descr">Conserver le brouillon du dernier message, avec les pièces jointes.</string>
<string name="v4_5_reduced_battery_usage">Réduction de la consommation de batterie</string>
<string name="v4_5_private_filenames">Noms de fichiers privés</string>
<string name="v4_5_italian_interface_descr">Merci aux utilisateurs - contribuez via Weblate !</string>
<string name="v4_4_french_interface_descr">Merci aux utilisateurs - contribuez via Weblate !</string>
<string name="v4_5_private_filenames_descr">Pour préserver le fuseau horaire, les fichiers image/voix utilisent le système UTC.</string>
<string name="v4_5_transport_isolation">Isolation du transport</string>
<string name="v4_5_multiple_chat_profiles_descr">Différents noms, avatars et mode d\'isolation de transport.</string>
</resources>
@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>
@@ -742,7 +742,6 @@
<string name="settings_section_title_support">SUPPORTA SIMPLEX CHAT</string>
<string name="settings_section_title_themes">TEMI</string>
<string name="delete_chat_profile_action_cannot_be_undone_warning">Questa azione non può essere annullata: il tuo profilo, i contatti, i messaggi e i file andranno persi in modo irreversibile.</string>
<string name="transfer_images_faster">Trasferisci immagini più velocemente</string>
<string name="settings_section_title_you">TU</string>
<string name="your_chat_database">Il tuo database della chat</string>
<string name="your_current_chat_database_will_be_deleted_and_replaced_with_the_imported_one">Il tuo attuale database di chat verrà ELIMINATO e SOSTITUITO con quello importato.
@@ -24,4 +24,63 @@
<string name="smp_servers_add">サーバを追加…</string>
<string name="network_enable_socks_info">SOCKSプロキシ(ポート9050)経由で接続しますか?(※設定する前にプロキシ起動が必要※)</string>
<string name="users_delete_all_chats_deleted">全チャットとメッセージが削除されます(※元に戻せません※)!</string>
</resources>
<string name="allow_your_contacts_to_send_voice_messages">送信相手からの音声メッセージを許可する。</string>
<string name="both_you_and_your_contact_can_send_voice">あなたと連絡相手が音声メッセージを送信できます。</string>
<string name="onboarding_notifications_mode_periodic_desc"><b>電池省エネに良い</b>:バックグラウンド機能で10分毎に新着メッセージを確認します。通話と緊急メッセージを見逃す可能性があります。</string>
<string name="icon_descr_audio_off">音声オフ</string>
<string name="attach">添付する</string>
<string name="app_version_code">アプリ・ビルド番号: %s</string>
<string name="all_your_contacts_will_remain_connected">あなたの連絡先が繋がったまま継続します。</string>
<string name="accept_requests">リクエストを承諾</string>
<string name="accept_automatically">自動的に</string>
<string name="icon_descr_audio_on">音声オン</string>
<string name="integrity_msg_bad_hash">メッセージのハッシュ値問題</string>
<string name="integrity_msg_bad_id">メッセージIDの問題</string>
<string name="allow_verb">許可</string>
<string name="allow_voice_messages_question">音声メッセージを許可しますか?</string>
<string name="back">戻る</string>
<string name="appearance_settings">見た目</string>
<string name="app_version_title">アプリのバージョン</string>
<string name="app_version_name">アプリのバージョン: v%s</string>
<string name="network_session_mode_user_description"><b>アプリ内の各チャットプロフィールに、</b>.連絡先毎にそれぞれのTCP接続(とSOCKS資格情報)が使われます。</string>
<string name="network_session_mode_entity_description"><b>各連絡先とグループに、</b>それぞれのTCP接続(とSOCKS資格情報)が使われます。
\n<b>※注意※</b> 接続が多かったら、電池とデータの使用量が増えて、切断する可能性もあります。</string>
<string name="bold">太文字</string>
<string name="icon_descr_audio_call">音声通話</string>
<string name="settings_audio_video_calls">音声とビデオ通話</string>
<string name="impossible_to_recover_passphrase"><b>※注意※</b>:喪失したら、パスフレーズの回復・変更ができません。</string>
<string name="all_group_members_will_remain_connected">グループ全員の接続が継続します。</string>
<string name="allow_your_contacts_to_send_disappearing_messages">送信相手が消えるメッセージを送るのを許可する。</string>
<string name="allow_your_contacts_irreversibly_delete">送信相手が永久メッセージ削除するのを許可する。</string>
<string name="allow_voice_messages_only_if">送信相手も音声メッセージを許可する時のみに許可する。</string>
<string name="both_you_and_your_contact_can_send_disappearing">あなたと連絡相手が消えるメッセージを送信できます。</string>
<string name="v4_2_auto_accept_contact_requests">連絡先を自動的に承諾</string>
<string name="chat_preferences_always">常に</string>
<string name="notifications_mode_service">常にオン</string>
<string name="clear_chat_warning">全てのメッセージが削除されます(※注意:元に戻せません!※)。削除されるのは片方あなたのメッセージのみ</string>
<string name="allow_disappearing_messages_only_if">送信相手も消えるメッセージ機能を許可する時のみに許可する。</string>
<string name="allow_irreversible_message_deletion_only_if">送信相手も永久メッセージ削除を許可する時のみに許可する。</string>
<string name="allow_to_delete_messages">送信済みメッセージの永久削除を許可</string>
<string name="allow_to_send_disappearing">消えるメッセージの送信を許可</string>
<string name="allow_direct_messages">メンバーへのダイレクトメッセージを許可</string>
<string name="allow_to_send_voice">音声メッセージの送信を許可</string>
<string name="notifications_mode_off_desc">アクティブの時のみに通知が出ます。バックグラウンド通知サービスは起動されません。</string>
<string name="keychain_is_storing_securely">Androidキーストアはパスフレーズの保管に使われます。通知機能に必要です。</string>
<string name="keychain_allows_to_receive_ntfs">再起動時とパスフレーズ変更時にAndroidキーストアがパスフレーズの保管に使われます。通知機能に必要です。</string>
<string name="answer_call">通話に応答</string>
<string name="settings_section_title_icon">アプリのアイコン</string>
<string name="full_backup">アプリデータのバックアップ</string>
<string name="incognito_random_profile_from_contact_description">このリンクの送信元にランダムなプロフィール(ダミー)が送られます。</string>
<string name="incognito_random_profile_description">連絡先にランダムなプロフィール(ダミー)が送られます。</string>
<string name="audio_call_no_encryption">音声通話 (エンドツーエンド暗号化なし)</string>
<string name="icon_descr_asked_to_receive">画像受信を依頼しました。</string>
<string name="auth_unavailable">認証不可能</string>
<string name="auto_accept_images">画像を自動的に受信</string>
<string name="notifications_mode_service_desc">バックグラウンド機能が常にオンで、メッセージが到着次第に通知が出ます。</string>
<string name="add_new_contact_to_create_one_time_QR_code"><b>新しい連絡先を追加</b>:使い捨てのQRコードを発行</string>
<string name="turning_off_service_and_periodic">電池省エネをオンに、バックグラウンド機能と定期的な受信依頼をオフにします。設定メニューにて変更できます。</string>
<string name="onboarding_notifications_mode_off_desc"><b>電池消費が最少</b>:アプリがアクティブ時のみに通知が出ます。</string>
<string name="it_can_disabled_via_settings_notifications_still_shown"><b>設定メニューにてオフにできます。</b> アプリがアクティブ時に通知が出ます。</string>
<string name="both_you_and_your_contacts_can_delete">あなたと連絡相手が送信済みメッセージを永久削除できます。</string>
<string name="scan_QR_code_to_connect_to_contact_who_shows_QR_code"><b>QRコードを読み込み</b>:連絡相手のQRコードをスキャンすると繋がります。</string>
</resources>
@@ -404,4 +404,214 @@
<string name="failed_to_parse_chats_title">Kan chats niet laden</string>
<string name="simplex_link_mode_full">Volledige link</string>
<string name="integrity_msg_duplicate">dubbel bericht</string>
<string name="invalid_connection_link">Ongeldige verbindingslink</string>
<string name="service_notifications_disabled">Onmiddelijke meldingen zijn uitgeschakeld!</string>
<string name="service_notifications">Onmiddellijke berichten!</string>
<string name="notification_preview_new_message">nieuw bericht</string>
<string name="icon_descr_image_snd_complete">Afbeelding verzonden</string>
<string name="live_message">Live bericht!</string>
<string name="if_you_received_simplex_invitation_link_you_can_open_in_browser">Als je een uitnodigingslink voor <xliff:g id="appName">SimpleX Chat</xliff:g> hebt ontvangen, kun je deze in je browser openen:</string>
<string name="onboarding_notifications_mode_subtitle">Dit kan later worden gewijzigd via instellingen.</string>
<string name="join_group_question">Deelnemen aan groep\?</string>
<string name="icon_descr_add_members">Nodig leden uit</string>
<string name="no_contacts_selected">Geen contacten geselecteerd</string>
<string name="v4_4_live_messages">Live berichten</string>
<string name="icon_descr_instant_notifications">Onmiddellijke meldingen</string>
<string name="notification_new_contact_request">Nieuw contactverzoek</string>
<string name="auth_log_in_using_credential">Log in met uw inloggegevens</string>
<string name="message_delivery_error_desc">Hoogstwaarschijnlijk heeft dit contact de verbinding met jou verwijderd.</string>
<string name="delete_message_cannot_be_undone_warning">Bericht wordt verwijderd - dit kan niet ongedaan worden gemaakt!</string>
<string name="large_file">Groot bestand!</string>
<string name="mark_read">Markeer gelezen</string>
<string name="mark_unread">Markeer als ongelezen</string>
<string name="mute_chat">Stom</string>
<string name="if_you_cannot_meet_in_person_scan_QR_in_video_call_or_ask_for_invitation_link">Als u elkaar niet persoonlijk kunt ontmoeten, kunt u <b> de QR-code scannen in het videogesprek </b>, of uw contactpersoon kan een uitnodigingslink delen.</string>
<string name="if_you_cannot_meet_in_person_show_QR_in_video_call_or_via_another_channel">Als je elkaar niet persoonlijk kunt ontmoeten, <b>toon je de QR-code in het videogesprek</b> of deel je de link.</string>
<string name="invalid_QR_code">Ongeldige QR-code</string>
<string name="icon_descr_more_button">Meer</string>
<string name="incorrect_code">Onjuiste beveiligingscode!</string>
<string name="mark_code_verified">Markeer geverifieerd</string>
<string name="how_to_use_simplex_chat">Hoe te gebruiken</string>
<string name="markdown_help">Markdown-hulp</string>
<string name="markdown_in_messages">Markdown in berichten</string>
<string name="network_settings_title">Netwerkinstellingen</string>
<string name="how_to_use_markdown">Markdown gebruiken</string>
<string name="italic">cursief</string>
<string name="how_it_works">Hoe het werkt</string>
<string name="callstatus_missed">gemiste oproep</string>
<string name="how_simplex_works">Hoe <xliff:g id="appName">SimpleX</xliff:g> werkt</string>
<string name="many_people_asked_how_can_it_deliver">Veel mensen vroegen: <i>als <xliff:g id="appName">SimpleX</xliff:g> geen gebruikers-ID\'s heeft, hoe kan het dan berichten bezorgen\?</i></string>
<string name="incoming_audio_call">Inkomende audio-oproep</string>
<string name="incoming_video_call">Inkomend videogesprek</string>
<string name="ignore">Negeren</string>
<string name="status_no_e2e_encryption">geen e2e-encryptie</string>
<string name="import_database_question">Chatdatabase importeren\?</string>
<string name="chat_item_ttl_none">nooit</string>
<string name="no_received_app_files">Geen ontvangen of verzonden bestanden</string>
<string name="alert_title_group_invitation_expired">Uitnodiging verlopen!</string>
<string name="rcv_group_event_member_left">Verlaten</string>
<string name="group_member_status_left">Verlaten</string>
<string name="group_member_status_invited">uitgenodigd</string>
<string name="button_leave_group">Groep verlaten</string>
<string name="info_row_local_name">Lokale naam</string>
<string name="group_unsupported_incognito_main_profile_sent">Incognitomodus wordt hier niet ondersteund - uw hoofdprofiel wordt naar groepsleden verzonden</string>
<string name="users_delete_data_only">Alleen lokale profielgegevens</string>
<string name="message_deletion_prohibited_in_chat">Het onomkeerbaar verwijderen van berichten is verboden in deze groep.</string>
<string name="v4_3_improved_privacy_and_security_desc">App-scherm verbergen in de recente apps.</string>
<string name="settings_section_title_incognito">Incognito modus</string>
<string name="messages_section_title">Berichten</string>
<string name="new_passphrase">Nieuwe wachtwoordzin…</string>
<string name="keychain_error">Keychain fout</string>
<string name="join_group_button">Word lid van</string>
<string name="leave_group_question">Groep verlaten\?</string>
<string name="new_member_role">Nieuwe ledenrol</string>
<string name="no_contacts_to_add">Geen contacten om toe te voegen</string>
<string name="incognito_info_allows">Het maakt het mogelijk om veel anonieme verbindingen te hebben zonder enige gedeelde gegevens tussen hen in een enkel chatprofiel.</string>
<string name="theme_light">Licht</string>
<string name="chat_preferences_no">Nee</string>
<string name="v4_5_multiple_chat_profiles">Meerdere chatprofielen</string>
<string name="v4_5_italian_interface">Italiaanse interface</string>
<string name="v4_5_message_draft">Concept bericht</string>
<string name="v4_5_reduced_battery_usage_descr">Meer verbeteringen volgen snel!</string>
<string name="button_add_members">Nodig leden uit</string>
<string name="notification_display_mode_hidden_desc">Verberg contact en bericht</string>
<string name="turn_off_battery_optimization">Om het te gebruiken &lt;b xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\"&gt;batterijoptimalisatie uitschakelen&lt;/b&gt; voor &lt;xliff:g xmlns:xliff=\"urn:oasis: names:tc:xliff:document:1.2\" id=\"appName\"&gt;SimpleX&lt;/xliff:g&gt; in het volgende dialoogvenster. Anders worden de meldingen uitgeschakeld.</string>
<string name="if_you_choose_to_reject_the_sender_will_not_be_notified">Als u ervoor kiest om te weigeren, wordt de afzender NIET op de hoogte gesteld.</string>
<string name="onboarding_notifications_mode_service">Onmiddellijk</string>
<string name="rcv_group_event_member_added">uitgenodigd <xliff:g id="member profile" example="alice (Alice)">%1$s</xliff:g></string>
<string name="group_invitation_item_description">uitnodiging voor groep <xliff:g id="group_name">%1$s</xliff:g></string>
<string name="invite_to_group_button">Uitnodigen voor groep</string>
<string name="join_group_incognito_button">Doe incognito mee</string>
<string name="group_preview_join_as">lid worden als %s</string>
<string name="alert_text_skipped_messages_it_can_happen_when">Het kan gebeuren wanneer:
\n1. De berichten op de server verlopen als ze 30 dagen niet zijn ontvangen,
\n2. De server die u gebruikt om de berichten van deze contactpersoon te ontvangen, is bijgewerkt en opnieuw opgestart.
\n3. De verbinding is verbroken.
\nMaak verbinding met de ontwikkelaars via Instellingen om de updates over de servers te ontvangen.
\nWe zullen serverredundantie toevoegen om verloren berichten te voorkomen.</string>
<string name="joining_group">Deel nemen aan groep</string>
<string name="leave_group_button">Verlaten</string>
<string name="group_member_role_member">lid</string>
<string name="image_descr_link_preview">link voorbeeldafbeelding</string>
<string name="member_info_section_title_member">LID</string>
<string name="settings_section_title_messages">BERICHTEN</string>
<string name="mobile_tap_open_in_mobile_app_then_tap_connect_in_app">📱 mobiel: tik op <b>Openen in mobiele app</b> en tik vervolgens op <b>Verbinden</b> in de app.</string>
<string name="member_will_be_removed_from_group_cannot_be_undone">Lid wordt uit de groep verwijderd - dit kan niet ongedaan worden gemaakt!</string>
<string name="message_delivery_error_title">Fout bij bezorging van bericht</string>
<string name="delete_message_mark_deleted_warning">Bericht wordt gemarkeerd voor verwijdering. De ontvanger(s) kunnen dit bericht onthullen.</string>
<string name="network_status">Netwerk status</string>
<string name="image_descr">Afbeelding</string>
<string name="image_saved">Afbeelding opgeslagen in Galerij</string>
<string name="import_database_confirmation">Importeren</string>
<string name="import_database">Database importeren</string>
<string name="v4_3_improved_privacy_and_security">Verbeterde privacy en veiligheid</string>
<string name="image_will_be_received_when_contact_is_online">De afbeelding wordt ontvangen wanneer uw contact online is, even geduld a.u.b. of kijk later!</string>
<string name="incognito_info_protects">De incognitomodus beschermt de privacy van uw hoofdprofielnaam en -afbeelding - voor elk nieuw contact wordt een nieuw willekeurig profiel gemaakt.</string>
<string name="new_database_archive">Nieuw database-archief</string>
<string name="no_details">geen details</string>
<string name="conn_level_desc_indirect">indirect (<xliff:g id="conn_level">%1$s</xliff:g>)</string>
<string name="thousand_abbreviation">k</string>
<string name="notification_preview_mode_message">Bericht tekst</string>
<string name="settings_notification_preview_title">Meldingsvoorbeeld</string>
<string name="settings_notifications_mode_title">Meldingsservice</string>
<string name="notifications">Meldingen</string>
<string name="invalid_contact_link">Ongeldige link!</string>
<string name="smp_servers_invalid_address">Ongeldig serveradres!</string>
<string name="install_simplex_chat_for_terminal">Installeer <xliff:g id="appNameFull">SimpleX Chat</xliff:g> voor terminal</string>
<string name="how_to">Hoe</string>
<string name="how_to_use_your_servers">Hoe u uw servers gebruikt</string>
<string name="network_and_servers">Netwerk &amp; servers</string>
<string name="enter_one_ICE_server_per_line">ICE-servers (één per lijn)</string>
<string name="ensure_ICE_server_address_are_correct_format_and_unique">Zorg ervoor dat WebRTC ICE-serveradressen de juiste indeling hebben, regelgescheiden zijn en niet gedupliceerd zijn.</string>
<string name="network_disable_socks_info">Als u bevestigt, kunnen de berichtenservers uw IP-adres zien en uw provider - met welke servers u verbinding maakt.</string>
<string name="network_use_onion_hosts_no">Nee</string>
<string name="immune_to_spam_and_abuse">Immuun voor spam en misbruik</string>
<string name="make_private_connection">Maak een privéverbinding</string>
<string name="message_deletion_prohibited">Het onomkeerbaar verwijderen van berichten is verboden in deze chat.</string>
<string name="new_in_version">Nieuw in %s</string>
<string name="v4_3_voice_messages_desc">Max 40 seconden, direct ontvangen.</string>
<string name="v4_3_improved_server_configuration">Verbeterde serverconfiguratie</string>
<string name="v4_3_irreversible_message_deletion">Onomkeerbare berichtverwijdering</string>
<string name="rcv_group_event_invited_via_your_group_link">uitgenodigd via je groepslink</string>
<string name="incognito">Incognito</string>
<string name="icon_descr_call_missed">Gemiste oproep</string>
<string name="description_via_contact_address_link_incognito">incognito via link naar contactadres</string>
<string name="description_via_group_link_incognito">incognito via groepslink</string>
<string name="description_via_one_time_link_incognito">incognito via eenmalige link</string>
<string name="invalid_chat">ongeldige chat</string>
<string name="invalid_data">onjuiste data</string>
<string name="invalid_message_format">ongeldig berichtformaat</string>
<string name="display_name_invited_to_connect">uitgenodigd om te verbinden</string>
<string name="live">LIVE</string>
<string name="ensure_smp_server_address_are_correct_format_and_unique">Zorg ervoor dat SMP-serveradressen de juiste indeling hebben, regelgescheiden zijn en niet gedupliceerd zijn.</string>
<string name="marked_deleted_description">gemarkeerd als verwijderd</string>
<string name="please_check_correct_link_and_maybe_ask_for_a_new_one">Controleer of u de juiste link heeft gebruikt of vraag uw contactpersoon om u een andere te sturen.</string>
<string name="image_descr_profile_image">profielfoto</string>
<string name="privacy_redefined">Privacy opnieuw gedefinieerd</string>
<string name="privacy_and_security">Privacy en beveiliging</string>
<string name="network_error_desc">Controleer uw netwerkverbinding met <xliff:g id="serverHost" example="smp.simplex.im">%1$s</xliff:g> en probeer het opnieuw.</string>
<string name="error_smp_test_certificate">Mogelijk is de certificaatvingerafdruk in het serveradres onjuist</string>
<string name="periodic_notifications">Periodieke meldingen</string>
<string name="auth_open_chat_console">Chatconsole openen</string>
<string name="toast_permission_denied">Geen toestemming!</string>
<string name="icon_descr_profile_image_placeholder">profielafbeelding tijdelijke aanduiding</string>
<string name="one_time_link">Eenmalige uitnodigingslink</string>
<string name="paste_button">Plakken</string>
<string name="smp_servers_preset_address">Vooraf ingesteld serveradres</string>
<string name="network_use_onion_hosts_no_desc_in_alert">Onion hosts worden niet gebruikt.</string>
<string name="onboarding_notifications_mode_title">Privé meldingen</string>
<string name="paste_the_link_you_received">Plak de ontvangen link</string>
<string name="onboarding_notifications_mode_periodic">Periodiek</string>
<string name="open_verb">Open</string>
<string name="open_simplex_chat_to_accept_call">Open <xliff:g id="appNameFull">SimpleX Chat</xliff:g> om de oproep te accepteren</string>
<string name="call_connection_peer_to_peer">peer-to-peer</string>
<string name="notifications_will_be_hidden">Meldingen worden alleen afgeleverd totdat de app stopt!</string>
<string name="restore_passphrase_not_found_desc">Wachtwoordzin niet gevonden in Keystore, voer deze handmatig in. Dit kan zijn gebeurd als u de gegevens van de app hebt hersteld met een back-uptool. Als dit niet het geval is, neem dan contact op met de ontwikkelaars.</string>
<string name="users_delete_with_connections">Profiel- en serververbindingen</string>
<string name="chat_preferences_off">uit</string>
<string name="chat_preferences_on">aan</string>
<string name="only_you_can_send_disappearing">Alleen jij kunt verdwijnende berichten verzenden.</string>
<string name="only_your_contact_can_send_disappearing">Alleen uw contactpersoon kan verdwijnende berichten verzenden.</string>
<string name="only_you_can_delete_messages">Alleen jij kunt berichten onomkeerbaar verwijderen (je contactpersoon kan ze markeren voor verwijdering).</string>
<string name="feature_offered_item_with_param">aangeboden %s: %2s</string>
<string name="old_database_archive">Oud database-archief</string>
<string name="enter_correct_current_passphrase">Voer de juiste huidige wachtwoordzin in.</string>
<string name="group_member_role_owner">eigenaar</string>
<string name="network_option_ping_count">PING-telling</string>
<string name="network_option_ping_interval">PING-interval</string>
<string name="v4_5_message_draft_descr">Bewaar het laatste berichtconcept, met bijlagen.</string>
<string name="v4_5_private_filenames">Privé bestandsnamen</string>
<string name="images_limit_desc">Er kunnen slechts 10 afbeeldingen tegelijk worden verzonden</string>
<string name="enter_passphrase_notification_title">Wachtwoordzin is nodig</string>
<string name="feature_off">uit</string>
<string name="add_contact">Eenmalige uitnodigingslink</string>
<string name="network_use_onion_hosts_required_desc_in_alert">Onion hosts zijn vereist voor verbinding.</string>
<string name="only_group_owners_can_change_prefs">Alleen groepseigenaren kunnen groepsvoorkeuren wijzigen.</string>
<string name="only_stored_on_members_devices">(alleen opgeslagen door groepsleden)</string>
<string name="paste_connection_link_below_to_connect">Plak de link die je hebt ontvangen in het vak hieronder om verbinding te maken met je contactpersoon.</string>
<string name="smp_servers_preset_server">Vooraf ingestelde server</string>
<string name="periodic_notifications_disabled">Periodieke meldingen zijn uitgeschakeld!</string>
<string name="icon_descr_server_status_pending">In behandeling</string>
<string name="only_group_owners_can_enable_voice">Alleen groepseigenaren kunnen spraakberichten inschakelen.</string>
<string name="ask_your_contact_to_enable_voice">Vraag uw contactpersoon om het verzenden van spraakberichten in te schakelen.</string>
<string name="ok">OK</string>
<string name="network_use_onion_hosts_required_desc">Onion hosts zijn vereist voor verbinding.</string>
<string name="network_use_onion_hosts_prefer_desc">Onion hosts worden gebruikt indien beschikbaar.</string>
<string name="network_use_onion_hosts_prefer_desc_in_alert">Onion hosts worden gebruikt indien beschikbaar.</string>
<string name="network_use_onion_hosts_no_desc">Onion hosts worden niet gebruikt.</string>
<string name="opensource_protocol_and_code_anybody_can_run_servers">Open-source protocol en code iedereen kan de servers draaien.</string>
<string name="people_can_connect_only_via_links_you_share">Mensen kunnen alleen verbinding met u maken via de links die u deelt.</string>
<string name="only_your_contact_can_delete">Alleen uw contactpersoon kan berichten onherroepelijk verwijderen (u kunt ze markeren voor verwijdering).</string>
<string name="only_you_can_send_voice">Alleen jij kunt spraakberichten verzenden.</string>
<string name="only_your_contact_can_send_voice">Alleen uw contactpersoon kan spraakberichten verzenden.</string>
<string name="prohibit_message_deletion">Verbied het onomkeerbaar verwijderen van berichten.</string>
<string name="feature_offered_item">aangeboden %s</string>
<string name="store_passphrase_securely_without_recover">Sla de wachtwoordzin veilig op. Als u deze kwijtraakt, heeft u GEEN toegang tot de chat.</string>
<string name="store_passphrase_securely">Bewaar de wachtwoordzin veilig, u kunt deze NIET wijzigen als u deze kwijtraakt.</string>
<string name="open_chat">Chat openen</string>
<string name="restore_database_alert_desc">Voer het vorige wachtwoord in na het herstellen van de databaseback-up. Deze actie kan niet ongedaan gemaakt worden.</string>
<string name="icon_descr_call_pending_sent">Oproep in behandeling</string>
<string name="simplex_link_mode_browser_warning">Het openen van de link in de browser kan de privacy en beveiliging van de verbinding verminderen. Niet-vertrouwde SimpleX-links worden rood weergegeven.</string>
<string name="contact_developers">Werk de app bij en neem contact op met de ontwikkelaars.</string>
<string name="only_client_devices_store_contacts_groups_e2e_encrypted_messages">Alleen client-apparaten slaan gebruikersprofielen, contacten, groepen en berichten op die zijn verzonden met <b>2-laags end-to-end-codering</b>.</string>
</resources>
@@ -560,7 +560,6 @@
<string name="your_privacy">Конфиденциальность</string>
<string name="protect_app_screen">Защитить экран приложения</string>
<string name="auto_accept_images">Автоприем изображений</string>
<string name="transfer_images_faster">Передавать изображения быстрее</string>
<string name="send_link_previews">Отправлять картинки ссылок</string>
<string name="full_backup">Резервная копия данных</string>
<!-- Settings sections -->
@@ -223,4 +223,37 @@
<string name="save_passphrase_in_keychain">在密钥库中保存密码</string>
<string name="simplex_service_notification_title"><xliff:g id="appNameFull">SimpleX Chat</xliff:g> 服务</string>
<string name="settings_notifications_mode_title">通知服务</string>
<string name="confirm_new_passphrase">确认新口令…</string>
<string name="group_member_status_complete">完整的</string>
<string name="group_member_status_connected">连接的</string>
<string name="chat_preferences">聊天偏好</string>
<string name="settings_section_title_chats">聊天</string>
<string name="clear_verb">清空</string>
<string name="clear_chat_menu_action">清空</string>
<string name="clear_chat_button">清除聊天记录</string>
<string name="clear_chat_question">清除聊天记录?</string>
<string name="chat_with_developers">与开发者聊天</string>
<string name="clear_contacts_selection_button">清除</string>
<string name="colored">有色</string>
<string name="callstate_connected">连接的</string>
<string name="connect_button">连接</string>
<string name="connect_via_link_verb">连接</string>
<string name="choose_file">选择文件</string>
<string name="network_session_mode_user">聊天资料</string>
<string name="v4_5_transport_isolation_descr">按聊天资料(默认)或按连接(BETA)。</string>
<string name="smp_servers_check_address">检查服务器地址并再试一次。</string>
<string name="clear_verification">清晰的验证</string>
<string name="icon_descr_close_button">关闭键</string>
<string name="configure_ICE_servers">配置ICE服务器</string>
<string name="confirm_verb">确认</string>
<string name="auth_confirm_credential">确认您的证书</string>
<string name="server_connected">连接的</string>
<string name="icon_descr_server_status_connected">连接的</string>
<string name="smp_server_test_connect">连接</string>
<string name="notification_contact_connected">连接的</string>
<string name="server_connecting">连接的</string>
<string name="group_member_status_connecting">连接的</string>
<string name="notifications_mode_periodic_desc">每10分钟检查一次新消息,最长1分钟</string>
<string name="rcv_group_event_member_connected">连接的</string>
<string name="v4_4_verify_connection_security_desc">与你的联系人比较安全码</string>
</resources>
@@ -1,2 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="chat_item_ttl_week">1 個星期</string>
<string name="accept_requests">接受請求</string>
<string name="a_plus_b">a + b</string>
<string name="about_simplex">關於 SimpleX</string>
<string name="accept_call_on_lock_screen">接受</string>
<string name="accept_feature">接受</string>
<string name="chat_item_ttl_day">1 天</string>
<string name="chat_item_ttl_month">1 個月</string>
<string name="accept_contact_button">接受</string>
<string name="about_simplex_chat">關於<xliff:g id="appNameFull">SimpleX Chat</xliff:g></string>
<string name="accept_connection_request__question">接受新連線要求\?</string>
<string name="callstatus_accepted">已接受電話</string>
<string name="network_enable_socks_info">要在端口 9050 啟動 SOCKS 代理伺服器嗎\? 在啟用這個選項之前,必須先啟動代理伺服器。</string>
<string name="group_member_role_admin">管理員</string>
<string name="above_then_preposition_continuation">以上,然後:</string>
<string name="smp_servers_preset_add">加入預設伺服器</string>
<string name="smp_servers_add">新增伺服器…</string>
<string name="accept">接受</string>
</resources>
@@ -28,6 +28,7 @@
<string name="unknown_message_format">unknown message format</string>
<string name="invalid_message_format">invalid message format</string>
<string name="live">LIVE</string>
<string name="moderated_description">moderated</string>
<string name="invalid_chat">invalid chat</string>
<string name="invalid_data">invalid data</string>
@@ -673,7 +674,6 @@
<string name="your_privacy">Your privacy</string>
<string name="protect_app_screen">Protect app screen</string>
<string name="auto_accept_images">Auto-accept images</string>
<string name="transfer_images_faster">Transfer images faster</string>
<string name="send_link_previews">Send link previews</string>
<string name="full_backup">App data backup</string>
@@ -1,3 +1,4 @@
<paths>
<files-path name="my_files" path="/"/>
<files-path name="app_temp" path="../app_temp"/>
</paths>
+49 -1
View File
@@ -133,7 +133,7 @@ func imageHasAlpha(_ img: UIImage) -> Bool {
context.draw(cgImage, in: CGRect(x: 0, y: 0, width: cgImage.width, height: cgImage.height))
if let data = context.data {
let data = data.assumingMemoryBound(to: UInt8.self)
let size = cgImage.width * cgImage.height
let size = cgImage.width * cgImage.height * 4
var i = 0
while i < size {
if data[i] < 255 { return true }
@@ -203,3 +203,51 @@ func dropImagePrefix(_ s: String) -> String {
private func dropPrefix(_ s: String, _ prefix: String) -> String {
s.hasPrefix(prefix) ? String(s.dropFirst(prefix.count)) : s
}
extension UIImage {
func replaceColor(_ from: UIColor, _ to: UIColor) -> UIImage {
if let cgImage = cgImage {
let colorSpace = CGColorSpaceCreateDeviceRGB()
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue)
if let context = CGContext(data: nil, width: cgImage.width, height: cgImage.height, bitsPerComponent: 8, bytesPerRow: cgImage.width * 4, space: colorSpace, bitmapInfo: bitmapInfo.rawValue) {
context.draw(cgImage, in: CGRect(x: 0, y: 0, width: cgImage.width, height: cgImage.height))
if let data = context.data {
var fromAlpha: CGFloat = 0
var fromRed: CGFloat = 0
var fromGreen: CGFloat = 0
var fromBlue: CGFloat = 0
var toAlpha: CGFloat = 0
var toRed: CGFloat = 0
var toGreen: CGFloat = 0
var toBlue: CGFloat = 0
from.getRed(&fromRed, green: &fromGreen, blue: &fromBlue, alpha: &fromAlpha)
to.getRed(&toRed, green: &toGreen, blue: &toBlue, alpha: &toAlpha)
let fAlpha = UInt8(UInt8(fromAlpha * 255))
let fRed = UInt8(fromRed * 255)
let fGreen = UInt8(fromGreen * 255)
let fBlue = UInt8(fromBlue * 255)
let tAlpha = UInt8(toAlpha * 255)
let tRed = UInt8(toRed * 255)
let tGreen = UInt8(toGreen * 255)
let tBlue = UInt8(toBlue * 255)
let data = data.assumingMemoryBound(to: UInt8.self)
let size = cgImage.width * cgImage.height * 4
var i = 0
while i < size {
if data[i] == fAlpha && data[i + 1] == fRed && data[i + 2] == fGreen && data[i + 3] == fBlue {
data[i + 0] = tAlpha
data[i + 1] = tRed
data[i + 2] = tGreen
data[i + 3] = tBlue
}
i += 4
}
}
if let img = context.makeImage() {
return UIImage(cgImage: img)
}
}
}
return self
}
}
+2 -3
View File
@@ -636,13 +636,12 @@ func apiChatUnread(type: ChatType, id: Int64, unreadChat: Bool) async throws {
}
func receiveFile(user: User, fileId: Int64) async {
let inline = privacyTransferImagesInlineGroupDefault.get()
if let chatItem = await apiReceiveFile(fileId: fileId, inline: inline) {
if let chatItem = await apiReceiveFile(fileId: fileId) {
DispatchQueue.main.async { chatItemSimpleUpdate(user, chatItem) }
}
}
func apiReceiveFile(fileId: Int64, inline: Bool) async -> AChatItem? {
func apiReceiveFile(fileId: Int64, inline: Bool? = nil) async -> AChatItem? {
let r = await chatSendCmd(.receiveFile(fileId: fileId, inline: inline))
let am = AlertManager.shared
if case let .rcvFileAccepted(_, chatItem) = r { return chatItem }
@@ -228,8 +228,9 @@ struct ActiveCallOverlay: View {
Text(call.callState.text)
HStack {
Text(call.encryptionStatus)
if let connInfo = call.connectionInfo?.text {
Text("(") + Text(connInfo) + Text(")")
if let connInfo = call.connectionInfo {
// Text("(") + Text(connInfo.text) + Text(", \(connInfo.protocolText))")
Text("(") + Text(connInfo.text) + Text(")")
}
}
}
+30 -13
View File
@@ -362,22 +362,37 @@ struct ConnectionInfo: Codable, Equatable {
var remoteCandidate: RTCIceCandidate?
var text: LocalizedStringKey {
get {
if localCandidate?.candidateType == .host && remoteCandidate?.candidateType == .host {
return "peer-to-peer"
} else if localCandidate?.candidateType == .relay && remoteCandidate?.candidateType == .relay {
return "via relay"
} else {
let unknown = NSLocalizedString("unknown", comment: "connection info")
return "\(localCandidate?.candidateType?.rawValue ?? unknown) / \(remoteCandidate?.candidateType?.rawValue ?? unknown)"
}
let local = localCandidate?.candidateType
let remote = remoteCandidate?.candidateType
if local == .host && remote == .host {
return "peer-to-peer"
} else if local == .relay && remote == .relay {
return "via relay"
} else {
let unknown = NSLocalizedString("unknown", comment: "connection info")
return "\(local?.rawValue ?? unknown) / \(remote?.rawValue ?? unknown)"
}
}
var protocolText: String {
let unknown = NSLocalizedString("unknown", comment: "connection info")
let local = localCandidate?.protocol?.uppercased() ?? unknown
let localRelay = localCandidate?.relayProtocol?.uppercased() ?? unknown
let remote = remoteCandidate?.protocol?.uppercased() ?? unknown
let localText = localRelay == local || localCandidate?.relayProtocol == nil
? local
: "\(local) (\(localRelay))"
return local == remote
? localText
: "\(localText) / \(remote)"
}
}
// https://developer.mozilla.org/en-US/docs/Web/API/RTCIceCandidate
struct RTCIceCandidate: Codable, Equatable {
var candidateType: RTCIceCandidateType?
var `protocol`: String?
var relayProtocol: String?
}
// https://developer.mozilla.org/en-US/docs/Web/API/RTCIceCandidate/type
@@ -396,18 +411,20 @@ struct RTCIceServer: Codable, Equatable {
}
// the servers are expected in this format:
// stun:stun.simplex.im:443
// turn:private:yleob6AVkiNI87hpR94Z@turn.simplex.im:443
// stun:stun.simplex.im:443?transport=tcp
// turn:private:yleob6AVkiNI87hpR94Z@turn.simplex.im:443?transport=tcp
func parseRTCIceServer(_ str: String) -> RTCIceServer? {
var s = replaceScheme(str, "stun:")
s = replaceScheme(s, "turn:")
s = replaceScheme(s, "turns:")
if let u: URL = URL(string: s),
let scheme = u.scheme,
let host = u.host,
let port = u.port,
u.path == "" && (scheme == "stun" || scheme == "turn") {
u.path == "" && (scheme == "stun" || scheme == "turn" || scheme == "turns") {
let query = u.query == nil || u.query == "" ? "" : "?" + (u.query ?? "")
return RTCIceServer(
urls: ["\(scheme):\(host):\(port)"],
urls: ["\(scheme):\(host):\(port)\(query)"],
username: u.user,
credential: u.password
)
@@ -75,7 +75,7 @@ struct CIFeaturePreferenceView_Previews: PreviewProvider {
let content = CIContent.rcvChatPreference(feature: .timedMessages, allowed: .yes, param: 30)
let chatItem = ChatItem(
chatDir: .directRcv,
meta: CIMeta.getSample(1, .now, content.text, .rcvRead, false, false, false),
meta: CIMeta.getSample(1, .now, content.text, .rcvRead),
content: content,
quotedItem: nil,
file: nil
@@ -138,14 +138,14 @@ struct CIFileView_Previews: PreviewProvider {
static var previews: some View {
let sentFile: ChatItem = ChatItem(
chatDir: .directSnd,
meta: CIMeta.getSample(1, .now, "", .sndSent, false, true, false),
meta: CIMeta.getSample(1, .now, "", .sndSent, itemEdited: true),
content: .sndMsgContent(msgContent: .file("")),
quotedItem: nil,
file: CIFile.getSample(fileStatus: .sndComplete)
)
let fileChatItemWtFile = ChatItem(
chatDir: .directRcv,
meta: CIMeta.getSample(1, .now, "", .rcvRead, false, false, false),
meta: CIMeta.getSample(1, .now, "", .rcvRead),
content: .rcvMsgContent(msgContent: .file("")),
quotedItem: nil,
file: nil
@@ -52,7 +52,7 @@ struct CIMetaView_Previews: PreviewProvider {
static var previews: some View {
Group {
CIMetaView(chatItem: ChatItem.getSample(2, .directSnd, .now, "https://simplex.chat", .sndSent))
CIMetaView(chatItem: ChatItem.getSample(2, .directSnd, .now, "https://simplex.chat", .sndSent, false, true))
CIMetaView(chatItem: ChatItem.getSample(2, .directSnd, .now, "https://simplex.chat", .sndSent, itemEdited: true))
CIMetaView(chatItem: ChatItem.getDeletedContentSample())
}
.previewLayout(.fixed(width: 360, height: 100))
@@ -221,14 +221,14 @@ struct CIVoiceView_Previews: PreviewProvider {
static var previews: some View {
let sentVoiceMessage: ChatItem = ChatItem(
chatDir: .directSnd,
meta: CIMeta.getSample(1, .now, "", .sndSent, false, true, false),
meta: CIMeta.getSample(1, .now, "", .sndSent, itemEdited: true),
content: .sndMsgContent(msgContent: .voice(text: "", duration: 30)),
quotedItem: nil,
file: CIFile.getSample(fileStatus: .sndComplete)
)
let voiceMessageWtFile = ChatItem(
chatDir: .directRcv,
meta: CIMeta.getSample(1, .now, "", .rcvRead, false, false, false),
meta: CIMeta.getSample(1, .now, "", .rcvRead),
content: .rcvMsgContent(msgContent: .voice(text: "", duration: 30)),
quotedItem: nil,
file: nil
@@ -10,6 +10,7 @@ import SwiftUI
import SimpleXChat
struct DeletedItemView: View {
@Environment(\.colorScheme) var colorScheme
var chatItem: ChatItem
var showMember = false
@@ -26,7 +27,7 @@ struct DeletedItemView: View {
}
.padding(.leading, 12)
.padding(.vertical, 6)
.background(Color(uiColor: .tertiarySystemGroupedBackground))
.background(chatItemFrameColor(chatItem, colorScheme))
.cornerRadius(18)
.textSelection(.disabled)
}
@@ -47,14 +47,14 @@ struct FramedCIVoiceView_Previews: PreviewProvider {
static var previews: some View {
let sentVoiceMessage: ChatItem = ChatItem(
chatDir: .directSnd,
meta: CIMeta.getSample(1, .now, "", .sndSent, false, true, false),
meta: CIMeta.getSample(1, .now, "", .sndSent, itemEdited: true),
content: .sndMsgContent(msgContent: .voice(text: "Hello there", duration: 30)),
quotedItem: nil,
file: CIFile.getSample(fileStatus: .sndComplete)
)
let voiceMessageWithQuote: ChatItem = ChatItem(
chatDir: .directSnd,
meta: CIMeta.getSample(1, .now, "", .sndSent, false, true, false),
meta: CIMeta.getSample(1, .now, "", .sndSent, itemEdited: true),
content: .sndMsgContent(msgContent: .voice(text: "", duration: 30)),
quotedItem: CIQuote.getSample(1, .now, "Hi", chatDir: .directRcv),
file: CIFile.getSample(fileStatus: .sndComplete)
File diff suppressed because one or more lines are too long
@@ -37,7 +37,7 @@ struct MarkedDeletedItemView: View {
struct MarkedDeletedItemView_Previews: PreviewProvider {
static var previews: some View {
Group {
MarkedDeletedItemView(chatItem: ChatItem.getSample(1, .directSnd, .now, "hello", .sndSent, true, false))
MarkedDeletedItemView(chatItem: ChatItem.getSample(1, .directSnd, .now, "hello", .sndSent, itemDeleted: .deleted))
}
.previewLayout(.fixed(width: 360, height: 200))
}
+11 -9
View File
@@ -19,9 +19,9 @@ struct ChatItemView: View {
var body: some View {
let ci = chatItem
if chatItem.meta.itemDeleted && !revealed {
if chatItem.meta.itemDeleted != nil && !revealed {
MarkedDeletedItemView(chatItem: chatItem, showMember: showMember)
} else if ci.quotedItem == nil && !ci.meta.itemDeleted && !ci.meta.isLive {
} else if ci.quotedItem == nil && ci.meta.itemDeleted == nil && !ci.meta.isLive {
if let mc = ci.content.msgContent, mc.isText && isShortEmoji(ci.content.text) {
EmojiItemView(chatItem: ci)
} else if ci.content.text.isEmpty, case let .voice(_, duration) = ci.content.msgContent {
@@ -72,6 +72,8 @@ struct ChatItemContentView<Content: View>: View {
case let .sndGroupFeature(feature, preference, _): chatFeatureView(feature, preference.enable.iconColor)
case let .rcvChatFeatureRejected(feature): chatFeatureView(feature, .red)
case let .rcvGroupFeatureRejected(feature): chatFeatureView(feature, .red)
case .sndModerated: deletedItemView()
case .rcvModerated: deletedItemView()
case let .invalidJSON(json): CIInvalidJSONView(json: json)
}
}
@@ -106,9 +108,9 @@ struct ChatItemView_Previews: PreviewProvider {
ChatItemView(chatInfo: ChatInfo.sampleData.direct, chatItem: ChatItem.getSample(2, .directRcv, .now, "🙂🙂🙂🙂🙂"), revealed: Binding.constant(false))
ChatItemView(chatInfo: ChatInfo.sampleData.direct, chatItem: ChatItem.getSample(2, .directRcv, .now, "🙂🙂🙂🙂🙂🙂"), revealed: Binding.constant(false))
ChatItemView(chatInfo: ChatInfo.sampleData.direct, chatItem: ChatItem.getDeletedContentSample(), revealed: Binding.constant(false))
ChatItemView(chatInfo: ChatInfo.sampleData.direct, chatItem: ChatItem.getSample(1, .directSnd, .now, "hello", .sndSent, true, false), revealed: Binding.constant(false))
ChatItemView(chatInfo: ChatInfo.sampleData.direct, chatItem: ChatItem.getSample(1, .directSnd, .now, "🙂", .sndSent, false, false, true), revealed: Binding.constant(true))
ChatItemView(chatInfo: ChatInfo.sampleData.direct, chatItem: ChatItem.getSample(1, .directSnd, .now, "hello", .sndSent, false, false, true), revealed: Binding.constant(true))
ChatItemView(chatInfo: ChatInfo.sampleData.direct, chatItem: ChatItem.getSample(1, .directSnd, .now, "hello", .sndSent, itemDeleted: .deleted), revealed: Binding.constant(false))
ChatItemView(chatInfo: ChatInfo.sampleData.direct, chatItem: ChatItem.getSample(1, .directSnd, .now, "🙂", .sndSent, itemLive: true), revealed: Binding.constant(true))
ChatItemView(chatInfo: ChatInfo.sampleData.direct, chatItem: ChatItem.getSample(1, .directSnd, .now, "hello", .sndSent, itemLive: true), revealed: Binding.constant(true))
}
.previewLayout(.fixed(width: 360, height: 70))
.environmentObject(Chat.sampleData)
@@ -123,7 +125,7 @@ struct ChatItemView_NonMsgContentDeleted_Previews: PreviewProvider {
chatInfo: ChatInfo.sampleData.direct,
chatItem: ChatItem(
chatDir: .directRcv,
meta: CIMeta.getSample(1, .now, "1 skipped message", .rcvRead, true, false, false),
meta: CIMeta.getSample(1, .now, "1 skipped message", .rcvRead, itemDeleted: .deleted),
content: .rcvIntegrityError(msgError: .msgSkipped(fromMsgId: 1, toMsgId: 2)),
quotedItem: nil,
file: nil
@@ -134,7 +136,7 @@ struct ChatItemView_NonMsgContentDeleted_Previews: PreviewProvider {
chatInfo: ChatInfo.sampleData.direct,
chatItem: ChatItem(
chatDir: .directRcv,
meta: CIMeta.getSample(1, .now, "received invitation to join group team as admin", .rcvRead, true, false, false),
meta: CIMeta.getSample(1, .now, "received invitation to join group team as admin", .rcvRead, itemDeleted: .deleted),
content: .rcvGroupInvitation(groupInvitation: CIGroupInvitation.getSample(status: .pending), memberRole: .admin),
quotedItem: nil,
file: nil
@@ -145,7 +147,7 @@ struct ChatItemView_NonMsgContentDeleted_Previews: PreviewProvider {
chatInfo: ChatInfo.sampleData.direct,
chatItem: ChatItem(
chatDir: .directRcv,
meta: CIMeta.getSample(1, .now, "group event text", .rcvRead, true, false, false),
meta: CIMeta.getSample(1, .now, "group event text", .rcvRead, itemDeleted: .deleted),
content: .rcvGroupEvent(rcvGroupEvent: .memberAdded(groupMemberId: 1, profile: Profile.sampleData)),
quotedItem: nil,
file: nil
@@ -156,7 +158,7 @@ struct ChatItemView_NonMsgContentDeleted_Previews: PreviewProvider {
chatInfo: ChatInfo.sampleData.direct,
chatItem: ChatItem(
chatDir: .directRcv,
meta: CIMeta.getSample(1, .now, ciFeatureContent.text, .rcvRead, true, false, false),
meta: CIMeta.getSample(1, .now, ciFeatureContent.text, .rcvRead, itemDeleted: .deleted),
content: ciFeatureContent,
quotedItem: nil,
file: nil
+5 -4
View File
@@ -16,6 +16,7 @@ struct ChatView: View {
@EnvironmentObject var chatModel: ChatModel
@Environment(\.colorScheme) var colorScheme
@Environment(\.dismiss) var dismiss
@Environment(\.presentationMode) var presentationMode
@State @ObservedObject var chat: Chat
@State private var showChatInfoSheet: Bool = false
@State private var showAddMembersSheet: Bool = false
@@ -77,7 +78,7 @@ struct ChatView: View {
if chatModel.chatId == nil { dismiss() }
}
.onDisappear {
if chatModel.chatId == cInfo.id {
if chatModel.chatId == cInfo.id && !presentationMode.wrappedValue.isPresented {
chatModel.chatId = nil
DispatchQueue.main.asyncAfter(deadline: .now() + 0.35) {
if chatModel.chatId == nil {
@@ -465,8 +466,8 @@ struct ChatView: View {
private func menu(live: Bool) -> [UIAction] {
var menu: [UIAction] = []
if let mc = ci.content.msgContent, !ci.meta.itemDeleted || revealed {
if !ci.meta.itemDeleted && !ci.isLiveDummy && !live {
if let mc = ci.content.msgContent, ci.meta.itemDeleted == nil || revealed {
if ci.meta.itemDeleted == nil && !ci.isLiveDummy && !live {
menu.append(replyUIAction())
}
menu.append(shareUIAction())
@@ -491,7 +492,7 @@ struct ChatView: View {
if !live || !ci.meta.isLive {
menu.append(deleteUIAction())
}
} else if ci.meta.itemDeleted {
} else if ci.meta.itemDeleted != nil {
menu.append(revealUIAction())
menu.append(deleteUIAction())
} else if ci.isDeletedContent {
@@ -151,8 +151,8 @@ struct ChatPreviewView: View {
}
func chatItemPreview(_ cItem: ChatItem) -> Text {
let itemText = !cItem.meta.itemDeleted ? cItem.text : NSLocalizedString("marked deleted", comment: "marked deleted chat item preview text")
let itemFormattedText = !cItem.meta.itemDeleted ? cItem.formattedText : nil
let itemText = cItem.meta.itemDeleted == nil ? cItem.text : NSLocalizedString("marked deleted", comment: "marked deleted chat item preview text")
let itemFormattedText = cItem.meta.itemDeleted == nil ? cItem.formattedText : nil
return messageText(itemText, itemFormattedText, cItem.memberDisplayName, icon: attachment(), preview: true)
func attachment() -> String? {
@@ -259,7 +259,7 @@ struct ChatPreviewView_Previews: PreviewProvider {
))
ChatPreviewView(chat: Chat(
chatInfo: ChatInfo.sampleData.direct,
chatItems: [ChatItem.getSample(1, .directSnd, .now, "hello", .sndSent, true, false)]
chatItems: [ChatItem.getSample(1, .directSnd, .now, "hello", .sndSent, itemDeleted: .deleted)]
))
ChatPreviewView(chat: Chat(
chatInfo: ChatInfo.sampleData.direct,
@@ -15,6 +15,16 @@ enum LAResult {
case unavailable(authError: String?)
}
func authorize(_ text: String, _ authorized: Binding<Bool>) {
authenticate(reason: text) { laResult in
switch laResult {
case .success: authorized.wrappedValue = true
case .unavailable: authorized.wrappedValue = true
case .failed: authorized.wrappedValue = false
}
}
}
func authenticate(reason: String, completed: @escaping (LAResult) -> Void) {
let laContext = LAContext()
var authAvailabilityError: NSError?
+41 -2
View File
@@ -30,17 +30,42 @@ struct MutableQRCode: View {
struct QRCode: View {
let uri: String
@State private var image: UIImage?
var withLogo: Bool = true
var tintColor = UIColor(red: 0.023, green: 0.176, blue: 0.337, alpha: 1)
@State private var image: UIImage? = nil
@State private var makeScreenshotBinding: () -> Void = {}
var body: some View {
ZStack {
if let image = image {
qrCodeImage(image)
}
GeometryReader { geo in
ZStack {
if withLogo {
let w = geo.size.width
Image("icon-light")
.resizable()
.scaledToFit()
.frame(width: w * 0.16, height: w * 0.16)
.frame(width: w * 0.165, height: w * 0.165)
.background(.white)
.clipShape(Circle())
}
}
.onAppear {
makeScreenshotBinding = {
let size = CGSizeMake(1024 / UIScreen.main.scale, 1024 / UIScreen.main.scale)
showShareSheet(items: [makeScreenshot(geo.frame(in: .local).origin, size)])}
}
.frame(width: geo.size.width, height: geo.size.height)
}
}
.onTapGesture(perform: makeScreenshotBinding)
.onAppear {
image = image ?? generateImage(uri)
image = image ?? generateImage(uri)?.replaceColor(UIColor.black, tintColor)
}
}
}
@@ -63,6 +88,20 @@ private func generateImage(_ uri: String) -> UIImage? {
return nil
}
extension View {
func makeScreenshot(_ origin: CGPoint? = nil, _ targetSize: CGSize? = nil) -> UIImage {
let controller = UIHostingController(rootView: self.edgesIgnoringSafeArea(.all))
let targetSize = targetSize ?? controller.view.intrinsicContentSize
let view = controller.view
view?.bounds = CGRect(origin: origin ?? .zero, size: targetSize)
view?.backgroundColor = .clear
let renderer = UIGraphicsImageRenderer(size: targetSize)
return renderer.image { _ in
view?.drawHierarchy(in: controller.view.bounds, afterScreenUpdates: true)
}
}
}
struct QRCode_Previews: PreviewProvider {
static var previews: some View {
QRCode(uri: "https://simplex.chat/invitation#/?v=1&smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FFe5ICmvrm4wkrr6X1LTMii-lhBqLeB76%23MCowBQYDK2VuAyEAdhZZsHpuaAk3Hh1q0uNb_6hGTpuwBIrsp2z9U2T0oC0%3D&e2e=v%3D1%26x3dh%3DMEIwBQYDK2VvAzkAcz6jJk71InuxA0bOX7OUhddfB8Ov7xwQIlIDeXBRZaOntUU4brU5Y3rBzroZBdQJi0FKdtt_D7I%3D%2CMEIwBQYDK2VvAzkA-hDvk1duBi1hlOr08VWSI-Ou4JNNSQjseY69QyKm7Kgg1zZjbpGfyBqSZ2eqys6xtoV4ZtoQUXQ%3D")
+1 -9
View File
@@ -30,15 +30,7 @@ struct TerminalView: View {
}
}
private func runAuth() {
authenticate(reason: NSLocalizedString("Open chat console", comment: "authentication reason")) { laResult in
switch laResult {
case .success: authorized = true
case .unavailable: authorized = true
case .failed: authorized = false
}
}
}
private func runAuth() { authorize(NSLocalizedString("Open chat console", comment: "authentication reason"), $authorized) }
private func terminalView() -> some View {
VStack {
@@ -13,7 +13,6 @@ struct PrivacySettings: View {
@AppStorage(DEFAULT_PRIVACY_ACCEPT_IMAGES) private var autoAcceptImages = true
@AppStorage(DEFAULT_PRIVACY_LINK_PREVIEWS) private var useLinkPreviews = true
@AppStorage(DEFAULT_DEVELOPER_TOOLS) private var developerTools = false
@AppStorage(GROUP_DEFAULT_PRIVACY_TRANSFER_IMAGES_INLINE, store: groupDefaults) private var transferImagesInline = true
@State private var simplexLinkMode = privacySimplexLinkModeDefault.get()
@AppStorage(DEFAULT_PRIVACY_PROTECT_SCREEN) private var protectScreen = false
@@ -34,9 +33,6 @@ struct PrivacySettings: View {
privacyAcceptImagesGroupDefault.set($0)
}
}
settingsRow("photo.on.rectangle") {
Toggle("Transfer images faster", isOn: $transferImagesInline)
}
settingsRow("network") {
Toggle("Send link previews", isOn: $useLinkPreviews)
}
@@ -121,7 +121,6 @@ struct SettingsView: View {
NavigationLink {
UserProfilesView()
.navigationTitle("Your chat profiles")
} label: {
settingsRow("person.crop.rectangle.stack") { Text("Your chat profiles") }
}
@@ -12,6 +12,7 @@ struct UserProfilesView: View {
@State private var showDeleteConfirmation = false
@State private var userToDelete: Int?
@State private var alert: UserProfilesAlert?
@State var authorized = !UserDefaults.standard.bool(forKey: DEFAULT_PERFORM_LA)
private enum UserProfilesAlert: Identifiable {
case deleteUser(index: Int, delSMPQueues: Bool)
@@ -28,6 +29,17 @@ struct UserProfilesView: View {
}
var body: some View {
if authorized {
userProfilesView()
} else {
Button(action: runAuth) { Label("Unlock", systemImage: "lock") }
.onAppear(perform: runAuth)
}
}
private func runAuth() { authorize(NSLocalizedString("Open user profiles", comment: "authentication reason"), $authorized) }
private func userProfilesView() -> some View {
List {
Section {
ForEach(m.users) { u in
@@ -52,6 +64,7 @@ struct UserProfilesView: View {
}
}
.toolbar { EditButton() }
.navigationTitle("Your chat profiles")
.confirmationDialog("Delete chat profile?", isPresented: $showDeleteConfirmation, titleVisibility: .visible) {
deleteModeButton("Profile and server connections", true)
deleteModeButton("Local profile data only", false)
File diff suppressed because it is too large Load Diff
@@ -940,11 +940,6 @@
<target>Dunkel</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Data" xml:space="preserve">
<source>Data</source>
<target>Daten</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Database ID" xml:space="preserve">
<source>Database ID</source>
<target>Datenbank-ID</target>
@@ -1093,11 +1088,6 @@
<target>Datenbank löschen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete files &amp; media" xml:space="preserve">
<source>Delete files &amp; media</source>
<target>Dateien &amp; Medien löschen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete files and media?" xml:space="preserve">
<source>Delete files and media?</source>
<target>Dateien und Medien löschen?</target>
@@ -3307,11 +3297,6 @@ Sie werden aufgefordert, die Authentifizierung abzuschließen, bevor diese Funkt
<target>Um die Ende-zu-Ende-Verschlüsselung mit Ihrem Kontakt zu überprüfen, müssen Sie den Sicherheitscode in Ihren Apps vergleichen oder scannen.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Transfer images faster" xml:space="preserve">
<source>Transfer images faster</source>
<target>Bilder schneller übertragen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Transport isolation" xml:space="preserve">
<source>Transport isolation</source>
<target>Transport-Isolation</target>
@@ -3764,11 +3749,6 @@ Bitten Sie Ihren Kontakt darum einen weiteren Verbindungs-Link zu erzeugen, um s
<target>Ihre Chat-Datenbank ist nicht verschlüsselt. Bitte legen Sie ein Passwort fest, um sie zu schützen.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your chat profile" xml:space="preserve">
<source>Your chat profile</source>
<target>Mein Chat-Profil</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your chat profile will be sent to group members" xml:space="preserve">
<source>Your chat profile will be sent to group members</source>
<target>Ihr Chat-Profil wird an Gruppenmitglieder gesendet</target>
@@ -940,11 +940,6 @@
<target>Dark</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Data" xml:space="preserve">
<source>Data</source>
<target>Data</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Database ID" xml:space="preserve">
<source>Database ID</source>
<target>Database ID</target>
@@ -1093,11 +1088,6 @@
<target>Delete database</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete files &amp; media" xml:space="preserve">
<source>Delete files &amp; media</source>
<target>Delete files &amp; media</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete files and media?" xml:space="preserve">
<source>Delete files and media?</source>
<target>Delete files and media?</target>
@@ -3307,11 +3297,6 @@ You will be prompted to complete authentication before this feature is enabled.<
<target>To verify end-to-end encryption with your contact compare (or scan) the code on your devices.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Transfer images faster" xml:space="preserve">
<source>Transfer images faster</source>
<target>Transfer images faster</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Transport isolation" xml:space="preserve">
<source>Transport isolation</source>
<target>Transport isolation</target>
@@ -3764,11 +3749,6 @@ To connect, please ask your contact to create another connection link and check
<target>Your chat database is not encrypted - set passphrase to encrypt it.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your chat profile" xml:space="preserve">
<source>Your chat profile</source>
<target>Your chat profile</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your chat profile will be sent to group members" xml:space="preserve">
<source>Your chat profile will be sent to group members</source>
<target>Your chat profile will be sent to group members</target>
@@ -567,6 +567,7 @@
</trans-unit>
<trans-unit id="By chat profile (default) or [by connection](https://simplex.chat/blog/20230204-simplex-chat-v4-5-user-chat-profiles.html#transport-isolation) (BETA)." xml:space="preserve">
<source>By chat profile (default) or [by connection](https://simplex.chat/blog/20230204-simplex-chat-v4-5-user-chat-profiles.html#transport-isolation) (BETA).</source>
<target>Par profil de chat (par défaut) ou [par connexion](https://simplex.chat/blog/20230204-simplex-chat-v4-5-user-chat-profiles.html#transport-isolation) (BETA).</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Call already ended!" xml:space="preserve">
@@ -939,11 +940,6 @@
<target>Sombre</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Data" xml:space="preserve">
<source>Data</source>
<target>Données</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Database ID" xml:space="preserve">
<source>Database ID</source>
<target>ID de base de données</target>
@@ -1092,11 +1088,6 @@
<target>Supprimer la base de données</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete files &amp; media" xml:space="preserve">
<source>Delete files &amp; media</source>
<target>Supprimer les fichiers et médias</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete files and media?" xml:space="preserve">
<source>Delete files and media?</source>
<target>Supprimer les fichiers et médias ?</target>
@@ -1219,6 +1210,7 @@
</trans-unit>
<trans-unit id="Different names, avatars and transport isolation." xml:space="preserve">
<source>Different names, avatars and transport isolation.</source>
<target>Différents noms, avatars et mode d'isolation de transport.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Direct messages" xml:space="preserve">
@@ -1628,6 +1620,7 @@
</trans-unit>
<trans-unit id="French interface" xml:space="preserve">
<source>French interface</source>
<target>Interface en français</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Full link" xml:space="preserve">
@@ -1979,6 +1972,7 @@ Nous allons ajouter une redondance des serveurs pour éviter la perte de message
</trans-unit>
<trans-unit id="Italian interface" xml:space="preserve">
<source>Italian interface</source>
<target>Interface en italien</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Join" xml:space="preserve">
@@ -2133,6 +2127,7 @@ Nous allons ajouter une redondance des serveurs pour éviter la perte de message
</trans-unit>
<trans-unit id="Message draft" xml:space="preserve">
<source>Message draft</source>
<target>Brouillon de message</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Message text" xml:space="preserve">
@@ -2167,6 +2162,7 @@ Nous allons ajouter une redondance des serveurs pour éviter la perte de message
</trans-unit>
<trans-unit id="More improvements are coming soon!" xml:space="preserve">
<source>More improvements are coming soon!</source>
<target>Plus d'améliorations à venir !</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Most likely this contact has deleted the connection with you." xml:space="preserve">
@@ -2176,6 +2172,7 @@ Nous allons ajouter une redondance des serveurs pour éviter la perte de message
</trans-unit>
<trans-unit id="Multiple chat profiles" xml:space="preserve">
<source>Multiple chat profiles</source>
<target>Différents profils de chat</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Mute" xml:space="preserve">
@@ -2485,6 +2482,7 @@ Nous allons ajouter une redondance des serveurs pour éviter la perte de message
</trans-unit>
<trans-unit id="Preserve the last message draft, with attachments." xml:space="preserve">
<source>Preserve the last message draft, with attachments.</source>
<target>Conserver le brouillon du dernier message, avec les pièces jointes.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Preset server" xml:space="preserve">
@@ -2509,6 +2507,7 @@ Nous allons ajouter une redondance des serveurs pour éviter la perte de message
</trans-unit>
<trans-unit id="Private filenames" xml:space="preserve">
<source>Private filenames</source>
<target>Noms de fichiers privés</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Profile and server connections" xml:space="preserve">
@@ -2593,6 +2592,7 @@ Nous allons ajouter une redondance des serveurs pour éviter la perte de message
</trans-unit>
<trans-unit id="Reduced battery usage" xml:space="preserve">
<source>Reduced battery usage</source>
<target>Réduction de la consommation de batterie</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Reject" xml:space="preserve">
@@ -3137,10 +3137,12 @@ Nous allons ajouter une redondance des serveurs pour éviter la perte de message
</trans-unit>
<trans-unit id="Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#translate-the-apps)!" xml:space="preserve">
<source>Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#translate-the-apps)!</source>
<target>Merci aux utilisateurs - [contribuer via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#translate-the-apps) !</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Thanks to the users contribute via Weblate!" xml:space="preserve">
<source>Thanks to the users contribute via Weblate!</source>
<target>Merci aux utilisateurs - contribuez via Weblate !</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="The 1st platform without any user identifiers private by design." xml:space="preserve">
@@ -3270,6 +3272,7 @@ Nous allons ajouter une redondance des serveurs pour éviter la perte de message
</trans-unit>
<trans-unit id="To protect timezone, image/voice files use UTC." xml:space="preserve">
<source>To protect timezone, image/voice files use UTC.</source>
<target>Pour préserver le fuseau horaire, les fichiers image/voix utilisent le système UTC.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="To protect your information, turn on SimpleX Lock.&#10;You will be prompted to complete authentication before this feature is enabled." xml:space="preserve">
@@ -3294,11 +3297,6 @@ Vous serez invité à confirmer l'authentification avant que cette fonction ne s
<target>Pour vérifier le chiffrement de bout en bout avec votre contact, comparez (ou scannez) le code sur vos appareils.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Transfer images faster" xml:space="preserve">
<source>Transfer images faster</source>
<target>Transfert d'images plus rapide</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Transport isolation" xml:space="preserve">
<source>Transport isolation</source>
<target>Isolement du transport</target>
@@ -3751,11 +3749,6 @@ Pour vous connecter, veuillez demander à votre contact de créer un autre lien
<target>Votre base de données de chat n'est pas chiffrée - définisez une phrase secrète.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your chat profile" xml:space="preserve">
<source>Your chat profile</source>
<target>Votre profil de chat</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your chat profile will be sent to group members" xml:space="preserve">
<source>Your chat profile will be sent to group members</source>
<target>Votre profil de chat sera envoyé aux membres du groupe</target>
File diff suppressed because it is too large Load Diff
@@ -940,11 +940,6 @@
<target>Scuro</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Data" xml:space="preserve">
<source>Data</source>
<target>Dati</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Database ID" xml:space="preserve">
<source>Database ID</source>
<target>ID database</target>
@@ -1093,11 +1088,6 @@
<target>Elimina database</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete files &amp; media" xml:space="preserve">
<source>Delete files &amp; media</source>
<target>Elimina file e multimediali</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete files and media?" xml:space="preserve">
<source>Delete files and media?</source>
<target>Eliminare i file e i multimediali?</target>
@@ -3307,11 +3297,6 @@ Ti verrà chiesto di completare l'autenticazione prima di attivare questa funzio
<target>Per verificare la crittografia end-to-end con il tuo contatto, confrontate (o scansionate) il codice sui vostri dispositivi.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Transfer images faster" xml:space="preserve">
<source>Transfer images faster</source>
<target>Trasferisci immagini più velocemente</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Transport isolation" xml:space="preserve">
<source>Transport isolation</source>
<target>Isolamento del trasporto</target>
@@ -3764,11 +3749,6 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e
<target>Il tuo database della chat non è crittografato: imposta la password per crittografarlo.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your chat profile" xml:space="preserve">
<source>Your chat profile</source>
<target>Il tuo profilo di chat</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your chat profile will be sent to group members" xml:space="preserve">
<source>Your chat profile will be sent to group members</source>
<target>Il tuo profilo di chat verrà inviato ai membri del gruppo</target>
@@ -940,11 +940,6 @@
<target>Тёмная</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Data" xml:space="preserve">
<source>Data</source>
<target>Данные</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Database ID" xml:space="preserve">
<source>Database ID</source>
<target>ID базы данных</target>
@@ -1093,11 +1088,6 @@
<target>Удалить данные чата</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete files &amp; media" xml:space="preserve">
<source>Delete files &amp; media</source>
<target>Удалить файлы и медиа</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Delete files and media?" xml:space="preserve">
<source>Delete files and media?</source>
<target>Удалить файлы и медиа?</target>
@@ -3307,11 +3297,6 @@ You will be prompted to complete authentication before this feature is enabled.<
<target>Чтобы подтвердить end-to-end шифрование с вашим контактом сравните (или сканируйте) код безопасности на ваших устройствах.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Transfer images faster" xml:space="preserve">
<source>Transfer images faster</source>
<target>Передавать изображения быстрее</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Transport isolation" xml:space="preserve">
<source>Transport isolation</source>
<target>Отдельные сессии для</target>
@@ -3764,11 +3749,6 @@ 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="Your chat profile" xml:space="preserve">
<source>Your chat profile</source>
<target>Ваш профиль</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your chat profile will be sent to group members" xml:space="preserve">
<source>Your chat profile will be sent to group members</source>
<target>Ваш профиль чата будет отправлен членам группы</target>
@@ -789,16 +789,19 @@
<target state="translated">创建地址</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create group link" xml:space="preserve">
<trans-unit id="Create group link" xml:space="preserve" approved="no">
<source>Create group link</source>
<target state="translated">创建群组链接</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create link" xml:space="preserve">
<trans-unit id="Create link" xml:space="preserve" approved="no">
<source>Create link</source>
<target state="translated">创建链接</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create one-time invitation link" xml:space="preserve">
<trans-unit id="Create one-time invitation link" xml:space="preserve" approved="no">
<source>Create one-time invitation link</source>
<target state="translated">创建一次性邀请链接</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Create queue" xml:space="preserve">
@@ -3668,6 +3671,16 @@ SimpleX servers cannot see your profile.</source>
<target state="translated">一个单独的TCP连接将被用于**您在应用程序中的每个聊天资料**。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Core built at: %@" xml:space="preserve" approved="no">
<source>Core built at: %@</source>
<target state="translated">核心构建于:%@</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Core version: v%@" xml:space="preserve" approved="no">
<source>Core version: v%@</source>
<target state="translated">核心版本: v%@</target>
<note>No comment provided by engineer.</note>
</trans-unit>
</body>
</file>
<file original="en.lproj/SimpleX--iOS--InfoPlist.strings" source-language="en" target-language="zh-Hans" datatype="plaintext">
@@ -225,16 +225,14 @@ func receivedMsgNtf(_ res: ChatResponse) async -> (String, UNMutableNotification
if let file = cItem.file,
file.fileSize <= MAX_IMAGE_SIZE_AUTO_RCV,
privacyAcceptImagesGroupDefault.get() {
let inline = privacyTransferImagesInlineGroupDefault.get()
cItem = apiReceiveFile(fileId: file.fileId, inline: inline)?.chatItem ?? cItem
cItem = apiReceiveFile(fileId: file.fileId)?.chatItem ?? cItem
}
} else if case .voice = cItem.content.msgContent { // TODO check inlineFileMode != IFMSent
if let file = cItem.file,
file.fileSize <= MAX_IMAGE_SIZE,
file.fileSize > MAX_VOICE_MESSAGE_SIZE_INLINE_SEND,
privacyAcceptImagesGroupDefault.get() {
let inline = privacyTransferImagesInlineGroupDefault.get()
cItem = apiReceiveFile(fileId: file.fileId, inline: inline)?.chatItem ?? cItem
cItem = apiReceiveFile(fileId: file.fileId)?.chatItem ?? cItem
}
}
return cItem.showMutableNotification ? (aChatItem.chatId, createMessageReceivedNtf(user, cInfo, cItem)) : nil
@@ -308,7 +306,7 @@ func apiGetNtfMessage(nonce: String, encNtfInfo: String) -> NtfMessages? {
return nil
}
func apiReceiveFile(fileId: Int64, inline: Bool) -> AChatItem? {
func apiReceiveFile(fileId: Int64, inline: Bool? = nil) -> AChatItem? {
let r = sendSimpleXCmd(.receiveFile(fileId: fileId, inline: inline))
if case let .rcvFileAccepted(_, chatItem) = r { return chatItem }
logger.error("receiveFile error: \(responseError(r))")
+28 -28
View File
@@ -27,11 +27,6 @@
5C116CDC27AABE0400E66D01 /* ContactRequestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C116CDB27AABE0400E66D01 /* ContactRequestView.swift */; };
5C13730B28156D2700F43030 /* ContactConnectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C13730A28156D2700F43030 /* ContactConnectionView.swift */; };
5C1A4C1E27A715B700EAD5AD /* ChatItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C1A4C1D27A715B700EAD5AD /* ChatItemView.swift */; };
5C1E4301298D5C5900042FC4 /* libHSsimplex-chat-4.5.0.4-5yV27REgiwW3BgWrVxeIJK.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C1E42FC298D5C5900042FC4 /* libHSsimplex-chat-4.5.0.4-5yV27REgiwW3BgWrVxeIJK.a */; };
5C1E4302298D5C5900042FC4 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C1E42FD298D5C5900042FC4 /* libgmp.a */; };
5C1E4303298D5C5900042FC4 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C1E42FE298D5C5900042FC4 /* libffi.a */; };
5C1E4304298D5C5900042FC4 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C1E42FF298D5C5900042FC4 /* libgmpxx.a */; };
5C1E4305298D5C5900042FC4 /* libHSsimplex-chat-4.5.0.4-5yV27REgiwW3BgWrVxeIJK-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C1E4300298D5C5900042FC4 /* libHSsimplex-chat-4.5.0.4-5yV27REgiwW3BgWrVxeIJK-ghc8.10.7.a */; };
5C2E260727A2941F00F70299 /* SimpleXAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260627A2941F00F70299 /* SimpleXAPI.swift */; };
5C2E260B27A30CFA00F70299 /* ChatListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260A27A30CFA00F70299 /* ChatListView.swift */; };
5C2E260F27A30FDC00F70299 /* ChatView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260E27A30FDC00F70299 /* ChatView.swift */; };
@@ -149,6 +144,11 @@
6442E0BA287F169300CEC0F9 /* AddGroupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6442E0B9287F169300CEC0F9 /* AddGroupView.swift */; };
6442E0BE2880182D00CEC0F9 /* GroupChatInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6442E0BD2880182D00CEC0F9 /* GroupChatInfoView.swift */; };
6448BBB628FA9D56000D2AB9 /* GroupLinkView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6448BBB528FA9D56000D2AB9 /* GroupLinkView.swift */; };
644E727429962516003534BE /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 644E726F29962515003534BE /* libgmpxx.a */; };
644E727529962516003534BE /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 644E727029962516003534BE /* libffi.a */; };
644E727629962516003534BE /* libHSsimplex-chat-4.5.2.0-3DFmi70wk2S4RlkJCMDsZW.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 644E727129962516003534BE /* libHSsimplex-chat-4.5.2.0-3DFmi70wk2S4RlkJCMDsZW.a */; };
644E727729962516003534BE /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 644E727229962516003534BE /* libgmp.a */; };
644E727829962516003534BE /* libHSsimplex-chat-4.5.2.0-3DFmi70wk2S4RlkJCMDsZW-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 644E727329962516003534BE /* libHSsimplex-chat-4.5.2.0-3DFmi70wk2S4RlkJCMDsZW-ghc8.10.7.a */; };
644EFFDE292BCD9D00525D5B /* ComposeVoiceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 644EFFDD292BCD9D00525D5B /* ComposeVoiceView.swift */; };
644EFFE0292CFD7F00525D5B /* CIVoiceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 644EFFDF292CFD7F00525D5B /* CIVoiceView.swift */; };
644EFFE2292D089800525D5B /* FramedCIVoiceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 644EFFE1292D089800525D5B /* FramedCIVoiceView.swift */; };
@@ -246,11 +246,6 @@
5C13730A28156D2700F43030 /* ContactConnectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactConnectionView.swift; sourceTree = "<group>"; };
5C13730C2815740A00F43030 /* DebugJSON.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = DebugJSON.playground; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
5C1A4C1D27A715B700EAD5AD /* ChatItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatItemView.swift; sourceTree = "<group>"; };
5C1E42FC298D5C5900042FC4 /* libHSsimplex-chat-4.5.0.4-5yV27REgiwW3BgWrVxeIJK.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-4.5.0.4-5yV27REgiwW3BgWrVxeIJK.a"; sourceTree = "<group>"; };
5C1E42FD298D5C5900042FC4 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
5C1E42FE298D5C5900042FC4 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
5C1E42FF298D5C5900042FC4 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
5C1E4300298D5C5900042FC4 /* libHSsimplex-chat-4.5.0.4-5yV27REgiwW3BgWrVxeIJK-ghc8.10.7.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-4.5.0.4-5yV27REgiwW3BgWrVxeIJK-ghc8.10.7.a"; sourceTree = "<group>"; };
5C2E260627A2941F00F70299 /* SimpleXAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleXAPI.swift; sourceTree = "<group>"; };
5C2E260A27A30CFA00F70299 /* ChatListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatListView.swift; sourceTree = "<group>"; };
5C2E260E27A30FDC00F70299 /* ChatView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatView.swift; sourceTree = "<group>"; };
@@ -381,6 +376,11 @@
6442E0B9287F169300CEC0F9 /* AddGroupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddGroupView.swift; sourceTree = "<group>"; };
6442E0BD2880182D00CEC0F9 /* GroupChatInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupChatInfoView.swift; sourceTree = "<group>"; };
6448BBB528FA9D56000D2AB9 /* GroupLinkView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupLinkView.swift; sourceTree = "<group>"; };
644E726F29962515003534BE /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
644E727029962516003534BE /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
644E727129962516003534BE /* libHSsimplex-chat-4.5.2.0-3DFmi70wk2S4RlkJCMDsZW.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-4.5.2.0-3DFmi70wk2S4RlkJCMDsZW.a"; sourceTree = "<group>"; };
644E727229962516003534BE /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
644E727329962516003534BE /* libHSsimplex-chat-4.5.2.0-3DFmi70wk2S4RlkJCMDsZW-ghc8.10.7.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-4.5.2.0-3DFmi70wk2S4RlkJCMDsZW-ghc8.10.7.a"; sourceTree = "<group>"; };
644EFFDD292BCD9D00525D5B /* ComposeVoiceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeVoiceView.swift; sourceTree = "<group>"; };
644EFFDF292CFD7F00525D5B /* CIVoiceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIVoiceView.swift; sourceTree = "<group>"; };
644EFFE1292D089800525D5B /* FramedCIVoiceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FramedCIVoiceView.swift; sourceTree = "<group>"; };
@@ -432,13 +432,13 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
5C1E4304298D5C5900042FC4 /* libgmpxx.a in Frameworks */,
5C1E4301298D5C5900042FC4 /* libHSsimplex-chat-4.5.0.4-5yV27REgiwW3BgWrVxeIJK.a in Frameworks */,
644E727429962516003534BE /* libgmpxx.a in Frameworks */,
5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */,
5C1E4302298D5C5900042FC4 /* libgmp.a in Frameworks */,
5C1E4303298D5C5900042FC4 /* libffi.a in Frameworks */,
644E727629962516003534BE /* libHSsimplex-chat-4.5.2.0-3DFmi70wk2S4RlkJCMDsZW.a in Frameworks */,
644E727829962516003534BE /* libHSsimplex-chat-4.5.2.0-3DFmi70wk2S4RlkJCMDsZW-ghc8.10.7.a in Frameworks */,
5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */,
5C1E4305298D5C5900042FC4 /* libHSsimplex-chat-4.5.0.4-5yV27REgiwW3BgWrVxeIJK-ghc8.10.7.a in Frameworks */,
644E727729962516003534BE /* libgmp.a in Frameworks */,
644E727529962516003534BE /* libffi.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -496,11 +496,11 @@
5C764E5C279C70B7000C6508 /* Libraries */ = {
isa = PBXGroup;
children = (
5C1E42FE298D5C5900042FC4 /* libffi.a */,
5C1E42FD298D5C5900042FC4 /* libgmp.a */,
5C1E42FF298D5C5900042FC4 /* libgmpxx.a */,
5C1E4300298D5C5900042FC4 /* libHSsimplex-chat-4.5.0.4-5yV27REgiwW3BgWrVxeIJK-ghc8.10.7.a */,
5C1E42FC298D5C5900042FC4 /* libHSsimplex-chat-4.5.0.4-5yV27REgiwW3BgWrVxeIJK.a */,
644E727029962516003534BE /* libffi.a */,
644E727229962516003534BE /* libgmp.a */,
644E726F29962515003534BE /* libgmpxx.a */,
644E727329962516003534BE /* libHSsimplex-chat-4.5.2.0-3DFmi70wk2S4RlkJCMDsZW-ghc8.10.7.a */,
644E727129962516003534BE /* libHSsimplex-chat-4.5.2.0-3DFmi70wk2S4RlkJCMDsZW.a */,
);
path = Libraries;
sourceTree = "<group>";
@@ -1330,7 +1330,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 123;
CURRENT_PROJECT_VERSION = 125;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
ENABLE_PREVIEWS = YES;
@@ -1351,7 +1351,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 4.5;
MARKETING_VERSION = 4.5.2;
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app;
PRODUCT_NAME = SimpleX;
SDKROOT = iphoneos;
@@ -1372,7 +1372,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 123;
CURRENT_PROJECT_VERSION = 125;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
ENABLE_PREVIEWS = YES;
@@ -1393,7 +1393,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 4.5;
MARKETING_VERSION = 4.5.2;
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app;
PRODUCT_NAME = SimpleX;
SDKROOT = iphoneos;
@@ -1451,7 +1451,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 123;
CURRENT_PROJECT_VERSION = 125;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
GENERATE_INFOPLIST_FILE = YES;
@@ -1464,7 +1464,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 4.5;
MARKETING_VERSION = 4.5.2;
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-NSE";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
@@ -1481,7 +1481,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 123;
CURRENT_PROJECT_VERSION = 125;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
GENERATE_INFOPLIST_FILE = YES;
@@ -1494,7 +1494,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 4.5;
MARKETING_VERSION = 4.5.2;
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-NSE";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
+6 -2
View File
@@ -91,7 +91,7 @@ public enum ChatCommand {
case apiCallStatus(contact: Contact, callStatus: WebRTCCallStatus)
case apiChatRead(type: ChatType, id: Int64, itemRange: (Int64, Int64))
case apiChatUnread(type: ChatType, id: Int64, unreadChat: Bool)
case receiveFile(fileId: Int64, inline: Bool)
case receiveFile(fileId: Int64, inline: Bool?)
case showVersion
case string(String)
@@ -180,7 +180,11 @@ public enum ChatCommand {
case let .apiCallStatus(contact, callStatus): return "/_call status @\(contact.apiId) \(callStatus.rawValue)"
case let .apiChatRead(type, id, itemRange: (from, to)): return "/_read chat \(ref(type, id)) from=\(from) to=\(to)"
case let .apiChatUnread(type, id, unreadChat): return "/_unread chat \(ref(type, id)) \(onOff(unreadChat))"
case let .receiveFile(fileId, inline): return "/freceive \(fileId) inline=\(onOff(inline))"
case let .receiveFile(fileId, inline):
if let inline = inline {
return "/freceive \(fileId) inline=\(onOff(inline))"
}
return "/freceive \(fileId)"
case .showVersion: return "/version"
case let .string(str): return str
}
+2 -2
View File
@@ -14,7 +14,7 @@ let GROUP_DEFAULT_DB_CONTAINER = "dbContainer"
public let GROUP_DEFAULT_CHAT_LAST_START = "chatLastStart"
let GROUP_DEFAULT_NTF_PREVIEW_MODE = "ntfPreviewMode"
let GROUP_DEFAULT_PRIVACY_ACCEPT_IMAGES = "privacyAcceptImages"
public let GROUP_DEFAULT_PRIVACY_TRANSFER_IMAGES_INLINE = "privacyTransferImagesInline"
public let GROUP_DEFAULT_PRIVACY_TRANSFER_IMAGES_INLINE = "privacyTransferImagesInline" // no longer used
let GROUP_DEFAULT_NTF_BADGE_COUNT = "ntgBadgeCount"
let GROUP_DEFAULT_NETWORK_USE_ONION_HOSTS = "networkUseOnionHosts"
let GROUP_DEFAULT_NETWORK_SESSION_MODE = "networkSessionMode"
@@ -50,7 +50,7 @@ public func registerGroupDefaults() {
GROUP_DEFAULT_STORE_DB_PASSPHRASE: true,
GROUP_DEFAULT_INITIAL_RANDOM_DB_PASSPHRASE: false,
GROUP_DEFAULT_PRIVACY_ACCEPT_IMAGES: true,
GROUP_DEFAULT_PRIVACY_TRANSFER_IMAGES_INLINE: true
GROUP_DEFAULT_PRIVACY_TRANSFER_IMAGES_INLINE: false
])
}
+32 -14
View File
@@ -1762,6 +1762,8 @@ public struct ChatItem: Identifiable, Decodable {
case .sndGroupFeature: return showNtfDir
case .rcvChatFeatureRejected: return showNtfDir
case .rcvGroupFeatureRejected: return showNtfDir
case .sndModerated: return true
case .rcvModerated: return true
case .invalidJSON: return false
}
}
@@ -1784,10 +1786,10 @@ public struct ChatItem: Identifiable, Decodable {
}
}
public static func getSample (_ id: Int64, _ dir: CIDirection, _ ts: Date, _ text: String, _ status: CIStatus = .sndNew, quotedItem: CIQuote? = nil, file: CIFile? = nil, _ itemDeleted: Bool = false, _ itemEdited: Bool = false, _ itemLive: Bool = false, _ editable: Bool = true) -> ChatItem {
public static func getSample (_ id: Int64, _ dir: CIDirection, _ ts: Date, _ text: String, _ status: CIStatus = .sndNew, quotedItem: CIQuote? = nil, file: CIFile? = nil, itemDeleted: CIDeleted? = nil, itemEdited: Bool = false, itemLive: Bool = false, editable: Bool = true) -> ChatItem {
ChatItem(
chatDir: dir,
meta: CIMeta.getSample(id, ts, text, status, itemDeleted, itemEdited, itemLive, editable),
meta: CIMeta.getSample(id, ts, text, status, itemDeleted: itemDeleted, itemEdited: itemEdited, itemLive: itemLive, editable: editable),
content: .sndMsgContent(msgContent: .text(text)),
quotedItem: quotedItem,
file: file
@@ -1797,7 +1799,7 @@ public struct ChatItem: Identifiable, Decodable {
public static func getVoiceMsgContentSample (id: Int64 = 1, text: String = "", fileName: String = "voice.m4a", fileSize: Int64 = 65536, fileStatus: CIFileStatus = .rcvComplete) -> ChatItem {
ChatItem(
chatDir: .directRcv,
meta: CIMeta.getSample(id, .now, text, .rcvRead, false, false, false),
meta: CIMeta.getSample(id, .now, text, .rcvRead),
content: .rcvMsgContent(msgContent: .voice(text: text, duration: 30)),
quotedItem: nil,
file: CIFile.getSample(fileName: fileName, fileSize: fileSize, fileStatus: fileStatus)
@@ -1807,7 +1809,7 @@ public struct ChatItem: Identifiable, Decodable {
public static func getFileMsgContentSample (id: Int64 = 1, text: String = "", fileName: String = "test.txt", fileSize: Int64 = 100, fileStatus: CIFileStatus = .rcvComplete) -> ChatItem {
ChatItem(
chatDir: .directRcv,
meta: CIMeta.getSample(id, .now, text, .rcvRead, false, false, false),
meta: CIMeta.getSample(id, .now, text, .rcvRead),
content: .rcvMsgContent(msgContent: .file(text)),
quotedItem: nil,
file: CIFile.getSample(fileName: fileName, fileSize: fileSize, fileStatus: fileStatus)
@@ -1817,7 +1819,7 @@ public struct ChatItem: Identifiable, Decodable {
public static func getDeletedContentSample (_ id: Int64 = 1, dir: CIDirection = .directRcv, _ ts: Date = .now, _ text: String = "this item is deleted", _ status: CIStatus = .rcvRead) -> ChatItem {
ChatItem(
chatDir: dir,
meta: CIMeta.getSample(id, ts, text, status, false, false, false),
meta: CIMeta.getSample(id, ts, text, status),
content: .rcvDeleted(deleteMode: .cidmBroadcast),
quotedItem: nil,
file: nil
@@ -1827,7 +1829,7 @@ public struct ChatItem: Identifiable, Decodable {
public static func getIntegrityErrorSample (_ status: CIStatus = .rcvRead, fromMsgId: Int64 = 1, toMsgId: Int64 = 2) -> ChatItem {
ChatItem(
chatDir: .directRcv,
meta: CIMeta.getSample(1, .now, "1 skipped message", status, false, false, false),
meta: CIMeta.getSample(1, .now, "1 skipped message", status),
content: .rcvIntegrityError(msgError: .msgSkipped(fromMsgId: fromMsgId, toMsgId: toMsgId)),
quotedItem: nil,
file: nil
@@ -1837,7 +1839,7 @@ public struct ChatItem: Identifiable, Decodable {
public static func getGroupInvitationSample (_ status: CIGroupInvitationStatus = .pending) -> ChatItem {
ChatItem(
chatDir: .directRcv,
meta: CIMeta.getSample(1, .now, "received invitation to join group team as admin", .rcvRead, false, false, false),
meta: CIMeta.getSample(1, .now, "received invitation to join group team as admin", .rcvRead),
content: .rcvGroupInvitation(groupInvitation: CIGroupInvitation.getSample(status: status), memberRole: .admin),
quotedItem: nil,
file: nil
@@ -1847,7 +1849,7 @@ public struct ChatItem: Identifiable, Decodable {
public static func getGroupEventSample () -> ChatItem {
ChatItem(
chatDir: .directRcv,
meta: CIMeta.getSample(1, .now, "group event text", .rcvRead, false, false, false),
meta: CIMeta.getSample(1, .now, "group event text", .rcvRead),
content: .rcvGroupEvent(rcvGroupEvent: .memberAdded(groupMemberId: 1, profile: Profile.sampleData)),
quotedItem: nil,
file: nil
@@ -1858,7 +1860,7 @@ public struct ChatItem: Identifiable, Decodable {
let content = CIContent.rcvChatFeature(feature: feature, enabled: enabled, param: nil)
return ChatItem(
chatDir: .directRcv,
meta: CIMeta.getSample(1, .now, content.text, .rcvRead, false, false, false),
meta: CIMeta.getSample(1, .now, content.text, .rcvRead),
content: content,
quotedItem: nil,
file: nil
@@ -1875,7 +1877,7 @@ public struct ChatItem: Identifiable, Decodable {
itemStatus: .rcvRead,
createdAt: .now,
updatedAt: .now,
itemDeleted: false,
itemDeleted: nil,
itemEdited: false,
itemLive: false,
editable: false
@@ -1896,7 +1898,7 @@ public struct ChatItem: Identifiable, Decodable {
itemStatus: .rcvRead,
createdAt: .now,
updatedAt: .now,
itemDeleted: false,
itemDeleted: nil,
itemEdited: false,
itemLive: true,
editable: false
@@ -1945,7 +1947,7 @@ public struct CIMeta: Decodable {
public var itemStatus: CIStatus
var createdAt: Date
public var updatedAt: Date
public var itemDeleted: Bool
public var itemDeleted: CIDeleted?
public var itemEdited: Bool
public var itemTimed: CITimed?
public var itemLive: Bool?
@@ -1971,7 +1973,7 @@ public struct CIMeta: Decodable {
}
}
public static func getSample(_ id: Int64, _ ts: Date, _ text: String, _ status: CIStatus = .sndNew, _ itemDeleted: Bool = false, _ itemEdited: Bool = false, _ itemLive: Bool = false, _ editable: Bool = true) -> CIMeta {
public static func getSample(_ id: Int64, _ ts: Date, _ text: String, _ status: CIStatus = .sndNew, itemDeleted: CIDeleted? = nil, itemEdited: Bool = false, itemLive: Bool = false, editable: Bool = true) -> CIMeta {
CIMeta(
itemId: id,
itemTs: ts,
@@ -1994,7 +1996,7 @@ public struct CIMeta: Decodable {
itemStatus: .sndNew,
createdAt: .now,
updatedAt: .now,
itemDeleted: false,
itemDeleted: nil,
itemEdited: false,
itemLive: false,
editable: false
@@ -2037,6 +2039,18 @@ public enum CIStatus: Decodable {
}
}
public enum CIDeleted: Decodable {
case deleted
case moderated(byGroupMember: GroupMember)
var id: String {
switch self {
case .deleted: return "deleted"
case .moderated: return "moderated"
}
}
}
public enum CIDeleteMode: String, Decodable {
case cidmBroadcast = "broadcast"
case cidmInternal = "internal"
@@ -2068,6 +2082,8 @@ public enum CIContent: Decodable, ItemContent {
case sndGroupFeature(groupFeature: GroupFeature, preference: GroupPreference, param: Int?)
case rcvChatFeatureRejected(feature: ChatFeature)
case rcvGroupFeatureRejected(groupFeature: GroupFeature)
case sndModerated
case rcvModerated
case invalidJSON(json: String)
public var text: String {
@@ -2094,6 +2110,8 @@ public enum CIContent: Decodable, ItemContent {
case let .sndGroupFeature(feature, preference, param): return CIContent.featureText(feature, preference.enable.text, param)
case let .rcvChatFeatureRejected(feature): return String.localizedStringWithFormat("%@: received, prohibited", feature.text)
case let .rcvGroupFeatureRejected(groupFeature): return String.localizedStringWithFormat("%@: received, prohibited", groupFeature.text)
case .sndModerated: return NSLocalizedString("moderated", comment: "moderated chat item")
case .rcvModerated: return NSLocalizedString("moderated", comment: "moderated chat item")
case .invalidJSON: return NSLocalizedString("invalid data", comment: "invalid chat item")
}
}
-12
View File
@@ -674,9 +674,6 @@
/* No comment provided by engineer. */
"Dark" = "Dunkel";
/* No comment provided by engineer. */
"Data" = "Daten";
/* No comment provided by engineer. */
"Database encrypted!" = "Datenbank verschlüsselt!";
@@ -764,9 +761,6 @@
/* No comment provided by engineer. */
"Delete database" = "Datenbank löschen";
/* No comment provided by engineer. */
"Delete files & media" = "Dateien & Medien löschen";
/* No comment provided by engineer. */
"Delete files and media?" = "Dateien und Medien löschen?";
@@ -2256,9 +2250,6 @@
/* No comment provided by engineer. */
"To verify end-to-end encryption with your contact compare (or scan) the code on your devices." = "Um die Ende-zu-Ende-Verschlüsselung mit Ihrem Kontakt zu überprüfen, müssen Sie den Sicherheitscode in Ihren Apps vergleichen oder scannen.";
/* No comment provided by engineer. */
"Transfer images faster" = "Bilder schneller übertragen";
/* No comment provided by engineer. */
"Transport isolation" = "Transport-Isolation";
@@ -2586,9 +2577,6 @@
/* No comment provided by engineer. */
"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 profile" = "Mein Chat-Profil";
/* No comment provided by engineer. */
"Your chat profile will be sent to group members" = "Ihr Chat-Profil wird an Gruppenmitglieder gesendet";
+39 -12
View File
@@ -374,6 +374,9 @@
/* No comment provided by engineer. */
"Both you and your contact can send voice messages." = "Vous et votre contact êtes tous deux en mesure d'envoyer des messages vocaux.";
/* No comment provided by engineer. */
"By chat profile (default) or [by connection](https://simplex.chat/blog/20230204-simplex-chat-v4-5-user-chat-profiles.html#transport-isolation) (BETA)." = "Par profil de chat (par défaut) ou [par connexion](https://simplex.chat/blog/20230204-simplex-chat-v4-5-user-chat-profiles.html#transport-isolation) (BETA).";
/* No comment provided by engineer. */
"Call already ended!" = "Appel déjà terminé !";
@@ -671,9 +674,6 @@
/* No comment provided by engineer. */
"Dark" = "Sombre";
/* No comment provided by engineer. */
"Data" = "Données";
/* No comment provided by engineer. */
"Database encrypted!" = "Base de données chiffrée !";
@@ -761,9 +761,6 @@
/* No comment provided by engineer. */
"Delete database" = "Supprimer la base de données";
/* No comment provided by engineer. */
"Delete files & media" = "Supprimer les fichiers et médias";
/* No comment provided by engineer. */
"Delete files and media?" = "Supprimer les fichiers et médias ?";
@@ -842,6 +839,9 @@
/* No comment provided by engineer. */
"Device authentication is not enabled. You can turn on SimpleX Lock via Settings, once you enable device authentication." = "L'authentification de l'appareil n'est pas activée. Vous pouvez activer SimpleX Lock via Paramètres, une fois que vous avez activé l'authentification de l'appareil.";
/* No comment provided by engineer. */
"Different names, avatars and transport isolation." = "Différents noms, avatars et mode d'isolation de transport.";
/* connection level description */
"direct" = "direct";
@@ -1112,6 +1112,9 @@
/* No comment provided by engineer. */
"For console" = "Pour la console";
/* No comment provided by engineer. */
"French interface" = "Interface en français";
/* No comment provided by engineer. */
"Full link" = "Lien entier";
@@ -1361,6 +1364,9 @@
/* 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 (%@)." = "Il semblerait que vous êtes déjà connecté via ce lien. Si ce n'est pas le cas, il y a eu une erreur (%@).";
/* No comment provided by engineer. */
"Italian interface" = "Interface en italien";
/* No comment provided by engineer. */
"italic" = "italique";
@@ -1469,6 +1475,9 @@
/* No comment provided by engineer. */
"Message delivery error" = "Erreur de distribution du message";
/* No comment provided by engineer. */
"Message draft" = "Brouillon de message";
/* notification */
"message received" = "message reçu";
@@ -1493,9 +1502,15 @@
/* call status */
"missed call" = "appel manqué";
/* No comment provided by engineer. */
"More improvements are coming soon!" = "Plus d'améliorations à venir !";
/* No comment provided by engineer. */
"Most likely this contact has deleted the connection with you." = "Il est fort probable que ce contact ait supprimé la connexion avec vous.";
/* No comment provided by engineer. */
"Multiple chat profiles" = "Différents profils de chat";
/* No comment provided by engineer. */
"Mute" = "Muet";
@@ -1713,6 +1728,9 @@
/* server test error */
"Possibly, certificate fingerprint in server address is incorrect" = "Il est possible que l'empreinte du certificat dans l'adresse du serveur soit incorrecte";
/* No comment provided by engineer. */
"Preserve the last message draft, with attachments." = "Conserver le brouillon du dernier message, avec les pièces jointes.";
/* No comment provided by engineer. */
"Preset server" = "Serveur prédéfini";
@@ -1725,6 +1743,9 @@
/* No comment provided by engineer. */
"Privacy redefined" = "La vie privée redéfinie";
/* No comment provided by engineer. */
"Private filenames" = "Noms de fichiers privés";
/* No comment provided by engineer. */
"Profile and server connections" = "Profil et connexions au serveur";
@@ -1779,6 +1800,9 @@
/* No comment provided by engineer. */
"Recipients see updates as you type them." = "Les destinataires voient les mises à jour au fur et à mesure que vous les tapez.";
/* No comment provided by engineer. */
"Reduced battery usage" = "Réduction de la consommation de batterie";
/* reject incoming call via notification */
"Reject" = "Rejeter";
@@ -2127,6 +2151,12 @@
/* No comment provided by engineer. */
"Thank you for installing SimpleX Chat!" = "Merci d'avoir installé SimpleX Chat!";
/* No comment provided by engineer. */
"Thanks to the users [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#translate-the-apps)!" = "Merci aux utilisateurs - [contribuer via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#translate-the-apps) !";
/* No comment provided by engineer. */
"Thanks to the users contribute via Weblate!" = "Merci aux utilisateurs - contribuez via Weblate !";
/* No comment provided by engineer. */
"The 1st platform without any user identifiers private by design." = "La 1ère plateforme sans aucun identifiant d'utilisateur privée par design.";
@@ -2205,6 +2235,9 @@
/* No comment provided by engineer. */
"To protect privacy, instead of user IDs used by all other platforms, SimpleX has identifiers for message queues, separate for each of your contacts." = "Pour protéger votre vie privée, au lieu dIDs utilisés par toutes les autres plateformes, SimpleX a des IDs pour les queues de messages, distinctes pour chacun de vos contacts.";
/* No comment provided by engineer. */
"To protect timezone, image/voice files use UTC." = "Pour préserver le fuseau horaire, les fichiers image/voix utilisent le système UTC.";
/* No comment provided by engineer. */
"To protect your information, turn on SimpleX Lock.\nYou will be prompted to complete authentication before this feature is enabled." = "Pour protéger vos informations, activez la fonction SimpleX Lock.\nVous serez invité à confirmer l'authentification avant que cette fonction ne soit activée.";
@@ -2217,9 +2250,6 @@
/* No comment provided by engineer. */
"To verify end-to-end encryption with your contact compare (or scan) the code on your devices." = "Pour vérifier le chiffrement de bout en bout avec votre contact, comparez (ou scannez) le code sur vos appareils.";
/* No comment provided by engineer. */
"Transfer images faster" = "Transfert d'images plus rapide";
/* No comment provided by engineer. */
"Transport isolation" = "Isolement du transport";
@@ -2547,9 +2577,6 @@
/* No comment provided by engineer. */
"Your chat database is not encrypted - set passphrase to encrypt it." = "Votre base de données de chat n'est pas chiffrée - définisez une phrase secrète.";
/* No comment provided by engineer. */
"Your chat profile" = "Votre profil de chat";
/* No comment provided by engineer. */
"Your chat profile will be sent to group members" = "Votre profil de chat sera envoyé aux membres du groupe";
-12
View File
@@ -674,9 +674,6 @@
/* No comment provided by engineer. */
"Dark" = "Scuro";
/* No comment provided by engineer. */
"Data" = "Dati";
/* No comment provided by engineer. */
"Database encrypted!" = "Database crittografato!";
@@ -764,9 +761,6 @@
/* No comment provided by engineer. */
"Delete database" = "Elimina database";
/* No comment provided by engineer. */
"Delete files & media" = "Elimina file e multimediali";
/* No comment provided by engineer. */
"Delete files and media?" = "Eliminare i file e i multimediali?";
@@ -2256,9 +2250,6 @@
/* No comment provided by engineer. */
"To verify end-to-end encryption with your contact compare (or scan) the code on your devices." = "Per verificare la crittografia end-to-end con il tuo contatto, confrontate (o scansionate) il codice sui vostri dispositivi.";
/* No comment provided by engineer. */
"Transfer images faster" = "Trasferisci immagini più velocemente";
/* No comment provided by engineer. */
"Transport isolation" = "Isolamento del trasporto";
@@ -2586,9 +2577,6 @@
/* No comment provided by engineer. */
"Your chat database is not encrypted - set passphrase to encrypt it." = "Il tuo database della chat non è crittografato: imposta la password per crittografarlo.";
/* No comment provided by engineer. */
"Your chat profile" = "Il tuo profilo di chat";
/* No comment provided by engineer. */
"Your chat profile will be sent to group members" = "Il tuo profilo di chat verrà inviato ai membri del gruppo";
-12
View File
@@ -674,9 +674,6 @@
/* No comment provided by engineer. */
"Dark" = "Тёмная";
/* No comment provided by engineer. */
"Data" = "Данные";
/* No comment provided by engineer. */
"Database encrypted!" = "База данных зашифрована!";
@@ -764,9 +761,6 @@
/* No comment provided by engineer. */
"Delete database" = "Удалить данные чата";
/* No comment provided by engineer. */
"Delete files & media" = "Удалить файлы и медиа";
/* No comment provided by engineer. */
"Delete files and media?" = "Удалить файлы и медиа?";
@@ -2256,9 +2250,6 @@
/* No comment provided by engineer. */
"To verify end-to-end encryption with your contact compare (or scan) the code on your devices." = "Чтобы подтвердить end-to-end шифрование с вашим контактом сравните (или сканируйте) код безопасности на ваших устройствах.";
/* No comment provided by engineer. */
"Transfer images faster" = "Передавать изображения быстрее";
/* No comment provided by engineer. */
"Transport isolation" = "Отдельные сессии для";
@@ -2586,9 +2577,6 @@
/* No comment provided by engineer. */
"Your chat database is not encrypted - set passphrase to encrypt it." = "База данных НЕ зашифрована. Установите пароль, чтобы защитить ваши данные.";
/* No comment provided by engineer. */
"Your chat profile" = "Ваш профиль";
/* No comment provided by engineer. */
"Your chat profile will be sent to group members" = "Ваш профиль чата будет отправлен членам группы";
@@ -1,19 +1,17 @@
---
layout: layouts/article.html
title: "SimpleX Chat v4.5 released with multiple chat profiles, message draft, transport isolation and Italian language!"
title: "SimpleX Chat v4.5 released with multiple chat profiles, message draft, transport isolation and Italian language!"
date: 2023-02-04
# image: images/20230103-disappearing1.png
# imageBottom: true
# previewBody: blog_previews/20230103.html
image: images/20230204-profiles2.png
imageBottom: true
previewBody: blog_previews/20230204.html
permalink: "/blog/20230204-simplex-chat-v4-5-user-chat-profiles.html"
---
# SimpleX Chat v4.5 released with multiple user profiles, message draft, transport isolation and Italian language!
# SimpleX Chat v4.5 released with multiple user profiles, message draft, transport isolation and Italian interface!
**Published:** Feb 4, 2023
TODO this is a post stub to reserve permalink
## What's new in v4.5
- [multiple chat profiles](#multiple-chat-profiles).
@@ -22,14 +20,103 @@ TODO this is a post stub to reserve permalink
- [reduced battery usage](#reduced-battery-usage).
- [private filenames](#private-filenames).
Also, we added [Italian language interface](#french-language-interface), thanks to the users' community and Weblate!
Also, we added [Italian interface](#italian-interface), thanks to the users' community and Weblate!
### Multiple chat profiles
<img src="./images/20230204-profiles1.png" width="288"> &nbsp;&nbsp; <img src="./images/20230204-profiles2.png" width="288">
Incognito mode added in v3.2 allows to share a random profile name with your new contacts. It is quite popular - more than half of users connecting to our support profile use it. In case when you just want a throw-away profile name that doesn't share any information about you it is more convenient that creating a new profile for each contact manually.
But there are many cases when a disposable profile is not good enough enough, and you want to create separate profiles - one for your family, another for work, yet one more for your online contacts that only know your pseudonym rather than your real name.
Previously this was only possible by using separate chat databases. This version adds a chat profile manager that allows you to create unlimited number of profiles, and very quickly switch them. All these profiles are connected at the same time.
When you delete profile you no longer need you have two options - either delete both profile data on the device and any message queues that this profile created on SMP servers (e.g., when it is more important to leave as few meta-data on the servers), or delete only profile data without making any network requests (when it is more important to delete all data from the device quickly).
While most app settings apply to all profiles, several settings are profile-specific.
You can separately set which SMP servers are used to create the new contacts in each profile (via Network settings). Please note: changing SMP servers in one profile won't affect other profiles, and all new profiles are created with preset servers.
You can also separately set the retention time for messages in each profile (via Database settings).
Also, you have a different contact address in each profile, and different Chat preferences.
All other settings are used for all profiles. While you may want to have different settings for different security levels, it is much better to use different devices in this case.
### Message draft
<img src="./images/20230204-draft1.png" width="288"> &nbsp;&nbsp; <img src="./images/20230204-draft2.png" width="288">
Previously, if you've closed the conversation with unsent message, this message was disappearing. While it might be better for privacy, there are several scenarios when it is very inconvenient:
- you need to compose the message from several parts that you copy from other conversations.
- some messages arrives that you need to answer urgently, so you can leave unfinished message to return to it later.
Both are now possible - the message you wrote, together with any attachments, and even a voice message you recorded, will remain available as draft until you either close the app or leave another message unfinished - while you can send the message in another chat without losing the current draft, there can be only one draft at a time.
### Transport isolation
<img src="./images/20230204-transport.png" width="288">
Even when you create different chat profiles you are still connecting to your contacts via the same device. Transport isolation, by default, makes connections belonging to the same profile use different TCP sessions, so while the server sees the same IP address, it doesn't see it as the same client connection. If you are connecting via Tor using SOCKS proxy (e.g. Orbot app on Android) not only the app will use different TCP sessions, it will also use separate Tor circuits for connections from different profiles, preventing the servers and network observers seeing this as traffic coming from the same device.
There is an additional BETA option to use a separate transport connection for each contact and group member connection you have it is available in Network settings if you enable dev tools. In case you have a large number of contacts or participate in large groups across all profiles in the app, you should not use this option, as it may create a lot of traffic and also can exceed the quota for TCP sockets. Also creating a lot of separate Tor circuits can be slow. We will be testing at which number of connections this option starts failing and by the time it's available without dev tools we will add some limits.
### Reduced battery usage
Battery usage is one of the biggest complaints of SimpleX Chat users. The main reason for excess traffic is inefficient retry strategies for Network operations in these cases:
- the message queue capacity is exceeded - the app will keep retrying to send the message until there will be capacity.
- the server is not available, e.g. if you connect to somebody via their server, and they later disable it. This case creates much less extra traffic than the first.
This version makes retries for exceeded queue capacity 10x less frequent and adds SMP protocol extension that will allow to reduce retries even further by the next version. It works in the following way:
- when the sender encounters "queue quota exceeded" error, the sender stops trying to send the message.
- the server also takes note of that error.
- once recipient receives all messages from this queue, the server will notify the recipient that the sender had "queue quota exceeded" error.
- the recipient will then send a special message to the sender client to instruct it that it can resume delivery.
- the sender can still occasionally try sending the message, e.g. once every hours, but it won't need to retry once every few minutes as it does now.
Reducing battery usage is our big priority - we expect to reduce it by at least 2-3x in the next few months.
### Private filenames
When you send an image or voice message they are sent as files with filenames including timestamp. We didn't see it as a problem, as files are sent together with the message, and messages have server-side timestamps anyway. But the users pointed out that the timestamp we used was in the local timezone, and therefore leaked the country (or continent) where the user is located. A simple workaround was to reset timezone to UTC, and that is what most users who need to protect their location do anyway. But this version resolves it - these filenames now include UTC timezones no workarounds are needed.
### Italian interface
Thanks to our users' community and to Weblate providing a free hosting plan for SimpleX Chat translations we can now support more languages in the interface this version adds Italian and many more is in progress - Chinese, Japanese, Czech, Dutch, etc.
You can [contribute the translation](https://github.com/simplex-chat/simplex-chat/tree/stable#translate-the-apps) of the apps to your language too!
## SimpleX platform
Some links to answer the most common questions:
[How can SimpleX deliver messages without user identifiers](./20220511-simplex-chat-v2-images-files.md#the-first-messaging-platform-without-user-identifiers).
[What are the risks to have identifiers assigned to the users](./20220711-simplex-chat-v3-released-ios-notifications-audio-video-calls-database-export-import-protocol-improvements.md#why-having-users-identifiers-is-bad-for-the-users).
[Technical details and limitations](https://github.com/simplex-chat/simplex-chat#privacy-technical-details-and-limitations).
[How SimpleX is different from Session, Matrix, Signal, etc.](https://github.com/simplex-chat/simplex-chat/blob/stable/README.md#frequently-asked-questions).
Please also see our [website](https://simplex.chat).
## Help us with donations
Huge thank you to everybody who donated to SimpleX Chat!
We are prioritizing users privacy and security - it would be impossible without your support.
Our pledge to our users is that SimpleX protocols are and will remain open, and in public domain, - so anybody can build the future implementations of the clients and the servers. We are building SimpleX platform based on the same principles as email and web, but much more private and secure.
Your donations help us raise more funds any amount, even the price of the cup of coffee, makes a big difference for us.
See [this section](https://github.com/simplex-chat/simplex-chat/tree/master#help-us-with-donations) for the ways to donate.
Thank you,
Evgeny
SimpleX Chat founder
+10
View File
@@ -1,5 +1,15 @@
# Blog
Feb 4, 2023 [SimpleX Chat v4.5 released](./20230103-simplex-chat-v4.4-disappearing-messages.md)
- multiple chat profiles.
- message draft.
- transport isolation.
- reduced battery usage.
- private filenames.
Also, we added [Italian language interface](#french-language-interface), thanks to our users and Weblate!
Jan 3, 2023 [SimpleX Chat v4.4 released](./20230103-simplex-chat-v4.4-disappearing-messages.md)
- disappearing messages.
Binary file not shown.

After

Width:  |  Height:  |  Size: 224 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

+115
View File
@@ -0,0 +1,115 @@
# Blog
4 févr. 2023 [SimpleX Chat v4.5 publié](./20230103-simplex-chat-v4.4-disappearing-messages.md)
- profils de chat multiples.
- brouillon de message.
- isolation du transport.
- réduction de l'utilisation de la batterie.
- noms de fichiers privés.
Nous avons également ajouté [l'interface en italien](#french-language-interface), grâce à nos utilisateurs et à Weblate !
3 janv. 2023 [SimpleX Chat v4.4 publié](./20230103-simplex-chat-v4.4-disappearing-messages.md)
- messages éphèméres.
- messages "en direct" (dynamique).
- vérification de la sécurité de la connexion.
- images animées et autocollants - maintenant aussi sur iOS.
Nous avons également ajouté [l'interface en français](#french-language-interface), grâce à nos utilisateurs et à Weblate !
6 déc. 2022 [SimpleX Chat : révision et sortie de la v4.3](./20221206-simplex-chat-v4.3-voice-messages.md)
Critiques de novembre :
- Recommandations de [Privacy Guides](https://www.privacyguides.org/real-time-communication/#simplex-chat).
- [Revue par Mike Kuketz](https://www.kuketz-blog.de/simplex-eindruecke-vom-messenger-ohne-identifier/).
- [La matrice des messageries](https://www.messenger-matrix.de).
- [Revue de Supernova](https://supernova.tilde.team/detailed_reviews.html#simplex) et [évaluations des messageries](https://supernova.tilde.team/messengers.html).
Sortie de la v4.3 :
- messages vocaux instantanés !
- suppression irréversible des messages envoyés pour tous les destinataires
- amélioration de la configuration du serveur SMP et du support des mots de passe du serveur
- améliorations de la confidentialité et de la sécurité : protection de l'écran de l'application, sécurité des liens SimpleX, etc.
8 nov. 2022 [Audit de sécurité par Trail of Bits, nouveau site web et sortie de la v4.2](./20221108-simplex-chat-v4.2-security-audit-new-website.md)
_"Avez-vous été audité ou devons-nous simplement vous ignorer ?"_
SimpleX Chat a été audité par [Trail of Bits](https://www.trailofbits.com/about), 4 problèmes ont été identifiés, et 3 d'entre eux sont corrigés dans la version 4.2.
Le nouveau site web est en ligne : https://simplex.chat
Sortie de la v4.2 :
- liens de groupes - les administrateurs de groupes peuvent créer les liens pour que les nouveaux membres puissent les rejoindre
- acceptation automatique des demandes de contact + configuration de l'acceptation de l'incognito et du message de bienvenue
- petites nouveautés : changer un rôle de membre du groupe, marquer le chat comme non lu, envoyer des autocollants et des GIFs depuis les claviers Android.
- changer manuellement de contact ou de membre vers une autre adresse / serveur (BETA)
- recevoir des fichiers plus rapidement (BETA)
28 sept. 2022 [v4 : chiffrement de la base de données locale](./20220928-simplex-chat-v4-encrypted-database.md)
- base de données locale de chat chiffrée - si vous utilisez déjà l'application, vous pouvez chiffrer la base de données dans les paramètres de l'application.
- support pour les serveurs WebRTC ICE auto-hébergés
- amélioration de la stabilité de la création de nouvelles connexions : groupes, fichiers et contacts plus fiables
- suppression des fichiers et des médias - par sécurité et pour économiser de l'espace de stockage
- Pour les développeurs - TypeScript SDK pour l'intégration avec SimpleX Chat
- support des images animées dans l'application Android
- Interface utilisateur en allemand pour les applications mobiles
1 sept. 2022 [v3.2 : Mode Incognito](./20220901-simplex-chat-v3.2-incognito-mode.md)
- Mode Incognito - utiliser un nouveau nom de profil aléatoire pour chaque contact
- utiliser des adresses de serveur .onion avec Tor
- défilement et recherche sans fin
- choix d'une couleur secondaire et du mode sombre
- réduction de la taille des APK pour le téléchargement direct et dans le repo F-Droid de 200 à 46Mb !
L'audit d'implémentation est prévu pour Octobre !
8 août 2022 [v3.1 : groupes de discussion](./20220808-simplex-chat-v3.1-chat-groups.md)
- enfin, des groupes de chat secrets - personne d'autre que les membres ne sait qu'ils existent !
- accès aux serveurs de messagerie via Tor sur toutes les plateformes
- paramètres réseau avancés pour optimiser l'utilisation du trafic
- protocole de chat publié
- nouvelles icônes d'application
23 juil. 2022 [v3.1-beta : accès aux serveurs via Tor](./20220723-simplex-chat-v3.1-tor-groups-efficiency.md)
- application terminale : accès aux serveurs de messagerie via un proxy SOCKS5 (par exemple, Tor).
- applications mobiles : rejoindre et quitter des groupes de discussion.
- utilisation optimisée de la batterie et du trafic - réduction jusqu'à 90x !
- deux configurations docker pour les serveurs SMP auto-hébergés.
11 juil. 2022 [v3 : notifications push instantanées pour iOS et appels audio/vidéo](./20220711-simplex-chat-v3-released-ios-notifications-audio-video-calls-database-export-import-protocol-improvements.md) :
- exportation et importation de la base de données de chat
- appels audio/vidéo chiffrés de bout en bout
- amélioration de la confidentialité du protocole et des performances
4 juin 2022 [v2.2 : nouveaux paramètres de confidentialité et de sécurité](./20220604-simplex-chat-new-privacy-security-settings.md)
24 mai 2022 [v2.1 : effacement des messages pour une meilleure confidentialité des conversations](./20220524-simplex-chat-better-privacy.md)
11 mai 2022 [Publication de la v2.0 - envoi d'images et de fichiers dans les applications mobiles](./20220511-simplex-chat-v2-images-files.md)
04 avr. 2022 [Notifications instantanées pour les applications mobiles SimpleX Chat](./20220404-simplex-chat-instant-notifications.md)
08 mars 2022 [Applications mobiles pour iOS et Android](./20220308-simplex-chat-mobile-apps.md)
14 févr. 2022. [SimpleX Chat : rejoignez notre version bêta publique pour iOS](./20220214-simplex-chat-ios-public-beta.md)
12 janv. 2022. [SimpleX Chat v1 : la plateforme de chat et d'application la plus privée et la plus sécurisée](./20220112-simplex-chat-v1-released.md)
08 déc. 2021. [Sortie de SimpleX Chat v0.5 : la première plateforme de chat 100% privée par définition - aucun accès à votre graphe de connexions](./20211208-simplex-chat-v0.5-released.md)
14 septembre 2021. [SimpleX Chat v0.4 publié : chat open-source qui utilise un protocole de routage de messages préservant la confidentialité](./20210914-simplex-chat-v0.4-released.md)
12 mai 2021. [Prototype de chat SimpleX](./20210512-simplex-chat-terminal-ui.md)
22 oct. 2020. [SimpleX Chat](./20201022-simplex-chat.md)
+1 -1
View File
@@ -7,7 +7,7 @@ constraints: zip +disable-bzip2 +disable-zstd
source-repository-package
type: git
location: https://github.com/simplex-chat/simplexmq.git
tag: 3be0008c5a371508a5bf1375cbb68ad470589644
tag: ee2a764f93a8b5af485949699d6a64ebbbaf2557
source-repository-package
type: git
+39
View File
@@ -0,0 +1,39 @@
# Accessing files in Android app
SimpleX uses databases and stores its preferences inside private data directory in Android. The directory contains:
- databases
- sent and received files
- temporary files that will be deleted when not needed
- user preferences.
If you want to view what's stored inside SimpleX data directory you need to have:
- Unix-based operating system (or [MinGW](https://www.mingw-w64.org/downloads/) on Windows)
- ADB (Android Debug Bridge) tool installed on a computer ([download it here](https://developer.android.com/studio/releases/platform-tools) and install)
- your device connected via USB or Wi-Fi to the computer.
## The process:
- open SimpleX, go to `Database passphrase & export`, enable `App data backup`. This will make other steps working
- _optional_: if you want to view database contents, change database passphrase from random to yours. To do this, stop a chat in `Database passphrase & export` screen, open `Database passphrase`, enter new passphrase and confirm it, then update it. Do not forget it, otherwise you'll lose all your data in case passphrase will be asked again later
- open a terminal emulator (Windows CMD/Powershell will not work) and change directory to the one you want to use for storing the backup:
```bash
cd /tmp # just an example
```
Then run the following:
```bash
adb -d backup -f chat.ab -noapk chat.simplex.app &&
tail -n +5 chat.ab > chat.dat &&
printf "\x1f\x8b\x08\x00\x00\x00\x00\x00" | cat - chat.dat > chat.gz &&
tar -xvzf chat.gz
```
Now unlock the device and confirm a backup operation without using a password for encryption, otherwise the commands will not work.
After that the backup should be ended. If you see an error saying `tar: Error is not recoverable: exiting now` but before that you have printed some file names, don't worry, it's ok.
Now the backed-up files will be inside `./apps/chat.simplex.app/`.
Please, note, that if you use a modern version of SimpleX, the databases will be encrypted, and you'll not be able to view contents of them without using `sqlcipher` application and without knowing decryption passphrase (you need to change it to yours from randomly generated in the app firstly).
Please, follow [SQL.md](./SQL.md) guide for more info of how to decrypt your databases and to make queries to them.
+2
View File
@@ -1,3 +1,5 @@
| Updated 31.01.2023 | Languages: EN, [FR](/docs/lang/fr/CLI.md) |
# SimpleX Chat terminal (console) app for Linux/MacOS/Windows
## Table of contents
+2
View File
@@ -1,3 +1,5 @@
| Updated 31.01.2023 | Languages: EN, [FR](/docs/lang/fr/CONTRIBUTING.md) |
# Contributing guide
## Compiling with SQLCipher encryption enabled
+3 -1
View File
@@ -1,3 +1,5 @@
| Updated 31.01.2023 | Languages: EN, [FR](/docs/lang/fr/SERVER.md) |
# Hosting your own SMP Server
## Overview
@@ -152,7 +154,7 @@ For example, run:
sudo su smp -c "smp-server init -y -l --ip 192.168.1.5 --password test"
```
to initilize your `smp-server` configuration with:
to initialize your `smp-server` configuration with:
- restoring connections and messages when the server is restarted (`-l` flag),
- IP address `192.168.1.5`,
+4 -1
View File
@@ -1,3 +1,5 @@
| Updated 07.02.2023 | Languages: EN, [FR](/docs/lang/fr/SIMPLEX.md) |
# SimpleX platform - motivation and comparison
## Problems
@@ -83,7 +85,7 @@ There are several P2P chat/messaging protocols and implementations that aim to s
5. All known P2P networks are likely to be vulnerable to [Sybil attack][12], because each node is discoverable, and the network operates as a whole. Known measures to reduce the probability of the Sybil attack either require a centralized component or expensive [proof of work][13]. The proposed design, on the opposite, has no server discoverability - servers are not connected, not known to each other and to all clients. The SimpleX network is fragmented and operates as multiple isolated connections. It makes network-wide attacks on SimpleX network impossible - even if some servers are compromised, other parts of the network can operate normally, and affected clients can switch to using other servers without losing contacts or messages.
6. P2P networks are likely to be vulnerable to [DRDoS attack][14]. In the proposed design clients only relay traffic from known trusted connection and cannot be used to reflect and amplify the traffic in the whole network.
6. P2P networks are likely to be [vulnerable][14] to [DRDoS attack][15]. In the proposed design clients only relay traffic from known trusted connection and cannot be used to reflect and amplify the traffic in the whole network.
[1]: https://en.wikipedia.org/wiki/End-to-end_encryption
[2]: https://en.wikipedia.org/wiki/Man-in-the-middle_attack
@@ -93,3 +95,4 @@ There are several P2P chat/messaging protocols and implementations that aim to s
[12]: https://en.wikipedia.org/wiki/Sybil_attack
[13]: https://en.wikipedia.org/wiki/Proof_of_work
[14]: https://www.usenix.org/conference/woot15/workshop-program/presentation/p2p-file-sharing-hell-exploiting-bittorrent
[15]: https://en.wikipedia.org/wiki/Denial-of-service_attack#Reflected_attack
+17 -1
View File
@@ -1,4 +1,20 @@
# Accessing message history via SQL queries
| Updated 31.01.2023 | Languages: EN, [FR](/docs/lang/fr/SQL.md) |
# Accessing messages in the database
## Decrypting databases
In order to view database data you need to decrypt it first. Install `sqlcipher` using your favorite package manager and run the following commands in the directory with databases:
```bash
sqlcipher files_chat.db
pragma key="youDecryptionPassphrase";
# Ensure it works fine
select * from users;
```
If you see `Parse error: no such table: users`, make sure you entered correct passphrase, and you have changed passphrase from random in Android app (if you got this database from Android device, of course).
## SQL queries
You can run queries against `direct_messages`, `group_messages` and `all_messages` (or their simpler alternatives `direct_messages_plain`, `group_messages_plain` and `all_messages_plain`), for example:
+57
View File
@@ -0,0 +1,57 @@
# Contributing translations to SimpleX Chat
Huge thanks for your interest in translating SimpleX Chat - it helps a lot to make it accessible to a wider range of users, and we really appreciate your help.
It requires a substantial time investment - most people underestimate it initially - and ongoing maintenance as we develop the application.
This document is created to speed up this process, and share some important "gotchas" we've discovered while working with Weblate - the platform we use for interface translations.
## Before you start translation
1. Create an account in Weblate, using the same email that you use in GitHub - it will make your contributions associated with your GitHub account, and might help you in some cases. Once translation is released to the users we will add your account name to the [list of translators](https://github.com/simplex-chat/simplex-chat#translate-the-apps).
2. Before you start the translation there is a simple contributor agreement to sign via Weblate - this is to avoid any conflicts around IP rights.
3. We can also add you to the group of translators for any questions and updates - please connect to me via chat.
## Translation progress
1. Please start from [Android app](https://hosted.weblate.org/projects/simplex-chat/android/), both when you do the most time-consuming initial translation, and add any strings later. Firstly, iOS strings can be a bit delayed from appearing in Weblate, as it requires a manual step from us before they are visible. Secondary, Android app is set up as a glossary for iOS app, and 2/3 of all strings require just to clicks to transfer them from Android to iOS (it still takes some time, Weblate doesn't automate it, unfortunately).
2. Some of the strings do not need translations, but they still need to be copied over - there is a button in weblate UI for that:
<img src="./images/weblate_1.png" alt="weblate: copy source to translation" width="100%">
3. Weblate also has automatic suggestions that can speed up the process. Sometimes they can be used as is, sometimes they need some editing - click to use them in translations.
4. Once all strings in Android app are translated, please review it to ensure consistent style and language, so that the same words are consistently used for similar user actions, same as in English. Sometimes, you will have to use different words in cases when English has just one, please try to use these choices consistently in similar contexts, to make it easier for the end users.
5. When you translate [iOS app](https://hosted.weblate.org/projects/simplex-chat/ios/), a large part of the strings are exactly the same - they can be copied over in one click in glossary section. The visual hint that it can be done is that the whole source string is highlighted in yellow. Many other strings are very similar, they only differ in interpolation syntax or how bold font is used - they require minimal editing. There are some strings that are unique to iOS platform - they need to be translated separately.
<img src="./images/weblate_2.png" alt="weblate: automatic suggestions" width="100%">
## Once translation is completed
Once both Android and iOS apps are translated, please let us know.
We will then:
- review all the translations and suggest any corrections - it also takes a bit of time :)
- merge them to the source code - while we do it weblate will be locked for changes.
- create beta releases of both iOS and Android apps - we can also add you to the internal tester groups, so you can install the apps before anybody else.
- release it to our beta users - it's more than a thousand people who use our beta versions.
- release the app and include the new language in the announcement.
*Please note*: we aim to keep app functions consistent between Android and iOS platforms, when possible, so we will release and announce a new language once both platforms have been translated. It doesn't mean you have to do it, but we will have to wait until somebody else translates the second platform. But if you start from Android, iOS usually takes 3-4x less time to add.
## What is next
1. As we update the app, we post the updates in the group of translators. You are absolutely under no obligation to translate these additional strings. We hugely appreciate if you do though, as it makes the users experience so much better when they depend on your translations, than if some new part of the app is not translated.
2. You can also help adoption in your country / language group by translating our documents - we have just started it - and also our website content. There have been many requests to do it and we are currently adding the translation framework for the website.
3. Also, if you want to be a moderator/admin of the users group in your language, once the app is translated we can host such group - we are preparing community guidelines and adding some moderation tools to the app to be released in v5 in March.
Thank you very much again for helping us grow SimpleX Chat!
Evgeny, SimpleX Chat founder.
+4 -2
View File
@@ -1,3 +1,5 @@
| Updated 31.01.2023 | Languages: EN, [FR](/docs/lang/fr/WEBRTC.md) |
# Using custom WebRTC ICE servers in SimpleX Chat
## Deploy STUN/TURN server
@@ -87,7 +89,7 @@ stun:stun.example.com:5349
turn:username:password@turn.example.com:5349
```
This is it - you now can make audio and video calls via your own server, without sharing any data with our servers (other than the key excange with your contact in E2E encrypted messages).
This is it - you now can make audio and video calls via your own server, without sharing any data with our servers (other than the key exchange with your contact in E2E encrypted messages).
## Troubleshoot
@@ -116,7 +118,7 @@ This is it - you now can make audio and video calls via your own server, without
Connection to <your_ip_or_domain> 5349 port [tcp/*] succeeded!
```
- **Test STUN/TURN connectivity:**
- **Test STUN/TURN connectivity**:
1. Go to [IceTest](https://icetest.info/).
Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

+254
View File
@@ -0,0 +1,254 @@
| Updated 07.02.2023 | Languages: [EN](/docs/CLI.md), FR |
# Application de terminal (console) SimpleX Chat pour Linux/MacOS/Windows
## Table des matières
- [Fonctionnalités du terminal de chat](#fonctionnalités-du-terminal-de-chat)
- [Installation](#🚀-installation)
- [Télécharger le client de chat](#télécharger-le-client-de-chat)
- [Linux et MacOS](#linux-et-macos)
- [Windows](#windows)
- [Compiler depuis la source](#compiler-depuis-la-source)
- [Utiliser Docker](#utiliser-docker)
- [Utiliser Haskell stack](#utiliser-haskell-stack)
- [Utilisation](#utilisation)
- [Lancement du client de chat](#lancement-du-client-de-chat)
- [Accéder aux serveurs de messagerie via Tor](#accéder-aux-serveurs-de-messagerie-via-Tor)
- [Comment utiliser SimpleX chat](#comment-utiliser-simplex-chat)
- [Groupes](#groupes)
- [Envoi de fichiers](#envoi-de-fichiers)
- [Adresses de contact d'utilisateur](#adresses-de-contact-dutilisateur)
- [Accéder à l'historique des chats](#accéder-à-lhistorique-des-chats)
## Fonctionnalités du terminal de chat
- Chat individuel avec plusieurs personnes dans la même fenêtre de terminal.
- Messagerie de groupe.
- Envoi de fichiers aux contacts et aux groupes.
- Adresses de contact des utilisateurs - établissez des connexions via des liens de contact à usage multiple.
- Les messages sont conservés dans une base de données SQLite locale.
- Nom du destinataire auto-rempli - il suffit de taper vos messages pour répondre à l'expéditeur une fois la connexion établie.
- Des serveurs SMP de démonstration sont disponibles et préconfigurés dans l'application - ou vous pouvez [déployer votre propre serveur](https://github.com/simplex-chat/simplexmq#using-smp-server-and-smp-agent).
- Pas d'identité globale ni de noms visibles par le.s serveur.s, ce qui garantit la confidentialité totale de vos contacts et de vos conversations.
- Deux couches de chiffrement E2E (double ratchet pour les connexions duplex, utilisant un accord de clé X3DH avec des clés Curve448 éphémères, et NaCl crypto_box pour les files d'attente SMP, utilisant des clés Curve25519) et transmission hors bande des clés des destinataires (voir [Comment utiliser SimpleX chat](#comment-utiliser-simplex-chat)).
- Validation de l'intégrité du message (en incluant les résumés des messages précédents).
- Authentification de chaque commande/message par les serveurs SMP avec des clés Ed448 générées automatiquement.
- Chiffrement de transport TLS 1.3.
- Chiffrement supplémentaire des messages du serveur SMP au destinataire pour réduire la corrélation du trafic.
Les clés publiques impliquées dans l'échange de clés ne sont pas utilisées comme identité, elles sont générées aléatoirement pour chaque contact.
Voir les [primitives de chiffrement utilisées](https://github.com/simplex-chat/simplexmq/blob/master/protocol/overview-tjr.md#encryption-primitives-used) pour les détails techniques.
<a name="🚀-installation"></a>
## 🚀 Installation
### Télécharger le client de chat
#### Linux et MacOS
Pour **installer** ou **mettre à jour** `simplex-chat`, vous devez exécuter le script d'installation. Pour ce faire, utilisez la commande cURL ou Wget suivante :
```sh
curl -o- https://raw.githubusercontent.com/simplex-chat/simplex-chat/stable/install.sh | bash
```
```sh
wget -qO- https://raw.githubusercontent.com/simplex-chat/simplex-chat/stable/install.sh | bash
```
Une fois le client de chat téléchargé, vous pouvez le lancer avec la commande `simplex-chat` dans votre terminal.
Vous pouvez également télécharger manuellement une version binary de chat pour votre système à partir de la [dernière version stable] (https://github.com/simplex-chat/simplex-chat/releases) et le rendre exécutable comme indiqué ci-dessous.
```sh
chmod +x <binary>
mv <binary> ~/.local/bin/simplex-chat
```
(ou tout autre emplacement préféré sur `PATH`).
Sous MacOS, vous devez également [autoriser Gatekeeper à l'exécuter](https://support.apple.com/en-us/HT202491).
#### Windows
```sh
move <binary> %APPDATA%/local/bin/simplex-chat.exe
```
### Compiler depuis la source
> **Veuillez noter** : pour compiler l'application, utilisez le code source de la [branche stable](https://github.com/simplex-chat/simplex-chat/tree/stable).
#### Utiliser Docker
Sous Linux, vous pouvez compiler l'exécutable du chat en utilisant [docker build with custom output](https://docs.docker.com/engine/reference/commandline/build/#custom-build-outputs) :
```shell
git clone git@github.com:simplex-chat/simplex-chat.git
cd simplex-chat
git checkout stable
DOCKER_BUILDKIT=1 docker build --output ~/.local/bin .
```
> **Veuillez noter** : Si vous rencontrez l'erreur ``version `GLIBC_2.28' non trouvée``, reconstruisez-le avec l'image de base `haskell:8.10.7-stretch`(changez-la dans votre [Dockerfile](Dockerfile) local).
#### Utiliser Haskell stack
(sur n'importe quel OS)
1. Installer [Haskell GHCup](https://www.haskell.org/ghcup/), GHC 8.10.7 et cabal :
```shell
curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh
```
2. Compiler le projet :
```shell
git clone git@github.com:simplex-chat/simplex-chat.git
cd simplex-chat
git checkout stable
# sur Linux
apt-get update && apt-get install -y build-essential libgmp3-dev zlib1g-dev
cp scripts/cabal.project.local.linux cabal.project.local
# ou sur MacOS:
# brew install openssl@1.1
# cp scripts/cabal.project.local.mac cabal.project.local
# vous devrez peut-être modifier cabal.project.local pour indiquer l'emplacement réel d'openssl
cabal update
cabal install
```
## Utilisation
### Lancement du client de chat
Pour démarrer le client de chat, exécutez `simplex-chat` depuis le terminal.
Par défaut, le répertoire de données de l'application est créé dans le répertoire personnel (`~/.simplex`, ou `%APPDATA%/simplex` sous Windows), et deux fichiers de base de données SQLite `simplex_v1_chat.db` et `simplex_v1_agent.db` y sont initialisés.
Pour spécifier un préfixe de chemin de fichier différent pour les fichiers de la base de données, utilisez l'option de ligne de commande `-d` :
```shell
$ simplex-chat -d alice
```
L'exécution ci-dessus, par exemple, créera les fichiers de base de données `alice_v1_chat.db` et `alice_v1_agent.db` dans le répertoire actuel.
Trois serveurs SMP par défaut sont hébergés sur Linode - ils sont [pré-configurés dans l'application](https://github.com/simplex-chat/simplex-chat/blob/stable/src/Simplex/Chat/Options.hs#L42).
Si vous avez déployé votre propre serveur SMP, vous pouvez configurer le client via l'option `-s` :
```shell
$ simplex-chat -s smp://LcJUMfVhwD8yxjAiSaDzzGF3-kLG4Uh0Fl_ZIjrRwjI=@smp.example.com
```
La chaîne encodée en Base64url qui précède l'adresse du serveur est l'empreinte du certificat hors ligne du serveur qui est validée par le client lors du handshake TLS.
Vous pouvez toujours parler aux gens en utilisant le serveur par défaut ou tout autre serveur - cela n'affecte que l'emplacement de la file d'attente des messages lorsque vous initiez la connexion (et la file d'attente des réponses peut se trouver sur un autre serveur, comme défini par le client de l'autre coté).
Exécutez `simplex-chat -h` pour voir toutes les options disponibles.
### Accéder aux serveurs de messagerie via Tor
Installez Tor et exécutez-le en tant que proxy SOCKS5 sur le port 9050, par exemple sur Mac vous pouvez :
```
brew install tor
brew services start tor
```
Utilisez l'option `-x` pour accéder aux serveurs via Tor :
```
simplex-chat -x
```
Vous pouvez également utiliser l'option `--socks-proxy=ipv4:port` ou `--socks-proxy=:port` pour configurer l'hôte et le port de votre proxy SOCKS5, par exemple si vous l'exécutez sur un autre hôte ou port.
### Comment utiliser SimpleX chat
Une fois que vous aurez lancé le chat, vous serez invité à indiquer un "nom d'affichage" et un "nom complet" facultatif pour créer un profil de chat local. Votre nom d'affichage est un alias par lequel vos contacts peuvent se référer à vous. Il n'est pas unique et ne sert pas d'identité globale. Si certains de vos contacts ont choisi le même nom d'affichage, le client de chat ajoute un suffixe numérique à leur nom d'affichage local.
Le schéma ci-dessous montre comment connecter et envoyer un message à un contact :
<div align="center">
<img align="center" src="/images/how-to-use-simplex.svg">
</div>
Une fois que vous avez configuré votre profil local, entrez `/c` (pour `/connect`) pour créer une nouvelle connexion et générer une invitation. Envoyez cette invitation à votre contact via n'importe quel autre canal.
Vous pouvez créer plusieurs invitations en saisissant plusieurs fois la commande `/connect` et en envoyant ces invitations aux contacts correspondants avec lesquels vous souhaitez vous connecter.
L'invitation ne peut être utilisée qu'une seule fois et même si elle est interceptée, l'attaquant ne pourra pas l'utiliser pour vous envoyer les messages via cette file d'attente une fois que votre contact aura confirmé que la connexion est établie. Voir le protocole de l'agent pour une explication du [format d'invitation](https://github.com/simplex-chat/simplexmq/blob/master/protocol/agent-protocol.md#connection-request).
Le contact qui a reçu l'invitation doit saisir `/c <invitation>` pour accepter la connexion. La connexion est alors établie, et les deux parties sont notifiées.
Ils utiliseraient alors les commandes `@<name> <message>` pour envoyer des messages. Vous pouvez aussi simplement commencer à taper un message pour l'envoyer au contact qui était le dernier.
Utilisez `/help` dans le chat pour voir la liste des commandes disponibles.
### Groupes
Pour créer un groupe, utilisez `/g <groupe>`, puis ajoutez-y des contacts avec `/a <groupe> <nom>`. Vous pouvez ensuite envoyer des messages au groupe en entrant `#<groupe> <message>`. Utilisez `/help groups` pour d'autres commandes.
![simplex-chat](/images/groups.gif)
> **Veuillez noter** : les groupes ne sont pas stockés sur un serveur, ils sont conservés comme une liste de membres dans la base de données de l'application à qui les messages seront envoyés.
### Envoi de fichiers
Vous pouvez envoyer un fichier à votre contact avec `/f @<contact> <chemin_du_fichier>` - le destinataire devra l'accepter avant qu'il ne soit envoyé. Utilisez `/help files` pour les autres commandes.
![simplex-chat](/images/files.gif)
Vous pouvez envoyer des fichiers à un groupe avec `/f #<group> <chemin_du_fichier>`.
### Adresses de contact d'utilisateur
Comme alternative aux liens d'invitation unique, vous pouvez créer une adresse à long terme avec `/ad` (pour `/address`). L'adresse créée peut ensuite être partagée via n'importe quel canal, et utilisée par d'autres utilisateurs comme lien pour faire une demande de contact avec `/c <adresse_de_contact_de_l'utilisateur>`.
Vous pouvez accepter ou rejeter les demandes entrantes avec les commandes `/ac <nom>` et `/rc <nom>`.
L'adresse de l'utilisateur est "à long terme" dans le sens où il s'agit d'un lien de connexion à usage multiple - elle peut être utilisée jusqu'à ce qu'elle soit supprimée par l'utilisateur, auquel cas toutes les connexions établies resteront actives (contrairement à ce qui se passe avec le courrier électronique, où le changement d'adresse empêche les gens de vous envoyer des messages).
Utilisez `/help address` pour les autres commandes.
![simplex-chat](/images/user-addresses.gif)
### Accéder à l'historique des chats
SimpleX chat stocke tous vos contacts et conversations dans une base de données SQLite locale, ce qui la rend privée et portable par définition, appartenant et contrôlée par l'utilisateur.
Vous pouvez visualiser et rechercher votre historique de chat en interrogeant votre base de données. Exécutez le script ci-dessous pour créer des aperçus de messages dans votre base de données.
```sh
curl -o- https://raw.githubusercontent.com/simplex-chat/simplex-chat/stable/scripts/message_views.sql | sqlite3 ~/.simplex/simplex_v1_chat.db
```
Ouvrir un terminal de commande SQLite :
```sh
sqlite3 ~/.simplex/simplex_v1_chat.db
```
Voir les [requêtes de message](./SQL.md) à titre d'exemple.
> **Veuillez noter :** Les contraintes de clé étrangère SQLite sont désactivées par défaut, et doivent être **[activé séparément pour chaque connexion de base de données](https://sqlite.org/foreignkeys.html#fk_enable)**. Cette dernière peut être réalisée en exécutant la commande `PRAGMA foreign_keys = ON;` sur une connexion de base de données ouverte. En exécutant des requêtes modifiant les données sans activer les clés étrangères au préalable, vous risquez de mettre votre base de données dans un état inconsistant.
**Requêtes de commodité**
Pour recevoir tous les messages du jour (`chat_dt` est en UTC) :
```sql
select * from all_messages_plain where date(chat_dt) > date('now', '-1 day') order by chat_dt;
```
Pour recevoir les messages de la nuit dans la matinée :
```sql
select * from all_messages_plain where chat_dt > datetime('now', '-15 hours') order by chat_dt;
```
+21
View File
@@ -0,0 +1,21 @@
| Updated 31.01.2023 | Languages: [EN](/docs/CONTRIBUTING.md), FR |
# Guide pour contribuer
## Compiler avec le chiffrement SQLCipher activé
Ajoutez `cabal.project.local` à la racine du projet avec les emplacements des en-têtes et des bibliothèques OpenSSL ainsi que le paramètre définissant le mode de chiffrement :
```
cp scripts/cabal.project.local.mac cabal.project.local
# or
# cp scripts/cabal.project.local.linux cabal.project.local
```
## OpenSSL sur MacOS
LibreSSL est fourni par défaut sur MacOS, OpenSSL doit être installé pour compiler SimpleX à partir de la source.
OpenSSL peut être installé avec `brew install openssl@1.1`
Vous devez ajouter `/opt/homebrew/opt/openssl@1.1/bin` à votre PATH pour que tout fonctionne correctement.
+330
View File
@@ -0,0 +1,330 @@
| Updated 07.02.2023 | Languages: [EN](/README.md), FR |
<img src="/images/simplex-chat-logo.svg" alt="SimpleX logo" width="100%">
# SimpleX - la première plateforme de messagerie qui n'a pas le moindre identifiant d'utilisateur - 100% privé par définition !
[![build](https://github.com/simplex-chat/simplex-chat/actions/workflows/build.yml/badge.svg?branch=stable)](https://github.com/simplex-chat/simplex-chat/actions/workflows/build.yml)
[![GitHub downloads](https://img.shields.io/github/downloads/simplex-chat/simplex-chat/total)](https://github.com/simplex-chat/simplex-chat/releases)
[![GitHub release](https://img.shields.io/github/v/release/simplex-chat/simplex-chat)](https://github.com/simplex-chat/simplex-chat/releases)
[![Join on Reddit](https://img.shields.io/reddit/subreddit-subscribers/SimpleXChat?style=social)](https://www.reddit.com/r/SimpleXChat)
[![Follow on Mastodon](https://img.shields.io/mastodon/follow/108619463746856738?domain=https%3A%2F%2Fmastodon.social&style=social)](https://mastodon.social/@simplex)
[<img src="https://github.com/simplex-chat/.github/blob/master/profile/images/apple_store.svg" alt="iOS app" height="42">](https://apps.apple.com/us/app/simplex-chat/id1605771084)
&nbsp;
[![Android app](https://github.com/simplex-chat/.github/blob/master/profile/images/google_play.svg)](https://play.google.com/store/apps/details?id=chat.simplex.app)
&nbsp;
[<img src="https://github.com/simplex-chat/.github/blob/master/profile/images/f_droid.svg" alt="F-Droid" height="41">](https://app.simplex.chat)
&nbsp;
[<img src="https://github.com/simplex-chat/.github/blob/master/profile/images/testflight.png" alt="iOS TestFlight" height="41">](https://testflight.apple.com/join/DWuT2LQu)
&nbsp;
[<img src="https://github.com/simplex-chat/.github/blob/master/profile/images/apk_icon.png" alt="APK" height="41">](https://github.com/simplex-chat/simplex-chat/releases/latest/download/simplex.apk)
- 🖲 Protège vos messages et vos métadonnées - avec qui vous parlez et quand.
- 🔐 Chiffrement de bout en bout à double ratchet, avec couche de chiffrement supplémentaire.
- 📱 Apps mobiles pour Android ([Google Play](https://play.google.com/store/apps/details?id=chat.simplex.app), [APK](https://github.com/simplex-chat/simplex-chat/releases/latest/download/simplex.apk)) et [iOS](https://apps.apple.com/us/app/simplex-chat/id1605771084).
- 🚀 [Bêta TestFlight pour iOS](https://testflight.apple.com/join/DWuT2LQu) avec les nouvelles fonctionnalités 1 à 2 semaines plus tôt - **limitée à 10 000 utilisateurs** !
- 🖥 Disponible en tant que terminal (console) / CLI sur Linux, MacOS, Windows.
**NOUVEAU** : Audit de sécurité par [Trail of Bits](https://www.trailofbits.com/about), le [nouveau site](https://simplex.chat) et la v4.2 est disponible ! [Voir l'annonce](/blog/20221108-simplex-chat-v4.2-security-audit-new-website.md)
## Sommaire
- [Pourquoi la vie privée est importante](#pourquoi-la-vie-privée-est-importante)
- [L'approche SimpleX de la vie privée et de la sécurité](#lapproche-simplex-de-la-vie-privée-et-de-la-sécurité)
- [Confidentialité totale](#confidentialité-totale-de-votre-identité-de-votre-profil-de-vos-contacts-et-de-vos-métadonnées)
- [Protection contre le spam et les abus](#protection-contre-le-spam-et-les-abus)
- [Propriété et sécurité de vos données](#propriété-contrôle-et-sécurité-totale-de-vos-données)
- [Les utilisateurs sont maîtres de leur réseau SimpleX](#les-utilisateurs-sont-maîtres-du-réseau-simplex)
- [Foire aux questions](#foire-aux-questions)
- [Nouvelles et mises à jour](#nouvelles-et-mises-à-jour)
- [Établir une connexion privée](#établir-une-connexion-privée)
- [Installation rapide d'une application terminale](#⚡-installation-rapide-dune-application-pour-terminal)
- [Le modèle de la plateforme SimpleX](#le-modèle-de-la-plateforme-simplex)
- [Vie privée : détails techniques et limites](#vie-privée--détails-techniques-et-limites)
- [Pour les développeurs](#pour-les-développeurs)
- [Feuille de route](#feuille-de-route)
- [Rejoindre un groupe d'utilisateurs](#rejoindre-un-groupe-dutilisateurs)
- [Traduire l'application](#traduire-lapplication)
- [Contribuer](#contribuer)
- [Aidez-nous en faisant des dons](#aidez-nous-en-faisant-des-dons)
- [Avertissements, contact de sécurité, licence](#avertissements)
## Pourquoi la vie privée est importante
Tout le monde devrait se soucier de la confidentialité et de la sécurité de ses communications - des conversations anodines peuvent vous mettre en danger, même si vous n'avez rien à cacher.
L'une des histoires les plus choquantes est l'expérience de [Mohamedou Ould Salahi](https://fr.wikipedia.org/wiki/Mohamedou_Ould_Slahi) dont il a parlé dans ses Mémoires et qui est illustrée dans le film Désigné coupable (The Mauritanian). Il a été placé dans le camp de Guantanamo, sans procès, et y a été torturé pendant 15 ans après un appel téléphonique à un proche en Afghanistan, soupçonné d'être impliqué dans les attentats du 11 septembre, bien qu'il ait vécu en Allemagne pendant les 10 années précédant les attentats.
Il ne suffit pas d'utiliser une messagerie chiffrée de bout en bout, nous devrions tous utiliser des messageries qui protègent la vie privée de nos réseaux personnels, c'est-à-dire les personnes avec lesquelles nous sommes connectés.
## L'approche SimpleX de la vie privée et de la sécurité
### Confidentialité totale de votre identité, de votre profil, de vos contacts et de vos métadonnées.
**Contrairement à toutes les autres plateformes de messagerie existante, SimpleX n'a pas d'identifiant attribué aux utilisateurs.** - pas même des nombres aléatoires. Cela protège la confidentialité des personnes avec lesquelles vous communiquez, en les cachant aux serveurs de la plateforme SimpleX et à tout observateur. [En savoir plus](./SIMPLEX.md#protection-complète-de-votre-identité,-profil,-contacts-et-métadonnées).
### La meilleure protection contre le spam et les abus
Comme vous n'avez pas d'identifiant sur la plateforme SimpleX, vous ne pouvez pas être contacté, sauf si vous partagez un lien d'invitation unique ou une adresse d'utilisateur temporaire facultative. [En savoir plus](./SIMPLEX.md#la-meilleure-protection-contre-le-spam-et-les-abus).
### Propriété, contrôle et sécurité totale de vos données
SimpleX stocke toutes les données de l'utilisateur sur les appareils clients, les messages ne sont conservés que temporairement sur les serveurs relais SimpleX jusqu'à leur réception. [En savoir plus](./SIMPLEX.md#propriété,-contrôle-et-sécurité-totale-de-vos-données).
### Les utilisateurs sont maîtres du réseau SimpleX
Vous pouvez utiliser SimpleX avec vos propres serveurs et continuer à communiquer avec les personnes utilisant les serveurs préconfigurés dans les applications ou tout autre serveur SimpleX. [En savoir plus](./SIMPLEX.md#les-utilisateurs-sont-maîtres-du-réseau-simplex).
## Foire aux questions
1. _Comment SimpleX peut distribuer des messages sans aucun identifiant d'utilisateur ?_ Voir [l'annonce de la v2](/blog/20220511-simplex-chat-v2-images-files.md#the-first-messaging-platform-without-user-identifiers) explaining how SimpleX works.
2. _Pourquoi ne pas simplement utiliser Signal ?_ Signal est une plateforme centralisée qui utilise les numéros de téléphone pour identifier ses utilisateurs et leurs contacts. Cela signifie que, si le contenu de vos messages sur Signal est protégé par un chiffrement robuste de bout en bout, une importante quantité de métadonnées est visible pour Signal - avec qui vous parlez et quand.
3. _En quoi est-ce différent de Matrix, Session, Ricochet, Cwtch, etc., qui ne requièrent pas non plus d'identité d'utilisateur ?_ Bien que ces plateformes ne requièrent pas d'_identité réelle_, elles s'appuient sur des identités d'utilisateur anonymes pour transmettre les messages - il peut s'agir, par exemple, d'une clé d'identité ou d'un nombre aléatoire. L'utilisation d'une identité d'utilisateur persistante, même anonyme, crée un risque que le profil de connexion de l'utilisateur devienne connu des observateurs et/ou des fournisseurs de services, et peut conduire à la désanonymisation de certains utilisateurs. Si le même profil d'utilisateur est utilisé pour se connecter à deux personnes différentes via un messager autre que SimpleX, ces deux personnes peuvent confirmer si elles sont connectées à la même personne - elles utiliseraient le même identifiant d'utilisateur dans les messages. Avec SimpleX, il n'y a pas de métadonnées communes entre vos conversations avec différents contacts - une qualité qu'aucune autre plateforme de messagerie ne possède.
## Nouvelles et mises à jour
Mises à jour récentes :
[04 févr. 2023. Sortie de la v4.5 - avec plusieurs profils d'utilisateurs, les brouillons de messages, l'isolation du transport et l'interface en italien](/blog/20230204-simplex-chat-v4-5-user-chat-profiles.md).
[03 janv. 2023. Sortie de la v4.4 - avec les messages éphèmères, les messages "en direct" (dynamique), la vérification de sécurité de la connexion, les GIFs et les autocollants ainsi que la langue de l'interface en français](/blog/20230103-simplex-chat-v4.4-disappearing-messages.md).
[06 déc. 2022. Revues de novembre et sortie de la v4.3 - avec les messages vocaux instantanés, la suppression irréversible de messages et une configuration améliorée des serveurs](/blog/20221206-simplex-chat-v4.3-voice-messages.md).
[08 nov. 2022. Audit de sécurité par Trail of Bits, nouveau site web et sortie de la v4.2](/blog/20221108-simplex-chat-v4.2-security-audit-new-website.md).
[28 sept. 2022. v4.0 : base de données de chat local chiffrée et beaucoup d'autres changements](/blog/20220928-simplex-chat-v4-encrypted-database.md).
[Toutes les mises à jour](/blog)
## Établir une connexion privée
Vous devez partager un lien ou scanner un code QR (en personne ou pendant un appel vidéo) pour établir une connexion et commencer à envoyer des messages.
Le canal par lequel vous partagez le lien n'a pas besoin d'être sécurisé - il suffit que vous puissiez confirmer qui vous a envoyé le message et que votre connexion SimpleX soit établie.
<img src="https://github.com/simplex-chat/.github/blob/master/profile/images/app1.png" alt="Établir une connexion privée" height="360"> <img src="https://github.com/simplex-chat/.github/blob/master/profile/images/arrow.png" height="360"> <img src="https://github.com/simplex-chat/.github/blob/master/profile/images/app2.png" alt="Conversation" height="360"> <img src="https://github.com/simplex-chat/.github/blob/master/profile/images/arrow.png" height="360"> <img src="https://github.com/simplex-chat/.github/blob/master/profile/images/app3.png" alt="Appel vidéo" height="360">
## ⚡ Installation rapide d'une application pour terminal
```sh
curl -o- https://raw.githubusercontent.com/simplex-chat/simplex-chat/stable/install.sh | bash
```
Une fois le client de chat installé, exécutez simplement `simplex-chat` depuis votre terminal.
![simplex-chat](/images/connection.gif)
En savoir plus sur [l'installation et l'utilisation de l'application terminal](/docs/lang/fr/CLI.md).
## Le modèle de la plateforme SimpleX
SimpleX est un réseau client-serveur doté d'une topologie de réseau unique qui utilise des nœuds de relais de messages redondants et jetables pour transmettre de manière asynchrone des messages via des files d'attente de messages unidirectionnelles (simplex), assurant l'anonymat du destinataire et de l'expéditeur.
Contrairement aux réseaux P2P, tous les messages passent par un ou plusieurs nœuds de serveur, qui n'ont même pas besoin de persistance. En fait, la [mise en place de serveurs SMP actuelle](https://github.com/simplex-chat/simplexmq#smp-server) utilise un stockage des messages en mémoire, ne conservant que les enregistrements de la file d'attente. SimpleX offre une meilleure protection des métadonnées que les conceptions P2P, car aucun identifiant global de participant n'est utilisé pour transmettre les messages, et évite [les problèmes des réseaux P2P](/docs/lang/fr/SIMPLEX.md#comparaison-avec-dautres-protocoles).
Contrairement aux réseaux fédérés, les nœuds serveurs **ne possèdent pas d'enregistrements des utilisateurs**, **ne communiquent pas entre eux** et **ne stockent pas les messages** après leur livraison aux destinataires. Il n'existe aucun moyen de découvrir la liste complète des serveurs participant au réseau SimpleX. Cette conception permet d'éviter le problème de visibilité des métadonnées que connaissent tous les réseaux fédérés et protège mieux contre les attaques à l'échelle du réseau.
Seuls les appareils clients disposent d'informations sur les utilisateurs, leurs contacts et leurs groupes.
Voir le [livre blanc de SimpleX](https://github.com/simplex-chat/simplexmq/blob/stable/protocol/overview-tjr.md) pour plus d'informations sur les objectifs et la conception technique de la plateforme.
Voir [SimpleX Chat Protocol](/docs/protocol/simplex-chat.md) pour le format des messages envoyés entre les clients de chat sur [SimpleX Messaging Protocol](https://github.com/simplex-chat/simplexmq/blob/stable/protocol/simplex-messaging.md).
## Vie privée : détails techniques et limites
SimpleX Chat est un projet en cours - nous publions des améliorations dès qu'elles sont prêtes. Vous devez décider si l'état actuel est suffisant pour votre scénario d'utilisation.
Ce qui est déjà mis en place :
1. Au lieu des identifiants de profil utilisateur utilisés par toutes les autres plateformes, même les plus privées, SimpleX utilise des identifiants par paire et par file d'attente (2 adresses pour chaque file d'attente de messages unidirectionnelle, avec une 3ème adresse optionnelle pour les notifications push sur iOS, 2 files d'attente dans chaque connexion entre les utilisateurs). Cela rend l'observation du graphe du réseau au niveau de l'application plus difficile, car pour `n` utilisateurs il peut y avoir jusqu'à `n * (n-1)` files de messages.
2. Chiffrement de bout en bout dans chaque file d'attente de messages en utilisant [NaCl cryptobox](https://nacl.cr.yp.to/box.html). Ce système est ajouté pour permettre la redondance à l'avenir (en faisant passer chaque message par plusieurs serveurs), pour éviter d'avoir le même texte chiffré dans différentes files d'attente (qui ne serait visible pour l'attaquant que si TLS est compromis). Les clés de chiffrement utilisées pour ce chiffrement ne sont pas tournées, mais nous prévoyons de faire tourner les files d'attente. Des clés Curve25519 sont utilisées pour la négociation des clés.
3. Chiffrement [Double ratchet](https://signal.org/docs/specifications/doubleratchet/) de bout en bout de chaque conversation entre deux utilisateurs (ou membres d'un groupe). Il s'agit du même algorithme que celui utilisé dans Signal et dans de nombreuses autres applications de messagerie ; il fournit à la messagerie OTR un secret avant (chaque message est chiffré par sa propre clé éphémère), une récupération après effraction (les clés sont fréquemment renégociées dans le cadre de l'échange de messages). Deux paires de clés Curve448 sont utilisées pour l'accord de clé initial, la partie initiatrice transmet ces clés via le lien de connexion, la partie acceptante - dans l'en-tête du message de confirmation.
4. Couche supplémentaire de chiffrement utilisant la cryptobox NaCL pour les messages livrés du serveur au destinataire. Cette couche évite d'avoir tout texte chiffré en commun entre le trafic envoyé et reçu du serveur dans TLS (et il n'y a pas d'identifiants en commun non plus).
5. Plusieurs niveaux de remplissage de données pour contrer les attaques sur la taille des messages.
6. À partir de la v2 du protocole SMP (la version actuelle est la v4), toutes les métadonnées des messages, y compris l'heure de réception du message par le serveur (arrondie à la seconde), sont envoyées aux destinataires à l'intérieur d'une enveloppe chiffrée, de sorte que même si le protocole TLS est compromis, il ne peut être observé.
7. Seul TLS 1.2/1.3 est autorisé pour les connexions client-serveur, limité aux algorithmes cryptographiques : CHACHA20POLY1305_SHA256, Ed25519/Ed448, Curve25519/Curve448.
8. Pour se protéger contre les attaques par relecture, les serveurs SimpleX exigent le [tlsunique channel binding](https://www.rfc-editor.org/rfc/rfc5929.html) comme identifiant de session dans chaque commande client signée avec une clé éphémère par file d'attente.
9. Pour protéger votre adresse IP, tous les clients SimpleX Chat permettent d'accéder aux serveurs de messagerie via Tor - voir [v3.1 release announcement](/blog/20220808-simplex-chat-v3.1-chat-groups.md) pour plus de détails.
10. Chiffrement de la base de données locale avec une phrase secrète - vos contacts, groupes et tous les messages envoyés et reçus sont stockés de manière chiffrée. Si vous avez utilisé SimpleX Chat avant la version 4.0, vous devez activer le chiffrement via les paramètres de l'application.
11. Isolation du transport - des connexions TCP et des circuits Tor différents sont utilisés pour le trafic de différents profils d'utilisateurs, optionnellement - pour des connexions différentes avec des contacts et des membres de groupes.
Nous prévoyons d'ajouter bientôt :
1. Rotation automatique des files d'attente de messages. Actuellement, les files d'attente créées entre deux utilisateurs sont utilisées jusqu'à ce que la file d'attente soit modifiée manuellement par l'utilisateur ou que le contact soit supprimé. Nous prévoyons d'ajouter une rotation de file d'attente pour rendre ces identifiants temporaires et les faire tourner selon un calendrier à déterminer (par exemple, tous les X messages, ou toutes les X heures/jours).
2. Chiffrement des fichiers locaux. Actuellement, les images et les fichiers que vous envoyez et recevez sont stockés dans l'application sans être cryptés, vous pouvez les supprimer via `Paramètres / Base de données phrase secrète et exportation`.
3. Mélange de messages - ajout d'une latence à la livraison des messages, pour se protéger contre la corrélation du trafic par le temps de transmission des messages.
## Pour les développeurs
Vous pouvez :
- utiliser la bibliothèque SimpleX Chat pour intégrer des fonctionnalités de chat dans vos applications mobiles.
- créer des bots et services de chat en Haskell - voir un exemple de chat bot [simple](/apps/simplex-bot/) et un plus [avancé](/apps/simplex-bot-advanced/).
- créer des bots et des services de chat dans n'importe quelle langue en utilisant la CLI du terminal SimpleX Chat comme un serveur WebSocket local. Voir [TypeScript SimpleX Chat client](/packages/simplex-chat-client/) et un [exemple de chat bot en JavaScript](/packages/simplex-chat-client/typescript/examples/squaring-bot.js).
- exécuter [simplex-chat terminal CLI](/docs/lang/fr/CLI.md) pour exécuter des commandes de chat individuelles, par exemple pour envoyer des messages dans le cadre de l'exécution d'un script shell.
Si vous envisagez de développer avec la plateforme SimpleX, n'hésitez pas à nous contacter pour obtenir des conseils et de l'aide.
## Feuille de route
- ✅ Déploiement facile de serveur SimpleX avec stockage des messages en mémoire, sans aucune dépendance.
- ✅ Client terminal (console) avec support des groupes et des fichiers.
- ✅ Déploiement de serveur SimpleX en un clic sur Linode.
- ✅ Chiffrement de bout en bout à l'aide du protocole double ratchet avec une couche de chiffrement supplémentaire.
- ✅ Applications mobiles v1 pour Android et iOS.
- ✅ Notifications instantanées privées pour Android utilisant un service d'arrière-plan.
- ✅ Modèles de chat bot en Haskell.
- ✅ v2.0 - prise en charge des images et des fichiers dans les applications mobiles.
- ✅ Suppression manuelle de l'historique des chats.
- ✅ Appels audio et vidéo WebRTC chiffrés de bout en bout via les apps mobiles.
- ✅ Notifications instantanées préservant la confidentialité pour iOS à l'aide du service Apple Push Notification.
- ✅ Exportation et importation de la base de données de chat.
- ✅ Groupes de discussion dans les applications mobiles.
- ✅ Connexion aux serveurs de messagerie via Tor.
- ✅ Double adresse de serveur pour accéder aux serveurs de messagerie en tant que services cachés v3.
- ✅ Serveur de chat et SDK client TypeScript pour développer des interfaces de chat, des intégrations et des bots de chat (prêt à être annoncé).
- ✅ Mode incognito pour partager un nouveau nom aléatoire avec chaque contact.
- ✅ Chiffrement de la base de données de chat.
- ✅ Suppression automatique de l'historique des chats.
- ✅ Liens pour rejoindre des groupes et améliorer la stabilité des groupes.
- ✅ Messages vocaux (avec opt-out du destinataire par contact).
- ✅ Authentification de base pour les serveurs SMP (pour autoriser la création de nouvelles files d'attente).
- ✅ Affichage des messages supprimés, suppression complète des messages par l'expéditeur (avec opt-in du destinataire par contact).
- ✅ Blocage des captures d'écran et affichage dans les apps récentes.
- ✅ Configuration avancée du serveur.
- ✅ Messages éphèmére (avec opt-in du destinataire par contact).
- ✅ Messages "en direct" (dynamique).
- ✅ Vérification des contacts via un canal distinct extérieur.
- ✅ Plusieurs profils d'utilisateurs dans la même base de données de chat.
- ✅ Optionnellement, éviter de réutiliser la même session TCP pour plusieurs connexions.
- ✅ Conservation des brouillons de message.
- 🏗 Serveur de fichiers pour optimiser l'envoi efficace et privé de fichiers volumineux.
- 🏗 Amélioration des appels audio et vidéo.
- 🏗 Redondance et rotation des files d'attente SMP (mode manuel déjà fonctionnel).
- 🏗 Réduction de l'utilisation de la batterie et du trafic dans les grands groupes.
- 🏗 Prise en charge d'anciens OS d'Android et des processeurs 32 bits.
- Conversations éphémères/disparaissantes/OTR avec les contacts existants.
- Mot de passe/pin d'accès (avec mot de passe d'accès alternatif facultatif).
- Chiffrement des fichiers locaux de l'app.
- Messages vidéo.
- Amélioration de la navigation et de la recherche dans la conversation (développer et faire défiler jusqu'au message cité, faire défiler jusqu'aux résultats de la recherche, etc.)
- Confirmation de la distribution du message (avec option d'acceptation ou de refus de l'expéditeur par contact, TBC).
- Flux/diffusion.
- Widgets Web pour une interactivité personnalisée dans les chats.
- Automatismes et règles de chat programmables (réponses/transferts/suppressions/envois automatiques, rappels, etc.)
- Prise en charge du même profil sur plusieurs appareils.
- Client de bureau.
- Serveur d'identité préservant la confidentialité des adresses de contact/groupe basées sur le DNS pour simplifier la connexion et la découverte, mais non utilisé pour délivrer des messages :
- conservez tous vos contacts et groupes même si vous perdez le domaine.
- le serveur ne dispose pas d'informations sur vos contacts et groupes.
- Serveur hôte pour les grands groupes, les communautés et les canaux publics.
- Relais de distribution des messages pour les expéditeurs (pour dissimuler l'adresse IP des serveurs des destinataires et réduire le trafic).
- Relais SMP multi-nœuds à haute capacité.
## Rejoindre un groupe d'utilisateurs
Vous pouvez rejoindre le groupe anglophone général : [#SimpleX-Group](https://simplex.chat/contact#/?v=1-2&smp=smp%3A%2F%2Fhpq7_4gGJiilmz5Rf-CswuU5kZGkm_zOIooSw6yALRg%3D%40smp5.simplex.im%2FcIS0gu1h0Y8pZpQkDaSz7HZGSHcKpMB9%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAKzzWAJYrVt1zdgRp4pD3FBst6eK7233DJeNElENLJRA%253D%26srv%3Djjbyvoemxysm7qxap7m5d5m35jzv5qq6gnlv7s4rsn7tdwwmuqciwpid.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%228mazMhefXoM5HxWBfZnvwQ%3D%3D%22%7D). Just bear in mind that it has ~300 members now, and that it is fully decentralized, so sending a message and connecting to all members in this group will take some time, only join it if you:
- voir comment fonctionnent les grands groupes.
- le réseau n'est pas un problème (l'envoi de chaque message est de ~5mb).
Vous pouvez également rejoindre un nouveau groupe anglophone, plus petit, si vous souhaitez poser des questions sans trop de trafic : [#SimpleX-Group-2](https://simplex.chat/contact#/?v=1-2&smp=smp%3A%2F%2Fhpq7_4gGJiilmz5Rf-CswuU5kZGkm_zOIooSw6yALRg%3D%40smp5.simplex.im%2FQP8zaGjjmlXV-ix_Er4JgJ0lNPYGS1KX%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEApAgBkRZ3x12ayZ7sHrjHQWNMvqzZpWUgM_fFCUdLXwo%253D%26srv%3Djjbyvoemxysm7qxap7m5d5m35jzv5qq6gnlv7s4rsn7tdwwmuqciwpid.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22xWpPXEZZsQp_F7vwAcAYDw%3D%3D%22%7D)
Il existe également plusieurs groupes dans des langues autres que l'anglais, dans lesquelles nous avons traduit l'interface de l'application. Ces groupes sont destinés à tester et à poser des questions aux autres utilisateurs de SimpleX Chat. Nous ne répondons pas toujours aux questions dans ces groupes, alors veuillez les poser dans l'un des groupes anglophones.
- [\#SimpleX-DE](https://simplex.chat/contact#/?v=1-2&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FkIEl7OQzcp-J6aDmjdlQbRJwqkcZE7XR%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAR16PCu02MobRmKAsjzhDWMZcWP9hS8l5AUZi-Gs8z18%253D%26srv%3Dbylepyau3ty4czmn77q4fglvperknl4bi2eb2fdy2bh4jxtf32kf73yd.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22puYPMCQt11yPUvgmI5jCiw%3D%3D%22%7D) (Germanophone).
- [\#SimpleX-FR](https://simplex.chat/contact#/?v=1-2&smp=smp%3A%2F%2Fhpq7_4gGJiilmz5Rf-CswuU5kZGkm_zOIooSw6yALRg%3D%40smp5.simplex.im%2FvIHQDxTor53nwnWWTy5cHNwQQAdWN5Hw%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAPdgK1eBnETmgiqEQufbUkydKBJafoRx4iRrtrC2NAGc%253D%26srv%3Djjbyvoemxysm7qxap7m5d5m35jzv5qq6gnlv7s4rsn7tdwwmuqciwpid.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%221FyUryBPza-1ZFFE80Ekbg%3D%3D%22%7D) (Francophone).
- [\#SimpleX-RU](https://simplex.chat/contact#/?v=1-2&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FXZyt3hJmWsycpN7Dqve_wbrAqb6myk1R%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAMFVIoytozTEa_QXOgoZFq_oe0IwZBYKvW50trSFXzXo%253D%26srv%3Dbylepyau3ty4czmn77q4fglvperknl4bi2eb2fdy2bh4jxtf32kf73yd.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22xz05ngjA3pNIxLZ32a8Vxg%3D%3D%22%7D) (Russophone).
- [\#SimpleX-IT](https://simplex.chat/contact#/?v=1-2&smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2F0weR-ZgDUl7ruOtI_8TZwEsnJP6UiImA%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAq4PSThO9Fvb5ydF48wB0yNbpzCbuQJCW3vZ9BGUfcxk%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22e-iceLA0SctC62eARgYDWg%3D%3D%22%7D) (Italophone).
Vous pouvez rejoindre ces groupes soit en ouvrant ces liens dans l'application, soit en les ouvrant dans un navigateur de bureau et en scannant le code QR.
Rejoignez-nous via l'application pour échanger sur ce qui se passe et poser toutes vos questions !
## Traduire l'application
Grâce à nos utilisateurs et à [Weblate](https://hosted.weblate.org/engage/simplex-chat/), les applications de chat SimpleX sont traduites dans de nombreuses autres langues. Rejoignez nos traducteurs pour aider SimpleX à se développer plus rapidement !
Langues d'interface existantes :
Anglais (langue de développement)
Allemand : [@mlanp](https://github.com/mlanp)
Français : [@ishi_sama](https://github.com/ishi-sama)
Italien : [@unbranched](https://github.com/unbranched)
Russe : équipe du projet
Langues en cours : Chinois, hindi, japonais, néerlandais et [beaucoup d'autres](https://hosted.weblate.org/projects/simplex-chat/#languages). Nous ajouterons d'autres langues au fur et à mesure de l'achèvement de certaines d'entre elles. N'hésitez pas à suggérer de nouvelles langues et à nous contacter !
## Contribuer
Nous serions ravis de vous voir rejoindre le développement ! Vous pouvez contribuer à SimpleX Chat pour :
- traduire la page d'accueil du site web - il y a beaucoup de contenu que nous aimerions partager, cela permettrait d'attirer les nouveaux utilisateurs.
- écrire un tutoriel ou des recommandations sur l'hébergement de serveurs, l'automatisation des bots de chat, etc.
- développer des nouvelles fonctionnalités - veuillez nous contacter par chat pour que nous puissions vous aider à démarrer.
## Aidez-nous en faisant des dons
Un grand merci à tous ceux qui ont fait un don à SimpleX Chat !
Nous donnons la priorité à la confidentialité et à la sécurité des utilisateurs - ce serait impossible sans votre soutien.
Notre promesse à nos utilisateurs est que les protocoles SimpleX sont et resteront open-source, et dans le domaine public, - afin que tout le monde puisse créer les futures implémentations des clients et des serveurs. Nous créons une plateforme SimpleX basée sur les mêmes principes que l'e-mail et le web, mais bien plus privée et sécurisée.
Vos dons nous aident à collecter plus de fonds - tout montant, même le prix d'une tasse de café, ferait une grande différence pour nous.
Il est possible de faire un don via :
- [GitHub](https://github.com/sponsors/simplex-chat) - sans commission pour nous.
- [OpenCollective](https://opencollective.com/simplex-chat) - perçoit une commission, et accepte également les dons en crypto-monnaies.
- Adresse Monero : 8568eeVjaJ1RQ65ZUn9PRQ8ENtqeX9VVhcCYYhnVLxhV4JtBqw42so2VEUDQZNkFfsH5sXCuV7FN8VhRQ21DkNibTZP57Qt
- Adresse Bitcoin : 1bpefFkzuRoMY3ZuBbZNZxycbg7NYPYTG
- Adresse BCH : 1bpefFkzuRoMY3ZuBbZNZxycbg7NYPYTG
- Adresse Ethereum : 0x83fd788f7241a2be61780ea9dc72d2151e6843e2
- Adresse Solana : 43tWFWDczgAcn4Rzwkpqg2mqwnQETSiTwznmCgA2tf1L
- si vous souhaitez effectuer un don dans une autre crypto-monnaie, veuillez nous en informer via une demande GitHub ou un chat. Nous ajouterons l'adresse à la liste.
Merci,
Evgeny
Fondateur de SimpleX Chat
## Avertissements
[Protocoles et modèle de sécurité de SimpleX](https://github.com/simplex-chat/simplexmq/blob/master/protocol/overview-tjr.md) a été revu et a fait l'objet de nombreuses modifications et améliorations dans la v1.0.0.
L'audit de sécurité a été réalisé en octobre 2022 par [Trail of Bits](https://www.trailofbits.com/about), et la plupart des corrections ont été publiées dans la version 4.2.0 - voir [l'annonce](/blog/20221108-simplex-chat-v4.2-security-audit-new-website.md).
SimpleX Chat est une plateforme encore relativement jeune (les applications mobiles ont été lancées en mars 2022), il est donc possible que vous découvriez quelques bugs et des fonctionnalités manquantes. Nous apprécierions vraiment que vous nous fassiez part de tout ce qui doit être corrigé ou amélioré.
Les serveurs par défaut configurés dans l'application sont fournis dans la mesure du possible. Nous ne garantissons actuellement aucun accord de niveau de service, bien qu'historiquement nos serveurs aient eu un temps de disponibilité de plus de 99,9 % chacun.
Nous n'avons jamais fourni ou demandé l'accès à nos serveurs ou à toute information provenant de nos serveurs à des tiers. S'il nous est demandé de fournir un tel accès ou de telles informations, nous suivrons la procédure légale en vigueur.
Nous n'enregistrons pas les adresses IP des utilisateurs et nous n'effectuons aucune corrélation de trafic sur nos serveurs. Si la sécurité au niveau du trafic est primordiale, vous devez utiliser Tor ou un autre réseau similaire pour accéder aux serveurs de messagerie. Nous allons améliorer les applications client afin de réduire les possibilités de corrélation du trafic.
Pour en savoir plus, consultez la section [Conditions et politique de confidentialité](/PRIVACY.md).
## Contact de sécurité
Pour signaler une vulnérabilité de sécurité, veuillez nous envoyer un courriel à chat@simplex.chat. Nous coordonnerons la correction et la divulgation. Veuillez ne PAS signaler les vulnérabilités de sécurité via les problèmes GitHub.
Veuillez traiter toute découverte d'une éventuelle attaque par corrélation de trafic permettant de corréler deux conversations différentes au même utilisateur, autre que celle couverte par [le modèle de menace](https://github.com/simplex-chat/simplexmq/blob/stable/protocol/overview-tjr.md#threat-model), comme une vulnérabilité de sécurité, et suivez ce processus de publication.
## Licence
[AGPL v3](/LICENSE)
[<img src="https://github.com/simplex-chat/.github/blob/master/profile/images/apple_store.svg" alt="iOS app" height="42">](https://apps.apple.com/us/app/simplex-chat/id1605771084)
&nbsp;
[![Android app](https://github.com/simplex-chat/.github/blob/master/profile/images/google_play.svg)](https://play.google.com/store/apps/details?id=chat.simplex.app)
&nbsp;
[<img src="https://github.com/simplex-chat/.github/blob/master/profile/images/f_droid.svg" alt="F-Droid" height="41">](https://app.simplex.chat)
&nbsp;
[<img src="https://github.com/simplex-chat/.github/blob/master/profile/images/testflight.png" alt="iOS TestFlight" height="41">](https://testflight.apple.com/join/DWuT2LQu)
&nbsp;
[<img src="https://github.com/simplex-chat/.github/blob/master/profile/images/apk_icon.png" alt="APK" height="41">](https://github.com/simplex-chat/simplex-chat/releases/latest/download/simplex.apk)
+330
View File
@@ -0,0 +1,330 @@
| Updated 07.02.2023 | Languages: [EN](/docs/SERVER.md), FR |
# Héberger votre propre serveur SMP
## Présentation générale
Un serveur SMP est un serveur relais utilisé pour transmettre les messages sur le réseau SimpleX. Les apps SimpleX Chat ont des serveurs prédéfinis (pour les apps mobiles, smp8, smp9 et smp10.simplex.im), mais vous pouvez facilement modifier la configuration de l'app pour utiliser d'autres serveurs.
Seuls les utilisateurs de SimpleX déterminent quel serveur est utilisé pour recevoir les messages, séparément pour chaque contact (ou pour chaque connexion à un membre d'un groupe), et ces serveurs ne sont que temporaires, car l'adresse de réception peut changer.
_Veuillez noter_ : lorsque vous modifiez les serveurs dans la configuration de l'app, cela n'affecte que les serveurs qui seront utilisés pour les nouveaux contacts. Les contacts existants ne seront pas automatiquement déplacés vers les nouveaux serveurs, mais vous pouvez les déplacer manuellement à l'aide du bouton ["Changer d'adresse de réception"](/blog/20221108-simplex-chat-v4.2-security-audit-new-website.md#change-your-delivery-address-beta) sur les fiches d'information de contact/membre ce sera bientôt automatisé.
## Installation
0. Tout d'abord, installez `smp-server`:
- Déploiement manuel :
- [Compiler à partir de la source](https://github.com/simplex-chat/simplexmq#using-your-distribution)
- [Utiliser une version pré-compilée](https://github.com/simplex-chat/simplexmq#install-binaries)
- Sinon, vous pouvez déployer votre `smp-server` en utilisant :
- [Docker container](https://github.com/simplex-chat/simplexmq#using-docker-1)
- [Linode StackScript](https://github.com/simplex-chat/simplexmq#deploy-smp-server-on-linode)
L'installation manuelle nécessite quelques actions préalables :
1. Créer un utilisateur et un groupe pour votre `smp-server`:
```sh
sudo useradd -m smp
```
2. Créer les répertoires nécessaires et y attribuer les permissions :
```sh
sudo mkdir -p /var/opt/simplex /etc/opt/simplex
sudo chown smp:smp /var/opt/simplex /etc/opt/simplex
```
3. Autoriser le port du `smp-server` dans le pare-feu:
```sh
# Pour Ubuntu
ufw allow 5233
```
4. **Optionnel** - Si vous utilisez une distribution avec `systemd`, créez le fichier `/etc/systemd/system/smp-server.service` avec le contenu suivant :
```sh
[Unit]
Description=Serveur SMP
[Service]
User=smp
Group=smp
Type=simple
ExecStart=smp-server start
ExecStopPost=/usr/bin/env sh -c '[ -e "/var/opt/simplex/smp-server-store.log" ] && cp "/var/opt/simplex/smp-server-store.log" "/var/opt/simplex/smp-server-store.log.bak"'
KillSignal=SIGINT
TimeoutStopSec=infinity
Restart=always
RestartSec=10
LimitNOFILE=65535
[Install]
WantedBy=multi-user.target
```
Et exécutez `sudo systemctl daemon-reload`.
## Configuration
Pour voir les options disponibles, exécutez `smp-server` sans paramètres :
```sh
sudo su smp -c smp-server
...
Available commands:
init Initialize server - creates /etc/opt/simplex and
/var/opt/simplex directories and configuration files
start Start server (configuration:
/etc/opt/simplex/smp-server.ini)
delete Delete configuration and log files
```
Vous pouvez obtenir de l'aide supplémentaire en exécutant `sudo su smp -c "smp-server <command> -h"`
Ensuite, nous devons configurer `smp-server`:
### Interactif
Exécutez la commande suivante :
```sh
sudo su smp -c "smp-server init"
```
Il y a plusieurs options disponibles :
- `Enable store log to restore queues and messages on server restart (Yn):`
Entrez `y` pour permettre la sauvegarde et la restauration des connexions et des messages lorsque le serveur est redémarré.
_Veuillez noter_ : il est important d'utiliser SIGINT pour redémarrer le serveur, sinon les messages non distribués ne seront pas restaurés. Les connexions seront restaurées indépendamment de la façon dont le serveur est redémarré, car contrairement aux messages, elles sont ajoutées aux logs (append-only) seulement à chaque changement.
- `Enable logging daily statistics (yN):`
Entrez `y` pour activer l'enregistrement des statistiques au format CSV, par exemple, elles peuvent être utilisées pour afficher des graphiques d'utilisation globale dans `Grafana`.
Ces statistiques incluent le nombre quotidien de files d'attente créées, sécurisées et supprimées, de messages envoyés et reçus, ainsi que le nombre quotidien, hebdomadaire et mensuel de files d'attente actives (c'est-à-dire les files d'attente qui ont été utilisées pour des messages). Nous estimons que ces informations ne comportent aucun élément permettant de corréler différentes files d'attente comme appartenant aux mêmes utilisateurs, mais si vous pensez que cela peut être exploité de quelque manière que ce soit, veuillez nous le faire savoir, de manière confidentielle.
- `Require a password to create new messaging queues?`
Entrez `r` ou votre mot de passe pour protéger votre `smp-server`, ou `n` pour désactiver la protection par mot de passe.
- `Enter server FQDN or IP address for certificate (127.0.0.1):`
Entrez votre domaine ou l'adresse IP sur laquelle votre serveur smp fonctionne - elle sera incluse dans les certificats du serveur et également indiquée dans l'adresse du serveur.
### Option via ligne de commande
Exécutez la commande suivante :
```sh
sudo su smp -c "smp-server init -h"
...
Available options:
-l,--store-log Enable store log for persistence
-s,--daily-stats Enable logging daily server statistics
-a,--sign-algorithm ALG Signature algorithm used for TLS certificates:
ED25519, ED448 (default: ED448)
--ip IP Server IP address, used as Common Name for TLS online
certificate if FQDN is not supplied
(default: "127.0.0.1")
-n,--fqdn FQDN Server FQDN used as Common Name for TLS online
certificate
--no-password Allow creating new queues without password
--password PASSWORD Set password to create new messaging queues
-y,--yes Non-interactive initialization using command-line
options
-h,--help Show this help text
```
Vous devriez déterminer quels paramètres sont nécessaires pour votre cas d'utilisation et ensuite exécuter `smp-server init` avec le paramètre `-y` pour une initialisation non-interactive :
```sh
sudo su smp -c "smp-server init -y -<your flag> <your option>"
```
Par exemple, exécutez :
```sh
sudo su smp -c "smp-server init -y -l --ip 192.168.1.5 --password test"
```
pour initialiser votre `smp-server` avec comme configuration :
- restauration des connexions et des messages lors du redémarrage du serveur (paramètre `-l`),
- adresse IP `192.168.1.5`,
- protection du `smp-server` avec comme mot de passe `test`.
---
Après cela, votre installation est terminée et vous devriez voir dans votre teminal quelque chose comme ceci :
```sh
Certificate request self-signature ok
subject=CN = 127.0.0.1
Server initialized, you can modify configuration in /etc/opt/simplex/smp-server.ini.
Run `smp-server start` to start server.
----------
You should store CA private key securely and delete it from the server.
If server TLS credential is compromised this key can be used to sign a new one, keeping the same server identity and established connections.
CA private key location: /etc/opt/simplex/ca.key
----------
SMP server v3.4.0
Fingerprint: d5fcsc7hhtPpexYUbI2XPxDbyU2d3WsVmROimcL90ss=
Server address: smp://d5fcsc7hhtPpexYUbI2XPxDbyU2d3WsVmROimcL90ss=:V8ONoJ6ICwnrZnTC_QuSHfCEYq53uLaJKQ_oIC6-ve8=@<hostnames>
```
L'adresse du serveur ci-dessus doit être utilisée dans la configuration de votre client et si vous avez ajouté le mot de passe du serveur, il ne doit être partagé qu'avec les personnes que vous souhaitez autoriser à utiliser votre serveur pour recevoir les messages (tous vos contacts pourront envoyer des messages, car cela ne nécessite pas de mot de passe). Si vous avez fourni une adresse IP ou un nom d'hôte lors de l'initialisation, ils seront indiqués dans l'adresse du serveur, sinon remplacez `<hostnames>` par les adresses réelles du serveur.
## Documentation
Tous les fichiers requis pour `smp-server` sont situés dans le dossier `/etc/opt/simplex/`.
Les messages stockés, les connexions, les statistiques et les logs du serveur sont situés dans le dossier `/var/opt/simplex/`.
### Adresse de serveur SMP
Une adresse de serveur SMP a le format suivant :
```
smp://<fingerprint>[:<password>]@<public_hostname>[,<onion_hostname>]
```
- `<fingerprint>`
Empreinte du certificat de votre `smp-server`. Vous pouvez vérifier l'empreinte de votre certificat dans `/etc/opt/simplex/fingerprint`.
- **optionnel** `<password>`
Votre mot de passe configuré pour `smp-server`. Vous pouvez vérifier votre mot de passe configuré dans `/etc/opt/simplex/smp-server.ini`, sous la section `[AUTH]` dans le champ `create_password:`.
- `<public_hostname>`, **optionnel** `<onion_hostname>`
Votre(vos) nom(s) d'hôte configuré(s) de `smp-server`. Vous pouvez vérifier vos hôtes configurés dans `/etc/opt/simplex/smp-server.ini`, dans la section `[AUTH]` dans le champ `host:`.
### Systemd commandes
Pour démarrer `smp-server` au démarrage de l'hôte, exécutez :
```sh
sudo systemctl enable smp-server.service
Created symlink /etc/systemd/system/multi-user.target.wants/smp-server.service → /etc/systemd/system/smp-server.service.
```
Pour démarrer `smp-server`, exécutez :
```sh
sudo systemctl start smp-server.service
```
Pour vérifier l'état du `smp-server`, exécutez :
```sh
sudo systemctl status smp-server.service
● smp-server.service - SMP server
Loaded: loaded (/etc/systemd/system/smp-server.service; enabled; vendor preset: enabled)
Active: active (running) since Sat 2022-11-23 19:23:21 UTC; 1min 48s ago
Main PID: 30878 (smp-server)
CGroup: /docker/5588ab759e80546b4296a7c50ffebbb1fb7b55b8401300e9201313b720989aa8/system.slice/smp-server.service
└─30878 smp-server start
Nov 23 19:23:21 5588ab759e80 systemd[1]: Started SMP server.
Nov 23 19:23:21 5588ab759e80 smp-server[30878]: SMP server v3.4.0
Nov 23 19:23:21 5588ab759e80 smp-server[30878]: Fingerprint: d5fcsc7hhtPpexYUbI2XPxDbyU2d3WsVmROimcL90ss=
Nov 23 19:23:21 5588ab759e80 smp-server[30878]: Server address: smp://d5fcsc7hhtPpexYUbI2XPxDbyU2d3WsVmROimcL90ss=:V8ONoJ6ICwnrZnTC_QuSHfCEYq53uLaJKQ_oIC6-ve8=@<hostnames>
Nov 23 19:23:21 5588ab759e80 smp-server[30878]: Store log: /var/opt/simplex/smp-server-store.log
Nov 23 19:23:21 5588ab759e80 smp-server[30878]: Listening on port 5223 (TLS)...
Nov 23 19:23:21 5588ab759e80 smp-server[30878]: not expiring inactive clients
Nov 23 19:23:21 5588ab759e80 smp-server[30878]: creating new queues requires password
```
Pour arrêter `smp-server`, exécutez :
```sh
sudo systemctl stop smp-server.service
```
Pour vérifier la "tail" de `smp-server` des logs, exécutez :
```sh
sudo journalctl -fu smp-server.service
Nov 23 19:23:21 5588ab759e80 systemd[1]: Started SMP server.
Nov 23 19:23:21 5588ab759e80 smp-server[30878]: SMP server v3.4.0
Nov 23 19:23:21 5588ab759e80 smp-server[30878]: Fingerprint: d5fcsc7hhtPpexYUbI2XPxDbyU2d3WsVmROimcL90ss=
Nov 23 19:23:21 5588ab759e80 smp-server[30878]: Server address: smp://d5fcsc7hhtPpexYUbI2XPxDbyU2d3WsVmROimcL90ss=:V8ONoJ6ICwnrZnTC_QuSHfCEYq53uLaJKQ_oIC6-ve8=@<hostnames>
Nov 23 19:23:21 5588ab759e80 smp-server[30878]: Store log: /var/opt/simplex/smp-server-store.log
Nov 23 19:23:21 5588ab759e80 smp-server[30878]: Listening on port 5223 (TLS)...
Nov 23 19:23:21 5588ab759e80 smp-server[30878]: not expiring inactive clients
Nov 23 19:23:21 5588ab759e80 smp-server[30878]: creating new queues requires password
```
### Suivi de l'activité
Vous pouvez activer les statistiques de `smp-server` sur le tableau de bord `Grafana` en mettant la valeur `on` dans `/etc/opt/simplex/smp-server.ini`, sous la section `[STORE_LOG]` dans le champ `log_stats:`.
Les journaux seront stockés dans un fichier `csv` dans `/var/opt/simplex/smp-server-stats.daily.log`. Les champs pour le fichier `csv` sont :
```sh
fromTime,qCreated,qSecured,qDeleted,msgSent,msgRecv,dayMsgQueues,weekMsgQueues,monthMsgQueues
```
- `fromTime` - horodatage; date et heure de l'événement
- `qCreated` - int; files d'attente créées
- `qSecured` - int; files d'attente établies
- `qDeleted` - int; files d'attente supprimées
- `msgSent` - int; messages envoyés
- `msgRecv` - int; messages reçus
- `dayMsgQueues` - int; files d'attente actives en un jour
- `weekMsgQueues` - int; files d'attente actives en une semaine
- `monthMsgQueues` - int; files d'attente actives en un mois
Pour importer du `csv` dans `Grafana` il faut :
1. Installer le plugin Grafana : [Grafana - CSV datasource](https://grafana.com/grafana/plugins/marcusolsson-csv-datasource/)
2. Autoriser le mode local en ajoutant ce qui suit :
```sh
[plugin.marcusolsson-csv-datasource]
allow_local_mode = true
```
... to `/etc/grafana/grafana.ini`
3. Ajouter une source de données CSV :
- Dans le menu latéral, cliquez sur l'onglet Configuration (icône en forme de rouage).
- Cliquez sur Ajouter une source de données dans le coin supérieur droit de l'onglet Sources de données.
- Entrez "CSV" dans le champ de recherche pour trouver la source de données CSV.
- Cliquez sur le résultat de la recherche qui indique "CSV".
- Dans URL, entrez un fichier qui pointe vers le contenu CSV.
4. C'est fait ! Vous devriez être en mesure de créer votre propre tableau de bord avec des statistiques.
Pour plus de documentation, voir : [CSV Data Source pour Grafana - Documentation](https://grafana.github.io/grafana-csv-datasource/)
### Configurer l'app pour utiliser le serveur
Pour configurer l'app afin d'utiliser votre serveur de messagerie, copiez son adresse complète, y compris le mot de passe, et ajoutez-la à l'application. Vous avez la possibilité d'utiliser votre serveur avec les serveurs prédéfinis ou sans eux - vous pouvez les supprimer ou les désactiver.
Il est également possible de partager l'adresse de votre serveur avec vos amis en leur permettant de scanner le code QR dans les paramètres du serveur. Ce code inclura le mot de passe du serveur, ce qui leur permettra aussi de recevoir des messages via votre serveur.
_Veuillez noter_ : vous avez besoin de la version 4.0 du serveur SMP pour avoir le support du mot de passe. Si vous avez déjà déployé un serveur, vous pouvez ajouter le mot de passe en l'ajoutant au fichier INI du serveur.
<img src="/docs/server_config_1.png" width="288"> &nbsp;&nbsp; <img src="/docs/server_config_2.png" width="288"> &nbsp;&nbsp; <img src="/docs/server_config_3.png" width="288">
+98
View File
@@ -0,0 +1,98 @@
| Updated 07.02.2023 | Languages: [EN](/docs/SIMPLEX.md), FR |
# Plateforme SimpleX - motivation et comparaison
## Problèmes
Les plateformes et protocoles de chat existants présentent une partie ou la totalité des problèmes suivants :
- Absence de confidentialité du profil et des contacts de l'utilisateur (confidentialité des métadonnées).
- Aucune protection (ou seulement une protection optionnelle) des implémentations [E2EE][1] contre les attaques MITM via le fournisseur.
- Messages non sollicités (spam et abus).
- Absence de propriété et de protection des données.
- Complexité d'utilisation de tous les protocoles non centralisés pour les utilisateurs non techniques.
La concentration de la communication dans un petit nombre de plateformes centralisées rend la résolution de ces problèmes assez difficile.
## Solutions
Les différents protocoles proposés résolvent ces problèmes en faisant en sorte que les messages comme les contacts soit stockés exclusivement sur l'appareil client, tout en réduisant le rôle des serveurs à de simples relais de message qui ne nécessite que l'autorisation des messages envoyés dans les files d'attentes, mais qui NE nécessite PAS une authentification utilisateur - les message ne sont pas les seuls à être protégé, les métadonnées le sont aussi car l'utilisateur n'est pas lié à un identifiant - contrairement aux autres platformes.
Voir [le livre blanc de SimpleX](https://github.com/simplex-chat/simplexmq/blob/master/protocol/overview-tjr.md) pour plus d'information sur les objectifs de la platforme et ses détails techniques.
## Pourquoi utiliser SimpleX
## SimpleX une approche unique en terme de confidentialité et de sécurité
Tout le monde devrait se soucier de la confidentialité et de la sécurité de ses communications - même une conversation lambda peut vous mettre en danger.
### Protection complète de votre identité, profil, contacts et métadonnées
**Contrairement aux autres platformes de messagerie, SimpleX ne lie pas d'identifiant à l'utilisateur** - il n'y a pas besoin de numéro de télèphone (comme Signal ou WhatsApp), d'adresses basés sur des noms de domaines (comme les e-mails, XMPP ou Matrix), de noms d'utilisateurs (comme Telegram), ou de clés publiques ou même de nombres aléatoires pour identifié les utilisateurs - on ne sait même pas combiens de personnes utilise SimpleX.
Pour distribuer les messages au lieu d'utiliser des identifiants d'utilisateur que toute les autres platformes utilisent, SimpleX utilise des adresses unidirectionnelles (simplex) de files d'attentes de messages. Utiliser SimpleX c'est comme avoir une adresse e-mail différentes ou un numéro de télèphone différent par contact, sans les inconvenients qui viennent avec. Dans un futur proche les apps SimpleX changeront automatiquement les files d'attentes, déplacant les conversations d'un serveur à un autre, pour une meilleure confidentialité.
Cette approche protège la vie privé de la personne avec qui vous communiquez, elle est masquée des serveurs SimpleX et de n'importe quel autre observateur. Vous pouvez encore améliorer votre protection en configurant votre réseau pour qu'il passe via des réseaux superposé comme, par exemple Tor.
### La meilleure protection contre le spam et les abus
Comme vous n'avez pas d'identifiant sur la plateforme SimpleX, vous ne pouvez pas être contacté, sauf si vous partagez un lien d'invitation unique ou une adresse d'utilisateur temporaire facultative. Même avec les adresses d'utilisateur facultatives, bien qu'elles puissent être utilisées pour envoyer des demandes de contact non sollicitées, vous pouvez les modifier ou les supprimer complètement sans perdre aucune de vos connexions.
### Propriété, contrôle et sécurité totale de vos données
SimpleX stocke toutes les données de l'utilisateur sur les appareils clients, les messages ne sont conservés que temporairement sur les serveurs relais SimpleX jusqu'à leur réception.
Nous utilisons un format de base de données portable qui peut être utilisé sur tous les appareils pris en charge. Nous ajouterons bientôt la possibilité d'exporter la base de données de chat depuis l'application mobile afin qu'elle puisse être utilisée sur un autre appareil.
Contrairement aux serveurs des réseaux fédérés (e-mail, XMPP ou Matrix), les serveurs SimpleX ne stockent pas les comptes des utilisateurs, ils se contentent de relayer les messages aux destinataires, protégeant ainsi la vie privée des deux parties. Il n'y a aucun identifiant ou message chiffré en commun entre le trafic envoyé et reçu du serveur, grâce à la couche de chiffrement supplémentaire pour les messages délivrés. Par conséquent, si quelqu'un observe le trafic du serveur, il ne peut pas facilement déterminer qui communique avec qui (Voir [le livre blanc de SimpleX](https://github.com/simplex-chat/simplexmq/blob/master/protocol/overview-tjr.md) pour les attaques connues de corrélation réseau).
### Les utilisateurs sont maîtres du réseau SimpleX
Vous pouvez utiliser SimpleX avec vos propres serveurs et continuer à communiquer avec les personnes utilisant les serveurs préconfigurés dans les applications ou tout autre serveur SimpleX.
La plateforme SimpleX utilise un protocole ouvert et fournit un SDK pour créer des chatbot, permettant la mise en œuvre de services avec lesquels les utilisateurs peuvent interagir via les applications SimpleX Chat - nous sommes vraiment impatients de voir quels services SimpleX peuvent être créés.
Si vous envisagez de développer avec la plateforme SimpleX, que ce soit pour des services de chatbot pour les utilisateurs de l'application SimpleX ou pour intégrer la bibliothèque de chat SimpleX dans vos applications mobiles, n'hésitez pas à nous contacter pour tout conseil et assistance.
## Comparaison avec d'autres protocoles
| | SimpleX chat | Signal et autres... | XMPP, Matrix | Protocoles P2P |
| :--------------------------------------------- | :----------------: | :-------------------: | :-------------: | :-------------: |
| Identifiants d'utilisateur nécessaire | Non = privé | Oui<sup>1</sup> | Oui<sup>2</sup> | Oui<sup>3</sup> |
| Risque d'attaque MITM | Non = securisé | Oui<sup>4</sup> | Oui | Oui |
| Dépendance au DNS | Non = résistant | Oui | Oui | Non |
| Un opérateur ou un réseau unique | Non = décentralisé | Oui | Non | Oui<sup>5</sup> |
| Attaque à l'échelle du réseau | Non = résistant | Oui | Oui<sup>2</sup> | Oui<sup>6</sup> |
1. Généralement basé sur un numéro de téléphone, dans certains cas sur des noms d'utilisateur.
2. Basé sur le DNS.
3. Clé publique ou tout autre identifiant global unique.
4. Si les serveurs de l'opérateur sont compromis.
5. Si les réseaux P2P et les réseaux basés sur les crypto-monnaies sont distribués, ils ne sont pas décentralisés : ils fonctionnent comme un seul réseau, avec un seul espace de noms des adresses des utilisateurs.
6. Les réseaux P2P ont soit une autorité centrale, soit l'ensemble du réseau peut être compromis - voir la section suivante.
## Comparaison avec les protocoles de messagerie [P2P][9]
Il existe plusieurs protocoles et implémentations de chat/messagerie P2P qui visent à résoudre le problème de la protection de la vie privée et de la centralisation, mais ils ont leur propre série de problèmes qui les rendent moins fiables que la forme proposée, plus complexes à mettre en œuvre et à analyser et plus vulnérables aux attaques.
1. Les réseaux [P2P][9] utilisent une variante de [DHT][10] pour acheminer les messages/demandes à travers le réseau. Les implémentations du DHT ont des designs complexes qui doivent équilibrer la fiabilité, la garantie de livraison et la latence. La méthode proposée offre à la fois de meilleures garanties de livraison et une latence plus faible (le message est transmis plusieurs fois en parallèle, à travers un nœud à chaque fois, en utilisant des serveurs choisis par le destinataire, alors que dans les réseaux P2P, le message est transmis à travers `O(log N)` nœuds séquentiellement, en utilisant des nœuds choisis par un algorithme).
2. Le modèle proposé, contrairement à la plupart des réseaux P2P, ne comporte aucun identifiant global d'utilisateur, même temporaire.
3. Le P2P en lui-même ne résout pas le problème des [attaques MITM][2], et la plupart des solutions existantes n'utilisent pas de messages hors bande pour l'échange initial de clés. La conception proposée utilise des messages hors bande ou, dans certains cas, des connexions sécurisées et fiables préexistantes pour l'échange initial de clés.
4. Les implémentations P2P peuvent être bloquées par certains fournisseurs d'accès à Internet (comme [BitTorrent][11]). Le modèle proposée est indépendant des moyens de transport : il peut fonctionner avec des protocoles web standard et les serveurs peuvent être déployés sur les mêmes domaines que les sites web.
5. Tous les réseaux P2P connus sont susceptibles d'être vulnérables à une [attaque Sybil][12], car chaque nœud peut être découvert et le réseau fonctionne comme un tout. Les mesures connues pour réduire la probabilité de l'attaque Sybil nécessitent soit un composant centralisé, soit des [preuves de travail][13] coûteuses. Le modèle proposée, au contraire, ne permet pas de découvrir les serveurs - les serveurs ne sont pas connectés, ni connus les uns des autres, ni de tous les clients. Le réseau SimpleX est fragmenté et fonctionne comme de multiples connexions isolées. Cela rend impossible les attaques à l'échelle du réseau SimpleX - même si certains serveurs sont compromis, d'autres parties du réseau peuvent fonctionner normalement, et les clients affectés peuvent passer à l'utilisation d'autres serveurs sans perdre de contacts ou de messages.
6. Les réseaux P2P sont susceptibles d'être [vulnérables][14] aux [attaques DRDoS][15]. Dans la conception proposée, les clients ne relaient que le trafic provenant de connexions de confiance connues et ne peuvent pas être utilisés pour refléter et amplifier le trafic dans l'ensemble du réseau.
[1]: https://fr.wikipedia.org/wiki/Chiffrement_de_bout_en_bout
[2]: https://fr.wikipedia.org/wiki/Attaque_de_l%27homme_du_milieu
[9]: https://fr.wikipedia.org/wiki/Pair-%C3%A0-pair
[10]: https://fr.wikipedia.org/wiki/Table_de_hachage_distribu%C3%A9e
[11]: https://fr.wikipedia.org/wiki/BitTorrent
[12]: https://fr.wikipedia.org/wiki/Attaque_Sybil
[13]: https://fr.wikipedia.org/wiki/Preuve_de_travail
[14]: https://www.usenix.org/conference/woot15/workshop-program/presentation/p2p-file-sharing-hell-exploiting-bittorrent
[15]: https://en.wikipedia.org/wiki/Denial-of-service_attack#Reflected_attack
+41
View File
@@ -0,0 +1,41 @@
| Updated 31.01.2023 | Languages: [EN](/docs/SQL.md), FR |
# Accès à l'historique des messages via des requêtes SQL
Vous pouvez exécuter des requêtes `direct_messages`, `group_messages` et `all_messages` (ou leurs alternatives plus simples `direct_messages_plain`, `group_messages_plain` et `all_messages_plain`), par exemple :
```sql
-- vous pouvez mettre ces paramètres ou ceux que vous préférez dans ~/.sqliterc
-- pour maintenir les sessions du client sqlite3
.mode column
.headers on
.nullvalue NULL
-- vues simples pour direct, group et all_messages
-- avec les messages de l'utilisateur dédupliqués pour group et all_messages ;
-- seuls les événements de chat "x.msg.new" ("nouveau message") - filtre les événements de service ;
-- msg_sent est 0 pour reçu, 1 pour envoyé
select * from direct_messages_plain;
select * from group_messages_plain;
select * from all_messages_plain;
-- demander d'autres détails de votre historique de chat avec le SQL régulier, par exemple :
-- les fichiers que vous avez soumis pour l'envoi
select * from direct_messages where msg_sent = 1 and chat_msg_event = 'x.file';
-- tout ce que Catherine a envoyé lié aux chats
select * from direct_messages where msg_sent = 0 and contact = 'catherine' and msg_body like '%cats%';
-- toute correspondance avec alice dans #team
select * from group_messages where group_name = 'team' and contact = 'alice';
-- regrouper vos données de chat
select contact_or_group, num_messages from (
select
contact as contact_or_group, count(1) as num_messages
from direct_messages_plain group by contact
union
select
group_name as contact_or_group, count(1) as num_messages
from group_messages_plain group by group_name
)
order by num_messages desc;
```
+143
View File
@@ -0,0 +1,143 @@
| Updated 31.01.2023 | Languages: [EN](/docs/WEBRTC.md), FR |
# Utilisation de serveurs WebRTC ICE personnalisés dans SimpleX Chat
## Déployer un serveur STUN/TURN
Pour ce guide, nous utiliserons l'implémentation de serveur STUN/TURN la plus complète et la plus testée - [`coturn`](https://github.com/coturn/coturn) et la distribution Linux [`Ubuntu 20.04 LTS`](https://ubuntu.com/download/server).
0. Obtenez les certificats `stun.$VOTRE_DOMAINE` et `turn.$VOTRE_DOMAINE`.
Nous utilisons [Let's Encrypt](https://letsencrypt.org/fr/getting-started/).
1. Installez le package `coturn` depuis le dépôt principal.
```sh
apt update && apt install coturn`
```
2. Décommentez `TURNSERVER_ENABLED=1` de `/etc/default/coturn` :
```sh
sed -i '/TURN/s/^#//g' /etc/default/coturn
```
3. Configurez `coturn` dans `/etc/turnserver.conf` :
Veuillez également consulter les commentaires relatifs pour chacune des options.
```sh
# tls sur le port 443
alt-tls-listening-port=443
# Utiliser les empreintes dans les messages TURN
fingerprint
# Utiliser le mécanisme d'identification à long terme
lt-cred-mech
# Vos informations d'identification
user=$VOTRE_LOGIN:$VOTRE_MOT_DE_PASSE
# Le domaine de votre serveur
server-name=$VOTRE_DOMAINE
# Le domaine par défaut à utiliser pour les utilisateurs lorsqu'aucune relation explicite origine/domaine n'a été trouvée
realm=$VOTRE_DOMAINE
# Chemin vers vos certificats. Assurez-vous qu'ils sont lisibles par l'utilisateur/groupe du processus cotun
cert=/var/lib/turn/cert.pem
pkey=/var/lib/turn/key.pem
# Utiliser la clé DH TLS prédéfinie de 2066 bits
dh2066
# Log sur journalctl
syslog
# Utilisateur/groupe qui exécutera le service coturn
proc-user=turnserver
proc-group=turnserver
# Désactiver le chiffrement faible
no-tlsv1
no-tlsv1_1
no-tlsv1_2
```
4. Démarrez et activez le service `coturn` :
```sh
systemctl enable coturn && systemctl start coturn
```
5. Optionnellement, si vous utilisez le pare-feu `ufw`, ouvrez les ports appropriés :
- **3478** "simple" TURN/STUN;
- **5349** TURN/STUN over TLS;
- **443** TURN/STUN over TLS, qui peuvent contourner les pare-feu;
- **49152:65535** plage de ports que Coturn utilisera par défaut pour le relais TURN.
```sh
ufw allow 3478 && \
ufw allow 443 && \
ufw allow 5349 && \
ufw allow 49152:65535/tcp && \
ufw allow 49152:65535/udp
```
## Configurer l'app mobile
Pour configurer votre application mobile afin d'utiliser votre serveur :
1. Ouvrez `Paramètres / Réseau & Serveurs / Serveurs WebRTC ICE` et activez la case `Configurer les serveurs ICE`.
2. Entrez toutes les adresses des serveurs dans le champ, une par ligne, par exemple si vos serveurs sont sur le port 5349 :
```
stun:stun.example.com:5349
turn:username:password@turn.example.com:5349
```
Voilà, vous pouvez désormais passer des appels audio et vidéo via votre propre serveur, sans partager aucune donnée avec nos serveurs (autre que l'échange de clés avec votre contact dans les messages cryptés E2E).
## Dépannage
- **Déterminer si un serveur est disponible** :
Exécutez cette commande dans votre terminal :
```sh
ping <votre_ip_ou_domaine>
```
Si des paquets sont transmis, le serveur est opérationnel !
- **Déterminez si les ports sont ouverts** :
Exécutez cette commande dans votre terminal :
```sh
nc -zvw10 <votre_ip_ou_domaine> 443 5349
```
Vous devriez voir :
```
Connection to <votre_ip_ou_domaine> 443 port [tcp/https] succeeded!
Connection to <votre_ip_ou_domaine> 5349 port [tcp/*] succeeded!
```
- **Testez la connectivité STUN/TURN** :
1. Allez sur [IceTest](https://icetest.info/).
2. Dans la section **Build up ICE Server List**, ajoutez :
<img src="/docs/stun_1.png">
- `STUN: stun:<votre_ip_ou_domaine>:<port>` et appuyez sur `Add STUN`
- `TURN: turn:<votre_ip_ou_domaine>:<port>`, `Username: <votre_login>`, `Credential: <votre_pass>` et appuyez sur `Add TURN`
`<port>` est 443 ou 5349.
3. Vous devriez voir vos serveurs dans la section **ICE server list**. Si tout est correctement configuré, cliquez sur `Start test` :
<img src="/docs/stun_2.png">
4. Dans la section **Results**, vous devriez obtenir quelque chose comme ceci :
<img src="/docs/stun_3.png">
Si les résultats montrent des candidats `srflx` et `relay`, tout est correctement configuré !
+1 -1
View File
@@ -1,5 +1,5 @@
name: simplex-chat
version: 4.5.0.4
version: 4.5.2.0
#synopsis:
#description:
homepage: https://github.com/simplex-chat/simplex-chat#readme
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@simplex-chat/webrtc",
"version": "0.2.1",
"version": "0.2.3",
"description": "WebRTC call in browser and webview for SimpleX Chat clients",
"main": "dist/call.js",
"types": "dist/call.d.ts",

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