diff --git a/.github/workflows/artifacts.yml b/.github/workflows/artifacts.yml index a350e2351..4267113ba 100644 --- a/.github/workflows/artifacts.yml +++ b/.github/workflows/artifacts.yml @@ -7,7 +7,7 @@ on: jobs: artifacts-url-comments: name: add artifact links to pull request - runs-on: windows-2019 + runs-on: ubuntu-latest if: ${{ github.event.workflow_run.conclusion == 'success' }} steps: - name: add artifact links to pull request diff --git a/.github/workflows/preview-apk.yml b/.github/workflows/preview-apk.yml index 15caaf2d0..b8abccc7e 100644 --- a/.github/workflows/preview-apk.yml +++ b/.github/workflows/preview-apk.yml @@ -2,16 +2,16 @@ name: Upload Preview APK on: pull_request +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + jobs: build: name: Upload Preview APK runs-on: ubuntu-latest steps: - - name: Cancel Previous Runs - uses: styfle/cancel-workflow-action@0.9.1 - with: - access_token: ${{ github.token }} - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 with: submodules: recursive - name: Validate Fastlane Metadata @@ -19,12 +19,12 @@ jobs: - uses: Swatinem/rust-cache@v2 with: working-directory: jni/deltachat-core-rust - - uses: actions/setup-java@v3 + - uses: actions/setup-java@v5 with: java-version: 17 distribution: 'temurin' - uses: android-actions/setup-android@v3 - - uses: actions/cache@v3 + - uses: actions/cache@v4 with: path: | ~/.gradle/caches @@ -37,6 +37,9 @@ jobs: with: ndk-version: r27 + - name: Validate Gradle Wrapper + uses: gradle/actions/wrapper-validation@v4 + - name: Compile core env: ANDROID_NDK_ROOT: ${{ steps.setup-ndk.outputs.ndk-path }} @@ -44,9 +47,6 @@ jobs: export PATH="${PATH}:${ANDROID_NDK_ROOT}/toolchains/llvm/prebuilt/linux-x86_64/bin/" scripts/install-toolchains.sh && scripts/ndk-make.sh armeabi-v7a - - name: Validate Gradle Wrapper - uses: gradle/wrapper-validation-action@v1 - - name: Build APK run: ./gradlew --no-daemon -PABI_FILTER=armeabi-v7a assembleFossDebug diff --git a/CHANGELOG-upstream.md b/CHANGELOG-upstream.md index a3e4940a3..221d7ed07 100644 --- a/CHANGELOG-upstream.md +++ b/CHANGELOG-upstream.md @@ -4,7 +4,19 @@ * target Android 15 * improve readability of info messages in dark mode +* drop too short disappearing messages options * fix Direct Share shortcuts +* fix: don't show error message when cancelling profile creation +* enable permanent notification by default if push notifications are not available +* hide "clone chat" and member list for incoming channels +* show warning if background notifications will be unreliable +* warn if the app has not been updated after 6 months instead of 1 year +* avoid "unknown sender for this chat" error +* properly display "Messages are end-to-end encrypted." in all encrypted groups +* show dialog if user has permanently denied camera permission and tries to take picture for group avatar +* several small fixes and improvements +* add experimental built-in calls +* update to core 2.17.0 ## v2.11.0 2025-08 diff --git a/build.gradle b/build.gradle index 4a804c9eb..2099c0ccb 100644 --- a/build.gradle +++ b/build.gradle @@ -233,7 +233,6 @@ dependencies { implementation 'com.google.zxing:core:3.3.0' // fixed version to support SDK<24 implementation ('com.journeyapps:zxing-android-embedded:4.3.0') { transitive = false } // QR Code scanner implementation 'com.fasterxml.jackson.core:jackson-databind:2.11.1' // used as JSON library - implementation 'com.google.code.gson:gson:2.12.1' // used as JSON library. implementation 'com.github.Baseflow:PhotoView:2.3.0' // does the zooming on photos / media implementation 'com.github.penfeizhou.android.animation:awebp:3.0.5' // animated webp support. implementation 'com.caverock:androidsvg-aar:1.4' // SVG support. diff --git a/flake.lock b/flake.lock index 4bd2500b4..290045b63 100644 --- a/flake.lock +++ b/flake.lock @@ -7,11 +7,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1733948466, - "narHash": "sha256-o/uq/tU458Ykudi8Zk3sRga5iazkuSczt9wDOCUDOSU=", + "lastModified": 1756239746, + "narHash": "sha256-0ibN685tT+u/Nbmbrrq9G3mRUzct2Votyv/a7Wwv26s=", "owner": "tadfisher", "repo": "android-nixpkgs", - "rev": "0bf99ffaea6a7c0948ae10cf2e40c2905e4e4d6b", + "rev": "256631d162ec883b2341ee59621516e1f65f0f6b", "type": "github" }, "original": { @@ -28,11 +28,11 @@ ] }, "locked": { - "lastModified": 1728330715, - "narHash": "sha256-xRJ2nPOXb//u1jaBnDP56M7v5ldavjbtR6lfGqSvcKg=", + "lastModified": 1741473158, + "narHash": "sha256-kWNaq6wQUbUMlPgw8Y+9/9wP0F8SHkjy24/mN3UAppg=", "owner": "numtide", "repo": "devshell", - "rev": "dd6b80932022cea34a019e2bb32f6fa9e494dfef", + "rev": "7c9e793ebe66bcba8292989a68c0419b737a22a0", "type": "github" }, "original": { @@ -79,11 +79,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1733759999, - "narHash": "sha256-463SNPWmz46iLzJKRzO3Q2b0Aurff3U1n0nYItxq7jU=", + "lastModified": 1756125398, + "narHash": "sha256-XexyKZpf46cMiO5Vbj+dWSAXOnr285GHsMch8FBoHbc=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "a73246e2eef4c6ed172979932bc80e1404ba2d56", + "rev": "3b9f00d7a7bf68acd4c4abb9d43695afb04e03a5", "type": "github" }, "original": { @@ -95,11 +95,11 @@ }, "nixpkgs_2": { "locked": { - "lastModified": 1733749988, - "narHash": "sha256-+5qdtgXceqhK5ZR1YbP1fAUsweBIrhL38726oIEAtDs=", + "lastModified": 1756159630, + "narHash": "sha256-ohMvsjtSVdT/bruXf5ClBh8ZYXRmD4krmjKrXhEvwMg=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "bc27f0fde01ce4e1bfec1ab122d72b7380278e68", + "rev": "84c256e42600cb0fdf25763b48d28df2f25a0c8b", "type": "github" }, "original": { @@ -138,11 +138,11 @@ "nixpkgs": "nixpkgs_3" }, "locked": { - "lastModified": 1747017456, - "narHash": "sha256-C/U12fcO+HEF071b5mK65lt4XtAIZyJSSJAg9hdlvTk=", + "lastModified": 1756197489, + "narHash": "sha256-S16rPaBH1TnMbDyL5NlGSJcYd7wPlOEWTStdBDL7BHw=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "5b07506ae89b025b14de91f697eba23b48654c52", + "rev": "8ec04f46f1edeeed3f870da62191745b93975da7", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index a7b137f39..f460f5959 100644 --- a/flake.nix +++ b/flake.nix @@ -18,7 +18,7 @@ build-tools-35-0-0 cmdline-tools-latest platform-tools - platforms-android-34 + platforms-android-35 ndk-27-2-12479018 ]); rust-version = pkgs.lib.removeSuffix "\n" diff --git a/jni/dc_wrapper.c b/jni/dc_wrapper.c index 9590f3aca..d49237702 100644 --- a/jni/dc_wrapper.c +++ b/jni/dc_wrapper.c @@ -735,12 +735,6 @@ JNIEXPORT jint Java_com_b44t_messenger_DcContext_sendTextMsg(JNIEnv *env, jobjec } -JNIEXPORT jint Java_com_b44t_messenger_DcContext_sendVideochatInvitation(JNIEnv *env, jobject obj, jint chat_id) -{ - return (jint)dc_send_videochat_invitation(get_dc_context(env, obj), chat_id); -} - - JNIEXPORT jboolean Java_com_b44t_messenger_DcContext_sendWebxdcStatusUpdate(JNIEnv *env, jobject obj, jint msg_id, jstring payload) { CHAR_REF(payload); @@ -1608,21 +1602,6 @@ JNIEXPORT jstring Java_com_b44t_messenger_DcMsg_getSetupCodeBegin(JNIEnv *env, j } -JNIEXPORT jstring Java_com_b44t_messenger_DcMsg_getVideochatUrl(JNIEnv *env, jobject obj) -{ - char* temp = dc_msg_get_videochat_url(get_dc_msg(env, obj)); - jstring ret = JSTRING_NEW(temp); - dc_str_unref(temp); - return ret; -} - - -JNIEXPORT jint Java_com_b44t_messenger_DcMsg_getVideochatType(JNIEnv *env, jobject obj) -{ - return (jint)dc_msg_get_videochat_type(get_dc_msg(env, obj)); -} - - JNIEXPORT void Java_com_b44t_messenger_DcMsg_setSubject(JNIEnv *env, jobject obj, jstring text) { CHAR_REF(text); diff --git a/jni/deltachat-core-rust b/jni/deltachat-core-rust index 194b200a7..1b59eda47 160000 --- a/jni/deltachat-core-rust +++ b/jni/deltachat-core-rust @@ -1 +1 @@ -Subproject commit 194b200a75933e617198bdd32820b78a8c6f5e1b +Subproject commit 1b59eda47b5ddba9d8074098523d5b5f717a9de7 diff --git a/proguard-rules.pro b/proguard-rules.pro index d4079a968..9702be776 100644 --- a/proguard-rules.pro +++ b/proguard-rules.pro @@ -1,15 +1,11 @@ # native methods -keep class com.b44t.messenger.** { * ; } -# Gson uses generic type information stored in a class file when working with -# fields. Proguard removes such information by default, keep it. --keepattributes Signature -# This is also needed for R8 in compat mode since multiple -# optimizations will remove the generic signature such as class -# merging and argument removal. See: -# https://r8.googlesource.com/r8/+/refs/heads/main/compatibility-faq.md#troubleshooting-gson-gson --keep class com.google.gson.reflect.TypeToken { *; } --keep class * extends com.google.gson.reflect.TypeToken +# Keep metadata needed by the JSON parser +-keep class chat.delta.rpc.** { * ; } +-keepattributes *Annotation*,EnclosingMethod,Signature +-keepnames class com.fasterxml.jackson.** { *; } +#-dontwarn com.fasterxml.jackson.databind.** # bug with video recoder -keep class com.coremedia.iso.** { *; } diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index aaf6a5f61..e2fbbf939 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -370,7 +370,7 @@ android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"> - + + + + + + diff --git a/src/main/assets/calls/index.html b/src/main/assets/calls/index.html new file mode 100644 index 000000000..96fbfcbd8 --- /dev/null +++ b/src/main/assets/calls/index.html @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + +
+ + diff --git a/src/main/assets/help/en/help.html b/src/main/assets/help/en/help.html index 2f2ad51f4..98ac157f5 100644 --- a/src/main/assets/help/en/help.html +++ b/src/main/assets/help/en/help.html @@ -784,8 +784,8 @@ there are no lock or similar markers on end-to-end encrypted messages, anymore.< it is impossible to receive or send messages without end-to-end encryption.

If you instead create a profile using a classic e-mail server, -you can send and receive messages without end-to-end encryption. -Such messages lacking end-to-end encryption are marked with an e-mail icon +you can send and receive messages with or without end-to-end encryption. +Messages lacking end-to-end encryption are marked with an e-mail icon email.

diff --git a/src/main/assets/help/it/help.html b/src/main/assets/help/it/help.html index be7ffc26b..79a3157e5 100644 --- a/src/main/assets/help/it/help.html +++ b/src/main/assets/help/it/help.html @@ -50,10 +50,10 @@
  • I messaggi contrassegnati dall’icona della posta sono esposti su Internet?
  • In che modo Delta Chat protegge i metadati nei messaggi?
  • Come proteggere i metadati e contatti quando un dispositivo viene sequestrato?
  • -
  • Does Delta Chat support “Sealed Sender”?
  • +
  • Delta Chat supporta “Mittente Sigillato”?
  • Delta Chat supporta Perfect Forward Secrecy?
  • -
  • Does Delta Chat support Post-Quantum-Cryptography?
  • -
  • How can I manually check encryption information?
  • +
  • Delta Chat supporta la Crittografia Post-Quantistica?
  • +
  • Come posso controllare manualmente le informazioni di crittografia?
  • Posso riutilizzare la mia chiave privata esistente?
  • Delta Chat è stata verificata in modo indipendente per le vulnerabilità di sicurezza?
  • @@ -969,25 +969,25 @@ anche se il messaggio non sarà crittografato end-to-end.

    -

    Unlike most other messengers, -Delta Chat apps do not store any metadata about contacts or groups on servers, also not in encrypted form. -Instead, all group metadata is end-to-end encrypted and stored on end-user devices, only.

    +

    A differenza della maggior parte degli altri servizi di messaggistica, +le apps Delta Chat non memorizzano alcun metadato sui contatti o sui gruppi sui server, né in forma crittografata. +Tutti i metadati dei gruppi sono invece crittografati end-to-end e memorizzati esclusivamente sui dispositivi degli utenti finali.

    -

    E-mail Servers can therefore only see

    +

    I Server E-mail possono quindi vedere solo

    -

    All other message, contact and group metadata resides in the end-to-end encrypted part of messages.

    +

    Tutti gli altri metadati dei messaggi, dei contatti e dei gruppi risiedono nella parte crittografata end-to-end dei messaggi.

    @@ -997,36 +997,36 @@ Instead, all group metadata is end-to-end encrypted and stored on end-user devic

    -

    Both for protecting against metadata-collecting e-mail servers -as well as against the threat of device seizure -we recommend to use a chatmail relay -to create chat profiles using random e-mail addresses for transport. -Note that Delta Chat apps on all platforms support multiple profiles -so you can easily use situation-specific profiles next to your “main” profile -with the knowledge that all their data, along with all metadata, will be deleted. -Moreover, if a device is seized then chat contacts using short-lived profiles -can not be identified easily.

    +

    Sia per proteggersi dai server e-mail che raccolgono metadati +sia per proteggersi dal rischio di sequestro del dispositivo, +consigliamo di utilizzare un chatmail relay +per creare profili di chat utilizzando indirizzi e-mail casuali per il trasporto. +Si noti che le apps Delta Chat su tutte le piattaforme supportano più profili, +quindi è possibile utilizzare facilmente profili specifici per ogni situazione accanto al profilo “principale”, +con la consapevolezza che tutti i loro dati, insieme a tutti i metadati, verranno eliminati. +Inoltre, se un dispositivo viene sequestrato, i contatti di chat che utilizzano profili di breve durata +non possono essere identificati facilmente.

    - Does Delta Chat support “Sealed Sender”? + Delta Chat supporta “Mittente Sigillato”?

    No, non ancora.

    -

    The Signal messenger introduced “Sealed Sender” in 2018 -to keep their server infrastructure ignorant of who is sending a message to a set of recipients. -It is particularly important because the Signal server knows the mobile number of each account, -which is usually associated with a passport identity.

    +

    Il messenger Signal ha introdotto “Mittente Sigillato” nel 2018 +per impedire che la propria infrastruttura server venga a conoscenza di chi sta inviando un messaggio a un insieme di destinatari. +È particolarmente importante perché il server Signal conosce il numero di cellulare di ciascun profilo, +che di solito è associato a un’identità tramite passaporto.

    -

    Even if chatmail relays -do not ask for any private data (including no phone numbers), -it might still be worthwhile to protect relational metadata between addresses. -We don’t foresee bigger problems in using random throw-away e-mail addresses for sealed sending -but an implementation has not been agreed as a priority yet.

    +

    Anche se i relays di chat +non richiedono dati privati (inclusi numeri di telefono), +potrebbe comunque valere la pena proteggere i metadati relazionali tra gli indirizzi. +Non prevediamo problemi maggiori nell’utilizzo di indirizzi e-mail casuali usa e getta per l’invio sigillato, +ma un’implementazione non è stata ancora concordata come priorità.

    @@ -1038,41 +1038,41 @@ but an implementation has not been agreed as a priority yet.

    No, non ancora.

    -

    Delta Chat today doesn’t support Perfect Forward Secrecy (PFS). -This means that if your private decryption key is leaked, -and someone has collected your prior in-transit messages, -they will be able to decrypt and read them using the leaked decryption key. -Note that Forward Secrecy only increases security if you delete messages. -Otherwise, someone obtaining your decryption keys -is typically also able to get all your non-deleted messages -and doesn’t even need to decrypt any previously collected messages.

    +

    Delta Chat al momento non supporta la tecnologia Perfect Forward Secrecy (PFS). +Ciò significa che se la tua chiave di decrittazione privata viene divulgata +e qualcuno ha raccolto i tuoi messaggi in transito precedenti, +sarà in grado di decifrarli e leggerli utilizzando la chiave di decrittazione divulgata. +Tieni presente che la tecnologia Forward Secrecy aumenta la sicurezza solo se elimini i messaggi. +In caso contrario, chi ottiene le tue chiavi di decrittazione +in genere è in grado di ottenere anche tutti i tuoi messaggi non eliminati +e non ha nemmeno bisogno di decifrare i messaggi raccolti in precedenza.

    -

    We designed a Forward Secrecy approach that withstood -initial examination from some cryptographers and implementation experts -but is pending a more formal write up -to ascertain it reliably works in federated messaging and with multi-device usage, -before it could be implemented in chatmail core, -which would make it available in all chatmail clients.

    +

    Abbiamo progettato un approccio Forward Secrecy che ha superato +l’esame iniziale di alcuni crittografi ed esperti di implementazione +ma è in attesa di una stesura più formale +per accertarne l’affidabilità nella messaggistica federata e nell’utilizzo su più dispositivi, +prima di poter essere implementato in chatmail core, +che lo renderebbe disponibile in tutti i clients di chatmail.

    - Does Delta Chat support Post-Quantum-Cryptography? + Delta Chat supporta la Crittografia Post-Quantistica?

    No, non ancora.

    -

    Delta Chat uses the Rust OpenPGP library rPGP -which supports the latest IETF Post-Quantum-Cryptography OpenPGP draft. -We aim to add PQC support in chatmail core after the draft is finalized at the IETF -in collaboration with other OpenPGP implementers.

    +

    Delta Chat utilizza la libreria Rust OpenPGP rPGP +che supporta l’ultima bozza IETF Post-Quantum-Cryptography OpenPGP. +Il nostro obiettivo è aggiungere il supporto PQC nel core di chatmail dopo che la bozza sarà stata finalizzata dall’IETF +in collaborazione con altri implementatori di OpenPGP.

    -

    +

    - How can I manually check encryption information? + Come posso controllare manualmente le informazioni di crittografia?

    @@ -1096,8 +1096,8 @@ la connessione è sicura.

    Delta Chat genera chiavi OpenPGP sicure in conformità alle specifiche di Autocrypt 1.1. Puoi esportare le tue chiavi private ma non puoi importare chiavi private aggiuntive.

    -

    In generale, non raccomandiamo on proponiamo agli utenti di gestire manualmente le chiavi. -Noi vogliamo assicurare che gli audit di sicurezza si possano focalizzare su pochi algoritmi crittografici comprovati +

    In generale, non raccomandiamo o proponiamo agli utenti di gestire manualmente le chiavi. +Noi vogliamo assicurare che gli audits di sicurezza si possano focalizzare su pochi algoritmi crittografici comprovati invece che sull’intera estensione dei possibili algoritmi consentiti con OpenPGP.

    diff --git a/src/main/assets/help/uk/help.html b/src/main/assets/help/uk/help.html index 3fb3894dc..1ae3df027 100644 --- a/src/main/assets/help/uk/help.html +++ b/src/main/assets/help/uk/help.html @@ -606,7 +606,7 @@ Push-сповіщення автоматично активуються для

    -

    Delta Chat використовує [безпечну підмножину стандарту OpenPGP] (#openpgp-secure) для забезпечення автоматичного наскрізного шифрування за допомогою цих протоколів:

    +

    Delta Chat використовує безпечну підмножину стандарту OpenPGP для забезпечення автоматичного наскрізного шифрування за допомогою цих протоколів:

    @@ -687,7 +687,7 @@ Push-сповіщення автоматично активуються для -

    У профілі контакту може відображатися зелена галочка green checkmark і рядок “Представлений”. Кожен контакт із зеленою галочкою або зробив пряме [QR-сканування] (#howtoe2ee) з вами або був представлений іншим контактом, позначеним зеленою галочкою. Знайомство відбувається автоматично під час додавання учасників до груп. Той, хто додає контакт із зеленою галочкою до групи, в якій є лише учасники із зеленою галочкою стає представником. У профілі контакту ви можете кілька разів натиснути на текст “Представлений …” поки не потрапите до того, з ким ви безпосередньо зробили [QR-сканування] (#howtoe2ee).

    +

    У профілі контакту може відображатися зелена галочка green checkmark і рядок “Представлений”. Кожен контакт із зеленою галочкою або зробив пряме QR-сканування з вами або був представлений іншим контактом, позначеним зеленою галочкою. Знайомство відбувається автоматично під час додавання учасників до груп. Той, хто додає контакт із зеленою галочкою до групи, в якій є лише учасники із зеленою галочкою стає представником. У профілі контакту ви можете кілька разів натиснути на текст “Представлений …” поки не потрапите до того, з ким ви безпосередньо зробили QR-сканування.

    Для більш детального обговорення “гарантованого наскрізного шифрування” будь ласка, перегляньте Протоколи безпечного приєднання і, зокрема, прочитайте про “Перевірені групи”, технічний термін того, що тут називається чатами з “зеленою галочкою” або “гарантованим наскрізним шифруванням”.

    @@ -802,7 +802,7 @@ Delta Chat скоріше використовує реалізацію OpenPGP

    Ні, поки ще ні.

    -

    Месенджер Signal запровадив [“Запечатаного відправника” у 2018 році] (https://signal.org/blog/sealed-sender/) щоб їхня серверна інфраструктура не знала, хто надсилає повідомлення певній групі одержувачів. Це особливо важливо, оскільки сервер Signal знає номер мобільного телефону кожного акаунта, який зазвичай асоціюється з паспортними даними.

    +

    Месенджер Signal запровадив “Запечатаного відправника” у 2018 році щоб їхня серверна інфраструктура не знала, хто надсилає повідомлення певній групі одержувачів. Це особливо важливо, оскільки сервер Signal знає номер мобільного телефону кожного акаунта, який зазвичай асоціюється з паспортними даними.

    Навіть якщо чат-мейл релей не запитує ніяких приватних даних (в тому числі номерів телефонів), все одно може мати сенс захистити реляційні метадані між адресами. Ми не передбачаємо великих проблем у використанні випадкових одноразових адрес електронної пошти для запечатаних відправлень але реалізація такої можливості ще не є пріоритетною.

    @@ -1265,7 +1265,7 @@ Delta Chat скоріше використовує реалізацію OpenPGP diff --git a/src/main/java/chat/delta/rpc/BaseTransport.java b/src/main/java/chat/delta/rpc/BaseTransport.java new file mode 100644 index 000000000..971bb130f --- /dev/null +++ b/src/main/java/chat/delta/rpc/BaseTransport.java @@ -0,0 +1,124 @@ +/* Autogenerated file, do not edit manually */ +package chat.delta.rpc; + +import chat.delta.util.SettableFuture; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.io.IOException; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutionException; + +/* Basic RPC Transport implementation */ +public abstract class BaseTransport implements Rpc.Transport { + private final Map> requestFutures = new ConcurrentHashMap<>(); + private int requestId = 0; + private final ObjectMapper mapper = new ObjectMapper(); + private Thread worker; + + /* Send a Request as raw JSON String to the RPC server */ + protected abstract void sendRequest(String jsonRequest); + + /* Get next Response as raw JSON String from the RPC server */ + protected abstract String getResponse(); + + public ObjectMapper getObjectMapper() { + return mapper; + } + + public void call(String method, JsonNode... params) throws RpcException { + innerCall(method, params); + } + + public T callForResult(TypeReference resultType, String method, JsonNode... params) throws RpcException { + try { + JsonNode node = innerCall(method, params); + if (node.isNull()) return null; + return mapper.readValue(node.traverse(), resultType); + } catch (IOException e) { + throw new RpcException(e.getMessage()); + } + } + + private JsonNode innerCall(String method, JsonNode... params) throws RpcException { + int id; + synchronized (this) { + id = ++requestId; + ensureWorkerThread(); + } + try { + String jsonRequest = mapper.writeValueAsString(new Request(method, params, id)); + SettableFuture future = new SettableFuture<>(); + requestFutures.put(id, future); + sendRequest(jsonRequest); + return future.get(); + } catch (ExecutionException e) { + throw (RpcException)e.getCause(); + } catch (InterruptedException e) { + throw new RpcException(e.getMessage()); + } catch (JsonProcessingException e) { + throw new RpcException(e.getMessage()); + } + } + + private void ensureWorkerThread() { + if (worker != null) return; + + worker = new Thread(() -> { + while (true) { + try { + processResponse(); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + } + }, "jsonrpcThread"); + worker.start(); + } + + private void processResponse() throws JsonProcessingException { + String jsonResponse = getResponse(); + Response response = mapper.readValue(jsonResponse, Response.class); + + if (response.id == 0) { // Got JSON-RPC notification/event, ignore + return; + } + + SettableFuture future = requestFutures.remove(response.id); + if (future == null) { // Got a response with unknown ID, ignore + return; + } + + if (response.error != null) { + future.setException(new RpcException(response.error.toString())); + } else if (response.result != null) { + future.set(response.result); + } else { + future.setException(new RpcException("Got JSON-RPC response without result or error: " + jsonResponse)); + } + } + + private static class Request { + private final String jsonrpc = "2.0"; + public final String method; + public final JsonNode[] params; + public final int id; + + public Request(String method, JsonNode[] params, int id) { + this.method = method; + this.params = params; + this.id = id; + } + } + + private static class Response { + public String jsonrpc; + public int id; + public JsonNode result; + public JsonNode error; + } +} \ No newline at end of file diff --git a/src/main/java/chat/delta/rpc/Rpc.java b/src/main/java/chat/delta/rpc/Rpc.java new file mode 100644 index 000000000..f157b8d22 --- /dev/null +++ b/src/main/java/chat/delta/rpc/Rpc.java @@ -0,0 +1,249 @@ +/* Autogenerated file, do not edit manually */ +package chat.delta.rpc; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import chat.delta.rpc.types.*; + +public class Rpc { + + public interface Transport { + void call(String method, JsonNode... params) throws RpcException; + T callForResult(TypeReference resultType, String method, JsonNode... params) throws RpcException; + ObjectMapper getObjectMapper(); + } + + public final Transport transport; + private final ObjectMapper mapper; + + public Rpc(Transport transport) { + this.transport = transport; + this.mapper = transport.getObjectMapper(); + } + + public Integer addAccount() throws RpcException { + return transport.callForResult(new TypeReference(){}, "add_account"); + } + + /** + * Set the order of accounts. + * The provided list should contain all account IDs in the desired order. + * If an account ID is missing from the list, it will be appended at the end. + * If the list contains non-existent account IDs, they will be ignored. + */ + public void setAccountsOrder(java.util.List order) throws RpcException { + transport.call("set_accounts_order", mapper.valueToTree(order)); + } + + /* Get the combined filesize of an account in bytes */ + public Integer getAccountFileSize(Integer accountId) throws RpcException { + return transport.callForResult(new TypeReference(){}, "get_account_file_size", mapper.valueToTree(accountId)); + } + + /** + * If there was an error while the account was opened + * and migrated to the current version, + * then this function returns it. + *

    + * This function is useful because the key-contacts migration could fail due to bugs + * and then the account will not work properly. + *

    + * After opening an account, the UI should call this function + * and show the error string if one is returned. + */ + public String getMigrationError(Integer accountId) throws RpcException { + return transport.callForResult(new TypeReference(){}, "get_migration_error", mapper.valueToTree(accountId)); + } + + public Integer draftSelfReport(Integer accountId) throws RpcException { + return transport.callForResult(new TypeReference(){}, "draft_self_report", mapper.valueToTree(accountId)); + } + + /* Returns configuration value for the given key. */ + public String getConfig(Integer accountId, String key) throws RpcException { + return transport.callForResult(new TypeReference(){}, "get_config", mapper.valueToTree(accountId), mapper.valueToTree(key)); + } + + /** + * Configures a new email account using the provided parameters + * and adds it as a transport. + *

    + * If the email address is the same as an existing transport, + * then this existing account will be reconfigured instead of a new one being added. + *

    + * This function stops and starts IO as needed. + *

    + * Usually it will be enough to only set `addr` and `password`, + * and all the other settings will be autoconfigured. + *

    + * During configuration, ConfigureProgress events are emitted; + * they indicate a successful configuration as well as errors + * and may be used to create a progress bar. + * This function will return after configuration is finished. + *

    + * If configuration is successful, + * the working server parameters will be saved + * and used for connecting to the server. + * The parameters entered by the user will be saved separately + * so that they can be prefilled when the user opens the server-configuration screen again. + *

    + * See also: + * - [Self::is_configured()] to check whether there is + * at least one working transport. + * - [Self::add_transport_from_qr()] to add a transport + * from a server encoded in a QR code. + * - [Self::list_transports()] to get a list of all configured transports. + * - [Self::delete_transport()] to remove a transport. + */ + public void addOrUpdateTransport(Integer accountId, EnteredLoginParam param) throws RpcException { + transport.call("add_or_update_transport", mapper.valueToTree(accountId), mapper.valueToTree(param)); + } + + /** + * Adds a new email account as a transport + * using the server encoded in the QR code. + * See [Self::add_or_update_transport]. + */ + public void addTransportFromQr(Integer accountId, String qr) throws RpcException { + transport.call("add_transport_from_qr", mapper.valueToTree(accountId), mapper.valueToTree(qr)); + } + + /** + * Create a new unencrypted group chat. + *

    + * Same as [`Self::create_group_chat`], but the chat is unencrypted and can only have + * address-contacts. + */ + public Integer createGroupChatUnencrypted(Integer accountId, String name) throws RpcException { + return transport.callForResult(new TypeReference(){}, "create_group_chat_unencrypted", mapper.valueToTree(accountId), mapper.valueToTree(name)); + } + + /** + * Create a new **broadcast channel** + * (called "Channel" in the UI). + *

    + * Broadcast channels are similar to groups on the sending device, + * however, recipients get the messages in a read-only chat + * and will not see who the other members are. + *

    + * Called `broadcast` here rather than `channel`, + * because the word "channel" already appears a lot in the code, + * which would make it hard to grep for it. + *

    + * After creation, the chat contains no recipients and is in _unpromoted_ state; + * see [`CommandApi::create_group_chat`] for more information on the unpromoted state. + *

    + * Returns the created chat's id. + */ + public Integer createBroadcast(Integer accountId, String chatName) throws RpcException { + return transport.callForResult(new TypeReference(){}, "create_broadcast", mapper.valueToTree(accountId), mapper.valueToTree(chatName)); + } + + /* Returns contact id of the created or existing DM chat with that contact */ + public Integer createChatByContactId(Integer accountId, Integer contactId) throws RpcException { + return transport.callForResult(new TypeReference(){}, "create_chat_by_contact_id", mapper.valueToTree(accountId), mapper.valueToTree(contactId)); + } + + /* Sets display name for existing contact. */ + public void changeContactName(Integer accountId, Integer contactId, String name) throws RpcException { + transport.call("change_contact_name", mapper.valueToTree(accountId), mapper.valueToTree(contactId), mapper.valueToTree(name)); + } + + + /* Parses a vCard file located at the given path. Returns contacts in their original order. */ + public java.util.List parseVcard(String path) throws RpcException { + return transport.callForResult(new TypeReference>(){}, "parse_vcard", mapper.valueToTree(path)); + } + + /** + * Imports contacts from a vCard file located at the given path. + *

    + * Returns the ids of created/modified contacts in the order they appear in the vCard. + */ + public java.util.List importVcard(Integer accountId, String path) throws RpcException { + return transport.callForResult(new TypeReference>(){}, "import_vcard", mapper.valueToTree(accountId), mapper.valueToTree(path)); + } + + /* Returns a vCard containing contacts with the given ids. */ + public String makeVcard(Integer accountId, java.util.List contacts) throws RpcException { + return transport.callForResult(new TypeReference(){}, "make_vcard", mapper.valueToTree(accountId), mapper.valueToTree(contacts)); + } + + public void sendWebxdcRealtimeData(Integer accountId, Integer instanceMsgId, java.util.List data) throws RpcException { + transport.call("send_webxdc_realtime_data", mapper.valueToTree(accountId), mapper.valueToTree(instanceMsgId), mapper.valueToTree(data)); + } + + public void sendWebxdcRealtimeAdvertisement(Integer accountId, Integer instanceMsgId) throws RpcException { + transport.call("send_webxdc_realtime_advertisement", mapper.valueToTree(accountId), mapper.valueToTree(instanceMsgId)); + } + + /** + * Leaves the gossip of the webxdc with the given message id. + *

    + * NB: When this is called before closing a webxdc app in UIs, it must be guaranteed that + * `send_webxdc_realtime_*()` functions aren't called for the given `instance_message_id` + * anymore until the app is open again. + */ + public void leaveWebxdcRealtime(Integer accountId, Integer instanceMessageId) throws RpcException { + transport.call("leave_webxdc_realtime", mapper.valueToTree(accountId), mapper.valueToTree(instanceMessageId)); + } + + /* Starts an outgoing call. */ + public Integer placeOutgoingCall(Integer accountId, Integer chatId, String placeCallInfo) throws RpcException { + return transport.callForResult(new TypeReference(){}, "place_outgoing_call", mapper.valueToTree(accountId), mapper.valueToTree(chatId), mapper.valueToTree(placeCallInfo)); + } + + /* Accepts an incoming call. */ + public void acceptIncomingCall(Integer accountId, Integer msgId, String acceptCallInfo) throws RpcException { + transport.call("accept_incoming_call", mapper.valueToTree(accountId), mapper.valueToTree(msgId), mapper.valueToTree(acceptCallInfo)); + } + + /* Ends incoming or outgoing call. */ + public void endCall(Integer accountId, Integer msgId) throws RpcException { + transport.call("end_call", mapper.valueToTree(accountId), mapper.valueToTree(msgId)); + } + + /* Returns information about the call. */ + public CallInfo callInfo(Integer accountId, Integer msgId) throws RpcException { + return transport.callForResult(new TypeReference(){}, "call_info", mapper.valueToTree(accountId), mapper.valueToTree(msgId)); + } + + /* Returns JSON with ICE servers, to be used for WebRTC video calls. */ + public String iceServers(Integer accountId) throws RpcException { + return transport.callForResult(new TypeReference(){}, "ice_servers", mapper.valueToTree(accountId)); + } + + /** + * Makes an HTTP GET request and returns a response. + *

    + * `url` is the HTTP or HTTPS URL. + */ + public HttpResponse getHttpResponse(Integer accountId, String url) throws RpcException { + return transport.callForResult(new TypeReference(){}, "get_http_response", mapper.valueToTree(accountId), mapper.valueToTree(url)); + } + + /** + * Send a reaction to message. + *

    + * Reaction is a string of emojis separated by spaces. Reaction to a + * single message can be sent multiple times. The last reaction + * received overrides all previously received reactions. It is + * possible to remove all reactions by sending an empty string. + */ + public Integer sendReaction(Integer accountId, Integer messageId, java.util.List reaction) throws RpcException { + return transport.callForResult(new TypeReference(){}, "send_reaction", mapper.valueToTree(accountId), mapper.valueToTree(messageId), mapper.valueToTree(reaction)); + } + + /* Returns reactions to the message. */ + public Reactions getMessageReactions(Integer accountId, Integer messageId) throws RpcException { + return transport.callForResult(new TypeReference(){}, "get_message_reactions", mapper.valueToTree(accountId), mapper.valueToTree(messageId)); + } + + /* Checks if messages can be sent to a given chat. */ + public Boolean canSend(Integer accountId, Integer chatId) throws RpcException { + return transport.callForResult(new TypeReference(){}, "can_send", mapper.valueToTree(accountId), mapper.valueToTree(chatId)); + } + +} diff --git a/src/main/java/chat/delta/rpc/RpcException.java b/src/main/java/chat/delta/rpc/RpcException.java new file mode 100644 index 000000000..6d165e387 --- /dev/null +++ b/src/main/java/chat/delta/rpc/RpcException.java @@ -0,0 +1,8 @@ +/* Autogenerated file, do not edit manually */ +package chat.delta.rpc; + +public class RpcException extends Exception { + + public RpcException(String message) { super(message); } + +} \ No newline at end of file diff --git a/src/main/java/chat/delta/rpc/types/CallInfo.java b/src/main/java/chat/delta/rpc/types/CallInfo.java new file mode 100644 index 000000000..dd177c186 --- /dev/null +++ b/src/main/java/chat/delta/rpc/types/CallInfo.java @@ -0,0 +1,19 @@ +/* Autogenerated file, do not edit manually */ +package chat.delta.rpc.types; + +public class CallInfo { + /* True if SDP offer has a video. */ + public Boolean hasVideo; + /** + * SDP offer. + *

    + * Can be used to manually answer the call even if incoming call event was missed. + */ + public String sdpOffer; + /** + * Call state. + *

    + * For example, if the call is accepted, active, canceled, declined etc. + */ + public CallState state; +} \ No newline at end of file diff --git a/src/main/java/chat/delta/rpc/types/CallState.java b/src/main/java/chat/delta/rpc/types/CallState.java new file mode 100644 index 000000000..b18577053 --- /dev/null +++ b/src/main/java/chat/delta/rpc/types/CallState.java @@ -0,0 +1,48 @@ +/* Autogenerated file, do not edit manually */ +package chat.delta.rpc.types; + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonSubTypes.Type; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeInfo.Id; +import com.fasterxml.jackson.annotation.JsonTypeInfo.As; + +@JsonTypeInfo(use=Id.NAME, include=As.PROPERTY, property="kind") +@JsonSubTypes({@Type(value = CallState.Alerting.class, name="Alerting"), @Type(value = CallState.Active.class, name="Active"), @Type(value = CallState.Completed.class, name="Completed"), @Type(value = CallState.Missed.class, name="Missed"), @Type(value = CallState.Declined.class, name="Declined"), @Type(value = CallState.Canceled.class, name="Canceled")}) +public abstract class CallState { + +/** + * Fresh incoming or outgoing call that is still ringing. + *

    + * There is no separate state for outgoing call that has been dialled but not ringing on the other side yet as we don't know whether the other side received our call. + */ + public static class Alerting extends CallState { + } + +/* Active call. */ + public static class Active extends CallState { + } + +/* Completed call that was once active and then was terminated for any reason. */ + public static class Completed extends CallState { + /* Call duration in seconds. */ + public Integer duration; + } + +/* Incoming call that was not picked up within a timeout or was explicitly ended by the caller before we picked up. */ + public static class Missed extends CallState { + } + +/* Incoming call that was explicitly ended on our side before picking up or outgoing call that was declined before the timeout. */ + public static class Declined extends CallState { + } + +/** + * Outgoing call that has been canceled on our side before receiving a response. + *

    + * Incoming calls cannot be canceled, on the receiver side canceled calls usually result in missed calls. + */ + public static class Canceled extends CallState { + } + +} \ No newline at end of file diff --git a/src/main/java/chat/delta/rpc/types/EnteredCertificateChecks.java b/src/main/java/chat/delta/rpc/types/EnteredCertificateChecks.java new file mode 100644 index 000000000..77c8f9f85 --- /dev/null +++ b/src/main/java/chat/delta/rpc/types/EnteredCertificateChecks.java @@ -0,0 +1,13 @@ +/* Autogenerated file, do not edit manually */ +package chat.delta.rpc.types; + +public enum EnteredCertificateChecks { + /* `Automatic` means that provider database setting should be taken. If there is no provider database setting for certificate checks, check certificates strictly. */ + automatic, + + /* Ensure that TLS certificate is valid for the server hostname. */ + strict, + + /* Accept certificates that are expired, self-signed or otherwise not valid for the server hostname. */ + acceptInvalidCertificates, +} \ No newline at end of file diff --git a/src/main/java/chat/delta/rpc/types/EnteredLoginParam.java b/src/main/java/chat/delta/rpc/types/EnteredLoginParam.java new file mode 100644 index 000000000..87c1c9427 --- /dev/null +++ b/src/main/java/chat/delta/rpc/types/EnteredLoginParam.java @@ -0,0 +1,51 @@ +/* Autogenerated file, do not edit manually */ +package chat.delta.rpc.types; + +/** + * Login parameters entered by the user. + *

    + * Usually it will be enough to only set `addr` and `password`, and all the other settings will be autoconfigured. + */ +public class EnteredLoginParam { + /* Email address. */ + public String addr; + /* TLS options: whether to allow invalid certificates and/or invalid hostnames. Default: Automatic */ + @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET) + public EnteredCertificateChecks certificateChecks; + /* Imap server port. */ + @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET) + public Integer imapPort; + /* Imap socket security. */ + @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET) + public Socket imapSecurity; + /* Imap server hostname or IP address. */ + @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET) + public String imapServer; + /* Imap username. */ + @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET) + public String imapUser; + /* If true, login via OAUTH2 (not recommended anymore). Default: false */ + @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET) + public Boolean oauth2; + /* Password. */ + public String password; + /** + * SMTP Password. + *

    + * Only needs to be specified if different than IMAP password. + */ + @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET) + public String smtpPassword; + /* SMTP server port. */ + @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET) + public Integer smtpPort; + /* SMTP socket security. */ + @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET) + public Socket smtpSecurity; + /* SMTP server hostname or IP address. */ + @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET) + public String smtpServer; + /* SMTP username. */ + @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET) + public String smtpUser; +} \ No newline at end of file diff --git a/src/main/java/chat/delta/rpc/types/HttpResponse.java b/src/main/java/chat/delta/rpc/types/HttpResponse.java new file mode 100644 index 000000000..8ad3c6438 --- /dev/null +++ b/src/main/java/chat/delta/rpc/types/HttpResponse.java @@ -0,0 +1,13 @@ +/* Autogenerated file, do not edit manually */ +package chat.delta.rpc.types; + +public class HttpResponse { + /* base64-encoded response body. */ + public String blob; + /* Encoding, e.g. "utf-8". */ + @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET) + public String encoding; + /* MIME type, e.g. "text/plain" or "text/html". */ + @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET) + public String mimetype; +} \ No newline at end of file diff --git a/src/main/java/chat/delta/rpc/types/Reaction.java b/src/main/java/chat/delta/rpc/types/Reaction.java new file mode 100644 index 000000000..3ac86d5b7 --- /dev/null +++ b/src/main/java/chat/delta/rpc/types/Reaction.java @@ -0,0 +1,12 @@ +/* Autogenerated file, do not edit manually */ +package chat.delta.rpc.types; + +/* A single reaction emoji. */ +public class Reaction { + /* Emoji frequency. */ + public Integer count; + /* Emoji. */ + public String emoji; + /* True if we reacted with this emoji. */ + public Boolean isFromSelf; +} \ No newline at end of file diff --git a/src/main/java/chat/delta/rpc/types/Reactions.java b/src/main/java/chat/delta/rpc/types/Reactions.java new file mode 100644 index 000000000..a7daf1155 --- /dev/null +++ b/src/main/java/chat/delta/rpc/types/Reactions.java @@ -0,0 +1,10 @@ +/* Autogenerated file, do not edit manually */ +package chat.delta.rpc.types; + +/* Structure representing all reactions to a particular message. */ +public class Reactions { + /* Unique reactions and their count, sorted in descending order. */ + public java.util.List reactions; + /* Map from a contact to it's reaction to message. */ + public java.util.Map> reactionsByContact; +} \ No newline at end of file diff --git a/src/main/java/chat/delta/rpc/types/Socket.java b/src/main/java/chat/delta/rpc/types/Socket.java new file mode 100644 index 000000000..1dccf6935 --- /dev/null +++ b/src/main/java/chat/delta/rpc/types/Socket.java @@ -0,0 +1,16 @@ +/* Autogenerated file, do not edit manually */ +package chat.delta.rpc.types; + +public enum Socket { + /* Unspecified socket security, select automatically. */ + automatic, + + /* TLS connection. */ + ssl, + + /* STARTTLS connection. */ + starttls, + + /* No TLS, plaintext connection. */ + plain, +} \ No newline at end of file diff --git a/src/main/java/chat/delta/rpc/types/VcardContact.java b/src/main/java/chat/delta/rpc/types/VcardContact.java new file mode 100644 index 000000000..f028f3357 --- /dev/null +++ b/src/main/java/chat/delta/rpc/types/VcardContact.java @@ -0,0 +1,20 @@ +/* Autogenerated file, do not edit manually */ +package chat.delta.rpc.types; + +public class VcardContact { + /* Email address. */ + public String addr; + /* Contact color as hex string. */ + public String color; + /* The contact's name, or the email address if no name was given. */ + public String displayName; + /* Public PGP key in Base64. */ + @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET) + public String key; + /* Profile image in Base64. */ + @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET) + public String profileImage; + /* Last update timestamp. */ + @com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET) + public Integer timestamp; +} \ No newline at end of file diff --git a/src/main/java/chat/delta/util/ListenableFuture.java b/src/main/java/chat/delta/util/ListenableFuture.java new file mode 100644 index 000000000..d511ec729 --- /dev/null +++ b/src/main/java/chat/delta/util/ListenableFuture.java @@ -0,0 +1,14 @@ +/* Autogenerated file, do not edit manually */ +package chat.delta.util; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +public interface ListenableFuture extends Future { + void addListener(Listener listener); + + public interface Listener { + public void onSuccess(T result); + public void onFailure(ExecutionException e); + } +} \ No newline at end of file diff --git a/src/main/java/chat/delta/util/SettableFuture.java b/src/main/java/chat/delta/util/SettableFuture.java new file mode 100644 index 000000000..0a14c4876 --- /dev/null +++ b/src/main/java/chat/delta/util/SettableFuture.java @@ -0,0 +1,137 @@ +/* Autogenerated file, do not edit manually */ +package chat.delta.util; + +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class SettableFuture implements ListenableFuture { + + private final List> listeners = new LinkedList<>(); + + private boolean completed; + private boolean canceled; + private volatile T result; + private volatile Throwable exception; + + public SettableFuture() { } + + public SettableFuture(T value) { + this.result = value; + this.completed = true; + } + + @Override + public synchronized boolean cancel(boolean mayInterruptIfRunning) { + if (!completed && !canceled) { + canceled = true; + return true; + } + + return false; + } + + @Override + public synchronized boolean isCancelled() { + return canceled; + } + + @Override + public synchronized boolean isDone() { + return completed; + } + + public boolean set(T result) { + synchronized (this) { + if (completed || canceled) return false; + + this.result = result; + this.completed = true; + + notifyAll(); + } + + notifyAllListeners(); + return true; + } + + public boolean setException(Throwable throwable) { + synchronized (this) { + if (completed || canceled) return false; + + this.exception = throwable; + this.completed = true; + + notifyAll(); + } + + notifyAllListeners(); + return true; + } + + public void deferTo(ListenableFuture other) { + other.addListener(new Listener() { + @Override + public void onSuccess(T result) { + SettableFuture.this.set(result); + } + + @Override + public void onFailure(ExecutionException e) { + SettableFuture.this.setException(e.getCause()); + } + }); + } + + @Override + public synchronized T get() throws InterruptedException, ExecutionException { + while (!completed) wait(); + + if (exception != null) throw new ExecutionException(exception); + else return result; + } + + @Override + public synchronized T get(long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException + { + long startTime = System.currentTimeMillis(); + + while (!completed && System.currentTimeMillis() - startTime > unit.toMillis(timeout)) { + wait(unit.toMillis(timeout)); + } + + if (!completed) throw new TimeoutException(); + else return get(); + } + + @Override + public void addListener(Listener listener) { + synchronized (this) { + listeners.add(listener); + + if (!completed) return; + } + + notifyListener(listener); + } + + private void notifyAllListeners() { + List> localListeners; + + synchronized (this) { + localListeners = new LinkedList<>(listeners); + } + + for (Listener listener : localListeners) { + notifyListener(listener); + } + } + + private void notifyListener(Listener listener) { + if (exception != null) listener.onFailure(new ExecutionException(exception)); + else listener.onSuccess(result); + } +} \ No newline at end of file diff --git a/src/main/java/com/b44t/messenger/DcAccounts.java b/src/main/java/com/b44t/messenger/DcAccounts.java index e828a0946..2dec50068 100644 --- a/src/main/java/com/b44t/messenger/DcAccounts.java +++ b/src/main/java/com/b44t/messenger/DcAccounts.java @@ -50,4 +50,14 @@ public class DcAccounts { private native long getJsonrpcInstanceCPtr (); private native long getAccountCPtr (int accountId); private native long getSelectedAccountCPtr (); + + public boolean isAllChatmail() { + for (int accountId : getAll()) { + DcContext dcContext = getAccount(accountId); + if (!dcContext.isChatmail()) { + return false; + } + } + return true; + } } diff --git a/src/main/java/com/b44t/messenger/DcContext.java b/src/main/java/com/b44t/messenger/DcContext.java index d606e0c7b..93dc1babe 100644 --- a/src/main/java/com/b44t/messenger/DcContext.java +++ b/src/main/java/com/b44t/messenger/DcContext.java @@ -31,6 +31,10 @@ public class DcContext { public final static int DC_EVENT_WEBXDC_INSTANCE_DELETED = 2121; public final static int DC_EVENT_WEBXDC_REALTIME_DATA = 2150; public final static int DC_EVENT_ACCOUNTS_BACKGROUND_FETCH_DONE = 2200; + public final static int DC_EVENT_INCOMING_CALL = 2550; + public final static int DC_EVENT_INCOMING_CALL_ACCEPTED = 2560; + public final static int DC_EVENT_OUTGOING_CALL_ACCEPTED = 2570; + public final static int DC_EVENT_CALL_ENDED = 2580; public final static int DC_IMEX_EXPORT_SELF_KEYS = 1; public final static int DC_IMEX_IMPORT_SELF_KEYS = 2; @@ -201,7 +205,6 @@ public class DcContext { public native boolean resendMsgs (int msg_ids[]); public native int sendMsg (int chat_id, DcMsg msg); public native int sendTextMsg (int chat_id, String text); - public native int sendVideochatInvitation(int chat_id); public native boolean sendWebxdcStatusUpdate(int msg_id, String payload); public native String getWebxdcStatusUpdates(int msg_id, int last_known_serial); public native void setWebxdcIntegration (String file); diff --git a/src/main/java/com/b44t/messenger/DcMsg.java b/src/main/java/com/b44t/messenger/DcMsg.java index 37645b48d..ac9282687 100644 --- a/src/main/java/com/b44t/messenger/DcMsg.java +++ b/src/main/java/com/b44t/messenger/DcMsg.java @@ -18,7 +18,7 @@ public class DcMsg { public final static int DC_MSG_VOICE = 41; public final static int DC_MSG_VIDEO = 50; public final static int DC_MSG_FILE = 60; - public final static int DC_MSG_VIDEOCHAT_INVITATION = 70; + public final static int DC_MSG_CALL = 71; public final static int DC_MSG_WEBXDC = 80; public final static int DC_MSG_VCARD = 90; @@ -155,8 +155,6 @@ public class DcMsg { public native boolean isInfo (); public native boolean hasHtml (); public native String getSetupCodeBegin (); - public native String getVideochatUrl (); - public native int getVideochatType (); public native void setText (String text); public native void setSubject (String text); public native void setHtml (String text); @@ -196,7 +194,7 @@ public class DcMsg { public boolean canSave() { // saving info-messages out of context results in confusion, see https://github.com/deltachat/deltachat-ios/issues/2567 - return !isInfo() && getType() != DC_MSG_VIDEOCHAT_INVITATION; + return !isInfo(); } public File getFileAsFile() { diff --git a/src/main/java/com/b44t/messenger/FFITransport.java b/src/main/java/com/b44t/messenger/FFITransport.java new file mode 100644 index 000000000..401048c52 --- /dev/null +++ b/src/main/java/com/b44t/messenger/FFITransport.java @@ -0,0 +1,22 @@ +package com.b44t.messenger; + +import chat.delta.rpc.BaseTransport; + +/* RPC transport over C FFI */ +public class FFITransport extends BaseTransport { + private final DcJsonrpcInstance dcJsonrpcInstance; + + public FFITransport(DcJsonrpcInstance dcJsonrpcInstance) { + this.dcJsonrpcInstance = dcJsonrpcInstance; + } + + @Override + protected void sendRequest(String jsonRequest) { + dcJsonrpcInstance.request(jsonRequest); + } + + @Override + protected String getResponse() { + return dcJsonrpcInstance.getNextResponse(); + } +} \ No newline at end of file diff --git a/src/main/java/com/b44t/messenger/rpc/EnteredLoginParam.java b/src/main/java/com/b44t/messenger/rpc/EnteredLoginParam.java deleted file mode 100644 index 9c65486d5..000000000 --- a/src/main/java/com/b44t/messenger/rpc/EnteredLoginParam.java +++ /dev/null @@ -1,171 +0,0 @@ -package com.b44t.messenger.rpc; - -public class EnteredLoginParam { - // Email address. - private final String addr; - - // Password. - private final String password; - - // ============ IMAP settings ============ - - // Server hostname or IP address. - private final String imapServer; - - // Server port. - private final int imapPort; - - // Socket security. - private final SocketSecurity imapSecurity; - - // Username. - private final String imapUser; - - // ============ SMTP settings ============ - - // Server hostname or IP address. - private final String smtpServer; - - // Server port. - private final int smtpPort; - - // Socket security. - private final SocketSecurity smtpSecurity; - - // Username. - private final String smtpUser; - - // SMTP Password. Only needs to be specified if different than IMAP password. - private final String smtpPassword; - - // TLS options: whether to allow invalid certificates and/or - // invalid hostnames - private final EnteredCertificateChecks certificateChecks; - - // If true, login via OAUTH2 (not recommended anymore) - private final boolean oauth2; - - public EnteredLoginParam(String addr, - String password, - String imapServer, - int imapPort, - SocketSecurity imapSecurity, - String imapUser, - String smtpServer, - int smtpPort, - SocketSecurity smtpSecurity, - String smtpUser, - String smtpPassword, - EnteredCertificateChecks certificateChecks, - boolean oauth2) { - this.addr = addr; - this.password = password; - this.imapServer = imapServer; - this.imapPort = imapPort; - this.imapSecurity = imapSecurity; - this.imapUser = imapUser; - this.smtpServer = smtpServer; - this.smtpPort = smtpPort; - this.smtpSecurity = smtpSecurity; - this.smtpUser = smtpUser; - this.smtpPassword = smtpPassword; - this.certificateChecks = certificateChecks; - this.oauth2 = oauth2; - } - - public String getAddr() { - return addr; - } - - public String getPassword() { - return password; - } - - public String getImapServer() { - return imapServer; - } - - public int getImapPort() { - return imapPort; - } - - public SocketSecurity getImapSecurity() { - return imapSecurity; - } - - public String getImapUser() { - return imapUser; - } - - public String getSmtpServer() { - return smtpServer; - } - - public int getSmtpPort() { - return smtpPort; - } - - public SocketSecurity getSmtpSecurity() { - return smtpSecurity; - } - - public String getSmtpUser() { - return smtpUser; - } - - public String getSmtpPassword() { - return smtpPassword; - } - - public EnteredCertificateChecks getCertificateChecks() { - return certificateChecks; - } - - public boolean isOauth2() { - return oauth2; - } - - public enum EnteredCertificateChecks { - automatic, strict, acceptInvalidCertificates, - } - - public static EnteredCertificateChecks certificateChecksFromInt(int position) { - switch (position) { - case 0: - return EnteredCertificateChecks.automatic; - case 1: - return EnteredCertificateChecks.strict; - case 2: - return EnteredCertificateChecks.acceptInvalidCertificates; - } - throw new IllegalArgumentException("Invalid certificate position: " + position); - } - - public enum SocketSecurity { - // Unspecified socket security, select automatically. - automatic, - - // TLS connection. - ssl, - - // STARTTLS connection. - starttls, - - // No TLS, plaintext connection. - plain, - } - - public static SocketSecurity socketSecurityFromInt(int position) { - switch (position) { - case 0: - return SocketSecurity.automatic; - case 1: - return SocketSecurity.ssl; - case 2: - return SocketSecurity.starttls; - case 3: - return SocketSecurity.plain; - } - throw new IllegalArgumentException("Invalid socketSecurity position: " + position); - } -} diff --git a/src/main/java/com/b44t/messenger/rpc/HttpResponse.java b/src/main/java/com/b44t/messenger/rpc/HttpResponse.java deleted file mode 100644 index ccc6b8c6b..000000000 --- a/src/main/java/com/b44t/messenger/rpc/HttpResponse.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.b44t.messenger.rpc; - -import android.util.Base64; - -public class HttpResponse { - // base64-encoded response body. - private final String blob; - // MIME type, e.g. "text/plain" or "text/html". - private final String mimetype; - // Encoding, e.g. "utf-8". - private final String encoding; - - public HttpResponse(String blob, String mimetype, String encoding) { - this.blob = blob; - this.mimetype = mimetype; - this.encoding = encoding; - } - - public byte[] getBlob() { - if (blob == null) { - return null; - } - return Base64.decode(blob, Base64.NO_WRAP | Base64.NO_PADDING); - } - - public String getMimetype() { - return mimetype; - } - - public String getEncoding() { - return encoding; - } -} diff --git a/src/main/java/com/b44t/messenger/rpc/Reaction.java b/src/main/java/com/b44t/messenger/rpc/Reaction.java deleted file mode 100644 index 493cb4ec5..000000000 --- a/src/main/java/com/b44t/messenger/rpc/Reaction.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.b44t.messenger.rpc; - -import androidx.annotation.Nullable; - -public class Reaction { - // The reaction emoji string. - private final String emoji; - // The count of users that have reacted with this reaction. - private final int count; - // true if self-account reacted with this reaction, false otherwise. - private final boolean isFromSelf; - - public Reaction(String emoji, int count, boolean isFromSelf) { - this.emoji = emoji; - this.count = count; - this.isFromSelf = isFromSelf; - } - - public String getEmoji() { - return emoji; - } - - public int getCount() { - return count; - } - - public boolean isFromSelf() { - return isFromSelf; - } - - @Override - public boolean equals(@Nullable Object obj) { - if (obj instanceof Reaction) { - Reaction reaction = (Reaction) obj; - return emoji.equals(reaction.getEmoji()) && count == reaction.getCount() && isFromSelf == reaction.isFromSelf(); - } - return false; - } -} diff --git a/src/main/java/com/b44t/messenger/rpc/Reactions.java b/src/main/java/com/b44t/messenger/rpc/Reactions.java deleted file mode 100644 index 7b8849868..000000000 --- a/src/main/java/com/b44t/messenger/rpc/Reactions.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.b44t.messenger.rpc; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class Reactions { - // Map from a contact to it's reaction to message. - private final HashMap reactionsByContact; - // Unique reactions, sorted in descending order. - private final ArrayList reactions; - - public Reactions(HashMap reactionsByContact, ArrayList reactions) { - this.reactionsByContact = reactionsByContact; - this.reactions = reactions; - } - - public Map getReactionsByContact() { - return reactionsByContact; - } - - public List getReactions() { - return reactions; - } -} diff --git a/src/main/java/com/b44t/messenger/rpc/Rpc.java b/src/main/java/com/b44t/messenger/rpc/Rpc.java deleted file mode 100644 index 12fa326b2..000000000 --- a/src/main/java/com/b44t/messenger/rpc/Rpc.java +++ /dev/null @@ -1,203 +0,0 @@ -package com.b44t.messenger.rpc; - -import android.util.Log; - -import com.b44t.messenger.DcJsonrpcInstance; -import com.b44t.messenger.util.concurrent.SettableFuture; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonElement; -import com.google.gson.JsonSyntaxException; -import com.google.gson.reflect.TypeToken; - -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutionException; - -public class Rpc { - private final static String TAG = Rpc.class.getSimpleName(); - - private final Map> requestFutures = new ConcurrentHashMap<>(); - private final DcJsonrpcInstance dcJsonrpcInstance; - private int requestId = 0; - private boolean started = false; - private final Gson gson = new GsonBuilder().serializeNulls().create(); - - public Rpc(DcJsonrpcInstance dcJsonrpcInstance) { - this.dcJsonrpcInstance = dcJsonrpcInstance; - } - - private void processResponse() throws JsonSyntaxException { - String jsonResponse = dcJsonrpcInstance.getNextResponse(); - - Response response = gson.fromJson(jsonResponse, Response.class); - if (response == null) { - Log.e(TAG, "Error parsing JSON: " + jsonResponse); - return; - } else if (response.id == 0) { - // Got JSON-RPC notification/event, ignore - return; - } - - SettableFuture future = requestFutures.remove(response.id); - if (future == null) { // Got a response with unknown ID, ignore - return; - } - - if (response.error != null) { - String message; - try { - message = response.error.getAsJsonObject().get("message").getAsString(); - } catch (Exception e) { - Log.e(TAG, "Can't get response error message: " + e); - message = response.error.toString(); - } - future.setException(new RpcException(message)); - } else if (response.result != null) { - future.set(response.result); - } else { - future.setException(new RpcException("Got JSON-RPC response without result or error: " + jsonResponse)); - } - } - - public void start() { - started = true; - new Thread(() -> { - while (true) { - try { - processResponse(); - } catch (Exception e) { - e.printStackTrace(); - } - } - }, "jsonrpcThread").start(); - } - - public SettableFuture call(String method, Object... params) throws RpcException { - if (!started) throw new RpcException("RPC not started yet."); - - int id; - synchronized (this) { - id = ++requestId; - } - String jsonRequest = gson.toJson(new Request(method, params, id)); - SettableFuture future = new SettableFuture<>(); - requestFutures.put(id, future); - dcJsonrpcInstance.request(jsonRequest); - return future; - } - - public JsonElement getResult(String method, Object... params) throws RpcException { - try { - return call(method, params).get(); - } catch (ExecutionException e) { - throw (RpcException)e.getCause(); - } catch (InterruptedException e) { - throw new RpcException(e.getMessage()); - } - } - - public List parseVcard(String path) throws RpcException { - TypeToken> listType = new TypeToken>(){}; - return gson.fromJson(getResult("parse_vcard", path), listType.getType()); - } - - public String makeVcard(int accountId, int... contacts) throws RpcException { - return gson.fromJson(getResult("make_vcard", accountId, contacts), String.class); - } - - public List importVcard(int accountId, String path) throws RpcException { - TypeToken> listType = new TypeToken>(){}; - return gson.fromJson(getResult("import_vcard", accountId, path), listType.getType()); - } - - public HttpResponse getHttpResponse(int accountId, String url) throws RpcException { - return gson.fromJson(getResult("get_http_response", accountId, url), HttpResponse.class); - } - - public Reactions getMsgReactions(int accountId, int msgId) throws RpcException { - return gson.fromJson(getResult("get_message_reactions", accountId, msgId), Reactions.class); - } - - public int sendReaction(int accountId, int msgId, String... reaction) throws RpcException { - return getResult("send_reaction", accountId, msgId, reaction).getAsInt(); - } - - public int draftSelfReport(int accountId) throws RpcException { - return getResult("draft_self_report", accountId).getAsInt(); - } - - public void sendWebxdcRealtimeData(Integer accountId, Integer instanceMsgId, List data) throws RpcException { - getResult("send_webxdc_realtime_data", accountId, instanceMsgId, data); - } - - public void sendWebxdcRealtimeAdvertisement(Integer accountId, Integer instanceMsgId) throws RpcException { - getResult("send_webxdc_realtime_advertisement", accountId, instanceMsgId); - } - - public void leaveWebxdcRealtime(Integer accountId, Integer instanceMessageId) throws RpcException { - getResult("leave_webxdc_realtime", accountId, instanceMessageId); - } - - public int getAccountFileSize(int accountId) throws RpcException { - return getResult("get_account_file_size", accountId).getAsInt(); - } - - public void changeContactName(int accountId, int contactId, String name) throws RpcException { - getResult("change_contact_name", accountId, contactId, name); - } - - public int addAccount() throws RpcException { - return getResult("add_account").getAsInt(); - } - - public void addTransportFromQr(int accountId, String qrCode) throws RpcException { - getResult("add_transport_from_qr", accountId, qrCode); - } - - public void addOrUpdateTransport(int accountId, EnteredLoginParam param) throws RpcException { - getResult("add_or_update_transport", accountId, param); - } - - public int createBroadcast(int accountId, String chatName) throws RpcException { - return gson.fromJson(getResult("create_broadcast", accountId, chatName), Integer.class); - } - - public int createGroupChatUnencrypted(int accountId, String chatName) throws RpcException { - return gson.fromJson(getResult("create_group_chat_unencrypted", accountId, chatName), Integer.class); - } - - public void setAccountsOrder(List order) throws RpcException { - getResult("set_accounts_order", order); - } - - private static class Request { - private final String jsonrpc = "2.0"; - public final String method; - public final Object[] params; - public final int id; - - public Request(String method, Object[] params, int id) { - this.method = method; - this.params = params; - this.id = id; - } - } - - public String getMigrationError(int accountId) throws RpcException { - return gson.fromJson(getResult("get_migration_error", accountId), String.class); - } - - private static class Response { - public final int id; - public final JsonElement result; - public final JsonElement error; - - public Response(int id, JsonElement result, JsonElement error) { - this.id = id; - this.result = result; - this.error = error; - } - } -} diff --git a/src/main/java/com/b44t/messenger/rpc/RpcException.java b/src/main/java/com/b44t/messenger/rpc/RpcException.java deleted file mode 100644 index 9879b940f..000000000 --- a/src/main/java/com/b44t/messenger/rpc/RpcException.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.b44t.messenger.rpc; - -/** - * An exception occurred while processing a request in ArcaneChat core. - **/ -public class RpcException extends Exception { - - public RpcException(String message) { - super(message); - } -} diff --git a/src/main/java/com/b44t/messenger/rpc/VcardContact.java b/src/main/java/com/b44t/messenger/rpc/VcardContact.java deleted file mode 100644 index 75c47ea0a..000000000 --- a/src/main/java/com/b44t/messenger/rpc/VcardContact.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.b44t.messenger.rpc; - -import android.util.Base64; - -public class VcardContact { - // Email address. - private final String addr; - - // The contact's name, or the email address if no name was given. - private final String displayName; - - // Public PGP key in Base64. - private final String key; - - // Profile image in Base64. - private final String profileImage; - - // Contact color in HTML color format. - private final String color; - - // Last update timestamp. - private final int timestamp; - - public VcardContact(String addr, String displayName, String key, String profileImage, String color, int timestamp) { - this.addr = addr; - this.displayName = displayName; - this.key = key; - this.profileImage = profileImage; - this.color = color; - this.timestamp = timestamp; - } - - public String getAddr() { - return addr; - } - - public String getDisplayName() { - return displayName; - } - - public byte[] getKey() { - return key == null? null : Base64.decode(key, Base64.NO_WRAP | Base64.NO_PADDING); - } - - public boolean hasProfileImage() { - return profileImage != null; - } - - public byte[] getProfileImage() { - return profileImage == null? null : Base64.decode(profileImage, Base64.NO_WRAP | Base64.NO_PADDING); - } - - public String getColor() { - return color; - } - - public int getTimestamp() { - return timestamp; - } -} diff --git a/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java b/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java index e260f9198..5fcb48ad9 100644 --- a/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java +++ b/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java @@ -25,8 +25,7 @@ import com.b44t.messenger.DcAccounts; import com.b44t.messenger.DcContext; import com.b44t.messenger.DcEvent; import com.b44t.messenger.DcEventEmitter; -import com.b44t.messenger.rpc.Rpc; -import com.b44t.messenger.rpc.RpcException; +import com.b44t.messenger.FFITransport; import org.thoughtcrime.securesms.connect.AccountManager; import org.thoughtcrime.securesms.connect.DcEventCenter; @@ -53,6 +52,9 @@ import java.io.PrintWriter; import java.io.StringWriter; import java.util.concurrent.TimeUnit; +import chat.delta.rpc.Rpc; +import chat.delta.rpc.RpcException; + public class ApplicationContext extends MultiDexApplication { private static final String TAG = ApplicationContext.class.getSimpleName(); @@ -109,8 +111,7 @@ public class ApplicationContext extends MultiDexApplication { System.loadLibrary("native-utils"); dcAccounts = new DcAccounts(new File(getFilesDir(), "accounts").getAbsolutePath()); - rpc = new Rpc(dcAccounts.getJsonrpcInstance()); - rpc.start(); + rpc = new Rpc(new FFITransport(dcAccounts.getJsonrpcInstance())); AccountManager.getInstance().migrateToDcAccounts(this); int[] allAccounts = dcAccounts.getAll(); for (int accountId : allAccounts) { diff --git a/src/main/java/org/thoughtcrime/securesms/BaseConversationItem.java b/src/main/java/org/thoughtcrime/securesms/BaseConversationItem.java index 9a5e5eb66..4b2072c1d 100644 --- a/src/main/java/org/thoughtcrime/securesms/BaseConversationItem.java +++ b/src/main/java/org/thoughtcrime/securesms/BaseConversationItem.java @@ -14,7 +14,6 @@ import androidx.appcompat.app.AlertDialog; import com.b44t.messenger.DcChat; import com.b44t.messenger.DcContext; import com.b44t.messenger.DcMsg; -import com.b44t.messenger.rpc.Rpc; import org.thoughtcrime.securesms.connect.DcHelper; import org.thoughtcrime.securesms.recipients.Recipient; @@ -24,6 +23,8 @@ import org.thoughtcrime.securesms.util.ViewUtil; import java.util.HashSet; import java.util.Set; +import chat.delta.rpc.Rpc; + public abstract class BaseConversationItem extends LinearLayout implements BindableConversationItem { diff --git a/src/main/java/org/thoughtcrime/securesms/ConversationActivity.java b/src/main/java/org/thoughtcrime/securesms/ConversationActivity.java index c14d6c013..c3cbc415d 100644 --- a/src/main/java/org/thoughtcrime/securesms/ConversationActivity.java +++ b/src/main/java/org/thoughtcrime/securesms/ConversationActivity.java @@ -74,8 +74,6 @@ import com.b44t.messenger.DcContact; import com.b44t.messenger.DcContext; import com.b44t.messenger.DcEvent; import com.b44t.messenger.DcMsg; -import com.b44t.messenger.rpc.Rpc; -import com.b44t.messenger.rpc.RpcException; import com.b44t.messenger.util.concurrent.ListenableFuture; import com.b44t.messenger.util.concurrent.SettableFuture; @@ -122,13 +120,17 @@ import org.thoughtcrime.securesms.util.concurrent.AssertedSuccessListener; import org.thoughtcrime.securesms.util.guava.Optional; import org.thoughtcrime.securesms.util.views.ProgressDialog; import org.thoughtcrime.securesms.video.recode.VideoRecoder; -import org.thoughtcrime.securesms.videochat.VideochatUtil; +import org.thoughtcrime.securesms.calls.CallUtil; import java.io.File; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.concurrent.ExecutionException; +import chat.delta.rpc.Rpc; +import chat.delta.rpc.RpcException; + /** * Activity for displaying a message thread, as well as * composing/sending a new message into that thread. @@ -448,6 +450,14 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity menu.findItem(R.id.menu_show_map).setVisible(false); } + menu.findItem(R.id.menu_start_call).setVisible( + Prefs.isCallsEnabled(this) + && dcChat.canSend() + && dcChat.isEncrypted() + && !dcChat.isSelfTalk() + && !dcChat.isMultiUser() + ); + if (!dcChat.isEncrypted() || !dcChat.canSend() || dcChat.isMailingList() ) { menu.findItem(R.id.menu_ephemeral_messages).setVisible(false); } @@ -538,6 +548,9 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity } else if (itemId == R.id.menu_show_map) { WebxdcActivity.openMaps(this, chatId); return true; + } else if (itemId == R.id.menu_start_call) { + CallUtil.startCall(this, chatId); + return true; } else if (itemId == R.id.menu_all_media) { handleAllMedia(); return true; @@ -972,8 +985,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity AttachmentManager.selectGallery(this, PICK_GALLERY); break; case AttachmentTypeSelector.ADD_DOCUMENT: AttachmentManager.selectDocument(this, PICK_DOCUMENT); break; - case AttachmentTypeSelector.INVITE_VIDEO_CHAT: - new VideochatUtil().invite(this, chatId); break; case AttachmentTypeSelector.ADD_CONTACT_INFO: startContactChooserActivity(); break; case AttachmentTypeSelector.ADD_LOCATION: @@ -1012,7 +1023,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity } try { - byte[] vcard = rpc.makeVcard(dcContext.getAccountId(), contactId).getBytes(); + byte[] vcard = rpc.makeVcard(dcContext.getAccountId(), Collections.singletonList(contactId)).getBytes(); String mimeType = "application/octet-stream"; setMedia(PersistentBlobProvider.getInstance().create(this, vcard, mimeType, "vcard.vcf"), MediaType.DOCUMENT); } catch (RpcException e) { @@ -1464,7 +1475,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity Recipient author = new Recipient(this, dcContext.getContact(msg.getFromId())); SlideDeck slideDeck = new SlideDeck(); - if (msg.getType() != DcMsg.DC_MSG_TEXT) { + if (msg.hasFile()) { slideDeck.addSlide(MediaUtil.getSlideForMsg(this, msg)); } diff --git a/src/main/java/org/thoughtcrime/securesms/ConversationAdapter.java b/src/main/java/org/thoughtcrime/securesms/ConversationAdapter.java index c2e805af4..10d30f9b0 100644 --- a/src/main/java/org/thoughtcrime/securesms/ConversationAdapter.java +++ b/src/main/java/org/thoughtcrime/securesms/ConversationAdapter.java @@ -77,9 +77,8 @@ public class ConversationAdapter private static final int MESSAGE_TYPE_THUMBNAIL_INCOMING = 6; private static final int MESSAGE_TYPE_DOCUMENT_OUTGOING = 7; private static final int MESSAGE_TYPE_DOCUMENT_INCOMING = 8; - private static final int MESSAGE_TYPE_VIDEOCHAT_INVITE = 9; - private static final int MESSAGE_TYPE_STICKER_INCOMING = 10; - private static final int MESSAGE_TYPE_STICKER_OUTGOING = 11; + private static final int MESSAGE_TYPE_STICKER_INCOMING = 9; + private static final int MESSAGE_TYPE_STICKER_OUTGOING = 10; private final Set batchSelected = Collections.synchronizedSet(new HashSet()); @@ -279,7 +278,6 @@ public class ConversationAdapter case MESSAGE_TYPE_STICKER_INCOMING: case MESSAGE_TYPE_INCOMING: return R.layout.conversation_item_received; case MESSAGE_TYPE_INFO: return R.layout.conversation_item_update; - case MESSAGE_TYPE_VIDEOCHAT_INVITE:return R.layout.conversation_item_videochat; default: throw new IllegalArgumentException("unsupported item view type given to ConversationAdapter"); } } @@ -303,9 +301,6 @@ public class ConversationAdapter else if (type == DcMsg.DC_MSG_STICKER) { return dcMsg.isOutgoing()? MESSAGE_TYPE_STICKER_OUTGOING : MESSAGE_TYPE_STICKER_INCOMING; } - else if (type == DcMsg.DC_MSG_VIDEOCHAT_INVITATION) { - return MESSAGE_TYPE_VIDEOCHAT_INVITE; - } else { return dcMsg.isOutgoing()? MESSAGE_TYPE_OUTGOING : MESSAGE_TYPE_INCOMING; } diff --git a/src/main/java/org/thoughtcrime/securesms/ConversationFragment.java b/src/main/java/org/thoughtcrime/securesms/ConversationFragment.java index ef3fd040d..8987eefc4 100644 --- a/src/main/java/org/thoughtcrime/securesms/ConversationFragment.java +++ b/src/main/java/org/thoughtcrime/securesms/ConversationFragment.java @@ -66,7 +66,7 @@ import org.thoughtcrime.securesms.util.StickyHeaderDecoration; import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.views.ConversationAdaptiveActionsToolbar; -import org.thoughtcrime.securesms.videochat.VideochatUtil; +import org.thoughtcrime.securesms.calls.CallUtil; import java.util.Collections; import java.util.LinkedList; @@ -367,8 +367,7 @@ public class ConversationFragment extends MessageSelectorFragment } static boolean canReplyToMsg(DcMsg dcMsg) { - boolean canReply = dcMsg.getType() != DcMsg.DC_MSG_VIDEOCHAT_INVITATION; - if (canReply && dcMsg.isInfo()) { + if (dcMsg.isInfo()) { switch (dcMsg.getInfoType()) { case DcMsg.DC_INFO_GROUP_NAME_CHANGED: case DcMsg.DC_INFO_GROUP_IMAGE_CHANGED: @@ -377,16 +376,16 @@ public class ConversationFragment extends MessageSelectorFragment case DcMsg.DC_INFO_LOCATIONSTREAMING_ENABLED: case DcMsg.DC_INFO_EPHEMERAL_TIMER_CHANGED: case DcMsg.DC_INFO_WEBXDC_INFO_MESSAGE: - break; + return true; default: - canReply = false; + return false; } } - return canReply; + return true; } static boolean canEditMsg(DcMsg dcMsg) { - return dcMsg.isOutgoing() && !dcMsg.isInfo() && dcMsg.getType() != DcMsg.DC_MSG_VIDEOCHAT_INVITATION && !dcMsg.hasHtml() && !dcMsg.getText().isEmpty(); + return dcMsg.isOutgoing() && !dcMsg.isInfo() && dcMsg.getType() != DcMsg.DC_MSG_CALL && !dcMsg.hasHtml() && !dcMsg.getText().isEmpty(); } public void handleClearChat() { @@ -758,9 +757,6 @@ public class ConversationFragment extends MessageSelectorFragment actionMode.setTitleOptionalHint(false); // the title represents important information, also indicating implicitly, more items can be selected } } - else if (messageRecord.getType()==DcMsg.DC_MSG_VIDEOCHAT_INVITATION) { - new VideochatUtil().join(getActivity(), messageRecord.getId()); - } else if(DozeReminder.isDozeReminderMsg(getContext(), messageRecord)) { DozeReminder.dozeReminderTapped(getContext()); } diff --git a/src/main/java/org/thoughtcrime/securesms/ConversationItem.java b/src/main/java/org/thoughtcrime/securesms/ConversationItem.java index 49bb89c5a..52bf4527f 100644 --- a/src/main/java/org/thoughtcrime/securesms/ConversationItem.java +++ b/src/main/java/org/thoughtcrime/securesms/ConversationItem.java @@ -40,14 +40,12 @@ import androidx.appcompat.app.AlertDialog; import com.b44t.messenger.DcChat; import com.b44t.messenger.DcContact; import com.b44t.messenger.DcMsg; -import com.b44t.messenger.rpc.Reactions; -import com.b44t.messenger.rpc.RpcException; -import com.b44t.messenger.rpc.VcardContact; import org.thoughtcrime.securesms.audio.AudioSlidePlayer; import org.thoughtcrime.securesms.components.AudioView; import org.thoughtcrime.securesms.components.AvatarImageView; import org.thoughtcrime.securesms.components.BorderlessImageView; +import org.thoughtcrime.securesms.components.CallItemView; import org.thoughtcrime.securesms.components.ConversationItemFooter; import org.thoughtcrime.securesms.components.ConversationItemThumbnail; import org.thoughtcrime.securesms.components.DocumentView; @@ -73,10 +71,17 @@ import org.thoughtcrime.securesms.util.MediaUtil; import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.views.Stub; +import org.thoughtcrime.securesms.calls.CallUtil; import java.util.List; import java.util.Set; +import chat.delta.rpc.RpcException; +import chat.delta.rpc.types.CallInfo; +import chat.delta.rpc.types.CallState; +import chat.delta.rpc.types.Reactions; +import chat.delta.rpc.types.VcardContact; + /** * A view that displays an individual conversation item within a conversation * thread. Used by ComposeMessageActivity's ListActivity via a ConversationAdapter. @@ -118,6 +123,7 @@ public class ConversationItem extends BaseConversationItem private @NonNull Stub webxdcViewStub; private Stub stickerStub; private Stub vcardViewStub; + private Stub callViewStub; private @Nullable EventListener eventListener; private int measureCalls; @@ -152,6 +158,7 @@ public class ConversationItem extends BaseConversationItem this.webxdcViewStub = new Stub<>(findViewById(R.id.webxdc_view_stub)); this.stickerStub = new Stub<>(findViewById(R.id.sticker_view_stub)); this.vcardViewStub = new Stub<>(findViewById(R.id.vcard_view_stub)); + this.callViewStub = new Stub<>(findViewById(R.id.call_view_stub)); this.groupSenderHolder = findViewById(R.id.group_sender_holder); this.quoteView = findViewById(R.id.quote_view); this.container = findViewById(R.id.container); @@ -322,6 +329,11 @@ public class ConversationItem extends BaseConversationItem vcardViewStub.get().setFocusable(!shouldInterceptClicks(messageRecord) && batchSelected.isEmpty()); vcardViewStub.get().setClickable(batchSelected.isEmpty()); } + + if (callViewStub.resolved()) { + callViewStub.get().setFocusable(!shouldInterceptClicks(messageRecord) && batchSelected.isEmpty()); + callViewStub.get().setClickable(batchSelected.isEmpty()); + } } private void setContentDescription() { @@ -338,6 +350,8 @@ public class ConversationItem extends BaseConversationItem desc += webxdcViewStub.get().getDescription() + "\n"; } else if (vcardViewStub.resolved() && vcardViewStub.get().getVisibility() == View.VISIBLE) { desc += vcardViewStub.get().getDescription() + "\n"; + } else if (callViewStub.resolved() && callViewStub.get().getVisibility() == View.VISIBLE) { + desc += callViewStub.get().getDescription() + "\n"; } else if (mediaThumbnailStub.resolved() && mediaThumbnailStub.get().getVisibility() == View.VISIBLE) { desc += mediaThumbnailStub.get().getDescription() + "\n"; } else if (stickerStub.resolved() && stickerStub.get().getVisibility() == View.VISIBLE) { @@ -399,7 +413,7 @@ public class ConversationItem extends BaseConversationItem String text = messageRecord.getText(); - if (text.isEmpty()) { + if (messageRecord.getType() == DcMsg.DC_MSG_CALL || text.isEmpty()) { bodyText.setVisibility(View.GONE); } else { @@ -490,6 +504,7 @@ public class ConversationItem extends BaseConversationItem if (webxdcViewStub.resolved()) webxdcViewStub.get().setVisibility(View.GONE); if (stickerStub.resolved()) stickerStub.get().setVisibility(View.GONE); if (vcardViewStub.resolved()) vcardViewStub.get().setVisibility(View.GONE); + if (callViewStub.resolved()) callViewStub.get().setVisibility(View.GONE); //noinspection ConstantConditions int duration = messageRecord.getDuration(); @@ -515,6 +530,7 @@ public class ConversationItem extends BaseConversationItem if (webxdcViewStub.resolved()) webxdcViewStub.get().setVisibility(View.GONE); if (stickerStub.resolved()) stickerStub.get().setVisibility(View.GONE); if (vcardViewStub.resolved()) vcardViewStub.get().setVisibility(View.GONE); + if (callViewStub.resolved()) callViewStub.get().setVisibility(View.GONE); //noinspection ConstantConditions documentViewStub.get().setDocument(new DocumentSlide(context, messageRecord)); @@ -533,6 +549,7 @@ public class ConversationItem extends BaseConversationItem if (documentViewStub.resolved()) documentViewStub.get().setVisibility(View.GONE); if (stickerStub.resolved()) stickerStub.get().setVisibility(View.GONE); if (vcardViewStub.resolved()) vcardViewStub.get().setVisibility(View.GONE); + if (callViewStub.resolved()) callViewStub.get().setVisibility(View.GONE); webxdcViewStub.get().setWebxdc(messageRecord, context.getString(R.string.webxdc_app)); webxdcViewStub.get().setWebxdcClickListener(new ThumbnailClickListener()); @@ -550,6 +567,7 @@ public class ConversationItem extends BaseConversationItem if (documentViewStub.resolved()) documentViewStub.get().setVisibility(View.GONE); if (webxdcViewStub.resolved()) webxdcViewStub.get().setVisibility(View.GONE); if (stickerStub.resolved()) stickerStub.get().setVisibility(View.GONE); + if (callViewStub.resolved()) callViewStub.get().setVisibility(View.GONE); vcardViewStub.get().setVcard(glideRequests, new VcardSlide(context, messageRecord), rpc); vcardViewStub.get().setVcardClickListener(new ThumbnailClickListener()); @@ -561,6 +579,27 @@ public class ConversationItem extends BaseConversationItem ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); footer.setVisibility(VISIBLE); } + else if (messageRecord.getType() == DcMsg.DC_MSG_CALL) { + callViewStub.get().setVisibility(View.VISIBLE); + if (mediaThumbnailStub.resolved()) mediaThumbnailStub.get().setVisibility(View.GONE); + if (audioViewStub.resolved()) audioViewStub.get().setVisibility(View.GONE); + if (documentViewStub.resolved()) documentViewStub.get().setVisibility(View.GONE); + if (webxdcViewStub.resolved()) webxdcViewStub.get().setVisibility(View.GONE); + if (stickerStub.resolved()) stickerStub.get().setVisibility(View.GONE); + if (vcardViewStub.resolved()) vcardViewStub.get().setVisibility(View.GONE); + + try { + callViewStub.get().setCallItem(messageRecord.isOutgoing(), rpc.callInfo(dcContext.getAccountId(), messageRecord.getId())); + } catch (RpcException e) { + Log.e(TAG, "Error in Rpc.callInfo", e); + } + callViewStub.get().setCallClickListener(new CallClickListener()); + callViewStub.get().setOnLongClickListener(passthroughClickListener); + + callViewStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); + + ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); + } else if (hasThumbnail(messageRecord)) { mediaThumbnailStub.get().setVisibility(View.VISIBLE); if (audioViewStub.resolved()) audioViewStub.get().setVisibility(View.GONE); @@ -568,6 +607,7 @@ public class ConversationItem extends BaseConversationItem if (webxdcViewStub.resolved()) webxdcViewStub.get().setVisibility(View.GONE); if (stickerStub.resolved()) stickerStub.get().setVisibility(View.GONE); if (vcardViewStub.resolved()) vcardViewStub.get().setVisibility(View.GONE); + if (callViewStub.resolved()) callViewStub.get().setVisibility(View.GONE); Slide slide = MediaUtil.getSlideForMsg(context, messageRecord); @@ -607,6 +647,7 @@ public class ConversationItem extends BaseConversationItem if (webxdcViewStub.resolved()) webxdcViewStub.get().setVisibility(View.GONE); if (mediaThumbnailStub.resolved()) mediaThumbnailStub.get().setVisibility(View.GONE); if (vcardViewStub.resolved()) vcardViewStub.get().setVisibility(View.GONE); + if (callViewStub.resolved()) callViewStub.get().setVisibility(View.GONE); bodyBubble.setBackgroundColor(Color.TRANSPARENT); @@ -627,6 +668,7 @@ public class ConversationItem extends BaseConversationItem if (documentViewStub.resolved()) documentViewStub.get().setVisibility(View.GONE); if (webxdcViewStub.resolved()) webxdcViewStub.get().setVisibility(View.GONE); if (vcardViewStub.resolved()) vcardViewStub.get().setVisibility(View.GONE); + if (callViewStub.resolved()) callViewStub.get().setVisibility(View.GONE); ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); @@ -757,11 +799,11 @@ public class ConversationItem extends BaseConversationItem private void setReactions(@NonNull DcMsg current) { try { - Reactions reactions = rpc.getMsgReactions(dcContext.getAccountId(), current.getId()); + Reactions reactions = rpc.getMessageReactions(dcContext.getAccountId(), current.getId()); if (reactions == null) { reactionsView.clear(); } else { - reactionsView.setReactions(reactions.getReactions()); + reactionsView.setReactions(reactions.reactions); reactionsView.setOnClickListener(view -> { if (eventListener != null && batchSelected.isEmpty()) { eventListener.onReactionClicked(current); @@ -780,6 +822,8 @@ public class ConversationItem extends BaseConversationItem return stickerStub.get().getFooter(); } else if (hasOnlyThumbnail(messageRecord) && TextUtils.isEmpty(messageRecord.getText())) { return mediaThumbnailStub.get().getFooter(); + } else if (messageRecord.getType() == DcMsg.DC_MSG_CALL) { + return callViewStub.get().getFooter(); } else { return footer; } @@ -881,6 +925,7 @@ public class ConversationItem extends BaseConversationItem else if (documentViewStub.resolved()) documentViewStub.get().performClick(); else if (webxdcViewStub.resolved()) webxdcViewStub.get().performClick(); else if (vcardViewStub.resolved()) vcardViewStub.get().performClick(); + else if (callViewStub.resolved()) callViewStub.get().performClick(); } /// Event handlers @@ -896,7 +941,7 @@ public class ConversationItem extends BaseConversationItem String path = slide.asAttachment().getRealPath(context); VcardContact vcardContact = rpc.parseVcard(path).get(0); new AlertDialog.Builder(context) - .setMessage(context.getString(R.string.ask_start_chat_with, vcardContact.getDisplayName())) + .setMessage(context.getString(R.string.ask_start_chat_with, vcardContact.displayName)) .setPositiveButton(android.R.string.ok, (dialog, which) -> { try { List contactIds = rpc.importVcard(dcContext.getAccountId(), path); @@ -942,4 +987,21 @@ public class ConversationItem extends BaseConversationItem } } } + + private class CallClickListener implements CallItemView.CallClickListener { + public void onClick(final View v, final CallInfo callInfo) { + if (shouldInterceptClicks(messageRecord) || !batchSelected.isEmpty()) { + performClick(); + } else { + int accId = dcContext.getAccountId(); + int chatId = messageRecord.getChatId(); + if (!messageRecord.isOutgoing() && callInfo.state instanceof CallState.Alerting) { + int callId = messageRecord.getId(); + CallUtil.openCall(getContext(), accId, chatId, callId, callInfo.sdpOffer); + } else { + CallUtil.startCall(getContext(), accId, chatId); + } + } + } + } } diff --git a/src/main/java/org/thoughtcrime/securesms/ConversationVideochatItem.java b/src/main/java/org/thoughtcrime/securesms/ConversationVideochatItem.java deleted file mode 100644 index 92ea322cc..000000000 --- a/src/main/java/org/thoughtcrime/securesms/ConversationVideochatItem.java +++ /dev/null @@ -1,99 +0,0 @@ -package org.thoughtcrime.securesms; - -import android.content.Context; -import android.text.TextUtils; -import android.util.AttributeSet; -import android.view.ViewGroup; -import android.widget.LinearLayout; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.b44t.messenger.DcChat; -import com.b44t.messenger.DcContact; -import com.b44t.messenger.DcContext; -import com.b44t.messenger.DcMsg; - -import org.thoughtcrime.securesms.components.AvatarImageView; -import org.thoughtcrime.securesms.components.ConversationItemFooter; -import org.thoughtcrime.securesms.connect.DcHelper; -import org.thoughtcrime.securesms.mms.GlideRequests; -import org.thoughtcrime.securesms.recipients.Recipient; -import org.thoughtcrime.securesms.util.Util; -import org.thoughtcrime.securesms.util.ViewUtil; - -import java.util.Set; - -public class ConversationVideochatItem extends LinearLayout - implements BindableConversationItem -{ - private TextView body; - private ConversationItemFooter footer; - private AvatarImageView contactPhoto; - private ViewGroup contactPhotoHolder; - private DcMsg dcMsg; - - public ConversationVideochatItem(Context context) { - super(context); - } - - public ConversationVideochatItem(Context context, AttributeSet attrs) { - super(context, attrs); - } - - @Override - public void onFinishInflate() { - super.onFinishInflate(); - this.body = findViewById(R.id.conversation_update_body); - this.footer = findViewById(R.id.conversation_item_footer); - this.contactPhoto = findViewById(R.id.contact_photo); - this.contactPhotoHolder = findViewById(R.id.contact_photo_container); - } - - @Override - public void bind(@NonNull DcMsg dcMsg, - @NonNull DcChat dcChat, - @NonNull GlideRequests glideRequests, - @NonNull Set batchSelected, - @NonNull Recipient conversationRecipient, - boolean pulseUpdate) - { - this.dcMsg = dcMsg; - DcContext dcContext = DcHelper.getContext(getContext()); - DcContact dcContact = dcContext.getContact(dcMsg.getFromId()); - - CharSequence line1 = dcMsg.isOutgoing()? getContext().getString(R.string.videochat_you_invited_hint) : - getContext().getString(R.string.videochat_contact_invited_hint, dcContact.getDisplayName()); - CharSequence line2 = Util.getBoldedString(dcMsg.isOutgoing()? getContext().getString(R.string.videochat_tap_to_open) : - getContext().getString(R.string.videochat_tap_to_join)); - - body.setText(TextUtils.concat(line1, "\n", line2)); - - contactPhoto.setAvatar(glideRequests, new Recipient(getContext(), dcContact), true); - - setSelected(batchSelected.contains(dcMsg)); - setFooter(dcMsg); - } - - private void setFooter(@NonNull DcMsg dcMsg) { - ViewUtil.updateLayoutParams(footer, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); - - footer.setVisibility(VISIBLE); - footer.setMessageRecord(dcMsg); - } - - @Override - public void setEventListener(@Nullable EventListener listener) { - // No events to report yet - } - - @Override - public DcMsg getMessageRecord() { - return dcMsg; - } - - @Override - public void unbind() { - } -} diff --git a/src/main/java/org/thoughtcrime/securesms/EphemeralMessagesDialog.java b/src/main/java/org/thoughtcrime/securesms/EphemeralMessagesDialog.java index ecc0881cf..338660eef 100644 --- a/src/main/java/org/thoughtcrime/securesms/EphemeralMessagesDialog.java +++ b/src/main/java/org/thoughtcrime/securesms/EphemeralMessagesDialog.java @@ -60,14 +60,12 @@ public class EphemeralMessagesDialog { .setPositiveButton(R.string.ok, (dialog, which) -> { final long burnAfter; switch (selectedChoice[0]) { - case 1: burnAfter = TimeUnit.MINUTES.toSeconds(1); break; - case 2: burnAfter = TimeUnit.MINUTES.toSeconds(5); break; - case 3: burnAfter = TimeUnit.MINUTES.toSeconds(30); break; - case 4: burnAfter = TimeUnit.HOURS.toSeconds(1); break; - case 5: burnAfter = TimeUnit.DAYS.toSeconds(1); break; - case 6: burnAfter = TimeUnit.DAYS.toSeconds(7); break; - case 7: burnAfter = TimeUnit.DAYS.toSeconds(35); break; - case 8: burnAfter = TimeUnit.DAYS.toSeconds(365); break; + case 1: burnAfter = TimeUnit.MINUTES.toSeconds(5); break; + case 2: burnAfter = TimeUnit.HOURS.toSeconds(1); break; + case 3: burnAfter = TimeUnit.DAYS.toSeconds(1); break; + case 4: burnAfter = TimeUnit.DAYS.toSeconds(7); break; + case 5: burnAfter = TimeUnit.DAYS.toSeconds(35); break; + case 6: burnAfter = TimeUnit.DAYS.toSeconds(365); break; default: burnAfter = 0; break; } listener.onTimeSelected(burnAfter); @@ -84,30 +82,23 @@ public class EphemeralMessagesDialog { if (timespan == 0) { return 0; // off } - // Choose timespan close to the current one out of available options. - if (timespan < TimeUnit.MINUTES.toSeconds(5)) { - return 1; // 1 minute - } - if (timespan < TimeUnit.MINUTES.toSeconds(30)) { - return 2; // 5 minutes - } if (timespan < TimeUnit.HOURS.toSeconds(1)) { - return 3; // 30 minutes + return 1; // 5 minutes } if (timespan < TimeUnit.DAYS.toSeconds(1)) { - return 4; // 1 hour + return 2; // 1 hour } if (timespan < TimeUnit.DAYS.toSeconds(7)) { - return 5; // 1 day + return 3; // 1 day } if (timespan < TimeUnit.DAYS.toSeconds(35)) { - return 6; // 1 week + return 4; // 1 week } if (timespan < TimeUnit.DAYS.toSeconds(365)) { - return 7; // 5 weeks + return 5; // 5 weeks } - return 8; // 1 year + return 6; // 1 year } } diff --git a/src/main/java/org/thoughtcrime/securesms/FullMsgActivity.java b/src/main/java/org/thoughtcrime/securesms/FullMsgActivity.java index 93e9cca57..017dc6e59 100644 --- a/src/main/java/org/thoughtcrime/securesms/FullMsgActivity.java +++ b/src/main/java/org/thoughtcrime/securesms/FullMsgActivity.java @@ -13,17 +13,19 @@ import android.webkit.WebView; import androidx.appcompat.app.AlertDialog; import com.b44t.messenger.DcContext; -import com.b44t.messenger.rpc.HttpResponse; -import com.b44t.messenger.rpc.Rpc; import org.thoughtcrime.securesms.connect.DcHelper; import org.thoughtcrime.securesms.util.DynamicTheme; +import org.thoughtcrime.securesms.util.JsonUtils; import org.thoughtcrime.securesms.util.Prefs; import org.thoughtcrime.securesms.util.Util; import java.io.ByteArrayInputStream; import java.lang.ref.WeakReference; +import chat.delta.rpc.Rpc; +import chat.delta.rpc.types.HttpResponse; + public class FullMsgActivity extends WebViewActivity { public static final String MSG_ID_EXTRA = "msg_id"; @@ -227,11 +229,12 @@ public class FullMsgActivity extends WebViewActivity throw new Exception("no url specified"); } HttpResponse httpResponse = rpc.getHttpResponse(dcContext.getAccountId(), url); - String mimeType = httpResponse.getMimetype(); + String mimeType = httpResponse.mimetype; if (mimeType == null) { mimeType = "application/octet-stream"; } - res = new WebResourceResponse(mimeType, httpResponse.getEncoding(), new ByteArrayInputStream(httpResponse.getBlob())); + byte[] blob = JsonUtils.decodeBase64(httpResponse.blob); + res = new WebResourceResponse(mimeType, httpResponse.encoding, new ByteArrayInputStream(blob)); } catch (Exception e) { e.printStackTrace(); res = new WebResourceResponse("text/plain", "UTF-8", new ByteArrayInputStream(("Error: " + e.getMessage()).getBytes())); diff --git a/src/main/java/org/thoughtcrime/securesms/GroupCreateActivity.java b/src/main/java/org/thoughtcrime/securesms/GroupCreateActivity.java index f85a525cd..0ae42148b 100644 --- a/src/main/java/org/thoughtcrime/securesms/GroupCreateActivity.java +++ b/src/main/java/org/thoughtcrime/securesms/GroupCreateActivity.java @@ -23,7 +23,6 @@ import androidx.loader.app.LoaderManager; import com.b44t.messenger.DcChat; import com.b44t.messenger.DcContact; import com.b44t.messenger.DcContext; -import com.b44t.messenger.rpc.RpcException; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.request.target.CustomTarget; import com.bumptech.glide.request.transition.Transition; @@ -33,6 +32,7 @@ import org.thoughtcrime.securesms.connect.DcHelper; import org.thoughtcrime.securesms.contacts.avatars.ResourceContactPhoto; import org.thoughtcrime.securesms.mms.AttachmentManager; import org.thoughtcrime.securesms.mms.GlideApp; +import org.thoughtcrime.securesms.permissions.Permissions; import org.thoughtcrime.securesms.profiles.AvatarHelper; import org.thoughtcrime.securesms.scribbles.ScribbleActivity; import org.thoughtcrime.securesms.util.SelectedContactsAdapter; @@ -44,6 +44,8 @@ import java.io.File; import java.util.ArrayList; import java.util.Objects; +import chat.delta.rpc.RpcException; + public class GroupCreateActivity extends PassphraseRequiredActionBarActivity implements ItemClickListener { @@ -340,6 +342,12 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity return ret; } + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults); + } + @Override public void onActivityResult(int reqCode, int resultCode, final Intent data) { super.onActivityResult(reqCode, resultCode, data); diff --git a/src/main/java/org/thoughtcrime/securesms/InstantOnboardingActivity.java b/src/main/java/org/thoughtcrime/securesms/InstantOnboardingActivity.java index 275e515d8..a09c43bdb 100644 --- a/src/main/java/org/thoughtcrime/securesms/InstantOnboardingActivity.java +++ b/src/main/java/org/thoughtcrime/securesms/InstantOnboardingActivity.java @@ -34,8 +34,6 @@ import androidx.loader.app.LoaderManager; import com.b44t.messenger.DcContext; import com.b44t.messenger.DcEvent; import com.b44t.messenger.DcLot; -import com.b44t.messenger.rpc.Rpc; -import com.b44t.messenger.rpc.RpcException; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.request.target.CustomTarget; import com.bumptech.glide.request.transition.Transition; @@ -64,6 +62,9 @@ import java.io.IOException; import java.security.SecureRandom; import java.util.Objects; +import chat.delta.rpc.Rpc; +import chat.delta.rpc.RpcException; + public class InstantOnboardingActivity extends BaseActionBarActivity implements DcEventCenter.DcEventDelegate { private static final String TAG = InstantOnboardingActivity.class.getSimpleName(); @@ -89,7 +90,10 @@ public class InstantOnboardingActivity extends BaseActionBarActivity implements private AttachmentManager attachmentManager; private Bitmap avatarBmp; + private @Nullable ProgressDialog progressDialog; + private boolean cancelled; + private DcContext dcContext; @Override @@ -422,7 +426,6 @@ public class InstantOnboardingActivity extends BaseActionBarActivity implements } private void progressSuccess() { - DcHelper.getEventCenter(this).endCaptureNextError(); if (progressDialog != null) { progressDialog.dismiss(); } @@ -481,11 +484,14 @@ public class InstantOnboardingActivity extends BaseActionBarActivity implements progressDialog = null; } + cancelled = false; + progressDialog = new ProgressDialog(this); progressDialog.setMessage(getResources().getString(R.string.one_moment)); progressDialog.setCanceledOnTouchOutside(false); progressDialog.setCancelable(false); progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getResources().getString(android.R.string.cancel), (dialog, which) -> { + cancelled = true; dcContext.stopOngoingProcess(); }); progressDialog.show(); @@ -496,9 +502,13 @@ public class InstantOnboardingActivity extends BaseActionBarActivity implements Rpc rpc = DcHelper.getRpc(this); try { rpc.addTransportFromQr(dcContext.getAccountId(), qrCode); + DcHelper.getEventCenter(this).endCaptureNextError(); progressSuccess(); } catch (RpcException e) { - Util.runOnMain(() -> progressError(e.getMessage())); + DcHelper.getEventCenter(this).endCaptureNextError(); + if (!cancelled) { + Util.runOnMain(() -> progressError(e.getMessage())); + } } }).start(); } diff --git a/src/main/java/org/thoughtcrime/securesms/ProfileActivity.java b/src/main/java/org/thoughtcrime/securesms/ProfileActivity.java index b52cc913a..21b52f6fc 100644 --- a/src/main/java/org/thoughtcrime/securesms/ProfileActivity.java +++ b/src/main/java/org/thoughtcrime/securesms/ProfileActivity.java @@ -23,8 +23,6 @@ import com.b44t.messenger.DcChat; import com.b44t.messenger.DcContact; import com.b44t.messenger.DcContext; import com.b44t.messenger.DcEvent; -import com.b44t.messenger.rpc.Rpc; -import com.b44t.messenger.rpc.RpcException; import org.thoughtcrime.securesms.connect.DcEventCenter; import org.thoughtcrime.securesms.connect.DcHelper; @@ -36,6 +34,9 @@ import org.thoughtcrime.securesms.util.ViewUtil; import java.io.File; +import chat.delta.rpc.Rpc; +import chat.delta.rpc.RpcException; + public class ProfileActivity extends PassphraseRequiredActionBarActivity implements DcEventCenter.DcEventDelegate { @@ -109,7 +110,7 @@ public class ProfileActivity extends PassphraseRequiredActionBarActivity if (chatId != 0) { DcChat dcChat = dcContext.getChat(chatId); - menu.findItem(R.id.menu_clone).setVisible(chatIsMultiUser && !chatIsMailingList); + menu.findItem(R.id.menu_clone).setVisible(chatIsMultiUser && !chatIsInBroadcast && !chatIsMailingList); if (chatIsDeviceTalk) { menu.findItem(R.id.edit_name).setVisible(false); menu.findItem(R.id.show_encr_info).setVisible(false); diff --git a/src/main/java/org/thoughtcrime/securesms/ProfileAdapter.java b/src/main/java/org/thoughtcrime/securesms/ProfileAdapter.java index 5660880d5..ffd4d3c01 100644 --- a/src/main/java/org/thoughtcrime/securesms/ProfileAdapter.java +++ b/src/main/java/org/thoughtcrime/securesms/ProfileAdapter.java @@ -278,6 +278,7 @@ public class ProfileAdapter extends RecyclerView.Adapter itemDataStatusText = ""; isOutBroadcast = dcChat != null && dcChat.isOutBroadcast(); boolean isMailingList = dcChat != null && dcChat.isMailingList(); + boolean isInBroadcast = dcChat != null && dcChat.isInBroadcast(); boolean isSelfTalk = dcChat != null && dcChat.isSelfTalk(); boolean isDeviceTalk = dcChat != null && dcChat.isDeviceTalk(); memberCount = memberList!=null ? memberList.length : 0; @@ -311,7 +312,7 @@ public class ProfileAdapter extends RecyclerView.Adapter } */ - if (memberList!=null && !isMailingList) { + if (memberList!=null && !isInBroadcast && !isMailingList) { itemData.add(new ItemData(ITEM_DIVIDER, null, 0)); if (dcChat != null) { if (dcChat.canSend() && dcChat.isEncrypted()) { diff --git a/src/main/java/org/thoughtcrime/securesms/RegistrationActivity.java b/src/main/java/org/thoughtcrime/securesms/RegistrationActivity.java index 019cedd33..df6408066 100644 --- a/src/main/java/org/thoughtcrime/securesms/RegistrationActivity.java +++ b/src/main/java/org/thoughtcrime/securesms/RegistrationActivity.java @@ -46,9 +46,6 @@ import androidx.constraintlayout.widget.Group; import com.b44t.messenger.DcContext; import com.b44t.messenger.DcEvent; import com.b44t.messenger.DcProvider; -import com.b44t.messenger.rpc.EnteredLoginParam; -import com.b44t.messenger.rpc.Rpc; -import com.b44t.messenger.rpc.RpcException; import com.b44t.messenger.util.concurrent.ListenableFuture; import com.b44t.messenger.util.concurrent.SettableFuture; import com.google.android.material.textfield.TextInputEditText; @@ -66,6 +63,12 @@ import org.thoughtcrime.securesms.util.views.ProgressDialog; import java.lang.ref.WeakReference; import java.util.concurrent.ExecutionException; +import chat.delta.rpc.Rpc; +import chat.delta.rpc.RpcException; +import chat.delta.rpc.types.EnteredCertificateChecks; +import chat.delta.rpc.types.EnteredLoginParam; +import chat.delta.rpc.types.Socket; + public class RegistrationActivity extends BaseActionBarActivity implements DcEventCenter.DcEventDelegate { private enum VerificationType { @@ -87,6 +90,7 @@ public class RegistrationActivity extends BaseActionBarActivity implements DcEve private Group advancedGroup; private ImageView advancedIcon; private ProgressDialog progressDialog; + private boolean cancelled = false; Spinner imapSecurity; Spinner smtpSecurity; @@ -563,6 +567,7 @@ public class RegistrationActivity extends BaseActionBarActivity implements DcEve return; } + cancelled = false; setupConfig(); if (progressDialog != null) { @@ -574,7 +579,10 @@ public class RegistrationActivity extends BaseActionBarActivity implements DcEve progressDialog.setMessage(getString(R.string.one_moment)); progressDialog.setCanceledOnTouchOutside(false); progressDialog.setCancelable(false); - progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getString(android.R.string.cancel), (dialog, which) -> stopLoginProcess()); + progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getString(android.R.string.cancel), (dialog, which) -> { + cancelled = true; + DcHelper.getContext(this).stopOngoingProcess(); + }); progressDialog.show(); } @@ -584,24 +592,49 @@ public class RegistrationActivity extends BaseActionBarActivity implements DcEve && !passwordInput.getText().toString().isEmpty(); } + private EnteredCertificateChecks certificateChecksFromInt(int position) { + switch (position) { + case 0: + return EnteredCertificateChecks.automatic; + case 1: + return EnteredCertificateChecks.strict; + case 2: + return EnteredCertificateChecks.acceptInvalidCertificates; + } + throw new IllegalArgumentException("Invalid certificate position: " + position); + } + + public static Socket socketSecurityFromInt(int position) { + switch (position) { + case 0: + return Socket.automatic; + case 1: + return Socket.ssl; + case 2: + return Socket.starttls; + case 3: + return Socket.plain; + } + throw new IllegalArgumentException("Invalid socketSecurity position: " + position); + } + private void setupConfig() { DcHelper.getEventCenter(this).captureNextError(); - EnteredLoginParam param = new EnteredLoginParam( - getParam(R.id.email_text, true), - getParam(R.id.password_text, false), - getParam(R.id.imap_server_text, true), - Util.objectToInt(getParam(R.id.imap_port_text, true)), - EnteredLoginParam.socketSecurityFromInt(imapSecurity.getSelectedItemPosition()), - getParam(R.id.imap_login_text, false), - getParam(R.id.smtp_server_text, true), - Util.objectToInt(getParam(R.id.smtp_port_text, true)), - EnteredLoginParam.socketSecurityFromInt(smtpSecurity.getSelectedItemPosition()), - getParam(R.id.smtp_login_text, false), - getParam(R.id.smtp_password_text, false), - EnteredLoginParam.certificateChecksFromInt(certCheck.getSelectedItemPosition()), - authMethod.getSelectedItemPosition() == 1 - ); + EnteredLoginParam param = new EnteredLoginParam(); + param.addr = getParam(R.id.email_text, true); + param.password = getParam(R.id.password_text, false); + param.imapServer = getParam(R.id.imap_server_text, true); + param.imapPort = Util.objectToInt(getParam(R.id.imap_port_text, true)); + param.imapSecurity = socketSecurityFromInt(imapSecurity.getSelectedItemPosition()); + param.imapUser = getParam(R.id.imap_login_text, false); + param.smtpServer = getParam(R.id.smtp_server_text, true); + param.smtpPort = Util.objectToInt(getParam(R.id.smtp_port_text, true)); + param.smtpSecurity = socketSecurityFromInt(smtpSecurity.getSelectedItemPosition()); + param.smtpUser = getParam(R.id.smtp_login_text, false); + param.smtpPassword = getParam(R.id.smtp_password_text, false); + param.certificateChecks = certificateChecksFromInt(certCheck.getSelectedItemPosition()); + param.oauth2 = authMethod.getSelectedItemPosition() == 1; new Thread(() -> { Rpc rpc = DcHelper.getRpc(this); @@ -613,11 +646,13 @@ public class RegistrationActivity extends BaseActionBarActivity implements DcEve startActivity(conversationList); finish(); } catch (RpcException e) { - Util.runOnMain(() -> { - DcHelper.getEventCenter(this).endCaptureNextError(); - progressDialog.dismiss(); - WelcomeActivity.maybeShowConfigurationError(this, e.getMessage()); - }); + DcHelper.getEventCenter(this).endCaptureNextError(); + if (!cancelled) { + Util.runOnMain(() -> { + progressDialog.dismiss(); + WelcomeActivity.maybeShowConfigurationError(this, e.getMessage()); + }); + } } }).start(); } @@ -631,10 +666,6 @@ public class RegistrationActivity extends BaseActionBarActivity implements DcEve return value.isEmpty()? null : value; } - private void stopLoginProcess() { - DcHelper.getContext(this).stopOngoingProcess(); - } - @Override public void handleEvent(@NonNull DcEvent event) { if (event.getId()==DcContext.DC_EVENT_CONFIGURE_PROGRESS) { diff --git a/src/main/java/org/thoughtcrime/securesms/WebxdcActivity.java b/src/main/java/org/thoughtcrime/securesms/WebxdcActivity.java index 9fa79ed0c..4bf6b536b 100644 --- a/src/main/java/org/thoughtcrime/securesms/WebxdcActivity.java +++ b/src/main/java/org/thoughtcrime/securesms/WebxdcActivity.java @@ -38,8 +38,6 @@ import com.b44t.messenger.DcChat; import com.b44t.messenger.DcContext; import com.b44t.messenger.DcEvent; import com.b44t.messenger.DcMsg; -import com.b44t.messenger.rpc.Rpc; -import com.b44t.messenger.rpc.RpcException; import com.google.common.base.Charsets; import org.json.JSONObject; @@ -63,6 +61,9 @@ import java.util.HashMap; import java.util.Locale; import java.util.Map; +import chat.delta.rpc.Rpc; +import chat.delta.rpc.RpcException; + public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcEventDelegate { private static final String TAG = WebxdcActivity.class.getSimpleName(); private static final String EXTRA_ACCOUNT_ID = "accountId"; diff --git a/src/main/java/org/thoughtcrime/securesms/WebxdcStoreActivity.java b/src/main/java/org/thoughtcrime/securesms/WebxdcStoreActivity.java index 2bb90a7e4..fd95b3401 100644 --- a/src/main/java/org/thoughtcrime/securesms/WebxdcStoreActivity.java +++ b/src/main/java/org/thoughtcrime/securesms/WebxdcStoreActivity.java @@ -17,13 +17,11 @@ import android.widget.Toast; import androidx.appcompat.app.ActionBar; import com.b44t.messenger.DcContext; -import com.b44t.messenger.rpc.HttpResponse; -import com.b44t.messenger.rpc.Rpc; -import com.b44t.messenger.rpc.RpcException; import org.thoughtcrime.securesms.connect.DcHelper; import org.thoughtcrime.securesms.providers.PersistentBlobProvider; import org.thoughtcrime.securesms.util.IntentUtils; +import org.thoughtcrime.securesms.util.JsonUtils; import org.thoughtcrime.securesms.util.MediaUtil; import org.thoughtcrime.securesms.util.Prefs; import org.thoughtcrime.securesms.util.Util; @@ -31,6 +29,10 @@ import org.thoughtcrime.securesms.util.Util; import java.io.ByteArrayInputStream; import java.util.HashMap; +import chat.delta.rpc.Rpc; +import chat.delta.rpc.RpcException; +import chat.delta.rpc.types.HttpResponse; + public class WebxdcStoreActivity extends PassphraseRequiredActionBarActivity { private static final String TAG = WebxdcStoreActivity.class.getSimpleName(); @@ -59,7 +61,8 @@ public class WebxdcStoreActivity extends PassphraseRequiredActionBarActivity { Util.runOnAnyBackgroundThread(() -> { try { HttpResponse httpResponse = rpc.getHttpResponse(dcContext.getAccountId(), url); - Uri uri = PersistentBlobProvider.getInstance().create(WebxdcStoreActivity.this, httpResponse.getBlob(), "application/octet-stream", "app.xdc"); + byte[] blob = JsonUtils.decodeBase64(httpResponse.blob); + Uri uri = PersistentBlobProvider.getInstance().create(WebxdcStoreActivity.this, blob, "application/octet-stream", "app.xdc"); Intent intent = new Intent(); intent.setData(uri); setResult(Activity.RESULT_OK, intent); @@ -108,13 +111,14 @@ public class WebxdcStoreActivity extends PassphraseRequiredActionBarActivity { throw new Exception("no url specified"); } HttpResponse httpResponse = rpc.getHttpResponse(dcContext.getAccountId(), url); - String mimeType = httpResponse.getMimetype(); + String mimeType = httpResponse.mimetype; if (mimeType == null) { mimeType = "application/octet-stream"; } - ByteArrayInputStream data = new ByteArrayInputStream(httpResponse.getBlob()); - res = new WebResourceResponse(mimeType, httpResponse.getEncoding(), data); + byte[] blob = JsonUtils.decodeBase64(httpResponse.blob); + ByteArrayInputStream data = new ByteArrayInputStream(blob); + res = new WebResourceResponse(mimeType, httpResponse.encoding, data); } catch (Exception e) { e.printStackTrace(); ByteArrayInputStream data = new ByteArrayInputStream(("Could not load apps. Are you online?\n\n" + e.getMessage()).getBytes()); diff --git a/src/main/java/org/thoughtcrime/securesms/accounts/AccountSelectionListFragment.java b/src/main/java/org/thoughtcrime/securesms/accounts/AccountSelectionListFragment.java index dfa694c79..01f64f489 100644 --- a/src/main/java/org/thoughtcrime/securesms/accounts/AccountSelectionListFragment.java +++ b/src/main/java/org/thoughtcrime/securesms/accounts/AccountSelectionListFragment.java @@ -26,8 +26,6 @@ import com.b44t.messenger.DcAccounts; import com.b44t.messenger.DcContact; import com.b44t.messenger.DcContext; import com.b44t.messenger.DcEvent; -import com.b44t.messenger.rpc.Rpc; -import com.b44t.messenger.rpc.RpcException; import org.thoughtcrime.securesms.ConnectivityActivity; import org.thoughtcrime.securesms.ConversationListActivity; @@ -43,6 +41,9 @@ import org.thoughtcrime.securesms.util.ViewUtil; import java.util.Arrays; +import chat.delta.rpc.Rpc; +import chat.delta.rpc.RpcException; + public class AccountSelectionListFragment extends DialogFragment implements DcEventCenter.DcEventDelegate { private static final String TAG = AccountSelectionListFragment.class.getSimpleName(); diff --git a/src/main/java/org/thoughtcrime/securesms/calls/CallActivity.java b/src/main/java/org/thoughtcrime/securesms/calls/CallActivity.java new file mode 100644 index 000000000..d20eb88a7 --- /dev/null +++ b/src/main/java/org/thoughtcrime/securesms/calls/CallActivity.java @@ -0,0 +1,203 @@ +package org.thoughtcrime.securesms.calls; + +import android.Manifest; +import android.annotation.SuppressLint; +import android.content.Context; +import android.os.Bundle; +import android.text.TextUtils; +import android.util.Base64; +import android.util.Log; +import android.view.Menu; +import android.webkit.JavascriptInterface; +import android.webkit.PermissionRequest; +import android.webkit.WebChromeClient; +import android.webkit.WebSettings; + +import androidx.annotation.NonNull; + +import com.b44t.messenger.DcChat; +import com.b44t.messenger.DcContext; +import com.b44t.messenger.DcEvent; + +import org.thoughtcrime.securesms.R; +import org.thoughtcrime.securesms.WebViewActivity; +import org.thoughtcrime.securesms.connect.DcEventCenter; +import org.thoughtcrime.securesms.connect.DcHelper; +import org.thoughtcrime.securesms.permissions.Permissions; +import org.thoughtcrime.securesms.recipients.Recipient; +import org.thoughtcrime.securesms.util.AvatarUtil; +import org.thoughtcrime.securesms.util.Util; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.Objects; + +import chat.delta.rpc.Rpc; +import chat.delta.rpc.RpcException; + +public class CallActivity extends WebViewActivity implements DcEventCenter.DcEventDelegate { + private static final String TAG = CallActivity.class.getSimpleName(); + + public static final String EXTRA_ACCOUNT_ID = "acc_id"; + public static final String EXTRA_CHAT_ID = "chat_id"; + public static final String EXTRA_CALL_ID = "call_id"; + public static final String EXTRA_HASH = "hash"; + + private DcContext dcContext; + private Rpc rpc; + private int accId; + private int chatId; + private int callId; + private boolean ended = false; + + @SuppressLint("SetJavaScriptEnabled") + @Override + protected void onCreate(Bundle state, boolean ready) { + super.onCreate(state, ready); + + Bundle bundle = getIntent().getExtras(); + assert bundle != null; + String hash = bundle.getString(EXTRA_HASH, ""); + accId = bundle.getInt(EXTRA_ACCOUNT_ID, -1); + chatId = bundle.getInt(EXTRA_CHAT_ID, 0); + callId = bundle.getInt(EXTRA_CALL_ID, 0); + rpc = DcHelper.getRpc(this); + dcContext = DcHelper.getAccounts(this).getAccount(accId); + + DcHelper.getNotificationCenter(this).removeCallNotification(accId, callId); + + WebSettings webSettings = webView.getSettings(); + webSettings.setJavaScriptEnabled(true); + webSettings.setMediaPlaybackRequiresUserGesture(false); + webView.addJavascriptInterface(new InternalJSApi(), "calls"); + + webView.setWebChromeClient(new WebChromeClient() { + @Override + public void onPermissionRequest(PermissionRequest request) { + Util.runOnMain(() -> request.grant(request.getResources())); + } + }); + + DcEventCenter eventCenter = DcHelper.getEventCenter(getApplicationContext()); + eventCenter.addObserver(DcContext.DC_EVENT_OUTGOING_CALL_ACCEPTED, this); + eventCenter.addObserver(DcContext.DC_EVENT_CALL_ENDED, this); + + Util.runOnAnyBackgroundThread(() -> { + final DcChat chat = dcContext.getChat(chatId); + Util.runOnMain(() -> Objects.requireNonNull(getSupportActionBar()).setTitle(chat.getName())); + }); + + Permissions.with(this) + .request(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO) + .ifNecessary() + .withPermanentDenialDialog(getString(R.string.perm_explain_access_to_camera_denied)) + .onAllGranted(() -> { + String url = "file:///android_asset/calls/index.html"; + webView.loadUrl(url + hash); + }).onAnyDenied(this::finish) + .execute(); + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults); + } + + @Override + protected void onDestroy() { + DcHelper.getEventCenter(this).removeObservers(this); + if (callId != 0 && !ended) { + try { + rpc.endCall(accId, callId); + } catch (RpcException e) { + Log.e(TAG, "Error", e); + } + } + super.onDestroy(); + } + + @Override + public boolean onPrepareOptionsMenu(Menu menu) { + // do not call super.onPrepareOptionsMenu() as the default "Search" menu is not needed + return true; + } + + @Override + protected boolean openOnlineUrl(String url) { + finish(); + return true; + } + + @Override + public void handleEvent(@NonNull DcEvent event) { + switch (event.getId()) { + case DcContext.DC_EVENT_OUTGOING_CALL_ACCEPTED: + if (event.getData1Int() == callId) { + try { + String base64 = Base64.encodeToString(event.getData2Str().getBytes(StandardCharsets.UTF_8), Base64.NO_WRAP); + String hash = "#onAnswer=" + URLEncoder.encode(base64, "UTF-8"); + webView.evaluateJavascript("window.location.hash = `"+hash+"`", null); + } catch (UnsupportedEncodingException e) { + Log.e(TAG, "Error", e); + } + } + break; + case DcContext.DC_EVENT_CALL_ENDED: + if (event.getData1Int() == callId) { + ended = true; + finish(); + } + break; + } + } + + + class InternalJSApi { + @JavascriptInterface + public String getIceServers() { + try { + return rpc.iceServers(accId); + } catch (RpcException e) { + Log.e(TAG, "Error", e); + return null; + } + } + + @JavascriptInterface + public void startCall(String payload) { + try { + callId = rpc.placeOutgoingCall(accId, chatId, payload); + } catch (RpcException e) { + Log.e(TAG, "Error", e); + } + } + + @JavascriptInterface + public void acceptCall(String payload) { + try { + rpc.acceptIncomingCall(accId, callId, payload); + } catch (RpcException e) { + Log.e(TAG, "Error", e); + } + } + + @JavascriptInterface + public void endCall() { + finish(); + } + + @JavascriptInterface + public String getAvatar() { + final Context context = CallActivity.this; + final DcChat dcChat = dcContext.getChat(chatId); + if (!TextUtils.isEmpty(dcChat.getProfileImage())) { + return AvatarUtil.asDataUri(dcChat.getProfileImage()); + } else { + final Recipient recipient = new Recipient(context, dcChat); + return AvatarUtil.asDataUri(recipient.getFallbackAvatarDrawable(context, false)); + } + } + } +} diff --git a/src/main/java/org/thoughtcrime/securesms/calls/CallUtil.java b/src/main/java/org/thoughtcrime/securesms/calls/CallUtil.java new file mode 100644 index 000000000..f84e2385b --- /dev/null +++ b/src/main/java/org/thoughtcrime/securesms/calls/CallUtil.java @@ -0,0 +1,60 @@ +package org.thoughtcrime.securesms.calls; + +import android.Manifest; +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.util.Base64; +import android.util.Log; + +import org.thoughtcrime.securesms.R; +import org.thoughtcrime.securesms.connect.DcHelper; +import org.thoughtcrime.securesms.permissions.Permissions; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; + +public class CallUtil { + private static final String TAG = CallUtil.class.getSimpleName(); + + public static void startCall(Activity activity, int chatId) { + Permissions.with(activity) + .request(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO) + .ifNecessary() + .withPermanentDenialDialog(activity.getString(R.string.perm_explain_access_to_camera_denied)) + .onAllGranted(() -> { + int accId = DcHelper.getContext(activity).getAccountId(); + startCall(activity, accId, chatId); + }) + .execute(); + } + + public static void startCall(Context context, int accId, int chatId) { + Intent intent = new Intent(context, CallActivity.class); + intent.setAction(Intent.ACTION_VIEW); + intent.putExtra(CallActivity.EXTRA_ACCOUNT_ID, accId); + intent.putExtra(CallActivity.EXTRA_CHAT_ID, chatId); + intent.putExtra(CallActivity.EXTRA_HASH, "#startCall"); + context.startActivity(intent); + } + + public static void openCall(Context context, int accId, int chatId, int callId, String payload) { + String base64 = Base64.encodeToString(payload.getBytes(StandardCharsets.UTF_8), Base64.NO_WRAP); + String hash = ""; + try { + hash = "#offerIncomingCall=" + URLEncoder.encode(base64, "UTF-8"); + } catch (UnsupportedEncodingException e) { + Log.e(TAG, "Error", e); + } + + Intent intent = new Intent(context, CallActivity.class); + intent.setAction(Intent.ACTION_VIEW); + intent.putExtra(CallActivity.EXTRA_ACCOUNT_ID, accId); + intent.putExtra(CallActivity.EXTRA_CHAT_ID, chatId); + intent.putExtra(CallActivity.EXTRA_CALL_ID, callId); + intent.putExtra(CallActivity.EXTRA_HASH, hash); + context.startActivity(intent); + } + +} diff --git a/src/main/java/org/thoughtcrime/securesms/components/AttachmentTypeSelector.java b/src/main/java/org/thoughtcrime/securesms/components/AttachmentTypeSelector.java index 9750cddef..a31d60f31 100644 --- a/src/main/java/org/thoughtcrime/securesms/components/AttachmentTypeSelector.java +++ b/src/main/java/org/thoughtcrime/securesms/components/AttachmentTypeSelector.java @@ -35,19 +35,17 @@ public class AttachmentTypeSelector extends PopupWindow { public static final int ADD_GALLERY = 1; public static final int ADD_DOCUMENT = 2; - public static final int INVITE_VIDEO_CHAT = 3; - public static final int ADD_CONTACT_INFO = 4; - public static final int TAKE_PHOTO = 5; - public static final int ADD_LOCATION = 6; - public static final int RECORD_VIDEO = 7; - public static final int ADD_WEBXDC = 8; + public static final int ADD_CONTACT_INFO = 3; + public static final int TAKE_PHOTO = 4; + public static final int ADD_LOCATION = 5; + public static final int RECORD_VIDEO = 6; + public static final int ADD_WEBXDC = 7; private static final int ANIMATION_DURATION = 300; private final @NonNull LoaderManager loaderManager; private final @NonNull RecentPhotoViewRail recentRail; private final @NonNull ImageView imageButton; - private final @NonNull ImageView videoChatButton; private final @NonNull ImageView documentButton; private final @NonNull ImageView contactButton; //private final @NonNull ImageView cameraButton; @@ -70,7 +68,6 @@ public class AttachmentTypeSelector extends PopupWindow { this.chatId = chatId; this.recentRail = ViewUtil.findById(layout, R.id.recent_photos); this.imageButton = ViewUtil.findById(layout, R.id.gallery_button); - this.videoChatButton = ViewUtil.findById(layout, R.id.invite_video_chat_button); this.documentButton = ViewUtil.findById(layout, R.id.document_button); this.contactButton = ViewUtil.findById(layout, R.id.contact_button); //this.cameraButton = ViewUtil.findById(layout, R.id.camera_button); @@ -79,7 +76,6 @@ public class AttachmentTypeSelector extends PopupWindow { this.webxdcButton = ViewUtil.findById(layout, R.id.webxdc_button); this.imageButton.setOnClickListener(new PropagatingClickListener(ADD_GALLERY)); - this.videoChatButton.setOnClickListener(new PropagatingClickListener(INVITE_VIDEO_CHAT)); this.documentButton.setOnClickListener(new PropagatingClickListener(ADD_DOCUMENT)); this.contactButton.setOnClickListener(new PropagatingClickListener(ADD_CONTACT_INFO)); //this.cameraButton.setOnClickListener(new PropagatingClickListener(TAKE_PHOTO)); @@ -137,7 +133,6 @@ public class AttachmentTypeSelector extends PopupWindow { animateButtonIn(locationButton, ANIMATION_DURATION / 4); animateButtonIn(documentButton, ANIMATION_DURATION / 4); animateButtonIn(webxdcButton, 0); - animateButtonIn(videoChatButton, 0); } @Override diff --git a/src/main/java/org/thoughtcrime/securesms/components/CallItemView.java b/src/main/java/org/thoughtcrime/securesms/components/CallItemView.java new file mode 100644 index 000000000..a66f54790 --- /dev/null +++ b/src/main/java/org/thoughtcrime/securesms/components/CallItemView.java @@ -0,0 +1,103 @@ +package org.thoughtcrime.securesms.components; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Color; +import android.util.AttributeSet; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; + +import org.thoughtcrime.securesms.R; + +import chat.delta.rpc.types.CallInfo; +import chat.delta.rpc.types.CallState; + +public class CallItemView extends FrameLayout { + private static final String TAG = CallItemView.class.getSimpleName(); + + private final @NonNull ImageView icon; + private final @NonNull TextView title; + private final @NonNull ConversationItemFooter footer; + private CallInfo callInfo; + private CallClickListener viewListener; + + public CallItemView(Context context) { + this(context, null); + } + + public CallItemView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public CallItemView(final Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + inflate(context, R.layout.call_item_view, this); + + this.icon = findViewById(R.id.call_icon); + this.title = findViewById(R.id.title); + this.footer = findViewById(R.id.footer); + + setOnClickListener(v -> { + if (viewListener != null && callInfo != null) { + viewListener.onClick(v, callInfo); + } + }); + } + + public void setCallClickListener(CallClickListener listener) { + viewListener = listener; + } + + public void setCallItem(boolean isOutgoing, CallInfo callInfo) { + this.callInfo = callInfo; + if (callInfo.state instanceof CallState.Completed) { + footer.setCallDuration(((CallState.Completed) callInfo.state).duration); + } else { + footer.setCallDuration(0); // reset + } + + if (callInfo.state instanceof CallState.Missed) { + title.setText(R.string.missed_call); + } else if (callInfo.state instanceof CallState.Canceled) { + title.setText(R.string.canceled_call); + } else if (callInfo.state instanceof CallState.Declined) { + title.setText(R.string.declined_call); + } else { + title.setText(isOutgoing? R.string.outgoing_call : R.string.incoming_call); + } + + int[] attrs; + if (isOutgoing) { + attrs = new int[]{ + R.attr.conversation_item_outgoing_text_primary_color, + R.attr.conversation_item_outgoing_text_secondary_color, + }; + } else { + attrs = new int[]{ + R.attr.conversation_item_incoming_text_primary_color, + R.attr.conversation_item_incoming_text_secondary_color, + }; + } + try (TypedArray ta = getContext().obtainStyledAttributes(attrs)) { + icon.setColorFilter(ta.getColor(0, Color.BLACK)); + footer.setTextColor(ta.getColor(1, Color.BLACK)); + } + } + + public ConversationItemFooter getFooter() { + return footer; + } + + public String getDescription() { + return title.getText() + "\n" + footer.getDescription(); + } + + public interface CallClickListener { + void onClick(View v, CallInfo callInfo); + } +} diff --git a/src/main/java/org/thoughtcrime/securesms/components/ConversationItemFooter.java b/src/main/java/org/thoughtcrime/securesms/components/ConversationItemFooter.java index 8caa030f8..ffc6906ac 100644 --- a/src/main/java/org/thoughtcrime/securesms/components/ConversationItemFooter.java +++ b/src/main/java/org/thoughtcrime/securesms/components/ConversationItemFooter.java @@ -26,6 +26,7 @@ public class ConversationItemFooter extends LinearLayout { private ImageView locationIndicatorView; private DeliveryStatusView deliveryStatusView; private Integer textColor = null; + private int callDuration = 0; public ConversationItemFooter(Context context) { super(context); @@ -54,12 +55,16 @@ public class ConversationItemFooter extends LinearLayout { if (attrs != null) { try (TypedArray typedArray = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.ConversationItemFooter, 0, 0)) { - textColor = typedArray.getInt(R.styleable.ConversationItemFooter_footer_text_color, getResources().getColor(R.color.core_white)); - setTextColor(textColor); + setTextColor(typedArray.getInt(R.styleable.ConversationItemFooter_footer_text_color, getResources().getColor(R.color.core_white))); } } } + /* Call duration in seconds. Only >0 if this is a call message */ + public void setCallDuration(int duration) { + callDuration = duration; + } + public void setMessageRecord(@NonNull DcMsg messageRecord) { presentDate(messageRecord); boolean bookmark = messageRecord.getOriginalMsgId() != 0 || messageRecord.getSavedMsgId() != 0; @@ -77,7 +82,8 @@ public class ConversationItemFooter extends LinearLayout { presentDeliveryStatus(messageRecord); } - private void setTextColor(int color) { + public void setTextColor(int color) { + textColor = color; dateView.setTextColor(color); editedView.setTextColor(color); bookmarkIndicatorView.setColorFilter(color); @@ -86,18 +92,29 @@ public class ConversationItemFooter extends LinearLayout { deliveryStatusView.setTint(color); } - private void presentDate(@NonNull DcMsg messageRecord) { + private void presentDate(@NonNull DcMsg dcMsg) { dateView.forceLayout(); - dateView.setText(DateUtils.getExtendedRelativeTimeSpanString(getContext(), messageRecord.getTimestamp())); + Context context = getContext(); + String date = dcMsg.getType() == DcMsg.DC_MSG_CALL? + DateUtils.getExtendedTimeSpanString(context, dcMsg.getTimestamp()) + : DateUtils.getExtendedRelativeTimeSpanString(context, dcMsg.getTimestamp()); + if (callDuration > 0) { + String duration = DateUtils.getFormattedCallDuration(context, callDuration); + dateView.setText(context.getString(R.string.call_date_and_duration, date, duration)); + } else { + dateView.setText(date); + } } private void presentDeliveryStatus(@NonNull DcMsg messageRecord) { // isDownloading is temporary and should be checked first. boolean isDownloading = messageRecord.getDownloadState() == DcMsg.DC_DOWNLOAD_IN_PROGRESS; + boolean isCall = messageRecord.getType() == DcMsg.DC_MSG_CALL; if (isDownloading) deliveryStatusView.setDownloading(); + else if (messageRecord.isPending()) deliveryStatusView.setPending(); else if (messageRecord.isFailed()) deliveryStatusView.setFailed(); - else if (!messageRecord.isOutgoing()) deliveryStatusView.setNone(); + else if (!messageRecord.isOutgoing() || isCall) deliveryStatusView.setNone(); else if (messageRecord.isRemoteRead()) deliveryStatusView.setRead(); else if (messageRecord.isDelivered()) deliveryStatusView.setSent(); else if (messageRecord.isPreparing()) deliveryStatusView.setPreparing(); diff --git a/src/main/java/org/thoughtcrime/securesms/components/QuoteView.java b/src/main/java/org/thoughtcrime/securesms/components/QuoteView.java index 609590a9c..c40cd8a22 100644 --- a/src/main/java/org/thoughtcrime/securesms/components/QuoteView.java +++ b/src/main/java/org/thoughtcrime/securesms/components/QuoteView.java @@ -19,8 +19,6 @@ import androidx.annotation.Nullable; import com.b44t.messenger.DcContact; import com.b44t.messenger.DcMsg; -import com.b44t.messenger.rpc.RpcException; -import com.b44t.messenger.rpc.VcardContact; import com.bumptech.glide.load.engine.DiskCacheStrategy; import org.json.JSONObject; @@ -41,6 +39,9 @@ import org.thoughtcrime.securesms.util.Util; import java.util.List; +import chat.delta.rpc.RpcException; +import chat.delta.rpc.types.VcardContact; + public class QuoteView extends FrameLayout implements RecipientForeverObserver { private static final String TAG = QuoteView.class.getSimpleName(); diff --git a/src/main/java/org/thoughtcrime/securesms/components/VcardView.java b/src/main/java/org/thoughtcrime/securesms/components/VcardView.java index 36b8e84b5..8a9ce5f1c 100644 --- a/src/main/java/org/thoughtcrime/securesms/components/VcardView.java +++ b/src/main/java/org/thoughtcrime/securesms/components/VcardView.java @@ -9,16 +9,16 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.b44t.messenger.rpc.Rpc; -import com.b44t.messenger.rpc.RpcException; -import com.b44t.messenger.rpc.VcardContact; - import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.mms.SlideClickListener; import org.thoughtcrime.securesms.mms.VcardSlide; import org.thoughtcrime.securesms.recipients.Recipient; +import chat.delta.rpc.Rpc; +import chat.delta.rpc.RpcException; +import chat.delta.rpc.types.VcardContact; + public class VcardView extends FrameLayout { private static final String TAG = VcardView.class.getSimpleName(); @@ -60,8 +60,8 @@ public class VcardView extends FrameLayout { public void setVcard(@NonNull GlideRequests glideRequests, final @NonNull VcardSlide slide, final @NonNull Rpc rpc) { try { VcardContact vcardContact = rpc.parseVcard(slide.asAttachment().getRealPath(getContext())).get(0); - name.setText(vcardContact.getDisplayName()); - address.setText(vcardContact.getAddr()); + name.setText(vcardContact.displayName); + address.setText(vcardContact.addr); avatar.setAvatar(glideRequests, new Recipient(getContext(), vcardContact), false); this.slide = slide; } catch (RpcException e) { diff --git a/src/main/java/org/thoughtcrime/securesms/components/reminder/DozeReminder.java b/src/main/java/org/thoughtcrime/securesms/components/reminder/DozeReminder.java index a6bcab74c..611dc8a6b 100644 --- a/src/main/java/org/thoughtcrime/securesms/components/reminder/DozeReminder.java +++ b/src/main/java/org/thoughtcrime/securesms/components/reminder/DozeReminder.java @@ -109,18 +109,9 @@ public class DozeReminder { } } - private static boolean isAllChatmail() { - for (int accountId : ApplicationContext.dcAccounts.getAll()) { - DcContext context = ApplicationContext.dcAccounts.getAccount(accountId); - if (!context.isChatmail()) { - return false; - } - } - return true; - } - private static boolean isPushAvailableAndSufficient() { - return isAllChatmail() && FcmReceiveService.getToken() != null; + return ApplicationContext.dcAccounts.isAllChatmail() + && FcmReceiveService.getToken() != null; } public static void maybeAskDirectly(Context context) { diff --git a/src/main/java/org/thoughtcrime/securesms/connect/AccountManager.java b/src/main/java/org/thoughtcrime/securesms/connect/AccountManager.java index 070a8fc0a..2a0fbf5a1 100644 --- a/src/main/java/org/thoughtcrime/securesms/connect/AccountManager.java +++ b/src/main/java/org/thoughtcrime/securesms/connect/AccountManager.java @@ -13,8 +13,6 @@ import androidx.preference.PreferenceManager; import com.b44t.messenger.DcAccounts; import com.b44t.messenger.DcContext; -import com.b44t.messenger.rpc.Rpc; -import com.b44t.messenger.rpc.RpcException; import org.thoughtcrime.securesms.ApplicationContext; import org.thoughtcrime.securesms.ConversationListActivity; @@ -24,6 +22,9 @@ import org.thoughtcrime.securesms.accounts.AccountSelectionListFragment; import java.io.File; +import chat.delta.rpc.Rpc; +import chat.delta.rpc.RpcException; + public class AccountManager { private static final String TAG = AccountManager.class.getSimpleName(); diff --git a/src/main/java/org/thoughtcrime/securesms/connect/DcEventCenter.java b/src/main/java/org/thoughtcrime/securesms/connect/DcEventCenter.java index 41abd0567..4262dbd6c 100644 --- a/src/main/java/org/thoughtcrime/securesms/connect/DcEventCenter.java +++ b/src/main/java/org/thoughtcrime/securesms/connect/DcEventCenter.java @@ -183,6 +183,15 @@ public class DcEventCenter { DcHelper.getNotificationCenter(context).notifyWebxdc(accountId, event.getData1Int(), event.getData2Int(), event.getData2Str()); break; + case DcContext.DC_EVENT_INCOMING_CALL: + DcHelper.getNotificationCenter(context).notifyCall(accountId, event.getData1Int(), event.getData2Str()); + break; + + case DcContext.DC_EVENT_INCOMING_CALL_ACCEPTED: + case DcContext.DC_EVENT_CALL_ENDED: + DcHelper.getNotificationCenter(context).removeCallNotification(accountId, event.getData1Int()); + break; + case DcContext.DC_EVENT_MSGS_NOTICED: DcHelper.getNotificationCenter(context).removeNotifications(accountId, event.getData1Int()); break; diff --git a/src/main/java/org/thoughtcrime/securesms/connect/DcHelper.java b/src/main/java/org/thoughtcrime/securesms/connect/DcHelper.java index f9e505138..f30d131df 100644 --- a/src/main/java/org/thoughtcrime/securesms/connect/DcHelper.java +++ b/src/main/java/org/thoughtcrime/securesms/connect/DcHelper.java @@ -22,8 +22,6 @@ import com.b44t.messenger.DcChat; import com.b44t.messenger.DcContext; import com.b44t.messenger.DcLot; import com.b44t.messenger.DcMsg; -import com.b44t.messenger.rpc.Rpc; -import com.b44t.messenger.rpc.RpcException; import org.thoughtcrime.securesms.ApplicationContext; import org.thoughtcrime.securesms.BuildConfig; @@ -43,6 +41,9 @@ import java.io.File; import java.util.Date; import java.util.HashMap; +import chat.delta.rpc.Rpc; +import chat.delta.rpc.RpcException; + public class DcHelper { private static final String TAG = DcHelper.class.getSimpleName(); @@ -69,16 +70,12 @@ public class DcHelper { public static final String CONFIG_BCC_SELF = "bcc_self"; public static final String CONFIG_SHOW_EMAILS = "show_emails"; public static final String CONFIG_MEDIA_QUALITY = "media_quality"; - public static final String CONFIG_WEBRTC_INSTANCE = "webrtc_instance"; public static final String CONFIG_PROXY_ENABLED = "proxy_enabled"; public static final String CONFIG_PROXY_URL = "proxy_url"; public static final String CONFIG_VERIFIED_ONE_ON_ONE_CHATS = "verified_one_on_one_chats"; public static final String CONFIG_WEBXDC_REALTIME_ENABLED = "webxdc_realtime_enabled"; public static final String CONFIG_PRIVATE_TAG = "private_tag"; - public static final String DEFAULT_VIDEOCHAT_URL_PREFIX = "https://meet.systemli.org/"; - public static final String DEFAULT_VIDEOCHAT_URL = DEFAULT_VIDEOCHAT_URL_PREFIX + "$ROOM#config.prejoinConfig.enabled=false&config.notifications=[]&config.toolbarButtons=[%22microphone%22,%22camera%22,%22hangup%22]"; - public static DcContext getContext(@NonNull Context context) { return ApplicationContext.getInstance(context).dcContext; } @@ -247,6 +244,11 @@ public class DcHelper { dcContext.setStockTranslation(177, context.getString(R.string.reaction_by_other)); dcContext.setStockTranslation(190, context.getString(R.string.secure_join_wait)); dcContext.setStockTranslation(193, context.getString(R.string.donate_device_msg)); + dcContext.setStockTranslation(194, context.getString(R.string.outgoing_call)); + dcContext.setStockTranslation(195, context.getString(R.string.incoming_call)); + dcContext.setStockTranslation(196, context.getString(R.string.declined_call)); + dcContext.setStockTranslation(197, context.getString(R.string.canceled_call)); + dcContext.setStockTranslation(198, context.getString(R.string.missed_call)); } public static File getImexDir() { @@ -411,14 +413,6 @@ public class DcHelper { } - public static String getVideochatURL(DcContext dcContext) { - String instance = dcContext.getConfig(DcHelper.CONFIG_WEBRTC_INSTANCE); - if (instance != null && !instance.isEmpty()) { - return instance; - } - return DEFAULT_VIDEOCHAT_URL; - } - @NonNull public static ThreadRecord getThreadRecord(Context context, DcLot summary, DcChat chat) { // adapted from ThreadDatabase.getCurrent() int chatId = chat.getId(); diff --git a/src/main/java/org/thoughtcrime/securesms/contacts/avatars/VcardContactPhoto.java b/src/main/java/org/thoughtcrime/securesms/contacts/avatars/VcardContactPhoto.java index 36fac9f10..a15fbc697 100644 --- a/src/main/java/org/thoughtcrime/securesms/contacts/avatars/VcardContactPhoto.java +++ b/src/main/java/org/thoughtcrime/securesms/contacts/avatars/VcardContactPhoto.java @@ -6,7 +6,7 @@ import android.net.Uri; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.b44t.messenger.rpc.VcardContact; +import org.thoughtcrime.securesms.util.JsonUtils; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -14,6 +14,8 @@ import java.io.InputStream; import java.nio.ByteBuffer; import java.security.MessageDigest; +import chat.delta.rpc.types.VcardContact; + public class VcardContactPhoto implements ContactPhoto { private final VcardContact vContact; @@ -23,7 +25,7 @@ public class VcardContactPhoto implements ContactPhoto { @Override public InputStream openInputStream(Context context) throws IOException { - byte[] blob = vContact.getProfileImage(); + byte[] blob = JsonUtils.decodeBase64(vContact.profileImage); return (blob == null)? null : new ByteArrayInputStream(blob); } @@ -39,7 +41,7 @@ public class VcardContactPhoto implements ContactPhoto { @Override public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) { - messageDigest.update(vContact.getAddr().getBytes()); - messageDigest.update(ByteBuffer.allocate(4).putFloat(vContact.getTimestamp()).array()); + messageDigest.update(vContact.addr.getBytes()); + messageDigest.update(ByteBuffer.allocate(4).putFloat(vContact.timestamp).array()); } } diff --git a/src/main/java/org/thoughtcrime/securesms/mms/AttachmentManager.java b/src/main/java/org/thoughtcrime/securesms/mms/AttachmentManager.java index c3dbd0e65..24d05b5bb 100644 --- a/src/main/java/org/thoughtcrime/securesms/mms/AttachmentManager.java +++ b/src/main/java/org/thoughtcrime/securesms/mms/AttachmentManager.java @@ -40,7 +40,6 @@ import androidx.appcompat.app.AlertDialog; import com.b44t.messenger.DcContext; import com.b44t.messenger.DcMsg; -import com.b44t.messenger.rpc.RpcException; import com.b44t.messenger.util.concurrent.ListenableFuture; import com.b44t.messenger.util.concurrent.ListenableFuture.Listener; import com.b44t.messenger.util.concurrent.SettableFuture; @@ -78,6 +77,8 @@ import java.util.LinkedList; import java.util.List; import java.util.concurrent.ExecutionException; +import chat.delta.rpc.RpcException; + public class AttachmentManager { diff --git a/src/main/java/org/thoughtcrime/securesms/notifications/DeclineCallReceiver.java b/src/main/java/org/thoughtcrime/securesms/notifications/DeclineCallReceiver.java new file mode 100644 index 000000000..d0ef72426 --- /dev/null +++ b/src/main/java/org/thoughtcrime/securesms/notifications/DeclineCallReceiver.java @@ -0,0 +1,41 @@ +package org.thoughtcrime.securesms.notifications; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.util.Log; + +import org.thoughtcrime.securesms.connect.DcHelper; +import org.thoughtcrime.securesms.util.Util; + +import chat.delta.rpc.RpcException; + +public class DeclineCallReceiver extends BroadcastReceiver { + private static final String TAG = DeclineCallReceiver.class.getSimpleName(); + + public static final String DECLINE_ACTION = "org.thoughtcrime.securesms.notifications.DECLINE_CALL"; + public static final String ACCOUNT_ID_EXTRA = "account_id"; + public static final String CALL_ID_EXTRA = "call_id"; + + @Override + public void onReceive(final Context context, Intent intent) { + if (!DECLINE_ACTION.equals(intent.getAction())) { + return; + } + + final int accountId = intent.getIntExtra(ACCOUNT_ID_EXTRA, 0); + final int callId = intent.getIntExtra(CALL_ID_EXTRA, 0); + if (accountId == 0) { + return; + } + + Util.runOnAnyBackgroundThread(() -> { + DcHelper.getNotificationCenter(context).removeCallNotification(accountId, callId); + try { + DcHelper.getRpc(context).endCall(accountId, callId); + } catch (RpcException e) { + Log.e(TAG, "Error", e); + } + }); + } +} diff --git a/src/main/java/org/thoughtcrime/securesms/notifications/NotificationCenter.java b/src/main/java/org/thoughtcrime/securesms/notifications/NotificationCenter.java index cfbc520c5..e6a83198d 100644 --- a/src/main/java/org/thoughtcrime/securesms/notifications/NotificationCenter.java +++ b/src/main/java/org/thoughtcrime/securesms/notifications/NotificationCenter.java @@ -13,9 +13,11 @@ import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.media.AudioAttributes; +import android.media.RingtoneManager; import android.net.Uri; import android.os.Build; import android.text.TextUtils; +import android.util.Base64; import android.util.Log; import androidx.annotation.NonNull; @@ -47,8 +49,12 @@ import org.thoughtcrime.securesms.util.JsonUtils; import org.thoughtcrime.securesms.util.Pair; import org.thoughtcrime.securesms.util.Prefs; import org.thoughtcrime.securesms.util.Util; +import org.thoughtcrime.securesms.calls.CallActivity; +import java.io.UnsupportedEncodingException; import java.math.BigInteger; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.util.ArrayList; import java.util.HashMap; @@ -158,6 +164,41 @@ public class NotificationCenter { return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | IntentUtils.FLAG_MUTABLE()); } + public PendingIntent getOpenCallIntent(ChatData chatData, int callId, String payload, boolean autoAccept) { + final Intent chatIntent = new Intent(context, ConversationActivity.class) + .putExtra(ConversationActivity.ACCOUNT_ID_EXTRA, chatData.accountId) + .putExtra(ConversationActivity.CHAT_ID_EXTRA, chatData.chatId) + .setAction(Intent.ACTION_VIEW); + + String base64 = Base64.encodeToString(payload.getBytes(StandardCharsets.UTF_8), Base64.NO_WRAP); + String hash = ""; + try { + hash = (autoAccept? "#acceptCall=" : "#offerIncomingCall=") + URLEncoder.encode(base64, "UTF-8"); + } catch (UnsupportedEncodingException e) { + Log.e(TAG, "Error", e); + } + + Intent intent = new Intent(context, CallActivity.class); + intent.setAction(autoAccept? Intent.ACTION_ANSWER : Intent.ACTION_VIEW); + intent.putExtra(CallActivity.EXTRA_ACCOUNT_ID, chatData.accountId); + intent.putExtra(CallActivity.EXTRA_CHAT_ID, chatData.chatId); + intent.putExtra(CallActivity.EXTRA_CALL_ID, callId); + intent.putExtra(CallActivity.EXTRA_HASH, hash); + intent.setPackage(context.getPackageName()); + return TaskStackBuilder.create(context) + .addNextIntentWithParentStack(chatIntent) + .addNextIntent(intent) + .getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT | IntentUtils.FLAG_MUTABLE()); + } + + public PendingIntent getDeclineCallIntent(ChatData chatData, int callId) { + Intent intent = new Intent(DeclineCallReceiver.DECLINE_ACTION); + intent.setClass(context, DeclineCallReceiver.class); + intent.putExtra(DeclineCallReceiver.ACCOUNT_ID_EXTRA, chatData.accountId); + intent.putExtra(DeclineCallReceiver.CALL_ID_EXTRA, callId); + intent.setPackage(context.getPackageName()); + return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | IntentUtils.FLAG_MUTABLE()); + } // Groups and Notification channel groups // -------------------------------------------------------------------------------------------- @@ -202,6 +243,7 @@ public class NotificationCenter { public static final String CH_MSG_VERSION = "5"; public static final String CH_PERMANENT = "dc_foreground_notification_ch"; public static final String CH_GENERIC = "ch_generic"; + public static final String CH_CALLS_PREFIX = "call_chan"; private boolean notificationChannelsSupported() { return Build.VERSION.SDK_INT >= 26; @@ -333,10 +375,107 @@ public class NotificationCenter { return channelId; } + public String getCallNotificationChannel(NotificationManagerCompat notificationManager, ChatData chatData, String name) { + String channelId = CH_CALLS_PREFIX + "-" + chatData.accountId + "-"+ chatData.chatId; + + if (notificationChannelsSupported()) { + try { + name = "(calls) " + name; + + // check if there is already a channel with the given name + List channels = notificationManager.getNotificationChannels(); + boolean channelExists = false; + for (int i = 0; i < channels.size(); i++) { + String currChannelId = channels.get(i).getId(); + if (currChannelId.startsWith(CH_CALLS_PREFIX)) { + // this is one of the calls channels handled here ... + if (currChannelId.equals(channelId)) { + // ... this is the actually required channel, fine :) + // update the name to reflect localize changes and chat renames + channelExists = true; + channels.get(i).setName(name); + } + } + } + + // create a the channel + if(!channelExists) { + NotificationChannel channel = new NotificationChannel(channelId, name, NotificationManager.IMPORTANCE_MAX); + channel.setDescription("Informs about incoming calls."); + channel.setShowBadge(true); + + Uri ringtone = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE); + channel.setSound(ringtone, new AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE) + .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) + .build()); + notificationManager.createNotificationChannel(channel); + } + } catch(Exception e) { + Log.e(TAG, "Error in getCallNotificationChannel()", e); + } + } + + return channelId; + } + // add notifications & co. // -------------------------------------------------------------------------------------------- + public void notifyCall(int accId, int callId, String payload) { + Util.runOnAnyBackgroundThread(() -> { + NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context); + DcContext dcContext = context.dcAccounts.getAccount(accId); + int chatId = dcContext.getMsg(callId).getChatId(); + DcChat dcChat = dcContext.getChat(chatId); + String name = dcChat.getName(); + ChatData chatData = new ChatData(accId, chatId); + String notificationChannel = getCallNotificationChannel(notificationManager, chatData, name); + + PendingIntent declineCallIntent = getDeclineCallIntent(chatData, callId); + PendingIntent openCallIntent = getOpenCallIntent(chatData, callId, payload, false); + + NotificationCompat.Builder builder = new NotificationCompat.Builder(context, notificationChannel) + .setSmallIcon(R.drawable.icon_notification) + .setColor(context.getResources().getColor(R.color.def_accent)) + .setPriority(NotificationCompat.PRIORITY_HIGH) + .setCategory(NotificationCompat.CATEGORY_CALL) + .setOngoing(true) + .setOnlyAlertOnce(false) + .setTicker(name) + .setContentTitle(name) + .setFullScreenIntent(openCallIntent, true) + .setContentIntent(openCallIntent) + .setContentText("Incoming Call"); + + builder.addAction( + new NotificationCompat.Action.Builder( + R.drawable.baseline_call_end_24, + context.getString(R.string.end_call), + declineCallIntent).build()); + + builder.addAction( + new NotificationCompat.Action.Builder( + R.drawable.baseline_call_24, + context.getString(R.string.answer_call), + getOpenCallIntent(chatData, callId, payload, true)).build()); + + Bitmap bitmap = getAvatar(dcChat); + if (bitmap != null) { + builder.setLargeIcon(bitmap); + } + + Notification notif = builder.build(); + notif.flags = notif.flags | Notification.FLAG_INSISTENT; + try { + notificationManager.notify("call-" + accId, callId, notif); + } catch (Exception e) { + Log.e(TAG, "cannot add notification", e); + } + }); + } + public void notifyMessage(int accountId, int chatId, int msgId) { Util.runOnAnyBackgroundThread(() -> { DcContext dcContext = context.dcAccounts.getAccount(accountId); @@ -495,31 +634,11 @@ public class NotificationCenter { } // set avatar - Recipient recipient = new Recipient(context, dcChat); if (privacy.isDisplayContact()) { - try { - Drawable drawable; - ContactPhoto contactPhoto = recipient.getContactPhoto(context); - if (contactPhoto != null) { - drawable = GlideApp.with(context.getApplicationContext()) - .load(contactPhoto) - .diskCacheStrategy(DiskCacheStrategy.NONE) - .circleCrop() - .submit(context.getResources().getDimensionPixelSize(android.R.dimen.notification_large_icon_width), - context.getResources().getDimensionPixelSize(android.R.dimen.notification_large_icon_height)) - .get(); - - } else { - drawable = recipient.getFallbackContactPhoto().asDrawable(context, recipient.getFallbackAvatarColor()); - } - if (drawable != null) { - int wh = context.getResources().getDimensionPixelSize(R.dimen.contact_photo_target_size); - Bitmap bitmap = BitmapUtil.createFromDrawable(drawable, wh, wh); - if (bitmap != null) { - builder.setLargeIcon(bitmap); - } - } - } catch (Exception e) { Log.w(TAG, e); } + Bitmap bitmap = getAvatar(dcChat); + if (bitmap != null) { + builder.setLargeIcon(bitmap); + } } // add buttons that allow some actions without opening ArcaneChat. @@ -619,6 +738,40 @@ public class NotificationCenter { } } + public Bitmap getAvatar(DcChat dcChat) { + Recipient recipient = new Recipient(context, dcChat); + try { + Drawable drawable; + ContactPhoto contactPhoto = recipient.getContactPhoto(context); + if (contactPhoto != null) { + drawable = GlideApp.with(context.getApplicationContext()) + .load(contactPhoto) + .diskCacheStrategy(DiskCacheStrategy.NONE) + .circleCrop() + .submit(context.getResources().getDimensionPixelSize(android.R.dimen.notification_large_icon_width), + context.getResources().getDimensionPixelSize(android.R.dimen.notification_large_icon_height)) + .get(); + + } else { + drawable = recipient.getFallbackContactPhoto().asDrawable(context, recipient.getFallbackAvatarColor()); + } + if (drawable != null) { + int wh = context.getResources().getDimensionPixelSize(R.dimen.contact_photo_target_size); + return BitmapUtil.createFromDrawable(drawable, wh, wh); + } + } catch (Exception e) { Log.w(TAG, e); } + + return null; + } + + public void removeCallNotification(int accountId, int callId) { + try { + NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context); + String tag = "call-" + accountId; + notificationManager.cancel(tag, callId); + } catch (Exception e) { Log.w(TAG, e); } + } + public void removeNotifications(int accountId, int chatId) { boolean removeSummary; synchronized (inboxes) { @@ -692,7 +845,7 @@ public class NotificationCenter { } } - private static class ChatData { + public static class ChatData { public final int accountId; public final int chatId; diff --git a/src/main/java/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java b/src/main/java/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java index c4204b6d0..9edc4370b 100644 --- a/src/main/java/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java +++ b/src/main/java/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java @@ -27,8 +27,6 @@ import androidx.preference.CheckBoxPreference; import androidx.preference.ListPreference; import androidx.preference.Preference; -import com.b44t.messenger.rpc.RpcException; - import org.thoughtcrime.securesms.ApplicationPreferencesActivity; import org.thoughtcrime.securesms.ConversationActivity; import org.thoughtcrime.securesms.LogViewActivity; @@ -49,6 +47,8 @@ import java.io.InputStream; import java.io.OutputStream; import java.util.Objects; +import chat.delta.rpc.RpcException; + public class AdvancedPreferenceFragment extends ListSummaryPreferenceFragment implements DcEventCenter.DcEventDelegate @@ -132,12 +132,6 @@ public class AdvancedPreferenceFragment extends ListSummaryPreferenceFragment submitDebugLog.setOnPreferenceClickListener(new ViewLogListener()); } - Preference webrtcInstance = this.findPreference("pref_webrtc_instance"); - if (webrtcInstance != null) { - webrtcInstance.setOnPreferenceClickListener(new WebrtcInstanceListener()); - } - updateWebrtcSummary(); - Preference webxdcStore = this.findPreference(Prefs.WEBXDC_STORE_URL_PREF); if (webxdcStore != null) { webxdcStore.setOnPreferenceClickListener(new WebxdcStoreUrlListener()); @@ -259,29 +253,6 @@ public class AdvancedPreferenceFragment extends ListSummaryPreferenceFragment } } - private class WebrtcInstanceListener implements Preference.OnPreferenceClickListener { - @Override - public boolean onPreferenceClick(@NonNull Preference preference) { - View gl = View.inflate(requireActivity(), R.layout.single_line_input, null); - EditText inputField = gl.findViewById(R.id.input_field); - inputField.setHint(R.string.videochat_instance_placeholder); - inputField.setText(DcHelper.getVideochatURL(dcContext)); - inputField.setSelection(inputField.getText().length()); - inputField.setInputType(TYPE_TEXT_VARIATION_URI); - new AlertDialog.Builder(requireActivity()) - .setTitle(R.string.videochat_instance) - .setMessage(getString(R.string.videochat_instance_explain_2)+"\n\n"+getString(R.string.videochat_instance_example)) - .setView(gl) - .setNegativeButton(android.R.string.cancel, null) - .setPositiveButton(android.R.string.ok, (dialog, which) -> { - dcContext.setConfig(DcHelper.CONFIG_WEBRTC_INSTANCE, inputField.getText().toString()); - updateWebrtcSummary(); - }) - .show(); - return true; - } - } - private class WebxdcStoreUrlListener implements Preference.OnPreferenceClickListener { @Override public boolean onPreferenceClick(@NonNull Preference preference) { @@ -305,13 +276,6 @@ public class AdvancedPreferenceFragment extends ListSummaryPreferenceFragment } } - private void updateWebrtcSummary() { - Preference webrtcInstance = this.findPreference("pref_webrtc_instance"); - if (webrtcInstance != null) { - webrtcInstance.setSummary(DcHelper.getVideochatURL(dcContext)); - } - } - private void updateWebxdcStoreSummary() { Preference preference = this.findPreference(Prefs.WEBXDC_STORE_URL_PREF); if (preference != null) { diff --git a/src/main/java/org/thoughtcrime/securesms/preferences/NotificationsPreferenceFragment.java b/src/main/java/org/thoughtcrime/securesms/preferences/NotificationsPreferenceFragment.java index 2356e89d0..e6e282cd7 100644 --- a/src/main/java/org/thoughtcrime/securesms/preferences/NotificationsPreferenceFragment.java +++ b/src/main/java/org/thoughtcrime/securesms/preferences/NotificationsPreferenceFragment.java @@ -28,9 +28,10 @@ import org.thoughtcrime.securesms.ApplicationPreferencesActivity; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.connect.DcHelper; import org.thoughtcrime.securesms.connect.KeepAliveService; +import org.thoughtcrime.securesms.notifications.FcmReceiveService; import org.thoughtcrime.securesms.util.Prefs; -public class NotificationsPreferenceFragment extends ListSummaryPreferenceFragment { +public class NotificationsPreferenceFragment extends ListSummaryPreferenceFragment implements Preference.OnPreferenceChangeListener { private static final String TAG = NotificationsPreferenceFragment.class.getSimpleName(); private static final int REQUEST_CODE_NOTIFICATION_SELECTED = 1; @@ -38,6 +39,7 @@ public class NotificationsPreferenceFragment extends ListSummaryPreferenceFragme private CheckBoxPreference ignoreBattery; private CheckBoxPreference notificationsEnabled; private CheckBoxPreference mentionNotifEnabled; + private CheckBoxPreference reliableService; @Override public void onCreate(Bundle paramBundle) { @@ -85,18 +87,12 @@ public class NotificationsPreferenceFragment extends ListSummaryPreferenceFragme } - CheckBoxPreference reliableService = this.findPreference("pref_reliable_service"); + // reliableService is just used for displaying the actual value + // of the reliable service preference that is managed via + // Prefs.setReliableService() and Prefs.reliableService() + reliableService = this.findPreference("pref_reliable_service2"); if (reliableService != null) { - reliableService.setOnPreferenceChangeListener((preference, newValue) -> { - Context context = getContext(); - boolean enabled = (Boolean) newValue; // Prefs.reliableService() still has the old value - if (enabled) { - KeepAliveService.startSelf(context); - } else { - context.stopService(new Intent(context, KeepAliveService.class)); - } - return true; - }); + reliableService.setOnPreferenceChangeListener(this); } notificationsEnabled = this.findPreference("pref_enable_notifications"); @@ -104,6 +100,7 @@ public class NotificationsPreferenceFragment extends ListSummaryPreferenceFragme notificationsEnabled.setOnPreferenceChangeListener((preference, newValue) -> { boolean enabled = (Boolean) newValue; dcContext.setMuted(!enabled); + notificationsEnabled.setSummary(getSummary(getContext(), false)); return true; }); } @@ -131,7 +128,13 @@ public class NotificationsPreferenceFragment extends ListSummaryPreferenceFragme // update ignoreBattery in onResume() to reflects changes done in the system settings ignoreBattery.setChecked(isIgnoringBatteryOptimizations()); notificationsEnabled.setChecked(!dcContext.isMuted()); + notificationsEnabled.setSummary(getSummary(getContext(), false)); mentionNotifEnabled.setChecked(dcContext.isMentionsEnabled()); + + // set without altering "unset" state of the preference + reliableService.setOnPreferenceChangeListener(null); + reliableService.setChecked(Prefs.reliableService(getActivity())); + reliableService.setOnPreferenceChangeListener(this); } @Override @@ -150,6 +153,20 @@ public class NotificationsPreferenceFragment extends ListSummaryPreferenceFragme } } + @Override + public boolean onPreferenceChange(@NonNull Preference preference, Object newValue) { + Context context = getContext(); + boolean enabled = (Boolean) newValue; + Prefs.setReliableService(context, enabled); + if (enabled) { + KeepAliveService.startSelf(context); + } else { + context.stopService(new Intent(context, KeepAliveService.class)); + } + notificationsEnabled.setSummary(getSummary(context, false)); + return true; + } + private class RingtoneSummaryListener implements Preference.OnPreferenceChangeListener { @Override public boolean onPreferenceChange(@NonNull Preference preference, Object newValue) { @@ -226,11 +243,21 @@ public class NotificationsPreferenceFragment extends ListSummaryPreferenceFragme } public static CharSequence getSummary(Context context) { + return getSummary(context, true); + } + + public static CharSequence getSummary(Context context, boolean detailed) { NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU || notificationManager.areNotificationsEnabled()) { - return context.getString(DcHelper.getContext(context).isMuted() ? R.string.off : R.string.on); + if (DcHelper.getContext(context).isMuted()) { + return detailed? context.getString(R.string.off) : ""; + } + if (FcmReceiveService.getToken() == null && !Prefs.reliableService(context)) { + return "⚠️ " + context.getString(R.string.unreliable_bg_notifications); + } + return detailed? context.getString(R.string.on) : ""; } else { - return context.getString(R.string.disabled_in_system_settings); + return "⚠️ " + context.getString(R.string.disabled_in_system_settings); } } } diff --git a/src/main/java/org/thoughtcrime/securesms/reactions/AddReactionView.java b/src/main/java/org/thoughtcrime/securesms/reactions/AddReactionView.java index 6754bba62..0662fc29f 100644 --- a/src/main/java/org/thoughtcrime/securesms/reactions/AddReactionView.java +++ b/src/main/java/org/thoughtcrime/securesms/reactions/AddReactionView.java @@ -13,16 +13,19 @@ import androidx.emoji2.emojipicker.EmojiPickerView; import com.b44t.messenger.DcContact; import com.b44t.messenger.DcContext; import com.b44t.messenger.DcMsg; -import com.b44t.messenger.rpc.Reactions; -import com.b44t.messenger.rpc.Rpc; -import com.b44t.messenger.rpc.RpcException; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.connect.DcHelper; import org.thoughtcrime.securesms.util.ViewUtil; +import java.util.Collections; +import java.util.List; import java.util.Map; +import chat.delta.rpc.Rpc; +import chat.delta.rpc.RpcException; +import chat.delta.rpc.types.Reactions; + public class AddReactionView extends LinearLayout { private AppCompatTextView[] defaultReactionViews; private AppCompatTextView anyReactionView; @@ -66,7 +69,6 @@ public class AddReactionView extends LinearLayout { init(); // init delayed as needed if ( msgToReactTo.isInfo() - || msgToReactTo.getType() == DcMsg.DC_MSG_VIDEOCHAT_INVITATION || !dcContext.getChat(msgToReactTo.getChatId()).canSend()) { return; } @@ -123,12 +125,12 @@ public class AddReactionView extends LinearLayout { private String getSelfReaction() { String result = null; try { - final Reactions reactions = rpc.getMsgReactions(dcContext.getAccountId(), msgToReactTo.getId()); + final Reactions reactions = rpc.getMessageReactions(dcContext.getAccountId(), msgToReactTo.getId()); if (reactions != null) { - final Map reactionsByContact = reactions.getReactionsByContact(); - final String [] selfReactions = reactionsByContact.get(DcContact.DC_CONTACT_ID_SELF); - if (selfReactions != null && selfReactions.length > 0) { - result = selfReactions[0]; + final Map> reactionsByContact = reactions.reactionsByContact; + final List selfReactions = reactionsByContact.get(String.valueOf(DcContact.DC_CONTACT_ID_SELF)); + if (selfReactions != null && !selfReactions.isEmpty()) { + result = selfReactions.get(0); } } } catch(RpcException e) { @@ -175,9 +177,9 @@ public class AddReactionView extends LinearLayout { private void sendReaction(final String reaction) { try { if (reaction == null || reaction.equals(getSelfReaction())) { - rpc.sendReaction(dcContext.getAccountId(), msgToReactTo.getId(), ""); + rpc.sendReaction(dcContext.getAccountId(), msgToReactTo.getId(), Collections.singletonList("")); } else { - rpc.sendReaction(dcContext.getAccountId(), msgToReactTo.getId(), reaction); + rpc.sendReaction(dcContext.getAccountId(), msgToReactTo.getId(), Collections.singletonList(reaction)); } } catch(Exception e) { e.printStackTrace(); diff --git a/src/main/java/org/thoughtcrime/securesms/reactions/ReactionsConversationView.java b/src/main/java/org/thoughtcrime/securesms/reactions/ReactionsConversationView.java index 8000de338..4c23426ea 100644 --- a/src/main/java/org/thoughtcrime/securesms/reactions/ReactionsConversationView.java +++ b/src/main/java/org/thoughtcrime/securesms/reactions/ReactionsConversationView.java @@ -14,14 +14,14 @@ import androidx.annotation.Nullable; import androidx.appcompat.widget.AppCompatTextView; import androidx.core.content.ContextCompat; -import com.b44t.messenger.rpc.Reaction; - import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.util.ViewUtil; import java.util.ArrayList; import java.util.List; +import chat.delta.rpc.types.Reaction; + public class ReactionsConversationView extends LinearLayout { // Normally 6dp, but we have 1dp left+right margin on the pills themselves @@ -80,10 +80,14 @@ public class ReactionsConversationView extends LinearLayout { int count = 0; boolean isFromSelf = false; for (int index = 2; index < reactions.size(); index++) { - count += reactions.get(index).getCount(); - isFromSelf = isFromSelf || reactions.get(index).isFromSelf(); + count += reactions.get(index).count; + isFromSelf = isFromSelf || reactions.get(index).isFromSelf; } - shortened.add(new Reaction(null, count, isFromSelf)); + Reaction reaction = new Reaction(); + reaction.emoji = null; + reaction.count = count; + reaction.isFromSelf = isFromSelf; + shortened.add(reaction); return shortened; } else { @@ -97,11 +101,11 @@ public class ReactionsConversationView extends LinearLayout { TextView countView = root.findViewById(R.id.reactions_pill_count); View spacer = root.findViewById(R.id.reactions_pill_spacer); - if (reaction.getEmoji() != null) { - emojiView.setText(reaction.getEmoji()); + if (reaction.emoji != null) { + emojiView.setText(reaction.emoji); - if (reaction.getCount() > 1) { - countView.setText(String.valueOf(reaction.getCount())); + if (reaction.count > 1) { + countView.setText(String.valueOf(reaction.count)); } else { countView.setVisibility(GONE); spacer.setVisibility(GONE); @@ -109,10 +113,10 @@ public class ReactionsConversationView extends LinearLayout { } else { emojiView.setVisibility(GONE); spacer.setVisibility(GONE); - countView.setText("+" + reaction.getCount()); + countView.setText("+" + reaction.count); } - if (reaction.isFromSelf()) { + if (reaction.isFromSelf) { root.setBackground(ContextCompat.getDrawable(context, R.drawable.reaction_pill_background_selected)); countView.setTextColor(ContextCompat.getColor(context, R.color.reaction_pill_text_color_selected)); } else { diff --git a/src/main/java/org/thoughtcrime/securesms/reactions/ReactionsDetailsFragment.java b/src/main/java/org/thoughtcrime/securesms/reactions/ReactionsDetailsFragment.java index f352cdb6f..7cc1a104e 100644 --- a/src/main/java/org/thoughtcrime/securesms/reactions/ReactionsDetailsFragment.java +++ b/src/main/java/org/thoughtcrime/securesms/reactions/ReactionsDetailsFragment.java @@ -16,9 +16,6 @@ import androidx.recyclerview.widget.RecyclerView; import com.b44t.messenger.DcContact; import com.b44t.messenger.DcContext; import com.b44t.messenger.DcEvent; -import com.b44t.messenger.rpc.Reactions; -import com.b44t.messenger.rpc.Rpc; -import com.b44t.messenger.rpc.RpcException; import org.thoughtcrime.securesms.ProfileActivity; import org.thoughtcrime.securesms.R; @@ -29,8 +26,14 @@ import org.thoughtcrime.securesms.util.Pair; import org.thoughtcrime.securesms.util.ViewUtil; import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.Map; +import chat.delta.rpc.Rpc; +import chat.delta.rpc.RpcException; +import chat.delta.rpc.types.Reactions; + public class ReactionsDetailsFragment extends DialogFragment implements DcEventCenter.DcEventDelegate { private static final String TAG = ReactionsDetailsFragment.class.getSimpleName(); @@ -87,14 +90,14 @@ public class ReactionsDetailsFragment extends DialogFragment implements DcEventC int accId = DcHelper.getContext(requireActivity()).getAccountId(); try { - final Reactions reactions = DcHelper.getRpc(requireActivity()).getMsgReactions(accId, msgId); + final Reactions reactions = DcHelper.getRpc(requireActivity()).getMessageReactions(accId, msgId); ArrayList> contactsReactions = new ArrayList<>(); if (reactions != null) { - Map reactionsByContact = reactions.getReactionsByContact(); - String[] selfReactions = reactionsByContact.remove(DcContact.DC_CONTACT_ID_SELF); - for (Integer contact: reactionsByContact.keySet()) { + Map> reactionsByContact = reactions.reactionsByContact; + List selfReactions = reactionsByContact.remove(String.valueOf(DcContact.DC_CONTACT_ID_SELF)); + for (String contact: reactionsByContact.keySet()) { for (String reaction: reactionsByContact.get(contact)) { - contactsReactions.add(new Pair<>(contact, reaction)); + contactsReactions.add(new Pair<>(Integer.parseInt(contact), reaction)); } } if (selfReactions != null) { @@ -118,12 +121,12 @@ public class ReactionsDetailsFragment extends DialogFragment implements DcEventC private String getSelfReaction(Rpc rpc, int accId) { String result = null; try { - final Reactions reactions = rpc.getMsgReactions(accId, msgId); + final Reactions reactions = rpc.getMessageReactions(accId, msgId); if (reactions != null) { - final Map reactionsByContact = reactions.getReactionsByContact(); - final String [] selfReactions = reactionsByContact.get(DcContact.DC_CONTACT_ID_SELF); - if (selfReactions != null && selfReactions.length > 0) { - result = selfReactions[0]; + final Map> reactionsByContact = reactions.reactionsByContact; + final List selfReactions = reactionsByContact.get(String.valueOf(DcContact.DC_CONTACT_ID_SELF)); + if (selfReactions != null && !selfReactions.isEmpty()) { + result = selfReactions.get(0); } } } catch(RpcException e) { @@ -139,9 +142,9 @@ public class ReactionsDetailsFragment extends DialogFragment implements DcEventC try { if (reaction == null || reaction.equals(getSelfReaction(rpc, accId))) { - rpc.sendReaction(accId, msgId, ""); + rpc.sendReaction(accId, msgId, Collections.singletonList("")); } else { - rpc.sendReaction(accId, msgId, reaction); + rpc.sendReaction(accId, msgId, Collections.singletonList(reaction)); } } catch(Exception e) { e.printStackTrace(); diff --git a/src/main/java/org/thoughtcrime/securesms/recipients/Recipient.java b/src/main/java/org/thoughtcrime/securesms/recipients/Recipient.java index 3942c3bd6..82aa6b29b 100644 --- a/src/main/java/org/thoughtcrime/securesms/recipients/Recipient.java +++ b/src/main/java/org/thoughtcrime/securesms/recipients/Recipient.java @@ -29,7 +29,6 @@ import androidx.annotation.Nullable; import com.b44t.messenger.DcChat; import com.b44t.messenger.DcContact; import com.b44t.messenger.DcContext; -import com.b44t.messenger.rpc.VcardContact; import org.thoughtcrime.securesms.connect.DcHelper; import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto; @@ -50,6 +49,8 @@ import java.util.HashSet; import java.util.Set; import java.util.WeakHashMap; +import chat.delta.rpc.types.VcardContact; + public class Recipient { private final Set listeners = Collections.newSetFromMap(new WeakHashMap()); @@ -149,7 +150,7 @@ public class Recipient { return dcContact.getDisplayName(); } else if(vContact!=null) { - return vContact.getDisplayName(); + return vContact.displayName; } return ""; } @@ -199,7 +200,7 @@ public class Recipient { rgb = dcContact.getColor(); } else if(vContact!=null) { - rgb = Color.parseColor(vContact.getColor()); + rgb = Color.parseColor(vContact.color); } return Color.argb(0xFF, Color.red(rgb), Color.green(rgb), Color.blue(rgb)); } @@ -235,7 +236,7 @@ public class Recipient { } } - if (vContact!=null && vContact.hasProfileImage()) { + if (vContact!=null && vContact.profileImage != null) { return new VcardContactPhoto(vContact); } diff --git a/src/main/java/org/thoughtcrime/securesms/util/AvatarUtil.java b/src/main/java/org/thoughtcrime/securesms/util/AvatarUtil.java new file mode 100644 index 000000000..fd85c17d0 --- /dev/null +++ b/src/main/java/org/thoughtcrime/securesms/util/AvatarUtil.java @@ -0,0 +1,51 @@ +package org.thoughtcrime.securesms.util; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.drawable.Drawable; +import android.util.Base64; + +import java.io.ByteArrayOutputStream; + +public class AvatarUtil { + + /** + * convert image path to data URI. + * + * @param filePath File path to image + * @return data URI like "data:image/jpeg;base64,..." + */ + public static String asDataUri(String filePath) { + Bitmap bitmap = BitmapFactory.decodeFile(filePath); + if (bitmap == null) return null; + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + bitmap.compress(Bitmap.CompressFormat.JPEG, 90, baos); + byte[] bytes = baos.toByteArray(); + String base64 = Base64.encodeToString(bytes, Base64.NO_WRAP); + return "data:image/jpeg;base64," + base64; + } + + /** + * convert Drawable to data URI. + * + * @param drawable avatar image as Drawable + * @return data URI like "data:image/png;base64,..." + */ + public static String asDataUri(Drawable drawable) { + int w = Math.max(1, drawable.getIntrinsicWidth()); + int h = Math.max(1, drawable.getIntrinsicHeight()); + Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + drawable.setBounds(0, 0, w, h); + drawable.draw(canvas); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + bitmap.compress(Bitmap.CompressFormat.JPEG, 90, baos); + byte[] bytes = baos.toByteArray(); + String base64 = Base64.encodeToString(bytes, Base64.NO_WRAP); + return "data:image/jpeg;base64," + base64; + } + +} diff --git a/src/main/java/org/thoughtcrime/securesms/util/DateUtils.java b/src/main/java/org/thoughtcrime/securesms/util/DateUtils.java index 14c6cdf33..0a99bf7e1 100644 --- a/src/main/java/org/thoughtcrime/securesms/util/DateUtils.java +++ b/src/main/java/org/thoughtcrime/securesms/util/DateUtils.java @@ -119,6 +119,15 @@ public class DateUtils extends android.text.format.DateUtils { TimeUnit.MILLISECONDS.toSeconds(millis-(TimeUnit.MILLISECONDS.toMinutes(millis)*60000))); } + public static String getFormattedCallDuration(Context c, int seconds) { + if (seconds < 60) { + return c.getResources().getQuantityString(R.plurals.n_seconds_ext, seconds, seconds); + } + + int mins = seconds / 60; + return c.getResources().getQuantityString(R.plurals.n_minutes_ext, mins, mins); + } + public static String getFormattedTimespan(Context c, int timestamp) { int mins = timestamp / (1000 * 60); if (mins / 60 == 0) { diff --git a/src/main/java/org/thoughtcrime/securesms/util/JsonUtils.java b/src/main/java/org/thoughtcrime/securesms/util/JsonUtils.java index e21b04ba3..c248527ad 100644 --- a/src/main/java/org/thoughtcrime/securesms/util/JsonUtils.java +++ b/src/main/java/org/thoughtcrime/securesms/util/JsonUtils.java @@ -1,5 +1,7 @@ package org.thoughtcrime.securesms.util; +import android.util.Base64; + import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; @@ -21,6 +23,13 @@ public class JsonUtils { objectMapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING); } + public static byte[] decodeBase64(String base64) { + if (base64 == null) { + return null; + } + return Base64.decode(base64, Base64.NO_WRAP | Base64.NO_PADDING); + } + public static T fromJson(byte[] serialized, Class clazz) throws IOException { return fromJson(new String(serialized), clazz); } diff --git a/src/main/java/org/thoughtcrime/securesms/util/Prefs.java b/src/main/java/org/thoughtcrime/securesms/util/Prefs.java index cff0d9f66..a6432c034 100644 --- a/src/main/java/org/thoughtcrime/securesms/util/Prefs.java +++ b/src/main/java/org/thoughtcrime/securesms/util/Prefs.java @@ -12,10 +12,12 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.app.NotificationCompat; +import com.b44t.messenger.DcAccounts; import com.b44t.messenger.DcContext; import org.thoughtcrime.securesms.BuildConfig; import org.thoughtcrime.securesms.connect.DcHelper; +import org.thoughtcrime.securesms.notifications.FcmReceiveService; import org.thoughtcrime.securesms.preferences.widgets.NotificationPrivacyPreference; import java.util.ArrayList; @@ -28,6 +30,7 @@ public class Prefs { private static final String TAG = Prefs.class.getSimpleName(); + public static final String RELIABLE_SERVICE_PREF = "pref_reliable_service"; public static final String DISABLE_PASSPHRASE_PREF = "pref_disable_passphrase"; public static final String THEME_PREF = "pref_theme"; public static final String BACKGROUND_PREF = "pref_chat_background"; @@ -171,6 +174,11 @@ public class Prefs { return true; } + + public static boolean isCallsEnabled(Context context) { + return true; + } + // ringtone public static @NonNull Uri getNotificationRingtone(Context context) { @@ -207,13 +215,20 @@ public class Prefs { return result==null? null : Uri.parse(result); } + public static void setReliableService(Context context, boolean value) { + setBooleanPreference(context, RELIABLE_SERVICE_PREF, value); + } + public static boolean reliableService(Context context) { - try { - return getBooleanPreference(context, "pref_reliable_service", false); - } - catch(Exception e) { - return false; + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + if (prefs.contains(RELIABLE_SERVICE_PREF)) { + try { + return prefs.getBoolean(RELIABLE_SERVICE_PREF, true); + } catch(Exception e) {} } + + // if the key was unset, then calculate default value + return !isPushEnabled(context) || !DcHelper.getAccounts(context).isAllChatmail(); } // vibrate diff --git a/src/main/java/org/thoughtcrime/securesms/videochat/VideochatActivity.java b/src/main/java/org/thoughtcrime/securesms/videochat/VideochatActivity.java deleted file mode 100644 index ca80ffd97..000000000 --- a/src/main/java/org/thoughtcrime/securesms/videochat/VideochatActivity.java +++ /dev/null @@ -1,68 +0,0 @@ -package org.thoughtcrime.securesms.videochat; - -import android.os.Bundle; -import android.view.Menu; -import android.webkit.PermissionRequest; -import android.webkit.WebChromeClient; -import android.webkit.WebSettings; - -import com.b44t.messenger.DcChat; -import com.b44t.messenger.DcContext; - -import org.thoughtcrime.securesms.WebViewActivity; -import org.thoughtcrime.securesms.connect.DcHelper; -import org.thoughtcrime.securesms.util.Util; - -public class VideochatActivity extends WebViewActivity { - private static final String TAG = VideochatActivity.class.getSimpleName(); - - public static final String EXTRA_CHAT_ID = "chat_id"; - public static final String EXTRA_URL = "url"; - - private DcContext dcContext; - private String url = ""; - - @Override - protected void onCreate(Bundle state, boolean ready) { - super.onCreate(state, ready); - this.dcContext = DcHelper.getContext(getApplicationContext()); - - Bundle b = getIntent().getExtras(); - url = b.getString(EXTRA_URL, ""); - int chatId = b.getInt(EXTRA_CHAT_ID, 0); - - WebSettings webSettings = webView.getSettings(); - webSettings.setJavaScriptEnabled(true); - webSettings.setUserAgentString("Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36"); - - webView.setWebChromeClient(new WebChromeClient() { - @Override - public void onPermissionRequest(PermissionRequest request) { - Util.runOnMain(() -> { - request.grant(request.getResources()); - }); - } - }); - - Util.runOnAnyBackgroundThread(() -> { - final DcChat chat = dcContext.getChat(chatId); - Util.runOnMain(() -> { - getSupportActionBar().setTitle(chat.getName()); - }); - }); - - webView.loadUrl(url); - } - - @Override - public boolean onPrepareOptionsMenu(Menu menu) { - // do not call super.onPrepareOptionsMenu() as the default "Search" menu is not needed - return true; - } - - @Override - protected boolean openOnlineUrl(String url) { - finish(); - return true; - } -} diff --git a/src/main/java/org/thoughtcrime/securesms/videochat/VideochatUtil.java b/src/main/java/org/thoughtcrime/securesms/videochat/VideochatUtil.java deleted file mode 100644 index 8b0cd046a..000000000 --- a/src/main/java/org/thoughtcrime/securesms/videochat/VideochatUtil.java +++ /dev/null @@ -1,77 +0,0 @@ -package org.thoughtcrime.securesms.videochat; - -import android.Manifest; -import android.app.Activity; -import android.content.Intent; - -import androidx.appcompat.app.AlertDialog; - -import com.b44t.messenger.DcChat; -import com.b44t.messenger.DcContext; -import com.b44t.messenger.DcMsg; - -import org.thoughtcrime.securesms.R; -import org.thoughtcrime.securesms.connect.DcHelper; -import org.thoughtcrime.securesms.permissions.Permissions; - -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; - -public class VideochatUtil { - - public void invite(Activity activity, int chatId) { - DcContext dcContext = DcHelper.getContext(activity); - DcChat dcChat = dcContext.getChat(chatId); - - new AlertDialog.Builder(activity) - .setTitle(activity.getString(R.string.videochat_invite_user_to_videochat, dcChat.getName())) - .setMessage(R.string.videochat_invite_user_hint) - .setNegativeButton(R.string.cancel, null) - .setPositiveButton(R.string.ok, (dialog, which) -> { - String instance = dcContext.getConfig(DcHelper.CONFIG_WEBRTC_INSTANCE); - boolean unset = instance == null || instance.isEmpty(); - if (unset) { - dcContext.setConfig(DcHelper.CONFIG_WEBRTC_INSTANCE, DcHelper.DEFAULT_VIDEOCHAT_URL); - } - - int msgId = dcContext.sendVideochatInvitation(dcChat.getId()); - - if (unset) { - dcContext.setConfig(DcHelper.CONFIG_WEBRTC_INSTANCE, null); - } - - if (msgId != 0) { - join(activity, msgId); - } - }) - .show(); - } - - public void join(Activity activity, int msgId) { - Permissions.with(activity) - .request(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO) - .ifNecessary() - .withPermanentDenialDialog(activity.getString(R.string.perm_explain_access_to_camera_denied)) - .onAllGranted(() -> { - DcContext dcContext = DcHelper.getContext(activity); - DcMsg dcMsg = dcContext.getMsg(msgId); - String url = dcMsg.getVideochatUrl(); - if (url.startsWith(DcHelper.DEFAULT_VIDEOCHAT_URL_PREFIX) && url.contains("#")) { - String name = dcContext.getName(); - try { - name = URLEncoder.encode(dcContext.getName(), StandardCharsets.UTF_8.toString()); - } catch (UnsupportedEncodingException ignored) {} - url += "&userInfo.displayName=%22" + name +"%22"; - } - - Intent intent = new Intent(activity, VideochatActivity.class); - intent.setAction(Intent.ACTION_VIEW); - intent.putExtra(VideochatActivity.EXTRA_CHAT_ID, dcMsg.getChatId()); - intent.putExtra(VideochatActivity.EXTRA_URL, url); - activity.startActivity(intent); - }) - .execute(); - } - -} diff --git a/src/main/res/drawable/baseline_call_end_24.xml b/src/main/res/drawable/baseline_call_end_24.xml new file mode 100644 index 000000000..fa4cd2c10 --- /dev/null +++ b/src/main/res/drawable/baseline_call_end_24.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/src/main/res/layout/attachment_type_selector.xml b/src/main/res/layout/attachment_type_selector.xml index 69668c4ab..03f3c1f7d 100644 --- a/src/main/res/layout/attachment_type_selector.xml +++ b/src/main/res/layout/attachment_type_selector.xml @@ -161,30 +161,6 @@ - - - - - - - - + + + + + + + + + + + + + diff --git a/src/main/res/layout/conversation_item_call.xml b/src/main/res/layout/conversation_item_call.xml new file mode 100644 index 000000000..15a28934f --- /dev/null +++ b/src/main/res/layout/conversation_item_call.xml @@ -0,0 +1,9 @@ + + diff --git a/src/main/res/layout/conversation_item_received.xml b/src/main/res/layout/conversation_item_received.xml index 12b5c0f97..f75a035ae 100644 --- a/src/main/res/layout/conversation_item_received.xml +++ b/src/main/res/layout/conversation_item_received.xml @@ -172,6 +172,16 @@ android:layout_marginLeft="@dimen/message_bubble_horizontal_padding" android:layout_marginRight="@dimen/message_bubble_horizontal_padding" /> + + + + - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/main/res/layout/media_preview_activity.xml b/src/main/res/layout/media_preview_activity.xml index b151df949..002a571f3 100644 --- a/src/main/res/layout/media_preview_activity.xml +++ b/src/main/res/layout/media_preview_activity.xml @@ -3,6 +3,7 @@ + + منح إحدى الأذونات مطلو استمر - - رسالة مشفرة - اختر اللغة… الملف تعديل diff --git a/src/main/res/values-az/strings.xml b/src/main/res/values-az/strings.xml index 36e2aec07..d1ef54f43 100644 --- a/src/main/res/values-az/strings.xml +++ b/src/main/res/values-az/strings.xml @@ -396,10 +396,6 @@ %1$silə əlaqə qurmaq üçün bunu skan edin İnternet bağlantısı yoxdur, QR kodunu qura bilmir. %1$s yoxlanıldı. - - %1$sDoğrula bilmir - - %1$süçün quraşdırma dəyişdirildi Cavab ver Yeni mesaj @@ -417,9 +413,6 @@ Delta Chat yer əlavə etmək üçün yer icazə tələb edir, lakin daimi olaraq rədd edilmişdir. \"İcazələr\"-i seçin və\"Yerləşmə\" izni verin. Delta Chat, fotoşəkilləri, videoları və ya səsləri əlavə etmək və ya ixrac etmək üçün saxlama icazəsini tələb edir, lakin bu daimi olaraq rədd edildi. Xahiş edirik tətbiq ayarları menyusuna davam edin, \"İzinlər\" seçin və \"Yaddaş\" funksiyasını aktivləşdirin. Delta Chat yer əlavə etmək üçün yer icazə tələb edir, lakin daimi olaraq rədd edilmişdir. \"İcazələr\"-i seçin və\"Yerləşmə\" izni verin. - - Şifrələnmiş mesaj - Dil səç Fayl Çıxış diff --git a/src/main/res/values-bg/strings.xml b/src/main/res/values-bg/strings.xml index 7cdd0eec9..02d04ce26 100644 --- a/src/main/res/values-bg/strings.xml +++ b/src/main/res/values-bg/strings.xml @@ -199,19 +199,7 @@ Нов чат Нова група Клониране на чат - - Списък за разпространение - - Списъци за разпространение - - Нов списък за разпространение Добавяне на получатели - - Редактиране на списък за разпространение - - Име на списък за разпространение - - Моля, въведете име за списъка за разпространение Изпращане Включване/изключване на Emoji клавиатура Редактиране на група @@ -343,8 +331,6 @@ Чат с %1$s? Премахване на %1$s от групата? - - Да бъдат ли премахнати %1$s от списъка за разпространение? Искате ли да отворите тази връзка? @@ -374,8 +360,6 @@ Изпращане на съобщение до %1$s. - - Получателите в един списък за разпространение получават съобщения в чат \"само за четене\" с Вас. Другите ще виждат тази група едва след като изпратите първо съобщение. Приплъзнете, за да откажете Докоснете и задръжте, за да запишете гласово съобщение, отпуснете, за да го изпратите @@ -473,11 +457,6 @@ Мрежа от квадрати Изпращане на съобщение - - %1$s промени своя адрес от %2$s на %3$s - - Променихте своя email адрес от %1$s на %2$s.\n\nАко от тук нататък изпратите съобщение до проверена група, контактите в нея автоматично ще заменят стария с новия Ви адрес.\n\nСилно се препоръчва да извършите настройка в предишния си доставчик на електронна поща така, че всички email съобщения да се препращат към новия Ви email адрес. В противен случай е възможно да не получавате съобщения от контакти, които все още не са получили новия Ви адрес. - @@ -844,14 +823,8 @@ Установихте таймера на изчезващите съобщения на %1$s седмици. Таймерът на изчезващите съобщения е установен на %1$s седмици от %2$s. - - %1$s изпрати съобщение от друго устройство. От тук нататък е гарантирано, че съобщенията ще бъдат криптирани от край до край. Докоснете, за да научите повече. От тук нататък е гарантирано, че всички съобщения в този чат са криптирани от край до край.\n\nКриптирането от край до край запазва поверителността на съобщенията между вас и вашите партньори в чата. Дори Вашият e-mail доставчик не може да ги прочете. - - %1$s изпрати съобщение от друго съобщение. Докоснете, за да научите повече. - - Криптирането от край до край повече не може да бъде гарантирано, вероятно защото %1$s преинсталира Delta Chat или изпрати съобщение от друго устройство.\n\nБихте могли да се срещнете с него/нея лично, да сканирате неговия/нейния QR код отново и отново да установите гарантирано криптиране от край до край. ⚠️%1$s изисква криптиране от край до край, което все още не е установено за този чат. Докоснете, за да научите повече. За да установите криптиране от край до край, бихте могли да се срещате с лицата, с които желаете да контактувате, лично и да сканирате техните QR кодове, за да ги въведете. Научете повече @@ -910,16 +883,10 @@ %1$s отговори, изчаква се да бъдете добавени към групата… Установява се гарантирано криптиране от край до край, моля изчакайте… - - Все още не може да бъде установено гарантирано криптиране от край до край, но вече можете да пратите съобщение. %1$s е проверен. - - Не може да бъде проверен %1$s. Проверен от%1$s Представен от мен - - Настройката за %1$s е сменена. За да се гарантира криптирането от край до край, можете да добавяте в тази група само контакти, отбелязани със зелена отметка.\n\nБихте могли да се срещнете с лицата, с които желаете да контактувате, лично и да сканирате техните QR кодове, за да ги въведете. Изберете чат, към който да бъде пратено съобщението @@ -962,9 +929,6 @@ Обръщане Завъртане - - Криптирано съобщение - Това е официалното настолно приложение Delta Chat. Този софтуер е лицензиран под GNU GPL версия 3. Изходният код е наличен в GitHub. diff --git a/src/main/res/values-bqi/strings.xml b/src/main/res/values-bqi/strings.xml index aab6c60fd..c73533adf 100644 --- a/src/main/res/values-bqi/strings.xml +++ b/src/main/res/values-bqi/strings.xml @@ -24,7 +24,7 @@ گۊشیڌن دانلود هونی دانلود ابۊ... - گۊشیڌن زمینه + گۊشیڌن پیوست ٱووڌن ز نۊ ٱووڌن پاک کردن @@ -33,7 +33,7 @@ زبار ورۊ کردن ایموجی - زمینه + پیوست «%1$s» پیوست بۊ؟ وورگشتن @@ -54,17 +54,17 @@ بؽ دونگ بؽ دونگ پیوما بؽڌارکۊنی - یو ری پوی منتورا ای گوفت ۉ لوفت، ٱر دلتا چت ن و کار بگرن ائمال ابۊ. ولی هنی ترن پیوما ن لف گیری، زفت وو فوروارد کونن. + یو ری پوی منتورا ای گوفت وو لوفت، ٱر دلتا چت ن و کار بگرن ائمال ابۊ. ولی هنی ترن پیوما ن لف گیری، زفت وو فوروارد کونن. زفت کردن - گوفت ۉ لوفت + گوفت وو لوفت وارسگر برنومه یل وو وارسگرا پوروفایل پوی پوروفایلا پوروفایل هیم سکویی نومگه ٱسلی - ناڌن پا گوفت ۉ لوفت - نشۉ داڌن پیوم کامل... + ناڌن پا گوفت وو لوفت + نشووݩ داڌن پیوم کامل... پوی ن خونده بیڌه بزݩ نشووه ناڌن و عونوان خونده وابیڌه @@ -78,12 +78,12 @@ همیشه شؽواتا دیر ز دسرس هی بوگوئشن هیم ی کرت - نشۉ داڌن هوشدار - نشۉ داڌن رزم + نشووݩ داڌن هوشدار + نشووݩ داڌن رزم بؽڌار کردن رزم سکو ن هیچ - ی دمۉ... + ی دمووݩ... ٱنجوم وابی وورگندن آفلاین @@ -97,11 +97,11 @@ نتره %1$s ن زفت کونه. من ویرگه لف گیری وابی. - هومدنگۉݩ + هومدنگووݩ نشۊوی ایمیل نشۊوی ایمیل موشکل داره. رزم - رزم مۉجۊڌ + رزم مووجۊد سکو بپا @@ -188,6 +188,7 @@ فشناڌن فایلا ٱسلی وو شؽواتا تپنیڌه نوابیڌه پسند ز من فایلا + پسند ز شؽوات مال برنومه @@ -200,7 +201,7 @@ ٱوزار هندا تیجنیڌن - ٱووردن و گوفت ۉ لوفت + ٱووردن و گوفت وو لوفت پیتینیڌن ناشناس @@ -227,43 +228,56 @@ هومدنگ نۊ ٱووردن هومدنگ و هالت دستی - گوفت ۉ لوفت نۊ + گوفت وو لوفت نۊ جرگه نۊ - ناڌن پا گوفت ۉ لوفت وا... - وورکل گوفت ۉ لوفت نۊ ز ای گوفت ۉ لوفت - - نومگه Broadcast - - نومگه یل Broadcast - - نومگه Broadcast نۊ - - آلشت نومگه Broadcast + ناڌن پا گوفت وو لوفت وا... + وورکل گوفت وو لوفت نۊ ز ای گوفت وو لوفت + + تورگه + + تورگه یل + + تورگه نۊ + + نوم تورگه + ایمیل + + ایمیل نۊ + + سرتال فشناڌن + آلشت تخته کیلیت ایموجی یل آلشت جرگه نوم وو شؽوات جرگه - بایگۊوی گوفت ۉ لوفت - و در زیڌن گوفت ۉ لوفت ز بایگۊوی - ازاف کردن زمینه + نشووݩ داڌن پوی جاگه یل + بایگۊوی گوفت وو لوفت + و در زیڌن گوفت وو لوفت ز بایگۊوی + ازاف کردن پیوست رئڌن ز جرگه - پاک کردن گوفت ۉ لوفت + رئڌن ز تورگه + پاک کردن گوفت وو لوفت - روفتن ویرگار گوفت ۉ لوفت + روفتن ویرگار گوفت وو لوفت پاک کردن هومدنگ ای جاگه پاک بۊ؟ + جۊزیات پیوم لف گیری من ویرگه + یک رسۊوی لینگ موکش + موکش رفؽقووݩ + لف گیری ز پسند بیڌه لف گیری لینک لف گیری هؽل لف گیری شؽوات لف گیری ایمیل جا وندن ز ویرگه + فوروارد پیوم ولوم ب پیوم بؽ دونگ کردن وارسۊویا وا دونگ کردن پوی وارسگرا - نشۉ داڌن من گوفت ۉ لوفت + نشووݩ داڌن من گوفت وو لوفت یک رسۊوی قوۊل پشک @@ -272,7 +286,7 @@ رئڌن ب روء هیاری پسند پوی - پسند گوفت ۉ لوفت + پسند گوفت وو لوفت پسند بیشتر آلشت نوم سامووا @@ -287,7 +301,7 @@ پیوما منی آلشت هومدنگ - دیسنیڌن گوفت ۉ لوفت + دیسنیڌن گوفت وو لوفت دیسنیڌن کود بونچک @@ -305,23 +319,21 @@ فایل من «%1$s» زفت وابی. - گوفت ۉ لوفت ویدیویی - موکش و گوفت ۉ لوفت ویدیویی + گوفت وو لوفت ویدیویی + موکش و گوفت وو لوفت ویدیویی êxuy %d payom pāk bu? اخۊی %d پیوم پاک بۊ؟ - گوفت ۉ لوفت وا %1$s؟ + گوفت وو لوفت وا %1$s؟ پاک کردن %1$s ز جرگه؟ - - %1$s ز نومگه Broadcast پاک بۊ؟ اخۊی ای لینگن بۊگۊشی؟ - هومدنگۉݩ + هومدنگووݩ بؽ هومدنگ. @@ -347,7 +359,7 @@ فشناڌن \"%1$s\" و... فشناڌن پیوم و... - نشۉ داڌن جا پا + نشووݩ داڌن جا پا پیتینیڌن @@ -363,8 +375,9 @@ سندا لینگا نقشه - نشۉ داڌن وارسگر + نشووݩ داڌن وارسگر فشناڌن پیوم + زفت کردن من %1$s @@ -378,9 +391,13 @@ پیوما ورۊ کردن پوی نوم ایسا - نشۉ داڌن - زۉݩ - گوفت ۉ لوفتا + نشووݩ داڌن + تاریک + شؽوات + تم + زووݩ + فونت سیستوم ن و کار بگر + گوفت وو لوفتا گوزارش پسند ز شؽوات مال پوی @@ -425,13 +442,14 @@ نوم وو پیوم تینا نوم بؽ نوم یا پیوم - زۉݩ + زووݩ فایل و در زیڌن آلشت جا گورو لف گیری جا وندن + زبار دلتا چت گۊشیڌن دلتا چت پاک کردن پیوم پاک کردن @@ -440,7 +458,7 @@ پسند شؽوات جرگه فشناڌ گرؽڌه وابی - نشۉ داڌن نیمدری + نشووݩ داڌن نیمدری گۊشیڌن سامووا diff --git a/src/main/res/values-ca/strings.xml b/src/main/res/values-ca/strings.xml index 8806e6e2b..573c6835b 100644 --- a/src/main/res/values-ca/strings.xml +++ b/src/main/res/values-ca/strings.xml @@ -28,12 +28,14 @@ Uneix-te Torna a unir-te Esborra - Esborra per a Mi - Esborra per a Tothom + Elimina per a mi + Esborra per a tothom Info Actualitza Emojis Adjunt + + Voleu adjuntar \"%1$s\"? Enrere Tanca Tanca la finestra @@ -52,11 +54,14 @@ Silencia Silenciat Missatges efímers - Aquestes opcions s\'apliquen a tots els integrants del xat que usin Delta Chat. Tot i això, poden copiar, desar o reenviar missatges o utilitzar altres clients de correu. + Aquestes opcions s\'apliquen a tots els integrants del xat que utiltizen Delta Chat. Tot i així, poden copiar, desar o reenviar missatges o utilitzar altres clients de correu. Desa Xat Multimèdia + Apps & Multimèdia Perfil + Tots els Perfils + Perfil Actual Menú principal Inicia un xat Mostra el missatge sencer... @@ -91,6 +96,8 @@ No sé trobar cap aplicació per a gestionar aquest tipus de dades. No hi ha instal·lat cap navegador. No s\'ha trobat %1$s. + + No es pot desar %1$s. Copiat al porta-retalls. Contactes Adreça de correu electrònic @@ -150,6 +157,7 @@ %d triat %d seleccionats + Seleccionat: Jo Esborrany Imatge @@ -183,12 +191,17 @@ Imatges i vídeos Fitxer Fitxers + Envia els fitxers originals i les imatges sense comprimir + + Trieu d’entre els Fitxers + Trieu de la Galeria App Apps URL del selector d\'aplicacions Si està definit, s\'usarà l\'URL com a selector d\'aplicacions en comptes del predeterminat + Prem “Envia” per compartir Inici Jocs Eines @@ -220,26 +233,27 @@ Contacte nou - Afegeix un contacte de forma manual + Afegeix un contacte manualment Els contactes afegits manualment es poden usar per a enviar correus electrònics clàssics i no es garanteix que se xifrin d\'extrem a extrem. Xat nou Grup nou Xateja amb… Clona el xat - - Llista de difusió - - Llistes de difusió - - Llista de difusió nova + + Canal + + Canals + + Nou Canal Afegeix destinataris - - Edita la llista de difusió - - Nom de la llista de difusió - - Poseu el nom de la llista de difusió. + + Nom del Canal + Correu electrònic + + Nou correu electrònic + + Assumpte Envia Canvia al teclat d\'emojis Edita el grup @@ -249,6 +263,7 @@ Desarxiva el xat Afegeix un adjunt Deixa el grup + Sortir del Canal Esborra el xat Buida el xat @@ -260,7 +275,7 @@ Qualsevol amb aquest enllaç pot veure el vostre perfil i començar un xat amb vós. Compartiu-lo només amb qui tingueu confiança. Convida amics - Contacta amb mi a Delta Chat:\n%1$s + Contacta\'m a Delta Chat:\n%1$s Copia la selecció Copia l\'enllaç Copia el text @@ -275,6 +290,7 @@ Exporta l\'adjunt Exporta els adjunts Tots els multimèdia + Totes les Apps & Multimèdia Mostra al xat Mostra l\'aplicació al xat @@ -332,6 +348,8 @@ Afegeix a la pantalla d\'inici Feu un donatiu + ❤️ Sembla que estàs gaudint de Delta Chat!\n\nConsidera fer una donació per ajudar a garantir que Delta Chat segueixi sent gratuït per a tothom.\n\nTot i que Delta Chat és gratuït i de codi obert, el desenvolupament té un cost.\n\nAjuda’ns a mantenir Delta Chat independent i a fer-lo encara millor en el futur.\n\nhttps://delta.chat/donate + Silencia 1 hora Silencia 8 hores Silencia 1 dia @@ -366,6 +384,9 @@ Invitació a un xat de vídeo Us han convidat a un xat de vídeo, feu clic a %1$s per unir-vos-hi. + + + Segur que vols sortir? ¿Esborrar %d xat de tots els teus dispositius? ¿Esborrar %d xats de tots els teus dispositius? @@ -391,8 +412,8 @@ Voleu xatejar amb %1$s? Voleu eliminar %1$s del grup? - - Voleu eliminar %1$s de la llista de difusió? + + Eliminar %1$s del canal? Voleu obrir aquest enllaç? @@ -422,8 +443,8 @@ Envia un missatge a %1$s. - - En una llista de difusió, els destinataris rebran missatges en mode de només lectura en un xat amb tu. + + Els canals són una eina d’un a molts per difondre els teus missatges. Els altres membres només veuran aquest grup després que hi envieu el primer missatge. Llisca per cancel·lar Mantingues premut per gravar un missatge de veu i deixa anar per enviar-lo @@ -433,6 +454,7 @@ Missatge Arxivat Sol·licitud + Inclou les sol·licituds als comptadors i notificacions Cap missatge. Missatges enviats a mi mateix/a Si arxiveu xats, els voreu aquí. @@ -531,17 +553,12 @@ Graella quadrada Envia el missatge - - %1$s ha canviat la seva adreça de %2$s a %3$s - - Heu canviat la vostra adreça de correu electrònic de %1$s a %2$s.\n\nSi ara envieu un missatge a un grup verificat, els contactes del grup canviaran de forma automàtica l\'adreça antiga per la nova.\n\nUs recomanem que configureu el compte antic a fi que us reenvïi els missatges a l\'adreça nova. Si no ho feu, podríeu perdre missatges de contactes que encara no hagin actualitzat la vostra adreça. - Afegeix un segon dispositiu Assegureu-vos que els dos dispositius estan a la mateixa Wi-Fi o xarxa - Això crea codi QR que es pot escanejar en el segon dispositiu per a copiar el perfil. + Això crea un codi QR que es pot escanejar en un segon dispositiu per a copiar el perfil. Instal·leu Delta Chat en el vostre altre dispositiu (https://get.delta.chat) Inicieu Delta Chat, toqueu «Ja tinc un perfil / Afegeix un segon dispositiu» i escanegeu el codi que es mostra aquí. @@ -646,7 +663,7 @@ Comparteix l\'enllaç Voleu continuar amb la configuració simplificada? - L’adreça electrònica que heu introduït admet una configuració simplificada. (OAuth2).\n\nEn el pas següent, permeteu que Delta Chat actuï com a xat amb l\'aplicació de correu electrònic..\n\nNo hi ha servidors de Delta Chat, les vostres dades romanen al vostre dispositiu! + L’adreça electrònica que heu introduït admet una configuració simplificada. (OAuth2.0).\n\nEn el pas següent, permeteu que Delta Chat actuï com a xat amb l\'aplicació de correu electrònic..\n\nNo hi ha servidors de Delta Chat, les vostres dades romanen al vostre dispositiu! El certificat coincideix Si us plau poseu una adreça d\'email vàlida Si us plau poseu un servidor / adreça IP vàlida @@ -654,7 +671,7 @@ Si us plau poseu una adreça i contrasenya vàlids Importa una còpia de seguretat S\'ha trobat una còpia de seguretat a \"%1$s\".\n\nVoleu importar-la i fer-ne servir les dades i els paràmetres de configuració? - No s\'han trobat còpies de seguretat.\n\nCopieu la còpia de seguretat a \"%1$s\" i torneu-ho a provar. Com a alternativa, premeu \"Comença a escriure\" per encetar el procés de configuració habitual. + No s\'han trobat còpies de seguretat.\n\nCol·loca la còpia de seguretat a \"%1$s\" i torneu-ho a provar. Com a alternativa, premeu \"Comença a escriure\" per continuar amb el procés de configuració habitual. No es pot iniciar la sessió com a \"%1$s\". Comproveu que l\'adreça electrònica i la contrasenya són correctes. @@ -696,7 +713,7 @@ Contactes bloquejats Els contactes blocats apareixeran aquí. Contrasenya i compte - La vostra imatge de perfil, el vostre nom i també la biografia s\'enviaran amb els missatges que envieu als altres usuaris. + La vostra imatge de perfil, nom i biografia s\'enviaran amb juntament els missatges que escriviu quant us comuniqueu amb altres usuaris. El vostre nom Signatura @@ -716,7 +733,7 @@ Mostra Prioritat Habilita les notificacions del sistema per als missatges nous - Mostra el contingut del missatge en la notificació + Mostra el contingut del missatge a la notificació Mostra el remitent i les primeres paraules del missatge en les notificacions Color LED So @@ -802,6 +819,7 @@ %1$s missatge Baixa el màxim disponible fins a %1$s + Trieu Perfil Trieu la imatge de perfil Trieu la imatge nova de perfil Esborra la imatge del perfil @@ -841,7 +859,7 @@ Voleu esborrar ara %1$d missatges i tots els missatges \"%2$s\" futurs?\n\n• Això inclou tot el contingut multimèdia\n\n• S\'esborraran els missatges fins i tot si no s\'han llegit\n\n• Els \"Missatges desats\" no s\'esborraran de l\'emmagatzematge local - Voleu esborrar ara %1$d missatges i tots els missatges nous \"%2$s\" futurs?\n\n⚠️ Això inclou els correus, contingut multimèdia i \"Missatges desats\" a totes les carpetes del servidor\n\n⚠️ No utilitzeu aquesta funció si voleu conservar les dades al servidor\n\n⚠️ No utilitzeu aquesta funció si feu servir un client de correu diferent del Delta Chat + Voleu esborrar ara %1$d missatges i tots els missatges nous \"%2$s\" futurs?\n\n⚠️ Això inclou els correus, contingut multimèdia i \"Missatges desats\" a totes les carpetes del servidor\n\n⚠️ No utilitzeu aquesta funció si voleu conservar les dades al servidor\n\n⚠️ No utilitzeu aquesta funció si feu servir un client de correu diferent a Delta Chat Això inclou els correus electrònics, contingut multimèdia i «Missatges desats» en totes les carpetes del servidor. No useu aquesta funció si voleu conservar dades al servidor o si useu altres clients de correu més enllà de Delta Chat. Activa l\'esborrament immediat @@ -860,9 +878,9 @@ Després d\'1 any - Envia el missatge de configuració Autocrypt + Envia el missatge de configuració d\'Autocrypt Un \"missatge de configuració Autocrypt\" comparteix de forma segura la vostra configuració d\'extrem a extrem amb altres aplicacions compatibles amb Autocrypt.\n\nLa configuració es xifrarà amb un codi de configuració que es mostrarà aquí i que haureu d\'escriure a l’altre dispositiu. - Envia el missatge de configuració Autocrypt + Envia el missatge de configuració d\'Autocrypt Se us ha enviat la vostra configuració. Canvieu a l\'altre dispositiu i obriu el missatge de configuració. Se us demanarà un codi de configuració. Introduïu els dígits següents a l\'indicador.\n\nUn cop fet, l\'altre dispositiu estarà llest per utilitzar Autocrypt. Prefereix l\'encriptació d\'extrem a extrem @@ -888,6 +906,8 @@ Heu eliminat el membre %1$s. Membre %1$s eliminat per %2$s. + + Has sortit. %1$sha abandonat el grup Heu esborrat la imatge de grup. @@ -915,6 +935,9 @@ Heu definit el temporitzador dels missatges fonedissos a 1 setmana %1$s ha definit el temporitzador dels missatges efímers a 1 setmana. + Has establert el temporitzador de missatges efímers a 1 any. + + El temporitzador de missatges efímers s’ha establert a 1 any per %1$s. Heu definit el temporitzador dels missatges fonedissos a %1$s minuts. @@ -931,14 +954,8 @@ Heu definit el temporitzador dels missatges fonedissos a %1$s setmanes. %2$s ha definit el temporitzador dels missatges efímers a %1$s setmanes. - - %1$s ha enviat un missatge des d\'un altre dispositiu. Us garantim que a partir d\'ara els missatges són xifrats d\'extrem a extrem. Toqueu per a obtenir més informació. Ara es garanteix que tots els missatges d\'aquest xat són xifrats d\'extrem a extrem.\n\nEl xifratge d\'extrem a extrem manté privats els missatges entre vós i els companys de xat. Ni tan sols el vostre proveïdor de correu electrònic pot llegir-los. - - %1$s ha enviat un missatge des d\'un altre dispositiu. Toqueu per a obtenir més informació. - - No es pot garantir el xifrat d\'extrem a extrem, probablement perquè %1$s ha reinstal·lat Delta Chat o ha enviat un missatge des d\'un altre dispositiu.\n\n Podeu trobar-vos físicament amb la persona i tornar a escanejar el seu codi QR per tomar-hi a tenir xifrat d\'extrem a extrem. %1$srequereix xifratge d\'extrem a extrem, que encara no s\'ha configurat per a aquest xat. Toqueu per a obtenir més informació. Per a establir xifratge d\'extrem a extrem, heu de trobar-vos amb els contactes en persona i escanejar el seu codi QR per a poder afegir-los. Més informació @@ -955,7 +972,7 @@ Codi QR - Carrega el codi QR com a imatge + Carrega un codi QR com a imatge Escaneja codi QR Poseu la càmera davant del codi QR Mou el codi QR a la càmera @@ -997,16 +1014,11 @@ %1$s ha respost, espereu per a ser afegit al grup... S\'està establint el xifratge d\'extrem a extrem garantit, espereu... - - Encara no es pot garantir el xifrat punt-a-punt, però ja podeu enviar un missatge. %1$s verificat. - - No es pot verificar%1$s Afegit per %1$s Afegit per mi - - Configuració canviada per %1$s + Afegit Per a garantir el xifrat extrem a extrem, només podeu afegir a aquest grup contactes que tinguin la marca verda.\n\nPodeu trobar-vos en persona amb els contactes per a escanejar els seus codis QR i poder-los afegir. Trieu el xat on enviar el missatge @@ -1049,9 +1061,6 @@ Capgira Gira - - Missatge encriptat - Aquesta és l\'aplicació d\'escriptori oficial de Delta Chat. Aquest programari és llicenciat amb la llicència GNU GPL versió 3 i el codi font és disponible a GitHub @@ -1166,7 +1175,6 @@ Delta Chat vol desar imatges a la biblioteca de fotografies. Delta Chat pot usar Face ID per a protegir el vostre perfil local, la creació de còpies de seguretat i la configuració d\'un segon dispositiu. - Entrega immediata Usa la connexió en segon pla @@ -1179,8 +1187,6 @@ Prem aquí per rebre missatges mentre Delta Chat és en segon pla. Ja heu autoritzat Delta Chat a rebre missatges en segon pla.\n\nSi encara no us arriben els missatge, reviseu els paràmetres de sistema. - - Què hi ha de nou?\n\n❤️‍🔥 Un selector d\'emojis nou amb més emojis\n\n🎮 Aplicacions al xat millorades: rebeu notificacions i obriu les aplicacions suportades segons el context. P. ex. obriu una entrada afegida al calendari directament.\n\n👍 Rebeu notificacions de les reaccions dels vostres missatges\n\n... 🛠️ Correccions i moltes coses més a %1$s - - ℹ️ S\'ha mogut l\'opció «Canvia el perfil»: toqueu en la vostra imatge de perfil en la cantonada superior de la finestra principal per a afegir o canviar perfils 💡 + + Què hi ha de nou?\n\n💯 L’encriptació de punta a punta és fiable i permanent. Els candaus 🔒 han desaparegut!\n\n✉️ El correu electrònic clàssic sense encriptació de punta a punta es mostra amb el símbol d\'un sobre.\n\n😻 Nova pantalla de perfil millorada per a tots els teus contactes.\n\n🔲 Nou botó per accedir ràpidament a les aplicacions utilitzades als xats.\n\n❤️ Si us plau, fes una donació per ajudar-nos a continuar independents i seguir aportant millores: %1$s diff --git a/src/main/res/values-ckb/strings.xml b/src/main/res/values-ckb/strings.xml index d0c7788f6..2a9b6d8c0 100644 --- a/src/main/res/values-ckb/strings.xml +++ b/src/main/res/values-ckb/strings.xml @@ -319,6 +319,7 @@ بەڵگە و مۆسیقا و هەموو پەڕگە هاوبەشکراوەکانی نێو ئەم وتووێژە، لێرەدا پیشان دەدرێن. پێشدیتنی ڕەنگاڵە پەیام بنێرە + بچۆ ژوورەوە بچۆ ژوورەوە بۆ سێرڤێرەکەی خۆت بچۆ ژوورەوە بە ناونیشانی ئیمەیلێکەوە @@ -495,10 +496,6 @@ دەتەوێت ناونیشانی ئیمەیلێکی نوێ لەسەر \"%1$s\" درووست بکەیت و لەوێ بچیتە ژوورەوە؟ ناتوانی لە کۆدی QRە سکان کراوەکە کەڵک بگریت بۆ پێکهێنانی هەژمارێکی نوێ. %1$s پشتڕاست کرایەوە - - %1$s پشتڕاست ناکرێتەوە. - - ڕێکخستن بۆ %1$s گۆڕا. وەڵام دانەوە پەیامی نوێ @@ -516,9 +513,6 @@ بۆ هەناردنی پەیامی دەنگی، بچۆ بەشی ڕێکخستنەکانی نەرمامێرەکە، لە بەشی \"ڕێگەپێدان\"دا، \"مایک\" چالاک بکەوە. بۆ هەناردن و وەرگرتنی پەڕگەکان، بچۆ بەشی ڕێکخستنەکانی نەرمامێرەکە، لە بەشی \"ڕێگەپێدان\"دا، \"بیرگە\" چالاک بکەوە. بۆ لکاندنی شوێنێک، بچۆ بەشی ڕێکخستنەکانی نەرمامێرەکە، لە بەشی \"ڕێگەپێدان\"دا، \"شوێن\" چالاک بکەوە. - - پەیامی شفرەکراو - ئەمە نەرمامێری فەرمی دێڵتا چاتە بۆ کۆمپووتەری ڕوومێز. بەخێر بێن بۆ دێڵتا چات diff --git a/src/main/res/values-cs/strings.xml b/src/main/res/values-cs/strings.xml index 17edffafb..2d5267d3e 100644 --- a/src/main/res/values-cs/strings.xml +++ b/src/main/res/values-cs/strings.xml @@ -251,19 +251,7 @@ Chatovat s... Klonovat chat - - Seznam vysílání - - Seznamy vysílání - - Nový seznam vysílání Přidat příjemce - - Upravit seznam vysílání - - Název seznamu vysílání - - Prosím, zadejte název seznamu vysílání. Odeslat Přepnout emoji klávesnici Upravit skupinu @@ -424,8 +412,6 @@ Přejete si chatovat s uživatelem %1$s? Přejete si odstranit uživatele %1$s ze skupiny? - - Přejete si odstranit uživatele %1$s ze seznamu vysílání? Přejete si otevřít tento odkaz? @@ -461,8 +447,6 @@ Poslat zprávu uživateli %1$s. - - Seznam vysílání slouží k posílání zpráv příjemcům v chatu, který je pro ně pouze pro čtení. Ostatní tuto skupinu uvidí až poté, co odešlete první zprávu. Zrušit tahem Pro nahrání hlasové zprávy stiskněte a držte ikonu mikrofonu; uvolněte pro odeslání. @@ -570,11 +554,6 @@ Mřížka čtverců Odeslat zprávu - - Uživatel %1$s změnil svou adresu z %2$s na %3$s - - Změnili jste svou e-mailovou adresu z %1$s na %2$s.\n\nPokud nyní pošlete zprávu ověřené skupině, všem kontaktům v ní se vaše adresa aktualizuje na novou.\n\nJe důrazně doporučeno, abyste u svého starého poskytovatele nastavili přesměrování všech e-mailů na novou adresu, jinak byste mohli přijít o zprávy od kontaktů, které vaši novou adresu dosud nedostaly. - @@ -970,14 +949,8 @@ Samomazací zprávy vyprší po %1$s týdnech ode mě. Uživatel %2$s změnil časovač mizejících zpráv na %1$s týdnů. - - Uživatel %1$s odeslal zprávu z jiného zařízení. Nyní je garantováno koncové šifrování vašich zpráv. Stiskněte pro více informací. Nyní je garantováno, že všechny zprávy v tomto chatu jsou koncově šifrovány.\n\nKoncové šifrování zajišťuje soukromí mezi vámi a vašimi kontakty. Nedokáže je přečíst ani váš poskytovatel e-mailu. - - Uživatel %1$s odeslal zprávu z jiného zařízení. Stiskněte pro více informací. - - Koncové šifrování již nemůže být garantováno, pravděpodobně protože uživatel %1$s přeinstaloval Delta Chat nebo odeslal zprávu z jiného zařízení.\n\nPro obnovení garantovaného koncového šifrování se sejděte osobně a naskenujte si své QR kódy. ⚠️%1$s vyžaduje koncové šifrování, které pro tento chat ještě není nastaveno. Stiskněte pro více informací. Pro navázání koncově šifrovaného spojení se můžete se svými kontakty setkat osobně a naskenovat jejich QR kódy. Další informace @@ -1036,18 +1009,10 @@ Uživatel %1$s odpověděl, čekání na přidání do skupiny... Navazování koncově šifrovaného spojení, prosím, čekejte... - - Zatím nebylo navázáno koncově šifrované spojení, ale již nyní můžete posílat zprávy. - - Vypadá to, že to trvá trochu déle. Možná jste vy nebo váš kontakt offline.\n\nProces však pokračuje na pozadí. Zatím můžete dělat něco jiného... Uživatel %1$s ověřen. - - Navázání garantovaného koncově šifrovaného spojení s uživatelem %1$s selhalo. Ověřeni uživatelem %1$s. Ověřeni mnou - - Nastavení pro uživatele %1$s změněno. Aby mohlo být garantováno koncové šifrování, můžete do této skupiny přidávat pouze uživatele se zeleným zaškrtávátkem.\n\nSe svými kontakty se můžete setkat osobně a naskenovat jejich QR kód, abyste je ověřili. Vyberte chat, do kterého chcete zprávu poslat @@ -1090,9 +1055,6 @@ Zrcadlení Otočení - - Šifrovaná zpráva - Toto je oficiální aplikace Delta Chat Desktop. Tento software je distribuován pod licencí GNU GPL verze 3 a jeho zdrojový kód je k dispozici na GitHubu. @@ -1207,7 +1169,6 @@ Delta Chat ukládá obrázky do vaší galerie. Delta Chat umí využívat Face ID k ochraně vašeho lokálního profilu, vytváření záloh a přidávání dalších zařízení. - Okamžité doručení Používat připojení na pozadí @@ -1220,8 +1181,4 @@ Stiskem nastavíte přijímání zpráv, když je aplikace Delta Chat na pozadí. Přijímání zpráv na pozadí jste již aplikaci Delta Chat povolili.\n\nV případě, že vám zprávy na pozadí stále nechodí, prosím zkontrolujte svá systémová nastavení. - - Co je nového?\n\n❤️‍🔥 Nová nabídka emoji s více druhy emoji\n\n🎮 Vylepšené aplikace v chatu: Oznámení a podpůrné aplikace přímo v kontextu chatu, např. odkaz na novou nové položky z kalendáři\n\n👍 Oznámení o reakcích na zprávy\n\n... 🛠️ OPRAVY a DALŠÍ na %1$s - - ℹ️ Volba \"Přepnout profil\" byla přesunuta: Pro přidávání či přepínání profilů stiskněte svůj profilový obrázek v horním rohu hlavní obrazovky. - + diff --git a/src/main/res/values-da/strings.xml b/src/main/res/values-da/strings.xml index 9ee07b761..2ab7d6502 100644 --- a/src/main/res/values-da/strings.xml +++ b/src/main/res/values-da/strings.xml @@ -343,6 +343,7 @@ Dokumenter, musik og andre filer delt i denne samtale vises her. Medie forhåndsvisning Send besked + Indkommende beskeder @@ -631,10 +632,6 @@ Opret ny e-mail adresse på \"%1$s\" og log ind der?\n\nDin eksisterende konto bliver ikke slettet. Brug \"Skift konto\" for at skifte imellem dine konti. Den skannede QR-kode kan ikke bruges til at opsætte en ny konto. %1$s bekræftet. - - Kan ikke bekræfte %1$s - - Ændret opsætning for %1$s Svar Ny besked @@ -656,9 +653,6 @@ Tegn hvor som helst for at sløre Roter - - Krypteret besked - Dette er den officielle Delta Chat Desktop app. Denne software er licenseret under GNU GPL version 3 og kildekoden er tilgængelig på GitHub diff --git a/src/main/res/values-de/strings.xml b/src/main/res/values-de/strings.xml index 50c4922c4..5332a72cc 100644 --- a/src/main/res/values-de/strings.xml +++ b/src/main/res/values-de/strings.xml @@ -240,12 +240,6 @@ Chatte mit… Chat klonen - - Broadcast-Liste - - Broadcast-Listen - - Neue Broadcast-Liste Kanal @@ -253,12 +247,6 @@ Neuer Kanal Empfänger hinzufügen - - Broadcast-Liste bearbeiten - - Broadcast-Listen-Name - - Bitten einen Namen für die Broadcast-Liste eingeben. Name des Kanals E-Mail @@ -425,8 +413,6 @@ Chat mit %1$s starten? %1$s aus der Gruppe löschen? - - %1$s von der Broadcast-Liste entfernen? %1$s vom Kanal entfernen? Diesen Link öffnen? @@ -458,8 +444,6 @@ Senden Sie eine Nachricht an %1$s. - - In Broadcast-Listen erhalten die Empfänger die Nachrichten in einem Nur-Lesen-Chat. Kanäle dienen der Verbreitung von Nachrichten an viele Empfänger. Andere sehen diese Gruppe erst, nachdem Sie eine erste Nachricht gesendet haben. @@ -570,11 +554,6 @@ Quadratisches Raster Nachricht senden - - %1$s hat die E-Mail-Adresse von %2$s nach %3$s geändert - - Sie haben Ihre E-Mail-Adresse von %1$s auf %2$s geändert.\n\nWenn Sie jetzt eine Nachricht an eine verifizierte Gruppe senden, wird dort automatisch die alte durch die neue Adresse ersetzt.\n\nEs wird dringend empfohlen, Ihren alten E-Mail-Anbieter so einzurichten, dass er alle E-Mails an Ihre neue E-Mail-Adresse weiterleitet. Andernfalls könnten Sie Nachrichten von Kontakten verpassen, die Ihre neue E-Mail-Adresse noch nicht erhalten haben. - @@ -957,6 +936,9 @@ Sie haben die Ablaufzeit verschwindender Nachrichten auf 1 Woche gesetzt. Ablaufzeit verschwindender Nachrichten auf 1 Woche gesetzt von %1$s. + Sie haben die Ablaufzeit verschwindender Nachrichten auf 1 Jahr gesetzt. + + Ablaufzeit verschwindender Nachrichten auf 1 Jahr gesetzt von %1$s. Sie haben die Ablaufzeit verschwindender Nachrichten auf %1$s Minuten gesetzt. @@ -973,14 +955,8 @@ Sie haben die Ablaufzeit verschwindender Nachrichten auf %1$s Wochen gesetzt. Ablaufzeit verschwindender Nachrichten auf %1$s Wochen gesetzt von %2$s. - - %1$s hat eine Nachricht von einem anderen Gerät gesendet. Nachrichten sind Ende-zu-Ende-verschlüsselt. Tippen, um mehr zu erfahren. Alle Nachrichten in diesem Chat sind Ende-zu-Ende verschlüsselt.\n\nDurch die Ende-zu-Ende-Verschlüsselung bleiben die Nachrichten zwischen Ihnen und Ihren Chat-Partnern privat. Nicht einmal Server, Provider oder Relays können sie lesen. - - %1$s hat eine Nachricht von einem anderen Gerät gesendet. Tippen, um mehr zu erfahren. - - Die Ende-zu-Ende-Verschlüsselung kann nicht mehr garantiert werden, wahrscheinlich weil %1$s Delta Chat neu installiert oder eine Nachricht von einem anderen Gerät gesendet hat.\n\nSie können sich persönlich treffen und den QR-Code erneut scannen, um die garantierte Ende-zu-Ende-Verschlüsselung wiederherzustellen. ⚠️ %1$s verlangt eine Ende-zu-Ende-Verschlüsselung, die für diesen Chat noch nicht hergestellt wurde. Tippen, um mehr zu erfahren. Um eine Ende-zu-Ende-Verschlüsselung herzustellen, können Sie Kontakte persönlich treffen und ihren QR-Code scannen. Mehr erfahren @@ -1039,19 +1015,11 @@ %1$s antwortet. Warte, zur Gruppe hinzugefügt zu werden... Ende-zu-Ende-Verschlüsselung wird aufgebaut, bitte warten... - - Noch konnte keine garantierte Ende-zu-Ende-Verschlüsselung aufgebaut werden, aber Sie können bereits eine Nachricht senden. - - Der Kontakt muss online sein, um fortzufahren.\n\nDieser Vorgang wird automatisch im Hintergrund fortgesetzt. %1$s eingeführt. - - Kann keine Ende-zu-Ende-Verschlüsselung mit %1$s herstellen. Eingeführt von %1$s Durch mich eingeführt Eingeführt - - Geändertes Setup für %1$s Um Ende-zu-Ende-Verschlüsselung zu gewährleisten, können nur Kontakte mit grünem Häkchen zu dieser Gruppe hinzugefügt werden.\n\nSie könne Kontakte persönlich treffen und ihren QR-Code scannen, um sie einzuführen. Wählen Sie den Chat, an den die Nachricht gesendet werden soll @@ -1094,9 +1062,6 @@ Spiegeln Drehen - - Verschlüsselte Nachricht - Dies ist die offizielle Delta Chat Desktop App. Dieses Programm ist lizenziert unter der GNU GPL version 3 und der Quellcode ist auf Github verfügbar. @@ -1211,7 +1176,6 @@ Delta Chat möchte Bilder in Ihrer Fotobibliothek speichern. Delta Chat kann Face-ID verwenden, um Ihr lokales Profil, Backups und die Einrichtung eines zweiten Geräts zu schützen. - Sofortige Benachrichtigungen Hintergrundverbindung verwenden @@ -1226,8 +1190,4 @@ Was ist neu?\n\n💯 Die Ende-zu-Ende-Verschlüsselung ist jetzt dauerhaft. Vorhängeschlösser 🔒 gibt es nicht mehr!\n\n✉️ Klassische E-Mails ohne Ende-zu-Ende-Verschlüsselung sind mit einem Umschlag-Symbol gekennzeichnet\n\n😻 Neues, verbessertes Profil für alle Kontakte\n\n🔲 Neue Schaltfläche für den schnellen Zugriff auf Apps, die in einem Chat verwendet werden\n\n❤️ Bitte Spenden Sie und helfen uns, unabhängig zu bleiben und weiterhin Verbesserungen zu bringen: %1$s - - Was ist neu?\n\n❤️‍🔥 Neuer Emoji-icker mit mehr Emojis\n\n🎮 In-Chat-App Verbesserungen: Benachrichtigungen erhalten und Apps im Kontext öffnen, z.B. einen hinzugefügten Kalendereintrag direkt anzeigen\n\n👍 Lassen Sie sich über Reaktionen auf Ihre Nachrichten benachrichtigen\n\n... 🛠️ FIXES und NOCH MEHR unter %1$s - - ℹ️ \"Profil wechseln\" verschoben: Tippen Sie auf Ihr Profilbild in der oberen Ecke des Hauptbildschirms, um Profile hinzuzufügen oder zu wechseln 💡. diff --git a/src/main/res/values-el/strings.xml b/src/main/res/values-el/strings.xml index b32b7748a..57ed3ebf0 100644 --- a/src/main/res/values-el/strings.xml +++ b/src/main/res/values-el/strings.xml @@ -181,12 +181,6 @@ Νέα Επαφή Νέα Συνομιλία Νέα ομάδα - - Λίστα Μέσων - - Λίστες Μέσων - - Νέα Λίστα Μέσων Προσθήκη Παραλήπτη Αποστολή Εναλλαγή πληκτρολογίου emoji @@ -311,8 +305,6 @@ Συνομιλία με %1$s; Αφαίρεση του/της %1$s από την ομάδα; - - Αφαίρεση %1$s από την λίστα εκπομπών; Θέλετε να ανοίξετε αυτό τον σύνδεσμό; @@ -427,11 +419,6 @@ Οι ιδιωτικές εφαρμογές που λαμβάνονται ή αποστέλλονται σε οποιαδήποτε συνομιλία θα εμφανίζονται εδώ. Προεπισκόπιση Αποστολή μηνύματος - - %1$s άλλαξαν την διεύθυνσή τους από %2$s σε %3$s - - Αλλάξατε την διεύθυνσή σας από %1$s σε %2$s.\n\nΤώρα, εάν στείλετε ένα μήνυμα σε μια επαληθευμένη ομάδα, οι επαφές εκεί θα αντικαταστήσουν αυτόματα την παλιά με τη νέα σας διεύθυνση.\n\nΣυνιστάται ιδιαίτερα να ρυθμίσετε τον παλιό σας πάροχο email ώστε να προωθεί όλα τα μηνύματα ηλεκτρονικού ταχυδρομείου στη νέα σας διεύθυνση ηλεκτρονικού ταχυδρομείου. Διαφορετικά, ενδέχεται να χάσετε μηνύματα επαφών που δεν έχουν λάβει ακόμη τη νέα σας διεύθυνση. - @@ -773,10 +760,6 @@ %1$s απάντησε, αναμονή για να προστεθεί στην ομάδα… %1$s επαληθεύτηκε. - - Αδυναμία επαλήθευσης %1$s. - - Άλλαξε η ρύθμιση για %1$s. Επιλέξτε συνομιλία για να στείλετε το μήνυμα %1$s έχει ήδη ένα πρόχειρο μήνυμα, θέλετε να το αντικαταστήσετε; @@ -809,9 +792,6 @@ Εναλλαγή Περιστροφή - - Κρυπτογραφημένο μήνυμα - Αυτή είναι η επίσημη εφαρμογή Delta Chat Desktop. Αυτό το λογισμικό έχει άδεια χρήσης σύμφωνα με την GNU GPL έκδοση 3 και ο πηγαίος κώδικας είναι διαθέσιμος στο GitHub. diff --git a/src/main/res/values-eo/strings.xml b/src/main/res/values-eo/strings.xml index 66d441dcf..59d8986e9 100644 --- a/src/main/res/values-eo/strings.xml +++ b/src/main/res/values-eo/strings.xml @@ -188,12 +188,6 @@ Nova kontakto Nova babilo Nova grupo - - Elsenda Listo - - Elsendaj Listoj - - Nova Elsenda Listo Aldoni Ricevantojn Sendi Baskuligi emoĝian klavaron @@ -341,6 +335,7 @@ Mapo Aŭdvida antaŭrigardo Sendi mesaĝon + Ensaluti Ensaluti al via servilo Ricevujo diff --git a/src/main/res/values-es/strings.xml b/src/main/res/values-es/strings.xml index f98df0874..8bda1ac33 100644 --- a/src/main/res/values-es/strings.xml +++ b/src/main/res/values-es/strings.xml @@ -262,12 +262,6 @@ Chatear con... Clonar chat - - Difusión - - Difusiones - - Nueva difusión Canal @@ -275,12 +269,6 @@ Nuevo canal Agregar destinatarios - - Editar difusión - - Nombre de difusión - - Por favor, introduce un nombre para la difusión. Nombre del canal Correo electrónico @@ -450,8 +438,6 @@ ¿Chatear con %1$s? ¿Eliminar a %1$s del grupo? - - ¿Eliminar %1$s de la lista de difusión? ¿Quita %1$s del canal? ¿Quieres abrir este enlace? @@ -486,8 +472,6 @@ Envíe un mensaje a %1$s. - - En una difusión, los destinatarios recibirán mensajes en un chat de solo lectura contigo. Canales son una herramienta para comunicación de uno a muchos para crear un transmisión de mensajes. Los demás sólo verán este grupo después de que hayas enviado un primer mensaje. @@ -598,11 +582,6 @@ Cuadrícula cuadrada Enviar mensaje - - %1$s cambió su dirección de %2$s a %3$s - - Has cambiado tu dirección de correo electrónico de %1$s a %2$s.\n\nSi ahora envías un mensaje a un grupo verificado, los contactos de éste sustituirán automáticamente la antigua por tu nueva dirección.\n\nEs muy recomendable que configures tu antiguo proveedor de correo electrónico para que reenvíe todos los mensajes a tu nueva dirección. De lo contrario, podrías perderte los mensajes de los contactos que aún no han recibido tu nueva dirección. - @@ -985,6 +964,9 @@ Estableciste el temporizador de la desaparición de mensajes en 1 semana. Temporizador de la desaparición de mensajes establecido en 1 semana por %1$s. + Estableciste el temporizador de la desaparición de mensajes en 1 año. + + Temporizador de la desaparición de mensajes establecido en 1 año por %1$s. Estableciste el temporizador de la desaparición de mensajes en %1$s minutos. @@ -1001,14 +983,8 @@ Estableciste el temporizador de la desaparición de mensajes en %1$s semanas. Temporizador de la desaparición de mensajes establecido en %1$s semanas por %2$s. - - %1$s envió un mensaje desde otro dispositivo. A partir de ahora se garantiza que los mensajes están cifrados de extremo a extremo . Toca para obtener más información. Ahora se garantiza que todos los mensajes en este chat están cifrados de extremo a extremo.\n\nEl cifrado de extremo a extremo mantiene los mensajes privados entre tú y tus compañeros de chat. Ni siquiera tu proveedor de correo electrónico puede leerlos. - - %1$s envió un mensaje desde otro dispositivo. Toca para obtener más información. - - El cifrado de extremo a extremo ya no se puede garantizar, probablemente porque %1$s reinstaló Delta Chat o envió un mensaje desde otro dispositivo.\n\nPueden encontrarse en persona y escanear su código QR nuevamente para restablecer el cifrado de extremo a extremo garantizado. ⚠️ %1$s requiere cifrado de extremo a extremo que aún no está configurado para este chat. Toca para obtener más información. Para establecer un cifrado de extremo a extremo, puede reunirse con los contactos en persona y escanear su código QR. Aprender más @@ -1067,19 +1043,11 @@ %1$s respondió, esperando ser agregado al grupo… Estableciendo cifrado de extremo a extremo garantizado, por favor, espere... - - No se pudo aún establecer el cifrado de extremo a extremo garantizado, pero ya puede enviar mensajes. - - El contacto debe estar en línea para continuar.\n\nEste proceso continuará automáticamente en segundo plano. %1$s verificado. - - No se pudo verificar %1$s. Verificado por %1$s Verificado por ti Introducido - - Configuración cambiada para %1$s. Para garantizar el cifrado de extremo a extremo, solo puedes añadir contactos con una marca de verificación verde Seleccione el chat para enviar el mensaje @@ -1122,9 +1090,6 @@ Voltear Rotar - - Mensaje cifrado - Esta es la aplicación oficial de Delta Chat para escritorio. Este programa está licenciado bajo GNU GPL versión 3 y el código está disponible en GitHub. @@ -1239,7 +1204,6 @@ Delta Chat quiere guardar imágenes en tu galería Delta Chat puede utilizar Face ID para proteger su perfil local, la creación de copias de seguridad y la configuración de un segundo dispositivo. - Entrega inmediata Usar conexión en segundo plano diff --git a/src/main/res/values-et/strings.xml b/src/main/res/values-et/strings.xml index 4c20534d1..f67fd28be 100644 --- a/src/main/res/values-et/strings.xml +++ b/src/main/res/values-et/strings.xml @@ -53,7 +53,7 @@ Tõsta arhiivist välja Summuta Summutatud - Kaduvad sõnumid + Isekustuvad sõnumid Kehtib kõikidele selles vestluses osalejatele - aga siiski saavad nad sõnumeid kopeerida, salvestada ja edastada. Salvesta Vestlus @@ -300,7 +300,7 @@ Lõpeta kontakti blokeerimine Nõustu Esita - eata + Peata Keri lõpuni Keri algusesse Abiteave @@ -315,6 +315,7 @@ Kasutaja „%1$s“ hüüdnimi Seadistused + Täiendavad seadistused Vaata profiili Suumi sisse Suumi välja @@ -325,8 +326,10 @@ Mine sõnumi juurde Mine algse sõnumi juurde Kopeeri JSON-vormingus + Asenda kavand Jaga asukohta kõikide grupi liikmetega Seadme sõnumid + Kohalikus seadmes loodud sõnumid Muuda kontakti Tõsta vestlus esile @@ -350,6 +353,16 @@ Summuta seitsmeks päevaks Summuta alatiseks + Kestusega 5 minutit + Kestusega 30 minutit + Kestusega 1 tund + Kestusega 2 tundi + Kestusega 6 tundi + + + Kas saadame järgnevad faili kasutajale %s? + Kas saadame järgnevad %d faili kasutajale %s? + Fail on salvestatud: „%1$s“. Videovestlus @@ -363,6 +376,9 @@ Sinu videovestluse server Näide: https://sinu-server.org/$ROOM + Kutse videovestlusele + Oled saanud kutse videovestlusele - liitumiseks klõpsi %1$s. + Kas oled kindel, et soovid lahkuda? @@ -380,7 +396,14 @@ Kas lõpetad kontakti blokeerimise? Kas soovid vestelda kasutajaga %1$s? + Kas eemaldad järgnevad kasutajad grupist: %1$s? + Kas eemaldad järgnevad kasutajad kanalilt: %1$s? + Kas sa soovid selle lingi avada? + + + + Kontaktid Sisesta nimi või e-posti aadress Palun sisesta ülale e-posti aadress Kontakte pole. @@ -408,17 +431,30 @@ Kanalid on üks-mitmele suhtlusviisid oma sõnumite levitamiseks. Katkestamiseks viipa + Häälsõnumi salvestamiseks vajuta nupp alla ja hoia all ning saatmiseks lase nupp lahti Vestlusi pole.\nUue vestluse loomiseks klõpsi + ikooni. Kõik vestlused on arhiveeritud.\nUue vestluse algatamiseks klõpsi + ikooni. + Jaga kasutajaga + Sõnum + Arhiveeritud + Päring Lisa päringud nii loenduritesse kui teavitustesse + Sõnumeid pole. Salvestatud sõnumid Salvestatud Salvesta kui + Proovi uuesti sõnumit saata + Selle failitüübi kuvamine pole võimalik: %s + Manuse laadimine ei õnnestunud Postiloend Saada sõnum… + Saada huvipunkti teave + + %1$s vestluse kontroll-logi + Tuvastasin kahtlase lingi Otsi Otsi vestlusest @@ -440,7 +476,7 @@ Selle tegevuse jaoks pead olemagrupi liige. Krüptimine Ühised vestlused - Sarnased vestlused + Sarnaste osalejatega vestlused Varasemad liikmed Kontakt @@ -460,6 +496,7 @@ Ükspuha mis vestlusele lisatud rakendused saavad olema nähtavad siin. Meediumi eelvaade Saada sõnum + Lisa täiendav seade @@ -551,6 +588,7 @@ SMTP server SMTP port SMTP turvalisus + Tuvastamise meetod Proksiserver Kasuta proksiserverit @@ -594,15 +632,43 @@ Seadistamine ei õnnestunud: Viga: %1$s + + + Edasta kasutajale… Kas saadad %1$d faili „%2$s“ vestlusesse? + Kas saadad %1$d faili „%2$d“ vestlusesse? (Videod saadetakse algupäraste suurte failidena. Videote mahu vähendamiseks lisa nad manustena ükshaaval) + Puuduvate õiguste tõttu on jagamine katkestatud. + + + + Kasutan kohandatud väärtust: %s + Kasutan vaikimisi väärtust: %s Sinu profiil + Profiilipilt Blokeeritud kontaktid + Blokeeritud kontaktid saavad olema leitavad siin. Salasõna ja kasutajakonto Sinu nimi + + Elulugu/allkiri/moto + Sisestusklahv saadab sõnumi Saadetava meediumi kvaliteet + Kõige kehvem kvaliteet, aga väikseim maht + Väristamine + Ekraani turvalisus + Ekraaniturvalisusega seotud seadistuste kasutamisele võtmiseks palun käivita rakendus uuesti. Teavitused + Mainimised + Näita + Prioriteet + Kasuta uute sõnumite puhul süsteemi teavitusi + Näita teavituses sõnumi sisu + Näitab teavituses sõnumi saatjat ja esimesi sõnu + LED-värv + Heli + Vaikne Privaatsus Vestlused ja meediumid Süsteemi vaikimisi valik @@ -613,6 +679,9 @@ Kujundus Keel Kasuta süsteemi kirjatüüpi + Privaatne klahvistik + + Palu, et operatsioonisüsteem ei jätaks meelde klahvistikust sisestatud (aga see ei pruugi alati toimida) Lugemisteatised Kui sinu lugemisteatised on lülitatud välja, siis ka sina ei näe teiste lugemisteatisi. Server @@ -648,9 +717,11 @@ Taustapilt Kasuta vaikimisi pilti Vali galeriist + IMAP-i kaustade kasutamine Välju saadetud sõnumite kausta Saada koopia iseendale Vajalik, kui kasutad seda kontot mitmes seadmes. + Näita klassikalisi e-kirju Katselised funktsionaalsused Arendaja režiim Lülitab sisse veaotsingu tarvikud ja see võib rakenduse töökindlust vähendada. Sobib arendajatele. @@ -704,8 +775,20 @@ Kustuta vanad sõnumid Kustuta sõnumid seadmest Kustuta sõnumid serverist + Ma saan aru, kustuta kõik need sõnumid Kohe peale allalaadimist + 5 minuti järel + 30 minuti järel + 5 tunni järel + 5 päeva järel + 5 nädala järel + 5 nädala järel + 5 aasta järel + + + Saada Autocrypti seadistussõnum + Saada Autocrypti seadistussõnum Eelista läbivat krüptimist Sõnum kasutajalt %1$s @@ -737,14 +820,46 @@ Sina lülitasid sisse oma asukoha jagamise reaalajas. %1$s lülitas sisse oma asukoha jagamise reaalajas. - - %1$s saatis sõnumi muust seadmest. + Sa lülitasid isekustuvate sõnumite taimeri välja. + + %1$s lülitas isekustuvate sõnumite taimeri välja. + + Sa määrasid isekustuvate sõnumite kehtivuseks %1$s sekundit. + + %2$s määras isekustuvate sõnumite kehtivuseks %1$s sekundit. + Sa määrasid isekustuvate sõnumite kehtivuseks 1 minuti. + + %1$s määras isekustuvate sõnumite kehtivuseks 1 minuti. + Sa määrasid isekustuvate sõnumite kehtivuseks 1 tunni. + + %1$s määras isekustuvate sõnumite kehtivuseks 1 tunni. + Sa määrasid isekustuvate sõnumite kehtivuseks 1 päeva. + + %1$s määras isekustuvate sõnumite kehtivuseks 1 päeva. + Sa määrasid isekustuvate sõnumite kehtivuseks 1 nädala. + + %1$s määras isekustuvate sõnumite kehtivuseks 1 nädala. + Sa määrasid isekustuvate sõnumite kehtivuseks 1 aasta. + + %1$s määras isekustuvate sõnumite kehtivuseks 1 aasta. + + Sa määrasid isekustuvate sõnumite kehtivuseks %1$s minutit. + + %2$s määras isekustuvate sõnumite kehtivuseks %1$s minutit. + + Sa määrasid isekustuvate sõnumite kehtivuseks %1$s tundi. + + %2$s määras isekustuvate sõnumite kehtivuseks %1$s tundi. + + Sa määrasid isekustuvate sõnumite kehtivuseks %1$s päeva. + + %2$s määras isekustuvate sõnumite kehtivuseks %1$s päeva. + + Sa määrasid isekustuvate sõnumite kehtivuseks %1$s nädalat. + + %2$s määras isekustuvate sõnumite kehtivuseks %1$s nädalat. Sõnumid on läbivalt krüptitud. Lisateabe ligemiseks klõpsi. Kõik selle vestluse sõnumid on läbivalt krüptitud.\n\nSee tagab, et sõnumid on loetavad vaid sinu ja vestluse teis(t)e osapool(t)e poolt. Ei teenusepakkujad, serverihaldajad, ega põrgatajad ei saa neid sõnumeid lugeda. - - %1$s saatis sõnumi muust seadmest. Lisateabeks klõpsi. - - Läbiv krüptimine pole enam garanteeritud. Ilmselt on põhjuseks see, et %1$s on Delta Chati uuesti paigaldanud või saatnud sõnumi muust seadmest.\n\nParim viis olukorra lahendamiseks on see, kui kohtute omavahel ja sa skaneerid tema QR-koodi ning sellega korrektselt lisad ta uuesti läbivalt krüptitud vestlusesse. ⚠️ %1$s eeldab läbiva krüptimise kasutamist, aga see pole veel antud vestluse jaoks seadistatud. Lisateabe ligemiseks klõpsi. Läbiva krüptimise kasutuselevõtmiseks oarim viis on omavahel kohtuda ning teise osapoole QR-koodi skaneerimisega lisada ta vestlusesse. Lisateave @@ -792,19 +907,11 @@ Kas logid sisse „%1$s“ profiili? Panen aluse läbivale krüptimisele… - - Tagatud läbivat krüptimist ei saa veel luua, aga sa võid juba sõnumit saata. - - Jätkamaks peab kontakt olema hetkel võrgus.\n\nProtsess jätkub automaatselt taustal. %1$s lisas vestlusesse. - - Läbivat krüptimist teise osapoolega (%1$s) ei õnnestu luua. %1$s lisas kontakti vestlusesse Mina lisasin kontakti vestlusesse Vestlusesse lisatud - - %1$s seadistus on muutunud Selleks, et läbiv krüptimine toimiks garanteeritult, sa võid sellesse vestlusesse lisada vaid rohelise linnukesega kontakte.\n\nParim viis on omavahel kohtuda ning teise osapoole QR-koodi skaneerimisega lisada ta vestlusesse. Vali vestlus, kuhu soovid sõnumi saata @@ -814,6 +921,9 @@ Vasta Uus sõnum + Taustal toimiv ühendus on kasutusel + Oluline + Kõik olulisem Nimi ja sõnum Vaid nimi Ei nime ega sõnumit @@ -844,9 +954,6 @@ Pööra teistpidi Pööra - - Krüptitud sõnum - See on Delta Chati ametlik töölauarakendus. See tarkvara on litsentseeritud GNU GPL versiooni 3 alusel ning rakenduse lähtekood on saadaval GitHubis. @@ -915,6 +1022,8 @@ Vigane kohaletoimetamise olek Tegevused sõnumiga Taustapildi eelvaade + Isekustuvad sõnumid on kasutusel + Lõpeta asukoha jagamine Peale salvestamist saad topeltpuudutusega saata. Salvestisest saad loobuda hõõrudes kahe sõrmega. @@ -958,11 +1067,8 @@ Delta Chat soovib pilte salvestada sinu fotode kogusse. Delta Chat võib kasutada Face ID teenust sinu kohaliku profiili kaitsmiseks, varukoopia tegemiseks ja täiendavate seadmete seadistamiseks. - + + Kui soovid, et Delta Chat saaks sõnumeid ka taustateenusena toimides, siis klõpsi siin. Mida on meil uut?\n\n💯 Läbiv krüptimine on töökindel ja seda nüüd igaveseks. Tabalukud 🔒 on läinud!\n\n✉️ Klassikalised e-kirjad, kus läbiv krüptimine on puudu, on märgitud ümbriku ikooniga\n\n😻 Uus ja tõhusam profiilivaade kõikide sinu kontaktide jaoks\n\n🔲 Uus nupp kiireks ligipääsuks vestluses kasutatavate rakendusteni\n\n❤️ Palun toeta meie arendust rahaliselt - nii saame jääda sõltumatuteks ja jätkata selle rakenduse täiustamist: %1$s - - Mida on meil uut?\n\n❤️‍🔥 Uus emojide valija lisaemojidega\n\n🎮 Paremad vestlusesisesed rakendused: saa teavitusi ja ava kontekstuaalseid tugirakendusi, nt. ava otse vajalik kalendrikirje\n\n👍 Teavitused, kui keegi reageerib sinu sõnumitele\n\n... 🛠️ PARANDUSED ja PALJUGI VEEL siin %1$s - - ℹ️ Valik „Vaheta profiili“ on uues kohas: Profiilide lisamiseks ja vahetamiseks klõpsi põhivate ülanurgas asuvat tunnuspilti💡 diff --git a/src/main/res/values-eu/strings.xml b/src/main/res/values-eu/strings.xml index 92fb1f6e4..7af353ae0 100644 --- a/src/main/res/values-eu/strings.xml +++ b/src/main/res/values-eu/strings.xml @@ -4,35 +4,80 @@ Delta Chat Ados Utzi + Garbitu bilaketa + + Esteka + + Eskaneatu Bai Ez + Hautatu Bai Ez - Lehenetsita + Lehenetsia + Lehenetsia (%1$s) + Lehenetsia (aurreko bera) Pertsonalizatua Bat ere ez Automatikoa Zorrotza Ireki + Deskargatu + Deskargatzen... + Erantsitakoa ireki + Batu + Batu berriro Ezabatu + Ezabatu niretzat + Ezabatu denontzat Informazioa Eguneratu Emojia Eranskina + + Erantsi \"%1$s\"? Atzera Itxi + Leihoa itxi Birbidali + Sortu + Berrezarri + Geroago + + Berriro bidali + Editatu egin da + Mezua editatu Artxibatu Berreskuratu artxibotik Isilarazi + Isilarazia Mezuen desagerpena + Txat honetako kide guztiei aplikatzen zaie; mezuak kopiatu, gorde eta birbidali ahal izango dituzte oraindik ere. Gorde Txata Multimedia + Profila + Profil guztiak + Oraingo profila Menu nagusia Hasi txata + Erakutsi mezu osoa + + Ezarri denak irakurri gisa + Ezarri irakurri gisa + + Kargatzen... + Ezkutatu + Aktibatu + Kargatu urrutiko irudiak + + Urrutiko irudiek zure jarraipena egin dezakete.\n\nEzarpen honek letra-tipoak eta beste eduki batzuk ere karga ditzake. Desaktibatuta badago irudi kapsulatuak edo cachean daudenak agertu ahal dira.\n\nKargatu urrutiko irudiak? + Beti + Kargatu urrutiko irudiak beti + Behin + Erakutsi abisua Erakutsi pasahitza Ezkutatu pasahitza Orain ez @@ -40,6 +85,7 @@ Unetxo bat... Egina Desegin + Lineaz kanpo Hurrengoa Errorea @@ -47,6 +93,8 @@ Ezin izan da datu mota hau kudeatzeko aplikaziorik. Ez dago nabigatzailerik instalatuta. Ezin izan da %1$s aurkitu. + + Ezin da %1$s gorde. Arbelera kopiatuta. Kontaktuak E-mail helbidea @@ -62,6 +110,11 @@ Hilabete honetan Azken astea Azken hilabetea + + %1$s-n ikusi da azken + + Azken aldiz begiratua %1$s + Azken aldiz begiratzea: ezezaguna min %d @@ -84,18 +137,42 @@ Mezu %d %d mezu + + Erreakzio %d + %d erreakzio + Kide %d %d kide + + Hartzaile %d + %d hartzaile + + + + %d hautatu da + %d hautatu dira + + Hautaketa: Ni Zirriborroa Irudia + + Erantzuna Gif-a + + Stickerra + Gehitu Sticker bildumara + Stickerretara gehitzeko, klik egin \"Ireki sticker karpeta\" aukeran, sortu azpikarpeta bat zure sticker multzoarentzat eta arrastatu irudi eta sticker fitxategiak bertara. + Ireki sticker karpeta Irudiak Audioa Ahots-mezua + Birbidalia Birbidalitako mezua + + %1$s(e)k birbidalia Bideoa Dokumentuak Kontaktua @@ -262,6 +339,7 @@ Txat honetan partekatutako dokumentuak, musika, eta bestelako fitxategiak agertuko dira hemen Multimediaren aurrebista Bidali mezua + Hasi saioa Hasi saioa zure zerbitzarian Badagoen e-mail kontu batekin saioa hasten @@ -447,10 +525,6 @@ Sortu kontu berria \"%1$s\" zerbitzarian eta saioa han hasi? Eskaneatutako QR kodea ezin da kontu berri bat ezartzeko erabili. %1$s egiaztatuta. - - Ezin da %1$s egiaztatu - - Aldatu %1$s(r)en ezarpena Erantzun Mezu berria @@ -468,9 +542,6 @@ Delta Chat-ek mikrofonoa erabiltzeko baimena behar du ahots-mezuak bidali ahal izateko, baina behin betiko ukatu zaio. Joan aplikazioaren ezarpenetara, hautatu \"Baimenak\" eta gaitu \"Mikrofonoa\". Delta Chat-ek biltegiratze baimena behar du argazkiak, bideoak edo audioa erantsi edo esportatzeko, baina behin betiko ukatu zaio. Joan aplikazioaren ezarpen menura, hautatu \"baimenak\", eta gaitu \"Biltegiratzea\" Delta Chat-ek kokaleku aatzitzeko baimena behar du kokalekua eransteko, baina behin betiko ukatu zaio. Joan aplikazioaren ezarpen menura, hautatu \"baimenak\", eta gaitu \"Kokalekua\". - - Zifratutako mezua - Ongi etorri Delta Chat-era Hautatu hizkuntza... Fitxategia diff --git a/src/main/res/values-fa/strings.xml b/src/main/res/values-fa/strings.xml index eb4e4b193..09d1c98b0 100644 --- a/src/main/res/values-fa/strings.xml +++ b/src/main/res/values-fa/strings.xml @@ -239,12 +239,6 @@ شروع گفتگو با... درست کردن گپ جدید از این گپ - - لیست Broadcast - - لیست‌های Broadcast - - لیست Broadcast جدید کانال @@ -252,12 +246,6 @@ کانال جدید افزودن گیرنده - - ویرایش فهرست Broadcast - - نام فهرست BroadCast - - وارد کردن نام برای فهرست Broadcast. نام کانال @@ -429,8 +417,6 @@ https://meet.jit.si/$ROOM گپ زدن با %1$s؟ حذف %1$s از گروه؟ - - آيا%1$s از لیست Broadcast پاک شود؟ حذف %1$s از کانال؟ آیا می‌خواهید این لینک را باز کنید؟ @@ -462,8 +448,6 @@ https://meet.jit.si/$ROOM ارسال پیام. مشکلی نیست اگر %1$s از دلتاچت استفاده نمی‌کند. - - در یک فهرست Broadcast گیرنده‌ها در یک گپ فقط خواندنی با شما، پیام‌ها را دریافت می‌کنند. کانال‌ها یک ابزار یک به چند برای اعلام عمومی پیام‌هایتان هستند. نوشتن اولین پیام به دیگران امکان می‌دهد در این گروه پاسخ دهند. \n\n• مشکلی نیست اگر همه اعضا از دلتاچت استفاده نکنند\n\n• دریافت اولین پیام ممکن است به زمان بیشتری نیاز داشته باشد. @@ -574,11 +558,6 @@ https://meet.jit.si/$ROOM جدول مربعی ارسال پیام - - مخاطب %1$s نشانی خود را از %2$s به %3$s تغییر داده است. - - شما نشانی رایانامهٔ خود را از %1$s به %2$s تغییر دادید.\n\nاگر به یک گروه تأیید شده پیام بفرستید، مخاطبان آن به صورت خودکار نشانی جدید را جایگزین نشانی پیشین می‌کنند.\n\nبه شدت توصیه می‌شود که نشانی رایانامهٔ پیشین خود را به نحوی تنظیم کنید که تمام رایانامه‌ها را به نشانی جدید شما هدایت کند؛ در غیر این صورت ممکن است پیام‌های مخاطبانی که از تغییر نشانی شما مطلع نشده‌اند را از دست بدهید. - @@ -977,12 +956,8 @@ https://meet.jit.si/$ROOM زمان‌سنج ناپدید شدن پیام‌ها را روی %1$s هفته تنظیم کردید. زمان‌سنج ناپدید شدن پیام‌ها توسط %2$s روی %1$s هفته تنظیم شد. - - %1$s پیامی را از دستگاه دیگری ارسال کرد. رمزنگاری سرتاسر پیام ها از این به بعد تضمین می شود. برای اطلاعات بیشتر ضربه بزنید. رمزنگاری سراسری پیام‌های این گفتگو اکنون تضمین می‌شود. رمزنگاری سراسری باعث می‌شود پیام‌هایتان بین شما و مخاطبین شما محرمانه بماند. حتی ارائه‌دهندهٔ رایانامه شما هم نمی‌تواند آن‌ها را بخواند. - - %1$s پیامی را از دستگاه دیگری ارسال کرد. برای اطلاعات بیشتر ضربه بزنید. ⚠️ %1$s به رمزنگاری سراسری نیاز دارد که هنوز برای این گپ پیکره‌بندی نشده است. برای یادگیری بیش‌تر این‌جا بزنید. برای برقراری رمزنگاری سراسری، می‌توانید به صورت حضوری با مخاطب‌های خود دیدار کنید و کد کیوآر آن‌ها را برای معرفی اسکن کنید. بیشتر بدانید @@ -1048,18 +1023,10 @@ https://meet.jit.si/$ROOM کاربر %1$s پاسخ داد، در انتظار اضافه شدن به گروه... در حال برقراری رمزگذاری سراسری تضمین‌شده، لطفا صبر کنید... - - اکنون نمی توانیم رمزگذاری سراسری تضمین‌شده را برقرار کنیم. با این وجود می‌توانید پیام ارسال کنید. - - برای ادامه، مخاطب باید برخط باشد.\n\nاین فرآیند به صورت خودکار در پس‌زمینه ادامه خواهد داشت. %1$s تأیید شد. - - امکان تایید رمزگذاری در مبدا، برای %1$sوجود ندارد. احراز هویت شده توسط %1$s تأیید شده توسط من - - تنظیم‌ها برای %1$s تغییر کرد. برای تضمین رمزنگاری سراسری شما تنها می‌توانید مخاطب‌هایی که یک تیک سبز دارند به این گروه اضافه کنید.\n\nمی‌توانید با مخاطب‌هایتان حضوری ملاقات کنید و برای معرفی، کد QR آن‌ها را اسکن کنید. گپ را برای ارسال پیام انتخاب کنید @@ -1114,9 +1081,6 @@ https://meet.jit.si/$ROOM برعکس کردن چرخاندن - - پیام رمزگذاری شده - این نرم‌افزار رسمی دلتاچت در محیط رایانه است. این نرم افزار تحت مجوز @@ -1225,7 +1189,6 @@ GNU GPL ورژن ۳ دلتاچت میخواهد تصاویر را در آلبوم شما ذخیره کند. دلتاچت می‌تواند از عکس چهرهٔ شما برای محافظت از نمایهٔ محلی، ساخت نسخهٔ پشتیبان و پیکره‌بندی دستگاه دوم استفاده کند. - تحویل آنی استفاده از اتصال پس‌زمینه diff --git a/src/main/res/values-fi/strings.xml b/src/main/res/values-fi/strings.xml index 150b1f608..98d101bc9 100644 --- a/src/main/res/values-fi/strings.xml +++ b/src/main/res/values-fi/strings.xml @@ -199,19 +199,7 @@ Uusi keskustelu Uusi ryhmä Kloonaa keskustelu - - Kuulutuslista - - Kuulutuslistat - - Uusi kuulutuslista Lisää vastaanottajia - - Muokkaa kuulutuslistaa - - Kuulutuslistan nimi - - Anna kuulutuslistalle nimi. Lähetä Näytä emoji-näppäimistö Muokkaa ryhmää @@ -343,8 +331,6 @@ Aloita keskustelu yhteystiedon %1$s kanssa? Poista %1$s ryhmästä? - - Poista %1$s kuulutuslistalta? Haluatko avata tämän linkin? @@ -374,8 +360,6 @@ Lähetä viesti. Ei haittaa, vaikka %1$s ei käyttäisi Delta Chatia. - - Kuulutuslistalla vastaanottajat saavat viestit keskusteluna kanssasi, jossa heillä on vain lukuoikeus. Muut näkevät ryhmän vasta, kun lähetät ensimmäisen viestin. Pyyhkäise peruuttaaksesi Pidä painettuna nauhoittaaksesi ääniviestin, irrota lähettääksesi @@ -473,11 +457,6 @@ Neliöruudukko Lähetä viesti - - %1$s vaihtui osoitteesta %2$s osoitteeksi %3$s - - Vaihdoit sähköpostiosoitteesi osoitteesta %1$s osoitteeksi %2$s.\n\nJos lähetät viestin vahvistettuun ryhmään, ryhmän jäsenet saavat automaattisesti uuden osoitteesi.\n\nOn suositeltavaa asettaa vanha tilisi välittämään kaikki viestit uuteen osoitteeseesi. Muuten et välttämättä saa viestejä niiltä yhteystiedoiltasi, joilla ei ole uutta osoitettasi. - @@ -844,14 +823,8 @@ Katoavien viestien ajastin asetettu %1$s viikkoon minun toimestani. Katoavien viestien ajastin asetettu %1$s viikkoon käyttäjän %2$s toimesta. - - %1$s lähetti viestin toiselta laitteelta. Tästä eteenpäin viestit on taatusti päästä-päähän salattuja. Lisätietoja napauttamalla. Kaikki viestit tässä keskustelussa ovat taatusti päästä-päähän salattuja.\n\nPäästä-päähän -salaus pitää viestisi sinun ja keskustelukumppanisi välillä. Edes sähköpostipalveluntarjoaja ei pysty niitä lukemaan. - - %1$s lähetti viestin toiselta laitteelta. Lue lisää napauttamalla. - - Päästä päähän salausta ei voida enää taata, todennäköisesti koska %1$s uudelleenasensi Delta Chatin tai lähetti viestin toiselta laitteelta.\n\nTapaamalla hänet voit skannata hänen QR -koodinsa uudelleen päästä-päähän salauksen palauttamiseksi. ⚠️ %1$s vaatii päästä-päähän -salausta joka ei enää ole käytössä tässä keskustelussa. Lue lisää napauttamalla. Päästä-päähän salauksen saat käyttöön tapaamalla yhteystietosi ja skannaamalla hänen QR -koodinsa. Lue lisää @@ -910,16 +883,10 @@ Vastaus saatu käyttäjältä %1$s, odotetaan lisäystä ryhmään... Otetaan taattua päästä-päähän salausta käyttöön, odota... - - Taattua päästä päähän salausta ei vielä voitu ottaa käyttöön, mutta voit jo lähettää viestin. %1$s varmistettu. - - Keskustelun päästä-päähän -salausta ei voida taata henkilön %1$s kanssa. %1$s lisäsi Lisäämäni - - Asetukset muutettu kohteessa %1$s. Päästä-päähän -salauksen takaamiseksi, voit lisätä ryhmään ainoastaan yhteystietoja joilla on vihreä \"oikein\" -merkki.\n\nVoit tavata yhteystietoja kasvotusten ja skannata heidän QR -koodinsa niin saat lisättyä salauksen käyttöön Valitse keskustelu viestien lähettämiseen @@ -962,9 +929,6 @@ Käännä Pyöritä - - Salattu viesti - Tämä on virallinen Delta Chat -työpöytäsovellus. Tämä ohjelmisto on GNU GPL v3 -lisensoitu, ja lähdekoodi on saatavilla GitHubissa. diff --git a/src/main/res/values-fr/strings.xml b/src/main/res/values-fr/strings.xml index deeb13254..46e97bc6a 100644 --- a/src/main/res/values-fr/strings.xml +++ b/src/main/res/values-fr/strings.xml @@ -233,19 +233,7 @@ Discuter avec... Cloner la discussion - - Liste de diffusion - - Listes de diffusion - - Nouvelle liste de diffusion Ajouter des destinataires - - Modifier la liste de diffusion - - Nom de la liste de diffusion - - Entrez un nom pour la liste de diffusion. Envoyer Basculer le clavier emoji Modifier le groupe @@ -394,8 +382,6 @@ Discuter avec %1$s ? Retirer %1$s du groupe ? - - Retirer %1$s de la liste de diffusion ? Voulez-vous ouvrir ce lien ? @@ -428,8 +414,6 @@ Envoyez un message. Il n\'y a pas de problème si %1$s n\'utilise pas Delta Chat. - - Dans une liste de diffusion, les destinataires reçoivent les messages dans une discussion avec vous en lecture seule. Les autres participants ne verront ce groupe qu\'après que vous avez envoyé un premier message. Glisser pour annuler Appuyer et maintenir pour enregistrer un message vocal, relâcher pour l’envoyer @@ -537,11 +521,6 @@ Grille de photos carrées Envoyer message - - %1$s a changé son adresse de %2$s à %3$s - - Vous avez changé votre adresse courriel de %1$s à %2$s.\n\nSi vous envoyez maintenant un message à un groupe connu, votre ancienne adresse sera automatiquement remplacée par la nouvelle chez tous vos contacts dans ce groupe.\n\nIl est fortement conseillé de configurer votre ancien fournisseur de courriel de sorte à transférer tous vos courriels à votre nouvelle adresse. Sinon, vous risquez de manquer des messages de contacts qui n\'ont pas encore reçu votre nouvelle adresse. - @@ -929,14 +908,8 @@ Vous avez réglé le temps d\'affichage des messages éphémères à %1$s semaines. Minuterie des messages éphémères réglée à %1$s semaines par %2$s. - - %1$s a envoyé un message depuis un nouvel appareil. Les messages sont désormais garantis chiffrés de bout en bout. Appuyer pour en savoir plus. Il n\'est pas garanti que tous les messages de cette discussion sont chiffrés de bout en bout.\n\nLe chiffrement de bout en bout assure la confidentialité des messages échangés par les membres d\'une discussion. Même votre fournisseur de courriel ne peut pas les lire. - - %1$s a envoyé un message depuis un nouvel appareil. Appuyez pour en savoir plus. - - Le chiffrement de bout en bout ne peut plus être garanti, probablement parce que %1$s a réinstallé Delta Chat ou envoyé un message depuis un nouvel appareil.\n\nVous pouvez convenir d\'une rencontre physique afin de scanner à nouveau son code QR pour ré-instaurer la garantie du chiffrement de bout en bout. ⚠️ %1$s nécessite un chiffrement de bout en bout qui n\'est pas encore configuré sur cette discussion. Appuyez pour en savoir plus. Pour établir un chiffrement de bout en bout vous pouvez rencontrer vos contacts en personne et scanner leur code QR. En savoir plus @@ -995,16 +968,10 @@ %1$s a répondu, en attente d’être ajouté au groupe… Chiffrement de bout en bout en cours d\'établissement, merci de patienter... - - Le chiffrement de bout en bout n\'est pas encore garanti, mais vous pouvez déjà envoyer un message. %1$s connu. - - Impossible de garantir le chiffrement de bout en bout avec %1$s. Connu par %1$s Connu par vous - - Configuration modifiée pour %1$s Pour garantir le chiffrement de bout en bout, vous pouvez ajouter à ce groupe uniquement les contacts avec un badge vert.\n\nVous pouvez rencontrer ces contacts en personne pour scanner leur code QR et les ajouter à votre liste de contacts connus. Sélectionnez une discussion à qui envoyer le message @@ -1047,9 +1014,6 @@ Tourner Pivoter - - Message chiffré - Ceci est l\'application de bureau Delta Chat officielle. Ce logiciel est sous licence GNU GPL version 3 et le code source est disponible sur GitHub. diff --git a/src/main/res/values-gl/strings.xml b/src/main/res/values-gl/strings.xml index 6c736bfae..c557cb5bc 100644 --- a/src/main/res/values-gl/strings.xml +++ b/src/main/res/values-gl/strings.xml @@ -30,10 +30,12 @@ Eliminar Eliminar para min Eliminar para todas - Infor + Info Actualizar Emoji Anexo + + Anexar \"%1$s\"? Atrás Pechar Fechar xanalela @@ -51,12 +53,15 @@ Desarquivar Acalar Acalada - Desaparición das mensaxes + Desaparición de Mensaxes Estos axustes aplícanse a todas as participantes que usan Delta Chat. Porén, elas poderían copiar, gardar e reenviar mensaxes ou usar outros clientes de email. Gardar Chat Medios + Apps & Multimedia Perfil + Todos os Perfís + Perfil Actual Menú principal Inciar chat Mostrar mensaxe completa… @@ -91,6 +96,8 @@ Non se atopa unha app para este tipo de datos. Sen navegador instalado. Non se atopou %1$s. + + Non se puido gardar %1$s. Copiado ao portaretallos. Contactos Enderezo de correo @@ -187,8 +194,8 @@ App privada Apps privadas - URL do Selector de adhesivos - Se está establecido o URL vaise usar como Selector de adhesivos no lugar do predeterminado + URL do Selector de Apps + Se está establecido o URL vaise usar como Selector de apps no lugar do predeterminado Inicio Xogos Ferramentas @@ -227,13 +234,20 @@ Conversar con… Clonar conversa - - Lista de difusión - - Listas de difusión - - Nova lista de difusión + + Canle + + Canles + + Nova Canle Engadir correspondentes + + Nome da Canle + Email + + Novo email + + Asunto Enviar Activar teclado emoji Editar grupo @@ -243,6 +257,7 @@ Restaurar conversa Engadir anexo Deixar grupo + Saír da canle Eliminar conversa Limpar Chat @@ -269,6 +284,7 @@ Exportar anexo Exportar anexos Todos os medios + Todas as Apps & Multimedia Mostrar na conversa Mostrar App na conversa @@ -359,6 +375,9 @@ Convite a chat de vídeo Convidáronte a un chat de vídeo, preme %1$s para unirte. + + + Tes a certeza de querer saír? Eliminar %d conversa en todos os teus dispositivos? Eliminar %d conversas en todos os teus dispositivos? @@ -384,8 +403,8 @@ Conversa con %1$s? Eliminar %1$s do grupo? - - Eliminar %1$s da lista de difusión? + + Eliminar %1$s da canle? Queres abrir esta ligazón? @@ -415,6 +434,8 @@ Envía unha mensaxe. Funciona incluso se %1$s non usa Delta Chat. + + Canles son unha ferramenta de-un-para-moitos para difundir as túas mensaxes. Escribe a primeira mensaxe, permita a outras responder a este grupo.\n\n• Da igual se outros membros non utilizan Delta Chat.\n\n• A entrega da primeira mensaxe podería demorarse un pouco. Desliza para cancelar Toca e mantén para gravar mensaxe de voz, solta para enviar @@ -522,17 +543,12 @@ Grella cadrada Enviar mensaxe - - %1$s cambiou o seu enderezo de %2$s a %3$s - - Cambiaches o teu enderezo de email de %1$s a %2$s.\n\nSe envías unha mensaxe a un grupo verificado os contactos cambiarán automáticamente o enderezo antigo polo novo.\n\nÉ moi recomendable que configures o email antigo para que che reenvíe todo o correo ao novo enderezo. De non facelo poderías perder mensaxes de contactos que aínda non coñezan o teu novo enderezo. - Engadir segundo dispositivo Comproba que os dous dispositivos estean na mesma Wi-Fi ou rede - Isto crea un código QR que hai que escanear co segundo dispositivo para copiar o perfil.\n\nComproba que non hai ninguén mirando ou unha cámara que poid ver a seguinte pantalla. + Isto crea un código QR que hai que escanear co segundo dispositivo para copiar o perfil.\n\nComproba que non hai ninguén mirando ou unha cámara que poida ver a seguinte pantalla. Instala Delta Chat no teu outro dispositivo (https://get.delta.chat) Inicia Delta Chat, toca en \"Xa teño un perfil / Engadir como segundo dispositivo\" e escanea este código @@ -633,6 +649,8 @@ Eliminar Proxy Tes certeza de querer eliminar \"%1$s\"? Queres usar o proxy \"%1$s\"? + Compartir ligazón + Continuar co axuste simplificado? O enderezo introducido soporta o axuste simplificado (OAuth 2.0).\n\nNo seguinte paso, permite a Delta Chat actuar como app de Conversa sobre Correo-e.\n\nNon hai servidores Delta Chat, os teus datos permanecen no dispositivo. Comprobacións do certificado @@ -662,6 +680,8 @@ Reenviar a… + + Enviar %1$d ficheiros para \"%2$s\"? Enviar %1$d ficheiro(s) a %2$d conversas? Enviar este texto a %1$d conversas?\n\n\"%2$s\" Cancelouse a compartición debido a falta de permisos. @@ -681,7 +701,7 @@ Texto de firma A tecla Enter envía Ao premer Enter enviarás a mensaxe - Calidade dos medios saíntes + Calidade de Multimedia Enviados Equilibrado Menor calidade, tamaño pequeno Vibrar @@ -690,12 +710,14 @@ Solicitar bloqueo de captura de pantalla para a lista de recentes e dentro da app Para aplicar o axuste de seguridade da pantalla debes reiniciar a app. Notificacións + Mención + En grupos acalados, notificar de mensaxes dirixidas a ti, como respostas ou reaccións Mostrar Prioridade Activa as notificación para as novas mensaxes Motra o contido da mensaxe na notificación Mostra a remitente e as primeiras palabras da mensaxe na notificación - cor LED + Cor LED Son Mudo Intimidade @@ -707,11 +729,13 @@ Aspecto Decorado Idioma + Utilizar Fonte do Sistema Teclado incógnito Solicitar que o teclado non aprenda palabras escritas Confirmación de lectura Se a confirmación de lectura está desactivada, non poderás ver as confirmacións dos demais. + Servidor Xestión das chaves Utilizar emoji do sistema Desactivar o soporte interno para emoji de Delta Chat @@ -724,7 +748,11 @@ Outro Respaldo Respaldar conversas na almacenaxe externa - Un respaldo axúdache a configurar unha nova instalación en este ou outro dispositivo.\n\nO respaldo contén as mensaxes, contactos e conversas e os axustes de cifrado extremo-a-extremo Autocrypt. Garda o ficheiro de respaldo nun lugar seguro ou bórrao tan pronto sexa posible. + Un respaldo axúdache a configurar unha nova instalación neste ou noutro dispositivo.\n\nO respaldo contén as mensaxes, contactos e conversas e os axustes de cifrado extremo-a-extremo Autocrypt. Garda o ficheiro de respaldo nun lugar seguro ou bórrao tan pronto sexa posible. + + Exportar %1$s + + Exportar todos os %1$d perfís Inciar respaldo Respaldo gardado en \"%1$s\". Xestionar chaves @@ -753,7 +781,7 @@ Todos Zona de probas Difusión da ubicación por solicitude - Modo desenvolvemento + Modo Desenvolvemento Activa opcións de depuración e pode desestabilizar a app. Só para desenvolvedoras. Fondo por omisión Cor por omisión @@ -763,18 +791,22 @@ Descarga automática de mensaxes Ata %1$s - Ata %1$s, a maioría de imaxes da peor calidade - Ata %1$s, a maioría de imaxes de calidade equilibrada + Ata %1$s, a maioría de imaxes da menor calidade + Ata %1$s, a maioría de imaxes de calidade media Fallou a descarga %1$s mensaxe Descarga o máximo dispoñible ata %1$s + Seleccionar Perfil Elixe imaxe de perfil Elixe a túa nova imaxe de perfil Elimina a imaxe de perfil Mostrar icona na bandexa Editar perfil + Enviar estatísticas ós desenvolvedores do Delta Chat + + Resultados da busca Non se atopan emojis @@ -788,19 +820,23 @@ Símbolos Bandeiras + + Reaccións + + Reaxir Eliminar mensaxes antigas Borrar mensaxes do dispositivo Borrar mensaxes do servidor - Queres borrar %1$d mensaxes agora e todas as novas mensaxes \"%2$s\" no futuro?\n\n• Esto inclúe todo o multimedia\n\n• As mensaxes borraranse fosen lidas ou non\n\n• As \"mensaxes gardadas\" non será borradas do dispositivo. + Queres borrar %1$d mensaxes agora e todas as novas mensaxes \"%2$s\" no futuro?\n\n• Esto inclúe todo o multimedia\n\n• As mensaxes borraranse fosen lidas ou non\n\n• As \"mensaxes gardadas\" non serán borradas do dispositivo. Desexas eliminar %1$d mensaxes e todas as \"%2$s\" novas mensaxes obtidas no futuro?\n\n⚠️ Esto inclúe emails, multimedia e \"Mensaxes gardadas\" en tódolos cartafoles do servidor\n\n⚠️ Non uses esta función se queres manter os datos gardados no servidor\n\n⚠️ Non uses esta función se estás a utilizar outro cliente de email ademáis de Delta Chat Esto inclúe emails, multimedia e \"Mensaxes gardadas\" en tódolos cartafoles do servidor. Non uses esta función se queres manter os datos gardados no servidor ou se estás a utilizar outro cliente de email ademáis de Delta Chat. Entendo, dalle e borra as mensaxes todas - dunha vez + Logo despois de descargar Após 30 segundos Após 1 minuto Após 5 minutos @@ -829,6 +865,8 @@ Imaxe do grupo cambiada por %1$s. + Membro %1$s adicionado/a. + Engadiches un membro %1$s. %1$s engadido por %2$s. @@ -836,6 +874,8 @@ Eliminaches a %1$s. %1$s eliminado por %2$s. + + Saíches. %1$s deixou o grupo. Eliminaches a imaxe do grupo @@ -852,6 +892,36 @@ O temporizador de desaparición de mensaxes establecido en %1$s segundos por %2$s. Puxeches en 1 minuto o temporizador de desaparición de mensaxes. + + Temporizador de desaparición de mensaxes definido en 1 minuto por %1$s. + Definiches o temporizador de desaparición de mensaxes en 1 hora. + + Temporizador de desaparición de mensaxes definido en 1 hora por %1$s. + Definiches o temporizador de desaparición de mensaxes en 1 día. + + Temporizador de desaparición de mensaxes definido en 1 día por %1$s. + Definiches o temporizador de desaparición de mensaxes en 1 semana. + + Temporizador de desaparición de mensaxes definido en 1 semana por %1$s. + Definiches o temporizador de desaparición de mensaxes en 1 ano. + + Temporizador de desaparición de mensaxes definido en 1 ano por %1$s. + + Definiches o temporizador de desaparición de mensaxes en %1$s minutos. + + Temporizador de desaparición de mensaxes definido en %1$s minutos por %2$s. + + Definiches o temporizador de desaparición de mensaxes en %1$s horas. + + Temporizador de desaparición de mensaxes definido en %1$s horas por %2$s. + + Definiches o temporizador de desaparición de mensaxes en %1$s días. + + Temporizador de desaparición de mensaxes definido en %1$s días por %2$s. + + Definiches o temporizador de desaparición de mensaxes en %1$s semanas. + + Temporizador de desaparición de mensaxes definido en %1$s semanas por %2$s. Eliminaches o chat \"Mensaxes gardadas\".\n\nℹ️ Para usar \"Mensaxes gardadas\" de novo, crea un novo chat contigo mesmo. ⚠️ A almacenaxe do teu provedor vaise esgotar, xa utilizaches %1$s %%.\n\nPode que non recibas mensaxes cando a almacenaxe chegue a 100%% utilizado.\n\n👉 Mira se podes eliminar datos antigos na interface web do teu provedor e pensa se debes activar \"Axustes / Eliminar Mensaxes Antigas\". Podes ver a almacenaxe actual utilizada en \"Axustes / Conectividade\". @@ -893,16 +963,19 @@ Sen conexión a internet, non se pode facer o axuste por código QR Crear un novo enderezo de correo en \"%1$s\" e acceder ali? Crear un novo enderezo de email en \"%1$s\" e acceder?\n\nNon se eliminará a conta actual. Usa \"Cambiar de conta\" para cambiar entre as túas contas. + Define un nome recoñecíbel polos teus contactos. Tamén podes definir unha imaxe de perfil. + Por favor introduce un nome. O código QR escaneado non se pode utilizar para crear unha nova conta. %1$s convidoute a este grupo.\n\nAgardando a que responda o dispositivo de %2$s ... %1$s respondeu, agardando a que sexa engadido ao grupo... %1$s verificado. - - Non se puido verificar %1$s. - - Cambiaron os axustes para %1$s. + + Introducido/a por %1$s + Introducido/a por min + Introducido/a + Para garantir cifrado extremo-a-extremo, só podes adicionar contactos com un visto verde a este grupo.\n\nPodes encontrarche con contactos en persoa e escanear os seus códigos QR para os introducir. Elexir chat ao que enviar a mensaxe %1$s xa ten un borrador, queres susbstituílo? @@ -912,11 +985,18 @@ Responder Nova mensaxe Conexión en segundo plano establecida - Alto + Alta Máx Nome e mensaxe Só nome Sen nome ou mensaxe + Notificacións desactivadas + Novas mensaxes + + Tes novas mensaxes + %1$dmensaxes en %2$d conversas + + Permiso requerido Continuar @@ -925,6 +1005,8 @@ Para enviar mensaxes de voz, vaite aos axustes da app, escolle \"Permisos\" e activa \"Micrófono\". Para recibir ou enviar ficheiros, vaite aos axustes da app, escolle \"Permisos\" e activa \"Almacenaxe\". Para engadir a localización, vaite aos axustes da app, escolle \"Permisos\" e activa \"Localización\". + Para recibir notificacións, vai a \"Axustes de Sistema / Apps / Delta Chat\" e activa as \"Notificacións\". + Debuxa para esborranchar Engadir texto @@ -935,9 +1017,6 @@ Voltear Rotar - - Mensaxe cifrada - Esta é a app oficial de Escritorio para Delta Chat Este software está baixo licenza GNU GPL versión 3 e o código fonte está dispoñible en GitHub. @@ -953,10 +1032,12 @@ Pegar Ver Poñer arriba - Desenvolvedora - Ferramentas de desenvolvedora + Desenvolvedor + Ferramentas de Desenvolvemento Axuda - Informa dun fallo + Páxina principal do Delta Chat + Contribuír + Informar dun fallo Acerca de Delta Chat Abrir Delta Chat Minimizar @@ -1026,6 +1107,10 @@ De media cada %1$d minutos De media cada %1$d horas Comprobado en %1$s + Axustes do Sistema + + + Atallos Conceder acceso a cámara permíteche tomar fotos e vídeos. Permitir o acceso a libreta de enderezos permíteche conversar con contactos do dispositivo. @@ -1034,9 +1119,18 @@ Permitindo o acceso ao micrófono poderás gravar audio. Permitindo o acceso a galería de fotos poderás subir imaxes desde ela. Delta Chat quere gardar imaxes na galería de fotos. + + Entrega Instantánea + Usar Conexión en Segundo Plano + Necesita de ignorar optimizacións de batería, usa se as notificacións non chegan a tempo + Forzar Conexión en Segundo Plano + Mostra unha notificación permanente + Para manter a conexión co servidor de correo e recibir mensaxes en segundo plano, ignora as optimizacións de batería no seguinte paso.\n\nDelta Chat utiliza moi poucos recursos e preocúpase de non esgotar a batería. Toca aquí para recibir mensaxes mentras Delta Chat está en segundo plano. Xa permitiches que Delta Chat reciba mensaxes en segundo plano\n\nSe aínda así non recibes as mensaxes, por favor comproba os axustes do sistema. - + + Que hai de novo?\n\n💯 Agora cifrado extremo-a-extremo é de fiar e para sempre. Non hai máis cadeados 🔒!\n\n✉️ Emails clásicos sen cifrado extremo-a-extremo son marcados con unha carta\n\n😻 Nova páxina de perfil mellorada para todos os teus contactos\n\n🔲 Novo botón de acceso rápido a apps usadas nun chat\n\n❤️ Por favor doa para continuarmos independentes e a mellorar: %1$s + diff --git a/src/main/res/values-hu/strings.xml b/src/main/res/values-hu/strings.xml index 80e831730..9e8ffe0c4 100644 --- a/src/main/res/values-hu/strings.xml +++ b/src/main/res/values-hu/strings.xml @@ -240,12 +240,6 @@ Csevegés vele… Csevegés klónozása - - Adáslista - - Adásliták - - Új adáslista Csatorna @@ -253,12 +247,6 @@ Új csatorna Címzettek hozzáadása - - Adáslista szerkesztése - - Adáslista neve - - Adjon meg egy nevet az adáslistának Csatorna neve E-mail @@ -424,8 +412,6 @@ Csevegés vele: %1$s? Eltávolítja a csoportból őt: %1$s? - - Eltávolítja az adáslistából őt: %1$s? Eltávolítja a csatornából a következőt: %1$s? Biztosan megnyitja ezt a hivatkozást? @@ -457,8 +443,6 @@ Üzenet küldése „%1$s” számára. - - Az adáslistán a címzettek csak olvasható módban kapják meg az üzeneteket öntől. A csatornák egy blogszerű eszköz az üzenetek megosztására a közönséggel. Mások csak az első üzenet elküldése után fogják látni ezt a csoportot. @@ -569,11 +553,6 @@ Négyzetrács Üzenet küldése - - %1$s megváltoztatta a címét következőről: %2$s, erre: %3$s - - Ön megváltoztatta a saját e-mail-címét erről: %1$s erre: %2$s.\n\nHa most üzenetet küld egy hitelesített csoportba, az ottani partnerei automatikusan lecserélik az Ön régi címét az új címére.\n\nEzért nagyon ajánlott beállítani, hogy a régi e-mail-szolgáltatója továbbítsa-e az összes e-mailt az e-mail-címére. Ellenkező esetben lemaradhat azoknak a partnereinek az üzeneteiről, akik még nem kapták meg az új címét. - @@ -734,10 +713,10 @@ Letiltott névjegyek A letiltott névjegyek itt fognak megjelenni Fiók és jelszó - A profilképe, neve és életrajza az üzenetekkel együtt kerül elküldésre, amikor más felhasználókkal kommunikál. + A profilképe, neve és névjegye az üzenetekkel együtt kerül elküldésre, amikor más felhasználókkal kommunikál. Név - Életrajz + Névjegy Küldés „Enterrel” Az „Enter” billentyű megnyomásával szöveges üzeneteket küldhet Kimenő média minősége @@ -956,6 +935,9 @@ Ön az eltűnő üzenetek időzítőjét 1 hétre állította be. %1$s az eltűnő üzenetek időzítőjét 1 hétre állította be. + Ön az eltűnő üzenetek időzítőjét 1 évre állította be. + + %1$s az eltűnő üzenetek időzítőjét 1 évre állította be. Ön az eltűnő üzenetek időzítőjét %1$s percre állította be. @@ -972,14 +954,8 @@ Ön az eltűnő üzenetek időzítőjét %1$s hétre állította be. %2$s az eltűnő üzenetek időzítőjét%1$s hétre állította be. - - %1$s egy másik eszközről küldött üzenetet. Az üzenetek mostantól garantáltan titkosítva lesznek a végpontok között. Koppintson, ha többet szeretne tudni. Mostantól garantált, hogy ebben a csevegésben az összes üzenet végpontok közötti titkosítással rendelkezik.\n\nA végpontok közötti titkosítással az üzenetek bizalmasak maradnak Ön és a partnerei között. Még az e-mail-szolgáltatója sem tudja elolvasni őket. - - %1$s egy másik eszközről küldött üzenetet. Koppintson, ha többet szeretne tudni. - - A végpontok közötti titkosítás már nem garantálható, valószínűleg azért, mert %1$s újratelepítette a Delta Chatet, vagy egy másik eszközről küldött üzenetet.\n\n Személyesen találkozhat vele, és újra beolvashatja a QR-kódját a garantált végpontok közötti titkosítás visszaállításához. ⚠️ A(z) %1$s végpontok közötti titkosítást igényel, ami még nincs beállítva erre a csevegésre. Koppintson, ha többet szeretne megtudni. A végpontok közötti titkosítás létrehozásához személyesen is találkozhat a partnereivel, és a QR-kódjukat beolvasva bemutathatja őket. Tudjon meg többet @@ -1038,19 +1014,11 @@ %1$s válaszolt, várakozik, hogy fölvegyék a csoportba… Garantált végpontok közötti titkosítás létrehozása, várjon… - - Még nem sikerült a garantált végpontok közötti titkosítást létrehozni, de már küldhet üzenetet. - - Úgy tűnik, hogy ez tovább tart, mint gondoltuk, talán a partnere vagy Ön offline állapotban van.\n\nMindenesetre a folyamat a háttérben folytatódik, eközben csinálhat valami mást… %1$s bemutatva. - - Nem lehet garantált végpontok közötti titkosítást létrehozni vele: %1$s. %1$s által bemutatva Ön által bemutatva Bemutatva - - Megváltoztatta a beállításokat %1$s számára. A végpontok közötti titkosítás garantálása érdekében csak zöld jelöléssel rendelkező névjegyeket adhat hozzá ehhez a csoporthoz.\n\n Személyesen is találkozhat a partnereivel és beolvashatja a QR-kódjukat, hogy bemutassa őket. Válassza ki a csevegést az üzenet elküldéséhez @@ -1093,9 +1061,6 @@ Tükrözés Forgatás - - Titkosított üzenet - Ez a hivatalos Delta Chat Desktop alkalmazás. Ez a szoftver a GNU GPLv3 licenc alatt áll és a forráskód elérhető a GitHubon. @@ -1210,7 +1175,6 @@ A Delta Chat el akarja menteni a képeket az eszköze fotótárába. A Delta Chat használhatja az arcfelimerést az Ön helyi profiljának biztonsági mentésének létrehozásához és a második eszköz biztonságos beállításához. - Azonnali kézbesítés Háttérkapcsolat használata @@ -1225,9 +1189,4 @@ Újdonságok:\n\n💯 A végpontok közötti titkosítás most már megbízható és örökre megmarad. A lakatok 🔒 eltűntek!\n\n✉️ A végpontok közötti titkosítás nélküli klasszikus e-mailek betűszimbólummal vannak jelölve\n\n😻 Új, továbbfejlesztett profilképernyő az összes névjegyhez\n\n🔲 Új gomb a csevegésben használt alkalmazások gyors eléréséhez\n\n❤️ Ha teheti, adományozzon nekünk, hogy függetlenek maradhassunk és továbbra is fejlesztéseket tudjunk végrehajtani: %1$s - - Mik az újdonságok?\n\n❤️‍🔥 Új emodzsi-választó még több emodzsival\n\n🎮 Továbbfejlesztett, a csevegésben használható alkalmazások: Értesítéseket kaphat és megnyithatja az azokat támogató alkalmazásokban, azaz közvetlenül megnyithat egy hozzáadott naptárbejegyzést\n\n👍 Értesítést kaphat az üzeneteire adott reakciókról\n\n… 🛠️ Egyéb javítások, tudjon meg többet itt: %1$s - - ℹ️ A „Profilváltás” beállítás át lett helyezve: -Érintse meg a főképernyő felső sarkában lévő profilképet a profilok hozzáadásához vagy váltásához 💡 diff --git a/src/main/res/values-in/strings.xml b/src/main/res/values-in/strings.xml index 3a30b5055..b9e70170a 100644 --- a/src/main/res/values-in/strings.xml +++ b/src/main/res/values-in/strings.xml @@ -366,6 +366,7 @@ Dokumen, musik dan berkas yang dibagikan di obrolan ini akan ditampilkan disini. Tampilan media Kirim pesan + Masuk Masuk ke server Anda Masuk dengan akun surel yang ada @@ -566,10 +567,6 @@ Buat alamat email baru di\"%1$s\" dan masuk ke sana?\n\nAkun yang sudah ada tidak akan di hapus. Gunakankan item \"Ganti akun\" untuk mengganti akun anda Kode QR yang dipindai tidak dapat digunakan untuk mengatur akun baru. %1$sdiverifikasi. - - Tidak bisa memverifikasi %1$s. - - Ubah pengaturan untuk %1$s. Balasan Pesan baru @@ -589,9 +586,6 @@ Untuk melampirkan lokasi, lihat pengaturan aplikasi, pilih \"Perizinan\", dan aktifkan \"Lokasi\". Gambar di mana saja untuk diburamkan - - Pesan terenkripsi - Ini adalah aplikasi resmi Delta Chat Desktop. Perangkat lunak ini berlisensi di bawah GNU GPL versi 3 dan kode sumber tersedia di GitHub. diff --git a/src/main/res/values-it/strings.xml b/src/main/res/values-it/strings.xml index 38027fb82..cf0db6e1a 100644 --- a/src/main/res/values-it/strings.xml +++ b/src/main/res/values-it/strings.xml @@ -249,12 +249,6 @@ Chatta con… Clona Chat - - Lista Trasmissione - - Liste Trasmissioni - - Nuova Lista Trasmissione Canale @@ -262,12 +256,6 @@ Nuovo Canale Aggiungi Destinatari - - Modifica Lista Trasmissione - - Nome Lista Trasmissione - - Per piacere inserisci un nome per la lista trasmissione. Nome Canale E-Mail @@ -438,8 +426,6 @@ Chattare con %1$s? Rimuovere %1$s dal gruppo? - - Rimuovere %1$s dalla lista di trasmissione? Rimuovere %1$s dal canale? Vuoi aprire questo collegamento? @@ -474,8 +460,6 @@ Invia un messaggio a %1$s. - - In una lista di trasmissione, i destinatari riceveranno i messaggi in una chat di sola lettura con te. I canali sono uno strumento uno-a-molti per trasmettere i tuoi messaggi. Gli altri vedranno questo gruppo solo dopo che avrai inviato un primo messaggio. @@ -586,11 +570,6 @@ Griglia Quadrata Invia Messaggio - - %1$s ha cambiato il suo indirizzo da %2$s a %3$s - - Hai cambiato il tuo indirizzo email da %1$s a %2$s.\n\nSe ora invii un messaggio a un gruppo verificato, i contatti sostituiranno automaticamente il vecchio indirizzo con il tuo nuovo indirizzo.\n\nSi consiglia vivamente di impostare il tuo vecchio fornitore email per inoltrare tutte le email al tuo nuovo indirizzo. Altrimenti potresti perdere i messaggi di contatti che non hanno ancora ricevuto il tuo nuovo indirizzo. - @@ -973,6 +952,9 @@ Hai impostato il timer dei messaggi a scomparsa su 1 settimana. Timer messaggi a scomparsa impostato su 1 settimana da %1$s. + Hai impostato il timer dei messaggi a scomparsa su 1 anno. + + Timer messaggi a scomparsa impostato su 1 anno da %1$s. Hai impostato il timer dei messaggi a scomparsa su %1$s minuti. @@ -989,14 +971,8 @@ Hai impostato il timer dei messaggi a scomparsa su %1$s settimane. Timer messaggi a scomparsa impostato su %1$s settimane da %2$s. - - %1$s ha inviato un messaggio da un altro dispositivo. I messaggi sono crittografati end-to-end. Tocca per saperne di più. Tutti i messaggi in questa chat sono crittografati end-to-end. La crittografia end-to-end mantiene privati i messaggi tra te e i tuoi interlocutori. Nemmeno servers, providers o relays possono leggerli. - - %1$s ha inviato un messaggio da un altro dispositivo. Tocca per saperne di più. - - La crittografia end-to-end non può più essere garantita, probabilmente perché %1$s ha reinstallato Delta Chat o inviato un messaggio da un altro dispositivo.\n\nPuoi incontrarlo di persona e scansionare nuovamente il suo Codice QR per ristabilire la crittografia end-to-end garantita. ⚠️ %1$s richiede la crittografia end-to-end che non è ancora configurata per questa chat. Tocca per saperne di più. Per stabilire la crittografia end-to-end, potresti incontrare i contatti di persona e scansionare il loro Codice QR per verificarli. Per Saperne di Più @@ -1055,19 +1031,11 @@ %1$s ha risposto, in attesa di essere aggiunto al gruppo… Impostazione della crittografia end-to-end, attendere... - - Non è ancora possibile stabilire la crittografia end-to-end garantita, ma potresti già inviare un messaggio. - - Il contatto deve essere in linea per proseguire.\n\nQuesto processo continuerà automaticamente in sottofondo. %1$s verificato. - - Impossibile stabilire una crittografia end-to-end con %1$s. Verificato da %1$s Verificato da me Presentato - - Impostazioni modificate per %1$s Per garantire la crittografia end-to-end, puoi aggiungere a questo gruppo solo i contatti con un segno di spunta verde.\n\nPuoi incontrare i contatti di persona e scansionare il loro Codice QR per verificarli. Seleziona la chat a cui inviare il messaggio @@ -1110,9 +1078,6 @@ Capovolgi Ruota - - Messaggio cifrato - Questa è l\'app Desktop Delta Chat ufficiale. Questo software è concesso in licenza con GNU GPL versione 3 e il codice sorgente è disponibile su GitHub. @@ -1227,7 +1192,6 @@ Delta Chat vuole salvare le immagini nella tua libreria fotografica. Delta Chat può utilizzare Face ID per proteggere il tuo profilo locale, la creazione di backup e la configurazione di un secondo dispositivo. - Consegna Istantanea Utilizza Connessione Secondo Piano @@ -1242,8 +1206,4 @@ Novità?\n\n💯 La crittografia end-to-end è ora affidabile e definitiva. I lucchetti 🔒 sono spariti!\n\n✉️ Le email classiche senza crittografia end-to-end sono contrassegnate dal simbolo di una lettera\n\n😻 Nuova schermata del profilo migliorata per tutti i tuoi contatti\n\n🔲 Nuovo pulsante per l\'accesso rapido alle app utilizzate in una chat\n\n❤️ Dona per aiutarci a rimanere indipendenti e continuare a migliorare: %1$s - - Novità?\n\n❤️‍🔥 Nuovo selettore di emoji con più emoji\n\n🎮 App in chat migliorate: ricevi notifiche e apri le app supportate nel contesto, es. apri una voce del calendario cliccando direttamente sul messaggio\n\n👍 Ricevi notifiche sulle reazioni ai tuoi messaggi...\n\n🛠️ CORREZIONI e ANCORA DI PIÙ su %1$s - - ℹ️ Opzione \"Cambia Profilo\" spostata: Tocca l\'immagine del tuo profilo nell\'angolo superiore della schermata principale per aggiungere o cambiare profili 💡 diff --git a/src/main/res/values-ja/strings.xml b/src/main/res/values-ja/strings.xml index a100f532f..d7922a57d 100644 --- a/src/main/res/values-ja/strings.xml +++ b/src/main/res/values-ja/strings.xml @@ -335,6 +335,7 @@ このチャットで共有されたドキュメントや音楽などがここに表示されます。 メディアのプレビュー 送る + 接続性 未接続 @@ -595,10 +596,6 @@ インターネットに接続されていないので、QRコードの設定ができません。 %1$sに新しいメールアドレスを作ってログしますか。 %1$sを確認しました。 - - %1$sを確認できません。 - - 設定が%1$sに変わりました。 返信 新規メッセージ @@ -616,9 +613,6 @@ 反転 回転 - - 暗号化されたメッセージ - Delta Chatにようこそ 言語を選択して下さい ファイル diff --git a/src/main/res/values-ko/strings.xml b/src/main/res/values-ko/strings.xml index f8f8ff4e9..5a575f493 100644 --- a/src/main/res/values-ko/strings.xml +++ b/src/main/res/values-ko/strings.xml @@ -173,12 +173,6 @@ 대화상대 추가 채팅 시작 새 그룹 - - 방송 목록 - - 방송 목록 - - 새 방송 목록 수신자 추가 보내기 이모티콘 키보드 전환 @@ -300,8 +294,6 @@ %1$s와 채팅하시겠습니까? 그룹에서 %1$s을/를 제거하시겠습니까? - - 브로드 캐스트 목록에서 %1$s을/를 제거하시겠습니까? 이 링크를 여시겠습니까? @@ -408,11 +400,6 @@ 채팅에서 보내거나 받은 개인 앱들이 여기에 나타납니다. 미디어 미리보기 메시지 전송 - - %1$s의 주소가 %2$s에서 %3$s로 변경됨. - - 이메일 주소를 %1$s에서 %2$s로 바꿨습니다.\n\n확인된 그룹으로 메시지를 보내면 해당 그룹의 연락처가 자동으로 이전 주소를 새 주소로 대체합니다.\n\n모든 이메일을 새 이메일 주소로 전달하도록 이전 이메일 공급자를 설정하는 것이 좋습니다. 그렇지 않으면 새 주소를 받지 못한 연락처의 메시지를 놓칠 수 있습니다. - @@ -737,10 +724,6 @@ %1$s이 응하여, 그룹에 추가되기를 기다리는 중입니다... %1$s이 확인됨 - - %1$s 확인할 수 없음 - - %1$s에 대한 설정이 변경되었습니다. 메시지를 보내려면 채팅을 선택하십시오 %1$s에 이미 임시 저장된 메시지가 있습니다. 바꾸시겠습니까? @@ -773,9 +756,6 @@ 뒤집기 돌리기 - - 암호화된 메시지 - 이것은 Delta Chat 데스크톱 공식 앱입니다. 이 소프트웨어는 GNU GPL 버전 3에 따라 라이센스가 부여되며 소스 코드는 GitHub에서 사용할 수 있습니다. diff --git a/src/main/res/values-lt/strings.xml b/src/main/res/values-lt/strings.xml index e48267ade..c4cc6c6a2 100644 --- a/src/main/res/values-lt/strings.xml +++ b/src/main/res/values-lt/strings.xml @@ -415,8 +415,7 @@ Čia bus rodoma bet kuriame pokalbyje bendrinama medija. Medijos peržiūra Siųsti žinutę - - %1$s pasikeitė adresą iš %2$s į %3$s + Pridėti antrąjį įrenginį @@ -707,10 +706,6 @@ Jūs nustatėte išnykstančių žinučių laikmatį į %1$s sav. %2$s nustatė išnykstančių žinučių laikmatį į %1$s sav. - - %1$s išsiuntė žinutę iš kito įrenginio. - - %1$s išsiuntė žinutę iš kito įrenginio. Bakstelėkite norėdami sužinoti daugiau. Sužinoti daugiau @@ -746,10 +741,6 @@ Prisijungti prie „%1$s“? %1$s patvirtintas. - - Nepavyksta patvirtinti %1$s - - Pakeista sąranka, skirta %1$s. Pasirinkite pokalbį, į kurį siųsti žinutę nepavyko dekoduoti mailto nuorodos: %1$s @@ -777,9 +768,6 @@ Apversti Pasukti - - Šifruota žinutė - Ši programinė įranga yra licencijuota pagal GNU GPL versiją 3, o pirminis kodas yra prieinamas „GitHub“ internetinėje svetainėje. Sveiki atvykę į Delta Chat Pasirinkti kalbą... diff --git a/src/main/res/values-nb/strings.xml b/src/main/res/values-nb/strings.xml index 39575cd2e..0f0a25241 100644 --- a/src/main/res/values-nb/strings.xml +++ b/src/main/res/values-nb/strings.xml @@ -386,9 +386,6 @@ Tillatelse kreves Fortsett - - Kryptert melding - Velkommen til Delta Chat Språk Rediger diff --git a/src/main/res/values-nl/strings.xml b/src/main/res/values-nl/strings.xml index c2b242424..24e7b519a 100644 --- a/src/main/res/values-nl/strings.xml +++ b/src/main/res/values-nl/strings.xml @@ -240,12 +240,6 @@ Gesprek voeren met… Gesprek klonen - - Verzendlijst - - Verzendlijsten - - Nieuwe verzendlijst Kanaal @@ -253,12 +247,6 @@ Nieuw kanaal Ontvangers toevoegen - - Verzendlijst bewerken - - Naam van verzendlijst - - Geef de verzendlijst een naam. Kanaalnaam E-mail @@ -424,8 +412,6 @@ Wil je een gesprek voeren met %1$s? Wil je %1$s verwijderen uit de groep? - - Wil je %1$s verwijderen van de verzendlijst? Weet je zeker dat je %1$s van het kanaal wilt verwijderen? Weet je zeker dat je deze link wilt openen? @@ -457,8 +443,6 @@ Stuur een bericht aan %1$s . - - Op een verzendlijst hebben ontvangers niet de mogelijkheid om te reageren op je berichten. Kanalen zijn bedoeld om te gebruiken als verzendlijsten. Stel het eerste bericht op zodat anderen binnen deze groep kunnen reageren. @@ -569,11 +553,6 @@ Vierkant rooster Bericht versturen - - %1$s heeft zijn/haar adres veranderd van %2$s naar %3$s - - Je hebt je e-mailadres veranderd van %1$s naar %2$s.\n\nAls je een bericht stuurt aan een goedgekeurde groep, dan zien contactpersonen in de groep je nieuwe adres.\n\nWel raden we aan om bij je oude provider in te stellen dat je e-mails wilt doorsturen naar je nieuwe adres, anders missen sommige contactpersonen mogelijk je berichten. - @@ -956,6 +935,9 @@ Je hebt de tijdklok van verdwijnende berichten ingesteld op 1 week. De tijdklok van verdwijnende berichten is door %1$s ingesteld op 1 week. + Je hebt de tijdklok van verdwijnende berichten ingesteld op 1 jaar. + + De tijdklok van verdwijnende berichten is door %1$s ingesteld op 1 jaar. Je hebt de tijdklok van verdwijnende berichten ingesteld op %1$s minuten. @@ -972,14 +954,8 @@ Je hebt de tijdklok van verdwijnende berichten ingesteld op %1$s weken. De tijdklok van verdwijnende berichten is door %2$s ingesteld op %1$s weken. - - %1$s heeft een bericht verstuurd vanaf een ander apparaat. Berichten zijn gegarandeerd van eind-tot-eindversleuteling voorzien. Druk hier voor meer informatie. Alle berichten in dit gesprek zijn gegarandeerd van eind-tot-eindversleuteling voorzien.\n\nMet behulp van deze versleuteling blijven berichten tussen jou en je gesprekspartners geheim - zelfs je e-mailprovider kan ze niet uitlezen. - - %1$s heeft een bericht verstuurd vanaf een ander apparaat. Druk hier voor meer informatie. - - Eind-tot-eindversleuteling kan niet meer worden gegarandeerd, omdat %1$s Delta Chat opnieuw heeft geïnstalleerd of een bericht vanaf een ander apparaat heeft verstuurd.\n\nMaak een afspraak met hem/haar en scan de QR-code opnieuw om eind-tot-eindversleuteling weer in te schakelen. ⚠️ Voor %1$s is eind-tot-eindversleuteling vereist, maar dit is nog niet ingesteld in het huidige gesprek. Druk voor meer informatie. Spreek met elkaar af en scan elkaars QR-code om eind-tot-eindversleuteling op te zetten. Meer informatie @@ -1038,19 +1014,11 @@ %1$s heeft geantwoord en wacht op toelating tot de groep… Bezig met opzetten van eind-tot-eindversleuteling… - - Er kan nog geen eind-tot-eindversleuteling worden gegarandeerd, maar je kunt wel alvast een bericht sturen. - - Het lijkt langer te duren dan verwacht - wellicht is een van jullie offline.\n\nHet proces wordt echter op de achtergrond voortgezet. %1$s is goedgekeurd. - - Er kan geen eind-tot-eindversleuteling met %1$s worden gegarandeerd. Geïntroduceerd door %1$s Geïntroduceerd door mij Geïntroduceerd - - Gewijzigde instellingen voor %1$s Om de eind-tot-eindversleuteling te garanderen, kun je alleen contactpersonen met een groen vinkje toevoegen aan deze groep.\n\nVan niet-goedgekeurde contactpersonen kun je de QR-code scannen om ze goed te keuren. Kies in welk gesprek je dit bericht wilt delen @@ -1093,9 +1061,6 @@ Spiegelen Draaien - - Versleuteld bericht - Dit is de officiële Delta Chat-computerapp. Deze software is vrijgegeven onder de GNU GPL versie 3 en de broncode is beschikbaar op GitHub. @@ -1210,7 +1175,6 @@ Delta Chat wil afbeeldingen opslaan in je fotogalerij. Delta Chat kan gebruikmaken van Face ID om je account te beveiligen, reservekopieën te maken en secundaire apparaten in te stellen. - Onmiddellijke bezorging Achtergrondverbinding gebruiken @@ -1225,8 +1189,4 @@ Wijzigingslog:\n\n💯 Eind-tot-eindversleuteling is voortaan betrouwbaarder én standaard. Slotjes 🔒 zijn verleden tijd!\n\n✉️ Klassieke e-mails zonder eind-tot-eindversleuteling worden voortaan gemarkeerd met een letter\n\n😻 Nieuwe, mooiere profielpagina\'s van al je contactpersonen\n\n🔲 Nieuwe knop voor snelle toegang tot apps in gesprekken\n\n❤️ Overweeg een donatie, zodat we onafhankelijk kunnen blijven en verbeteringen kunnen blijven aanbrengen: %1$s - - Wijzigingslog:\n\n❤️‍🔥 Nieuwe emojikiezer met veel meer emojis\n\n🎮 Verbeterde apps in gesprekken: ontvang meldingen open ondersteunde apps met links, bijv. een agenda-uitnodiging\n\n👍 Ontvang meldingen bij reacties op berichten\n\n… 🛠️ Opgeloste fouten en VEEL MEER op %1$s - - ℹ️ De optie om een ander profiel te kiezen is verplaatst: druk op je profielfoto op het hoofdscherm om het profielmenu te openen.💡 diff --git a/src/main/res/values-pl/strings.xml b/src/main/res/values-pl/strings.xml index d49f58981..b8ec2778e 100644 --- a/src/main/res/values-pl/strings.xml +++ b/src/main/res/values-pl/strings.xml @@ -258,12 +258,6 @@ Czat z… Klonuj czat - - Lista rozgłoszeniowa - - Lista rozgłoszeniowa - - Nowa lista rozgłoszeniowa Kanał @@ -271,12 +265,6 @@ Nowy kanał Dodaj odbiorców - - Edytuj listę rozgłoszeniową - - Nazwa listy rozgłoszeniowej - - Wpisz nazwę listy rozgłoszeniowej Nazwa kanału E-mail @@ -450,8 +438,6 @@ Rozpocząć czat z %1$s? Usunąć %1$s z grupy? - - Usunąć odbiorcę %1$s z listy rozgłoszeniowej? Usunąć %1$s z kanału? Czy chcesz otworzyć ten link? @@ -489,8 +475,6 @@ Wyślij wiadomość do %1$s. - - Na liście rozgłoszeniowej odbiorcy będą otrzymywać wiadomości w czacie tylko do odczytu. Kanały są narzędziem typu „jeden do wielu” do nadawania wiadomości. Napisz pierwszą wiadomość, by inni mogli odpowiedzieć w tej grupie.\n\n• Nie ma problemu, jeśli nie wszyscy członkowie korzystają z Delta Chat.\n\n• Dostarczenie pierwszej wiadomości może chwilę potrwać. @@ -601,11 +585,6 @@ Siatka kwadratowa Wyślij wiadomość - - %1$s zmieniła swój adres z %2$s na %3$s - - Zmieniłeś swój adres e-mail z %1$s na %2$s.\n\nJeśli teraz wyślesz wiadomość do zweryfikowanej grupy, kontakty tam zawarte automatycznie zastąpią stary adres Twoim nowym.\n\nBardzo zalecane jest, aby ustawić swojego starego dostawcę emaila tak, aby przekazywał wszystkie emaile na Twój nowy adres email. W przeciwnym razie możesz przegapić wiadomości od kontaktów, które jeszcze nie dostały Twojego nowego adresu. - @@ -988,6 +967,9 @@ Ustawiono zegar znikających wiadomości na 1 tydzień. Użytkownik %1$s ustawił zegar znikających wiadomości na 1 tydzień. + Ustawiono zegar znikających wiadomości na 1 rok. + + Użytkownik %1$s ustawił zegar znikających wiadomości na 1 rok. Ustawiono zegar znikających wiadomości na %1$s min. @@ -1004,14 +986,8 @@ Ustawiono zegar znikających wiadomości na %1$s tyg. Użytkownik %2$s ustawił zegar znikających wiadomości na %1$s tyg. - - Użytkownik %1$s wysłał wiadomość z innego urządzenia. Wiadomości będą szyfrowane metodą end-to-end. Dotknij, aby przeczytać więcej. Wszystkie wiadomości w tym czacie są szyfrowane metodą end-to-end.\n\nSzyfrowanie end-to-end zapewnia prywatność wiadomości między tobą a twoimi partnerami czatów. Nawet serwery, dostawcy i pośrednicy nie są w stanie ich odczytać. - - Użytkownik %1$s wysłał wiadomość z innego urządzenia. Dotknij, aby przeczytać więcej. - - Nie można już zagwarantować szyfrowania end-to-end, prawdopodobnie z powodu ponownej instalacji Delta Chat przez %1$s lub wysłania wiadomości z innego urządzenia.\n\nMożesz spotkać się z tą osobą osobiście i ponownie zeskanować jej kod QR, aby przywrócić gwarantowane szyfrowanie end-to-end. ⚠️ %1$s wymaga szyfrowania end-to-end, które nie zostało jeszcze skonfigurowane dla tego czatu. Dotknij, aby dowiedzieć się więcej. Aby ustanowić szyfrowanie end-to-end, możesz spotkać się z kontaktami osobiście i zeskanować ich kod QR, żeby ich zweryfikować. Czytaj więcej @@ -1070,19 +1046,11 @@ Użytkownik %1$s odpowiedział, czekając na dodanie do grupy… Ustanawiam szyfrowanie typu end-to-end, proszę czekać… - - Nie można jeszcze ustanowić gwarantowanego szyfrowania typu end-to-end, ale być może już wysłałeś wiadomość. - - Aby kontynuować, kontakt musi być online.\n\nTen proces będzie kontynuowany automatycznie w tle. Kontakt %1$s zweryfikowany. - - Nie można ustanowić szyfrowania typu end-to-end z %1$s Kontakt zweryfikowany przez %1$s Kontakt zweryfikowany przez ciebie Zweryfikowano - - Zmieniono konfigurację dla %1$s Aby zagwarantować szyfrowanie end-to-end, do tej grupy możesz dodawać wyłącznie kontakty oznaczone zielonym znacznikiem wyboru.\n\nMożesz spotkać się z kontaktami osobiście i zeskanować ich kod QR, aby je zweryfikować. Wybierz czat, do którego chcesz wysłać wiadomość @@ -1125,9 +1093,6 @@ Przełącz Obróć - - Zaszyfrowana wiadomość - To jest oficjalna aplikacja Delta Chat Desktop. To oprogramowanie jest objęte licencją GNU GPL w wersji 3, a kod źródłowy jest dostępny na GitHub. @@ -1242,7 +1207,6 @@ Delta Chat chce zapisać obrazy w twojej bibliotece zdjęć. Delta Chat może używać Face ID do ochrony twojego lokalnego profilu, tworzenia kopii zapasowych i konfiguracji drugiego urządzenia. - Natychmiastowe dostarczenie Użyj połączenia w tle @@ -1257,8 +1221,4 @@ Co nowego?\n\n💯 Szyfrowanie end-to-end jest niezawodne i na zawsze. Kłódki 🔒 odchodzą w zapomnienie!\n\n✉️ Klasyczna poczta e-mail bez szyfrowania end-to-end jest oznaczona symbolem litery.\n\n😻 Nowy, ulepszony ekran profilu dla wszystkich kontaktów.\n\n🔲 Nowy przycisk szybkiego dostępu do aplikacji używanych na czacie.\n\n❤️ Prosimy o darowizny, które pomogą nam zachować niezależność i stale wprowadzać ulepszenia: %1$s - - Co nowego?\n\n❤️‍🔥 Nowy selektor emoji z większą liczbą emoji\n\n🎮 Ulepszone aplikacje czatu: Otrzymuj powiadomienia i otwieraj aplikacje pomocnicze w kontekście, np. otwieraj dodany wpis kalendarza bezpośrednio\n\n👍 Otrzymuj powiadomienia o reakcjach na swoje wiadomości\n\n... 🛠️ POPRAWKI i JESZCZE WIĘCEJ na %1$s - - ℹ️ Opcja „Przełącz profil” została przeniesiona: Dotknij swojego zdjęcia profilowego w górnym rogu ekranu głównego, aby dodać lub przełączyć profile 💡 diff --git a/src/main/res/values-pt-rBR/strings.xml b/src/main/res/values-pt-rBR/strings.xml index 3b4ed5afa..51711b771 100644 --- a/src/main/res/values-pt-rBR/strings.xml +++ b/src/main/res/values-pt-rBR/strings.xml @@ -204,12 +204,6 @@ Novo contato Nova conversa Novo grupo - - Lista de Transmissão - - Listas de Transmissão - - Nova Lista de Transmissão Adicionar Destinatários Enviar Ativar teclado de emojis @@ -339,8 +333,6 @@ Conversar com %1$s? Remover %1$s do grupo? - - Remover %1$s da lista de transmissão? Você quer abrir este link? @@ -463,11 +455,6 @@ Apps recebidas ou enviadas em qualquer bate-papo aparecerão aqui. Pré-visualização. Enviar mensagem - - %1$s mudou seu endereço de %2$s para %3$s - - Você mudou seu endereço de e-mail de %1$s para %2$s.\n\nSe você agora enviar uma mensagem para um grupo verificado, os contatos lá substituirão automaticamente o antigo por seu novo endereço.\n\nÉ altamente recomendável configurar seu antigo provedor de e-mail para encaminhar todos os e-mails para seu novo endereço de e-mail. Caso contrário, você pode perder mensagens de contatos que ainda não receberam seu novo endereço. - @@ -831,12 +818,8 @@ %1$srespondeu, esperando para ser adicionado ao grupo... %1$s verificado. - - Impossível verificar %1$s Verificado por %1$s - - A configuração Autocrypt mudou para %1$s Selecione o bate-papo para enviar a mensagem %1$s já tem um rascunho de mensagem, deseja substituí-lo? @@ -869,9 +852,6 @@ Girar Rodar - - Mensagem criptografada - Este é o aplicativo oficial Delta Chat Desktop. Este software é licenciado sob a GNU GPL versão 3 e o código-fonte está disponível no GitHub. diff --git a/src/main/res/values-pt/strings.xml b/src/main/res/values-pt/strings.xml index 23df180ce..aca5fe302 100644 --- a/src/main/res/values-pt/strings.xml +++ b/src/main/res/values-pt/strings.xml @@ -329,10 +329,6 @@ Digitalize para configurar um contato com %1$s %1$s verificado. - - Não é possível verificar %1$s - - Configuração alterada para %1$s Responder Mensagem nova @@ -350,9 +346,6 @@ O Delta Chat necessita de permissão de acesso ao microfone para enviar mensagens de áudio, mas foi negado. Por favor, continue com as configurações do aplicativo, selecione \"Permissões\" e active \"Microfone\". O Delta Chat necessita da permissão de armazenamento para anexar ou exportar fotos, vídeos ou áudio, mas foi negado. Por favor, continue no menu de configurações do aplicativo, seleccione \"Permissões\" e active \"Armazenamento\". O Delta Chat necessita permissão de acesso à localização para anexar um local, mas ele negado. Por favor, continue no menu de configurações do aplicativo, selecione \"Permissões \"e ative \"Localização\". - - Mensagem encriptada - Escolha o seu idioma... Arquivo Sair diff --git a/src/main/res/values-ro/strings.xml b/src/main/res/values-ro/strings.xml index ea1e2ef05..d184fdfdb 100644 --- a/src/main/res/values-ro/strings.xml +++ b/src/main/res/values-ro/strings.xml @@ -195,12 +195,6 @@ Contact Nou Chat Nou Grup Nou - - Listă de difuzare - - Liste de difuzare - - Noua Listă de Difuzare Adăugați Destinatari Trimiteți Comutați Tastatura Emoji @@ -329,8 +323,6 @@ Chat cu %1$s? Scoateți %1$s din grup? - - Eliminați %1$s din lista de difuzare? Doriți să deschideți acest link? @@ -448,11 +440,6 @@ Materialele media partajate în orice chat vor apărea aici. Previzualizare Media Trimiteți Mesaj - - %1$s și-au schimbat adresa de la %2$s la %3$s - - V-ați schimbat adresa de e-mail de la %1$s la %2$s.\n\nDacă trimiteți acum un mesaj către un grup verificat, contactele de acolo vor înlocui automat vechea adresă cu noua dumneavoastră adresă.\n\nSe recomandă să vă configurați vechiul furnizor de e-mail pentru a redirecționa toate e-mailurile către noua dumneavoastră adresă de e-mail. În caz contrar, s-ar putea să pierdeți mesaje ale contactelor care nu au primit încă noua dumneavoastră adresă. - diff --git a/src/main/res/values-ru/strings.xml b/src/main/res/values-ru/strings.xml index 54086f5e9..245f02599 100644 --- a/src/main/res/values-ru/strings.xml +++ b/src/main/res/values-ru/strings.xml @@ -258,12 +258,6 @@ Начать чат с… Клонировать чат - - Список рассылки - - Списки рассылки - - Новый список рассылки Канал @@ -271,12 +265,6 @@ Новый канал Добавить получателей - - Редактировать список рассылки - - Название списка рассылки - - Введите название списка рассылки. Название канала Электронная почта @@ -450,8 +438,6 @@ Создать чат с %1$s? Удалить %1$s из группы? - - Удалить %1$s из списка рассылки? Удалить %1$s из канала? Вы хотите открыть эту ссылку? @@ -489,8 +475,6 @@ Отправьте сообщение %1$s. - - В списке рассылки получатели будут получать сообщения в чате с вами, доступном только для чтения. Каналы представляют собой инструмент одностороннего вещания ваших сообщений множеству получателей. Другие пользователи увидят эту группу только после того, как вы отправите первое сообщение. @@ -601,11 +585,6 @@ Сетка квадратов Отправить сообщение - - %1$s меняет адрес с %2$s на %3$s - - Вы изменили свой адрес электронной почты с %1$s на %2$s.\n\nЕсли вы отправите сообщение в подтвержденную группу, контакты в ней автоматически обновят ваш старый адрес на новый.\n\nНастоятельно рекомендуется настроить старого поставщика электронной почты на пересылку всех писем на новый адрес. Иначе вы можете пропустить сообщения от контактов, которые еще не получили ваш новый адрес. - @@ -988,6 +967,9 @@ Вы включили автоудаление сообщений через 1 неделю. %1$s включает автоудаление сообщений через 1 неделю. + Вы включили автоудаление сообщений на 1 год. + + %1$s включает автоудаление сообщений на 1 год. Вы включили автоудаление сообщений через %1$s минут. @@ -1004,14 +986,8 @@ Вы включили автоудаление сообщений через %1$s недель. %2$s включает автоудаление сообщений через %1$s недель. - - %1$s отправил сообщение с другого устройства. Сообщения защищены сквозным шифрованием. Нажмите, чтобы узнать больше. Все сообщения в этом чате защищены сквозным шифрованием.\n\nСквозное шифрование гарантирует, что сообщения остаются конфиденциальными между вами и вашими собеседниками. Ни серверы, ни провайдеры, ни ретрансляторы не смогут их прочитать. - - %1$s отправил сообщение с другого устройства. Нажмите, чтобы узнать больше. - - Сквозное шифрование больше не может быть гарантировано, вероятно, потому что %1$s переустановил Delta Chat или отправил сообщение с другого устройства.\n\nВы можете встретиться с ним лично и отсканировать QR-код снова чтобы восстановить гарантированное сквозное шифрование. ⚠️ %1$s требуется сквозное шифрование, которое ещё не настроено для данного чата. Нажмите, чтобы узнать больше. Чтобы установить сквозное шифрование, вы можете встретиться с контактами лично и отсканировать их QR-код, чтобы подтвердить их личность. Узнать больше @@ -1070,19 +1046,11 @@ %1$s ответил(а), ожидаем добавления в группу… Устанавливается сквозное шифрование, пожалуйста, подождите… - - Не удалось установить гарантированное сквозное шифрование, но вы уже можете отправить сообщение. - - Контакт должен быть в режиме онлайн, чтобы продолжить.\n\nЭтот процесс будет автоматически продолжен в фоновом режиме. %1$s подтверждён. - - Невозможно установить сквозное шифрование с %1$s. Подтверждён: %1$s Подтверждён: Лично Подтверждён - - Изменены настройки для %1$s Чтобы обеспечить сквозное шифрование, вы можете добавлять в эту группу только контакты с зеленой галочкой.\n\nВы можете встретиться с контактами лично и отсканировать их QR-код, чтобы подтвердить их личность. Выберите чат, чтобы отправить сообщение @@ -1125,9 +1093,6 @@ Отразить Вращать - - Зашифрованное сообщение - Это официальное приложение Delta Chat для ПК. Это программное обеспечение выпущено под лицензией GNU GPL 3 версии, исходный код доступен на GitHub. @@ -1242,7 +1207,6 @@ Delta Chat хочет сохранить изображения в вашей галерее. Delta Chat поддерживает использование Face ID для защиты локального профиля, создания резервных копий и настройки второго устройства. - Мгновенная доставка Использовать соединение в фоновом режиме @@ -1257,8 +1221,4 @@ Что нового?\n\n💯 Сквозное шифрование стало постоянной и надёжной функцией. 🔒 Замков больше нет!\n\n✉️ Обычные письма без сквозного шифрования помечены значком конверта\n\n😻 Обновлённый экран профиля для всех контактов\n\n🔲 Новая кнопка быстрого доступа к приложениям, используемым в чате\n\n❤️ Поддержите нас финансово, чтобы мы сохранили независимость и продолжали вносить улучшения: %1$s - - Что нового?\n\n❤️‍🔥 Обновленный выбор эмодзи с еще большим выбором эмодзи\n\n🎮 Расширенные приложения в чате: получайте уведомления и открывайте поддерживаемые приложения в нужном контексте, например, открывайте добавленную запись в календаре напрямую\n\n👍 Получайте уведомления о реакциях на ваши сообщения\n\n... 🛠️ ИСПРАВЛЕНИЯ и ЕЩЁ БОЛЬШЕ в %1$s - - ℹ️ \"Сменить профиль\" перемещено: Нажмите на изображение вашего профиля в верхнем углу главного экрана, чтобы добавить или переключить профили. 💡 diff --git a/src/main/res/values-sc/strings.xml b/src/main/res/values-sc/strings.xml index ae5938b9b..c3115b2ea 100644 --- a/src/main/res/values-sc/strings.xml +++ b/src/main/res/values-sc/strings.xml @@ -300,6 +300,7 @@ Sos documentos editàbiles, cussos musicales e totu sas àteras castas de documentos cumpartzidos in custa tzarrada ant a èssere ammustrados inoghe. Anteprima de su documentu multimediale Imbia messàgiu + Intra Intra in su servidore tuo Intra cun un\'indiritzu de posta eletrònica chi esistat diff --git a/src/main/res/values-sk/strings.xml b/src/main/res/values-sk/strings.xml index dc634137d..1138466d2 100644 --- a/src/main/res/values-sk/strings.xml +++ b/src/main/res/values-sk/strings.xml @@ -244,12 +244,6 @@ Nová konverzácia Nová skupina Kopírovať konverzáciu - - Zoznam Rozosielania - - Zoznamy Rozosielania - - Nový Zoznam Rozosielania Kanál @@ -423,8 +417,6 @@ Písať si s %1$s? Odstrániť %1$s zo skupiny? - - Odstrániť %1$s zo zoznamu rozosielania? Odstrániť %1$s z kanálu? Chcete otvoriť tento odkaz? @@ -556,8 +548,7 @@ Tu sú zobrazené súkromné aplikácie zdieľané v rámci tejto konverzácie. Ukážka pre médiá Odoslanie správy - - %1$s zmenil(a) svoju adresu z %2$s na %3$s + Pridať ďalšie zariadenie @@ -986,10 +977,6 @@ Váš existujúci účet nebude odstránený. Medzi účtami môžete prepínať %1$sodpovedal a čaká sa na pridanie do skupiny... Nadväzovanie šifrovaného spojenia, počkajte prosím... %1$s overené. - - Cannot verify %1$s. - - Zmena nastavenia pre %1$s. Vyberte konverzáciu, kam bude správa odoslaná %1$s už má koncept správy, chcete ho nahradiť? @@ -1025,9 +1012,6 @@ Váš existujúci účet nebude odstránený. Medzi účtami môžete prepínať Preklopiť Otočiť - - Zašifrovaná správa - Toto je oficiálna aplikácia Delta Chat Desktop. Tento softvér je licencovaný pod GNU GPL verzie 3 a zdrojový kód je k dispozícii na GitHub-e. diff --git a/src/main/res/values-sq/strings.xml b/src/main/res/values-sq/strings.xml index 9c49334cc..0afbdd2d3 100644 --- a/src/main/res/values-sq/strings.xml +++ b/src/main/res/values-sq/strings.xml @@ -236,19 +236,7 @@ Bisedoni me… Klononi Fjalosjen - - Listë Transmetimi - - Lista Transmetimi - - Listë e Re Transmetimi Shtoni Marrës - - Përpunoni Listë Transmetimesh - - Emër Liste Transmetimesh - - Ju lutemi, jepni një emër për listën e transmetimeve Dërgoje Shfaq/fshih Tastierë Emoji-sh Përpunoni Grup @@ -401,8 +389,6 @@ Të bisedohet me %1$s? Të hiqet %1$s nga grupi? - - Të hiqen %1$s prej liste transmetimi? Doni të hapet kjo lidhje? @@ -432,8 +418,6 @@ Dërgoni një mesazh për %1$s. - - Në një listë transmetimesh, marrësit do të marrin mesazhe në një fjalosje të llojit “vetëm lexim” me ju. Të tjerët do ta shohin këtë grup pasi të keni dërguar një mesazh të parë. Rrëshqiteni që të anulohet Prekeni dhe mbajeni të prekur që të incizoni një mesazh zanor; lëshojeni, që të dërgohet @@ -541,11 +525,6 @@ Mozaik Katror Dërgo Mesazh - - %1$s ndryshoi adresën e vet nga %2$s në %3$s - - Ndryshuat adresën tuaj nga %1$s në %2$s.\n\nNëse dërgoni tani një mesazh te një grup i verifikuar, kontaktet atje do të zëvendësojnë automatikisht adresën tuaj të vjetër me të renë.\n\nËshtë tejet e këshillueshme të ujdisni shërbimin tuaj të vjetër të email-it të përcjellë krejt email-et te adresa juaj e re email. Përndryshe, mund të humbni mesazhe të kontakteve që s’e kanë marrë ende adresën tuaj të re. - @@ -941,14 +920,8 @@ E vutë kohëmatësin e zhdukjes së mesazheve në %1$s javë. Kohëmatësi i zhdukjes së mesazheve u vu në %1$s javë nga %2$s. - - %1$s dërgoi një mesazh nga një pajisje tjetër. Nga sot e tutje për mesazhet garantohet fshehtëzimi skaj-më-skaj. Prekeni, që të mësoni më tepër. Tanimë për mesazhet në këtë fjalosje garantohet fshehtëzimi skaj-më-skaj.\n\nFshehtëzimi skaj-më-skaj i mban private mesazhet mes jush dhe partnerëve tuaj të fjalosjes. Ato s’mund t’i lexojë as furnizuesi i shërbimit tuaj email. - - %1$s dërgoi një mesazh nga një pajisje tjetër. Prekeni, që të mësoni më tepër. - - Fshehtëzimi skaj-më-skaj s’mund të garantohet më, ngaqë, sipas gjasash, %1$s riinstaloi Delta Chat-in, ose dërgoi një mesazh nga një tjetër pajisje.\n\nMund ta takoni dhe të skanoni sërish KODIN e tij QR, që të rivendoset fshehtëzim skaj-më-skaj i garantuar. ⚠️ %1$s lyp fshehtëzim, i cili s’është ujdisur ende për këtë fjalosje. Që të mësoni më tepër, prekeni. Për të vendosur fshehtëzim skaj-më-skaj, mund të takoheni personalisht me kontaktet dhe të skanoni kodin e tyre QR, për t’i pranuar. Mësoni Më Tepër @@ -1007,18 +980,10 @@ %1$s u përgjigj, po pritet që të shtohet te grupi… Po vendoset fshehtëzim skaj-më-skaj i garantuar, ju lutemi, pritni… - - S’u vendos dot fshehtëzim skaj-më-skaj i garantuar, por mundeni tashmë të dërgoni një mesazh. - - Duket se po zgjat ca, mos ndoshta kontakti juaj, ose vetë ju s’jeni lidhur në internet.\n\nSidoqoftë, procesi vazhdon në prapaskenë, mund të merreni me diçka tjetër… %1$s u verifikua. - - S’vendoset dot fshehtëzim i garantuar skaj-më-skaj me %1$s. Sjellë nga %1$s Sjellë nga unë - - U ndryshua udjisja për %1$s Që të garantohet fshehtëzim skaj-më-skaj, mund të shtoni në këtë grup vetëm kontakte me shenjën e gjelbër të verifikimit.\n\nMund të takoheni drejtpërsëdrejti me kontakte të paverifikuar dhe të skanoni kodin e tyre QR për t’i verifikuar ata. Përzgjidhni fjalosje ku të dërgohet mesazhi @@ -1061,9 +1026,6 @@ Ktheje në anë tjetër Rrotulloje - - Mesazh i fshehtëzuar - Ky është aplikacioni zyrtar Delta Chat Desktop. Ky program licencohet sipas GNU GPL version 3 dhe kodi burim mund të kihet që prej GitHub-i. @@ -1174,7 +1136,6 @@ Delta Chat dëshiron të ruajë figura në fototekën tuaj. Delta Chat mund të përdorë Face ID që të mbrojë profilin tuaj vendor, krijim kopjeruajtjesh dhe ujdisje pajisjeje të dytë. - Dërgim i Menjëhershëm Përdor Lidhje Në Prapaskenë @@ -1187,8 +1148,4 @@ Prekeni këtu që të merrni mesazhe, teksa Delta Chat rri në prapaskenë. E keni lejuar tashmë Delta Chat-in të marrë mesazhe në prapaskenë.\n\nNëse mesazhet prapë nuk mbërrijnë në prapaskenë, ju lutemi, kontrolloni edhe rregullimet e sistemit tuaj. - - Ç’ka të re?\n\n❤️‍🔥 Zgjedhës i ri emoji-sh, me më shumë të tillë\n\n🎮 Zgjerim aplikacionesh brenda fjalosjesh: Merrni njoftim dhe hapni aplikacionet përkatës sipas kontekstit, p.sh., hapni drejtpërdrejt një zë të saposhtuar kalendari\n\n👍 Merrni njoftim mbi reagime te mesazhet tuaj\n\n… 🛠️ NDREQJE DHE MË TEPËR te %1$s - - ℹ️ Mundësia “Ndërroni Profil” u hoq: Që të shtoni, ose ndërroni profile, prekni figurën e profilit tuaj në cepin e sipërm të skenës kryesore 💡 - + diff --git a/src/main/res/values-sr/strings.xml b/src/main/res/values-sr/strings.xml index cfd6dcbff..bdcb7a8d9 100644 --- a/src/main/res/values-sr/strings.xml +++ b/src/main/res/values-sr/strings.xml @@ -197,12 +197,6 @@ Нови контакт Ново ћаскање Нова група - - Листа за емитовање - - Листе за емитовање - - Нова листа за емитовање Додај примаоце Пошаљи Емоџи тастатура @@ -332,8 +326,6 @@ Да ли желите да ћаскате са %1$s? Да ли желите да уклонитите %1$s из групе? - - Да ли желите да уклоните %1$s са листе за емитовање? Да ли желите да отворите ову везу? @@ -451,11 +443,6 @@ Приватне апликације примљене или послате у било ком ћаскању ће се појавити овде. Преглед медијума Пошаљи поруку - - %1$sје променио њихову адресу %2$sу %3$s - - Ви сте променили вашу имејл адресу %1$sу %2$s.\n\nАко сада пошаљете поруку провереној групи, тамошњи контакти ће аутоматски заменити стару адресу новом.\n\nПрепоручљиво је да подесите свог предходног имејл провајдера да прослеђује све имејл поруке на вашу нову имејл адресу. У супротном бисте могли да пропустите поруке од контаката који још нису добили вашу нову адресу. - @@ -797,12 +784,8 @@ %1$s је одговорио и чека да буде додат у групу... %1$s потврђен. - - Немогуће је проверити %1$s. Проверено од %1$s - - Подешавања су се променила за %1$s. Изабери ћаскање у које желите да пошаљете поруку %1$s већ има нацрт поруке, да ли желите да је замените? @@ -835,9 +818,6 @@ Окрени Обрни - - Шифрована порука - Ово је званична Delta Chat апликација за рачунар. Овај програм је лиценциран под ГНУ ГПЛ верзија 3 лиценцом и изворни код је доступан на Гитхабу. diff --git a/src/main/res/values-sv/strings.xml b/src/main/res/values-sv/strings.xml index e9525947c..4619feb90 100644 --- a/src/main/res/values-sv/strings.xml +++ b/src/main/res/values-sv/strings.xml @@ -201,19 +201,7 @@ Ny chatt Ny grupp Klona chatt - - Sändlista - - Sändlistor - - Ny sändlista Lägg till mottagare - - Redigera sändlista - - Sändlistans namn - - Ange ett namn på sändlistan Skicka Byt emoji-tangentbord Redigera grupp @@ -349,8 +337,6 @@ Chatta med %1$s ? Ta bort %1$s från gruppen? - - Vill du ta bort %1$s från sändlistan? Vill du öppna denna länk? @@ -380,8 +366,6 @@ Skicka ett meddelande till %1$s. - - I en sändlista kommer mottagarna att få meddelanden i en skrivskyddad chatt med dig. Komponera det första meddelandet, så att andra kan svara inom denna grupp.\n\n• Det är okej om inte alla medlemmar använder Delta Chat.\n\n• Det kan ta en stund innan det första meddelandet levereras. Svep för att avbryta Tryck och håll ner för att spela in ett röstmeddelande, släpp för att skicka. @@ -479,11 +463,6 @@ Kvadratiskt rutnät Skicka meddelande - - %1$s ändrade sin adress från %2$s till %3$s - - Du har ändrat din e-postadress från %1$s till %2$s.\n\nOm du nu skickar ett meddelande till en verifierad grupp kommer kontakterna där automatiskt att ersätta den gamla med din nya adress. Vi rekommenderar starkt att du ställer in din gamla e-postleverantör så att den vidarebefordrar alla e-postmeddelanden till din nya e-postadress. Annars kan du missa meddelanden från kontakter som inte har fått din nya adress ännu. - @@ -852,14 +831,8 @@ Du satte tiduret för meddelandeborttagning till %1$s veckor. Tiduret för meddelandeborttagning är satt till %1$s veckor av %2$s. - - %1$s skickade ett meddelande från en annan enhet. Meddelanden är garanterat totalsträckskrypterade från och med nu. Tryck för att få veta mer. Det är nu garanterat att alla meddelanden i den här chatten är totalsträckskrypterade.\n\nTotalsträckskryptering håller meddelanden privata mellan dig och dina chattpartners. Inte ens din e-postleverantör kan läsa dem. - - %1$s skickade ett meddelande från en annan enhet. Tryck för att läsa mer. - - Totalsträckskryptering kan inte garanteras längre, troligen för att %1$s installerade om Delta Chat eller skickade ett meddelande från en annan enhet.\n\nDu kan träffa dem personligen och skanna deras QR-kod igen för att återupprätta garanterad totalsträckskryptering. ⚠️ %1$s kräver totalsträckskryptering som inte är kofigurerad för den här chatten ännu. Tryck för att lära dig mer. För att skapa totalsträckskryptering kan du träffa kontakter personligen och skanna deras QR-kod för att introducera dem. Lär dig mer @@ -918,16 +891,10 @@ %1$s svarade och väntar på att bli tillagd i gruppen... Upprättar garanterad totalsträckskryptering, vänligen vänta... - - Kunde ännu inte upprätta garanterad totalsträckskryptering, men du kan redan skicka ett meddelande. %1$s verifierad. - - Kan inte verifiera %1$s. Introducerad av %1$s Introducerad av mig - - Ändrade inställningarna för %1$s. För att garantera totalsträckskryptering kan du bara lägga till kontakter med en grön bock i den här gruppen.\n\nDu kan träffa kontakter personligen och skanna deras QR-kod för att introducera dem. Välj chatt för att skicka meddelandet till @@ -970,9 +937,6 @@ Vänd Rotera - - Krypterat meddelande - Detta är den officiella Delta Chat skrivbordsappen. Denna programvara är licensierad enligt GNU GPL version 3 och källkoden finns tillgänglig på GitHub. @@ -1081,6 +1045,4 @@ Tryck här för att ta emot meddelanden medan Delta Chat är i bakgrunden. Du har redan gett Delta Chatt tillstånd att ta emot meddelanden i bakgrunden.\n\nKontrollera dina systeminställningar också, om det fortfarande inte kommer några meddelanden i bakgrunden. - - ℹ️ Alternativet \"Byt profil\" har flyttats: Tryck på din profilbild i det övre hörnet av huvudskärmen för att lägga till eller byta profil 💡 - + diff --git a/src/main/res/values-ta/strings.xml b/src/main/res/values-ta/strings.xml index f8e7b3ad9..f5e6b6b23 100644 --- a/src/main/res/values-ta/strings.xml +++ b/src/main/res/values-ta/strings.xml @@ -226,9 +226,6 @@ அனுமதி தேவை தொடர் - - மறைகுறியாக்கப்பட்ட செய்தி - Delta Chat க்கு வரவேற்கிறது. நிறவடிவமைப்பு கோப்பு diff --git a/src/main/res/values-te/strings.xml b/src/main/res/values-te/strings.xml index d259b061d..fcac5b203 100644 --- a/src/main/res/values-te/strings.xml +++ b/src/main/res/values-te/strings.xml @@ -195,9 +195,6 @@ అనుమతి అవసరం కొనసాగించు - - ఎంక్రిప్ట్ చెసిన సందేశం - Delta Chat కి స్వాగతం. ఫైల్ మార్చు diff --git a/src/main/res/values-tr/strings.xml b/src/main/res/values-tr/strings.xml index ec784079a..b2dcd45ae 100644 --- a/src/main/res/values-tr/strings.xml +++ b/src/main/res/values-tr/strings.xml @@ -240,12 +240,6 @@ Sohbet et… Sohbeti Çoğalt - - Yayın Listesi - - Yayın Listeleri - - Yeni Yayın Listesi Kanal @@ -253,12 +247,6 @@ Yeni Kanal Alıcılar Ekle - - Yayın Listesini Düzenle - - Yayın Listesi Adı - - Lütfen yayın listesi için bir ad girin. Kanal Adı E-Posta @@ -424,8 +412,6 @@ %1$s ile sohbet edilsin mi? %1$s öbekten kaldırılsın mı? - - %1$s yayın listesinden kaldırılsın mı? %1$s kanaldan kaldırılsın mı? Bu bağlantıyı açmak istiyor musunuz? @@ -457,8 +443,6 @@ %1$s kişisine bir ileti gönderin. - - Bir yayın listesinde, alıcılar sizinle salt okunur bir sohbette iletiler alacak. Kanallar, iletilerinizi yayınlamak için birden çoğa bir araçtır. Diğerleri, yalnızca siz bir ilk ileti gönderdikten sonra bu öbeği görecek. @@ -569,11 +553,6 @@ Kare Izgara İleti Gönder - - %1$s, %2$s adresini %3$s olarak değiştirdi - - %1$s e-posta adresinizi %2$s olarak değiştirdiniz.\n\nŞimdi bir doğrulanan öbeğe ileti gönderirseniz, oradaki kişiler yeni adresinizle eskisini otomatik olarak değiştirecek.\n\nTüm e-postaları yeni e-posta adresinize iletmek için eski e-posta sağlayıcınızı ayarlamanız önemle önerilir. Yoksa henüz yeni adresinizi almamış olan kişilerin iletilerini kaçırabilirsiniz. - @@ -956,6 +935,9 @@ Kaybolan iletiler zamanlayıcısını 1 hafta olarak ayarladınız. %1$s tarafından kaybolan iletiler zamanlayıcısı 1 hafta olarak ayarlandı. + Kaybolan iletiler zamanlayıcısını 1 yıl olarak ayarladınız. + + %1$s tarafından kaybolan iletiler zamanlayıcısı 1 yıl olarak ayarlandı. Kaybolan iletiler zamanlayıcısını %1$s dakika olarak ayarladınız. @@ -972,14 +954,8 @@ Kaybolan iletiler zamanlayıcısını %1$s hafta olarak ayarladınız. %2$s tarafından kaybolan iletiler zamanlayıcısı %1$s hafta olarak ayarlandı. - - %1$s başka bir aygıttan bir ileti gönderdi. İletiler uçtan uca şifreleniyor. Daha fazlasını öğrenmek için dokunun. Bu sohbetteki tüm iletiler uçtan uca şifreleniyor.\n\nUçtan uca şifreleme, iletilerinizi sizin ve sohbet ortaklarınızın arasında özel tutar. Sunucular, sağlayıcılar ya da aktarıcılar bile onları okuyamaz. - - %1$s başka bir aygıttan bir ileti gönderdi. Daha fazlasını öğrenmek için dokunun. - - Uçtan uca şifreleme artık güvencelenemiyor; çünkü büyük olasılıkla %1$s Delta Chat\'i yeniden yükledi ya da başka bir aygıttan ileti gönderdi.\n\nOnlarla kişisel olarak tanışabilir ve güvenceli uçtan uca şifrelemeyi yeniden kurmak için onların QR kodunu yeniden tarayabilirsiniz. ⚠️ %1$s, bu sohbet için henüz ayarlanmayan uçtan uca şifrelemeyi gerektirir. Daha fazlasını öğrenmek için dokunun. Uçtan uca şifrelemeyi kurmak için kişilerle kişisel olarak tanışabilir ve onları tanıtmak için onların QR kodunu tarayabilirsiniz. Daha Fazlasını Öğrenin @@ -1038,19 +1014,11 @@ %1$s yanıtladı; öbeğe eklenmesi bekleniyor… Uçtan uca şifreleme kuruluyor, lütfen bekleyin… - - Henüz güvencelenen uçtan uca şifreleme kurulamadı; ama zaten bir ileti gönderebilirsiniz. - - Sürdürmek için kişi çevrimiçi olmalıdır.\n\nBu işlem, arka planda otomatik olarak sürecek. %1$s tanıtıldı. - - %1$s ile uçtan uca şifreleme kurulamıyor. %1$s tarafından tanıtıldı Benim tarafımdan tanıtıldı Tanıtıldı - - %1$s için ayarlama değiştirildi. Uçtan uca şifrelemeyi güvencelemek için bu öbeğe yalnızca yeşil bir onay imi olan kişileri ekleyebilirsiniz.\n\nDoğrulanmayan kişilerle kişisel olarak tanışabilir ve onları tanıtmak için onların QR kodunu tarayabilirsiniz. İletiyi göndermek için sohbet seçin @@ -1093,9 +1061,6 @@ Çevir Döndür - - Şifrelenen ileti - Bu, resmî Delta Chat Masaüstü uygulamasıdır. Bu yazılım, GNU GPL sürüm 3 altında lisanslıdır ve kaynak kodu GitHub\'da kullanılabilir. @@ -1210,7 +1175,6 @@ Delta Chat, görselleri fotoğraf kitaplığınıza kaydetmek istiyor. Delta Chat; yerel profilinizi korumak, yedek oluşturmak ve ikinci aygıt ayarlaması için Face ID\'yi kullanabilir. - Anında Teslimat Arka Plan Bağlantısı Kullan @@ -1225,8 +1189,4 @@ Ne yeni?\n\n💯 Uçtan uca şifreleme artık güvenilir ve sonsuza kadar geçerli. Asma kilitlerle 🔒 anlaşılabilir!\n\n✉️ Uçtan uca şifrelemeli olmayan klasik e-posta bir mektup sembolü olarak işaretlenir\n\n😻 Tüm kişileriniz için yeni geliştirilen profil ekranı\n\n🔲 Bir sohbette kullanılan uygulamalara hızlı erişim için yeni düğme\n\n❤️ Bağımsız kalmamız ve yeni geliştirmeler getirmemiz için lütfen bize yardım edin: %1$s - - Ne yeni?\n\n❤️‍🔥 Daha fazla emojiyle yeni emoji seçicisi\n\n🎮 Geliştirilen sohbet içi uygulamalar: Bildirimler alın ve destekleyen uygulamaları bağlamda açın, yani eklenen bir takvim girdisini doğrudan açın\n\n👍 İletilerinize verilen tepkiler hakkında bildirimler alın\n\n... 🛠️ DÜZELTMELER ve HATTA DAHA FAZLASI için %1$s - - ℹ️ “Profili Değiştir” seçeneği taşındı: Yeni profil eklemek ya da profilleri değiştirmek için ana ekranın üst köşesindeki profil görselinize dokunun 💡 diff --git a/src/main/res/values-uk/strings.xml b/src/main/res/values-uk/strings.xml index 5d331d889..90070d343 100644 --- a/src/main/res/values-uk/strings.xml +++ b/src/main/res/values-uk/strings.xml @@ -258,12 +258,6 @@ Повідомлення до... Клонувати чат - - Список трансляцій - - Списки трансляцій - - Новий Список трансляцій Канал @@ -271,12 +265,6 @@ Новий Канал Додати одержувачів - - Редагувати список трансляцій - - Назва списку трансляцій - - Будь ласка, введіть назву для списку трансляцій. Назва Каналу E-Mail @@ -450,8 +438,6 @@ Створити чат з %1$s? Видалити %1$s із групи? - - Видалити %1$s зі списку трансляцій? Видалити %1$s з каналу? Ви впевнені, що хочете відкрити це посилання? @@ -489,8 +475,6 @@ Відправити повідомлення → %1$s. - - У списку трансляцій одержувачі будуть отримувати повідомлення в чаті з Вами в режимі тільки-для-читання. Канали - це інструмент \"один до багатьох\" для трансляції ваших повідомлень. Інші побачать цю групу лише після того, як ви надішлете перше повідомлення. @@ -601,11 +585,6 @@ Квадратна сітка Надіслати повідомлення - - %1$s змінили їх адресу з %2$s на %3$s - - Ви змінили свою електронну поштову адресу з %1$s на %2$s.\n\nЯкщо тепер відправите повідомлення в підтверджену групу, контакти в ній автоматично замінять стару адресу новою.\n\nРекомендується налаштувати стару поштову скриньку на пересилання всіх електронних листів на Вашу нову скриньку. Інакше Ви можете пропустити повідомлення від контактних осіб, які ще не довідалися вашої нової адреси. - @@ -1004,14 +983,8 @@ Ви встановили таймер зникнення повідомлень на %1$s тижнів. %2$s встановив (-ла) таймер зникнення повідомлень на %1$s тижнів. - - %1$s тепер шле повідомлення з іншого пристрою. Відтепер повідомлення гарантовано будуть мати наскрізне шифрування. Торкніться, щоб дізнатися більше. Тепер гарантовано, що всі повідомлення в цьому чаті наскрізь зашифровані.\n\nНаскрізне шифрування зберігає конфіденційність повідомлень між вами і вашими партнерами по чату. Навіть сервери, провайдери або ретранслятори не можуть їх прочитати. - - %1$s відправив (-ла) повідомлення з іншого пристрою. Торкніться, щоб дізнатися більше. - - Наскрізне шифрування більше не гарантується, імовірно, через те, що %1$s перевстановив (-ла) Delta Chat або надіслав (-ла) повідомлення з іншого пристрою.\n\nВи можете зустрітися з ним (нею) особисто та знову відсканувати його (її) QR-код, щоб відновити гарантоване наскрізне шифрування. ⚠️ %1$s вимагає наскрізного шифрування, яке ще не налаштоване для цього чату. Натисніть, щоб дізнатися більше. Для налагодження наскрізного шифрування можна зустрітись із контактною особою та відсканувати баркод із її пристрою, щоби представити її. Дізнатися більше @@ -1070,19 +1043,11 @@ %1$s відповіли, очікуємо на додавання до групи… Встановлення гарантованого наскрізного шифрування, будь ласка, зачекайте... - - Ще не вдалося встановити гарантоване наскрізне шифрування, але ви вже можете надсилати повідомлення. - - Щоб продовжити, контакт повинен бути онлайн.\n\nЦей процес продовжиться автоматично у фоновому режимі. %1$s представлено! - - Не вдається встановити гарантоване наскрізне шифрування з %1$s Представни·ця: %1$s Представлено мною Представлено - - Змінені параметри для %1$s Аби наскрізне шифрування лишалося ґарантованим, у цю групу можна додавати лише контактних осіб із зеленою галочкою.\n\nМожна зустрітись із контактною особою та відсканувати баркод із її пристрою, щоби представити її. Виберіть чат, куди потрібно надіслати повідомлення @@ -1125,9 +1090,6 @@ Обернути Обертати - - Зашифроване повідомлення - Це офіційний додаток Delta Chat для ПК. Це програмне забезпечення ліцензується за GNU GPL версії 3, а початковий код доступний на GitHub. @@ -1242,7 +1204,6 @@ Delta Chat хоче зберігати зображення до Вашої фото-бібліотеки. Delta Chat може використовувати Face ID для захисту вашого локального профілю, створення резервної копії та налаштування другого пристрою. - Миттєва доставка Використовувати фонове підключення @@ -1257,8 +1218,4 @@ Що нового?\n\n💯 Наскрізне шифрування тепер надійне і завжди. Навісні замки 🔒 зникли!\n\n✉️ Класична електронна пошта без наскрізного шифрування позначається символом листа\n\n😻 Новий покращений екран профілю для всіх ваших контактів\n\n🔲 Нова кнопка для швидкого доступу до додатків, що використовуються в чаті\n\n❤️ Будь ласка, пожертвуйте, щоб допомогти нам залишатися незалежними та продовжувати вдосконалюватися: %1$s - - Що нового? \n\n❤️‍🔥 Новий вибірник емодзі з більшою кількістю смайликів \n\n🎮 Покращені програми в чаті: отримуйте сповіщення та відкривайте додатки безпосередньо в контексті, наприклад, доданий запис у календарі \n\n👍 Отримуйте сповіщення про реакції на ваші повідомлення \n\n... 🛠️ ВИПРАВЛЕННЯ та ЩЕ БІЛЬШЕ на %1$s - - ℹ️ Опцію \"Перемкнути профіль\" переміщено: Торкніться зображення свого профілю у верхньому кутку головного екрану, щоб додати або перемкнути профіль 💡. diff --git a/src/main/res/values-vi/strings.xml b/src/main/res/values-vi/strings.xml index 4430eb7cf..a2e5b0b2c 100644 --- a/src/main/res/values-vi/strings.xml +++ b/src/main/res/values-vi/strings.xml @@ -189,19 +189,7 @@ Trò chuyện mới Nhóm mới Sao chép cuộc trò chuyện - - Danh sách phát sóng - - Danh sách phát sóng - - Danh sách phát sóng mới Thêm người nhận - - Chỉnh sửa danh sách phát sóng - - Tên danh sách phát sóng - - Vui lòng nhập tên cho danh sách phát sóng. Gửi Chuyển đổi Bàn phím Emoji Chỉnh sửa nhóm @@ -330,8 +318,6 @@ Trò chuyện với %1$s? Loại %1$s khỏi nhóm? - - Loại %1$s khỏi danh sách phát sóng? Bạn có muốn mở liên kết này không? @@ -358,8 +344,6 @@ Gửi tin nhắn tới %1$s. - - Trong danh sách phát sóng, người nhận sẽ nhận được tin nhắn trong cuộc trò chuyện chỉ đọc với bạn. Những người khác sẽ chỉ nhìn thấy nhóm này sau khi bạn gửi tin nhắn đầu tiên. Trượt để hủy Nhấn và giữ để ghi tin nhắn thoại, thả ra để gửi @@ -457,11 +441,6 @@ Lưới vuông Gửi tin nhắn - - %1$s đã thay đổi địa chỉ của họ từ %2$s thành %3$s - - Bạn đã thay đổi địa chỉ email của mình từ %1$s thành %2$s.\n\nNếu bây giờ bạn gửi thư đến một nhóm đã được xác minh, những người liên hệ ở đó sẽ tự động thay thế địa chỉ cũ bằng địa chỉ mới của bạn.\n\nĐiều đó thật tuyệt vời khuyên bạn nên thiết lập nhà cung cấp email cũ để chuyển tiếp tất cả email đến địa chỉ email mới của bạn. Nếu không, bạn có thể bỏ lỡ tin nhắn của những người chưa nhận được địa chỉ mới của bạn. - @@ -786,14 +765,8 @@ Bạn đặt bộ hẹn giờ cho tin nhắn biến mất thành %1$s tuần. Bộ hẹn giờ cho tin nhắn biến mất được %2$s đặt thành %1$s tuần. - - %1$s đã gửi tin nhắn từ một thiết bị khác. Tin nhắn được đảm bảo sẽ được mã hóa hai đầu kể từ bây giờ. Nhấn để tìm hiểu thêm. Hiện tại, chúng tôi đảm bảo rằng tất cả tin nhắn trong cuộc trò chuyện này đều được mã hóa hai đầu.\n\nMã hóa hai đầu giúp giữ tin nhắn giữa bạn và đối tác trò chuyện của bạn ở chế độ riêng tư. Ngay cả nhà cung cấp email của bạn cũng không thể đọc được chúng. - - %1$s đã gửi tin nhắn từ một thiết bị khác. Nhấn để tìm hiểu thêm. - - Mã hóa hai đầu không còn được đảm bảo nữa, có thể vì %1$s đã cài đặt lại Delta Chat hoặc đã gửi tin nhắn từ một thiết bị khác.\n\nBạn có thể gặp trực tiếp họ và quét lại mã QR của họ để thiết lập lại tính năng mã hóa hai đầu được đảm bảo kết thúc mã hóa. Tìm hiểu thêm Bạn đã xóa cuộc trò chuyện \"Tin nhắn đã lưu\".\n\nℹ️ Để sử dụng lại tính năng \"Tin nhắn đã lưu\", hãy tạo một cuộc trò chuyện mới với chính bạn. @@ -847,13 +820,9 @@ %1$s đã trả lời, đang chờ được thêm vào nhóm… %1$s đã được giới thiệu. - - Không thể thiết lập mã hóa đầu cuối được đảm bảo với %1$s. Được giới thiệu bởi %1$s Được tôi giới thiệu - - Đã thay đổi thiết lập cho %1$s. Để đảm bảo mã hóa hai đầu, bạn chỉ có thể thêm những người liên hệ có dấu kiểm màu xanh lục vào nhóm này.\n\nBạn có thể gặp trực tiếp những người liên hệ và quét Mã QR của họ để giới thiệu họ. Chọn trò chuyện để gửi tin nhắn tới @@ -894,9 +863,6 @@ Lật Xoay - - Tin nhắn được mã hóa - Đây là ứng dụng Delta Chat Desktop chính thức. Phần mềm này được cấp phép theo GNU GPL phiên bản 3 và mã nguồn có sẵn trên GitHub. diff --git a/src/main/res/values-zh-rCN/strings.xml b/src/main/res/values-zh-rCN/strings.xml index 80145f368..074ff98de 100644 --- a/src/main/res/values-zh-rCN/strings.xml +++ b/src/main/res/values-zh-rCN/strings.xml @@ -231,12 +231,6 @@ 聊天… 克隆聊天 - - 广播列表 - - 广播列表 - - 新建广播列表 频道 @@ -244,12 +238,6 @@ 新建频道 添加接收者 - - 编辑广播列表 - - 广播列表名称 - - 请输入广播列表的名称。 频道名称 邮件 @@ -411,8 +399,6 @@ 与 %1$s 聊天? 将 %1$s 从群组中移除? - - 从广播列表中移除 %1$s? 从频道中移除 %1$s? 您要打开此链接吗? @@ -441,8 +427,6 @@ 发一条消息给 %1$s。 - - 在广播列表中,收件人会在和你进行的只读聊天中收到消息 频道是广播消息的一对多工具。 在您发出第一条消息后,其他人才会看到此群组。 @@ -553,11 +537,6 @@ 方形网格 发送消息 - - %1$s 将邮箱从 %2$s 更改为 %3$s - - 你将邮箱从 %1$s 改为了 %2$s。\n\n如果你现在发送一条消息到已验证群组,那里的联系人将自动用你的新邮箱替换旧邮箱。\n\n我们建议你将旧邮箱配置为转发所有邮件到新邮箱。否则,你可能收不到还不知道你新邮箱的联系人发过来的消息。 - @@ -940,6 +919,9 @@ 你将消息定时销毁计时器设为 1 周 %1$s 将消息定时销毁计时器设为 1 天 + 您将消失消息计时器设置为 1 年。 + + %1$s 将消失消息计时器设置为 1 年。 你将消息定时销毁计时器设为 %1$s 分钟 @@ -956,14 +938,8 @@ 你将消息定时销毁计时器设为 %1$s 周 %2$s 将消息定时销毁计时器设为 %1$s 周 - - %1$s 从另一台设备发送了消息 消息是端到端加密的。点按即可了解详情。 此聊天中的所有消息都经过端到端加密。\n\n端到端加密可确保您与聊天对象之间的消息保持私密。即使是服务器、提供者或中继也无法读取。 - - %1$s 从另一台设备发送了一条消息。点按即可了解详情。 - - 无法再确保端到端加密,可能的原因是 %1$s 重新安装了 Delta Chat 或从其他设备发送了一则消息。\n\n你可以和联系人线下见面并再次扫描联系人的二维码重新建立端到端加密的通信。 ⚠️ %1$s 需要端到端加密,但此聊天尚未设置。点按即可了解详情。 要建立端到端加密,你可以亲自和联系人碰面并扫描联系人的二维码 了解更多 @@ -1022,19 +998,11 @@ %1$s 已回复,等待被加入群组… 正在建立端到端加密,请稍候… - - 无法建立有保证的端到端加密,但您可能已经发送了一条消息。 - - 联系人必须在线才能继续。\n\n此过程将在后台自动继续。 %1$s 已验证。 - - 无法与 %1$s 建立端到端加密。 验证人 %1$s 由您验证 已验证 - - %1$s 的加密设置已更改。 要确保端到端加密,你只能将带有绿色验证标识的联系人到此群中。\n\n你可以亲自和未验证联系人线下碰面并扫描联系人二维码来验证。 选择要发送消息的聊天 @@ -1077,9 +1045,6 @@ 翻转 旋转 - - 加密的消息 - 这是 Delta Chat 官方桌面应用。 本软件在 GNU GPL 版本 3 下获得授权,其源代码可从 GitHub 获得。 @@ -1194,7 +1159,6 @@ Delta Chat 想将图像保存到图库。 Delta Chat 可以使用 Face ID 保护你的本地配置文件,备份创建和第二台设备设置。 - 即时传送 使用后台连接 @@ -1209,8 +1173,4 @@ 新版变化?\n\n💯 端到端加密现在可靠且永久。挂锁图标 🔒 没有了!\n\n✉️ 没有端到端加密的经典电子邮件用字母符号标记l\n\n😻 所有联系人的新的增强的个人资料屏\n\n🔲 新增快速访问聊天中所用应用的按钮\n\n❤️ 请捐赠帮助我们保持独立并继续带来改进: %1$s - - 有什么新功能?\n\n❤️‍🔥 新的表情符号选择器,包含更多表情符号\n\n🎮 增强的聊天应用:获取通知并在上下文中打开支持应用,即直接打开添加的日历条目\n\n👍 收到有关对您的消息的回应的通知\n\n…🛠️ %1$s 上的修复和更多内容 - - ℹ️ “切换账号”选项已移动:点击主屏幕上角的个人资料图片以添加或切换账号 💡 diff --git a/src/main/res/values-zh-rTW/strings.xml b/src/main/res/values-zh-rTW/strings.xml index dbdb4d29f..5fd9a3f3b 100644 --- a/src/main/res/values-zh-rTW/strings.xml +++ b/src/main/res/values-zh-rTW/strings.xml @@ -231,19 +231,7 @@ 與……聊天 克隆聊天 - - 廣播列表 - - 廣播列表 - - 新增廣播列表 新增對象 - - 編輯廣播列表 - - 廣播列表名稱 - - 請為廣播列表輸入名稱。 送出 切換表情符號鍵盤 編輯群組 @@ -392,8 +380,6 @@ 要和%1$s開始對話嗎? 要把%1$s移出群組嗎? - - 將%1$s自廣播列表中移除? 你想開啟此連結嗎? @@ -420,8 +406,6 @@ 向 %1$s 傳送訊息。 - - 在廣播清單中,收件者將在與您的只讀聊天中收到消息。 只有在你傳送第一條訊息後,其他人才會看到此群組。 滑動以取消 按住錄音,放開後傳送 @@ -530,11 +514,6 @@ 方形網格 傳送訊息 - - %1$s 已將他的位址從 %2$s更改 為 %3$s - - 您已將電子郵件位址從%1$s更改為%2$s 。\n\n如果您現在向已驗證的群組發送消息,那裡的聯絡人會自動將舊位址替換為您的新位址。\n\n強烈建議您將舊電子郵件供應商設置為將所有電子郵件轉發到您的新電子郵件位址。否則,您可能會錯過尚未獲得新地址的聯絡人的消息。 - @@ -931,14 +910,8 @@ 您將自動刪除訊息計時器設置為%1$s週。 %2$s將自動刪除訊息計時器設置為%1$s週。 - - %1$s從另一台裝置傳送了一條訊息。 從現在開始,保證消息進行端到端加密。輕觸以瞭解更多資訊。 現在可以保證此聊天中的所有消息都是端到端加密的。\n\n端到端加密使您和您的聊天夥伴之間的消息保持私密。甚至您的電子郵件供應商也無法讀取它們。 - - %1$s從另一台裝置傳送了一條訊息。輕觸以瞭解更多資訊。 - - 無法再保證端到端加密,可能是因為%1$s重新安裝了 Delta Chat 或從其他裝置傳送了訊息\n\n您可以再次當面掃描他們的QR碼,以重新建立有保證的端到端加密。 ⚠️ %1$s需要端到端加密,但尚未為此聊天設置。輕觸以瞭解更多資訊。 要建立端到端加密,您可以當面掃描聯絡人的QR碼。 瞭解更多 @@ -997,18 +970,10 @@ %1$s已回覆,等待被添加到群組中... 正在建立有保證的端到端加密,請稍候... - - 尚無法建立有保證的端到端加密,但您可能已經送出了一條訊息。 - - 聯繫人必須處於連線狀態才能繼續。\n\n此過程將在後台自動繼續。 %1$s已介紹。 - - 無法與%1$s建立有保證的端到端加密。 由%1$s介紹 由我介紹 - - 已爲%1$s更改設定。 為了保證端到端加密,您只能將帶有綠色驗證標識的聯絡人添加到此群組。\n\n您可以當面掃描聯絡人的QR碼以介紹他們。 選擇要將消息發送到的聊天 @@ -1051,9 +1016,6 @@ 翻轉 旋轉 - - 已加密的訊息 - 這是 Delta Chat 官方桌面應用程式。 該軟體根據 GNU GPL 第 3 版獲得許可,原始程式碼可在 GitHub 上找到。 @@ -1168,7 +1130,6 @@ Delta Chat 希望將圖像保存到您的照片庫。 Delta Chat 可以使用 Face ID 保護您的本地賬戶、備份創建和第二台裝置設定。 - 即時傳送 使用背景連接 @@ -1181,8 +1142,4 @@ 點擊此處可在 Delta Chat 處於後台時接收訊息。 您已經允許 Delta Chat 在後台接收訊息。\n\n如果消息仍未在後台到達,請同時檢查您的系統設定。 - - 新功能\n\n❤️ 🔥 新的表情符號選擇器,包含更多表情符號\n\n🎮 增強的聊天應用程式:在上下文中獲取通知並打開支援應用程式,即直接打開添加的日曆條目\n\n👍獲取有關對您的消訊息的回應的通知\n\n...🛠️ 修復以及更多在%1$s - - ℹ️「切換賬戶」選項已移動:點擊主螢幕右上角的賬戶大頭貼以添加或切換賬戶 💡 - + diff --git a/src/main/res/values/arrays.xml b/src/main/res/values/arrays.xml index 3a7b857f8..aa308b4cb 100644 --- a/src/main/res/values/arrays.xml +++ b/src/main/res/values/arrays.xml @@ -61,14 +61,12 @@ @string/off - @string/after_1_minute - @string/after_5_minutes - @string/after_30_minutes - @string/autodel_after_1_hour - @string/autodel_after_1_day - @string/autodel_after_1_week - @string/after_5_weeks - @string/autodel_after_1_year + @string/after_5_minutes + @string/autodel_after_1_hour + @string/autodel_after_1_day + @string/autodel_after_1_week + @string/after_5_weeks + @string/autodel_after_1_year diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 1853d0078..9e1190960 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -134,11 +134,22 @@ last seen %1$s last seen: Unknown + + + %d second + %d seconds + + + + %d minute + %d minutes + %d min %d min + %d hour @@ -256,12 +267,6 @@ Chat with… Clone Chat - - Broadcast List - - Broadcast Lists - - New Broadcast List Channel @@ -269,12 +274,6 @@ New Channel Add Recipients - - Edit Broadcast List - - Broadcast List Name - - Please enter a name for the broadcast list. Channel Name E-Mail @@ -396,20 +395,47 @@ File saved to \"%1$s\". + + Call + + Answer + + Decline + Outgoing call + Incoming call + Declined call + Canceled call + Missed call + + %1$s, %2$s + + Video Chat + Invite %1$s to a video chat? + This requires a compatible app or browser on both ends. + %1$s invited to a video chat. + You sent a video chat invitation. + Tap to Join + Tap to Open + Video Chat Instance + Your Video Chat Instance - + Example: https://your-server.org/$ROOM + If enabled, you can start a video chat from each chat. Requires a compatible app or a browser on both ends. + Use \"%1$s\" to invite others to video chats?\n\nOnce set, you can start a video chat from each chat. This replaces any previous setting for video chats. + Video chat invitation + You are invited to a video chat, click %1$s to join. @@ -440,8 +466,6 @@ Chat with %1$s? Remove %1$s from group? - - Remove %1$s from broadcast list? Remove %1$s from channel? Do you want to open this link? @@ -473,8 +497,6 @@ Send a message to %1$s. - - In a broadcast list, recipients will receive messages in a read-only chat with you. Channels are a one-to-many tool for broadcasting your messages. Others will only see this group after you sent a first message. @@ -490,6 +512,8 @@ No messages. Messages to Self Archived chats will appear here. + + Save Message Saved Messages • Forward messages here for easy access\n\n• Take notes or voice memos\n\n• Attach media to save them @@ -585,11 +609,6 @@ Square Grid Send Message - - %1$s changed their address from %2$s to %3$s - - You changed your email address from %1$s to %2$s.\n\nIf you now send a message to a verified group, contacts there will automatically replace the old with your new address.\n\nIt\'s highly advised to set up your old email provider to forward all emails to your new email address. Otherwise you might miss messages of contacts who did not get your new address yet. - @@ -905,8 +924,10 @@ At once after Download After 30 seconds + After 1 minute After 5 minutes + After 30 minutes After 1 hour After 1 day @@ -960,8 +981,9 @@ You set disappearing messages timer to %1$s seconds Disappearing messages timer set to %1$s seconds by %2$s. + You set disappearing messages timer to 1 minute. - + Disappearing messages timer set to 1 minute by %1$s. You set disappearing messages timer to 1 hour. @@ -991,14 +1013,8 @@ You set disappearing messages timer to %1$s weeks. Disappearing messages timer set to %1$s weeks by %2$s. - - %1$s sent a message from another device. Messages are end-to-end encrypted. Tap to learn more. All messages in this chat are end-to-end encrypted.\n\nEnd-to-end encryption keeps messages private between you and your chat partners. Not even servers, providers or relays can read them. - - %1$s sent a message from another device. Tap to learn more. - - End-to-end encryption cannot be guaranteed anymore, likely because %1$s reinstalled Delta Chat or sent a message from another device.\n\nYou may meet them in person and scan their QR code again to reestablish guaranteed end-to-end encryption. ⚠️ %1$s requires end-to-end encryption which is not setup for this chat yet. Tap to learn more. To establish end-to-end-encryption, you may meet contacts in person and scan their QR Code to introduce them. Learn More @@ -1057,19 +1073,11 @@ %1$s replied, waiting for being added to the group… Establishing end-to-end encryption, please wait… - - Could not yet establish guaranteed end-to-end encryption, but you may already send a message. - - The contact must be online to proceed.\n\nThis process will continue automatically in background. %1$s introduced. - - Cannot establish end-to-end encryption with %1$s. Introduced by %1$s Introduced by me Introduced - - Changed setup for %1$s. To guarantee end-to-end-encryption, you can only add contacts with a green checkmark to this group.\n\nYou may meet contacts in person and scan their QR Code to introduce them. Select chat to send the message to @@ -1086,6 +1094,7 @@ Name only No name or message Notifications disabled + Enable \"Force Background Connection\" for reliable notifications New messages You have new messages @@ -1112,9 +1121,6 @@ Flip Rotate - - Encrypted message - This is the official Delta Chat Desktop app. This software is licensed under GNU GPL version 3 and the source code is available on GitHub. @@ -1202,7 +1208,7 @@ Disabled in Delta Chat Disabled in system settings \"Background App Refresh\" disabled in system settings - + Delayed On average every %1$d minutes On average every %1$d hours @@ -1229,7 +1235,6 @@ Delta Chat wants to save images to your photo library. Delta Chat can use Face ID to protect your local profile, backup creation and second device setup. - Instant Delivery Use Background Connection diff --git a/src/main/res/xml/preferences_advanced.xml b/src/main/res/xml/preferences_advanced.xml index ffa8d751d..fae5d1ec0 100644 --- a/src/main/res/xml/preferences_advanced.xml +++ b/src/main/res/xml/preferences_advanced.xml @@ -16,10 +16,6 @@ - - diff --git a/src/main/res/xml/preferences_notifications.xml b/src/main/res/xml/preferences_notifications.xml index 612b34c6f..b96873fc6 100644 --- a/src/main/res/xml/preferences_notifications.xml +++ b/src/main/res/xml/preferences_notifications.xml @@ -64,7 +64,7 @@ android:summary="@string/pref_background_notifications_explain"/>