mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2024-12-17 17:20:21 +01:00
Compare commits
122 Commits
docs-polish
...
v5.1.1
| Author | SHA1 | Date | |
|---|---|---|---|
| de33fedea4 | |||
| 9f89104f94 | |||
| f0e88220c6 | |||
| 6d7e16d6e1 | |||
| d7d38fddb8 | |||
| 527a5bc6b5 | |||
| 9644dcb9b4 | |||
| f4861482f1 | |||
| dc73bb3caf | |||
| bcbfc1758e | |||
| e65dcf51b0 | |||
| 1326701440 | |||
| c32e45f686 | |||
| 0160684004 | |||
| 734b920fde | |||
| 174e703b4c | |||
| 36336a3a57 | |||
| c10a4346a9 | |||
| db55496fc7 | |||
| 9a2efd0ef0 | |||
| 579af09816 | |||
| d39614713d | |||
| 34af1e258c | |||
| 3ff68dbc7b | |||
| 8952ac9af0 | |||
| 7799a1e260 | |||
| 353927e6d2 | |||
| d40db1ddea | |||
| f85a9e174c | |||
| 838e14af60 | |||
| 1d84c5cad8 | |||
| 3be2259068 | |||
| acc4cad082 | |||
| 10a1788754 | |||
| f1c1059ff8 | |||
| 690c8ea2c9 | |||
| 1c8d1bc9ff | |||
| a9416d89e3 | |||
| 9e33ba46af | |||
| a0c4726af3 | |||
| a0b3c0a5a4 | |||
| 9978957e6c | |||
| f155611d29 | |||
| 01b3e98358 | |||
| 3a50da1b53 | |||
| a32fd5e665 | |||
| b6a4f5f518 | |||
| e799e80843 | |||
| 63cb7a75b3 | |||
| 922e95756a | |||
| b49f0d211b | |||
| 761fbf7757 | |||
| 4ee052e71e | |||
| 0274f3c2ac | |||
| ae13f1aa23 | |||
| 904405ebee | |||
| a059739210 | |||
| 25156bb56c | |||
| d62761b3a8 | |||
| 817c0a5672 | |||
| c06a970987 | |||
| baf3a12009 | |||
| 0ec2468dce | |||
| 0cfc9fd1fa | |||
| a2de9a3846 | |||
| 88059a2cc5 | |||
| 635d797b2e | |||
| e635c45ec6 | |||
| 594ae61192 | |||
| 2945f688fa | |||
| d86cca2e26 | |||
| fca315ee1f | |||
| a12f140333 | |||
| ad7e4488ef | |||
| df4e954f8a | |||
| 63f344bde6 | |||
| 0b8d9d11e2 | |||
| 57801fde1f | |||
| c87f4e68f7 | |||
| 27762492d7 | |||
| da7c408686 | |||
| 0c0a98605d | |||
| 108226bcdc | |||
| 8b400d4f2c | |||
| d838e7b44d | |||
| 7b157fa8e5 | |||
| d19a59a364 | |||
| b95a351222 | |||
| 1038acd2ea | |||
| 54fc052e47 | |||
| 62bac800af | |||
| aa2b36d5cc | |||
| b5f482bb50 | |||
| 649c104d29 | |||
| 41368c85bf | |||
| af59178318 | |||
| 5149623b57 | |||
| 205c74b5d8 | |||
| 5116bfa79c | |||
| 69767126aa | |||
| 5af389ae3f | |||
| f711f4d8a8 | |||
| 8b80efd537 | |||
| 7b83450a9c | |||
| e3011a1cb0 | |||
| 7ff8dcfb78 | |||
| 551ed202be | |||
| 6f11913359 | |||
| d91a78da7d | |||
| 02fdd058ec | |||
| 08148afac7 | |||
| f037ffe107 | |||
| fa6ba3110b | |||
| 6f82ddc032 | |||
| ee3267388f | |||
| f97a1fcedf | |||
| 199835b671 | |||
| ce2225d355 | |||
| b4f1f94bcc | |||
| 90cee6b802 | |||
| 2a883bb958 | |||
| 0b57cc08a7 |
@@ -62,6 +62,14 @@ jobs:
|
||||
cache_path: C:/cabal
|
||||
asset_name: simplex-chat-windows-x86-64
|
||||
steps:
|
||||
- name: Configure pagefile (Windows)
|
||||
if: matrix.os == 'windows-latest'
|
||||
uses: al-cheb/configure-pagefile-action@v1.3
|
||||
with:
|
||||
minimum-size: 16GB
|
||||
maximum-size: 16GB
|
||||
disk-root: "C:"
|
||||
|
||||
- name: Clone project
|
||||
uses: actions/checkout@v2
|
||||
|
||||
|
||||
+1
-1
@@ -49,8 +49,8 @@ logs/
|
||||
# for website
|
||||
website/node_modules/
|
||||
website/src/blog/
|
||||
website/src/docs/
|
||||
website/translations.json
|
||||
website/src/_data/supported_languages.json
|
||||
website/src/img/images/
|
||||
website/src/images/
|
||||
# Generated files
|
||||
|
||||
@@ -68,7 +68,7 @@ You can join an English-speaking users group if you want to ask any questions: [
|
||||
|
||||
There are groups in other languages, that we have the apps interface translated into. These groups are for testing, and asking questions to other SimpleX Chat users:
|
||||
|
||||
[\#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) (German-speaking), [\#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) (French-speaking), [\#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) (Russian-speaking), [\#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) (Italian-speaking).
|
||||
[\#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) (German-speaking), [\#SimpleX-ES](https://simplex.chat/contact#/?v=1-2&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FaJ8O1O8A8GbeoaHTo_V8dcefaCl7ouPb%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEA034qWTA3sWcTsi6aWhNf9BA34vKVCFaEBdP2R66z6Ao%253D%26srv%3Dbylepyau3ty4czmn77q4fglvperknl4bi2eb2fdy2bh4jxtf32kf73yd.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22wiZ1v_wNjLPlT-nCSB-bRA%3D%3D%22%7D) (Spanish-speaking), [\#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) (French-speaking), [\#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) (Russian-speaking), [\#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) (Italian-speaking).
|
||||
|
||||
You can join either by opening these links in the app or by opening them in a desktop browser and scanning the QR code.
|
||||
|
||||
@@ -101,8 +101,10 @@ Join our translators to help SimpleX grow!
|
||||
|🇪🇸 es|Español |[Mateyhv](https://github.com/Mateyhv)|[](https://hosted.weblate.org/projects/simplex-chat/android/es/)<br>[](https://hosted.weblate.org/projects/simplex-chat/ios/es/)|[](https://hosted.weblate.org/projects/simplex-chat/website/es/)||
|
||||
|🇫🇷 fr|Français |[ishi_sama](https://github.com/ishi-sama)|[](https://hosted.weblate.org/projects/simplex-chat/android/fr/)<br>[](https://hosted.weblate.org/projects/simplex-chat/ios/fr/)|[](https://hosted.weblate.org/projects/simplex-chat/website/fr/)|[✓](https://github.com/simplex-chat/simplex-chat/tree/master/docs/lang/fr)|
|
||||
|🇮🇹 it|Italiano |[unbranched](https://github.com/unbranched)|[](https://hosted.weblate.org/projects/simplex-chat/android/it/)<br>[](https://hosted.weblate.org/projects/simplex-chat/ios/it/)|[](https://hosted.weblate.org/projects/simplex-chat/website/it/)||
|
||||
|🇯🇵 ja|Japanese ||[](https://hosted.weblate.org/projects/simplex-chat/android/ja/)<br>[](https://hosted.weblate.org/projects/simplex-chat/ios/ja/)|||
|
||||
|🇳🇱 nl|Nederlands|[mika-nl](https://github.com/mika-nl)|[](https://hosted.weblate.org/projects/simplex-chat/android/nl/)<br>[](https://hosted.weblate.org/projects/simplex-chat/ios/nl/)|[](https://hosted.weblate.org/projects/simplex-chat/website/nl/)||
|
||||
|🇵🇱 pl|Polski |[BxOxSxS](https://github.com/BxOxSxS)|[](https://hosted.weblate.org/projects/simplex-chat/android/ru/)<br>[](https://hosted.weblate.org/projects/simplex-chat/ios/pl/)|||
|
||||
|🇧🇷 pt-BR|Português||[](https://hosted.weblate.org/projects/simplex-chat/android/pt_BR/)<br>-|[](https://hosted.weblate.org/projects/simplex-chat/website/pt_BR/)||
|
||||
|🇷🇺 ru|Русский ||[](https://hosted.weblate.org/projects/simplex-chat/android/ru/)<br>[](https://hosted.weblate.org/projects/simplex-chat/ios/ru/)|||
|
||||
|🇨🇳 zh-CHS|简体中文|[sith-on-mars](https://github.com/sith-on-mars)<br><br>[Float-hu](https://github.com/Float-hu)|[](https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/)<br>[](https://hosted.weblate.org/projects/simplex-chat/ios/zh_Hans/)<br> |<br><br>[](https://hosted.weblate.org/projects/simplex-chat/website/zh_Hans/)||
|
||||
|
||||
@@ -112,6 +114,7 @@ Languages in progress: Arabic, Japanese, Korean, Portuguese and [others](https:/
|
||||
|
||||
We would love to have you join the development! You can help us with:
|
||||
|
||||
- [share the color theme](./docs/THEMES.md) you use in Android app!
|
||||
- writing a tutorial or recipes about hosting servers, chat bot automations, etc.
|
||||
- contributing to SimpleX Chat knowledge-base.
|
||||
- developing features - please connect to us via chat so we can help you get started.
|
||||
@@ -197,6 +200,8 @@ You can use SimpleX with your own servers and still communicate with people usin
|
||||
|
||||
Recent updates:
|
||||
|
||||
[May 23, 2023. SimpleX Chat: v5.1 released with message reactions and self-destruct passcode](./blog/20230523-simplex-chat-v5-1-message-reactions-self-destruct-passcode.md).
|
||||
|
||||
[Apr 22, 2023. SimpleX Chat: vision and funding, v5.0 released with videos and files up to 1gb](./blog/20230422-simplex-chat-vision-funding-v5-videos-files-passcode.md).
|
||||
|
||||
[Mar 28, 2023. v4.6 released - with Android 8+ and ARMv7a support, hidden profiles, community moderation, improved audio/video calls and reduced battery usage](./blog/20230328-simplex-chat-v4-6-hidden-profiles.md).
|
||||
@@ -245,13 +250,15 @@ See [SimpleX Chat Protocol](./docs/protocol/simplex-chat.md) for the format of m
|
||||
|
||||
SimpleX Chat is a work in progress – we are releasing improvements as they are ready. You have to decide if the current state is good enough for your usage scenario.
|
||||
|
||||
We compiled a [glossary of terms](./docs/GLOSSARY.md) used to describe communication systems to help understand some terms below and to help compare advantages and disadvantages of various communication systems.
|
||||
|
||||
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 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.
|
||||
1. Instead of user profile identifiers used by all other platforms, even the most private ones, SimpleX uses [pairwise per-queue identifiers](./docs/GLOSSARY.md#pairwise-pseudonymous-identifier) (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](./docs/GLOSSARY.md#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](./docs/GLOSSARY.md#double-ratchet-algorithm) 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](./docs/GLOSSARY.md#forward-secrecy) (each message is encrypted by its own ephemeral key) and [break-in recovery](./docs/GLOSSARY.md#post-compromise-security) (the keys are frequently re-negotiated as part of the message exchange). Two pairs of Curve448 keys are used for the initial [key agreement](./docs/GLOSSARY.md#key-agreement-protocol), 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).
|
||||
5. Several levels of content padding to frustrate message size attacks.
|
||||
5. Several levels of [content padding](./docs/GLOSSARY.md#message-padding) to frustrate message size attacks.
|
||||
6. Starting from v2 of SMP protocol (the current version is v4) all message metadata, including the time when the message was received by the server (rounded to a second) is sent to the recipients inside an encrypted envelope, so even if TLS is compromised it cannot be observed.
|
||||
7. Only TLS 1.2/1.3 are allowed for client-server connections, limited to cryptographic algorithms: CHACHA20POLY1305_SHA256, Ed25519/Ed448, Curve25519/Curve448.
|
||||
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.
|
||||
@@ -316,25 +323,27 @@ If you are considering developing with SimpleX platform please get in touch for
|
||||
- ✅ Sending and receiving large files via [XFTP protocol](./blog/20230301-simplex-file-transfer-protocol.md).
|
||||
- ✅ Video messages.
|
||||
- ✅ App access passcode.
|
||||
- 🏗 Improved Android app UI design.
|
||||
- 🏗 SMP queue redundancy and rotation (manual is supported).
|
||||
- 🏗 Reduced battery and traffic usage in large groups.
|
||||
- ✅ Improved Android app UI design.
|
||||
- ✅ Optional alternative access password.
|
||||
- ✅ Message reactions
|
||||
- ✅ Message editing history
|
||||
- ✅ Reduced battery and traffic usage in large groups.
|
||||
- 🏗 Desktop client.
|
||||
- 🏗 Message delivery confirmation (with sender opt-in or opt-out per contact, TBC).
|
||||
- SMP queue redundancy and rotation (manual is supported).
|
||||
- Include optional message into connection request sent via contact address.
|
||||
- Ephemeral/disappearing/OTR conversations with the existing contacts.
|
||||
- Optional alternative access password.
|
||||
- Local app files encryption.
|
||||
- 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).
|
||||
- Privately share your location.
|
||||
- Large groups, communities and public channels.
|
||||
- Feeds/broadcasts.
|
||||
- Ephemeral/disappearing/OTR conversations with the existing contacts.
|
||||
- Privately share your location.
|
||||
- Web widgets for custom interactivity in the chats.
|
||||
- Programmable chat automations / rules (automatic replies/forward/deletion/sending, reminders, etc.).
|
||||
- Supporting the same profile on multiple devices.
|
||||
- Desktop client.
|
||||
- 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.
|
||||
- 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.
|
||||
|
||||
|
||||
+12
-1
@@ -4,7 +4,6 @@ This readme is currently a stub and as such is in development.
|
||||
|
||||
Ultimately, this readme will act as a guide to contributing to the develop of the SimpleX android app.
|
||||
|
||||
|
||||
## Gotchas
|
||||
|
||||
#### SHA Signature for verification for app links/deep links
|
||||
@@ -23,3 +22,15 @@ To find your SHA certificate fingerprint perform the following steps.
|
||||
More information is available [here](https://developer.android.com/training/app-links/verify-site-associations#manual-verification). If there is no response when running the `pm get-app-links` command, the intents in `AndroidManifest.xml` are likely misspecified. A verification attempt can be triggered using `adb shell pm verify-app-links --re-verify chat.simplex.app`.
|
||||
|
||||
Note that this is not an issue for the app store build of the app as this is signed with our app store credentials and thus there is a stable signature over users. Developers do not have general access to these credentials for development and testing.
|
||||
|
||||
## Adding icons
|
||||
|
||||
1. Find a [Material symbol](https://fonts.google.com/icons?icon.style=Rounded) in Rounded category.
|
||||
|
||||
2. Set weight to 400, grade to -25 and size to 48px.
|
||||
|
||||
3. Click on the icon, choose Android and download XML file.
|
||||
|
||||
4. Update the color to black (#FF000000) and the size to "24.dp", as in other icons.
|
||||
|
||||
For example, this is [add reaction icon](https://fonts.google.com/icons?selected=Material+Symbols+Rounded:add_reaction:FILL@0;wght@300;GRAD@-25;opsz@24&icon.style=Rounded).
|
||||
|
||||
@@ -11,8 +11,10 @@ android {
|
||||
applicationId "chat.simplex.app"
|
||||
minSdk 26
|
||||
targetSdk 32
|
||||
versionCode 117
|
||||
versionName "5.0"
|
||||
// !!!
|
||||
// skip version code after release to F-Droid, as it uses two version codes
|
||||
versionCode 123
|
||||
versionName "5.1.1"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables {
|
||||
@@ -84,8 +86,10 @@ android {
|
||||
"es",
|
||||
"fr",
|
||||
"it",
|
||||
"ja",
|
||||
"nl",
|
||||
"pl",
|
||||
"pt-rBR",
|
||||
"ru",
|
||||
"zh-rCN"
|
||||
)
|
||||
@@ -158,6 +162,9 @@ dependencies {
|
||||
// Video support
|
||||
implementation "com.google.android.exoplayer:exoplayer:2.17.1"
|
||||
|
||||
// Wheel picker
|
||||
implementation 'com.github.zj565061763:compose-wheel-picker:1.0.0-alpha10'
|
||||
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
|
||||
|
||||
@@ -10,14 +10,12 @@ import android.view.WindowManager
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.viewModels
|
||||
import androidx.compose.animation.core.*
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
@@ -32,10 +30,12 @@ import chat.simplex.app.views.SplashView
|
||||
import chat.simplex.app.views.call.ActiveCallView
|
||||
import chat.simplex.app.views.call.IncomingCallAlertView
|
||||
import chat.simplex.app.views.chat.ChatView
|
||||
import chat.simplex.app.views.chat.group.ProgressIndicator
|
||||
import chat.simplex.app.views.chatlist.*
|
||||
import chat.simplex.app.views.database.DatabaseErrorView
|
||||
import chat.simplex.app.views.helpers.*
|
||||
import chat.simplex.app.views.helpers.DatabaseUtils.ksAppPassword
|
||||
import chat.simplex.app.views.helpers.DatabaseUtils.ksSelfDestructPassword
|
||||
import chat.simplex.app.views.localauth.SetAppPasscodeView
|
||||
import chat.simplex.app.views.newchat.*
|
||||
import chat.simplex.app.views.onboarding.*
|
||||
@@ -61,6 +61,7 @@ class MainActivity: FragmentActivity() {
|
||||
}
|
||||
}
|
||||
private val vm by viewModels<SimplexViewModel>()
|
||||
private val destroyedAfterBackPress = mutableStateOf(false)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@@ -83,14 +84,17 @@ class MainActivity: FragmentActivity() {
|
||||
}
|
||||
setContent {
|
||||
SimpleXTheme {
|
||||
MainPage(
|
||||
m,
|
||||
userAuthorized,
|
||||
laFailed,
|
||||
::runAuthenticate,
|
||||
::setPerformLA,
|
||||
showLANotice = { showLANotice(m.controller.appPrefs.laNoticeShown, this) }
|
||||
)
|
||||
Surface(color = MaterialTheme.colors.background) {
|
||||
MainPage(
|
||||
m,
|
||||
userAuthorized,
|
||||
laFailed,
|
||||
destroyedAfterBackPress,
|
||||
::runAuthenticate,
|
||||
::setPerformLA,
|
||||
showLANotice = { showLANotice(m.controller.appPrefs.laNoticeShown, this) }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
SimplexApp.context.schedulePeriodicServiceRestartWorker()
|
||||
@@ -108,7 +112,12 @@ class MainActivity: FragmentActivity() {
|
||||
val enteredBackgroundVal = enteredBackground.value
|
||||
val delay = vm.chatModel.controller.appPrefs.laLockDelay.get()
|
||||
if (enteredBackgroundVal == null || elapsedRealtime() - enteredBackgroundVal >= delay * 1000) {
|
||||
runAuthenticate()
|
||||
if (userAuthorized.value != false) {
|
||||
/** [runAuthenticate] will be called in [MainPage] if needed. Making like this prevents double showing of passcode on start */
|
||||
setAuthState()
|
||||
} else if (!vm.chatModel.activeCallViewIsVisible.value) {
|
||||
runAuthenticate()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,6 +151,7 @@ class MainActivity: FragmentActivity() {
|
||||
// When pressed Back and there is no one wants to process the back event, clear auth state to force re-auth on launch
|
||||
clearAuthState()
|
||||
laFailed.value = true
|
||||
destroyedAfterBackPress.value = true
|
||||
}
|
||||
if (!onBackPressedDispatcher.hasEnabledCallbacks()) {
|
||||
// Drop shared content
|
||||
@@ -149,13 +159,14 @@ class MainActivity: FragmentActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun setAuthState() {
|
||||
userAuthorized.value = !vm.chatModel.controller.appPrefs.performLA.get()
|
||||
}
|
||||
|
||||
private fun runAuthenticate() {
|
||||
val m = vm.chatModel
|
||||
if (!m.controller.appPrefs.performLA.get()) {
|
||||
userAuthorized.value = true
|
||||
} else {
|
||||
userAuthorized.value = false
|
||||
ModalManager.shared.closeModals()
|
||||
setAuthState()
|
||||
if (userAuthorized.value == false) {
|
||||
// To make Main thread free in order to allow to Compose to show blank view that hiding content underneath of it faster on slow devices
|
||||
CoroutineScope(Dispatchers.Default).launch {
|
||||
delay(50)
|
||||
@@ -169,6 +180,7 @@ class MainActivity: FragmentActivity() {
|
||||
generalGetString(R.string.auth_log_in_using_credential)
|
||||
else
|
||||
generalGetString(R.string.auth_unlock),
|
||||
selfDestruct = true,
|
||||
this@MainActivity,
|
||||
completed = { laResult ->
|
||||
when (laResult) {
|
||||
@@ -238,7 +250,7 @@ class MainActivity: FragmentActivity() {
|
||||
authenticate(
|
||||
generalGetString(R.string.auth_enable_simplex_lock),
|
||||
generalGetString(R.string.auth_confirm_credential),
|
||||
activity,
|
||||
activity = activity,
|
||||
completed = { laResult ->
|
||||
when (laResult) {
|
||||
LAResult.Success -> {
|
||||
@@ -279,7 +291,8 @@ class MainActivity: FragmentActivity() {
|
||||
appPrefs.performLA.set(false)
|
||||
laPasscodeNotSetAlert()
|
||||
},
|
||||
close)
|
||||
close = close
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -304,7 +317,7 @@ class MainActivity: FragmentActivity() {
|
||||
generalGetString(R.string.auth_confirm_credential)
|
||||
else
|
||||
"",
|
||||
activity,
|
||||
activity = activity,
|
||||
completed = { laResult ->
|
||||
val prefPerformLA = m.controller.appPrefs.performLA
|
||||
when (laResult) {
|
||||
@@ -340,14 +353,17 @@ class MainActivity: FragmentActivity() {
|
||||
generalGetString(R.string.auth_confirm_credential)
|
||||
else
|
||||
generalGetString(R.string.auth_disable_simplex_lock),
|
||||
activity,
|
||||
activity = activity,
|
||||
completed = { laResult ->
|
||||
val prefPerformLA = m.controller.appPrefs.performLA
|
||||
val selfDestructPref = m.controller.appPrefs.selfDestruct
|
||||
when (laResult) {
|
||||
LAResult.Success -> {
|
||||
m.performLA.value = false
|
||||
prefPerformLA.set(false)
|
||||
ksAppPassword.remove()
|
||||
selfDestructPref.set(false)
|
||||
ksSelfDestructPassword.remove()
|
||||
}
|
||||
is LAResult.Failed -> { /* Can be called multiple times on every failure */ }
|
||||
is LAResult.Error -> {
|
||||
@@ -376,6 +392,7 @@ fun MainPage(
|
||||
chatModel: ChatModel,
|
||||
userAuthorized: MutableState<Boolean?>,
|
||||
laFailed: MutableState<Boolean>,
|
||||
destroyedAfterBackPress: MutableState<Boolean>,
|
||||
runAuthenticate: () -> Unit,
|
||||
setPerformLA: (Boolean, FragmentActivity) -> Unit,
|
||||
showLANotice: () -> Unit
|
||||
@@ -412,43 +429,38 @@ fun MainPage(
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun authView() {
|
||||
Box(
|
||||
Modifier.fillMaxSize().background(MaterialTheme.colors.background),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
SimpleButton(
|
||||
stringResource(R.string.auth_unlock),
|
||||
icon = painterResource(R.drawable.ic_lock),
|
||||
click = {
|
||||
laFailed.value = false
|
||||
runAuthenticate()
|
||||
}
|
||||
)
|
||||
fun AuthView() {
|
||||
Surface(color = MaterialTheme.colors.background) {
|
||||
Box(
|
||||
Modifier.fillMaxSize(),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
SimpleButton(
|
||||
stringResource(R.string.auth_unlock),
|
||||
icon = painterResource(R.drawable.ic_lock),
|
||||
click = {
|
||||
laFailed.value = false
|
||||
runAuthenticate()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Box {
|
||||
val onboarding = chatModel.onboardingStage.value
|
||||
val userCreated = chatModel.userCreated.value
|
||||
var showInitializationView by remember { mutableStateOf(false) }
|
||||
when {
|
||||
chatModel.chatDbStatus.value == null && showInitializationView -> InitializationView()
|
||||
showChatDatabaseError -> {
|
||||
chatModel.chatDbStatus.value?.let {
|
||||
DatabaseErrorView(chatModel.chatDbStatus, chatModel.controller.appPrefs)
|
||||
}
|
||||
}
|
||||
onboarding == null || userCreated == null -> SplashView()
|
||||
userAuthorized.value != true -> {
|
||||
if (chatModel.controller.appPrefs.performLA.get() && laFailed.value) {
|
||||
authView()
|
||||
} else {
|
||||
SplashView()
|
||||
}
|
||||
}
|
||||
onboarding == OnboardingStage.OnboardingComplete && userCreated -> {
|
||||
Box {
|
||||
if (chatModel.showCallView.value) ActiveCallView(chatModel)
|
||||
else {
|
||||
showAdvertiseLAAlert = true
|
||||
BoxWithConstraints {
|
||||
var currentChatId by rememberSaveable { mutableStateOf(chatModel.chatId.value) }
|
||||
@@ -494,16 +506,41 @@ fun MainPage(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
onboarding == OnboardingStage.Step1_SimpleXInfo -> SimpleXInfo(chatModel, onboarding = true)
|
||||
onboarding == OnboardingStage.Step2_CreateProfile -> CreateProfile(chatModel) {}
|
||||
onboarding == OnboardingStage.Step3_SetNotificationsMode -> SetNotificationsMode(chatModel)
|
||||
onboarding == OnboardingStage.Step3_CreateSimpleXAddress -> CreateSimpleXAddress(chatModel)
|
||||
onboarding == OnboardingStage.Step4_SetNotificationsMode -> SetNotificationsMode(chatModel)
|
||||
}
|
||||
ModalManager.shared.showInView()
|
||||
val unauthorized = remember { derivedStateOf { userAuthorized.value != true } }
|
||||
if (unauthorized.value && !(chatModel.activeCallViewIsVisible.value && chatModel.showCallView.value)) {
|
||||
LaunchedEffect(Unit) {
|
||||
// With these constrains when user presses back button while on ChatList, activity destroys and shows auth request
|
||||
// while the screen moves to a launcher. Detect it and prevent showing the auth
|
||||
if (!(destroyedAfterBackPress.value && chatModel.controller.appPrefs.laMode.get() == LAMode.SYSTEM)) {
|
||||
runAuthenticate()
|
||||
}
|
||||
}
|
||||
if (chatModel.controller.appPrefs.performLA.get() && laFailed.value) {
|
||||
AuthView()
|
||||
} else {
|
||||
SplashView()
|
||||
}
|
||||
} else if (chatModel.showCallView.value) {
|
||||
ActiveCallView(chatModel)
|
||||
}
|
||||
ModalManager.shared.showPasscodeInView()
|
||||
val invitation = chatModel.activeCallInvitation.value
|
||||
if (invitation != null) IncomingCallAlertView(invitation, chatModel)
|
||||
AlertManager.shared.showInView()
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
delay(1000)
|
||||
if (chatModel.chatDbStatus.value == null) {
|
||||
showInitializationView = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DisposableEffectOnRotate {
|
||||
@@ -515,6 +552,22 @@ fun MainPage(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun InitializationView() {
|
||||
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
CircularProgressIndicator(
|
||||
Modifier
|
||||
.padding(bottom = DEFAULT_PADDING)
|
||||
.size(30.dp),
|
||||
color = MaterialTheme.colors.secondary,
|
||||
strokeWidth = 2.5.dp
|
||||
)
|
||||
Text(stringResource(R.string.opening_database))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun processNotificationIntent(intent: Intent?, chatModel: ChatModel) {
|
||||
val userId = getUserIdFromIntent(intent)
|
||||
when (intent?.action) {
|
||||
|
||||
@@ -36,13 +36,11 @@ external fun chatParseServer(str: String): String
|
||||
external fun chatPasswordHash(pwd: String, salt: String): String
|
||||
|
||||
class SimplexApp: Application(), LifecycleEventObserver {
|
||||
lateinit var chatController: ChatController
|
||||
|
||||
var isAppOnForeground: Boolean = false
|
||||
|
||||
val defaultLocale: Locale = Locale.getDefault()
|
||||
|
||||
fun initChatController(useKey: String? = null, confirmMigrations: MigrationConfirmation? = null, startChat: Boolean = true) {
|
||||
suspend fun initChatController(useKey: String? = null, confirmMigrations: MigrationConfirmation? = null, startChat: Boolean = true) {
|
||||
val dbKey = useKey ?: DatabaseUtils.useDatabaseKey()
|
||||
val dbAbsolutePathPrefix = getFilesDirectory(SimplexApp.context)
|
||||
val confirm = confirmMigrations ?: if (appPreferences.confirmDBUpgrades.get()) MigrationConfirmation.Error else MigrationConfirmation.YesUp
|
||||
@@ -53,11 +51,7 @@ class SimplexApp: Application(), LifecycleEventObserver {
|
||||
val ctrl = if (res is DBMigrationResult.OK) {
|
||||
migrated[1] as Long
|
||||
} else null
|
||||
if (::chatController.isInitialized) {
|
||||
chatController.ctrl = ctrl
|
||||
} else {
|
||||
chatController = ChatController(ctrl, ntfManager, applicationContext, appPreferences)
|
||||
}
|
||||
chatController.ctrl = ctrl
|
||||
chatModel.chatDbEncrypted.value = dbKey != ""
|
||||
chatModel.chatDbStatus.value = res
|
||||
if (res != DBMigrationResult.OK) {
|
||||
@@ -65,12 +59,22 @@ class SimplexApp: Application(), LifecycleEventObserver {
|
||||
} else if (startChat) {
|
||||
// If we migrated successfully means previous re-encryption process on database level finished successfully too
|
||||
if (appPreferences.encryptionStartedAt.get() != null) appPreferences.encryptionStartedAt.set(null)
|
||||
withApi {
|
||||
val user = chatController.apiGetActiveUser()
|
||||
if (user == null) {
|
||||
chatModel.onboardingStage.value = OnboardingStage.Step1_SimpleXInfo
|
||||
val user = chatController.apiGetActiveUser()
|
||||
if (user == null) {
|
||||
chatModel.controller.appPrefs.onboardingStage.set(OnboardingStage.Step1_SimpleXInfo)
|
||||
chatModel.onboardingStage.value = OnboardingStage.Step1_SimpleXInfo
|
||||
chatModel.currentUser.value = null
|
||||
chatModel.users.clear()
|
||||
} else {
|
||||
val savedOnboardingStage = appPreferences.onboardingStage.get()
|
||||
chatModel.onboardingStage.value = if (listOf(OnboardingStage.Step1_SimpleXInfo, OnboardingStage.Step2_CreateProfile).contains(savedOnboardingStage) && chatModel.users.size == 1) {
|
||||
OnboardingStage.Step3_CreateSimpleXAddress
|
||||
} else {
|
||||
chatController.startChat(user)
|
||||
savedOnboardingStage
|
||||
}
|
||||
chatController.startChat(user)
|
||||
// Prevents from showing "Enable notifications" alert when onboarding wasn't complete yet
|
||||
if (chatModel.onboardingStage.value == OnboardingStage.OnboardingComplete) {
|
||||
chatController.showBackgroundServiceNoticeIfNeeded()
|
||||
if (appPreferences.notificationsMode.get() == NotificationsMode.SERVICE.name)
|
||||
SimplexService.start(applicationContext)
|
||||
@@ -90,13 +94,20 @@ class SimplexApp: Application(), LifecycleEventObserver {
|
||||
AppPreferences(applicationContext)
|
||||
}
|
||||
|
||||
val chatController: ChatController by lazy {
|
||||
ChatController(0L, ntfManager, applicationContext, appPreferences)
|
||||
}
|
||||
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
context = this
|
||||
initChatController()
|
||||
ProcessLifecycleOwner.get().lifecycle.addObserver(this)
|
||||
context.getDir("temp", MODE_PRIVATE).deleteRecursively()
|
||||
runMigrations()
|
||||
withBGApi {
|
||||
initChatController()
|
||||
runMigrations()
|
||||
}
|
||||
ProcessLifecycleOwner.get().lifecycle.addObserver(this@SimplexApp)
|
||||
}
|
||||
|
||||
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
|
||||
|
||||
@@ -9,9 +9,9 @@ import android.util.Log
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.work.*
|
||||
import chat.simplex.app.model.ChatController
|
||||
import chat.simplex.app.views.helpers.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.coroutines.*
|
||||
|
||||
// based on:
|
||||
// https://robertohuertas.com/2019/06/29/android_foreground_services/
|
||||
@@ -86,6 +86,7 @@ class SimplexService: Service() {
|
||||
isStartingService = true
|
||||
withApi {
|
||||
val chatController = (application as SimplexApp).chatController
|
||||
waitDbMigrationEnds(chatController)
|
||||
try {
|
||||
Log.w(TAG, "Starting foreground service")
|
||||
val chatDbStatus = chatController.chatModel.chatDbStatus.value
|
||||
@@ -324,6 +325,18 @@ class SimplexService: Service() {
|
||||
notificationManager.cancel(PASSPHRASE_NOTIFICATION_ID)
|
||||
}
|
||||
|
||||
/*
|
||||
* When the app starts the database is in migration process. It can take from seconds to tens of seconds.
|
||||
* It happens in background thread, so other places that relies on database should wait til the end of migration
|
||||
* */
|
||||
suspend fun waitDbMigrationEnds(chatController: ChatController) {
|
||||
var maxWaitTime = 50_000
|
||||
while (chatController.chatModel.chatDbStatus.value == null && maxWaitTime > 0) {
|
||||
delay(50)
|
||||
maxWaitTime -= 50
|
||||
}
|
||||
}
|
||||
|
||||
private fun getPreferences(context: Context): SharedPreferences = context.getSharedPreferences(SHARED_PREFS_ID, Context.MODE_PRIVATE)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@ import android.net.Uri
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.font.*
|
||||
import androidx.compose.ui.text.style.TextDecoration
|
||||
@@ -19,12 +17,16 @@ import chat.simplex.app.views.usersettings.NotificationPreviewMode
|
||||
import chat.simplex.app.views.usersettings.NotificationsMode
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.datetime.*
|
||||
import kotlinx.datetime.TimeZone
|
||||
import kotlinx.serialization.*
|
||||
import kotlinx.serialization.descriptors.*
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import kotlinx.serialization.json.*
|
||||
import java.io.File
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.time.format.FormatStyle
|
||||
import java.util.*
|
||||
import kotlin.random.Random
|
||||
import kotlin.time.*
|
||||
|
||||
@@ -41,7 +43,6 @@ class ChatModel(val controller: ChatController) {
|
||||
val chatDbChanged = mutableStateOf<Boolean>(false)
|
||||
val chatDbEncrypted = mutableStateOf<Boolean?>(false)
|
||||
val chatDbStatus = mutableStateOf<DBMigrationResult?>(null)
|
||||
val chatDbDeleted = mutableStateOf(false)
|
||||
val chats = mutableStateListOf<Chat>()
|
||||
// map of connections network statuses, key is agent connection id
|
||||
val networkStatuses = mutableStateMapOf<String, NetworkStatus>()
|
||||
@@ -75,6 +76,7 @@ class ChatModel(val controller: ChatController) {
|
||||
val callInvitations = mutableStateMapOf<String, RcvCallInvitation>()
|
||||
val activeCallInvitation = mutableStateOf<RcvCallInvitation?>(null)
|
||||
val activeCall = mutableStateOf<Call?>(null)
|
||||
val activeCallViewIsVisible = mutableStateOf<Boolean>(false)
|
||||
val callCommand = mutableStateOf<WCallCommand?>(null)
|
||||
val showCallView = mutableStateOf(false)
|
||||
val switchingCall = mutableStateOf(false)
|
||||
@@ -238,6 +240,17 @@ class ChatModel(val controller: ChatController) {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun updateChatItem(cInfo: ChatInfo, cItem: ChatItem) {
|
||||
if (chatId.value == cInfo.id) {
|
||||
withContext(Dispatchers.Main) {
|
||||
val itemIndex = chatItems.indexOfFirst { it.id == cItem.id }
|
||||
if (itemIndex >= 0) {
|
||||
chatItems[itemIndex] = cItem
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun removeChatItem(cInfo: ChatInfo, cItem: ChatItem) {
|
||||
if (cItem.isRcvNew) {
|
||||
decreaseCounterInChat(cInfo.id)
|
||||
@@ -461,6 +474,8 @@ data class User(
|
||||
|
||||
val showNotifications: Boolean = activeUser || showNtfs
|
||||
|
||||
val addressShared: Boolean = profile.contactLink != null
|
||||
|
||||
companion object {
|
||||
val sampleData = User(
|
||||
userId = 1,
|
||||
@@ -727,6 +742,7 @@ data class Contact(
|
||||
override fun featureEnabled(feature: ChatFeature) = when (feature) {
|
||||
ChatFeature.TimedMessages -> mergedPreferences.timedMessages.enabled.forUser
|
||||
ChatFeature.FullDelete -> mergedPreferences.fullDelete.enabled.forUser
|
||||
ChatFeature.Reactions -> mergedPreferences.reactions.enabled.forUser
|
||||
ChatFeature.Voice -> mergedPreferences.voice.enabled.forUser
|
||||
ChatFeature.Calls -> mergedPreferences.calls.enabled.forUser
|
||||
}
|
||||
@@ -734,6 +750,7 @@ data class Contact(
|
||||
override val displayName get() = localAlias.ifEmpty { profile.displayName }
|
||||
override val fullName get() = profile.fullName
|
||||
override val image get() = profile.image
|
||||
val contactLink: String? = profile.contactLink
|
||||
override val localAlias get() = profile.localAlias
|
||||
val verified get() = activeConn.connectionCode != null
|
||||
|
||||
@@ -747,12 +764,14 @@ data class Contact(
|
||||
ChatFeature.TimedMessages -> mergedPreferences.timedMessages.contactPreference.allow != FeatureAllowed.NO
|
||||
ChatFeature.FullDelete -> mergedPreferences.fullDelete.contactPreference.allow != FeatureAllowed.NO
|
||||
ChatFeature.Voice -> mergedPreferences.voice.contactPreference.allow != FeatureAllowed.NO
|
||||
ChatFeature.Reactions -> mergedPreferences.reactions.contactPreference.allow != FeatureAllowed.NO
|
||||
ChatFeature.Calls -> mergedPreferences.calls.contactPreference.allow != FeatureAllowed.NO
|
||||
}
|
||||
|
||||
fun userAllowsFeature(feature: ChatFeature): Boolean = when (feature) {
|
||||
ChatFeature.TimedMessages -> mergedPreferences.timedMessages.userPreference.pref.allow != FeatureAllowed.NO
|
||||
ChatFeature.FullDelete -> mergedPreferences.fullDelete.userPreference.pref.allow != FeatureAllowed.NO
|
||||
ChatFeature.Reactions -> mergedPreferences.reactions.userPreference.pref.allow != FeatureAllowed.NO
|
||||
ChatFeature.Voice -> mergedPreferences.voice.userPreference.pref.allow != FeatureAllowed.NO
|
||||
ChatFeature.Calls -> mergedPreferences.calls.userPreference.pref.allow != FeatureAllowed.NO
|
||||
}
|
||||
@@ -814,6 +833,7 @@ data class Profile(
|
||||
override val fullName: String,
|
||||
override val image: String? = null,
|
||||
override val localAlias : String = "",
|
||||
val contactLink: String? = null,
|
||||
val preferences: ChatPreferences? = null
|
||||
): NamedChat {
|
||||
val profileViewName: String
|
||||
@@ -821,7 +841,7 @@ data class Profile(
|
||||
return if (fullName == "" || displayName == fullName) displayName else "$displayName ($fullName)"
|
||||
}
|
||||
|
||||
fun toLocalProfile(profileId: Long): LocalProfile = LocalProfile(profileId, displayName, fullName, image, localAlias, preferences)
|
||||
fun toLocalProfile(profileId: Long): LocalProfile = LocalProfile(profileId, displayName, fullName, image, localAlias, contactLink, preferences)
|
||||
|
||||
companion object {
|
||||
val sampleData = Profile(
|
||||
@@ -832,17 +852,18 @@ data class Profile(
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class LocalProfile(
|
||||
data class LocalProfile(
|
||||
val profileId: Long,
|
||||
override val displayName: String,
|
||||
override val fullName: String,
|
||||
override val image: String? = null,
|
||||
override val localAlias: String,
|
||||
val contactLink: String? = null,
|
||||
val preferences: ChatPreferences? = null
|
||||
): NamedChat {
|
||||
val profileViewName: String = localAlias.ifEmpty { if (fullName == "" || displayName == fullName) displayName else "$displayName ($fullName)" }
|
||||
|
||||
fun toProfile(): Profile = Profile(displayName, fullName, image, localAlias, preferences)
|
||||
fun toProfile(): Profile = Profile(displayName, fullName, image, localAlias, contactLink, preferences)
|
||||
|
||||
companion object {
|
||||
val sampleData = LocalProfile(
|
||||
@@ -883,6 +904,7 @@ data class GroupInfo (
|
||||
override fun featureEnabled(feature: ChatFeature) = when (feature) {
|
||||
ChatFeature.TimedMessages -> fullGroupPreferences.timedMessages.on
|
||||
ChatFeature.FullDelete -> fullGroupPreferences.fullDelete.on
|
||||
ChatFeature.Reactions -> fullGroupPreferences.reactions.on
|
||||
ChatFeature.Voice -> fullGroupPreferences.voice.on
|
||||
ChatFeature.Calls -> false
|
||||
}
|
||||
@@ -952,6 +974,7 @@ data class GroupMember (
|
||||
val displayName: String get() = memberProfile.localAlias.ifEmpty { memberProfile.displayName }
|
||||
val fullName: String get() = memberProfile.fullName
|
||||
val image: String? get() = memberProfile.image
|
||||
val contactLink: String? = memberProfile.contactLink
|
||||
val verified get() = activeConn?.connectionCode != null
|
||||
|
||||
val chatViewName: String
|
||||
@@ -1251,6 +1274,20 @@ class AChatItem (
|
||||
val chatItem: ChatItem
|
||||
)
|
||||
|
||||
@Serializable
|
||||
class ACIReaction(
|
||||
val chatInfo: ChatInfo,
|
||||
val chatReaction: CIReaction
|
||||
)
|
||||
|
||||
@Serializable
|
||||
class CIReaction(
|
||||
val chatDir: CIDirection,
|
||||
val chatItem: ChatItem,
|
||||
val sentAt: Instant,
|
||||
val reaction: MsgReaction
|
||||
)
|
||||
|
||||
@Serializable @Stable
|
||||
data class ChatItem (
|
||||
val chatDir: CIDirection,
|
||||
@@ -1258,6 +1295,7 @@ data class ChatItem (
|
||||
val content: CIContent,
|
||||
val formattedText: List<FormattedText>? = null,
|
||||
val quotedItem: CIQuote? = null,
|
||||
val reactions: List<CIReactionCount>,
|
||||
val file: CIFile? = null
|
||||
) {
|
||||
val id: Long get() = meta.itemId
|
||||
@@ -1274,6 +1312,11 @@ data class ChatItem (
|
||||
|
||||
val isRcvNew: Boolean get() = meta.isRcvNew
|
||||
|
||||
val allowAddReaction: Boolean get() =
|
||||
meta.itemDeleted == null && !isLiveDummy && (reactions.count { it.userReacted } < 3)
|
||||
|
||||
private val isLiveDummy: Boolean get() = meta.itemId == TEMP_LIVE_CHAT_ITEM_ID
|
||||
|
||||
val memberDisplayName: String? get() =
|
||||
if (chatDir is CIDirection.GroupRcv) chatDir.groupMember.displayName
|
||||
else null
|
||||
@@ -1363,6 +1406,7 @@ data class ChatItem (
|
||||
meta = CIMeta.getSample(id, ts, text, status, itemDeleted, itemEdited, itemTimed, editable),
|
||||
content = CIContent.SndMsgContent(msgContent = MsgContent.MCText(text)),
|
||||
quotedItem = quotedItem,
|
||||
reactions = listOf(),
|
||||
file = file
|
||||
)
|
||||
|
||||
@@ -1378,6 +1422,7 @@ data class ChatItem (
|
||||
meta = CIMeta.getSample(id, Clock.System.now(), text, CIStatus.RcvRead()),
|
||||
content = CIContent.RcvMsgContent(msgContent = MsgContent.MCFile(text)),
|
||||
quotedItem = null,
|
||||
reactions = listOf(),
|
||||
file = CIFile.getSample(fileName = fileName, fileSize = fileSize, fileStatus = fileStatus)
|
||||
)
|
||||
|
||||
@@ -1393,6 +1438,7 @@ data class ChatItem (
|
||||
meta = CIMeta.getSample(id, ts, text, status),
|
||||
content = CIContent.RcvDeleted(deleteMode = CIDeleteMode.cidmBroadcast),
|
||||
quotedItem = null,
|
||||
reactions = listOf(),
|
||||
file = null
|
||||
)
|
||||
|
||||
@@ -1402,6 +1448,7 @@ data class ChatItem (
|
||||
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,
|
||||
reactions = listOf(),
|
||||
file = null
|
||||
)
|
||||
|
||||
@@ -1411,6 +1458,7 @@ data class ChatItem (
|
||||
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,
|
||||
reactions = listOf(),
|
||||
file = null
|
||||
)
|
||||
|
||||
@@ -1421,6 +1469,7 @@ data class ChatItem (
|
||||
meta = CIMeta.getSample(1, Clock.System.now(), content.text, CIStatus.RcvRead()),
|
||||
content = content,
|
||||
quotedItem = null,
|
||||
reactions = listOf(),
|
||||
file = null
|
||||
)
|
||||
}
|
||||
@@ -1446,6 +1495,7 @@ data class ChatItem (
|
||||
),
|
||||
content = CIContent.RcvDeleted(deleteMode = CIDeleteMode.cidmBroadcast),
|
||||
quotedItem = null,
|
||||
reactions = listOf(),
|
||||
file = null
|
||||
)
|
||||
|
||||
@@ -1466,6 +1516,7 @@ data class ChatItem (
|
||||
),
|
||||
content = CIContent.SndMsgContent(MsgContent.MCText("")),
|
||||
quotedItem = null,
|
||||
reactions = listOf(),
|
||||
file = null
|
||||
)
|
||||
|
||||
@@ -1475,6 +1526,7 @@ data class ChatItem (
|
||||
meta = meta ?: CIMeta.invalidJSON(),
|
||||
content = CIContent.InvalidJSON(json),
|
||||
quotedItem = null,
|
||||
reactions = listOf(),
|
||||
file = null
|
||||
)
|
||||
}
|
||||
@@ -1574,8 +1626,28 @@ fun getTimestampText(t: Instant): String {
|
||||
val time: LocalDateTime = t.toLocalDateTime(tz)
|
||||
val recent = now.date == time.date ||
|
||||
(now.date.minus(time.date).days == 1 && now.hour < 12 && time.hour >= 18 )
|
||||
return if (recent) String.format("%02d:%02d", time.hour, time.minute)
|
||||
else String.format("%02d/%02d", time.dayOfMonth, time.monthNumber)
|
||||
val dateFormatter =
|
||||
if (recent) {
|
||||
DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT)
|
||||
} else {
|
||||
DateTimeFormatter.ofPattern(
|
||||
when (Locale.getDefault().country) {
|
||||
"US" -> "M/dd"
|
||||
"DE" -> "dd.MM"
|
||||
"RU" -> "dd.MM"
|
||||
else -> "dd/MM"
|
||||
}
|
||||
)
|
||||
// DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT)
|
||||
}
|
||||
return time.toJavaLocalDateTime().format(dateFormatter)
|
||||
}
|
||||
|
||||
fun localTimestamp(t: Instant): String {
|
||||
val tz = TimeZone.currentSystemDefault()
|
||||
val ts: LocalDateTime = t.toLocalDateTime(tz)
|
||||
val dateFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)
|
||||
return ts.toJavaLocalDateTime().format(dateFormatter)
|
||||
}
|
||||
|
||||
@Serializable
|
||||
@@ -1590,8 +1662,8 @@ sealed class CIStatus {
|
||||
|
||||
@Serializable
|
||||
sealed class CIDeleted {
|
||||
@Serializable @SerialName("deleted") class Deleted: CIDeleted()
|
||||
@Serializable @SerialName("moderated") class Moderated(val byGroupMember: GroupMember): CIDeleted()
|
||||
@Serializable @SerialName("deleted") class Deleted(val deletedTs: Instant?): CIDeleted()
|
||||
@Serializable @SerialName("moderated") class Moderated(val deletedTs: Instant?, val byGroupMember: GroupMember): CIDeleted()
|
||||
}
|
||||
|
||||
@Serializable
|
||||
@@ -1665,18 +1737,18 @@ sealed class CIContent: ItemContent {
|
||||
companion object {
|
||||
fun featureText(feature: Feature, enabled: String, param: Int?): String =
|
||||
if (feature.hasParam) {
|
||||
"${feature.text}: ${TimedMessagesPreference.ttlText(param)}"
|
||||
"${feature.text}: ${timeText(param)}"
|
||||
} else {
|
||||
"${feature.text}: $enabled"
|
||||
}
|
||||
|
||||
fun preferenceText(feature: Feature, allowed: FeatureAllowed, param: Int?): String = when {
|
||||
allowed != FeatureAllowed.NO && feature.hasParam && param != null ->
|
||||
String.format(generalGetString(R.string.feature_offered_item_with_param), feature.text, TimedMessagesPreference.ttlText(param))
|
||||
String.format(generalGetString(R.string.feature_offered_item_with_param), feature.text, timeText(param))
|
||||
allowed != FeatureAllowed.NO ->
|
||||
String.format(generalGetString(R.string.feature_offered_item), feature.text, TimedMessagesPreference.ttlText(param))
|
||||
String.format(generalGetString(R.string.feature_offered_item), feature.text, timeText(param))
|
||||
else ->
|
||||
String.format(generalGetString(R.string.feature_cancelled_item), feature.text, TimedMessagesPreference.ttlText(param))
|
||||
String.format(generalGetString(R.string.feature_cancelled_item), feature.text, timeText(param))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1723,6 +1795,75 @@ class CIQuote (
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class CIReactionCount(val reaction: MsgReaction, val userReacted: Boolean, val totalReacted: Int)
|
||||
|
||||
@Serializable(with = MsgReactionSerializer::class)
|
||||
sealed class MsgReaction {
|
||||
@Serializable(with = MsgReactionSerializer::class) class Emoji(val emoji: MREmojiChar): MsgReaction()
|
||||
@Serializable(with = MsgReactionSerializer::class) class Unknown(val type: String? = null, val json: JsonElement): MsgReaction()
|
||||
|
||||
val text: String get() = when (this) {
|
||||
is Emoji -> when (emoji) {
|
||||
MREmojiChar.Heart -> "❤️"
|
||||
else -> emoji.value
|
||||
}
|
||||
is Unknown -> ""
|
||||
}
|
||||
|
||||
companion object {
|
||||
val values: List<MsgReaction> get() = MREmojiChar.values().map(::Emoji)
|
||||
}
|
||||
}
|
||||
|
||||
object MsgReactionSerializer : KSerializer<MsgReaction> {
|
||||
override val descriptor: SerialDescriptor = buildSerialDescriptor("MsgReaction", PolymorphicKind.SEALED) {
|
||||
element("Emoji", buildClassSerialDescriptor("Emoji") {
|
||||
element<String>("emoji")
|
||||
})
|
||||
element("Unknown", buildClassSerialDescriptor("Unknown"))
|
||||
}
|
||||
|
||||
override fun deserialize(decoder: Decoder): MsgReaction {
|
||||
require(decoder is JsonDecoder)
|
||||
val json = decoder.decodeJsonElement()
|
||||
return if (json is JsonObject && "type" in json) {
|
||||
when(val t = json["type"]?.jsonPrimitive?.content ?: "") {
|
||||
"emoji" -> {
|
||||
val emoji = Json.decodeFromString<MREmojiChar>(json["emoji"].toString())
|
||||
if (emoji == null) MsgReaction.Unknown(t, json) else MsgReaction.Emoji(emoji)
|
||||
}
|
||||
else -> MsgReaction.Unknown(t, json)
|
||||
}
|
||||
} else {
|
||||
MsgReaction.Unknown("", json)
|
||||
}
|
||||
}
|
||||
|
||||
override fun serialize(encoder: Encoder, value: MsgReaction) {
|
||||
require(encoder is JsonEncoder)
|
||||
val json = when (value) {
|
||||
is MsgReaction.Emoji ->
|
||||
buildJsonObject {
|
||||
put("type", "emoji")
|
||||
put("emoji", json.encodeToJsonElement(value.emoji))
|
||||
}
|
||||
is MsgReaction.Unknown -> value.json
|
||||
}
|
||||
encoder.encodeJsonElement(json)
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
enum class MREmojiChar(val value: String) {
|
||||
@SerialName("👍") ThumbsUp("👍"),
|
||||
@SerialName("👎") ThumbsDown("👎"),
|
||||
@SerialName("😀") Smile("😀"),
|
||||
@SerialName("😢") Sad("😢"),
|
||||
@SerialName("❤") Heart("❤"),
|
||||
@SerialName("🚀") Launch("🚀");
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class CIFile(
|
||||
val fileId: Long,
|
||||
@@ -2243,3 +2384,17 @@ sealed class ChatItemTTL: Comparable<ChatItemTTL?> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class ChatItemInfo(
|
||||
val itemVersions: List<ChatItemVersion>,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class ChatItemVersion(
|
||||
val chatItemVersionId: Long,
|
||||
val msgContent: MsgContent,
|
||||
val formattedText: List<FormattedText>?,
|
||||
val itemVersionTs: Instant,
|
||||
val createdAt: Instant,
|
||||
)
|
||||
|
||||
@@ -231,6 +231,10 @@ class NtfManager(val context: Context, private val appPreferences: AppPreference
|
||||
manager.cancel(CallNotificationId)
|
||||
}
|
||||
|
||||
fun cancelAllNotifications() {
|
||||
manager.cancelAll()
|
||||
}
|
||||
|
||||
fun hasNotificationsForChat(chatId: String): Boolean = manager.activeNotifications.any { it.id == chatId.hashCode() }
|
||||
|
||||
private fun hideSecrets(cItem: ChatItem) : String {
|
||||
|
||||
@@ -141,14 +141,19 @@ class AppPreferences(val context: Context) {
|
||||
val showMuteProfileAlert = mkBoolPreference(SHARED_PREFS_SHOW_MUTE_PROFILE_ALERT, true)
|
||||
val appLanguage = mkStrPreference(SHARED_PREFS_APP_LANGUAGE, null)
|
||||
|
||||
val onboardingStage = mkEnumPreference(SHARED_PREFS_ONBOARDING_STAGE, OnboardingStage.OnboardingComplete) { OnboardingStage.values().firstOrNull { it.name == this } }
|
||||
val storeDBPassphrase = mkBoolPreference(SHARED_PREFS_STORE_DB_PASSPHRASE, true)
|
||||
val initialRandomDBPassphrase = mkBoolPreference(SHARED_PREFS_INITIAL_RANDOM_DB_PASSPHRASE, false)
|
||||
val encryptedDBPassphrase = mkStrPreference(SHARED_PREFS_ENCRYPTED_DB_PASSPHRASE, null)
|
||||
val initializationVectorDBPassphrase = mkStrPreference(SHARED_PREFS_INITIALIZATION_VECTOR_DB_PASSPHRASE, null)
|
||||
val encryptedAppPassphrase = mkStrPreference(SHARED_PREFS_ENCRYPTED_APP_PASSPHRASE, null)
|
||||
val initializationVectorAppPassphrase = mkStrPreference(SHARED_PREFS_INITIALIZATION_VECTOR_APP_PASSPHRASE, null)
|
||||
val encryptedSelfDestructPassphrase = mkStrPreference(SHARED_PREFS_ENCRYPTED_SELF_DESTRUCT_PASSPHRASE, null)
|
||||
val initializationVectorSelfDestructPassphrase = mkStrPreference(SHARED_PREFS_INITIALIZATION_VECTOR_SELF_DESTRUCT_PASSPHRASE, null)
|
||||
val encryptionStartedAt = mkDatePreference(SHARED_PREFS_ENCRYPTION_STARTED_AT, null, true)
|
||||
val confirmDBUpgrades = mkBoolPreference(SHARED_PREFS_CONFIRM_DB_UPGRADES, false)
|
||||
val selfDestruct = mkBoolPreference(SHARED_PREFS_SELF_DESTRUCT, false)
|
||||
val selfDestructDisplayName = mkStrPreference(SHARED_PREFS_SELF_DESTRUCT_DISPLAY_NAME, null)
|
||||
|
||||
val currentTheme = mkStrPreference(SHARED_PREFS_CURRENT_THEME, DefaultTheme.SYSTEM.name)
|
||||
val systemDarkTheme = mkStrPreference(SHARED_PREFS_SYSTEM_DARK_THEME, DefaultTheme.SIMPLEX.name)
|
||||
@@ -160,6 +165,7 @@ class AppPreferences(val context: Context) {
|
||||
|
||||
val whatsNewVersion = mkStrPreference(SHARED_PREFS_WHATS_NEW_VERSION, null)
|
||||
val lastMigratedVersionCode = mkIntPreference(SHARED_PREFS_LAST_MIGRATED_VERSION_CODE, 0)
|
||||
val customDisappearingMessageTime = mkIntPreference(SHARED_PREFS_CUSTOM_DISAPPEARING_MESSAGE_TIME, 300)
|
||||
|
||||
private fun mkIntPreference(prefName: String, default: Int) =
|
||||
SharedPreference(
|
||||
@@ -246,6 +252,7 @@ class AppPreferences(val context: Context) {
|
||||
private const val SHARED_PREFS_CHAT_ARCHIVE_NAME = "ChatArchiveName"
|
||||
private const val SHARED_PREFS_CHAT_ARCHIVE_TIME = "ChatArchiveTime"
|
||||
private const val SHARED_PREFS_APP_LANGUAGE = "AppLanguage"
|
||||
private const val SHARED_PREFS_ONBOARDING_STAGE = "OnboardingStage"
|
||||
private const val SHARED_PREFS_CHAT_LAST_START = "ChatLastStart"
|
||||
private const val SHARED_PREFS_DEVELOPER_TOOLS = "DeveloperTools"
|
||||
private const val SHARED_PREFS_NETWORK_USE_SOCKS_PROXY = "NetworkUseSocksProxy"
|
||||
@@ -272,13 +279,18 @@ class AppPreferences(val context: Context) {
|
||||
private const val SHARED_PREFS_INITIALIZATION_VECTOR_DB_PASSPHRASE = "InitializationVectorDBPassphrase"
|
||||
private const val SHARED_PREFS_ENCRYPTED_APP_PASSPHRASE = "EncryptedAppPassphrase"
|
||||
private const val SHARED_PREFS_INITIALIZATION_VECTOR_APP_PASSPHRASE = "InitializationVectorAppPassphrase"
|
||||
private const val SHARED_PREFS_ENCRYPTED_SELF_DESTRUCT_PASSPHRASE = "EncryptedSelfDestructPassphrase"
|
||||
private const val SHARED_PREFS_INITIALIZATION_VECTOR_SELF_DESTRUCT_PASSPHRASE = "InitializationVectorSelfDestructPassphrase"
|
||||
private const val SHARED_PREFS_ENCRYPTION_STARTED_AT = "EncryptionStartedAt"
|
||||
private const val SHARED_PREFS_CONFIRM_DB_UPGRADES = "ConfirmDBUpgrades"
|
||||
private const val SHARED_PREFS_SELF_DESTRUCT = "LocalAuthenticationSelfDestruct"
|
||||
private const val SHARED_PREFS_SELF_DESTRUCT_DISPLAY_NAME = "LocalAuthenticationSelfDestructDisplayName"
|
||||
private const val SHARED_PREFS_CURRENT_THEME = "CurrentTheme"
|
||||
private const val SHARED_PREFS_SYSTEM_DARK_THEME = "SystemDarkTheme"
|
||||
private const val SHARED_PREFS_THEMES = "Themes"
|
||||
private const val SHARED_PREFS_WHATS_NEW_VERSION = "WhatsNewVersion"
|
||||
private const val SHARED_PREFS_LAST_MIGRATED_VERSION_CODE = "LastMigratedVersionCode"
|
||||
private const val SHARED_PREFS_CUSTOM_DISAPPEARING_MESSAGE_TIME = "CustomDisappearingMessageTime"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -326,7 +338,6 @@ open class ChatController(var ctrl: ChatCtrl?, val ntfManager: NtfManager, val a
|
||||
chatModel.userCreated.value = true
|
||||
apiSetIncognito(chatModel.incognito.value)
|
||||
getUserChatData()
|
||||
chatModel.onboardingStage.value = OnboardingStage.OnboardingComplete
|
||||
chatModel.controller.appPrefs.chatLastStart.set(Clock.System.now())
|
||||
chatModel.chatRunning.value = true
|
||||
startReceiver()
|
||||
@@ -433,8 +444,8 @@ open class ChatController(var ctrl: ChatCtrl?, val ntfManager: NtfManager, val a
|
||||
return null
|
||||
}
|
||||
|
||||
suspend fun apiCreateActiveUser(p: Profile): User? {
|
||||
val r = sendCmd(CC.CreateActiveUser(p))
|
||||
suspend fun apiCreateActiveUser(p: Profile?, sameServers: Boolean = false, pastTimestamp: Boolean = false): User? {
|
||||
val r = sendCmd(CC.CreateActiveUser(p, sameServers = sameServers, pastTimestamp = pastTimestamp))
|
||||
if (r is CR.ActiveUser) return r.user
|
||||
else if (
|
||||
r is CR.ChatCmdError && r.chatError is ChatError.ChatErrorStore && r.chatError.storeError is StoreError.DuplicateName ||
|
||||
@@ -570,8 +581,8 @@ open class ChatController(var ctrl: ChatCtrl?, val ntfManager: NtfManager, val a
|
||||
return null
|
||||
}
|
||||
|
||||
suspend fun apiSendMessage(type: ChatType, id: Long, file: String? = null, quotedItemId: Long? = null, mc: MsgContent, live: Boolean = false): AChatItem? {
|
||||
val cmd = CC.ApiSendMessage(type, id, file, quotedItemId, mc, live)
|
||||
suspend fun apiSendMessage(type: ChatType, id: Long, file: String? = null, quotedItemId: Long? = null, mc: MsgContent, live: Boolean = false, ttl: Int? = null): AChatItem? {
|
||||
val cmd = CC.ApiSendMessage(type, id, file, quotedItemId, mc, live, ttl)
|
||||
val r = sendCmd(cmd)
|
||||
return when (r) {
|
||||
is CR.NewChatItem -> r.chatItem
|
||||
@@ -584,6 +595,16 @@ open class ChatController(var ctrl: ChatCtrl?, val ntfManager: NtfManager, val a
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun apiGetChatItemInfo(type: ChatType, id: Long, itemId: Long): ChatItemInfo? {
|
||||
return when (val r = sendCmd(CC.ApiGetChatItemInfo(type, id, itemId))) {
|
||||
is CR.ApiChatItemInfo -> r.chatItemInfo
|
||||
else -> {
|
||||
apiErrorAlert("apiGetChatItemInfo", generalGetString(R.string.error_loading_details), r)
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun apiUpdateChatItem(type: ChatType, id: Long, itemId: Long, mc: MsgContent, live: Boolean = false): AChatItem? {
|
||||
val r = sendCmd(CC.ApiUpdateChatItem(type, id, itemId, mc, live))
|
||||
if (r is CR.ChatItemUpdated) return r.chatItem
|
||||
@@ -591,6 +612,13 @@ open class ChatController(var ctrl: ChatCtrl?, val ntfManager: NtfManager, val a
|
||||
return null
|
||||
}
|
||||
|
||||
suspend fun apiChatItemReaction(type: ChatType, id: Long, itemId: Long, add: Boolean, reaction: MsgReaction): ChatItem? {
|
||||
val r = sendCmd(CC.ApiChatItemReaction(type, id, itemId, add, reaction))
|
||||
if (r is CR.ChatItemReaction) return r.reaction.chatReaction.chatItem
|
||||
Log.e(TAG, "apiUpdateChatItem bad response: ${r.responseType} ${r.details}")
|
||||
return null
|
||||
}
|
||||
|
||||
suspend fun apiDeleteChatItem(type: ChatType, id: Long, itemId: Long, mode: CIDeleteMode): CR.ChatItemDeleted? {
|
||||
val r = sendCmd(CC.ApiDeleteChatItem(type, id, itemId, mode))
|
||||
if (r is CR.ChatItemDeleted) return r
|
||||
@@ -855,6 +883,15 @@ open class ChatController(var ctrl: ChatCtrl?, val ntfManager: NtfManager, val a
|
||||
return null
|
||||
}
|
||||
|
||||
suspend fun apiSetProfileAddress(on: Boolean): User? {
|
||||
val userId = try { currentUserId("apiSetProfileAddress") } catch (e: Exception) { return null }
|
||||
return when (val r = sendCmd(CC.ApiSetProfileAddress(userId, on))) {
|
||||
is CR.UserProfileNoChange -> null
|
||||
is CR.UserProfileUpdated -> r.user
|
||||
else -> throw Exception("failed to set profile address: ${r.responseType} ${r.details}")
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun apiSetContactPrefs(contactId: Long, prefs: ChatPreferences): Contact? {
|
||||
val r = sendCmd(CC.ApiSetContactPrefs(contactId, prefs))
|
||||
if (r is CR.ContactPrefsUpdated) return r.toContact
|
||||
@@ -890,12 +927,12 @@ open class ChatController(var ctrl: ChatCtrl?, val ntfManager: NtfManager, val a
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun apiDeleteUserAddress(): Boolean {
|
||||
val userId = kotlin.runCatching { currentUserId("apiDeleteUserAddress") }.getOrElse { return false }
|
||||
suspend fun apiDeleteUserAddress(): User? {
|
||||
val userId = try { currentUserId("apiDeleteUserAddress") } catch (e: Exception) { return null }
|
||||
val r = sendCmd(CC.ApiDeleteMyAddress(userId))
|
||||
if (r is CR.UserContactLinkDeleted) return true
|
||||
if (r is CR.UserContactLinkDeleted) return r.user
|
||||
Log.e(TAG, "apiDeleteUserAddress bad response: ${r.responseType} ${r.details}")
|
||||
return false
|
||||
return null
|
||||
}
|
||||
|
||||
private suspend fun apiGetUserAddress(): UserContactLinkRec? {
|
||||
@@ -1337,12 +1374,12 @@ open class ChatController(var ctrl: ChatCtrl?, val ntfManager: NtfManager, val a
|
||||
}
|
||||
val file = cItem.file
|
||||
val mc = cItem.content.msgContent
|
||||
if (file != null && file.fileSize <= MAX_IMAGE_SIZE_AUTO_RCV) {
|
||||
val acceptImages = appPrefs.privacyAcceptImages.get()
|
||||
if ((mc is MsgContent.MCImage && acceptImages)
|
||||
|| (mc is MsgContent.MCVoice && ((file.fileSize > MAX_VOICE_SIZE_FOR_SENDING && acceptImages) || cInfo is ChatInfo.Group))) {
|
||||
withApi { receiveFile(r.user, file.fileId) } // TODO check inlineFileMode != IFMSent
|
||||
}
|
||||
if (file != null &&
|
||||
appPrefs.privacyAcceptImages.get() &&
|
||||
((mc is MsgContent.MCImage && file.fileSize <= MAX_IMAGE_SIZE_AUTO_RCV)
|
||||
|| (mc is MsgContent.MCVideo && file.fileSize <= MAX_VIDEO_SIZE_AUTO_RCV)
|
||||
|| (mc is MsgContent.MCVoice && file.fileSize <= MAX_VOICE_SIZE_AUTO_RCV && file.fileStatus !is CIFileStatus.RcvAccepted))) {
|
||||
withApi { receiveFile(r.user, file.fileId) }
|
||||
}
|
||||
if (cItem.showNotification && (!SimplexApp.context.isAppOnForeground || chatModel.chatId.value != cInfo.id)) {
|
||||
ntfManager.notifyMessageReceived(r.user, cInfo, cItem)
|
||||
@@ -1360,6 +1397,11 @@ open class ChatController(var ctrl: ChatCtrl?, val ntfManager: NtfManager, val a
|
||||
}
|
||||
is CR.ChatItemUpdated ->
|
||||
chatItemSimpleUpdate(r.user, r.chatItem)
|
||||
is CR.ChatItemReaction -> {
|
||||
if (active(r.user)) {
|
||||
chatModel.updateChatItem(r.reaction.chatInfo, r.reaction.chatReaction.chatItem)
|
||||
}
|
||||
}
|
||||
is CR.ChatItemDeleted -> {
|
||||
if (!active(r.user)) {
|
||||
if (r.toChatItem == null && r.deletedChatItem.chatItem.isRcvNew && r.deletedChatItem.chatInfo.ntfsEnabled) {
|
||||
@@ -1803,6 +1845,9 @@ open class ChatController(var ctrl: ChatCtrl?, val ntfManager: NtfManager, val a
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* [AppPreferences.networkProxyHostPort] is not changed here, use appPrefs to set it
|
||||
* */
|
||||
fun setNetCfg(cfg: NetCfg) {
|
||||
appPrefs.networkUseSocksProxy.set(cfg.useSocksProxy)
|
||||
appPrefs.networkHostMode.set(cfg.hostMode.name)
|
||||
@@ -1840,7 +1885,7 @@ class SharedPreference<T>(val get: () -> T, set: (T) -> Unit) {
|
||||
sealed class CC {
|
||||
class Console(val cmd: String): CC()
|
||||
class ShowActiveUser: CC()
|
||||
class CreateActiveUser(val profile: Profile): CC()
|
||||
class CreateActiveUser(val profile: Profile?, val sameServers: Boolean, val pastTimestamp: Boolean): CC()
|
||||
class ListUsers: CC()
|
||||
class ApiSetActiveUser(val userId: Long, val viewPwd: String?): CC()
|
||||
class ApiHideUser(val userId: Long, val viewPwd: String): CC()
|
||||
@@ -1860,10 +1905,12 @@ sealed class CC {
|
||||
class ApiStorageEncryption(val config: DBEncryptionConfig): CC()
|
||||
class ApiGetChats(val userId: Long): CC()
|
||||
class ApiGetChat(val type: ChatType, val id: Long, val pagination: ChatPagination, val search: String = ""): CC()
|
||||
class ApiSendMessage(val type: ChatType, val id: Long, val file: String?, val quotedItemId: Long?, val mc: MsgContent, val live: Boolean): CC()
|
||||
class ApiGetChatItemInfo(val type: ChatType, val id: Long, val itemId: Long): CC()
|
||||
class ApiSendMessage(val type: ChatType, val id: Long, val file: String?, val quotedItemId: Long?, val mc: MsgContent, val live: Boolean, val ttl: Int?): CC()
|
||||
class ApiUpdateChatItem(val type: ChatType, val id: Long, val itemId: Long, val mc: MsgContent, val live: Boolean): CC()
|
||||
class ApiDeleteChatItem(val type: ChatType, val id: Long, val itemId: Long, val mode: CIDeleteMode): CC()
|
||||
class ApiDeleteMemberChatItem(val groupId: Long, val groupMemberId: Long, val itemId: Long): CC()
|
||||
class ApiChatItemReaction(val type: ChatType, val id: Long, val itemId: Long, val add: Boolean, val reaction: MsgReaction): CC()
|
||||
class ApiNewGroup(val userId: Long, val groupProfile: GroupProfile): CC()
|
||||
class ApiAddMember(val groupId: Long, val contactId: Long, val memberRole: GroupMemberRole): CC()
|
||||
class ApiJoinGroup(val groupId: Long): CC()
|
||||
@@ -1905,6 +1952,7 @@ sealed class CC {
|
||||
class ApiCreateMyAddress(val userId: Long): CC()
|
||||
class ApiDeleteMyAddress(val userId: Long): CC()
|
||||
class ApiShowMyAddress(val userId: Long): CC()
|
||||
class ApiSetProfileAddress(val userId: Long, val on: Boolean): CC()
|
||||
class ApiAddressAutoAccept(val userId: Long, val autoAccept: AutoAccept?): CC()
|
||||
class ApiSendCallInvitation(val contact: Contact, val callType: CallType): CC()
|
||||
class ApiRejectCall(val contact: Contact): CC()
|
||||
@@ -1924,7 +1972,10 @@ sealed class CC {
|
||||
val cmdString: String get() = when (this) {
|
||||
is Console -> cmd
|
||||
is ShowActiveUser -> "/u"
|
||||
is CreateActiveUser -> "/create user ${profile.displayName} ${profile.fullName}"
|
||||
is CreateActiveUser -> {
|
||||
val user = NewUser(profile, sameServers = sameServers, pastTimestamp = pastTimestamp)
|
||||
"/_create user ${json.encodeToString(user)}"
|
||||
}
|
||||
is ListUsers -> "/users"
|
||||
is ApiSetActiveUser -> "/_user $userId${maybePwd(viewPwd)}"
|
||||
is ApiHideUser -> "/_hide user $userId ${json.encodeToString(viewPwd)}"
|
||||
@@ -1944,10 +1995,15 @@ sealed class CC {
|
||||
is ApiStorageEncryption -> "/_db encryption ${json.encodeToString(config)}"
|
||||
is ApiGetChats -> "/_get chats $userId pcc=on"
|
||||
is ApiGetChat -> "/_get chat ${chatRef(type, id)} ${pagination.cmdString}" + (if (search == "") "" else " search=$search")
|
||||
is ApiSendMessage -> "/_send ${chatRef(type, id)} live=${onOff(live)} json ${json.encodeToString(ComposedMessage(file, quotedItemId, mc))}"
|
||||
is ApiGetChatItemInfo -> "/_get item info ${chatRef(type, id)} $itemId"
|
||||
is ApiSendMessage -> {
|
||||
val ttlStr = if (ttl != null) "$ttl" else "default"
|
||||
"/_send ${chatRef(type, id)} live=${onOff(live)} ttl=${ttlStr} json ${json.encodeToString(ComposedMessage(file, quotedItemId, mc))}"
|
||||
}
|
||||
is ApiUpdateChatItem -> "/_update item ${chatRef(type, id)} $itemId live=${onOff(live)} ${mc.cmdString}"
|
||||
is ApiDeleteChatItem -> "/_delete item ${chatRef(type, id)} $itemId ${mode.deleteMode}"
|
||||
is ApiDeleteMemberChatItem -> "/_delete member item #$groupId $groupMemberId $itemId"
|
||||
is ApiChatItemReaction -> "/_reaction ${chatRef(type, id)} $itemId ${onOff(add)} ${json.encodeToString(reaction)}"
|
||||
is ApiNewGroup -> "/_group $userId ${json.encodeToString(groupProfile)}"
|
||||
is ApiAddMember -> "/_add #$groupId $contactId ${memberRole.memberRole}"
|
||||
is ApiJoinGroup -> "/_join #$groupId"
|
||||
@@ -1989,6 +2045,7 @@ sealed class CC {
|
||||
is ApiCreateMyAddress -> "/_address $userId"
|
||||
is ApiDeleteMyAddress -> "/_delete_address $userId"
|
||||
is ApiShowMyAddress -> "/_show_address $userId"
|
||||
is ApiSetProfileAddress -> "/_profile_address $userId ${onOff(on)}"
|
||||
is ApiAddressAutoAccept -> "/_auto_accept $userId ${AutoAccept.cmdString(autoAccept)}"
|
||||
is ApiAcceptContact -> "/_accept $contactReqId"
|
||||
is ApiRejectContact -> "/_reject $contactReqId"
|
||||
@@ -2029,10 +2086,12 @@ sealed class CC {
|
||||
is ApiStorageEncryption -> "apiStorageEncryption"
|
||||
is ApiGetChats -> "apiGetChats"
|
||||
is ApiGetChat -> "apiGetChat"
|
||||
is ApiGetChatItemInfo -> "apiGetChatItemInfo"
|
||||
is ApiSendMessage -> "apiSendMessage"
|
||||
is ApiUpdateChatItem -> "apiUpdateChatItem"
|
||||
is ApiDeleteChatItem -> "apiDeleteChatItem"
|
||||
is ApiDeleteMemberChatItem -> "apiDeleteMemberChatItem"
|
||||
is ApiChatItemReaction -> "apiChatItemReaction"
|
||||
is ApiNewGroup -> "apiNewGroup"
|
||||
is ApiAddMember -> "apiAddMember"
|
||||
is ApiJoinGroup -> "apiJoinGroup"
|
||||
@@ -2074,6 +2133,7 @@ sealed class CC {
|
||||
is ApiCreateMyAddress -> "apiCreateMyAddress"
|
||||
is ApiDeleteMyAddress -> "apiDeleteMyAddress"
|
||||
is ApiShowMyAddress -> "apiShowMyAddress"
|
||||
is ApiSetProfileAddress -> "apiSetProfileAddress"
|
||||
is ApiAddressAutoAccept -> "apiAddressAutoAccept"
|
||||
is ApiAcceptContact -> "apiAcceptContact"
|
||||
is ApiRejectContact -> "apiRejectContact"
|
||||
@@ -2128,6 +2188,13 @@ sealed class CC {
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class NewUser(
|
||||
val profile: Profile?,
|
||||
val sameServers: Boolean,
|
||||
val pastTimestamp: Boolean
|
||||
)
|
||||
|
||||
sealed class ChatPagination {
|
||||
class Last(val count: Int): ChatPagination()
|
||||
class After(val chatItemId: Long, val count: Int): ChatPagination()
|
||||
@@ -2343,6 +2410,15 @@ data class NetCfg(
|
||||
val useSocksProxy: Boolean get() = socksProxy != null
|
||||
val enableKeepAlive: Boolean get() = tcpKeepAlive != null
|
||||
|
||||
fun withHostPort(hostPort: String?, default: String? = ":9050"): NetCfg {
|
||||
val socksProxy = if (hostPort?.startsWith("localhost:") == true) {
|
||||
hostPort.removePrefix("localhost")
|
||||
} else {
|
||||
hostPort ?: default
|
||||
}
|
||||
return copy(socksProxy = socksProxy)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val defaults: NetCfg =
|
||||
NetCfg(
|
||||
@@ -2430,15 +2506,23 @@ data class ChatSettings(
|
||||
data class FullChatPreferences(
|
||||
val timedMessages: TimedMessagesPreference,
|
||||
val fullDelete: SimpleChatPreference,
|
||||
val reactions: SimpleChatPreference,
|
||||
val voice: SimpleChatPreference,
|
||||
val calls: SimpleChatPreference,
|
||||
) {
|
||||
fun toPreferences(): ChatPreferences = ChatPreferences(timedMessages = timedMessages, fullDelete = fullDelete, voice = voice, calls = calls)
|
||||
fun toPreferences(): ChatPreferences = ChatPreferences(
|
||||
timedMessages = timedMessages,
|
||||
fullDelete = fullDelete,
|
||||
reactions = reactions,
|
||||
voice = voice,
|
||||
calls = calls
|
||||
)
|
||||
|
||||
companion object {
|
||||
val sampleData = FullChatPreferences(
|
||||
timedMessages = TimedMessagesPreference(allow = FeatureAllowed.NO),
|
||||
fullDelete = SimpleChatPreference(allow = FeatureAllowed.NO),
|
||||
reactions = SimpleChatPreference(allow = FeatureAllowed.YES),
|
||||
voice = SimpleChatPreference(allow = FeatureAllowed.YES),
|
||||
calls = SimpleChatPreference(allow = FeatureAllowed.YES),
|
||||
)
|
||||
@@ -2449,6 +2533,7 @@ data class FullChatPreferences(
|
||||
data class ChatPreferences(
|
||||
val timedMessages: TimedMessagesPreference?,
|
||||
val fullDelete: SimpleChatPreference?,
|
||||
val reactions: SimpleChatPreference?,
|
||||
val voice: SimpleChatPreference?,
|
||||
val calls: SimpleChatPreference?,
|
||||
) {
|
||||
@@ -2456,6 +2541,7 @@ data class ChatPreferences(
|
||||
when (feature) {
|
||||
ChatFeature.TimedMessages -> this.copy(timedMessages = TimedMessagesPreference(allow = allowed, ttl = param ?: this.timedMessages?.ttl))
|
||||
ChatFeature.FullDelete -> this.copy(fullDelete = SimpleChatPreference(allow = allowed))
|
||||
ChatFeature.Reactions -> this.copy(reactions = SimpleChatPreference(allow = allowed))
|
||||
ChatFeature.Voice -> this.copy(voice = SimpleChatPreference(allow = allowed))
|
||||
ChatFeature.Calls -> this.copy(calls = SimpleChatPreference(allow = allowed))
|
||||
}
|
||||
@@ -2464,6 +2550,7 @@ data class ChatPreferences(
|
||||
val sampleData = ChatPreferences(
|
||||
timedMessages = TimedMessagesPreference(allow = FeatureAllowed.NO),
|
||||
fullDelete = SimpleChatPreference(allow = FeatureAllowed.NO),
|
||||
reactions = SimpleChatPreference(allow = FeatureAllowed.YES),
|
||||
voice = SimpleChatPreference(allow = FeatureAllowed.YES),
|
||||
calls = SimpleChatPreference(allow = FeatureAllowed.YES),
|
||||
)
|
||||
@@ -2486,62 +2573,115 @@ data class TimedMessagesPreference(
|
||||
): ChatPreference {
|
||||
companion object {
|
||||
val ttlValues: List<Int?>
|
||||
get() = listOf(30, 300, 3600, 8 * 3600, 86400, 7 * 86400, 30 * 86400, null)
|
||||
get() = listOf(600, 3600, 86400, 7 * 86400, 30 * 86400, 3 * 30 * 86400, null)
|
||||
}
|
||||
}
|
||||
|
||||
fun ttlText(ttl: Int?): String {
|
||||
ttl ?: return generalGetString(R.string.feature_off)
|
||||
if (ttl == 0) return String.format(generalGetString(R.string.ttl_sec), 0)
|
||||
val (m_, s) = divMod(ttl, 60)
|
||||
val (h_, m) = divMod(m_, 60)
|
||||
val (d_, h) = divMod(h_, 24)
|
||||
val (mm, d) = divMod(d_, 30)
|
||||
return maybe(mm, if (mm == 1) String.format(generalGetString(R.string.ttl_month), 1) else String.format(generalGetString(R.string.ttl_months), mm)) +
|
||||
maybe(d, if (d == 1) String.format(generalGetString(R.string.ttl_day), 1) else if (d == 7) String.format(generalGetString(R.string.ttl_week), 1) else if (d == 14) String.format(generalGetString(R.string.ttl_weeks), 2) else String.format(generalGetString(R.string.ttl_days), d)) +
|
||||
maybe(h, if (h == 1) String.format(generalGetString(R.string.ttl_hour), 1) else String.format(generalGetString(R.string.ttl_hours), h)) +
|
||||
maybe(m, String.format(generalGetString(R.string.ttl_min), m)) +
|
||||
maybe(s, String.format(generalGetString(R.string.ttl_sec), s))
|
||||
sealed class CustomTimeUnit {
|
||||
object Second: CustomTimeUnit()
|
||||
object Minute: CustomTimeUnit()
|
||||
object Hour: CustomTimeUnit()
|
||||
object Day: CustomTimeUnit()
|
||||
object Week: CustomTimeUnit()
|
||||
object Month: CustomTimeUnit()
|
||||
|
||||
val toSeconds: Int
|
||||
get() =
|
||||
when (this) {
|
||||
Second -> 1
|
||||
Minute -> 60
|
||||
Hour -> 3600
|
||||
Day -> 86400
|
||||
Week -> 7 * 86400
|
||||
Month -> 30 * 86400
|
||||
}
|
||||
|
||||
val text: String
|
||||
get() =
|
||||
when (this) {
|
||||
Second -> generalGetString(R.string.custom_time_unit_seconds)
|
||||
Minute -> generalGetString(R.string.custom_time_unit_minutes)
|
||||
Hour -> generalGetString(R.string.custom_time_unit_hours)
|
||||
Day -> generalGetString(R.string.custom_time_unit_days)
|
||||
Week -> generalGetString(R.string.custom_time_unit_weeks)
|
||||
Month -> generalGetString(R.string.custom_time_unit_months)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun toTimeUnit(seconds: Int): Pair<CustomTimeUnit, Int> {
|
||||
val tryUnits = listOf(Month, Week, Day, Hour, Minute)
|
||||
var selectedUnit: Pair<CustomTimeUnit, Int>? = null
|
||||
for (unit in tryUnits) {
|
||||
val (v, r) = divMod(seconds, unit.toSeconds)
|
||||
if (r == 0) {
|
||||
selectedUnit = Pair(unit, v)
|
||||
break
|
||||
}
|
||||
}
|
||||
return selectedUnit ?: Pair(Second, seconds)
|
||||
}
|
||||
|
||||
fun shortTtlText(ttl: Int?): String {
|
||||
ttl ?: return generalGetString(R.string.feature_off)
|
||||
val m = ttl / 60
|
||||
if (m == 0) {
|
||||
return String.format(generalGetString(R.string.ttl_s), ttl)
|
||||
}
|
||||
val h = m / 60
|
||||
if (h == 0) {
|
||||
return String.format(generalGetString(R.string.ttl_m), m)
|
||||
}
|
||||
val d = h / 24
|
||||
if (d == 0) {
|
||||
return String.format(generalGetString(R.string.ttl_h), h)
|
||||
}
|
||||
val mm = d / 30
|
||||
if (mm > 0) {
|
||||
return String.format(generalGetString(R.string.ttl_mth), mm)
|
||||
}
|
||||
val w = d / 7
|
||||
return if (w == 0 || d % 7 != 0) String.format(generalGetString(R.string.ttl_d), d) else String.format(generalGetString(R.string.ttl_w), w)
|
||||
}
|
||||
|
||||
fun divMod(n: Int, d: Int): Pair<Int, Int> =
|
||||
private fun divMod(n: Int, d: Int): Pair<Int, Int> =
|
||||
n / d to n % d
|
||||
|
||||
fun maybe(n: Int, s: String): String =
|
||||
if (n == 0) "" else s
|
||||
fun toText(seconds: Int): String {
|
||||
val (unit, value) = toTimeUnit(seconds)
|
||||
return when (unit) {
|
||||
Second -> String.format(generalGetString(R.string.ttl_sec), value)
|
||||
Minute -> String.format(generalGetString(R.string.ttl_min), value)
|
||||
Hour -> if (value == 1) String.format(generalGetString(R.string.ttl_hour), 1) else String.format(generalGetString(R.string.ttl_hours), value)
|
||||
Day -> if (value == 1) String.format(generalGetString(R.string.ttl_day), 1) else String.format(generalGetString(R.string.ttl_days), value)
|
||||
Week -> if (value == 1) String.format(generalGetString(R.string.ttl_week), 1) else String.format(generalGetString(R.string.ttl_weeks), value)
|
||||
Month -> if (value == 1) String.format(generalGetString(R.string.ttl_month), 1) else String.format(generalGetString(R.string.ttl_months), value)
|
||||
}
|
||||
}
|
||||
|
||||
fun toShortText(seconds: Int): String {
|
||||
val (unit, value) = toTimeUnit(seconds)
|
||||
return when (unit) {
|
||||
Second -> String.format(generalGetString(R.string.ttl_s), value)
|
||||
Minute -> String.format(generalGetString(R.string.ttl_m), value)
|
||||
Hour -> String.format(generalGetString(R.string.ttl_h), value)
|
||||
Day -> String.format(generalGetString(R.string.ttl_d), value)
|
||||
Week -> String.format(generalGetString(R.string.ttl_w), value)
|
||||
Month -> String.format(generalGetString(R.string.ttl_mth), value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun timeText(seconds: Int?): String {
|
||||
if (seconds == null) {
|
||||
return generalGetString(R.string.feature_off)
|
||||
}
|
||||
if (seconds == 0) {
|
||||
String.format(generalGetString(R.string.ttl_sec), 0)
|
||||
}
|
||||
return CustomTimeUnit.toText(seconds)
|
||||
}
|
||||
|
||||
fun shortTimeText(seconds: Int?): String {
|
||||
if (seconds == null) {
|
||||
return generalGetString(R.string.feature_off)
|
||||
}
|
||||
if (seconds == 0) {
|
||||
String.format(generalGetString(R.string.ttl_s), 0)
|
||||
}
|
||||
return CustomTimeUnit.toShortText(seconds)
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class ContactUserPreferences(
|
||||
val timedMessages: ContactUserPreferenceTimed,
|
||||
val fullDelete: ContactUserPreference,
|
||||
val reactions: ContactUserPreference,
|
||||
val voice: ContactUserPreference,
|
||||
val calls: ContactUserPreference,
|
||||
) {
|
||||
fun toPreferences(): ChatPreferences = ChatPreferences(
|
||||
timedMessages = timedMessages.userPreference.pref,
|
||||
fullDelete = fullDelete.userPreference.pref,
|
||||
reactions = reactions.userPreference.pref,
|
||||
voice = voice.userPreference.pref,
|
||||
calls = calls.userPreference.pref
|
||||
)
|
||||
@@ -2558,6 +2698,11 @@ data class ContactUserPreferences(
|
||||
userPreference = ContactUserPref.User(preference = SimpleChatPreference(allow = FeatureAllowed.NO)),
|
||||
contactPreference = SimpleChatPreference(allow = FeatureAllowed.NO)
|
||||
),
|
||||
reactions = ContactUserPreference(
|
||||
enabled = FeatureEnabled(forUser = true, forContact = true),
|
||||
userPreference = ContactUserPref.User(preference = SimpleChatPreference(allow = FeatureAllowed.YES)),
|
||||
contactPreference = SimpleChatPreference(allow = FeatureAllowed.YES)
|
||||
),
|
||||
voice = ContactUserPreference(
|
||||
enabled = FeatureEnabled(forUser = true, forContact = true),
|
||||
userPreference = ContactUserPref.User(preference = SimpleChatPreference(allow = FeatureAllowed.YES)),
|
||||
@@ -2654,6 +2799,7 @@ interface Feature {
|
||||
enum class ChatFeature: Feature {
|
||||
@SerialName("timedMessages") TimedMessages,
|
||||
@SerialName("fullDelete") FullDelete,
|
||||
@SerialName("reactions") Reactions,
|
||||
@SerialName("voice") Voice,
|
||||
@SerialName("calls") Calls;
|
||||
|
||||
@@ -2671,6 +2817,7 @@ enum class ChatFeature: Feature {
|
||||
get() = when(this) {
|
||||
TimedMessages -> generalGetString(R.string.timed_messages)
|
||||
FullDelete -> generalGetString(R.string.full_deletion)
|
||||
Reactions -> generalGetString(R.string.message_reactions)
|
||||
Voice -> generalGetString(R.string.voice_messages)
|
||||
Calls -> generalGetString(R.string.audio_video_calls)
|
||||
}
|
||||
@@ -2679,6 +2826,7 @@ enum class ChatFeature: Feature {
|
||||
@Composable get() = when(this) {
|
||||
TimedMessages -> painterResource(R.drawable.ic_timer)
|
||||
FullDelete -> painterResource(R.drawable.ic_delete_forever)
|
||||
Reactions -> painterResource(R.drawable.ic_add_reaction)
|
||||
Voice -> painterResource(R.drawable.ic_keyboard_voice)
|
||||
Calls -> painterResource(R.drawable.ic_call)
|
||||
}
|
||||
@@ -2687,6 +2835,7 @@ enum class ChatFeature: Feature {
|
||||
override fun iconFilled(): Painter = when(this) {
|
||||
TimedMessages -> painterResource(R.drawable.ic_timer_filled)
|
||||
FullDelete -> painterResource(R.drawable.ic_delete_forever_filled)
|
||||
Reactions -> painterResource(R.drawable.ic_add_reaction_filled)
|
||||
Voice -> painterResource(R.drawable.ic_keyboard_voice_filled)
|
||||
Calls -> painterResource(R.drawable.ic_call_filled)
|
||||
}
|
||||
@@ -2703,7 +2852,12 @@ enum class ChatFeature: Feature {
|
||||
FeatureAllowed.YES -> generalGetString(R.string.allow_irreversible_message_deletion_only_if)
|
||||
FeatureAllowed.NO -> generalGetString(R.string.contacts_can_mark_messages_for_deletion)
|
||||
}
|
||||
Voice -> when (allowed) {
|
||||
Reactions -> when (allowed) {
|
||||
FeatureAllowed.ALWAYS -> generalGetString(R.string.allow_your_contacts_adding_message_reactions)
|
||||
FeatureAllowed.YES -> generalGetString(R.string.allow_message_reactions_only_if)
|
||||
FeatureAllowed.NO -> generalGetString(R.string.prohibit_message_reactions)
|
||||
}
|
||||
Voice -> when (allowed) {
|
||||
FeatureAllowed.ALWAYS -> generalGetString(R.string.allow_your_contacts_to_send_voice_messages)
|
||||
FeatureAllowed.YES -> generalGetString(R.string.allow_voice_messages_only_if)
|
||||
FeatureAllowed.NO -> generalGetString(R.string.prohibit_sending_voice_messages)
|
||||
@@ -2729,6 +2883,12 @@ enum class ChatFeature: Feature {
|
||||
enabled.forContact -> generalGetString(R.string.only_your_contact_can_delete)
|
||||
else -> generalGetString(R.string.message_deletion_prohibited)
|
||||
}
|
||||
Reactions -> when {
|
||||
enabled.forUser && enabled.forContact -> generalGetString(R.string.both_you_and_your_contact_can_add_message_reactions)
|
||||
enabled.forUser -> generalGetString(R.string.only_you_can_add_message_reactions)
|
||||
enabled.forContact -> generalGetString(R.string.only_your_contact_can_add_message_reactions)
|
||||
else -> generalGetString(R.string.message_reactions_prohibited_in_this_chat)
|
||||
}
|
||||
Voice -> when {
|
||||
enabled.forUser && enabled.forContact -> generalGetString(R.string.both_you_and_your_contact_can_send_voice)
|
||||
enabled.forUser -> generalGetString(R.string.only_you_can_send_voice)
|
||||
@@ -2749,6 +2909,7 @@ enum class GroupFeature: Feature {
|
||||
@SerialName("timedMessages") TimedMessages,
|
||||
@SerialName("directMessages") DirectMessages,
|
||||
@SerialName("fullDelete") FullDelete,
|
||||
@SerialName("reactions") Reactions,
|
||||
@SerialName("voice") Voice;
|
||||
|
||||
override val hasParam: Boolean get() = when(this) {
|
||||
@@ -2761,6 +2922,7 @@ enum class GroupFeature: Feature {
|
||||
TimedMessages -> generalGetString(R.string.timed_messages)
|
||||
DirectMessages -> generalGetString(R.string.direct_messages)
|
||||
FullDelete -> generalGetString(R.string.full_deletion)
|
||||
Reactions -> generalGetString(R.string.message_reactions)
|
||||
Voice -> generalGetString(R.string.voice_messages)
|
||||
}
|
||||
|
||||
@@ -2769,6 +2931,7 @@ enum class GroupFeature: Feature {
|
||||
TimedMessages -> painterResource(R.drawable.ic_timer)
|
||||
DirectMessages -> painterResource(R.drawable.ic_swap_horizontal_circle)
|
||||
FullDelete -> painterResource(R.drawable.ic_delete_forever)
|
||||
Reactions -> painterResource(R.drawable.ic_add_reaction)
|
||||
Voice -> painterResource(R.drawable.ic_keyboard_voice)
|
||||
}
|
||||
|
||||
@@ -2777,6 +2940,7 @@ enum class GroupFeature: Feature {
|
||||
TimedMessages -> painterResource(R.drawable.ic_timer_filled)
|
||||
DirectMessages -> painterResource(R.drawable.ic_swap_horizontal_circle_filled)
|
||||
FullDelete -> painterResource(R.drawable.ic_delete_forever_filled)
|
||||
Reactions -> painterResource(R.drawable.ic_add_reaction_filled)
|
||||
Voice -> painterResource(R.drawable.ic_keyboard_voice_filled)
|
||||
}
|
||||
|
||||
@@ -2795,6 +2959,10 @@ enum class GroupFeature: Feature {
|
||||
GroupFeatureEnabled.ON -> generalGetString(R.string.allow_to_delete_messages)
|
||||
GroupFeatureEnabled.OFF -> generalGetString(R.string.prohibit_message_deletion)
|
||||
}
|
||||
Reactions -> when(enabled) {
|
||||
GroupFeatureEnabled.ON -> generalGetString(R.string.allow_message_reactions)
|
||||
GroupFeatureEnabled.OFF -> generalGetString(R.string.prohibit_message_reactions_group)
|
||||
}
|
||||
Voice -> when(enabled) {
|
||||
GroupFeatureEnabled.ON -> generalGetString(R.string.allow_to_send_voice)
|
||||
GroupFeatureEnabled.OFF -> generalGetString(R.string.prohibit_sending_voice)
|
||||
@@ -2814,6 +2982,10 @@ enum class GroupFeature: Feature {
|
||||
GroupFeatureEnabled.ON -> generalGetString(R.string.group_members_can_delete)
|
||||
GroupFeatureEnabled.OFF -> generalGetString(R.string.message_deletion_prohibited_in_chat)
|
||||
}
|
||||
Reactions -> when(enabled) {
|
||||
GroupFeatureEnabled.ON -> generalGetString(R.string.group_members_can_add_message_reactions)
|
||||
GroupFeatureEnabled.OFF -> generalGetString(R.string.message_reactions_are_prohibited)
|
||||
}
|
||||
Voice -> when(enabled) {
|
||||
GroupFeatureEnabled.ON -> generalGetString(R.string.group_members_can_send_voice)
|
||||
GroupFeatureEnabled.OFF -> generalGetString(R.string.voice_messages_are_prohibited)
|
||||
@@ -2854,6 +3026,7 @@ data class ContactFeaturesAllowed(
|
||||
val timedMessagesAllowed: Boolean,
|
||||
val timedMessagesTTL: Int?,
|
||||
val fullDelete: ContactFeatureAllowed,
|
||||
val reactions: ContactFeatureAllowed,
|
||||
val voice: ContactFeatureAllowed,
|
||||
val calls: ContactFeatureAllowed,
|
||||
) {
|
||||
@@ -2862,6 +3035,7 @@ data class ContactFeaturesAllowed(
|
||||
timedMessagesAllowed = false,
|
||||
timedMessagesTTL = null,
|
||||
fullDelete = ContactFeatureAllowed.UserDefault(FeatureAllowed.NO),
|
||||
reactions = ContactFeatureAllowed.UserDefault(FeatureAllowed.YES),
|
||||
voice = ContactFeatureAllowed.UserDefault(FeatureAllowed.YES),
|
||||
calls = ContactFeatureAllowed.UserDefault(FeatureAllowed.YES),
|
||||
)
|
||||
@@ -2875,6 +3049,7 @@ fun contactUserPrefsToFeaturesAllowed(contactUserPreferences: ContactUserPrefere
|
||||
timedMessagesAllowed = allow == FeatureAllowed.YES || allow == FeatureAllowed.ALWAYS,
|
||||
timedMessagesTTL = pref.pref.ttl,
|
||||
fullDelete = contactUserPrefToFeatureAllowed(contactUserPreferences.fullDelete),
|
||||
reactions = contactUserPrefToFeatureAllowed(contactUserPreferences.reactions),
|
||||
voice = contactUserPrefToFeatureAllowed(contactUserPreferences.voice),
|
||||
calls = contactUserPrefToFeatureAllowed(contactUserPreferences.calls),
|
||||
)
|
||||
@@ -2894,6 +3069,7 @@ fun contactFeaturesAllowedToPrefs(contactFeaturesAllowed: ContactFeaturesAllowed
|
||||
ChatPreferences(
|
||||
timedMessages = TimedMessagesPreference(if (contactFeaturesAllowed.timedMessagesAllowed) FeatureAllowed.YES else FeatureAllowed.NO, contactFeaturesAllowed.timedMessagesTTL),
|
||||
fullDelete = contactFeatureAllowedToPref(contactFeaturesAllowed.fullDelete),
|
||||
reactions = contactFeatureAllowedToPref(contactFeaturesAllowed.reactions),
|
||||
voice = contactFeatureAllowedToPref(contactFeaturesAllowed.voice),
|
||||
calls = contactFeatureAllowedToPref(contactFeaturesAllowed.calls),
|
||||
)
|
||||
@@ -2925,16 +3101,24 @@ data class FullGroupPreferences(
|
||||
val timedMessages: TimedMessagesGroupPreference,
|
||||
val directMessages: GroupPreference,
|
||||
val fullDelete: GroupPreference,
|
||||
val reactions: GroupPreference,
|
||||
val voice: GroupPreference
|
||||
) {
|
||||
fun toGroupPreferences(): GroupPreferences =
|
||||
GroupPreferences(timedMessages = timedMessages, directMessages = directMessages, fullDelete = fullDelete, voice = voice)
|
||||
GroupPreferences(
|
||||
timedMessages = timedMessages,
|
||||
directMessages = directMessages,
|
||||
fullDelete = fullDelete,
|
||||
reactions = reactions,
|
||||
voice = voice
|
||||
)
|
||||
|
||||
companion object {
|
||||
val sampleData = FullGroupPreferences(
|
||||
timedMessages = TimedMessagesGroupPreference(GroupFeatureEnabled.OFF),
|
||||
directMessages = GroupPreference(GroupFeatureEnabled.OFF),
|
||||
fullDelete = GroupPreference(GroupFeatureEnabled.OFF),
|
||||
reactions = GroupPreference(GroupFeatureEnabled.ON),
|
||||
voice = GroupPreference(GroupFeatureEnabled.ON)
|
||||
)
|
||||
}
|
||||
@@ -2945,6 +3129,7 @@ data class GroupPreferences(
|
||||
val timedMessages: TimedMessagesGroupPreference?,
|
||||
val directMessages: GroupPreference?,
|
||||
val fullDelete: GroupPreference?,
|
||||
val reactions: GroupPreference?,
|
||||
val voice: GroupPreference?
|
||||
) {
|
||||
companion object {
|
||||
@@ -2952,6 +3137,7 @@ data class GroupPreferences(
|
||||
timedMessages = TimedMessagesGroupPreference(GroupFeatureEnabled.OFF),
|
||||
directMessages = GroupPreference(GroupFeatureEnabled.OFF),
|
||||
fullDelete = GroupPreference(GroupFeatureEnabled.OFF),
|
||||
reactions = GroupPreference(GroupFeatureEnabled.ON),
|
||||
voice = GroupPreference(GroupFeatureEnabled.ON)
|
||||
)
|
||||
}
|
||||
@@ -3081,6 +3267,7 @@ sealed class CR {
|
||||
@Serializable @SerialName("chatStopped") class ChatStopped: CR()
|
||||
@Serializable @SerialName("apiChats") class ApiChats(val user: User, val chats: List<Chat>): CR()
|
||||
@Serializable @SerialName("apiChat") class ApiChat(val user: User, val chat: Chat): CR()
|
||||
@Serializable @SerialName("chatItemInfo") class ApiChatItemInfo(val user: User, val chatItem: AChatItem, val chatItemInfo: ChatItemInfo): CR()
|
||||
@Serializable @SerialName("userProtoServers") class UserProtoServers(val user: User, val servers: UserProtocolServers): CR()
|
||||
@Serializable @SerialName("serverTestResult") class ServerTestResult(val user: User, val testServer: String, val testFailure: ProtocolTestFailure? = null): CR()
|
||||
@Serializable @SerialName("chatItemTTL") class ChatItemTTL(val user: User, val chatItemTTL: Long? = null): CR()
|
||||
@@ -3123,6 +3310,7 @@ sealed class CR {
|
||||
@Serializable @SerialName("newChatItem") class NewChatItem(val user: User, val chatItem: AChatItem): CR()
|
||||
@Serializable @SerialName("chatItemStatusUpdated") class ChatItemStatusUpdated(val user: User, val chatItem: AChatItem): CR()
|
||||
@Serializable @SerialName("chatItemUpdated") class ChatItemUpdated(val user: User, val chatItem: AChatItem): CR()
|
||||
@Serializable @SerialName("chatItemReaction") class ChatItemReaction(val user: User, val added: Boolean, val reaction: ACIReaction): CR()
|
||||
@Serializable @SerialName("chatItemDeleted") class ChatItemDeleted(val user: User, val deletedChatItem: AChatItem, val toChatItem: AChatItem? = null, val byUser: Boolean): CR()
|
||||
@Serializable @SerialName("contactsList") class ContactsList(val user: User, val contacts: List<Contact>): CR()
|
||||
// group events
|
||||
@@ -3192,6 +3380,7 @@ sealed class CR {
|
||||
is ChatStopped -> "chatStopped"
|
||||
is ApiChats -> "apiChats"
|
||||
is ApiChat -> "apiChat"
|
||||
is ApiChatItemInfo -> "chatItemInfo"
|
||||
is UserProtoServers -> "userProtoServers"
|
||||
is ServerTestResult -> "serverTestResult"
|
||||
is ChatItemTTL -> "chatItemTTL"
|
||||
@@ -3234,6 +3423,7 @@ sealed class CR {
|
||||
is NewChatItem -> "newChatItem"
|
||||
is ChatItemStatusUpdated -> "chatItemStatusUpdated"
|
||||
is ChatItemUpdated -> "chatItemUpdated"
|
||||
is ChatItemReaction -> "chatItemReaction"
|
||||
is ChatItemDeleted -> "chatItemDeleted"
|
||||
is ContactsList -> "contactsList"
|
||||
is GroupCreated -> "groupCreated"
|
||||
@@ -3300,6 +3490,7 @@ sealed class CR {
|
||||
is ChatStopped -> noDetails()
|
||||
is ApiChats -> withUser(user, json.encodeToString(chats))
|
||||
is ApiChat -> withUser(user, json.encodeToString(chat))
|
||||
is ApiChatItemInfo -> withUser(user, "chatItem: ${json.encodeToString(AChatItem)}\n${json.encodeToString(chatItemInfo)}")
|
||||
is UserProtoServers -> withUser(user, "servers: ${json.encodeToString(servers)}")
|
||||
is ServerTestResult -> withUser(user, "server: $testServer\nresult: ${json.encodeToString(testFailure)}")
|
||||
is ChatItemTTL -> withUser(user, json.encodeToString(chatItemTTL))
|
||||
@@ -3343,6 +3534,7 @@ sealed class CR {
|
||||
is NewChatItem -> withUser(user, json.encodeToString(chatItem))
|
||||
is ChatItemStatusUpdated -> withUser(user, json.encodeToString(chatItem))
|
||||
is ChatItemUpdated -> withUser(user, json.encodeToString(chatItem))
|
||||
is ChatItemReaction -> withUser(user, "added: $added\n${json.encodeToString(reaction)}")
|
||||
is ChatItemDeleted -> withUser(user, "deletedChatItem:\n${json.encodeToString(deletedChatItem)}\ntoChatItem:\n${json.encodeToString(toChatItem)}\nbyUser: $byUser")
|
||||
is ContactsList -> withUser(user, json.encodeToString(contacts))
|
||||
is GroupCreated -> withUser(user, json.encodeToString(groupInfo))
|
||||
|
||||
@@ -21,7 +21,6 @@ val ToolbarDark = Color(80, 80, 80, 12)
|
||||
val SettingsSecondaryLight = Color(200, 196, 195, 90)
|
||||
val GroupDark = Color(80, 80, 80, 60)
|
||||
val IncomingCallLight = Color(239, 237, 236, 255)
|
||||
val IncomingCallDark = Color(34, 30, 29, 255)
|
||||
val WarningOrange = Color(255, 127, 0, 255)
|
||||
val WarningYellow = Color(255, 192, 0, 255)
|
||||
val FileLight = Color(183, 190, 199, 255)
|
||||
|
||||
@@ -16,6 +16,7 @@ import chat.simplex.app.views.helpers.*
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import okhttp3.internal.toHexString
|
||||
|
||||
enum class DefaultTheme {
|
||||
SYSTEM, LIGHT, DARK, SIMPLEX;
|
||||
@@ -128,11 +129,29 @@ data class ThemeColors(
|
||||
receivedMessage = receivedMessage?.colorFromReadableHex() ?: baseColors.receivedMessage,
|
||||
)
|
||||
}
|
||||
|
||||
fun withFilledColors(base: DefaultTheme): ThemeColors {
|
||||
val c = toColors(base)
|
||||
val ac = toAppColors(base)
|
||||
return ThemeColors(
|
||||
primary = c.primary.toReadableHex(),
|
||||
primaryVariant = c.primaryVariant.toReadableHex(),
|
||||
secondary = c.secondary.toReadableHex(),
|
||||
secondaryVariant = c.secondaryVariant.toReadableHex(),
|
||||
background = c.background.toReadableHex(),
|
||||
surface = c.surface.toReadableHex(),
|
||||
title = ac.title.toReadableHex(),
|
||||
sentMessage = ac.sentMessage.toReadableHex(),
|
||||
receivedMessage = ac.receivedMessage.toReadableHex()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun String.colorFromReadableHex(): Color =
|
||||
Color(this.replace("#", "").toLongOrNull(16) ?: Color.White.toArgb().toLong())
|
||||
|
||||
private fun Color.toReadableHex(): String = "#" + toArgb().toHexString()
|
||||
|
||||
@Serializable
|
||||
data class ThemeOverrides (
|
||||
val base: DefaultTheme,
|
||||
@@ -153,9 +172,6 @@ data class ThemeOverrides (
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class ThemeData (val colors: ThemeColors)
|
||||
|
||||
fun Modifier.themedBackground(baseTheme: DefaultTheme = CurrentColors.value.base, shape: Shape = RectangleShape): Modifier {
|
||||
return if (baseTheme == DefaultTheme.SIMPLEX) {
|
||||
this.background(brush = Brush.linearGradient(
|
||||
|
||||
@@ -44,19 +44,16 @@ object ThemeManager {
|
||||
return ActiveTheme(themeName, baseTheme.first, theme.colors.toColors(theme.base), theme.colors.toAppColors(theme.base))
|
||||
}
|
||||
|
||||
fun currentThemeData(darkForSystemTheme: Boolean): ThemeData {
|
||||
val t = currentColors(darkForSystemTheme)
|
||||
return ThemeData(colors = ThemeColors(
|
||||
primary = t.colors.primary.toReadableHex(),
|
||||
primaryVariant = t.colors.primaryVariant.toReadableHex(),
|
||||
secondary = t.colors.secondary.toReadableHex(),
|
||||
secondaryVariant = t.colors.secondaryVariant.toReadableHex(),
|
||||
background = t.colors.background.toReadableHex(),
|
||||
surface = t.colors.surface.toReadableHex(),
|
||||
title = t.appColors.title.toReadableHex(),
|
||||
sentMessage = t.appColors.sentMessage.toReadableHex(),
|
||||
receivedMessage = t.appColors.receivedMessage.toReadableHex()
|
||||
))
|
||||
fun currentThemeOverridesForExport(darkForSystemTheme: Boolean): ThemeOverrides {
|
||||
val themeName = appPrefs.currentTheme.get()!!
|
||||
val nonSystemThemeName = if (themeName != DefaultTheme.SYSTEM.name) {
|
||||
themeName
|
||||
} else {
|
||||
if (darkForSystemTheme) appPrefs.systemDarkTheme.get()!! else DefaultTheme.LIGHT.name
|
||||
}
|
||||
val overrides = appPrefs.themeOverrides.get().toMutableMap()
|
||||
val nonFilledTheme = overrides[nonSystemThemeName] ?: ThemeOverrides(base = CurrentColors.value.base, colors = ThemeColors())
|
||||
return nonFilledTheme.copy(colors = nonFilledTheme.colors.withFilledColors(CurrentColors.value.base))
|
||||
}
|
||||
|
||||
// colors, default theme enum, localized name of theme
|
||||
@@ -128,11 +125,12 @@ object ThemeManager {
|
||||
CurrentColors.value = currentColors(!CurrentColors.value.colors.isLight)
|
||||
}
|
||||
|
||||
fun saveAndApplyThemeData(name: String, theme: ThemeData, darkForSystemTheme: Boolean) {
|
||||
fun saveAndApplyThemeOverrides(theme: ThemeOverrides, darkForSystemTheme: Boolean) {
|
||||
val overrides = appPrefs.themeOverrides.get().toMutableMap()
|
||||
val prevValue = overrides[name] ?: ThemeOverrides(base = CurrentColors.value.base, colors = ThemeColors())
|
||||
overrides[name] = prevValue.copy(colors = theme.colors)
|
||||
val prevValue = overrides[theme.base.name] ?: ThemeOverrides(base = CurrentColors.value.base, colors = ThemeColors())
|
||||
overrides[theme.base.name] = prevValue.copy(colors = theme.colors)
|
||||
appPrefs.themeOverrides.set(overrides)
|
||||
appPrefs.currentTheme.set(theme.base.name)
|
||||
CurrentColors.value = currentColors(!CurrentColors.value.colors.isLight)
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,11 @@ val Typography = Typography(
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 18.5.sp
|
||||
),
|
||||
h4 = TextStyle(
|
||||
fontFamily = Inter,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 17.5.sp
|
||||
),
|
||||
body1 = TextStyle(
|
||||
fontFamily = Inter,
|
||||
fontWeight = FontWeight.Normal,
|
||||
|
||||
@@ -86,7 +86,7 @@ fun TerminalLayout(
|
||||
userIsObserver = false,
|
||||
userCanSend = true,
|
||||
allowVoiceToContact = {},
|
||||
sendMessage = sendCommand,
|
||||
sendMessage = { sendCommand() },
|
||||
sendLiveMessage = null,
|
||||
updateLiveMessage = null,
|
||||
onMessageChange = ::onMessageChange,
|
||||
@@ -99,8 +99,8 @@ fun TerminalLayout(
|
||||
Surface(
|
||||
modifier = Modifier
|
||||
.padding(contentPadding)
|
||||
.fillMaxWidth()
|
||||
.themedBackground()
|
||||
.fillMaxWidth(),
|
||||
color = MaterialTheme.colors.background
|
||||
) {
|
||||
TerminalLog(terminalItems)
|
||||
}
|
||||
|
||||
@@ -44,77 +44,75 @@ fun CreateProfilePanel(chatModel: ChatModel, close: () -> Unit) {
|
||||
val fullName = rememberSaveable { mutableStateOf("") }
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
|
||||
Surface(Modifier.background(MaterialTheme.colors.onBackground)) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState())
|
||||
) {
|
||||
/*CloseSheetBar(close = {
|
||||
if (chatModel.users.isEmpty()) {
|
||||
chatModel.onboardingStage.value = OnboardingStage.Step1_SimpleXInfo
|
||||
} else {
|
||||
close()
|
||||
}
|
||||
})*/
|
||||
Column(Modifier.padding(horizontal = DEFAULT_PADDING * 1f)) {
|
||||
AppBarTitle(stringResource(R.string.create_profile))
|
||||
ReadableText(R.string.your_profile_is_stored_on_your_device, TextAlign.Center, padding = PaddingValues())
|
||||
ReadableText(R.string.profile_is_only_shared_with_your_contacts, TextAlign.Center)
|
||||
Spacer(Modifier.height(DEFAULT_PADDING * 1.5f))
|
||||
Row(Modifier.padding(bottom = DEFAULT_PADDING_HALF).fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
|
||||
Text(
|
||||
stringResource(R.string.display_name),
|
||||
fontSize = 16.sp
|
||||
)
|
||||
if (!isValidDisplayName(displayName.value)) {
|
||||
Text(
|
||||
stringResource(R.string.no_spaces),
|
||||
fontSize = 16.sp,
|
||||
color = Color.Red
|
||||
)
|
||||
}
|
||||
}
|
||||
ProfileNameField(displayName, "", ::isValidDisplayName, focusRequester)
|
||||
Spacer(Modifier.height(DEFAULT_PADDING))
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState())
|
||||
) {
|
||||
/*CloseSheetBar(close = {
|
||||
if (chatModel.users.isEmpty()) {
|
||||
chatModel.onboardingStage.value = OnboardingStage.Step1_SimpleXInfo
|
||||
} else {
|
||||
close()
|
||||
}
|
||||
})*/
|
||||
Column(Modifier.padding(horizontal = DEFAULT_PADDING)) {
|
||||
AppBarTitle(stringResource(R.string.create_profile), bottomPadding = DEFAULT_PADDING)
|
||||
ReadableText(R.string.your_profile_is_stored_on_your_device, TextAlign.Center, padding = PaddingValues(), style = MaterialTheme.typography.body1)
|
||||
ReadableText(R.string.profile_is_only_shared_with_your_contacts, TextAlign.Center, style = MaterialTheme.typography.body1)
|
||||
Spacer(Modifier.height(DEFAULT_PADDING))
|
||||
Row(Modifier.padding(bottom = DEFAULT_PADDING_HALF).fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
|
||||
Text(
|
||||
stringResource(R.string.full_name_optional__prompt),
|
||||
fontSize = 16.sp,
|
||||
modifier = Modifier.padding(bottom = DEFAULT_PADDING_HALF)
|
||||
stringResource(R.string.display_name),
|
||||
fontSize = 16.sp
|
||||
)
|
||||
ProfileNameField(fullName, "", ::isValidDisplayName)
|
||||
}
|
||||
Spacer(Modifier.fillMaxHeight().weight(1f))
|
||||
Row {
|
||||
if (chatModel.users.isEmpty()) {
|
||||
SimpleButtonDecorated(
|
||||
text = stringResource(R.string.about_simplex),
|
||||
icon = painterResource(R.drawable.ic_arrow_back_ios_new),
|
||||
textDecoration = TextDecoration.None,
|
||||
fontWeight = FontWeight.Medium
|
||||
) { chatModel.onboardingStage.value = OnboardingStage.Step1_SimpleXInfo }
|
||||
}
|
||||
Spacer(Modifier.fillMaxWidth().weight(1f))
|
||||
val enabled = displayName.value.isNotEmpty() && isValidDisplayName(displayName.value)
|
||||
val createModifier: Modifier
|
||||
val createColor: Color
|
||||
if (enabled) {
|
||||
createModifier = Modifier.clickable { createProfile(chatModel, displayName.value, fullName.value, close) }.padding(8.dp)
|
||||
createColor = MaterialTheme.colors.primary
|
||||
} else {
|
||||
createModifier = Modifier.padding(8.dp)
|
||||
createColor = MaterialTheme.colors.secondary
|
||||
}
|
||||
Surface(shape = RoundedCornerShape(20.dp)) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically, modifier = createModifier) {
|
||||
Text(stringResource(R.string.create_profile_button), style = MaterialTheme.typography.caption, color = createColor, fontWeight = FontWeight.Medium)
|
||||
Icon(painterResource(R.drawable.ic_arrow_forward_ios), stringResource(R.string.create_profile_button), tint = createColor)
|
||||
}
|
||||
if (!isValidDisplayName(displayName.value)) {
|
||||
Text(
|
||||
stringResource(R.string.no_spaces),
|
||||
fontSize = 16.sp,
|
||||
color = Color.Red
|
||||
)
|
||||
}
|
||||
}
|
||||
ProfileNameField(displayName, "", ::isValidDisplayName, focusRequester)
|
||||
Spacer(Modifier.height(DEFAULT_PADDING))
|
||||
Text(
|
||||
stringResource(R.string.full_name_optional__prompt),
|
||||
fontSize = 16.sp,
|
||||
modifier = Modifier.padding(bottom = DEFAULT_PADDING_HALF)
|
||||
)
|
||||
ProfileNameField(fullName, "", ::isValidDisplayName)
|
||||
}
|
||||
Spacer(Modifier.fillMaxHeight().weight(1f))
|
||||
Row {
|
||||
if (chatModel.users.isEmpty()) {
|
||||
SimpleButtonDecorated(
|
||||
text = stringResource(R.string.about_simplex),
|
||||
icon = painterResource(R.drawable.ic_arrow_back_ios_new),
|
||||
textDecoration = TextDecoration.None,
|
||||
fontWeight = FontWeight.Medium
|
||||
) { chatModel.onboardingStage.value = OnboardingStage.Step1_SimpleXInfo }
|
||||
}
|
||||
Spacer(Modifier.fillMaxWidth().weight(1f))
|
||||
val enabled = displayName.value.isNotEmpty() && isValidDisplayName(displayName.value)
|
||||
val createModifier: Modifier
|
||||
val createColor: Color
|
||||
if (enabled) {
|
||||
createModifier = Modifier.clickable { createProfile(chatModel, displayName.value, fullName.value, close) }.padding(8.dp)
|
||||
createColor = MaterialTheme.colors.primary
|
||||
} else {
|
||||
createModifier = Modifier.padding(8.dp)
|
||||
createColor = MaterialTheme.colors.secondary
|
||||
}
|
||||
Surface(shape = RoundedCornerShape(20.dp), color = Color.Transparent) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically, modifier = createModifier) {
|
||||
Text(stringResource(R.string.create_profile_button), style = MaterialTheme.typography.caption, color = createColor, fontWeight = FontWeight.Medium)
|
||||
Icon(painterResource(R.drawable.ic_arrow_forward_ios), stringResource(R.string.create_profile_button), tint = createColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
delay(300)
|
||||
focusRequester.requestFocus()
|
||||
}
|
||||
LaunchedEffect(Unit) {
|
||||
delay(300)
|
||||
focusRequester.requestFocus()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -127,13 +125,17 @@ fun createProfile(chatModel: ChatModel, displayName: String, fullName: String, c
|
||||
chatModel.currentUser.value = user
|
||||
if (chatModel.users.isEmpty()) {
|
||||
chatModel.controller.startChat(user)
|
||||
chatModel.onboardingStage.value = OnboardingStage.Step3_SetNotificationsMode
|
||||
SimplexApp.context.chatModel.controller.ntfManager.createNtfChannelsMaybeShowAlert()
|
||||
chatModel.controller.appPrefs.onboardingStage.set(OnboardingStage.Step3_CreateSimpleXAddress)
|
||||
chatModel.onboardingStage.value = OnboardingStage.Step3_CreateSimpleXAddress
|
||||
} else {
|
||||
val users = chatModel.controller.listUsers()
|
||||
chatModel.users.clear()
|
||||
chatModel.users.addAll(users)
|
||||
chatModel.controller.getUserChatData()
|
||||
// the next two lines are only needed for failure case when because of the database error the app gets stuck on on-boarding screen,
|
||||
// this will get it unstuck.
|
||||
chatModel.controller.appPrefs.onboardingStage.set(OnboardingStage.OnboardingComplete)
|
||||
chatModel.onboardingStage.value = OnboardingStage.OnboardingComplete
|
||||
close()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ class CallManager(val chatModel: ChatModel) {
|
||||
}
|
||||
|
||||
fun acceptIncomingCall(invitation: RcvCallInvitation) {
|
||||
ModalManager.shared.closeModals()
|
||||
val call = chatModel.activeCall.value
|
||||
if (call == null) {
|
||||
justAcceptIncomingCall(invitation = invitation)
|
||||
|
||||
@@ -185,10 +185,12 @@ fun ActiveCallView(chatModel: ChatModel) {
|
||||
activity.volumeControlStream = AudioManager.STREAM_VOICE_CALL
|
||||
// Lock orientation to portrait in order to have good experience with calls
|
||||
activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
||||
chatModel.activeCallViewIsVisible.value = true
|
||||
onDispose {
|
||||
activity.volumeControlStream = prevVolumeControlStream
|
||||
// Unlock orientation
|
||||
activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
|
||||
chatModel.activeCallViewIsVisible.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,8 +97,9 @@ fun IncomingCallActivityView(m: ChatModel) {
|
||||
SimpleXTheme {
|
||||
Surface(
|
||||
Modifier
|
||||
.themedBackground()
|
||||
.fillMaxSize()) {
|
||||
.fillMaxSize(),
|
||||
color = MaterialTheme.colors.background
|
||||
) {
|
||||
if (showCallView) {
|
||||
Box {
|
||||
ActiveCallView(m)
|
||||
@@ -226,8 +227,9 @@ fun PreviewIncomingCallLockScreenAlert() {
|
||||
SimpleXTheme(true) {
|
||||
Surface(
|
||||
Modifier
|
||||
.themedBackground()
|
||||
.fillMaxSize()) {
|
||||
.fillMaxSize(),
|
||||
color = MaterialTheme.colors.background
|
||||
) {
|
||||
IncomingCallLockScreenAlertLayout(
|
||||
invitation = RcvCallInvitation(
|
||||
user = User.sampleData,
|
||||
|
||||
@@ -50,13 +50,13 @@ fun IncomingCallAlertLayout(
|
||||
ignoreCall: () -> Unit,
|
||||
acceptCall: () -> Unit
|
||||
) {
|
||||
val color = if (isInDarkTheme()) IncomingCallDark else IncomingCallLight
|
||||
val color = if (isInDarkTheme()) MaterialTheme.colors.surface else IncomingCallLight
|
||||
Column(Modifier.fillMaxWidth().background(color).padding(top = DEFAULT_PADDING, bottom = DEFAULT_PADDING, start = DEFAULT_PADDING, end = 8.dp)) {
|
||||
IncomingCallInfo(invitation, chatModel)
|
||||
Spacer(Modifier.height(8.dp))
|
||||
Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceBetween) {
|
||||
Row(Modifier.fillMaxWidth().weight(1f), verticalAlignment = Alignment.CenterVertically) {
|
||||
ProfilePreview(profileOf = invitation.contact, size = 64.dp, color = Color.White)
|
||||
ProfilePreview(profileOf = invitation.contact, size = 64.dp)
|
||||
}
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
CallButton(stringResource(R.string.reject), painterResource(R.drawable.ic_call_end_filled), Color.Red, rejectCall)
|
||||
@@ -78,7 +78,7 @@ fun IncomingCallInfo(invitation: RcvCallInvitation, chatModel: ChatModel) {
|
||||
if (invitation.callType.media == CallMediaType.Video) CallIcon(painterResource(R.drawable.ic_videocam_filled), stringResource(R.string.icon_descr_video_call))
|
||||
else CallIcon(painterResource(R.drawable.ic_call_filled), stringResource(R.string.icon_descr_audio_call))
|
||||
Spacer(Modifier.width(4.dp))
|
||||
Text(invitation.callTypeText)
|
||||
Text(invitation.callTypeText, color = MaterialTheme.colors.onBackground)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,8 +5,11 @@ import InfoRowEllipsis
|
||||
import SectionBottomSpacer
|
||||
import SectionDividerSpaced
|
||||
import SectionItemView
|
||||
import SectionItemViewWithIcon
|
||||
import SectionSpacer
|
||||
import SectionTextFooter
|
||||
import SectionView
|
||||
import TextIconSpaced
|
||||
import android.widget.Toast
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.*
|
||||
@@ -18,8 +21,7 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.ClipboardManager
|
||||
import androidx.compose.ui.platform.LocalClipboardManager
|
||||
import androidx.compose.ui.platform.*
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
@@ -34,6 +36,7 @@ import chat.simplex.app.SimplexApp
|
||||
import chat.simplex.app.model.*
|
||||
import chat.simplex.app.ui.theme.*
|
||||
import chat.simplex.app.views.helpers.*
|
||||
import chat.simplex.app.views.newchat.QRCode
|
||||
import chat.simplex.app.views.usersettings.*
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.*
|
||||
@@ -195,6 +198,15 @@ fun ChatInfoLayout(
|
||||
}
|
||||
|
||||
SectionDividerSpaced()
|
||||
if (contact.contactLink != null) {
|
||||
val context = LocalContext.current
|
||||
SectionView(stringResource(R.string.address_section_title).uppercase()) {
|
||||
QRCode(contact.contactLink, Modifier.padding(horizontal = DEFAULT_PADDING, vertical = DEFAULT_PADDING_HALF).aspectRatio(1f))
|
||||
ShareAddressButton { shareText(context, contact.contactLink) }
|
||||
SectionTextFooter(stringResource(R.string.you_can_share_this_address_with_your_contacts).format(contact.displayName))
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
}
|
||||
|
||||
SectionView(title = stringResource(R.string.conn_stats_section_title_servers)) {
|
||||
SwitchAddressButton(switchContactAddress)
|
||||
@@ -416,6 +428,17 @@ private fun DeleteContactButton(onClick: () -> Unit) {
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ShareAddressButton(onClick: () -> Unit) {
|
||||
SettingsActionItem(
|
||||
painterResource(R.drawable.ic_share_filled),
|
||||
stringResource(R.string.share_address),
|
||||
onClick,
|
||||
iconColor = MaterialTheme.colors.primary,
|
||||
textColor = MaterialTheme.colors.primary,
|
||||
)
|
||||
}
|
||||
|
||||
private fun setContactAlias(contactApiId: Long, localAlias: String, chatModel: ChatModel) = withApi {
|
||||
chatModel.controller.apiSetContactAlias(contactApiId, localAlias)?.let {
|
||||
chatModel.updateContact(it)
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
package chat.simplex.app.views.chat
|
||||
|
||||
import InfoRow
|
||||
import SectionBottomSpacer
|
||||
import SectionDividerSpaced
|
||||
import SectionView
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontStyle
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import chat.simplex.app.R
|
||||
import chat.simplex.app.model.*
|
||||
import chat.simplex.app.ui.theme.CurrentColors
|
||||
import chat.simplex.app.ui.theme.DEFAULT_PADDING
|
||||
import chat.simplex.app.views.chat.item.ItemAction
|
||||
import chat.simplex.app.views.chat.item.MarkdownText
|
||||
import chat.simplex.app.views.helpers.*
|
||||
|
||||
@Composable
|
||||
fun ChatItemInfoView(ci: ChatItem, ciInfo: ChatItemInfo, devTools: Boolean) {
|
||||
val sent = ci.chatDir.sent
|
||||
val appColors = CurrentColors.collectAsState().value.appColors
|
||||
val itemColor = if (sent) appColors.sentMessage else appColors.receivedMessage
|
||||
val context = LocalContext.current
|
||||
val uriHandler = LocalUriHandler.current
|
||||
|
||||
@Composable
|
||||
fun ItemVersionView(ciVersion: ChatItemVersion, current: Boolean) {
|
||||
val showMenu = remember { mutableStateOf(false) }
|
||||
val text = ciVersion.msgContent.text
|
||||
|
||||
@Composable
|
||||
fun VersionText() {
|
||||
if (text != "") {
|
||||
MarkdownText(
|
||||
text, if (text.isEmpty()) emptyList() else ciVersion.formattedText,
|
||||
linkMode = SimplexLinkMode.DESCRIPTION, uriHandler = uriHandler,
|
||||
onLinkLongClick = { showMenu.value = true }
|
||||
)
|
||||
} else {
|
||||
Text(
|
||||
generalGetString(R.string.item_info_no_text),
|
||||
style = MaterialTheme.typography.body1.copy(color = MaterialTheme.colors.secondary, lineHeight = 22.sp, fontStyle = FontStyle.Italic)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
Box(
|
||||
Modifier.clip(RoundedCornerShape(18.dp)).background(itemColor).padding(bottom = 3.dp)
|
||||
.combinedClickable(onLongClick = { showMenu.value = true }, onClick = {})
|
||||
) {
|
||||
Box(Modifier.padding(vertical = 6.dp, horizontal = 12.dp)) {
|
||||
VersionText()
|
||||
}
|
||||
}
|
||||
Row(Modifier.padding(start = 12.dp, top = 3.dp, bottom = 16.dp)) {
|
||||
Text(
|
||||
localTimestamp(ciVersion.itemVersionTs),
|
||||
fontSize = 12.sp,
|
||||
color = MaterialTheme.colors.secondary,
|
||||
modifier = Modifier.padding(end = 6.dp)
|
||||
)
|
||||
if (current && ci.meta.itemDeleted == null) {
|
||||
Text(
|
||||
stringResource(R.string.item_info_current),
|
||||
fontSize = 12.sp,
|
||||
color = MaterialTheme.colors.secondary
|
||||
)
|
||||
}
|
||||
}
|
||||
if (text != "") {
|
||||
DefaultDropdownMenu(showMenu) {
|
||||
ItemAction(stringResource(R.string.share_verb), painterResource(R.drawable.ic_share), onClick = {
|
||||
shareText(context, text)
|
||||
showMenu.value = false
|
||||
})
|
||||
ItemAction(stringResource(R.string.copy_verb), painterResource(R.drawable.ic_content_copy), onClick = {
|
||||
copyText(context, text)
|
||||
showMenu.value = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column(Modifier.fillMaxWidth().verticalScroll(rememberScrollState())) {
|
||||
AppBarTitle(stringResource(if (sent) R.string.sent_message else R.string.received_message))
|
||||
SectionView {
|
||||
InfoRow(stringResource(R.string.info_row_sent_at), localTimestamp(ci.meta.itemTs))
|
||||
if (!sent) {
|
||||
InfoRow(stringResource(R.string.info_row_received_at), localTimestamp(ci.meta.createdAt))
|
||||
}
|
||||
when (val itemDeleted = ci.meta.itemDeleted) {
|
||||
is CIDeleted.Deleted ->
|
||||
if (itemDeleted.deletedTs != null) {
|
||||
InfoRow(stringResource(R.string.info_row_deleted_at), localTimestamp(itemDeleted.deletedTs))
|
||||
}
|
||||
is CIDeleted.Moderated ->
|
||||
if (itemDeleted.deletedTs != null) {
|
||||
InfoRow(stringResource(R.string.info_row_moderated_at), localTimestamp(itemDeleted.deletedTs))
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
val deleteAt = ci.meta.itemTimed?.deleteAt
|
||||
if (deleteAt != null) {
|
||||
InfoRow(stringResource(R.string.info_row_disappears_at), localTimestamp(deleteAt))
|
||||
}
|
||||
if (devTools) {
|
||||
InfoRow(stringResource(R.string.info_row_database_id), ci.meta.itemId.toString())
|
||||
InfoRow(stringResource(R.string.info_row_updated_at), localTimestamp(ci.meta.updatedAt))
|
||||
}
|
||||
}
|
||||
val versions = ciInfo.itemVersions
|
||||
if (versions.isNotEmpty()) {
|
||||
SectionDividerSpaced(maxTopPadding = false, maxBottomPadding = false)
|
||||
SectionView(padding = PaddingValues(horizontal = DEFAULT_PADDING)) {
|
||||
Text(stringResource(R.string.edit_history), style = MaterialTheme.typography.h2, modifier = Modifier.padding(bottom = DEFAULT_PADDING))
|
||||
versions.forEachIndexed { i, ciVersion ->
|
||||
ItemVersionView(ciVersion, current = i == 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
SectionBottomSpacer()
|
||||
}
|
||||
}
|
||||
|
||||
fun itemInfoShareText(ci: ChatItem, chatItemInfo: ChatItemInfo, devTools: Boolean): String {
|
||||
val meta = ci.meta
|
||||
val sent = ci.chatDir.sent
|
||||
val shareText = mutableListOf<String>(generalGetString(if (sent) R.string.sent_message else R.string.received_message), "")
|
||||
|
||||
shareText.add(String.format(generalGetString(R.string.share_text_sent_at), localTimestamp(meta.itemTs)))
|
||||
if (!ci.chatDir.sent) {
|
||||
shareText.add(String.format(generalGetString(R.string.share_text_received_at), localTimestamp(meta.createdAt)))
|
||||
}
|
||||
when (val itemDeleted = ci.meta.itemDeleted) {
|
||||
is CIDeleted.Deleted ->
|
||||
if (itemDeleted.deletedTs != null) {
|
||||
shareText.add(String.format(generalGetString(R.string.share_text_deleted_at), localTimestamp(itemDeleted.deletedTs)))
|
||||
}
|
||||
is CIDeleted.Moderated ->
|
||||
if (itemDeleted.deletedTs != null) {
|
||||
shareText.add(String.format(generalGetString(R.string.share_text_moderated_at), localTimestamp(itemDeleted.deletedTs)))
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
val deleteAt = ci.meta.itemTimed?.deleteAt
|
||||
if (deleteAt != null) {
|
||||
shareText.add(String.format(generalGetString(R.string.share_text_disappears_at), localTimestamp(deleteAt)))
|
||||
}
|
||||
if (devTools) {
|
||||
shareText.add(String.format(generalGetString(R.string.share_text_database_id), meta.itemId))
|
||||
shareText.add(String.format(generalGetString(R.string.share_text_updated_at), meta.updatedAt))
|
||||
}
|
||||
val versions = chatItemInfo.itemVersions
|
||||
if (versions.isNotEmpty()) {
|
||||
shareText.add("")
|
||||
shareText.add(generalGetString(R.string.edit_history))
|
||||
versions.forEachIndexed { index, itemVersion ->
|
||||
val ts = localTimestamp(itemVersion.itemVersionTs)
|
||||
shareText.add("")
|
||||
shareText.add(
|
||||
if (index == 0 && ci.meta.itemDeleted == null) {
|
||||
String.format(generalGetString(R.string.current_version_timestamp), ts)
|
||||
} else {
|
||||
localTimestamp(itemVersion.itemVersionTs)
|
||||
}
|
||||
)
|
||||
val t = itemVersion.msgContent.text
|
||||
shareText.add(if (t != "") t else generalGetString(R.string.item_info_no_text))
|
||||
}
|
||||
}
|
||||
return shareText.joinToString(separator = "\n")
|
||||
}
|
||||
@@ -101,6 +101,7 @@ fun ChatView(chatId: String, chatModel: ChatModel, onComposed: () -> Unit) {
|
||||
}
|
||||
}
|
||||
val view = LocalView.current
|
||||
val context = LocalContext.current
|
||||
if (activeChat.value == null || user == null) {
|
||||
chatModel.chatId.value = null
|
||||
} else {
|
||||
@@ -258,6 +259,32 @@ fun ChatView(chatId: String, chatModel: ChatModel, onComposed: () -> Unit) {
|
||||
chatModel.controller.allowFeatureToContact(contact, feature, param)
|
||||
}
|
||||
},
|
||||
setReaction = { cInfo, cItem, add, reaction ->
|
||||
withApi {
|
||||
val updatedCI = chatModel.controller.apiChatItemReaction(
|
||||
type = cInfo.chatType,
|
||||
id = cInfo.apiId,
|
||||
itemId = cItem.id,
|
||||
add = add,
|
||||
reaction = reaction
|
||||
)
|
||||
if (updatedCI != null) {
|
||||
chatModel.updateChatItem(cInfo, updatedCI)
|
||||
}
|
||||
}
|
||||
},
|
||||
showItemDetails = { cInfo, cItem ->
|
||||
withApi {
|
||||
val ciInfo = chatModel.controller.apiGetChatItemInfo(cInfo.chatType, cInfo.apiId, cItem.id)
|
||||
if (ciInfo != null) {
|
||||
ModalManager.shared.showModal(endButtons = { ShareButton {
|
||||
shareText(context, itemInfoShareText(cItem, ciInfo, chatModel.controller.appPrefs.developerTools.get()))
|
||||
} }) {
|
||||
ChatItemInfoView(cItem, ciInfo, devTools = chatModel.controller.appPrefs.developerTools.get())
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
addMembers = { groupInfo ->
|
||||
hideKeyboard(view)
|
||||
withApi {
|
||||
@@ -316,6 +343,8 @@ fun ChatLayout(
|
||||
startCall: (CallMediaType) -> Unit,
|
||||
acceptCall: (Contact) -> Unit,
|
||||
acceptFeature: (Contact, ChatFeature, Int?) -> Unit,
|
||||
setReaction: (ChatInfo, ChatItem, Boolean, MsgReaction) -> Unit,
|
||||
showItemDetails: (ChatInfo, ChatItem) -> Unit,
|
||||
addMembers: (GroupInfo) -> Unit,
|
||||
markRead: (CC.ItemRange, unreadCountAfter: Int?) -> Unit,
|
||||
changeNtfsState: (Boolean, currentValue: MutableState<Boolean>) -> Unit,
|
||||
@@ -326,7 +355,6 @@ fun ChatLayout(
|
||||
Box(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.themedBackground()
|
||||
) {
|
||||
ProvideWindowInsets(windowInsetsAnimationsEnabled = true) {
|
||||
ModalBottomSheetLayout(
|
||||
@@ -352,11 +380,14 @@ fun ChatLayout(
|
||||
modifier = Modifier.navigationBarsWithImePadding(),
|
||||
floatingActionButton = { floatingButton.value() },
|
||||
) { contentPadding ->
|
||||
BoxWithConstraints(Modifier.fillMaxHeight().padding(contentPadding)) {
|
||||
BoxWithConstraints(Modifier
|
||||
.fillMaxHeight()
|
||||
.padding(contentPadding)
|
||||
) {
|
||||
ChatItemsList(
|
||||
chat, unreadCount, composeState, chatItems, searchValue,
|
||||
useLinkPreviews, linkMode, chatModelIncognito, showMemberInfo, loadPrevMessages, deleteMessage,
|
||||
receiveFile, cancelFile, joinGroup, acceptCall, acceptFeature, markRead, setFloatingButton, onComposed,
|
||||
receiveFile, cancelFile, joinGroup, acceptCall, acceptFeature, setReaction, showItemDetails, markRead, setFloatingButton, onComposed,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -529,6 +560,8 @@ fun BoxWithConstraintsScope.ChatItemsList(
|
||||
joinGroup: (Long) -> Unit,
|
||||
acceptCall: (Contact) -> Unit,
|
||||
acceptFeature: (Contact, ChatFeature, Int?) -> Unit,
|
||||
setReaction: (ChatInfo, ChatItem, Boolean, MsgReaction) -> Unit,
|
||||
showItemDetails: (ChatInfo, ChatItem) -> Unit,
|
||||
markRead: (CC.ItemRange, unreadCountAfter: Int?) -> Unit,
|
||||
setFloatingButton: (@Composable () -> Unit) -> Unit,
|
||||
onComposed: () -> Unit,
|
||||
@@ -616,12 +649,13 @@ fun BoxWithConstraintsScope.ChatItemsList(
|
||||
}
|
||||
}
|
||||
}
|
||||
val voiceWithTransparentBack = cItem.content.msgContent is MsgContent.MCVoice && cItem.content.text.isEmpty() && cItem.quotedItem == null
|
||||
if (chat.chatInfo is ChatInfo.Group) {
|
||||
if (cItem.chatDir is CIDirection.GroupRcv) {
|
||||
val prevItem = if (i < reversedChatItems.lastIndex) reversedChatItems[i + 1] else null
|
||||
val member = cItem.chatDir.groupMember
|
||||
val showMember = showMemberImage(member, prevItem)
|
||||
Row(Modifier.padding(start = 8.dp, end = 66.dp).then(swipeableModifier)) {
|
||||
Row(Modifier.padding(start = 8.dp, end = if (voiceWithTransparentBack) 12.dp else 66.dp).then(swipeableModifier)) {
|
||||
if (showMember) {
|
||||
val contactId = member.memberContactId
|
||||
if (contactId == null) {
|
||||
@@ -641,22 +675,22 @@ fun BoxWithConstraintsScope.ChatItemsList(
|
||||
} else {
|
||||
Spacer(Modifier.size(42.dp))
|
||||
}
|
||||
ChatItemView(chat.chatInfo, cItem, composeState, provider, showMember = showMember, useLinkPreviews = useLinkPreviews, linkMode = linkMode, deleteMessage = deleteMessage, receiveFile = receiveFile, cancelFile = cancelFile, joinGroup = {}, acceptCall = acceptCall, acceptFeature = acceptFeature, scrollToItem = scrollToItem)
|
||||
ChatItemView(chat.chatInfo, cItem, composeState, provider, showMember = showMember, useLinkPreviews = useLinkPreviews, linkMode = linkMode, deleteMessage = deleteMessage, receiveFile = receiveFile, cancelFile = cancelFile, joinGroup = {}, acceptCall = acceptCall, acceptFeature = acceptFeature, scrollToItem = scrollToItem, setReaction = setReaction, showItemDetails = showItemDetails)
|
||||
}
|
||||
} else {
|
||||
Box(Modifier.padding(start = 104.dp, end = 12.dp).then(swipeableModifier)) {
|
||||
ChatItemView(chat.chatInfo, cItem, composeState, provider, useLinkPreviews = useLinkPreviews, linkMode = linkMode, deleteMessage = deleteMessage, receiveFile = receiveFile, cancelFile = cancelFile, joinGroup = {}, acceptCall = acceptCall, acceptFeature = acceptFeature, scrollToItem = scrollToItem)
|
||||
Box(Modifier.padding(start = if (voiceWithTransparentBack) 12.dp else 104.dp, end = 12.dp).then(swipeableModifier)) {
|
||||
ChatItemView(chat.chatInfo, cItem, composeState, provider, useLinkPreviews = useLinkPreviews, linkMode = linkMode, deleteMessage = deleteMessage, receiveFile = receiveFile, cancelFile = cancelFile, joinGroup = {}, acceptCall = acceptCall, acceptFeature = acceptFeature, scrollToItem = scrollToItem, setReaction = setReaction, showItemDetails = showItemDetails)
|
||||
}
|
||||
}
|
||||
} else { // direct message
|
||||
val sent = cItem.chatDir.sent
|
||||
Box(
|
||||
Modifier.padding(
|
||||
start = if (sent) 76.dp else 12.dp,
|
||||
end = if (sent) 12.dp else 76.dp,
|
||||
start = if (sent && !voiceWithTransparentBack) 76.dp else 12.dp,
|
||||
end = if (sent || voiceWithTransparentBack) 12.dp else 76.dp,
|
||||
).then(swipeableModifier)
|
||||
) {
|
||||
ChatItemView(chat.chatInfo, cItem, composeState, provider, useLinkPreviews = useLinkPreviews, linkMode = linkMode, deleteMessage = deleteMessage, receiveFile = receiveFile, cancelFile = cancelFile, joinGroup = joinGroup, acceptCall = acceptCall, acceptFeature = acceptFeature, scrollToItem = scrollToItem)
|
||||
ChatItemView(chat.chatInfo, cItem, composeState, provider, useLinkPreviews = useLinkPreviews, linkMode = linkMode, deleteMessage = deleteMessage, receiveFile = receiveFile, cancelFile = cancelFile, joinGroup = joinGroup, acceptCall = acceptCall, acceptFeature = acceptFeature, scrollToItem = scrollToItem, setReaction = setReaction, showItemDetails = showItemDetails)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -855,6 +889,7 @@ private fun TopEndFloatingButton(
|
||||
FloatingActionButton(
|
||||
{}, // no action here
|
||||
modifier.size(48.dp),
|
||||
backgroundColor = MaterialTheme.colors.secondaryVariant,
|
||||
elevation = FloatingActionButtonDefaults.elevation(0.dp, 0.dp),
|
||||
interactionSource = interactionSource,
|
||||
) {
|
||||
@@ -881,7 +916,8 @@ private fun bottomEndFloatingButton(
|
||||
FloatingActionButton(
|
||||
onClick = onClickCounter,
|
||||
elevation = FloatingActionButtonDefaults.elevation(0.dp, 0.dp, 0.dp, 0.dp),
|
||||
modifier = Modifier.size(48.dp)
|
||||
modifier = Modifier.size(48.dp),
|
||||
backgroundColor = MaterialTheme.colors.secondaryVariant,
|
||||
) {
|
||||
Text(
|
||||
unreadCountStr(unreadCount),
|
||||
@@ -896,7 +932,8 @@ private fun bottomEndFloatingButton(
|
||||
FloatingActionButton(
|
||||
onClick = onClickArrowDown,
|
||||
elevation = FloatingActionButtonDefaults.elevation(0.dp, 0.dp, 0.dp, 0.dp),
|
||||
modifier = Modifier.size(48.dp)
|
||||
modifier = Modifier.size(48.dp),
|
||||
backgroundColor = MaterialTheme.colors.secondaryVariant,
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.ic_keyboard_arrow_down),
|
||||
@@ -1076,6 +1113,8 @@ fun PreviewChatLayout() {
|
||||
startCall = {},
|
||||
acceptCall = { _ -> },
|
||||
acceptFeature = { _, _, _ -> },
|
||||
setReaction = { _, _, _, _ -> },
|
||||
showItemDetails = { _, _ -> },
|
||||
addMembers = { _ -> },
|
||||
markRead = { _, _ -> },
|
||||
changeNtfsState = { _, _ -> },
|
||||
@@ -1136,6 +1175,8 @@ fun PreviewGroupChatLayout() {
|
||||
startCall = {},
|
||||
acceptCall = { _ -> },
|
||||
acceptFeature = { _, _, _ -> },
|
||||
setReaction = { _, _, _, _ -> },
|
||||
showItemDetails = { _, _ -> },
|
||||
addMembers = { _ -> },
|
||||
markRead = { _, _ -> },
|
||||
changeNtfsState = { _, _ -> },
|
||||
|
||||
@@ -118,7 +118,7 @@ data class ComposeState(
|
||||
|
||||
val attachmentDisabled: Boolean
|
||||
get() {
|
||||
if (editing || liveMessage != null) return true
|
||||
if (editing || liveMessage != null || inProgress) return true
|
||||
return when (preview) {
|
||||
ComposePreview.NoPreview -> false
|
||||
is ComposePreview.CLinkPreview -> false
|
||||
@@ -366,22 +366,27 @@ fun ComposeView(
|
||||
chatModel.filesToDelete.clear()
|
||||
}
|
||||
|
||||
suspend fun send(cInfo: ChatInfo, mc: MsgContent, quoted: Long?, file: String? = null, live: Boolean = false): ChatItem? {
|
||||
suspend fun send(cInfo: ChatInfo, mc: MsgContent, quoted: Long?, file: String? = null, live: Boolean = false, ttl: Int?): ChatItem? {
|
||||
val aChatItem = chatModel.controller.apiSendMessage(
|
||||
type = cInfo.chatType,
|
||||
id = cInfo.apiId,
|
||||
file = file,
|
||||
quotedItemId = quoted,
|
||||
mc = mc,
|
||||
live = live
|
||||
live = live,
|
||||
ttl = ttl
|
||||
)
|
||||
if (aChatItem != null) chatModel.addChatItem(cInfo, aChatItem.chatItem)
|
||||
return aChatItem?.chatItem
|
||||
if (aChatItem != null) {
|
||||
chatModel.addChatItem(cInfo, aChatItem.chatItem)
|
||||
return aChatItem.chatItem
|
||||
}
|
||||
if (file != null) removeFile(context, file)
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
|
||||
suspend fun sendMessageAsync(text: String?, live: Boolean): ChatItem? {
|
||||
suspend fun sendMessageAsync(text: String?, live: Boolean, ttl: Int?): ChatItem? {
|
||||
val cInfo = chat.chatInfo
|
||||
val cs = composeState.value
|
||||
var sent: ChatItem?
|
||||
@@ -495,7 +500,8 @@ fun ComposeView(
|
||||
msgs.forEachIndexed { index, content ->
|
||||
if (index > 0) delay(100)
|
||||
sent = send(cInfo, content, if (index == 0) quotedItemId else null, files.getOrNull(index),
|
||||
if (content !is MsgContent.MCVoice && index == msgs.lastIndex) live else false
|
||||
live = if (content !is MsgContent.MCVoice && index == msgs.lastIndex) live else false,
|
||||
ttl = ttl
|
||||
)
|
||||
}
|
||||
if (sent == null &&
|
||||
@@ -503,16 +509,16 @@ fun ComposeView(
|
||||
cs.preview is ComposePreview.FilePreview ||
|
||||
cs.preview is ComposePreview.VoicePreview)
|
||||
) {
|
||||
sent = send(cInfo, MsgContent.MCText(msgText), quotedItemId, null, live)
|
||||
sent = send(cInfo, MsgContent.MCText(msgText), quotedItemId, null, live, ttl)
|
||||
}
|
||||
}
|
||||
clearState(live)
|
||||
return sent
|
||||
}
|
||||
|
||||
fun sendMessage() {
|
||||
fun sendMessage(ttl: Int?) {
|
||||
withBGApi {
|
||||
sendMessageAsync(null, false)
|
||||
sendMessageAsync(null, false, ttl)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -588,7 +594,7 @@ fun ComposeView(
|
||||
val cs = composeState.value
|
||||
val typedMsg = cs.message
|
||||
if ((cs.sendEnabled() || cs.contextItem is ComposeContextItem.QuotedItem) && (cs.liveMessage == null || !cs.liveMessage?.sent)) {
|
||||
val ci = sendMessageAsync(typedMsg, live = true)
|
||||
val ci = sendMessageAsync(typedMsg, live = true, ttl = null)
|
||||
if (ci != null) {
|
||||
composeState.value = composeState.value.copy(liveMessage = LiveMessage(ci, typedMsg = typedMsg, sentMsg = typedMsg, sent = true))
|
||||
}
|
||||
@@ -609,7 +615,7 @@ fun ComposeView(
|
||||
if (liveMessage != null) {
|
||||
val sentMsg = liveMessageToSend(liveMessage, typedMsg)
|
||||
if (sentMsg != null) {
|
||||
val ci = sendMessageAsync(sentMsg, live = true)
|
||||
val ci = sendMessageAsync(sentMsg, live = true, ttl = null)
|
||||
if (ci != null) {
|
||||
composeState.value = composeState.value.copy(liveMessage = LiveMessage(ci, typedMsg = typedMsg, sentMsg = sentMsg, sent = true))
|
||||
}
|
||||
@@ -623,23 +629,27 @@ fun ComposeView(
|
||||
fun previewView() {
|
||||
when (val preview = composeState.value.preview) {
|
||||
ComposePreview.NoPreview -> {}
|
||||
is ComposePreview.CLinkPreview -> ComposeLinkView(preview.linkPreview, ::cancelLinkPreview)
|
||||
is ComposePreview.CLinkPreview -> ComposeLinkView(
|
||||
preview.linkPreview,
|
||||
::cancelLinkPreview,
|
||||
cancelEnabled = !composeState.value.inProgress
|
||||
)
|
||||
is ComposePreview.MediaPreview -> ComposeImageView(
|
||||
preview,
|
||||
::cancelImages,
|
||||
cancelEnabled = !composeState.value.editing
|
||||
cancelEnabled = !composeState.value.editing && !composeState.value.inProgress
|
||||
)
|
||||
is ComposePreview.VoicePreview -> ComposeVoiceView(
|
||||
preview.voice,
|
||||
preview.durationMs,
|
||||
preview.finished,
|
||||
cancelEnabled = !composeState.value.editing,
|
||||
cancelEnabled = !composeState.value.editing && !composeState.value.inProgress,
|
||||
::cancelVoice
|
||||
)
|
||||
is ComposePreview.FilePreview -> ComposeFileView(
|
||||
preview.fileName,
|
||||
::cancelFile,
|
||||
cancelEnabled = !composeState.value.editing
|
||||
cancelEnabled = !composeState.value.editing && !composeState.value.inProgress
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -657,6 +667,14 @@ fun ComposeView(
|
||||
}
|
||||
}
|
||||
|
||||
// In case a user sent something, state is in progress, the user rotates a screen to different orientation.
|
||||
// Without clearing the state the user will be unable to send anything until re-enters ChatView
|
||||
LaunchedEffect(Unit) {
|
||||
if (composeState.value.inProgress) {
|
||||
clearState()
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(chatModel.sharedContent.value) {
|
||||
// Important. If it's null, don't do anything, chat is not closed yet but will be after a moment
|
||||
if (chatModel.chatId.value == null) return@LaunchedEffect
|
||||
@@ -674,11 +692,22 @@ fun ComposeView(
|
||||
val userIsObserver = rememberUpdatedState(chat.userIsObserver)
|
||||
|
||||
Column {
|
||||
contextItemView()
|
||||
when {
|
||||
composeState.value.editing && composeState.value.preview is ComposePreview.VoicePreview -> {}
|
||||
composeState.value.editing && composeState.value.preview is ComposePreview.FilePreview -> {}
|
||||
else -> previewView()
|
||||
if (composeState.value.preview !is ComposePreview.VoicePreview || composeState.value.editing) {
|
||||
contextItemView()
|
||||
when {
|
||||
composeState.value.editing && composeState.value.preview is ComposePreview.VoicePreview -> {}
|
||||
composeState.value.editing && composeState.value.preview is ComposePreview.FilePreview -> {}
|
||||
else -> previewView()
|
||||
}
|
||||
} else {
|
||||
Box {
|
||||
Box(Modifier.align(Alignment.TopStart).padding(bottom = 69.dp)) {
|
||||
contextItemView()
|
||||
}
|
||||
Box(Modifier.align(Alignment.BottomStart)) {
|
||||
previewView()
|
||||
}
|
||||
}
|
||||
}
|
||||
Row(
|
||||
modifier = Modifier.padding(end = 8.dp),
|
||||
@@ -740,10 +769,12 @@ fun ComposeView(
|
||||
if (orientation == activity.resources.configuration.orientation) {
|
||||
val cs = composeState.value
|
||||
if (cs.liveMessage != null && (cs.message.isNotEmpty() || cs.liveMessage.sent)) {
|
||||
sendMessage()
|
||||
sendMessage(null)
|
||||
resetLinkPreview()
|
||||
clearCurrentDraft()
|
||||
deleteUnusedFiles()
|
||||
} else if (composeState.value.inProgress) {
|
||||
clearCurrentDraft()
|
||||
} else if (!composeState.value.empty) {
|
||||
if (cs.preview is ComposePreview.VoicePreview && !cs.preview.finished) {
|
||||
composeState.value = cs.copy(preview = cs.preview.copy(finished = true))
|
||||
@@ -759,6 +790,9 @@ fun ComposeView(
|
||||
}
|
||||
}
|
||||
|
||||
// TODO in 5.2 - allow if ttl is not configured
|
||||
// val timedMessageAllowed = remember(chat.chatInfo) { chat.chatInfo.featureEnabled(ChatFeature.TimedMessages) }
|
||||
val timedMessageAllowed = remember(chat.chatInfo) { chat.chatInfo.featureEnabled(ChatFeature.TimedMessages) && chat.chatInfo.timedMessagesTTL != null }
|
||||
SendMsgView(
|
||||
composeState,
|
||||
showVoiceRecordIcon = true,
|
||||
@@ -770,8 +804,10 @@ fun ComposeView(
|
||||
allowVoiceToContact = ::allowVoiceToContact,
|
||||
userIsObserver = userIsObserver.value,
|
||||
userCanSend = userCanSend.value,
|
||||
sendMessage = {
|
||||
sendMessage()
|
||||
timedMessageAllowed = timedMessageAllowed,
|
||||
customDisappearingMessageTimePref = chatModel.controller.appPrefs.customDisappearingMessageTime,
|
||||
sendMessage = { ttl ->
|
||||
sendMessage(ttl)
|
||||
resetLinkPreview()
|
||||
},
|
||||
sendLiveMessage = ::sendLiveMessage,
|
||||
|
||||
@@ -6,6 +6,10 @@ import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.drawBehind
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
@@ -25,99 +29,135 @@ fun ComposeVoiceView(
|
||||
cancelEnabled: Boolean,
|
||||
cancelVoice: () -> Unit
|
||||
) {
|
||||
BoxWithConstraints(Modifier
|
||||
.fillMaxWidth()
|
||||
) {
|
||||
val audioPlaying = rememberSaveable { mutableStateOf(false) }
|
||||
val progress = rememberSaveable { mutableStateOf(0) }
|
||||
val duration = rememberSaveable(recordedDurationMs) { mutableStateOf(recordedDurationMs) }
|
||||
val progressBarWidth = remember { Animatable(0f) }
|
||||
LaunchedEffect(recordedDurationMs, finishedRecording) {
|
||||
snapshotFlow { progress.value }
|
||||
.distinctUntilChanged()
|
||||
.collect {
|
||||
val startTime = when {
|
||||
finishedRecording -> progress.value
|
||||
else -> recordedDurationMs
|
||||
}
|
||||
val endTime = when {
|
||||
finishedRecording -> duration.value
|
||||
audioPlaying.value -> recordedDurationMs
|
||||
else -> MAX_VOICE_MILLIS_FOR_SENDING
|
||||
}
|
||||
val to = ((startTime.toDouble() / endTime) * maxWidth.value).dp
|
||||
progressBarWidth.animateTo(to.value, audioProgressBarAnimationSpec())
|
||||
}
|
||||
}
|
||||
Spacer(
|
||||
val progress = rememberSaveable { mutableStateOf(0) }
|
||||
val duration = rememberSaveable(recordedDurationMs) { mutableStateOf(recordedDurationMs) }
|
||||
val sentColor = CurrentColors.collectAsState().value.appColors.sentMessage
|
||||
Box {
|
||||
Box(
|
||||
Modifier
|
||||
.requiredWidth(progressBarWidth.value.dp)
|
||||
.padding(top = 58.dp)
|
||||
.height(3.dp)
|
||||
.background(MaterialTheme.colors.primary)
|
||||
)
|
||||
val sentColor = CurrentColors.collectAsState().value.appColors.sentMessage
|
||||
Row(
|
||||
Modifier
|
||||
.height(60.dp)
|
||||
.fillMaxWidth()
|
||||
.padding(top = 8.dp)
|
||||
.background(sentColor),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
.fillMaxWidth().padding(top = 22.dp)
|
||||
) {
|
||||
IconButton(
|
||||
onClick = {
|
||||
if (!audioPlaying.value) {
|
||||
AudioPlayer.play(filePath, audioPlaying, progress, duration, false)
|
||||
} else {
|
||||
AudioPlayer.pause(audioPlaying, progress)
|
||||
}
|
||||
},
|
||||
enabled = finishedRecording) {
|
||||
Icon(
|
||||
if (audioPlaying.value) painterResource(R.drawable.ic_pause_filled) else painterResource(R.drawable.ic_play_arrow_filled),
|
||||
stringResource(R.string.icon_descr_file),
|
||||
Modifier
|
||||
.padding(start = 4.dp, end = 2.dp)
|
||||
.size(36.dp),
|
||||
tint = if (finishedRecording) MaterialTheme.colors.primary else MaterialTheme.colors.secondary
|
||||
)
|
||||
}
|
||||
val numberInText = remember(recordedDurationMs, progress.value) {
|
||||
derivedStateOf {
|
||||
when {
|
||||
finishedRecording && progress.value == 0 && !audioPlaying.value -> duration.value / 1000
|
||||
finishedRecording -> progress.value / 1000
|
||||
else -> recordedDurationMs / 1000
|
||||
}
|
||||
}
|
||||
}
|
||||
Text(
|
||||
durationText(numberInText.value),
|
||||
fontSize = 18.sp,
|
||||
color = MaterialTheme.colors.secondary,
|
||||
)
|
||||
Spacer(Modifier.weight(1f))
|
||||
if (cancelEnabled) {
|
||||
val audioPlaying = rememberSaveable { mutableStateOf(false) }
|
||||
Row(
|
||||
Modifier
|
||||
.height(57.dp)
|
||||
.fillMaxWidth()
|
||||
.background(sentColor)
|
||||
.padding(top = 3.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
IconButton(
|
||||
onClick = {
|
||||
AudioPlayer.stop(filePath)
|
||||
cancelVoice()
|
||||
if (!audioPlaying.value) {
|
||||
AudioPlayer.play(filePath, audioPlaying, progress, duration, false)
|
||||
} else {
|
||||
AudioPlayer.pause(audioPlaying, progress)
|
||||
}
|
||||
},
|
||||
modifier = Modifier.padding(0.dp)
|
||||
enabled = finishedRecording
|
||||
) {
|
||||
Icon(
|
||||
painterResource(R.drawable.ic_close),
|
||||
contentDescription = stringResource(R.string.icon_descr_cancel_file_preview),
|
||||
tint = MaterialTheme.colors.primary,
|
||||
modifier = Modifier.padding(10.dp)
|
||||
if (audioPlaying.value) painterResource(R.drawable.ic_pause_filled) else painterResource(R.drawable.ic_play_arrow_filled),
|
||||
stringResource(R.string.icon_descr_file),
|
||||
Modifier
|
||||
.padding(start = 4.dp, end = 2.dp)
|
||||
.size(36.dp),
|
||||
tint = if (finishedRecording) MaterialTheme.colors.primary else MaterialTheme.colors.secondary
|
||||
)
|
||||
}
|
||||
val numberInText = remember(recordedDurationMs, progress.value) {
|
||||
derivedStateOf {
|
||||
when {
|
||||
finishedRecording && progress.value == 0 && !audioPlaying.value -> duration.value / 1000
|
||||
finishedRecording -> progress.value / 1000
|
||||
else -> recordedDurationMs / 1000
|
||||
}
|
||||
}
|
||||
}
|
||||
Text(
|
||||
durationText(numberInText.value),
|
||||
fontSize = 18.sp,
|
||||
color = MaterialTheme.colors.secondary,
|
||||
)
|
||||
Spacer(Modifier.weight(1f))
|
||||
if (cancelEnabled) {
|
||||
IconButton(
|
||||
onClick = {
|
||||
AudioPlayer.stop(filePath)
|
||||
cancelVoice()
|
||||
},
|
||||
modifier = Modifier.padding(0.dp)
|
||||
) {
|
||||
Icon(
|
||||
painterResource(R.drawable.ic_close),
|
||||
contentDescription = stringResource(R.string.icon_descr_cancel_file_preview),
|
||||
tint = MaterialTheme.colors.primary,
|
||||
modifier = Modifier.padding(10.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (finishedRecording) {
|
||||
FinishedRecordingSlider(sentColor, progress, duration, filePath)
|
||||
} else {
|
||||
RecordingInProgressSlider(recordedDurationMs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun FinishedRecordingSlider(backgroundColor: Color, progress: MutableState<Int>, duration: MutableState<Int>, filePath: String) {
|
||||
val dp4 = with(LocalDensity.current) { 4.dp.toPx() }
|
||||
val dp10 = with(LocalDensity.current) { 10.dp.toPx() }
|
||||
val primary = MaterialTheme.colors.primary
|
||||
val inactiveTrackColor = MaterialTheme.colors.primary.mixWith(
|
||||
backgroundColor.copy(1f).mixWith(MaterialTheme.colors.background, backgroundColor.alpha),
|
||||
0.24f)
|
||||
Slider(
|
||||
progress.value.toFloat(),
|
||||
onValueChange = { AudioPlayer.seekTo(it.toInt(), progress, filePath) },
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.drawBehind {
|
||||
drawRect(primary, Offset(0f, (size.height - dp4) / 2), size = androidx.compose.ui.geometry.Size(dp10, dp4))
|
||||
drawRect(inactiveTrackColor, Offset(size.width - dp10, (size.height - dp4) / 2), size = androidx.compose.ui.geometry.Size(dp10, dp4))
|
||||
},
|
||||
colors = SliderDefaults.colors(inactiveTrackColor = inactiveTrackColor),
|
||||
valueRange = 0f..duration.value.toFloat()
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RecordingInProgressSlider(recordedDurationMs: Int) {
|
||||
val thumbPosition = remember { Animatable(0f) }
|
||||
val recDuration = rememberUpdatedState(recordedDurationMs)
|
||||
LaunchedEffect(Unit) {
|
||||
snapshotFlow { recDuration.value }
|
||||
.distinctUntilChanged()
|
||||
.collect {
|
||||
thumbPosition.animateTo(it.toFloat(), audioProgressBarAnimationSpec())
|
||||
}
|
||||
}
|
||||
val dp4 = with(LocalDensity.current) { 4.dp.toPx() }
|
||||
val dp10 = with(LocalDensity.current) { 10.dp.toPx() }
|
||||
val primary = MaterialTheme.colors.primary
|
||||
val inactiveTrackColor = Color.Transparent
|
||||
Slider(
|
||||
thumbPosition.value,
|
||||
onValueChange = {},
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.drawBehind {
|
||||
drawRect(primary, Offset(0f, (size.height - dp4) / 2), size = androidx.compose.ui.geometry.Size(dp10, dp4))
|
||||
},
|
||||
colors = SliderDefaults.colors(disabledInactiveTrackColor = inactiveTrackColor, disabledActiveTrackColor = primary, thumbColor = Color.Transparent, disabledThumbColor = Color.Transparent),
|
||||
enabled = false,
|
||||
valueRange = 0f..MAX_VOICE_MILLIS_FOR_SENDING.toFloat()
|
||||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun PreviewComposeAudioView() {
|
||||
|
||||
@@ -95,6 +95,11 @@ private fun ContactPreferencesLayout(
|
||||
applyPrefs(featuresAllowed.copy(fullDelete = it))
|
||||
}
|
||||
SectionDividerSpaced(true, maxBottomPadding = false)
|
||||
// val allowReactions: MutableState<ContactFeatureAllowed> = remember(featuresAllowed) { mutableStateOf(featuresAllowed.reactions) }
|
||||
// FeatureSection(ChatFeature.Reactions, user.fullPreferences.reactions.allow, contact.mergedPreferences.reactions, allowReactions) {
|
||||
// applyPrefs(featuresAllowed.copy(reactions = it))
|
||||
// }
|
||||
// SectionDividerSpaced(true, maxBottomPadding = false)
|
||||
val allowVoice: MutableState<ContactFeatureAllowed> = remember(featuresAllowed) { mutableStateOf(featuresAllowed.voice) }
|
||||
FeatureSection(ChatFeature.Voice, user.fullPreferences.voice.allow, contact.mergedPreferences.voice, allowVoice) {
|
||||
applyPrefs(featuresAllowed.copy(voice = it))
|
||||
@@ -139,7 +144,6 @@ private fun FeatureSection(
|
||||
ContactFeatureAllowed.values(userDefault).map { it to it.text },
|
||||
allowFeature,
|
||||
icon = null,
|
||||
enabled = remember { mutableStateOf(feature != ChatFeature.Calls) },
|
||||
onSelected = onSelected
|
||||
)
|
||||
InfoRow(
|
||||
@@ -147,7 +151,7 @@ private fun FeatureSection(
|
||||
pref.contactPreference.allow.text
|
||||
)
|
||||
}
|
||||
SectionTextFooter(feature.enabledDescription(enabled) + (if (feature == ChatFeature.Calls) generalGetString(R.string.available_in_v51) else ""))
|
||||
SectionTextFooter(feature.enabledDescription(enabled))
|
||||
}
|
||||
|
||||
@Composable
|
||||
@@ -182,9 +186,17 @@ private fun TimedMessagesFeatureSection(
|
||||
)
|
||||
if (featuresAllowed.timedMessagesAllowed) {
|
||||
val ttl = rememberSaveable(featuresAllowed.timedMessagesTTL) { mutableStateOf(featuresAllowed.timedMessagesTTL) }
|
||||
TimedMessagesTTLPicker(ttl, onTTLUpdated)
|
||||
DropdownCustomTimePickerSettingRow(
|
||||
selection = ttl,
|
||||
propagateExternalSelectionUpdate = true, // for Reset
|
||||
label = generalGetString(R.string.delete_after),
|
||||
dropdownValues = TimedMessagesPreference.ttlValues,
|
||||
customPickerTitle = generalGetString(R.string.delete_after),
|
||||
customPickerConfirmButtonText = generalGetString(R.string.custom_time_picker_select),
|
||||
onSelected = onTTLUpdated
|
||||
)
|
||||
} else if (pref.contactPreference.allow == FeatureAllowed.YES || pref.contactPreference.allow == FeatureAllowed.ALWAYS) {
|
||||
InfoRow(generalGetString(R.string.delete_after), TimedMessagesPreference.ttlText(pref.contactPreference.ttl))
|
||||
InfoRow(generalGetString(R.string.delete_after), timeText(pref.contactPreference.ttl))
|
||||
}
|
||||
}
|
||||
SectionTextFooter(ChatFeature.TimedMessages.enabledDescription(enabled))
|
||||
@@ -202,18 +214,6 @@ private fun ResetSaveButtons(reset: () -> Unit, save: () -> Unit, disabled: Bool
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TimedMessagesTTLPicker(selection: MutableState<Int?>, onSelected: (Int?) -> Unit) {
|
||||
val ttlValues = TimedMessagesPreference.ttlValues
|
||||
val values = ttlValues + if (ttlValues.contains(selection.value)) listOf() else listOf(selection.value)
|
||||
ExposedDropDownSettingRow(
|
||||
generalGetString(R.string.delete_after),
|
||||
values.map { it to TimedMessagesPreference.ttlText(it) },
|
||||
selection,
|
||||
onSelected = onSelected
|
||||
)
|
||||
}
|
||||
|
||||
private fun showUnsavedChangesAlert(save: () -> Unit, revert: () -> Unit) {
|
||||
AlertManager.shared.showAlertDialogStacked(
|
||||
title = generalGetString(R.string.save_preferences_question),
|
||||
|
||||
@@ -18,7 +18,7 @@ import androidx.compose.animation.core.*
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.*
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.runtime.*
|
||||
@@ -29,14 +29,14 @@ import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.*
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.platform.*
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.res.*
|
||||
import androidx.compose.ui.semantics.Role
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontStyle
|
||||
import androidx.compose.ui.text.font.*
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.*
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.core.graphics.drawable.DrawableCompat
|
||||
import androidx.core.view.inputmethod.EditorInfoCompat
|
||||
import androidx.core.view.inputmethod.InputConnectionCompat
|
||||
@@ -44,8 +44,7 @@ import androidx.core.widget.*
|
||||
import chat.simplex.app.R
|
||||
import chat.simplex.app.SimplexApp
|
||||
import chat.simplex.app.model.*
|
||||
import chat.simplex.app.ui.theme.CurrentColors
|
||||
import chat.simplex.app.ui.theme.SimpleXTheme
|
||||
import chat.simplex.app.ui.theme.*
|
||||
import chat.simplex.app.views.chat.item.ItemAction
|
||||
import chat.simplex.app.views.helpers.*
|
||||
import com.google.accompanist.permissions.rememberMultiplePermissionsState
|
||||
@@ -64,13 +63,25 @@ fun SendMsgView(
|
||||
userIsObserver: Boolean,
|
||||
userCanSend: Boolean,
|
||||
allowVoiceToContact: () -> Unit,
|
||||
sendMessage: () -> Unit,
|
||||
timedMessageAllowed: Boolean = false,
|
||||
customDisappearingMessageTimePref: SharedPreference<Int>? = null,
|
||||
sendMessage: (Int?) -> Unit,
|
||||
sendLiveMessage: (suspend () -> Unit)? = null,
|
||||
updateLiveMessage: (suspend () -> Unit)? = null,
|
||||
cancelLiveMessage: (() -> Unit)? = null,
|
||||
onMessageChange: (String) -> Unit,
|
||||
textStyle: MutableState<TextStyle>
|
||||
) {
|
||||
val showCustomDisappearingMessageDialog = remember { mutableStateOf(false) }
|
||||
|
||||
if (showCustomDisappearingMessageDialog.value) {
|
||||
CustomDisappearingMessageDialog(
|
||||
sendMessage = sendMessage,
|
||||
setShowDialog = { showCustomDisappearingMessageDialog.value = it },
|
||||
customDisappearingMessageTimePref = customDisappearingMessageTimePref
|
||||
)
|
||||
}
|
||||
|
||||
Box(Modifier.padding(vertical = 8.dp)) {
|
||||
val cs = composeState.value
|
||||
val showProgress = cs.inProgress && (cs.preview is ComposePreview.MediaPreview || cs.preview is ComposePreview.FilePreview)
|
||||
@@ -79,15 +90,16 @@ fun SendMsgView(
|
||||
val showDeleteTextButton = rememberSaveable { mutableStateOf(false) }
|
||||
NativeKeyboard(composeState, textStyle, showDeleteTextButton, userIsObserver, onMessageChange)
|
||||
// Disable clicks on text field
|
||||
if (cs.preview is ComposePreview.VoicePreview || !userCanSend) {
|
||||
Box(Modifier
|
||||
.matchParentSize()
|
||||
.clickable(enabled = !userCanSend, indication = null, interactionSource = remember { MutableInteractionSource() }, onClick = {
|
||||
AlertManager.shared.showAlertMsg(
|
||||
title = generalGetString(R.string.observer_cant_send_message_title),
|
||||
text = generalGetString(R.string.observer_cant_send_message_desc)
|
||||
)
|
||||
})
|
||||
if (cs.preview is ComposePreview.VoicePreview || !userCanSend || cs.inProgress) {
|
||||
Box(
|
||||
Modifier
|
||||
.matchParentSize()
|
||||
.clickable(enabled = !userCanSend, indication = null, interactionSource = remember { MutableInteractionSource() }, onClick = {
|
||||
AlertManager.shared.showAlertMsg(
|
||||
title = generalGetString(R.string.observer_cant_send_message_title),
|
||||
text = generalGetString(R.string.observer_cant_send_message_desc)
|
||||
)
|
||||
})
|
||||
)
|
||||
}
|
||||
if (showDeleteTextButton.value) {
|
||||
@@ -124,10 +136,11 @@ fun SendMsgView(
|
||||
else ->
|
||||
RecordVoiceView(recState, stopRecOnNextClick)
|
||||
}
|
||||
if (sendLiveMessage != null
|
||||
&& updateLiveMessage != null
|
||||
&& (cs.preview !is ComposePreview.VoicePreview || !stopRecOnNextClick.value)
|
||||
&& cs.contextItem is ComposeContextItem.NoContextItem) {
|
||||
if (sendLiveMessage != null
|
||||
&& updateLiveMessage != null
|
||||
&& (cs.preview !is ComposePreview.VoicePreview || !stopRecOnNextClick.value)
|
||||
&& cs.contextItem is ComposeContextItem.NoContextItem
|
||||
) {
|
||||
Spacer(Modifier.width(10.dp))
|
||||
StartLiveMessageButton(userCanSend) {
|
||||
if (composeState.value.preview is ComposePreview.NoPreview) {
|
||||
@@ -146,27 +159,53 @@ fun SendMsgView(
|
||||
val cs = composeState.value
|
||||
val icon = if (cs.editing || cs.liveMessage != null) painterResource(R.drawable.ic_check_filled) else painterResource(R.drawable.ic_arrow_upward)
|
||||
val disabled = !cs.sendEnabled() ||
|
||||
(!allowedVoiceByPrefs && cs.preview is ComposePreview.VoicePreview) ||
|
||||
cs.endLiveDisabled
|
||||
if (cs.liveMessage == null &&
|
||||
cs.preview !is ComposePreview.VoicePreview && !cs.editing &&
|
||||
cs.contextItem is ComposeContextItem.NoContextItem &&
|
||||
sendLiveMessage != null && updateLiveMessage != null
|
||||
) {
|
||||
val showDropdown = rememberSaveable { mutableStateOf(false) }
|
||||
SendMsgButton(icon, sendButtonSize, sendButtonAlpha, !disabled, sendMessage) { showDropdown.value = true }
|
||||
(!allowedVoiceByPrefs && cs.preview is ComposePreview.VoicePreview) ||
|
||||
cs.endLiveDisabled
|
||||
val showDropdown = rememberSaveable { mutableStateOf(false) }
|
||||
|
||||
DefaultDropdownMenu(
|
||||
showDropdown,
|
||||
) {
|
||||
ItemAction(
|
||||
generalGetString(R.string.send_live_message),
|
||||
BoltFilled,
|
||||
onClick = {
|
||||
startLiveMessage(scope, sendLiveMessage, updateLiveMessage, sendButtonSize, sendButtonAlpha, composeState, liveMessageAlertShown)
|
||||
showDropdown.value = false
|
||||
@Composable
|
||||
fun MenuItems(): List<@Composable () -> Unit> {
|
||||
val menuItems = mutableListOf<@Composable () -> Unit>()
|
||||
|
||||
if (cs.liveMessage == null && !cs.editing) {
|
||||
if (
|
||||
cs.preview !is ComposePreview.VoicePreview &&
|
||||
cs.contextItem is ComposeContextItem.NoContextItem &&
|
||||
sendLiveMessage != null && updateLiveMessage != null
|
||||
) {
|
||||
menuItems.add {
|
||||
ItemAction(
|
||||
generalGetString(R.string.send_live_message),
|
||||
BoltFilled,
|
||||
onClick = {
|
||||
startLiveMessage(scope, sendLiveMessage, updateLiveMessage, sendButtonSize, sendButtonAlpha, composeState, liveMessageAlertShown)
|
||||
showDropdown.value = false
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
if (timedMessageAllowed) {
|
||||
menuItems.add {
|
||||
ItemAction(
|
||||
generalGetString(R.string.disappearing_message),
|
||||
painterResource(R.drawable.ic_timer),
|
||||
onClick = {
|
||||
showCustomDisappearingMessageDialog.value = true
|
||||
showDropdown.value = false
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return menuItems
|
||||
}
|
||||
|
||||
val menuItems = MenuItems()
|
||||
if (menuItems.isNotEmpty()) {
|
||||
SendMsgButton(icon, sendButtonSize, sendButtonAlpha, !disabled, sendMessage) { showDropdown.value = true }
|
||||
DefaultDropdownMenu(showDropdown) {
|
||||
menuItems.forEach { composable -> composable() }
|
||||
}
|
||||
} else {
|
||||
SendMsgButton(icon, sendButtonSize, sendButtonAlpha, !disabled, sendMessage)
|
||||
@@ -177,6 +216,99 @@ fun SendMsgView(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CustomDisappearingMessageDialog(
|
||||
sendMessage: (Int?) -> Unit,
|
||||
setShowDialog: (Boolean) -> Unit,
|
||||
customDisappearingMessageTimePref: SharedPreference<Int>?
|
||||
) {
|
||||
val showCustomTimePicker = remember { mutableStateOf(false) }
|
||||
|
||||
if (showCustomTimePicker.value) {
|
||||
val selectedDisappearingMessageTime = remember {
|
||||
mutableStateOf(customDisappearingMessageTimePref?.get?.invoke() ?: 300)
|
||||
}
|
||||
CustomTimePickerDialog(
|
||||
selectedDisappearingMessageTime,
|
||||
title = generalGetString(R.string.delete_after),
|
||||
confirmButtonText = generalGetString(R.string.send_disappearing_message_send),
|
||||
confirmButtonAction = { ttl ->
|
||||
sendMessage(ttl)
|
||||
customDisappearingMessageTimePref?.set?.invoke(ttl)
|
||||
setShowDialog(false)
|
||||
},
|
||||
cancel = { setShowDialog(false) }
|
||||
)
|
||||
} else {
|
||||
@Composable
|
||||
fun ChoiceButton(
|
||||
text: String,
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
TextButton(onClick) {
|
||||
Text(
|
||||
text,
|
||||
fontSize = 18.sp,
|
||||
color = MaterialTheme.colors.primary
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Dialog(onDismissRequest = { setShowDialog(false) }) {
|
||||
Surface(
|
||||
shape = RoundedCornerShape(corner = CornerSize(25.dp))
|
||||
) {
|
||||
Box(
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(DEFAULT_PADDING),
|
||||
verticalArrangement = Arrangement.spacedBy(6.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(" ") // centers title
|
||||
Text(
|
||||
generalGetString(R.string.send_disappearing_message),
|
||||
fontSize = 16.sp,
|
||||
color = MaterialTheme.colors.secondary
|
||||
)
|
||||
Icon(
|
||||
painterResource(R.drawable.ic_close),
|
||||
generalGetString(R.string.icon_descr_close_button),
|
||||
tint = MaterialTheme.colors.secondary,
|
||||
modifier = Modifier
|
||||
.size(25.dp)
|
||||
.clickable { setShowDialog(false) }
|
||||
)
|
||||
}
|
||||
|
||||
ChoiceButton(generalGetString(R.string.send_disappearing_message_30_seconds)) {
|
||||
sendMessage(30)
|
||||
setShowDialog(false)
|
||||
}
|
||||
ChoiceButton(generalGetString(R.string.send_disappearing_message_1_minute)) {
|
||||
sendMessage(60)
|
||||
setShowDialog(false)
|
||||
}
|
||||
ChoiceButton(generalGetString(R.string.send_disappearing_message_5_minutes)) {
|
||||
sendMessage(300)
|
||||
setShowDialog(false)
|
||||
}
|
||||
ChoiceButton(generalGetString(R.string.send_disappearing_message_custom_time)) {
|
||||
showCustomTimePicker.value = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun NativeKeyboard(
|
||||
composeState: MutableState<ComposeState>,
|
||||
@@ -250,14 +382,20 @@ private fun NativeKeyboard(
|
||||
Log.e(chat.simplex.app.TAG, e.stackTraceToString())
|
||||
}
|
||||
}
|
||||
editText.doOnTextChanged { text, _, _, _ -> onMessageChange(text.toString()) }
|
||||
editText.doOnTextChanged { text, _, _, _ ->
|
||||
if (!composeState.value.inProgress) {
|
||||
onMessageChange(text.toString())
|
||||
} else if (text.toString() != composeState.value.message) {
|
||||
editText.setText(composeState.value.message)
|
||||
}
|
||||
}
|
||||
editText.doAfterTextChanged { text -> if (composeState.value.preview is ComposePreview.VoicePreview && text.toString() != "") editText.setText("") }
|
||||
editText
|
||||
}) {
|
||||
it.setTextColor(textColor.toArgb())
|
||||
it.textSize = textStyle.value.fontSize.value
|
||||
DrawableCompat.setTint(it.background, tintColor.toArgb())
|
||||
it.isFocusable = composeState.value.preview !is ComposePreview.VoicePreview
|
||||
it.isFocusable = composeState.value.preview !is ComposePreview.VoicePreview && !cs.inProgress
|
||||
it.isFocusableInTouchMode = it.isFocusable
|
||||
if (cs.message != it.text.toString()) {
|
||||
it.setText(cs.message)
|
||||
@@ -270,7 +408,7 @@ private fun NativeKeyboard(
|
||||
imm.showSoftInput(it, InputMethodManager.SHOW_IMPLICIT)
|
||||
showKeyboard = false
|
||||
}
|
||||
showDeleteTextButton.value = it.lineCount >= 4
|
||||
showDeleteTextButton.value = it.lineCount >= 4 && !cs.inProgress
|
||||
}
|
||||
if (composeState.value.preview is ComposePreview.VoicePreview) {
|
||||
ComposeOverlay(R.string.voice_message_send_text, textStyle, padding)
|
||||
@@ -301,7 +439,7 @@ private fun BoxScope.DeleteTextButton(composeState: MutableState<ComposeState>)
|
||||
|
||||
@Composable
|
||||
private fun RecordVoiceView(recState: MutableState<RecordingState>, stopRecOnNextClick: MutableState<Boolean>) {
|
||||
val rec: Recorder = remember { RecorderNative(MAX_VOICE_SIZE_FOR_SENDING) }
|
||||
val rec: Recorder = remember { RecorderNative() }
|
||||
DisposableEffect(Unit) { onDispose { rec.stop() } }
|
||||
val stopRecordingAndAddAudio: () -> Unit = {
|
||||
recState.value.filePathNullable?.let {
|
||||
@@ -449,14 +587,14 @@ private fun SendMsgButton(
|
||||
sizeDp: Animatable<Float, AnimationVector1D>,
|
||||
alpha: Animatable<Float, AnimationVector1D>,
|
||||
enabled: Boolean,
|
||||
sendMessage: () -> Unit,
|
||||
sendMessage: (Int?) -> Unit,
|
||||
onLongClick: (() -> Unit)? = null
|
||||
) {
|
||||
val interactionSource = remember { MutableInteractionSource() }
|
||||
Box(
|
||||
modifier = Modifier.requiredSize(36.dp)
|
||||
.combinedClickable(
|
||||
onClick = sendMessage,
|
||||
onClick = { sendMessage(null) },
|
||||
onLongClick = onLongClick,
|
||||
enabled = enabled,
|
||||
role = Role.Button,
|
||||
@@ -601,6 +739,7 @@ fun PreviewSendMsgView() {
|
||||
userIsObserver = false,
|
||||
userCanSend = true,
|
||||
allowVoiceToContact = {},
|
||||
timedMessageAllowed = false,
|
||||
sendMessage = {},
|
||||
onMessageChange = { _ -> },
|
||||
textStyle = textStyle
|
||||
@@ -631,6 +770,7 @@ fun PreviewSendMsgViewEditing() {
|
||||
userIsObserver = false,
|
||||
userCanSend = true,
|
||||
allowVoiceToContact = {},
|
||||
timedMessageAllowed = false,
|
||||
sendMessage = {},
|
||||
onMessageChange = { _ -> },
|
||||
textStyle = textStyle
|
||||
@@ -661,6 +801,7 @@ fun PreviewSendMsgViewInProgress() {
|
||||
userIsObserver = false,
|
||||
userCanSend = true,
|
||||
allowVoiceToContact = {},
|
||||
timedMessageAllowed = false,
|
||||
sendMessage = {},
|
||||
onMessageChange = { _ -> },
|
||||
textStyle = textStyle
|
||||
|
||||
@@ -175,6 +175,8 @@ fun GroupChatInfoLayout(
|
||||
SectionView {
|
||||
if (groupInfo.canEdit) {
|
||||
EditGroupProfileButton(editGroupProfile)
|
||||
}
|
||||
if (groupInfo.groupProfile.description != null || groupInfo.canEdit) {
|
||||
AddOrEditWelcomeMessage(groupInfo.groupProfile.description, addOrEditWelcomeMessage)
|
||||
}
|
||||
GroupPreferencesButton(openPreferences)
|
||||
|
||||
+58
-4
@@ -4,7 +4,10 @@ import InfoRow
|
||||
import SectionBottomSpacer
|
||||
import SectionDividerSpaced
|
||||
import SectionSpacer
|
||||
import SectionTextFooter
|
||||
import SectionView
|
||||
import android.net.Uri
|
||||
import android.util.Log
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.layout.*
|
||||
@@ -13,17 +16,20 @@ import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import chat.simplex.app.*
|
||||
import chat.simplex.app.R
|
||||
import chat.simplex.app.model.*
|
||||
import chat.simplex.app.ui.theme.*
|
||||
import chat.simplex.app.views.chat.*
|
||||
import chat.simplex.app.views.helpers.*
|
||||
import chat.simplex.app.views.newchat.*
|
||||
import chat.simplex.app.views.usersettings.SettingsActionItem
|
||||
import kotlinx.datetime.Clock
|
||||
|
||||
@@ -64,6 +70,15 @@ fun GroupMemberInfoView(
|
||||
}
|
||||
}
|
||||
},
|
||||
connectViaAddress = { connReqUri ->
|
||||
val uri = Uri.parse(connReqUri)
|
||||
withUriAction(uri) { linkType ->
|
||||
withApi {
|
||||
Log.d(TAG, "connectViaUri: connecting")
|
||||
connectViaUri(chatModel, linkType, uri)
|
||||
}
|
||||
}
|
||||
},
|
||||
removeMember = { removeMemberDialog(groupInfo, member, chatModel, close) },
|
||||
onRoleSelected = {
|
||||
if (it == newRole.value) return@GroupMemberInfoLayout
|
||||
@@ -143,11 +158,21 @@ fun GroupMemberInfoLayout(
|
||||
connectionCode: String?,
|
||||
getContactChat: (Long) -> Chat?,
|
||||
openDirectChat: (Long) -> Unit,
|
||||
connectViaAddress: (String) -> Unit,
|
||||
removeMember: () -> Unit,
|
||||
onRoleSelected: (GroupMemberRole) -> Unit,
|
||||
switchMemberAddress: () -> Unit,
|
||||
verifyClicked: () -> Unit,
|
||||
) {
|
||||
fun knownDirectChat(contactId: Long): Chat? {
|
||||
val chat = getContactChat(contactId)
|
||||
return if (chat != null && chat.chatInfo is ChatInfo.Direct && chat.chatInfo.contact.directOrUsed) {
|
||||
chat
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
@@ -161,22 +186,39 @@ fun GroupMemberInfoLayout(
|
||||
}
|
||||
SectionSpacer()
|
||||
|
||||
val contactId = member.memberContactId
|
||||
|
||||
if (member.memberActive) {
|
||||
val contactId = member.memberContactId
|
||||
if (contactId != null) {
|
||||
SectionView {
|
||||
val chat = getContactChat(contactId)
|
||||
if ((chat != null && chat.chatInfo is ChatInfo.Direct && chat.chatInfo.contact.directOrUsed) || groupInfo.fullGroupPreferences.directMessages.on) {
|
||||
if (knownDirectChat(contactId) != null || groupInfo.fullGroupPreferences.directMessages.on) {
|
||||
OpenChatButton(onClick = { openDirectChat(contactId) })
|
||||
}
|
||||
if (connectionCode != null) {
|
||||
VerifyCodeButton(member.verified, verifyClicked)
|
||||
}
|
||||
}
|
||||
SectionSpacer()
|
||||
SectionDividerSpaced()
|
||||
}
|
||||
}
|
||||
|
||||
if (member.contactLink != null) {
|
||||
val context = LocalContext.current
|
||||
SectionView(stringResource(R.string.address_section_title).uppercase()) {
|
||||
QRCode(member.contactLink, Modifier.padding(horizontal = DEFAULT_PADDING, vertical = DEFAULT_PADDING_HALF).aspectRatio(1f))
|
||||
ShareAddressButton { shareText(context, member.contactLink) }
|
||||
if (contactId != null) {
|
||||
if (knownDirectChat(contactId) == null && !groupInfo.fullGroupPreferences.directMessages.on) {
|
||||
ConnectViaAddressButton(onClick = { connectViaAddress(member.contactLink) })
|
||||
}
|
||||
} else {
|
||||
ConnectViaAddressButton(onClick = { connectViaAddress(member.contactLink) })
|
||||
}
|
||||
SectionTextFooter(stringResource(R.string.you_can_share_this_address_with_your_contacts).format(member.displayName))
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
}
|
||||
|
||||
SectionView(title = stringResource(R.string.member_info_section_title_member)) {
|
||||
InfoRow(stringResource(R.string.info_row_group), groupInfo.displayName)
|
||||
val roles = remember { member.canChangeRoleTo(groupInfo) }
|
||||
@@ -281,6 +323,17 @@ fun OpenChatButton(onClick: () -> Unit) {
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ConnectViaAddressButton(onClick: () -> Unit) {
|
||||
SettingsActionItem(
|
||||
painterResource(R.drawable.ic_link),
|
||||
stringResource(R.string.connect_button),
|
||||
click = onClick,
|
||||
textColor = MaterialTheme.colors.primary,
|
||||
iconColor = MaterialTheme.colors.primary,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun RoleSelectionRow(
|
||||
roles: List<GroupMemberRole>,
|
||||
@@ -340,6 +393,7 @@ fun PreviewGroupMemberInfoLayout() {
|
||||
connectionCode = "123",
|
||||
getContactChat = { Chat.sampleData },
|
||||
openDirectChat = {},
|
||||
connectViaAddress = {},
|
||||
removeMember = {},
|
||||
onRoleSelected = {},
|
||||
switchMemberAddress = {},
|
||||
|
||||
+15
-3
@@ -17,7 +17,6 @@ import androidx.compose.ui.res.stringResource
|
||||
import chat.simplex.app.R
|
||||
import chat.simplex.app.model.*
|
||||
import chat.simplex.app.ui.theme.*
|
||||
import chat.simplex.app.views.chat.TimedMessagesTTLPicker
|
||||
import chat.simplex.app.views.helpers.*
|
||||
import chat.simplex.app.views.usersettings.PreferenceToggleWithIcon
|
||||
|
||||
@@ -95,6 +94,11 @@ private fun GroupPreferencesLayout(
|
||||
applyPrefs(preferences.copy(fullDelete = GroupPreference(enable = it)))
|
||||
}
|
||||
SectionDividerSpaced(true, maxBottomPadding = false)
|
||||
// val allowReactions = remember(preferences) { mutableStateOf(preferences.reactions.enable) }
|
||||
// FeatureSection(GroupFeature.Reactions, allowReactions, groupInfo, preferences, onTTLUpdated) {
|
||||
// applyPrefs(preferences.copy(reactions = GroupPreference(enable = it)))
|
||||
// }
|
||||
// SectionDividerSpaced(true, maxBottomPadding = false)
|
||||
val allowVoice = remember(preferences) { mutableStateOf(preferences.voice.enable) }
|
||||
FeatureSection(GroupFeature.Voice, allowVoice, groupInfo, preferences, onTTLUpdated) {
|
||||
applyPrefs(preferences.copy(voice = GroupPreference(enable = it)))
|
||||
@@ -136,7 +140,15 @@ private fun FeatureSection(
|
||||
}
|
||||
if (timedOn) {
|
||||
val ttl = rememberSaveable(preferences.timedMessages) { mutableStateOf(preferences.timedMessages.ttl) }
|
||||
TimedMessagesTTLPicker(ttl, onTTLUpdated)
|
||||
DropdownCustomTimePickerSettingRow(
|
||||
selection = ttl,
|
||||
propagateExternalSelectionUpdate = true, // for Reset
|
||||
label = generalGetString(R.string.delete_after),
|
||||
dropdownValues = TimedMessagesPreference.ttlValues.filterNotNull(), // TODO in 5.2 - allow "off"
|
||||
customPickerTitle = generalGetString(R.string.delete_after),
|
||||
customPickerConfirmButtonText = generalGetString(R.string.custom_time_picker_select),
|
||||
onSelected = onTTLUpdated
|
||||
)
|
||||
}
|
||||
} else {
|
||||
InfoRow(
|
||||
@@ -146,7 +158,7 @@ private fun FeatureSection(
|
||||
iconTint = iconTint,
|
||||
)
|
||||
if (timedOn) {
|
||||
InfoRow(generalGetString(R.string.delete_after), TimedMessagesPreference.ttlText(preferences.timedMessages.ttl))
|
||||
InfoRow(generalGetString(R.string.delete_after), timeText(preferences.timedMessages.ttl))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+99
-18
@@ -1,27 +1,35 @@
|
||||
package chat.simplex.app.views.chat.group
|
||||
|
||||
import SectionBottomSpacer
|
||||
import SectionDividerSpaced
|
||||
import SectionItemView
|
||||
import SectionSpacer
|
||||
import SectionView
|
||||
import TextIconSpaced
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.text.selection.SelectionContainer
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
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.model.*
|
||||
import chat.simplex.app.ui.theme.*
|
||||
import chat.simplex.app.ui.theme.DEFAULT_PADDING
|
||||
import chat.simplex.app.views.chat.item.MarkdownText
|
||||
import chat.simplex.app.views.helpers.*
|
||||
import kotlinx.coroutines.delay
|
||||
|
||||
@Composable
|
||||
fun GroupWelcomeView(m: ChatModel, groupInfo: GroupInfo, close: () -> Unit) {
|
||||
var groupInfo by remember { mutableStateOf(groupInfo) }
|
||||
val welcomeText = remember { mutableStateOf(groupInfo.groupProfile.description ?: "") }
|
||||
var gInfo by remember { mutableStateOf(groupInfo) }
|
||||
val welcomeText = remember { mutableStateOf(gInfo.groupProfile.description ?: "") }
|
||||
|
||||
fun save(afterSave: () -> Unit = {}) {
|
||||
withApi {
|
||||
@@ -29,10 +37,10 @@ fun GroupWelcomeView(m: ChatModel, groupInfo: GroupInfo, close: () -> Unit) {
|
||||
if (welcome?.length == 0) {
|
||||
welcome = null
|
||||
}
|
||||
val groupProfileUpdated = groupInfo.groupProfile.copy(description = welcome)
|
||||
val res = m.controller.apiUpdateGroup(groupInfo.groupId, groupProfileUpdated)
|
||||
val groupProfileUpdated = gInfo.groupProfile.copy(description = welcome)
|
||||
val res = m.controller.apiUpdateGroup(gInfo.groupId, groupProfileUpdated)
|
||||
if (res != null) {
|
||||
groupInfo = res
|
||||
gInfo = res
|
||||
m.updateGroup(res)
|
||||
welcomeText.value = welcome ?: ""
|
||||
}
|
||||
@@ -42,13 +50,14 @@ fun GroupWelcomeView(m: ChatModel, groupInfo: GroupInfo, close: () -> Unit) {
|
||||
|
||||
ModalView(
|
||||
close = {
|
||||
if (welcomeText.value == groupInfo.groupProfile.description || (welcomeText.value == "" && groupInfo.groupProfile.description == null)) close()
|
||||
if (welcomeText.value == gInfo.groupProfile.description || (welcomeText.value == "" && gInfo.groupProfile.description == null)) close()
|
||||
else showUnsavedChangesAlert({ save(close) }, close)
|
||||
},
|
||||
) {
|
||||
GroupWelcomeLayout(
|
||||
welcomeText,
|
||||
groupInfo,
|
||||
gInfo,
|
||||
m.controller.appPrefs.simplexLinkMode.get(),
|
||||
save = ::save
|
||||
)
|
||||
}
|
||||
@@ -58,23 +67,66 @@ fun GroupWelcomeView(m: ChatModel, groupInfo: GroupInfo, close: () -> Unit) {
|
||||
private fun GroupWelcomeLayout(
|
||||
welcomeText: MutableState<String>,
|
||||
groupInfo: GroupInfo,
|
||||
linkMode: SimplexLinkMode,
|
||||
save: () -> Unit,
|
||||
) {
|
||||
Column(
|
||||
Modifier.fillMaxWidth().verticalScroll(rememberScrollState()),
|
||||
) {
|
||||
val editMode = remember { mutableStateOf(true) }
|
||||
AppBarTitle(stringResource(R.string.group_welcome_title))
|
||||
val welcomeText = remember { welcomeText }
|
||||
TextEditor(Modifier.padding(horizontal = DEFAULT_PADDING).height(160.dp), text = welcomeText)
|
||||
SectionSpacer()
|
||||
SaveButton(
|
||||
save = save,
|
||||
disabled = welcomeText.value == groupInfo.groupProfile.description || (welcomeText.value == "" && groupInfo.groupProfile.description == null)
|
||||
)
|
||||
val wt = rememberSaveable { welcomeText }
|
||||
if (groupInfo.canEdit) {
|
||||
if (editMode.value) {
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
TextEditor(
|
||||
wt,
|
||||
Modifier.height(140.dp), stringResource(R.string.enter_welcome_message),
|
||||
focusRequester = focusRequester
|
||||
)
|
||||
LaunchedEffect(Unit) {
|
||||
delay(300)
|
||||
focusRequester.requestFocus()
|
||||
}
|
||||
} else {
|
||||
TextPreview(wt.value, linkMode)
|
||||
}
|
||||
ChangeModeButton(
|
||||
editMode.value,
|
||||
click = {
|
||||
editMode.value = !editMode.value
|
||||
},
|
||||
wt.value.isEmpty()
|
||||
)
|
||||
CopyTextButton { copyText(SimplexApp.context, wt.value) }
|
||||
SectionDividerSpaced(maxBottomPadding = false)
|
||||
SaveButton(
|
||||
save = save,
|
||||
disabled = wt.value == groupInfo.groupProfile.description || (wt.value == "" && groupInfo.groupProfile.description == null)
|
||||
)
|
||||
} else {
|
||||
TextPreview(wt.value, linkMode)
|
||||
CopyTextButton { copyText(SimplexApp.context, wt.value) }
|
||||
}
|
||||
SectionBottomSpacer()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TextPreview(text: String, linkMode: SimplexLinkMode, markdown: Boolean = true) {
|
||||
Column {
|
||||
SelectionContainer(Modifier.fillMaxWidth()) {
|
||||
MarkdownText(
|
||||
text,
|
||||
formattedText = if (markdown) remember(text) { parseToMarkdown(text) } else null,
|
||||
modifier = Modifier.fillMaxHeight().padding(horizontal = DEFAULT_PADDING),
|
||||
linkMode = linkMode,
|
||||
style = MaterialTheme.typography.body1.copy(color = MaterialTheme.colors.onBackground, lineHeight = 22.sp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SaveButton(save: () -> Unit, disabled: Boolean) {
|
||||
SectionView {
|
||||
@@ -84,6 +136,35 @@ private fun SaveButton(save: () -> Unit, disabled: Boolean) {
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ChangeModeButton(editMode: Boolean, click: () -> Unit, disabled: Boolean) {
|
||||
SectionItemView(click, disabled = disabled) {
|
||||
Icon(
|
||||
painterResource(if (editMode) R.drawable.ic_visibility else R.drawable.ic_edit),
|
||||
contentDescription = generalGetString(R.string.edit_verb),
|
||||
tint = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary,
|
||||
)
|
||||
TextIconSpaced()
|
||||
Text(
|
||||
stringResource(if (editMode) R.string.group_welcome_preview else R.string.edit_verb),
|
||||
color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CopyTextButton(click: () -> Unit) {
|
||||
SectionItemView(click) {
|
||||
Icon(
|
||||
painterResource(R.drawable.ic_content_copy),
|
||||
contentDescription = generalGetString(R.string.copy_verb),
|
||||
tint = MaterialTheme.colors.primary,
|
||||
)
|
||||
TextIconSpaced()
|
||||
Text(stringResource(R.string.copy_verb), color = MaterialTheme.colors.primary)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showUnsavedChangesAlert(save: () -> Unit, revert: () -> Unit) {
|
||||
AlertManager.shared.showAlertDialogStacked(
|
||||
title = generalGetString(R.string.save_welcome_message_question),
|
||||
|
||||
@@ -211,6 +211,7 @@ class ChatItemProvider: PreviewParameterProvider<ChatItem> {
|
||||
meta = CIMeta.getSample(1, Clock.System.now(), "", CIStatus.SndSent(), itemEdited = true),
|
||||
content = CIContent.SndMsgContent(msgContent = MsgContent.MCFile("")),
|
||||
quotedItem = null,
|
||||
reactions = listOf(),
|
||||
file = CIFile.getSample(fileStatus = CIFileStatus.SndComplete)
|
||||
)
|
||||
private val fileChatItemWtFile = ChatItem(
|
||||
@@ -218,6 +219,7 @@ class ChatItemProvider: PreviewParameterProvider<ChatItem> {
|
||||
meta = CIMeta.getSample(1, Clock.System.now(), "", CIStatus.RcvRead(), ),
|
||||
content = CIContent.RcvMsgContent(msgContent = MsgContent.MCFile("")),
|
||||
quotedItem = null,
|
||||
reactions = listOf(),
|
||||
file = null
|
||||
)
|
||||
override val values = listOf(
|
||||
|
||||
@@ -24,7 +24,7 @@ fun CIMetaView(chatItem: ChatItem, timedMessagesTTL: Int?, metaColor: Color = Ma
|
||||
Text(
|
||||
chatItem.timestampText,
|
||||
color = metaColor,
|
||||
fontSize = 14.sp,
|
||||
fontSize = 12.sp,
|
||||
modifier = Modifier.padding(start = 3.dp)
|
||||
)
|
||||
} else {
|
||||
@@ -44,7 +44,7 @@ private fun CIMetaText(meta: CIMeta, chatTTL: Int?, color: Color) {
|
||||
StatusIconText(painterResource(R.drawable.ic_timer), color)
|
||||
val ttl = meta.itemTimed?.ttl
|
||||
if (ttl != chatTTL) {
|
||||
Text(TimedMessagesPreference.shortTtlText(ttl), color = color, fontSize = 13.sp)
|
||||
Text(shortTimeText(ttl), color = color, fontSize = 12.sp)
|
||||
}
|
||||
Spacer(Modifier.width(4.dp))
|
||||
}
|
||||
@@ -57,7 +57,7 @@ private fun CIMetaText(meta: CIMeta, chatTTL: Int?, color: Color) {
|
||||
StatusIconText(painterResource(R.drawable.ic_circle_filled), Color.Transparent)
|
||||
Spacer(Modifier.width(4.dp))
|
||||
}
|
||||
Text(meta.timestampText, color = color, fontSize = 13.sp, maxLines = 1, overflow = TextOverflow.Ellipsis)
|
||||
Text(meta.timestampText, color = color, fontSize = 12.sp, maxLines = 1, overflow = TextOverflow.Ellipsis)
|
||||
}
|
||||
|
||||
// the conditions in this function should match CIMetaText
|
||||
@@ -69,7 +69,7 @@ fun reserveSpaceForMeta(meta: CIMeta, chatTTL: Int?): String {
|
||||
res += iconSpace
|
||||
val ttl = meta.itemTimed.ttl
|
||||
if (ttl != chatTTL) {
|
||||
res += TimedMessagesPreference.shortTtlText(ttl)
|
||||
res += shortTimeText(ttl)
|
||||
}
|
||||
}
|
||||
if (meta.statusIcon(CurrentColors.value.colors.secondary) != null || !meta.disappearing) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package chat.simplex.app.views.chat.item
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CornerSize
|
||||
@@ -9,20 +10,19 @@ import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.drawWithCache
|
||||
import androidx.compose.ui.draw.*
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.geometry.Size
|
||||
import androidx.compose.ui.graphics.*
|
||||
import androidx.compose.ui.graphics.drawscope.Stroke
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.*
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.*
|
||||
import chat.simplex.app.R
|
||||
import chat.simplex.app.model.*
|
||||
import chat.simplex.app.ui.theme.*
|
||||
import chat.simplex.app.views.helpers.*
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
|
||||
// TODO refactor https://github.com/simplex-chat/simplex-chat/pull/1451#discussion_r1033429901
|
||||
|
||||
@@ -36,9 +36,10 @@ fun CIVoiceView(
|
||||
ci: ChatItem,
|
||||
timedMessagesTTL: Int?,
|
||||
longClick: () -> Unit,
|
||||
receiveFile: (Long) -> Unit,
|
||||
) {
|
||||
Row(
|
||||
Modifier.padding(top = if (hasText) 14.dp else 4.dp, bottom = if (hasText) 14.dp else 6.dp, start = 6.dp, end = 6.dp),
|
||||
Modifier.padding(top = if (hasText) 14.dp else 4.dp, bottom = if (hasText) 14.dp else 6.dp, start = if (hasText) 6.dp else 0.dp, end = if (hasText) 6.dp else 0.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
if (file != null) {
|
||||
@@ -64,9 +65,11 @@ fun CIVoiceView(
|
||||
durationText(time / 1000)
|
||||
}
|
||||
}
|
||||
VoiceLayout(file, ci, text, audioPlaying, progress, duration, brokenAudio, sent, hasText, timedMessagesTTL, play, pause, longClick)
|
||||
VoiceLayout(file, ci, text, audioPlaying, progress, duration, brokenAudio, sent, hasText, timedMessagesTTL, play, pause, longClick, receiveFile) {
|
||||
AudioPlayer.seekTo(it, progress, filePath)
|
||||
}
|
||||
} else {
|
||||
VoiceMsgIndicator(null, false, sent, hasText, null, null, false, {}, {}, longClick)
|
||||
VoiceMsgIndicator(null, false, sent, hasText, null, null, false, {}, {}, longClick, receiveFile)
|
||||
val metaReserve = if (edited)
|
||||
" "
|
||||
else
|
||||
@@ -90,39 +93,89 @@ private fun VoiceLayout(
|
||||
timedMessagesTTL: Int?,
|
||||
play: () -> Unit,
|
||||
pause: () -> Unit,
|
||||
longClick: () -> Unit
|
||||
longClick: () -> Unit,
|
||||
receiveFile: (Long) -> Unit,
|
||||
onProgressChanged: (Int) -> Unit,
|
||||
) {
|
||||
@Composable
|
||||
fun RowScope.Slider(backgroundColor: Color, padding: PaddingValues = PaddingValues(horizontal = DEFAULT_PADDING_HALF)) {
|
||||
var movedManuallyTo by rememberSaveable(file.fileId) { mutableStateOf(-1) }
|
||||
if (audioPlaying.value || progress.value > 0 || movedManuallyTo == progress.value) {
|
||||
val dp4 = with(LocalDensity.current) { 4.dp.toPx() }
|
||||
val dp10 = with(LocalDensity.current) { 10.dp.toPx() }
|
||||
val primary = MaterialTheme.colors.primary
|
||||
val inactiveTrackColor =
|
||||
MaterialTheme.colors.primary.mixWith(
|
||||
backgroundColor.copy(1f).mixWith(MaterialTheme.colors.background, backgroundColor.alpha),
|
||||
0.24f)
|
||||
val width = with(LocalDensity.current) { LocalView.current.width.toDp() }
|
||||
val colors = SliderDefaults.colors(
|
||||
inactiveTrackColor = inactiveTrackColor
|
||||
)
|
||||
Slider(
|
||||
progress.value.toFloat(),
|
||||
onValueChange = {
|
||||
onProgressChanged(it.toInt())
|
||||
movedManuallyTo = it.toInt()
|
||||
},
|
||||
Modifier
|
||||
.size(width, 48.dp)
|
||||
.weight(1f)
|
||||
.padding(padding)
|
||||
.drawBehind {
|
||||
drawRect(primary, Offset(0f, (size.height - dp4) / 2), size = androidx.compose.ui.geometry.Size(dp10, dp4))
|
||||
drawRect(inactiveTrackColor, Offset(size.width - dp10, (size.height - dp4) / 2), size = androidx.compose.ui.geometry.Size(dp10, dp4))
|
||||
},
|
||||
valueRange = 0f..duration.value.toFloat(),
|
||||
colors = colors
|
||||
)
|
||||
LaunchedEffect(Unit) {
|
||||
snapshotFlow { audioPlaying.value }
|
||||
.distinctUntilChanged()
|
||||
.collect {
|
||||
movedManuallyTo = -1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
when {
|
||||
hasText -> {
|
||||
val sentColor = CurrentColors.collectAsState().value.appColors.sentMessage
|
||||
val receivedColor = CurrentColors.collectAsState().value.appColors.receivedMessage
|
||||
Spacer(Modifier.width(6.dp))
|
||||
VoiceMsgIndicator(file, audioPlaying.value, sent, hasText, progress, duration, brokenAudio, play, pause, longClick)
|
||||
DurationText(text, PaddingValues(start = 12.dp))
|
||||
VoiceMsgIndicator(file, audioPlaying.value, sent, hasText, progress, duration, brokenAudio, play, pause, longClick, receiveFile)
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
DurationText(text, PaddingValues(start = 12.dp))
|
||||
Slider(if (ci.chatDir.sent) sentColor else receivedColor)
|
||||
}
|
||||
}
|
||||
sent -> {
|
||||
Row {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Spacer(Modifier.height(56.dp))
|
||||
DurationText(text, PaddingValues(end = 12.dp))
|
||||
}
|
||||
Column {
|
||||
VoiceMsgIndicator(file, audioPlaying.value, sent, hasText, progress, duration, brokenAudio, play, pause, longClick)
|
||||
Box(Modifier.align(Alignment.CenterHorizontally).padding(top = 6.dp)) {
|
||||
CIMetaView(ci, timedMessagesTTL)
|
||||
Column(horizontalAlignment = Alignment.End) {
|
||||
Row {
|
||||
Row(Modifier.weight(1f, false), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.End) {
|
||||
Spacer(Modifier.height(56.dp))
|
||||
Slider(MaterialTheme.colors.background, PaddingValues(end = DEFAULT_PADDING_HALF + 3.dp))
|
||||
DurationText(text, PaddingValues(end = 12.dp))
|
||||
}
|
||||
VoiceMsgIndicator(file, audioPlaying.value, sent, hasText, progress, duration, brokenAudio, play, pause, longClick, receiveFile)
|
||||
}
|
||||
Box(Modifier.padding(top = 6.dp, end = 6.dp)) {
|
||||
CIMetaView(ci, timedMessagesTTL)
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
Row {
|
||||
Column {
|
||||
VoiceMsgIndicator(file, audioPlaying.value, sent, hasText, progress, duration, brokenAudio, play, pause, longClick)
|
||||
Box(Modifier.align(Alignment.CenterHorizontally).padding(top = 6.dp)) {
|
||||
CIMetaView(ci, timedMessagesTTL)
|
||||
Column(horizontalAlignment = Alignment.Start) {
|
||||
Row {
|
||||
VoiceMsgIndicator(file, audioPlaying.value, sent, hasText, progress, duration, brokenAudio, play, pause, longClick, receiveFile)
|
||||
Row(Modifier.weight(1f, false), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.Start) {
|
||||
DurationText(text, PaddingValues(start = 12.dp))
|
||||
Slider(MaterialTheme.colors.background, PaddingValues(start = DEFAULT_PADDING_HALF + 3.dp))
|
||||
Spacer(Modifier.height(56.dp))
|
||||
}
|
||||
}
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
DurationText(text, PaddingValues(start = 12.dp))
|
||||
Spacer(Modifier.height(56.dp))
|
||||
Box(Modifier.padding(top = 6.dp)) {
|
||||
CIMetaView(ci, timedMessagesTTL)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -193,7 +246,8 @@ private fun VoiceMsgIndicator(
|
||||
error: Boolean,
|
||||
play: () -> Unit,
|
||||
pause: () -> Unit,
|
||||
longClick: () -> Unit
|
||||
longClick: () -> Unit,
|
||||
receiveFile: (Long) -> Unit,
|
||||
) {
|
||||
val strokeWidth = with(LocalDensity.current) { 3.dp.toPx() }
|
||||
val strokeColor = MaterialTheme.colors.primary
|
||||
@@ -212,8 +266,9 @@ private fun VoiceMsgIndicator(
|
||||
PlayPauseButton(audioPlaying, sent, angle, strokeWidth, strokeColor, true, error, play, pause, longClick = longClick)
|
||||
}
|
||||
} else {
|
||||
if (file?.fileStatus is CIFileStatus.RcvInvitation
|
||||
|| file?.fileStatus is CIFileStatus.RcvTransfer
|
||||
if (file?.fileStatus is CIFileStatus.RcvInvitation) {
|
||||
PlayPauseButton(audioPlaying, sent, 0f, strokeWidth, strokeColor, true, error, { receiveFile(file.fileId) }, {}, longClick = longClick)
|
||||
} else if (file?.fileStatus is CIFileStatus.RcvTransfer
|
||||
|| file?.fileStatus is CIFileStatus.RcvAccepted
|
||||
) {
|
||||
Box(
|
||||
|
||||
@@ -2,7 +2,8 @@ package chat.simplex.app.views.chat.item
|
||||
|
||||
import android.Manifest
|
||||
import android.os.Build
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.gestures.scrollable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.*
|
||||
@@ -16,15 +17,17 @@ import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.platform.*
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
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.model.*
|
||||
import chat.simplex.app.ui.theme.*
|
||||
import chat.simplex.app.views.chat.ComposeContextItem
|
||||
import chat.simplex.app.views.chat.ComposeState
|
||||
import chat.simplex.app.views.chat.*
|
||||
import chat.simplex.app.views.helpers.*
|
||||
import chat.simplex.app.views.usersettings.IncognitoView
|
||||
import com.google.accompanist.permissions.rememberPermissionState
|
||||
import kotlinx.datetime.Clock
|
||||
|
||||
@@ -45,7 +48,9 @@ fun ChatItemView(
|
||||
joinGroup: (Long) -> Unit,
|
||||
acceptCall: (Contact) -> Unit,
|
||||
scrollToItem: (Long) -> Unit,
|
||||
acceptFeature: (Contact, ChatFeature, Int?) -> Unit
|
||||
acceptFeature: (Contact, ChatFeature, Int?) -> Unit,
|
||||
setReaction: (ChatInfo, ChatItem, Boolean, MsgReaction) -> Unit,
|
||||
showItemDetails: (ChatInfo, ChatItem) -> Unit,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val uriHandler = LocalUriHandler.current
|
||||
@@ -75,186 +80,256 @@ fun ChatItemView(
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
Column(
|
||||
Modifier
|
||||
.clip(RoundedCornerShape(18.dp))
|
||||
.combinedClickable(onLongClick = { showMenu.value = true }, onClick = onClick),
|
||||
) {
|
||||
@Composable
|
||||
fun framedItemView() {
|
||||
FramedItemView(cInfo, cItem, uriHandler, imageProvider, showMember = showMember, linkMode = linkMode, showMenu, receiveFile, onLinkLongClick, scrollToItem)
|
||||
}
|
||||
|
||||
fun deleteMessageQuestionText(): String {
|
||||
return if (fullDeleteAllowed) {
|
||||
generalGetString(R.string.delete_message_cannot_be_undone_warning)
|
||||
} else {
|
||||
generalGetString(R.string.delete_message_mark_deleted_warning)
|
||||
}
|
||||
}
|
||||
|
||||
fun moderateMessageQuestionText(): String {
|
||||
return if (fullDeleteAllowed) {
|
||||
generalGetString(R.string.moderate_message_will_be_deleted_warning)
|
||||
} else {
|
||||
generalGetString(R.string.moderate_message_will_be_marked_warning)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MsgContentItemDropdownMenu() {
|
||||
DefaultDropdownMenu(showMenu) {
|
||||
if (cItem.meta.itemDeleted == null && !live) {
|
||||
ItemAction(stringResource(R.string.reply_verb), painterResource(R.drawable.ic_reply), onClick = {
|
||||
if (composeState.value.editing) {
|
||||
composeState.value = ComposeState(contextItem = ComposeContextItem.QuotedItem(cItem), useLinkPreviews = useLinkPreviews)
|
||||
} else {
|
||||
composeState.value = composeState.value.copy(contextItem = ComposeContextItem.QuotedItem(cItem))
|
||||
}
|
||||
showMenu.value = false
|
||||
})
|
||||
}
|
||||
ItemAction(stringResource(R.string.share_verb), painterResource(R.drawable.ic_share), onClick = {
|
||||
val filePath = getLoadedFilePath(SimplexApp.context, cItem.file)
|
||||
when {
|
||||
filePath != null -> shareFile(context, cItem.text, filePath)
|
||||
else -> shareText(context, cItem.content.text)
|
||||
@Composable
|
||||
fun ChatItemReactions() {
|
||||
Row {
|
||||
cItem.reactions.forEach { r ->
|
||||
var modifier = Modifier.padding(horizontal = 5.dp, vertical = 2.dp).clip(RoundedCornerShape(8.dp))
|
||||
if (cInfo.featureEnabled(ChatFeature.Reactions) && (cItem.allowAddReaction || r.userReacted)) {
|
||||
modifier = modifier.clickable {
|
||||
setReaction(cInfo, cItem, !r.userReacted, r.reaction)
|
||||
}
|
||||
showMenu.value = false
|
||||
})
|
||||
ItemAction(stringResource(R.string.copy_verb), painterResource(R.drawable.ic_content_copy), onClick = {
|
||||
copyText(context, cItem.content.text)
|
||||
showMenu.value = false
|
||||
})
|
||||
if (cItem.content.msgContent is MsgContent.MCImage || cItem.content.msgContent is MsgContent.MCVideo || cItem.content.msgContent is MsgContent.MCFile || cItem.content.msgContent is MsgContent.MCVoice) {
|
||||
val filePath = getLoadedFilePath(context, cItem.file)
|
||||
if (filePath != null) {
|
||||
val writePermissionState = rememberPermissionState(permission = Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
ItemAction(stringResource(R.string.save_verb), painterResource(R.drawable.ic_download), onClick = {
|
||||
when (cItem.content.msgContent) {
|
||||
is MsgContent.MCImage -> {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R || writePermissionState.hasPermission) {
|
||||
saveImage(context, cItem.file)
|
||||
} else {
|
||||
writePermissionState.launchPermissionRequest()
|
||||
}
|
||||
}
|
||||
is MsgContent.MCFile, is MsgContent.MCVoice, is MsgContent.MCVideo -> saveFileLauncher.launch(cItem.file?.fileName)
|
||||
else -> {}
|
||||
}
|
||||
Row(modifier.padding(2.dp)) {
|
||||
Text(r.reaction.text, fontSize = 12.sp)
|
||||
if (r.totalReacted > 1) {
|
||||
Spacer(Modifier.width(4.dp))
|
||||
Text("${r.totalReacted}",
|
||||
fontSize = 11.5.sp,
|
||||
fontWeight = if (r.userReacted) FontWeight.Bold else FontWeight.Normal,
|
||||
color = if (r.userReacted) MaterialTheme.colors.primary else MaterialTheme.colors.secondary,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column(horizontalAlignment = if (cItem.chatDir.sent) Alignment.End else Alignment.Start) {
|
||||
Column(
|
||||
Modifier
|
||||
.clip(RoundedCornerShape(18.dp))
|
||||
.combinedClickable(onLongClick = { showMenu.value = true }, onClick = onClick),
|
||||
) {
|
||||
@Composable
|
||||
fun framedItemView() {
|
||||
FramedItemView(cInfo, cItem, uriHandler, imageProvider, showMember = showMember, linkMode = linkMode, showMenu, receiveFile, onLinkLongClick, scrollToItem)
|
||||
}
|
||||
|
||||
fun deleteMessageQuestionText(): String {
|
||||
return if (fullDeleteAllowed) {
|
||||
generalGetString(R.string.delete_message_cannot_be_undone_warning)
|
||||
} else {
|
||||
generalGetString(R.string.delete_message_mark_deleted_warning)
|
||||
}
|
||||
}
|
||||
|
||||
fun moderateMessageQuestionText(): String {
|
||||
return if (fullDeleteAllowed) {
|
||||
generalGetString(R.string.moderate_message_will_be_deleted_warning)
|
||||
} else {
|
||||
generalGetString(R.string.moderate_message_will_be_marked_warning)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MsgReactionsMenu() {
|
||||
val rs = MsgReaction.values.mapNotNull { r ->
|
||||
if (null == cItem.reactions.find { it.userReacted && it.reaction.text == r.text }) {
|
||||
r
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
if (rs.isNotEmpty()) {
|
||||
Row(modifier = Modifier.padding(horizontal = DEFAULT_PADDING).horizontalScroll(rememberScrollState())) {
|
||||
rs.forEach() { r ->
|
||||
Box(
|
||||
Modifier.size(36.dp).clickable {
|
||||
setReaction(cInfo, cItem, true, r)
|
||||
showMenu.value = false
|
||||
},
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(r.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MsgContentItemDropdownMenu() {
|
||||
DefaultDropdownMenu(showMenu) {
|
||||
if (cInfo.featureEnabled(ChatFeature.Reactions) && cItem.allowAddReaction) {
|
||||
MsgReactionsMenu()
|
||||
}
|
||||
if (cItem.meta.itemDeleted == null && !live) {
|
||||
ItemAction(stringResource(R.string.reply_verb), painterResource(R.drawable.ic_reply), onClick = {
|
||||
if (composeState.value.editing) {
|
||||
composeState.value = ComposeState(contextItem = ComposeContextItem.QuotedItem(cItem), useLinkPreviews = useLinkPreviews)
|
||||
} else {
|
||||
composeState.value = composeState.value.copy(contextItem = ComposeContextItem.QuotedItem(cItem))
|
||||
}
|
||||
showMenu.value = false
|
||||
})
|
||||
}
|
||||
}
|
||||
if (cItem.meta.editable && cItem.content.msgContent !is MsgContent.MCVoice && !live) {
|
||||
ItemAction(stringResource(R.string.edit_verb), painterResource(R.drawable.ic_edit_filled), onClick = {
|
||||
composeState.value = ComposeState(editingItem = cItem, useLinkPreviews = useLinkPreviews)
|
||||
ItemAction(stringResource(R.string.share_verb), painterResource(R.drawable.ic_share), onClick = {
|
||||
val filePath = getLoadedFilePath(SimplexApp.context, cItem.file)
|
||||
when {
|
||||
filePath != null -> shareFile(context, cItem.text, filePath)
|
||||
else -> shareText(context, cItem.content.text)
|
||||
}
|
||||
showMenu.value = false
|
||||
})
|
||||
}
|
||||
if (cItem.meta.itemDeleted != null && revealed.value) {
|
||||
ItemAction(
|
||||
stringResource(R.string.hide_verb),
|
||||
painterResource(R.drawable.ic_visibility_off),
|
||||
onClick = {
|
||||
revealed.value = false
|
||||
showMenu.value = false
|
||||
ItemAction(stringResource(R.string.copy_verb), painterResource(R.drawable.ic_content_copy), onClick = {
|
||||
copyText(context, cItem.content.text)
|
||||
showMenu.value = false
|
||||
})
|
||||
if (cItem.content.msgContent is MsgContent.MCImage || cItem.content.msgContent is MsgContent.MCVideo || cItem.content.msgContent is MsgContent.MCFile || cItem.content.msgContent is MsgContent.MCVoice) {
|
||||
val filePath = getLoadedFilePath(context, cItem.file)
|
||||
if (filePath != null) {
|
||||
val writePermissionState = rememberPermissionState(permission = Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
ItemAction(stringResource(R.string.save_verb), painterResource(R.drawable.ic_download), onClick = {
|
||||
when (cItem.content.msgContent) {
|
||||
is MsgContent.MCImage -> {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R || writePermissionState.hasPermission) {
|
||||
saveImage(context, cItem.file)
|
||||
} else {
|
||||
writePermissionState.launchPermissionRequest()
|
||||
}
|
||||
}
|
||||
is MsgContent.MCFile, is MsgContent.MCVoice, is MsgContent.MCVideo -> saveFileLauncher.launch(cItem.file?.fileName)
|
||||
else -> {}
|
||||
}
|
||||
showMenu.value = false
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
if (cItem.meta.editable && cItem.content.msgContent !is MsgContent.MCVoice && !live) {
|
||||
ItemAction(stringResource(R.string.edit_verb), painterResource(R.drawable.ic_edit_filled), onClick = {
|
||||
composeState.value = ComposeState(editingItem = cItem, useLinkPreviews = useLinkPreviews)
|
||||
showMenu.value = false
|
||||
})
|
||||
}
|
||||
if (cItem.meta.itemDeleted != null && revealed.value) {
|
||||
ItemAction(
|
||||
stringResource(R.string.hide_verb),
|
||||
painterResource(R.drawable.ic_visibility_off),
|
||||
onClick = {
|
||||
revealed.value = false
|
||||
showMenu.value = false
|
||||
}
|
||||
)
|
||||
}
|
||||
if (cItem.meta.itemDeleted == null && cItem.file != null && cItem.file.cancelAction != null) {
|
||||
CancelFileItemAction(cItem.file.fileId, showMenu, cancelFile = cancelFile, cancelAction = cItem.file.cancelAction)
|
||||
}
|
||||
ItemInfoAction(cInfo, cItem, showItemDetails, showMenu)
|
||||
if (!(live && cItem.meta.isLive)) {
|
||||
DeleteItemAction(cItem, showMenu, questionText = deleteMessageQuestionText(), deleteMessage)
|
||||
}
|
||||
val groupInfo = cItem.memberToModerate(cInfo)?.first
|
||||
if (groupInfo != null) {
|
||||
ModerateItemAction(cItem, questionText = moderateMessageQuestionText(), showMenu, deleteMessage)
|
||||
}
|
||||
}
|
||||
if (cItem.meta.itemDeleted == null && cItem.file != null && cItem.file.cancelAction != null) {
|
||||
CancelFileItemAction(cItem.file.fileId, showMenu, cancelFile = cancelFile, cancelAction = cItem.file.cancelAction)
|
||||
}
|
||||
if (!(live && cItem.meta.isLive)) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MarkedDeletedItemDropdownMenu() {
|
||||
DefaultDropdownMenu(showMenu) {
|
||||
if (!cItem.isDeletedContent) {
|
||||
ItemAction(
|
||||
stringResource(R.string.reveal_verb),
|
||||
painterResource(R.drawable.ic_visibility),
|
||||
onClick = {
|
||||
revealed.value = true
|
||||
showMenu.value = false
|
||||
}
|
||||
)
|
||||
ItemInfoAction(cInfo, cItem, showItemDetails, showMenu)
|
||||
}
|
||||
DeleteItemAction(cItem, showMenu, questionText = deleteMessageQuestionText(), deleteMessage)
|
||||
}
|
||||
val groupInfo = cItem.memberToModerate(cInfo)?.first
|
||||
if (groupInfo != null) {
|
||||
ModerateItemAction(cItem, questionText = moderateMessageQuestionText(), showMenu, deleteMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MarkedDeletedItemDropdownMenu() {
|
||||
DefaultDropdownMenu(showMenu) {
|
||||
if (!cItem.isDeletedContent) {
|
||||
ItemAction(
|
||||
stringResource(R.string.reveal_verb),
|
||||
painterResource(R.drawable.ic_visibility),
|
||||
onClick = {
|
||||
revealed.value = true
|
||||
showMenu.value = false
|
||||
}
|
||||
)
|
||||
}
|
||||
DeleteItemAction(cItem, showMenu, questionText = deleteMessageQuestionText(), deleteMessage)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ContentItem() {
|
||||
val mc = cItem.content.msgContent
|
||||
if (cItem.meta.itemDeleted != null && !revealed.value) {
|
||||
MarkedDeletedItemView(cItem, cInfo.timedMessagesTTL, showMember = showMember)
|
||||
MarkedDeletedItemDropdownMenu()
|
||||
} 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()
|
||||
} else if (mc is MsgContent.MCVoice && cItem.content.text.isEmpty()) {
|
||||
CIVoiceView(mc.duration, cItem.file, cItem.meta.itemEdited, cItem.chatDir.sent, hasText = false, cItem, cInfo.timedMessagesTTL, longClick = { onLinkLongClick("") })
|
||||
MsgContentItemDropdownMenu()
|
||||
@Composable
|
||||
fun ContentItem() {
|
||||
val mc = cItem.content.msgContent
|
||||
if (cItem.meta.itemDeleted != null && !revealed.value) {
|
||||
MarkedDeletedItemView(cItem, cInfo.timedMessagesTTL, showMember = showMember)
|
||||
MarkedDeletedItemDropdownMenu()
|
||||
} else {
|
||||
framedItemView()
|
||||
if (cItem.quotedItem == null && cItem.meta.itemDeleted == null && !cItem.meta.isLive) {
|
||||
if (mc is MsgContent.MCText && isShortEmoji(cItem.content.text)) {
|
||||
EmojiItemView(cItem, cInfo.timedMessagesTTL)
|
||||
} else if (mc is MsgContent.MCVoice && cItem.content.text.isEmpty()) {
|
||||
CIVoiceView(mc.duration, cItem.file, cItem.meta.itemEdited, cItem.chatDir.sent, hasText = false, cItem, cInfo.timedMessagesTTL, longClick = { onLinkLongClick("") }, receiveFile)
|
||||
} else {
|
||||
framedItemView()
|
||||
}
|
||||
} else {
|
||||
framedItemView()
|
||||
}
|
||||
MsgContentItemDropdownMenu()
|
||||
}
|
||||
} else {
|
||||
framedItemView()
|
||||
MsgContentItemDropdownMenu()
|
||||
}
|
||||
|
||||
@Composable fun DeletedItem() {
|
||||
DeletedItemView(cItem, cInfo.timedMessagesTTL, showMember = showMember)
|
||||
DefaultDropdownMenu(showMenu) {
|
||||
DeleteItemAction(cItem, showMenu, questionText = deleteMessageQuestionText(), deleteMessage)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable fun CallItem(status: CICallStatus, duration: Int) {
|
||||
CICallItemView(cInfo, cItem, status, duration, acceptCall)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ModeratedItem() {
|
||||
MarkedDeletedItemView(cItem, cInfo.timedMessagesTTL, showMember = showMember)
|
||||
DefaultDropdownMenu(showMenu) {
|
||||
DeleteItemAction(cItem, showMenu, questionText = generalGetString(R.string.delete_message_cannot_be_undone_warning), deleteMessage)
|
||||
}
|
||||
}
|
||||
|
||||
when (val c = cItem.content) {
|
||||
is CIContent.SndMsgContent -> ContentItem()
|
||||
is CIContent.RcvMsgContent -> ContentItem()
|
||||
is CIContent.SndDeleted -> DeletedItem()
|
||||
is CIContent.RcvDeleted -> DeletedItem()
|
||||
is CIContent.SndCall -> CallItem(c.status, c.duration)
|
||||
is CIContent.RcvCall -> CallItem(c.status, c.duration)
|
||||
is CIContent.RcvIntegrityError -> IntegrityErrorItemView(c.msgError, cItem, cInfo.timedMessagesTTL, showMember = showMember)
|
||||
is CIContent.RcvDecryptionError -> CIRcvDecryptionError(c.msgDecryptError, c.msgCount, cItem, cInfo.timedMessagesTTL, showMember = showMember)
|
||||
is CIContent.RcvGroupInvitation -> CIGroupInvitationView(cItem, c.groupInvitation, c.memberRole, joinGroup = joinGroup, chatIncognito = cInfo.incognito)
|
||||
is CIContent.SndGroupInvitation -> CIGroupInvitationView(cItem, c.groupInvitation, c.memberRole, joinGroup = joinGroup, chatIncognito = cInfo.incognito)
|
||||
is CIContent.RcvGroupEventContent -> CIEventView(cItem)
|
||||
is CIContent.SndGroupEventContent -> CIEventView(cItem)
|
||||
is CIContent.RcvConnEventContent -> CIEventView(cItem)
|
||||
is CIContent.SndConnEventContent -> CIEventView(cItem)
|
||||
is CIContent.RcvChatFeature -> CIChatFeatureView(cItem, c.feature, c.enabled.iconColor)
|
||||
is CIContent.SndChatFeature -> CIChatFeatureView(cItem, c.feature, c.enabled.iconColor)
|
||||
is CIContent.RcvChatPreference -> {
|
||||
val ct = if (cInfo is ChatInfo.Direct) cInfo.contact else null
|
||||
CIFeaturePreferenceView(cItem, ct, c.feature, c.allowed, acceptFeature)
|
||||
}
|
||||
is CIContent.SndChatPreference -> CIChatFeatureView(cItem, c.feature, MaterialTheme.colors.secondary, icon = c.feature.icon,)
|
||||
is CIContent.RcvGroupFeature -> CIChatFeatureView(cItem, c.groupFeature, c.preference.enable.iconColor)
|
||||
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 -> ModeratedItem()
|
||||
is CIContent.RcvModerated -> ModeratedItem()
|
||||
is CIContent.InvalidJSON -> CIInvalidJSONView(c.json)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable fun DeletedItem() {
|
||||
DeletedItemView(cItem, cInfo.timedMessagesTTL, showMember = showMember)
|
||||
DefaultDropdownMenu(showMenu) {
|
||||
DeleteItemAction(cItem, showMenu, questionText = deleteMessageQuestionText(), deleteMessage)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable fun CallItem(status: CICallStatus, duration: Int) {
|
||||
CICallItemView(cInfo, cItem, status, duration, acceptCall)
|
||||
}
|
||||
|
||||
when (val c = cItem.content) {
|
||||
is CIContent.SndMsgContent -> ContentItem()
|
||||
is CIContent.RcvMsgContent -> ContentItem()
|
||||
is CIContent.SndDeleted -> DeletedItem()
|
||||
is CIContent.RcvDeleted -> DeletedItem()
|
||||
is CIContent.SndCall -> CallItem(c.status, c.duration)
|
||||
is CIContent.RcvCall -> CallItem(c.status, c.duration)
|
||||
is CIContent.RcvIntegrityError -> IntegrityErrorItemView(c.msgError, cItem, cInfo.timedMessagesTTL, showMember = showMember)
|
||||
is CIContent.RcvDecryptionError -> CIRcvDecryptionError(c.msgDecryptError, c.msgCount, cItem, cInfo.timedMessagesTTL, showMember = showMember)
|
||||
is CIContent.RcvGroupInvitation -> CIGroupInvitationView(cItem, c.groupInvitation, c.memberRole, joinGroup = joinGroup, chatIncognito = cInfo.incognito)
|
||||
is CIContent.SndGroupInvitation -> CIGroupInvitationView(cItem, c.groupInvitation, c.memberRole, joinGroup = joinGroup, chatIncognito = cInfo.incognito)
|
||||
is CIContent.RcvGroupEventContent -> CIEventView(cItem)
|
||||
is CIContent.SndGroupEventContent -> CIEventView(cItem)
|
||||
is CIContent.RcvConnEventContent -> CIEventView(cItem)
|
||||
is CIContent.SndConnEventContent -> CIEventView(cItem)
|
||||
is CIContent.RcvChatFeature -> CIChatFeatureView(cItem, c.feature, c.enabled.iconColor)
|
||||
is CIContent.SndChatFeature -> CIChatFeatureView(cItem, c.feature, c.enabled.iconColor)
|
||||
is CIContent.RcvChatPreference -> {
|
||||
val ct = if (cInfo is ChatInfo.Direct) cInfo.contact else null
|
||||
CIFeaturePreferenceView(cItem, ct, c.feature, c.allowed, acceptFeature)
|
||||
}
|
||||
is CIContent.SndChatPreference -> CIChatFeatureView(cItem, c.feature, MaterialTheme.colors.secondary, icon = c.feature.icon,)
|
||||
is CIContent.RcvGroupFeature -> CIChatFeatureView(cItem, c.groupFeature, c.preference.enable.iconColor)
|
||||
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 -> MarkedDeletedItemView(cItem, cInfo.timedMessagesTTL, showMember = showMember)
|
||||
is CIContent.RcvModerated -> MarkedDeletedItemView(cItem, cInfo.timedMessagesTTL, showMember = showMember)
|
||||
is CIContent.InvalidJSON -> CIInvalidJSONView(c.json)
|
||||
if (cItem.content.msgContent != null && (cItem.meta.itemDeleted == null || revealed.value) && cItem.reactions.isNotEmpty()) {
|
||||
ChatItemReactions()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -278,6 +353,24 @@ fun CancelFileItemAction(
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ItemInfoAction(
|
||||
cInfo: ChatInfo,
|
||||
cItem: ChatItem,
|
||||
showItemDetails: (ChatInfo, ChatItem) -> Unit,
|
||||
showMenu: MutableState<Boolean>
|
||||
) {
|
||||
ItemAction(
|
||||
stringResource(R.string.info_menu),
|
||||
painterResource(R.drawable.ic_info),
|
||||
onClick = {
|
||||
showItemDetails(cInfo, cItem)
|
||||
showMenu.value = false
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
fun DeleteItemAction(
|
||||
cItem: ChatItem,
|
||||
@@ -430,7 +523,9 @@ fun PreviewChatItemView() {
|
||||
joinGroup = {},
|
||||
acceptCall = { _ -> },
|
||||
scrollToItem = {},
|
||||
acceptFeature = { _, _, _ -> }
|
||||
acceptFeature = { _, _, _ -> },
|
||||
setReaction = { _, _, _, _ -> },
|
||||
showItemDetails = { _, _ -> },
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -451,7 +546,9 @@ fun PreviewChatItemViewDeletedContent() {
|
||||
joinGroup = {},
|
||||
acceptCall = { _ -> },
|
||||
scrollToItem = {},
|
||||
acceptFeature = { _, _, _ -> }
|
||||
acceptFeature = { _, _, _ -> },
|
||||
setReaction = { _, _, _, _ -> },
|
||||
showItemDetails = { _, _ -> },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,7 +221,7 @@ fun FramedItemView(
|
||||
}
|
||||
}
|
||||
is MsgContent.MCVoice -> {
|
||||
CIVoiceView(mc.duration, ci.file, ci.meta.itemEdited, ci.chatDir.sent, hasText = true, ci, timedMessagesTTL = chatTTL, longClick = { onLinkLongClick("") })
|
||||
CIVoiceView(mc.duration, ci.file, ci.meta.itemEdited, ci.chatDir.sent, hasText = true, ci, timedMessagesTTL = chatTTL, longClick = { onLinkLongClick("") }, receiveFile)
|
||||
if (mc.text != "") {
|
||||
CIMarkdownText(ci, chatTTL, showMember, linkMode, uriHandler)
|
||||
}
|
||||
|
||||
+2
-1
@@ -19,6 +19,7 @@ import chat.simplex.app.model.CIDeleted
|
||||
import chat.simplex.app.model.ChatItem
|
||||
import chat.simplex.app.ui.theme.*
|
||||
import chat.simplex.app.views.helpers.generalGetString
|
||||
import kotlinx.datetime.Clock
|
||||
|
||||
@Composable
|
||||
fun MarkedDeletedItemView(ci: ChatItem, timedMessagesTTL: Int?, showMember: Boolean = false) {
|
||||
@@ -67,7 +68,7 @@ private fun MarkedDeletedText(text: String) {
|
||||
fun PreviewMarkedDeletedItemView() {
|
||||
SimpleXTheme {
|
||||
DeletedItemView(
|
||||
ChatItem.getSampleData(itemDeleted = CIDeleted.Deleted()),
|
||||
ChatItem.getSampleData(itemDeleted = CIDeleted.Deleted(Clock.System.now())),
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
@@ -18,7 +17,7 @@ import androidx.compose.ui.unit.sp
|
||||
import chat.simplex.app.R
|
||||
import chat.simplex.app.ui.theme.SimpleXTheme
|
||||
import chat.simplex.app.views.helpers.annotatedStringResource
|
||||
import chat.simplex.app.views.helpers.openUriCatching
|
||||
import chat.simplex.app.views.onboarding.ReadableTextWithLink
|
||||
import chat.simplex.app.views.usersettings.MarkdownHelpView
|
||||
import chat.simplex.app.views.usersettings.simplexTeamUri
|
||||
|
||||
@@ -29,17 +28,8 @@ fun ChatHelpView(addContact: (() -> Unit)? = null) {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(10.dp)
|
||||
) {
|
||||
val uriHandler = LocalUriHandler.current
|
||||
|
||||
Text(stringResource(R.string.thank_you_for_installing_simplex), lineHeight = 22.sp)
|
||||
Text(
|
||||
annotatedStringResource(R.string.you_can_connect_to_simplex_chat_founder),
|
||||
modifier = Modifier.clickable(onClick = {
|
||||
uriHandler.openUriCatching(simplexTeamUri)
|
||||
}),
|
||||
lineHeight = 22.sp
|
||||
)
|
||||
|
||||
ReadableTextWithLink(R.string.you_can_connect_to_simplex_chat_founder, simplexTeamUri)
|
||||
Column(
|
||||
Modifier.padding(top = 24.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(10.dp)
|
||||
|
||||
@@ -35,7 +35,6 @@ fun ShareListView(chatModel: ChatModel, stopped: Boolean) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.themedBackground()
|
||||
) {
|
||||
if (chatModel.chats.isNotEmpty()) {
|
||||
ShareList(chatModel, search = searchInList)
|
||||
|
||||
@@ -64,7 +64,6 @@ fun DatabaseView(
|
||||
importArchiveAlert(m, context, uri, appFilesCountAndSize, progressIndicator)
|
||||
}
|
||||
}
|
||||
val chatDbDeleted = remember { m.chatDbDeleted }
|
||||
LaunchedEffect(m.chatRunning) {
|
||||
runChat.value = m.chatRunning.value ?: true
|
||||
}
|
||||
@@ -83,7 +82,6 @@ fun DatabaseView(
|
||||
chatArchiveName,
|
||||
chatArchiveTime,
|
||||
chatLastStart,
|
||||
chatDbDeleted.value,
|
||||
m.controller.appPrefs.privacyFullBackup,
|
||||
appFilesCountAndSize,
|
||||
chatItemTTL,
|
||||
@@ -134,7 +132,6 @@ fun DatabaseLayout(
|
||||
chatArchiveName: MutableState<String?>,
|
||||
chatArchiveTime: MutableState<Instant?>,
|
||||
chatLastStart: MutableState<Instant?>,
|
||||
chatDbDeleted: Boolean,
|
||||
privacyFullBackup: SharedPreference<Boolean>,
|
||||
appFilesCountAndSize: MutableState<Pair<Int, Long>>,
|
||||
chatItemTTL: MutableState<ChatItemTTL>,
|
||||
@@ -173,7 +170,7 @@ fun DatabaseLayout(
|
||||
SectionDividerSpaced(maxTopPadding = true)
|
||||
|
||||
SectionView(stringResource(R.string.run_chat_section)) {
|
||||
RunChatSetting(runChat, stopped, chatDbDeleted, startChat, stopChatAlert)
|
||||
RunChatSetting(runChat, stopped, startChat, stopChatAlert)
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
|
||||
@@ -330,7 +327,6 @@ private fun TtlOptions(current: State<ChatItemTTL>, enabled: State<Boolean>, onS
|
||||
fun RunChatSetting(
|
||||
runChat: Boolean,
|
||||
stopped: Boolean,
|
||||
chatDbDeleted: Boolean,
|
||||
startChat: () -> Unit,
|
||||
stopChatAlert: () -> Unit
|
||||
) {
|
||||
@@ -341,7 +337,6 @@ fun RunChatSetting(
|
||||
iconColor = if (stopped) Color.Red else MaterialTheme.colors.primary,
|
||||
) {
|
||||
DefaultSwitch(
|
||||
enabled = !chatDbDeleted,
|
||||
checked = runChat,
|
||||
onCheckedChange = { runChatSwitch ->
|
||||
if (runChatSwitch) {
|
||||
@@ -371,9 +366,14 @@ private fun startChat(m: ChatModel, runChat: MutableState<Boolean?>, chatLastSta
|
||||
ModalManager.shared.closeModals()
|
||||
return@withApi
|
||||
}
|
||||
m.controller.apiStartChat()
|
||||
runChat.value = true
|
||||
m.chatRunning.value = true
|
||||
if (m.currentUser.value == null) {
|
||||
ModalManager.shared.closeModals()
|
||||
return@withApi
|
||||
} else {
|
||||
m.controller.apiStartChat()
|
||||
runChat.value = true
|
||||
m.chatRunning.value = true
|
||||
}
|
||||
val ts = Clock.System.now()
|
||||
m.controller.appPrefs.chatLastStart.set(ts)
|
||||
chatLastStart.value = ts
|
||||
@@ -410,7 +410,7 @@ private fun authStopChat(m: ChatModel, runChat: MutableState<Boolean?>, context:
|
||||
authenticate(
|
||||
generalGetString(R.string.auth_stop_chat),
|
||||
generalGetString(R.string.auth_log_in_using_credential),
|
||||
context as FragmentActivity,
|
||||
activity = context as FragmentActivity,
|
||||
completed = { laResult ->
|
||||
when (laResult) {
|
||||
LAResult.Success, is LAResult.Unavailable -> {
|
||||
@@ -433,18 +433,28 @@ private fun authStopChat(m: ChatModel, runChat: MutableState<Boolean?>, context:
|
||||
private fun stopChat(m: ChatModel, runChat: MutableState<Boolean?>, context: Context) {
|
||||
withApi {
|
||||
try {
|
||||
m.controller.apiStopChat()
|
||||
runChat.value = false
|
||||
m.chatRunning.value = false
|
||||
SimplexService.safeStopService(context)
|
||||
stopChatAsync(m)
|
||||
SimplexService.safeStopService(SimplexApp.context)
|
||||
MessagesFetcherWorker.cancelAll()
|
||||
} catch (e: Error) {
|
||||
runChat.value = true
|
||||
AlertManager.shared.showAlertMsg(generalGetString(R.string.error_starting_chat), e.toString())
|
||||
AlertManager.shared.showAlertMsg(generalGetString(R.string.error_stopping_chat), e.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun stopChatAsync(m: ChatModel) {
|
||||
m.controller.apiStopChat()
|
||||
m.chatRunning.value = false
|
||||
}
|
||||
|
||||
suspend fun deleteChatAsync(m: ChatModel) {
|
||||
m.controller.apiDeleteStorage()
|
||||
DatabaseUtils.ksDatabasePassword.remove()
|
||||
m.controller.appPrefs.storeDBPassphrase.set(true)
|
||||
}
|
||||
|
||||
private fun exportArchive(
|
||||
context: Context,
|
||||
m: ChatModel,
|
||||
@@ -619,10 +629,7 @@ private fun deleteChat(m: ChatModel, progressIndicator: MutableState<Boolean>) {
|
||||
progressIndicator.value = true
|
||||
withApi {
|
||||
try {
|
||||
m.controller.apiDeleteStorage()
|
||||
m.chatDbDeleted.value = true
|
||||
DatabaseUtils.ksDatabasePassword.remove()
|
||||
m.controller.appPrefs.storeDBPassphrase.set(true)
|
||||
deleteChatAsync(m)
|
||||
operationEnded(m, progressIndicator) {
|
||||
AlertManager.shared.showAlertMsg(generalGetString(R.string.chat_database_deleted), generalGetString(R.string.restart_the_app_to_create_a_new_chat_profile))
|
||||
}
|
||||
@@ -717,7 +724,6 @@ fun PreviewDatabaseLayout() {
|
||||
chatArchiveName = remember { mutableStateOf("dummy_archive") },
|
||||
chatArchiveTime = remember { mutableStateOf(Clock.System.now()) },
|
||||
chatLastStart = remember { mutableStateOf(Clock.System.now()) },
|
||||
chatDbDeleted = false,
|
||||
privacyFullBackup = SharedPreference({ true }, {}),
|
||||
appFilesCountAndSize = remember { mutableStateOf(0 to 0L) },
|
||||
chatItemTTL = remember { mutableStateOf(ChatItemTTL.None) },
|
||||
|
||||
@@ -12,6 +12,7 @@ import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import chat.simplex.app.ui.theme.*
|
||||
|
||||
@@ -43,7 +44,7 @@ fun CloseSheetBar(close: (() -> Unit)?, endButtons: @Composable RowScope.() -> U
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AppBarTitle(title: String, withPadding: Boolean = true) {
|
||||
fun AppBarTitle(title: String, withPadding: Boolean = true, bottomPadding: Dp = DEFAULT_PADDING * 1.5f) {
|
||||
val theme = CurrentColors.collectAsState()
|
||||
val titleColor = CurrentColors.collectAsState().value.appColors.title
|
||||
val brush = if (theme.value.base == DefaultTheme.SIMPLEX)
|
||||
@@ -54,7 +55,7 @@ fun AppBarTitle(title: String, withPadding: Boolean = true) {
|
||||
title,
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(bottom = DEFAULT_PADDING * 1.5f, start = if (withPadding) DEFAULT_PADDING else 0.dp, end = if (withPadding) DEFAULT_PADDING else 0.dp,),
|
||||
.padding(bottom = bottomPadding, start = if (withPadding) DEFAULT_PADDING else 0.dp, end = if (withPadding) DEFAULT_PADDING else 0.dp,),
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
style = MaterialTheme.typography.h1.copy(brush = brush),
|
||||
color = MaterialTheme.colors.primaryVariant,
|
||||
|
||||
@@ -0,0 +1,290 @@
|
||||
package chat.simplex.app.views.helpers
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CornerSize
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import chat.simplex.app.R
|
||||
import chat.simplex.app.model.*
|
||||
import chat.simplex.app.ui.theme.DEFAULT_PADDING
|
||||
import com.sd.lib.compose.wheel_picker.*
|
||||
|
||||
@Composable
|
||||
fun CustomTimePicker(
|
||||
selection: MutableState<Int>,
|
||||
timeUnitsLimits: List<TimeUnitLimits> = TimeUnitLimits.defaultUnitsLimits
|
||||
) {
|
||||
fun getUnitValues(unit: CustomTimeUnit, selectedValue: Int): List<Int> {
|
||||
val unitLimits = timeUnitsLimits.firstOrNull { it.timeUnit == unit } ?: TimeUnitLimits.defaultUnitLimits(unit)
|
||||
val regularUnitValues = (unitLimits.minValue..unitLimits.maxValue).toList()
|
||||
return regularUnitValues + if (regularUnitValues.contains(selectedValue)) emptyList() else listOf(selectedValue)
|
||||
}
|
||||
|
||||
val (unit, duration) = CustomTimeUnit.toTimeUnit(selection.value)
|
||||
val selectedUnit: MutableState<CustomTimeUnit> = remember { mutableStateOf(unit) }
|
||||
val selectedDuration = remember { mutableStateOf(duration) }
|
||||
val selectedUnitValues = remember { mutableStateOf(getUnitValues(selectedUnit.value, selectedDuration.value)) }
|
||||
val isTriggered = remember { mutableStateOf(false) }
|
||||
|
||||
LaunchedEffect(selectedUnit.value) {
|
||||
// on initial composition, if passed selection doesn't fit into picker bounds, so that selectedDuration is bigger than selectedUnit maxValue
|
||||
// (e.g., for selection = 121 seconds: selectedUnit would be Second, selectedDuration would be 121 > selectedUnit maxValue of 120),
|
||||
// selectedDuration would've been replaced by maxValue - isTriggered check prevents this by skipping LaunchedEffect on initial composition
|
||||
if (isTriggered.value) {
|
||||
val maxValue = timeUnitsLimits.firstOrNull { it.timeUnit == selectedUnit.value }?.maxValue
|
||||
if (maxValue != null && selectedDuration.value > maxValue) {
|
||||
selectedDuration.value = maxValue
|
||||
selectedUnitValues.value = getUnitValues(selectedUnit.value, selectedDuration.value)
|
||||
} else {
|
||||
selectedUnitValues.value = getUnitValues(selectedUnit.value, selectedDuration.value)
|
||||
selection.value = selectedUnit.value.toSeconds * selectedDuration.value
|
||||
}
|
||||
} else {
|
||||
isTriggered.value = true
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(selectedDuration.value) {
|
||||
selection.value = selectedUnit.value.toSeconds * selectedDuration.value
|
||||
}
|
||||
|
||||
Row(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = DEFAULT_PADDING),
|
||||
horizontalArrangement = Arrangement.spacedBy(0.dp)
|
||||
) {
|
||||
Column(Modifier.weight(1f)) {
|
||||
val durationPickerState = rememberFWheelPickerState(selectedUnitValues.value.indexOf(selectedDuration.value))
|
||||
FVerticalWheelPicker(
|
||||
count = selectedUnitValues.value.count(),
|
||||
state = durationPickerState,
|
||||
unfocusedCount = 2,
|
||||
focus = {
|
||||
FWheelPickerFocusVertical(dividerColor = MaterialTheme.colors.primary)
|
||||
}
|
||||
) { index ->
|
||||
Text(
|
||||
selectedUnitValues.value[index].toString(),
|
||||
fontSize = 18.sp,
|
||||
color = MaterialTheme.colors.primary
|
||||
)
|
||||
}
|
||||
LaunchedEffect(durationPickerState) {
|
||||
snapshotFlow { durationPickerState.currentIndex }
|
||||
.collect {
|
||||
selectedDuration.value = selectedUnitValues.value[it]
|
||||
}
|
||||
}
|
||||
}
|
||||
Column(Modifier.weight(1f)) {
|
||||
val unitPickerState = rememberFWheelPickerState(timeUnitsLimits.indexOfFirst { it.timeUnit == selectedUnit.value })
|
||||
FVerticalWheelPicker(
|
||||
count = timeUnitsLimits.count(),
|
||||
state = unitPickerState,
|
||||
unfocusedCount = 2,
|
||||
focus = {
|
||||
FWheelPickerFocusVertical(dividerColor = MaterialTheme.colors.primary)
|
||||
}
|
||||
) { index ->
|
||||
Text(
|
||||
timeUnitsLimits[index].timeUnit.text,
|
||||
fontSize = 18.sp,
|
||||
color = MaterialTheme.colors.primary
|
||||
)
|
||||
}
|
||||
LaunchedEffect(unitPickerState) {
|
||||
snapshotFlow { unitPickerState.currentIndex }
|
||||
.collect {
|
||||
selectedUnit.value = timeUnitsLimits[it].timeUnit
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class TimeUnitLimits(
|
||||
val timeUnit: CustomTimeUnit,
|
||||
val minValue: Int = 1,
|
||||
val maxValue: Int
|
||||
) {
|
||||
companion object {
|
||||
fun defaultUnitLimits(unit: CustomTimeUnit): TimeUnitLimits {
|
||||
return when (unit) {
|
||||
CustomTimeUnit.Second -> TimeUnitLimits(CustomTimeUnit.Second, maxValue = 120)
|
||||
CustomTimeUnit.Minute -> TimeUnitLimits(CustomTimeUnit.Minute, maxValue = 120)
|
||||
CustomTimeUnit.Hour -> TimeUnitLimits(CustomTimeUnit.Hour, maxValue = 72)
|
||||
CustomTimeUnit.Day -> TimeUnitLimits(CustomTimeUnit.Day, maxValue = 60)
|
||||
CustomTimeUnit.Week -> TimeUnitLimits(CustomTimeUnit.Week, maxValue = 12) // TODO in 5.2 - 54
|
||||
CustomTimeUnit.Month -> TimeUnitLimits(CustomTimeUnit.Month, maxValue = 3) // TODO in 5.2 - 12
|
||||
}
|
||||
}
|
||||
|
||||
val defaultUnitsLimits: List<TimeUnitLimits>
|
||||
get() = listOf(
|
||||
defaultUnitLimits(CustomTimeUnit.Second),
|
||||
defaultUnitLimits(CustomTimeUnit.Minute),
|
||||
defaultUnitLimits(CustomTimeUnit.Hour),
|
||||
defaultUnitLimits(CustomTimeUnit.Day),
|
||||
defaultUnitLimits(CustomTimeUnit.Week),
|
||||
defaultUnitLimits(CustomTimeUnit.Month)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CustomTimePickerDialog(
|
||||
selection: MutableState<Int>,
|
||||
timeUnitsLimits: List<TimeUnitLimits> = TimeUnitLimits.defaultUnitsLimits,
|
||||
title: String,
|
||||
confirmButtonText: String,
|
||||
confirmButtonAction: (Int) -> Unit,
|
||||
cancel: () -> Unit
|
||||
) {
|
||||
Dialog(onDismissRequest = cancel) {
|
||||
Surface(
|
||||
shape = RoundedCornerShape(corner = CornerSize(25.dp))
|
||||
) {
|
||||
Box(
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(DEFAULT_PADDING),
|
||||
verticalArrangement = Arrangement.spacedBy(6.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(" ") // centers title
|
||||
Text(
|
||||
title,
|
||||
fontSize = 16.sp,
|
||||
color = MaterialTheme.colors.secondary
|
||||
)
|
||||
Icon(
|
||||
painterResource(R.drawable.ic_close),
|
||||
generalGetString(R.string.icon_descr_close_button),
|
||||
tint = MaterialTheme.colors.secondary,
|
||||
modifier = Modifier
|
||||
.size(25.dp)
|
||||
.clickable { cancel() }
|
||||
)
|
||||
}
|
||||
|
||||
CustomTimePicker(
|
||||
selection,
|
||||
timeUnitsLimits
|
||||
)
|
||||
|
||||
TextButton(onClick = { confirmButtonAction(selection.value) }) {
|
||||
Text(
|
||||
confirmButtonText,
|
||||
fontSize = 18.sp,
|
||||
color = MaterialTheme.colors.primary
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun DropdownCustomTimePickerSettingRow(
|
||||
selection: MutableState<Int?>,
|
||||
propagateExternalSelectionUpdate: Boolean = false,
|
||||
label: String,
|
||||
dropdownValues: List<Int?>,
|
||||
customPickerTitle: String,
|
||||
customPickerConfirmButtonText: String,
|
||||
customPickerTimeUnitsLimits: List<TimeUnitLimits> = TimeUnitLimits.defaultUnitsLimits,
|
||||
onSelected: (Int?) -> Unit
|
||||
) {
|
||||
fun getValues(selectedValue: Int?): List<DropdownSelection> =
|
||||
dropdownValues.map { DropdownSelection.DropdownValue(it) } +
|
||||
(if (dropdownValues.contains(selectedValue)) listOf() else listOf(DropdownSelection.DropdownValue(selectedValue))) +
|
||||
listOf(DropdownSelection.Custom)
|
||||
|
||||
val dropdownSelection: MutableState<DropdownSelection> = remember { mutableStateOf(DropdownSelection.DropdownValue(selection.value)) }
|
||||
val values: MutableState<List<DropdownSelection>> = remember { mutableStateOf(getValues(selection.value)) }
|
||||
val showCustomTimePicker = remember { mutableStateOf(false) }
|
||||
|
||||
fun updateValue(selectedValue: Int?) {
|
||||
values.value = getValues(selectedValue)
|
||||
dropdownSelection.value = DropdownSelection.DropdownValue(selectedValue)
|
||||
onSelected(selectedValue)
|
||||
}
|
||||
|
||||
if (propagateExternalSelectionUpdate) {
|
||||
LaunchedEffect(selection.value) {
|
||||
values.value = getValues(selection.value)
|
||||
dropdownSelection.value = DropdownSelection.DropdownValue(selection.value)
|
||||
}
|
||||
}
|
||||
|
||||
ExposedDropDownSettingRow(
|
||||
label,
|
||||
values.value.map { sel: DropdownSelection ->
|
||||
when (sel) {
|
||||
is DropdownSelection.DropdownValue -> sel to timeText(sel.value)
|
||||
DropdownSelection.Custom -> sel to generalGetString(R.string.custom_time_picker_custom)
|
||||
}
|
||||
},
|
||||
dropdownSelection,
|
||||
onSelected = { sel: DropdownSelection ->
|
||||
when (sel) {
|
||||
is DropdownSelection.DropdownValue -> updateValue(sel.value)
|
||||
DropdownSelection.Custom -> showCustomTimePicker.value = true
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
if (showCustomTimePicker.value) {
|
||||
val selectedCustomTime = remember { mutableStateOf(selection.value ?: 86400) }
|
||||
CustomTimePickerDialog(
|
||||
selectedCustomTime,
|
||||
timeUnitsLimits = customPickerTimeUnitsLimits,
|
||||
title = customPickerTitle,
|
||||
confirmButtonText = customPickerConfirmButtonText,
|
||||
confirmButtonAction = { time ->
|
||||
updateValue(time)
|
||||
showCustomTimePicker.value = false
|
||||
},
|
||||
cancel = {
|
||||
dropdownSelection.value = DropdownSelection.DropdownValue(selection.value)
|
||||
showCustomTimePicker.value = false
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class DropdownSelection {
|
||||
data class DropdownValue(val value: Int?): DropdownSelection()
|
||||
object Custom: DropdownSelection()
|
||||
|
||||
override fun equals(other: Any?): Boolean =
|
||||
other is DropdownSelection &&
|
||||
when (other) {
|
||||
is DropdownValue -> this is DropdownValue && this.value == other.value
|
||||
is Custom -> this is Custom
|
||||
}
|
||||
|
||||
override fun hashCode(): Int =
|
||||
// DO NOT REMOVE the as? cast as it will turn them into recursive hashCode calls
|
||||
// https://youtrack.jetbrains.com/issue/KT-31239
|
||||
when (this) {
|
||||
is DropdownValue -> (this as? DropdownValue).hashCode()
|
||||
is Custom -> (this as? Custom).hashCode()
|
||||
}
|
||||
}
|
||||
@@ -18,9 +18,11 @@ object DatabaseUtils {
|
||||
|
||||
private const val DATABASE_PASSWORD_ALIAS: String = "databasePassword"
|
||||
private const val APP_PASSWORD_ALIAS: String = "appPassword"
|
||||
private const val SELF_DESTRUCT_PASSWORD_ALIAS: String = "selfDestructPassword"
|
||||
|
||||
val ksDatabasePassword = KeyStoreItem(DATABASE_PASSWORD_ALIAS, appPreferences.encryptedDBPassphrase, appPreferences.initializationVectorDBPassphrase)
|
||||
val ksAppPassword = KeyStoreItem(APP_PASSWORD_ALIAS, appPreferences.encryptedAppPassphrase, appPreferences.initializationVectorAppPassphrase)
|
||||
val ksSelfDestructPassword = KeyStoreItem(SELF_DESTRUCT_PASSWORD_ALIAS, appPreferences.encryptedSelfDestructPassphrase, appPreferences.initializationVectorSelfDestructPassphrase)
|
||||
|
||||
class KeyStoreItem(private val alias: String, val passphrase: SharedPreference<String?>, val initVector: SharedPreference<String?>) {
|
||||
fun get(): String? {
|
||||
|
||||
@@ -77,7 +77,7 @@ suspend fun getLinkPreview(url: String): LinkPreview? {
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ComposeLinkView(linkPreview: LinkPreview?, cancelPreview: () -> Unit) {
|
||||
fun ComposeLinkView(linkPreview: LinkPreview?, cancelPreview: () -> Unit, cancelEnabled: Boolean) {
|
||||
val sentColor = CurrentColors.collectAsState().value.appColors.sentMessage
|
||||
Row(
|
||||
Modifier.fillMaxWidth().padding(top = 8.dp).background(sentColor),
|
||||
@@ -109,13 +109,15 @@ fun ComposeLinkView(linkPreview: LinkPreview?, cancelPreview: () -> Unit) {
|
||||
)
|
||||
}
|
||||
}
|
||||
IconButton(onClick = cancelPreview, modifier = Modifier.padding(0.dp)) {
|
||||
Icon(
|
||||
painterResource(R.drawable.ic_close),
|
||||
contentDescription = stringResource(R.string.icon_descr_cancel_link_preview),
|
||||
tint = MaterialTheme.colors.primary,
|
||||
modifier = Modifier.padding(10.dp)
|
||||
)
|
||||
if (cancelEnabled) {
|
||||
IconButton(onClick = cancelPreview, modifier = Modifier.padding(0.dp)) {
|
||||
Icon(
|
||||
painterResource(R.drawable.ic_close),
|
||||
contentDescription = stringResource(R.string.icon_descr_cancel_link_preview),
|
||||
tint = MaterialTheme.colors.primary,
|
||||
modifier = Modifier.padding(10.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -193,7 +195,7 @@ fun PreviewChatItemLinkView() {
|
||||
@Composable
|
||||
fun PreviewComposeLinkView() {
|
||||
SimpleXTheme {
|
||||
ComposeLinkView(LinkPreview.sampleData) { -> }
|
||||
ComposeLinkView(LinkPreview.sampleData, cancelPreview = { -> }, true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,6 +203,6 @@ fun PreviewComposeLinkView() {
|
||||
@Composable
|
||||
fun PreviewComposeLinkViewLoading() {
|
||||
SimpleXTheme {
|
||||
ComposeLinkView(null) { -> }
|
||||
ComposeLinkView(null, cancelPreview = { -> }, true)
|
||||
}
|
||||
}
|
||||
|
||||
+5
-3
@@ -28,16 +28,18 @@ data class LocalAuthRequest (
|
||||
val title: String?,
|
||||
val reason: String,
|
||||
val password: String,
|
||||
val selfDestruct: Boolean,
|
||||
val completed: (LAResult) -> Unit
|
||||
) {
|
||||
companion object {
|
||||
val sample = LocalAuthRequest(generalGetString(R.string.la_enter_app_passcode), generalGetString(R.string.la_authenticate), "") { }
|
||||
val sample = LocalAuthRequest(generalGetString(R.string.la_enter_app_passcode), generalGetString(R.string.la_authenticate), "", selfDestruct = false) { }
|
||||
}
|
||||
}
|
||||
|
||||
fun authenticate(
|
||||
promptTitle: String,
|
||||
promptSubtitle: String,
|
||||
selfDestruct: Boolean = false,
|
||||
activity: FragmentActivity,
|
||||
usingLAMode: LAMode = SimplexApp.context.chatModel.controller.appPrefs.laMode.get(),
|
||||
completed: (LAResult) -> Unit
|
||||
@@ -53,13 +55,13 @@ fun authenticate(
|
||||
}
|
||||
LAMode.PASSCODE -> {
|
||||
val password = ksAppPassword.get() ?: return completed(LAResult.Unavailable(generalGetString(R.string.la_no_app_password)))
|
||||
ModalManager.shared.showCustomModal(animated = false) { close ->
|
||||
ModalManager.shared.showPasscodeCustomModal { close ->
|
||||
BackHandler {
|
||||
close()
|
||||
completed(LAResult.Error(generalGetString(R.string.authentication_cancelled)))
|
||||
}
|
||||
Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background) {
|
||||
LocalAuthView(SimplexApp.context.chatModel, LocalAuthRequest(promptTitle, promptSubtitle, password) {
|
||||
LocalAuthView(SimplexApp.context.chatModel, LocalAuthRequest(promptTitle, promptSubtitle, password, selfDestruct && SimplexApp.context.chatModel.controller.appPrefs.selfDestruct.get()) {
|
||||
close()
|
||||
completed(it)
|
||||
})
|
||||
|
||||
@@ -56,6 +56,7 @@ class MessagesFetcherWork(
|
||||
try {
|
||||
withTimeout(durationSeconds * 1000L) {
|
||||
val chatController = (applicationContext as SimplexApp).chatController
|
||||
SimplexService.waitDbMigrationEnds(chatController)
|
||||
val chatDbStatus = chatController.chatModel.chatDbStatus.value
|
||||
if (chatDbStatus != DBMigrationResult.OK) {
|
||||
Log.w(TAG, "Worker: problem with the database: $chatDbStatus")
|
||||
|
||||
@@ -37,6 +37,7 @@ class ModalManager {
|
||||
private val modalCount = mutableStateOf(0)
|
||||
private val toRemove = mutableSetOf<Int>()
|
||||
private var oldViewChanging = AtomicBoolean(false)
|
||||
private var passcodeView: MutableState<(@Composable (close: () -> Unit) -> Unit)?> = mutableStateOf(null)
|
||||
|
||||
fun showModal(settings: Boolean = false, endButtons: @Composable RowScope.() -> Unit = {}, content: @Composable () -> Unit) {
|
||||
showCustomModal { close ->
|
||||
@@ -51,7 +52,7 @@ class ModalManager {
|
||||
}
|
||||
|
||||
fun showCustomModal(animated: Boolean = true, modal: @Composable (close: () -> Unit) -> Unit) {
|
||||
Log.d(TAG, "ModalManager.showModal")
|
||||
Log.d(TAG, "ModalManager.showCustomModal")
|
||||
// Means, animation is in progress or not started yet. Do not wait until animation finishes, just remove all from screen.
|
||||
// This is useful when invoking close() and ShowCustomModal one after another without delay. Otherwise, screen will hold prev view
|
||||
if (toRemove.isNotEmpty()) {
|
||||
@@ -61,6 +62,11 @@ class ModalManager {
|
||||
modalCount.value = modalViews.size - toRemove.size
|
||||
}
|
||||
|
||||
fun showPasscodeCustomModal(modal: @Composable (close: () -> Unit) -> Unit) {
|
||||
Log.d(TAG, "ModalManager.showPasscodeCustomModal")
|
||||
passcodeView.value = modal
|
||||
}
|
||||
|
||||
fun hasModalsOpen() = modalCount.value > 0
|
||||
|
||||
fun closeModal() {
|
||||
@@ -72,7 +78,9 @@ class ModalManager {
|
||||
}
|
||||
|
||||
fun closeModals() {
|
||||
while (modalCount.value > 0) closeModal()
|
||||
modalViews.clear()
|
||||
toRemove.clear()
|
||||
modalCount.value = 0
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalAnimationApi::class)
|
||||
@@ -100,6 +108,11 @@ class ModalManager {
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun showPasscodeInView() {
|
||||
remember { passcodeView }.value?.invoke { passcodeView.value = null }
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to modify a list without getting [ConcurrentModificationException]
|
||||
* */
|
||||
|
||||
@@ -21,7 +21,7 @@ interface Recorder {
|
||||
fun stop(): Int
|
||||
}
|
||||
|
||||
class RecorderNative(private val recordedBytesLimit: Long): Recorder {
|
||||
class RecorderNative(): Recorder {
|
||||
companion object {
|
||||
// Allows to stop the recorder from outside without having the recorder in a variable
|
||||
var stopRecording: (() -> Unit)? = null
|
||||
@@ -48,9 +48,8 @@ class RecorderNative(private val recordedBytesLimit: Long): Recorder {
|
||||
rec.setAudioEncoder(MediaRecorder.AudioEncoder.AAC)
|
||||
rec.setAudioChannels(1)
|
||||
rec.setAudioSamplingRate(16000)
|
||||
rec.setAudioEncodingBitRate(16000)
|
||||
rec.setAudioEncodingBitRate(32000)
|
||||
rec.setMaxDuration(MAX_VOICE_MILLIS_FOR_SENDING)
|
||||
rec.setMaxFileSize(recordedBytesLimit)
|
||||
val tmpDir = SimplexApp.context.getDir("temp", Application.MODE_PRIVATE)
|
||||
val fileToSave = File.createTempFile(generateNewFileName(SimplexApp.context, "voice", "${extension}_"), ".tmp", tmpDir)
|
||||
fileToSave.deleteOnExit()
|
||||
@@ -274,6 +273,13 @@ object AudioPlayer {
|
||||
audioPlaying.value = false
|
||||
}
|
||||
|
||||
fun seekTo(ms: Int, pro: MutableState<Int>, filePath: String?) {
|
||||
pro.value = ms
|
||||
if (this.currentlyPlaying.value?.first == filePath) {
|
||||
player.seekTo(ms)
|
||||
}
|
||||
}
|
||||
|
||||
fun duration(filePath: String): Int? {
|
||||
var res: Int? = null
|
||||
kotlin.runCatching {
|
||||
|
||||
@@ -202,9 +202,9 @@ fun SectionDividerSpaced(maxTopPadding: Boolean = false, maxBottomPadding: Boole
|
||||
Divider(
|
||||
Modifier.padding(
|
||||
start = DEFAULT_PADDING_HALF,
|
||||
top = if (maxTopPadding) 40.dp else 30.dp,
|
||||
top = if (maxTopPadding) 37.dp else 27.dp,
|
||||
end = DEFAULT_PADDING_HALF,
|
||||
bottom = if (maxBottomPadding) 40.dp else 30.dp)
|
||||
bottom = if (maxBottomPadding) 37.dp else 27.dp)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.Manifest
|
||||
import android.content.*
|
||||
import android.net.Uri
|
||||
import android.provider.MediaStore
|
||||
import android.util.Log
|
||||
import android.webkit.MimeTypeMap
|
||||
import android.widget.Toast
|
||||
import androidx.activity.compose.ManagedActivityResultLauncher
|
||||
@@ -48,6 +49,17 @@ fun copyText(cxt: Context, text: String) {
|
||||
clipboard?.setPrimaryClip(ClipData.newPlainText("text", text))
|
||||
}
|
||||
|
||||
fun sendEmail(context: Context, subject: String, body: CharSequence) {
|
||||
val emailIntent = Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:"))
|
||||
emailIntent.putExtra(Intent.EXTRA_SUBJECT, subject)
|
||||
emailIntent.putExtra(Intent.EXTRA_TEXT, body)
|
||||
try {
|
||||
context.startActivity(emailIntent)
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
Log.e(TAG, "No activity was found for handling email intent")
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun rememberSaveFileLauncher(cxt: Context, ciFile: CIFile?): ManagedActivityResultLauncher<String, Uri?> =
|
||||
rememberLauncherForActivityResult(
|
||||
|
||||
@@ -79,7 +79,7 @@ fun SimpleButtonIconEnded(
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SimpleButtonFrame(click: () -> Unit, modifier: Modifier = Modifier, disabled: Boolean = false, content: @Composable () -> Unit) {
|
||||
fun SimpleButtonFrame(click: () -> Unit, modifier: Modifier = Modifier, disabled: Boolean = false, content: @Composable RowScope.() -> Unit) {
|
||||
Box(Modifier.clip(RoundedCornerShape(20.dp))) {
|
||||
val modifier = if (disabled) modifier else modifier.clickable { click() }
|
||||
Row(
|
||||
|
||||
@@ -1,64 +1,117 @@
|
||||
package chat.simplex.app.views.helpers
|
||||
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.background
|
||||
import android.util.Log
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.BasicTextField
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Surface
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.foundation.text.selection.SelectionContainer
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.*
|
||||
import androidx.compose.ui.graphics.*
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.input.KeyboardCapitalization
|
||||
import androidx.compose.ui.text.input.VisualTransformation
|
||||
import androidx.compose.ui.unit.*
|
||||
import chat.simplex.app.ui.theme.DEFAULT_PADDING
|
||||
import chat.simplex.app.TAG
|
||||
import chat.simplex.app.chatParseMarkdown
|
||||
import chat.simplex.app.model.*
|
||||
import chat.simplex.app.ui.theme.*
|
||||
import chat.simplex.app.views.chat.item.MarkdownText
|
||||
import com.google.accompanist.insets.navigationBarsWithImePadding
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.serialization.Serializable
|
||||
import java.lang.Exception
|
||||
|
||||
@Composable
|
||||
fun TextEditor(
|
||||
value: MutableState<String>,
|
||||
modifier: Modifier,
|
||||
text: MutableState<String>,
|
||||
border: Boolean = true,
|
||||
fontSize: TextUnit = 14.sp,
|
||||
background: Color = MaterialTheme.colors.background,
|
||||
onChange: ((String) -> Unit)? = null
|
||||
placeholder: String? = null,
|
||||
contentPadding: PaddingValues = PaddingValues(horizontal = DEFAULT_PADDING),
|
||||
isValid: (String) -> Boolean = { true },
|
||||
focusRequester: FocusRequester? = null
|
||||
) {
|
||||
BasicTextField(
|
||||
value = text.value,
|
||||
onValueChange = { text.value = it; onChange?.invoke(it) },
|
||||
textStyle = TextStyle(
|
||||
fontFamily = FontFamily.Monospace, fontSize = fontSize,
|
||||
color = MaterialTheme.colors.onBackground
|
||||
),
|
||||
keyboardOptions = KeyboardOptions.Default.copy(
|
||||
capitalization = KeyboardCapitalization.None,
|
||||
autoCorrect = false
|
||||
),
|
||||
modifier = modifier,
|
||||
cursorBrush = SolidColor(MaterialTheme.colors.secondary),
|
||||
decorationBox = { innerTextField ->
|
||||
Surface(
|
||||
shape = if (border) RoundedCornerShape(10.dp) else RectangleShape,
|
||||
border = if (border) BorderStroke(1.dp, MaterialTheme.colors.secondaryVariant) else null
|
||||
) {
|
||||
Row(
|
||||
Modifier.background(background),
|
||||
verticalAlignment = Alignment.Top
|
||||
) {
|
||||
Box(
|
||||
Modifier
|
||||
.weight(1f)
|
||||
.padding(vertical = 5.dp, horizontal = if (border) 7.dp else DEFAULT_PADDING)
|
||||
) {
|
||||
innerTextField()
|
||||
}
|
||||
var valid by rememberSaveable { mutableStateOf(true) }
|
||||
var focused by rememberSaveable { mutableStateOf(false) }
|
||||
val strokeColor by remember {
|
||||
derivedStateOf {
|
||||
if (valid) {
|
||||
if (focused) {
|
||||
CurrentColors.value.colors.secondary.copy(alpha = 0.6f)
|
||||
} else {
|
||||
CurrentColors.value.colors.secondary.copy(alpha = 0.3f)
|
||||
}
|
||||
}
|
||||
} else Color.Red
|
||||
}
|
||||
)
|
||||
}
|
||||
Box(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(contentPadding)
|
||||
.heightIn(min = 52.dp),
|
||||
// .border(border = BorderStroke(1.dp, strokeColor), shape = RoundedCornerShape(26.dp)),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
val modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.navigationBarsWithImePadding()
|
||||
.onFocusChanged { focused = it.isFocused }
|
||||
|
||||
BasicTextField(
|
||||
value = value.value,
|
||||
onValueChange = { value.value = it },
|
||||
modifier = if (focusRequester == null) modifier else modifier.focusRequester(focusRequester),
|
||||
textStyle = MaterialTheme.typography.body1.copy(color = MaterialTheme.colors.onBackground, lineHeight = 22.sp),
|
||||
keyboardOptions = KeyboardOptions(
|
||||
capitalization = KeyboardCapitalization.None,
|
||||
autoCorrect = false
|
||||
),
|
||||
singleLine = false,
|
||||
maxLines = 5,
|
||||
cursorBrush = SolidColor(MaterialTheme.colors.secondary),
|
||||
decorationBox = @Composable { innerTextField ->
|
||||
TextFieldDefaults.TextFieldDecorationBox(
|
||||
value = value.value,
|
||||
innerTextField = innerTextField,
|
||||
placeholder = if (placeholder != null) {{ Text(placeholder, style = MaterialTheme.typography.body1.copy(color = MaterialTheme.colors.secondary, lineHeight = 22.sp)) }} else null,
|
||||
contentPadding = PaddingValues(),
|
||||
label = null,
|
||||
visualTransformation = VisualTransformation.None,
|
||||
leadingIcon = null,
|
||||
trailingIcon = null,
|
||||
singleLine = false,
|
||||
enabled = true,
|
||||
isError = false,
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
LaunchedEffect(Unit) {
|
||||
snapshotFlow { value.value }
|
||||
.distinctUntilChanged()
|
||||
.collect {
|
||||
valid = isValid(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class ParsedFormattedText(
|
||||
val formattedText: List<FormattedText>? = null
|
||||
)
|
||||
|
||||
fun parseToMarkdown(text: String): List<FormattedText>? {
|
||||
val formatted = chatParseMarkdown(text)
|
||||
return try {
|
||||
json.decodeFromString(ParsedFormattedText.serializer(), formatted).formattedText
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Failed to parse into markdown: " + e.stackTraceToString())
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,9 +23,11 @@ import android.view.View
|
||||
import android.view.ViewTreeObserver
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.saveable.Saver
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.platform.*
|
||||
import androidx.compose.ui.text.*
|
||||
import androidx.compose.ui.text.font.*
|
||||
@@ -33,11 +35,11 @@ import androidx.compose.ui.text.style.BaselineShift
|
||||
import androidx.compose.ui.text.style.TextDecoration
|
||||
import androidx.compose.ui.unit.*
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.core.graphics.ColorUtils
|
||||
import androidx.core.text.HtmlCompat
|
||||
import chat.simplex.app.*
|
||||
import chat.simplex.app.R
|
||||
import chat.simplex.app.model.*
|
||||
import chat.simplex.app.ui.theme.ThemeData
|
||||
import chat.simplex.app.ui.theme.ThemeOverrides
|
||||
import com.charleskorn.kaml.decodeFromStream
|
||||
import kotlinx.coroutines.*
|
||||
@@ -234,16 +236,16 @@ private fun spannableStringToAnnotatedString(
|
||||
}
|
||||
|
||||
// maximum image file size to be auto-accepted
|
||||
const val MAX_IMAGE_SIZE: Long = 236700
|
||||
const val MAX_IMAGE_SIZE: Long = 261_120 // 255KB
|
||||
const val MAX_IMAGE_SIZE_AUTO_RCV: Long = MAX_IMAGE_SIZE * 2
|
||||
const val MAX_VOICE_SIZE_AUTO_RCV: Long = MAX_IMAGE_SIZE
|
||||
const val MAX_VOICE_SIZE_AUTO_RCV: Long = MAX_IMAGE_SIZE * 2
|
||||
const val MAX_VIDEO_SIZE_AUTO_RCV: Long = 1_047_552 // 1023KB
|
||||
|
||||
const val MAX_VOICE_SIZE_FOR_SENDING: Long = 94680 // 6 chunks * 15780 bytes per chunk
|
||||
const val MAX_VOICE_MILLIS_FOR_SENDING: Int = 43_000
|
||||
const val MAX_VOICE_MILLIS_FOR_SENDING: Int = 300_000
|
||||
|
||||
const val MAX_FILE_SIZE_SMP: Long = 8000000
|
||||
|
||||
const val MAX_FILE_SIZE_XFTP: Long = 1_073_741_824
|
||||
const val MAX_FILE_SIZE_XFTP: Long = 1_073_741_824 // 1GB
|
||||
|
||||
fun getFilesDirectory(context: Context): String {
|
||||
return context.filesDir.toString()
|
||||
@@ -391,10 +393,10 @@ fun getDrawableFromUri(uri: Uri, withAlertOnException: Boolean = true): Drawable
|
||||
}
|
||||
}
|
||||
|
||||
fun getThemeFromUri(uri: Uri, withAlertOnException: Boolean = true): ThemeData? {
|
||||
fun getThemeFromUri(uri: Uri, withAlertOnException: Boolean = true): ThemeOverrides? {
|
||||
SimplexApp.context.contentResolver.openInputStream(uri).use {
|
||||
runCatching {
|
||||
return yaml.decodeFromStream<ThemeData>(it!!)
|
||||
return yaml.decodeFromStream<ThemeOverrides>(it!!)
|
||||
}.onFailure {
|
||||
if (withAlertOnException) {
|
||||
AlertManager.shared.showAlertMsg(
|
||||
@@ -588,6 +590,9 @@ fun Color.darker(factor: Float = 0.1f): Color =
|
||||
fun Color.lighter(factor: Float = 0.1f): Color =
|
||||
Color(min(red * (1 + factor), 1f), min(green * (1 + factor), 1f), min(blue * (1 + factor), 1f), alpha)
|
||||
|
||||
fun Color.mixWith(color: Color, alpha: Float): Color =
|
||||
Color(ColorUtils.blendARGB(color.toArgb(), toArgb(), alpha))
|
||||
|
||||
fun ByteArray.toBase64String() = Base64.encodeToString(this, Base64.DEFAULT)
|
||||
|
||||
fun String.toByteArrayFromBase64() = Base64.decode(this, Base64.DEFAULT)
|
||||
|
||||
@@ -1,22 +1,80 @@
|
||||
package chat.simplex.app.views.localauth
|
||||
|
||||
import android.util.Log
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import chat.simplex.app.R
|
||||
import chat.simplex.app.model.ChatModel
|
||||
import chat.simplex.app.*
|
||||
import chat.simplex.app.model.*
|
||||
import chat.simplex.app.views.database.deleteChatAsync
|
||||
import chat.simplex.app.views.database.stopChatAsync
|
||||
import chat.simplex.app.views.helpers.*
|
||||
import chat.simplex.app.views.helpers.DatabaseUtils.ksSelfDestructPassword
|
||||
import chat.simplex.app.views.helpers.DatabaseUtils.ksAppPassword
|
||||
import chat.simplex.app.views.onboarding.OnboardingStage
|
||||
import kotlinx.coroutines.delay
|
||||
|
||||
@Composable
|
||||
fun LocalAuthView(m: ChatModel, authRequest: LocalAuthRequest) {
|
||||
val passcode = rememberSaveable { mutableStateOf("") }
|
||||
PasscodeView(passcode, authRequest.title ?: stringResource(R.string.la_enter_app_passcode), authRequest.reason, stringResource(R.string.submit_passcode),
|
||||
submit = {
|
||||
val r: LAResult = if (passcode.value == authRequest.password) LAResult.Success else LAResult.Error(generalGetString(R.string.incorrect_passcode))
|
||||
authRequest.completed(r)
|
||||
val sdPassword = ksSelfDestructPassword.get()
|
||||
if (sdPassword == passcode.value && authRequest.selfDestruct) {
|
||||
deleteStorageAndRestart(m, sdPassword) { r ->
|
||||
authRequest.completed(r)
|
||||
}
|
||||
} else {
|
||||
val r: LAResult = if (passcode.value == authRequest.password) LAResult.Success else LAResult.Error(generalGetString(R.string.incorrect_passcode))
|
||||
authRequest.completed(r)
|
||||
}
|
||||
},
|
||||
cancel = {
|
||||
authRequest.completed(LAResult.Error(generalGetString(R.string.authentication_cancelled)))
|
||||
})
|
||||
}
|
||||
|
||||
private fun deleteStorageAndRestart(m: ChatModel, password: String, completed: (LAResult) -> Unit) {
|
||||
withBGApi {
|
||||
try {
|
||||
stopChatAsync(m)
|
||||
deleteChatAsync(m)
|
||||
ksAppPassword.set(password)
|
||||
ksSelfDestructPassword.remove()
|
||||
m.controller.ntfManager.cancelAllNotifications()
|
||||
val selfDestructPref = m.controller.appPrefs.selfDestruct
|
||||
val displayNamePref = m.controller.appPrefs.selfDestructDisplayName
|
||||
val displayName = displayNamePref.get()
|
||||
selfDestructPref.set(false)
|
||||
displayNamePref.set(null)
|
||||
m.chatDbChanged.value = true
|
||||
m.chatDbStatus.value = null
|
||||
try {
|
||||
SimplexApp.context.initChatController(startChat = true)
|
||||
} catch (e: Exception) {
|
||||
Log.d(TAG, "initializeChat ${e.stackTraceToString()}")
|
||||
}
|
||||
m.chatDbChanged.value = false
|
||||
if (m.currentUser.value != null) {
|
||||
return@withBGApi
|
||||
}
|
||||
var profile: Profile? = null
|
||||
if (!displayName.isNullOrEmpty()) {
|
||||
profile = Profile(displayName = displayName, fullName = "")
|
||||
}
|
||||
val createdUser = m.controller.apiCreateActiveUser(profile, pastTimestamp = true)
|
||||
m.currentUser.value = createdUser
|
||||
m.controller.appPrefs.onboardingStage.set(OnboardingStage.OnboardingComplete)
|
||||
m.onboardingStage.value = OnboardingStage.OnboardingComplete
|
||||
if (createdUser != null) {
|
||||
m.controller.startChat(createdUser)
|
||||
}
|
||||
ModalManager.shared.closeModals()
|
||||
AlertManager.shared.hideAlert()
|
||||
completed(LAResult.Success)
|
||||
} catch (e: Exception) {
|
||||
completed(LAResult.Error(generalGetString(R.string.incorrect_passcode)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-3
@@ -4,11 +4,15 @@ import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import chat.simplex.app.R
|
||||
import chat.simplex.app.views.helpers.DatabaseUtils
|
||||
import chat.simplex.app.views.helpers.DatabaseUtils.ksAppPassword
|
||||
import chat.simplex.app.views.helpers.generalGetString
|
||||
|
||||
@Composable
|
||||
fun SetAppPasscodeView(
|
||||
passcodeKeychain: DatabaseUtils.KeyStoreItem = ksAppPassword,
|
||||
title: String = generalGetString(R.string.new_passcode),
|
||||
reason: String? = null,
|
||||
submit: () -> Unit,
|
||||
cancel: () -> Unit,
|
||||
close: () -> Unit
|
||||
@@ -23,7 +27,7 @@ fun SetAppPasscodeView(
|
||||
close()
|
||||
cancel()
|
||||
}
|
||||
PasscodeView(passcode, title = title, submitLabel = submitLabel, submitEnabled = submitEnabled, submit = submit) {
|
||||
PasscodeView(passcode, title = title, reason = reason, submitLabel = submitLabel, submitEnabled = submitEnabled, submit = submit) {
|
||||
close()
|
||||
cancel()
|
||||
}
|
||||
@@ -36,7 +40,7 @@ fun SetAppPasscodeView(
|
||||
submitEnabled = { pwd -> pwd == enteredPassword }
|
||||
) {
|
||||
if (passcode.value == enteredPassword) {
|
||||
ksAppPassword.set(passcode.value)
|
||||
passcodeKeychain.set(passcode.value)
|
||||
enteredPassword = ""
|
||||
passcode.value = ""
|
||||
close()
|
||||
@@ -44,7 +48,7 @@ fun SetAppPasscodeView(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
SetPasswordView(generalGetString(R.string.new_passcode), generalGetString(R.string.save_verb)) {
|
||||
SetPasswordView(title, generalGetString(R.string.save_verb)) {
|
||||
enteredPassword = passcode.value
|
||||
passcode.value = ""
|
||||
confirming = true
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package chat.simplex.app.views.newchat
|
||||
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import chat.simplex.app.R
|
||||
import chat.simplex.app.views.helpers.AppBarTitle
|
||||
import chat.simplex.app.views.onboarding.ReadableText
|
||||
import chat.simplex.app.views.onboarding.ReadableTextWithLink
|
||||
|
||||
@Composable
|
||||
fun AddContactLearnMore() {
|
||||
Column(
|
||||
Modifier.verticalScroll(rememberScrollState()),
|
||||
) {
|
||||
AppBarTitle(stringResource(R.string.one_time_link))
|
||||
ReadableText(R.string.scan_qr_to_connect_to_contact)
|
||||
ReadableText(R.string.if_you_cant_meet_in_person)
|
||||
ReadableTextWithLink(R.string.read_more_in_user_guide_with_link, "https://simplex.chat/docs/guide/readme.html#connect-to-friends")
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package chat.simplex.app.views.newchat
|
||||
|
||||
import SectionBottomSpacer
|
||||
import SectionSpacer
|
||||
import SectionView
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
@@ -15,10 +17,10 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
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.ui.theme.*
|
||||
import chat.simplex.app.views.helpers.*
|
||||
import chat.simplex.app.views.usersettings.SettingsActionItem
|
||||
|
||||
@Composable
|
||||
fun AddContactView(connReqInvitation: String, connIncognito: Boolean) {
|
||||
@@ -26,64 +28,94 @@ fun AddContactView(connReqInvitation: String, connIncognito: Boolean) {
|
||||
AddContactLayout(
|
||||
connReq = connReqInvitation,
|
||||
connIncognito = connIncognito,
|
||||
share = { shareText(cxt, connReqInvitation) }
|
||||
share = { shareText(cxt, connReqInvitation) },
|
||||
learnMore = {
|
||||
ModalManager.shared.showModal {
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxHeight()
|
||||
.padding(horizontal = DEFAULT_PADDING),
|
||||
verticalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
AddContactLearnMore()
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AddContactLayout(connReq: String, connIncognito: Boolean, share: () -> Unit) {
|
||||
BoxWithConstraints {
|
||||
val screenHeight = maxHeight
|
||||
Column(
|
||||
Modifier
|
||||
.verticalScroll(rememberScrollState()),
|
||||
verticalArrangement = Arrangement.SpaceBetween,
|
||||
) {
|
||||
AppBarTitle(stringResource(R.string.add_contact), false)
|
||||
Text(
|
||||
stringResource(R.string.show_QR_code_for_your_contact_to_scan_from_the_app__multiline),
|
||||
)
|
||||
Row {
|
||||
InfoAboutIncognito(
|
||||
connIncognito,
|
||||
true,
|
||||
generalGetString(R.string.incognito_random_profile_description),
|
||||
generalGetString(R.string.your_profile_will_be_sent)
|
||||
)
|
||||
}
|
||||
if (connReq.isNotEmpty()) {
|
||||
QRCode(
|
||||
connReq, Modifier
|
||||
.aspectRatio(1f)
|
||||
.padding(vertical = 3.dp)
|
||||
)
|
||||
} else {
|
||||
CircularProgressIndicator(
|
||||
Modifier
|
||||
.size(36.dp)
|
||||
.padding(4.dp)
|
||||
.align(Alignment.CenterHorizontally),
|
||||
color = MaterialTheme.colors.secondary,
|
||||
strokeWidth = 3.dp
|
||||
)
|
||||
}
|
||||
Text(
|
||||
annotatedStringResource(R.string.if_you_cannot_meet_in_person_show_QR_in_video_call_or_via_another_channel),
|
||||
lineHeight = 22.sp,
|
||||
modifier = Modifier
|
||||
.padding(top = DEFAULT_PADDING, bottom = if (screenHeight > 600.dp) DEFAULT_PADDING else 0.dp)
|
||||
)
|
||||
Row(
|
||||
Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.Center
|
||||
) {
|
||||
SimpleButton(stringResource(R.string.share_invitation_link), icon = painterResource(R.drawable.ic_share), click = share)
|
||||
}
|
||||
SectionBottomSpacer()
|
||||
fun AddContactLayout(connReq: String, connIncognito: Boolean, share: () -> Unit, learnMore: () -> Unit) {
|
||||
Column(
|
||||
Modifier
|
||||
.verticalScroll(rememberScrollState()),
|
||||
verticalArrangement = Arrangement.SpaceBetween,
|
||||
) {
|
||||
AppBarTitle(stringResource(R.string.add_contact))
|
||||
OneTimeLinkProfileText(connIncognito)
|
||||
|
||||
SectionSpacer()
|
||||
SectionView(stringResource(R.string.one_time_link_short).uppercase()) {
|
||||
OneTimeLinkSection(connReq, share, learnMore)
|
||||
}
|
||||
SectionBottomSpacer()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun OneTimeLinkProfileText(connIncognito: Boolean) {
|
||||
Row(Modifier.padding(horizontal = DEFAULT_PADDING)) {
|
||||
InfoAboutIncognito(
|
||||
connIncognito,
|
||||
true,
|
||||
generalGetString(R.string.incognito_random_profile_description),
|
||||
generalGetString(R.string.your_profile_will_be_sent)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ColumnScope.OneTimeLinkSection(connReq: String, share: () -> Unit, learnMore: () -> Unit) {
|
||||
if (connReq.isNotEmpty()) {
|
||||
QRCode(
|
||||
connReq, Modifier
|
||||
.padding(horizontal = DEFAULT_PADDING, vertical = DEFAULT_PADDING_HALF)
|
||||
.aspectRatio(1f)
|
||||
)
|
||||
} else {
|
||||
CircularProgressIndicator(
|
||||
Modifier
|
||||
.size(36.dp)
|
||||
.padding(4.dp)
|
||||
.align(Alignment.CenterHorizontally),
|
||||
color = MaterialTheme.colors.secondary,
|
||||
strokeWidth = 3.dp
|
||||
)
|
||||
}
|
||||
ShareLinkButton(share)
|
||||
OneTimeLinkLearnMoreButton(learnMore)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ShareLinkButton(onClick: () -> Unit) {
|
||||
SettingsActionItem(
|
||||
painterResource(R.drawable.ic_share),
|
||||
stringResource(R.string.share_invitation_link),
|
||||
onClick,
|
||||
iconColor = MaterialTheme.colors.primary,
|
||||
textColor = MaterialTheme.colors.primary,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun OneTimeLinkLearnMoreButton(onClick: () -> Unit) {
|
||||
SettingsActionItem(
|
||||
painterResource(R.drawable.ic_info),
|
||||
stringResource(R.string.learn_more),
|
||||
onClick,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun InfoAboutIncognito(chatModelIncognito: Boolean, supportedIncognito: Boolean = true, onText: String, offText: String, centered: Boolean = false) {
|
||||
if (chatModelIncognito) {
|
||||
@@ -133,7 +165,8 @@ fun PreviewAddContactView() {
|
||||
AddContactLayout(
|
||||
connReq = "https://simplex.chat/contact#/?v=1&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FK1rslx-m5bpXVIdMZg9NLUZ_8JBm8xTt%23MCowBQYDK2VuAyEALDeVe-sG8mRY22LsXlPgiwTNs9dbiLrNuA7f3ZMAJ2w%3D",
|
||||
connIncognito = false,
|
||||
share = {}
|
||||
share = {},
|
||||
learnMore = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,7 +159,7 @@ fun CreateGroupButton(color: Color, modifier: Modifier) {
|
||||
Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.End
|
||||
) {
|
||||
Surface(shape = RoundedCornerShape(20.dp)) {
|
||||
Surface(shape = RoundedCornerShape(20.dp), color = Color.Transparent) {
|
||||
Row(modifier, verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(stringResource(R.string.create_profile_button), style = MaterialTheme.typography.caption, color = color, fontWeight = FontWeight.Bold)
|
||||
Icon(painterResource(R.drawable.ic_arrow_forward_ios), stringResource(R.string.create_profile_button), tint = color)
|
||||
|
||||
+27
-22
@@ -1,6 +1,7 @@
|
||||
package chat.simplex.app.views.newchat
|
||||
|
||||
import SectionBottomSpacer
|
||||
import SectionDividerSpaced
|
||||
import SectionView
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.layout.*
|
||||
@@ -10,6 +11,7 @@ import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
@@ -43,13 +45,16 @@ fun ContactConnectionInfoView(
|
||||
}
|
||||
}
|
||||
}
|
||||
val context = LocalContext.current
|
||||
ContactConnectionInfoLayout(
|
||||
connReq = connReqInvitation,
|
||||
contactConnection,
|
||||
connIncognito = contactConnection.incognito,
|
||||
focusAlias,
|
||||
deleteConnection = { deleteContactConnectionAlert(contactConnection, chatModel, close) },
|
||||
onLocalAliasChanged = { setContactAlias(contactConnection, it, chatModel) },
|
||||
showQr = {
|
||||
share = { if (connReqInvitation != null) shareText(context, connReqInvitation) },
|
||||
learnMore = {
|
||||
ModalManager.shared.showModal {
|
||||
Column(
|
||||
Modifier
|
||||
@@ -57,7 +62,7 @@ fun ContactConnectionInfoView(
|
||||
.padding(horizontal = DEFAULT_PADDING),
|
||||
verticalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
AddContactView(connReqInvitation ?: return@showModal, contactConnection.incognito)
|
||||
AddContactLearnMore()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -68,10 +73,12 @@ fun ContactConnectionInfoView(
|
||||
private fun ContactConnectionInfoLayout(
|
||||
connReq: String?,
|
||||
contactConnection: PendingContactConnection,
|
||||
connIncognito: Boolean,
|
||||
focusAlias: Boolean,
|
||||
deleteConnection: () -> Unit,
|
||||
onLocalAliasChanged: (String) -> Unit,
|
||||
showQr: () -> Unit,
|
||||
share: () -> Unit,
|
||||
learnMore: () -> Unit,
|
||||
) {
|
||||
Column(
|
||||
Modifier
|
||||
@@ -83,11 +90,6 @@ private fun ContactConnectionInfoLayout(
|
||||
else R.string.you_accepted_connection
|
||||
)
|
||||
)
|
||||
if (contactConnection.groupLinkId == null) {
|
||||
Row(Modifier.padding(bottom = DEFAULT_PADDING)) {
|
||||
LocalAliasEditor(contactConnection.localAlias, center = false, leadingIcon = true, focus = focusAlias, updateValue = onLocalAliasChanged)
|
||||
}
|
||||
}
|
||||
Text(
|
||||
stringResource(
|
||||
if (contactConnection.viaContactUri)
|
||||
@@ -97,27 +99,28 @@ private fun ContactConnectionInfoLayout(
|
||||
),
|
||||
Modifier.padding(start = DEFAULT_PADDING, end = DEFAULT_PADDING, bottom = DEFAULT_PADDING)
|
||||
)
|
||||
OneTimeLinkProfileText(connIncognito)
|
||||
|
||||
if (contactConnection.groupLinkId == null) {
|
||||
LocalAliasEditor(contactConnection.localAlias, center = false, leadingIcon = true, focus = focusAlias, updateValue = onLocalAliasChanged)
|
||||
}
|
||||
|
||||
SectionView {
|
||||
if (!connReq.isNullOrEmpty() && contactConnection.initiated) {
|
||||
ShowQrButton(contactConnection.incognito, showQr)
|
||||
OneTimeLinkSection(connReq, share, learnMore)
|
||||
} else {
|
||||
OneTimeLinkLearnMoreButton(learnMore)
|
||||
}
|
||||
DeleteButton(deleteConnection)
|
||||
}
|
||||
|
||||
SectionDividerSpaced(maxBottomPadding = false)
|
||||
|
||||
DeleteButton(deleteConnection)
|
||||
|
||||
SectionBottomSpacer()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ShowQrButton(incognito: Boolean, onClick: () -> Unit) {
|
||||
SettingsActionItem(
|
||||
painterResource(R.drawable.ic_qr_code),
|
||||
stringResource(R.string.show_QR_code),
|
||||
click = onClick,
|
||||
textColor = if (incognito) Indigo else MaterialTheme.colors.primary,
|
||||
iconColor = if (incognito) Indigo else MaterialTheme.colors.primary,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun DeleteButton(onClick: () -> Unit) {
|
||||
SettingsActionItem(
|
||||
@@ -147,10 +150,12 @@ private fun PreviewContactConnectionInfoView() {
|
||||
ContactConnectionInfoLayout(
|
||||
connReq = "https://simplex.chat/contact#/?v=1&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FK1rslx-m5bpXVIdMZg9NLUZ_8JBm8xTt%23MCowBQYDK2VuAyEALDeVe-sG8mRY22LsXlPgiwTNs9dbiLrNuA7f3ZMAJ2w%3D",
|
||||
PendingContactConnection.getSampleData(),
|
||||
connIncognito = false,
|
||||
focusAlias = false,
|
||||
deleteConnection = {},
|
||||
onLocalAliasChanged = {},
|
||||
showQr = {},
|
||||
share = {},
|
||||
learnMore = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,14 +45,13 @@ fun CreateLinkView(m: ChatModel, initialSelection: CreateLinkTab) {
|
||||
when {
|
||||
it == CreateLinkTab.ONE_TIME && connReqInvitation.value.isNullOrEmpty() -> stringResource(R.string.create_one_time_link)
|
||||
it == CreateLinkTab.ONE_TIME -> stringResource(R.string.one_time_link)
|
||||
it == CreateLinkTab.LONG_TERM -> stringResource(R.string.your_contact_address)
|
||||
it == CreateLinkTab.LONG_TERM -> stringResource(R.string.your_simplex_contact_address)
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxHeight()
|
||||
.padding(horizontal = DEFAULT_PADDING),
|
||||
.fillMaxHeight(),
|
||||
verticalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
Column(Modifier.weight(1f)) {
|
||||
@@ -61,7 +60,7 @@ fun CreateLinkView(m: ChatModel, initialSelection: CreateLinkTab) {
|
||||
AddContactView(connReqInvitation.value ?: "", m.incognito.value)
|
||||
}
|
||||
CreateLinkTab.LONG_TERM -> {
|
||||
UserAddressView(m)
|
||||
UserAddressView(m, viaCreateLinkView = true, close = {})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ fun ActionButton(
|
||||
disabled: Boolean = false,
|
||||
click: () -> Unit = {}
|
||||
) {
|
||||
Surface(shape = RoundedCornerShape(18.dp)) {
|
||||
Surface(shape = RoundedCornerShape(18.dp), color = Color.Transparent) {
|
||||
Column(
|
||||
Modifier
|
||||
.clickable(onClick = click)
|
||||
|
||||
@@ -85,7 +85,7 @@ fun PasteToConnectLayout(
|
||||
)
|
||||
|
||||
Box(Modifier.padding(top = DEFAULT_PADDING, bottom = 6.dp)) {
|
||||
TextEditor(Modifier.height(180.dp), text = connectionLink)
|
||||
TextEditor(connectionLink, Modifier.height(180.dp), contentPadding = PaddingValues())
|
||||
}
|
||||
|
||||
Row(
|
||||
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
package chat.simplex.app.views.onboarding
|
||||
|
||||
import SectionBottomSpacer
|
||||
import android.util.Log
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import chat.simplex.app.*
|
||||
import chat.simplex.app.R
|
||||
import chat.simplex.app.model.ChatModel
|
||||
import chat.simplex.app.model.UserContactLinkRec
|
||||
import chat.simplex.app.ui.theme.*
|
||||
import chat.simplex.app.views.helpers.*
|
||||
import chat.simplex.app.views.newchat.QRCode
|
||||
|
||||
@Composable
|
||||
fun CreateSimpleXAddress(m: ChatModel) {
|
||||
val context = LocalContext.current
|
||||
var progressIndicator by remember { mutableStateOf(false) }
|
||||
val userAddress = remember { m.userAddress }
|
||||
|
||||
CreateSimpleXAddressLayout(
|
||||
userAddress.value,
|
||||
share = { address: String -> shareText(context, address) },
|
||||
sendEmail = { address ->
|
||||
sendEmail(
|
||||
context,
|
||||
generalGetString(R.string.email_invite_subject),
|
||||
generalGetString(R.string.email_invite_body).format(address.connReqContact)
|
||||
)
|
||||
},
|
||||
createAddress = {
|
||||
withApi {
|
||||
progressIndicator = true
|
||||
val connReqContact = m.controller.apiCreateUserAddress()
|
||||
if (connReqContact != null) {
|
||||
m.userAddress.value = UserContactLinkRec(connReqContact)
|
||||
// TODO uncomment in v5.2
|
||||
// try {
|
||||
// val u = m.controller.apiSetProfileAddress(true)
|
||||
// if (u != null) {
|
||||
// m.updateUser(u)
|
||||
// }
|
||||
// } catch (e: Exception) {
|
||||
// Log.e(TAG, "CreateSimpleXAddress apiSetProfileAddress: ${e.stackTraceToString()}")
|
||||
// }
|
||||
progressIndicator = false
|
||||
}
|
||||
}
|
||||
},
|
||||
nextStep = {
|
||||
m.controller.appPrefs.onboardingStage.set(OnboardingStage.Step4_SetNotificationsMode)
|
||||
m.onboardingStage.value = OnboardingStage.Step4_SetNotificationsMode
|
||||
},
|
||||
)
|
||||
|
||||
if (progressIndicator) {
|
||||
ProgressIndicator()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CreateSimpleXAddressLayout(
|
||||
userAddress: UserContactLinkRec?,
|
||||
share: (String) -> Unit,
|
||||
sendEmail: (UserContactLinkRec) -> Unit,
|
||||
createAddress: () -> Unit,
|
||||
nextStep: () -> Unit,
|
||||
) {
|
||||
Column(
|
||||
Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(top = DEFAULT_PADDING),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
AppBarTitle(stringResource(R.string.simplex_address))
|
||||
|
||||
Spacer(Modifier.weight(1f))
|
||||
|
||||
if (userAddress != null) {
|
||||
QRCode(userAddress.connReqContact, Modifier.padding(horizontal = DEFAULT_PADDING, vertical = DEFAULT_PADDING_HALF).aspectRatio(1f))
|
||||
ShareAddressButton { share(userAddress.connReqContact) }
|
||||
Spacer(Modifier.weight(1f))
|
||||
ShareViaEmailButton { sendEmail(userAddress) }
|
||||
Spacer(Modifier.weight(1f))
|
||||
ContinueButton(nextStep)
|
||||
} else {
|
||||
CreateAddressButton(createAddress)
|
||||
// TODO remove color in v5.2
|
||||
TextBelowButton(stringResource(R.string.your_contacts_will_see_it), color = Color.Transparent)
|
||||
Spacer(Modifier.weight(1f))
|
||||
SkipButton(nextStep)
|
||||
}
|
||||
SectionBottomSpacer()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CreateAddressButton(onClick: () -> Unit) {
|
||||
TextButton(onClick) {
|
||||
Text(stringResource(R.string.create_simplex_address), style = MaterialTheme.typography.h2, color = MaterialTheme.colors.primary)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ShareAddressButton(onClick: () -> Unit) {
|
||||
SimpleButtonFrame(onClick) {
|
||||
Icon(
|
||||
painterResource(R.drawable.ic_share_filled), generalGetString(R.string.share_verb), tint = MaterialTheme.colors.primary,
|
||||
modifier = Modifier.padding(end = 8.dp).size(18.dp)
|
||||
)
|
||||
Text(stringResource(R.string.share_verb), style = MaterialTheme.typography.caption, color = MaterialTheme.colors.primary)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ShareViaEmailButton(onClick: () -> Unit) {
|
||||
SimpleButtonFrame(onClick) {
|
||||
Icon(
|
||||
painterResource(R.drawable.ic_mail), generalGetString(R.string.share_verb), tint = MaterialTheme.colors.primary,
|
||||
modifier = Modifier.padding(end = 8.dp).size(30.dp)
|
||||
)
|
||||
Text(stringResource(R.string.invite_friends), style = MaterialTheme.typography.h6, color = MaterialTheme.colors.primary)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ContinueButton(onClick: () -> Unit) {
|
||||
SimpleButtonIconEnded(stringResource(R.string.continue_to_next_step), painterResource(R.drawable.ic_chevron_right), click = onClick)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SkipButton(onClick: () -> Unit) {
|
||||
SimpleButtonIconEnded(stringResource(R.string.dont_create_address), painterResource(R.drawable.ic_chevron_right), click = onClick)
|
||||
TextBelowButton(stringResource(R.string.you_can_create_it_later))
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TextBelowButton(text: String, color: Color = Color.Unspecified) {
|
||||
// TODO remove color in v5.2
|
||||
Text(
|
||||
text,
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = DEFAULT_PADDING * 3),
|
||||
style = MaterialTheme.typography.subtitle1,
|
||||
textAlign = TextAlign.Center,
|
||||
color = color
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ProgressIndicator() {
|
||||
Box(
|
||||
Modifier.fillMaxSize(),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
CircularProgressIndicator(
|
||||
Modifier
|
||||
.padding(horizontal = 2.dp)
|
||||
.size(30.dp),
|
||||
color = MaterialTheme.colors.secondary,
|
||||
strokeWidth = 3.dp
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -4,21 +4,22 @@ import android.content.res.Configuration
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.*
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
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.SimplexApp
|
||||
import chat.simplex.app.model.User
|
||||
import chat.simplex.app.ui.theme.DEFAULT_PADDING
|
||||
import chat.simplex.app.ui.theme.SimpleXTheme
|
||||
import chat.simplex.app.ui.theme.*
|
||||
import chat.simplex.app.views.chat.item.MarkdownText
|
||||
import chat.simplex.app.views.helpers.*
|
||||
|
||||
@Composable
|
||||
@@ -33,12 +34,7 @@ fun HowItWorks(user: User?, onboardingStage: MutableState<OnboardingStage?>? = n
|
||||
ReadableText(R.string.you_control_servers_to_receive_your_contacts_to_send)
|
||||
ReadableText(R.string.only_client_devices_store_contacts_groups_e2e_encrypted_messages)
|
||||
if (onboardingStage == null) {
|
||||
val uriHandler = LocalUriHandler.current
|
||||
Text(
|
||||
annotatedStringResource(R.string.read_more_in_github_with_link),
|
||||
modifier = Modifier.padding(bottom = 12.dp).clickable { uriHandler.openUriCatching("https://github.com/simplex-chat/simplex-chat#readme") },
|
||||
lineHeight = 22.sp
|
||||
)
|
||||
ReadableTextWithLink(R.string.read_more_in_github_with_link, "https://github.com/simplex-chat/simplex-chat#readme")
|
||||
} else {
|
||||
ReadableText(R.string.read_more_in_github)
|
||||
}
|
||||
@@ -55,8 +51,28 @@ fun HowItWorks(user: User?, onboardingStage: MutableState<OnboardingStage?>? = n
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ReadableText(@StringRes stringResId: Int, textAlign: TextAlign = TextAlign.Start, padding: PaddingValues = PaddingValues(bottom = 12.dp)) {
|
||||
Text(annotatedStringResource(stringResId), modifier = Modifier.padding(padding), textAlign = textAlign, lineHeight = 22.sp)
|
||||
fun ReadableText(@StringRes stringResId: Int, textAlign: TextAlign = TextAlign.Start, padding: PaddingValues = PaddingValues(bottom = 12.dp), style: TextStyle = LocalTextStyle.current) {
|
||||
Text(annotatedStringResource(stringResId), modifier = Modifier.padding(padding), textAlign = textAlign, lineHeight = 22.sp, style = style)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ReadableTextWithLink(@StringRes stringResId: Int, link: String, textAlign: TextAlign = TextAlign.Start, padding: PaddingValues = PaddingValues(bottom = 12.dp)) {
|
||||
val annotated = annotatedStringResource(stringResId)
|
||||
val primary = MaterialTheme.colors.primary
|
||||
// This replaces links in text highlighted with specific color, e.g. SimplexBlue
|
||||
val newStyles = remember(stringResId) {
|
||||
val newStyles = ArrayList<AnnotatedString.Range<SpanStyle>>()
|
||||
annotated.spanStyles.forEach {
|
||||
if (it.item.color == SimplexBlue) {
|
||||
newStyles.add(it.copy(item = it.item.copy(primary)))
|
||||
} else {
|
||||
newStyles.add(it)
|
||||
}
|
||||
}
|
||||
newStyles
|
||||
}
|
||||
val uriHandler = LocalUriHandler.current
|
||||
Text(AnnotatedString(annotated.text, newStyles), modifier = Modifier.padding(padding).clickable { uriHandler.openUriCatching(link) }, textAlign = textAlign, lineHeight = 22.sp)
|
||||
}
|
||||
|
||||
@Composable
|
||||
@@ -64,6 +80,17 @@ fun ReadableText(text: String, textAlign: TextAlign = TextAlign.Start, padding:
|
||||
Text(text, modifier = Modifier.padding(padding), textAlign = textAlign, lineHeight = 22.sp)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ReadableMarkdownText(text: String, textAlign: TextAlign = TextAlign.Start, padding: PaddingValues = PaddingValues(bottom = 12.dp)) {
|
||||
MarkdownText(
|
||||
text,
|
||||
formattedText = remember(text) { parseToMarkdown(text) },
|
||||
modifier = Modifier.padding(padding),
|
||||
style = TextStyle(textAlign = textAlign, lineHeight = 22.sp, fontSize = 16.sp),
|
||||
linkMode = SimplexApp.context.chatModel.controller.appPrefs.simplexLinkMode.get(),
|
||||
)
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Preview(
|
||||
uiMode = Configuration.UI_MODE_NIGHT_YES,
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package chat.simplex.app.views.onboarding
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -16,7 +14,8 @@ import kotlinx.coroutines.launch
|
||||
enum class OnboardingStage {
|
||||
Step1_SimpleXInfo,
|
||||
Step2_CreateProfile,
|
||||
Step3_SetNotificationsMode,
|
||||
Step3_CreateSimpleXAddress,
|
||||
Step4_SetNotificationsMode,
|
||||
OnboardingComplete
|
||||
}
|
||||
|
||||
@@ -31,8 +30,7 @@ fun CreateProfile(chatModel: ChatModel, close: () -> Unit) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(color = MaterialTheme.colors.background)
|
||||
.padding(20.dp)
|
||||
.padding(top = 20.dp)
|
||||
) {
|
||||
CreateProfilePanel(chatModel, close)
|
||||
LaunchedEffect(Unit) {
|
||||
|
||||
+11
-7
@@ -40,13 +40,16 @@ fun SetNotificationsMode(m: ChatModel) {
|
||||
NotificationButton(currentMode, NotificationsMode.SERVICE, R.string.onboarding_notifications_mode_service, R.string.onboarding_notifications_mode_service_desc)
|
||||
}
|
||||
Spacer(Modifier.fillMaxHeight().weight(1f))
|
||||
Box(Modifier.fillMaxWidth().padding(bottom = DEFAULT_PADDING), contentAlignment = Alignment.Center) {
|
||||
OnboardingActionButton(R.string.use_chat, OnboardingStage.OnboardingComplete, m.onboardingStage, false) {
|
||||
changeNotificationsMode(currentMode.value, m)
|
||||
}
|
||||
Box(Modifier.fillMaxWidth().padding(bottom = DEFAULT_PADDING_HALF), contentAlignment = Alignment.Center) {
|
||||
OnboardingActionButton(R.string.use_chat, OnboardingStage.OnboardingComplete, m.onboardingStage, false) {
|
||||
changeNotificationsMode(currentMode.value, m)
|
||||
}
|
||||
Spacer(Modifier.fillMaxHeight().weight(1f))
|
||||
}
|
||||
Spacer(Modifier.fillMaxHeight().weight(1f))
|
||||
}
|
||||
LaunchedEffect(Unit) {
|
||||
m.controller.ntfManager.createNtfChannelsMaybeShowAlert()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@@ -56,10 +59,10 @@ private fun NotificationButton(currentMode: MutableState<NotificationsMode>, mod
|
||||
border = BorderStroke(1.dp, color = if (currentMode.value == mode) MaterialTheme.colors.primary else MaterialTheme.colors.secondary.copy(alpha = 0.5f)),
|
||||
shape = RoundedCornerShape(35.dp),
|
||||
) {
|
||||
Column(Modifier.padding(horizontal = 14.dp).padding(top = 4.dp, bottom = 8.dp)) {
|
||||
Column(Modifier.padding(horizontal = 10.dp).padding(top = 4.dp, bottom = 8.dp)) {
|
||||
Text(
|
||||
stringResource(title),
|
||||
style = MaterialTheme.typography.h2,
|
||||
style = MaterialTheme.typography.h3,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = if (currentMode.value == mode) MaterialTheme.colors.primary else MaterialTheme.colors.secondary,
|
||||
modifier = Modifier.padding(bottom = 8.dp).align(Alignment.CenterHorizontally),
|
||||
@@ -67,6 +70,7 @@ private fun NotificationButton(currentMode: MutableState<NotificationsMode>, mod
|
||||
)
|
||||
Text(annotatedStringResource(description),
|
||||
Modifier.align(Alignment.CenterHorizontally),
|
||||
fontSize = 15.sp,
|
||||
color = MaterialTheme.colors.onBackground,
|
||||
lineHeight = 24.sp,
|
||||
textAlign = TextAlign.Center
|
||||
|
||||
@@ -18,6 +18,7 @@ import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.*
|
||||
import chat.simplex.app.R
|
||||
import chat.simplex.app.SimplexApp
|
||||
import chat.simplex.app.model.ChatModel
|
||||
import chat.simplex.app.model.User
|
||||
import chat.simplex.app.ui.theme.*
|
||||
@@ -42,13 +43,13 @@ fun SimpleXInfoLayout(
|
||||
Modifier
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState())
|
||||
.padding(start = DEFAULT_PADDING * 1.5f, end = DEFAULT_PADDING * 1.5f, top = DEFAULT_PADDING * 4,/* bottom = DEFAULT_PADDING * 4*/),
|
||||
.padding(start = DEFAULT_PADDING , end = DEFAULT_PADDING, top = DEFAULT_PADDING),
|
||||
) {
|
||||
Box(Modifier.fillMaxWidth().padding(top = 8.dp, bottom = 10.dp), contentAlignment = Alignment.Center) {
|
||||
SimpleXLogo()
|
||||
}
|
||||
|
||||
Text(stringResource(R.string.next_generation_of_private_messaging), style = MaterialTheme.typography.h2, modifier = Modifier.padding(bottom = 60.dp).padding(horizontal = 48.dp), textAlign = TextAlign.Center)
|
||||
Text(stringResource(R.string.next_generation_of_private_messaging), style = MaterialTheme.typography.h2, modifier = Modifier.padding(bottom = 48.dp).padding(horizontal = 36.dp), textAlign = TextAlign.Center)
|
||||
|
||||
InfoRow(painterResource(R.drawable.privacy), R.string.privacy_redefined, R.string.first_platform_without_user_ids, width = 80.dp)
|
||||
InfoRow(painterResource(R.drawable.shield), R.string.immune_to_spam_and_abuse, R.string.people_can_connect_only_via_links_you_share)
|
||||
@@ -66,12 +67,11 @@ fun SimpleXInfoLayout(
|
||||
Box(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(bottom = DEFAULT_PADDING, top = DEFAULT_PADDING), contentAlignment = Alignment.Center
|
||||
.padding(bottom = DEFAULT_PADDING.times(1.5f), top = DEFAULT_PADDING), contentAlignment = Alignment.Center
|
||||
) {
|
||||
SimpleButtonDecorated(text = stringResource(R.string.how_it_works), icon = painterResource(R.drawable.ic_info),
|
||||
click = showModal { HowItWorks(user, onboardingStage) })
|
||||
}
|
||||
Spacer(Modifier.weight(1f))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ fun OnboardingActionButton(
|
||||
Modifier
|
||||
.border(border = BorderStroke(1.dp, MaterialTheme.colors.primary), shape = RoundedCornerShape(50))
|
||||
.padding(
|
||||
horizontal = DEFAULT_PADDING * 3,
|
||||
horizontal = DEFAULT_PADDING * 2,
|
||||
vertical = 4.dp
|
||||
)
|
||||
} else {
|
||||
@@ -130,13 +130,14 @@ fun OnboardingActionButton(
|
||||
SimpleButtonFrame(click = {
|
||||
onclick?.invoke()
|
||||
onboardingStage.value = onboarding
|
||||
if (onboarding != null) {
|
||||
SimplexApp.context.chatModel.controller.appPrefs.onboardingStage.set(onboarding)
|
||||
}
|
||||
}, modifier) {
|
||||
Text(stringResource(labelId), style = MaterialTheme.typography.h2, color = MaterialTheme.colors.primary, fontSize = 20.sp)
|
||||
Icon(
|
||||
painterResource(R.drawable.ic_arrow_forward_ios), "next stage", tint = MaterialTheme.colors.primary,
|
||||
modifier = Modifier
|
||||
.padding(start = DEFAULT_PADDING, top = 5.dp)
|
||||
.size(15.dp)
|
||||
modifier = Modifier.padding(start = DEFAULT_PADDING.div(4)).size(20.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import chat.simplex.app.BuildConfig
|
||||
import chat.simplex.app.R
|
||||
import chat.simplex.app.model.ChatModel
|
||||
@@ -42,9 +43,7 @@ fun WhatsNewView(viaSettings: Boolean = false, close: () -> Unit) {
|
||||
)
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier.padding(bottom = 12.dp)
|
||||
) {
|
||||
Column(modifier = Modifier.padding(bottom = 12.dp)) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
@@ -53,16 +52,16 @@ fun WhatsNewView(viaSettings: Boolean = false, close: () -> Unit) {
|
||||
Icon(icon, stringResource(titleId), tint = MaterialTheme.colors.secondary)
|
||||
Text(
|
||||
generalGetString(titleId),
|
||||
maxLines = 1,
|
||||
maxLines = 2,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
style = MaterialTheme.typography.h3,
|
||||
style = MaterialTheme.typography.h4,
|
||||
fontWeight = FontWeight.Medium
|
||||
)
|
||||
if (link != null) {
|
||||
linkButton(link)
|
||||
}
|
||||
}
|
||||
Text(generalGetString(descrId))
|
||||
Text(generalGetString(descrId), fontSize = 15.sp)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,14 +113,23 @@ fun WhatsNewView(viaSettings: Boolean = false, close: () -> Unit) {
|
||||
.fillMaxSize()
|
||||
.padding(horizontal = DEFAULT_PADDING)
|
||||
.verticalScroll(rememberScrollState()),
|
||||
verticalArrangement = Arrangement.spacedBy(DEFAULT_PADDING)
|
||||
verticalArrangement = Arrangement.spacedBy(DEFAULT_PADDING.times(0.75f))
|
||||
) {
|
||||
AppBarTitle(String.format(generalGetString(R.string.new_in_version), v.version))
|
||||
AppBarTitle(String.format(generalGetString(R.string.new_in_version), v.version), bottomPadding = DEFAULT_PADDING)
|
||||
|
||||
v.features.forEach { feature ->
|
||||
featureDescription(painterResource(feature.icon), feature.titleId, feature.descrId, feature.link)
|
||||
}
|
||||
|
||||
val uriHandler = LocalUriHandler.current
|
||||
if (v.post != null) {
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(8.dp), modifier = Modifier.padding(top = DEFAULT_PADDING.div(4))) {
|
||||
Text(stringResource(R.string.whats_new_read_more), color = MaterialTheme.colors.primary,
|
||||
modifier = Modifier.clickable { uriHandler.openUriCatching(v.post) })
|
||||
Icon(painterResource(R.drawable.ic_open_in_new), stringResource(R.string.whats_new_read_more), tint = MaterialTheme.colors.primary)
|
||||
}
|
||||
}
|
||||
|
||||
if (!viaSettings) {
|
||||
Spacer(Modifier.fillMaxHeight().weight(1f))
|
||||
Box(
|
||||
@@ -153,12 +161,14 @@ private data class FeatureDescription(
|
||||
|
||||
private data class VersionDescription(
|
||||
val version: String,
|
||||
val features: List<FeatureDescription>
|
||||
val features: List<FeatureDescription>,
|
||||
val post: String? = null,
|
||||
)
|
||||
|
||||
private val versionDescriptions: List<VersionDescription> = listOf(
|
||||
VersionDescription(
|
||||
version = "v4.2",
|
||||
post = "https://simplex.chat/blog/20221108-simplex-chat-v4.2-security-audit-new-website.html",
|
||||
features = listOf(
|
||||
FeatureDescription(
|
||||
icon = R.drawable.ic_verified_user,
|
||||
@@ -180,6 +190,7 @@ private val versionDescriptions: List<VersionDescription> = listOf(
|
||||
),
|
||||
VersionDescription(
|
||||
version = "v4.3",
|
||||
post = "https://simplex.chat/blog/20221206-simplex-chat-v4.3-voice-messages.html",
|
||||
features = listOf(
|
||||
FeatureDescription(
|
||||
icon = R.drawable.ic_mic,
|
||||
@@ -205,6 +216,7 @@ private val versionDescriptions: List<VersionDescription> = listOf(
|
||||
),
|
||||
VersionDescription(
|
||||
version = "v4.4",
|
||||
post = "https://simplex.chat/blog/20230103-simplex-chat-v4.4-disappearing-messages.html",
|
||||
features = listOf(
|
||||
FeatureDescription(
|
||||
icon = R.drawable.ic_timer,
|
||||
@@ -230,6 +242,7 @@ private val versionDescriptions: List<VersionDescription> = listOf(
|
||||
),
|
||||
VersionDescription(
|
||||
version = "v4.5",
|
||||
post = "https://simplex.chat/blog/20230204-simplex-chat-v4-5-user-chat-profiles.html",
|
||||
features = listOf(
|
||||
FeatureDescription(
|
||||
icon = R.drawable.ic_manage_accounts,
|
||||
@@ -261,12 +274,13 @@ private val versionDescriptions: List<VersionDescription> = listOf(
|
||||
icon = R.drawable.ic_translate,
|
||||
titleId = R.string.v4_5_italian_interface,
|
||||
descrId = R.string.v4_5_italian_interface_descr,
|
||||
link = "https://github.com/simplex-chat/simplex-chat/tree/stable#translate-the-apps"
|
||||
link = "https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat"
|
||||
)
|
||||
)
|
||||
),
|
||||
VersionDescription(
|
||||
version = "v4.6",
|
||||
post = "https://simplex.chat/blog/20230328-simplex-chat-v4-6-hidden-profiles.html",
|
||||
features = listOf(
|
||||
FeatureDescription(
|
||||
icon = R.drawable.ic_lock,
|
||||
@@ -297,12 +311,13 @@ private val versionDescriptions: List<VersionDescription> = listOf(
|
||||
icon = R.drawable.ic_translate,
|
||||
titleId = R.string.v4_6_chinese_spanish_interface,
|
||||
descrId = R.string.v4_6_chinese_spanish_interface_descr,
|
||||
link = "https://github.com/simplex-chat/simplex-chat/tree/stable#translate-the-apps"
|
||||
link = "https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat"
|
||||
)
|
||||
)
|
||||
),
|
||||
VersionDescription(
|
||||
version = "v5.0",
|
||||
post = "https://simplex.chat/blog/20230422-simplex-chat-vision-funding-v5-videos-files-passcode.html",
|
||||
features = listOf(
|
||||
FeatureDescription(
|
||||
icon = R.drawable.ic_upload_file,
|
||||
@@ -318,7 +333,45 @@ private val versionDescriptions: List<VersionDescription> = listOf(
|
||||
icon = R.drawable.ic_translate,
|
||||
titleId = R.string.v5_0_polish_interface,
|
||||
descrId = R.string.v5_0_polish_interface_descr,
|
||||
link = "https://github.com/simplex-chat/simplex-chat/tree/stable#translate-the-apps"
|
||||
link = "https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat"
|
||||
)
|
||||
)
|
||||
),
|
||||
// Also in v5.1
|
||||
// preference to disable calls per contact
|
||||
// configurable SOCKS proxy port
|
||||
// access welcome message via a group profile
|
||||
// improve calls on lock screen
|
||||
// better formatting of times and dates
|
||||
VersionDescription(
|
||||
version = "v5.1",
|
||||
post = "https://simplex.chat/blog/20230523-simplex-chat-v5-1-message-reactions-self-destruct-passcode.html",
|
||||
features = listOf(
|
||||
FeatureDescription(
|
||||
icon = R.drawable.ic_add_reaction,
|
||||
titleId = R.string.v5_1_message_reactions,
|
||||
descrId = R.string.v5_1_message_reactions_descr
|
||||
),
|
||||
FeatureDescription(
|
||||
icon = R.drawable.ic_chat,
|
||||
titleId = R.string.v5_1_better_messages,
|
||||
descrId = R.string.v5_1_better_messages_descr
|
||||
),
|
||||
FeatureDescription(
|
||||
icon = R.drawable.ic_light_mode,
|
||||
titleId = R.string.v5_1_custom_themes,
|
||||
descrId = R.string.v5_1_custom_themes_descr
|
||||
),
|
||||
FeatureDescription(
|
||||
icon = R.drawable.ic_lock,
|
||||
titleId = R.string.v5_1_self_destruct_passcode,
|
||||
descrId = R.string.v5_1_self_destruct_passcode_descr
|
||||
),
|
||||
FeatureDescription(
|
||||
icon = R.drawable.ic_translate,
|
||||
titleId = R.string.v5_1_japanese_portuguese_interface,
|
||||
descrId = R.string.whats_new_thanks_to_users_contribute_weblate,
|
||||
link = "https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat"
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
-160
@@ -1,160 +0,0 @@
|
||||
package chat.simplex.app.views.usersettings
|
||||
|
||||
import SectionBottomSpacer
|
||||
import SectionCustomFooter
|
||||
import SectionView
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import chat.simplex.app.R
|
||||
import chat.simplex.app.model.*
|
||||
import chat.simplex.app.ui.theme.*
|
||||
import chat.simplex.app.views.helpers.*
|
||||
|
||||
@Composable
|
||||
fun AcceptRequestsView(m: ChatModel, contactLink: UserContactLinkRec) {
|
||||
var contactLink by remember { mutableStateOf(contactLink) }
|
||||
AcceptRequestsLayout(
|
||||
contactLink,
|
||||
saveState = { new: MutableState<AutoAcceptState>, old: MutableState<AutoAcceptState> ->
|
||||
withApi {
|
||||
val link = m.controller.userAddressAutoAccept(new.value.autoAccept)
|
||||
if (link != null) {
|
||||
contactLink = link
|
||||
m.userAddress.value = link
|
||||
old.value = new.value
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AcceptRequestsLayout(
|
||||
contactLink: UserContactLinkRec,
|
||||
saveState: (new: MutableState<AutoAcceptState>, old: MutableState<AutoAcceptState>) -> Unit,
|
||||
) {
|
||||
Column(
|
||||
Modifier.fillMaxWidth().verticalScroll(rememberScrollState()),
|
||||
) {
|
||||
AppBarTitle(stringResource(R.string.contact_requests))
|
||||
val autoAcceptState = remember { mutableStateOf(AutoAcceptState(contactLink)) }
|
||||
val autoAcceptStateSaved = remember { mutableStateOf(autoAcceptState.value) }
|
||||
SectionView(stringResource(R.string.accept_requests).uppercase()) {
|
||||
PreferenceToggleWithIcon(stringResource(R.string.accept_automatically), painterResource(R.drawable.ic_check), checked = autoAcceptState.value.enable) {
|
||||
autoAcceptState.value = if (!it)
|
||||
AutoAcceptState()
|
||||
else
|
||||
AutoAcceptState(it, autoAcceptState.value.incognito, autoAcceptState.value.welcomeText)
|
||||
}
|
||||
if (autoAcceptState.value.enable) {
|
||||
PreferenceToggleWithIcon(
|
||||
stringResource(R.string.incognito),
|
||||
if (autoAcceptState.value.incognito) painterResource(R.drawable.ic_theater_comedy_filled) else painterResource(R.drawable.ic_theater_comedy),
|
||||
if (autoAcceptState.value.incognito) Indigo else MaterialTheme.colors.secondary,
|
||||
autoAcceptState.value.incognito,
|
||||
) {
|
||||
autoAcceptState.value = AutoAcceptState(autoAcceptState.value.enable, it, autoAcceptState.value.welcomeText)
|
||||
}
|
||||
}
|
||||
}
|
||||
val welcomeText = remember { mutableStateOf(autoAcceptState.value.welcomeText) }
|
||||
SectionCustomFooter(PaddingValues(horizontal = DEFAULT_PADDING)) {
|
||||
ButtonsFooter(
|
||||
cancel = {
|
||||
autoAcceptState.value = autoAcceptStateSaved.value
|
||||
welcomeText.value = autoAcceptStateSaved.value.welcomeText
|
||||
},
|
||||
save = { saveState(autoAcceptState, autoAcceptStateSaved) },
|
||||
disabled = autoAcceptState.value == autoAcceptStateSaved.value
|
||||
)
|
||||
}
|
||||
Spacer(Modifier.height(DEFAULT_PADDING))
|
||||
if (autoAcceptState.value.enable) {
|
||||
Text(
|
||||
stringResource(R.string.section_title_welcome_message), color = MaterialTheme.colors.secondary, style = MaterialTheme.typography.body2,
|
||||
modifier = Modifier.padding(start = DEFAULT_PADDING, bottom = 5.dp), fontSize = 12.sp
|
||||
)
|
||||
TextEditor(Modifier.padding(horizontal = DEFAULT_PADDING).height(160.dp), text = welcomeText)
|
||||
LaunchedEffect(welcomeText.value) {
|
||||
if (welcomeText.value != autoAcceptState.value.welcomeText) {
|
||||
autoAcceptState.value = AutoAcceptState(autoAcceptState.value.enable, autoAcceptState.value.incognito, welcomeText.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
SectionBottomSpacer()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ButtonsFooter(cancel: () -> Unit, save: () -> Unit, disabled: Boolean) {
|
||||
Row(
|
||||
Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
FooterButton(painterResource(R.drawable.ic_replay), stringResource(R.string.cancel_verb), cancel, disabled)
|
||||
FooterButton(painterResource(R.drawable.ic_check), stringResource(R.string.save_verb), save, disabled)
|
||||
}
|
||||
}
|
||||
|
||||
private class AutoAcceptState {
|
||||
var enable: Boolean = false
|
||||
private set
|
||||
var incognito: Boolean = false
|
||||
private set
|
||||
var welcomeText: String = ""
|
||||
private set
|
||||
|
||||
constructor(enable: Boolean = false, incognito: Boolean = false, welcomeText: String = "") {
|
||||
this.enable = enable
|
||||
this.incognito = incognito
|
||||
this.welcomeText = welcomeText
|
||||
}
|
||||
|
||||
constructor(contactLink: UserContactLinkRec) {
|
||||
contactLink.autoAccept?.let { aa ->
|
||||
enable = true
|
||||
incognito = aa.acceptIncognito
|
||||
aa.autoReply?.let { msg ->
|
||||
welcomeText = msg.text
|
||||
} ?: run {
|
||||
welcomeText = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val autoAccept: AutoAccept?
|
||||
get() {
|
||||
if (enable) {
|
||||
var autoReply: MsgContent? = null
|
||||
val s = welcomeText.trim()
|
||||
if (s != "") {
|
||||
autoReply = MsgContent.MCText(s)
|
||||
}
|
||||
return AutoAccept(incognito, autoReply)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other !is AutoAcceptState) return false
|
||||
return this.enable == other.enable && this.incognito == other.incognito && this.welcomeText == other.welcomeText
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = enable.hashCode()
|
||||
result = 31 * result + incognito.hashCode()
|
||||
result = 31 * result + welcomeText.hashCode()
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -240,8 +240,8 @@ fun CustomizeThemeView(editColor: (ThemeColor, Color) -> Unit) {
|
||||
val theme = remember { mutableStateOf(null as String?) }
|
||||
val exportThemeLauncher = rememberSaveThemeLauncher(context, theme)
|
||||
SectionItemView({
|
||||
val themeData = ThemeManager.currentThemeData(isInDarkTheme)
|
||||
theme.value = yaml.encodeToString<ThemeData>(themeData)
|
||||
val overrides = ThemeManager.currentThemeOverridesForExport(isInDarkTheme)
|
||||
theme.value = yaml.encodeToString<ThemeOverrides>(overrides)
|
||||
exportThemeLauncher.launch("simplex.theme")
|
||||
}) {
|
||||
Text(generalGetString(R.string.export_theme), color = colors.primary)
|
||||
@@ -251,7 +251,7 @@ fun CustomizeThemeView(editColor: (ThemeColor, Color) -> Unit) {
|
||||
if (uri != null) {
|
||||
val theme = getThemeFromUri(uri)
|
||||
if (theme != null) {
|
||||
ThemeManager.saveAndApplyThemeData(currentTheme.name, theme, isInDarkTheme)
|
||||
ThemeManager.saveAndApplyThemeOverrides(theme, isInDarkTheme)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -320,8 +320,10 @@ private fun LangSelector(state: State<String>, onSelected: (String) -> Unit) {
|
||||
"es" to "Español",
|
||||
"fr" to "Français",
|
||||
"it" to "Italiano",
|
||||
"ja" to "日本語",
|
||||
"nl" to "Nederlands",
|
||||
"pl" to "Polski",
|
||||
"pt-BR" to "Português (Brasil)",
|
||||
"ru" to "Русский",
|
||||
"zh-CN" to "简体中文"
|
||||
)
|
||||
|
||||
@@ -126,6 +126,30 @@ fun SharedPreferenceToggleWithIcon(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SharedPreferenceToggleWithIcon(
|
||||
text: String,
|
||||
icon: Painter,
|
||||
onClickInfo: () -> Unit,
|
||||
checked: Boolean,
|
||||
onCheckedChange: (Boolean) -> Unit,
|
||||
) {
|
||||
Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(text, Modifier.padding(end = 4.dp))
|
||||
Icon(
|
||||
icon,
|
||||
null,
|
||||
Modifier.clickable(onClick = onClickInfo),
|
||||
tint = MaterialTheme.colors.primary
|
||||
)
|
||||
Spacer(Modifier.fillMaxWidth().weight(1f))
|
||||
DefaultSwitch(
|
||||
checked = checked,
|
||||
onCheckedChange = onCheckedChange,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun <T>SharedPreferenceRadioButton(text: String, prefState: MutableState<T>, preference: SharedPreference<T>, value: T) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
|
||||
+44
-36
@@ -48,12 +48,13 @@ fun NetworkAndServersView(
|
||||
chatModel.userSMPServersUnsaved.value = null
|
||||
}
|
||||
|
||||
val proxyPort = remember { derivedStateOf { chatModel.controller.appPrefs.networkProxyHostPort.state.value?.split(":")?.lastOrNull()?.toIntOrNull() ?: 9050 } }
|
||||
NetworkAndServersLayout(
|
||||
developerTools = developerTools,
|
||||
networkUseSocksProxy = networkUseSocksProxy,
|
||||
onionHosts = onionHosts,
|
||||
sessionMode = sessionMode,
|
||||
proxyPort = remember { derivedStateOf { chatModel.controller.appPrefs.networkProxyHostPort.state.value?.split(":")?.lastOrNull()?.toIntOrNull() ?: 9050 } },
|
||||
proxyPort = proxyPort,
|
||||
showModal = showModal,
|
||||
showSettingsModal = showSettingsModal,
|
||||
showCustomModal = showCustomModal,
|
||||
@@ -61,14 +62,15 @@ fun NetworkAndServersView(
|
||||
if (enable) {
|
||||
AlertManager.shared.showAlertDialog(
|
||||
title = generalGetString(R.string.network_enable_socks),
|
||||
text = generalGetString(R.string.network_enable_socks_info),
|
||||
text = generalGetString(R.string.network_enable_socks_info).format(proxyPort.value),
|
||||
confirmText = generalGetString(R.string.confirm_verb),
|
||||
onConfirm = {
|
||||
withApi {
|
||||
chatModel.controller.apiSetNetworkConfig(NetCfg.proxyDefaults)
|
||||
chatModel.controller.setNetCfg(NetCfg.proxyDefaults)
|
||||
val conf = NetCfg.proxyDefaults.withHostPort(chatModel.controller.appPrefs.networkProxyHostPort.get())
|
||||
chatModel.controller.apiSetNetworkConfig(conf)
|
||||
chatModel.controller.setNetCfg(conf)
|
||||
networkUseSocksProxy.value = true
|
||||
onionHosts.value = NetCfg.proxyDefaults.onionHosts
|
||||
onionHosts.value = conf.onionHosts
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -79,10 +81,11 @@ fun NetworkAndServersView(
|
||||
confirmText = generalGetString(R.string.confirm_verb),
|
||||
onConfirm = {
|
||||
withApi {
|
||||
chatModel.controller.apiSetNetworkConfig(NetCfg.defaults)
|
||||
chatModel.controller.setNetCfg(NetCfg.defaults)
|
||||
val conf = NetCfg.defaults
|
||||
chatModel.controller.apiSetNetworkConfig(conf)
|
||||
chatModel.controller.setNetCfg(conf)
|
||||
networkUseSocksProxy.value = false
|
||||
onionHosts.value = NetCfg.defaults.onionHosts
|
||||
onionHosts.value = conf.onionHosts
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -206,35 +209,31 @@ fun UseSocksProxySwitch(
|
||||
) {
|
||||
Icon(
|
||||
painterResource(R.drawable.ic_settings_ethernet),
|
||||
stringResource(R.string.network_socks_toggle),
|
||||
stringResource(R.string.network_socks_toggle_use_socks_proxy),
|
||||
tint = MaterialTheme.colors.secondary
|
||||
)
|
||||
TextIconSpaced(false)
|
||||
if (networkUseSocksProxy.value) {
|
||||
val text = buildAnnotatedString {
|
||||
append(generalGetString(R.string.network_socks_toggle_use_socks_proxy) + " (")
|
||||
val style = SpanStyle(color = MaterialTheme.colors.primary)
|
||||
withAnnotation(tag = "PORT", annotation = generalGetString(R.string.network_proxy_port).format(proxyPort.value)) {
|
||||
withStyle(style) { append(generalGetString(R.string.network_proxy_port).format(proxyPort.value)) }
|
||||
}
|
||||
append(")")
|
||||
}
|
||||
ClickableText(
|
||||
text,
|
||||
style = TextStyle(color = MaterialTheme.colors.onBackground, fontSize = 16.sp, fontFamily = FontFamily(Font(R.font.inter_regular))),
|
||||
onClick = { offset ->
|
||||
text.getStringAnnotations(tag = "PORT", start = offset, end = offset)
|
||||
.firstOrNull()?.let { _ ->
|
||||
showSettingsModal { SockProxySettings(it) }()
|
||||
}
|
||||
},
|
||||
shouldConsumeEvent = { offset ->
|
||||
text.getStringAnnotations(tag = "PORT", start = offset, end = offset).any()
|
||||
}
|
||||
)
|
||||
} else {
|
||||
Text(stringResource(R.string.network_socks_toggle))
|
||||
val text = buildAnnotatedString {
|
||||
append(generalGetString(R.string.network_socks_toggle_use_socks_proxy) + " (")
|
||||
val style = SpanStyle(color = MaterialTheme.colors.primary)
|
||||
withAnnotation(tag = "PORT", annotation = generalGetString(R.string.network_proxy_port).format(proxyPort.value)) {
|
||||
withStyle(style) { append(generalGetString(R.string.network_proxy_port).format(proxyPort.value)) }
|
||||
}
|
||||
append(")")
|
||||
}
|
||||
ClickableText(
|
||||
text,
|
||||
style = TextStyle(color = MaterialTheme.colors.onBackground, fontSize = 16.sp, fontFamily = FontFamily(Font(R.font.inter_regular))),
|
||||
onClick = { offset ->
|
||||
text.getStringAnnotations(tag = "PORT", start = offset, end = offset)
|
||||
.firstOrNull()?.let { _ ->
|
||||
showSettingsModal { SockProxySettings(it) }()
|
||||
}
|
||||
},
|
||||
shouldConsumeEvent = { offset ->
|
||||
text.getStringAnnotations(tag = "PORT", start = offset, end = offset).any()
|
||||
}
|
||||
)
|
||||
}
|
||||
DefaultSwitch(
|
||||
checked = networkUseSocksProxy.value,
|
||||
@@ -262,13 +261,15 @@ fun SockProxySettings(m: ChatModel) {
|
||||
val save = {
|
||||
withBGApi {
|
||||
m.controller.appPrefs.networkProxyHostPort.set(hostUnsaved.value.text + ":" + portUnsaved.value.text)
|
||||
m.controller.apiSetNetworkConfig(m.controller.getNetCfg())
|
||||
if (m.controller.appPrefs.networkUseSocksProxy.get()) {
|
||||
m.controller.apiSetNetworkConfig(m.controller.getNetCfg())
|
||||
}
|
||||
}
|
||||
}
|
||||
SectionView {
|
||||
SectionItemView {
|
||||
ResetToDefaultsButton({
|
||||
showUpdateNetworkSettingsDialog {
|
||||
val reset = {
|
||||
m.controller.appPrefs.networkProxyHostPort.set(defaultHostPort)
|
||||
val newHost = defaultHostPort.split(":").first()
|
||||
val newPort = defaultHostPort.split(":").last()
|
||||
@@ -276,6 +277,13 @@ fun SockProxySettings(m: ChatModel) {
|
||||
portUnsaved.value = portUnsaved.value.copy(newPort, TextRange(newPort.length))
|
||||
save()
|
||||
}
|
||||
if (m.controller.appPrefs.networkUseSocksProxy.get()) {
|
||||
showUpdateNetworkSettingsDialog {
|
||||
reset()
|
||||
}
|
||||
} else {
|
||||
reset()
|
||||
}
|
||||
}, disabled = hostPort == defaultHostPort)
|
||||
}
|
||||
SectionItemView {
|
||||
@@ -307,7 +315,7 @@ fun SockProxySettings(m: ChatModel) {
|
||||
hostUnsaved.value = hostUnsaved.value.copy(prevHost, TextRange(prevHost.length))
|
||||
portUnsaved.value = portUnsaved.value.copy(prevPort, TextRange(prevPort.length))
|
||||
},
|
||||
save = { showUpdateNetworkSettingsDialog { save() } },
|
||||
save = { if (m.controller.appPrefs.networkUseSocksProxy.get()) showUpdateNetworkSettingsDialog { save() } else save() },
|
||||
revertDisabled = hostPort == (hostUnsaved.value.text + ":" + portUnsaved.value.text),
|
||||
saveDisabled = hostPort == (hostUnsaved.value.text + ":" + portUnsaved.value.text) ||
|
||||
remember { derivedStateOf { !validHost(hostUnsaved.value.text) } }.value ||
|
||||
|
||||
@@ -15,7 +15,6 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import chat.simplex.app.R
|
||||
import chat.simplex.app.model.*
|
||||
import chat.simplex.app.ui.theme.*
|
||||
import chat.simplex.app.views.helpers.*
|
||||
|
||||
@Composable
|
||||
@@ -72,6 +71,11 @@ private fun PreferencesLayout(
|
||||
applyPrefs(preferences.copy(fullDelete = SimpleChatPreference(allow = it)))
|
||||
}
|
||||
SectionDividerSpaced(true, maxBottomPadding = false)
|
||||
// val allowReactions = remember(preferences) { mutableStateOf(preferences.reactions.allow) }
|
||||
// FeatureSection(ChatFeature.Reactions, allowReactions) {
|
||||
// applyPrefs(preferences.copy(reactions = SimpleChatPreference(allow = it)))
|
||||
// }
|
||||
// SectionDividerSpaced(true, maxBottomPadding = false)
|
||||
val allowVoice = remember(preferences) { mutableStateOf(preferences.voice.allow) }
|
||||
FeatureSection(ChatFeature.Voice, allowVoice) {
|
||||
applyPrefs(preferences.copy(voice = SimpleChatPreference(allow = it)))
|
||||
@@ -99,11 +103,10 @@ private fun FeatureSection(feature: ChatFeature, allowFeature: State<FeatureAllo
|
||||
FeatureAllowed.values().map { it to it.text },
|
||||
allowFeature,
|
||||
icon = feature.icon,
|
||||
enabled = remember { mutableStateOf(feature != ChatFeature.Calls) },
|
||||
onSelected = onSelected,
|
||||
)
|
||||
}
|
||||
SectionTextFooter(feature.allowDescription(allowFeature.value) + (if (feature == ChatFeature.Calls) generalGetString(R.string.available_in_v51) else ""))
|
||||
SectionTextFooter(feature.allowDescription(allowFeature.value))
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
||||
+161
-12
@@ -6,9 +6,8 @@ import SectionItemView
|
||||
import SectionTextFooter
|
||||
import SectionView
|
||||
import android.view.WindowManager
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
@@ -17,12 +16,18 @@ import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import chat.simplex.app.R
|
||||
import chat.simplex.app.model.*
|
||||
import chat.simplex.app.ui.theme.*
|
||||
import chat.simplex.app.views.ProfileNameField
|
||||
import chat.simplex.app.views.helpers.*
|
||||
import chat.simplex.app.views.helpers.DatabaseUtils.ksAppPassword
|
||||
import chat.simplex.app.views.helpers.DatabaseUtils.ksSelfDestructPassword
|
||||
import chat.simplex.app.views.isValidDisplayName
|
||||
import chat.simplex.app.views.localauth.SetAppPasscodeView
|
||||
import chat.simplex.app.views.onboarding.ReadableText
|
||||
|
||||
enum class LAMode {
|
||||
SYSTEM,
|
||||
@@ -111,6 +116,9 @@ fun SimplexLockView(
|
||||
val laLockDelay = remember { chatModel.controller.appPrefs.laLockDelay }
|
||||
val showChangePasscode = remember { derivedStateOf { performLA.value && currentLAMode.state.value == LAMode.PASSCODE } }
|
||||
val activity = LocalContext.current as FragmentActivity
|
||||
val selfDestructPref = remember { chatModel.controller.appPrefs.selfDestruct }
|
||||
val selfDestructDisplayName = remember { mutableStateOf(chatModel.controller.appPrefs.selfDestructDisplayName.get() ?: "") }
|
||||
val selfDestructDisplayNamePref = remember { chatModel.controller.appPrefs.selfDestructDisplayName }
|
||||
|
||||
fun resetLAEnabled(onOff: Boolean) {
|
||||
chatModel.controller.appPrefs.performLA.set(onOff)
|
||||
@@ -123,6 +131,11 @@ fun SimplexLockView(
|
||||
laUnavailableInstructionAlert()
|
||||
}
|
||||
|
||||
fun resetSelfDestruct() {
|
||||
selfDestructPref.set(false)
|
||||
ksSelfDestructPassword.remove()
|
||||
}
|
||||
|
||||
fun toggleLAMode(toLAMode: LAMode) {
|
||||
authenticate(
|
||||
if (toLAMode == LAMode.SYSTEM) {
|
||||
@@ -130,7 +143,7 @@ fun SimplexLockView(
|
||||
} else {
|
||||
generalGetString(R.string.chat_lock)
|
||||
},
|
||||
generalGetString(R.string.change_lock_mode), activity
|
||||
generalGetString(R.string.change_lock_mode), activity = activity
|
||||
) { laResult ->
|
||||
when (laResult) {
|
||||
is LAResult.Error -> {
|
||||
@@ -140,16 +153,15 @@ fun SimplexLockView(
|
||||
LAResult.Success -> {
|
||||
when (toLAMode) {
|
||||
LAMode.SYSTEM -> {
|
||||
authenticate(generalGetString(R.string.auth_enable_simplex_lock), promptSubtitle = "", activity, toLAMode) { laResult ->
|
||||
authenticate(generalGetString(R.string.auth_enable_simplex_lock), promptSubtitle = "", activity = activity, usingLAMode = toLAMode) { laResult ->
|
||||
when (laResult) {
|
||||
LAResult.Success -> {
|
||||
currentLAMode.set(toLAMode)
|
||||
ksAppPassword.remove()
|
||||
resetSelfDestruct()
|
||||
laTurnedOnAlert()
|
||||
}
|
||||
is LAResult.Unavailable, is LAResult.Error -> {
|
||||
laFailedAlert()
|
||||
}
|
||||
is LAResult.Unavailable, is LAResult.Error -> laFailedAlert()
|
||||
is LAResult.Failed -> { /* Can be called multiple times on every failure */ }
|
||||
}
|
||||
}
|
||||
@@ -164,7 +176,7 @@ fun SimplexLockView(
|
||||
passcodeAlert(generalGetString(R.string.passcode_set))
|
||||
},
|
||||
cancel = {},
|
||||
close
|
||||
close = close
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -176,8 +188,27 @@ fun SimplexLockView(
|
||||
}
|
||||
}
|
||||
|
||||
fun toggleSelfDestruct(selfDestruct: SharedPreference<Boolean>) {
|
||||
authenticate(generalGetString(R.string.la_current_app_passcode), generalGetString(R.string.change_self_destruct_mode), activity = activity) { laResult ->
|
||||
when (laResult) {
|
||||
is LAResult.Error -> laFailedAlert()
|
||||
is LAResult.Failed -> { /* Can be called multiple times on every failure */ }
|
||||
LAResult.Success -> {
|
||||
if (!selfDestruct.get()) {
|
||||
ModalManager.shared.showCustomModal { close ->
|
||||
EnableSelfDestruct(selfDestruct, close)
|
||||
}
|
||||
} else {
|
||||
resetSelfDestruct()
|
||||
}
|
||||
}
|
||||
is LAResult.Unavailable -> disableUnavailableLA()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun changeLAPassword() {
|
||||
authenticate(generalGetString(R.string.la_current_app_passcode), generalGetString(R.string.la_change_app_passcode), activity) { laResult ->
|
||||
authenticate(generalGetString(R.string.la_current_app_passcode), generalGetString(R.string.la_change_app_passcode), activity = activity) { laResult ->
|
||||
when (laResult) {
|
||||
LAResult.Success -> {
|
||||
ModalManager.shared.showCustomModal { close ->
|
||||
@@ -187,7 +218,32 @@ fun SimplexLockView(
|
||||
passcodeAlert(generalGetString(R.string.passcode_changed))
|
||||
}, cancel = {
|
||||
passcodeAlert(generalGetString(R.string.passcode_not_changed))
|
||||
}, close
|
||||
}, close = close
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
is LAResult.Error -> laFailedAlert()
|
||||
is LAResult.Failed -> {}
|
||||
is LAResult.Unavailable -> disableUnavailableLA()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun changeSelfDestructPassword() {
|
||||
authenticate(generalGetString(R.string.la_current_app_passcode), generalGetString(R.string.change_self_destruct_passcode), activity = activity) { laResult ->
|
||||
when (laResult) {
|
||||
LAResult.Success -> {
|
||||
ModalManager.shared.showCustomModal { close ->
|
||||
Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background) {
|
||||
SetAppPasscodeView(
|
||||
passcodeKeychain = ksSelfDestructPassword,
|
||||
submit = {
|
||||
selfDestructPasscodeAlert(generalGetString(R.string.self_destruct_passcode_changed))
|
||||
}, cancel = {
|
||||
passcodeAlert(generalGetString(R.string.passcode_not_changed))
|
||||
},
|
||||
close = close
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -223,7 +279,8 @@ fun SimplexLockView(
|
||||
},
|
||||
cancel = {
|
||||
resetLAEnabled(false)
|
||||
}, close
|
||||
},
|
||||
close = close
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -246,7 +303,53 @@ fun SimplexLockView(
|
||||
LockDelaySelector(remember { laLockDelay.state }) { laLockDelay.set(it) }
|
||||
if (showChangePasscode.value && laMode.value == LAMode.PASSCODE) {
|
||||
SectionItemView({ changeLAPassword() }) {
|
||||
Text(generalGetString(R.string.la_change_app_passcode))
|
||||
Text(
|
||||
generalGetString(R.string.la_change_app_passcode),
|
||||
color = MaterialTheme.colors.primary
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (performLA.value && laMode.value == LAMode.PASSCODE) {
|
||||
SectionDividerSpaced()
|
||||
SectionView(stringResource(R.string.self_destruct_passcode).uppercase()) {
|
||||
val openInfo = {
|
||||
ModalManager.shared.showModal {
|
||||
SelfDestructInfoView()
|
||||
}
|
||||
}
|
||||
SettingsActionItemWithContent(null, null, click = openInfo) {
|
||||
SharedPreferenceToggleWithIcon(
|
||||
stringResource(R.string.enable_self_destruct),
|
||||
painterResource(R.drawable.ic_info),
|
||||
openInfo,
|
||||
remember { selfDestructPref.state }.value
|
||||
) {
|
||||
toggleSelfDestruct(selfDestructPref)
|
||||
}
|
||||
}
|
||||
|
||||
if (remember { selfDestructPref.state }.value) {
|
||||
Column(Modifier.padding(horizontal = DEFAULT_PADDING, vertical = DEFAULT_PADDING_HALF)) {
|
||||
Text(
|
||||
stringResource(R.string.self_destruct_new_display_name),
|
||||
fontSize = 16.sp,
|
||||
modifier = Modifier.padding(bottom = DEFAULT_PADDING_HALF)
|
||||
)
|
||||
ProfileNameField(selfDestructDisplayName, "", ::isValidDisplayName)
|
||||
LaunchedEffect(selfDestructDisplayName.value) {
|
||||
val new = selfDestructDisplayName.value
|
||||
if (isValidDisplayName(new) && selfDestructDisplayNamePref.get() != new) {
|
||||
selfDestructDisplayNamePref.set(new)
|
||||
}
|
||||
}
|
||||
}
|
||||
SectionItemView({ changeSelfDestructPassword() }) {
|
||||
Text(
|
||||
stringResource(R.string.change_self_destruct_passcode),
|
||||
color = MaterialTheme.colors.primary
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -255,6 +358,40 @@ fun SimplexLockView(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SelfDestructInfoView() {
|
||||
Column(
|
||||
Modifier.fillMaxWidth().verticalScroll(rememberScrollState()).padding(horizontal = DEFAULT_PADDING),
|
||||
) {
|
||||
AppBarTitle(stringResource(R.string.self_destruct), withPadding = false)
|
||||
ReadableText(stringResource(R.string.if_you_enter_self_destruct_code))
|
||||
Column(verticalArrangement = Arrangement.spacedBy(10.dp)) {
|
||||
TextListItem("1.", stringResource(R.string.all_app_data_will_be_cleared))
|
||||
TextListItem("2.", stringResource(R.string.app_passcode_replaced_with_self_destruct))
|
||||
TextListItem("3.", stringResource(R.string.empty_chat_profile_is_created))
|
||||
}
|
||||
SectionBottomSpacer()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun EnableSelfDestruct(
|
||||
selfDestruct: SharedPreference<Boolean>,
|
||||
close: () -> Unit
|
||||
) {
|
||||
Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background) {
|
||||
SetAppPasscodeView(
|
||||
passcodeKeychain = ksSelfDestructPassword, title = generalGetString(R.string.set_passcode), reason = generalGetString(R.string.enabled_self_destruct_passcode),
|
||||
submit = {
|
||||
selfDestruct.set(true)
|
||||
selfDestructPasscodeAlert(generalGetString(R.string.self_destruct_passcode_enabled))
|
||||
},
|
||||
cancel = {},
|
||||
close = close
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun EnableLock(performLA: MutableState<Boolean>, onCheckedChange: (Boolean) -> Unit) {
|
||||
SectionItemView {
|
||||
@@ -300,6 +437,14 @@ private fun LockDelaySelector(state: State<Int>, onSelected: (Int) -> Unit) {
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TextListItem(n: String, text: String) {
|
||||
Box {
|
||||
Text(n)
|
||||
Text(text, Modifier.padding(start = 20.dp))
|
||||
}
|
||||
}
|
||||
|
||||
private fun laDelayText(t: Int): String {
|
||||
val m = t / 60
|
||||
val s = t % 60
|
||||
@@ -319,3 +464,7 @@ private fun passcodeAlert(title: String) {
|
||||
text = generalGetString(R.string.la_please_remember_to_store_password)
|
||||
)
|
||||
}
|
||||
|
||||
private fun selfDestructPasscodeAlert(title: String) {
|
||||
AlertManager.shared.showAlertMsg(title, generalGetString(R.string.if_you_enter_passcode_data_removed))
|
||||
}
|
||||
|
||||
+12
-8
@@ -27,6 +27,8 @@ import chat.simplex.app.model.ServerAddress.Companion.parseServerAddress
|
||||
import chat.simplex.app.ui.theme.*
|
||||
import chat.simplex.app.views.helpers.*
|
||||
import chat.simplex.app.views.newchat.QRCode
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@@ -140,14 +142,16 @@ private fun CustomServer(
|
||||
) {
|
||||
val testedPreviously = remember { mutableMapOf<String, Boolean?>() }
|
||||
TextEditor(
|
||||
Modifier.height(144.dp),
|
||||
text = serverAddress,
|
||||
border = false,
|
||||
fontSize = 16.sp,
|
||||
background = if (isInDarkTheme()) GroupDark else MaterialTheme.colors.background
|
||||
) {
|
||||
testedPreviously[server.server] = server.tested
|
||||
onUpdate(server.copy(server = it, tested = testedPreviously[serverAddress.value]))
|
||||
serverAddress,
|
||||
Modifier.height(144.dp)
|
||||
)
|
||||
LaunchedEffect(Unit) {
|
||||
snapshotFlow { serverAddress.value }
|
||||
.distinctUntilChanged()
|
||||
.collect {
|
||||
testedPreviously[server.server] = server.tested
|
||||
onUpdate(server.copy(server = it, tested = testedPreviously[serverAddress.value]))
|
||||
}
|
||||
}
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
|
||||
+1
-1
@@ -266,7 +266,7 @@ private fun HowToButton() {
|
||||
SettingsActionItem(
|
||||
painterResource(R.drawable.ic_open_in_new),
|
||||
stringResource(R.string.how_to_use_your_servers),
|
||||
{ uriHandler.openUriCatching("https://github.com/simplex-chat/simplex-chat/blob/stable/docs/SERVER.md") },
|
||||
{ uriHandler.openUriCatching("https://simplex.chat/docs/server.html") },
|
||||
textColor = MaterialTheme.colors.primary,
|
||||
iconColor = MaterialTheme.colors.primary
|
||||
)
|
||||
|
||||
@@ -120,7 +120,7 @@ fun RTCServersLayout(
|
||||
} else {
|
||||
Text(stringResource(R.string.enter_one_ICE_server_per_line))
|
||||
if (editRTCServers) {
|
||||
TextEditor(Modifier.height(160.dp), text = userRTCServersStr)
|
||||
TextEditor(userRTCServersStr, Modifier.height(160.dp), contentPadding = PaddingValues())
|
||||
|
||||
Row(
|
||||
Modifier.fillMaxWidth(),
|
||||
@@ -197,7 +197,7 @@ private fun howToButton() {
|
||||
val uriHandler = LocalUriHandler.current
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.clickable { uriHandler.openUriCatching("https://github.com/simplex-chat/simplex-chat/blob/stable/docs/WEBRTC.md#configure-mobile-apps") }
|
||||
modifier = Modifier.clickable { uriHandler.openUriCatching("https://simplex.chat/docs/webrtc.html#configure-mobile-apps") }
|
||||
) {
|
||||
Text(stringResource(R.string.how_to), color = MaterialTheme.colors.primary)
|
||||
Icon(
|
||||
|
||||
@@ -8,7 +8,6 @@ import SectionView
|
||||
import TextIconSpaced
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.*
|
||||
@@ -151,7 +150,7 @@ fun SettingsLayout(
|
||||
val profileHidden = rememberSaveable { mutableStateOf(false) }
|
||||
SettingsActionItem(painterResource(R.drawable.ic_manage_accounts), stringResource(R.string.your_chat_profiles), { withAuth(generalGetString(R.string.auth_open_chat_profiles), generalGetString(R.string.auth_log_in_using_credential)) { showSettingsModalWithSearch { it, search -> UserProfilesView(it, search, profileHidden) } } }, disabled = stopped, extraPadding = true)
|
||||
SettingsIncognitoActionItem(incognitoPref, incognito, stopped) { showModal { IncognitoView() }() }
|
||||
SettingsActionItem(painterResource(R.drawable.ic_qr_code), stringResource(R.string.your_simplex_contact_address), showModal { CreateLinkView(it, CreateLinkTab.LONG_TERM) }, disabled = stopped, extraPadding = true)
|
||||
SettingsActionItem(painterResource(R.drawable.ic_qr_code), stringResource(R.string.your_simplex_contact_address), showCustomModal { it, close -> UserAddressView(it, shareViaProfile = it.currentUser.value!!.addressShared, close = close) }, disabled = stopped, extraPadding = true)
|
||||
ChatPreferencesItem(showCustomModal, stopped = stopped)
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
@@ -362,15 +361,15 @@ fun ChatLockItem(
|
||||
Text("v${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})")
|
||||
}
|
||||
|
||||
@Composable fun ProfilePreview(profileOf: NamedChat, size: Dp = 60.dp, color: Color = MaterialTheme.colors.secondaryVariant, stopped: Boolean = false) {
|
||||
ProfileImage(size = size, image = profileOf.image, color = color)
|
||||
@Composable fun ProfilePreview(profileOf: NamedChat, size: Dp = 60.dp, iconColor: Color = MaterialTheme.colors.secondaryVariant, textColor: Color = MaterialTheme.colors.onBackground, stopped: Boolean = false) {
|
||||
ProfileImage(size = size, image = profileOf.image, color = iconColor)
|
||||
Spacer(Modifier.padding(horizontal = 8.dp))
|
||||
Column(Modifier.height(size), verticalArrangement = Arrangement.Center) {
|
||||
Text(
|
||||
profileOf.displayName,
|
||||
style = MaterialTheme.typography.caption,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = if (stopped) MaterialTheme.colors.secondary else Color.Unspecified,
|
||||
color = if (stopped) MaterialTheme.colors.secondary else textColor,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
@@ -378,7 +377,7 @@ fun ChatLockItem(
|
||||
Text(
|
||||
profileOf.fullName,
|
||||
Modifier.padding(vertical = 5.dp),
|
||||
color = if (stopped) MaterialTheme.colors.secondary else Color.Unspecified,
|
||||
color = if (stopped) MaterialTheme.colors.secondary else textColor,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
@@ -484,7 +483,7 @@ private fun runAuth(title: String, desc: String, context: Context, onFinish: (su
|
||||
authenticate(
|
||||
title,
|
||||
desc,
|
||||
context as FragmentActivity,
|
||||
activity = context as FragmentActivity,
|
||||
completed = { laResult ->
|
||||
onFinish(laResult == LAResult.Success || laResult is LAResult.Unavailable)
|
||||
}
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package chat.simplex.app.views.usersettings
|
||||
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import chat.simplex.app.R
|
||||
import chat.simplex.app.views.helpers.*
|
||||
import chat.simplex.app.views.onboarding.ReadableText
|
||||
import chat.simplex.app.views.onboarding.ReadableTextWithLink
|
||||
|
||||
@Composable
|
||||
fun UserAddressLearnMore() {
|
||||
Column(
|
||||
Modifier.verticalScroll(rememberScrollState()),
|
||||
) {
|
||||
AppBarTitle(stringResource(R.string.simplex_address))
|
||||
ReadableText(R.string.you_can_share_your_address)
|
||||
ReadableText(R.string.you_wont_lose_your_contacts_if_delete_address)
|
||||
ReadableText(R.string.you_can_accept_or_reject_connection)
|
||||
ReadableTextWithLink(R.string.read_more_in_user_guide_with_link, "https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address")
|
||||
}
|
||||
}
|
||||
+396
-69
@@ -1,118 +1,425 @@
|
||||
package chat.simplex.app.views.usersettings
|
||||
|
||||
import SectionBottomSpacer
|
||||
import SectionDividerSpaced
|
||||
import SectionItemView
|
||||
import SectionTextFooter
|
||||
import SectionView
|
||||
import android.content.res.Configuration
|
||||
import android.util.Log
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
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.ChatModel
|
||||
import chat.simplex.app.model.UserContactLinkRec
|
||||
import chat.simplex.app.TAG
|
||||
import chat.simplex.app.model.*
|
||||
import chat.simplex.app.ui.theme.*
|
||||
import chat.simplex.app.views.chat.ShareAddressButton
|
||||
import chat.simplex.app.views.helpers.*
|
||||
import chat.simplex.app.views.newchat.QRCode
|
||||
|
||||
@Composable
|
||||
fun UserAddressView(chatModel: ChatModel) {
|
||||
val cxt = LocalContext.current
|
||||
UserAddressLayout(
|
||||
userAddress = remember { chatModel.userAddress }.value,
|
||||
createAddress = {
|
||||
withApi {
|
||||
val connReqContact = chatModel.controller.apiCreateUserAddress()
|
||||
if (connReqContact != null) {
|
||||
chatModel.userAddress.value = UserContactLinkRec(connReqContact)
|
||||
fun UserAddressView(
|
||||
chatModel: ChatModel,
|
||||
viaCreateLinkView: Boolean = false,
|
||||
shareViaProfile: Boolean = false,
|
||||
close: () -> Unit
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val shareViaProfile = remember { mutableStateOf(shareViaProfile) }
|
||||
var progressIndicator by remember { mutableStateOf(false) }
|
||||
val onCloseHandler: MutableState<(close: () -> Unit) -> Unit> = remember { mutableStateOf({ _ -> }) }
|
||||
|
||||
fun setProfileAddress(on: Boolean) {
|
||||
progressIndicator = true
|
||||
withBGApi {
|
||||
try {
|
||||
val u = chatModel.controller.apiSetProfileAddress(on)
|
||||
if (u != null) {
|
||||
chatModel.updateUser(u)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "UserAddressView apiSetProfileAddress: ${e.stackTraceToString()}")
|
||||
} finally {
|
||||
progressIndicator = false
|
||||
}
|
||||
},
|
||||
share = { userAddress: String -> shareText(cxt, userAddress) },
|
||||
acceptRequests = {
|
||||
chatModel.userAddress.value?.let { address ->
|
||||
ModalManager.shared.showModal(settings = true) { AcceptRequestsView(chatModel, address) }
|
||||
}
|
||||
},
|
||||
deleteAddress = {
|
||||
AlertManager.shared.showAlertDialog(
|
||||
title = generalGetString(R.string.delete_address__question),
|
||||
text = generalGetString(R.string.all_your_contacts_will_remain_connected),
|
||||
confirmText = generalGetString(R.string.delete_verb),
|
||||
onConfirm = {
|
||||
withApi {
|
||||
chatModel.controller.apiDeleteUserAddress()
|
||||
chatModel.userAddress.value = null
|
||||
}
|
||||
}
|
||||
val userAddress = remember { chatModel.userAddress }
|
||||
val showLayout = @Composable {
|
||||
UserAddressLayout(
|
||||
userAddress = userAddress.value,
|
||||
shareViaProfile,
|
||||
onCloseHandler,
|
||||
createAddress = {
|
||||
withApi {
|
||||
progressIndicator = true
|
||||
val connReqContact = chatModel.controller.apiCreateUserAddress()
|
||||
if (connReqContact != null) {
|
||||
chatModel.userAddress.value = UserContactLinkRec(connReqContact)
|
||||
|
||||
// TODO uncomment in v5.2
|
||||
// AlertManager.shared.showAlertDialog(
|
||||
// title = generalGetString(R.string.share_address_with_contacts_question),
|
||||
// text = generalGetString(R.string.add_address_to_your_profile),
|
||||
// confirmText = generalGetString(R.string.share_verb),
|
||||
// onConfirm = {
|
||||
// setProfileAddress(true)
|
||||
// shareViaProfile.value = true
|
||||
// }
|
||||
// )
|
||||
}
|
||||
},
|
||||
destructive = true,
|
||||
progressIndicator = false
|
||||
}
|
||||
},
|
||||
learnMore = {
|
||||
ModalManager.shared.showModal {
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxHeight()
|
||||
.padding(horizontal = DEFAULT_PADDING),
|
||||
verticalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
UserAddressLearnMore()
|
||||
}
|
||||
}
|
||||
},
|
||||
share = { userAddress: String -> shareText(context, userAddress) },
|
||||
sendEmail = { userAddress ->
|
||||
sendEmail(
|
||||
context,
|
||||
generalGetString(R.string.email_invite_subject),
|
||||
generalGetString(R.string.email_invite_body).format(userAddress.connReqContact)
|
||||
)
|
||||
},
|
||||
setProfileAddress = ::setProfileAddress,
|
||||
deleteAddress = {
|
||||
AlertManager.shared.showAlertDialog(
|
||||
title = generalGetString(R.string.delete_address__question),
|
||||
text = if (shareViaProfile.value) generalGetString(R.string.all_your_contacts_will_remain_connected_update_sent) else generalGetString(R.string.all_your_contacts_will_remain_connected),
|
||||
confirmText = generalGetString(R.string.delete_verb),
|
||||
onConfirm = {
|
||||
progressIndicator = true
|
||||
withApi {
|
||||
val u = chatModel.controller.apiDeleteUserAddress()
|
||||
if (u != null) {
|
||||
chatModel.userAddress.value = null
|
||||
chatModel.updateUser(u)
|
||||
shareViaProfile.value = false
|
||||
progressIndicator = false
|
||||
}
|
||||
}
|
||||
},
|
||||
destructive = true,
|
||||
)
|
||||
},
|
||||
saveAas = { aas: AutoAcceptState, savedAAS: MutableState<AutoAcceptState> ->
|
||||
withBGApi {
|
||||
val address = chatModel.controller.userAddressAutoAccept(aas.autoAccept)
|
||||
if (address != null) {
|
||||
chatModel.userAddress.value = address
|
||||
savedAAS.value = aas
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
if (viaCreateLinkView) {
|
||||
showLayout()
|
||||
} else {
|
||||
ModalView(close = { onCloseHandler.value(close) }) {
|
||||
showLayout()
|
||||
}
|
||||
}
|
||||
|
||||
if (progressIndicator) {
|
||||
Box(
|
||||
Modifier.fillMaxSize(),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
if (userAddress.value != null) {
|
||||
Surface(Modifier.size(50.dp), color = MaterialTheme.colors.background.copy(0.9f), shape = RoundedCornerShape(50)){}
|
||||
}
|
||||
CircularProgressIndicator(
|
||||
Modifier
|
||||
.padding(horizontal = 2.dp)
|
||||
.size(30.dp),
|
||||
color = MaterialTheme.colors.secondary,
|
||||
strokeWidth = 3.dp
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun UserAddressLayout(
|
||||
private fun UserAddressLayout(
|
||||
userAddress: UserContactLinkRec?,
|
||||
shareViaProfile: MutableState<Boolean>,
|
||||
onCloseHandler: MutableState<(close: () -> Unit) -> Unit>,
|
||||
createAddress: () -> Unit,
|
||||
learnMore: () -> Unit,
|
||||
share: (String) -> Unit,
|
||||
acceptRequests: () -> Unit,
|
||||
deleteAddress: () -> Unit
|
||||
sendEmail: (UserContactLinkRec) -> Unit,
|
||||
setProfileAddress: (Boolean) -> Unit,
|
||||
deleteAddress: () -> Unit,
|
||||
saveAas: (AutoAcceptState, MutableState<AutoAcceptState>) -> Unit,
|
||||
) {
|
||||
Column(
|
||||
Modifier.verticalScroll(rememberScrollState()),
|
||||
) {
|
||||
AppBarTitle(stringResource(R.string.your_contact_address), false)
|
||||
Text(
|
||||
stringResource(R.string.you_can_share_your_address_anybody_will_be_able_to_connect),
|
||||
Modifier.padding(bottom = 12.dp),
|
||||
lineHeight = 22.sp
|
||||
)
|
||||
AppBarTitle(stringResource(R.string.simplex_address), false)
|
||||
Column(
|
||||
Modifier.fillMaxWidth().padding(bottom = DEFAULT_PADDING_HALF),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.SpaceEvenly
|
||||
) {
|
||||
if (userAddress == null) {
|
||||
SimpleButton(stringResource(R.string.create_address), icon = painterResource(R.drawable.ic_qr_code), click = createAddress)
|
||||
} else {
|
||||
QRCode(userAddress.connReqContact, Modifier.aspectRatio(1f))
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(10.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.padding(vertical = DEFAULT_PADDING)
|
||||
) {
|
||||
SimpleButton(
|
||||
stringResource(R.string.share_link),
|
||||
icon = painterResource(R.drawable.ic_share),
|
||||
click = { share(userAddress.connReqContact) })
|
||||
SimpleButtonIconEnded(
|
||||
stringResource(R.string.contact_requests),
|
||||
icon = painterResource(R.drawable.ic_chevron_right),
|
||||
click = acceptRequests
|
||||
)
|
||||
SectionView {
|
||||
CreateAddressButton(createAddress)
|
||||
SectionTextFooter(stringResource(R.string.create_address_and_let_people_connect))
|
||||
}
|
||||
SectionDividerSpaced(maxBottomPadding = false)
|
||||
SectionView {
|
||||
LearnMoreButton(learnMore)
|
||||
}
|
||||
LaunchedEffect(Unit) {
|
||||
onCloseHandler.value = { close -> close() }
|
||||
}
|
||||
} else {
|
||||
val autoAcceptState = remember { mutableStateOf(AutoAcceptState(userAddress)) }
|
||||
val autoAcceptStateSaved = remember { mutableStateOf(autoAcceptState.value) }
|
||||
SectionView(stringResource(R.string.address_section_title).uppercase()) {
|
||||
QRCode(userAddress.connReqContact, Modifier.padding(horizontal = DEFAULT_PADDING, vertical = DEFAULT_PADDING_HALF).aspectRatio(1f))
|
||||
ShareAddressButton { share(userAddress.connReqContact) }
|
||||
ShareViaEmailButton { sendEmail(userAddress) }
|
||||
// TODO uncomment in v5.2
|
||||
// ShareWithContactsButton(shareViaProfile, setProfileAddress)
|
||||
AutoAcceptToggle(autoAcceptState) { saveAas(autoAcceptState.value, autoAcceptStateSaved) }
|
||||
LearnMoreButton(learnMore)
|
||||
}
|
||||
if (autoAcceptState.value.enable) {
|
||||
SectionDividerSpaced()
|
||||
AutoAcceptSection(autoAcceptState, autoAcceptStateSaved, saveAas)
|
||||
}
|
||||
|
||||
SectionDividerSpaced(maxBottomPadding = false)
|
||||
|
||||
SectionView {
|
||||
DeleteAddressButton(deleteAddress)
|
||||
SectionTextFooter(stringResource(R.string.your_contacts_will_remain_connected))
|
||||
}
|
||||
LaunchedEffect(Unit) {
|
||||
onCloseHandler.value = { close ->
|
||||
if (autoAcceptState.value == autoAcceptStateSaved.value) close()
|
||||
else showUnsavedChangesAlert({ saveAas(autoAcceptState.value, autoAcceptStateSaved); close() }, close)
|
||||
}
|
||||
}
|
||||
SimpleButton(
|
||||
stringResource(R.string.delete_address),
|
||||
icon = painterResource(R.drawable.ic_delete),
|
||||
color = Color.Red,
|
||||
click = deleteAddress
|
||||
)
|
||||
}
|
||||
}
|
||||
SectionBottomSpacer()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CreateAddressButton(onClick: () -> Unit) {
|
||||
SettingsActionItem(
|
||||
painterResource(R.drawable.ic_qr_code),
|
||||
stringResource(R.string.create_simplex_address),
|
||||
onClick,
|
||||
iconColor = MaterialTheme.colors.primary,
|
||||
textColor = MaterialTheme.colors.primary,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LearnMoreButton(onClick: () -> Unit) {
|
||||
SettingsActionItem(
|
||||
painterResource(R.drawable.ic_info),
|
||||
stringResource(R.string.learn_more_about_address),
|
||||
onClick,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ShareViaEmailButton(onClick: () -> Unit) {
|
||||
SettingsActionItem(
|
||||
painterResource(R.drawable.ic_mail),
|
||||
stringResource(R.string.invite_friends),
|
||||
onClick,
|
||||
iconColor = MaterialTheme.colors.primary,
|
||||
textColor = MaterialTheme.colors.primary,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ShareWithContactsButton(shareViaProfile: MutableState<Boolean>, setProfileAddress: (Boolean) -> Unit) {
|
||||
PreferenceToggleWithIcon(
|
||||
stringResource(R.string.share_with_contacts),
|
||||
painterResource(R.drawable.ic_person),
|
||||
checked = shareViaProfile.value,
|
||||
) { on ->
|
||||
shareViaProfile.value = on
|
||||
if (on) {
|
||||
AlertManager.shared.showAlertDialog(
|
||||
title = generalGetString(R.string.share_address_with_contacts_question),
|
||||
text = generalGetString(R.string.profile_update_will_be_sent_to_contacts),
|
||||
confirmText = generalGetString(R.string.share_verb),
|
||||
onConfirm = {
|
||||
setProfileAddress(on)
|
||||
},
|
||||
onDismiss = {
|
||||
shareViaProfile.value = !on
|
||||
},
|
||||
onDismissRequest = {
|
||||
shareViaProfile.value = !on
|
||||
})
|
||||
} else {
|
||||
AlertManager.shared.showAlertDialog(
|
||||
title = generalGetString(R.string.stop_sharing_address),
|
||||
text = generalGetString(R.string.profile_update_will_be_sent_to_contacts),
|
||||
confirmText = generalGetString(R.string.stop_sharing),
|
||||
onConfirm = {
|
||||
setProfileAddress(on)
|
||||
},
|
||||
onDismiss = {
|
||||
shareViaProfile.value = !on
|
||||
},
|
||||
onDismissRequest = {
|
||||
shareViaProfile.value = !on
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AutoAcceptToggle(autoAcceptState: MutableState<AutoAcceptState>, saveAas: (AutoAcceptState) -> Unit) {
|
||||
PreferenceToggleWithIcon(stringResource(R.string.auto_accept_contact), painterResource(R.drawable.ic_check), checked = autoAcceptState.value.enable) {
|
||||
autoAcceptState.value = if (!it)
|
||||
AutoAcceptState()
|
||||
else
|
||||
AutoAcceptState(it, autoAcceptState.value.incognito, autoAcceptState.value.welcomeText)
|
||||
saveAas(autoAcceptState.value)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DeleteAddressButton(onClick: () -> Unit) {
|
||||
SettingsActionItem(
|
||||
painterResource(R.drawable.ic_delete),
|
||||
stringResource(R.string.delete_address),
|
||||
onClick,
|
||||
iconColor = MaterialTheme.colors.error,
|
||||
textColor = MaterialTheme.colors.error,
|
||||
)
|
||||
}
|
||||
|
||||
private class AutoAcceptState {
|
||||
var enable: Boolean = false
|
||||
private set
|
||||
var incognito: Boolean = false
|
||||
private set
|
||||
var welcomeText: String = ""
|
||||
private set
|
||||
|
||||
constructor(enable: Boolean = false, incognito: Boolean = false, welcomeText: String = "") {
|
||||
this.enable = enable
|
||||
this.incognito = incognito
|
||||
this.welcomeText = welcomeText
|
||||
}
|
||||
|
||||
constructor(contactLink: UserContactLinkRec) {
|
||||
contactLink.autoAccept?.let { aa ->
|
||||
enable = true
|
||||
incognito = aa.acceptIncognito
|
||||
aa.autoReply?.let { msg ->
|
||||
welcomeText = msg.text
|
||||
} ?: run {
|
||||
welcomeText = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val autoAccept: AutoAccept?
|
||||
get() {
|
||||
if (enable) {
|
||||
var autoReply: MsgContent? = null
|
||||
val s = welcomeText.trim()
|
||||
if (s != "") {
|
||||
autoReply = MsgContent.MCText(s)
|
||||
}
|
||||
return AutoAccept(incognito, autoReply)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other !is AutoAcceptState) return false
|
||||
return this.enable == other.enable && this.incognito == other.incognito && this.welcomeText == other.welcomeText
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = enable.hashCode()
|
||||
result = 31 * result + incognito.hashCode()
|
||||
result = 31 * result + welcomeText.hashCode()
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AutoAcceptSection(
|
||||
autoAcceptState: MutableState<AutoAcceptState>,
|
||||
savedAutoAcceptState: MutableState<AutoAcceptState>,
|
||||
saveAas: (AutoAcceptState, MutableState<AutoAcceptState>) -> Unit
|
||||
) {
|
||||
SectionView(stringResource(R.string.auto_accept_contact).uppercase()) {
|
||||
AcceptIncognitoToggle(autoAcceptState)
|
||||
WelcomeMessageEditor(autoAcceptState)
|
||||
SaveAASButton(autoAcceptState.value == savedAutoAcceptState.value) { saveAas(autoAcceptState.value, savedAutoAcceptState) }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AcceptIncognitoToggle(autoAcceptState: MutableState<AutoAcceptState>) {
|
||||
PreferenceToggleWithIcon(
|
||||
stringResource(R.string.accept_contact_incognito_button),
|
||||
if (autoAcceptState.value.incognito) painterResource(R.drawable.ic_theater_comedy_filled) else painterResource(R.drawable.ic_theater_comedy),
|
||||
if (autoAcceptState.value.incognito) Indigo else MaterialTheme.colors.secondary,
|
||||
autoAcceptState.value.incognito,
|
||||
) {
|
||||
autoAcceptState.value = AutoAcceptState(autoAcceptState.value.enable, it, autoAcceptState.value.welcomeText)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun WelcomeMessageEditor(autoAcceptState: MutableState<AutoAcceptState>) {
|
||||
val welcomeText = rememberSaveable { mutableStateOf(autoAcceptState.value.welcomeText) }
|
||||
TextEditor(welcomeText, Modifier.height(100.dp), placeholder = stringResource(R.string.enter_welcome_message_optional))
|
||||
LaunchedEffect(welcomeText.value) {
|
||||
if (welcomeText.value != autoAcceptState.value.welcomeText) {
|
||||
autoAcceptState.value = AutoAcceptState(autoAcceptState.value.enable, autoAcceptState.value.incognito, welcomeText.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SaveAASButton(disabled: Boolean, onClick: () -> Unit) {
|
||||
SectionItemView(onClick, disabled = disabled) {
|
||||
Text(stringResource(R.string.save_verb), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Preview(
|
||||
uiMode = Configuration.UI_MODE_NIGHT_YES,
|
||||
@@ -126,12 +433,27 @@ fun PreviewUserAddressLayoutNoAddress() {
|
||||
userAddress = null,
|
||||
createAddress = {},
|
||||
share = { _ -> },
|
||||
acceptRequests = {},
|
||||
deleteAddress = {},
|
||||
saveAas = { _, _ -> },
|
||||
setProfileAddress = { _ -> },
|
||||
learnMore = {},
|
||||
shareViaProfile = remember { mutableStateOf(false) },
|
||||
onCloseHandler = remember { mutableStateOf({}) },
|
||||
sendEmail = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showUnsavedChangesAlert(save: () -> Unit, revert: () -> Unit) {
|
||||
AlertManager.shared.showAlertDialogStacked(
|
||||
title = generalGetString(R.string.save_settings_question),
|
||||
confirmText = generalGetString(R.string.save_auto_accept_settings),
|
||||
dismissText = generalGetString(R.string.exit_without_saving),
|
||||
onConfirm = save,
|
||||
onDismiss = revert,
|
||||
)
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Preview(
|
||||
uiMode = Configuration.UI_MODE_NIGHT_YES,
|
||||
@@ -145,8 +467,13 @@ fun PreviewUserAddressLayoutAddressCreated() {
|
||||
userAddress = UserContactLinkRec("https://simplex.chat/contact#/?v=1&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FK1rslx-m5bpXVIdMZg9NLUZ_8JBm8xTt%23MCowBQYDK2VuAyEALDeVe-sG8mRY22LsXlPgiwTNs9dbiLrNuA7f3ZMAJ2w%3D"),
|
||||
createAddress = {},
|
||||
share = { _ -> },
|
||||
acceptRequests = {},
|
||||
deleteAddress = {},
|
||||
saveAas = { _, _ -> },
|
||||
setProfileAddress = { _ -> },
|
||||
learnMore = {},
|
||||
shareViaProfile = remember { mutableStateOf(false) },
|
||||
onCloseHandler = remember { mutableStateOf({}) },
|
||||
sendEmail = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24.dp"
|
||||
android:height="24.dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M480.33,875Q398.63,875 326.7,843.74Q254.78,812.47 201.14,758.74Q147.5,705 116.25,633.21Q85,561.42 85,479.8Q85,398.09 116.36,325.93Q147.73,253.78 201.13,200.39Q254.54,147 326.79,116Q399.04,85 479.92,85Q526.76,85 570.69,95.51Q614.62,106.03 654,125Q650.5,133.5 649.25,142.08Q648,150.67 648,160Q648,167.9 648.75,174.95Q649.5,182 652,189Q614,166.5 570.93,154.5Q527.86,142.5 479.9,142.5Q339.69,142.5 241.09,240.75Q142.5,339 142.5,479.51Q142.5,620.03 241.24,718.76Q339.97,817.5 480.49,817.5Q621,817.5 719.25,718.91Q817.5,620.31 817.5,480Q817.5,441.47 809.25,404.99Q801,368.5 786,336Q796.96,343.76 810.93,347.88Q824.9,352 840,352Q843.36,352 846.75,352Q850.14,352 853.5,351.5Q864,382 869.5,413.93Q875,445.87 875,479.82Q875,560.91 843.99,633.3Q812.97,705.68 759.49,758.99Q706,812.3 633.98,843.65Q561.95,875 480.33,875ZM624.45,426.5Q647.4,426.5 662.45,411.5Q677.5,396.49 677.5,373.55Q677.5,350.6 662.5,335.55Q647.49,320.5 624.55,320.5Q601.6,320.5 586.55,335.5Q571.5,350.51 571.5,373.45Q571.5,396.4 586.5,411.45Q601.51,426.5 624.45,426.5ZM335.45,426.5Q358.4,426.5 373.45,411.5Q388.5,396.49 388.5,373.55Q388.5,350.6 373.5,335.55Q358.49,320.5 335.55,320.5Q312.6,320.5 297.55,335.5Q282.5,350.51 282.5,373.45Q282.5,396.4 297.5,411.45Q312.51,426.5 335.45,426.5ZM480,696Q544.5,696 599.25,661.5Q654,627 679,566.5L281,566.5Q307,627 361.25,661.5Q415.5,696 480,696ZM480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480ZM811.5,188.5L760,188.5Q747.75,188.5 739.63,180.33Q731.5,172.15 731.5,159.82Q731.5,147.5 739.63,139.25Q747.75,131 760,131L811.5,131L811.5,80Q811.5,67.75 819.67,59.38Q827.85,51 840.17,51Q852.5,51 860.75,59.38Q869,67.75 869,80L869,131L920,131Q932.25,131 940.63,139.43Q949,147.85 949,160.17Q949,172.5 940.63,180.5Q932.25,188.5 920,188.5L869,188.5L869,240Q869,252.25 860.58,260.38Q852.15,268.5 839.83,268.5Q827.5,268.5 819.5,260.38Q811.5,252.25 811.5,240L811.5,188.5Z"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24.dp"
|
||||
android:height="24.dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M811.5,188.5L760,188.5Q748.5,188.5 740,180.33Q731.5,172.15 731.5,159.82Q731.5,147.5 739.63,139.25Q747.75,131 760,131L811.5,131L811.5,80Q811.5,67.75 819.67,59.38Q827.85,51 840.17,51Q852.5,51 860.75,59.38Q869,67.75 869,80L869,131L920,131Q932.25,131 940.63,139.43Q949,147.85 949,160.17Q949,172.5 940.63,180.5Q932.25,188.5 920,188.5L869,188.5L869,240Q869,251.5 860.58,260Q852.15,268.5 839.83,268.5Q827.5,268.5 819.5,260.38Q811.5,252.25 811.5,240L811.5,188.5ZM480.33,875Q398.63,875 326.7,843.74Q254.78,812.47 201.14,758.74Q147.5,705 116.25,633.21Q85,561.42 85,479.8Q85,398.09 116.36,325.93Q147.73,253.78 201.13,200.39Q254.54,147 326.79,116Q399.04,85 479.92,85Q526.76,85 570.69,95.51Q614.62,106.03 654,125Q650.5,133.5 649.25,142.08Q648,150.67 648,159.57Q648,198 671.44,228.46Q694.88,258.93 732.5,267.5Q741.57,305.17 772.03,328.58Q802.48,352 840.28,352Q843.36,352 846.75,352Q850.14,352 853.5,351.5Q864,382 869.5,413.93Q875,445.87 875,479.82Q875,560.91 843.99,633.3Q812.97,705.68 759.49,758.99Q706,812.3 633.98,843.65Q561.95,875 480.33,875ZM624.45,426.5Q647.4,426.5 662.45,411.5Q677.5,396.49 677.5,373.55Q677.5,350.6 662.5,335.55Q647.49,320.5 624.55,320.5Q601.6,320.5 586.55,335.5Q571.5,350.51 571.5,373.45Q571.5,396.4 586.5,411.45Q601.51,426.5 624.45,426.5ZM335.45,426.5Q358.4,426.5 373.45,411.5Q388.5,396.49 388.5,373.55Q388.5,350.6 373.5,335.55Q358.49,320.5 335.55,320.5Q312.6,320.5 297.55,335.5Q282.5,350.51 282.5,373.45Q282.5,396.4 297.5,411.45Q312.51,426.5 335.45,426.5ZM480,696Q544.5,696 599.25,661.5Q654,627 679,566.5L281,566.5Q307,627 361.25,661.5Q415.5,696 480,696Z"/>
|
||||
</vector>
|
||||
@@ -5,5 +5,5 @@
|
||||
android:viewportHeight="960">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="m480,520.5 l-209,209q-9,9 -20.25,9t-20.25,-9q-9,-9 -9,-20.25t9,-20.25L440,479.5 230.5,270q-9,-8.5 -9,-19.75t9,-20.25q9,-9 20.25,-9t20.25,9l209,209.5 209,-209q9,-9 20.25,-9t20.25,9q9,9 9,20.25t-9,20.25l-209,209L730,689.5q8.5,9 8.5,20.25T730,729.5q-9,9 -20.25,9t-20.25,-9L480,520.5Z"/>
|
||||
android:pathData="M480,520.5L271,729.5Q262,738.5 250.75,738.5Q239.5,738.5 230.5,729.5Q221.5,720.5 221.5,709.25Q221.5,698 230.5,689L440,479.5L230.5,270Q221.5,261.5 221.5,250.25Q221.5,239 230.5,230Q239.5,221 250.75,221Q262,221 271,230L480,439.5L689,230.5Q698,221.5 709.25,221.5Q720.5,221.5 729.5,230.5Q738.5,239.5 738.5,250.75Q738.5,262 729.5,271L520.5,480L730,689.5Q738.5,698.5 738.5,709.75Q738.5,721 730,729.5Q721,738.5 709.75,738.5Q698.5,738.5 689.5,729.5L480,520.5Z"/>
|
||||
</vector>
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M480.02,479.5q-65.52,0 -106.52,-40.98t-41,-106.5q0,-65.52 40.98,-106.52t106.5,-41q65.52,0 106.52,40.98t41,106.5q0,65.52 -40.98,106.52t-106.5,41ZM738,793.5L222,793.5q-23.72,0 -40.61,-16.89Q164.5,759.72 164.5,736v-33.51q0,-37.49 18.75,-63.99t48.43,-40.17Q298,569 358.5,554T480,539q61,0 121,15.25t126.4,44.43q30.82,13.64 49.46,39.85Q795.5,664.75 795.5,702.47v33.77q0,23.45 -16.89,40.36Q761.72,793.5 738,793.5ZM222,736h516v-33.37q0,-16.32 -9.75,-30.97Q718.5,657 705,650q-64,-30.5 -116.29,-42t-108.57,-11.5Q423.5,596.5 370.5,608t-116,42q-14,7 -23.25,21.73T222,702.74L222,736ZM480,422q39,0 64.5,-25.5T570,332q0,-39 -25.5,-64.5T480,242q-39,0 -64.5,25.5T390,332q0,39 25.5,64.5T480,422ZM480,332ZM480,736Z"/>
|
||||
</vector>
|
||||
@@ -30,8 +30,7 @@
|
||||
<string name="smp_servers_preset_add">أضف خوادم محددة مسبقًا</string>
|
||||
<string name="smp_servers_add_to_another_device">أضف إلى جهاز آخر</string>
|
||||
<string name="users_delete_all_chats_deleted">سيتم حذف جميع الدردشات والرسائل - لا يمكن التراجع عن هذا!</string>
|
||||
<string name="network_enable_socks_info">الوصول إلى الخوادم عبر بروكسي SOCKS على المنفذ 9050؟ يجب بدء تشغيل الوكيل قبل تمكين هذا الخيار.</string>
|
||||
<string name="accept_requests">قبول طلبات</string>
|
||||
<string name="network_enable_socks_info">الوصول إلى الخوادم عبر بروكسي SOCKS على المنفذ %d؟ يجب بدء تشغيل الوكيل قبل تمكين هذا الخيار.</string>
|
||||
<string name="smp_servers_add">إضافة خادم …</string>
|
||||
<string name="network_settings">إعدادات الشبكة المتقدمة</string>
|
||||
<string name="all_group_members_will_remain_connected">سيبقى جميع أعضاء المجموعة على اتصال.</string>
|
||||
|
||||
@@ -9,18 +9,17 @@
|
||||
<string name="network_settings">Pokročilá nastavení sítě</string>
|
||||
<string name="accept">Přijmout</string>
|
||||
<string name="smp_servers_add">Přidat server…</string>
|
||||
<string name="network_enable_socks_info">Přistupovat k serverům přes SOCKS proxy na portu 9050\? Před povolením této možnosti musí být spuštěna proxy.</string>
|
||||
<string name="network_enable_socks_info">Přistupovat k serverům přes SOCKS proxy na portu %d\? Před povolením této možnosti musí být spuštěna proxy.</string>
|
||||
<string name="accept_feature">Přijmout</string>
|
||||
<string name="allow_your_contacts_to_send_disappearing_messages">Povolte svým kontaktům odesílat mizící zprávy.</string>
|
||||
<string name="about_simplex_chat">O <xliff:g id="appNameFull">SimpleX Chat</xliff:g></string>
|
||||
<string name="smp_servers_add_to_another_device">Přidat do jiného zařízení</string>
|
||||
<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="a_plus_b">a + b</string>
|
||||
<string name="accept_call_on_lock_screen">Přijmout</string>
|
||||
<string name="chat_item_ttl_day">1 dni</string>
|
||||
<string name="chat_item_ttl_day">1 den</string>
|
||||
<string name="group_member_role_admin">správce</string>
|
||||
<string name="users_add">Přidat profil</string>
|
||||
<string name="users_delete_all_chats_deleted">Všechny chaty a zprávy budou smazány – tuto akci nelze vrátit zpět!</string>
|
||||
@@ -129,7 +128,7 @@
|
||||
<string name="error_sending_message">Chyba odesílání zprávy</string>
|
||||
<string name="error_adding_members">Chyba přidávání členů</string>
|
||||
<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="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">Chyba příjmu požadavku od kontaktu</string>
|
||||
<string name="error_changing_address">Chyba změny adresy</string>
|
||||
@@ -241,8 +240,6 @@
|
||||
<string name="network_session_mode_entity">Připojení</string>
|
||||
<string name="core_simplexmq_version">simplexmq: v%s (%2s)</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>
|
||||
@@ -378,7 +375,6 @@
|
||||
<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">Pokud se nemůžete setkat osobně, ukažte ve <b>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>
|
||||
@@ -387,7 +383,7 @@
|
||||
<string name="clear_verification">Jasné ověření</string>
|
||||
<string name="to_verify_compare">Chcete-li ověřit koncové šifrování u svého kontaktu, porovnejte (nebo naskenujte) kód na svých zařízeních.</string>
|
||||
<string name="your_settings">Vaše nastavení</string>
|
||||
<string name="your_simplex_contact_address">Vaše adresa <xliff:g id="appName">SimpleX</xliff:g></string>
|
||||
<string name="your_simplex_contact_address">Vaše SimpleX adresa</string>
|
||||
<string name="database_passphrase_and_export">Heslo databáze a export</string>
|
||||
<string name="your_chat_profiles">Chat profily</string>
|
||||
<string name="chat_with_the_founder">Zaslat otázky a nápady</string>
|
||||
@@ -396,7 +392,6 @@
|
||||
<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 dopravní izolace\?</string>
|
||||
<string name="app_version_code">Sestavení aplikace: %s</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">Smazat adresu</string>
|
||||
<string name="full_name__field">Celé jméno:</string>
|
||||
@@ -573,7 +568,7 @@
|
||||
<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>
|
||||
<string name="share_image">Sdílet média…</string>
|
||||
<string name="icon_descr_cancel_file_preview">Zrušit náhled souboru</string>
|
||||
<string name="images_limit_title">Příliš mnoho obrázků!</string>
|
||||
<string name="waiting_for_file">Čekání na soubor</string>
|
||||
@@ -640,7 +635,6 @@
|
||||
<string name="ensure_ICE_server_address_are_correct_format_and_unique">Ujistěte se, že adresy serverů WebRTC ICE jsou ve správném formátu, oddělené na řádcích a nejsou duplicitní.</string>
|
||||
<string name="save_servers_button">Uložit</string>
|
||||
<string name="network_and_servers">Síť a servery</string>
|
||||
<string name="network_socks_toggle">Použít proxy server SOCKS (port 9050)</string>
|
||||
<string name="update_onion_hosts_settings_question">Aktualizovat nastavení hostitelů .onion\?</string>
|
||||
<string name="network_use_onion_hosts">Použít hostitele .onion</string>
|
||||
<string name="network_use_onion_hosts_prefer">Když bude dostupný</string>
|
||||
@@ -659,7 +653,6 @@
|
||||
<string name="core_version">Verze jádra: v%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 vidět nemohou.</string>
|
||||
<string name="save_preferences_question">Uložit předvolby\?</string>
|
||||
@@ -697,9 +690,9 @@
|
||||
<string name="onboarding_notifications_mode_subtitle">Lze změnit později v nastavení.</string>
|
||||
<string name="onboarding_notifications_mode_off">Když aplikace běží</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"><b>Dobré pro baterii</b>. Služba na pozadí bude kontrolovat 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 vždy spuštěna - oznámení se zobrazí, jakmile jsou zprávy k dispozici.</string>
|
||||
<string name="onboarding_notifications_mode_off_desc"><b>Nejlepší pro baterii</b>. Budete přijímat oznámení pouze když aplikace běží (žádná služba na pozadí).</string>
|
||||
<string name="onboarding_notifications_mode_periodic_desc"><b>Dobré pro baterii</b>. Služba na pozadí bude kontrolovat každých 10 minut. Můžete zmeškat hovory nebo 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>
|
||||
<string name="incoming_audio_call">Příchozí zvukový hovor</string>
|
||||
@@ -957,12 +950,11 @@
|
||||
<string name="v4_5_italian_interface">Italské rozhraní</string>
|
||||
<string name="v4_5_italian_interface_descr">Díky uživatelům - překládejte prostřednictvím Weblate!</string>
|
||||
<string name="you_will_be_connected_when_your_contacts_device_is_online">Budete připojeni, jakmile bude zařízení vašeho kontaktu online, vyčkejte prosím nebo se podívejte později!</string>
|
||||
<string name="your_contact_address">Vaše adresa</string>
|
||||
<string name="your_chat_profile_will_be_sent_to_your_contact">Váš chat profil bude odeslán
|
||||
\nvašemu kontaktu</string>
|
||||
<string name="your_chats">Vaše konverzace</string>
|
||||
<string name="paste_connection_link_below_to_connect">Do níže uvedeného pole vložte odkaz, který jste obdrželi pro spojení s kontaktem.</string>
|
||||
<string name="share_invitation_link">Sdílet pozvánku</string>
|
||||
<string name="share_invitation_link">Sdílet jednorázovou pozvánku</string>
|
||||
<string name="status_e2e_encrypted">koncově šifrované</string>
|
||||
<string name="moderated_description">moderované</string>
|
||||
<string name="moderated_item_description">moderovaný %s</string>
|
||||
@@ -1137,4 +1129,136 @@
|
||||
<string name="stop_file__action">Zastavit soubor</string>
|
||||
<string name="stop_snd_file__title">Zastavit odesílání souboru\?</string>
|
||||
<string name="stop_rcv_file__title">Zastavit příjem souboru\?</string>
|
||||
<string name="learn_more_about_address">O adrese SimpleX</string>
|
||||
<string name="one_time_link_short">Jednorázový odkaz</string>
|
||||
<string name="message_reactions">Reakce na zprávy</string>
|
||||
<string name="send_disappearing_message_send">Poslat</string>
|
||||
<string name="self_destruct_passcode">Samodestrukční heslo</string>
|
||||
<string name="self_destruct_passcode_changed">Heslo pro sebedestrukci změněno!</string>
|
||||
<string name="color_primary_variant">Další zbarvení</string>
|
||||
<string name="color_secondary">Sekundární</string>
|
||||
<string name="empty_chat_profile_is_created">Vytvořit prázdný chat profil se zadaným názvem a otevřít aplikaci jako obvykle.</string>
|
||||
<string name="if_you_enter_passcode_data_removed">Pokud tento přístupový kód zadáte při otevření aplikace, všechna data budou nenávratně smazána!</string>
|
||||
<string name="color_secondary_variant">Další sekundární</string>
|
||||
<string name="color_background">Pozadí</string>
|
||||
<string name="color_surface">Menu a upozornění</string>
|
||||
<string name="custom_time_picker_custom">vlastní</string>
|
||||
<string name="custom_time_picker_select">Vybrat</string>
|
||||
<string name="error_loading_details">Chyba načítání podrobností</string>
|
||||
<string name="info_menu">Info</string>
|
||||
<string name="auth_open_chat_profiles">Otevřít chat profily</string>
|
||||
<string name="edit_history">Historie</string>
|
||||
<string name="received_message">Přijatá zpráva</string>
|
||||
<string name="sent_message">Poslaná zpráva</string>
|
||||
<string name="disappearing_message">Mizící zpráva</string>
|
||||
<string name="send_disappearing_message">Poslat mizící zprávu</string>
|
||||
<string name="send_disappearing_message_1_minute">1 minutu</string>
|
||||
<string name="send_disappearing_message_30_seconds">30 vteřin</string>
|
||||
<string name="send_disappearing_message_custom_time">Vlastní čas</string>
|
||||
<string name="all_your_contacts_will_remain_connected_update_sent">Všechny vaše kontakty zůstanou připojeny. Aktualizace profilu bude odeslána vašim kontaktům.</string>
|
||||
<string name="invite_friends">Pozvat přátele</string>
|
||||
<string name="enabled_self_destruct_passcode">Povolit sebedestrukční heslo</string>
|
||||
<string name="self_destruct">Sebedestrukce</string>
|
||||
<string name="enable_self_destruct">Povolit sebedestrukci</string>
|
||||
<string name="if_you_enter_self_destruct_code">Pokud při otevření aplikace zadáte sebedestrukční heslo:</string>
|
||||
<string name="self_destruct_passcode_enabled">Sebedestrukční heslo povoleno!</string>
|
||||
<string name="set_passcode">Nastavit heslo</string>
|
||||
<string name="info_row_updated_at">Záznam aktualizován v</string>
|
||||
<string name="info_row_sent_at">Posláno v</string>
|
||||
<string name="share_address">Sdílet adresu</string>
|
||||
<string name="info_row_moderated_at">Upraveno v</string>
|
||||
<string name="info_row_received_at">Přijato v</string>
|
||||
<string name="share_text_received_at">Přijato v: %s</string>
|
||||
<string name="share_text_updated_at">Záznam aktualizován v: %s</string>
|
||||
<string name="share_text_sent_at">Posláno v: %s</string>
|
||||
<string name="share_text_disappears_at">Zmizí v: %s</string>
|
||||
<string name="share_text_moderated_at">Upraveno v: %s</string>
|
||||
<string name="current_version_timestamp">%s (aktuální)</string>
|
||||
<string name="dark_theme">Tmavý motiv</string>
|
||||
<string name="import_theme">Import motivu</string>
|
||||
<string name="theme_simplex">SimpleX</string>
|
||||
<string name="export_theme">Export motivu</string>
|
||||
<string name="color_sent_message">Poslaná zpráva</string>
|
||||
<string name="color_title">Titul</string>
|
||||
<string name="color_received_message">Přijatá zpráva</string>
|
||||
<string name="allow_your_contacts_adding_message_reactions">Povolit kontaktům přidávat reakce na zprávy.</string>
|
||||
<string name="both_you_and_your_contact_can_add_message_reactions">Vy i váš kontakt můžete přidávat reakce na zprávy.</string>
|
||||
<string name="message_reactions_prohibited_in_this_chat">Reakce na zprávy jsou v tomto chatu zakázány.</string>
|
||||
<string name="prohibit_message_reactions">Zakázat reakce na zprávy.</string>
|
||||
<string name="prohibit_message_reactions_group">Zakázat reakce na zprávy.</string>
|
||||
<string name="group_members_can_add_message_reactions">Členové skupin mohou přidávat reakce na zprávy.</string>
|
||||
<string name="message_reactions_are_prohibited">Reakce na zprávy jsou v této skupině zakázány.</string>
|
||||
<string name="custom_time_unit_months">měsíců</string>
|
||||
<string name="learn_more">Zjistit více</string>
|
||||
<string name="share_with_contacts">Sdílet s kontakty</string>
|
||||
<string name="group_welcome_preview">Náhled</string>
|
||||
<string name="opening_database">Otvírání databáze…</string>
|
||||
<string name="error_setting_address">Chyba nastavení adresy</string>
|
||||
<string name="scan_qr_to_connect_to_contact">Pro připojení může váš kontakt naskenovat QR kód, nebo použít odkaz v aplikaci.</string>
|
||||
<string name="you_can_accept_or_reject_connection">Když někdo požádá o připojení, můžete žádost přijmout nebo odmítnout.</string>
|
||||
<string name="read_more_in_user_guide_with_link">Přečtěte si více v <font color="#0088ff">Uživatelské příručce</font>.</string>
|
||||
<string name="simplex_address">Adresa SimpleX</string>
|
||||
<string name="theme_colors_section_title">BARVY MOTIVU</string>
|
||||
<string name="customize_theme_title">Přizpůsobit motiv</string>
|
||||
<string name="profile_update_will_be_sent_to_contacts">Aktualizace profilu bude zaslána vašim kontaktům.</string>
|
||||
<string name="share_address_with_contacts_question">Sdílet adresu s kontakty\?</string>
|
||||
<string name="stop_sharing_address">Přestat sdílet adresu\?</string>
|
||||
<string name="create_address_and_let_people_connect">Vytvořit adresu, aby se s vámi lidé mohli spojit.</string>
|
||||
<string name="save_auto_accept_settings">Uložit nastavení automatického přijímání</string>
|
||||
<string name="stop_sharing">Přestat sdílet</string>
|
||||
<string name="auto_accept_contact">Automaticky přijmout</string>
|
||||
<string name="you_can_create_it_later">Můžete vytvořit později</string>
|
||||
<string name="dont_create_address">Nevytvářet adresu</string>
|
||||
<string name="email_invite_body">Ahoj!
|
||||
\nSpojte se se mnou přes SimpleX Chat: %s</string>
|
||||
<string name="email_invite_subject">Promluvme si v SimpleX Chatu</string>
|
||||
<string name="whats_new_read_more">Přečíst více</string>
|
||||
<string name="v5_1_self_destruct_passcode_descr">Všechna data se při zadání vymažou.</string>
|
||||
<string name="v5_1_better_messages">Lepší zprávy</string>
|
||||
<string name="v5_1_custom_themes_descr">Přizpůsobit a sdílet barevné motivy.</string>
|
||||
<string name="v5_1_custom_themes">Vlastní motiv</string>
|
||||
<string name="v5_1_message_reactions_descr">Konečně je máme! 🚀</string>
|
||||
<string name="v5_1_message_reactions">Reakce na zprávy</string>
|
||||
<string name="v5_1_self_destruct_passcode">Samodestrukční heslo</string>
|
||||
<string name="v5_1_japanese_portuguese_interface">Japonské a portugalské uživatelské rozhraní</string>
|
||||
<string name="custom_time_unit_minutes">minut</string>
|
||||
<string name="custom_time_unit_seconds">vteřin</string>
|
||||
<string name="whats_new_thanks_to_users_contribute_weblate">Díky uživatelům - překládejte prostřednictvím Weblate!</string>
|
||||
<string name="v5_1_better_messages_descr">- 5 minutové hlasové zprávy.
|
||||
\n- vlastní čas mizení.
|
||||
\n- historie úprav.</string>
|
||||
<string name="custom_time_unit_days">dní</string>
|
||||
<string name="custom_time_unit_hours">hodin</string>
|
||||
<string name="custom_time_unit_weeks">týdnů</string>
|
||||
<string name="send_disappearing_message_5_minutes">5 minut</string>
|
||||
<string name="add_address_to_your_profile">Přidejte adresu do svého profilu, aby ji vaše kontakty mohly sdílet s dalšími lidmi. Aktualizace profilu bude zaslána vašim kontaktům.</string>
|
||||
<string name="all_app_data_will_be_cleared">Všechna data aplikace jsou smazána.</string>
|
||||
<string name="address_section_title">Adresa</string>
|
||||
<string name="allow_message_reactions">Povolit reakce na zprávy.</string>
|
||||
<string name="allow_message_reactions_only_if">Povolit reakce na zprávy, pokud je váš kontakt povolí.</string>
|
||||
<string name="create_simplex_address">Vytvořit SimpleX adresu</string>
|
||||
<string name="continue_to_next_step">Pokračovat</string>
|
||||
<string name="enter_welcome_message_optional">Zadat uvítací zprávu... (volitelně)</string>
|
||||
<string name="if_you_cant_meet_in_person">Pokud se nemůžete setkat osobně, zobrazte QR kód ve videohovoru nebo sdílejte odkaz.</string>
|
||||
<string name="change_self_destruct_mode">Změnit režim sebedestrukce</string>
|
||||
<string name="change_self_destruct_passcode">Změnit sebedestrukční heslo</string>
|
||||
<string name="item_info_current">(aktuální)</string>
|
||||
<string name="share_text_database_id">ID databáze: %d</string>
|
||||
<string name="info_row_deleted_at">Smazáno v</string>
|
||||
<string name="share_text_deleted_at">Smazáno v: %s</string>
|
||||
<string name="info_row_disappears_at">Zmizí v</string>
|
||||
<string name="enter_welcome_message">Zadat uvítací zprávu…</string>
|
||||
<string name="import_theme_error">Chyba importu motivu</string>
|
||||
<string name="import_theme_error_desc">Ujistěte se, že soubor má správnou syntaxi YAML. Exportujte motiv, abyste měli příklad struktury souboru.</string>
|
||||
<string name="self_destruct_new_display_name">Nově zobrazované jméno:</string>
|
||||
<string name="only_you_can_add_message_reactions">Reakce na zprávy můžete přidávat pouze vy.</string>
|
||||
<string name="save_settings_question">Uložit nastavení\?</string>
|
||||
<string name="only_your_contact_can_add_message_reactions">Reakce na zprávy může přidávat pouze váš kontakt.</string>
|
||||
<string name="your_contacts_will_remain_connected">Vaše kontakty zůstanou připojeny.</string>
|
||||
<string name="you_can_share_this_address_with_your_contacts">Tuto adresu můžete sdílet se svými kontakty, aby se mohli připojit k %s.</string>
|
||||
<string name="your_contacts_will_see_it">Vaše kontakty v SimpleX ji uvidí.
|
||||
\nMůžete ji změnit v Nastavení.</string>
|
||||
<string name="you_can_share_your_address">Svou adresu můžete sdílet jako odkaz nebo QR kód - kdokoli se k vám může připojit.</string>
|
||||
<string name="you_wont_lose_your_contacts_if_delete_address">Pokud později adresu odstraníte, o kontakty nepřijdete.</string>
|
||||
<string name="app_passcode_replaced_with_self_destruct">Přístupový kód aplikace je nahrazen sebedestrukčním přístupovým heslem.</string>
|
||||
</resources>
|
||||
@@ -63,7 +63,7 @@
|
||||
<string name="error_receiving_file">Fehler beim Empfangen der Datei</string>
|
||||
<string name="error_creating_address">Fehler beim Erstellen der Adresse</string>
|
||||
<string name="contact_already_exists">Kontakt ist bereits vorhanden</string>
|
||||
<string name="you_are_already_connected_to_vName_via_this_link">Sie sind bereits mit <xliff:g id="contactName" example="Alice">%1$s!</xliff:g> verbunden.</string>
|
||||
<string name="you_are_already_connected_to_vName_via_this_link">Sie sind bereits mit <xliff:g id="contactName" example="Alice">%1$s</xliff:g> verbunden.</string>
|
||||
<string name="invalid_connection_link">Ungültiger Verbindungslink</string>
|
||||
<string name="please_check_correct_link_and_maybe_ask_for_a_new_one">Überprüfen Sie bitte, ob Sie den richtigen Link genutzt haben oder bitten Sie Ihren Kontakt darum, Ihnen nochmal einen Link zuzusenden.</string>
|
||||
<string name="connection_error_auth">Verbindungsfehler (AUTH)</string>
|
||||
@@ -328,12 +328,11 @@
|
||||
<string name="you_will_be_connected_when_group_host_device_is_online">Sie werden mit der Gruppe verbunden, sobald das Endgerät des Gruppen-Hosts online ist. Bitte warten oder schauen Sie später nochmal nach!</string>
|
||||
<string name="you_will_be_connected_when_your_connection_request_is_accepted">Sie werden verbunden, sobald Ihre Verbindungsanfrage akzeptiert wird. Bitte warten oder schauen Sie später nochmal nach!</string>
|
||||
<string name="you_will_be_connected_when_your_contacts_device_is_online">Sie werden verbunden, sobald das Endgerät Ihres Kontakts online ist. Bitte warten oder schauen Sie später nochmal nach!</string>
|
||||
<string name="show_QR_code_for_your_contact_to_scan_from_the_app__multiline">Zeigen Sie Ihrem Kontakt den QR-Code aus der App zum Scannen.</string>
|
||||
<string name="if_you_cannot_meet_in_person_show_QR_in_video_call_or_via_another_channel">Wenn Sie sich nicht persönlich treffen können, können Sie <b>den QR-Code während eines Videoanrufs anzeigen</b> oder einen Einladungslink über einen anderen Kanal mit Ihrem Kontakt teilen.</string>
|
||||
<string name="your_chat_profile_will_be_sent_to_your_contact">Ihr Chat-Profil wird
|
||||
\nan Ihren Kontakt gesendet</string>
|
||||
<string name="if_you_cannot_meet_in_person_scan_QR_in_video_call_or_ask_for_invitation_link">Wenn Sie sich nicht persönlich treffen können, können Sie <b>den QR-Code während eines Videoanrufs scannen</b> oder Ihr Kontakt kann einen Einladungslink über einen anderen Kanal mit Ihnen teilen.</string>
|
||||
<string name="share_invitation_link">Einladungslink teilen</string>
|
||||
<string name="share_invitation_link">Einmal-Link teilen</string>
|
||||
<string name="paste_connection_link_below_to_connect">Fügen Sie den erhaltenen Link in das Feld unten ein, um sich mit Ihrem Kontakt zu verbinden.</string>
|
||||
<string name="your_profile_will_be_sent">Ihr Chat-Profil wird an Ihren Kontakt gesendet</string>
|
||||
<!-- PasteToConnect.kt -->
|
||||
@@ -345,10 +344,9 @@
|
||||
<!-- CreateLinkView.kt -->
|
||||
<string name="create_one_time_link">Link / QR-Code erstellen</string>
|
||||
<string name="one_time_link">Einmaliger Einladungs-Link</string>
|
||||
<string name="your_contact_address">Meine Kontaktadresse</string>
|
||||
<!-- settings - SettingsView.kt -->
|
||||
<string name="your_settings">Meine Einstellungen</string>
|
||||
<string name="your_simplex_contact_address">Meine <xliff:g id="appName">SimpleX</xliff:g> Kontaktadresse</string>
|
||||
<string name="your_simplex_contact_address">Meine SimpleX-Adresse</string>
|
||||
<string name="database_passphrase_and_export">Datenbank-Passwort & -Export</string>
|
||||
<string name="about_simplex_chat">Über <xliff:g id="appNameFull">SimpleX Chat</xliff:g></string>
|
||||
<string name="how_to_use_simplex_chat">Wie man SimpleX nutzt</string>
|
||||
@@ -397,9 +395,8 @@
|
||||
<string name="network_and_servers">Netzwerk & Server</string>
|
||||
<string name="network_settings">Erweiterte Netzwerkeinstellungen</string>
|
||||
<string name="network_settings_title">Netzwerkeinstellungen</string>
|
||||
<string name="network_socks_toggle">SOCKS-Proxy verwenden (Port 9050)</string>
|
||||
<string name="network_enable_socks">SOCKS-Proxy verwenden?</string>
|
||||
<string name="network_enable_socks_info">Zugriff auf die Server über SOCKS-Proxy auf Port 9050? Der Proxy muss gestartet werden, bevor diese Option aktiviert wird.</string>
|
||||
<string name="network_enable_socks_info">Zugriff auf die Server über SOCKS-Proxy auf Port %d? Der Proxy muss gestartet werden, bevor diese Option aktiviert wird.</string>
|
||||
<string name="network_disable_socks">Direkte Internetverbindung verwenden?</string>
|
||||
<string name="network_disable_socks_info">Wenn Sie dies bestätigen, können die Messaging-Server Ihre IP-Adresse und Ihren Provider sehen und mit welchen Servern Sie sich verbinden.</string>
|
||||
<string name="update_onion_hosts_settings_question">Einstellung für .onion-Hosts aktualisieren?</string>
|
||||
@@ -418,14 +415,8 @@
|
||||
<string name="create_address">Adresse erstellen</string>
|
||||
<string name="delete_address__question">Adresse löschen?</string>
|
||||
<string name="all_your_contacts_will_remain_connected">Alle Ihre Kontakte bleiben verbunden.</string>
|
||||
<string name="you_can_share_your_address_anybody_will_be_able_to_connect">Sie können Ihre Adresse als Link oder als QR-Code teilen – Jede Person kann sich darüber mit Ihnen verbinden. Sie werden Ihre mit dieser Adresse verbundenen Kontakte nicht verlieren, wenn Sie diese Adresse später löschen.</string>
|
||||
<string name="share_link">Link teilen</string>
|
||||
<string name="delete_address">Adresse löschen</string>
|
||||
<!-- AcceptRequestsView.kt -->
|
||||
<string name="contact_requests">Kontaktanfragen</string>
|
||||
<string name="accept_requests">Anfragen annehmen</string>
|
||||
<string name="accept_automatically">Automatisch</string>
|
||||
<string name="section_title_welcome_message">Begrüßungsmeldung</string>
|
||||
<!-- User profile details - UserProfileView.kt -->
|
||||
<string name="display_name__field">Angezeigter Name:</string>
|
||||
<string name="full_name__field">"Vollständiger Name:</string>
|
||||
@@ -914,8 +905,8 @@
|
||||
<string name="live">LIVE</string>
|
||||
<string name="view_security_code">Schauen Sie sich den Sicherheitscode an</string>
|
||||
<string name="onboarding_notifications_mode_service">Sofort</string>
|
||||
<string name="onboarding_notifications_mode_periodic_desc"><b>Gute Option für die Batterieausdauer</b>. Der Hintergrundservice überprüft alle 10 Minuten nach neuen Nachrichten. Sie können eventuell Anrufe und dringende Nachrichten verpassen.</string>
|
||||
<string name="onboarding_notifications_mode_off_desc"><b>Beste Option für die Batterieausdauer</b>. Sie empfangen Benachrichtigungen nur solange die App abläuft. Der Hintergrundservice wird nicht genutzt!</string>
|
||||
<string name="onboarding_notifications_mode_periodic_desc"><b>Gute Option für die Batterieausdauer</b>. Der Hintergrundservice überprüft alle 10 Minuten nach Nachrichten. Sie können eventuell Anrufe oder dringende Nachrichten verpassen.</string>
|
||||
<string name="onboarding_notifications_mode_off_desc"><b>Beste Option für die Batterieausdauer</b>. Sie empfangen Benachrichtigungen nur solange die App abläuft (kein aktiver Hintergrundservice).</string>
|
||||
<string name="send_verb">Senden</string>
|
||||
<string name="is_verified">%s wurde erfolgreich überprüft</string>
|
||||
<string name="clear_verification">Überprüfung zurücknehmen</string>
|
||||
@@ -951,7 +942,7 @@
|
||||
<string name="failed_to_parse_chat_title">Fehler beim Laden des Chats</string>
|
||||
<string name="failed_to_parse_chats_title">Fehler beim Laden der Chats</string>
|
||||
<string name="contact_developers">Bitte aktualisieren Sie die App und nehmen Sie Kontakt mit den Entwicklern auf.</string>
|
||||
<string name="onboarding_notifications_mode_service_desc"><b>Benötigt mehr Leistung Ihrer Batterie</b>! Der Hintergrundservice läuft die ganze Zeit ab. Benachrichtigungen werden Ihnen sofort angezeigt, nachdem Sie neue Nachrichten erhalten haben.</string>
|
||||
<string name="onboarding_notifications_mode_service_desc"><b>Benötigt mehr Leistung Ihrer Batterie</b>! Der Hintergrundservice läuft permanent ab. Benachrichtigungen werden Ihnen angezeigt, sobald Sie neue Nachrichten erhalten haben.</string>
|
||||
<string name="create_group_link">Gruppenlink erstellen</string>
|
||||
<string name="allow_your_contacts_to_send_disappearing_messages">Erlauben Sie Ihren Kontakten das Senden von verschwindenden Nachrichten.</string>
|
||||
<string name="prohibit_sending_disappearing_messages">Das Senden von verschwindenden Nachrichten verbieten.</string>
|
||||
@@ -1184,7 +1175,7 @@
|
||||
<string name="alert_text_msg_bad_id">Die ID der nächsten Nachricht ist falsch (kleiner oder gleich der Vorherigen).
|
||||
\nDies kann passieren, wenn es einen Fehler gegeben hat oder die Verbindung kompromittiert wurde.</string>
|
||||
<string name="alert_text_decryption_error_header"><xliff:g id="message count" example="1">%1$d</xliff:g> Nachrichten konnten nicht entschlüsselt werden.</string>
|
||||
<string name="alert_text_msg_bad_hash">Der Hash der vorherigen Nachricht ist unterschiedlich.</string>
|
||||
<string name="alert_text_msg_bad_hash">Der Hash der vorherigen Nachricht unterscheidet sich.</string>
|
||||
<string name="you_can_turn_on_lock">Sie können die SimpleX Sperre über die Einstellungen aktivieren.</string>
|
||||
<string name="network_socks_proxy_settings">SOCKS-Proxy Einstellungen</string>
|
||||
<string name="la_lock_mode_system">System-Authentifizierung</string>
|
||||
@@ -1218,4 +1209,136 @@
|
||||
<string name="only_your_contact_can_make_calls">Nur Ihr Kontakt kann Anrufe tätigen.</string>
|
||||
<string name="v5_0_app_passcode">App Passwort</string>
|
||||
<string name="calls_prohibited_with_this_contact">Audio/Video Anrufe sind nicht erlaubt.</string>
|
||||
<string name="address_section_title">Adresse</string>
|
||||
<string name="share_address">Adresse teilen</string>
|
||||
<string name="export_theme">Design exportieren</string>
|
||||
<string name="import_theme_error">Fehler beim Importieren des Designs</string>
|
||||
<string name="color_title">Bezeichnung</string>
|
||||
<string name="opening_database">Öffne Datenbank …</string>
|
||||
<string name="error_setting_address">Fehler bei der Adresseinstellung</string>
|
||||
<string name="learn_more">Mehr erfahren</string>
|
||||
<string name="scan_qr_to_connect_to_contact">Um eine Verbindung herzustellen, kann Ihr Kontakt den QR-Code scannen oder den Link in der App verwenden.</string>
|
||||
<string name="simplex_address">SimpleX-Adresse</string>
|
||||
<string name="you_can_accept_or_reject_connection">Wenn Personen eine Verbindung anfordern, können Sie diese annehmen oder ablehnen.</string>
|
||||
<string name="you_wont_lose_your_contacts_if_delete_address">Sie werden Ihre Kontakte nicht verlieren, falls Sie Ihre Adresse später löschen.</string>
|
||||
<string name="customize_theme_title">Design anpassen</string>
|
||||
<string name="theme_colors_section_title">DESIGN-FARBEN</string>
|
||||
<string name="add_address_to_your_profile">Fügen Sie die Adresse zu Ihrem Profil hinzu, damit Ihre Kontakte sie mit anderen Personen teilen können. Es wird eine Profilaktualisierung an Ihre Kontakte gesendet.</string>
|
||||
<string name="all_your_contacts_will_remain_connected_update_sent">Alle Ihre Kontakte bleiben verbunden. Es wird eine Profilaktualisierung an Ihre Kontakte gesendet.</string>
|
||||
<string name="create_address_and_let_people_connect">Erstellen Sie eine Adresse, damit sich Personen mit Ihnen verbinden können.</string>
|
||||
<string name="create_simplex_address">SimpleX-Adresse erstellen</string>
|
||||
<string name="share_with_contacts">Mit Kontakten teilen</string>
|
||||
<string name="your_contacts_will_remain_connected">Ihre Kontakte bleiben verbunden.</string>
|
||||
<string name="auto_accept_contact">Automatisch akzeptieren</string>
|
||||
<string name="enter_welcome_message_optional">Geben Sie eine Begrüßungsmeldung ein … (optional)</string>
|
||||
<string name="invite_friends">Freunde einladen</string>
|
||||
<string name="email_invite_subject">Lassen Sie uns in SimpleX Chat kommunizieren</string>
|
||||
<string name="profile_update_will_be_sent_to_contacts">Profil-Aktualisierung wird an Ihre Kontakte gesendet.</string>
|
||||
<string name="save_auto_accept_settings">Einstellungen von \"Automatisch akzeptieren\" speichern</string>
|
||||
<string name="save_settings_question">Einstellungen speichern\?</string>
|
||||
<string name="share_address_with_contacts_question">Die Adresse mit Kontakten teilen\?</string>
|
||||
<string name="stop_sharing">Teilen beenden</string>
|
||||
<string name="stop_sharing_address">Das Teilen der Adresse beenden\?</string>
|
||||
<string name="dont_create_address">Keine Adresse erstellt</string>
|
||||
<string name="email_invite_body">Hallo!
|
||||
\nVerbinden Sie sich per SimpleX Chat mit mir: %s</string>
|
||||
<string name="you_can_create_it_later">Sie können dies später erstellen</string>
|
||||
<string name="enter_welcome_message">Geben Sie eine Begrüßungsmeldung ein …</string>
|
||||
<string name="group_welcome_preview">Vorschau</string>
|
||||
<string name="you_can_share_this_address_with_your_contacts">Sie können diese Adresse mit Ihren Kontakten teilen, um sie mit %s verbinden zu lassen.</string>
|
||||
<string name="color_secondary_variant">Zweite Akzentfarbe</string>
|
||||
<string name="color_background">Hintergrund-Farbe</string>
|
||||
<string name="import_theme">Design importieren</string>
|
||||
<string name="color_surface">Menüs & Benachrichtigungen</string>
|
||||
<string name="color_received_message">Empfangene Nachricht</string>
|
||||
<string name="color_secondary">Zweite Farbe</string>
|
||||
<string name="color_sent_message">Gesendete Nachricht</string>
|
||||
<string name="theme_simplex">SimpleX</string>
|
||||
<string name="learn_more_about_address">Über die SimpleX-Adresse</string>
|
||||
<string name="one_time_link_short">Einmal-Link</string>
|
||||
<string name="color_primary_variant">Erste Akzentfarbe</string>
|
||||
<string name="continue_to_next_step">Weiter</string>
|
||||
<string name="dark_theme">Dunkles Design</string>
|
||||
<string name="if_you_cant_meet_in_person">Falls Sie sich nicht persönlich treffen können, zeigen Sie den QR-Code in einem Videoanruf oder teilen Sie den Link.</string>
|
||||
<string name="read_more_in_user_guide_with_link">Lesen Sie mehr dazu in der <font color="#0088ff">Benutzeranleitung</font>.</string>
|
||||
<string name="import_theme_error_desc">Stellen Sie sicher, dass die Datei die korrekte YAML-Syntax hat. Exportieren sie das Design, um ein Beispiel für die Dateistruktur des Designs zu erhalten.</string>
|
||||
<string name="auth_open_chat_profiles">Offene Chat-Profile</string>
|
||||
<string name="you_can_share_your_address">Sie können Ihre Adresse als Link oder QR-Code teilen - jede Person kann sich mit Ihnen verbinden.</string>
|
||||
<string name="your_contacts_will_see_it">Ihre Kontakte in SimpleX werden es sehen.
|
||||
\nSie können es in den Einstellungen ändern.</string>
|
||||
<string name="all_app_data_will_be_cleared">App-Daten werden komplett gelöscht.</string>
|
||||
<string name="empty_chat_profile_is_created">Es wurde ein leeres Chat-Profil mit dem eingegebenen Namen erstellt und die App öffnet wie gewohnt.</string>
|
||||
<string name="if_you_enter_self_destruct_code">Wenn Sie Ihr Selbstzerstörungspasswort während des Öffnens der App eingeben:</string>
|
||||
<string name="self_destruct_new_display_name">Neuer angezeigter Name:</string>
|
||||
<string name="self_destruct_passcode_changed">Das Selbstzerstörungspasswort wurde geändert!</string>
|
||||
<string name="change_self_destruct_mode">Selbstzerstörungs-Modus ändern</string>
|
||||
<string name="change_self_destruct_passcode">Selbstzerstörungspasswort ändern</string>
|
||||
<string name="enabled_self_destruct_passcode">Selbstzerstörungspasswort aktivieren</string>
|
||||
<string name="self_destruct">Selbstzerstörung</string>
|
||||
<string name="self_destruct_passcode_enabled">Das Selbstzerstörungspasswort wurde aktiviert!</string>
|
||||
<string name="app_passcode_replaced_with_self_destruct">Das App Passwort wurde durch das Selbstzerstörungspasswort ersetzt.</string>
|
||||
<string name="enable_self_destruct">Selbstzerstörung aktivieren</string>
|
||||
<string name="if_you_enter_passcode_data_removed">Wenn Sie dieses Passwort während des Öffnens der App eingeben, werden alle App-Daten unwiederbringlich gelöscht!</string>
|
||||
<string name="self_destruct_passcode">Selbstzerstörungspasswort</string>
|
||||
<string name="set_passcode">Passwort eingeben</string>
|
||||
<string name="message_reactions_are_prohibited">In dieser Gruppe sind Reaktionen auf Nachrichten nicht erlaubt.</string>
|
||||
<string name="error_loading_details">Fehler beim Laden von Details</string>
|
||||
<string name="received_message">Empfangene Nachricht</string>
|
||||
<string name="info_menu">Information</string>
|
||||
<string name="sent_message">Gesendete Nachricht</string>
|
||||
<string name="send_disappearing_message_custom_time">Zeit anpassen</string>
|
||||
<string name="disappearing_message">Verschwindende Nachricht</string>
|
||||
<string name="send_disappearing_message_send">Senden</string>
|
||||
<string name="send_disappearing_message_1_minute">1 Minute</string>
|
||||
<string name="send_disappearing_message">Verschwindende Nachricht senden</string>
|
||||
<string name="info_row_moderated_at">Moderiert um</string>
|
||||
<string name="info_row_deleted_at">Gelöscht um</string>
|
||||
<string name="info_row_received_at">Empfangen um</string>
|
||||
<string name="info_row_updated_at">Datensatz aktualisiert um</string>
|
||||
<string name="info_row_sent_at">Gesendet um</string>
|
||||
<string name="share_text_moderated_at">Moderiert um: %s</string>
|
||||
<string name="share_text_database_id">Datenbank-ID: %d</string>
|
||||
<string name="share_text_received_at">Empfangen um: %s</string>
|
||||
<string name="share_text_updated_at">Datensatz aktualisiert um: %s</string>
|
||||
<string name="current_version_timestamp">%s (aktuell)</string>
|
||||
<string name="share_text_sent_at">Gesendet um: %s</string>
|
||||
<string name="message_reactions">Reaktionen auf Nachrichten</string>
|
||||
<string name="allow_your_contacts_adding_message_reactions">Erlauben Sie Ihren Kontakten Reaktionen auf Nachrichten zu geben.</string>
|
||||
<string name="both_you_and_your_contact_can_add_message_reactions">Sowohl Sie, als auch Ihr Kontakt können Reaktionen auf Nachrichten geben.</string>
|
||||
<string name="only_you_can_add_message_reactions">Nur Sie können Reaktionen auf Nachrichten geben.</string>
|
||||
<string name="prohibit_message_reactions">Reaktionen auf Nachrichten nicht erlauben.</string>
|
||||
<string name="allow_message_reactions_only_if">Reaktionen auf Nachrichten sind nur möglich, falls Ihr Kontakt dies erlaubt.</string>
|
||||
<string name="only_your_contact_can_add_message_reactions">Nur Ihr Kontakt kann Reaktionen auf Nachrichten geben.</string>
|
||||
<string name="allow_message_reactions">Reaktionen auf Nachrichten erlauben.</string>
|
||||
<string name="prohibit_message_reactions_group">Reaktionen auf Nachrichten nicht erlauben.</string>
|
||||
<string name="group_members_can_add_message_reactions">Gruppenmitglieder können eine Reaktion auf Nachrichten geben.</string>
|
||||
<string name="whats_new_read_more">Mehr erfahren</string>
|
||||
<string name="v5_1_message_reactions_descr">Endlich haben wir sie! 🚀</string>
|
||||
<string name="v5_1_message_reactions">Reaktionen auf Nachrichten</string>
|
||||
<string name="v5_1_self_destruct_passcode">Selbstzerstörungspasswort</string>
|
||||
<string name="v5_1_self_destruct_passcode_descr">Sobald es eingegeben wird, werden alle Daten gelöscht.</string>
|
||||
<string name="v5_1_custom_themes">Benutzerdefinierte Designs</string>
|
||||
<string name="v5_1_japanese_portuguese_interface">Japanische und Portugiesische Bedienoberfläche</string>
|
||||
<string name="custom_time_unit_minutes">Minuten</string>
|
||||
<string name="custom_time_unit_seconds">Sekunden</string>
|
||||
<string name="whats_new_thanks_to_users_contribute_weblate">Dank der Nutzer - Tragen Sie per Weblate bei!</string>
|
||||
<string name="v5_1_better_messages">Verbesserungen bei Nachrichten</string>
|
||||
<string name="v5_1_custom_themes_descr">Farbdesigns anpassen und weitergeben.</string>
|
||||
<string name="custom_time_unit_days">Tage</string>
|
||||
<string name="custom_time_unit_hours">Stunden</string>
|
||||
<string name="v5_1_better_messages_descr">- Bis zu 5 Minuten lange Sprachnachrichten
|
||||
\n- Zeit für verschwindende Nachrichten anpassen
|
||||
\n- Vergangenheit bearbeiten</string>
|
||||
<string name="custom_time_picker_custom">benutzerdefiniert</string>
|
||||
<string name="custom_time_unit_months">Monate</string>
|
||||
<string name="custom_time_picker_select">Auswählen</string>
|
||||
<string name="custom_time_unit_weeks">Wochen</string>
|
||||
<string name="send_disappearing_message_5_minutes">5 Minuten</string>
|
||||
<string name="item_info_current">(aktuell)</string>
|
||||
<string name="send_disappearing_message_30_seconds">30 Sekunden</string>
|
||||
<string name="share_text_deleted_at">Gelöscht um: %s</string>
|
||||
<string name="info_row_disappears_at">Verschwindet um</string>
|
||||
<string name="share_text_disappears_at">Verschwindet um: %s</string>
|
||||
<string name="edit_history">Vergangenheit</string>
|
||||
<string name="message_reactions_prohibited_in_this_chat">In diesem Chat sind Reaktionen auf Nachrichten nicht erlaubt.</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="chat_item_ttl_day">1 μέρα</string>
|
||||
<string name="chat_item_ttl_month">1 μήνας</string>
|
||||
<string name="about_simplex">Για το SimpleX</string>
|
||||
<string name="scan_QR_code">Σαρώστε τον QR κωδικό</string>
|
||||
<string name="a_plus_b">α + β</string>
|
||||
<string name="about_simplex_chat">Για το <xliff:g id="appNameFull">SimpleX Chat</xliff:g></string>
|
||||
<string name="scan_code_from_contacts_app">Σαρώστε τον κωδικό ασφαλείας από την εφαρμογή επαφών σας</string>
|
||||
<string name="smp_server_test_secure_queue">Ασφαλή ουρά</string>
|
||||
<string name="network_option_seconds_label">δε</string>
|
||||
<string name="security_code">Κωδικός ασφαλείας</string>
|
||||
<string name="smp_servers_scan_qr">Σαρώστε τον κωδικό QR διακομιστή</string>
|
||||
<string name="secret">μυστικό</string>
|
||||
<string name="chat_item_ttl_week">1 εβδομάδα</string>
|
||||
<string name="v4_2_security_assessment">αξιολόγηση ασφαλείας</string>
|
||||
<string name="allow_verb">Συναινώ</string>
|
||||
<string name="accept_contact_button">Αποδοχή</string>
|
||||
<string name="accept_contact_incognito_button">Αποδοχή ανώνυμης περιήγησης</string>
|
||||
<string name="smp_servers_preset_add">Προσθήκη προκαθορισμένου διακομιστή</string>
|
||||
<string name="smp_servers_add_to_another_device">Προσθήκη σε άλλη συσκευή</string>
|
||||
<string name="all_your_contacts_will_remain_connected">Όλες οι επαφές σας θα παραμείνουν ενεργές.</string>
|
||||
<string name="accept_call_on_lock_screen">Αποδοχή</string>
|
||||
<string name="group_member_role_admin">διαχειριστής</string>
|
||||
<string name="button_add_welcome_message">Προσθέστε μήνυμα καλωσορίσματος</string>
|
||||
<string name="all_group_members_will_remain_connected">Όλα τα μέλη της ομάδας θα παραμήνουν συνδεδεμένα.</string>
|
||||
<string name="users_add">Προσθήκη προφίλ</string>
|
||||
<string name="color_primary">Προφορά</string>
|
||||
<string name="chat_preferences_always">πάντα</string>
|
||||
<string name="accept_feature">Αποδοχή</string>
|
||||
<string name="allow_disappearing_messages_only_if">Επιτρέψτε τα μηνύματα που εξαφανίζονται μόνο εάν το επιτρέπει η επαφή σας.</string>
|
||||
<string name="allow_your_contacts_irreversibly_delete">Επιτρέψτε στις επαφές σας να διαγράφουν μη αναστρέψιμα τα απεσταλμένα μηνύματα.</string>
|
||||
<string name="allow_your_contacts_to_send_disappearing_messages">Επιτρέψτε στις επαφές σας να στέλνουν μηνύματα που εξαφανίζονται.</string>
|
||||
<string name="allow_voice_messages_only_if">Επιτρέπονται τα φωνητικά μηνύματα μόνο εάν τα επιτρέπει η επαφή σας.</string>
|
||||
<string name="allow_your_contacts_to_call">Επιτρέψτε στις επαφές σας να σας καλέσουν.</string>
|
||||
<string name="allow_your_contacts_to_send_voice_messages">Επιτρέψτε στις επαφές σας να στέλνουν φωνητικά μηνύματα.</string>
|
||||
<string name="allow_direct_messages">Να επιτρέπεται η αποστολή άμεσων μηνυμάτων στα μέλη.</string>
|
||||
<string name="allow_to_send_disappearing">Επιτρέπεται η αποστολή μηνυμάτων που εξαφανίζονται.</string>
|
||||
<string name="allow_to_send_voice">Επιτρέπεται η αποστολή φωνητικών μηνυμάτων.</string>
|
||||
<string name="app_name"><xliff:g id="appName">SimpleX</xliff:g></string>
|
||||
<string name="accept">Αποδοχή</string>
|
||||
<string name="accept_connection_request__question">Αποδοχή αιτήματος σύνδεσης;</string>
|
||||
<string name="callstatus_accepted">αποδεκτή κλήση</string>
|
||||
<string name="network_enable_socks_info">Πρόσβαση στους διακομιστές μέσω SOCKS proxy στην πόρτα 9050; Ο διακομιστής μεσολάβησης (proxy server) πρέπει να είναι ενεργός πριν ενεργοποιηθεί αυτή η ρύθμιση.</string>
|
||||
<string name="accept_requests">Αποδοχή αιτημάτων</string>
|
||||
<string name="smp_servers_add">Προσθήκη διακομιστή…</string>
|
||||
<string name="network_settings">Προχωρημένες ρυθμίσεις δικτύου</string>
|
||||
<string name="v4_3_improved_server_configuration_desc">Προσθήκη διακομιστών μέσω σάρωσης QR κωδικών.</string>
|
||||
<string name="v4_2_group_links_desc">Οι διαχειριστές μπορούν να δημιουργήσουν τους συνδέσμους συμμετοχής σε ομάδες.</string>
|
||||
<string name="users_delete_all_chats_deleted">Όλες οι συνομιλίες και τα μηνύματα θα διαγραφούν - αυτή η ενέργεια δεν μπορεί να αντιστραφεί!</string>
|
||||
<string name="clear_chat_warning">Όλα τα μηνύματα θα διαγραφούν - αυτή η ενέργεια δεν μπορεί να αντιστραφεί! Τα μηνύματα θα διαγραφούν ΜΟΝΟ για εσάς.</string>
|
||||
<string name="allow_irreversible_message_deletion_only_if">Επιτρέψτε τη μη αναστρέψιμη διαγραφή μηνυμάτων μόνο εάν σας το επιτρέπει η επαφή σας.</string>
|
||||
<string name="allow_calls_only_if">Επιτρέπονται οι κλήσεις μόνο εάν η επαφή σας τις επιτρέπει.</string>
|
||||
<string name="allow_to_delete_messages">Επιτρέψτε τη μη αναστρέψιμη διαγραφή των απεσταλμένων μηνυμάτων.</string>
|
||||
<string name="allow_voice_messages_question">Να επιτρέπονται τα φωνητικά μηνύματα;</string>
|
||||
<string name="notifications_mode_service">Πάντα ενεργό</string>
|
||||
<string name="always_use_relay">Να χρησιμοποιείται πάντα αναμεταδότη</string>
|
||||
</resources>
|
||||
@@ -2,70 +2,70 @@
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="auth_unavailable">Autenticación no disponible</string>
|
||||
<string name="accept_contact_button">Aceptar</string>
|
||||
<string name="network_settings">Configuración de red avanzada</string>
|
||||
<string name="onboarding_notifications_mode_off_desc"><b>Mejor para la batería</b>. Recibirás notificaciones sólo cuando la aplicación se esté ejecutando, el servicio NO se usará en segundo plano.</string>
|
||||
<string name="onboarding_notifications_mode_periodic_desc"><b>Bueno para la batería</b>. El servicio en segundo plano comprueba si hay mensajes nuevos cada 10 minutos. Puedes perderte llamadas y mensajes urgentes.</string>
|
||||
<string name="network_settings">Configuración avanzada de red</string>
|
||||
<string name="onboarding_notifications_mode_off_desc"><b>Mejor para la batería</b>. Recibirás notificaciones sólo cuando la aplicación se esté ejecutando, SIN servicio en segundo plano.</string>
|
||||
<string name="onboarding_notifications_mode_periodic_desc"><b>Bueno para la batería</b>. El servicio en segundo plano comprueba si hay mensajes cada 10 minutos. Puedes perder llamadas o mensajes urgentes.</string>
|
||||
<string name="accept_call_on_lock_screen">Aceptar</string>
|
||||
<string name="full_backup">Copia de seguridad de los datos de la aplicación</string>
|
||||
<string name="chat_item_ttl_day">un dia</string>
|
||||
<string name="chat_item_ttl_month">un mes</string>
|
||||
<string name="chat_item_ttl_week">una semana</string>
|
||||
<string name="allow_disappearing_messages_only_if">Se permiten mensajes temporales sólo si tu contacto también los permite.</string>
|
||||
<string name="v4_3_improved_server_configuration_desc">Añadir servidores escaneando códigos QR.</string>
|
||||
<string name="allow_disappearing_messages_only_if">Se permiten los mensajes temporales pero sólo si tu contacto también los permite.</string>
|
||||
<string name="v4_3_improved_server_configuration_desc">Añadir servidores mediante el escaneo de códigos QR.</string>
|
||||
<string name="smp_servers_preset_add">Añadir servidores predefinidos</string>
|
||||
<string name="all_group_members_will_remain_connected">Todos los miembros del grupo permanecerán conectados.</string>
|
||||
<string name="allow_irreversible_message_deletion_only_if">Se permite la eliminación irreversible de mensajes sólo si tu contacto también lo permite para tí.</string>
|
||||
<string name="allow_irreversible_message_deletion_only_if">Se permite la eliminación irreversible de mensajes pero sólo si tu contacto también lo permite para tí.</string>
|
||||
<string name="keychain_allows_to_receive_ntfs">Android Keystore se usará para almacenar de forma segura la contraseña después de reiniciar la aplicación o cambiar la frase de contraseña - permitirá recibir notificaciones.</string>
|
||||
<string name="allow_your_contacts_to_send_disappearing_messages">Permites a tus contactos enviar mensajes temporales</string>
|
||||
<string name="allow_your_contacts_to_send_voice_messages">Permites a tus contactos enviar mensajes de voz.</string>
|
||||
<string name="chat_preferences_always">siempre</string>
|
||||
<string name="notifications_mode_off_desc">La aplicación sólo puede recibir notificaciones cuando se está ejecutando. No se iniciará ningún servicio en segundo plano.</string>
|
||||
<string name="settings_section_title_icon">ICONO DE LA APLICACIÓN</string>
|
||||
<string name="settings_section_title_icon">ICONO APLICACIÓN</string>
|
||||
<string name="incognito_random_profile_from_contact_description">Se enviará un perfil aleatorio al contacto del que recibió este enlace</string>
|
||||
<string name="turning_off_service_and_periodic">La optimización de la batería está activa, desactivando el servicio en segundo plano y las solicitudes periódicas de nuevos mensajes. Puedes volver a activarlos en Configuración.</string>
|
||||
<string name="notifications_mode_service_desc">El servicio está siempre en funcionamiento en segundo plano. Las notificaciones se muestran en cuanto haya mensajes nuevos.</string>
|
||||
<string name="it_can_disabled_via_settings_notifications_still_shown"><b>Se puede desactivar en Configuración</b> – las notificaciones se seguirán mostrando mientras la app esté en funcionamiento.</string>
|
||||
<string name="notifications_mode_service">Siempre activo</string>
|
||||
<string name="allow_verb">Permitir</string>
|
||||
<string name="above_then_preposition_continuation">arriba, entonces:</string>
|
||||
<string name="above_then_preposition_continuation">arriba y luego:</string>
|
||||
<string name="add_new_contact_to_create_one_time_QR_code"><b>Añadir nuevo contacto</b>: para crear tu código QR de un solo uso para tu contacto.</string>
|
||||
<string name="accept_connection_request__question">¿Aceptar solicitud de conexión\?</string>
|
||||
<string name="accept_contact_incognito_button">Aceptar incógnito</string>
|
||||
<string name="clear_chat_warning">Se eliminarán todos los mensajes SOLO para tí. ¡No puede deshacerse!</string>
|
||||
<string name="clear_chat_warning">Se eliminarán todos los mensajes SOLO para tí. ¡No se puede deshacer!</string>
|
||||
<string name="smp_servers_add">Añadir servidor…</string>
|
||||
<string name="network_enable_socks_info">¿Acceder a los servidores a través del proxy SOCKS en el puerto 9050\? El proxy debe iniciarse antes de activar esta opción.</string>
|
||||
<string name="network_enable_socks_info">¿Acceder a los servidores a través del proxy SOCKS en el puerto %d\? El proxy debe iniciarse antes de activar esta opción.</string>
|
||||
<string name="all_your_contacts_will_remain_connected">Todos tus contactos permanecerán conectados.</string>
|
||||
<string name="appearance_settings">Apariencia</string>
|
||||
<string name="app_version_title">Versión</string>
|
||||
<string name="network_session_mode_user_description">Se usará una conexión TCP independiente (y una credencial SOCKS) <b>para cada perfil de chat que tengas en la aplicación</b>.</string>
|
||||
<string name="network_session_mode_entity_description">Se usará una conexión TCP independiente (y una credencial SOCKS) <b>para cada contacto y miembro del grupo</b>.
|
||||
\n<b>Ten en cuenta</b>: si tienes muchas conexiones, tu consumo de batería y tráfico puede ser sustancialmente mayor y algunas conexiones pueden fallar.</string>
|
||||
<string name="network_session_mode_user_description">Se usará una conexión TCP independiente (y credencial SOCKS) <b>por cada perfil de chat que tengas en la aplicación</b>.</string>
|
||||
<string name="network_session_mode_entity_description">Se usará una conexión TCP independiente (y credencial SOCKS) <b>por cada contacto y miembro del grupo</b>.
|
||||
\n<b>Atención</b>: si tienes muchas conexiones, tu consumo de batería y tráfico pueden ser sustancialmente mayor y algunas conexiones pueden fallar.</string>
|
||||
<string name="a_plus_b">a + b</string>
|
||||
<string name="about_simplex">Acerca de SimpleX</string>
|
||||
<string name="bold">negrita</string>
|
||||
<string name="callstatus_accepted">llamada aceptada</string>
|
||||
<string name="accept">Aceptar</string>
|
||||
<string name="audio_call_no_encryption">llamada de audio (sin cifrado e2e)</string>
|
||||
<string name="icon_descr_audio_call">llamada de audio</string>
|
||||
<string name="settings_audio_video_calls">Llamadas y Videollamadas</string>
|
||||
<string name="audio_call_no_encryption">llamada (sin cifrar)</string>
|
||||
<string name="icon_descr_audio_call">llamada</string>
|
||||
<string name="settings_audio_video_calls">Llamadas y videollamadas</string>
|
||||
<string name="icon_descr_audio_off">Audio desactivado</string>
|
||||
<string name="icon_descr_audio_on">Audio activado</string>
|
||||
<string name="integrity_msg_bad_id">ID de mensaje erróneo</string>
|
||||
<string name="auto_accept_images">Aceptar automáticamente imágenes</string>
|
||||
<string name="users_delete_all_chats_deleted">Se eliminarán todos los chats y mensajes. ¡No puede deshacerse!</string>
|
||||
<string name="auto_accept_images">Auto aceptar imágenes</string>
|
||||
<string name="users_delete_all_chats_deleted">Se eliminarán todos los chats y mensajes. ¡No se puede deshacer!</string>
|
||||
<string name="accept_feature">Aceptar</string>
|
||||
<string name="allow_to_send_disappearing">Permitir enviar mensajes temporales.</string>
|
||||
<string name="allow_to_send_disappearing">Se permiten mensajes temporales.</string>
|
||||
<string name="keychain_is_storing_securely">Android Keystore se utiliza para almacenar de forma segura la contraseña - permite que el servicio de notificación funcione.</string>
|
||||
<string name="users_add">Añadir perfil</string>
|
||||
<string name="incognito_random_profile_description">Se enviará un perfil aleatorio a tu contacto</string>
|
||||
<string name="color_primary">Color</string>
|
||||
<string name="allow_your_contacts_irreversibly_delete">Permites a tus contactos eliminar irreversiblemente los mensajes enviados.</string>
|
||||
<string name="allow_voice_messages_only_if">Se permiten mensajes de voz sólo si tu contacto también los permite.</string>
|
||||
<string name="allow_direct_messages">Permitir el envío de mensajes directos a los miembros.</string>
|
||||
<string name="allow_to_delete_messages">Permitir la eliminación irreversible de los mensajes enviados.</string>
|
||||
<string name="allow_to_send_voice">Permitir enviar mensajes de voz.</string>
|
||||
<string name="v4_2_group_links_desc">Los administradores pueden crear los enlaces para unirse a los grupos.</string>
|
||||
<string name="v4_2_auto_accept_contact_requests">Aceptar automáticamente solicitudes del contacto</string>
|
||||
<string name="allow_voice_messages_only_if">Se permiten los mensajes de voz pero sólo si tu contacto también los permite.</string>
|
||||
<string name="allow_direct_messages">Se permiten mensajes directos entre miembros.</string>
|
||||
<string name="allow_to_delete_messages">Se permite la eliminación irreversible de mensajes.</string>
|
||||
<string name="allow_to_send_voice">Se permiten mensajes de voz.</string>
|
||||
<string name="v4_2_group_links_desc">Los administradores pueden crear enlaces para unirse a grupos.</string>
|
||||
<string name="v4_2_auto_accept_contact_requests">Auto aceptar solicitudes de contacto</string>
|
||||
<string name="attach">Adjuntar</string>
|
||||
<string name="integrity_msg_bad_hash">hash de mensaje erróneo</string>
|
||||
<string name="answer_call">Responder llamada</string>
|
||||
@@ -75,20 +75,18 @@
|
||||
<string name="about_simplex_chat">Sobre <xliff:g id="appNameFull">SimpleX Chat</xliff:g></string>
|
||||
<string name="smp_servers_add_to_another_device">Añadir a otro dispositivo</string>
|
||||
<string name="app_version_name">Versión de la aplicación: v%s</string>
|
||||
<string name="accept_requests">Aceptar solicitudes</string>
|
||||
<string name="accept_automatically">Automáticamente</string>
|
||||
<string name="icon_descr_asked_to_receive">Solicita recibir la imagen</string>
|
||||
<string name="impossible_to_recover_passphrase"><b>Ten en cuenta</b>: NO podrás recuperar o cambiar la contraseña si la pierdes.</string>
|
||||
<string name="impossible_to_recover_passphrase"><b>Atención</b>: NO podrás recuperar o cambiar la contraseña si la pierdes.</string>
|
||||
<string name="both_you_and_your_contact_can_send_voice">Tanto tú como tu contacto podéis enviar mensajes de voz.</string>
|
||||
<string name="onboarding_notifications_mode_service_desc"><b>¡Gasta más batería!</b> El servicio en segundo plano está siempre en funcionamiento - las notificaciones se mostrarán tan pronto como los mensajes estén disponibles.</string>
|
||||
<string name="onboarding_notifications_mode_service_desc"><b>¡Consume más batería!</b> El servicio en segundo plano se ejecuta siempre y las notificaciones se mostrarán en cuanto haya mensajes disponibles.</string>
|
||||
<string name="both_you_and_your_contacts_can_delete">Tanto tú como tu contacto podéis eliminar de forma irreversible los mensajes enviados.</string>
|
||||
<string name="both_you_and_your_contact_can_send_disappearing">Tanto tú como tu contacto podéis enviar mensajes temporales.</string>
|
||||
<string name="scan_QR_code_to_connect_to_contact_who_shows_QR_code"><b>Escanear código QR</b>: para conectar con tu contacto que te muestre código QR.</string>
|
||||
<string name="scan_QR_code_to_connect_to_contact_who_shows_QR_code"><b>Escanear código QR</b>: para conectar con tu contacto mediante su código QR.</string>
|
||||
<string name="create_profile_button">Crear</string>
|
||||
<string name="create_one_time_link">Crear enlace de invitación de un solo uso.</string>
|
||||
<string name="create_group">Crear grupo secreto</string>
|
||||
<string name="database_passphrase_will_be_updated">La contraseña de cifrado de la base de datos será actualizada.</string>
|
||||
<string name="info_row_database_id">ID de la base de datos</string>
|
||||
<string name="info_row_database_id">ID de base de datos</string>
|
||||
<string name="direct_messages_are_prohibited_in_chat">Los mensajes directos entre miembros del grupo no están permitidos.</string>
|
||||
<string name="passphrase_is_different">La contraseña es distinta a la almacenada en Keystore</string>
|
||||
<string name="database_will_be_encrypted_and_passphrase_stored">La base de datos será cifrada y la contraseña se guardará en Keystore.</string>
|
||||
@@ -103,7 +101,7 @@
|
||||
<string name="disappearing_prohibited_in_this_chat">Los mensajes temporales no están permitidos en este chat.</string>
|
||||
<string name="disappearing_messages_are_prohibited">Los mensajes temporales no están permitidos en este grupo.</string>
|
||||
<string name="display_name_cannot_contain_whitespace">El nombre mostrado no puede contener espacios en blanco.</string>
|
||||
<string name="encrypted_video_call">Videollamada con cifrado e2e</string>
|
||||
<string name="encrypted_video_call">Videollamada con cifrado de extremo a extremo</string>
|
||||
<string name="display_name_connection_established">conexión establecida</string>
|
||||
<string name="simplex_link_mode_description">Descripción</string>
|
||||
<string name="smp_server_test_connect">Conectar</string>
|
||||
@@ -113,12 +111,12 @@
|
||||
<string name="maximum_supported_file_size">El tamaño máximo de archivo admitido es <xliff:g id="maxFileSize">%1$s</xliff:g></string>
|
||||
<string name="clear_verification">Eliminar verificación</string>
|
||||
<string name="create_profile">Crear perfil</string>
|
||||
<string name="encrypted_audio_call">llamada con cifrado e2e</string>
|
||||
<string name="status_e2e_encrypted">Cifrado e2e</string>
|
||||
<string name="encrypted_audio_call">Llamada con cifrado de extremo a extremo</string>
|
||||
<string name="status_e2e_encrypted">cifrado de extremo a extremo</string>
|
||||
<string name="integrity_msg_duplicate">mensaje duplicado</string>
|
||||
<string name="settings_section_title_develop">DESARROLLO</string>
|
||||
<string name="settings_developer_tools">Herramientas desarrollo</string>
|
||||
<string name="delete_files_and_media_for_all_users">Eliminar archivos para todos los perfiles Chat</string>
|
||||
<string name="delete_files_and_media_for_all_users">Eliminar los archivos de todos los perfiles</string>
|
||||
<string name="delete_messages">Eliminar mensaje</string>
|
||||
<string name="database_encrypted">¡Base de datos cifrada!</string>
|
||||
<string name="encrypted_with_random_passphrase">La base de datos está cifrada con una contraseña aleatoria, puedes cambiarla.</string>
|
||||
@@ -143,11 +141,11 @@
|
||||
<string name="group_member_status_intro_invitation">conectando (invitación de presentación )</string>
|
||||
<string name="group_member_status_accepted">conectando (aceptado)</string>
|
||||
<string name="group_member_status_announced">conectando (anunciado)</string>
|
||||
<string name="connection_local_display_name">conexión<xliff:g xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\" id=\"connection ID\" example=\"1\"></string>
|
||||
<string name="connection_local_display_name">conexión <xliff:g id="connection ID" example="1">%1$d</xliff:g></string>
|
||||
<string name="connect_via_link_or_qr">Conectar mediante enlace / Código QR</string>
|
||||
<string name="delete_contact_all_messages_deleted_cannot_undo_warning">El contacto y todos los mensajes serán eliminados. ¡No puede deshacerse!</string>
|
||||
<string name="delete_contact_all_messages_deleted_cannot_undo_warning">El contacto y todos los mensajes serán eliminados. ¡No se puede deshacer!</string>
|
||||
<string name="icon_descr_contact_checked">Contacto verificado</string>
|
||||
<string name="status_contact_has_e2e_encryption">El contacto dispone de cifrado e2e</string>
|
||||
<string name="status_contact_has_e2e_encryption">el contacto dispone de cifrado de extremo a extremo</string>
|
||||
<string name="smp_server_test_disconnect">Desconectar</string>
|
||||
<string name="notification_preview_mode_contact">Nombre del contacto</string>
|
||||
<string name="copy_verb">Copiar</string>
|
||||
@@ -167,7 +165,7 @@
|
||||
<string name="icon_descr_server_status_connected">Conectado</string>
|
||||
<string name="copied">Copiado en portapapeles</string>
|
||||
<string name="share_one_time_link">Crear enlace de invitación de un solo uso.</string>
|
||||
<string name="desktop_scan_QR_code_from_app_via_scan_QR_code">💻 PC: escanéa el código QR desde la app mediante <b>Escanéo de código QR </b></string>
|
||||
<string name="desktop_scan_QR_code_from_app_via_scan_QR_code">💻 PC: escanéa el código QR desde la aplicación mediante <b>Escanear código QR </b></string>
|
||||
<string name="delete_contact_menu_action">Eliminar</string>
|
||||
<string name="delete_group_menu_action">Eliminar</string>
|
||||
<string name="alert_title_contact_connection_pending">¡El contacto aun no se ha conectado!</string>
|
||||
@@ -226,12 +224,12 @@
|
||||
<string name="archive_created_on_ts">Creado: <xliff:g id="archive_ts">%1$s</xliff:g></string>
|
||||
<string name="delete_archive">Eliminar archivo</string>
|
||||
<string name="group_member_status_connected">conectado</string>
|
||||
<string name="conn_level_desc_direct">directo</string>
|
||||
<string name="conn_level_desc_direct">directa</string>
|
||||
<string name="chat_preferences_contact_allows">El contacto permite</string>
|
||||
<string name="chat_preferences_default">predefinido (%s)</string>
|
||||
<string name="full_deletion">Eliminar para todos</string>
|
||||
<string name="feature_enabled">activado</string>
|
||||
<string name="contacts_can_mark_messages_for_deletion">El contacto solo puede marcar los mensajes para eliminar. Tu podrás verlos.</string>
|
||||
<string name="contacts_can_mark_messages_for_deletion">Tus contactos sólo pueden marcar los mensajes para eliminar. Tu podrás verlos.</string>
|
||||
<string name="ttl_w">%ds</string>
|
||||
<string name="deleted_description">eliminado</string>
|
||||
<string name="connect_via_contact_link">¿Conectar mediante enlace de contacto\?</string>
|
||||
@@ -244,7 +242,7 @@
|
||||
<string name="contact_connection_pending">conectando…</string>
|
||||
<string name="group_connection_pending">conectando…</string>
|
||||
<string name="icon_descr_context">Icono contextual</string>
|
||||
<string name="status_contact_has_no_e2e_encryption">El contacto no dispone de cifrado e2e</string>
|
||||
<string name="status_contact_has_no_e2e_encryption">el contacto no dispone de cifrado</string>
|
||||
<string name="icon_descr_call_connecting">Conectando llamada</string>
|
||||
<string name="create_secret_group_title">Crear grupo secreto</string>
|
||||
<string name="icon_descr_email">Email</string>
|
||||
@@ -254,7 +252,6 @@
|
||||
\nContraseña</string>
|
||||
<string name="contribute">Contribuye</string>
|
||||
<string name="core_version">Core versión: v%s</string>
|
||||
<string name="contact_requests">Solicitud del contacto</string>
|
||||
<string name="delete_image">Eliminar imagen</string>
|
||||
<string name="edit_image">Editar imagen</string>
|
||||
<string name="settings_section_title_chats">CHATS</string>
|
||||
@@ -264,8 +261,8 @@
|
||||
<string name="change_member_role_question">¿Cambiar rol de grupo\?</string>
|
||||
<string name="v4_4_verify_connection_security_desc">Compara los códigos de seguridad con tus contactos</string>
|
||||
<string name="choose_file">Archivo</string>
|
||||
<string name="clear_verb">Limpiar</string>
|
||||
<string name="clear_chat_button">Limpiar chat</string>
|
||||
<string name="clear_verb">Vaciar</string>
|
||||
<string name="clear_chat_button">Vaciar chat</string>
|
||||
<string name="configure_ICE_servers">Configurar servidores ICE</string>
|
||||
<string name="callstatus_ended">Llamada terminada <xliff:g id="duration" example="01:15">%1$s</xliff:g></string>
|
||||
<string name="callstatus_error">error en la llamada</string>
|
||||
@@ -273,24 +270,24 @@
|
||||
<string name="callstatus_in_progress">llamada en curso</string>
|
||||
<string name="colored">coloreado</string>
|
||||
<string name="rcv_group_event_changed_your_role">ha cambiado tu rol a %s</string>
|
||||
<string name="snd_conn_event_switch_queue_phase_changing_for_member">cambiando dirección por %s</string>
|
||||
<string name="snd_conn_event_switch_queue_phase_changing_for_member">cambiando de servidor para %s</string>
|
||||
<string name="group_member_status_complete">completado</string>
|
||||
<string name="invite_prohibited">¡No se puede invitar el contacto!</string>
|
||||
<string name="cannot_receive_file">No se puede recibir el archivo</string>
|
||||
<string name="database_initialization_error_title">No se puede iniciar la base de datos</string>
|
||||
<string name="clear_chat_question">Limpiar chat\?</string>
|
||||
<string name="clear_chat_question">¿Vaciar chat\?</string>
|
||||
<string name="network_session_mode_user">Perfil de Chat</string>
|
||||
<string name="chat_is_stopped_indication">Chat está detenido</string>
|
||||
<string name="rcv_group_event_changed_member_role">rol de %s cambiado a %s</string>
|
||||
<string name="change_role">Cambiar rol</string>
|
||||
<string name="v4_5_transport_isolation_descr">Mediante perfil de Chat (por defecto) o por conexión (BETA)</string>
|
||||
<string name="snd_conn_event_switch_queue_phase_changing">cambiando dirección…</string>
|
||||
<string name="snd_conn_event_switch_queue_phase_changing">cambiando de servidor…</string>
|
||||
<string name="chat_preferences">Preferencias de Chat</string>
|
||||
<string name="feature_cancelled_item">cancelado %s</string>
|
||||
<string name="chat_is_stopped">Chat está detenido</string>
|
||||
<string name="settings_section_title_calls">LLAMADAS</string>
|
||||
<string name="chat_is_running">El chat está en ejecución</string>
|
||||
<string name="rcv_conn_event_switch_queue_phase_changing">cambiando dirección…</string>
|
||||
<string name="chat_is_running">Chat está en ejecución</string>
|
||||
<string name="rcv_conn_event_switch_queue_phase_changing">cambiando de servidor…</string>
|
||||
<string name="chat_with_developers">habla con los desarrolladores</string>
|
||||
<string name="icon_descr_cancel_file_preview">Cancelar vista previa del archivo</string>
|
||||
<string name="icon_descr_cancel_image_preview">Cancelar vista previa de la imagen</string>
|
||||
@@ -303,14 +300,14 @@
|
||||
<string name="cancel_verb">Cancelar</string>
|
||||
<string name="icon_descr_cancel_live_message">Cancelar mensaje en directo</string>
|
||||
<string name="confirm_verb">Confirmar</string>
|
||||
<string name="clear_chat_menu_action">Limpiar</string>
|
||||
<string name="clear_chat_menu_action">Vaciar</string>
|
||||
<string name="app_version_code">Build de la aplicación</string>
|
||||
<string name="call_already_ended">¡La llamada ha terminado!</string>
|
||||
<string name="rcv_conn_event_switch_queue_phase_completed">su dirección ha cambiado para tí</string>
|
||||
<string name="rcv_conn_event_switch_queue_phase_completed">el servidor de envío ha cambiado para tí</string>
|
||||
<string name="icon_descr_cancel_link_preview">cancelar vista previa del enlace</string>
|
||||
<string name="call_on_lock_screen">Llamadas en la ventana de bloqueo</string>
|
||||
<string name="alert_title_cant_invite_contacts">¡No se puede invitar a los contactos!</string>
|
||||
<string name="chat_console">Consola del chat</string>
|
||||
<string name="chat_console">Consola de Chat</string>
|
||||
<string name="chat_database_section">BASE DE DATOS DE CHAT</string>
|
||||
<string name="chat_database_deleted">Base de datos eliminada</string>
|
||||
<string name="chat_database_imported">Base de datos importada</string>
|
||||
@@ -327,9 +324,9 @@
|
||||
<string name="icon_descr_flip_camera">Voltear la cámara</string>
|
||||
<string name="group_invitation_expired">Invitación de grupo caducada</string>
|
||||
<string name="alert_message_group_invitation_expired">La invitación al grupo ya no es válida, ha sido eliminada por el remitente.</string>
|
||||
<string name="delete_group_for_self_cannot_undo_warning">El grupo se eliminará para tí. ¡No puede deshacerse!</string>
|
||||
<string name="how_to_use_markdown">Cómo usar sintaxis markdown</string>
|
||||
<string name="description_via_one_time_link_incognito">Incógnito mediante enlace de un uso</string>
|
||||
<string name="delete_group_for_self_cannot_undo_warning">El grupo se eliminará para tí. ¡No se puede deshacer!</string>
|
||||
<string name="how_to_use_markdown">Cómo usar la sintaxis markdown</string>
|
||||
<string name="description_via_one_time_link_incognito">en modo incógnito mediante enlace de un solo uso</string>
|
||||
<string name="simplex_link_contact">Dirección de contacto SimpleX</string>
|
||||
<string name="error_saving_smp_servers">Error guardando servidores SMP</string>
|
||||
<string name="simplex_link_mode_browser_warning">Abrir el enlace en el navegador puede reducir la privacidad y seguridad de la conexión. Los enlaces SimpleX que no son de confianza aparecerán en rojo.</string>
|
||||
@@ -345,7 +342,7 @@
|
||||
<string name="file_with_path">Archivo: %s</string>
|
||||
<string name="failed_to_active_user_title">¡Error cambiando perfil!</string>
|
||||
<string name="smp_servers_enter_manually">Introduce el servidor manualmente</string>
|
||||
<string name="how_to_use_your_servers">Cómo usar tus servidores</string>
|
||||
<string name="how_to_use_your_servers">Cómo usar los servidores</string>
|
||||
<string name="error_stopping_chat">Error deteniendo Chat</string>
|
||||
<string name="enter_correct_passphrase">Introduce la contraseña correcta.</string>
|
||||
<string name="enter_passphrase">Introduce la contraseña…</string>
|
||||
@@ -361,7 +358,7 @@
|
||||
<string name="from_gallery_button">De la Galería</string>
|
||||
<string name="gallery_image_button">Imagen</string>
|
||||
<string name="gallery_video_button">Vídeo</string>
|
||||
<string name="if_you_received_simplex_invitation_link_you_can_open_in_browser">Si has recibido el enlace de invitación a <xliff:g id="appName">SimpleX Chat</xliff:g>, puedes abrirlo en tu navegador:</string>
|
||||
<string name="if_you_received_simplex_invitation_link_you_can_open_in_browser">Si has recibido un enlace de invitación a <xliff:g id="appName">SimpleX Chat</xliff:g> puedes abrirlo en tu navegador:</string>
|
||||
<string name="if_you_choose_to_reject_the_sender_will_not_be_notified">Si eliges rechazar, el remitente NO será notificado.</string>
|
||||
<string name="invalid_contact_link">¡Enlace no válido!</string>
|
||||
<string name="if_you_cannot_meet_in_person_scan_QR_in_video_call_or_ask_for_invitation_link">Si no puedes reunirte en persona, puedes <b>escanear el código QR en la videollamada</b>, o tu contacto puede compartir un enlace de invitación.</string>
|
||||
@@ -371,8 +368,8 @@
|
||||
<string name="error_deleting_database">Error eliminando la base de datos</string>
|
||||
<string name="encrypted_database">Base de datos cifrada</string>
|
||||
<string name="error_removing_member">Error eliminando miembro</string>
|
||||
<string name="group_members_can_send_voice">Los miembros del grupo pueden mandar mensajes de voz.</string>
|
||||
<string name="description_via_contact_address_link_incognito">Incógnito mediante enlace de dirección del contacto</string>
|
||||
<string name="group_members_can_send_voice">Los miembros del grupo pueden enviar mensajes de voz.</string>
|
||||
<string name="description_via_contact_address_link_incognito">en modo incógnito mediante enlace de dirección del contacto</string>
|
||||
<string name="failed_to_create_user_title">Error creando perfil!</string>
|
||||
<string name="failed_to_parse_chat_title">No se pudo cargar el chat</string>
|
||||
<string name="failed_to_parse_chats_title">No se pudieron cargar los chats</string>
|
||||
@@ -396,10 +393,10 @@
|
||||
<string name="error_saving_ICE_servers">Error guardando servidores ICE</string>
|
||||
<string name="enter_one_ICE_server_per_line">Servidores ICE (uno por línea)</string>
|
||||
<string name="full_name__field">Nombre completo:</string>
|
||||
<string name="people_can_connect_only_via_links_you_share">Las personas pueden conectarse contigo solo mediante los enlaces que compartes.</string>
|
||||
<string name="people_can_connect_only_via_links_you_share">Las personas pueden conectarse contigo sólo mediante los enlaces que compartes.</string>
|
||||
<string name="how_simplex_works">Cómo funciona <xliff:g id="appName">SimpleX</xliff:g></string>
|
||||
<string name="icon_descr_hang_up">Colgar</string>
|
||||
<string name="files_and_media_section">Archivo y multimedia</string>
|
||||
<string name="files_and_media_section">Archivos y multimedia</string>
|
||||
<string name="alert_title_no_group">¡Grupo no encontrado!</string>
|
||||
<string name="snd_group_event_group_profile_updated">perfil de grupo actualizado</string>
|
||||
<string name="error_creating_link_for_group">Error al crear enlace de grupo</string>
|
||||
@@ -415,7 +412,7 @@
|
||||
<string name="export_database">Exportar base de datos</string>
|
||||
<string name="error_exporting_chat_database">Error exportando la base de datos</string>
|
||||
<string name="error_starting_chat">Error iniciando chat</string>
|
||||
<string name="rcv_group_event_invited_via_your_group_link">Invitado mediante tu enlace de grupo</string>
|
||||
<string name="rcv_group_event_invited_via_your_group_link">se ha unido mediante tu enlace de grupo</string>
|
||||
<string name="error_updating_link_for_group">Error actualizando el enlace de grupo</string>
|
||||
<string name="section_title_for_console">PARA CONSOLA</string>
|
||||
<string name="error_changing_role">Error cambiando rol</string>
|
||||
@@ -427,11 +424,11 @@
|
||||
<string name="v4_3_improved_privacy_and_security_desc">Ocultar pantalla de aplicaciones en aplicaciones recientes.</string>
|
||||
<string name="encrypt_database">Cifrar</string>
|
||||
<string name="icon_descr_expand_role">Ampliar la selección de roles</string>
|
||||
<string name="delete_group_for_all_members_cannot_undo_warning">El grupo se eliminará para todos los miembros. ¡No puede deshacerse!</string>
|
||||
<string name="delete_group_for_all_members_cannot_undo_warning">El grupo se eliminará para todos los miembros. ¡No se puede deshacer!</string>
|
||||
<string name="network_option_enable_tcp_keep_alive">Activar TCP keep-alive</string>
|
||||
<string name="feature_enabled_for_you">activado para tí</string>
|
||||
<string name="server_error">error</string>
|
||||
<string name="description_via_group_link_incognito">Incógnito mediante enlace de grupo</string>
|
||||
<string name="description_via_group_link_incognito">en modo incógnito mediante enlace de grupo</string>
|
||||
<string name="error_adding_members">Error al añadir miembro(s)</string>
|
||||
<string name="error_sending_message">Error enviando mensaje</string>
|
||||
<string name="error_encrypting_database">Error cifrando la base de datos</string>
|
||||
@@ -445,15 +442,15 @@
|
||||
<string name="paste_connection_link_below_to_connect">Pega el enlace que has recibido en el recuadro para conectar con tu contacto.</string>
|
||||
<string name="share_link">Compartir enlace</string>
|
||||
<string name="how_it_works">Cómo funciona</string>
|
||||
<string name="delete_message_cannot_be_undone_warning">El mensaje se eliminará. ¡No puede deshacerse!</string>
|
||||
<string name="delete_message_cannot_be_undone_warning">El mensaje se eliminará. ¡No se puede deshacer!</string>
|
||||
<string name="incognito_info_protects">La función del modo incógnito es proteger la identidad del perfil principal: por cada contacto nuevo se genera un perfil aleatorio.</string>
|
||||
<string name="turn_off_battery_optimization">Para poder usarse <b>deshabilita la optimización de batería</b> para <xliff:g id="appName">SimpleX</xliff:g> en el siguiente cuadro de diálogo. De lo contrario las notificaciones estarán desactivadas.</string>
|
||||
<string name="install_simplex_chat_for_terminal">Instalar <xliff:g id="appNameFull">SimpleX Chat</xliff:g> para terminal</string>
|
||||
<string name="install_simplex_chat_for_terminal">Instalar terminal para <xliff:g id="appNameFull">SimpleX Chat</xliff:g></string>
|
||||
<string name="group_invitation_item_description">invitación al grupo <xliff:g id="group_name">%1$s</xliff:g></string>
|
||||
<string name="rcv_group_event_member_added">invitado <xliff:g id="member profile" example="alice (Alice)">%1$s</xliff:g></string>
|
||||
<string name="rcv_group_event_member_added">ha invitado a <xliff:g id="member profile" example="alice (Alice)">%1$s</xliff:g></string>
|
||||
<string name="incognito_info_allows">Permite tener varias conexiones anónimas sin datos compartidos entre estas dentro del mismo perfil.</string>
|
||||
<string name="invite_to_group_button">Invitar al grupo</string>
|
||||
<string name="to_verify_compare">Para comprobar el cifrado de extremo a extremo con su contacto compare (o escanee) el código en sus dispositivos.</string>
|
||||
<string name="to_verify_compare">Para comprobar el cifrado de extremo a extremo con tu contacto compara (o escanea) el código en tus dispositivos.</string>
|
||||
<string name="database_is_not_encrypted">La base de datos no está cifrada. Escribe una contraseña para protegerla.</string>
|
||||
<string name="ensure_smp_server_address_are_correct_format_and_unique">Asegúrate de que las direcciones del servidor SMP tienen el formato correcto, están separadas por líneas y no están duplicadas.</string>
|
||||
<string name="icon_descr_instant_notifications">Notificación instantánea</string>
|
||||
@@ -464,7 +461,7 @@
|
||||
<string name="onboarding_notifications_mode_service">Instantánea</string>
|
||||
<string name="join_group_button">Únete</string>
|
||||
<string name="join_group_incognito_button">Únete en modo incógnito</string>
|
||||
<string name="conn_level_desc_indirect">indirecto (<xliff:g id="conn_level">%1$s</xliff:g>)</string>
|
||||
<string name="conn_level_desc_indirect">indirecta (<xliff:g id="conn_level">%1$s</xliff:g>)</string>
|
||||
<string name="theme_light">Claro</string>
|
||||
<string name="chat_preferences_on">Activado</string>
|
||||
<string name="message_deletion_prohibited">La eliminación irreversible de mensajes no está permitida en este chat.</string>
|
||||
@@ -492,7 +489,7 @@
|
||||
<string name="mark_unread">Marcar como no leído</string>
|
||||
<string name="invalid_QR_code">Código QR inválido</string>
|
||||
<string name="incorrect_code">¡Código de seguridad incorrecto!</string>
|
||||
<string name="markdown_in_messages">Sintaxis markdown en mensajes</string>
|
||||
<string name="markdown_in_messages">Sintaxis markdown en los mensajes</string>
|
||||
<string name="network_use_onion_hosts_no">No</string>
|
||||
<string name="callstatus_missed">llamada perdida</string>
|
||||
<string name="import_database_confirmation">Importar</string>
|
||||
@@ -521,13 +518,13 @@
|
||||
<string name="mute_chat">Silenciar</string>
|
||||
<string name="ensure_ICE_server_address_are_correct_format_and_unique">Asegúrate de que las direcciones del servidor WebRTC ICE tienen el formato correcto, están separadas por líneas y no duplicadas.</string>
|
||||
<string name="network_use_onion_hosts_required_desc">Se requieren hosts .onion para la conexión</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc_in_alert">Se usarán hosts .onion cuando estén disponibles.</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc_in_alert">Se usarán hosts .onion si están disponibles.</string>
|
||||
<string name="immune_to_spam_and_abuse">Inmune a spam y abuso</string>
|
||||
<string name="many_people_asked_how_can_it_deliver">Muchos se preguntarán: <i>si <xliff:g id="appName">SimpleX</xliff:g> no tiene identificadores de usuario, ¿cómo puede entregar los mensajes\?</i></string>
|
||||
<string name="incoming_video_call">Videollamada entrante</string>
|
||||
<string name="snd_group_event_user_left">has salido</string>
|
||||
<string name="snd_conn_event_switch_queue_phase_completed">has cambiado la dirección</string>
|
||||
<string name="feature_off">apagado</string>
|
||||
<string name="feature_off">desactivado</string>
|
||||
<string name="v4_3_irreversible_message_deletion">Eliminación irreversible del mensaje</string>
|
||||
<string name="v4_3_voice_messages_desc">Máximo 40 segundos, recibido al instante.</string>
|
||||
<string name="v4_5_italian_interface">Interfaz en italiano</string>
|
||||
@@ -539,12 +536,12 @@
|
||||
<string name="ok">OK</string>
|
||||
<string name="only_stored_on_members_devices">(sólo almacenado por miembros del grupo)</string>
|
||||
<string name="markdown_help">Ayuda sintaxis markdown</string>
|
||||
<string name="network_and_servers">Redes y Servidores</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc">Se usarán hosts .onion cuando estén disponibles.</string>
|
||||
<string name="network_and_servers">Servidores y Redes</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc">Se usarán hosts .onion si están disponibles.</string>
|
||||
<string name="italic">cursiva</string>
|
||||
<string name="incoming_audio_call">Llamada entrante</string>
|
||||
<string name="video_call_no_encryption">videollamada (sin cifrado e2e)</string>
|
||||
<string name="status_no_e2e_encryption">sin cifrado e2e</string>
|
||||
<string name="video_call_no_encryption">videollamada (sin cifrar)</string>
|
||||
<string name="status_no_e2e_encryption">sin cifrar</string>
|
||||
<string name="import_database">Importar base de datos</string>
|
||||
<string name="settings_section_title_messages">MENSAJES Y ARCHIVOS</string>
|
||||
<string name="import_database_question">¿Importar base de datos\?</string>
|
||||
@@ -557,24 +554,24 @@
|
||||
<string name="icon_descr_add_members">Invitar miembros</string>
|
||||
<string name="group_member_role_observer">observador</string>
|
||||
<string name="group_member_role_member">miembro</string>
|
||||
<string name="group_member_status_removed">eliminado</string>
|
||||
<string name="group_member_status_invited">invitado</string>
|
||||
<string name="group_member_status_removed">expulsado</string>
|
||||
<string name="group_member_status_invited">ha invitado a</string>
|
||||
<string name="no_contacts_to_add">Sin contactos que añadir</string>
|
||||
<string name="new_member_role">Nuevo rol de miembro</string>
|
||||
<string name="initial_member_role">Rol inicial</string>
|
||||
<string name="info_row_local_name">Nombre local</string>
|
||||
<string name="network_status">Estado de la red</string>
|
||||
<string name="incognito">Incógnito</string>
|
||||
<string name="chat_preferences_off">apagado</string>
|
||||
<string name="chat_preferences_off">desactivado</string>
|
||||
<string name="new_in_version">Nuevo en %s</string>
|
||||
<string name="v4_3_improved_privacy_and_security">Seguridad y privacidad mejoradas</string>
|
||||
<string name="settings_section_title_incognito">Modo incógnito</string>
|
||||
<string name="new_database_archive">Nuevo archivo de base de datos</string>
|
||||
<string name="old_database_archive">Archivo de base de datos antiguo</string>
|
||||
<string name="old_database_archive">Archivo de bases de datos antiguas</string>
|
||||
<string name="snd_conn_event_switch_queue_phase_completed_for_member">has cambiado la dirección por %s</string>
|
||||
<string name="rcv_group_event_member_left">ha salido</string>
|
||||
<string name="button_leave_group">Salir del grupo</string>
|
||||
<string name="only_group_owners_can_change_prefs">Sólo los propietarios del grupo pueden modificar las preferencias de grupo.</string>
|
||||
<string name="only_group_owners_can_change_prefs">Sólo los propietarios pueden modificar las preferencias de grupo.</string>
|
||||
<string name="users_delete_data_only">Sólo datos del perfil local</string>
|
||||
<string name="chat_preferences_no">no</string>
|
||||
<string name="thousand_abbreviation">k</string>
|
||||
@@ -584,14 +581,14 @@
|
||||
<string name="leave_group_button">Salir</string>
|
||||
<string name="leave_group_question">¿Salir del grupo\?</string>
|
||||
<string name="group_member_role_owner">propietario</string>
|
||||
<string name="member_will_be_removed_from_group_cannot_be_undone">El miembro será eliminado del grupo. ¡No puede deshacerse!</string>
|
||||
<string name="only_group_owners_can_enable_voice">Sólo los propietarios del grupo pueden activar los mensajes de voz.</string>
|
||||
<string name="member_will_be_removed_from_group_cannot_be_undone">El miembro será expulsado del grupo. ¡No se puede deshacer!</string>
|
||||
<string name="only_group_owners_can_enable_voice">Sólo los propietarios pueden activar los mensajes de voz.</string>
|
||||
<string name="group_unsupported_incognito_main_profile_sent">El modo incógnito no se admite aquí, tu perfil principal aparecerá en miembros del grupo</string>
|
||||
<string name="icon_descr_more_button">Más</string>
|
||||
<string name="mark_code_verified">Marcar como verificado</string>
|
||||
<string name="smp_servers_invalid_address">¡Dirección de servidor no válida!</string>
|
||||
<string name="make_private_connection">Establecer una conexión privada</string>
|
||||
<string name="network_error_desc">Comprueba su conexión de red con <xliff:g id="serverHost" example="smp.simplex.im">%1$s</xliff:g> e inténtelo de nuevo.</string>
|
||||
<string name="network_error_desc">Comprueba tu conexión de red con <xliff:g id="serverHost" example="smp.simplex.im">%1$s</xliff:g> e inténtalo de nuevo.</string>
|
||||
<string name="sender_may_have_deleted_the_connection_request">El remitente puede haber eliminado la solicitud de conexión.</string>
|
||||
<string name="error_smp_test_certificate">Posiblemente la huella digital del certificado en la dirección del servidor es incorrecta</string>
|
||||
<string name="reply_verb">Responder</string>
|
||||
@@ -600,15 +597,15 @@
|
||||
<string name="select_contacts">Seleccionar contactos</string>
|
||||
<string name="save_group_profile">Guardar perfil de grupo</string>
|
||||
<string name="reset_color">Restablecer colores</string>
|
||||
<string name="only_you_can_send_disappearing">Sólo tú puedes enviar mensajes temporales</string>
|
||||
<string name="only_you_can_send_disappearing">Sólo tú puedes enviar mensajes temporales.</string>
|
||||
<string name="only_your_contact_can_send_disappearing">Sólo tu contacto puede enviar mensajes temporales.</string>
|
||||
<string name="prohibit_sending_voice">Prohibes el envío de mensajes de voz.</string>
|
||||
<string name="prohibit_sending_voice">No se permiten mensajes de voz.</string>
|
||||
<string name="notifications_mode_off">Se ejecuta sólo cuando la aplicación está abierta</string>
|
||||
<string name="auth_open_chat_console">Abrir la consola de chat</string>
|
||||
<string name="auth_open_chat_console">Abrir consola de chat</string>
|
||||
<string name="save_verb">Guardar</string>
|
||||
<string name="restore_database_alert_confirm">Restaurar</string>
|
||||
<string name="network_options_save">Guardar</string>
|
||||
<string name="prohibit_message_deletion">Prohibir la eliminación irreversible de mensajes.</string>
|
||||
<string name="prohibit_message_deletion">No se permite la eliminación irreversible de mensajes.</string>
|
||||
<string name="v4_4_live_messages_desc">Los destinatarios ven la actualizacion mientras escribes.</string>
|
||||
<string name="icon_descr_send_message">Enviar Mensaje</string>
|
||||
<string name="toast_permission_denied">¡Permiso denegado!</string>
|
||||
@@ -626,15 +623,15 @@
|
||||
<string name="restore_database_alert_title">¿Restaurar copia de seguridad de la base de datos\?</string>
|
||||
<string name="onboarding_notifications_mode_title">Notificaciones privadas</string>
|
||||
<string name="image_descr_profile_image">imagen del perfil</string>
|
||||
<string name="prohibit_sending_voice_messages">Prohibes el envío de mensajes de voz.</string>
|
||||
<string name="prohibit_sending_voice_messages">No se permiten mensajes de voz.</string>
|
||||
<string name="protect_app_screen">Proteger la pantalla de la aplicación</string>
|
||||
<string name="read_more_in_github_with_link">Más información en nuestro <font color="#0088ff">repositorio GitHub</font> .</string>
|
||||
<string name="icon_descr_record_voice_message">Grabar mensaje de voz</string>
|
||||
<string name="rcv_group_event_member_deleted">eliminado <xliff:g id="member profile" example="alice (Alice)">%1$s</xliff:g></string>
|
||||
<string name="send_link_previews">Enviar previsualizaciones de enlaces</string>
|
||||
<string name="rcv_group_event_member_deleted">ha expulsado a <xliff:g id="member profile" example="alice (Alice)">%1$s</xliff:g></string>
|
||||
<string name="send_link_previews">Enviar previsualizacion de enlaces</string>
|
||||
<string name="send_live_message_desc">Envía un mensaje en vivo: se actualizará para el(los) destinatario(s) a medida que se escribe</string>
|
||||
<string name="icon_descr_sent_msg_status_send_failed">error de envío</string>
|
||||
<string name="sending_via">Enviando mediante</string>
|
||||
<string name="sending_via">Enviando vía</string>
|
||||
<string name="contact_developers">Por favor, actualiza la aplicación y ponte en contacto con los desarrolladores.</string>
|
||||
<string name="sender_cancelled_file_transfer">El remitente ha cancelado la transferencia de archivos.</string>
|
||||
<string name="smp_server_test_secure_queue">Cola segura</string>
|
||||
@@ -657,7 +654,7 @@
|
||||
<string name="v4_5_reduced_battery_usage">Reducción del uso de la batería</string>
|
||||
<string name="observer_cant_send_message_desc">Póngase en contacto con el administrador del grupo.</string>
|
||||
<string name="ask_your_contact_to_enable_voice">Solicita que tu contacto habilite el envío de mensajes de voz.</string>
|
||||
<string name="send_live_message">Enviar mensaje en vivo</string>
|
||||
<string name="send_live_message">Mensaje en vivo</string>
|
||||
<string name="scan_QR_code">Escanear código QR</string>
|
||||
<string name="send_verb">Enviar</string>
|
||||
<string name="connect_via_link_or_qr_from_clipboard_or_in_person">(escanear o pegar desde el portapapeles)</string>
|
||||
@@ -665,7 +662,7 @@
|
||||
<string name="image_descr_qr_code">Código QR</string>
|
||||
<string name="chat_with_the_founder">Consultas y sugerencias</string>
|
||||
<string name="smp_servers_preset_address">Dirección del servidor predefinida</string>
|
||||
<string name="send_us_an_email">Contacta por email</string>
|
||||
<string name="send_us_an_email">Contacta vía email</string>
|
||||
<string name="rate_the_app">Valora la aplicación</string>
|
||||
<string name="save_servers_button">Guardar</string>
|
||||
<string name="callstate_received_answer">respuesta recibida…</string>
|
||||
@@ -680,12 +677,12 @@
|
||||
<string name="store_passphrase_securely_without_recover">Guarda la contraseña de forma segura, NO podrás acceder al chat si la pierdes.</string>
|
||||
<string name="save_archive">Guardar archivo</string>
|
||||
<string name="restore_database_alert_desc">Introduce la contraseña anterior después de restaurar la copia de seguridad de la base de datos. Esta acción no se puede deshacer.</string>
|
||||
<string name="rcv_group_event_user_deleted">te ha eliminado</string>
|
||||
<string name="receiving_via">Recibiendo mediante</string>
|
||||
<string name="rcv_group_event_user_deleted">te ha expulsado</string>
|
||||
<string name="receiving_via">Recibiendo vía</string>
|
||||
<string name="network_option_protocol_timeout">Tiempo de espera del protocolo</string>
|
||||
<string name="network_option_seconds_label">seg</string>
|
||||
<string name="users_delete_with_connections">Perfil y conexiones de servidor</string>
|
||||
<string name="prohibit_sending_disappearing_messages">Prohibes el envío de mensajes temporales</string>
|
||||
<string name="prohibit_sending_disappearing_messages">No se permiten mensajes temporales.</string>
|
||||
<string name="only_you_can_send_voice">Sólo tú puedes enviar mensajes de voz.</string>
|
||||
<string name="only_your_contact_can_send_voice">Sólo tu contacto puede enviar mensajes de voz.</string>
|
||||
<string name="run_chat_section">EJECUTAR CHAT</string>
|
||||
@@ -693,8 +690,8 @@
|
||||
<string name="enter_correct_current_passphrase">Introduce la contraseña actual correcta.</string>
|
||||
<string name="feature_received_prohibited">recepción prohibida</string>
|
||||
<string name="only_you_can_delete_messages">Sólo tú puedes eliminar mensajes de forma irreversible (tu contacto puede marcarlos para eliminar).</string>
|
||||
<string name="prohibit_direct_messages">Prohibir el envío de mensajes directos a los miembros.</string>
|
||||
<string name="prohibit_sending_disappearing">Prohibes el envío de mensajes temporales</string>
|
||||
<string name="prohibit_direct_messages">No se permiten mensajes directos entre miembros.</string>
|
||||
<string name="prohibit_sending_disappearing">No se permiten mensajes temporales.</string>
|
||||
<string name="v4_2_security_assessment">Evaluación de la seguridad</string>
|
||||
<string name="receiving_files_not_yet_supported">la recepción de archivos aún no está disponible</string>
|
||||
<string name="sending_files_not_yet_supported">el envío de archivos aún no está disponible</string>
|
||||
@@ -706,8 +703,8 @@
|
||||
<string name="restore_database">Restaurar copia de seguridad de la base de datos</string>
|
||||
<string name="save_passphrase_and_open_chat">Guardar contraseña y abrir el chat</string>
|
||||
<string name="restore_passphrase_not_found_desc">La contraseña no se ha encontrado en Keystore, introdúzcala manualmente. Esto puede haber ocurrido si has restaurado los datos de la aplicación con una herramienta de copia de seguridad. Si no es así, por favor ponte en contacto con los desarrolladores.</string>
|
||||
<string name="remove_member_confirmation">Eliminar</string>
|
||||
<string name="button_remove_member">Eliminar miembro</string>
|
||||
<string name="remove_member_confirmation">Expulsar</string>
|
||||
<string name="button_remove_member">Expulsar miembro</string>
|
||||
<string name="button_send_direct_message">Enviar mensaje directo</string>
|
||||
<string name="reset_verb">Restablecer</string>
|
||||
<string name="paste_button">Pegar</string>
|
||||
@@ -741,37 +738,36 @@
|
||||
<string name="share_verb">Compartir</string>
|
||||
<string name="icon_descr_sent_msg_status_unauthorized_send">envío no autorizado</string>
|
||||
<string name="set_contact_name">Escribe un nombre para el contacto</string>
|
||||
<string name="network_socks_toggle">Usar proxy SOCKS (puerto 9050)</string>
|
||||
<string name="unknown_error">Error desconocido</string>
|
||||
<string name="member_role_will_be_changed_with_notification">El rol cambiará a \"%s\". Se notificará a todos los miembros del grupo.</string>
|
||||
<string name="v4_2_security_assessment_desc">La seguridad de SimpleX Chat fue auditada por Trail of Bits.</string>
|
||||
<string name="v4_2_security_assessment_desc">La seguridad de SimpleX Chat ha sido auditada por Trail of Bits.</string>
|
||||
<string name="v4_4_disappearing_messages_desc">Los mensajes enviados se eliminarán una vez transcurrido el tiempo establecido.</string>
|
||||
<string name="ntf_channel_messages">Mensajes de chat SimpleX</string>
|
||||
<string name="icon_descr_received_msg_status_unread">no leído</string>
|
||||
<string name="text_field_set_contact_placeholder">Escribe un nombre para el contacto…</string>
|
||||
<string name="switch_receiving_address_question">¿Cambiar dirección de recepción\?</string>
|
||||
<string name="switch_receiving_address_question">¿Cambiar servidor de recepción\?</string>
|
||||
<string name="use_camera_button">Cámara</string>
|
||||
<string name="contact_you_shared_link_with_wont_be_able_to_connect">¡El contacto con el que has compartido este enlace NO podrá conectarse!</string>
|
||||
<string name="show_QR_code">Mostrar código QR</string>
|
||||
<string name="this_link_is_not_a_valid_connection_link">¡El enlace no es un enlace de conexión válido!</string>
|
||||
<string name="this_QR_code_is_not_a_link">¡El código QR no es un enlace!</string>
|
||||
<string name="share_invitation_link">Compartir enlace de invitación</string>
|
||||
<string name="share_invitation_link">Compartir enlace de un uso</string>
|
||||
<string name="update_network_session_mode_question">¿Actualizar el modo de aislamiento de transporte\?</string>
|
||||
<string name="icon_descr_speaker_on">Altavoz activado</string>
|
||||
<string name="stop_chat_to_enable_database_actions">Detén Chat para habilitar las acciones sobre la base de datos.</string>
|
||||
<string name="stop_chat_to_enable_database_actions">Para habilitar las acciones sobre la base de datos, previamente debes detener Chat</string>
|
||||
<string name="connection_you_accepted_will_be_cancelled">¡La conexión que has aceptado se cancelará!</string>
|
||||
<string name="database_initialization_error_desc">La base de datos no funciona correctamente. Pulsa para obtener más información</string>
|
||||
<string name="database_initialization_error_desc">La base de datos no funciona correctamente. Pulsa para saber más</string>
|
||||
<string name="moderate_message_will_be_marked_warning">El mensaje será marcado como moderado para todos los miembros.</string>
|
||||
<string name="next_generation_of_private_messaging">La próxima generación de mensajería privada</string>
|
||||
<string name="delete_files_and_media_desc">Esta acción no se puede deshacer. Se eliminarán todos los archivos y multimedia recibidos y enviados. Las imágenes de baja resolución permanecerán.</string>
|
||||
<string name="enable_automatic_deletion_message">Esta acción no se puede deshacer. Se eliminarán los mensajes enviados y recibidos anteriores a la selección. Puede tardar varios minutos.</string>
|
||||
<string name="messages_section_description">Esta configuración se aplica a los mensajes en tu perfil actual</string>
|
||||
<string name="messages_section_description">Esta configuración se aplica a los mensajes del perfil actual</string>
|
||||
<string name="this_string_is_not_a_connection_link">¡Esta cadena no es un enlace de conexión!</string>
|
||||
<string name="to_preserve_privacy_simplex_has_background_service_instead_of_push_notifications_it_uses_a_few_pc_battery">Para preservar tu privacidad, en lugar de notificaciones automáticas la aplicación cuenta con un <b>servicio en segundo plano<xliff:g id="appName">SimpleX</xliff:g></b>, utiliza un pequeño porcentaje de la batería al día.</string>
|
||||
<string name="icon_descr_settings">Configuración</string>
|
||||
<string name="icon_descr_speaker_off">Altavoz apagado</string>
|
||||
<string name="icon_descr_speaker_off">Altavoz desactivado</string>
|
||||
<string name="add_contact_or_create_group">Inciar chat nuevo</string>
|
||||
<string name="stop_chat_to_export_import_or_delete_chat_database">Detén Chat para poder exportar, importar o eliminar la base de datos. No puedes recibir ni enviar mensajes mientras Chat esté detenido.</string>
|
||||
<string name="stop_chat_to_export_import_or_delete_chat_database">Para poder exportar, importar o eliminar la base de datos primero debes detener Chat. Durante el tiempo que esté detenido no podrás recibir ni enviar mensajes.</string>
|
||||
<string name="thank_you_for_installing_simplex">Gracias por instalar <xliff:g id="appNameFull">SimpleX Chat</xliff:g>!</string>
|
||||
<string name="to_protect_privacy_simplex_has_ids_for_queues">Para proteger la privacidad, en lugar de los identificadores de usuario que utilizan el resto de plataformas, <xliff:g id="appName">SimpleX</xliff:g> dispone de identificadores para las colas de mensajes, independientes para cada uno de tus contactos.</string>
|
||||
<string name="la_notice_to_protect_your_information_turn_on_simplex_lock_you_will_be_prompted_to_complete_authentication_before_this_feature_is_enabled">Para proteger tu información, activa Bloqueo SimpleX.
|
||||
@@ -786,7 +782,7 @@
|
||||
<string name="ntf_channel_calls">Llamadas de chat SimpleX</string>
|
||||
<string name="notifications_mode_periodic">Se ejecuta periódicamente</string>
|
||||
<string name="notification_preview_mode_message_desc">Se muestran el nombre del contacto y el mensaje</string>
|
||||
<string name="notification_preview_mode_contact_desc">Se muestra solo el nombre del contacto</string>
|
||||
<string name="notification_preview_mode_contact_desc">Se muestra sólo el nombre del contacto</string>
|
||||
<string name="auth_simplex_lock_turned_on">Bloqueo SimpleX activado</string>
|
||||
<string name="auth_stop_chat">Detener chat</string>
|
||||
<string name="moderate_message_will_be_deleted_warning">El mensaje se eliminará para todos los miembros.</string>
|
||||
@@ -801,8 +797,8 @@
|
||||
<string name="alert_message_no_group">Este grupo ya no existe.</string>
|
||||
<string name="incognito_info_find">Para conocer el perfil usado en una conexión en modo incógnito, pulsa el nombre del contacto o del grupo en la parte superior del chat.</string>
|
||||
<string name="accept_feature_set_1_day">Establecer 1 día</string>
|
||||
<string name="v4_4_french_interface_descr">Agradecimientos a los usuarios. ¡Contribuye a través de Weblate!</string>
|
||||
<string name="v4_5_italian_interface_descr">Agradecimientos a los usuarios. ¡Contribuye a través de Weblate!</string>
|
||||
<string name="v4_4_french_interface_descr">¡Gracias a los colaboradores! Contribuye a través de Weblate.</string>
|
||||
<string name="v4_5_italian_interface_descr">¡Gracias a los colaboradores! Contribuye a través de Weblate.</string>
|
||||
<string name="v4_5_private_filenames_descr">Para proteger la zona horaria, los archivos de imagen/voz usan la hora UTC.</string>
|
||||
<string name="v4_5_transport_isolation">Aislamiento de transporte</string>
|
||||
<string name="to_share_with_your_contact">(para compartir con tu contacto)</string>
|
||||
@@ -812,7 +808,7 @@
|
||||
<string name="smp_servers_test_server">Probar servidor</string>
|
||||
<string name="smp_servers_test_servers">Probar servidores</string>
|
||||
<string name="star_on_github">Estrella en GitHub</string>
|
||||
<string name="smp_servers_per_user">Los servidores para nuevas conexiones de tu perfil de Chat actual</string>
|
||||
<string name="smp_servers_per_user">Lista de servidores para las conexiones nuevas de tu perfil actual</string>
|
||||
<string name="network_disable_socks">¿Usar conexión directa a Internet\?</string>
|
||||
<string name="update_onion_hosts_settings_question">¿Actualizar la configuración de los hosts .onion\?</string>
|
||||
<string name="profile_is_only_shared_with_your_contacts">El perfil sólo se comparte con tus contactos.</string>
|
||||
@@ -822,7 +818,7 @@
|
||||
<string name="stop_chat_question">¿Detener Chat\?</string>
|
||||
<string name="chat_item_ttl_seconds">%s segundo(s)</string>
|
||||
<string name="group_invitation_tap_to_join">Pulsa para unirse</string>
|
||||
<string name="rcv_group_event_updated_group_profile">perfil de grupo actualizado</string>
|
||||
<string name="rcv_group_event_updated_group_profile">ha actualizado el perfil del grupo</string>
|
||||
<string name="network_option_tcp_connection_timeout">Tiempo de espera de la conexión TCP agotado</string>
|
||||
<string name="theme">Tema</string>
|
||||
<string name="set_group_preferences">Establece preferencias de grupo</string>
|
||||
@@ -847,24 +843,23 @@
|
||||
<string name="database_backup_can_be_restored">El intento de cambiar la contraseña de la base de datos no se ha completado.</string>
|
||||
<string name="chat_help_tap_button">Pulsa el botón</string>
|
||||
<string name="to_start_a_new_chat_help_header">Para iniciar un chat nuevo</string>
|
||||
<string name="switch_receiving_address">Cambiar dirección de recepción</string>
|
||||
<string name="switch_receiving_address">Cambiar servidor de recepción</string>
|
||||
<string name="group_is_decentralized">El grupo está totalmente descentralizado: sólo es visible para los miembros.</string>
|
||||
<string name="to_connect_via_link_title">Para conectarse mediante enlace</string>
|
||||
<string name="to_connect_via_link_title">Para conectarte mediante enlace</string>
|
||||
<string name="smp_servers_test_failed">¡Error en prueba del servidor!</string>
|
||||
<string name="smp_servers_test_some_failed">Algunos servidores no superaron la prueba:</string>
|
||||
<string name="smp_servers_use_server">Usar servidor</string>
|
||||
<string name="smp_servers_use_server_for_new_conn">Usar para conexiones nuevas</string>
|
||||
<string name="theme_system">Sistema</string>
|
||||
<string name="description_via_one_time_link">mediante enlace de un uso</string>
|
||||
<string name="your_chats">Tus chats</string>
|
||||
<string name="description_via_one_time_link">mediante enlace de un solo uso</string>
|
||||
<string name="your_chats">Mis chats</string>
|
||||
<string name="voice_message_send_text">Mensaje de voz…</string>
|
||||
<string name="your_contact_address">Mi dirección de contacto</string>
|
||||
<string name="icon_descr_video_off">Desactivar vídeo</string>
|
||||
<string name="icon_descr_video_on">Activar vídeo</string>
|
||||
<string name="wrong_passphrase">Contraseña de base de datos incorrecta</string>
|
||||
<string name="wrong_passphrase_title">¡Contraseña incorrecta!</string>
|
||||
<string name="youve_accepted_group_invitation_connecting_to_inviting_group_member">Te has unido a este grupo. Conectando con miembro del grupo invitado.</string>
|
||||
<string name="alert_title_cant_invite_contacts_descr">Estás usando un perfil incógnito para este grupo, por tanto para evitar compartir tu perfil principal no se permite invitar contactos</string>
|
||||
<string name="youve_accepted_group_invitation_connecting_to_inviting_group_member">Te has unido a este grupo. Conectando con el miembro que emite la invitacíon.</string>
|
||||
<string name="alert_title_cant_invite_contacts_descr">Estás usando un perfil incógnito para este grupo, por tanto para evitar compartir tu perfil principal no se permite invitar a contactos</string>
|
||||
<string name="you_are_invited_to_group">Has sido invitado al grupo</string>
|
||||
<string name="v4_3_voice_messages">Mensajes de voz</string>
|
||||
<string name="v4_3_irreversible_message_deletion_desc">Tus contactos pueden permitir la eliminación completa de mensajes.</string>
|
||||
@@ -872,11 +867,11 @@
|
||||
<string name="voice_messages">Mensajes de voz</string>
|
||||
<string name="voice_messages_are_prohibited">Los mensajes de voz no están permitidos en este grupo.</string>
|
||||
<string name="v4_4_verify_connection_security">Comprobar la seguridad de la conexión</string>
|
||||
<string name="you_are_already_connected_to_vName_via_this_link">¡Ya estás conectado a <xliff:g id="contactName" example="Alice">%1$s! </xliff:g>.</string>
|
||||
<string name="you_are_already_connected_to_vName_via_this_link">¡Ya estás conectado a <xliff:g id="contactName" example="Alice">%1$s</xliff:g>.</string>
|
||||
<string name="welcome">¡Bienvenido!</string>
|
||||
<string name="your_chat_profile_will_be_sent_to_your_contact">Tu perfil Chat será enviado
|
||||
\na tu contacto</string>
|
||||
<string name="your_ICE_servers">Tus servidores ICE</string>
|
||||
<string name="your_ICE_servers">Mis servidores ICE</string>
|
||||
<string name="you_rejected_group_invitation">Has rechazado la invitación del grupo.</string>
|
||||
<string name="snd_group_event_changed_member_role">has cambiado el rol de %s a %s</string>
|
||||
<string name="call_connection_via_relay">mediante relay</string>
|
||||
@@ -886,9 +881,8 @@
|
||||
<string name="webrtc_ice_servers">Servidores WebRTC ICE</string>
|
||||
<string name="contact_wants_to_connect_via_call"><xliff:g id="contactName" example="Alice">%1$s</xliff:g> quiere conectarse contigo mediante</string>
|
||||
<string name="failed_to_create_user_duplicate_desc">Tienes un perfil de chat con el mismo nombre mostrado. Debes elegir otro nombre.</string>
|
||||
<string name="you_can_also_connect_by_clicking_the_link">También puedes conectarte haciendo clic en el enlace. Si se abre en el navegador, haz clic en <b>Abrir en aplicación móvil</b>.</string>
|
||||
<string name="you_can_also_connect_by_clicking_the_link">También puedes conectarte pulsando el enlace. Si se abre en el navegador, pulsa en <b>Abrir en aplicación móvil</b>.</string>
|
||||
<string name="you_can_connect_to_simplex_chat_founder">Puedes <font color="#0088ff">ponerte en contacto con los desarrolladores de <xliff:g id="appNameFull">SimpleX Chat</xliff:g> para consultas y para recibir actualizaciones</font>.</string>
|
||||
<string name="you_can_share_your_address_anybody_will_be_able_to_connect">Puedes compartir tu dirección como enlace o como código QR: cualquiera podrá conectarse contigo. Si lo eliminas más tarde tus contactos no se perderán.</string>
|
||||
<string name="observer_cant_send_message_title">¡No puedes enviar mensajes!</string>
|
||||
<string name="you_can_use_markdown_to_format_messages__prompt">Puedes usar la sintaxis markdown para dar formato a los mensajes:</string>
|
||||
<string name="you_must_use_the_most_recent_version_of_database">Debes usar la versión más reciente de tu base de datos ÚNICAMENTE en un dispositivo, de lo contrario podrías dejar de recibir mensajes de algunos contactos.</string>
|
||||
@@ -901,7 +895,7 @@
|
||||
<string name="you_will_be_connected_when_your_contacts_device_is_online">Te conectarás cuando el dispositivo de tu contacto esté en línea, por favor espera o compruébalo más tarde.</string>
|
||||
<string name="auth_you_will_be_required_to_authenticate_when_you_start_or_resume">Se te pedirá identificarte cuándo inicies o continues usando la aplicación tras 30 segundos en segundo plano.</string>
|
||||
<string name="invite_prohibited_description">Estás intentando invitar a un contacto con el que compartes un perfil incógnito a un grupo en el que usas tu perfil principal</string>
|
||||
<string name="simplex_link_mode_browser">mediante navegador</string>
|
||||
<string name="simplex_link_mode_browser">Mediante navegador</string>
|
||||
<string name="simplex_link_connection">mediante <xliff:g id="serverHost" example="smp.simplex.im">%1$s</xliff:g></string>
|
||||
<string name="simplex_service_notification_title">Servicio <xliff:g id="appNameFull">SimpleX Chat</xliff:g></string>
|
||||
<string name="personal_welcome">¡Bienvenido <xliff:g>%1$s</xliff:g> !</string>
|
||||
@@ -909,31 +903,30 @@
|
||||
<string name="waiting_for_file">Esperando archivo</string>
|
||||
<string name="icon_descr_waiting_for_image">Esperando imagen</string>
|
||||
<string name="voice_message_with_duration">Mensaje de voz (<xliff:g id="duration">%1$s</xliff:g> )</string>
|
||||
<string name="network_use_onion_hosts_prefer">Cuando esté disponible</string>
|
||||
<string name="network_use_onion_hosts_prefer">Si disponible</string>
|
||||
<string name="we_do_not_store_contacts_or_messages_on_servers">No almacenamos ninguno de tus contactos o mensajes (una vez entregados) en los servidores.</string>
|
||||
<string name="you_are_invited_to_group_join_to_connect_with_group_members">Has sido invitado al grupo. Únete para conectarte con los miembros del grupo.</string>
|
||||
<string name="snd_group_event_member_deleted">has eliminado <xliff:g id="member profile" example="alice (Alice)">%1$s</xliff:g></string>
|
||||
<string name="snd_group_event_member_deleted">has expulsado a <xliff:g id="member profile" example="alice (Alice)">%1$s</xliff:g></string>
|
||||
<string name="group_info_member_you">Tú: <xliff:g id="group_info_you">%1$s</xliff:g></string>
|
||||
<string name="you_can_share_group_link_anybody_will_be_able_to_connect">Puedes compartir un enlace o un código QR: cualquiera podrá unirse al grupo. Si lo eliminas más tarde los miembros del grupo no se perderán.</string>
|
||||
<string name="incognito_info_share">Cuando compartes un perfil incógnito con alguien, este perfil también se usará para los grupos a los que te inviten.</string>
|
||||
<string name="your_preferences">Tus preferencias</string>
|
||||
<string name="your_preferences">Mis preferencias</string>
|
||||
<string name="v4_2_auto_accept_contact_requests_desc">Con mensaje de bienvenida opcional.</string>
|
||||
<string name="you_are_observer">Tu rol es observador</string>
|
||||
<string name="verify_security_code">Comprobar código de seguridad</string>
|
||||
<string name="you_accepted_connection">Has aceptado la conexión</string>
|
||||
<string name="you_invited_your_contact">Has invitado a tu contacto</string>
|
||||
<string name="you_will_be_connected_when_group_host_device_is_online">Te conectarás al grupo cuando el dispositivo del anfitrión esté en línea, por favor espera o compruébalo más tarde.</string>
|
||||
<string name="show_QR_code_for_your_contact_to_scan_from_the_app__multiline">Tu contacto puede escanear el código QR desde la aplicación.</string>
|
||||
<string name="your_settings">Mi configuración</string>
|
||||
<string name="your_SMP_servers">Tus servidores SMP</string>
|
||||
<string name="you_will_be_connected_when_group_host_device_is_online">Te conectarás al grupo cuando el dispositivo anfitrión esté en línea, por favor espera o compruébalo más tarde.</string>
|
||||
<string name="your_settings">Configuración</string>
|
||||
<string name="your_SMP_servers">Mis servidores SMP</string>
|
||||
<string name="you_control_your_chat">¡Tú controlas tu chat!</string>
|
||||
<string name="your_profile_is_stored_on_your_device">Tu perfil, contactos y mensajes entregados se almacenan en tu dispositivo.</string>
|
||||
<string name="callstate_waiting_for_answer">esperando respuesta…</string>
|
||||
<string name="callstate_waiting_for_confirmation">esperando confirmación…</string>
|
||||
<string name="onboarding_notifications_mode_off">Cuando la aplicación se está ejecutando</string>
|
||||
<string name="icon_descr_video_call">Videollamada</string>
|
||||
<string name="your_calls">Tus llamadas</string>
|
||||
<string name="your_ice_servers">Tus servidores ICE</string>
|
||||
<string name="your_calls">Mis llamadas</string>
|
||||
<string name="your_ice_servers">Mis servidores ICE</string>
|
||||
<string name="your_privacy">Privacidad</string>
|
||||
<string name="settings_section_title_you">MIS DATOS</string>
|
||||
<string name="your_chat_database">Base de datos Chat</string>
|
||||
@@ -954,13 +947,13 @@
|
||||
<string name="connected_to_server_to_receive_messages_from_contact">Estás conectado al servidor utilizado para recibir mensajes de este contacto.</string>
|
||||
<string name="description_via_contact_address_link">mediante enlace de dirección de contacto</string>
|
||||
<string name="description_via_group_link">mediante enlace de grupo</string>
|
||||
<string name="description_you_shared_one_time_link">has compartido enlace de un uso</string>
|
||||
<string name="description_you_shared_one_time_link_incognito">has compartido enlace de un uso en módo incógnito</string>
|
||||
<string name="description_you_shared_one_time_link">has compartido enlace de un solo uso</string>
|
||||
<string name="description_you_shared_one_time_link_incognito">has compartido enlace de un solo uso en módo incógnito</string>
|
||||
<string name="you_have_no_chats">No tienes chats</string>
|
||||
<string name="contact_sent_large_file">El contacto ha enviado un archivo mayor al máximo admitido (<xliff:g id="maxFileSize">%1$s</xliff:g> ).</string>
|
||||
<string name="integrity_msg_skipped"><xliff:g id="connection ID" example="1">%1$d</xliff:g> mensaje(s) omitido(s)</string>
|
||||
<string name="you_will_stop_receiving_messages_from_this_group_chat_history_will_be_preserved">Dejarás de recibir mensajes de este grupo. El historial del chat se conservará.</string>
|
||||
<string name="view_security_code">Ver código de seguridad</string>
|
||||
<string name="view_security_code">Mostrar código de seguridad</string>
|
||||
<string name="you_need_to_allow_to_send_voice">Para poder enviar mensajes de voz antes debes permitir que tu contacto pueda enviarlos.</string>
|
||||
<string name="voice_messages_prohibited">¡Mensajes de voz prohibidos!</string>
|
||||
<string name="group_main_profile_sent">Tu perfil Chat será enviado a los miembros del grupo</string>
|
||||
@@ -969,14 +962,13 @@
|
||||
<string name="icon_descr_simplex_team">Equipo <xliff:g id="appName">SimpleX</xliff:g></string>
|
||||
<string name="your_profile_will_be_sent">Tu perfil Chat se enviará a tu contacto</string>
|
||||
<string name="your_chat_profiles">Mis perfiles</string>
|
||||
<string name="your_simplex_contact_address">Mi dirección de contacto <xliff:g id="appName">SimpleX</xliff:g></string>
|
||||
<string name="your_simplex_contact_address">Mi dirección SimpleX</string>
|
||||
<string name="smp_servers_your_server">Tu servidor</string>
|
||||
<string name="smp_servers_your_server_address">Dirección de tu servidor</string>
|
||||
<string name="section_title_welcome_message">MENSAJE DE BIENVENIDA</string>
|
||||
<string name="your_current_profile">Tu perfil actual</string>
|
||||
<string name="your_profile_is_stored_on_device_and_shared_only_with_contacts_simplex_cannot_see_it">Tu perfil se almacena en tu dispositivo y sólo se comparte con tus contactos. Los servidores <xliff:g id="appName">SimpleX</xliff:g> no pueden ver tu perfil.</string>
|
||||
<string name="language_system">Sistema</string>
|
||||
<string name="button_add_welcome_message">Agregar mensaje de bienvenida</string>
|
||||
<string name="button_add_welcome_message">Añadir mensaje de bienvenida</string>
|
||||
<string name="v4_6_audio_video_calls">Llamadas y videollamadas</string>
|
||||
<string name="smp_save_servers_question">¿Guardar servidores\?</string>
|
||||
<string name="hide_profile">Ocultar perfil</string>
|
||||
@@ -989,7 +981,7 @@
|
||||
<string name="enter_password_to_show">Introduce la contraseña</string>
|
||||
<string name="user_hide">Ocultar</string>
|
||||
<string name="user_mute">Silenciar</string>
|
||||
<string name="save_and_update_group_profile">Guardar y actualizar perfil del grupo</string>
|
||||
<string name="save_and_update_group_profile">Guardar y actualizar perfil de grupo</string>
|
||||
<string name="tap_to_activate_profile">Pulsa sobre un perfil para activarlo.</string>
|
||||
<string name="should_be_at_least_one_visible_profile">Debe haber al menos un perfil de usuario visible.</string>
|
||||
<string name="user_unhide">Mostrar</string>
|
||||
@@ -1002,13 +994,13 @@
|
||||
<string name="v4_6_group_moderation">Moderación de grupos</string>
|
||||
<string name="v4_6_hidden_chat_profiles">Perfiles Chat ocultos</string>
|
||||
<string name="v4_6_hidden_chat_profiles_descr">¡Protege tus perfiles con contraseña!</string>
|
||||
<string name="v4_6_audio_video_calls_descr">Soporte bluetooth y otras mejoras.</string>
|
||||
<string name="v4_6_group_welcome_message_descr">¡Establece el mensaje mostrado a los miembros nuevos!</string>
|
||||
<string name="v4_6_audio_video_calls_descr">Ahora con soporte bluetooth y otras mejoras.</string>
|
||||
<string name="v4_6_group_welcome_message_descr">¡Guarda un mensaje para ser mostrado a los miembros nuevos!</string>
|
||||
<string name="v4_6_chinese_spanish_interface">Interfaz en chino y español</string>
|
||||
<string name="v4_6_chinese_spanish_interface_descr">Agradecimientos a los usuarios. ¡Contribuye a través de Weblate!</string>
|
||||
<string name="v4_6_chinese_spanish_interface_descr">¡Gracias a los colaboradores! Contribuye a través de Weblate.</string>
|
||||
<string name="error_updating_user_privacy">Error actualizando la privacidad de usuario</string>
|
||||
<string name="confirm_password">Confirmar contraseña</string>
|
||||
<string name="v4_6_reduced_battery_usage">Consumo de batería reducido aun más</string>
|
||||
<string name="v4_6_reduced_battery_usage">Reducción consumo de batería</string>
|
||||
<string name="v4_6_group_welcome_message">Mensaje de bienvenida en grupos</string>
|
||||
<string name="v4_6_reduced_battery_usage_descr">¡Más mejoras en camino!</string>
|
||||
<string name="hidden_profile_password">Contraseña de perfil oculto</string>
|
||||
@@ -1016,9 +1008,9 @@
|
||||
<string name="user_unmute">Activar audio</string>
|
||||
<string name="you_can_hide_or_mute_user_profile">Puedes ocultar o silenciar un perfil. Mantenlo pulsado para abrir el menú.</string>
|
||||
<string name="you_will_still_receive_calls_and_ntfs">Seguirás recibiendo llamadas y notificaciones de los perfiles silenciados cuando estén activos.</string>
|
||||
<string name="v4_6_group_moderation_descr">Ahora los administradores pueden
|
||||
<string name="v4_6_group_moderation_descr">Ahora los administradores pueden:
|
||||
\n- borrar mensajes de los miembros.
|
||||
\n- desactivar el rol a miembros (a rol \"observador\")</string>
|
||||
\n- desactivar el rol a miembros (pasando a rol \"observador\")</string>
|
||||
<string name="to_reveal_profile_enter_password">Para hacer visible tu perfil oculto, introduce la contraseña completa en el campo de búsqueda de la página Tus perfiles Chat.</string>
|
||||
<string name="database_upgrade">Actualización de la base de datos</string>
|
||||
<string name="database_downgrade">Volviendo a versión anterior de la base de datos</string>
|
||||
@@ -1032,7 +1024,7 @@
|
||||
<string name="confirm_database_upgrades">Confirmar actualizaciones de la bases de datos</string>
|
||||
<string name="mtr_error_no_down_migration">la versión de la base de datos es más reciente que la aplicación, pero no hay migración hacia versión anterior para: %s</string>
|
||||
<string name="settings_section_title_experimenta">EXPERIMENTAL</string>
|
||||
<string name="developer_options">ID de base de datos y opción de aislamiento de transporte.</string>
|
||||
<string name="developer_options">IDs de la base de datos y opciónes de aislamiento de transporte.</string>
|
||||
<string name="file_will_be_received_when_contact_completes_uploading">El archivo se recibirá cuando tu contacto termine de subirlo.</string>
|
||||
<string name="image_will_be_received_when_contact_completes_uploading">La imagen se recibirá cuando tu contacto termine de subirla.</string>
|
||||
<string name="show_developer_options">Mostrar opciones de desarrollador</string>
|
||||
@@ -1050,7 +1042,7 @@
|
||||
<string name="videos_limit_title">¡Demasiados vídeos!</string>
|
||||
<string name="icon_descr_video_snd_complete">Vídeo enviado</string>
|
||||
<string name="video_will_be_received_when_contact_completes_uploading">El vídeo se recibirá cuando tu contacto termine de subirlo.</string>
|
||||
<string name="videos_limit_desc">Solo se pueden enviar 10 vídeos de forma simultánea</string>
|
||||
<string name="videos_limit_desc">Sólo se pueden enviar 10 vídeos de forma simultánea</string>
|
||||
<string name="icon_descr_waiting_for_video">Esperando el vídeo</string>
|
||||
<string name="error_saving_xftp_servers">Error guardando servidores SMP</string>
|
||||
<string name="error_loading_xftp_servers">Error cargando servidores XFTP</string>
|
||||
@@ -1062,7 +1054,7 @@
|
||||
<string name="smp_server_test_delete_file">Eliminar archivo</string>
|
||||
<string name="smp_server_test_upload_file">Subir archivo</string>
|
||||
<string name="xftp_servers">Servidores XFTP</string>
|
||||
<string name="your_XFTP_servers">Tus servidores XFTP</string>
|
||||
<string name="your_XFTP_servers">Mis servidores XFTP</string>
|
||||
<string name="port_verb">Puerto</string>
|
||||
<string name="network_proxy_port">puerto %d</string>
|
||||
<string name="disable_onion_hosts_when_not_supported">Establece <i>Usar hosts .onion</i> en No si el proxy SOCKS no los admite.</string>
|
||||
@@ -1071,31 +1063,31 @@
|
||||
<string name="host_verb">Host</string>
|
||||
<string name="network_socks_proxy_settings">Configuración proxy SOCKS</string>
|
||||
<string name="la_authenticate">Autenticar</string>
|
||||
<string name="la_current_app_passcode">Código de acceso actual</string>
|
||||
<string name="la_current_app_passcode">Código de acceso</string>
|
||||
<string name="authentication_cancelled">Autenticación cancelada</string>
|
||||
<string name="change_lock_mode">Cambiar el modo de bloqueo</string>
|
||||
<string name="la_seconds">%d segundos</string>
|
||||
<string name="la_auth_failed">Error de autenticación</string>
|
||||
<string name="la_change_app_passcode">Cambiar el código de acceso</string>
|
||||
<string name="la_change_app_passcode">Cambiar código de acceso</string>
|
||||
<string name="passcode_not_changed">¡Código de acceso no cambiado!</string>
|
||||
<string name="la_lock_mode_system">Autenticación del sistema</string>
|
||||
<string name="la_no_app_password">Sin código de acceso de la aplicación</string>
|
||||
<string name="la_lock_mode_passcode">Campo de código de acceso</string>
|
||||
<string name="la_lock_mode">Modo Bloqueo SimpleX</string>
|
||||
<string name="la_could_not_be_verified">No has podido ser verificado. Inténtelo de nuevo.</string>
|
||||
<string name="la_could_not_be_verified">No has podido ser autenticado. Inténtalo de nuevo.</string>
|
||||
<string name="la_minutes">%d minutos</string>
|
||||
<string name="la_enter_app_passcode">Introducir el código de acceso</string>
|
||||
<string name="la_enter_app_passcode">Introduce código</string>
|
||||
<string name="la_immediately">Inmediatamente</string>
|
||||
<string name="la_please_remember_to_store_password">Por favor, recuerda y guarda la contraseña en un lugar seguro. ¡No hay ninguna manera de recuperar una contraseña perdida!</string>
|
||||
<string name="la_please_remember_to_store_password">Por favor, recuerda y guarda el código de acceso en un lugar seguro. ¡No hay ninguna manera de recuperar un código perdido!</string>
|
||||
<string name="lock_not_enabled">¡Bloqueo SimpleX no activado!</string>
|
||||
<string name="you_can_turn_on_lock">Puedes activar el Bloqueo SimpleX a través de Configuración.</string>
|
||||
<string name="confirm_passcode">Confirmar el código de acceso</string>
|
||||
<string name="confirm_passcode">Confirma código</string>
|
||||
<string name="enable_lock">Activar bloqueo</string>
|
||||
<string name="lock_after">Bloquear después de</string>
|
||||
<string name="lock_mode">Modo de bloqueo</string>
|
||||
<string name="submit_passcode">Enviar</string>
|
||||
<string name="incorrect_passcode">Código de acceso incorrecto</string>
|
||||
<string name="new_passcode">Nuevo código de acceso</string>
|
||||
<string name="new_passcode">Código nuevo</string>
|
||||
<string name="la_mode_passcode">Código de acceso</string>
|
||||
<string name="passcode_changed">¡Código de acceso cambiado!</string>
|
||||
<string name="passcode_set">¡Código de acceso guardado!</string>
|
||||
@@ -1122,20 +1114,152 @@
|
||||
<string name="stop_file__confirm">Detener</string>
|
||||
<string name="stop_rcv_file__title">¿Dejar de recibir el archivo\?</string>
|
||||
<string name="stop_snd_file__title">¿Dejar de enviar el archivo\?</string>
|
||||
<string name="allow_calls_only_if">Se permiten llamadas sólo si tu contacto también las permite.</string>
|
||||
<string name="allow_calls_only_if">Se permiten las llamadas pero sólo si tu contacto también las permite.</string>
|
||||
<string name="allow_your_contacts_to_call">Permites que tus contactos puedan llamarte.</string>
|
||||
<string name="audio_video_calls">Llamadas/Videollamadas</string>
|
||||
<string name="calls_prohibited_with_this_contact">Las llamadas/videollamadas no están permitidas.</string>
|
||||
<string name="audio_video_calls">Llamadas y videollamadas</string>
|
||||
<string name="calls_prohibited_with_this_contact">Las llamadas y videollamadas no están permitidas.</string>
|
||||
<string name="available_in_v51">"
|
||||
\nDisponible en v5.1"</string>
|
||||
<string name="both_you_and_your_contact_can_make_calls">Tanto tú como tu contacto podéis realizar llamadas.</string>
|
||||
<string name="only_you_can_make_calls">Solo tú puedes realizar llamadas.</string>
|
||||
<string name="only_you_can_make_calls">Sólo tú puedes realizar llamadas.</string>
|
||||
<string name="only_your_contact_can_make_calls">Sólo tu contacto puede realizar llamadas.</string>
|
||||
<string name="prohibit_calls">Prohibir las llamadas/videollamadas.</string>
|
||||
<string name="v5_0_app_passcode">Código de acceso a la aplicación</string>
|
||||
<string name="v5_0_polish_interface">Interfaz polaco</string>
|
||||
<string name="prohibit_calls">No se permiten llamadas y videollamadas.</string>
|
||||
<string name="v5_0_app_passcode">Código de acceso de la aplicación</string>
|
||||
<string name="v5_0_polish_interface">Interfaz en polaco</string>
|
||||
<string name="v5_0_app_passcode_descr">Úsalo en lugar de la autenticación del sistema.</string>
|
||||
<string name="v5_0_polish_interface_descr">Agradecimientos a los usuarios. ¡Contribuye a través de Weblate!</string>
|
||||
<string name="v5_0_polish_interface_descr">¡Gracias a los colaboradores! Contribuye a través de Weblate.</string>
|
||||
<string name="v5_0_large_files_support">Vídeos y archivos de hasta 1Gb</string>
|
||||
<string name="v5_0_large_files_support_descr">¡Rápido y sin tener que esperar a que el remitente esté en línea!</string>
|
||||
<string name="v5_0_large_files_support_descr">¡Rápido y sin necesidad de esperar a que el remitente esté en línea!</string>
|
||||
<string name="auth_open_chat_profiles">Abrir perfiles de chat</string>
|
||||
<string name="learn_more">Más información</string>
|
||||
<string name="if_you_cant_meet_in_person">Si no puedes reunirte en persona, **muestra el código QR por videollamada**, o comparte el enlace.</string>
|
||||
<string name="scan_qr_to_connect_to_contact">Para conectarse, tu contacto puede escanear el código QR o usar el enlace en la aplicación.</string>
|
||||
<string name="create_simplex_address">Crear dirección SimpleX</string>
|
||||
<string name="auto_accept_contact">Auto aceptar</string>
|
||||
<string name="group_welcome_preview">Vista previa</string>
|
||||
<string name="opening_database">Abriendo base de datos…</string>
|
||||
<string name="error_setting_address">Error al introducir la dirección</string>
|
||||
<string name="read_more_in_user_guide_with_link">Más información en la <font color="#0088ff">Guía de usuario</font>.</string>
|
||||
<string name="one_time_link_short">Enlace un uso</string>
|
||||
<string name="simplex_address">Dirección SimpleX</string>
|
||||
<string name="you_can_accept_or_reject_connection">Cuando alguien solicite conectarse podrás aceptar o rechazar su solicitud.</string>
|
||||
<string name="share_address">Compartir dirección</string>
|
||||
<string name="enter_welcome_message">Introduce mensaje de bienvenida…</string>
|
||||
<string name="theme_simplex">SimpleX</string>
|
||||
<string name="color_primary_variant">Color adicional</string>
|
||||
<string name="color_secondary_variant">Secundario adicional</string>
|
||||
<string name="color_background">Fondo</string>
|
||||
<string name="export_theme">Exportar tema</string>
|
||||
<string name="color_surface">Menús y alertas</string>
|
||||
<string name="add_address_to_your_profile">Añade la dirección a tu perfil para que tus contactos puedan compartirla con otros. La actualización del perfil se enviará a tus contactos.</string>
|
||||
<string name="learn_more_about_address">Acerca de dirección SimpleX</string>
|
||||
<string name="address_section_title">Dirección</string>
|
||||
<string name="all_your_contacts_will_remain_connected_update_sent">Todos tus contactos permanecerán conectados. La actualización del perfil se enviará a tus contactos.</string>
|
||||
<string name="continue_to_next_step">Continuar</string>
|
||||
<string name="dark_theme">Tema oscuro</string>
|
||||
<string name="customize_theme_title">Personalizar tema</string>
|
||||
<string name="enter_welcome_message_optional">Introduce mensaje de bienvenida… (opcional)</string>
|
||||
<string name="create_address_and_let_people_connect">Crear una dirección para que la gente se pueda conectar contigo.</string>
|
||||
<string name="dont_create_address">No crear dirección</string>
|
||||
<string name="email_invite_body">¡Hola!
|
||||
\nConecta conmigo a través de SimpleX Chat: %s</string>
|
||||
<string name="import_theme">Importar tema</string>
|
||||
<string name="import_theme_error">Error al importar tema</string>
|
||||
<string name="invite_friends">Invitar amigos</string>
|
||||
<string name="email_invite_subject">Hablemos en SimpleX Chat</string>
|
||||
<string name="import_theme_error_desc">Asegúrate de que el archivo tiene la sintaxis YAML correcta. Exporta el tema para tener un ejemplo de la estructura del archivo de tema.</string>
|
||||
<string name="profile_update_will_be_sent_to_contacts">La actualización del perfil se enviará a tus contactos.</string>
|
||||
<string name="color_received_message">Mensaje recibido</string>
|
||||
<string name="save_auto_accept_settings">Guardar configuración de auto aceptar</string>
|
||||
<string name="you_can_share_your_address">Puedes compartir tu dirección como enlace o como código QR: cualquiera podrá conectarse contigo.</string>
|
||||
<string name="save_settings_question">¿Guardar configuración\?</string>
|
||||
<string name="color_secondary">Secundario</string>
|
||||
<string name="color_sent_message">Mensaje enviado</string>
|
||||
<string name="stop_sharing">Dejar de compartir</string>
|
||||
<string name="stop_sharing_address">¿Dejar de compartir la dirección\?</string>
|
||||
<string name="theme_colors_section_title">COLORES DEL TEMA</string>
|
||||
<string name="you_can_create_it_later">Puedes crearlo más tarde</string>
|
||||
<string name="share_address_with_contacts_question">¿Compartir la dirección con los contactos\?</string>
|
||||
<string name="share_with_contacts">Compartir con contactos</string>
|
||||
<string name="color_title">Título</string>
|
||||
<string name="you_can_share_this_address_with_your_contacts">Puedes compartir esta dirección con tus contactos para que puedan conectar con %s.</string>
|
||||
<string name="your_contacts_will_see_it">Tus contactos en SimpleX lo verán.
|
||||
\nPuedes cambiarlo en Configuración.</string>
|
||||
<string name="your_contacts_will_remain_connected">Tus contactos permanecerán conectados.</string>
|
||||
<string name="you_wont_lose_your_contacts_if_delete_address">Si más tarde decides borrar tu dirección los contactos no se perderán.</string>
|
||||
<string name="all_app_data_will_be_cleared">Todos los datos de la aplicación se eliminarán.</string>
|
||||
<string name="empty_chat_profile_is_created">Se creará un perfil vacío con el nombre proporcionado, y la aplicación se abrirá como de costumbre.</string>
|
||||
<string name="self_destruct">Autodestrucción</string>
|
||||
<string name="enabled_self_destruct_passcode">Activar código de autodestrucción</string>
|
||||
<string name="app_passcode_replaced_with_self_destruct">El código de acceso será reemplazado por código de autodestrucción.</string>
|
||||
<string name="change_self_destruct_mode">Cambiar el modo de autodestrucción</string>
|
||||
<string name="change_self_destruct_passcode">Cambiar código autodestrucción</string>
|
||||
<string name="if_you_enter_passcode_data_removed">¡Si introduces este código al abrir la aplicación, todos los datos de la misma se eliminarán de forma irreversible!</string>
|
||||
<string name="if_you_enter_self_destruct_code">Si al abrir la aplicación introduces el código de autodestrucción:</string>
|
||||
<string name="self_destruct_new_display_name">Nuevo nombre mostrado:</string>
|
||||
<string name="self_destruct_passcode">Código de autodestrucción</string>
|
||||
<string name="self_destruct_passcode_changed">¡Código de autodestrucción cambiado!</string>
|
||||
<string name="self_destruct_passcode_enabled">¡Código de autodestrucción activado!</string>
|
||||
<string name="enable_self_destruct">Activar autodestrucción</string>
|
||||
<string name="set_passcode">Código autodestrucción</string>
|
||||
<string name="both_you_and_your_contact_can_add_message_reactions">Tanto tú como tu contacto podéis añadir reacciones a los mensajes.</string>
|
||||
<string name="custom_time_picker_select">Seleccionar</string>
|
||||
<string name="custom_time_picker_custom">personalizado</string>
|
||||
<string name="edit_history">Historial</string>
|
||||
<string name="info_menu">Detalles</string>
|
||||
<string name="received_message">Mensaje entrante</string>
|
||||
<string name="sent_message">Mensaje saliente</string>
|
||||
<string name="disappearing_message">Mensaje temporal</string>
|
||||
<string name="send_disappearing_message">Enviar mensaje temporal</string>
|
||||
<string name="send_disappearing_message_custom_time">Tiempo personalizado</string>
|
||||
<string name="send_disappearing_message_send">Enviar</string>
|
||||
<string name="info_row_moderated_at">Moderado el</string>
|
||||
<string name="info_row_received_at">Recibido el</string>
|
||||
<string name="info_row_sent_at">Enviado el</string>
|
||||
<string name="item_info_current">(actual)</string>
|
||||
<string name="share_text_database_id">ID de base de datos: %d</string>
|
||||
<string name="share_text_deleted_at">Borrado el: %s</string>
|
||||
<string name="share_text_disappears_at">Desaparecerá el: %s</string>
|
||||
<string name="share_text_moderated_at">Moderado el: %s</string>
|
||||
<string name="share_text_received_at">Recibido el: %s</string>
|
||||
<string name="share_text_updated_at">Registro actualizado: %s</string>
|
||||
<string name="current_version_timestamp">%s (actual)</string>
|
||||
<string name="share_text_sent_at">Enviado el: %s</string>
|
||||
<string name="info_row_disappears_at">Desaparecerá el</string>
|
||||
<string name="message_reactions">Reacciones a los mensajes</string>
|
||||
<string name="prohibit_message_reactions">No se permiten reacciones a los mensajes.</string>
|
||||
<string name="allow_message_reactions">Permitir reacciones a los mensajes.</string>
|
||||
<string name="message_reactions_prohibited_in_this_chat">Las reacciones a los mensajes no están permitidas en este chat.</string>
|
||||
<string name="only_you_can_add_message_reactions">Sólo tú puedes añadir reacciones a los mensajes.</string>
|
||||
<string name="prohibit_message_reactions_group">No se permiten reacciones a los mensajes</string>
|
||||
<string name="custom_time_unit_days">días</string>
|
||||
<string name="custom_time_unit_hours">horas</string>
|
||||
<string name="custom_time_unit_minutes">minutos</string>
|
||||
<string name="custom_time_unit_months">meses</string>
|
||||
<string name="custom_time_unit_seconds">segundos</string>
|
||||
<string name="custom_time_unit_weeks">semanas</string>
|
||||
<string name="error_loading_details">Error al cargar detalles</string>
|
||||
<string name="group_members_can_add_message_reactions">Los miembros pueden añadir reacciones a los mensajes.</string>
|
||||
<string name="message_reactions_are_prohibited">Las reacciones a los mensajes no están permitidas en este grupo.</string>
|
||||
<string name="only_your_contact_can_add_message_reactions">Sólo tu contacto puede añadir reacciones a los mensajes.</string>
|
||||
<string name="send_disappearing_message_1_minute">1 minuto</string>
|
||||
<string name="info_row_updated_at">Registro actualizado</string>
|
||||
<string name="send_disappearing_message_30_seconds">30 segundos</string>
|
||||
<string name="send_disappearing_message_5_minutes">5 minutos</string>
|
||||
<string name="allow_your_contacts_adding_message_reactions">Permitir que tus contactos añadan reacciones a los mensajes.</string>
|
||||
<string name="info_row_deleted_at">Eliminado el</string>
|
||||
<string name="allow_message_reactions_only_if">Se permiten las reacciones a los mensajes pero sólo si tu contacto también las permite.</string>
|
||||
<string name="v5_1_custom_themes">Temas personalizados</string>
|
||||
<string name="v5_1_self_destruct_passcode">Código de autodestrucción</string>
|
||||
<string name="v5_1_better_messages_descr">- mensajes de voz de hasta 5 minutos.
|
||||
\n- tiempo personalizado para mensajes temporales.
|
||||
\n- historial de edición.</string>
|
||||
<string name="whats_new_thanks_to_users_contribute_weblate">¡Gracias a los colaboradores! Contribuye a través de Weblate.</string>
|
||||
<string name="v5_1_better_messages">Mensajes mejorados</string>
|
||||
<string name="v5_1_self_destruct_passcode_descr">Al introducirlo todos los datos son borrados.</string>
|
||||
<string name="v5_1_custom_themes_descr">Personalizar y compartir temas de color.</string>
|
||||
<string name="v5_1_message_reactions_descr">¡Por fin los tenemos! 🚀</string>
|
||||
<string name="v5_1_message_reactions">Reacciones a los mensajes</string>
|
||||
<string name="whats_new_read_more">Saber más</string>
|
||||
<string name="v5_1_japanese_portuguese_interface">Interfaz en japonés y portugués</string>
|
||||
</resources>
|
||||
@@ -60,7 +60,7 @@
|
||||
<string name="invalid_connection_link">Lien de connection invalide</string>
|
||||
<string name="connection_timeout">Délai de connexion</string>
|
||||
<string name="error_sending_message">Erreur lors de l\'envoi du message</string>
|
||||
<string name="you_are_already_connected_to_vName_via_this_link">Vous êtes déjà connecté à <xliff:g id="contactName" example="Alice">%1$s!</xliff:g>.</string>
|
||||
<string name="you_are_already_connected_to_vName_via_this_link">Vous êtes déjà connecté à <xliff:g id="contactName" example="Alice">%1$s</xliff:g>.</string>
|
||||
<string name="connection_error_auth">Erreur de connexion (AUTH)</string>
|
||||
<string name="connection_error_auth_desc">A moins que votre contact ait supprimé la connexion ou que ce lien ait déjà été utilisé, il peut s\'agir d\'un bug - veuillez le signaler.
|
||||
\nPour vous connecter, veuillez demander à votre contact de créer un autre lien de connexion et vérifiez que vous disposez d\'une connexion réseau stable.</string>
|
||||
@@ -240,10 +240,9 @@
|
||||
<string name="this_QR_code_is_not_a_link">Ce code QR n\'est pas un lien !</string>
|
||||
<string name="you_will_be_connected_when_your_connection_request_is_accepted">Vous serez connecté·e lorsque votre demande de connexion sera acceptée, veuillez attendre ou vérifier plus tard !</string>
|
||||
<string name="you_will_be_connected_when_your_contacts_device_is_online">Vous serez connecté·e lorsque l\'appareil de votre contact sera en ligne, veuillez attendre ou vérifier plus tard !</string>
|
||||
<string name="show_QR_code_for_your_contact_to_scan_from_the_app__multiline">Votre contact peut scanner le code QR depuis l\'app.</string>
|
||||
<string name="your_chat_profile_will_be_sent_to_your_contact">Votre profil de chat sera envoyé
|
||||
\nà votre contact</string>
|
||||
<string name="share_invitation_link">Partager le lien d\'invitation</string>
|
||||
<string name="share_invitation_link">Partager un lien unique</string>
|
||||
<string name="your_profile_will_be_sent">Votre profil de chat sera envoyé à votre contact</string>
|
||||
<string name="paste_button">Coller</string>
|
||||
<string name="this_string_is_not_a_connection_link">Cette chaîne n\'est pas un lien de connexion !</string>
|
||||
@@ -260,7 +259,6 @@
|
||||
<string name="connect_via_link">Se connecter via un lien</string>
|
||||
<string name="clear_verification">Retirer la vérification</string>
|
||||
<string name="one_time_link">Lien d\'invitation unique</string>
|
||||
<string name="your_contact_address">Votre adresse de contact</string>
|
||||
<string name="scan_code">Scanner le code</string>
|
||||
<string name="incorrect_code">Code de sécurité incorrect !</string>
|
||||
<string name="security_code">Code de sécurité</string>
|
||||
@@ -326,7 +324,7 @@
|
||||
<string name="use_simplex_chat_servers__question">Utiliser les serveurs <xliff:g id="appNameFull">SimpleX Chat</xliff:g> \?</string>
|
||||
<string name="smp_servers_delete_server">Supprimer le serveur</string>
|
||||
<string name="ensure_ICE_server_address_are_correct_format_and_unique">Assurez-vous que les adresses des serveurs WebRTC ICE sont au bon format et ne sont pas dupliquées, un par ligne.</string>
|
||||
<string name="network_enable_socks_info">Accéder aux serveurs via un proxy SOCKS sur le port 9050 \? Le proxy doit être démarré avant d\'activer cette option.</string>
|
||||
<string name="network_enable_socks_info">Accéder aux serveurs via un proxy SOCKS sur le port %d \? Le proxy doit être démarré avant d\'activer cette option.</string>
|
||||
<string name="network_use_onion_hosts">Utiliser les hôtes .onions</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc_in_alert">Les hôtes .onion seront utilisés lorsqu\'ils sont disponibles.</string>
|
||||
<string name="network_use_onion_hosts_required_desc_in_alert">Les hôtes .onion seront nécessaires pour la connexion.</string>
|
||||
@@ -352,7 +350,6 @@
|
||||
<string name="configure_ICE_servers">Configurer les serveurs ICE</string>
|
||||
<string name="network_settings">Paramètres réseau avancés</string>
|
||||
<string name="network_settings_title">Paramètres réseau</string>
|
||||
<string name="network_socks_toggle">Utiliser un proxy SOCKS (port 9050)</string>
|
||||
<string name="network_enable_socks">Utiliser un proxy SOCKS \?</string>
|
||||
<string name="network_disable_socks">Utiliser une connexion Internet directe \?</string>
|
||||
<string name="network_disable_socks_info">Si vous confirmez, les serveurs de messagerie seront en mesure de voir votre adresse IP, votre fournisseur ainsi que les serveurs auxquels vous vous connectez.</string>
|
||||
@@ -361,7 +358,6 @@
|
||||
<string name="network_use_onion_hosts_prefer_desc">Les hôtes .onion seront utilisés lorsqu\'ils sont disponibles.</string>
|
||||
<string name="appearance_settings">Apparence</string>
|
||||
<string name="create_address">Créer une adresse</string>
|
||||
<string name="you_can_share_your_address_anybody_will_be_able_to_connect">Vous pouvez partager votre adresse sous forme de lien ou de code QR - n\'importe qui pourra se connecter à vous. Vous ne perdrez pas vos contacts si vous la supprimez par la suite.</string>
|
||||
<string name="your_current_profile">Votre profil de chat</string>
|
||||
<string name="edit_image">Modifier l\'image</string>
|
||||
<string name="save_and_notify_contacts">Sauvegarder et notifier les contacts</string>
|
||||
@@ -392,7 +388,7 @@
|
||||
<string name="onboarding_notifications_mode_off">Quand l\'application fonctionne</string>
|
||||
<string name="onboarding_notifications_mode_periodic">Périodique</string>
|
||||
<string name="onboarding_notifications_mode_service">Instantanée</string>
|
||||
<string name="onboarding_notifications_mode_off_desc"><b>Économie de batterie</b>. Vous recevrez des notifications uniquement lorsque l\'application est en cours d\'exécution, le service de fond ne sera PAS utilisé.</string>
|
||||
<string name="onboarding_notifications_mode_off_desc"><b>Économie de batterie</b>. Vous recevrez des notifications uniquement lorsque l\'application est en cours d\'exécution (PAS de service d\'arrière-plan)</string>
|
||||
<string name="about_simplex_chat">À propos de <xliff:g id="appNameFull">SimpleX Chat</xliff:g></string>
|
||||
<string name="how_to_use_simplex_chat">Comment l\'utiliser</string>
|
||||
<string name="markdown_help">Aide Markdown</string>
|
||||
@@ -406,7 +402,7 @@
|
||||
<string name="callstate_starting">lancement…</string>
|
||||
<string name="is_verified">%s est vérifié·e</string>
|
||||
<string name="is_not_verified">%s n\'est pas vérifié·e</string>
|
||||
<string name="your_simplex_contact_address">Votre adresse de contact <xliff:g id="appName">SimpleX</xliff:g></string>
|
||||
<string name="your_simplex_contact_address">Votre adresse SimpleX</string>
|
||||
<string name="database_passphrase_and_export">Phrase secrète et exportation de la base de données</string>
|
||||
<string name="chat_with_the_founder">Envoyez vos questions et idées</string>
|
||||
<string name="send_us_an_email">Envoyez nous un e-mail</string>
|
||||
@@ -433,10 +429,6 @@
|
||||
<string name="all_your_contacts_will_remain_connected">Tous vos contacts resteront connectés.</string>
|
||||
<string name="share_link">Partager le lien</string>
|
||||
<string name="delete_address">Supprimer l\'adresse</string>
|
||||
<string name="contact_requests">Demandes de contact</string>
|
||||
<string name="accept_requests">Accepter les demandes</string>
|
||||
<string name="accept_automatically">Automatiquement</string>
|
||||
<string name="section_title_welcome_message">MESSAGE DE BIENVENUE</string>
|
||||
<string name="display_name__field">Nom affiché :</string>
|
||||
<string name="full_name__field">Nom complet :</string>
|
||||
<string name="your_profile_is_stored_on_device_and_shared_only_with_contacts_simplex_cannot_see_it">Votre profil est stocké sur votre appareil et partagé uniquement avec vos contacts. Les serveurs <xliff:g id="appName">SimpleX</xliff:g> ne peuvent pas voir votre profil.</string>
|
||||
@@ -470,8 +462,8 @@
|
||||
<string name="many_people_asked_how_can_it_deliver">Beaucoup se demandent : <i>si <xliff:g id="appName">SimpleX</xliff:g> n\'a pas d\'identifiant d\'utilisateur, comment peut-il transmettre des messages \?</i></string>
|
||||
<string name="only_client_devices_store_contacts_groups_e2e_encrypted_messages">Seuls les appareils clients stockent les profils des utilisateurs, les contacts, les groupes et les messages envoyés avec un <b>chiffrement de bout en bout à deux couches</b>.</string>
|
||||
<string name="read_more_in_github_with_link">Pour en savoir plus, consultez notre <font color="#0088ff">GitHub repository</font>.</string>
|
||||
<string name="onboarding_notifications_mode_periodic_desc"><b>Batterie peu utilisée</b>. Le service de fond vérifie les nouveaux messages toutes les 10 minutes. Vous risquez de manquer des appels et des messages urgents.</string>
|
||||
<string name="onboarding_notifications_mode_service_desc"><b>Batterie plus utilisée </b> ! Le service de fond est toujours en cours d\'exécution - les notifications s\'afficheront dès que les messages seront disponibles.</string>
|
||||
<string name="onboarding_notifications_mode_periodic_desc"><b>Batterie peu utilisée</b>. Le service de fond vérifie les messages toutes les 10 minutes. Vous risquez de manquer des appels ou des messages urgents.</string>
|
||||
<string name="onboarding_notifications_mode_service_desc"><b>Batterie plus utilisée </b> ! Le service de fond est toujours en cours d\'exécution - les notifications s\'affichent dès que les messages sont disponibles.</string>
|
||||
<string name="integrity_msg_skipped"><xliff:g id="connection ID" example="1">%1$d</xliff:g> message⸱s manqué⸱s</string>
|
||||
<string name="integrity_msg_bad_id">ID de message incorrecte</string>
|
||||
<string name="settings_section_title_settings">PARAMÈTRES</string>
|
||||
@@ -967,7 +959,7 @@
|
||||
<string name="moderated_description">modéré</string>
|
||||
<string name="moderated_item_description">modéré par %s</string>
|
||||
<string name="delete_member_message__question">Supprimer le message de ce membre \?</string>
|
||||
<string name="moderate_verb">Modéré</string>
|
||||
<string name="moderate_verb">Modérer</string>
|
||||
<string name="moderate_message_will_be_deleted_warning">Le message sera supprimé pour tous les membres.</string>
|
||||
<string name="moderate_message_will_be_marked_warning">Le message sera marqué comme modéré pour tous les membres.</string>
|
||||
<string name="you_are_observer">vous êtes observateur</string>
|
||||
@@ -1137,4 +1129,136 @@
|
||||
<string name="v5_0_large_files_support_descr">Rapide et ne nécessitant pas d\'attendre que l\'expéditeur soit en ligne !</string>
|
||||
<string name="v5_0_polish_interface">Interface en polonais</string>
|
||||
<string name="v5_0_app_passcode_descr">Il permet de remplacer l\'authentification du système.</string>
|
||||
<string name="opening_database">Ouverture de la base de données…</string>
|
||||
<string name="learn_more_about_address">À propos de l\'adresse SimpleX</string>
|
||||
<string name="learn_more">En savoir plus</string>
|
||||
<string name="you_can_share_your_address">Vous pouvez partager votre adresse sous la forme d\'un lien ou d\'un code QR - tout le monde peut se connecter à vous.</string>
|
||||
<string name="you_wont_lose_your_contacts_if_delete_address">Vous ne perdrez pas vos contacts si vous supprimez votre adresse ultérieurement.</string>
|
||||
<string name="simplex_address">Adresse SimpleX</string>
|
||||
<string name="you_can_accept_or_reject_connection">Lorsque des personnes demandent à se connecter, vous pouvez les accepter ou les refuser.</string>
|
||||
<string name="theme_colors_section_title">COULEURS DU THÈME</string>
|
||||
<string name="your_contacts_will_remain_connected">Vos contacts resteront connectés.</string>
|
||||
<string name="share_address_with_contacts_question">Partager l\'adresse avec vos contacts \?</string>
|
||||
<string name="share_with_contacts">Partager avec vos contacts</string>
|
||||
<string name="enter_welcome_message_optional">Entrez un message de bienvenue… (facultatif)</string>
|
||||
<string name="stop_sharing">Cesser le partage</string>
|
||||
<string name="stop_sharing_address">Cesser le partage d\'adresse \?</string>
|
||||
<string name="invite_friends">Inviter des amis</string>
|
||||
<string name="email_invite_subject">Discutons sur SimpleX Chat</string>
|
||||
<string name="save_settings_question">Sauvegarder les paramètres \?</string>
|
||||
<string name="dont_create_address">Ne pas créer d\'adresse</string>
|
||||
<string name="address_section_title">Adresse</string>
|
||||
<string name="share_address">Partager l\'adresse</string>
|
||||
<string name="you_can_share_this_address_with_your_contacts">Vous pouvez partager cette adresse avec vos contacts pour leur permettre de se connecter avec %s.</string>
|
||||
<string name="group_welcome_preview">Aperçu</string>
|
||||
<string name="color_background">Fond d\'écran</string>
|
||||
<string name="dark_theme">Thème sombre</string>
|
||||
<string name="export_theme">Exporter le thème</string>
|
||||
<string name="import_theme">Importer un thème</string>
|
||||
<string name="import_theme_error">Erreur lors de l\'importation d\'un thème</string>
|
||||
<string name="color_secondary">Secondaire</string>
|
||||
<string name="theme_simplex">SimpleX</string>
|
||||
<string name="color_sent_message">Message envoyé</string>
|
||||
<string name="color_title">Titre</string>
|
||||
<string name="one_time_link_short">Lien à usage unique</string>
|
||||
<string name="color_primary_variant">Accentuation supplémentaire</string>
|
||||
<string name="add_address_to_your_profile">Ajoutez une adresse à votre profil, afin que vos contacts puissent la partager avec d\'autres personnes. La mise à jour du profil sera envoyée à vos contacts.</string>
|
||||
<string name="color_secondary_variant">Secondaire supplémentaire</string>
|
||||
<string name="all_your_contacts_will_remain_connected_update_sent">Tous vos contacts resteront connectés. La mise à jour du profil sera envoyée à vos contacts.</string>
|
||||
<string name="auto_accept_contact">Auto-acceptation</string>
|
||||
<string name="create_simplex_address">Créer une adresse SimpleX</string>
|
||||
<string name="customize_theme_title">Personnaliser le thème</string>
|
||||
<string name="continue_to_next_step">Continuer</string>
|
||||
<string name="error_setting_address">Erreur lors du réglage de l\'adresse</string>
|
||||
<string name="create_address_and_let_people_connect">Créez une adresse pour permettre aux gens de vous contacter.</string>
|
||||
<string name="enter_welcome_message">Entrez un message de bienvenue…</string>
|
||||
<string name="you_can_create_it_later">Vous pouvez la créer plus tard</string>
|
||||
<string name="email_invite_body">Bonjour !
|
||||
\nContactez-moi via SimpleX Chat : %s</string>
|
||||
<string name="if_you_cant_meet_in_person">Si vous ne pouvez pas vous rencontrer en personne, montrez le code QR lors d\'un appel vidéo ou partagez le lien.</string>
|
||||
<string name="auth_open_chat_profiles">Ouvrir les profils de chat</string>
|
||||
<string name="color_surface">Menus et alertes</string>
|
||||
<string name="color_received_message">Message reçu</string>
|
||||
<string name="import_theme_error_desc">Assurez-vous que le fichier a une syntaxe YAML correcte. Exporter le thème pour avoir un exemple de la structure du fichier du thème.</string>
|
||||
<string name="profile_update_will_be_sent_to_contacts">La mise à jour du profil sera envoyée à vos contacts.</string>
|
||||
<string name="read_more_in_user_guide_with_link">Pour en savoir plus, consultez le <font color="#0088ff">Guide de l\'utilisateur</font>.</string>
|
||||
<string name="save_auto_accept_settings">Sauvegarder les paramètres d\'acceptation automatique</string>
|
||||
<string name="scan_qr_to_connect_to_contact">Pour se connecter, votre contact peut scanner le code QR ou utiliser le lien dans l\'application.</string>
|
||||
<string name="your_contacts_will_see_it">Vos contacts dans SimpleX la verront.
|
||||
\nVous pouvez modifier ce choix dans les Paramètres.</string>
|
||||
<string name="app_passcode_replaced_with_self_destruct">Le code d\'accès de l\'application est remplacé par un code d\'autodestruction.</string>
|
||||
<string name="enable_self_destruct">Activer l\'autodestruction</string>
|
||||
<string name="empty_chat_profile_is_created">Un profil de chat vierge portant le nom fourni est créé et l\'application s\'ouvre normalement.</string>
|
||||
<string name="change_self_destruct_passcode">Modifier le code d\'autodestruction</string>
|
||||
<string name="enabled_self_destruct_passcode">Activer le code d\'autodestruction</string>
|
||||
<string name="self_destruct">Autodestruction</string>
|
||||
<string name="change_self_destruct_mode">Modifier le mode d\'autodestruction</string>
|
||||
<string name="self_destruct_new_display_name">Nouveau nom affiché :</string>
|
||||
<string name="self_destruct_passcode">Code d\'autodestruction</string>
|
||||
<string name="self_destruct_passcode_changed">Le code d\'autodestruction a été modifié !</string>
|
||||
<string name="self_destruct_passcode_enabled">Code d\'autodestruction activé !</string>
|
||||
<string name="all_app_data_will_be_cleared">Toutes les données de l\'application sont supprimées.</string>
|
||||
<string name="if_you_enter_self_destruct_code">Si vous entrez votre code d\'autodestruction à l\'ouverture de l\'application :</string>
|
||||
<string name="if_you_enter_passcode_data_removed">Si vous saisissez ce code à l\'ouverture de l\'application, toutes les données de l\'application seront irréversiblement supprimées !</string>
|
||||
<string name="set_passcode">Définir le code d\'accès</string>
|
||||
<string name="send_disappearing_message_30_seconds">30 secondes</string>
|
||||
<string name="send_disappearing_message_custom_time">Délai personnalisé</string>
|
||||
<string name="disappearing_message">Message éphémère</string>
|
||||
<string name="send_disappearing_message">Envoyer un message éphémère</string>
|
||||
<string name="send_disappearing_message_send">Envoyer</string>
|
||||
<string name="allow_message_reactions_only_if">Autoriser les réactions aux messages uniquement si votre contact les autorise.</string>
|
||||
<string name="allow_your_contacts_adding_message_reactions">Autoriser vos contacts à ajouter des réactions aux messages.</string>
|
||||
<string name="message_reactions">Réactions aux messages</string>
|
||||
<string name="prohibit_message_reactions">Interdire les réactions aux messages.</string>
|
||||
<string name="both_you_and_your_contact_can_add_message_reactions">Vous et votre contact pouvez ajouter des réactions aux messages.</string>
|
||||
<string name="message_reactions_prohibited_in_this_chat">Les réactions aux messages sont interdites dans ce chat.</string>
|
||||
<string name="only_you_can_add_message_reactions">Vous seul pouvez ajouter des réactions aux messages.</string>
|
||||
<string name="allow_message_reactions">Autoriser les réactions aux messages.</string>
|
||||
<string name="prohibit_message_reactions_group">Interdire les réactions aux messages.</string>
|
||||
<string name="group_members_can_add_message_reactions">Les membres du groupe peuvent ajouter des réactions aux messages.</string>
|
||||
<string name="message_reactions_are_prohibited">Les réactions aux messages sont interdites dans ce groupe.</string>
|
||||
<string name="custom_time_unit_hours">heures</string>
|
||||
<string name="custom_time_unit_minutes">minutes</string>
|
||||
<string name="custom_time_unit_seconds">secondes</string>
|
||||
<string name="custom_time_unit_weeks">semaines</string>
|
||||
<string name="send_disappearing_message_1_minute">1 minute</string>
|
||||
<string name="send_disappearing_message_5_minutes">5 minutes</string>
|
||||
<string name="custom_time_unit_days">jours</string>
|
||||
<string name="custom_time_unit_months">mois</string>
|
||||
<string name="only_your_contact_can_add_message_reactions">Seul votre contact peut ajouter des réactions aux messages.</string>
|
||||
<string name="error_loading_details">Erreur de chargement des détails</string>
|
||||
<string name="edit_history">Historique</string>
|
||||
<string name="info_menu">Info</string>
|
||||
<string name="received_message">Message reçu</string>
|
||||
<string name="custom_time_picker_custom">personnalisé</string>
|
||||
<string name="custom_time_picker_select">Choisir</string>
|
||||
<string name="whats_new_read_more">En savoir plus</string>
|
||||
<string name="v5_1_better_messages_descr">- messages vocaux pouvant durer jusqu\'à 5 minutes.
|
||||
\n- délai personnalisé de disparition.
|
||||
\n- l\'historique de modification.</string>
|
||||
<string name="share_text_received_at">Reçu le : %s</string>
|
||||
<string name="v5_1_better_messages">Meilleurs messages</string>
|
||||
<string name="v5_1_custom_themes">Thèmes personnalisés</string>
|
||||
<string name="v5_1_self_destruct_passcode_descr">Toutes les données sont effacées lorsqu\'il est saisi.</string>
|
||||
<string name="v5_1_custom_themes_descr">Personnalisez et partagez des thèmes de couleurs.</string>
|
||||
<string name="item_info_current">(actuel)</string>
|
||||
<string name="info_row_deleted_at">Supprimé à</string>
|
||||
<string name="info_row_received_at">Reçu le</string>
|
||||
<string name="info_row_sent_at">Envoyé le</string>
|
||||
<string name="share_text_database_id">ID de base de données : %d</string>
|
||||
<string name="share_text_deleted_at">Supprimé à : %s</string>
|
||||
<string name="share_text_disappears_at">Disparaît à : %s</string>
|
||||
<string name="info_row_disappears_at">Disparaît à</string>
|
||||
<string name="v5_1_japanese_portuguese_interface">Interface en japonais et en portugais</string>
|
||||
<string name="whats_new_thanks_to_users_contribute_weblate">Merci aux utilisateurs - contribuez via Weblate !</string>
|
||||
<string name="v5_1_message_reactions_descr">Enfin, les voilà ! 🚀</string>
|
||||
<string name="info_row_moderated_at">Modéré à</string>
|
||||
<string name="share_text_updated_at">Enregistrement mis à jour le : %s</string>
|
||||
<string name="v5_1_message_reactions">Réactions aux messages</string>
|
||||
<string name="share_text_moderated_at">Modéré à : %s</string>
|
||||
<string name="info_row_updated_at">Enregistrement mis à jour le</string>
|
||||
<string name="current_version_timestamp">%s (actuel)</string>
|
||||
<string name="v5_1_self_destruct_passcode">Code d\'autodestruction</string>
|
||||
<string name="share_text_sent_at">Envoyé le : %s</string>
|
||||
<string name="sent_message">Message envoyé</string>
|
||||
</resources>
|
||||
@@ -10,7 +10,6 @@
|
||||
<string name="above_then_preposition_continuation">ऊपर,तब:</string>
|
||||
<string name="accept_contact_button">स्वीकार करना</string>
|
||||
<string name="connect_button">जुडिये</string>
|
||||
<string name="your_contact_address">आपका संपर्क पता</string>
|
||||
<string name="smp_servers_add_to_another_device">दूसरे उपकरण में जोड़ें</string>
|
||||
<string name="bold">निडर</string>
|
||||
<string name="answer_call">कॉल का उत्तर दें</string>
|
||||
@@ -35,7 +34,6 @@
|
||||
<string name="accept_connection_request__question">संबंध अनुरोध स्वीकार करें\?</string>
|
||||
<string name="callstatus_accepted">स्वीकृत कॉल</string>
|
||||
<string name="accept_contact_incognito_button">गुप्त स्वीकार करें</string>
|
||||
<string name="accept_requests">निवेदन स्वीकार करो</string>
|
||||
<string name="smp_servers_preset_add">पूर्वनिर्धारित सर्वर जोड़ें</string>
|
||||
<string name="users_add">प्रोफ़ाइल जोड़ें</string>
|
||||
<string name="smp_servers_add">सर्वर जोड़े…</string>
|
||||
@@ -67,7 +65,6 @@
|
||||
<string name="chat_preferences_you_allow">आप आज्ञा दें</string>
|
||||
<string name="welcome">स्वागत!</string>
|
||||
<string name="la_notice_turn_on">चालू करो</string>
|
||||
<string name="section_title_welcome_message">स्वागत संदेश</string>
|
||||
<string name="unknown_message_format">अज्ञात संदेश प्रारूप</string>
|
||||
<string name="personal_welcome">स्वागत <xliff:g>%1$s</xliff:g>!</string>
|
||||
<string name="callstate_starting">शुरुआत</string>
|
||||
@@ -235,7 +232,6 @@
|
||||
<string name="chat_console">चैट कंसोल</string>
|
||||
<string name="all_your_contacts_will_remain_connected">आपके सभी संपर्क जुड़े रहेंगे।</string>
|
||||
<string name="network_session_mode_user">चैट प्रोफ़ाइल</string>
|
||||
<string name="contact_requests">संपर्क अनुरोध</string>
|
||||
<string name="create_profile_button">बनाएं</string>
|
||||
<string name="callstatus_error">कॉल त्रुटि</string>
|
||||
<string name="callstatus_in_progress">कॉल चल रहा है</string>
|
||||
|
||||
@@ -207,7 +207,7 @@
|
||||
<string name="simplex_link_mode_description">Descrizione</string>
|
||||
<string name="simplex_link_connection">via <xliff:g id="serverHost" example="smp.simplex.im">%1$s</xliff:g></string>
|
||||
<string name="simplex_link_mode_browser_warning">Aprire il link nel browser può ridurre la privacy e la sicurezza della connessione. I link SimpleX non fidati saranno in rosso.</string>
|
||||
<string name="you_are_already_connected_to_vName_via_this_link">Sei già connesso a <xliff:g id="contactName" example="Alice">%1$s!</xliff:g>.</string>
|
||||
<string name="you_are_already_connected_to_vName_via_this_link">Sei già connesso a <xliff:g id="contactName" example="Alice">%1$s</xliff:g>.</string>
|
||||
<string name="connection_error_auth_desc">A meno che il tuo contatto non abbia eliminato la connessione o che questo link non sia già stato usato, potrebbe essere un errore; per favore segnalalo.
|
||||
\nPer connetterti, chiedi al tuo contatto di creare un altro link di connessione e controlla di avere una connessione di rete stabile.</string>
|
||||
<string name="error_smp_test_certificate">Probabilmente l\'impronta del certificato nell\'indirizzo del server è sbagliata</string>
|
||||
@@ -239,8 +239,7 @@
|
||||
<string name="allow_disappearing_messages_only_if">Consenti i messaggi a tempo solo se il tuo contatto li consente.</string>
|
||||
<string name="allow_to_delete_messages">Permetti di eliminare irreversibilmente i messaggi inviati.</string>
|
||||
<string name="allow_your_contacts_to_send_disappearing_messages">Permetti ai tuoi contatti di inviare messaggi a tempo.</string>
|
||||
<string name="accept_requests">Accetta le richieste</string>
|
||||
<string name="network_enable_socks_info">Accedere ai server via proxy SOCKS sulla porta 9050\? Il proxy deve essere avviato prima di attivare questa opzione.</string>
|
||||
<string name="network_enable_socks_info">Accedere ai server via proxy SOCKS sulla porta %d\? Il proxy deve essere avviato prima di attivare questa opzione.</string>
|
||||
<string name="v4_3_improved_server_configuration_desc">Aggiungi server scansionando codici QR.</string>
|
||||
<string name="all_group_members_will_remain_connected">Tutti i membri del gruppo resteranno connessi.</string>
|
||||
<string name="allow_irreversible_message_deletion_only_if">Consenti l\'eliminazione irreversibile dei messaggi solo se il contatto la consente a te.</string>
|
||||
@@ -273,8 +272,8 @@
|
||||
<string name="settings_section_title_icon">ICONA APP</string>
|
||||
<string name="incognito_random_profile_from_contact_description">Verrà inviato un profilo casuale al contatto da cui hai ricevuto questo link</string>
|
||||
<string name="incognito_random_profile_description">Verrà inviato un profilo casuale al tuo contatto</string>
|
||||
<string name="onboarding_notifications_mode_off_desc"><b>Ideale per la batteria</b>. Riceverai notifiche solo quando l\'app è in esecuzione, il servizio in secondo piano NON verrà usato.</string>
|
||||
<string name="onboarding_notifications_mode_service_desc"><b>Consuma più batteria</b>! Il servizio in secondo piano è sempre attivo: le notifiche verranno mostrate non appena i messaggi saranno disponibili.</string>
|
||||
<string name="onboarding_notifications_mode_off_desc"><b>Ideale per la batteria</b>. Riceverai notifiche solo quando l\'app è in esecuzione (NO servizio in secondo piano).</string>
|
||||
<string name="onboarding_notifications_mode_service_desc"><b>Consuma più batteria</b>! Servizio in secondo piano sempre attivo: le notifiche sono mostrate non appena i messaggi sono disponibili.</string>
|
||||
<string name="callstatus_calling">chiamata…</string>
|
||||
<string name="icon_descr_cancel_link_preview">annulla anteprima link</string>
|
||||
<string name="cannot_access_keychain">Impossibile accedere al Keystore per salvare la password del database</string>
|
||||
@@ -284,7 +283,6 @@
|
||||
<string name="snd_conn_event_switch_queue_phase_changing">cambio indirizzo…</string>
|
||||
<string name="chat_is_stopped">Chat fermata</string>
|
||||
<string name="group_member_status_introduced">connessione (presentato)</string>
|
||||
<string name="contact_requests">Richieste del contatto</string>
|
||||
<string name="connection_request_sent">Richiesta di connessione inviata!</string>
|
||||
<string name="delete_link_question">Eliminare il link\?</string>
|
||||
<string name="delete_link">Elimina link</string>
|
||||
@@ -339,7 +337,6 @@
|
||||
<string name="how_to">Come si fa</string>
|
||||
<string name="how_to_use_your_servers">Come usare i tuoi server</string>
|
||||
<string name="enter_one_ICE_server_per_line">Server ICE (uno per riga)</string>
|
||||
<string name="accept_automatically">Automaticamente</string>
|
||||
<string name="bold">grassetto</string>
|
||||
<string name="callstatus_ended">chiamata terminata <xliff:g id="duration" example="01:15">%1$s</xliff:g></string>
|
||||
<string name="callstatus_error">errore di chiamata</string>
|
||||
@@ -360,7 +357,7 @@
|
||||
<string name="how_to_use_markdown">Come usare il markdown</string>
|
||||
<string name="icon_descr_audio_call">chiamata audio</string>
|
||||
<string name="audio_call_no_encryption">chiamata audio (non crittografata e2e)</string>
|
||||
<string name="onboarding_notifications_mode_periodic_desc"><b>Buono per la batteria</b>. Il servizio in secondo piano controlla nuovi messaggi ogni 10 minuti. Potresti perdere chiamate e messaggi urgenti.</string>
|
||||
<string name="onboarding_notifications_mode_periodic_desc"><b>Buono per la batteria</b>. Il servizio in secondo piano cerca messaggi ogni 10 minuti. Potresti perdere chiamate o messaggi urgenti.</string>
|
||||
<string name="call_already_ended">Chiamata già terminata!</string>
|
||||
<string name="create_your_profile">Crea il tuo profilo</string>
|
||||
<string name="decentralized">Decentralizzato</string>
|
||||
@@ -575,7 +572,6 @@
|
||||
<string name="you_invited_your_contact">Hai invitato il contatto</string>
|
||||
<string name="your_chat_profile_will_be_sent_to_your_contact">Il tuo profilo di chat verrà inviato
|
||||
\nal tuo contatto</string>
|
||||
<string name="show_QR_code_for_your_contact_to_scan_from_the_app__multiline">Il tuo contatto può scansionare il codice QR dall\'app.</string>
|
||||
<string name="alert_text_connection_pending_they_need_to_be_online_can_delete_and_retry">Il tuo contatto deve essere in linea per completare la connessione.
|
||||
\nPuoi annullare questa connessione e rimuovere il contatto (e riprovare più tardi con un link nuovo).</string>
|
||||
<string name="you_will_be_connected_when_your_connection_request_is_accepted">Verrai connesso/a quando la tua richiesta di connessione verrà accettata, attendi o controlla più tardi!</string>
|
||||
@@ -598,24 +594,23 @@
|
||||
<string name="chat_with_the_founder">Invia domande e idee</string>
|
||||
<string name="send_us_an_email">Inviaci un\'email</string>
|
||||
<string name="smp_servers_test_failed">Test del server fallito!</string>
|
||||
<string name="share_invitation_link">Condividi link di invito</string>
|
||||
<string name="share_invitation_link">Condividi link una tantum</string>
|
||||
<string name="chat_lock">SimpleX Lock</string>
|
||||
<string name="is_not_verified">%s non è verificato/a</string>
|
||||
<string name="is_verified">%s è verificato/a</string>
|
||||
<string name="smp_servers">Server SMP</string>
|
||||
<string name="smp_servers_test_some_failed">Alcuni server hanno fallito il test:</string>
|
||||
<string name="smp_servers_test_server">Testa server</string>
|
||||
<string name="smp_servers_test_servers">Testa i server</string>
|
||||
<string name="smp_servers_test_server">Prova server</string>
|
||||
<string name="smp_servers_test_servers">Prova i server</string>
|
||||
<string name="this_string_is_not_a_connection_link">Questa stringa non è un link di connessione!</string>
|
||||
<string name="to_verify_compare">Per verificare la crittografia end-to-end con il tuo contatto, confrontate (o scansionate) il codice sui vostri dispositivi.</string>
|
||||
<string name="smp_servers_use_server_for_new_conn">Usa per connessioni nuove</string>
|
||||
<string name="smp_servers_use_server">Usa il server</string>
|
||||
<string name="you_can_also_connect_by_clicking_the_link">Puoi anche connetterti cliccando il link. Se si apre nel browser, clicca il pulsante <b>Apri nell\'app mobile</b>.</string>
|
||||
<string name="your_profile_will_be_sent">Il tuo profilo di chat verrà inviato al tuo contatto</string>
|
||||
<string name="your_contact_address">Il tuo indirizzo di contatto</string>
|
||||
<string name="smp_servers_your_server">Il tuo server</string>
|
||||
<string name="smp_servers_your_server_address">L\'indirizzo del tuo server</string>
|
||||
<string name="your_simplex_contact_address">Il tuo indirizzo di contatto di <xliff:g id="appName">SimpleX</xliff:g></string>
|
||||
<string name="your_simplex_contact_address">Il tuo indirizzo SimpleX</string>
|
||||
<string name="network_disable_socks_info">Se confermi, i server di messaggistica saranno in grado di vedere il tuo indirizzo IP e il tuo fornitore, a quali server ti stai connettendo.</string>
|
||||
<string name="install_simplex_chat_for_terminal">Installa <xliff:g id="appNameFull">SimpleX Chat</xliff:g> per terminale</string>
|
||||
<string name="ensure_ICE_server_address_are_correct_format_and_unique">Assicurati che gli indirizzi dei server WebRTC ICE siano nel formato corretto, uno per riga e non doppi.</string>
|
||||
@@ -638,11 +633,9 @@
|
||||
<string name="network_disable_socks">Usare una connessione internet diretta\?</string>
|
||||
<string name="network_use_onion_hosts">Usa gli host .onion</string>
|
||||
<string name="network_enable_socks">Usare il proxy SOCKS\?</string>
|
||||
<string name="network_socks_toggle">Usa il proxy SOCKS (porta 9050)</string>
|
||||
<string name="use_simplex_chat_servers__question">Usare i server di <xliff:g id="appNameFull">SimpleX Chat</xliff:g>\?</string>
|
||||
<string name="using_simplex_chat_servers">Stai usando i server di <xliff:g id="appNameFull">SimpleX Chat</xliff:g>.</string>
|
||||
<string name="network_use_onion_hosts_prefer">Quando disponibili</string>
|
||||
<string name="you_can_share_your_address_anybody_will_be_able_to_connect">Puoi condividere il tuo indirizzo come link o come codice QR: chiunque potrà connettersi a te. Non perderai i tuoi contatti se in seguito lo elimini.</string>
|
||||
<string name="your_ICE_servers">I tuoi server ICE</string>
|
||||
<string name="your_SMP_servers">I tuoi server SMP</string>
|
||||
<string name="italic">corsivo</string>
|
||||
@@ -662,7 +655,6 @@
|
||||
<string name="callstate_waiting_for_answer">in attesa di risposta…</string>
|
||||
<string name="callstate_waiting_for_confirmation">in attesa di conferma…</string>
|
||||
<string name="we_do_not_store_contacts_or_messages_on_servers">Non memorizziamo nessuno dei tuoi contatti o messaggi (una volta recapitati) sui server.</string>
|
||||
<string name="section_title_welcome_message">MESSAGGIO DI BENVENUTO</string>
|
||||
<string name="you_can_use_markdown_to_format_messages__prompt">Puoi usare il markdown per formattare i messaggi:</string>
|
||||
<string name="you_control_your_chat">Sei tu a controllare la tua chat!</string>
|
||||
<string name="your_current_profile">Il tuo profilo attuale</string>
|
||||
@@ -1121,7 +1113,7 @@
|
||||
<string name="stop_file__confirm">Ferma</string>
|
||||
<string name="stop_rcv_file__title">Fermare la ricezione del file\?</string>
|
||||
<string name="no_spaces">Niente spazi!</string>
|
||||
<string name="allow_calls_only_if">Consenti le chiamate solo se il contatto le consente.</string>
|
||||
<string name="allow_calls_only_if">Consenti le chiamate solo se il tuo contatto le consente.</string>
|
||||
<string name="calls_prohibited_with_this_contact">Le chiamate audio/video sono vietate.</string>
|
||||
<string name="both_you_and_your_contact_can_make_calls">Sia tu che il tuo contatto potete effettuare chiamate.</string>
|
||||
<string name="only_you_can_make_calls">Solo tu puoi effettuare chiamate.</string>
|
||||
@@ -1134,7 +1126,139 @@
|
||||
<string name="v5_0_app_passcode">Codice di accesso dell\'app</string>
|
||||
<string name="v5_0_large_files_support_descr">Veloce e senza aspettare che il mittente sia in linea!</string>
|
||||
<string name="v5_0_polish_interface">Interfaccia polacca</string>
|
||||
<string name="v5_0_app_passcode_descr">Impostala al posto dell\'autenticazione di sistema.</string>
|
||||
<string name="v5_0_app_passcode_descr">Impostalo al posto dell\'autenticazione di sistema.</string>
|
||||
<string name="v5_0_polish_interface_descr">Grazie agli utenti – contribuite via Weblate!</string>
|
||||
<string name="v5_0_large_files_support">Video e file fino a 1 GB</string>
|
||||
<string name="auto_accept_contact">Accetta automaticamente</string>
|
||||
<string name="auth_open_chat_profiles">Apri i profili di chat</string>
|
||||
<string name="learn_more">Maggiori informazioni</string>
|
||||
<string name="scan_qr_to_connect_to_contact">Per connettervi, il tuo contatto può scansionare il codice QR o usare il link nell\'app.</string>
|
||||
<string name="you_can_accept_or_reject_connection">Quando le persone chiedono di connettersi, puoi accettare o rifiutare.</string>
|
||||
<string name="simplex_address">Indirizzo SimpleX</string>
|
||||
<string name="theme_colors_section_title">COLORI DEL TEMA</string>
|
||||
<string name="your_contacts_will_remain_connected">I tuoi contatti resteranno connessi.</string>
|
||||
<string name="add_address_to_your_profile">Aggiungi l\'indirizzo al tuo profilo, in modo che i tuoi contatti possano condividerlo con altre persone. L\'aggiornamento del profilo verrà inviato ai tuoi contatti.</string>
|
||||
<string name="create_address_and_let_people_connect">Crea un indirizzo per consentire alle persone di connettersi con te.</string>
|
||||
<string name="create_simplex_address">Crea indirizzo SimpleX</string>
|
||||
<string name="share_with_contacts">Condividi con i contatti</string>
|
||||
<string name="share_address_with_contacts_question">Condividere l\'indirizzo con i contatti\?</string>
|
||||
<string name="stop_sharing">Smetti di condividere</string>
|
||||
<string name="enter_welcome_message_optional">Inserisci il messaggio di benvenuto… (facoltativo)</string>
|
||||
<string name="email_invite_body">Ciao!
|
||||
\nConnettiti a me tramite SimpleX Chat: %s</string>
|
||||
<string name="invite_friends">Invita amici</string>
|
||||
<string name="save_auto_accept_settings">Salva le impostazioni di accettazione automatica</string>
|
||||
<string name="you_can_create_it_later">Puoi crearlo più tardi</string>
|
||||
<string name="your_contacts_will_see_it">I tuoi contatti in SimpleX lo vedranno.
|
||||
\nPuoi modificarlo nelle impostazioni.</string>
|
||||
<string name="share_address">Condividi indirizzo</string>
|
||||
<string name="enter_welcome_message">Inserisci il messaggio di benvenuto…</string>
|
||||
<string name="group_welcome_preview">Anteprima</string>
|
||||
<string name="you_can_share_this_address_with_your_contacts">Puoi condividere questo indirizzo con i contatti per consentire loro di connettersi con %s.</string>
|
||||
<string name="import_theme">Importa tema</string>
|
||||
<string name="theme_simplex">SimpleX</string>
|
||||
<string name="color_primary_variant">Principale aggiuntivo</string>
|
||||
<string name="color_secondary_variant">Secondario aggiuntivo</string>
|
||||
<string name="export_theme">Esporta tema</string>
|
||||
<string name="import_theme_error">Errore di importazione del tema</string>
|
||||
<string name="import_theme_error_desc">Assicurati che il file abbia una sintassi YAML corretta. Esporta il tema per avere un esempio della struttura del file del tema.</string>
|
||||
<string name="color_secondary">Secondario</string>
|
||||
<string name="color_received_message">Messaggio ricevuto</string>
|
||||
<string name="color_sent_message">Messaggio inviato</string>
|
||||
<string name="color_title">Titolo</string>
|
||||
<string name="one_time_link_short">Link una tantum</string>
|
||||
<string name="learn_more_about_address">Info sull\'indirizzo SimpleX</string>
|
||||
<string name="all_your_contacts_will_remain_connected_update_sent">Tutti i tuoi contatti resteranno connessi. L\'aggiornamento del profilo verrà inviato ai tuoi contatti.</string>
|
||||
<string name="address_section_title">Indirizzo</string>
|
||||
<string name="color_background">Sfondo</string>
|
||||
<string name="continue_to_next_step">Continua</string>
|
||||
<string name="error_setting_address">Errore di impostazione dell\'indirizzo</string>
|
||||
<string name="dont_create_address">Non creare un indirizzo</string>
|
||||
<string name="customize_theme_title">Personalizza il tema</string>
|
||||
<string name="dark_theme">Tema scuro</string>
|
||||
<string name="if_you_cant_meet_in_person">Se non potete incontrarvi di persona, mostra il codice QR in una videochiamata o condividi il link.</string>
|
||||
<string name="email_invite_subject">Parliamo in SimpleX Chat</string>
|
||||
<string name="profile_update_will_be_sent_to_contacts">L\'aggiornamento del profilo verrà inviato ai tuoi contatti.</string>
|
||||
<string name="read_more_in_user_guide_with_link">Maggiori informazioni nella <font color="#0088ff">Guida per l\'utente</font>.</string>
|
||||
<string name="color_surface">Menu e avvisi</string>
|
||||
<string name="stop_sharing_address">Smettere di condividere l\'indirizzo\?</string>
|
||||
<string name="save_settings_question">Salvare le impostazioni\?</string>
|
||||
<string name="you_wont_lose_your_contacts_if_delete_address">Non perderai i contatti se in seguito elimini il tuo indirizzo.</string>
|
||||
<string name="you_can_share_your_address">Puoi condividere il tuo indirizzo come link o codice QR: chiunque può connettersi a te.</string>
|
||||
<string name="opening_database">Apertura del database…</string>
|
||||
<string name="change_self_destruct_mode">Cambia modalità di autodistruzione</string>
|
||||
<string name="enabled_self_destruct_passcode">Attiva il codice di autodistruzione</string>
|
||||
<string name="self_destruct">Autodistruzione</string>
|
||||
<string name="self_destruct_passcode_changed">Codice di autodistruzione modificato!</string>
|
||||
<string name="self_destruct_passcode_enabled">Codice di autodistruzione attivato!</string>
|
||||
<string name="all_app_data_will_be_cleared">Tutti i dati dell\'app vengono eliminati.</string>
|
||||
<string name="app_passcode_replaced_with_self_destruct">Il codice di accesso dell\'app viene sostituito da un codice di autodistruzione.</string>
|
||||
<string name="enable_self_destruct">Attiva l\'autodistruzione</string>
|
||||
<string name="if_you_enter_self_destruct_code">Se inserisci il tuo codice di autodistruzione mentre apri l\'app:</string>
|
||||
<string name="self_destruct_new_display_name">Nome da mostrare nuovo:</string>
|
||||
<string name="self_destruct_passcode">Codice di autodistruzione</string>
|
||||
<string name="empty_chat_profile_is_created">Viene creato un profilo di chat vuoto con il nome scelto e l\'app si apre come al solito.</string>
|
||||
<string name="if_you_enter_passcode_data_removed">Se inserisci questo codice all\'apertura dell\'app, tutti i dati di essa verranno rimossi in modo irreversibile!</string>
|
||||
<string name="set_passcode">Imposta codice</string>
|
||||
<string name="change_self_destruct_passcode">Cambia codice di autodistruzione</string>
|
||||
<string name="message_reactions">Reazioni ai messaggi</string>
|
||||
<string name="message_reactions_prohibited_in_this_chat">Le reazioni ai messaggi sono vietate in questa chat.</string>
|
||||
<string name="message_reactions_are_prohibited">Le reazioni ai messaggi sono vietate in questo gruppo.</string>
|
||||
<string name="only_you_can_add_message_reactions">Solo tu puoi aggiungere reazioni ai messaggi.</string>
|
||||
<string name="prohibit_message_reactions">Proibisci le reazioni ai messaggi.</string>
|
||||
<string name="prohibit_message_reactions_group">Proibisci le reazioni ai messaggi.</string>
|
||||
<string name="allow_message_reactions">Consenti reazioni ai messaggi.</string>
|
||||
<string name="both_you_and_your_contact_can_add_message_reactions">Sia tu che il tuo contatto potete aggiungere reazioni ai messaggi.</string>
|
||||
<string name="only_your_contact_can_add_message_reactions">Solo il tuo contatto può aggiungere reazioni ai messaggi.</string>
|
||||
<string name="allow_your_contacts_adding_message_reactions">Consenti ai tuoi contatti di aggiungere reazioni ai messaggi.</string>
|
||||
<string name="allow_message_reactions_only_if">Consenti reazioni ai messaggi solo se il tuo contatto le consente.</string>
|
||||
<string name="group_members_can_add_message_reactions">I membri del gruppo possono aggiungere reazioni ai messaggi.</string>
|
||||
<string name="send_disappearing_message_30_seconds">30 secondi</string>
|
||||
<string name="send_disappearing_message_send">Invia</string>
|
||||
<string name="send_disappearing_message">Invia messaggio a tempo</string>
|
||||
<string name="custom_time_unit_days">giorni</string>
|
||||
<string name="custom_time_unit_hours">ore</string>
|
||||
<string name="custom_time_unit_minutes">minuti</string>
|
||||
<string name="custom_time_unit_months">mesi</string>
|
||||
<string name="custom_time_unit_seconds">secondi</string>
|
||||
<string name="custom_time_unit_weeks">settimane</string>
|
||||
<string name="custom_time_picker_select">Seleziona</string>
|
||||
<string name="send_disappearing_message_1_minute">1 minuto</string>
|
||||
<string name="send_disappearing_message_custom_time">Tempo personalizzato</string>
|
||||
<string name="send_disappearing_message_5_minutes">5 minuti</string>
|
||||
<string name="custom_time_picker_custom">personalizzato</string>
|
||||
<string name="disappearing_message">Messaggio a tempo</string>
|
||||
<string name="error_loading_details">Errore caricamento dettagli</string>
|
||||
<string name="info_menu">Informazioni</string>
|
||||
<string name="edit_history">Cronologia</string>
|
||||
<string name="received_message">Messaggio ricevuto</string>
|
||||
<string name="sent_message">Messaggio inviato</string>
|
||||
<string name="share_text_database_id">ID database: %d</string>
|
||||
<string name="info_row_moderated_at">Moderato il</string>
|
||||
<string name="share_text_moderated_at">Moderato il: %s</string>
|
||||
<string name="info_row_received_at">Ricevuto il</string>
|
||||
<string name="share_text_received_at">Ricevuto il: %s</string>
|
||||
<string name="info_row_updated_at">Registro aggiornato il</string>
|
||||
<string name="share_text_updated_at">Registro aggiornato il: %s</string>
|
||||
<string name="info_row_sent_at">Inviato il</string>
|
||||
<string name="share_text_sent_at">Inviato il: %s</string>
|
||||
<string name="current_version_timestamp">%s (attuale)</string>
|
||||
<string name="whats_new_read_more">Leggi tutto</string>
|
||||
<string name="v5_1_self_destruct_passcode_descr">Tutti i dati vengono cancellati quando inserito.</string>
|
||||
<string name="v5_1_custom_themes_descr">Personalizza e condividi temi di colore.</string>
|
||||
<string name="v5_1_custom_themes">Temi personalizzati</string>
|
||||
<string name="v5_1_message_reactions_descr">Finalmente le abbiamo! 🚀</string>
|
||||
<string name="v5_1_message_reactions">Reazioni ai messaggi</string>
|
||||
<string name="v5_1_self_destruct_passcode">Codice di autodistruzione</string>
|
||||
<string name="whats_new_thanks_to_users_contribute_weblate">Grazie agli utenti – contribuite via Weblate!</string>
|
||||
<string name="v5_1_better_messages_descr">- messaggi vocali fino a 5 minuti.
|
||||
\n- tempo di scomparsa personalizzato.
|
||||
\n- cronologia delle modifiche.</string>
|
||||
<string name="v5_1_better_messages">Messaggi migliorati</string>
|
||||
<string name="v5_1_japanese_portuguese_interface">Interfaccia giapponese e portoghese</string>
|
||||
<string name="item_info_current">(attuale)</string>
|
||||
<string name="info_row_deleted_at">Eliminato il</string>
|
||||
<string name="share_text_deleted_at">Eliminato il: %s</string>
|
||||
<string name="info_row_disappears_at">Scompare il</string>
|
||||
<string name="share_text_disappears_at">Scompare il: %s</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,840 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="color_primary">הדגשה</string>
|
||||
<string name="accept_contact_button">אשר</string>
|
||||
<string name="accept_connection_request__question">לאשר בקשת חיבור\?</string>
|
||||
<string name="about_simplex_chat">אודות <xliff:g id="appNameFull">SimpleX Chat</xliff:g></string>
|
||||
<string name="accept_requests">אשר בקשות</string>
|
||||
<string name="about_simplex">אודות SimpleX</string>
|
||||
<string name="accept_call_on_lock_screen">ענה</string>
|
||||
<string name="chat_item_ttl_week">שבוע</string>
|
||||
<string name="accept_feature">קבל</string>
|
||||
<string name="chat_item_ttl_day">יום</string>
|
||||
<string name="chat_item_ttl_month">חודש</string>
|
||||
<string name="a_plus_b">a + b</string>
|
||||
<string name="above_then_preposition_continuation">למעלה, אז:</string>
|
||||
<string name="accept">אשר</string>
|
||||
<string name="callstatus_accepted">שיחה שהתקבלה</string>
|
||||
<string name="allow_verb">אפשר</string>
|
||||
<string name="clear_chat_warning">כל ההודעות יימחקו – לא ניתן לבטל זאת! ההודעות יימחקו רק עבורך.</string>
|
||||
<string name="accept_contact_incognito_button">אשר זהות נסתרת</string>
|
||||
<string name="smp_servers_preset_add">הוסף שרתים מוגדרים מראש</string>
|
||||
<string name="smp_servers_add">הוסף שרת…</string>
|
||||
<string name="network_enable_socks_info">לגשת לשרתים דרך פרוקסי SOCKS בפורט %d\? הפרוקסי חייב לפעול לפני הפעלת אפשרות זו.</string>
|
||||
<string name="network_settings">הגדרות רשת מתקדמות</string>
|
||||
<string name="appearance_settings">מראה</string>
|
||||
<string name="app_version_name">גרסת האפליקציה: v%s</string>
|
||||
<string name="app_version_code">גרסת אפליקציה: %s</string>
|
||||
<string name="section_title_welcome_message">הודעת פתיחה</string>
|
||||
<string name="all_your_contacts_will_remain_connected">כל אנשי הקשר יישארו מחוברים.</string>
|
||||
<string name="always_use_relay">תמיד להשתמש בממסר</string>
|
||||
<string name="answer_call">ענה לשיחה</string>
|
||||
<string name="all_group_members_will_remain_connected">כל חברי הקבוצה יישארו מחוברים.</string>
|
||||
<string name="button_add_welcome_message">הוסף הודעת פתיחה</string>
|
||||
<string name="button_welcome_message">הודעת פתיחה</string>
|
||||
<string name="group_welcome_title">הודעת פתיחה</string>
|
||||
<string name="chat_preferences_always">תמיד</string>
|
||||
<string name="allow_disappearing_messages_only_if">אפשר הודעות נעלמות רק אם איש הקשר מאפשר אותן.</string>
|
||||
<string name="allow_your_contacts_irreversibly_delete">אפשר לאנשי קשר מחיקה בלתי הפיכה של הודעות שנשלחו.</string>
|
||||
<string name="allow_your_contacts_to_send_disappearing_messages">אפשר לאנשי קשר לשלוח הודעות נעלמות.</string>
|
||||
<string name="allow_voice_messages_only_if">אפשר הודעות קוליות רק אם איש הקשר מאפשר אותן.</string>
|
||||
<string name="allow_your_contacts_to_call">אפשר לאנשי קשר להתקשר אליך.</string>
|
||||
<string name="allow_to_delete_messages">אפשר מחיקה בלתי הפיכה של הודעות שנשלחו.</string>
|
||||
<string name="allow_to_send_disappearing">אפשר שליחת הודעות נעלמות.</string>
|
||||
<string name="allow_to_send_voice">אפשר שליחת הודעות קוליות.</string>
|
||||
<string name="group_member_role_admin">מנהל</string>
|
||||
<string name="v4_2_group_links_desc">מנהלים יכולים ליצור קישורי הצטרפות לקבוצות.</string>
|
||||
<string name="users_delete_all_chats_deleted">כל הצ׳אטים וההודעות יימחקו – לא ניתן לבטל זאת!</string>
|
||||
<string name="users_add">הוסף פרופיל</string>
|
||||
<string name="v4_3_improved_server_configuration_desc">הוסף שרתים על ידי סריקת קוד QR.</string>
|
||||
<string name="smp_servers_add_to_another_device">הוסף למכשיר אחר</string>
|
||||
<string name="allow_calls_only_if">אפשר שיחות רק אם איש הקשר מאפשר אותן.</string>
|
||||
<string name="allow_irreversible_message_deletion_only_if">אפשר לאנשי קשר מחיקת הודעות בלתי הפיכה רק אם הם מאפשרים לך לעשות זאת.</string>
|
||||
<string name="allow_direct_messages">אפשר שליחת הודעות ישירות לחברי הקבוצה.</string>
|
||||
<string name="allow_voice_messages_question">לאפשר הודעות קוליות\?</string>
|
||||
<string name="allow_your_contacts_to_send_voice_messages">אפשר לאנשי קשר לשלוח הודעות קוליות.</string>
|
||||
<string name="notifications_mode_service">תמיד פעיל</string>
|
||||
<string name="keychain_is_storing_securely">ישנו שימוש ב־Android Keystore כדי לאחסן בבטחה את הסיסמה – דבר המאפשר לשירות ההתראות לעבוד.</string>
|
||||
<string name="keychain_allows_to_receive_ntfs">Android Keystore יאחסן בבטחה את הסיסמה לאחר הפעלה מחדש של האפליקציה או שינוי הסיסמה – דבר המאפשר קבלת התראות.</string>
|
||||
<string name="full_backup">גיבוי נתוני האפליקציה</string>
|
||||
<string name="settings_section_title_icon">סמל האפליקציה</string>
|
||||
<string name="notifications_mode_off_desc">האפליקציה יכולה לקבל התראות רק כאשר היא מופעלת, לא יופעל שירות ברקע.</string>
|
||||
<string name="v5_0_app_passcode">קוד גישה לאפליקציה</string>
|
||||
<string name="app_version_title">גרסת האפליקציה</string>
|
||||
<string name="incognito_random_profile_description">פרופיל אקראי יישלח לאיש הקשר</string>
|
||||
<string name="incognito_random_profile_from_contact_description">פרופיל אקראי יישלח לאיש הקשר שממנו קיבלת קישור זה</string>
|
||||
<string name="network_session_mode_user_description">חיבור TCP נפרד (ואישור SOCKS) ייווצר <b>לכל פרופיל צ׳אט שיש ברשותך באפליקציה</b>.</string>
|
||||
<string name="network_session_mode_entity_description">חיבור TCP נפרד (ואישור SOCKS) ייווצר <b>לכל איש קשר וחבר קבוצה</b>.
|
||||
\n<b>שימו לב</b>: אם ברשותכם חיבורים רבים, צריכת הסוללה ותעבורת האינטרנט עשויה להיות גבוהה משמעותית וחלק מהחיבורים עלולים להיכשל.</string>
|
||||
<string name="icon_descr_video_asked_to_receive">הנמען התבקש לקבל את הסרטון</string>
|
||||
<string name="icon_descr_asked_to_receive">הנמען התבקש לקבל את התמונה</string>
|
||||
<string name="attach">צרף</string>
|
||||
<string name="icon_descr_audio_call">שיחת שמע</string>
|
||||
<string name="icon_descr_audio_off">שמע כבוי</string>
|
||||
<string name="icon_descr_audio_on">שמע פעיל</string>
|
||||
<string name="calls_prohibited_with_this_contact">שיחות שמע/וידאו אסורות.</string>
|
||||
<string name="v4_6_audio_video_calls">שיחות שמע ווידאו</string>
|
||||
<string name="audio_call_no_encryption">שיחת שמע (לא מוצפנת מקצה־לקצה)</string>
|
||||
<string name="audio_video_calls">שיחות שמע/וידאו</string>
|
||||
<string name="settings_audio_video_calls">שיחות שמע ווידאו</string>
|
||||
<string name="turning_off_service_and_periodic">מיטוב הסוללה פעיל, מכבה את שירות הרקע ובקשות תקופתיות לקבלת הודעות חדשות. ניתן להפעיל אותם מחדש בהגדרות.</string>
|
||||
<string name="it_can_disabled_via_settings_notifications_still_shown"><b>ניתן להשבית זאת בהגדרות</b> – התראות עדיין יוצגו בזמן שהאפליקציה פועלת.</string>
|
||||
<string name="notifications_mode_service_desc">שירות רקע תמיד מופעל – התראות יוצגו מיד כאשר הודעות מגיעות.</string>
|
||||
<string name="la_authenticate">אימות</string>
|
||||
<string name="la_auth_failed">אימות נכשל</string>
|
||||
<string name="back">חזרה</string>
|
||||
<string name="accept_automatically">אוטומטית</string>
|
||||
<string name="bold">מודגש</string>
|
||||
<string name="integrity_msg_bad_hash">גיבוב הודעה שגוי</string>
|
||||
<string name="integrity_msg_bad_id">מזהה הודעה שגוי</string>
|
||||
<string name="alert_title_msg_bad_hash">גיבוב הודעה שגוי</string>
|
||||
<string name="alert_title_msg_bad_id">מזהה הודעה שגוי</string>
|
||||
<string name="auto_accept_images">קבל אוטומטית תמונות</string>
|
||||
<string name="impossible_to_recover_passphrase"><b>שימו לב</b>: לא ניתן יהיה לשחזר או לשנות את הסיסמה אם תאבדו אותה.</string>
|
||||
<string name="available_in_v51">"
|
||||
\nזמין מ־v5.1"</string>
|
||||
<string name="both_you_and_your_contact_can_send_voice">גם אתם וגם איש הקשר יכולים לשלוח הודעות קוליות.</string>
|
||||
<string name="both_you_and_your_contact_can_make_calls">גם אתם וגם איש הקשר יכולים לבצע שיחות.</string>
|
||||
<string name="v4_2_auto_accept_contact_requests">אשר אוטומטית בקשות ליצירת קשר.</string>
|
||||
<string name="authentication_cancelled">אימות בוטל</string>
|
||||
<string name="auth_unavailable">אימות לא זמין</string>
|
||||
<string name="add_new_contact_to_create_one_time_QR_code"><b>הוסף איש קשר חדש</b>: ליצירת קוד QR חד פעמי עבור איש הקשר שלך.</string>
|
||||
<string name="onboarding_notifications_mode_off_desc"><b>הטוב ביותר לסוללה</b>. התראות יוצגו רק כאשר האפליקציה מופעלת (ללא שירות רקע).</string>
|
||||
<string name="onboarding_notifications_mode_periodic_desc"><b>טוב לסוללה</b>. שירות הרקע ייבדוק הודעות כל 10 דקות. שיחות או הודעות דחופות עלולות להתפספס.</string>
|
||||
<string name="both_you_and_your_contacts_can_delete">גם אתם וגם איש הקשר יכולים למחוק באופן בלתי הפיך הודעות שנשלחו.</string>
|
||||
<string name="both_you_and_your_contact_can_send_disappearing">גם אתם וגם איש הקשר יכולים לשלוח הודעות נעלמות.</string>
|
||||
<string name="cannot_receive_file">לא ניתן לקבל את הקובץ</string>
|
||||
<string name="icon_descr_cancel_image_preview">בטל תצוגה מקדימה של תמונות</string>
|
||||
<string name="cancel_verb">ביטול</string>
|
||||
<string name="icon_descr_cancel_live_message">בטל הודעה חיה</string>
|
||||
<string name="use_camera_button">מצלמה</string>
|
||||
<string name="scan_QR_code_to_connect_to_contact_who_shows_QR_code"><b>סריקת קוד QR</b>: כדי להתחבר לאיש קשר המציג לכם קוד QR.</string>
|
||||
<string name="icon_descr_cancel_link_preview">בטל תצוגה מקדימה של קישורים</string>
|
||||
<string name="callstatus_error">שגיאת שיחה</string>
|
||||
<string name="callstatus_in_progress">שיחה מתמשכת</string>
|
||||
<string name="onboarding_notifications_mode_service_desc"><b>צורך יותר סוללה</b>! שירות רקע תמיד מופעל – התראות יוצגו מיד כאשר הודעות מגיעות.</string>
|
||||
<string name="call_already_ended">השיחה כבר הסתיימה!</string>
|
||||
<string name="call_on_lock_screen">שיחות במסך הנעילה:</string>
|
||||
<string name="icon_descr_call_ended">השיחה הסתיימה</string>
|
||||
<string name="icon_descr_call_progress">שיחה מתמשכת</string>
|
||||
<string name="settings_section_title_calls">שיחות</string>
|
||||
<string name="cannot_access_keychain">לא ניתן לגשת ל־Keystore כדי לאחסן את סיסמת מסד הנתונים</string>
|
||||
<string name="cant_delete_user_profile">לא ניתן למחוק פרופיל משתמש!</string>
|
||||
<string name="feature_cancelled_item">בוטל %s</string>
|
||||
<string name="v4_5_transport_isolation_descr">לפי פרופיל צ׳אט (ברירת מחדל) או לפי חיבור (בביטא).</string>
|
||||
<string name="callstatus_calling">מתקשר…</string>
|
||||
<string name="callstatus_ended">השיחה הסתיימה <xliff:g id="duration" example="01:15">%1$s</xliff:g></string>
|
||||
<string name="icon_descr_cancel_file_preview">בטל תצוגה מקדימה של קבצים</string>
|
||||
<string name="connect_via_contact_link">להתחבר באמצעות קישור ליצירת קשר\?</string>
|
||||
<string name="connect_via_link_verb">התחבר</string>
|
||||
<string name="connect_via_group_link">להתחבר באמצעות קישור קבוצה\?</string>
|
||||
<string name="server_connected">מחובר</string>
|
||||
<string name="server_connecting">מתחבר</string>
|
||||
<string name="display_name_connecting">מתחבר…</string>
|
||||
<string name="connection_error">שגיאת חיבור</string>
|
||||
<string name="connection_timeout">תם זמן ניסיון החיבור</string>
|
||||
<string name="connection_error_auth">שגיאת חיבור (אימות)</string>
|
||||
<string name="smp_server_test_connect">התחבר</string>
|
||||
<string name="smp_server_test_compare_file">השווה קובץ</string>
|
||||
<string name="database_initialization_error_title">לא ניתן לאתחל את מסד הנתונים</string>
|
||||
<string name="notifications_mode_periodic_desc">בודק הודעות חדשות כל 10 דקות למשך עד דקה אחת.</string>
|
||||
<string name="notification_contact_connected">מחובר</string>
|
||||
<string name="la_change_app_passcode">שנה קוד גישה</string>
|
||||
<string name="auth_confirm_credential">אימות אישורך</string>
|
||||
<string name="chat_with_developers">צ׳אט עם המפתחים</string>
|
||||
<string name="contact_connection_pending">מתחבר…</string>
|
||||
<string name="group_connection_pending">מתחבר…</string>
|
||||
<string name="confirm_verb">אשר</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="icon_descr_close_button">לחצן סגירה</string>
|
||||
<string name="connection_request_sent">בקשת חיבור נשלחה!</string>
|
||||
<string name="clear_verification">נקה אימות</string>
|
||||
<string name="connect_button">התחבר</string>
|
||||
<string name="chat_console">מסוף צ׳אט</string>
|
||||
<string name="smp_servers_check_address">בידקו את כתובת השרת ונסו שוב.</string>
|
||||
<string name="configure_ICE_servers">הגדר שרתי ICE</string>
|
||||
<string name="network_session_mode_user">פרופיל צ׳אט</string>
|
||||
<string name="network_session_mode_entity">חיבור</string>
|
||||
<string name="confirm_password">אימות סיסמה</string>
|
||||
<string name="colored">צבעוני</string>
|
||||
<string name="callstatus_connecting">מתחבר לשיחה…</string>
|
||||
<string name="callstate_connected">מחובר</string>
|
||||
<string name="callstate_connecting">מתחבר…</string>
|
||||
<string name="icon_descr_call_connecting">מתחבר לשיחה</string>
|
||||
<string name="confirm_passcode">אימות קוד גישה</string>
|
||||
<string name="change_lock_mode">שנה מצב נעילה</string>
|
||||
<string name="settings_section_title_chats">צ׳אטים</string>
|
||||
<string name="chat_database_section">מסד נתונים</string>
|
||||
<string name="chat_is_running">צ׳אט פעיל</string>
|
||||
<string name="chat_is_stopped">צ׳אט מופסק</string>
|
||||
<string name="chat_database_deleted">מסד הנתונים של הצ׳אט נמחק</string>
|
||||
<string name="chat_database_imported">מסד הנתונים של הצ׳אט יובא</string>
|
||||
<string name="confirm_database_upgrades">אשר שדרוגי מסד נתונים</string>
|
||||
<string name="chat_archive_header">ארכיון צ׳אט</string>
|
||||
<string name="chat_archive_section">ארכיון צ׳אט</string>
|
||||
<string name="chat_is_stopped_indication">צ׳אט מופסק</string>
|
||||
<string name="alert_title_cant_invite_contacts">לא ניתן להזמין את אנשי הקשר!</string>
|
||||
<string name="rcv_group_event_changed_your_role">שונה תפקידך ל%s</string>
|
||||
<string name="rcv_group_event_member_connected">מחובר</string>
|
||||
<string name="rcv_conn_event_switch_queue_phase_completed">כתובתך שונתה</string>
|
||||
<string name="rcv_conn_event_switch_queue_phase_changing">משנה כתובת…</string>
|
||||
<string name="snd_conn_event_switch_queue_phase_changing">משנה כתובת…</string>
|
||||
<string name="snd_conn_event_switch_queue_phase_changing_for_member">משנה כתובת עבור %s…</string>
|
||||
<string name="group_member_status_connected">מחובר</string>
|
||||
<string name="group_member_status_accepted">מתחבר (הזמנה אושרה)</string>
|
||||
<string name="group_member_status_announced">מתחבר (הוכרז)</string>
|
||||
<string name="group_member_status_intro_invitation">מתחבר (הזמנת היכרות)</string>
|
||||
<string name="group_member_status_introduced">מתחבר (בוצעה היכרות)</string>
|
||||
<string name="invite_prohibited">לא ניתן להזמין את איש הקשר!</string>
|
||||
<string name="clear_contacts_selection_button">נקה</string>
|
||||
<string name="group_member_status_complete">חיבור הושלם</string>
|
||||
<string name="group_member_status_connecting">מתחבר</string>
|
||||
<string name="change_verb">שנה</string>
|
||||
<string name="change_member_role_question">לשנות תפקיד בקבוצה\?</string>
|
||||
<string name="change_role">שנה תפקיד</string>
|
||||
<string name="info_row_connection">חיבור</string>
|
||||
<string name="chat_preferences">העדפות צ׳אט</string>
|
||||
<string name="v4_6_chinese_spanish_interface">ממשק סינית וספרדית</string>
|
||||
<string name="v4_4_verify_connection_security_desc">השוואת קודי אבטחה עם אנשי הקשר שלך.</string>
|
||||
<string name="change_database_passphrase_question">לשנות את סיסמת מסד הנתונים\?</string>
|
||||
<string name="rcv_group_event_changed_member_role">שונה התפקיד של %s ל%s</string>
|
||||
<string name="confirm_new_passphrase">אימות סיסמה חדשה…</string>
|
||||
<string name="icon_descr_server_status_connected">מחובר</string>
|
||||
<string name="display_name_connection_established">חיבור נוצר</string>
|
||||
<string name="connection_local_display_name">חיבור <xliff:g id="connection ID" example="1">%1$d</xliff:g></string>
|
||||
<string name="connect_via_invitation_link">להתחבר באמצעות קישור הזמנה\?</string>
|
||||
<string name="contact_already_exists">איש הקשר כבר קיים</string>
|
||||
<string name="delete_contact_all_messages_deleted_cannot_undo_warning">איש הקשר וכל ההודעות יימחקו – לא ניתן לבטל זאת!</string>
|
||||
<string name="connect_via_link_or_qr">התחברות באמצעות קישור / קוד QR</string>
|
||||
<string name="connect_via_link">התחברות באמצעות קישור</string>
|
||||
<string name="chat_preferences_contact_allows">איש הקשר מאפשר</string>
|
||||
<string name="notification_preview_somebody">איש קשר מוסתר:</string>
|
||||
<string name="notification_preview_mode_contact">שם איש קשר</string>
|
||||
<string name="alert_title_contact_connection_pending">איש הקשר עוד לא מחובר!</string>
|
||||
<string name="status_contact_has_e2e_encryption">לאיש הקשר יש הצפנה מקצה־לקצה</string>
|
||||
<string name="icon_descr_contact_checked">איש קשר נבדק</string>
|
||||
<string name="status_contact_has_no_e2e_encryption">לאיש הקשר אין הצפנה מקצה־לקצה</string>
|
||||
<string name="smp_server_test_create_queue">צור תור</string>
|
||||
<string name="smp_server_test_create_file">צור קובץ</string>
|
||||
<string name="copy_verb">העתק</string>
|
||||
<string name="icon_descr_context">סמל מידע נוסף</string>
|
||||
<string name="copied">הועתק ללוח</string>
|
||||
<string name="share_one_time_link">צור קישור הזמנה חד־פעמי</string>
|
||||
<string name="create_group">צור קבוצה סודית</string>
|
||||
<string name="create_one_time_link">צור קישור הזמנה חד־פעמי</string>
|
||||
<string name="contribute">תרומה</string>
|
||||
<string name="core_version">גרסת ליבה: v%s</string>
|
||||
<string name="create_address">צור כתובת</string>
|
||||
<string name="contact_requests">בקשות ליצירת קשר</string>
|
||||
<string name="create_profile_button">צור</string>
|
||||
<string name="create_profile">צור פרופיל</string>
|
||||
<string name="create_your_profile">יצירת הפרופיל שלך</string>
|
||||
<string name="archive_created_on_ts">נוצר ב־<xliff:g id="archive_ts">%1$s</xliff:g></string>
|
||||
<string name="create_group_link">צור קישור קבוצה</string>
|
||||
<string name="button_create_group_link">צור קישור</string>
|
||||
<string name="group_member_status_creator">יוצר הקבוצה</string>
|
||||
<string name="create_secret_group_title">צור קבוצה סודית</string>
|
||||
<string name="contact_preferences">העדפות איש קשר</string>
|
||||
<string name="contacts_can_mark_messages_for_deletion">אנשי קשר יכולים לסמן הודעות למחיקה; ניתן יהיה לראות אותן.</string>
|
||||
<string name="smp_server_test_delete_queue">מחק תור</string>
|
||||
<string name="la_current_app_passcode">קוד גישה נוכחי</string>
|
||||
<string name="delete_verb">מחק</string>
|
||||
<string name="button_delete_contact">מחק איש קשר</string>
|
||||
<string name="scan_QR_code">סריקת קוד QR</string>
|
||||
<string name="developer_options">מזהי מסד נתונים ואפשרות בידוד תעבורה.</string>
|
||||
<string name="delete_address">מחק כתובת</string>
|
||||
<string name="settings_developer_tools">כלי מפתחים</string>
|
||||
<string name="database_passphrase">סיסמת מסד הנתונים</string>
|
||||
<string name="delete_messages_after">מחק הודעות אחרי</string>
|
||||
<string name="encrypted_with_random_passphrase">מסד הנתונים מוצפן באמצעות סיסמה אקראית, באפשרותך לשנות אותה.</string>
|
||||
<string name="database_passphrase_will_be_updated">סיסמת הצפנת מסד הנתונים תעודכן.</string>
|
||||
<string name="database_encryption_will_be_updated">סיסמת הצפנת מסד הנתונים תעודכן ותאוחסן ב־Keystore.</string>
|
||||
<string name="passphrase_is_different">סיסמת מסד הנתונים שונה מזו המאוחסנת ב־Keystore.</string>
|
||||
<string name="mtr_error_no_down_migration">גרסת מסד הנתונים חדשה יותר מהאפליקציה, אך אין העברת נתונים עבור: %s</string>
|
||||
<string name="users_delete_profile_for">מחיקת פרופיל צ׳אט עבור</string>
|
||||
<string name="delete_profile">מחק פרופיל</string>
|
||||
<string name="delete_contact_question">למחוק איש קשר\?</string>
|
||||
<string name="delete_contact_menu_action">מחק</string>
|
||||
<string name="delete_group_menu_action">מחק</string>
|
||||
<string name="smp_servers_delete_server">מחק שרת</string>
|
||||
<string name="create_address_and_let_people_connect">צרו כתובת כדי לאפשר לאנשים להתחבר אליכם.</string>
|
||||
<string name="decentralized">מבוזר</string>
|
||||
<string name="set_password_to_export_desc">מסד הנתונים מוצפן באמצעות סיסמה אקראית. אנא שנו אותה לפני הייצוא.</string>
|
||||
<string name="delete_chat_archive_question">למחוק ארכיון צ׳אט\?</string>
|
||||
<string name="delete_chat_profile">מחק פרופיל צ׳אט</string>
|
||||
<string name="chat_preferences_default">ברירת מחדל (%s)</string>
|
||||
<string name="ttl_day">%d יום</string>
|
||||
<string name="ttl_h">%d שעות</string>
|
||||
<string name="ttl_hour">%d שעה</string>
|
||||
<string name="ttl_d">%d ימים</string>
|
||||
<string name="ttl_days">%d ימים</string>
|
||||
<string name="ttl_hours">%d שעות</string>
|
||||
<string name="decryption_error">שגיאת פענוח הצפנה</string>
|
||||
<string name="deleted_description">נמחק</string>
|
||||
<string name="simplex_link_mode_description">תיאור</string>
|
||||
<string name="delete_member_message__question">למחוק הודעת חבר קבוצה\?</string>
|
||||
<string name="delete_message__question">למחוק הודעה\?</string>
|
||||
<string name="image_decoding_exception_title">שגיאת פענוח קידוד</string>
|
||||
<string name="delete_pending_connection__question">למחוק חיבור ממתין\?</string>
|
||||
<string name="one_time_link_short">קישור חד־פעמי</string>
|
||||
<string name="network_session_mode_transport_isolation">בידוד תעבורה</string>
|
||||
<string name="all_your_contacts_will_remain_connected_update_sent">כל אנשי הקשר יישארו מחוברים. עדכון הפרופיל יישלח לאנשי הקשר.</string>
|
||||
<string name="create_simplex_address">צור כתובת SimpleX</string>
|
||||
<string name="delete_address__question">למחוק כתובת\?</string>
|
||||
<string name="auto_accept_contact">אשר אוטומטית</string>
|
||||
<string name="continue_to_next_step">המשך</string>
|
||||
<string name="delete_image">מחק תמונה</string>
|
||||
<string name="delete_chat_profile_question">למחוק פרופיל צ׳אט\?</string>
|
||||
<string name="delete_files_and_media_question">למחוק קבצים ומדיה\?</string>
|
||||
<string name="delete_files_and_media_for_all_users">מחק קבצים עבור כל פרופילי הצ׳אט</string>
|
||||
<string name="current_passphrase">סיסמה נוכחית…</string>
|
||||
<string name="database_encrypted">מסד הנתונים מוצפן!</string>
|
||||
<string name="delete_messages">מחק הודעות</string>
|
||||
<string name="database_will_be_encrypted">מסד הנתונים יוצפן.</string>
|
||||
<string name="database_will_be_encrypted_and_passphrase_stored">מסד הנתונים יוצפן והסיסמה תאוחסן ב־Keystore.</string>
|
||||
<string name="database_error">שגיאת מסד נתונים</string>
|
||||
<string name="database_passphrase_is_required">סיסמת מסד הנתונים נדרשת כדי לפתוח את הצ׳אט.</string>
|
||||
<string name="database_downgrade">שדרוג לאחור של מסד הנתונים</string>
|
||||
<string name="database_upgrade">שדרוג מסד הנתונים</string>
|
||||
<string name="num_contacts_selected">%d אנשי קשר נבחרו</string>
|
||||
<string name="delete_link_question">למחוק קישור\?</string>
|
||||
<string name="theme_dark">כהה</string>
|
||||
<string name="color_secondary">משני</string>
|
||||
<string name="color_secondary_variant">משני נוסף</string>
|
||||
<string name="color_background">רקע</string>
|
||||
<string name="learn_more_about_address">אודות כתובת SimpleX</string>
|
||||
<string name="add_address_to_your_profile">הוסיפו את הכתובת לפרופיל שלכם, כך שאנשי קשר יוכלו לשתף אותה עם אנשים אחרים. עדכון הפרופיל יישלח לאנשי הקשר.</string>
|
||||
<string name="color_primary_variant">הדגשה נוספת</string>
|
||||
<string name="address_section_title">כתובת</string>
|
||||
<string name="maximum_supported_file_size">גודל הקובץ המרבי הנתמך כרגע הוא <xliff:g id="maxFileSize">%1$s</xliff:g></string>
|
||||
<string name="customize_theme_title">התאמה אישית</string>
|
||||
<string name="dark_theme">מצב כהה</string>
|
||||
<string name="info_row_database_id">מזהה מסד נתונים</string>
|
||||
<string name="v4_5_transport_isolation">בידוד תעבורה</string>
|
||||
<string name="database_passphrase_and_export">סיסמה וייצוא של מסד הנתונים</string>
|
||||
<string name="delete_after">מחק אחרי</string>
|
||||
<string name="delete_files_and_media_all">מחק את כל הקבצים</string>
|
||||
<string name="delete_archive">מחק ארכיון</string>
|
||||
<string name="for_me_only">מחק עבורי</string>
|
||||
<string name="delete_link">מחק קישור</string>
|
||||
<string name="users_delete_question">למחוק פרופיל צ׳אט\?</string>
|
||||
<string name="delete_database">מחק מסד נתונים</string>
|
||||
<string name="rcv_group_event_group_deleted">קבוצה נמחקה</string>
|
||||
<string name="smp_server_test_delete_file">מחק קובץ</string>
|
||||
<string name="full_deletion">מחק לכולם</string>
|
||||
<string name="button_delete_group">מחק קבוצה</string>
|
||||
<string name="delete_group_question">למחוק קבוצה\?</string>
|
||||
<string name="desktop_scan_QR_code_from_app_via_scan_QR_code">💻 שולחן עבודה: סירקו את קוד ה־QR המוצג באפליקציה, באמצעות <b>סריקת קוד QR</b>.</string>
|
||||
<string name="settings_section_title_develop">פיתוח</string>
|
||||
<string name="settings_section_title_device">מכשיר</string>
|
||||
<string name="auth_device_authentication_is_disabled_turning_off">נעילת המכשיר מושבתת. מכבה נעילת SimpleX.</string>
|
||||
<string name="auth_device_authentication_is_not_enabled_you_can_turn_on_in_settings_once_enabled">נעילת המכשיר אינה מופעלת. ניתן להפעיל את נעילת SimpleX, לאחר שתפעילו את נעילת המכשיר.</string>
|
||||
<string name="total_files_count_and_size">%d קבצים בגודל כולל של %s</string>
|
||||
<string name="server_error">שגיאה</string>
|
||||
<string name="error_loading_smp_servers">שגיאה בטעינת שרתי SMP</string>
|
||||
<string name="failed_to_create_user_title">שגיאה ביצירת פרופיל!</string>
|
||||
<string name="failed_to_create_user_duplicate_title">שם תצוגה כבר קיים!</string>
|
||||
<string name="error_creating_address">שגיאה ביצירת כתובת</string>
|
||||
<string name="error_accepting_contact_request">שגיאה באישור בקשה ליצירת קשר</string>
|
||||
<string name="la_minutes">%d דקות</string>
|
||||
<string name="la_seconds">%d שניות</string>
|
||||
<string name="la_enter_app_passcode">הזינו קוד גישה</string>
|
||||
<string name="auth_enable_simplex_lock">הפעלת נעילת SimpleX</string>
|
||||
<string name="edit_verb">ערוך</string>
|
||||
<string name="display_name__field">שם תצוגה:</string>
|
||||
<string name="edit_image">ערוך תמונה</string>
|
||||
<string name="enter_correct_passphrase">הזינו סיסמה נכונה.</string>
|
||||
<string name="mtr_error_different">העברת נתונים שונה באפליקציה/מסד נתונים: %s / %s</string>
|
||||
<string name="downgrade_and_open_chat">שדרג לאחור ופתח צ׳אט</string>
|
||||
<string name="error_changing_role">שגיאה בשינוי תפקיד</string>
|
||||
<string name="network_option_enable_tcp_keep_alive">הפעל TCP keep-alive</string>
|
||||
<string name="disappearing_prohibited_in_this_chat">הודעות נעלמות אסורות בצ׳אט זה.</string>
|
||||
<string name="icon_descr_server_status_disconnected">מנותק</string>
|
||||
<string name="icon_descr_server_status_error">שגיאה</string>
|
||||
<string name="smp_servers_enter_manually">הזנת שרת ידנית</string>
|
||||
<string name="callstate_ended">הסתיימה</string>
|
||||
<string name="enable_lock">הפעל נעילה</string>
|
||||
<string name="error_exporting_chat_database">שגיאה בייצוא מסד הנתונים של הצ׳אט</string>
|
||||
<string name="enable_automatic_deletion_question">לאפשר מחיקת הודעות אוטומטית\?</string>
|
||||
<string name="error_encrypting_database">שגיאה בהצפנת מסד הנתונים</string>
|
||||
<string name="enter_password_to_show">הזינו סיסמה בחיפוש</string>
|
||||
<string name="error_adding_members">שגיאה בהוספת חברי קבוצה</string>
|
||||
<string name="error_deleting_contact_request">שגיאה במחיקת בקשה ליצירת קשר</string>
|
||||
<string name="error_deleting_group">שגיאה במחיקת קבוצה</string>
|
||||
<string name="error_joining_group">שגיאה בהצטרפות לקבוצה</string>
|
||||
<string name="smp_server_test_disconnect">התנתק</string>
|
||||
<string name="smp_server_test_download_file">הורד קובץ</string>
|
||||
<string name="error_changing_address">שגיאה בשינוי כתובת</string>
|
||||
<string name="error_deleting_user">שגיאה במחיקת פרופיל משתמש</string>
|
||||
<string name="auth_disable_simplex_lock">השבתת נעילת SimpleX</string>
|
||||
<string name="dont_create_address">לא ליצור כתובת</string>
|
||||
<string name="no_call_on_lock_screen">מושבת</string>
|
||||
<string name="integrity_msg_duplicate">הודעה כפולה</string>
|
||||
<string name="error_deleting_database">שגיאה במחיקת מסד הנתונים של הצ׳אט</string>
|
||||
<string name="error_importing_database">שגיאה בייבוא מסד הנתונים של הצ׳אט</string>
|
||||
<string name="encrypt_database">הצפן</string>
|
||||
<string name="error_changing_message_deletion">שגיאה בשינוי הגדרה</string>
|
||||
<string name="encrypt_database_question">להצפין מסד נתונים\?</string>
|
||||
<string name="encrypted_database">מסד נתונים מוצפן</string>
|
||||
<string name="button_edit_group_profile">ערוך פרופיל קבוצה</string>
|
||||
<string name="error_creating_link_for_group">שגיאה ביצירת קישור קבוצה</string>
|
||||
<string name="error_deleting_link_for_group">שגיאה במחיקת קישור קבוצה</string>
|
||||
<string name="dont_show_again">אל תציג שוב</string>
|
||||
<string name="direct_messages">הודעות ישירות</string>
|
||||
<string name="timed_messages">הודעות נעלמות</string>
|
||||
<string name="feature_enabled">מופעל</string>
|
||||
<string name="feature_enabled_for_contact">מופעל עבור איש הקשר</string>
|
||||
<string name="feature_enabled_for_you">מופעל עבורך</string>
|
||||
<string name="disappearing_messages_are_prohibited">הודעות נעלמות אסורות בקבוצה זו.</string>
|
||||
<string name="ttl_min">%d דקה</string>
|
||||
<string name="ttl_s">%d שניות</string>
|
||||
<string name="v4_4_disappearing_messages">הודעות נעלמות</string>
|
||||
<string name="ttl_m">%d דקות</string>
|
||||
<string name="ttl_month">%d חודש</string>
|
||||
<string name="ttl_w">%d שבועות</string>
|
||||
<string name="ttl_week">%d שבוע</string>
|
||||
<string name="ttl_weeks">%d שבועות</string>
|
||||
<string name="v4_5_multiple_chat_profiles_descr">שמות שונים, אווטארים ובידוד תעבורה.</string>
|
||||
<string name="conn_level_desc_direct">ישיר</string>
|
||||
<string name="direct_messages_are_prohibited_in_chat">הודעות ישירות בין חברי קבוצה אסורות בקבוצה זו.</string>
|
||||
<string name="display_name">שם תצוגה</string>
|
||||
<string name="display_name_cannot_contain_whitespace">שם תצוגה אינו יכול להכיל רווחים.</string>
|
||||
<string name="ttl_months">%d חודשים</string>
|
||||
<string name="ttl_mth">%d חודשים</string>
|
||||
<string name="ttl_sec">%d שנייה</string>
|
||||
<string name="status_e2e_encrypted">הצפנה מקצה־לקצה</string>
|
||||
<string name="encrypted_video_call">שיחת וידאו מוצפנת מקצה־לקצה</string>
|
||||
<string name="icon_descr_edited">הודעה נערכה</string>
|
||||
<string name="encrypted_audio_call">שיחת שמע מוצפנת מקצה־לקצה</string>
|
||||
<string name="icon_descr_email">אימייל</string>
|
||||
<string name="allow_accepting_calls_from_lock_screen">אפשרו שיחות ממסך הנעילה דרך ההגדרות.</string>
|
||||
<string name="enter_passphrase">הזינו סיסמה…</string>
|
||||
<string name="enter_welcome_message_optional">הזינו הודעת פתיחה (אופציונלי)</string>
|
||||
<string name="enter_welcome_message">הזינו הודעת פתיחה…</string>
|
||||
<string name="error_deleting_contact">שגיאה במחיקת איש קשר</string>
|
||||
<string name="error_deleting_pending_contact_connection">שגיאה במחיקת חיבור איש קשר ממתין</string>
|
||||
<string name="error_loading_xftp_servers">שגיאה בטעינת שרתי XFTP</string>
|
||||
<string name="error_sending_message">שגיאה בשליחת הודעה</string>
|
||||
<string name="error_receiving_file">שגיאה בקבלת קובץ</string>
|
||||
<string name="error_saving_ICE_servers">שגיאה בשמירת שרתי ICE</string>
|
||||
<string name="settings_experimental_features">תכונות ניסיוניות</string>
|
||||
<string name="export_database">ייצא מסד נתונים</string>
|
||||
<string name="error_removing_member">שגיאה בהסרת חבר קבוצה</string>
|
||||
<string name="error_saving_group_profile">שגיאה בשמירת פרופיל קבוצה</string>
|
||||
<string name="error_saving_file">שגיאה בשמירת קובץ</string>
|
||||
<string name="exit_without_saving">יציאה ללא שמירה</string>
|
||||
<string name="error_stopping_chat">שגיאה בעצירת צ׳אט</string>
|
||||
<string name="error_saving_smp_servers">שגיאה בשמירת שרתי SMP</string>
|
||||
<string name="error_saving_xftp_servers">שגיאה בשמירת שרתי XFTP</string>
|
||||
<string name="failed_to_active_user_title">שגיאה בהחלפת פרופיל!</string>
|
||||
<string name="error_setting_network_config">שגיאה בעדכון תצורת הרשת</string>
|
||||
<string name="failed_to_parse_chat_title">טעינת הצ׳אט נכשלה</string>
|
||||
<string name="failed_to_parse_chats_title">טעינת הצ׳אטים נכשלה</string>
|
||||
<string name="error_setting_address">שגיאה בהגדרת כתובת</string>
|
||||
<string name="error_updating_user_privacy">שגיאה בעדכון פרטיות משתמש</string>
|
||||
<string name="error_saving_user_password">שגיאה בשמירת סיסמת משתמש</string>
|
||||
<string name="settings_section_title_experimenta">ניסיוני</string>
|
||||
<string name="error_starting_chat">שגיאה בהפעלת צ׳אט</string>
|
||||
<string name="error_with_info">שגיאה: %s</string>
|
||||
<string name="error_updating_link_for_group">שגיאה בעדכון קישור קבוצה</string>
|
||||
<string name="export_theme">ייצא ערכת צבעים</string>
|
||||
<string name="icon_descr_expand_role">הרחב בחירת תפקיד</string>
|
||||
<string name="file_will_be_received_when_contact_is_online">הקובץ ייתקבל כאשר איש הקשר יהיה מקוון, אנא חכו או בידקו מאוחר יותר!</string>
|
||||
<string name="full_name__field">שם מלא:</string>
|
||||
<string name="file_with_path">קובץ: %s</string>
|
||||
<string name="icon_descr_group_inactive">קבוצה לא פעילה</string>
|
||||
<string name="group_invitation_expired">פג תוקפה של ההזמנה לקבוצה</string>
|
||||
<string name="group_display_name_field">שם תצוגה של הקבוצה:</string>
|
||||
<string name="group_full_name_field">שם מלא של הקבוצה:</string>
|
||||
<string name="v4_2_group_links">קישורי קבוצה</string>
|
||||
<string name="icon_descr_file">קובץ</string>
|
||||
<string name="file_will_be_received_when_contact_completes_uploading">הקובץ ייתקבל כאשר איש הקשר יסיים להעלות אותו.</string>
|
||||
<string name="file_not_found">קובץ לא נמצא</string>
|
||||
<string name="file_saved">קובץ נשמר</string>
|
||||
<string name="alert_message_group_invitation_expired">ההזמנה לקבוצה כבר לא תקפה, היא הוסרה על ידי השולח.</string>
|
||||
<string name="group_link">קישור קבוצה</string>
|
||||
<string name="info_row_group">קבוצה</string>
|
||||
<string name="simplex_link_mode_full">קישור מלא</string>
|
||||
<string name="for_everybody">עבור כולם</string>
|
||||
<string name="choose_file">קובץ</string>
|
||||
<string name="from_gallery_button">מתוך גלריה</string>
|
||||
<string name="full_name_optional__prompt">שם מלא (אופציונלי)</string>
|
||||
<string name="files_and_media_section">קבצים ומדיה</string>
|
||||
<string name="group_member_status_group_deleted">קבוצה נמחקה</string>
|
||||
<string name="section_title_for_console">עבור מסוף הצ׳אט</string>
|
||||
<string name="v5_0_large_files_support_descr">מהיר וללא המתנה עד שהשולח יהיה מקוון!</string>
|
||||
<string name="v4_4_french_interface">ממשק צרפתית</string>
|
||||
<string name="v4_6_reduced_battery_usage">הפחתה נוספת בשימוש בסוללה</string>
|
||||
<string name="revoke_file__message">הקובץ יימחק מהשרתים.</string>
|
||||
<string name="icon_descr_flip_camera">הפוך מצלמה</string>
|
||||
<string name="icon_descr_help">עזרה</string>
|
||||
<string name="if_you_cannot_meet_in_person_show_QR_in_video_call_or_via_another_channel">אם לא ניתן להיפגש פנים אל פנים, <b>הציגו את קוד ה־QR בשיחת וידאו</b>, או שתפו את הקישור.</string>
|
||||
<string name="how_to">איך</string>
|
||||
<string name="how_to_use_your_servers">איך להשתמש בשרתים שלך</string>
|
||||
<string name="enter_one_ICE_server_per_line">שרתי ICE (אחד בכל שורה)</string>
|
||||
<string name="host_verb">לארח</string>
|
||||
<string name="hide_dev_options">מוסתר:</string>
|
||||
<string name="snd_group_event_group_profile_updated">פרופיל הקבוצה עודכן</string>
|
||||
<string name="group_profile_is_stored_on_members_devices">פרופיל הקבוצה מאוחסן במכשירי חברי הקבוצה, לא על השרתים.</string>
|
||||
<string name="all_app_data_will_be_cleared">כל נתוני האפליקציה יימחקו.</string>
|
||||
<string name="empty_chat_profile_is_created">פרופיל צ׳אט ריק עם השם שסופק ייווצר, והאפליקציה תיפתח כרגיל.</string>
|
||||
<string name="app_passcode_replaced_with_self_destruct">קוד הגישה לאפליקציה יוחלף עם קוד הגישה להשמדה עצמית.</string>
|
||||
<string name="v4_3_improved_privacy_and_security_desc">ניתן להסתיר את מסך האפליקציה במסך האפליקציות האחרונות.</string>
|
||||
<string name="v4_6_hidden_chat_profiles">פרופילי צ׳אט מוסתרים</string>
|
||||
<string name="v4_6_group_moderation">ניהול קבוצה</string>
|
||||
<string name="v4_6_group_welcome_message">הודעת פתיחה בקבוצה</string>
|
||||
<string name="alert_title_no_group">קבוצה לא נמצאה!</string>
|
||||
<string name="hide_notification">הסתר</string>
|
||||
<string name="notification_preview_mode_hidden">מוסתר</string>
|
||||
<string name="notification_display_mode_hidden_desc">הסתר איש קשר והודעה</string>
|
||||
<string name="hide_verb">הסתר</string>
|
||||
<string name="if_you_cannot_meet_in_person_scan_QR_in_video_call_or_ask_for_invitation_link">אם לא ניתן להיפגש פנים אל פנים, ניתן <b>לסרוק את קוד ה־QR בשיחת וידאו</b>, או שאיש הקשר שלך ישתף קישור הזמנה.</string>
|
||||
<string name="if_you_cant_meet_in_person">אם לא ניתן להיפגש פנים אל פנים, הציגו את קוד ה־QR בשיחת וידאו, או שתפו את הקישור.</string>
|
||||
<string name="how_to_use_simplex_chat">איך להשתמש בזה</string>
|
||||
<string name="email_invite_body">היי!
|
||||
\nאפשר להתחבר אליי דרך SimpleX Chat: %s</string>
|
||||
<string name="hidden_profile_password">סיסמת פרופיל מוסתרת</string>
|
||||
<string name="hide_profile">הסתר פרופיל</string>
|
||||
<string name="how_to_use_markdown">איך להשתמש במרקדאון</string>
|
||||
<string name="how_it_works">איך זה עובד</string>
|
||||
<string name="how_simplex_works">איך <xliff:g id="appName">SimpleX</xliff:g> עובדת</string>
|
||||
<string name="icon_descr_hang_up">נתק</string>
|
||||
<string name="settings_section_title_help">עזרה</string>
|
||||
<string name="delete_group_for_all_members_cannot_undo_warning">הקבוצה תימחק עבור כל חברי הקבוצה – לא ניתן לבטל זאת!</string>
|
||||
<string name="delete_group_for_self_cannot_undo_warning">הקבוצה תימחק עבורך – לא ניתן לבטל זאת!</string>
|
||||
<string name="user_hide">הסתר</string>
|
||||
<string name="group_preferences">העדפות קבוצה</string>
|
||||
<string name="group_members_can_delete">חברי הקבוצה יכולים למחוק באופן בלתי הפיך הודעות שנשלחו.</string>
|
||||
<string name="group_members_can_send_disappearing">חברי הקבוצה יכולים לשלוח הודעות נעלמות.</string>
|
||||
<string name="group_members_can_send_dms">חברי הקבוצה יכולים לשלוח הודעות ישירות.</string>
|
||||
<string name="group_members_can_send_voice">חברי הקבוצה יכולים לשלוח הודעות קוליות.</string>
|
||||
<string name="enable_self_destruct">אפשר השמדה עצמית</string>
|
||||
<string name="if_you_choose_to_reject_the_sender_will_not_be_notified">אם תבחרו לדחות השולח לא יקבל התראה על כך.</string>
|
||||
<string name="network_disable_socks_info">אם תאשרו, שרתי העברת ההודעות יוכלו לראות את ה־IP שלכם, וספק האינטרנט שלכם – את השרתים אליהם אתם מחוברים.</string>
|
||||
<string name="image_descr">תמונה</string>
|
||||
<string name="if_you_received_simplex_invitation_link_you_can_open_in_browser">אם קיבלתם קישור הזמנה ל־<xliff:g id="appName">SimpleX Chat</xliff:g>, תוכלו לפתוח אותו בדפדפן.</string>
|
||||
<string name="if_you_enter_self_destruct_code">אם תזינו את קוד הגישה להשמדה עצמית בעת פתיחת האפליקציה:</string>
|
||||
<string name="if_you_enter_passcode_data_removed">אם תזינו קוד גישה זה בעת פתיחת האפליקציה, כל נתוני האפליקציה יימחקו באופן בלתי הפיך!</string>
|
||||
<string name="image_saved">תמונה נשמרה בגלריה</string>
|
||||
<string name="gallery_image_button">תמונה</string>
|
||||
<string name="ignore">התעלם</string>
|
||||
<string name="la_immediately">מיד</string>
|
||||
<string name="import_database">ייבא מסד נתונים</string>
|
||||
<string name="immune_to_spam_and_abuse">חסין מפני ספאם ושימוש לרעה</string>
|
||||
<string name="import_database_question">לייבא מסד נתונים של צ׳אט\?</string>
|
||||
<string name="icon_descr_image_snd_complete">תמונה נשלחה</string>
|
||||
<string name="image_will_be_received_when_contact_completes_uploading">התמונה תתקבל כאשר איש הקשר יסיים להעלות אותה.</string>
|
||||
<string name="image_will_be_received_when_contact_is_online">התמונה תתקבל כאשר איש הקשר יהיה מקוון, אנא המתינו או בידקו מאוחר יותר!</string>
|
||||
<string name="import_database_confirmation">ייבא</string>
|
||||
<string name="import_theme">ייבא ערכת צבעים</string>
|
||||
<string name="import_theme_error">שגיאה בייבוא ערכת צבעים</string>
|
||||
<string name="group_unsupported_incognito_main_profile_sent">מצב זהות נסתרת אינו נתמך כאן – הפרופיל הראשי שלך יישלח לחברי הקבוצה</string>
|
||||
<string name="v4_3_improved_server_configuration">תצורת שרתים משופרת</string>
|
||||
<string name="v4_3_improved_privacy_and_security">פרטיות ואבטחה משופרים</string>
|
||||
<string name="settings_section_title_incognito">מצב זהות נסתרת</string>
|
||||
<string name="incognito">זהות נסתרת</string>
|
||||
<string name="description_via_contact_address_link_incognito">זהות נסתרת באמצעות קישור כתובת איש קשר</string>
|
||||
<string name="description_via_group_link_incognito">זהות נסתרת באמצעות קישור קבוצה</string>
|
||||
<string name="description_via_one_time_link_incognito">זהות נסתרת באמצעות קישור חד־פעמי</string>
|
||||
<string name="invalid_connection_link">קישור חיבור לא תקין</string>
|
||||
<string name="turn_off_battery_optimization">על מנת להשתמש בזה, אנא <b>השביתו מיטוב סוללה</b> עבור <xliff:g id="appName">SimpleX</xliff:g> בתיבת הדו־שיח הבאה. אחרת, ההתראות יושבתו.</string>
|
||||
<string name="service_notifications_disabled">התראות מיידיות מושבתות!</string>
|
||||
<string name="icon_descr_add_members">הזמן חברי קבוצה</string>
|
||||
<string name="group_member_status_invited">הוזמן</string>
|
||||
<string name="conn_level_desc_indirect">עקיף (<xliff:g id="conn_level">%1$s</xliff:g>)</string>
|
||||
<string name="incognito_info_protects">מצב זהות נסתרת מגן על התמונה והפרטיות של שם הפרופיל הראשי שלך – עבור כל איש קשר חדש נוצר פרופיל חדש אקראי.</string>
|
||||
<string name="incompatible_database_version">גרסת מסד נתונים לא תואמת</string>
|
||||
<string name="invalid_migration_confirmation">אישור העברת נתונים לא תקין</string>
|
||||
<string name="v4_3_irreversible_message_deletion">מחיקה בלתי הפיכה של הודעות</string>
|
||||
<string name="v4_5_italian_interface">ממשק איטלקית</string>
|
||||
<string name="smp_servers_invalid_address">כתובת שרת לא תקינה!</string>
|
||||
<string name="install_simplex_chat_for_terminal">התקנת <xliff:g id="appNameFull">SimpleX Chat</xliff:g> עבור מסוף הפקודה</string>
|
||||
<string name="invite_friends">הזמן חברים</string>
|
||||
<string name="italic">נטוי</string>
|
||||
<string name="invalid_chat">צ׳אט לא תקין</string>
|
||||
<string name="invalid_data">נתונים לא תקינים</string>
|
||||
<string name="invalid_message_format">פורמט הודעה לא תקין</string>
|
||||
<string name="display_name_invited_to_connect">הוזמן להתחבר</string>
|
||||
<string name="icon_descr_instant_notifications">התראות מיידיות</string>
|
||||
<string name="service_notifications">התראות מיידיות!</string>
|
||||
<string name="invalid_contact_link">קישור לא תקין!</string>
|
||||
<string name="invalid_QR_code">קוד QR לא תקין</string>
|
||||
<string name="incorrect_code">קוד אבטחה שגוי!</string>
|
||||
<string name="onboarding_notifications_mode_service">מיידית</string>
|
||||
<string name="incoming_audio_call">שיחת שמע נכנסת</string>
|
||||
<string name="incoming_video_call">שיחת וידאו נכנסת</string>
|
||||
<string name="incorrect_passcode">קוד גישה שגוי</string>
|
||||
<string name="group_invitation_item_description">הזמנה לקבוצה <xliff:g id="group_name">%1$s</xliff:g></string>
|
||||
<string name="alert_title_group_invitation_expired">פג תוקף ההזמנה!</string>
|
||||
<string name="rcv_group_event_member_added">הוזמן <xliff:g id="member profile" example="alice (Alice)">%1$s</xliff:g></string>
|
||||
<string name="rcv_group_event_invited_via_your_group_link">הוזמן באמצעות קישור הקבוצה שלך</string>
|
||||
<string name="initial_member_role">תפקיד ראשוני</string>
|
||||
<string name="invite_to_group_button">הזמן לקבוצה</string>
|
||||
<string name="button_add_members">הזמן חברי קבוצה</string>
|
||||
<string name="message_deletion_prohibited">מחיקה בלתי הפיכה של הודעות אסורה בצ׳אט זה.</string>
|
||||
<string name="message_deletion_prohibited_in_chat">מחיקה בלתי הפיכה של הודעות אסורה בקבוצה זו.</string>
|
||||
<string name="group_preview_join_as">להצטרף בתור %s</string>
|
||||
<string name="incognito_info_allows">זה מאפשר חיבורים אנונימיים רבים ללא שום נתונים משותפים ביניהם בפרופיל צ׳אט יחיד.</string>
|
||||
<string name="alert_text_skipped_messages_it_can_happen_when">זה יכול לקרות כאשר:
|
||||
\n1. פג תוקפן של ההודעות בלקוח השולח לאחר 2 ימים או בשרת לאחר 30 ימים.
|
||||
\n2. פיענוח הצפנת הודעה נכשל, מכיוון שאתם או איש הקשר שלכם השתמשתם בגיבוי ישן של מסד הנתונים.
|
||||
\n3. החיבור נפגע.</string>
|
||||
<string name="onboarding_notifications_mode_subtitle">ניתן לשנות זאת מאוחר יותר באמצעות ההגדרות.</string>
|
||||
<string name="alert_text_fragment_encryption_out_of_sync_old_database">זה יכול לקרות כאשר אתם או איש הקשר שלכם השתמשתם בגיבוי ישן של מסד הנתונים.</string>
|
||||
<string name="join_group_question">להצטרף לקבוצה\?</string>
|
||||
<string name="join_group_button">הצטרף</string>
|
||||
<string name="large_file">קובץ גדול!</string>
|
||||
<string name="thousand_abbreviation">אלף</string>
|
||||
<string name="ensure_ICE_server_address_are_correct_format_and_unique">ודאו שכתובות שרתי ה־WebRTC ICE הן בפורמט הנכון, מופרדות בשורה ולא משוכפלות.</string>
|
||||
<string name="v4_4_live_messages">הודעות חיות</string>
|
||||
<string name="live_message">הודעה חיה!</string>
|
||||
<string name="image_descr_link_preview">תצוגה מקדימה של קישור</string>
|
||||
<string name="make_private_connection">צור חיבור פרטי</string>
|
||||
<string name="lock_after">נעל אחרי</string>
|
||||
<string name="lock_mode">מצב נעילה</string>
|
||||
<string name="joining_group">מצטרף לקבוצה</string>
|
||||
<string name="leave_group_button">עזוב</string>
|
||||
<string name="make_profile_private">הפוך את הפרופיל לפרטי!</string>
|
||||
<string name="live">הודעה חיה</string>
|
||||
<string name="ensure_smp_server_address_are_correct_format_and_unique">ודאו שכתובות שרתי ה־SMP הן בפורמט הנכון, מופרדות בשורה ולא משוכפלות.</string>
|
||||
<string name="ensure_xftp_server_address_are_correct_format_and_unique">ודאו שכתובות שרתי ה־XFTP הן בפורמט הנכון, מופרדות בשורה ולא משוכפלות.</string>
|
||||
<string name="auth_log_in_using_credential">התחבר באמצעות האישור שלך</string>
|
||||
<string name="learn_more">למדו עוד</string>
|
||||
<string name="markdown_help">עזרה במרקדאון</string>
|
||||
<string name="email_invite_subject">בואו נדבר ב־Simplex Chat</string>
|
||||
<string name="many_people_asked_how_can_it_deliver">אנשים רבים שאלו: <i>אם ל־<xliff:g id="appName">SimpleX</xliff:g> אין מזהי משתמש, איך ניתן להעביר הודעות\?</i></string>
|
||||
<string name="keychain_error">שגיאת Keychain</string>
|
||||
<string name="join_group_incognito_button">הצטרף עם זהות נסתרת</string>
|
||||
<string name="leave_group_question">לעזוב קבוצה\?</string>
|
||||
<string name="rcv_group_event_member_left">עזב</string>
|
||||
<string name="group_member_status_left">עזב</string>
|
||||
<string name="button_leave_group">עזוב קבוצה</string>
|
||||
<string name="info_row_local_name">שם מקומי</string>
|
||||
<string name="users_delete_data_only">נתוני פרופיל מקומיים בלבד</string>
|
||||
<string name="theme_light">בהיר</string>
|
||||
<string name="import_theme_error_desc">ודאו שלקובץ יש תחביר YAML תקין. ייצאו ערכת צבעים כדי לקבל דוגמה למבנה תקין של קובץ ערכת צבעים.</string>
|
||||
<string name="message_delivery_error_desc">ככל הנראה איש קשר זה מחק את החיבור איתך.</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc_in_alert">ייעשה שימוש במארחי Onion כאשר יהיו זמינים.</string>
|
||||
<string name="network_use_onion_hosts_required_desc_in_alert">מארחי Onion יידרשו לחיבור.</string>
|
||||
<string name="moderated_item_description">מנוהל על ידי %s</string>
|
||||
<string name="la_no_app_password">אין קוד גישה לאפליקציה</string>
|
||||
<string name="videos_limit_desc">ניתן לשלוח רק 10 סרטונים בו־זמנית</string>
|
||||
<string name="images_limit_desc">ניתן לשלוח רק 10 תמונות בו־זמנית</string>
|
||||
<string name="notifications">התראות</string>
|
||||
<string name="only_group_owners_can_enable_voice">רק בעלי הקבוצות יכולים לאפשר הודעות קוליות.</string>
|
||||
<string name="no_details">ללא פרטים</string>
|
||||
<string name="ok">אישור</string>
|
||||
<string name="add_contact">קישור הזמנה חד־פעמי</string>
|
||||
<string name="markdown_in_messages">מרקדאון בהודעות</string>
|
||||
<string name="network_and_servers">רשת ושרתים</string>
|
||||
<string name="network_settings_title">הגדרות רשת</string>
|
||||
<string name="no_spaces">בלי רווחים!</string>
|
||||
<string name="new_database_archive">ארכיון מסד נתונים חדש</string>
|
||||
<string name="messages_section_title">הודעות</string>
|
||||
<string name="group_member_role_member">חבר קבוצה</string>
|
||||
<string name="group_member_role_observer">צופה</string>
|
||||
<string name="only_group_owners_can_change_prefs">רק בעלי הקבוצות יכולים לשנות העדפות קבוצה.</string>
|
||||
<string name="network_status">מצב רשת</string>
|
||||
<string name="chat_preferences_on">פעיל</string>
|
||||
<string name="chat_preferences_no">לא</string>
|
||||
<string name="chat_preferences_off">כבוי</string>
|
||||
<string name="only_you_can_delete_messages">רק אתם יכולים למחוק הודעות באופן בלתי הפיך (איש הקשר שלכם יכול לסמן אותן למחיקה).</string>
|
||||
<string name="only_you_can_send_voice">רק אתם יכולים לשלוח הודעות קוליות.</string>
|
||||
<string name="only_your_contact_can_send_voice">רק איש הקשר שלכם יכול לשלוח הודעות קוליות.</string>
|
||||
<string name="only_you_can_make_calls">רק אתם יכולים לבצע שיחות.</string>
|
||||
<string name="only_your_contact_can_make_calls">רק איש הקשר שלכם יכול לבצע שיחות.</string>
|
||||
<string name="new_in_version">חדש ב־%s</string>
|
||||
<string name="self_destruct_new_display_name">שם תצוגה חדש:</string>
|
||||
<string name="notifications_will_be_hidden">התראות יוצגו רק עד שהאפליקציה תופסק!</string>
|
||||
<string name="new_passphrase">סיסמה חדשה…</string>
|
||||
<string name="database_migrations">העברות נתונים: %s</string>
|
||||
<string name="no_contacts_to_add">אין אנשי קשר להוסיף</string>
|
||||
<string name="only_you_can_send_disappearing">רק אתם יכולים לשלוח הודעות נעלמות.</string>
|
||||
<string name="only_your_contact_can_send_disappearing">רק איש הקשר שלכם יכול לשלוח הודעות נעלמות.</string>
|
||||
<string name="only_your_contact_can_delete">רק איש הקשר שלכם יכול למחוק הודעות באופן בלתי הפיך (אתם יכולים לסמן אותן למחיקה).</string>
|
||||
<string name="v4_5_message_draft">טיוטת הודעה</string>
|
||||
<string name="v4_5_multiple_chat_profiles">פרופילי צ׳אט מרובים</string>
|
||||
<string name="v4_5_reduced_battery_usage_descr">שיפורים נוספים יגיעו בקרוב!</string>
|
||||
<string name="v4_6_reduced_battery_usage_descr">שיפורים נוספים יגיעו בקרוב!</string>
|
||||
<string name="v4_6_group_moderation_descr">כעת מנהלים יכולים:
|
||||
\n- למחוק הודעות של חברי קבוצה.
|
||||
\n- להשבית חברי קבוצה (תפקיד ”צופה”)</string>
|
||||
<string name="notification_new_contact_request">בקשה חדשה ליצירת קשר</string>
|
||||
<string name="notification_preview_new_message">הודעה חדשה</string>
|
||||
<string name="mark_read">סמן כנקרא</string>
|
||||
<string name="mark_unread">סמן כלא נקרא</string>
|
||||
<string name="one_time_link">קישור הזמנה חד־פעמי</string>
|
||||
<string name="muted_when_inactive">מושתק כאשר אין פעילות!</string>
|
||||
<string name="feature_offered_item_with_param">הוצע %s: %2s</string>
|
||||
<string name="marked_deleted_description">מסומן כנמחק</string>
|
||||
<string name="moderated_description">מנוהל</string>
|
||||
<string name="settings_notifications_mode_title">שירות התראות</string>
|
||||
<string name="settings_notification_preview_title">תצוגה מקדימה של התראות</string>
|
||||
<string name="notification_preview_mode_message">טקסט הודעה</string>
|
||||
<string name="message_delivery_error_title">שגיאת מסירת הודעה</string>
|
||||
<string name="moderate_verb">נהל</string>
|
||||
<string name="delete_message_cannot_be_undone_warning">ההודעה תימחק – לא ניתן לבטל זאת!</string>
|
||||
<string name="delete_message_mark_deleted_warning">ההודעה תסומן למחיקה. הנמענים יוכלו לחשוף הודעה זו.</string>
|
||||
<string name="mobile_tap_open_in_mobile_app_then_tap_connect_in_app">📱 נייד: הקישו <b>פתח באפליקציה</b>, ואז הקישו <b>התחבר</b> באפליקציה.</string>
|
||||
<string name="only_stored_on_members_devices">(מאוחסן רק על ידי חברי הקבוצה)</string>
|
||||
<string name="mute_chat">השתק</string>
|
||||
<string name="icon_descr_more_button">עוד</string>
|
||||
<string name="mark_code_verified">סמן מאומת</string>
|
||||
<string name="network_use_onion_hosts_no">לא</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc">ייעשה שימוש במארחי Onion כאשר יהיו זמינים.</string>
|
||||
<string name="network_use_onion_hosts_required_desc">מארחי Onion יידרשו לחיבור.</string>
|
||||
<string name="network_use_onion_hosts_no_desc">לא ייעשה שימוש במארחי Onion.</string>
|
||||
<string name="network_use_onion_hosts_no_desc_in_alert">לא ייעשה שימוש במארחי Onion.</string>
|
||||
<string name="callstatus_missed">שיחה שלא נענתה</string>
|
||||
<string name="only_client_devices_store_contacts_groups_e2e_encrypted_messages">רק מכשירי לקוח מאחסנים פרופילי משתמש, אנשי קשר, קבוצות, והודעות שנשלחו עם <b>הצפנה מקצה־לקצה דו־שכבתית</b>.</string>
|
||||
<string name="status_no_e2e_encryption">ללא הצפנה מקצה־לקצה</string>
|
||||
<string name="icon_descr_call_missed">שיחה שלא נענתה</string>
|
||||
<string name="new_passcode">קוד גישה חדש</string>
|
||||
<string name="settings_section_title_messages">הודעות וקבצים</string>
|
||||
<string name="old_database_archive">ארכיון מסד נתונים ישן</string>
|
||||
<string name="chat_item_ttl_none">לעולם לא</string>
|
||||
<string name="no_received_app_files">לא התקבלו או נשלחו קבצים</string>
|
||||
<string name="new_member_role">תפקיד חבר קבוצה</string>
|
||||
<string name="no_contacts_selected">לא נבחרו אנשי קשר</string>
|
||||
<string name="member_info_section_title_member">חבר קבוצה</string>
|
||||
<string name="member_will_be_removed_from_group_cannot_be_undone">חבר הקבוצה יוסר מהקבוצה – לא ניתן לבטל זאת!</string>
|
||||
<string name="user_mute">השתק</string>
|
||||
<string name="color_surface">תפריטים והתראות</string>
|
||||
<string name="feature_off">כבוי</string>
|
||||
<string name="v4_3_voice_messages_desc">מקסימום 40 שניות, מתקבל מיידית.</string>
|
||||
<string name="feature_offered_item">הוצע %s</string>
|
||||
<string name="both_you_and_your_contact_can_add_message_reactions">גם אתם וגם איש הקשר יכולים להוסיף תגובות אמוג׳י להודעות.</string>
|
||||
<string name="message_reactions">תגובות אמוג׳י להודעות</string>
|
||||
<string name="allow_message_reactions">אפשר תגובות אמוג׳י להודעות.</string>
|
||||
<string name="message_reactions_prohibited_in_this_chat">תגובות אמוג׳י להודעות אסורות בצ׳אט זה.</string>
|
||||
<string name="message_reactions_are_prohibited">תגובות אמוג׳י להודעות אסורות בקבוצה זו.</string>
|
||||
<string name="allow_your_contacts_adding_message_reactions">אפשר לאנשי הקשר להוסיף תגובות אמוג׳י להודעות.</string>
|
||||
<string name="allow_message_reactions_only_if">אפשר תגובות אמוג׳י להודעות רק אם איש הקשר מאפשר אותן.</string>
|
||||
<string name="group_members_can_add_message_reactions">חברי הקבוצה יכולים להוסיף תגובות אמוג׳י להודעות.</string>
|
||||
<string name="only_you_can_add_message_reactions">רק אתם יכולים להוסיף תגובות אמוג׳י להודעות.</string>
|
||||
<string name="only_your_contact_can_add_message_reactions">רק איש הקשר שלכם יכול להוסיף תגובות אמוג׳י להודעות.</string>
|
||||
<string name="open_verb">פתח</string>
|
||||
<string name="prohibit_message_reactions">לאסור תגובות אמוג׳י להודעות.</string>
|
||||
<string name="send_disappearing_message_1_minute">דקה</string>
|
||||
<string name="send_disappearing_message_30_seconds">30 שניות</string>
|
||||
<string name="send_disappearing_message_5_minutes">5 דקות</string>
|
||||
<string name="send_disappearing_message_custom_time">זמן מותאם אישית</string>
|
||||
<string name="disappearing_message">הודעה נעלמת</string>
|
||||
<string name="toast_permission_denied">ההרשאה נדחתה!</string>
|
||||
<string name="image_descr_profile_image">תמונת פרופיל</string>
|
||||
<string name="profile_update_will_be_sent_to_contacts">עדכון הפרופיל יישלח לאנשי הקשר שלך.</string>
|
||||
<string name="open_simplex_chat_to_accept_call">פיתחו את <xliff:g id="appNameFull">Simplex Chat</xliff:g> כדי לענות לשיחה.</string>
|
||||
<string name="v4_5_message_draft_descr">שמירת טיוטת ההודעה האחרונה, עם קבצים מצורפים.</string>
|
||||
<string name="prohibit_message_reactions_group">לאסור תגובות אמוג׳י להודעות.</string>
|
||||
<string name="v4_5_private_filenames">שמות קבצים פרטיים</string>
|
||||
<string name="custom_time_unit_hours">שעות</string>
|
||||
<string name="custom_time_unit_minutes">דקות</string>
|
||||
<string name="custom_time_unit_days">ימים</string>
|
||||
<string name="custom_time_unit_months">חודשים</string>
|
||||
<string name="restore_passphrase_not_found_desc">סיסמת מסד הנתונים לא נמצאה ב־Keystore, יש להזין אותה ידנית. זה יכול לקרות אם נתוני האפליקציה שוחזרו על ידי כלי גיבוי. אם זה לא המקרה, אנא, תיצרו קשר עם המפתחים.</string>
|
||||
<string name="contact_developers">אנא עדכנו את האפליקציה וצרו קשר עם המפתחים.</string>
|
||||
<string name="please_check_correct_link_and_maybe_ask_for_a_new_one">אנא ודאו שהשתמשתם בקישור הנכון או בקשו מאיש הקשר שלכם לשלוח קישור נוסף.</string>
|
||||
<string name="periodic_notifications">התראות תקופתיות</string>
|
||||
<string name="enter_passphrase_notification_title">נדרשת סיסמה</string>
|
||||
<string name="la_lock_mode_passcode">הזנת קוד גישה</string>
|
||||
<string name="paste_button">הדבק</string>
|
||||
<string name="port_verb">פורט</string>
|
||||
<string name="network_proxy_port">פורט %d</string>
|
||||
<string name="privacy_and_security">פרטיות ואבטחה</string>
|
||||
<string name="passcode_set">קוד גישה הוגדר!</string>
|
||||
<string name="passcode_not_changed">קוד גישה לא השתנה!</string>
|
||||
<string name="passcode_changed">קוד גישה השתנה!</string>
|
||||
<string name="network_option_ping_count">ספירת PING</string>
|
||||
<string name="prohibit_sending_disappearing_messages">לאסור שליחת הודעות נעלמות.</string>
|
||||
<string name="prohibit_calls">לאסור שיחות שמע/וידאו.</string>
|
||||
<string name="enter_correct_current_passphrase">נא להזין את הסיסמה הנכונה הנוכחית.</string>
|
||||
<string name="periodic_notifications_disabled">התראות תקופתיות מושבתות!</string>
|
||||
<string name="network_option_ping_interval">מרווח PING</string>
|
||||
<string name="la_please_remember_to_store_password">אנא זיכרו או שימרו את הסיסמה בצורה מאובטחת – אין דרך לשחזר סיסמה אבודה!</string>
|
||||
<string name="observer_cant_send_message_desc">אנא צרו קשר עם מנהל הקבוצה.</string>
|
||||
<string name="ask_your_contact_to_enable_voice">אנא בקשו מאיש הקשר שלכם לאפשר שליחת הודעות קוליות.</string>
|
||||
<string name="icon_descr_profile_image_placeholder">שומר מקום לתמונת פרופיל</string>
|
||||
<string name="smp_servers_preset_server">שרת מוגדר מראש</string>
|
||||
<string name="privacy_redefined">פרטיות מוגדרת מחדש</string>
|
||||
<string name="people_can_connect_only_via_links_you_share">אנשים יכולים להתחבר אליכם רק דרך הקישורים שאתם משתפים.</string>
|
||||
<string name="opensource_protocol_and_code_anybody_can_run_servers">פרוטוקול וקוד פתוחים – כל אחד יכול להריץ את השרתים.</string>
|
||||
<string name="onboarding_notifications_mode_periodic">תקופתי</string>
|
||||
<string name="restore_database_alert_desc">נא להזין את הסיסמה הקודמת לאחר שחזור גיבוי מסד הנתונים, לא ניתן לבטל פעולה זו.</string>
|
||||
<string name="prohibit_message_deletion">לאסור מחיקה בלתי הפיכה של הודעות.</string>
|
||||
<string name="opening_database">פותח מסד נתונים…</string>
|
||||
<string name="simplex_link_mode_browser_warning">פתיחת הקישור בדפדפן עלולה להפחית את פרטיות ואבטחת החיבור. קישורי SimpleX לא מהימנים יהיו אדומים.</string>
|
||||
<string name="network_error_desc">אנא בידקו את חיבור האינטרנט שלכם עם <xliff:g id="serverHost" example="smp.simplex.im">%1$s</xliff:g> ונסו שוב.</string>
|
||||
<string name="error_smp_test_certificate">ייתכן שטביעת האצבע של התעודה בכתובת השרת שגויה</string>
|
||||
<string name="auth_open_chat_console">פתיחת מסוף צ׳אט</string>
|
||||
<string name="auth_open_chat_profiles">פתיחת פרופילי צ׳אט</string>
|
||||
<string name="icon_descr_server_status_pending">ממתין</string>
|
||||
<string name="paste_connection_link_below_to_connect">הדביקו את הקישור שקיבלתם בתיבה למטה כדי להתחבר לאיש הקשר שלכם.</string>
|
||||
<string name="smp_servers_preset_address">כתובת שרת מוגדר מראש</string>
|
||||
<string name="password_to_show">סיסמה להצגה</string>
|
||||
<string name="onboarding_notifications_mode_title">התראות פרטיות</string>
|
||||
<string name="paste_the_link_you_received">הדבק קישור שהתקבל</string>
|
||||
<string name="call_connection_peer_to_peer">עמית־לעמית</string>
|
||||
<string name="icon_descr_call_pending_sent">שיחה ממתינה</string>
|
||||
<string name="alert_text_fragment_please_report_to_developers">אנא דווחו על כך למפתחים.</string>
|
||||
<string name="la_mode_passcode">קוד גישה</string>
|
||||
<string name="store_passphrase_securely_without_recover">אנא שימרו את הסיסמה בצורה מאובטחת, לא תוכלו לגשת לצ׳אט אם תאבדו אותה.</string>
|
||||
<string name="store_passphrase_securely">אנא שימרו את הסיסמה בצורה מאובטחת, לא תוכלו לשנות אותה אם תאבדו אותה.</string>
|
||||
<string name="open_chat">פתח צ׳אט</string>
|
||||
<string name="group_member_role_owner">בעלים</string>
|
||||
<string name="group_welcome_preview">תצוגה מקדימה</string>
|
||||
<string name="users_delete_with_connections">פרופיל וחיבורי שרתים</string>
|
||||
<string name="profile_password">סיסמת פרופיל</string>
|
||||
<string name="prohibit_direct_messages">לאסור שליחת הודעות ישירות לחברי הקבוצה.</string>
|
||||
<string name="v5_0_polish_interface">ממשק פולנית</string>
|
||||
<string name="v4_6_hidden_chat_profiles_descr">הגנו על פרופילי הצ׳אט שלכם באמצעות סיסמה!</string>
|
||||
<string name="protect_app_screen">הגנה על מסך האפליקציה</string>
|
||||
<string name="prohibit_sending_voice">לאסור שליחת הודעות קוליות.</string>
|
||||
<string name="prohibit_sending_voice_messages">לאסור שליחת הודעות קוליות.</string>
|
||||
<string name="prohibit_sending_disappearing">לאסור שליחת הודעות נעלמות.</string>
|
||||
<string name="receiving_files_not_yet_supported">קבלת קבצים אינה נתמכת עדיין</string>
|
||||
<string name="image_descr_qr_code">קוד QR</string>
|
||||
<string name="callstatus_rejected">שיחה נדחתה</string>
|
||||
<string name="callstate_received_answer">התקבלה תשובה…</string>
|
||||
<string name="callstate_received_confirmation">התקבל אישור…</string>
|
||||
<string name="reject">דחיה</string>
|
||||
<string name="remove_passphrase">הסר</string>
|
||||
<string name="receiving_via">מקבל באמצעות</string>
|
||||
<string name="network_option_protocol_timeout">תום זמן הפרוטוקול</string>
|
||||
<string name="rcv_group_event_member_deleted"><xliff:g id="member profile" example="alice (Alice)">%1$s</xliff:g> הוסר/ה</string>
|
||||
<string name="color_received_message">הודעה שהתקבלה</string>
|
||||
<string name="v4_4_live_messages_desc">נמענים רואים הודעות תוך כדי הקלדתן.</string>
|
||||
<string name="v4_5_reduced_battery_usage">שימוש מופחת בסוללה</string>
|
||||
<string name="custom_time_picker_custom">מותאם אישית</string>
|
||||
<string name="simplex_service_notification_text">מקבל הודעות…</string>
|
||||
<string name="stop_rcv_file__message">קבלת הקובץ תופסק.</string>
|
||||
<string name="icon_descr_record_voice_message">הקלט הודעה קולית</string>
|
||||
<string name="reject_contact_button">דחיה</string>
|
||||
<string name="read_more_in_user_guide_with_link">קראו עוד ב<font color="#0088ff">מדריך למשתמש</font>.</string>
|
||||
<string name="rate_the_app">דרגו את האפליקציה</string>
|
||||
<string name="read_more_in_github">קראו עוד ב־GitHub repository שלנו.</string>
|
||||
<string name="read_more_in_github_with_link">קראו עוד ב־<font color="#0088ff">GitHub repository</font> שלנו.</string>
|
||||
<string name="relay_server_if_necessary">יבוצע שימוש בשרת ממסר רק במידת הצורך. גורם אחר יכול לצפות בכתובת ה־IP שלך.</string>
|
||||
<string name="relay_server_protects_ip">שרת ממסר מגן על כתובת ה־IP שלך, אך הוא יכול לראות את משך השיחה.</string>
|
||||
<string name="icon_descr_call_rejected">שיחה נדחתה</string>
|
||||
<string name="rcv_group_event_user_deleted">הסירו אותך</string>
|
||||
<string name="group_member_status_removed">הוסר</string>
|
||||
<string name="button_remove_member">הסר חבר קבוצה</string>
|
||||
<string name="remove_member_confirmation">הסר</string>
|
||||
<string name="feature_received_prohibited">התקבל, לא מאופשר</string>
|
||||
<string name="enabled_self_destruct_passcode">יצירת קוד גישה להשמדה עצמית</string>
|
||||
<string name="change_self_destruct_mode">שינוי מצב השמדה עצמית</string>
|
||||
<string name="change_self_destruct_passcode">שנה קוד גישה להשמדה עצמית</string>
|
||||
<string name="share_text_database_id">מזהה מסד נתונים: %d</string>
|
||||
<string name="share_text_deleted_at">נמחק ב: %s</string>
|
||||
<string name="share_text_disappears_at">ייעלם ב: %s</string>
|
||||
<string name="v5_1_self_destruct_passcode_descr">כל הנתונים נמחקים בהזנת הקוד.</string>
|
||||
<string name="v5_1_better_messages">הודעות משופרות</string>
|
||||
<string name="v5_1_custom_themes_descr">התאימו אישית ושתפו ערכות צבעים.</string>
|
||||
<string name="v5_1_custom_themes">ערכות צבעים מותאמות אישית</string>
|
||||
<string name="item_info_current">(נוכחי)</string>
|
||||
<string name="info_row_deleted_at">נמחק</string>
|
||||
<string name="info_row_disappears_at">ייעלם</string>
|
||||
</resources>
|
||||
@@ -11,9 +11,9 @@
|
||||
<string name="about_simplex">SimpleXについて</string>
|
||||
<string name="a_plus_b">a + b</string>
|
||||
<string name="about_simplex_chat"><xliff:g id="appNameFull">SimpleX Chat</xliff:g>について</string>
|
||||
<string name="color_primary">アクセント色</string>
|
||||
<string name="color_primary">アクセントカラー</string>
|
||||
<string name="accept_contact_button">承諾</string>
|
||||
<string name="accept_connection_request__question">繋がりを承諾しますか?</string>
|
||||
<string name="accept_connection_request__question">接続リクエストを承認しますか?</string>
|
||||
<string name="accept">承諾</string>
|
||||
<string name="accept_feature">承諾</string>
|
||||
<string name="accept_call_on_lock_screen">承諾</string>
|
||||
@@ -22,7 +22,7 @@
|
||||
<string name="smp_servers_add_to_another_device">別の端末に追加</string>
|
||||
<string name="users_add">プロフィールを追加</string>
|
||||
<string name="smp_servers_add">サーバを追加…</string>
|
||||
<string name="network_enable_socks_info">SOCKSプロキシ(ポート9050)経由で接続しますか?(※設定する前にプロキシ起動が必要※)</string>
|
||||
<string name="network_enable_socks_info">SOCKSプロキシ(ポート%d)経由で接続しますか?(※設定する前にプロキシ起動が必要※)</string>
|
||||
<string name="users_delete_all_chats_deleted">全チャットとメッセージが削除されます(※元に戻せません※)!</string>
|
||||
<string name="allow_your_contacts_to_send_voice_messages">送信相手からの音声メッセージを許可する。</string>
|
||||
<string name="both_you_and_your_contact_can_send_voice">あなたと連絡相手が音声メッセージを送信できます。</string>
|
||||
@@ -31,8 +31,6 @@
|
||||
<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>
|
||||
@@ -79,7 +77,7 @@
|
||||
<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="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>
|
||||
@@ -190,7 +188,7 @@
|
||||
<string name="icon_descr_close_button">閉じるボタン</string>
|
||||
<string name="clear_verification">検証を消す</string>
|
||||
<string name="image_saved">画像をギャラリーに保存しました。</string>
|
||||
<string name="choose_file">ファイルを選ぶ</string>
|
||||
<string name="choose_file">ファイル</string>
|
||||
<string name="clear_chat_menu_action">消す</string>
|
||||
<string name="image_will_be_received_when_contact_is_online">連絡先がオンラインになったら受信されます。しばらくお待ちください。</string>
|
||||
<string name="v4_4_verify_connection_security_desc">連絡先とセキュリティコードを確認</string>
|
||||
@@ -227,7 +225,6 @@
|
||||
<string name="contact_preferences">連絡先の設定</string>
|
||||
<string name="status_contact_has_no_e2e_encryption">連絡先はエンドツーエンド暗号化がありません。</string>
|
||||
<string name="alert_title_contact_connection_pending">連絡先がまだ繋がってません!</string>
|
||||
<string name="contact_requests">連絡先のリクエスト</string>
|
||||
<string name="icon_descr_context">追加情報アイコン</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc">オニオンのホストが利用可能時に使われます。</string>
|
||||
<string name="network_use_onion_hosts_no_desc">オニオンのホストが使われません。</string>
|
||||
@@ -242,7 +239,7 @@
|
||||
<string name="only_your_contact_can_delete">メッセージを完全削除できるのはあなたの連絡相手だけです (あなたは削除対象とすることができます)。</string>
|
||||
<string name="open_chat">チャットを開く</string>
|
||||
<string name="only_your_contact_can_send_voice">音声メッセージを送れるのはあなたの連絡相手だけです。</string>
|
||||
<string name="database_encryption_will_be_updated">データベース暗号化の暗号フレーズが更新され、キーストア (暗証キー保管庫)に保存されます。</string>
|
||||
<string name="database_encryption_will_be_updated">データベース暗号化のパスフレーズが更新され、キーストア (暗証キー保管庫)に保存されます。</string>
|
||||
<string name="database_error">データベースエラー</string>
|
||||
<string name="set_password_to_export_desc">データベースはランダムな暗証フレーズで暗号化済みです。エキスポートする前に更新してください。</string>
|
||||
<string name="passphrase_is_different">データベース暗証フレーズはキーストア (暗証キー保管庫) に保存された暗証フレーズと異なります。</string>
|
||||
@@ -359,7 +356,7 @@
|
||||
<string name="settings_section_title_chats">チャット</string>
|
||||
<string name="settings_developer_tools">開発ツール</string>
|
||||
<string name="settings_experimental_features">β機能</string>
|
||||
<string name="settings_section_title_messages">メッセージ</string>
|
||||
<string name="settings_section_title_messages">メッセージとファイル</string>
|
||||
<string name="settings_section_title_calls">通話</string>
|
||||
<string name="chat_is_running">チャットは稼働中</string>
|
||||
<string name="chat_is_stopped">チャットが停止してます。</string>
|
||||
@@ -375,15 +372,15 @@
|
||||
<string name="encrypt_database">暗号化する</string>
|
||||
<string name="remove_passphrase">削除</string>
|
||||
<string name="current_passphrase">現在の暗証フレーズ</string>
|
||||
<string name="encrypted_with_random_passphrase">データベースはランダムな暗証フレーズで暗号化済みで、変更可能です。</string>
|
||||
<string name="encrypted_with_random_passphrase">データベースはランダムなパスフレーズで暗号化済みで、変更可能です。</string>
|
||||
<string name="change_database_passphrase_question">データベースの暗証フレーズを更新しますか?</string>
|
||||
<string name="database_will_be_encrypted">データベースが暗号化されます。</string>
|
||||
<string name="database_will_be_encrypted_and_passphrase_stored">データベースが暗号化され、暗証フレーズがキーストア (暗証キー保管庫) にほぞんされます。</string>
|
||||
<string name="database_will_be_encrypted_and_passphrase_stored">データベースが暗号化され、パスフレーズがキーストア (暗証キー保管庫) にほぞんされます。</string>
|
||||
<string name="cannot_access_keychain">キーストア (暗証キーの保管庫) にアクセスできないため、データベースのパスワードが保存できません。</string>
|
||||
<string name="database_passphrase_will_be_updated">データベース暗号化の暗号フレーズが更新されます。</string>
|
||||
<string name="database_passphrase_will_be_updated">データベース暗号化のパスフレーズが更新されます。</string>
|
||||
<string name="database_passphrase_is_required">チャットを開くにはデータベース暗証フレーズが必要です。</string>
|
||||
<string name="file_with_path">ファイル: %s</string>
|
||||
<string name="archive_created_on_ts">作成日時 \u0020<xliff:g id="archive_ts">%1$s</xliff:g></string>
|
||||
<string name="archive_created_on_ts">作成日時 <xliff:g id="archive_ts">%1$s</xliff:g></string>
|
||||
<string name="delete_archive">アーカイブを削除</string>
|
||||
<string name="join_group_button">参加</string>
|
||||
<string name="join_group_question">グループに参加しますか?</string>
|
||||
@@ -400,7 +397,7 @@
|
||||
<string name="group_member_status_connected">接続中</string>
|
||||
<string name="group_member_status_announced">接続待ち (アナウンス済み)</string>
|
||||
<string name="icon_descr_contact_checked">連絡先が確認済み</string>
|
||||
<string name="delete_group_question">グループを削除をしますか?</string>
|
||||
<string name="delete_group_question">グループを削除しますか?</string>
|
||||
<string name="delete_link">リンクを削除</string>
|
||||
<string name="group_member_status_group_deleted">グループ削除済み</string>
|
||||
<string name="delete_group_for_all_members_cannot_undo_warning">全員にとってグループが削除されます (※元に戻せません※)!</string>
|
||||
@@ -467,7 +464,7 @@
|
||||
<string name="remove_passphrase_from_keychain">キーストア (暗証キー保管庫) を削除しますか?</string>
|
||||
<string name="database_encrypted">データベースは暗号化済み!</string>
|
||||
<string name="error_encrypting_database">データベース暗号化ににエラー発生</string>
|
||||
<string name="confirm_new_passphrase">新しい暗証フレーズを確認…</string>
|
||||
<string name="confirm_new_passphrase">新しいパスフレーズを確認…</string>
|
||||
<string name="encrypt_database_question">データベースを暗号化しますか?</string>
|
||||
<string name="store_passphrase_securely_without_recover">暗証フレーズを失くさないように保管してください。失くすとチャットにアクセスできなくなります。</string>
|
||||
<string name="enter_correct_passphrase">正しい暗証フレーズを入力</string>
|
||||
@@ -559,12 +556,10 @@
|
||||
<string name="reject">拒否</string>
|
||||
<string name="call_connection_peer_to_peer">P2P</string>
|
||||
<string name="privacy_and_security">プライバシーとセキュリティ</string>
|
||||
<string name="alert_text_skipped_messages_it_can_happen_when">次の場合に起こりうる:
|
||||
\n① メッセージが受信せずにサーバに溜まって30日が経つ場合
|
||||
\n② 連絡相手からメッセージが送信中に、ご利用の受信サーバが更新・再起動する場合
|
||||
\n③ 接続が不安定の場合
|
||||
\nサーバの更新情報をご希望でしたら、設定にて開発者とお繋ぎください。
|
||||
\nメッセージの喪失を防ぐために、サーバ冗長性を向上してまいります。</string>
|
||||
<string name="alert_text_skipped_messages_it_can_happen_when">次の場合に起こる場合があります:
|
||||
\n① メッセージの有効期限(送信側のクライアントでは2日後、サーバーでは30日後)が切れた
|
||||
\n②あなたや 連絡相手が古いデータベースのバックアップを使用したため、メッセージの復号化に失敗した
|
||||
\n③ 接続に問題があった</string>
|
||||
<string name="settings_section_title_device">端末</string>
|
||||
<string name="no_received_app_files">送受信済みのファイルがありません</string>
|
||||
<string name="delete_messages">メッセージを削除</string>
|
||||
@@ -642,7 +637,7 @@
|
||||
<string name="new_member_role">新しいメンバー役割</string>
|
||||
<string name="no_contacts_to_add">追加できる連絡先がありません</string>
|
||||
<string name="button_delete_group">グループを削除</string>
|
||||
<string name="create_group_link">グループのリンクを発行する</string>
|
||||
<string name="create_group_link">グループのリンクを生成する</string>
|
||||
<string name="button_edit_group_profile">グループのプロフィールを編集</string>
|
||||
<string name="delete_group_for_self_cannot_undo_warning">あなたにとってグループが削除されます (※元に戻せません※)!</string>
|
||||
<string name="button_leave_group">グループを脱退</string>
|
||||
@@ -719,7 +714,7 @@
|
||||
<string name="to_share_with_your_contact">(連絡先に共有)</string>
|
||||
<string name="connect_via_link_or_qr_from_clipboard_or_in_person">(クリップボードから読み込むか、貼り付ける)</string>
|
||||
<string name="thank_you_for_installing_simplex"><xliff:g id="appNameFull">SimpleX Chat</xliff:g>をご利用いただきありがとうございます!</string>
|
||||
<string name="use_camera_button">カメラ起動</string>
|
||||
<string name="use_camera_button">カメラ</string>
|
||||
<string name="you_accepted_connection">繋がりを承認しました</string>
|
||||
<string name="you_invited_your_contact">連絡先に招待を送りました</string>
|
||||
<string name="connection_you_accepted_will_be_cancelled">承認ずみの接続がキャンセルされます!</string>
|
||||
@@ -729,17 +724,15 @@
|
||||
<string name="this_link_is_not_a_valid_connection_link">このリンクは有効な接続リンクではありません!</string>
|
||||
<string name="this_QR_code_is_not_a_link">このQRコードはリンクではありません!</string>
|
||||
<string name="you_will_be_connected_when_group_host_device_is_online">グループのホスト端末がオンラインになったら、接続されます。後でチェックするか、しばらくお待ちください。</string>
|
||||
<string name="show_QR_code_for_your_contact_to_scan_from_the_app__multiline">連絡相手がアプリからQRコードを読み込めます。</string>
|
||||
<string name="you_will_be_connected_when_your_contacts_device_is_online">連絡先がオンラインになったら、接続されます。後でチェックするか、しばらくお待ちください。</string>
|
||||
<string name="your_chat_profile_will_be_sent_to_your_contact">あなたのチャットプロフィールが
|
||||
\n連絡相手に送られます。</string>
|
||||
<string name="share_invitation_link">招待リンクを送る</string>
|
||||
<string name="share_invitation_link">ワンタイムリンクを送る</string>
|
||||
<string name="your_profile_will_be_sent">あなたのチャットプロフィールが連絡相手に送られます。</string>
|
||||
<string name="scan_code">コードを読み込む</string>
|
||||
<string name="scan_code_from_contacts_app">連絡相手のアプリからセキュリティコードを読み込む</string>
|
||||
<string name="chat_lock">SimpleXロック</string>
|
||||
<string name="is_not_verified">%s は未認証</string>
|
||||
<string name="your_contact_address">あなたのチャットアドレス</string>
|
||||
<string name="is_not_verified">%s は未検証</string>
|
||||
<string name="your_settings">あなたの設定</string>
|
||||
<string name="smp_servers_test_server">テストサーバ</string>
|
||||
<string name="smp_servers_save">サーバを保存</string>
|
||||
@@ -753,7 +746,6 @@
|
||||
<string name="your_ICE_servers">あなたのICEサーバ</string>
|
||||
<string name="network_disable_socks">直接にインタネットに繋がりますか?</string>
|
||||
<string name="network_enable_socks">SOCKSプロキシを使いますか?</string>
|
||||
<string name="network_socks_toggle">SOCKSプロキシ (ポート9050) を使う</string>
|
||||
<string name="update_onion_hosts_settings_question">.onionのホスト設定を更新しますか?</string>
|
||||
<string name="network_use_onion_hosts">.onionホストを使う</string>
|
||||
<string name="network_use_onion_hosts_prefer">利用可能時に</string>
|
||||
@@ -890,8 +882,6 @@
|
||||
<string name="using_simplex_chat_servers"><xliff:g id="appNameFull">SimpleX Chat</xliff:g>を使っています。</string>
|
||||
<string name="share_link">リンクを送る</string>
|
||||
<string name="core_simplexmq_version">simplexmq: バージョン%s (%2s)</string>
|
||||
<string name="you_can_share_your_address_anybody_will_be_able_to_connect">あなたと繋がるリンク、またはQRコードを共有できます。誰でも接続できます。後で削除しても、連絡先がそのままのこります。</string>
|
||||
<string name="section_title_welcome_message">歓迎メッセージ</string>
|
||||
<string name="callstate_waiting_for_answer">応答待ち…</string>
|
||||
<string name="callstate_waiting_for_confirmation">確認待ち…</string>
|
||||
<string name="first_platform_without_user_ids">世界初のユーザーIDのないプラットフォーム|設計も元からプライベート</string>
|
||||
@@ -916,7 +906,7 @@
|
||||
<string name="restore_database_alert_title">データベースを復元しますか?</string>
|
||||
<string name="save_and_notify_group_members">保存して、グループのメンバーにに知らせる</string>
|
||||
<string name="send_us_an_email">メールを送る</string>
|
||||
<string name="share_image">画像共有…</string>
|
||||
<string name="share_image">メディア共有…</string>
|
||||
<string name="simplex_link_mode">SimpleXリンク</string>
|
||||
<string name="settings_section_title_support">SIMPLEX CHATを支援</string>
|
||||
<string name="smp_servers_test_servers">テストサーバ</string>
|
||||
@@ -935,12 +925,12 @@
|
||||
<string name="image_descr_simplex_logo"><xliff:g id="appName">SimpleX</xliff:g>ロゴ</string>
|
||||
<string name="you_need_to_allow_to_send_voice">音声メッセージを送るには、連絡相手からの音声メッセージを許可しなければなりません。</string>
|
||||
<string name="you_must_use_the_most_recent_version_of_database">あなたの最新データベースを1つの端末にしか使わなければ、一部の連絡先からメッセージが届きかねます。</string>
|
||||
<string name="you_are_already_connected_to_vName_via_this_link">既に繋がってます: <xliff:g id="contactName" example="Alice">%1$s!</xliff:g></string>
|
||||
<string name="you_are_already_connected_to_vName_via_this_link">既に繋がってます: <xliff:g id="contactName" example="Alice">%1$s</xliff:g></string>
|
||||
<string name="alert_title_cant_invite_contacts_descr">シークレットモードのプロフィールでこのグループに参加しています。メインのプロフィールを守るために、招待することができません。</string>
|
||||
<string name="description_you_shared_one_time_link">使い捨てリンクを送りました</string>
|
||||
<string name="profile_will_be_sent_to_contact_sending_link">リンクを送ってくれた連絡先にあなたのプロフィールを送ります。</string>
|
||||
<string name="your_SMP_servers">あなたのSMPサーバ</string>
|
||||
<string name="your_simplex_contact_address">あなたの<xliff:g id="appName">SimpleX</xliff:g>アドレス</string>
|
||||
<string name="your_simplex_contact_address">あなたのSimpleXアドレス</string>
|
||||
<string name="you_will_be_connected_when_your_connection_request_is_accepted">連絡先が繋がりリクエストを承認したら、接続されます。後でチェックするか、しばらくお待ちください。</string>
|
||||
<string name="switch_receiving_address">受信アドレスを変える</string>
|
||||
<string name="incognito_random_profile">あなたのランダム・プロフィール</string>
|
||||
@@ -957,4 +947,318 @@
|
||||
<string name="select_contacts">連絡先を選択</string>
|
||||
<string name="skip_inviting_button">今はメンバーを招待しません</string>
|
||||
<string name="group_info_section_title_num_members"><xliff:g id="num_members">%1$s</xliff:g>メンバー</string>
|
||||
<string name="xftp_servers">XFTPサーバ</string>
|
||||
<string name="save_welcome_message_question">ウェルカムメッセージを保存しますか?</string>
|
||||
<string name="dont_show_again">次から表示しない</string>
|
||||
<string name="la_change_app_passcode">パスコードを変更</string>
|
||||
<string name="la_current_app_passcode">現在のパスコード</string>
|
||||
<string name="la_lock_mode">SimpleXロックモード</string>
|
||||
<string name="la_lock_mode_system">システム認証</string>
|
||||
<string name="la_lock_mode_passcode">パスコード入力</string>
|
||||
<string name="la_auth_failed">認証失敗</string>
|
||||
<string name="la_enter_app_passcode">パスコードを入力</string>
|
||||
<string name="cant_delete_user_profile">ユーザープロフィールが削除できません。</string>
|
||||
<string name="la_mode_system">システム</string>
|
||||
<string name="change_lock_mode">ロックモードを変更</string>
|
||||
<string name="v4_6_chinese_spanish_interface">中国語とスペイン語UI</string>
|
||||
<string name="learn_more">さらに詳しく</string>
|
||||
<string name="new_passcode">新しいパスコード</string>
|
||||
<string name="lock_mode">ロックモード</string>
|
||||
<string name="submit_passcode">送信</string>
|
||||
<string name="passcode_changed">パスコードが変更されました</string>
|
||||
<string name="passcode_set">パスコードを設定しました!</string>
|
||||
<string name="passcode_not_changed">パスコードが変更されていません</string>
|
||||
<string name="dark_theme">ダークテーマ</string>
|
||||
<string name="gallery_image_button">画像</string>
|
||||
<string name="learn_more_about_address">SimpleXアドレスについて</string>
|
||||
<string name="read_more_in_user_guide_with_link"><font color="#0088ff">ユーザーガイド</font>で詳細を見る</string>
|
||||
<string name="simplex_address">SimpleXアドレス</string>
|
||||
<string name="network_proxy_port">ポート %d</string>
|
||||
<string name="enter_welcome_message_optional">ウェルカムメッセージを入力…(オプション)</string>
|
||||
<string name="save_settings_question">設定を保存しますか?</string>
|
||||
<string name="confirm_passcode">パスコードを確認</string>
|
||||
<string name="la_mode_passcode">パスコード</string>
|
||||
<string name="group_welcome_preview">プレビュー</string>
|
||||
<string name="smp_save_servers_question">サーバを保存しますか?</string>
|
||||
<string name="incompatible_database_version">データベースのバージョンと互換性がない</string>
|
||||
<string name="database_downgrade">データーベースダウングレード</string>
|
||||
<string name="scan_qr_to_connect_to_contact">接続するにはQRコードを読み込むか、アプリ内のリンクを使用する必要があります。</string>
|
||||
<string name="one_time_link_short">使い捨てのリンク</string>
|
||||
<string name="address_section_title">アドレス</string>
|
||||
<string name="color_background">背景色</string>
|
||||
<string name="confirm_password">パスワードを確認</string>
|
||||
<string name="settings_section_title_experimenta">β機能</string>
|
||||
<string name="decryption_error">復号化エラー</string>
|
||||
<string name="button_add_welcome_message">ウェルカムメッセージを追加</string>
|
||||
<string name="la_authenticate">認証</string>
|
||||
<string name="la_minutes">%d 分</string>
|
||||
<string name="database_upgrade">データベースアップグレード</string>
|
||||
<string name="audio_video_calls">音声/ビデオ通話</string>
|
||||
<string name="calls_prohibited_with_this_contact">音声/ビデオ通話は禁止されています。</string>
|
||||
<string name="feature_received_prohibited">禁帯出</string>
|
||||
<string name="ensure_xftp_server_address_are_correct_format_and_unique">XFTPサーバーのアドレスが正しい形式で、行で区切られており、重複していないことを確認してください。</string>
|
||||
<string name="smp_server_test_delete_file">ファイルの削除</string>
|
||||
<string name="icon_descr_waiting_for_video">ビデオ待機中</string>
|
||||
<string name="waiting_for_video">Waiting for video</string>
|
||||
<string name="group_welcome_title">ウェルカムメッセージ</string>
|
||||
<string name="host_verb">ホスト</string>
|
||||
<string name="lock_after">自動ロックまでの時間</string>
|
||||
<string name="opening_database">データベースを開いています…</string>
|
||||
<string name="observer_cant_send_message_title">メッセージを送信できませんでした!</string>
|
||||
<string name="gallery_video_button">ビデオ</string>
|
||||
<string name="above_then_preposition_continuation">← から:</string>
|
||||
<string name="network_socks_proxy_settings">SOCKSプロキシー設定</string>
|
||||
<string name="your_XFTP_servers">あなたのXFTPサーバ</string>
|
||||
<string name="add_address_to_your_profile">プロフィールにアドレスを追加し、連絡先があなたのアドレスを他の人と共有できるようにします。プロフィールの更新は連絡先に送信されます。</string>
|
||||
<string name="auto_accept_contact">自動承認</string>
|
||||
<string name="enable_lock">ロックモード</string>
|
||||
<string name="enter_welcome_message">ウェルカムメッセージを入力してください…</string>
|
||||
<string name="only_you_can_make_calls">自分からのみ通話ができます。</string>
|
||||
<string name="video_will_be_received_when_contact_is_online">動画は相手がオンラインになったら受信されます。しばらくお待ちください。</string>
|
||||
<string name="color_primary_variant">追加のアクセント</string>
|
||||
<string name="customize_theme_title">カスタムテーマ</string>
|
||||
<string name="videos_limit_desc">動画を1回で最大10個送信できます。</string>
|
||||
<string name="videos_limit_title">動画数の上限を超えています!</string>
|
||||
<string name="image_will_be_received_when_contact_completes_uploading">画像は相手がアップロードを完了した時点で受信するができます。</string>
|
||||
<string name="video_descr">ビデオ</string>
|
||||
<string name="alert_title_msg_bad_hash">メッセージのハッシュ値問題</string>
|
||||
<string name="you_are_observer">あなたはオブザーバーです</string>
|
||||
<string name="observer_cant_send_message_desc">グループの管理者に連絡してください。</string>
|
||||
<string name="video_will_be_received_when_contact_completes_uploading">動画は相手がアップロードを完了した時点で受信するができます。</string>
|
||||
<string name="disable_onion_hosts_when_not_supported">SOCKSプロキシがサポートしていない場合、<i>.onion hostを使用する</i>、は「いいえ」に設定します。</string>
|
||||
<string name="network_socks_toggle_use_socks_proxy">SOCKSプロキシーを使用</string>
|
||||
<string name="auth_open_chat_profiles">チャットのプロフィールを開く</string>
|
||||
<string name="file_will_be_received_when_contact_completes_uploading">連絡先がアップロードを完了した時点で、ファイルを受信します。</string>
|
||||
<string name="button_welcome_message">ウェルカムメッセージ</string>
|
||||
<string name="prohibit_calls">音声/ビデオ通話を禁止する 。</string>
|
||||
<string name="allow_your_contacts_to_call">連絡先からの通話を許可する。</string>
|
||||
<string name="allow_calls_only_if">連絡先が通話を許可している場合のみ通話を許可する。</string>
|
||||
<string name="available_in_v51">"
|
||||
\nv5.1 で利用可能"</string>
|
||||
<string name="only_your_contact_can_make_calls">連絡先からのみ通話ができます。</string>
|
||||
<string name="both_you_and_your_contact_can_make_calls">あなたからも連絡先からも通話ができます。</string>
|
||||
<string name="language_system">システム</string>
|
||||
<string name="error_saving_xftp_servers">XFTP サーバーの保存中にエラーが発生しました</string>
|
||||
<string name="smp_server_test_create_file">ファイルを作成</string>
|
||||
<string name="moderate_message_will_be_deleted_warning">メッセージはすべてのメンバーに対して削除されます。</string>
|
||||
<string name="la_could_not_be_verified">確認できませんでした。 もう一度お試しください。</string>
|
||||
<string name="user_mute">ミュート</string>
|
||||
<string name="user_unmute">ミュート解除</string>
|
||||
<string name="v4_6_audio_video_calls">音声通話とビデオ通話</string>
|
||||
<string name="upgrade_and_open_chat">アップグレードしてチャットを開く</string>
|
||||
<string name="delete_member_message__question">メンバーのメッセージを削除しますか?</string>
|
||||
<string name="import_theme">テーマのインポート</string>
|
||||
<string name="port_verb">ポート</string>
|
||||
<string name="theme_colors_section_title">テーマカラー</string>
|
||||
<string name="stop_sharing">共有を停止</string>
|
||||
<string name="invite_friends">友人を招待する</string>
|
||||
<string name="you_can_create_it_later">後からでも作成できます</string>
|
||||
<string name="password_to_show">パスワードを表示する</string>
|
||||
<string name="authentication_cancelled">認証がキャンセルされました</string>
|
||||
<string name="share_address">アドレスを共有する</string>
|
||||
<string name="theme_simplex">SimpleX</string>
|
||||
<string name="color_title">タイトル</string>
|
||||
<string name="v4_6_reduced_battery_usage_descr">まだまだ改善してまいります!</string>
|
||||
<string name="show_developer_options">開発者向けオプションを表示</string>
|
||||
<string name="v4_6_group_welcome_message_descr">新しいメンバーに表示されるメッセージを設定してください!</string>
|
||||
<string name="lock_not_enabled">SimpleXは ロックされていません!</string>
|
||||
<string name="smp_server_test_upload_file">ファイルをアップロードする</string>
|
||||
<string name="smp_server_test_compare_file">ファイルを比較</string>
|
||||
<string name="you_can_turn_on_lock">設定からSimpleXのロックをオンにすることができます。</string>
|
||||
<string name="la_seconds">%d 秒</string>
|
||||
<string name="database_downgrade_warning">警告: 一部のデータが失われる可能性があります!</string>
|
||||
<string name="revoke_file__confirm">取り消す</string>
|
||||
<string name="stop_file__confirm">停止</string>
|
||||
<string name="stop_snd_file__title">ファイルの送信を停止しますか?</string>
|
||||
<string name="alert_text_fragment_please_report_to_developers">開発者に報告してください。</string>
|
||||
<string name="alert_text_fragment_permanent_error_reconnect">このエラーはこの接続では永続的なものです。再接続してください。</string>
|
||||
<string name="v5_0_large_files_support">1GBまでのビデオとファイル</string>
|
||||
<string name="alert_text_decryption_error_header"><xliff:g id="message count" example="1">%1$d</xliff:g> メッセージの復号化に失敗しました。</string>
|
||||
<string name="alert_text_decryption_error_too_many_skipped"><xliff:g id="message count" example="1">%1$d</xliff:g> メッセージをスキップしました</string>
|
||||
<string name="error_loading_smp_servers">SMP サーバーのロード中にエラーが発生しました</string>
|
||||
<string name="error_saving_user_password">ユーザーパスワード保存エラー</string>
|
||||
<string name="error_loading_xftp_servers">XFTP サーバーのロード中にエラーが発生しました</string>
|
||||
<string name="export_theme">テーマのエクスポート</string>
|
||||
<string name="revoke_file__message">ファイルはサーバーから削除されます。</string>
|
||||
<string name="if_you_cant_meet_in_person">直接会えない場合は、ビデオ通話で QR コードを表示するか、リンクを共有してください。</string>
|
||||
<string name="v4_6_reduced_battery_usage">バッテリー使用量をさらに削減</string>
|
||||
<string name="la_no_app_password">アプリのパスコードがありません</string>
|
||||
<string name="muted_when_inactive">非アクティブ時はミュート!</string>
|
||||
<string name="continue_to_next_step">続ける</string>
|
||||
<string name="incorrect_passcode">パスコードが正しくありません</string>
|
||||
<string name="import_theme_error">テーマのインポートエラー</string>
|
||||
<string name="color_surface">メニュー & アラート</string>
|
||||
<string name="confirm_database_upgrades">データベースのアップグレードを確認</string>
|
||||
<string name="import_theme_error_desc">ファイルの YAML 構文が正しいことを確認してください。テーマをエクスポートすることでテーマ ファイル構造の例を確認できます。</string>
|
||||
<string name="la_immediately">即座に</string>
|
||||
<string name="alert_title_msg_bad_id">メッセージ ID が正しくありません</string>
|
||||
<string name="database_migrations">移行: %s</string>
|
||||
<string name="mtr_error_no_down_migration">アプリのバージョンよりも新しいデータベースが使用されていますが、データベースのバージョンダウンはできません: %s</string>
|
||||
<string name="initial_member_role">初期の役割</string>
|
||||
<string name="alert_text_fragment_encryption_out_of_sync_old_database">古いデータベースのバックアップを使用した場合に発生する可能性があります。</string>
|
||||
<string name="v4_6_chinese_spanish_interface_descr">ユーザーに感謝します – Weblate 経由で貢献してください!</string>
|
||||
<string name="v4_6_audio_video_calls_descr">Bluetooth およびその他の改善をサポートします。</string>
|
||||
<string name="relay_server_if_necessary">中継サーバーは必要な場合にのみ使用されます。 別の当事者があなたの IP アドレスを監視できます。</string>
|
||||
<string name="stop_sharing_address">アドレスの共有を停止しますか?</string>
|
||||
<string name="color_sent_message">送信</string>
|
||||
<string name="color_received_message">受信したメッセージ</string>
|
||||
<string name="alert_text_msg_bad_hash">以前のメッセージとハッシュ値が異なります。</string>
|
||||
<string name="alert_text_msg_bad_id">次のメッセージの ID が正しくありません (前のメッセージより小さいか等しい)。
|
||||
\n何らかのバグが原因で、または接続に問題があった場合に発生する可能性があります。</string>
|
||||
<string name="v5_0_polish_interface_descr">ユーザーに感謝します – Weblate 経由で貢献してください!</string>
|
||||
<string name="you_can_accept_or_reject_connection">接続が要求されたら、それを受け入れるか拒否するかを選択できます。</string>
|
||||
<string name="your_contacts_will_see_it">SimpleX の連絡先に表示されます。
|
||||
\n設定で変更できます。</string>
|
||||
<string name="icon_descr_video_snd_complete">ビデオが送信されました</string>
|
||||
<string name="v4_6_group_moderation_descr">管理者は次のことができます。
|
||||
\n- メンバーのメッセージを削除します。
|
||||
\n- メンバーを無効にする (メッセージの送信不可)</string>
|
||||
<string name="v5_0_polish_interface">ポーランド語UI</string>
|
||||
<string name="downgrade_and_open_chat">ダウングレードしてチャットを開く</string>
|
||||
<string name="la_please_remember_to_store_password">パスワードを覚えるか、安全に保管してください。失われたパスワードを回復する方法はありません。</string>
|
||||
<string name="smp_server_test_download_file">ファイルをダウンロード</string>
|
||||
<string name="no_spaces">空き容量がありません</string>
|
||||
<string name="you_can_hide_or_mute_user_profile">ユーザープロフィールを非表示またはミュートすることができます(メニューを長押し)。</string>
|
||||
<string name="v4_6_group_moderation">グループのモデレーション</string>
|
||||
<string name="email_invite_body">こんにちは!
|
||||
\nSimpleX Chatの招待が届いています: %s</string>
|
||||
<string name="v4_6_group_welcome_message">グループのウェルカムメッセージ</string>
|
||||
<string name="tap_to_activate_profile">タップしてプロフィールを有効化する。</string>
|
||||
<string name="profile_password">プロフィールのパスワード</string>
|
||||
<string name="v4_6_hidden_chat_profiles_descr">チャットのプロフィールをパスワードで保護します!</string>
|
||||
<string name="group_member_role_observer">オブザーバー</string>
|
||||
<string name="v5_0_large_files_support_descr">送信者がオンラインになるまでの待ち時間がなく、速い!</string>
|
||||
<string name="v5_0_app_passcode">アプリのパスコード</string>
|
||||
<string name="v5_0_app_passcode_descr">システム認証の代わりに設定します。</string>
|
||||
<string name="should_be_at_least_one_visible_profile">少なくとも1つのユーザープロフィールが表示されている必要があります。</string>
|
||||
<string name="should_be_at_least_one_profile">少なくとも1つのユーザープロファイルが必要です。</string>
|
||||
<string name="make_profile_private">プロフィールを非表示にできます!</string>
|
||||
<string name="relay_server_protects_ip">リレー サーバーは IP アドレスを保護しますが、通話時間は監視されます。</string>
|
||||
<string name="share_address_with_contacts_question">アドレスを連絡先と共有しますか\?</string>
|
||||
<string name="icon_descr_call_pending_sent">保留中の通話</string>
|
||||
<string name="invalid_migration_confirmation">データ移行の確認が正しくない</string>
|
||||
<string name="feature_offered_item">%s を提供しました</string>
|
||||
<string name="callstate_received_confirmation">確認を受け取りました…</string>
|
||||
<string name="feature_offered_item_with_param">提供された %s: %2s</string>
|
||||
<string name="error_xftp_test_server_auth">アップロードにはサーバーの認証が必要です。パスワードを確認してください</string>
|
||||
<string name="moderate_verb">モデレート</string>
|
||||
<string name="icon_descr_video_asked_to_receive">ビデオの受信を要求されました</string>
|
||||
<string name="moderated_item_description">モデレートされた %s</string>
|
||||
<string name="error_updating_user_privacy">ユーザーのプライバシーの更新エラー</string>
|
||||
<string name="moderate_message_will_be_marked_warning">メッセージはすべてのメンバーに対してモデレート済みとしてマークされます。</string>
|
||||
<string name="hide_profile">非表示のプロフィール</string>
|
||||
<string name="error_updating_link_for_group">グループ リンクの更新中にエラーが発生しました</string>
|
||||
<string name="v4_6_hidden_chat_profiles">非表示のチャットプロフィール</string>
|
||||
<string name="self_destruct">自己破壊</string>
|
||||
<string name="self_destruct_passcode_changed">自己破壊パスコードが変更されました!</string>
|
||||
<string name="self_destruct_passcode_enabled">自己破壊パスコードが有効になりました!</string>
|
||||
<string name="change_self_destruct_mode">自己破壊モードの変更</string>
|
||||
<string name="change_self_destruct_passcode">自己破壊パスコードを変更する</string>
|
||||
<string name="enabled_self_destruct_passcode">自己破壊パスコードを有効にする</string>
|
||||
<string name="all_app_data_will_be_cleared">すべてのアプリデータが削除されます。</string>
|
||||
<string name="empty_chat_profile_is_created">指定された名前の空のチャット プロファイルが作成され、アプリが通常どおり開きます。</string>
|
||||
<string name="app_passcode_replaced_with_self_destruct">アプリのパスコードは自己破壊パスコードに置き換えられます。</string>
|
||||
<string name="if_you_enter_passcode_data_removed">アプリを開くときにこのパスコードを入力すると、アプリのすべてのデータが元に戻せないように削除されます。</string>
|
||||
<string name="self_destruct_new_display_name">新たな表示名:</string>
|
||||
<string name="self_destruct_passcode">自己破壊パスコード</string>
|
||||
<string name="enable_self_destruct">自己破壊モードを有効にする</string>
|
||||
<string name="if_you_enter_self_destruct_code">アプリを開いているときに自己破壊パスコードを入力した場合:</string>
|
||||
<string name="set_passcode">パスコードを設定する</string>
|
||||
<string name="you_will_still_receive_calls_and_ntfs">ミュートされたプロファイルがアクティブな場合でも、そのプロファイルからの通話や通知は引き続き受信します。</string>
|
||||
<string name="color_secondary_variant">追加セカンダリ</string>
|
||||
<string name="color_secondary">副次的</string>
|
||||
<string name="mtr_error_different">アプリ/データベースの異なる移行: %s / %s</string>
|
||||
<string name="user_hide">非表示</string>
|
||||
<string name="user_unhide">表示にする</string>
|
||||
<string name="hidden_profile_password">非表示のプロフィール パスワード</string>
|
||||
<string name="show_dev_options">表示する:</string>
|
||||
<string name="create_address_and_let_people_connect">人々があなたとつながるためのアドレスを作成します。</string>
|
||||
<string name="error_setting_address">アドレス設定エラー</string>
|
||||
<string name="you_can_share_your_address">アドレスをリンクまたは QR コードとして共有すると、誰でもあなたに接続できます。</string>
|
||||
<string name="you_wont_lose_your_contacts_if_delete_address">後でアドレスを削除しても、連絡先が失われることはありません。</string>
|
||||
<string name="your_contacts_will_remain_connected">連絡先は接続されたままになります。</string>
|
||||
<string name="all_your_contacts_will_remain_connected_update_sent">すべての連絡先は接続されたままになります。 プロフィールの更新が連絡先に送信されます。</string>
|
||||
<string name="create_simplex_address">SimpleX のアドレスを作成</string>
|
||||
<string name="share_with_contacts">連絡先と共有する</string>
|
||||
<string name="profile_update_will_be_sent_to_contacts">プロフィールの更新は連絡先に送信されます。</string>
|
||||
<string name="dont_create_address">アドレスを作成しない</string>
|
||||
<string name="email_invite_subject">SimpleXチャットで会話しよう</string>
|
||||
<string name="save_auto_accept_settings">自動受け入れ設定を保存する</string>
|
||||
<string name="save_profile_password">プロフィールのパスワードを保存する</string>
|
||||
<string name="you_can_share_this_address_with_your_contacts">このアドレスを連絡先と共有して、%s に接続できるようにすることができます。</string>
|
||||
<string name="save_and_update_group_profile">グループプロフィールの保存と更新</string>
|
||||
<string name="to_reveal_profile_enter_password">非表示のプロフィールを表示するには、チャット プロフィール ページの検索フィールドに完全なパスワードを入力します。</string>
|
||||
<string name="hide_dev_options">非表示 :</string>
|
||||
<string name="delete_chat_profile">チャット プロフィールを削除する</string>
|
||||
<string name="delete_profile">プロフィールの削除</string>
|
||||
<string name="unhide_chat_profile">チャットのプロフィールを表示する</string>
|
||||
<string name="unhide_profile">プロフィールを表示する</string>
|
||||
<string name="developer_options">データベース ID とトランスポート分離オプション。</string>
|
||||
<string name="revoke_file__action">ファイルを取り消す</string>
|
||||
<string name="revoke_file__title">ファイルを取り消しますか?</string>
|
||||
<string name="stop_snd_file__message">ファイルの送信を停止します。</string>
|
||||
<string name="stop_file__action">ファイルを停止する</string>
|
||||
<string name="stop_rcv_file__message">ファイルの受信を停止します。</string>
|
||||
<string name="stop_rcv_file__title">ファイルの受信を停止しますか?</string>
|
||||
<string name="enter_password_to_show">検索にパスワードを入力してください</string>
|
||||
<string name="send_disappearing_message_send">送信</string>
|
||||
<string name="allow_message_reactions">メッセージへのリアクションを許可します。</string>
|
||||
<string name="message_reactions_prohibited_in_this_chat">このチャットではメッセージへのリアクションは禁止されています。</string>
|
||||
<string name="only_you_can_add_message_reactions">メッセージへのリアクションを追加できるのは、あなただけです。</string>
|
||||
<string name="only_your_contact_can_add_message_reactions">メッセージへのリアクションを追加できるのは連絡先だけです。</string>
|
||||
<string name="prohibit_message_reactions_group">メッセージへのリアクションは禁止されています。</string>
|
||||
<string name="custom_time_picker_select">選択</string>
|
||||
<string name="custom_time_picker_custom">カスタム</string>
|
||||
<string name="error_loading_details">詳細読み込みエラー</string>
|
||||
<string name="edit_history">履歴</string>
|
||||
<string name="info_menu">情報</string>
|
||||
<string name="received_message">受信したメッセージ</string>
|
||||
<string name="sent_message">送信済みメッセージ</string>
|
||||
<string name="send_disappearing_message_custom_time">カスタム時間</string>
|
||||
<string name="send_disappearing_message">消えるメッセージを送信</string>
|
||||
<string name="info_row_received_at">受信</string>
|
||||
<string name="info_row_sent_at">送信日時</string>
|
||||
<string name="share_text_database_id">データベースID: %d</string>
|
||||
<string name="share_text_deleted_at">削除されました: %s</string>
|
||||
<string name="info_row_disappears_at">に消えます</string>
|
||||
<string name="info_row_moderated_at">モデレーターによって介入済み</string>
|
||||
<string name="share_text_received_at">受信: %s</string>
|
||||
<string name="share_text_updated_at">レコード更新日時: %s</string>
|
||||
<string name="share_text_sent_at">送信日時: %s</string>
|
||||
<string name="item_info_current">(現在)</string>
|
||||
<string name="share_text_disappears_at">%s :に消えます</string>
|
||||
<string name="share_text_moderated_at">モデレーターによって介入済み: %s</string>
|
||||
<string name="current_version_timestamp">%s (現在)</string>
|
||||
<string name="both_you_and_your_contact_can_add_message_reactions">自分も相手もメッセージへのリアクションを追加できます。</string>
|
||||
<string name="message_reactions">メッセージへのリアクション</string>
|
||||
<string name="prohibit_message_reactions">メッセージへのリアクションは禁止されています。</string>
|
||||
<string name="custom_time_unit_minutes">分</string>
|
||||
<string name="custom_time_unit_seconds">秒</string>
|
||||
<string name="custom_time_unit_days">日</string>
|
||||
<string name="custom_time_unit_hours">時間</string>
|
||||
<string name="custom_time_unit_months">月</string>
|
||||
<string name="custom_time_unit_weeks">週</string>
|
||||
<string name="send_disappearing_message_1_minute">1分</string>
|
||||
<string name="send_disappearing_message_30_seconds">30秒</string>
|
||||
<string name="send_disappearing_message_5_minutes">5分</string>
|
||||
<string name="allow_message_reactions_only_if">連絡先が許可している場合にのみ、メッセージへのリアクションを許可します。</string>
|
||||
<string name="allow_your_contacts_adding_message_reactions">連絡先がメッセージへのリアクションを追加できるようにします。</string>
|
||||
<string name="info_row_deleted_at">削除完了</string>
|
||||
<string name="disappearing_message">消えるメッセージ</string>
|
||||
<string name="group_members_can_add_message_reactions">グループメンバーはメッセージへのリアクションを追加できます。</string>
|
||||
<string name="message_reactions_are_prohibited">このグループではメッセージへのリアクションは禁止されています。</string>
|
||||
<string name="info_row_updated_at">レコード更新日時</string>
|
||||
<string name="v5_1_message_reactions">メッセージへのリアクション</string>
|
||||
<string name="v5_1_self_destruct_passcode">自己破壊パスコード</string>
|
||||
<string name="v5_1_custom_themes">カスタムテーマ</string>
|
||||
<string name="v5_1_japanese_portuguese_interface">日本語とポルトガル語UI</string>
|
||||
<string name="v5_1_better_messages_descr">- 最長 5 分間の音声メッセージ。
|
||||
\n- 消えるまでのカスタム時間。
|
||||
\n- 編集履歴。</string>
|
||||
<string name="whats_new_read_more">続きを読む</string>
|
||||
<string name="v5_1_self_destruct_passcode_descr">入力するとすべてのデータが消去されます。</string>
|
||||
<string name="v5_1_custom_themes_descr">カラーテーマをカスタマイズして共有することができます。</string>
|
||||
<string name="whats_new_thanks_to_users_contribute_weblate">ユーザーに感謝します – Weblate 経由で貢献してください!</string>
|
||||
<string name="v5_1_message_reactions_descr">ついに、私たちはそれらを手に入れました! 🚀</string>
|
||||
<string name="v5_1_better_messages">より良いメッセージ</string>
|
||||
</resources>
|
||||
@@ -52,13 +52,10 @@
|
||||
<string name="network_settings">고급 네트워크 설정</string>
|
||||
<string name="network_session_mode_user">채팅 프로필</string>
|
||||
<string name="network_session_mode_entity">연결</string>
|
||||
<string name="accept_requests">요청 수락</string>
|
||||
<string name="app_version_code">앱 빌드 : %s</string>
|
||||
<string name="appearance_settings">외관</string>
|
||||
<string name="app_version_title">앱 버전</string>
|
||||
<string name="app_version_name">앱 버전 : v%s</string>
|
||||
<string name="accept_automatically">자동</string>
|
||||
<string name="contact_requests">대화 상대의 요청</string>
|
||||
<string name="core_version">코어 버전 : v%s</string>
|
||||
<string name="callstatus_accepted">전화 받음</string>
|
||||
<string name="bold">굵게</string>
|
||||
@@ -143,7 +140,7 @@
|
||||
<string name="accept_call_on_lock_screen">응답</string>
|
||||
<string name="accept_connection_request__question">연결 요청을 수락할까요\?</string>
|
||||
<string name="accept_feature">수락</string>
|
||||
<string name="network_enable_socks_info">SOCKS 프록시(포트 9050)를 통해 서버에 액세스할까요\? 이 설정을 활성화하기 전에 프록시를 시작해야 해요.</string>
|
||||
<string name="network_enable_socks_info">SOCKS 프록시(포트 %d)를 통해 서버에 액세스할까요\? 이 설정을 활성화하기 전에 프록시를 시작해야 해요.</string>
|
||||
<string name="smp_servers_add_to_another_device">다른 기기에 추가</string>
|
||||
<string name="v4_3_improved_server_configuration_desc">QR 코드 스캔으로 서버 추가</string>
|
||||
<string name="button_add_welcome_message">환영 메시지 추가</string>
|
||||
@@ -670,7 +667,6 @@
|
||||
<string name="mark_unread">읽지 않음으로 표시</string>
|
||||
<string name="mute_chat">음소거</string>
|
||||
<string name="markdown_in_messages">메시지에 사용된 마크다운</string>
|
||||
<string name="network_socks_toggle">SOCKS 프록시 사용 (포트 9050)</string>
|
||||
<string name="network_disable_socks">직접적인 인터넷 연결을 사용할까요\?</string>
|
||||
<string name="network_enable_socks">SOCKS 프록시를 사용할까요\?</string>
|
||||
<string name="network_disable_socks_info">설정하면 메시징 서버에서 내 IP 주소와 내가 연결하려는 서버를 볼 수 있어요.</string>
|
||||
@@ -828,12 +824,10 @@
|
||||
<string name="send_live_message_desc">라이브 메시지 보내기 - 입력 과정을 실시간으로 상대에게 보여줘요.</string>
|
||||
<string name="send_verb">보내기</string>
|
||||
<string name="share_invitation_link">초대 링크 공유</string>
|
||||
<string name="show_QR_code_for_your_contact_to_scan_from_the_app__multiline">연락하고자 하는 사람이 앱에서 QR 코드를 스캔할 수 있어요.</string>
|
||||
<string name="security_code">보안 코드</string>
|
||||
<string name="smp_servers_scan_qr">서버 QR코드 스캔</string>
|
||||
<string name="smp_servers_test_some_failed">일부 서버가 테스트에 통과하지 못했습니다 :</string>
|
||||
<string name="smp_servers_test_failed">서버 테스트 실패!</string>
|
||||
<string name="section_title_welcome_message">환영 메시지</string>
|
||||
<string name="share_link">링크 공유</string>
|
||||
<string name="show_call_on_lock_screen">표시하기</string>
|
||||
<string name="select_contacts">연락처 선택</string>
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
<string name="app_version_title">Programėlės versija</string>
|
||||
<string name="app_version_name">Programėlės versija: v%s</string>
|
||||
<string name="app_version_code">Programėlės darinys: %s</string>
|
||||
<string name="accept_automatically">Automatiškai</string>
|
||||
<string name="callstatus_calling">skambinama…</string>
|
||||
<string name="callstatus_error">skambučio klaida</string>
|
||||
<string name="call_already_ended">Skambutis jau baigtas!</string>
|
||||
@@ -276,10 +275,9 @@
|
||||
<string name="notification_preview_mode_contact_desc">Rodyti tik adresatą</string>
|
||||
<string name="auth_stop_chat">Stabdyti pokalbį</string>
|
||||
<string name="share_message">Bendrinti žinutę…</string>
|
||||
<string name="use_camera_button">Naudoti kamerą</string>
|
||||
<string name="use_camera_button">Kamera</string>
|
||||
<string name="thank_you_for_installing_simplex">Dėkojame, kad įdiegėte <xliff:g id="appNameFull">SimpleX Chat</xliff:g>!</string>
|
||||
<string name="smp_servers_use_server">Naudoti serverį</string>
|
||||
<string name="network_socks_toggle">Naudoti SOCKS įgaliotąjį serverį (prievadas 9050)</string>
|
||||
<string name="network_enable_socks">Naudoti SOCKS įgaliotąjį serverį\?</string>
|
||||
<string name="core_simplexmq_version">simplexmq: v%s (%2s)</string>
|
||||
<string name="share_link">Bendrinti nuorodą</string>
|
||||
@@ -355,4 +353,179 @@
|
||||
<string name="voice_message">Balso žinutė</string>
|
||||
<string name="icon_descr_simplex_team"><xliff:g id="appName">SimpleX</xliff:g> komanda</string>
|
||||
<string name="whats_new">Kas naujo</string>
|
||||
<string name="save_and_notify_group_members">Įrašyti ir pranešti grupės nariams</string>
|
||||
<string name="callstate_received_confirmation">gautas patvirtinimas…</string>
|
||||
<string name="read_more_in_github">Išsamiau skaitykite mūsų „GitHub“ saugykloje</string>
|
||||
<string name="icon_descr_call_missed">Praleistas skambutis</string>
|
||||
<string name="settings_section_title_chats">POKALBIAI</string>
|
||||
<string name="settings_section_title_themes">APIPAVIDALINIMAI</string>
|
||||
<string name="settings_section_title_incognito">Inkognito veiksena</string>
|
||||
<string name="settings_section_title_messages">ŽINUTĖS IR FAILAI</string>
|
||||
<string name="restart_the_app_to_use_imported_chat_database">Norėdami naudoti importuotą pokalbio duomenų bazę, paleiskite programėlę iš naujo.</string>
|
||||
<string name="button_add_members">Pakviesti narius</string>
|
||||
<string name="disappearing_prohibited_in_this_chat">Išnykstančios žinutės šiame pokalbyje yra uždraustos.</string>
|
||||
<string name="voice_messages_are_prohibited">Balso žinutės šioje grupėje yra uždraustos.</string>
|
||||
<string name="connect_via_group_link">Prisijungti per grupės nuorodą\?</string>
|
||||
<string name="connect_via_contact_link">Prisijungti per adresato nuorodą\?</string>
|
||||
<string name="sending_files_not_yet_supported">failų siuntimas kol kas nepalaikomas</string>
|
||||
<string name="invalid_message_format">neteisingas žinutės formatas</string>
|
||||
<string name="receiving_files_not_yet_supported">failų gavimas kol kas nepalaikomas</string>
|
||||
<string name="invalid_chat">neteisingas pokalbis</string>
|
||||
<string name="invalid_data">neteisingi duomenys</string>
|
||||
<string name="description_via_one_time_link_incognito">inkognito per vienkartinę nuorodą</string>
|
||||
<string name="contact_already_exists">Adresatas jau yra</string>
|
||||
<string name="database_initialization_error_title">Nepavyksta inicijuoti duomenų bazės</string>
|
||||
<string name="notification_preview_mode_message">Žinutės tekstas</string>
|
||||
<string name="notification_preview_somebody">Paslėptas adresatas:</string>
|
||||
<string name="share_image">Bendrinti mediją…</string>
|
||||
<string name="large_file">Didelis failas!</string>
|
||||
<string name="voice_messages_prohibited">Balso žinutės uždraustos!</string>
|
||||
<string name="send_verb">Siųsti</string>
|
||||
<string name="error_loading_smp_servers">Klaida įkeliant SMP serverius</string>
|
||||
<string name="error_saving_xftp_servers">Klaida įrašant XFTP serverius</string>
|
||||
<string name="error_loading_xftp_servers">Klaida įkeliant XFTP serverius</string>
|
||||
<string name="cannot_receive_file">Nepavyksta gauti failo</string>
|
||||
<string name="smp_server_test_create_queue">Sukurti eilę</string>
|
||||
<string name="error_smp_test_certificate">Gali būti, kad liudijimo kontrolinis kodas serverio adrese yra neteisingas</string>
|
||||
<string name="smp_server_test_delete_file">Ištrinti failą</string>
|
||||
<string name="image_decoding_exception_title">Dekodavimo klaida</string>
|
||||
<string name="add_new_contact_to_create_one_time_QR_code"><b>Pridėti naują adresatą</b>: norėdami sukurti adresatui vienkartinį QR kodą.</string>
|
||||
<string name="scan_QR_code_to_connect_to_contact_who_shows_QR_code"><b>Skenuoti QR kodą</b>: norėdami prisijungti prie adresato, kuris jums rodo QR kodą.</string>
|
||||
<string name="clear_chat_button">Išvalyti pokalbį</string>
|
||||
<string name="unmute_chat">Įjungti pranešimus</string>
|
||||
<string name="invalid_QR_code">Neteisingas QR kodas</string>
|
||||
<string name="this_QR_code_is_not_a_link">Šis QR kodas nėra nuoroda!</string>
|
||||
<string name="connect_via_link">Prisijungti per nuorodą</string>
|
||||
<string name="security_code">Saugumo kodas</string>
|
||||
<string name="mark_code_verified">Žymėti kaip patvirtintą</string>
|
||||
<string name="chat_lock">SimpleX užraktas</string>
|
||||
<string name="saved_ICE_servers_will_be_removed">Įrašyti WebRTC ICE serveriai bus pašalinti.</string>
|
||||
<string name="save_archive">Įrašyti archyvą</string>
|
||||
<string name="button_send_direct_message">Siųsti tiesioginę žinutę</string>
|
||||
<string name="button_remove_member">Šalinti narį</string>
|
||||
<string name="group_unsupported_incognito_main_profile_sent">Inkognito veiksena čia nepalaikoma – grupės nariams bus išsiųstas jūsų pagrindinis profilis</string>
|
||||
<string name="theme_light">Šviesus</string>
|
||||
<string name="feature_enabled_for_you">įjungta jums</string>
|
||||
<string name="both_you_and_your_contact_can_send_disappearing">Tiek jūs, tiek ir jūsų adresatas gali siųsti išnykstančias žinutes.</string>
|
||||
<string name="group_members_can_send_voice">Grupės nariai gali siųsti balso žinutes.</string>
|
||||
<string name="v4_2_security_assessment_desc">SimpleX Chat saugumo auditą atliko „Trail of Bits“.</string>
|
||||
<string name="v4_2_security_assessment">Saugumo įvertinimas</string>
|
||||
<string name="save_group_profile">Įrašyti grupės profilį</string>
|
||||
<string name="both_you_and_your_contacts_can_delete">Tiek jūs, tiek ir jūsų adresatas gali negrįžtamai ištrinti išsiųstas žinutes.</string>
|
||||
<string name="both_you_and_your_contact_can_send_voice">Tiek jūs, tiek ir jūsų adresatas gali siųsti balso žinutes.</string>
|
||||
<string name="enter_passphrase_notification_desc">Norėdami gauti pranešimus, įveskite duomenų bazės slaptafrazę</string>
|
||||
<string name="notification_preview_mode_contact">Adresato vardas</string>
|
||||
<string name="la_notice_title_simplex_lock">SimpleX užraktas</string>
|
||||
<string name="la_notice_turn_on">Įjungti</string>
|
||||
<string name="auth_simplex_lock_turned_on">SimpleX užraktas įjungtas</string>
|
||||
<string name="auth_enable_simplex_lock">Įjungti SimpleX užraktą</string>
|
||||
<string name="message_delivery_error_title">Žinutės pristatymo klaida</string>
|
||||
<string name="moderate_message_will_be_deleted_warning">Žinutė bus ištrinta visiems nariams.</string>
|
||||
<string name="icon_descr_sent_msg_status_sent">išsiųsta</string>
|
||||
<string name="copied">Nukopijuota į iškarpinę</string>
|
||||
<string name="choose_file">Failas</string>
|
||||
<string name="above_then_preposition_continuation">aukščiau, o tuomet:</string>
|
||||
<string name="clear_chat_question">Išvalyti pokalbį\?</string>
|
||||
<string name="mark_unread">Žymėti kaip neskaitytą</string>
|
||||
<string name="invalid_contact_link">Neteisinga nuoroda!</string>
|
||||
<string name="smp_servers_check_address">Patikrinkite serverio adresą ir bandykite dar kartą.</string>
|
||||
<string name="smp_servers_invalid_address">Neteisingas serverio adresas!</string>
|
||||
<string name="network_session_mode_user">Pokalbio profilis</string>
|
||||
<string name="profile_is_only_shared_with_your_contacts">Profilis yra bendrinamas tik su jūsų adresatais.</string>
|
||||
<string name="read_more_in_github_with_link">Išsamiau skaitykite mūsų <font color="#0088ff">„GitHub“ saugykloje</font>.</string>
|
||||
<string name="settings_section_title_socks">SOCKS ĮGALIOTASIS SERVERIS</string>
|
||||
<string name="save_passphrase_and_open_chat">Įrašyti slaptafrazę ir atverti pokalbį</string>
|
||||
<string name="restore_database">Atkurti atsarginę duomenų bazės kopiją</string>
|
||||
<string name="restore_database_alert_title">Atkurti atsarginę duomenų bazės kopiją\?</string>
|
||||
<string name="group_invitation_item_description">pakvietimas į <xliff:g id="group_name">%1$s</xliff:g> grupę</string>
|
||||
<string name="leave_group_button">Išeiti</string>
|
||||
<string name="rcv_conn_event_switch_queue_phase_changing">keičiamas adresas…</string>
|
||||
<string name="snd_conn_event_switch_queue_phase_changing_for_member">keičiamas %s adresas…</string>
|
||||
<string name="snd_conn_event_switch_queue_phase_changing">keičiamas adresas…</string>
|
||||
<string name="invite_to_group_button">Pakviesti į grupę</string>
|
||||
<string name="clear_contacts_selection_button">Išvalyti</string>
|
||||
<string name="button_leave_group">Išeiti iš grupės</string>
|
||||
<string name="role_in_group">Vaidmuo</string>
|
||||
<string name="group_is_decentralized">Grupė yra pilnai decentralizuota – ji yra matoma tik nariams.</string>
|
||||
<string name="theme">Apipavidalinimas</string>
|
||||
<string name="feature_enabled_for_contact">įjungta adresatui</string>
|
||||
<string name="disappearing_messages_are_prohibited">Išnykstančios žinutės šioje grupėje yra uždraustos.</string>
|
||||
<string name="group_members_can_send_dms">Grupės nariai gali siųsti tiesiogines žinutes.</string>
|
||||
<string name="group_members_can_send_disappearing">Grupės nariai gali siųsti išnykstančias žinutes.</string>
|
||||
<string name="v4_3_improved_privacy_and_security_desc">Slėpti programėlės ekraną paskiausių programėlių sąraše.</string>
|
||||
<string name="should_be_at_least_one_profile">Turėtų būti bent vienas naudotojo profilis.</string>
|
||||
<string name="should_be_at_least_one_visible_profile">Turėtų būti matomas bent vienas naudotojo profilis.</string>
|
||||
<string name="chat_preferences_contact_allows">Adresatas leidžia</string>
|
||||
<string name="voice_prohibited_in_this_chat">Balso žinutės šiame pokalbyje yra uždraustos.</string>
|
||||
<string name="v4_4_disappearing_messages_desc">Išsiųstos žinutės bus ištrintos po nustatyto laiko.</string>
|
||||
<string name="user_unhide">Nebeslėpti</string>
|
||||
<string name="la_lock_mode">SimpleX užrakto veiksena</string>
|
||||
<string name="host_verb">Serveris</string>
|
||||
<string name="callstatus_missed">praleistas skambutis</string>
|
||||
<string name="enable_lock">Įjungti užraktą</string>
|
||||
<string name="restart_the_app_to_create_a_new_chat_profile">Norėdami sukurti naują pokalbio profilį, paleiskite programėlę iš naujo.</string>
|
||||
<string name="join_group_question">Prisijungti prie grupės\?</string>
|
||||
<string name="database_restore_error">Duomenų bazės atkūrimo klaida</string>
|
||||
<string name="alert_message_no_group">Šios grupės daugiau nebėra.</string>
|
||||
<string name="network_option_seconds_label">sek.</string>
|
||||
<string name="member_role_will_be_changed_with_notification">Vaidmuo bus pakeistas į „%s“. Visiems grupėje bus pranešta.</string>
|
||||
<string name="member_role_will_be_changed_with_invitation">Vaidmuo bus pakeistas į „%s“. Narys gaus naują pakvietimą.</string>
|
||||
<string name="chat_preferences">Pokalbio nuostatos</string>
|
||||
<string name="contact_preferences">Adresato nuostatos</string>
|
||||
<string name="join_group_button">Prisijungti</string>
|
||||
<string name="change_verb">Keisti</string>
|
||||
<string name="conn_stats_section_title_servers">SERVERIAI</string>
|
||||
<string name="cant_delete_user_profile">Nepavyksta ištrinti naudotojo profilio!</string>
|
||||
<string name="clear_chat_menu_action">Išvalyti</string>
|
||||
<string name="unhide_profile">Nebeslėpti profilio</string>
|
||||
<string name="videos_limit_title">Per daug vaizdo įrašų!</string>
|
||||
<string name="connect_via_link_or_qr">Prisijungti per nuorodą / QR kodą</string>
|
||||
<string name="save_profile_password">Įrašyti profilio slaptažodį</string>
|
||||
<string name="decryption_error">Iššifravimo klaida</string>
|
||||
<string name="description_via_group_link_incognito">inkognito per grupės nuorodą</string>
|
||||
<string name="smp_server_test_create_file">Sukurti failą</string>
|
||||
<string name="lock_not_enabled">SimpleX užraktas neįjungtas!</string>
|
||||
<string name="icon_descr_send_message">Siųsti žinutę</string>
|
||||
<string name="alert_title_msg_bad_hash">Bloga žinutės maiša</string>
|
||||
<string name="messages_section_title">Žinutės</string>
|
||||
<string name="messages_section_description">Šis nustatymas yra taikomas jūsų dabartiniame pokalbio profilyje esančioms žinutėms</string>
|
||||
<string name="incognito">Inkognito</string>
|
||||
<string name="unhide_chat_profile">Nebeslėpti pokalbio profilio</string>
|
||||
<string name="smp_server_test_download_file">Atsisiųsti failą</string>
|
||||
<string name="la_immediately">Nedelsiant</string>
|
||||
<string name="network_socks_proxy_settings">SOCKS įgaliotojo serverio nustatymai</string>
|
||||
<string name="alert_text_msg_bad_hash">Skiriasi ankstesnės žinutės maiša.</string>
|
||||
<string name="change_database_passphrase_question">Keisti duomenų bazės slaptafrazę\?</string>
|
||||
<string name="network_proxy_port">prievadas %d</string>
|
||||
<string name="stop_rcv_file__message">Failo gavimas bus sustabdytas.</string>
|
||||
<string name="network_socks_toggle_use_socks_proxy">Naudoti SOCKS įgaliotąjį serverį</string>
|
||||
<string name="video_descr">Vaizdo įrašas</string>
|
||||
<string name="clear_verb">Išvalyti</string>
|
||||
<string name="icon_descr_context">Konteksto piktograma</string>
|
||||
<string name="revoke_file__message">Failas bus ištrintas iš serverių.</string>
|
||||
<string name="mark_read">Žymėti kaip skaitytą</string>
|
||||
<string name="port_verb">Prievadas</string>
|
||||
<string name="stop_snd_file__message">Failo siuntimas bus sustabdytas.</string>
|
||||
<string name="stop_file__confirm">Stabdyti</string>
|
||||
<string name="stop_file__action">Stabdyti failą</string>
|
||||
<string name="stop_rcv_file__title">Stabdyti failo gavimą\?</string>
|
||||
<string name="stop_snd_file__title">Stabdyti failo siuntimą\?</string>
|
||||
<string name="this_text_is_available_in_settings">Šis tekstas yra prieinamas nustatymuose</string>
|
||||
<string name="calls_prohibited_with_this_contact">Garso/vaizdo skambučiai yra uždrausti.</string>
|
||||
<string name="both_you_and_your_contact_can_make_calls">Tiek jūs, tiek ir jūsų adresatas gali skambinti.</string>
|
||||
<string name="v4_5_message_draft">Žinutės juodraštis</string>
|
||||
<string name="v4_6_hidden_chat_profiles_descr">Apsaugokite slaptažodžiu savo pokalbių profilius!</string>
|
||||
<string name="alert_title_msg_bad_id">Blogas žinutės ID</string>
|
||||
<string name="lock_after">Užrakinti po</string>
|
||||
<string name="alert_title_group_invitation_expired">Pakvietimas nebegalioja!</string>
|
||||
<string name="icon_descr_add_members">Pakviesti narius</string>
|
||||
<string name="leave_group_question">Išeiti iš grupės\?</string>
|
||||
<string name="unknown_database_error_with_info">Nežinoma duomenų bazės klaida: %s</string>
|
||||
<string name="users_delete_with_connections">Profilis ir ryšiai su serveriu</string>
|
||||
<string name="direct_messages_are_prohibited_in_chat">Tiesioginės žinutės tarp narių šioje grupėje yra uždraustos.</string>
|
||||
<string name="audio_video_calls">Garso/vaizdo skambučiai</string>
|
||||
<string name="available_in_v51">"
|
||||
\nPrieinama versijoje v5.1"</string>
|
||||
<string name="gallery_video_button">Vaizdo įrašas</string>
|
||||
<string name="v5_0_large_files_support">Vaizdo įrašai ir failai iki 1GB</string>
|
||||
</resources>
|
||||
@@ -16,7 +16,7 @@
|
||||
<string name="icon_descr_asked_to_receive">Gevraagd om de afbeelding te ontvangen</string>
|
||||
<string name="change_verb">Wijziging</string>
|
||||
<string name="network_settings">Geavanceerde netwerk instellingen</string>
|
||||
<string name="network_enable_socks_info">Toegang tot de servers via SOCKS proxy op poort 9050\? De proxy moet worden gestart voordat u deze optie inschakelt.</string>
|
||||
<string name="network_enable_socks_info">Toegang tot de servers via SOCKS proxy op poort %d\? De proxy moet worden gestart voordat u deze optie inschakelt.</string>
|
||||
<string name="alert_title_cant_invite_contacts">Kan geen contacten uitnodigen!</string>
|
||||
<string name="allow_direct_messages">Sta het verzenden van directe berichten naar leden toe.</string>
|
||||
<string name="allow_to_delete_messages">Sta toe om verzonden berichten onomkeerbaar te verwijderen.</string>
|
||||
@@ -66,7 +66,7 @@
|
||||
<string name="allow_your_contacts_to_send_voice_messages">Sta toe dat uw contacten spraak berichten verzenden.</string>
|
||||
<string name="all_your_contacts_will_remain_connected">Al uw contacten blijven verbonden.</string>
|
||||
<string name="allow_voice_messages_question">Spraak berichten toestaan\?</string>
|
||||
<string name="onboarding_notifications_mode_periodic_desc"><b>Goed voor batterij</b>. Achtergrondservice controleert elke 10 minuten op nieuwe berichten. U kunt oproepen en dringende berichten missen.</string>
|
||||
<string name="onboarding_notifications_mode_periodic_desc"><b>Goed voor de batterij</b>. Achtergrondservice controleert berichten elke 10 minuten. Mogelijk mist u oproepen of dringende berichten.</string>
|
||||
<string name="integrity_msg_bad_hash">Onjuiste bericht hash</string>
|
||||
<string name="scan_QR_code_to_connect_to_contact_who_shows_QR_code"><b>Scan QR-code</b>: om verbinding te maken met uw contactpersoon die u de QR-code laat zien.</string>
|
||||
<string name="integrity_msg_bad_id">Onjuiste bericht ID</string>
|
||||
@@ -75,7 +75,6 @@
|
||||
<string name="about_simplex">Over SimpleX</string>
|
||||
<string name="about_simplex_chat">Over <xliff:g id="appNameFull">SimpleX Chat</xliff:g></string>
|
||||
<string name="above_then_preposition_continuation">hier boven, dan:</string>
|
||||
<string name="accept_requests">Verzoeken accepteren</string>
|
||||
<string name="users_delete_all_chats_deleted">Alle gesprekken en berichten worden verwijderd, dit kan niet ongedaan worden gemaakt!</string>
|
||||
<string name="clear_chat_warning">Alle berichten worden verwijderd, dit kan niet ongedaan worden gemaakt! De berichten worden ALLEEN voor jou verwijderd.</string>
|
||||
<string name="allow_disappearing_messages_only_if">Sta verdwijnende berichten alleen toe als uw contactpersoon dit toestaat.</string>
|
||||
@@ -96,18 +95,17 @@
|
||||
<string name="app_version_name">App versie: v%s</string>
|
||||
<string name="network_session_mode_user_description">Er wordt een aparte TCP-verbinding (en SOCKS-referentie) gebruikt <b> voor elk chat profiel dat je in de app hebt </b>.</string>
|
||||
<string name="audio_call_no_encryption">audio oproep (niet e2e versleuteld)</string>
|
||||
<string name="accept_automatically">Automatisch</string>
|
||||
<string name="notifications_mode_service_desc">Achtergrondservice is altijd actief, meldingen worden weergegeven zodra de berichten beschikbaar zijn.</string>
|
||||
<string name="add_new_contact_to_create_one_time_QR_code"><b>Nieuw contact toevoegen</b>: om uw eenmalige QR-code voor uw contact te maken.</string>
|
||||
<string name="add_new_contact_to_create_one_time_QR_code"><b>Nieuw contact toevoegen</b>: om een eenmalige QR-code voor uw contact te maken.</string>
|
||||
<string name="icon_descr_call_ended">Oproep beëindigd</string>
|
||||
<string name="turning_off_service_and_periodic">Batterijoptimalisatie is actief, waardoor achtergrondservice en periodieke verzoeken om nieuwe berichten worden uitgeschakeld. Je kunt ze weer inschakelen via instellingen.</string>
|
||||
<string name="onboarding_notifications_mode_off_desc"><b>Beste voor de batterij</b>. U ontvangt alleen meldingen als de app draait, de achtergronddienst wordt NIET gebruikt.</string>
|
||||
<string name="onboarding_notifications_mode_off_desc"><b>Het beste voor de batterij</b>. U ontvangt alleen meldingen wanneer de app wordt uitgevoerd (GEEN achtergrondservice).</string>
|
||||
<string name="it_can_disabled_via_settings_notifications_still_shown"><b>Het kan worden uitgeschakeld via instellingen</b>, meldingen worden nog steeds weergegeven terwijl de app actief is.</string>
|
||||
<string name="both_you_and_your_contacts_can_delete">Zowel jij als je contactpersoon kunnen verzonden berichten onherroepelijk verwijderen.</string>
|
||||
<string name="both_you_and_your_contact_can_send_disappearing">Zowel jij als je contactpersoon kunnen verdwijnende berichten sturen.</string>
|
||||
<string name="both_you_and_your_contact_can_send_voice">Zowel jij als je contactpersoon kunnen spraak berichten verzenden.</string>
|
||||
<string name="impossible_to_recover_passphrase"><b>Let op</b>: u kunt het wachtwoord NIET herstellen of wijzigen als u het kwijt raakt.</string>
|
||||
<string name="onboarding_notifications_mode_service_desc"><b>Gebruikt meer batterij</b>! Achtergrondservice is altijd actief, meldingen worden weergegeven zodra de berichten beschikbaar zijn.</string>
|
||||
<string name="onboarding_notifications_mode_service_desc"><b>Gebruikt meer batterij</b>! Achtergrondservice wordt altijd uitgevoerd - meldingen worden weergegeven zodra berichten beschikbaar zijn.</string>
|
||||
<string name="icon_descr_cancel_link_preview">link voorbeeld annuleren</string>
|
||||
<string name="callstatus_ended">oproep beëindigd <xliff:g id="duration" example="01:15">%1$s</xliff:g></string>
|
||||
<string name="database_initialization_error_title">Kan de database niet initialiseren</string>
|
||||
@@ -210,7 +208,6 @@
|
||||
<string name="create_one_time_link">Maak een eenmalige uitnodiging link</string>
|
||||
<string name="colored">gekleurd</string>
|
||||
<string name="callstatus_connecting">Oproep verbinden…</string>
|
||||
<string name="contact_requests">Contact verzoeken</string>
|
||||
<string name="create_profile_button">Maak</string>
|
||||
<string name="create_profile">Maak een profiel aan</string>
|
||||
<string name="delete_address">Adres verwijderen</string>
|
||||
@@ -476,7 +473,7 @@
|
||||
<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 <b xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">batterijoptimalisatie uitschakelen</b> voor <xliff:g xmlns:xliff=\"urn:oasis: names:tc:xliff:document:1.2\" id=\"appName\">SimpleX</xliff:g> in het volgende dialoogvenster. Anders worden de meldingen uitgeschakeld.</string>
|
||||
<string name="turn_off_battery_optimization">Om het te gebruiken <b>batterijoptimalisatie uitschakelen</b> voor <xliff:g xmlns:xliff="urn:oasis: names:tc:xliff:document:1.2" id="appName">SimpleX</xliff:g> 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">heeft <xliff:g id="member profile" example="alice (Alice)">%1$s</xliff:g> uitgenodigd</string>
|
||||
@@ -625,10 +622,8 @@
|
||||
<string name="icon_descr_simplex_team"><xliff:g id="appName">SimpleX</xliff:g>-Team</string>
|
||||
<string name="this_QR_code_is_not_a_link">Deze QR-code is geen link!</string>
|
||||
<string name="this_link_is_not_a_valid_connection_link">Deze link is geen geldige link!</string>
|
||||
<string name="show_QR_code_for_your_contact_to_scan_from_the_app__multiline">Uw contactpersoon kan de QR-code vanuit de app scannen.</string>
|
||||
<string name="share_invitation_link">Uitnodiging link delen</string>
|
||||
<string name="share_invitation_link">Eenmalige link delen</string>
|
||||
<string name="scan_code">Code scannen</string>
|
||||
<string name="your_contact_address">Uw contact adres</string>
|
||||
<string name="your_settings">Uw instellingen</string>
|
||||
<string name="share_link">Deel link</string>
|
||||
<string name="you_control_your_chat">Jij beheert je gesprek!</string>
|
||||
@@ -637,13 +632,13 @@
|
||||
<string name="you_control_servers_to_receive_your_contacts_to_send">U bepaalt via welke server(s) je de berichten <b>ontvangt</b>, uw contacten de servers die u gebruikt om ze berichten te sturen.</string>
|
||||
<string name="icon_descr_video_on">Video aan</string>
|
||||
<string name="delete_chat_profile_action_cannot_be_undone_warning">Deze actie kan niet ongedaan worden gemaakt. Uw profiel, contacten, berichten en bestanden gaan onomkeerbaar verloren.</string>
|
||||
<string name="messages_section_description">Deze instelling is van toepassing op berichten in jou huidige chat profiel</string>
|
||||
<string name="messages_section_description">Deze instelling is van toepassing op berichten in uw huidige chat profiel</string>
|
||||
<string name="save_archive">Bewaar archief</string>
|
||||
<string name="rcv_group_event_updated_group_profile">bijgewerkt groep profiel</string>
|
||||
<string name="group_member_status_removed">verwijderd</string>
|
||||
<string name="group_main_profile_sent">Uw chat profiel wordt verzonden naar de groepsleden</string>
|
||||
<string name="failed_to_create_user_duplicate_desc">Je hebt al een chat profiel met dezelfde weergave naam. Kies een andere naam.</string>
|
||||
<string name="you_are_already_connected_to_vName_via_this_link">U bent al verbonden met <xliff:g id="contactName" example="Alice">%1$s!</xliff:g>.</string>
|
||||
<string name="you_are_already_connected_to_vName_via_this_link">U bent al verbonden met <xliff:g id="contactName" example="Alice">%1$s</xliff:g>.</string>
|
||||
<string name="error_smp_test_failed_at_step">Test mislukt bij stap %s.</string>
|
||||
<string name="smp_server_test_secure_queue">Veilige wachtrij</string>
|
||||
<string name="database_initialization_error_desc">De database werkt niet goed. Tik voor meer informatie</string>
|
||||
@@ -709,7 +704,7 @@
|
||||
<string name="you_can_also_connect_by_clicking_the_link">U kunt ook verbinding maken door op de link te klikken. Als het in de browser wordt geopend, klikt u op de knop <b> Openen in mobiele app </b>.</string>
|
||||
<string name="your_profile_will_be_sent">Uw chat profiel wordt naar uw contactpersoon verzonden</string>
|
||||
<string name="your_chat_profiles">Uw chat profielen</string>
|
||||
<string name="your_simplex_contact_address">Uw <xliff:g id="appName">SimpleX</xliff:g> contact adres</string>
|
||||
<string name="your_simplex_contact_address">Uw SimpleX adres</string>
|
||||
<string name="chat_with_the_founder">Stuur vragen en ideeën</string>
|
||||
<string name="send_us_an_email">Stuur ons een e-mail</string>
|
||||
<string name="chat_lock">SimpleX Vergrendelen</string>
|
||||
@@ -725,10 +720,8 @@
|
||||
<string name="smp_servers_your_server_address">Uw server adres</string>
|
||||
<string name="smp_servers_your_server">Uw server</string>
|
||||
<string name="network_session_mode_transport_isolation">Transport isolation</string>
|
||||
<string name="network_socks_toggle">SOCKS-proxy gebruiken (poort 9050)</string>
|
||||
<string name="save_preferences_question">Voorkeuren opslaan\?</string>
|
||||
<string name="save_and_notify_contact">Opslaan en Contact melden</string>
|
||||
<string name="section_title_welcome_message">WELKOMST BERICHT</string>
|
||||
<string name="your_current_profile">Je huidige profiel</string>
|
||||
<string name="save_and_notify_contacts">Opslaan en Contacten melden</string>
|
||||
<string name="save_and_notify_group_members">Opslaan en Groepsleden melden</string>
|
||||
@@ -767,7 +760,7 @@
|
||||
<string name="your_chat_database">Uw chat database</string>
|
||||
<string name="set_password_to_export">Wachtwoord instellen om te exporteren</string>
|
||||
<string name="restart_the_app_to_create_a_new_chat_profile">Start de app opnieuw om een nieuw chat profiel aan te maken.</string>
|
||||
<string name="you_must_use_the_most_recent_version_of_database">U mag de meest recente versie van uw chat database ALLEEN op één apparaat gebruiken, anders ontvangt u mogelijk geen berichten meer van sommige contacten.</string>
|
||||
<string name="you_must_use_the_most_recent_version_of_database">U mag de meest recente versie van uw chat-database ALLEEN op één apparaat gebruiken, anders ontvangt u mogelijk geen berichten meer van sommige contacten.</string>
|
||||
<string name="restart_the_app_to_use_imported_chat_database">Start de app opnieuw om de geïmporteerde chat database te gebruiken.</string>
|
||||
<string name="stop_chat_to_enable_database_actions">Stop de chat om database acties mogelijk te maken.</string>
|
||||
<string name="delete_files_and_media_desc">Deze actie kan niet ongedaan worden gemaakt, alle ontvangen en verzonden bestanden en media worden verwijderd. Foto\'s met een lage resolutie blijven behouden.</string>
|
||||
@@ -847,7 +840,7 @@
|
||||
<string name="connected_to_server_to_receive_messages_from_contact">U bent verbonden met de server die wordt gebruikt om berichten van dit contact te ontvangen.</string>
|
||||
<string name="profile_will_be_sent_to_contact_sending_link">Je profiel wordt verzonden naar het contact van wie je deze link hebt ontvangen.</string>
|
||||
<string name="you_will_join_group">U wordt lid van de groep waar deze link naar verwijst en maakt verbinding met de groepsleden.</string>
|
||||
<string name="notifications_mode_off">Wordt uitgevoerd wanneer de app is geopend</string>
|
||||
<string name="notifications_mode_off">Uitvoeren bij geopende app</string>
|
||||
<string name="settings_notification_preview_mode_title">Toon voorbeeld</string>
|
||||
<string name="ntf_channel_calls">SimpleX Chat oproepen</string>
|
||||
<string name="notifications_mode_periodic">Start periodiek</string>
|
||||
@@ -927,7 +920,6 @@
|
||||
<string name="use_simplex_chat_servers__question"><xliff:g id="appNameFull">SimpleX Chat</xliff:g> servers gebruiken\?</string>
|
||||
<string name="voice_messages_are_prohibited">Spraak berichten zijn verboden in deze groep.</string>
|
||||
<string name="personal_welcome">Welkom <xliff:g>%1$s</xliff:g>!</string>
|
||||
<string name="you_can_share_your_address_anybody_will_be_able_to_connect">U kunt uw adres delen als een link of als een QR-code. Iedereen kan verbinding met u maken. U verliest uw contacten niet als u deze later verwijdert.</string>
|
||||
<string name="you_can_start_chat_via_setting_or_by_restarting_the_app">U kunt de chat starten via app Instellingen / Database of door de app opnieuw op te starten.</string>
|
||||
<string name="snd_conn_event_switch_queue_phase_completed_for_member">je hebt het adres gewijzigd voor %s</string>
|
||||
<string name="snd_group_event_member_deleted">je hebt <xliff:g id="member profile" example="alice (Alice)">%1$s</xliff:g> verwijderd</string>
|
||||
@@ -1098,7 +1090,7 @@
|
||||
<string name="passcode_not_changed">Toegangscode niet gewijzigd!</string>
|
||||
<string name="passcode_set">Toegangscode ingesteld!</string>
|
||||
<string name="la_mode_system">Systeem</string>
|
||||
<string name="decryption_error">Decryptie fout</string>
|
||||
<string name="decryption_error">Decodering fout</string>
|
||||
<string name="alert_text_msg_bad_hash">De hash van het vorige bericht is anders.</string>
|
||||
<string name="alert_text_decryption_error_too_many_skipped"><xliff:g id="message count" example="1">%1$d</xliff:g> berichten overgeslagen.</string>
|
||||
<string name="alert_text_fragment_encryption_out_of_sync_old_database">Het kan gebeuren wanneer u of uw verbinding de oude databaseback-up gebruikte.</string>
|
||||
@@ -1116,7 +1108,7 @@
|
||||
<string name="revoke_file__title">Bestand intrekken\?</string>
|
||||
<string name="stop_file__confirm">Stop</string>
|
||||
<string name="stop_file__action">Bestand stoppen</string>
|
||||
<string name="stop_rcv_file__title">Stopt met het ontvangen van een bestand\?</string>
|
||||
<string name="stop_rcv_file__title">Stoppen met het ontvangen van bestand\?</string>
|
||||
<string name="stop_snd_file__title">Bestand verzenden stoppen\?</string>
|
||||
<string name="only_your_contact_can_make_calls">Alleen je contact kan bellen.</string>
|
||||
<string name="revoke_file__message">Het bestand wordt van de servers verwijderd.</string>
|
||||
@@ -1136,4 +1128,136 @@
|
||||
<string name="v5_0_polish_interface">Poolse interface</string>
|
||||
<string name="v5_0_polish_interface_descr">Dank aan de gebruikers – draag bij via Weblate!</string>
|
||||
<string name="v5_0_large_files_support">Video\'s en bestanden tot 1 GB</string>
|
||||
<string name="auth_open_chat_profiles">Chat profielen openen</string>
|
||||
<string name="learn_more_about_address">Over SimpleX adres</string>
|
||||
<string name="learn_more">Kom meer te weten</string>
|
||||
<string name="scan_qr_to_connect_to_contact">Om verbinding te maken, kan uw contact persoon de QR-code scannen of de link in de app gebruiken.</string>
|
||||
<string name="customize_theme_title">Thema aanpassen</string>
|
||||
<string name="group_welcome_preview">Voorbeeld</string>
|
||||
<string name="you_can_share_this_address_with_your_contacts">U kunt dit adres delen met uw contacten om ze verbinding te laten maken met %s.</string>
|
||||
<string name="export_theme">Exporteer thema</string>
|
||||
<string name="color_title">Titel</string>
|
||||
<string name="you_can_accept_or_reject_connection">Wanneer mensen vragen om verbinding te maken, kunt u dit accepteren of weigeren.</string>
|
||||
<string name="you_wont_lose_your_contacts_if_delete_address">U raakt uw contacten niet kwijt als u later uw adres verwijdert.</string>
|
||||
<string name="simplex_address">SimpleX adres</string>
|
||||
<string name="create_address_and_let_people_connect">Maak een adres aan zodat mensen contact met je kunnen opnemen.</string>
|
||||
<string name="create_simplex_address">Maak een SimpleX adres aan</string>
|
||||
<string name="share_with_contacts">Delen met contacten</string>
|
||||
<string name="your_contacts_will_remain_connected">Uw contacten blijven verbonden.</string>
|
||||
<string name="profile_update_will_be_sent_to_contacts">Profiel update wordt naar uw contacten verzonden.</string>
|
||||
<string name="share_address_with_contacts_question">Adres delen met contacten\?</string>
|
||||
<string name="stop_sharing">Stop met delen</string>
|
||||
<string name="stop_sharing_address">Stop met het delen van adres\?</string>
|
||||
<string name="invite_friends">Nodig vrienden uit</string>
|
||||
<string name="email_invite_subject">Laten we praten in SimpleX Chat</string>
|
||||
<string name="save_auto_accept_settings">Sla instellingen voor automatisch accepteren op</string>
|
||||
<string name="save_settings_question">Instellingen opslaan\?</string>
|
||||
<string name="enter_welcome_message_optional">Voer welkomst bericht in... (optioneel)</string>
|
||||
<string name="dont_create_address">Maak geen adres aan</string>
|
||||
<string name="email_invite_body">Hoi!
|
||||
\nMaak verbinding met mij via SimpleX Chat: %s</string>
|
||||
<string name="you_can_create_it_later">U kan het later maken</string>
|
||||
<string name="share_address">Adres delen</string>
|
||||
<string name="enter_welcome_message">Welkomst bericht invoeren…</string>
|
||||
<string name="import_theme">Thema importeren</string>
|
||||
<string name="theme_simplex">SimpleX</string>
|
||||
<string name="color_primary_variant">Extra accent</string>
|
||||
<string name="color_secondary_variant">Extra secundair</string>
|
||||
<string name="color_background">Achtergrond</string>
|
||||
<string name="color_surface">Menu\'s & waarschuwingen</string>
|
||||
<string name="color_received_message">Ontvangen bericht</string>
|
||||
<string name="color_sent_message">Verzonden bericht</string>
|
||||
<string name="color_secondary">Secundair</string>
|
||||
<string name="all_your_contacts_will_remain_connected_update_sent">Al uw contacten blijven verbonden. Profiel update wordt naar uw contacten verzonden.</string>
|
||||
<string name="one_time_link_short">Eenmalige link</string>
|
||||
<string name="address_section_title">Adres</string>
|
||||
<string name="add_address_to_your_profile">Voeg een adres toe aan uw profiel, zodat uw contacten het met andere mensen kunnen delen. Profiel update wordt naar uw contacten verzonden.</string>
|
||||
<string name="auto_accept_contact">Automatisch accepteren</string>
|
||||
<string name="if_you_cant_meet_in_person">Als je elkaar niet persoonlijk kunt ontmoeten, laat dan de QR-code zien in een videogesprek of deel de link.</string>
|
||||
<string name="continue_to_next_step">Doorgaan</string>
|
||||
<string name="dark_theme">Donker thema</string>
|
||||
<string name="error_setting_address">Fout bij het instellen van het adres</string>
|
||||
<string name="import_theme_error">Fout bij importeren thema</string>
|
||||
<string name="import_theme_error_desc">Zorg ervoor dat het bestand de juiste YAML-syntaxis heeft. Exporteer het thema om een voorbeeld te hebben van de themabestandsstructuur.</string>
|
||||
<string name="opening_database">Database openen…</string>
|
||||
<string name="read_more_in_user_guide_with_link">Lees meer in de <font color="#0088ff">Gebruikershandleiding</font>.</string>
|
||||
<string name="theme_colors_section_title">THEMA KLEUREN</string>
|
||||
<string name="you_can_share_your_address">U kunt uw adres delen als een link of QR-code - iedereen kan verbinding met u maken.</string>
|
||||
<string name="your_contacts_will_see_it">Uw contacten in SimpleX zullen het zien.
|
||||
\nU kunt dit wijzigen in Instellingen.</string>
|
||||
<string name="all_app_data_will_be_cleared">Alle app-gegevens worden verwijderd.</string>
|
||||
<string name="empty_chat_profile_is_created">Er wordt een leeg chatprofiel met de opgegeven naam gemaakt en de app wordt zoals gewoonlijk geopend.</string>
|
||||
<string name="enabled_self_destruct_passcode">Zelfvernietigings wachtwoord inschakelen</string>
|
||||
<string name="self_destruct">Zelfvernietiging</string>
|
||||
<string name="change_self_destruct_mode">Zelfvernietigings modus wijzigen</string>
|
||||
<string name="change_self_destruct_passcode">Zelfvernietigings code wijzigen</string>
|
||||
<string name="enable_self_destruct">Zelfvernietiging inschakelen</string>
|
||||
<string name="self_destruct_new_display_name">Nieuwe weergavenaam:</string>
|
||||
<string name="self_destruct_passcode">Zelfvernietigingscode</string>
|
||||
<string name="self_destruct_passcode_changed">Zelfvernietigingscode gewijzigd!</string>
|
||||
<string name="self_destruct_passcode_enabled">Zelfvernietigings wachtwoord ingeschakeld!</string>
|
||||
<string name="app_passcode_replaced_with_self_destruct">De app-toegangscode wordt vervangen door een zelfvernietigings wachtwoord.</string>
|
||||
<string name="if_you_enter_self_destruct_code">Als u uw zelfvernietigings wachtwoord invoert tijdens het openen van de app:</string>
|
||||
<string name="if_you_enter_passcode_data_removed">Als u deze toegangscode invoert bij het openen van de app, worden alle app-gegevens onomkeerbaar verwijderd!</string>
|
||||
<string name="set_passcode">Toegangscode instellen</string>
|
||||
<string name="prohibit_message_reactions">Berichtreacties verbieden.</string>
|
||||
<string name="only_you_can_add_message_reactions">Alleen jij kunt berichtreacties toevoegen.</string>
|
||||
<string name="message_reactions_are_prohibited">Reacties op berichten zijn verboden in deze groep.</string>
|
||||
<string name="prohibit_message_reactions_group">Berichten reacties verbieden.</string>
|
||||
<string name="allow_message_reactions_only_if">Sta berichtreacties alleen toe als uw contactpersoon dit toestaat.</string>
|
||||
<string name="allow_your_contacts_adding_message_reactions">Sta uw contactpersonen toe om berichtreacties toe te voegen.</string>
|
||||
<string name="allow_message_reactions">Sta berichtreacties toe.</string>
|
||||
<string name="group_members_can_add_message_reactions">Groepsleden kunnen berichtreacties toevoegen.</string>
|
||||
<string name="both_you_and_your_contact_can_add_message_reactions">Zowel u als uw contactpersoon kunnen berichtreacties toevoegen.</string>
|
||||
<string name="message_reactions">Reacties op berichten</string>
|
||||
<string name="message_reactions_prohibited_in_this_chat">Reacties op berichten zijn verboden in deze chat.</string>
|
||||
<string name="only_your_contact_can_add_message_reactions">Alleen uw contactpersoon kan berichtreacties toevoegen.</string>
|
||||
<string name="custom_time_unit_days">dagen</string>
|
||||
<string name="custom_time_unit_hours">uren</string>
|
||||
<string name="custom_time_unit_minutes">minuten</string>
|
||||
<string name="custom_time_unit_months">maanden</string>
|
||||
<string name="custom_time_unit_weeks">weken</string>
|
||||
<string name="send_disappearing_message_send">Versturen</string>
|
||||
<string name="send_disappearing_message_5_minutes">5 minuten</string>
|
||||
<string name="send_disappearing_message_30_seconds">30 seconden</string>
|
||||
<string name="send_disappearing_message">Stuur een verdwijnend bericht</string>
|
||||
<string name="send_disappearing_message_1_minute">1 minuut</string>
|
||||
<string name="send_disappearing_message_custom_time">Aangepaste tijd</string>
|
||||
<string name="disappearing_message">Verdwijnend bericht</string>
|
||||
<string name="custom_time_unit_seconds">seconden</string>
|
||||
<string name="custom_time_picker_select">Selecteer</string>
|
||||
<string name="custom_time_picker_custom">aangepast</string>
|
||||
<string name="info_row_moderated_at">Gemodereerd om</string>
|
||||
<string name="info_row_updated_at">Record bijgewerkt op</string>
|
||||
<string name="item_info_current">(huidig)</string>
|
||||
<string name="share_text_database_id">Database-ID: %d</string>
|
||||
<string name="info_menu">Info</string>
|
||||
<string name="info_row_disappears_at">Verdwijnt om</string>
|
||||
<string name="share_text_moderated_at">Gemodereerd op: %s</string>
|
||||
<string name="share_text_disappears_at">Verdwijnt om: %s</string>
|
||||
<string name="current_version_timestamp">%s (huidig)</string>
|
||||
<string name="share_text_sent_at">Verzonden op: %s</string>
|
||||
<string name="error_loading_details">Fout bij het laden van details</string>
|
||||
<string name="sent_message">Verzonden bericht</string>
|
||||
<string name="info_row_deleted_at">Verwijderd om</string>
|
||||
<string name="info_row_received_at">Ontvangen op</string>
|
||||
<string name="info_row_sent_at">Verzonden op</string>
|
||||
<string name="share_text_deleted_at">Verwijderd om: %s</string>
|
||||
<string name="share_text_received_at">Ontvangen op: %s</string>
|
||||
<string name="share_text_updated_at">Record bijgewerkt op: %s</string>
|
||||
<string name="edit_history">Geschiedenis</string>
|
||||
<string name="received_message">Ontvangen bericht</string>
|
||||
<string name="whats_new_read_more">Lees meer</string>
|
||||
<string name="v5_1_message_reactions">Reacties op berichten</string>
|
||||
<string name="v5_1_self_destruct_passcode_descr">Alle gegevens worden bij het invoeren gewist.</string>
|
||||
<string name="v5_1_better_messages">Betere berichten</string>
|
||||
<string name="v5_1_custom_themes_descr">Pas kleuren thema\'s aan en deel ze.</string>
|
||||
<string name="v5_1_custom_themes">Aangepaste thema\'s</string>
|
||||
<string name="v5_1_message_reactions_descr">Eindelijk, we hebben ze! 🚀</string>
|
||||
<string name="v5_1_japanese_portuguese_interface">Japanse en Portugese gebruikersinterface</string>
|
||||
<string name="v5_1_self_destruct_passcode">Zelfvernietigingscode</string>
|
||||
<string name="whats_new_thanks_to_users_contribute_weblate">Dank aan de gebruikers – draag bij via Weblate!</string>
|
||||
<string name="v5_1_better_messages_descr">- spraakberichten tot 5 minuten.
|
||||
\n- aangepaste tijd om te verdwijnen.
|
||||
\n- bewerkingsgeschiedenis.</string>
|
||||
</resources>
|
||||
@@ -279,7 +279,7 @@
|
||||
<string name="scan_code_from_contacts_app">Zeskanuj kod bezpieczeństwa z aplikacji Twojego kontaktu.</string>
|
||||
<string name="security_code">Kod bezpieczeństwa</string>
|
||||
<string name="icon_descr_settings">Ustawienia</string>
|
||||
<string name="share_invitation_link">Udostępnij link zaproszenia</string>
|
||||
<string name="share_invitation_link">Udostępnij 1-razowy link</string>
|
||||
<string name="show_QR_code">Pokaż kod QR</string>
|
||||
<string name="is_verified">%s jest zweryfikowany</string>
|
||||
<string name="this_QR_code_is_not_a_link">Ten kod QR nie jest linkiem!</string>
|
||||
@@ -290,7 +290,6 @@
|
||||
<string name="your_chat_profile_will_be_sent_to_your_contact">Twój profil czatu zostanie wysłany
|
||||
\ndo Twojego kontaktu</string>
|
||||
<string name="your_profile_will_be_sent">Twój profil czatu zostanie wysłany do Twojego kontaktu</string>
|
||||
<string name="your_contact_address">Twój adres kontaktowy</string>
|
||||
<string name="you_will_be_connected_when_group_host_device_is_online">Zostaniesz połączony do grupy, gdy urządzenie gospodarza grupy będzie online, proszę czekać lub sprawdzić później!</string>
|
||||
<string name="you_will_be_connected_when_your_contacts_device_is_online">Zostaniesz połączony, gdy urządzenie Twojego kontaktu będzie online, proszę czekać lub sprawdzić później!</string>
|
||||
<string name="smp_servers_preset_add">Dodaj gotowe serwery</string>
|
||||
@@ -330,9 +329,9 @@
|
||||
<string name="your_ICE_servers">Twoje serwery ICE</string>
|
||||
<string name="smp_servers_your_server">Twój serwer</string>
|
||||
<string name="smp_servers_your_server_address">Twój adres serwera</string>
|
||||
<string name="your_simplex_contact_address">Twój adres kontaktowy <xliff:g id="appName">SimpleX</xliff:g></string>
|
||||
<string name="your_simplex_contact_address">Twój adres SimpleX</string>
|
||||
<string name="contribute">Przyczyń się</string>
|
||||
<string name="network_enable_socks_info">Uzyskiwać dostęp do serwerów przez SOCKS proxy na porcie 9050\? Proxy musi zostać uruchomione przed włączeniem tej opcji.</string>
|
||||
<string name="network_enable_socks_info">Uzyskiwanie dostępu do serwerów przez SOCKS proxy na porcie %d\? Proxy musi zostać uruchomione przed włączeniem tej opcji.</string>
|
||||
<string name="network_settings">Zaawansowane ustawienia sieci</string>
|
||||
<string name="app_version_code">Kompilacja aplikacji: %s</string>
|
||||
<string name="appearance_settings">Wygląd</string>
|
||||
@@ -363,11 +362,7 @@
|
||||
<string name="network_disable_socks">Użyć bezpośredniego połączenia z Internetem\?</string>
|
||||
<string name="network_use_onion_hosts">Użyj hostów .onion</string>
|
||||
<string name="network_enable_socks">Użyć proxy SOCKS\?</string>
|
||||
<string name="network_socks_toggle">Użyj proxy SOCKS (port 9050)</string>
|
||||
<string name="accept_requests">Akceptuj prośby</string>
|
||||
<string name="all_your_contacts_will_remain_connected">Wszystkie Twoje kontakty pozostaną połączone.</string>
|
||||
<string name="accept_automatically">Automatycznie</string>
|
||||
<string name="contact_requests">Prośby kontaktu</string>
|
||||
<string name="create_address">Utwórz adres</string>
|
||||
<string name="developer_options">ID bazy danych i opcja izolacji transportu.</string>
|
||||
<string name="delete_address">Usuń adres</string>
|
||||
@@ -387,8 +382,6 @@
|
||||
<string name="show_dev_options">Pokaż:</string>
|
||||
<string name="show_developer_options">Pokaż opcje dewelopera</string>
|
||||
<string name="core_simplexmq_version">simplexmq: v%s (%2s)</string>
|
||||
<string name="section_title_welcome_message">WIADOMOŚĆ POWITALNA</string>
|
||||
<string name="you_can_share_your_address_anybody_will_be_able_to_connect">Możesz udostępnić swój adres jako link lub jako kod QR - każdy będzie mógł się z Tobą połączyć. Nie stracisz swoich kontaktów, jeśli później go usuniesz.</string>
|
||||
<string name="your_current_profile">Twój obecny profil</string>
|
||||
<string name="confirm_password">Potwierdź hasło</string>
|
||||
<string name="create_profile">Utwórz profil</string>
|
||||
@@ -1035,13 +1028,12 @@
|
||||
<string name="group_info_section_title_num_members"><xliff:g id="num_members">%1$s</xliff:g> CZŁONKÓW</string>
|
||||
<string name="simplex_service_notification_title">serwis <xliff:g id="appNameFull">SimpleX Chat</xliff:g></string>
|
||||
<string name="contact_wants_to_connect_via_call"><xliff:g id="contactName" example="Alice">%1$s</xliff:g> chce się z Tobą połączyć przez</string>
|
||||
<string name="you_are_already_connected_to_vName_via_this_link">Jesteś już połączony z <xliff:g id="contactName" example="Alice">%1$s!</xliff:g>.</string>
|
||||
<string name="you_are_already_connected_to_vName_via_this_link">Jesteś już połączony z <xliff:g id="contactName" example="Alice">%1$s</xliff:g>.</string>
|
||||
<string name="you_can_connect_to_simplex_chat_founder">Możesz <font color="#0088ff">połączyć się z deweloperami <xliff:g id="appNameFull">SimpleX Chat</xliff:g> aby zadać wszelkie pytania i otrzymywać aktualizacje</font>.</string>
|
||||
<string name="you_can_share_group_link_anybody_will_be_able_to_connect">Możesz udostępnić link lub kod QR - każdy będzie mógł dołączyć do grupy. Nie stracisz członków grupy, jeśli później ją usuniesz.</string>
|
||||
<string name="you_must_use_the_most_recent_version_of_database">Musisz używać najnowszej wersji bazy danych czatu TYLKO na jednym urządzeniu, w przeciwnym razie możesz przestać otrzymywać wiadomości od niektórych kontaktów.</string>
|
||||
<string name="you_can_start_chat_via_setting_or_by_restarting_the_app">Możesz rozpocząć czat poprzez Ustawienia aplikacji / Bazę danych lub poprzez ponowne uruchomienie aplikacji.</string>
|
||||
<string name="your_settings">Twoje ustawienia</string>
|
||||
<string name="show_QR_code_for_your_contact_to_scan_from_the_app__multiline">Twój kontakt może zeskanować kod QR z aplikacji.</string>
|
||||
<string name="your_current_chat_database_will_be_deleted_and_replaced_with_the_imported_one">Twoja obecna baza danych czatu zostanie USUNIĘTA i ZASTĄPIONA zaimportowaną.
|
||||
\nTej czynności nie można cofnąć - Twój profil, kontakty, wiadomości i pliki zostaną nieodwracalnie utracone.</string>
|
||||
<string name="contact_sent_large_file">Twój kontakt wysłał plik, który jest większy niż obecnie obsługiwany maksymalny rozmiar (<xliff:g id="maxFileSize">%1$s</xliff:g>).</string>
|
||||
@@ -1084,7 +1076,7 @@
|
||||
<string name="you_can_turn_on_lock">Możesz włączyć blokadę SimpleX poprzez Ustawienia.</string>
|
||||
<string name="enable_lock">Włącz blokadę</string>
|
||||
<string name="authentication_cancelled">Uwierzytelnianie anulowane</string>
|
||||
<string name="confirm_passcode">Potwierdź Pin</string>
|
||||
<string name="confirm_passcode">Potwierdź pin</string>
|
||||
<string name="incorrect_passcode">Nieprawidłowy pin</string>
|
||||
<string name="lock_after">Zablokuj po</string>
|
||||
<string name="lock_mode">Tryb blokady</string>
|
||||
@@ -1137,4 +1129,136 @@
|
||||
<string name="v5_0_app_passcode_descr">Ustaw go zamiast uwierzytelniania systemowego.</string>
|
||||
<string name="v5_0_large_files_support_descr">Szybko i bez czekania aż nadawca będzie online!</string>
|
||||
<string name="v5_0_polish_interface_descr">Podziękowania dla użytkowników - wkład za pośrednictwem Weblate!</string>
|
||||
<string name="change_self_destruct_mode">Zmień tryb samozniszczenia</string>
|
||||
<string name="change_self_destruct_passcode">Zmień pin samozniszczenia</string>
|
||||
<string name="enabled_self_destruct_passcode">Włącz pin samodestrukcji</string>
|
||||
<string name="self_destruct">Samozniszczenie</string>
|
||||
<string name="self_destruct_passcode_changed">Pin samozniszczenia zmieniony!</string>
|
||||
<string name="all_app_data_will_be_cleared">Wszystkie dane aplikacji są usunięte.</string>
|
||||
<string name="enable_self_destruct">Włącz samodestrukcję</string>
|
||||
<string name="if_you_enter_self_destruct_code">Jeśli wpiszesz swój pin samodestrukcji podczas otwierania aplikacji:</string>
|
||||
<string name="self_destruct_new_display_name">Nowa nazwa wyświetlana:</string>
|
||||
<string name="empty_chat_profile_is_created">Tworzony jest pusty profil czatu o podanej nazwie, a aplikacja otwiera się jak zwykle.</string>
|
||||
<string name="app_passcode_replaced_with_self_destruct">Pin aplikacji został zastąpiony pinem samozniszczenia.</string>
|
||||
<string name="if_you_enter_passcode_data_removed">Jeśli wprowadzisz ten pin podczas otwierania aplikacji, wszystkie dane aplikacji zostaną nieodwracalnie usunięte!</string>
|
||||
<string name="set_passcode">Ustaw pin</string>
|
||||
<string name="share_address">Udostępnij adres</string>
|
||||
<string name="you_can_share_this_address_with_your_contacts">Możesz udostępnić ten adres Twoim kontaktom, aby umożliwić im połączenie z %s.</string>
|
||||
<string name="learn_more">Dowiedz się więcej</string>
|
||||
<string name="stop_sharing_address">Przestać udostępniać adres\?</string>
|
||||
<string name="auto_accept_contact">Automatycznie akceptuj</string>
|
||||
<string name="share_address_with_contacts_question">Udostępnić adres kontaktom\?</string>
|
||||
<string name="enter_welcome_message_optional">Wpisz wiadomość powitalną… (opcjonalne)</string>
|
||||
<string name="profile_update_will_be_sent_to_contacts">Aktualizacja profilu zostanie wysłana do Twoich kontaktów.</string>
|
||||
<string name="save_settings_question">Zapisać ustawienia\?</string>
|
||||
<string name="stop_sharing">Przestań udostępniać</string>
|
||||
<string name="continue_to_next_step">Kontynuuj</string>
|
||||
<string name="dont_create_address">Nie twórz adresu</string>
|
||||
<string name="email_invite_body">Cześć!
|
||||
\nPołącz się ze mną za pomocą SimpleX Chat: %s</string>
|
||||
<string name="invite_friends">Zaproś znajomych</string>
|
||||
<string name="email_invite_subject">Porozmawiajmy w SimpleX Chat</string>
|
||||
<string name="group_welcome_preview">Podgląd</string>
|
||||
<string name="opening_database">Otwieranie bazy danych…</string>
|
||||
<string name="error_setting_address">Błąd ustawiania adresu</string>
|
||||
<string name="auth_open_chat_profiles">Otwórz profile czatu</string>
|
||||
<string name="learn_more_about_address">O adresie SimpleX</string>
|
||||
<string name="one_time_link_short">1-razowy link</string>
|
||||
<string name="read_more_in_user_guide_with_link">Przeczytaj więcej w <font color="#0088ff">Podręczniku Użytkownika</font>.</string>
|
||||
<string name="simplex_address">Adres SimpleX</string>
|
||||
<string name="you_can_accept_or_reject_connection">Kiedy ludzie proszą o połączenie, możesz je zaakceptować lub odrzucić.</string>
|
||||
<string name="you_wont_lose_your_contacts_if_delete_address">Nie stracisz kontaktów, jeśli później usuniesz swój adres.</string>
|
||||
<string name="customize_theme_title">Dostosuj motyw</string>
|
||||
<string name="theme_colors_section_title">KOLORY MOTYWU</string>
|
||||
<string name="your_contacts_will_remain_connected">Twoje kontakty pozostaną połączone.</string>
|
||||
<string name="add_address_to_your_profile">Dodaj adres do swojego profilu, aby Twoje kontakty mogły go udostępnić innym osobom. Aktualizacja profilu zostanie wysłana do Twoich kontaktów.</string>
|
||||
<string name="create_address_and_let_people_connect">Utwórz adres, aby ludzie mogli się z Tobą połączyć.</string>
|
||||
<string name="create_simplex_address">Utwórz adres SimpleX</string>
|
||||
<string name="save_auto_accept_settings">Zapisz ustawienia automatycznej akceptacji</string>
|
||||
<string name="share_with_contacts">Udostępnij kontaktom</string>
|
||||
<string name="you_can_create_it_later">Możesz go utworzyć później</string>
|
||||
<string name="your_contacts_will_see_it">Twoje kontakty w SimpleX będą to widzieć.
|
||||
\nMożesz to zmienić w Ustawieniach.</string>
|
||||
<string name="address_section_title">Adres</string>
|
||||
<string name="theme_simplex">SimpleX</string>
|
||||
<string name="color_secondary">Drugorzędny</string>
|
||||
<string name="color_primary_variant">Dodatkowy akcent</string>
|
||||
<string name="dark_theme">Ciemny motyw</string>
|
||||
<string name="export_theme">Eksportuj motyw</string>
|
||||
<string name="import_theme">Importuj motyw</string>
|
||||
<string name="import_theme_error">Błąd importu motywu</string>
|
||||
<string name="import_theme_error_desc">Upewnij się, że plik ma poprawną składnię YAML. Eksportuj motyw, aby mieć przykład struktury plików motywu.</string>
|
||||
<string name="color_surface">Menu i alerty</string>
|
||||
<string name="color_secondary_variant">Dodatkowy drugorzędny</string>
|
||||
<string name="color_background">Tło</string>
|
||||
<string name="color_received_message">Otrzymano wiadomość</string>
|
||||
<string name="color_sent_message">Wyślij wiadomość</string>
|
||||
<string name="color_title">Tytuł</string>
|
||||
<string name="all_your_contacts_will_remain_connected_update_sent">Wszystkie Twoje kontakty pozostaną połączone. Aktualizacja profilu zostanie wysłana do Twoich kontaktów.</string>
|
||||
<string name="enter_welcome_message">Wpisz wiadomość powitalną…</string>
|
||||
<string name="if_you_cant_meet_in_person">Jeśli nie możesz spotkać się osobiście, pokaż kod QR w rozmowie wideo lub udostępnij link.</string>
|
||||
<string name="you_can_share_your_address">Możesz udostępnić swój adres jako link lub kod QR - każdy może się z Tobą połączyć.</string>
|
||||
<string name="self_destruct_passcode">Pin samozniszczenia</string>
|
||||
<string name="self_destruct_passcode_enabled">Pin samozniszczenia włączony!</string>
|
||||
<string name="scan_qr_to_connect_to_contact">Aby się połączyć, Twój kontakt może zeskanować kod QR lub skorzystać z linku w aplikacji.</string>
|
||||
<string name="send_disappearing_message_custom_time">Niestandardowy czas</string>
|
||||
<string name="custom_time_unit_days">dni</string>
|
||||
<string name="send_disappearing_message_send">Wyślij</string>
|
||||
<string name="send_disappearing_message">Wyślij znikającą wiadomość</string>
|
||||
<string name="prohibit_message_reactions_group">Zabroń reakcje wiadomości.</string>
|
||||
<string name="message_reactions">Reakcje wiadomości</string>
|
||||
<string name="group_members_can_add_message_reactions">Członkowie grupy mogą dodawać reakcje wiadomości.</string>
|
||||
<string name="custom_time_unit_hours">godziny</string>
|
||||
<string name="message_reactions_prohibited_in_this_chat">Reakcje wiadomości są zabronione na tym czacie.</string>
|
||||
<string name="message_reactions_are_prohibited">Reakcje wiadomości są zabronione w tej grupie.</string>
|
||||
<string name="custom_time_unit_minutes">minuty</string>
|
||||
<string name="custom_time_unit_months">miesiące</string>
|
||||
<string name="only_you_can_add_message_reactions">Tylko Ty możesz dodawać reakcje wiadomości.</string>
|
||||
<string name="prohibit_message_reactions">Zabroń reakcje wiadomości.</string>
|
||||
<string name="only_your_contact_can_add_message_reactions">Tylko Twój kontakt może dodawać reakcje wiadomości.</string>
|
||||
<string name="custom_time_unit_seconds">sekundy</string>
|
||||
<string name="custom_time_unit_weeks">tygodnie</string>
|
||||
<string name="send_disappearing_message_5_minutes">5 minut</string>
|
||||
<string name="allow_message_reactions">Zezwalaj na reakcje wiadomości.</string>
|
||||
<string name="allow_your_contacts_adding_message_reactions">Zezwalaj kontaktom na reakcje wiadomości.</string>
|
||||
<string name="disappearing_message">Znikająca wiadomość</string>
|
||||
<string name="send_disappearing_message_30_seconds">30 sekund</string>
|
||||
<string name="send_disappearing_message_1_minute">1 minuta</string>
|
||||
<string name="allow_message_reactions_only_if">Zezwalaj na reakcje wiadomości tylko wtedy, gdy zezwala na to Twój kontakt.</string>
|
||||
<string name="both_you_and_your_contact_can_add_message_reactions">Zarówno Ty, jak i Twój kontakt możecie dodawać reakcje wiadomości.</string>
|
||||
<string name="custom_time_picker_select">Wybierz</string>
|
||||
<string name="custom_time_picker_custom">niestandardowy</string>
|
||||
<string name="error_loading_details">Błąd ładowania szczegółów</string>
|
||||
<string name="received_message">Otrzymano wiadomość</string>
|
||||
<string name="sent_message">Wyślij wiadomość</string>
|
||||
<string name="info_row_deleted_at">Usunięto o</string>
|
||||
<string name="info_row_moderated_at">Moderowany o</string>
|
||||
<string name="share_text_received_at">Otrzymane o: %s</string>
|
||||
<string name="info_row_updated_at">Rekord zaktualizowany o</string>
|
||||
<string name="info_row_sent_at">Wysłano o</string>
|
||||
<string name="share_text_sent_at">Wysłano o: %s</string>
|
||||
<string name="share_text_database_id">ID bazy danych: %d</string>
|
||||
<string name="item_info_current">(aktualny)</string>
|
||||
<string name="share_text_deleted_at">Usunięto o: %s</string>
|
||||
<string name="info_row_disappears_at">Znika o</string>
|
||||
<string name="share_text_disappears_at">Znika o: %s</string>
|
||||
<string name="info_menu">Info</string>
|
||||
<string name="share_text_moderated_at">Moderowany o: %s</string>
|
||||
<string name="edit_history">Historia</string>
|
||||
<string name="info_row_received_at">Otrzymane o</string>
|
||||
<string name="current_version_timestamp">%s (aktualny)</string>
|
||||
<string name="share_text_updated_at">Rekord zaktualizowany o: %s</string>
|
||||
<string name="v5_1_self_destruct_passcode_descr">Wszystkie dane są usuwane po jego wprowadzeniu.</string>
|
||||
<string name="whats_new_thanks_to_users_contribute_weblate">Podziękowania dla użytkowników - wkład za pośrednictwem Weblate!</string>
|
||||
<string name="v5_1_message_reactions">Reakcje wiadomości</string>
|
||||
<string name="v5_1_better_messages">Lepsze wiadomości</string>
|
||||
<string name="v5_1_custom_themes_descr">Dostosuj i udostępniaj motywy kolorów.</string>
|
||||
<string name="v5_1_custom_themes">Niestandardowe motywy</string>
|
||||
<string name="v5_1_message_reactions_descr">W końcu je mamy! 🚀</string>
|
||||
<string name="v5_1_japanese_portuguese_interface">Japoński i portugalski interfejs użytkownika</string>
|
||||
<string name="whats_new_read_more">Przeczytaj więcej</string>
|
||||
<string name="v5_1_self_destruct_passcode">Pin samozniszczenia</string>
|
||||
<string name="v5_1_better_messages_descr">- wiadomości głosowe do 5 minut.
|
||||
\n- niestandardowy czas zniknięcia.
|
||||
\n- historia edycji.</string>
|
||||
</resources>
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="about_simplex_chat">Sobre o <xliff:g id="appNameFull">SimpleX Chat</xliff:g></string>
|
||||
<string name="about_simplex">Sobre SimpleX</string>
|
||||
<string name="about_simplex">Sobre o SimpleX</string>
|
||||
<string name="chat_item_ttl_day">1 dia</string>
|
||||
<string name="chat_item_ttl_week">1 semana</string>
|
||||
<string name="chat_item_ttl_month">1 mês</string>
|
||||
@@ -50,7 +50,6 @@
|
||||
<string name="icon_descr_close_button">Botão Fechar</string>
|
||||
<string name="clear_verification">Limpar verificação</string>
|
||||
<string name="app_version_title">Versão do App</string>
|
||||
<string name="accept_automatically">Automaticamente</string>
|
||||
<string name="bold">negrito</string>
|
||||
<string name="callstatus_error">erro de chamada</string>
|
||||
<string name="settings_audio_video_calls">Chamadas de áudio e vídeo</string>
|
||||
@@ -67,7 +66,6 @@
|
||||
<string name="incognito_random_profile_description">Um perfil aleatório será enviado para o seu contato</string>
|
||||
<string name="chat_preferences">Preferências de chat</string>
|
||||
<string name="network_session_mode_user">perfil de chat</string>
|
||||
<string name="accept_requests">Aceitar solicitações</string>
|
||||
<string name="icon_descr_audio_off">Áudio desligado</string>
|
||||
<string name="auto_accept_images">Aceitar imagens automaticamente</string>
|
||||
<string name="chat_database_deleted">Banco de dados de chat excluído</string>
|
||||
@@ -79,8 +77,8 @@
|
||||
<string name="chat_console">Console de chat</string>
|
||||
<string name="smp_servers_check_address">Verifique o endereço do servidor e tente novamente.</string>
|
||||
<string name="network_session_mode_user_description">Uma conexão TCP separada (e credencial SOCKS) será usada <b>para cada perfil de chat que você tiver no aplicativo</b>.</string>
|
||||
<string name="onboarding_notifications_mode_off_desc"><b>Melhor para bateria</b>. Você receberá notificações apenas quando o aplicativo estiver em execução, o serviço em segundo plano NÃO será usado.</string>
|
||||
<string name="onboarding_notifications_mode_service_desc"><b>Consome mais bateria</b>! O serviço em segundo plano está sempre em execução - as notificações serão exibidas assim que as mensagens estiverem disponíveis.</string>
|
||||
<string name="onboarding_notifications_mode_off_desc"><b>Melhor para bateria</b>. Você receberá notificações apenas quando o aplicativo estiver em execução (sem segundo plano).</string>
|
||||
<string name="onboarding_notifications_mode_service_desc"><b>Consome mais bateria</b>! O serviço em segundo plano está sempre em execução - as notificações são exibidas assim que as mensagens estiverem disponíveis.</string>
|
||||
<string name="settings_section_title_chats">CHATS</string>
|
||||
<string name="settings_section_title_icon">ÍCONE DO APP</string>
|
||||
<string name="chat_database_section">BANCO DE DADOS DE CHAT</string>
|
||||
@@ -89,7 +87,7 @@
|
||||
<string name="change_database_passphrase_question">Alterar senha do banco de dados\?</string>
|
||||
<string name="chat_archive_header">Arquivo de chat</string>
|
||||
<string name="rcv_conn_event_switch_queue_phase_completed">endereço alterado para você</string>
|
||||
<string name="both_you_and_your_contact_can_send_disappearing">Você e seu contato podem enviar mensagens que desaparecem.</string>
|
||||
<string name="both_you_and_your_contact_can_send_disappearing">Você e seu contato podem enviar mensagens temporárias.</string>
|
||||
<string name="full_backup">Backup de dados do aplicativo</string>
|
||||
<string name="settings_section_title_calls">CHAMADAS</string>
|
||||
<string name="v4_2_auto_accept_contact_requests">Aceitar solicitações de contato automaticamente</string>
|
||||
@@ -97,7 +95,7 @@
|
||||
<string name="notifications_mode_service_desc">O serviço em segundo plano está sempre em execução - as notificações serão exibidas assim que as mensagens estiverem disponíveis.</string>
|
||||
<string name="network_session_mode_entity_description">Uma conexão TCP separada (e credencial SOCKS) será usada <b>para cada contato e membro do grupo</b>.
|
||||
\n<b>Observação</b>: se você tiver muitas conexões, o consumo de bateria e tráfego pode ser substancialmente maior e algumas conexões podem falhar.</string>
|
||||
<string name="onboarding_notifications_mode_periodic_desc"><b>Bom para bateria</b>. O serviço em segundo plano verifica novas mensagens a cada 10 minutos. Você pode perder chamadas e mensagens urgentes.</string>
|
||||
<string name="onboarding_notifications_mode_periodic_desc"><b>Bom para bateria</b>. O serviço em segundo plano procura por mensagens a cada 10 minutos. Você pode perder chamadas ou mensagens urgentes.</string>
|
||||
<string name="callstatus_ended">chamda encerrada <xliff:g id="duration" example="01:15">%1$s</xliff:g></string>
|
||||
<string name="chat_with_developers">Chat com os desenvolvedores</string>
|
||||
<string name="create_group_link">Criar link de grupo</string>
|
||||
@@ -111,7 +109,7 @@
|
||||
<string name="notification_preview_somebody">Contato oculto:</string>
|
||||
<string name="copy_verb">Copiar</string>
|
||||
<string name="allow_verb">Permitir</string>
|
||||
<string name="allow_to_send_disappearing">Permitir enviar mensagens que desaparecem.</string>
|
||||
<string name="allow_to_send_disappearing">Permitir enviar mensagens temporárias.</string>
|
||||
<string name="allow_direct_messages">Permitir o envio de mensagens diretas aos membros.</string>
|
||||
<string name="connect_via_link_or_qr">Conectar via link/QR</string>
|
||||
<string name="clear_chat_warning">Todas as mensagens serão excluídas - isso não pode ser desfeito! As mensagens serão excluídas APENAS para você.</string>
|
||||
@@ -123,7 +121,6 @@
|
||||
<string name="copied">Copiado para a área de transferência</string>
|
||||
<string name="accept_connection_request__question">Aceitar solicitação de conexão\?</string>
|
||||
<string name="network_settings">Configurações de rede avançadas</string>
|
||||
<string name="contact_requests">Solicitações de contato</string>
|
||||
<string name="create_address">Criar endereço</string>
|
||||
<string name="all_your_contacts_will_remain_connected">Todos os seus contatos permanecerão conectados.</string>
|
||||
<string name="callstatus_accepted">chamada aceita</string>
|
||||
@@ -145,7 +142,7 @@
|
||||
<string name="accept_feature">Aceitar</string>
|
||||
<string name="allow_disappearing_messages_only_if">Permitir mensagens temporárias apenas se o seu contato permitir.</string>
|
||||
<string name="allow_irreversible_message_deletion_only_if">Permita a exclusão irreversível da mensagem somente se o seu contato permitir.</string>
|
||||
<string name="allow_your_contacts_to_send_disappearing_messages">Permitir que seus contatos enviem mensagens que desaparecem.</string>
|
||||
<string name="allow_your_contacts_to_send_disappearing_messages">Permitir que seus contatos enviem mensagens temporárias.</string>
|
||||
<string name="allow_voice_messages_only_if">Permitir mensagens de voz somente se o seu contato permitir.</string>
|
||||
<string name="allow_your_contacts_to_send_voice_messages">Permitir que seus contatos enviem mensagens de voz.</string>
|
||||
<string name="group_member_role_admin">administrador</string>
|
||||
@@ -157,7 +154,7 @@
|
||||
<string name="alert_title_contact_connection_pending">Contato ainda não está conectado!</string>
|
||||
<string name="contribute">Contribuir</string>
|
||||
<string name="create_profile_button">Criar</string>
|
||||
<string name="network_enable_socks_info">Acessar os servidores via proxy SOCKS na porta 9050\? O proxy deve ser iniciado antes de habilitar esta opção.</string>
|
||||
<string name="network_enable_socks_info">Acessar os servidores via proxy SOCKS na porta %d\? O proxy deve ser iniciado antes de habilitar esta opção.</string>
|
||||
<string name="allow_your_contacts_irreversibly_delete">Permitir que seus contatos excluam de forma irreversível as mensagens enviadas.</string>
|
||||
<string name="smp_servers_add_to_another_device">Adicionar a outro dispositivo</string>
|
||||
<string name="v4_2_group_links_desc">Os administradores podem criar os links para ingressar em grupos.</string>
|
||||
@@ -263,7 +260,7 @@
|
||||
<string name="settings_section_title_device">DISPOSITIVO</string>
|
||||
<string name="settings_developer_tools">Ferramentas de desenvolvimento</string>
|
||||
<string name="group_member_status_introduced">conectando (introduzido)</string>
|
||||
<string name="color_primary">Realçar</string>
|
||||
<string name="color_primary">Acento</string>
|
||||
<string name="error_removing_member">Erro ao remover membro</string>
|
||||
<string name="error_changing_role">Erro ao alterar função</string>
|
||||
<string name="conn_level_desc_direct">direto</string>
|
||||
@@ -349,11 +346,11 @@
|
||||
<string name="ttl_h">%dh</string>
|
||||
<string name="ttl_hours">%d horas</string>
|
||||
<string name="description_via_contact_address_link_incognito">anônimo via link de endereço de contato</string>
|
||||
<string name="description_via_one_time_link_incognito">anônimo via link único</string>
|
||||
<string name="description_via_one_time_link_incognito">anônimo via link de uso único</string>
|
||||
<string name="hide_verb">Ocultar</string>
|
||||
<string name="from_gallery_button">Da Galeria</string>
|
||||
<string name="gallery_video_button">Vídeo</string>
|
||||
<string name="group_members_can_send_disappearing">Os membros do grupo podem enviar mensagens que desaparecem.</string>
|
||||
<string name="group_members_can_send_disappearing">Os membros do grupo podem enviar mensagens temporárias.</string>
|
||||
<string name="icon_descr_file">Arquivo</string>
|
||||
<string name="full_name__field">Nome completo:</string>
|
||||
<string name="incoming_audio_call">Chamada de áudio recebida</string>
|
||||
@@ -458,16 +455,15 @@
|
||||
<string name="reveal_verb">Revelar</string>
|
||||
<string name="icon_descr_server_status_pending">Pendente</string>
|
||||
<string name="prohibit_direct_messages">Proibir o envio de DMs para membros.</string>
|
||||
<string name="scan_QR_code">Escanear código QR</string>
|
||||
<string name="scan_QR_code">Escanear QR Code</string>
|
||||
<string name="reject_contact_button">Rejeitar</string>
|
||||
<string name="feature_offered_item">ofereceu %s</string>
|
||||
<string name="icon_descr_address"><xliff:g id="appName">Endereço</xliff:g> SimpleX</string>
|
||||
<string name="show_QR_code_for_your_contact_to_scan_from_the_app__multiline">Seu contato pode escanear o código QR do aplicativo.</string>
|
||||
<string name="feature_offered_item_with_param">ofereceu %s: %2s</string>
|
||||
<string name="paste_connection_link_below_to_connect">Cole o link que você recebeu na caixa abaixo para conectar com o seu contato.</string>
|
||||
<string name="new_in_version">Novo em %s</string>
|
||||
<string name="send_us_an_email">Envie-nos um e-mail</string>
|
||||
<string name="smp_servers_scan_qr">Escanear código QR do servidor</string>
|
||||
<string name="smp_servers_scan_qr">Escanear QR code do servidor</string>
|
||||
<string name="your_SMP_servers">Seus servidores SMP</string>
|
||||
<string name="chat_item_ttl_none">nunca</string>
|
||||
<string name="restore_database_alert_title">Restaurar o backup do banco de dados\?</string>
|
||||
@@ -608,7 +604,7 @@
|
||||
<string name="markdown_in_messages">Markdown em mensagens</string>
|
||||
<string name="smp_servers">Servidores SMP</string>
|
||||
<string name="smp_servers_preset_address">Endereço do servidor pré-definido</string>
|
||||
<string name="many_people_asked_how_can_it_deliver">Muitos perguntaram:<i> se <xliff:g id="appName">SimpleX</xliff:g> não tem identificadores de usuários, como ele pode mandar memsagens\?</i></string>
|
||||
<string name="many_people_asked_how_can_it_deliver">Muitos perguntaram:<i> se <xliff:g id="appName">SimpleX</xliff:g> não tem identificadores de usuários, como ele pode mandar mensagens\?</i></string>
|
||||
<string name="reject">Rejeitar</string>
|
||||
<string name="integrity_msg_skipped"><xliff:g id="connection ID" example="1">%1$d</xliff:g> mensagens ignoradas</string>
|
||||
<string name="protect_app_screen">Proteger a tela do app</string>
|
||||
@@ -617,8 +613,7 @@
|
||||
<string name="join_group_button">Junte-se</string>
|
||||
<string name="you_can_share_group_link_anybody_will_be_able_to_connect">Você pode compartilhar um link ou um código QR - qualquer um poderá entrar no grupo. Você não perderá membros do grupo se você deletá-los mais tarde.</string>
|
||||
<string name="users_delete_data_only">Somente dados de perfil local</string>
|
||||
<string name="only_you_can_send_disappearing">Somente você pode enviar mensagens
|
||||
\ntemporárias.</string>
|
||||
<string name="only_you_can_send_disappearing">Somente você pode enviar mensagens temporárias.</string>
|
||||
<string name="only_your_contact_can_send_disappearing">Somente seu contato pode enviar mensagens temporárias.</string>
|
||||
<string name="icon_descr_instant_notifications">Notificações instantâneas</string>
|
||||
<string name="service_notifications">Notificações instantâneas!</string>
|
||||
@@ -657,7 +652,6 @@
|
||||
<string name="this_QR_code_is_not_a_link">Esse código QR não é um link!</string>
|
||||
<string name="your_chat_profile_will_be_sent_to_your_contact">Seu perfil de chat será enviado para seu
|
||||
\ncontato</string>
|
||||
<string name="your_contact_address">Seu endereço de contato</string>
|
||||
<string name="you_will_be_connected_when_your_contacts_device_is_online">Você será conectado quando o dispositivo do seu contato estiver online, aguarde ou verifique mais tarde!</string>
|
||||
<string name="how_to">Como</string>
|
||||
<string name="smp_servers_test_failed">Teste do servidor falhou!</string>
|
||||
@@ -693,7 +687,7 @@
|
||||
<string name="settings_section_title_you">VOCÊ</string>
|
||||
<string name="settings_section_title_messages">MENSAGENS E ARQUIVOS</string>
|
||||
<string name="your_chat_database">Seu banco de dados de chat</string>
|
||||
<string name="snd_group_event_member_deleted">Você removeu<xliff:g xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\" id=\"member profile\" example=\"alice (Alice)\"></string>
|
||||
<string name="snd_group_event_member_deleted">Você removeu <xliff:g id="member profile" example="alice (Alice)">%1$s</xliff:g></string>
|
||||
<string name="group_member_status_removed">removido</string>
|
||||
<string name="group_member_status_left">saiu</string>
|
||||
<string name="group_member_role_owner">proprietário</string>
|
||||
@@ -738,7 +732,7 @@
|
||||
<string name="send_live_message">Enviar mensagem ao vivo</string>
|
||||
<string name="above_then_preposition_continuation">acima, então:</string>
|
||||
<string name="to_connect_via_link_title">Para conectar via link</string>
|
||||
<string name="image_descr_qr_code">Código QR</string>
|
||||
<string name="image_descr_qr_code">QR Code</string>
|
||||
<string name="mark_code_verified">Marcado como verificado</string>
|
||||
<string name="to_verify_compare">Para verificar a criptografia de ponta-a-ponta com seu contato, compare (ou escaneie) o código em seus dispositivos.</string>
|
||||
<string name="smp_save_servers_question">Salvar servidores\?</string>
|
||||
@@ -784,18 +778,15 @@
|
||||
<string name="network_use_onion_hosts_no_desc_in_alert">Hosts Onion não serão usados.</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc">Os hosts Onion serão usados quando disponíveis.</string>
|
||||
<string name="network_use_onion_hosts_prefer_desc_in_alert">Os hosts Onion serão usados quando disponíveis.</string>
|
||||
<string name="you_can_share_your_address_anybody_will_be_able_to_connect">Você pode compartilhar seu endereço como um link ou como um código QR - qualquer pessoa poderá se conectar a você. Você não perderá seus contatos se excluí-los posteriormente.</string>
|
||||
<string name="your_current_profile">Seu perfil atual</string>
|
||||
<string name="privacy_redefined">Privacidade redefinida</string>
|
||||
<string name="onboarding_notifications_mode_title">Notificações privadas</string>
|
||||
<string name="make_private_connection">Fazer uma conexão privada</string>
|
||||
<string name="people_can_connect_only_via_links_you_share">Pessoas podem se conectar com você somente via links compartilhados.</string>
|
||||
<string name="alert_text_skipped_messages_it_can_happen_when">Pode acontecer quando:
|
||||
\n1. As mensagens expiram no servidor se não forem recebidas por 30 dias,
|
||||
\n2. O servidor que você usa para receber as mensagens deste contato foi atualizado e reiniciado.
|
||||
\n3. A conexão está comprometida.
|
||||
\nPor favor, conecte-se aos desenvolvedores via Configurações para receber as atualizações sobre os servidores.
|
||||
\nEstaremos adicionando redundância de servidor para evitar perda de mensagens.</string>
|
||||
\n1. As mensagens expiraram no remetente após 2 dias ou no servidor após 30 dias.
|
||||
\n2. A descriptografia da mensagem falhou porque você ou seu contato usou o backup do banco de dados antigo.
|
||||
\n3. A conexão foi comprometida.</string>
|
||||
<string name="you_have_to_enter_passphrase_every_time">Você tem que digitar a senha toda vez que o aplicativo iniciar - ela não é armazenada no dispositivo.</string>
|
||||
<string name="save_welcome_message_question">Salvar mensagem de boas-vindas\?</string>
|
||||
<string name="delete_profile">Excluir perfil</string>
|
||||
@@ -803,7 +794,7 @@
|
||||
<string name="videos_limit_title">Excesso de vídeos!</string>
|
||||
<string name="icon_descr_video_asked_to_receive">Solicitou receber o vídeo</string>
|
||||
<string name="videos_limit_desc">Apenas 10 vídeos podem ser enviados ao mesmo tempo</string>
|
||||
<string name="contact_sent_large_file">Seu contato enviou um arquivo maior que o tamanho máximo permitido (<xliff:g xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\" id=\"maxFileSize\">).</string>
|
||||
<string name="contact_sent_large_file">Seu contato enviou um arquivo maior que o tamanho máximo permitido (<xliff:g id="maxFileSize">%1$s</xliff:g>).</string>
|
||||
<string name="file_will_be_received_when_contact_completes_uploading">O arquivo será recebido quando seu contato concluir o upload.</string>
|
||||
<string name="smp_servers_test_some_failed">Alguns servidores falharam o teste:</string>
|
||||
<string name="smp_servers_save">Salvar servidores</string>
|
||||
@@ -815,7 +806,6 @@
|
||||
<string name="network_settings_title">Configurações de conexão</string>
|
||||
<string name="no_details">sem detalhes</string>
|
||||
<string name="add_contact">Link de convite de uso único</string>
|
||||
<string name="network_socks_toggle">Usar proxy SOCKS (porta 9050)</string>
|
||||
<string name="smp_servers_your_server_address">Seu endereço de servidor</string>
|
||||
<string name="your_settings">Suas configurações</string>
|
||||
<string name="is_verified">%s é verificado</string>
|
||||
@@ -866,12 +856,12 @@
|
||||
<string name="voice_messages">Mensagens de voz</string>
|
||||
<string name="description_via_contact_address_link">via link de endereço de contato</string>
|
||||
<string name="description_via_one_time_link">via link de uso único</string>
|
||||
<string name="share_invitation_link">Compartilhar link de convite</string>
|
||||
<string name="share_invitation_link">Compartilhar link de uso único</string>
|
||||
<string name="network_use_onion_hosts">Usar hosts .onion</string>
|
||||
<string name="video_call_no_encryption">chamada de vídeo (não criptografada ponta-a-ponta)</string>
|
||||
<string name="stop_chat_question">Parar chat\?</string>
|
||||
<string name="simplex_link_mode_browser">Pelo navegador</string>
|
||||
<string name="you_are_already_connected_to_vName_via_this_link">Você já está conectado a<xliff:g id="contactName" example="Alice">%1$s!</xliff:g>.</string>
|
||||
<string name="you_are_already_connected_to_vName_via_this_link">Você já está conectado a<xliff:g id="contactName" example="Alice">%1$s</xliff:g>.</string>
|
||||
<string name="database_initialization_error_desc">O banco de dados não está funcionando corretamente. Toque para saber mais</string>
|
||||
<string name="waiting_for_image">Aguardando imagem</string>
|
||||
<string name="show_QR_code">Mostrar código QR</string>
|
||||
@@ -903,7 +893,7 @@
|
||||
<string name="v4_5_private_filenames_descr">Para proteger o fuso horário, os arquivos de imagem/voz usam UTC.</string>
|
||||
<string name="unknown_message_format">formato de mensagem desconhecido</string>
|
||||
<string name="description_via_group_link">via link de grupo</string>
|
||||
<string name="simplex_link_connection">via<xliff:g xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\" id=\"serverHost\" example=\"smp.simplex.im\"></string>
|
||||
<string name="simplex_link_connection">via <xliff:g id="serverHost" example="smp.simplex.im">%1$s</xliff:g></string>
|
||||
<string name="connection_error_auth_desc">A menos que seu contato tenha excluído a conexão ou este link já tenha sido usado, pode ser um bug - por favor, relate-o.
|
||||
\nPara se conectar, peça ao seu contato para criar outro link de conexão e verifique se você tem uma conexão de rede estável.</string>
|
||||
<string name="error_smp_test_failed_at_step">O teste falhou na etapa %s.</string>
|
||||
@@ -921,7 +911,6 @@
|
||||
<string name="you_are_observer">você é um observador</string>
|
||||
<string name="voice_message_with_duration">Mensagem de voz (<xliff:g id="duration">%1$s</xliff:g>)</string>
|
||||
<string name="share_link">Compartilhar link</string>
|
||||
<string name="section_title_welcome_message">MENSAGEM DE BOAS-VINDAS</string>
|
||||
<string name="to_protect_privacy_simplex_has_ids_for_queues">Para proteger a privacidade, em vez dos IDs de usuário usados por todas as outras plataformas, <xliff:g id="appName">SimpleX</xliff:g> tem identificadores para filas de mensagens, separados para cada um de seus contatos.</string>
|
||||
<string name="icon_descr_video_call">chamada de vídeo</string>
|
||||
<string name="show_call_on_lock_screen">Mostrar</string>
|
||||
@@ -939,7 +928,7 @@
|
||||
<string name="auth_unlock">Desbloquear</string>
|
||||
<string name="moderate_message_will_be_deleted_warning">A mensagem será excluída para todos os membros.</string>
|
||||
<string name="moderate_message_will_be_marked_warning">A mensagem será marcada como moderada para todos os membros.</string>
|
||||
<string name="share_image">Compartilhar imagem…</string>
|
||||
<string name="share_image">Compartilhar mídia…</string>
|
||||
<string name="icon_descr_waiting_for_image">Aguardando imagem</string>
|
||||
<string name="share_file">Compartilhar arquivo…</string>
|
||||
<string name="image_decoding_exception_desc">A imagem não pode ser decodificada. Por favor, tente uma imagem diferente ou entre em contato com os desenvolvedores.</string>
|
||||
@@ -976,7 +965,7 @@
|
||||
<string name="contact_you_shared_link_with_wont_be_able_to_connect">O contato com o qual você compartilhou este link NÃO será capaz de se conectar!</string>
|
||||
<string name="icon_descr_simplex_team">Equipe <xliff:g id="appName">SimpleX</xliff:g></string>
|
||||
<string name="use_simplex_chat_servers__question">Usar servidores<xliff:g id="appNameFull">SimpleX</xliff:g>\?</string>
|
||||
<string name="using_simplex_chat_servers">Usando servidores<xliff:g id="appNameFull">SimpleX</xliff:g>.</string>
|
||||
<string name="using_simplex_chat_servers">Usando servidores <xliff:g id="appNameFull">SimpleX</xliff:g>.</string>
|
||||
<string name="show_developer_options">Mostrar opções para desenvolvedores</string>
|
||||
<string name="v4_6_audio_video_calls_descr">Suporte bluetooth e outras melhorias.</string>
|
||||
<string name="to_reveal_profile_enter_password">Para revelar seu perfil oculto, digite uma senha em um campo de busca em sua página de perfis de chat.</string>
|
||||
@@ -1018,7 +1007,7 @@
|
||||
<string name="you_sent_group_invitation">Você enviou convite de grupo</string>
|
||||
<string name="incognito_random_profile">Seu perfil aleatório</string>
|
||||
<string name="auth_simplex_lock_turned_on">Bloqueio SimpleX ativado</string>
|
||||
<string name="your_simplex_contact_address">Seu endereço de contato<xliff:g id="appName">SimpleX</xliff:g></string>
|
||||
<string name="your_simplex_contact_address">Seu endereço SimpleX</string>
|
||||
<string name="network_options_reset_to_defaults">Redefinir para os padrões</string>
|
||||
<string name="image_descr_link_preview">imagem de pré-visualização do link</string>
|
||||
<string name="la_notice_to_protect_your_information_turn_on_simplex_lock_you_will_be_prompted_to_complete_authentication_before_this_feature_is_enabled">Para proteger suas informações, ative o bloqueio SimpleX. Você será solicitado a completar a autenticação antes que este recurso seja ativado.</string>
|
||||
@@ -1044,7 +1033,7 @@
|
||||
<string name="enable_automatic_deletion_message">Esta ação não pode ser desfeita - as mensagens enviadas e recebidas antes do selecionado serão excluídas. Pode levar vários minutos.</string>
|
||||
<string name="confirm_database_upgrades">Confirme as atualizações do banco de dados</string>
|
||||
<string name="only_client_devices_store_contacts_groups_e2e_encrypted_messages">Perfis de usuário, contatos, grupos e mensagens enviadas com <b>criptografia de ponta-a-ponta</b> são armazenados somente no seu dispositivo.</string>
|
||||
<string name="thank_you_for_installing_simplex">Obrigado por instalar<xliff:g id="appNameFull">SimpleX</xliff:g>!</string>
|
||||
<string name="thank_you_for_installing_simplex">Obrigado por instalar <xliff:g id="appNameFull">SimpleX</xliff:g>!</string>
|
||||
<string name="the_messaging_and_app_platform_protecting_your_privacy_and_security">A plataforma de mensagens que protege sua privacidade e segurança.</string>
|
||||
<string name="invite_prohibited_description">Você está tentando convidar um contato com quem compartilhou um perfil anônimo para o grupo no qual está usando seu perfil principal</string>
|
||||
<string name="you_control_servers_to_receive_your_contacts_to_send">Você controla por meio de qual(is) servidor(es) <b>receber</b> as mensagens, seus contatos controlam os servidores que você usa para enviar mensagens.</string>
|
||||
@@ -1082,7 +1071,7 @@
|
||||
<string name="network_socks_toggle_use_socks_proxy">Usar proxy SOCKS</string>
|
||||
<string name="host_verb">Hospedar</string>
|
||||
<string name="disable_onion_hosts_when_not_supported">Definir <i>Usar hosts .onion</i> para não se o proxy SOCKS não oferecer suporte a eles.</string>
|
||||
<string name="port_verb">Porta</string>
|
||||
<string name="port_verb">Migrar</string>
|
||||
<string name="confirm_passcode">Confirmar senha</string>
|
||||
<string name="incorrect_passcode">Senha incorreta</string>
|
||||
<string name="lock_after">Bloquear após</string>
|
||||
@@ -1098,4 +1087,175 @@
|
||||
<string name="enable_lock">Habilitar bloqueio</string>
|
||||
<string name="passcode_changed">Senha alterada!</string>
|
||||
<string name="you_can_turn_on_lock">Você pode ativar o bloqueio SimpleX via Configurações.</string>
|
||||
<string name="alert_title_msg_bad_hash">Hash de mensagem incorreta</string>
|
||||
<string name="alert_text_msg_bad_hash">O hash da mensagem anterior é diferente.</string>
|
||||
<string name="alert_text_decryption_error_header"><xliff:g id="message count" example="1"/> descriptografia das mensagens falhou</string>
|
||||
<string name="alert_title_msg_bad_id">ID de mensagem incorreta</string>
|
||||
<string name="alert_text_msg_bad_id">A ID da próxima mensagem está incorreta (menor ou igual à anterior).
|
||||
\nIsso pode acontecer por causa de algum bug ou quando a conexão está comprometida.</string>
|
||||
<string name="alert_text_fragment_encryption_out_of_sync_old_database">Isso pode acontecer quando você ou sua conexão usaram o backup do banco de dados antigo.</string>
|
||||
<string name="alert_text_fragment_please_report_to_developers">Por favor, informe aos desenvolvedores.</string>
|
||||
<string name="stop_rcv_file__message">O recebimento do arquivo será interrompido.</string>
|
||||
<string name="stop_snd_file__message">O envio do arquivo será interrompido.</string>
|
||||
<string name="stop_file__action">Parar arquivo</string>
|
||||
<string name="stop_rcv_file__title">Parar de receber arquivo\?</string>
|
||||
<string name="stop_snd_file__title">Parar de enviar arquivo\?</string>
|
||||
<string name="revoke_file__action">Revogar arquivo</string>
|
||||
<string name="stop_file__confirm">Parar</string>
|
||||
<string name="revoke_file__message">O arquivo será excluído dos servidores.</string>
|
||||
<string name="revoke_file__title">Revogar arquivo\?</string>
|
||||
<string name="no_spaces">Sem espaços!</string>
|
||||
<string name="alert_text_fragment_permanent_error_reconnect">Este erro é permanente para esta conexão, por favor, reconecte.</string>
|
||||
<string name="alert_text_decryption_error_too_many_skipped"><xliff:g id="message count" example="1"/> mensagens ignoradas</string>
|
||||
<string name="audio_video_calls">Chamadas de áudio/vídeo</string>
|
||||
<string name="calls_prohibited_with_this_contact">Chamadas de áudio/vídeo são proibidas.</string>
|
||||
<string name="available_in_v51">"
|
||||
\nDisponível em v5.1"</string>
|
||||
<string name="both_you_and_your_contact_can_make_calls">Você e seu contato podem fazer chamadas.</string>
|
||||
<string name="only_you_can_make_calls">Somente você pode fazer chamadas.</string>
|
||||
<string name="only_your_contact_can_make_calls">Somente seu contato pode fazer chamadas.</string>
|
||||
<string name="prohibit_calls">Proibir chamadas de áudio/vídeo.</string>
|
||||
<string name="allow_calls_only_if">Permita chamadas somente se o seu contato permiti-las.</string>
|
||||
<string name="allow_your_contacts_to_call">Permita que seus contatos liguem para você.</string>
|
||||
<string name="v5_0_app_passcode">Senha do aplicativo</string>
|
||||
<string name="v5_0_large_files_support_descr">Rápido e sem esperar até que o remetente esteja online!</string>
|
||||
<string name="v5_0_polish_interface">interface polonesa</string>
|
||||
<string name="v5_0_app_passcode_descr">Defina-o em vez da autenticação do sistema.</string>
|
||||
<string name="v5_0_polish_interface_descr">Obrigado aos usuários – contribuam via Weblate!</string>
|
||||
<string name="v5_0_large_files_support">Vídeos e arquivos de até 1gb</string>
|
||||
<string name="gallery_image_button">Imagem</string>
|
||||
<string name="decryption_error">erro de descriptografia</string>
|
||||
<string name="revoke_file__confirm">Revogar</string>
|
||||
<string name="learn_more_about_address">Sobre o endereço SimpleX</string>
|
||||
<string name="color_secondary_variant">Secundária adicional</string>
|
||||
<string name="color_primary_variant">Acento adicional</string>
|
||||
<string name="one_time_link_short">Link de uso único</string>
|
||||
<string name="add_address_to_your_profile">Adicione o endereço ao seu perfil, para que seus contatos possam compartilhá-lo com outras pessoas. A atualização do perfil será enviada aos seus contatos.</string>
|
||||
<string name="create_address_and_let_people_connect">Crie um endereço para permitir que as pessoas se conectem com você.</string>
|
||||
<string name="create_simplex_address">Criar endereço SimpleX</string>
|
||||
<string name="continue_to_next_step">Continuar</string>
|
||||
<string name="dont_create_address">Não criar endereço</string>
|
||||
<string name="address_section_title">Endereço</string>
|
||||
<string name="dark_theme">Tema escuro</string>
|
||||
<string name="color_background">Fundo</string>
|
||||
<string name="all_your_contacts_will_remain_connected_update_sent">Todos os seus contactos permanecerão ligados. A atualização do perfil será enviada para seus contatos.</string>
|
||||
<string name="auto_accept_contact">Aceitação automática</string>
|
||||
<string name="customize_theme_title">Personalizar o tema</string>
|
||||
<string name="enter_welcome_message">Digite a mensagem de boas-vindas…</string>
|
||||
<string name="error_setting_address">Erro ao definir o endereço</string>
|
||||
<string name="learn_more">Saiba mais</string>
|
||||
<string name="theme_simplex">SimpleX</string>
|
||||
<string name="import_theme_error_desc">Certifique-se que o arquivo tenha a sintaxe YAML correta. Exporte o tema para ter um exemplo da estrutura do arquivo do tema.</string>
|
||||
<string name="export_theme">Exportar tema</string>
|
||||
<string name="import_theme_error">Erro ao importar tema</string>
|
||||
<string name="color_surface">Menus e alertas</string>
|
||||
<string name="color_received_message">Mensagem recebida</string>
|
||||
<string name="color_sent_message">Mensagem enviada</string>
|
||||
<string name="color_title">Título</string>
|
||||
<string name="if_you_cant_meet_in_person">Se não puderem se encontrar pessoalmente, mostre o QR code em uma chamada de vídeo ou compartilhe o link.</string>
|
||||
<string name="scan_qr_to_connect_to_contact">Para se conectar, seu contato pode ler o QR code ou usar o link no aplicativo.</string>
|
||||
<string name="you_can_share_your_address">Você pode compartilhar seu endereço como um link ou QR code - qualquer pessoa pode se conectar a você.</string>
|
||||
<string name="you_wont_lose_your_contacts_if_delete_address">Você não perderá seus contatos se, posteriormente, excluir seu endereço.</string>
|
||||
<string name="simplex_address">Endereço SimpleX</string>
|
||||
<string name="you_can_accept_or_reject_connection">Quando as pessoas solicitam uma conexão, você pode aceitá-la ou rejeitá-la.</string>
|
||||
<string name="theme_colors_section_title">CORES DO TEMA</string>
|
||||
<string name="share_with_contacts">compartilhar com os contatos</string>
|
||||
<string name="profile_update_will_be_sent_to_contacts">A atualização do perfil será enviada aos seus contatos.</string>
|
||||
<string name="save_settings_question">Salvar configurações\?</string>
|
||||
<string name="stop_sharing">Parar de compartilhar</string>
|
||||
<string name="stop_sharing_address">Parar de compartilhar o endereço\?</string>
|
||||
<string name="email_invite_body">Oi!
|
||||
\nConecte-se comigo via SimpleX Chat: %s</string>
|
||||
<string name="invite_friends">Convide amigos</string>
|
||||
<string name="email_invite_subject">Vamos conversar no SimpleX</string>
|
||||
<string name="you_can_create_it_later">Você pode criá-lo mais tarde</string>
|
||||
<string name="share_address">Compartilhar endereço</string>
|
||||
<string name="you_can_share_this_address_with_your_contacts">Você pode compartilhar esse endereço com seus contatos para que eles se conectem com %s.</string>
|
||||
<string name="group_welcome_preview">Prévia</string>
|
||||
<string name="color_secondary">Secundária</string>
|
||||
<string name="import_theme">Importar tema</string>
|
||||
<string name="read_more_in_user_guide_with_link">Leia mais em <font color="#0088ff">Guia do Usuário</font>.</string>
|
||||
<string name="enter_welcome_message_optional">Digite a mensagem de boas-vindas... (opcional)</string>
|
||||
<string name="save_auto_accept_settings">Salvar configurações de aceitação automática</string>
|
||||
<string name="opening_database">Abrindo banco de dados…</string>
|
||||
<string name="auth_open_chat_profiles">Abrir perfis de bate-papo</string>
|
||||
<string name="share_address_with_contacts_question">Compartilhar endereço com os contatos\?</string>
|
||||
<string name="your_contacts_will_see_it">Seus contatos no SimpleX o verão.
|
||||
\nVocê pode alterá-la nas Configurações.</string>
|
||||
<string name="your_contacts_will_remain_connected">Seus contatos continuarão conectados.</string>
|
||||
<string name="all_app_data_will_be_cleared">Todos os dados do aplicativo serão excluídos.</string>
|
||||
<string name="app_passcode_replaced_with_self_destruct">A senha do aplicativo é substituída por uma senha de auto-destruição.</string>
|
||||
<string name="self_destruct_new_display_name">Novo nome de exibição:</string>
|
||||
<string name="set_passcode">Definir senha</string>
|
||||
<string name="enable_self_destruct">Ativar auto-destruição</string>
|
||||
<string name="send_disappearing_message">Enviar mensagem temporária</string>
|
||||
<string name="send_disappearing_message_1_minute">1 minuto</string>
|
||||
<string name="send_disappearing_message_30_seconds">30 segundos</string>
|
||||
<string name="send_disappearing_message_5_minutes">5 minutos</string>
|
||||
<string name="send_disappearing_message_custom_time">Horário personalizado</string>
|
||||
<string name="disappearing_message">Mensagem temporária</string>
|
||||
<string name="send_disappearing_message_send">Enviar</string>
|
||||
<string name="self_destruct_passcode_changed">A senha de auto-destruição foi alterada!</string>
|
||||
<string name="self_destruct_passcode">Senha de auto-destruição</string>
|
||||
<string name="self_destruct_passcode_enabled">Senha de auto-destruição ativada!</string>
|
||||
<string name="enabled_self_destruct_passcode">Ativar senha de auto-destruição</string>
|
||||
<string name="allow_message_reactions">Permitir reações à mensagens.</string>
|
||||
<string name="only_you_can_add_message_reactions">Somente você pode adicionar reações à mensagens.</string>
|
||||
<string name="only_your_contact_can_add_message_reactions">Somente seu contato pode adicionar reações à mensagens.</string>
|
||||
<string name="message_reactions_are_prohibited">Reações à mensagens são proibidas neste grupo.</string>
|
||||
<string name="custom_time_unit_hours">horas</string>
|
||||
<string name="custom_time_unit_minutes">minutos</string>
|
||||
<string name="custom_time_unit_seconds">segundos</string>
|
||||
<string name="self_destruct">Auto-destruição</string>
|
||||
<string name="error_loading_details">Erro ao carregar detalhes</string>
|
||||
<string name="edit_history">Histórico</string>
|
||||
<string name="info_menu">Info</string>
|
||||
<string name="received_message">Mensagem recebida</string>
|
||||
<string name="sent_message">Mensagem enviada</string>
|
||||
<string name="empty_chat_profile_is_created">Um perfil chat vazio com o nome fornecido é criado, e o aplicativo é aberto normalmente.</string>
|
||||
<string name="change_self_destruct_mode">Alterar o modo de auto-destruição</string>
|
||||
<string name="if_you_enter_passcode_data_removed">Se você digitar essa senha ao abrir o aplicativo, todos os dados do aplicativo serão excluídos irreversivelmente!</string>
|
||||
<string name="info_row_deleted_at">Excluído em</string>
|
||||
<string name="info_row_received_at">Recebido em</string>
|
||||
<string name="info_row_updated_at">Registro atualizado em</string>
|
||||
<string name="share_text_database_id">ID do banco de dados: %d</string>
|
||||
<string name="share_text_deleted_at">Excluído em: %s</string>
|
||||
<string name="info_row_disappears_at">Desaparece em</string>
|
||||
<string name="share_text_disappears_at">Desaparece em: %s</string>
|
||||
<string name="info_row_moderated_at">Moderado em</string>
|
||||
<string name="share_text_moderated_at">Moderado em: %s</string>
|
||||
<string name="share_text_received_at">Recebido em: %s</string>
|
||||
<string name="share_text_updated_at">Registro atualizado em: %s</string>
|
||||
<string name="item_info_current">(atual)</string>
|
||||
<string name="current_version_timestamp">%s (atual)</string>
|
||||
<string name="allow_your_contacts_adding_message_reactions">Permitir que seus contatos adicionem reações à mensagens.</string>
|
||||
<string name="both_you_and_your_contact_can_add_message_reactions">Você e seu contato podem adicionar reações à mensagens.</string>
|
||||
<string name="group_members_can_add_message_reactions">Os membros do grupo podem adicionar reações às mensagens.</string>
|
||||
<string name="message_reactions_prohibited_in_this_chat">Reações à mensagens são proibidas neste chat.</string>
|
||||
<string name="prohibit_message_reactions">Proibir reações à mensagens.</string>
|
||||
<string name="custom_time_picker_custom">personalizado</string>
|
||||
<string name="whats_new_read_more">Ler mais</string>
|
||||
<string name="v5_1_self_destruct_passcode_descr">Todos seus dados são apagados quando digitado</string>
|
||||
<string name="v5_1_message_reactions_descr">Finalmente, nós os temos! 🚀</string>
|
||||
<string name="v5_1_message_reactions">Reações à mensagens</string>
|
||||
<string name="v5_1_self_destruct_passcode">Senha de auto-destruição</string>
|
||||
<string name="v5_1_better_messages">Mensagens melhores</string>
|
||||
<string name="v5_1_japanese_portuguese_interface">IU em japonês e português</string>
|
||||
<string name="custom_time_unit_months">meses</string>
|
||||
<string name="custom_time_picker_select">Selecionar</string>
|
||||
<string name="whats_new_thanks_to_users_contribute_weblate">Obrigado aos usuários – contribua via Weblate!</string>
|
||||
<string name="v5_1_better_messages_descr">- mensagens de voz de até 5 minutos
|
||||
\n- tempo personalizado para desaparecer.
|
||||
\n- histórico de edição.</string>
|
||||
<string name="custom_time_unit_weeks">semanas</string>
|
||||
<string name="allow_message_reactions_only_if">Permitir reações à mensagens somente se o seu contato permitir.</string>
|
||||
<string name="v5_1_custom_themes_descr">Personalize e compartilhe temas de cores.</string>
|
||||
<string name="v5_1_custom_themes">Temas personalizados</string>
|
||||
<string name="custom_time_unit_days">dias</string>
|
||||
<string name="message_reactions">Reações à mensagens</string>
|
||||
<string name="prohibit_message_reactions_group">Proibir reações à mensagens.</string>
|
||||
<string name="share_text_sent_at">Enviado em: %s</string>
|
||||
<string name="info_row_sent_at">Enviado em</string>
|
||||
<string name="change_self_destruct_passcode">Alterar senha de auto-destruição</string>
|
||||
<string name="if_you_enter_self_destruct_code">Se você digitar sua senha de auto-destruição ao abrir o aplicativo:</string>
|
||||
</resources>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user