mirror of
https://github.com/ArcaneChat/android.git
synced 2026-07-03 14:05:24 +02:00
Compare commits
197 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1b0b87f148 | |||
| a955d6f2f7 | |||
| 2143bc01d1 | |||
| 5a3728428b | |||
| f236085b92 | |||
| b0cea8f099 | |||
| 7590b21928 | |||
| ea7fd0ec22 | |||
| 6a4e40d17b | |||
| 5302e86011 | |||
| 5382e880a9 | |||
| 2385b236c7 | |||
| 5224119f9e | |||
| dfef2b4120 | |||
| 6d7f417233 | |||
| 05ef95e757 | |||
| 8aa45b7bc9 | |||
| 7cea23caf5 | |||
| 4a2bed3e6c | |||
| 3aa2fbf67a | |||
| c5d9471f2a | |||
| 5117b70c58 | |||
| da4d17aa14 | |||
| 6135813bff | |||
| 8547f7aab8 | |||
| 6dca20045c | |||
| 58ef777091 | |||
| 4a836b3d82 | |||
| 363122fd15 | |||
| b751219c78 | |||
| e586fafc54 | |||
| 2c04319c52 | |||
| f9607e4453 | |||
| 6aec209ebc | |||
| 9adc9b34e5 | |||
| 9267501bc1 | |||
| 924c3f8920 | |||
| 8f93dacbff | |||
| a07e9312ea | |||
| 79f6010d5f | |||
| c5af1d4f2b | |||
| 20a3820871 | |||
| cb0d1106b4 | |||
| 291ef86a4f | |||
| b0457bc036 | |||
| 4d7107314a | |||
| 4185219088 | |||
| ef51492d0b | |||
| 4dc10f977e | |||
| aaba52dba6 | |||
| ca4808aaca | |||
| 66324fe914 | |||
| a5f67e9d9f | |||
| 8b5c887402 | |||
| 183cb03577 | |||
| b1e6d59ba9 | |||
| 33f38889c1 | |||
| f97e800907 | |||
| 21e597d09e | |||
| 6b040b160d | |||
| 57e5523bf3 | |||
| 874492c9ae | |||
| 8ae6407461 | |||
| ae8ce94c00 | |||
| 74208fff69 | |||
| 7ace2b9baf | |||
| f28fffb9df | |||
| 349e8d80c8 | |||
| 4b9217e3e6 | |||
| 4e6e805ede | |||
| 02a1c86f01 | |||
| b28fb4ac9e | |||
| fddc80e60b | |||
| e5b1becf13 | |||
| 01b78e37fd | |||
| d0b1f36f60 | |||
| e388464d28 | |||
| afc7a04b63 | |||
| b871e42b86 | |||
| 3479233f82 | |||
| 7e3e35a9a1 | |||
| 92711444e4 | |||
| ec576d7159 | |||
| 70a05221ab | |||
| 6335cfa178 | |||
| ebda8c4577 | |||
| de9a2df1b4 | |||
| a3c7e3db3d | |||
| 249fc829be | |||
| 5b62f7bf25 | |||
| df6c858b92 | |||
| c9816ae785 | |||
| a24069ce3d | |||
| f770f817d0 | |||
| bee804e095 | |||
| 6b1c6b37ac | |||
| 881e69c176 | |||
| ac6df2ff85 | |||
| 7698ac5c06 | |||
| c2abe42b60 | |||
| 3e95197d02 | |||
| 534a75feaa | |||
| 7a11234431 | |||
| 0e91537a4d | |||
| b074bf1819 | |||
| b8d2552aa8 | |||
| 320c120a61 | |||
| 6c1a3c850a | |||
| 7ec87f55b6 | |||
| f6ce98f9a2 | |||
| cb465ec85e | |||
| 6f10a90c5f | |||
| 9f439c852f | |||
| 2cc0451a8a | |||
| 02230d05a1 | |||
| 9a6f6d7ea6 | |||
| f4cd299f70 | |||
| d0358a4d0c | |||
| 4fc115b93d | |||
| 0157510c5d | |||
| 831ce19689 | |||
| 9431e26696 | |||
| 9ef01dd352 | |||
| 01c766db41 | |||
| 364d15442a | |||
| 32eefaab42 | |||
| 4b8177f7f0 | |||
| 092a5caf8b | |||
| bfe4438773 | |||
| d251fffc07 | |||
| 180c2bc8de | |||
| 082815f676 | |||
| 640688d774 | |||
| 30868198a2 | |||
| 75673ef1ad | |||
| 478d937b3c | |||
| 7a5eb6bea6 | |||
| 0142d51835 | |||
| 075bad3638 | |||
| 1f173bae9b | |||
| 2deb61477f | |||
| fcc1ab1079 | |||
| c72207da8a | |||
| 82233d7862 | |||
| 2547a0435c | |||
| b6ce6d908f | |||
| c6bbb0a524 | |||
| 826258a1be | |||
| 05dde13e68 | |||
| 06130c7cd8 | |||
| 5d7c701da8 | |||
| 91e898ee96 | |||
| 61e9466c59 | |||
| 39c48d3dcd | |||
| 1c7c3f06e6 | |||
| d4ddb68137 | |||
| c9ac421315 | |||
| e14bf24bb1 | |||
| 700d11f600 | |||
| fbb33c735c | |||
| 7cc9d7ea2f | |||
| ca27be240e | |||
| 8ab9b92517 | |||
| f95b48ad6a | |||
| 8ebdc5414a | |||
| a0e07cb2ea | |||
| 152360d94a | |||
| 8513f7cd36 | |||
| 17e3f3afdd | |||
| 7d7f62dae1 | |||
| 2bd0a0d935 | |||
| cf0414dd66 | |||
| 5fbd065882 | |||
| 5982a9dd8f | |||
| 4b20e3f41f | |||
| ac8d8886cc | |||
| a803d472bf | |||
| 396ed14067 | |||
| 5faea5e40a | |||
| 08bb248919 | |||
| 30dd7a9c33 | |||
| 28f57a2ccb | |||
| 79462c0596 | |||
| 88a4f99cf8 | |||
| f136b6d7d1 | |||
| d8eaf0ad4b | |||
| 2ef3811a56 | |||
| a9541a936e | |||
| 571f49ab13 | |||
| 365f1dbbe6 | |||
| 100bb06e20 | |||
| 27f662707a | |||
| 3086c72304 | |||
| eee218a3b6 | |||
| fa868077b0 | |||
| e8776177ba | |||
| 677c0592fc |
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -1,5 +1,23 @@
|
||||
# Delta Chat Android Changelog
|
||||
|
||||
## Unreleased
|
||||
|
||||
* 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.20.0
|
||||
|
||||
## v2.11.0
|
||||
2025-08
|
||||
|
||||
|
||||
+4
-6
@@ -21,7 +21,7 @@ android {
|
||||
}
|
||||
namespace "org.thoughtcrime.securesms"
|
||||
flavorDimensions "none"
|
||||
compileSdk 34
|
||||
compileSdk 35
|
||||
|
||||
// Set NDK version to strip native libraries.
|
||||
// Even though we compile our libraries outside Gradle with `scripts/ndk-make.sh`,
|
||||
@@ -33,14 +33,14 @@ android {
|
||||
useLibrary 'org.apache.http.legacy'
|
||||
|
||||
defaultConfig {
|
||||
versionCode 30000728
|
||||
versionName "2.11.0"
|
||||
versionCode 30000729
|
||||
versionName "2.20.0"
|
||||
|
||||
applicationId "chat.delta.lite"
|
||||
multiDexEnabled true
|
||||
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 34
|
||||
targetSdkVersion 35
|
||||
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
|
||||
@@ -233,9 +233,7 @@ 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.
|
||||
implementation 'com.github.bumptech.glide:glide:4.16.0'
|
||||
annotationProcessor 'com.github.bumptech.glide:compiler:4.16.0'
|
||||
|
||||
Generated
+15
-15
@@ -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": {
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
pkgs = import nixpkgs { inherit system overlays; };
|
||||
android-sdk = android.sdk.${system} (sdkPkgs:
|
||||
with sdkPkgs; [
|
||||
build-tools-34-0-0
|
||||
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"
|
||||
|
||||
@@ -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);
|
||||
|
||||
+1
-1
Submodule jni/deltachat-core-rust updated: 194b200a75...fc0fe1bd06
Vendored
+5
-9
@@ -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.** { *; }
|
||||
|
||||
@@ -370,7 +370,7 @@
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize">
|
||||
</activity>
|
||||
|
||||
<activity android:name=".videochat.VideochatActivity"
|
||||
<activity android:name=".calls.CallActivity"
|
||||
android:label=""
|
||||
android:theme="@style/TextSecure.LightTheme"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"
|
||||
@@ -436,6 +436,14 @@
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver android:name=".notifications.DeclineCallReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="org.thoughtcrime.securesms.notifications.DECLINE_CALL_NOTICED"/>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver android:name=".notifications.RemoteReplyReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="false">
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -87,6 +87,7 @@
|
||||
<ul>
|
||||
<li><a href="#jaká-oprávnění-delta-chat-potřebuje">Jaká oprávnění Delta Chat potřebuje?</a></li>
|
||||
<li><a href="#pracuje-delta-chat-s-mým-poskytovatelem-e-mailu">Pracuje Delta Chat s <em>mým</em> poskytovatelem e-mailu?</a></li>
|
||||
<li><a href="#can-i-use-delta-chat-in-parallel-with-other-e-mail-apps">Can I use Delta Chat in parallel with other E-Mail apps?</a></li>
|
||||
<li><a href="#i-want-to-manage-my-own-server-for-delta-chat-what-do-you-recommend">I want to manage my own server for Delta Chat. What do you recommend?</a></li>
|
||||
<li><a href="#proč-musím-delta-chatu-zadat-mé-e-mailové-heslo-je-to-bezpečné">Proč musím Delta Chatu zadat mé e-mailové heslo? Je to bezpečné?</a></li>
|
||||
<li><a href="#jaké-zprávy-delta-chat-zobrazuje">Jaké zprávy Delta Chat zobrazuje?</a></li>
|
||||
@@ -407,7 +408,7 @@ who could have already replied, forwarded, saved, screenshotted or otherwise cop
|
||||
in the settings of a chat,
|
||||
at the top right of the chat window,
|
||||
by selecting a time span
|
||||
between 1 minute and 5 weeks.</p>
|
||||
between 5 minutes and 1 year.</p>
|
||||
|
||||
<p>Until the setting is turned off again,
|
||||
each chat member’s Delta Chat app takes care
|
||||
@@ -780,8 +781,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.</p>
|
||||
|
||||
<p>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
|
||||
<img style="vertical-align:middle; width:1.2em; margin:1px" src="../email-icon.png" alt="email" />.</p>
|
||||
|
||||
<h3 id="howtoe2ee">
|
||||
@@ -1621,6 +1622,29 @@ Nicméně, někteří poskytovatelé vyžadují ke správnému chodu speciální
|
||||
podrobnější popis je na <a href="https://providers.delta.chat">Provider Overview</a></li>
|
||||
</ul>
|
||||
|
||||
<h3 id="can-i-use-delta-chat-in-parallel-with-other-e-mail-apps">
|
||||
|
||||
|
||||
Can I use Delta Chat in parallel with other E-Mail apps? <a href="#can-i-use-delta-chat-in-parallel-with-other-e-mail-apps" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Yes, but it is not recommended.</p>
|
||||
|
||||
<p>Parallel usage with the same E-Mail address might lead to the following inconveniences:</p>
|
||||
|
||||
<ul>
|
||||
<li>Next to your Delta Chat notifications,
|
||||
you might also get notifications for (encrypted, so unreadable) chat mail messages
|
||||
in your other email app</li>
|
||||
<li>If Delta Chat is not running
|
||||
or “Advanced > Move automatically to the DeltaChat Folder” is disabled,
|
||||
encrypted Delta Chat messages might clutter the Inbox in your other E-Mail apps.</li>
|
||||
</ul>
|
||||
|
||||
<p><a href="https://support.delta.chat/t/sieve-rule-to-move-deltachat-mails-to-deltachat-folder/288/10">Sieve rules</a> can solve these problems.</p>
|
||||
|
||||
<h3 id="i-want-to-manage-my-own-server-for-delta-chat-what-do-you-recommend">
|
||||
|
||||
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
<ul>
|
||||
<li><a href="#welche-app-berechtigungen-benötigt-delta-chat">Welche App-Berechtigungen benötigt Delta Chat?</a></li>
|
||||
<li><a href="#funktioniert-delta-chat-mit-meinem-e-mail-anbieter">Funktioniert Delta Chat mit <em>meinem</em> E-Mail-Anbieter?</a></li>
|
||||
<li><a href="#can-i-use-delta-chat-in-parallel-with-other-e-mail-apps">Can I use Delta Chat in parallel with other E-Mail apps?</a></li>
|
||||
<li><a href="#ich-möchte-meinen-eigenen-server-für-delta-chat-verwalten-gibt-es-empfehlungen">Ich möchte meinen eigenen Server für Delta Chat verwalten. Gibt es Empfehlungen?</a></li>
|
||||
<li><a href="#weshalb-muss-ich-mein-e-mail-kennwort-in-delta-chat-eingeben-ist-das-sicher">Weshalb muss ich mein E-Mail-Kennwort in Delta Chat eingeben? Ist das sicher?</a></li>
|
||||
<li><a href="#welche-nachrichten-erscheinen-in-delta-chat">Welche Nachrichten erscheinen in Delta Chat?</a></li>
|
||||
@@ -389,10 +390,11 @@ die die Nachricht bereits beantwortet, weitergeleitet, gespeichert, mit einem Sc
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Sie schalten “Verschwindende Nachrichten”
|
||||
oben rechts im Chatfenster,
|
||||
durch Auswahl einer Zeitspanne
|
||||
zwischen 1 Minute und 5 Wochen ein.</p>
|
||||
<p>You can turn on “disappearing messages”
|
||||
in the settings of a chat,
|
||||
at the top right of the chat window,
|
||||
by selecting a time span
|
||||
between 5 minutes and 1 year.</p>
|
||||
|
||||
<p>Bis die Einstellung wieder ausgeschaltet wird,
|
||||
kümmern sich die Delta-Chat-Apps der Chat-Teilnehmer
|
||||
@@ -720,9 +722,8 @@ ermöglicht es den Empfängern, eine Ende-zu-Ende-Verschlüsselung mit dem Konta
|
||||
|
||||
</h3>
|
||||
|
||||
<p>All messages in Delta Chat are <strong>end-to-end encrypted by default</strong>.
|
||||
Since the Delta Chat Version 2 release series (July 2025)
|
||||
there are no lock or similar markers on end-to-end encrypted messages, anymore.</p>
|
||||
<p>Alle Nachrichten in Delta Chat sind <strong>standardmäßig Ende-zu-Ende-verschlüsselt</strong>.
|
||||
Seit der Veröffentlichung von Delta Chat Version 2 (Juli 2025) gibt es keine Schlösser oder ähnliche Markierungen mehr an Ende‑zu‑Ende-verschlüsselten Nachrichten.</p>
|
||||
|
||||
<h3 id="kann-ich-e-mails-ohne-ende-zu-ende-verschlüsselung-empfangen-oder-senden">
|
||||
|
||||
@@ -734,9 +735,9 @@ there are no lock or similar markers on end-to-end encrypted messages, anymore.<
|
||||
|
||||
<p>Wenn Sie die Standard-<a href="https://chatmail.at/relays">Chatmail-Relays</a> verwenden, ist es unmöglich, Nachrichten ohne End-to-End-Verschlüsselung zu empfangen oder zu senden.</p>
|
||||
|
||||
<p>Wenn Sie stattdessen ein Profil mit einem klassischen E-Mail-Server erstellen,
|
||||
können Sie Nachrichten ohne End-to-End-Verschlüsselung senden und empfangen.
|
||||
Solche Nachrichten werden mit einem E-Mail-Symbol gekennzeichnet
|
||||
<p>If you instead create a profile using a classic e-mail server,
|
||||
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
|
||||
<img style="vertical-align:middle; width:1.2em; margin:1px" src="../email-icon.png" alt="email" />.</p>
|
||||
|
||||
<h3 id="howtoe2ee">
|
||||
@@ -747,9 +748,9 @@ Solche Nachrichten werden mit einem E-Mail-Symbol gekennzeichnet
|
||||
|
||||
</h3>
|
||||
|
||||
<p>You can send an invite link through another private chat,
|
||||
show an invitation QR code when next to each other or in a video call,
|
||||
or click on a “contact” that was shared in a chat.</p>
|
||||
<p>Man kann einen Einladungslink über einen anderen privaten Chat senden,
|
||||
einen Einladungs-QR-Code zeigen, wenn man nebeneinander steht oder einen Videoanruf tätigen,
|
||||
oder auf einen “Kontakt” klicken der per Chat geteilt wurde.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
@@ -758,35 +759,35 @@ tippen Sie auf den Titel der Gruppe, um die Mitgliederliste anzuzeigen,
|
||||
und wählen Sie „QR-Einladungscode“.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>For <strong>direct 1:1 chat invitations</strong>,
|
||||
tap the QR Code icon <img style="vertical-align:middle; width:1.8em; margin:1px" src="../qr-icon.png" />
|
||||
on the Delta Chat app main screen.</p>
|
||||
<p>Für <strong>direkte 1:1-Chat-Einladungen</strong>,
|
||||
tippt man auf das QR-Code-Symbol <img style="vertical-align:middle; width:1.8em; margin:1px" src="../qr-icon.png" />
|
||||
auf dem Hauptbildschirm der Delta-Chat-App.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Ask your chat partner to scan the QR image
|
||||
with their Delta Chat app,
|
||||
or click “Copy” or “Share” to create an invite link
|
||||
and share it with your chat partner.</p>
|
||||
<p>Man kann seinen Chat-Partner bitten, denn QR-Code
|
||||
mit seiner Delta Chat-App zu scannen,
|
||||
oder auf “Kopieren” oder “Teilen” drücken, um einen Einladungslink zu erstellen
|
||||
und diesen mit seinem Chat-Partner zu teilen.</p>
|
||||
|
||||
<p>Now wait while <a href="https://securejoin.delta.chat/en/latest/new.html#setup-contact-protocol">end-to-end encryption is getting established</a>.</p>
|
||||
<p>Nun wartet man, während die <a href="https://securejoin.delta.chat/en/latest/new.html#setup-contact-protocol">Ende-zu-Ende-Verschlüsselung eingerichtet wird</a>.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>If both sides are online, they will soon see a (group or direct) chat
|
||||
and can start messaging securely.</p>
|
||||
<p>Wenn beide Seiten online sind, sehen sie bald einen (Gruppen- oder direkten) Chat
|
||||
und können mit der sicheren Nachrichtenübermittlung beginnen.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>If one side is offline or in bad network,
|
||||
the ability to chat is delayed until connectivity is restored.</p>
|
||||
<p>Wenn eine Seite offline ist oder eine schlechte Verbindung hat,
|
||||
wird die Möglichkeit zu chatten verzögert, bis die Verbindung wiederhergestellt ist.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Congratulations!
|
||||
You now will automatically use end-to-end encryption
|
||||
with this contact.
|
||||
If you add each other to chat groups,
|
||||
end-to-end encryption will be established among all members.</p>
|
||||
<p>Glückwunsch!
|
||||
Du verwenden jetzt automatisch eine Ende-zu-Ende-Verschlüsselung
|
||||
mit diesem Kontakt.
|
||||
Wenn man sich gegenseitig zu Chatgruppen hinzufügt,
|
||||
wird eine Ende-zu-Ende-Verschlüsselung zwischen allen Mitgliedern eingerichtet.</p>
|
||||
|
||||
<h3 id="e2eeguarantee">
|
||||
|
||||
@@ -835,9 +836,9 @@ und Anhang-Metadaten wie Dateinamen.</p>
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Yes, Delta Chat uses a secure subset of OpenPGP
|
||||
requiring the whole message to be properly encrypted and signed.
|
||||
For example, “Detached signatures” are not treated as secure.</p>
|
||||
<p>Ja, Delta Chat verwendet ein sicheres subset von OpenPGP
|
||||
das verlangt, dass die gesamte Nachricht ordnungsgemäß verschlüsselt und signiert wurde.
|
||||
Als Beispiel, werden “angehängte Signaturen” nicht als sicher behandelt.</p>
|
||||
|
||||
<p>Die meisten öffentlich diskutierten OpenPGP-Probleme
|
||||
resultieren in Wirklichkeit aus schlechter Usability oder schlechter Implementierung von Tools oder Anwendungen - oder beidem.
|
||||
@@ -903,10 +904,11 @@ so wie in der Autocrypt-Level-1-Spezifikation definiert.</p>
|
||||
|
||||
</h3>
|
||||
|
||||
<p>If you are sending or receiving e-mail messages without end-to-end encryption (using a classic e-mail server),
|
||||
they are still protected from cell or cable companies who can not read or modify your e-mail messages.
|
||||
But both your and your recipient’s e-mail providers
|
||||
may read, analyze or modify your messages, including any attachments.</p>
|
||||
<p>Wenn Sie E-Mail-Nachrichten ohne Ende-zu-Ende-Verschlüsselung senden oder empfangen (mit einem klassischen E-Mail-Server),
|
||||
sind sie immer noch vor Mobilfunkanbietern oder Kabelnetzbetreibern geschützt, die Ihre E-Mail-Nachrichten nicht lesen oder verändern können.</p>
|
||||
|
||||
<p>Aber sowohl Ihr E-Mail-Anbieter als auch der E-Mail-Anbieter des Empfängers
|
||||
können Ihre Nachrichten, einschließlich aller Anhänge, lesen, analysieren oder verändern.</p>
|
||||
|
||||
<p>Delta Chat verwendet standardmäßig strikte
|
||||
<a href="https://en.wikipedia.org/wiki/Transport_Layer_Security">TLS-Verschlüsselung</a>,
|
||||
@@ -945,7 +947,7 @@ Stattdessen werden alle Gruppen-Metadaten durchgängig verschlüsselt und aussch
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>All other message, contact and group metadata resides in the end-to-end encrypted part of messages.</p>
|
||||
<p>Alle anderen Metadaten zu Nachrichten, Kontakten und Gruppen befinden sich im Ende-zu-Ende-verschlüsselten Teil der Nachrichten.</p>
|
||||
|
||||
<h3 id="device-seizure">
|
||||
|
||||
@@ -973,12 +975,12 @@ can not be identified easily.</p>
|
||||
|
||||
</h3>
|
||||
|
||||
<p>No, not yet.</p>
|
||||
<p>Nein, noch nichts.</p>
|
||||
|
||||
<p>The Signal messenger introduced <a href="https://signal.org/blog/sealed-sender/">“Sealed Sender” in 2018</a>
|
||||
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.</p>
|
||||
<p>Der Signal-Messenger führte 2018 <a href="https://signal.org/blog/sealed-sender/">“Sealed Sender”</a> ein
|
||||
um seine Serverinfrastruktur darüber im Unklaren zu lassen, wer eine Nachricht an eine Gruppe von Empfängern sendet.
|
||||
Dies ist besonders wichtig, weil der Signal-Server die Handynummer jedes Kontos kennt,
|
||||
die in der Regel mit einer Passidentität verbunden ist.</p>
|
||||
|
||||
<p>Even if <a href="https://chatmail.at/relays">chatmail relays</a>
|
||||
do not ask for any private data (including no phone numbers),
|
||||
@@ -994,7 +996,7 @@ but an implementation has not been agreed as a priority yet.</p>
|
||||
|
||||
</h3>
|
||||
|
||||
<p>No, not yet.</p>
|
||||
<p>Nein, noch nichts.</p>
|
||||
|
||||
<p>Delta Chat today doesn’t support Perfect Forward Secrecy (PFS).
|
||||
This means that if your private decryption key is leaked,
|
||||
@@ -1020,12 +1022,11 @@ which would make it available in all <a href="https://chatmail.at/clients">chatm
|
||||
|
||||
</h3>
|
||||
|
||||
<p>No, not yet.</p>
|
||||
<p>Nein, noch nichts.</p>
|
||||
|
||||
<p>Delta Chat uses the Rust OpenPGP library <a href="https://github.com/rpgp/rpgp">rPGP</a>
|
||||
which supports the latest <a href="https://datatracker.ietf.org/doc/draft-ietf-openpgp-pqc/">IETF Post-Quantum-Cryptography OpenPGP draft</a>.
|
||||
We aim to add PQC support in <a href="https://github.com/chatmail/core">chatmail core</a> after the draft is finalized at the IETF
|
||||
in collaboration with other OpenPGP implementers.</p>
|
||||
<p>Delta Chat verwendet die Rust OpenPGP-Bibliothek <a href="https://github.com/rpgp/rpgp">rPGP</a>
|
||||
die den neuesten <a href="https://datatracker.ietf.org/doc/draft-ietf-openpgp-pqc/">IETF Post-Quantum-Cryptography OpenPGP Entwurf</a> unterstützt.
|
||||
Wir beabsichtigen, PQC-Unterstützung zum <a href="https://github.com/chatmail/core">chatmail core</a> hinzuzufügen, sobald der Entwurf bei der IETF in Zusammenarbeit mit anderen OpenPGP-Implementierern fertiggestellt ist.</p>
|
||||
|
||||
<h3 id="wie-kann-ich-die-verschlüsselung-manuell-überprüfen">
|
||||
|
||||
@@ -1376,10 +1377,10 @@ forum</a> veröffentlicht und diskutiert.</li>
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Note:
|
||||
Changing email addresses is temporarily disabled
|
||||
because of ongoing changes to the DeltaChat core.
|
||||
It should be available again in a few months.</p>
|
||||
<p>Anmerkung:
|
||||
Das Ändern von E-Mail-Adressen ist vorübergehend deaktiviert
|
||||
wegen laufender Änderungen am DeltaChat-Core.
|
||||
Es sollte in ein paar Monaten wieder verfügbar sein.</p>
|
||||
|
||||
<ol>
|
||||
<li>
|
||||
@@ -1479,6 +1480,29 @@ gesendet haben, Nachrichten an Ihre neue Adresse senden.</p>
|
||||
Allerdings benötigen einige Anbieter besondere Einstellungen, um ordnungsgemäß zu funktionieren; eine von NutzerInnen erstellte Sammlung zu einigen Optionen findet sich unter <a href="https://providers.delta.chat">Provider Overview</a>.</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="can-i-use-delta-chat-in-parallel-with-other-e-mail-apps">
|
||||
|
||||
|
||||
Can I use Delta Chat in parallel with other E-Mail apps? <a href="#can-i-use-delta-chat-in-parallel-with-other-e-mail-apps" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Yes, but it is not recommended.</p>
|
||||
|
||||
<p>Parallel usage with the same E-Mail address might lead to the following inconveniences:</p>
|
||||
|
||||
<ul>
|
||||
<li>Next to your Delta Chat notifications,
|
||||
you might also get notifications for (encrypted, so unreadable) chat mail messages
|
||||
in your other email app</li>
|
||||
<li>If Delta Chat is not running
|
||||
or “Advanced > Move automatically to the DeltaChat Folder” is disabled,
|
||||
encrypted Delta Chat messages might clutter the Inbox in your other E-Mail apps.</li>
|
||||
</ul>
|
||||
|
||||
<p><a href="https://support.delta.chat/t/sieve-rule-to-move-deltachat-mails-to-deltachat-folder/288/10">Sieve rules</a> can solve these problems.</p>
|
||||
|
||||
<h3 id="ich-möchte-meinen-eigenen-server-für-delta-chat-verwalten-gibt-es-empfehlungen">
|
||||
|
||||
|
||||
@@ -1488,10 +1512,10 @@ Allerdings benötigen einige Anbieter besondere Einstellungen, um ordnungsgemä
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>Most mail servers will work well. But what we personally recommend is a
|
||||
chatmail relay server, as described <a href="https://delta.chat/en/2023-12-13-chatmail">in this
|
||||
blogpost</a>.</li>
|
||||
<li>You can find an <a href="https://github.com/chatmail/relay">installation guide on GitHub</a>.</li>
|
||||
<li>Die meisten Mailserver werden gut funktionieren. Aber wir persönlich empfehlen ein
|
||||
Chatmail-Relay-Server, wie er <a href="https://delta.chat/en/2023-12-13-chatmail">in diesem
|
||||
Blogpost</a> beschrieben wird.</li>
|
||||
<li>Man kann eine <a href="https://github.com/chatmail/relay">Installationsanleitung auf GitHub</a> finden.</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="weshalb-muss-ich-mein-e-mail-kennwort-in-delta-chat-eingeben-ist-das-sicher">
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
<ul>
|
||||
<li><a href="#which-permissions-does-delta-chat-need">Which permissions does Delta Chat need?</a></li>
|
||||
<li><a href="#does-delta-chat-work-with-my-e-mail-provider">Does Delta Chat work with <em>my</em> e-mail-provider?</a></li>
|
||||
<li><a href="#can-i-use-delta-chat-in-parallel-with-other-e-mail-apps">Can I use Delta Chat in parallel with other E-Mail apps?</a></li>
|
||||
<li><a href="#i-want-to-manage-my-own-server-for-delta-chat-what-do-you-recommend">I want to manage my own server for Delta Chat. What do you recommend?</a></li>
|
||||
<li><a href="#why-do-i-have-to-enter-my-e-mail-password-into-delta-chat-is-this-secure">Why do I have to enter my E-Mail password into Delta Chat? Is this secure?</a></li>
|
||||
<li><a href="#which-messages-do-appear-in-delta-chat">Which messages do appear in Delta Chat?</a></li>
|
||||
@@ -411,7 +412,7 @@ who could have already replied, forwarded, saved, screenshotted or otherwise cop
|
||||
in the settings of a chat,
|
||||
at the top right of the chat window,
|
||||
by selecting a time span
|
||||
between 1 minute and 5 weeks.</p>
|
||||
between 5 minutes and 1 year.</p>
|
||||
|
||||
<p>Until the setting is turned off again,
|
||||
each chat member’s Delta Chat app takes care
|
||||
@@ -784,8 +785,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.</p>
|
||||
|
||||
<p>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
|
||||
<img style="vertical-align:middle; width:1.2em; margin:1px" src="../email-icon.png" alt="email" />.</p>
|
||||
|
||||
<h3 id="howtoe2ee">
|
||||
@@ -1626,6 +1627,29 @@ However, some providers need special options to work properly,
|
||||
see <a href="https://providers.delta.chat">Provider Overview</a></li>
|
||||
</ul>
|
||||
|
||||
<h3 id="can-i-use-delta-chat-in-parallel-with-other-e-mail-apps">
|
||||
|
||||
|
||||
Can I use Delta Chat in parallel with other E-Mail apps? <a href="#can-i-use-delta-chat-in-parallel-with-other-e-mail-apps" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Yes, but it is not recommended.</p>
|
||||
|
||||
<p>Parallel usage with the same E-Mail address might lead to the following inconveniences:</p>
|
||||
|
||||
<ul>
|
||||
<li>Next to your Delta Chat notifications,
|
||||
you might also get notifications for (encrypted, so unreadable) chat mail messages
|
||||
in your other email app</li>
|
||||
<li>If Delta Chat is not running
|
||||
or “Advanced > Move automatically to the DeltaChat Folder” is disabled,
|
||||
encrypted Delta Chat messages might clutter the Inbox in your other E-Mail apps.</li>
|
||||
</ul>
|
||||
|
||||
<p><a href="https://support.delta.chat/t/sieve-rule-to-move-deltachat-mails-to-deltachat-folder/288/10">Sieve rules</a> can solve these problems.</p>
|
||||
|
||||
<h3 id="i-want-to-manage-my-own-server-for-delta-chat-what-do-you-recommend">
|
||||
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<li><a href="#qué-significa-fijar-mutear-archivar">¿Qué significa fijar, mutear, archivar?</a></li>
|
||||
<li><a href="#save">¿Cómo funcionan los “Mensajes guardados”?</a></li>
|
||||
<li><a href="#qué-significa-el-punto-verde">¿Qué significa el punto verde?</a></li>
|
||||
<li><a href="#edit">Correct typos and delete messages after sending</a></li>
|
||||
<li><a href="#edit">Corregir errores y borrar mensajes después de enviar</a></li>
|
||||
<li><a href="#ephemeralmsgs">¿Cómo funciona la desaparición de mensajes?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
@@ -27,12 +27,12 @@
|
||||
<li><a href="#delold">¿Qué pasa si activo “Borrar mensajes del dispositivo”?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#instant-delivery">Instant message delivery and Push Notifications</a>
|
||||
<li><a href="#instant-delivery">Entrega de mensajes instantáneos y notificaciones Push</a>
|
||||
<ul>
|
||||
<li><a href="#what-are-push-notifications-how-can-i-get-instant-message-delivery">What are Push Notifications? How can I get instant message delivery?</a></li>
|
||||
<li><a href="#are-push-notifications-enabled-on-ios-devices-is-there-an-alternative">Are Push Notifications enabled on iOS devices? Is there an alternative?</a></li>
|
||||
<li><a href="#android-push">Are Push notifications enabled / needed on Android devices?</a></li>
|
||||
<li><a href="#privacy-notifications">How private are Delta Chat Push Notifications?</a></li>
|
||||
<li><a href="#qué-son-las-notificaciones-push-cómo-puedo-recibir-mensajes-instantáneos">¿Qué son las Notificaciones Push? ¿Cómo puedo recibir mensajes instantáneos?</a></li>
|
||||
<li><a href="#están-activadas-las-notificaciones-push-en-los-dispositivos-ios-existe-alguna-alternativa">¿Están activadas las notificaciones Push en los dispositivos iOS? ¿Existe alguna alternativa?</a></li>
|
||||
<li><a href="#android-push">¿Están habilitadas / son necesarias las notificaciones Push en los dispositivos Android?</a></li>
|
||||
<li><a href="#privacy-notifications">¿Qué privadas son las notificaciones push de Delta Chat?</a></li>
|
||||
<li><a href="#why-does-delta-chat-integrate-with-centralized-proprietary-applegoogle-push-services">Why does Delta Chat integrate with centralized proprietary Apple/Google push services?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
@@ -41,7 +41,7 @@
|
||||
<li><a href="#qué-estándares-se-utilizan-para-el-cifrado-de-extremo-a-extremo">¿Qué estándares se utilizan para el cifrado de extremo a extremo?</a></li>
|
||||
<li><a href="#whene2e">¿Cómo puedo saber si los mensajes están cifrados de extremo a extremo?</a></li>
|
||||
<li><a href="#can-i-still-receive-or-send-mails-without-end-to-end-encryption">Can i still receive or send mails without end-to-end encryption?</a></li>
|
||||
<li><a href="#howtoe2ee">How can I establish a chat with a new contact?</a></li>
|
||||
<li><a href="#howtoe2ee">¿Cómo puedo establecer un chat con un nuevo contacto?</a></li>
|
||||
<li><a href="#e2eeguarantee">What does the green checkmark in a contact profile mean?</a></li>
|
||||
<li><a href="#los-adjuntos-imágenes-archivos-audio-etc-están-cifrados-de-extremo-a-extremo">¿Los adjuntos (imágenes, archivos, audio, etc.) están cifrados de extremo a extremo?</a></li>
|
||||
<li><a href="#openpgp-secure">¿Es OpenPGP seguro?</a></li>
|
||||
@@ -87,6 +87,7 @@
|
||||
<ul>
|
||||
<li><a href="#qué-permisos-necesita-delta-chat">¿Qué permisos necesita Delta Chat?</a></li>
|
||||
<li><a href="#delta-chat-funciona-con-mi-proveedor-de-correo-electrónico">¿Delta Chat funciona con <em>mi</em> proveedor de correo electrónico?</a></li>
|
||||
<li><a href="#can-i-use-delta-chat-in-parallel-with-other-e-mail-apps">Can I use Delta Chat in parallel with other E-Mail apps?</a></li>
|
||||
<li><a href="#i-want-to-manage-my-own-server-for-delta-chat-what-do-you-recommend">I want to manage my own server for Delta Chat. What do you recommend?</a></li>
|
||||
<li><a href="#por-qué-debo-ingresar-mi-contraseña-de-correo-electrónico-en-delta-chat-es-esto-seguro">¿Por qué debo ingresar mi contraseña de correo electrónico en Delta Chat? ¿Es esto seguro?</a></li>
|
||||
<li><a href="#qué-mensajes-se-muestran-en-delta-chat">¿Qué mensajes se muestran en Delta Chat?</a></li>
|
||||
@@ -215,18 +216,16 @@ Basado en <a href="https://github.com/chatmail/core/blob/main/standards.md#stand
|
||||
|
||||
</h3>
|
||||
|
||||
<p>A profile is <strong>a name, a picture</strong> and some additional information for encrypting messages.
|
||||
A profile lives on your device(s) only
|
||||
and uses a chatmail or a classic e-mail server to transport messages.</p>
|
||||
<p>Un perfil es <strong>un nombre, una foto</strong> y algunas informaciones adicionales para encriptar los mensajes.
|
||||
Un perfil solo existe dentro de tu dispositivo(s)
|
||||
y utilice un servidor de chatmail o correo electrónico clásico para el transporte de los mensajes.</p>
|
||||
|
||||
<p>En la primera instalación de Delta Chat se crea un primer perfil.</p>
|
||||
|
||||
<p>Después, puedes tocar la imagen de tu perfil en la esquina superior izquierda para <strong>Añadir perfiles</strong>
|
||||
o para <strong>Cambiar perfiles</strong>.</p>
|
||||
|
||||
<p>You may want to use separate profiles for political, family or work related activities,
|
||||
or e. g. for a dedicated “spam-profile” with which you register at websites and platforms
|
||||
that tend to cause unsolicited messages (“spam”) sooner or later.</p>
|
||||
<p>Se podría considerar la utilización de perfiles diferenciados para actividades vinculadas con políticas, familia o trabajo, o para un perfil dedicado a “spam”, que podría ser utilizado para páginas web y plataformas que tendrán la capacidad de generar mensajes no solicitados.</p>
|
||||
|
||||
<p>Quizás quieres aprender <a href="#multiclient">cómo se usa el mismo perfil en múltiples dispositivos</a>.</p>
|
||||
|
||||
@@ -265,11 +264,11 @@ dispositivo.</p>
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Yes,
|
||||
you can do so under <strong>Settings → Profile → Bio</strong>.
|
||||
Your contacts who use Delta Chat will see it
|
||||
when they view your contact details.
|
||||
Moreover, it will appear as a classic e-mail signature.</p>
|
||||
<p>Sí,
|
||||
es posible hacerlo en “Ajustes → Perfil → Texto de firma”.
|
||||
Los contactos que usan Delta Chat podrán ver
|
||||
si revisan los detalles de tu perfil.<br />
|
||||
Además, se encontrará en la firma de correos electrónicos clásicos.</p>
|
||||
|
||||
<h3 id="qué-significa-fijar-mutear-archivar">
|
||||
|
||||
@@ -326,15 +325,15 @@ Con pulsar a <img style="vertical-align:middle; width:1.2em; margin:1px" src="..
|
||||
puedes volver al mensaje original en el chat original</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Finally, you can also use “Save Messages” to take <strong>personal notes</strong> - open the chat, type something, add a photo or a voice message etc.</p>
|
||||
<p>Finalmente, también se puede utilizar “Mensajes guardados” para tomar <strong>notas personales</strong> - abre el chat, escribe algo, añade una foto o un mensaje de voz, etc.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>As “Saved Message” are synced, they can become very handy for transferring data between devices</p>
|
||||
<p>Como los “mensajes guardados” se sincronizan, pueden ser muy útiles para transferir datos entre dispositivos.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Messages stay saved even if they are edited or deleted -
|
||||
may it be by <a href="#edit">sender</a>, by <a href="#delold">device cleanup</a> or by <a href="#ephemeralmsgs">disappearing messages of other chats</a>.</p>
|
||||
<p>Los mensajes se quedan guardados, también si se han cambiado o están borrados -
|
||||
Sea por el <a href="#edit">remitente</a>, por la <a href="#delold">limpieza del dispositivo</a> o por la <a href="#ephemeralmsgs">desaparición de mensajes de otros chats</a>.</p>
|
||||
|
||||
<h3 id="qué-significa-el-punto-verde">
|
||||
|
||||
@@ -349,16 +348,16 @@ junto al avatar de un contacto.
|
||||
Significa que ha sido <strong>visto recientemente</strong> en los últimos 10 minutos:</p>
|
||||
|
||||
<ul>
|
||||
<li>either because they messaged you directly,</li>
|
||||
<li>because they wrote something to a group you are both a member of,</li>
|
||||
<li>because they sent you a read receipt for a message you wrote,</li>
|
||||
<li>because they edit or delete a message in a chat shared with you,</li>
|
||||
<li>or because they use an <a href="#webxdc">app</a> in a chat shared with you.</li>
|
||||
<li>sea porque te enviaron un mensaje directamente,</li>
|
||||
<li>porque escribieron algo en un grupo en que ambos son miembros,</li>
|
||||
<li>porque te enviaron un acuse de recibo de un mensaje que escribiste,</li>
|
||||
<li>porque editaron o borraron un mensaje en un chat compartido contigo,</li>
|
||||
<li>o porque utilizan una <a href="#webxdc">app</a> en un chat compartido contigo.</li>
|
||||
</ul>
|
||||
|
||||
<p>So this is not a real time online status -
|
||||
and if someone doesn’t answer right away even though they seem to be online,
|
||||
don’t worry and give them some space :)</p>
|
||||
<p>Así que esto no es un estado de en línea en tiempo real -
|
||||
y si alguien no responde de inmediato, aunque parece que estar en línea,
|
||||
no te preocupes y dale un poco de espacio :)</p>
|
||||
|
||||
<p>On the other hand, others will not always “see that you are online”.
|
||||
If you have turned off read receipts,
|
||||
@@ -368,16 +367,16 @@ until one of the above conditions are met.</p>
|
||||
<h3 id="edit">
|
||||
|
||||
|
||||
Correct typos and delete messages after sending <a href="#edit" class="anchor"></a>
|
||||
Corregir errores y borrar mensajes después de enviar <a href="#edit" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>You can edit the text of your messages after sending.
|
||||
For that, long tap or right click the message and select <strong>Edit</strong>
|
||||
or <img style="vertical-align:middle; width:1.2em; margin:1px" src="../edit-icon.png" alt="Edit icon" />.</p>
|
||||
<p>Se puede editar el texto de los mensajes después de enviarlos.
|
||||
Para ello, mantenga pulsado o haz clic con el botón derecho en el mensaje y seleccione <strong>Editar</strong>
|
||||
o <img style="vertical-align:middle; width:1.2em; margin:1px" src="../edit-icon.png" alt="Edit icon" />.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Si has enviado un mensaje accidentalmente
|
||||
@@ -400,11 +399,11 @@ who could have already replied, forwarded, saved, screenshotted or otherwise cop
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Puedes activar “desaparición de mensajes”
|
||||
en la configuración de un chat,
|
||||
en la parte superior derecha de la ventana de chat,
|
||||
seleccionando un lapso de tiempo
|
||||
entre 1 minuto y 5 semanas.</p>
|
||||
<p>You can turn on “disappearing messages”
|
||||
in the settings of a chat,
|
||||
at the top right of the chat window,
|
||||
by selecting a time span
|
||||
between 5 minutes and 1 year.</p>
|
||||
|
||||
<p>Hasta que la configuración se desactive nuevamente,
|
||||
La aplicación Delta Chat de cada miembro del chat se encarga
|
||||
@@ -560,15 +559,15 @@ older than that.</li>
|
||||
<h2 id="instant-delivery">
|
||||
|
||||
|
||||
Instant message delivery and Push Notifications <a href="#instant-delivery" class="anchor"></a>
|
||||
Entrega de mensajes instantáneos y notificaciones Push <a href="#instant-delivery" class="anchor"></a>
|
||||
|
||||
|
||||
</h2>
|
||||
|
||||
<h3 id="what-are-push-notifications-how-can-i-get-instant-message-delivery">
|
||||
<h3 id="qué-son-las-notificaciones-push-cómo-puedo-recibir-mensajes-instantáneos">
|
||||
|
||||
|
||||
What are Push Notifications? How can I get instant message delivery? <a href="#what-are-push-notifications-how-can-i-get-instant-message-delivery" class="anchor"></a>
|
||||
¿Qué son las Notificaciones Push? ¿Cómo puedo recibir mensajes instantáneos? <a href="#qué-son-las-notificaciones-push-cómo-puedo-recibir-mensajes-instantáneos" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
@@ -577,11 +576,11 @@ older than that.</li>
|
||||
so that an inactive Delta Chat app can fetch messages in the background
|
||||
and show notifications on a user’s phone if needed.</p>
|
||||
|
||||
<p>Push Notifications work with all <a href="https://delta.chat/chatmail">chatmail</a> servers on</p>
|
||||
<p>Las notificaciones push funcionan con todos los servidores de <a href="https://delta.chat/chatmail">chatmail</a> en</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>iOS devices, by integrating with Apple Push services.</p>
|
||||
<p>dispositivos iOS, por la integración de los servicios Push de Apple.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Android devices, by integrating with the Google FCM Push service,
|
||||
@@ -590,13 +589,13 @@ instead of proprietary Google code on the phone.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>As of May 2024, classic e-mail servers do not support Push Notifications
|
||||
for Delta Chat users.</p>
|
||||
<p>A partir de mayo de 2024, los servidores de correo electrónico clásicos no admiten notificaciones push
|
||||
para los usuarios de Delta Chat.</p>
|
||||
|
||||
<h3 id="are-push-notifications-enabled-on-ios-devices-is-there-an-alternative">
|
||||
<h3 id="están-activadas-las-notificaciones-push-en-los-dispositivos-ios-existe-alguna-alternativa">
|
||||
|
||||
|
||||
Are Push Notifications enabled on iOS devices? Is there an alternative? <a href="#are-push-notifications-enabled-on-ios-devices-is-there-an-alternative" class="anchor"></a>
|
||||
¿Están activadas las notificaciones Push en los dispositivos iOS? ¿Existe alguna alternativa? <a href="#están-activadas-las-notificaciones-push-en-los-dispositivos-ios-existe-alguna-alternativa" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
@@ -611,7 +610,7 @@ does not expose data to Apple that it doesn’t already have.</p>
|
||||
<h3 id="android-push">
|
||||
|
||||
|
||||
Are Push notifications enabled / needed on Android devices? <a href="#android-push" class="anchor"></a>
|
||||
¿Están habilitadas / son necesarias las notificaciones Push en los dispositivos Android? <a href="#android-push" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
@@ -649,7 +648,7 @@ safe to try if you experience messages arrive only with long delays.</p>
|
||||
<h3 id="privacy-notifications">
|
||||
|
||||
|
||||
How private are Delta Chat Push Notifications? <a href="#privacy-notifications" class="anchor"></a>
|
||||
¿Qué privadas son las notificaciones push de Delta Chat? <a href="#privacy-notifications" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
@@ -658,7 +657,7 @@ safe to try if you experience messages arrive only with long delays.</p>
|
||||
It does not leak e-mail, IP address or message content (not even encrypted)
|
||||
to any system involved in the delivery of Push Notifications.</p>
|
||||
|
||||
<p>Here is how Delta Chat apps perform Push Notification delivery:</p>
|
||||
<p>Así es como las aplicaciones Delta Chat realizan la entrega de Notificaciones Push:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
@@ -776,14 +775,14 @@ 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.</p>
|
||||
|
||||
<p>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
|
||||
<img style="vertical-align:middle; width:1.2em; margin:1px" src="../email-icon.png" alt="email" />.</p>
|
||||
|
||||
<h3 id="howtoe2ee">
|
||||
|
||||
|
||||
How can I establish a chat with a new contact? <a href="#howtoe2ee" class="anchor"></a>
|
||||
¿Cómo puedo establecer un chat con un nuevo contacto? <a href="#howtoe2ee" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
@@ -1604,6 +1603,29 @@ Esto es lo que hace Delta Chat con esos permisos:</p>
|
||||
Sin embargo, algunos proveedores necesitan opciones especiales para funcionar correctamente, ver <a href="https://providers.delta.chat">Descripción de proveedores</a></li>
|
||||
</ul>
|
||||
|
||||
<h3 id="can-i-use-delta-chat-in-parallel-with-other-e-mail-apps">
|
||||
|
||||
|
||||
Can I use Delta Chat in parallel with other E-Mail apps? <a href="#can-i-use-delta-chat-in-parallel-with-other-e-mail-apps" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Yes, but it is not recommended.</p>
|
||||
|
||||
<p>Parallel usage with the same E-Mail address might lead to the following inconveniences:</p>
|
||||
|
||||
<ul>
|
||||
<li>Next to your Delta Chat notifications,
|
||||
you might also get notifications for (encrypted, so unreadable) chat mail messages
|
||||
in your other email app</li>
|
||||
<li>If Delta Chat is not running
|
||||
or “Advanced > Move automatically to the DeltaChat Folder” is disabled,
|
||||
encrypted Delta Chat messages might clutter the Inbox in your other E-Mail apps.</li>
|
||||
</ul>
|
||||
|
||||
<p><a href="https://support.delta.chat/t/sieve-rule-to-move-deltachat-mails-to-deltachat-folder/288/10">Sieve rules</a> can solve these problems.</p>
|
||||
|
||||
<h3 id="i-want-to-manage-my-own-server-for-delta-chat-what-do-you-recommend">
|
||||
|
||||
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
<ul>
|
||||
<li><a href="#de-quelles-autorisations-delta-chat-a-t-il-besoin">De quelles autorisations Delta Chat a-t-il besoin?</a></li>
|
||||
<li><a href="#est-ce-que-delta-chat-fonctionne-avec-mon-fournisseur-de-courriel-">Est-ce que Delta Chat fonctionne avec <em>mon</em> fournisseur de courriel ?</a></li>
|
||||
<li><a href="#can-i-use-delta-chat-in-parallel-with-other-e-mail-apps">Can I use Delta Chat in parallel with other E-Mail apps?</a></li>
|
||||
<li><a href="#i-want-to-manage-my-own-server-for-delta-chat-what-do-you-recommend">I want to manage my own server for Delta Chat. What do you recommend?</a></li>
|
||||
<li><a href="#pourquoi-dois-je-entrer-le-mot-de-passe-de-mon-compte-de-courriel-dans-delta-chat--est-ce-sécurisé-">Pourquoi dois-je entrer le mot de passe de mon compte de courriel dans Delta Chat ? Est-ce sécurisé ?</a></li>
|
||||
<li><a href="#quels-sont-les-messages-qui-apparaissent-dans-delta-chat-">Quels sont les messages qui apparaissent dans Delta Chat ?</a></li>
|
||||
@@ -397,7 +398,7 @@ who could have already replied, forwarded, saved, screenshotted or otherwise cop
|
||||
in the settings of a chat,
|
||||
at the top right of the chat window,
|
||||
by selecting a time span
|
||||
between 1 minute and 5 weeks.</p>
|
||||
between 5 minutes and 1 year.</p>
|
||||
|
||||
<p>Until the setting is turned off again,
|
||||
each chat member’s Delta Chat app takes care
|
||||
@@ -758,8 +759,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.</p>
|
||||
|
||||
<p>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
|
||||
<img style="vertical-align:middle; width:1.2em; margin:1px" src="../email-icon.png" alt="email" />.</p>
|
||||
|
||||
<h3 id="howtoe2ee">
|
||||
@@ -1566,6 +1567,29 @@ Voici ce que fait Delta Chat avec ces autorisations:</p>
|
||||
Cependant, il faut activer des options spéciales pour que cela fonctionne correctement avec certains fournisseurs… Voir <a href="https://providers.delta.chat">la liste des fournisseurs</a>.</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="can-i-use-delta-chat-in-parallel-with-other-e-mail-apps">
|
||||
|
||||
|
||||
Can I use Delta Chat in parallel with other E-Mail apps? <a href="#can-i-use-delta-chat-in-parallel-with-other-e-mail-apps" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Yes, but it is not recommended.</p>
|
||||
|
||||
<p>Parallel usage with the same E-Mail address might lead to the following inconveniences:</p>
|
||||
|
||||
<ul>
|
||||
<li>Next to your Delta Chat notifications,
|
||||
you might also get notifications for (encrypted, so unreadable) chat mail messages
|
||||
in your other email app</li>
|
||||
<li>If Delta Chat is not running
|
||||
or “Advanced > Move automatically to the DeltaChat Folder” is disabled,
|
||||
encrypted Delta Chat messages might clutter the Inbox in your other E-Mail apps.</li>
|
||||
</ul>
|
||||
|
||||
<p><a href="https://support.delta.chat/t/sieve-rule-to-move-deltachat-mails-to-deltachat-folder/288/10">Sieve rules</a> can solve these problems.</p>
|
||||
|
||||
<h3 id="i-want-to-manage-my-own-server-for-delta-chat-what-do-you-recommend">
|
||||
|
||||
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
<ul>
|
||||
<li><a href="#izin-apa-yang-dibutuhkan-delta-chat">Izin apa yang dibutuhkan Delta Chat?</a></li>
|
||||
<li><a href="#does-delta-chat-work-with-my-e-mail-provider">Does Delta Chat work with <em>my</em> e-mail-provider?</a></li>
|
||||
<li><a href="#can-i-use-delta-chat-in-parallel-with-other-e-mail-apps">Can I use Delta Chat in parallel with other E-Mail apps?</a></li>
|
||||
<li><a href="#i-want-to-manage-my-own-server-for-delta-chat-what-do-you-recommend">I want to manage my own server for Delta Chat. What do you recommend?</a></li>
|
||||
<li><a href="#mengapa-saya-harus-memasukkan-kata-sandi-e-mail-saya-ke-delta-chat-apakah-ini-aman">Mengapa saya harus memasukkan kata sandi E-Mail saya ke Delta Chat? Apakah ini aman?</a></li>
|
||||
<li><a href="#pesan-mana-yang-muncul-di-delta-chat">Pesan mana yang muncul di Delta Chat?</a></li>
|
||||
@@ -411,7 +412,7 @@ who could have already replied, forwarded, saved, screenshotted or otherwise cop
|
||||
in the settings of a chat,
|
||||
at the top right of the chat window,
|
||||
by selecting a time span
|
||||
between 1 minute and 5 weeks.</p>
|
||||
between 5 minutes and 1 year.</p>
|
||||
|
||||
<p>Until the setting is turned off again,
|
||||
each chat member’s Delta Chat app takes care
|
||||
@@ -784,8 +785,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.</p>
|
||||
|
||||
<p>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
|
||||
<img style="vertical-align:middle; width:1.2em; margin:1px" src="../email-icon.png" alt="email" />.</p>
|
||||
|
||||
<h3 id="howtoe2ee">
|
||||
@@ -1626,6 +1627,29 @@ However, some providers need special options to work properly,
|
||||
see <a href="https://providers.delta.chat">Provider Overview</a></li>
|
||||
</ul>
|
||||
|
||||
<h3 id="can-i-use-delta-chat-in-parallel-with-other-e-mail-apps">
|
||||
|
||||
|
||||
Can I use Delta Chat in parallel with other E-Mail apps? <a href="#can-i-use-delta-chat-in-parallel-with-other-e-mail-apps" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Yes, but it is not recommended.</p>
|
||||
|
||||
<p>Parallel usage with the same E-Mail address might lead to the following inconveniences:</p>
|
||||
|
||||
<ul>
|
||||
<li>Next to your Delta Chat notifications,
|
||||
you might also get notifications for (encrypted, so unreadable) chat mail messages
|
||||
in your other email app</li>
|
||||
<li>If Delta Chat is not running
|
||||
or “Advanced > Move automatically to the DeltaChat Folder” is disabled,
|
||||
encrypted Delta Chat messages might clutter the Inbox in your other E-Mail apps.</li>
|
||||
</ul>
|
||||
|
||||
<p><a href="https://support.delta.chat/t/sieve-rule-to-move-deltachat-mails-to-deltachat-folder/288/10">Sieve rules</a> can solve these problems.</p>
|
||||
|
||||
<h3 id="i-want-to-manage-my-own-server-for-delta-chat-what-do-you-recommend">
|
||||
|
||||
|
||||
|
||||
@@ -50,10 +50,10 @@
|
||||
<li><a href="#tls">I messaggi contrassegnati dall’icona della posta sono esposti su Internet?</a></li>
|
||||
<li><a href="#message-metadata">In che modo Delta Chat protegge i metadati nei messaggi?</a></li>
|
||||
<li><a href="#device-seizure">Come proteggere i metadati e contatti quando un dispositivo viene sequestrato?</a></li>
|
||||
<li><a href="#sealedsender">Does Delta Chat support “Sealed Sender”?</a></li>
|
||||
<li><a href="#sealedsender">Delta Chat supporta “Mittente Sigillato”?</a></li>
|
||||
<li><a href="#pfs">Delta Chat supporta Perfect Forward Secrecy?</a></li>
|
||||
<li><a href="#pqc">Does Delta Chat support Post-Quantum-Cryptography?</a></li>
|
||||
<li><a href="#how-can-i-manually-check-encryption-information">How can I manually check encryption information?</a></li>
|
||||
<li><a href="#pqc">Delta Chat supporta la Crittografia Post-Quantistica?</a></li>
|
||||
<li><a href="#come-posso-controllare-manualmente-le-informazioni-di-crittografia">Come posso controllare manualmente le informazioni di crittografia?</a></li>
|
||||
<li><a href="#importkey">Posso riutilizzare la mia chiave privata esistente?</a></li>
|
||||
<li><a href="#security-audits">Delta Chat è stata verificata in modo indipendente per le vulnerabilità di sicurezza?</a></li>
|
||||
</ul>
|
||||
@@ -87,6 +87,7 @@
|
||||
<ul>
|
||||
<li><a href="#di-quali-autorizzazioni-ha-bisogno-delta-chat">Di quali autorizzazioni ha bisogno Delta Chat?</a></li>
|
||||
<li><a href="#delta-chat-funziona-con-il-mio-fornitore-e-mail">Delta Chat funziona con il <em>mio</em> fornitore e-mail?</a></li>
|
||||
<li><a href="#can-i-use-delta-chat-in-parallel-with-other-e-mail-apps">Can I use Delta Chat in parallel with other E-Mail apps?</a></li>
|
||||
<li><a href="#vorrei-gestire-il-mio-server-per-delta-chat-cosa-mi-consigliate">Vorrei gestire il mio server per Delta Chat. Cosa mi consigliate?</a></li>
|
||||
<li><a href="#perché-devo-inserire-la-mia-password-e-mail-in-delta-chat-è-sicuro">Perché devo inserire la mia password E-Mail in Delta Chat? È sicuro?</a></li>
|
||||
<li><a href="#quali-messaggi-vengono-mostrati-in-delta-chat">Quali messaggi vengono mostrati in Delta Chat?</a></li>
|
||||
@@ -405,11 +406,11 @@ che avrebbero già potuto rispondere, inoltrare, salvare, scattare una schermata
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Puoi attivare i “messaggi che scompaiono”
|
||||
nelle impostazioni di una chat,
|
||||
in alto a destra nella finestra della chat,
|
||||
selezionando un intervallo di tempo
|
||||
tra 1 minuto e 5 settimane.</p>
|
||||
<p>You can turn on “disappearing messages”
|
||||
in the settings of a chat,
|
||||
at the top right of the chat window,
|
||||
by selecting a time span
|
||||
between 5 minutes and 1 year.</p>
|
||||
|
||||
<p>Fino a quando l’impostazione non viene nuovamente disattivata,
|
||||
l’app Delta Chat di ogni membro della chat si prende cura
|
||||
@@ -776,9 +777,9 @@ non ci sono più lucchetti o marcatori simili, sui messaggi crittografati end-to
|
||||
<p>Se si utilizzano i <a href="https://chatmail.at/relays">relays di chatmail</a>,
|
||||
è impossibile ricevere o inviare messaggi senza la crittografia end-to-end.</p>
|
||||
|
||||
<p>Se invece si crea un profilo utilizzando un server di posta elettronica classico,
|
||||
è possibile inviare e ricevere messaggi senza crittografia end-to-end.
|
||||
I messaggi privi di crittografia end-to-end sono contrassegnati da un’icona e-mail<br />
|
||||
<p>If you instead create a profile using a classic e-mail server,
|
||||
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
|
||||
<img style="vertical-align:middle; width:1.2em; margin:1px" src="../email-icon.png" alt="email" />.</p>
|
||||
|
||||
<h3 id="howtoe2ee">
|
||||
@@ -969,25 +970,25 @@ anche se il messaggio non sarà crittografato end-to-end.</p>
|
||||
|
||||
</h3>
|
||||
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
|
||||
<p>E-mail Servers can therefore only see</p>
|
||||
<p>I Server E-mail possono quindi vedere solo</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>the message date,</p>
|
||||
<p>la data del messaggio,</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>sender and receiver addresses</p>
|
||||
<p>indirizzi del mittente e del destinatario</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>and message size.</p>
|
||||
<p>e dimensione del messaggio.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>All other message, contact and group metadata resides in the end-to-end encrypted part of messages.</p>
|
||||
<p>Tutti gli altri metadati dei messaggi, dei contatti e dei gruppi risiedono nella parte crittografata end-to-end dei messaggi.</p>
|
||||
|
||||
<h3 id="device-seizure">
|
||||
|
||||
@@ -997,36 +998,36 @@ Instead, all group metadata is end-to-end encrypted and stored on end-user devic
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Both for protecting against metadata-collecting e-mail servers
|
||||
as well as against the threat of device seizure
|
||||
we recommend to use a <a href="https://chatmail.at/relays">chatmail relay</a>
|
||||
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.</p>
|
||||
<p>Sia per proteggersi dai server e-mail che raccolgono metadati
|
||||
sia per proteggersi dal rischio di sequestro del dispositivo,
|
||||
consigliamo di utilizzare un <a href="https://chatmail.at/relays">chatmail relay</a>
|
||||
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.</p>
|
||||
|
||||
<h3 id="sealedsender">
|
||||
|
||||
|
||||
Does Delta Chat support “Sealed Sender”? <a href="#sealedsender" class="anchor"></a>
|
||||
Delta Chat supporta “Mittente Sigillato”? <a href="#sealedsender" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>No, non ancora.</p>
|
||||
|
||||
<p>The Signal messenger introduced <a href="https://signal.org/blog/sealed-sender/">“Sealed Sender” in 2018</a>
|
||||
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.</p>
|
||||
<p>Il messenger Signal ha introdotto <a href="https://signal.org/blog/sealed-sender/">“Mittente Sigillato” nel 2018</a>
|
||||
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.</p>
|
||||
|
||||
<p>Even if <a href="https://chatmail.at/relays">chatmail relays</a>
|
||||
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.</p>
|
||||
<p>Anche se i <a href="https://chatmail.at/relays">relays di chat</a>
|
||||
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à.</p>
|
||||
|
||||
<h3 id="pfs">
|
||||
|
||||
@@ -1038,41 +1039,41 @@ but an implementation has not been agreed as a priority yet.</p>
|
||||
|
||||
<p>No, non ancora.</p>
|
||||
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
|
||||
<p>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 <a href="https://github.com/chatmail/core">chatmail core</a>,
|
||||
which would make it available in all <a href="https://chatmail.at/clients">chatmail clients</a>.</p>
|
||||
<p>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 <a href="https://github.com/chatmail/core">chatmail core</a>,
|
||||
che lo renderebbe disponibile in tutti i <a href="https://chatmail.at/clients">clients di chatmail</a>.</p>
|
||||
|
||||
<h3 id="pqc">
|
||||
|
||||
|
||||
Does Delta Chat support Post-Quantum-Cryptography? <a href="#pqc" class="anchor"></a>
|
||||
Delta Chat supporta la Crittografia Post-Quantistica? <a href="#pqc" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>No, non ancora.</p>
|
||||
|
||||
<p>Delta Chat uses the Rust OpenPGP library <a href="https://github.com/rpgp/rpgp">rPGP</a>
|
||||
which supports the latest <a href="https://datatracker.ietf.org/doc/draft-ietf-openpgp-pqc/">IETF Post-Quantum-Cryptography OpenPGP draft</a>.
|
||||
We aim to add PQC support in <a href="https://github.com/chatmail/core">chatmail core</a> after the draft is finalized at the IETF
|
||||
in collaboration with other OpenPGP implementers.</p>
|
||||
<p>Delta Chat utilizza la libreria Rust OpenPGP <a href="https://github.com/rpgp/rpgp">rPGP</a>
|
||||
che supporta l’ultima <a href="https://datatracker.ietf.org/doc/draft-ietf-openpgp-pqc/">bozza IETF Post-Quantum-Cryptography OpenPGP</a>.
|
||||
Il nostro obiettivo è aggiungere il supporto PQC nel <a href="https://github.com/chatmail/core">core di chatmail</a> dopo che la bozza sarà stata finalizzata dall’IETF
|
||||
in collaborazione con altri implementatori di OpenPGP.</p>
|
||||
|
||||
<h3 id="how-can-i-manually-check-encryption-information">
|
||||
<h3 id="come-posso-controllare-manualmente-le-informazioni-di-crittografia">
|
||||
|
||||
|
||||
How can I manually check encryption information? <a href="#how-can-i-manually-check-encryption-information" class="anchor"></a>
|
||||
Come posso controllare manualmente le informazioni di crittografia? <a href="#come-posso-controllare-manualmente-le-informazioni-di-crittografia" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
@@ -1096,8 +1097,8 @@ la connessione è sicura.</p>
|
||||
<p>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.</p>
|
||||
|
||||
<p>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
|
||||
<p>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.</p>
|
||||
|
||||
<h3 id="security-audits">
|
||||
@@ -1596,6 +1597,29 @@ Tuttavia, alcuni provider necessitano di opzioni speciali per funzionare corrett
|
||||
vedi <a href="https://providers.delta.chat">Panoramica fornitore</a></li>
|
||||
</ul>
|
||||
|
||||
<h3 id="can-i-use-delta-chat-in-parallel-with-other-e-mail-apps">
|
||||
|
||||
|
||||
Can I use Delta Chat in parallel with other E-Mail apps? <a href="#can-i-use-delta-chat-in-parallel-with-other-e-mail-apps" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Yes, but it is not recommended.</p>
|
||||
|
||||
<p>Parallel usage with the same E-Mail address might lead to the following inconveniences:</p>
|
||||
|
||||
<ul>
|
||||
<li>Next to your Delta Chat notifications,
|
||||
you might also get notifications for (encrypted, so unreadable) chat mail messages
|
||||
in your other email app</li>
|
||||
<li>If Delta Chat is not running
|
||||
or “Advanced > Move automatically to the DeltaChat Folder” is disabled,
|
||||
encrypted Delta Chat messages might clutter the Inbox in your other E-Mail apps.</li>
|
||||
</ul>
|
||||
|
||||
<p><a href="https://support.delta.chat/t/sieve-rule-to-move-deltachat-mails-to-deltachat-folder/288/10">Sieve rules</a> can solve these problems.</p>
|
||||
|
||||
<h3 id="vorrei-gestire-il-mio-server-per-delta-chat-cosa-mi-consigliate">
|
||||
|
||||
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
<ul>
|
||||
<li><a href="#welke-android-rechten-heeft-delta-chat-nodig">Welke Android-rechten heeft Delta Chat nodig?</a></li>
|
||||
<li><a href="#wordt-mijn-e-mailprovider-ondersteund-door-delta-chat">Wordt <em>mijn</em> e-mailprovider ondersteund door Delta Chat?</a></li>
|
||||
<li><a href="#can-i-use-delta-chat-in-parallel-with-other-e-mail-apps">Can I use Delta Chat in parallel with other E-Mail apps?</a></li>
|
||||
<li><a href="#i-want-to-manage-my-own-server-for-delta-chat-what-do-you-recommend">I want to manage my own server for Delta Chat. What do you recommend?</a></li>
|
||||
<li><a href="#waarom-moet-ik-mijn-e-mailwachtwoord-invoeren-in-delta-chat-is-dat-wel-veilig">Waarom moet ik mijn e-mailwachtwoord invoeren in Delta Chat? Is dat wel veilig?</a></li>
|
||||
<li><a href="#welke-berichten-vind-ik-terug-in-delta-chat">Welke berichten vind ik terug in Delta Chat?</a></li>
|
||||
@@ -407,7 +408,7 @@ who could have already replied, forwarded, saved, screenshotted or otherwise cop
|
||||
in the settings of a chat,
|
||||
at the top right of the chat window,
|
||||
by selecting a time span
|
||||
between 1 minute and 5 weeks.</p>
|
||||
between 5 minutes and 1 year.</p>
|
||||
|
||||
<p>Until the setting is turned off again,
|
||||
each chat member’s Delta Chat app takes care
|
||||
@@ -777,8 +778,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.</p>
|
||||
|
||||
<p>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
|
||||
<img style="vertical-align:middle; width:1.2em; margin:1px" src="../email-icon.png" alt="email" />.</p>
|
||||
|
||||
<h3 id="howtoe2ee">
|
||||
@@ -1617,6 +1618,29 @@ Delta Chat doet het volgende met deze rechten:</p>
|
||||
Sommige providers verwachten echter bepaalde opties. Bekijk hiervoor het <a href="https://providers.delta.chat">provideroverzicht</a></li>
|
||||
</ul>
|
||||
|
||||
<h3 id="can-i-use-delta-chat-in-parallel-with-other-e-mail-apps">
|
||||
|
||||
|
||||
Can I use Delta Chat in parallel with other E-Mail apps? <a href="#can-i-use-delta-chat-in-parallel-with-other-e-mail-apps" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Yes, but it is not recommended.</p>
|
||||
|
||||
<p>Parallel usage with the same E-Mail address might lead to the following inconveniences:</p>
|
||||
|
||||
<ul>
|
||||
<li>Next to your Delta Chat notifications,
|
||||
you might also get notifications for (encrypted, so unreadable) chat mail messages
|
||||
in your other email app</li>
|
||||
<li>If Delta Chat is not running
|
||||
or “Advanced > Move automatically to the DeltaChat Folder” is disabled,
|
||||
encrypted Delta Chat messages might clutter the Inbox in your other E-Mail apps.</li>
|
||||
</ul>
|
||||
|
||||
<p><a href="https://support.delta.chat/t/sieve-rule-to-move-deltachat-mails-to-deltachat-folder/288/10">Sieve rules</a> can solve these problems.</p>
|
||||
|
||||
<h3 id="i-want-to-manage-my-own-server-for-delta-chat-what-do-you-recommend">
|
||||
|
||||
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
<ul>
|
||||
<li><a href="#jakich-uprawnień-potrzebuje-delta-chat">Jakich uprawnień potrzebuje Delta Chat?</a></li>
|
||||
<li><a href="#czy-delta-chat-działa-z-moim-dostawcą-poczty-e-mail">Czy Delta Chat działa z <em>moim</em> dostawcą poczty e-mail?</a></li>
|
||||
<li><a href="#can-i-use-delta-chat-in-parallel-with-other-e-mail-apps">Can I use Delta Chat in parallel with other E-Mail apps?</a></li>
|
||||
<li><a href="#chcę-zarządzać-własnym-serwerem-dla-delta-chat-co-polecacie">Chcę zarządzać własnym serwerem dla Delta Chat. Co polecacie?</a></li>
|
||||
<li><a href="#dlaczego-muszę-wpisać-moje-hasło-e-mail-do-delta-chat-czy-to-jest-bezpieczne">Dlaczego muszę wpisać moje hasło e-mail do Delta Chat? Czy to jest bezpieczne?</a></li>
|
||||
<li><a href="#jakie-wiadomości-pojawiają-się-w-delta-chat">Jakie wiadomości pojawiają się w Delta Chat?</a></li>
|
||||
@@ -356,7 +357,11 @@
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Możesz włączyć „znikające wiadomości” w ustawieniach czatu, w prawym górnym rogu okna czatu, wybierając przedział czasu od 1 minuty do 5 tygodni.</p>
|
||||
<p>You can turn on “disappearing messages”
|
||||
in the settings of a chat,
|
||||
at the top right of the chat window,
|
||||
by selecting a time span
|
||||
between 5 minutes and 1 year.</p>
|
||||
|
||||
<p>Dopóki ustawienie nie zostanie ponownie wyłączone, aplikacja Delta Chat u każdego członka czatu zajmie się usuwaniem wiadomości po wybranym okresie. Przedział czasu rozpoczyna się w momencie, gdy odbiorca po raz pierwszy zobaczy wiadomość w Delta Chat. Wiadomości są usuwane zarówno na każdym koncie e-mail na serwerze, jak i w samej aplikacji.</p>
|
||||
|
||||
@@ -638,7 +643,10 @@ nadal będziesz mógł pisać, ale nie będziesz już powiadamiany o żadnych no
|
||||
|
||||
<p>Jeśli korzystasz z domyślnych <a href="https://chatmail.at/relays">przekaźników chatmail</a>, odbieranie ani wysyłanie wiadomości bez szyfrowania end-to-end jest niemożliwe.</p>
|
||||
|
||||
<p>Jeśli zamiast tego utworzysz profil przy użyciu klasycznego serwera poczty e-mail, możesz wysyłać i odbierać wiadomości bez szyfrowania end-to-end. Takie wiadomości bez szyfrowania end-to-end są oznaczone ikoną e-mail <img style="vertical-align:middle; width:1.2em; margin:1px" src="../email-icon.png" alt="email" />.</p>
|
||||
<p>If you instead create a profile using a classic e-mail server,
|
||||
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
|
||||
<img style="vertical-align:middle; width:1.2em; margin:1px" src="../email-icon.png" alt="email" />.</p>
|
||||
|
||||
<h3 id="howtoe2ee">
|
||||
|
||||
@@ -1231,6 +1239,29 @@ Oto, co robi Delta Chat z tymi uprawnieniami:</p>
|
||||
Jednak niektórzy dostawcy potrzebują specjalnych opcji, aby działać poprawnie, zobacz <a href="https://providers.delta.chat">Przegląd dostawców</a></li>
|
||||
</ul>
|
||||
|
||||
<h3 id="can-i-use-delta-chat-in-parallel-with-other-e-mail-apps">
|
||||
|
||||
|
||||
Can I use Delta Chat in parallel with other E-Mail apps? <a href="#can-i-use-delta-chat-in-parallel-with-other-e-mail-apps" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Yes, but it is not recommended.</p>
|
||||
|
||||
<p>Parallel usage with the same E-Mail address might lead to the following inconveniences:</p>
|
||||
|
||||
<ul>
|
||||
<li>Next to your Delta Chat notifications,
|
||||
you might also get notifications for (encrypted, so unreadable) chat mail messages
|
||||
in your other email app</li>
|
||||
<li>If Delta Chat is not running
|
||||
or “Advanced > Move automatically to the DeltaChat Folder” is disabled,
|
||||
encrypted Delta Chat messages might clutter the Inbox in your other E-Mail apps.</li>
|
||||
</ul>
|
||||
|
||||
<p><a href="https://support.delta.chat/t/sieve-rule-to-move-deltachat-mails-to-deltachat-folder/288/10">Sieve rules</a> can solve these problems.</p>
|
||||
|
||||
<h3 id="chcę-zarządzać-własnym-serwerem-dla-delta-chat-co-polecacie">
|
||||
|
||||
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
<ul>
|
||||
<li><a href="#quais-permissões-o-delta-chat-precisa">Quais permissões o Delta Chat precisa?</a></li>
|
||||
<li><a href="#o-delta-chat-funciona-com-meu-provedor-de-e-mail">O Delta Chat funciona com <em>meu</em> provedor de e-mail?</a></li>
|
||||
<li><a href="#can-i-use-delta-chat-in-parallel-with-other-e-mail-apps">Can I use Delta Chat in parallel with other E-Mail apps?</a></li>
|
||||
<li><a href="#i-want-to-manage-my-own-server-for-delta-chat-what-do-you-recommend">I want to manage my own server for Delta Chat. What do you recommend?</a></li>
|
||||
<li><a href="#por-que-preciso-entrar-com-a-senha-do-meu-email-no-delta-chat-isso-é-seguro">Por que preciso entrar com a senha do meu email no Delta Chat? Isso é seguro?</a></li>
|
||||
<li><a href="#quais-mensagens-aparecem-no-delta-chat">Quais mensagens aparecem no Delta Chat?</a></li>
|
||||
@@ -407,7 +408,7 @@ who could have already replied, forwarded, saved, screenshotted or otherwise cop
|
||||
in the settings of a chat,
|
||||
at the top right of the chat window,
|
||||
by selecting a time span
|
||||
between 1 minute and 5 weeks.</p>
|
||||
between 5 minutes and 1 year.</p>
|
||||
|
||||
<p>Until the setting is turned off again,
|
||||
each chat member’s Delta Chat app takes care
|
||||
@@ -778,8 +779,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.</p>
|
||||
|
||||
<p>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
|
||||
<img style="vertical-align:middle; width:1.2em; margin:1px" src="../email-icon.png" alt="email" />.</p>
|
||||
|
||||
<h3 id="howtoe2ee">
|
||||
@@ -1618,6 +1619,29 @@ No entanto, alguns provedores precisam de opções especiais para funcionar corr
|
||||
ver <a href="https://providers.delta.chat">Visão Geral dos Provedores</a></li>
|
||||
</ul>
|
||||
|
||||
<h3 id="can-i-use-delta-chat-in-parallel-with-other-e-mail-apps">
|
||||
|
||||
|
||||
Can I use Delta Chat in parallel with other E-Mail apps? <a href="#can-i-use-delta-chat-in-parallel-with-other-e-mail-apps" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Yes, but it is not recommended.</p>
|
||||
|
||||
<p>Parallel usage with the same E-Mail address might lead to the following inconveniences:</p>
|
||||
|
||||
<ul>
|
||||
<li>Next to your Delta Chat notifications,
|
||||
you might also get notifications for (encrypted, so unreadable) chat mail messages
|
||||
in your other email app</li>
|
||||
<li>If Delta Chat is not running
|
||||
or “Advanced > Move automatically to the DeltaChat Folder” is disabled,
|
||||
encrypted Delta Chat messages might clutter the Inbox in your other E-Mail apps.</li>
|
||||
</ul>
|
||||
|
||||
<p><a href="https://support.delta.chat/t/sieve-rule-to-move-deltachat-mails-to-deltachat-folder/288/10">Sieve rules</a> can solve these problems.</p>
|
||||
|
||||
<h3 id="i-want-to-manage-my-own-server-for-delta-chat-what-do-you-recommend">
|
||||
|
||||
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
<ul>
|
||||
<li><a href="#какие-разрешения-нужны-delta-chat">Какие разрешения нужны Delta Chat?</a></li>
|
||||
<li><a href="#работает-ли-delta-chat-с-моим-провайдером-электронной-почты">Работает ли Delta Chat с <em>моим</em> провайдером электронной почты?</a></li>
|
||||
<li><a href="#can-i-use-delta-chat-in-parallel-with-other-e-mail-apps">Can I use Delta Chat in parallel with other E-Mail apps?</a></li>
|
||||
<li><a href="#я-хочу-управлять-своим-собственным-сервером-для-delta-chat-что-вы-посоветуете">Я хочу управлять своим собственным сервером для Delta Chat. Что вы посоветуете?</a></li>
|
||||
<li><a href="#почему-я-должен-вводить-свой-пароль-от-электронной-почты-в-delta-chat-это-безопасно">Почему я должен вводить свой пароль от электронной почты в Delta Chat? Это безопасно?</a></li>
|
||||
<li><a href="#какие-сообщения-отображаются-в-delta-chat">Какие сообщения отображаются в Delta Chat?</a></li>
|
||||
@@ -403,11 +404,11 @@
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Вы можете включить “исчезающие сообщения”
|
||||
в настройках чата,
|
||||
в правом верхнем углу окна чата,
|
||||
выбрав временной интервал
|
||||
от 1 минуты до 5 недель.</p>
|
||||
<p>You can turn on “disappearing messages”
|
||||
in the settings of a chat,
|
||||
at the top right of the chat window,
|
||||
by selecting a time span
|
||||
between 5 minutes and 1 year.</p>
|
||||
|
||||
<p>Пока настройка не будет снова отключена,
|
||||
приложение Delta Chat каждого участника чата позаботится
|
||||
@@ -776,9 +777,9 @@ Push-уведомления недоступны.</p>
|
||||
<p>Если вы используете стандартные <a href="https://chatmail.at/relays">ретрансляторы chatmail</a>,
|
||||
невозможно получать или отправлять сообщения без сквозного шифрования.</p>
|
||||
|
||||
<p>Если же вы создаёте профиль с использованием обычного почтового сервера,
|
||||
то можете отправлять и получать сообщения без сквозного шифрования.
|
||||
Такие сообщения, не имеющие сквозного шифрования, отмечаются значком электронной почты
|
||||
<p>If you instead create a profile using a classic e-mail server,
|
||||
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
|
||||
<img style="vertical-align:middle; width:1.2em; margin:1px" src="../email-icon.png" alt="email" />.</p>
|
||||
|
||||
<h3 id="howtoe2ee">
|
||||
@@ -1616,6 +1617,29 @@ Delta Chat</a>.</li>
|
||||
см. <a href="https://providers.delta.chat">Обзор провайдеров</a></li>
|
||||
</ul>
|
||||
|
||||
<h3 id="can-i-use-delta-chat-in-parallel-with-other-e-mail-apps">
|
||||
|
||||
|
||||
Can I use Delta Chat in parallel with other E-Mail apps? <a href="#can-i-use-delta-chat-in-parallel-with-other-e-mail-apps" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Yes, but it is not recommended.</p>
|
||||
|
||||
<p>Parallel usage with the same E-Mail address might lead to the following inconveniences:</p>
|
||||
|
||||
<ul>
|
||||
<li>Next to your Delta Chat notifications,
|
||||
you might also get notifications for (encrypted, so unreadable) chat mail messages
|
||||
in your other email app</li>
|
||||
<li>If Delta Chat is not running
|
||||
or “Advanced > Move automatically to the DeltaChat Folder” is disabled,
|
||||
encrypted Delta Chat messages might clutter the Inbox in your other E-Mail apps.</li>
|
||||
</ul>
|
||||
|
||||
<p><a href="https://support.delta.chat/t/sieve-rule-to-move-deltachat-mails-to-deltachat-folder/288/10">Sieve rules</a> can solve these problems.</p>
|
||||
|
||||
<h3 id="я-хочу-управлять-своим-собственным-сервером-для-delta-chat-что-вы-посоветуете">
|
||||
|
||||
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
<ul>
|
||||
<li><a href="#aké-povolenia-potrebuje-delta-chat">Aké povolenia potrebuje Delta Chat?</a></li>
|
||||
<li><a href="#funguje-delta-chat-s-mojím-poskytovateľom-e-mailov">Funguje Delta Chat s mojím poskytovateľom e-mailov?</a></li>
|
||||
<li><a href="#can-i-use-delta-chat-in-parallel-with-other-e-mail-apps">Can I use Delta Chat in parallel with other E-Mail apps?</a></li>
|
||||
<li><a href="#i-want-to-manage-my-own-server-for-delta-chat-what-do-you-recommend">I want to manage my own server for Delta Chat. What do you recommend?</a></li>
|
||||
<li><a href="#prečo-musím-zadávať-svoje-e-mailové-heslo-do-delta-chat-je-to-bezpečné">Prečo musím zadávať svoje e-mailové heslo do Delta Chat? Je to bezpečné?</a></li>
|
||||
<li><a href="#ktoré-správy-sa-zobrazujú-v-delta-chate">Ktoré správy sa zobrazujú v Delta Chate?</a></li>
|
||||
@@ -408,7 +409,7 @@ who could have already replied, forwarded, saved, screenshotted or otherwise cop
|
||||
in the settings of a chat,
|
||||
at the top right of the chat window,
|
||||
by selecting a time span
|
||||
between 1 minute and 5 weeks.</p>
|
||||
between 5 minutes and 1 year.</p>
|
||||
|
||||
<p>Until the setting is turned off again,
|
||||
each chat member’s Delta Chat app takes care
|
||||
@@ -781,8 +782,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.</p>
|
||||
|
||||
<p>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
|
||||
<img style="vertical-align:middle; width:1.2em; margin:1px" src="../email-icon.png" alt="email" />.</p>
|
||||
|
||||
<h3 id="howtoe2ee">
|
||||
@@ -1623,6 +1624,29 @@ Niektorí poskytovatelia však potrebujú na správne fungovanie špeciálne mo
|
||||
pozrite si <a href="https://providers.delta.chat">Prehľad poskytovateľa</a></li>
|
||||
</ul>
|
||||
|
||||
<h3 id="can-i-use-delta-chat-in-parallel-with-other-e-mail-apps">
|
||||
|
||||
|
||||
Can I use Delta Chat in parallel with other E-Mail apps? <a href="#can-i-use-delta-chat-in-parallel-with-other-e-mail-apps" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Yes, but it is not recommended.</p>
|
||||
|
||||
<p>Parallel usage with the same E-Mail address might lead to the following inconveniences:</p>
|
||||
|
||||
<ul>
|
||||
<li>Next to your Delta Chat notifications,
|
||||
you might also get notifications for (encrypted, so unreadable) chat mail messages
|
||||
in your other email app</li>
|
||||
<li>If Delta Chat is not running
|
||||
or “Advanced > Move automatically to the DeltaChat Folder” is disabled,
|
||||
encrypted Delta Chat messages might clutter the Inbox in your other E-Mail apps.</li>
|
||||
</ul>
|
||||
|
||||
<p><a href="https://support.delta.chat/t/sieve-rule-to-move-deltachat-mails-to-deltachat-folder/288/10">Sieve rules</a> can solve these problems.</p>
|
||||
|
||||
<h3 id="i-want-to-manage-my-own-server-for-delta-chat-what-do-you-recommend">
|
||||
|
||||
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
<ul>
|
||||
<li><a href="#çleje-lyp-delta-chat-i">Ç’leje lyp Delta Chat-i?</a></li>
|
||||
<li><a href="#a-funksionon-delta-chat-me-shërbimin-tim-email">A funksionon Delta Chat me shërbimin <em>tim</em> email?</a></li>
|
||||
<li><a href="#can-i-use-delta-chat-in-parallel-with-other-e-mail-apps">Can I use Delta Chat in parallel with other E-Mail apps?</a></li>
|
||||
<li><a href="#i-want-to-manage-my-own-server-for-delta-chat-what-do-you-recommend">I want to manage my own server for Delta Chat. What do you recommend?</a></li>
|
||||
<li><a href="#pse-më-duhet-të-jap-fjalëkalimin-e-email-it-tim-në-delta-chat-a-është-e-sigurt-kjo">Pse më duhet të jap fjalëkalimin e email-it tim në Delta Chat? A është e sigurt kjo?</a></li>
|
||||
<li><a href="#cilat-mesazhe-shfaqen-në-delta-chat">Cilat mesazhe shfaqen në Delta Chat?</a></li>
|
||||
@@ -408,7 +409,7 @@ who could have already replied, forwarded, saved, screenshotted or otherwise cop
|
||||
in the settings of a chat,
|
||||
at the top right of the chat window,
|
||||
by selecting a time span
|
||||
between 1 minute and 5 weeks.</p>
|
||||
between 5 minutes and 1 year.</p>
|
||||
|
||||
<p>Until the setting is turned off again,
|
||||
each chat member’s Delta Chat app takes care
|
||||
@@ -782,8 +783,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.</p>
|
||||
|
||||
<p>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
|
||||
<img style="vertical-align:middle; width:1.2em; margin:1px" src="../email-icon.png" alt="email" />.</p>
|
||||
|
||||
<h3 id="howtoe2ee">
|
||||
@@ -1623,6 +1624,29 @@ Sidoqoftë, disa furnizues shërbimesh kanë nevojë për mundësi speciale, që
|
||||
të funksionojnë si duhet, shihni <a href="https://providers.delta.chat">Provider Overview</a></li>
|
||||
</ul>
|
||||
|
||||
<h3 id="can-i-use-delta-chat-in-parallel-with-other-e-mail-apps">
|
||||
|
||||
|
||||
Can I use Delta Chat in parallel with other E-Mail apps? <a href="#can-i-use-delta-chat-in-parallel-with-other-e-mail-apps" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Yes, but it is not recommended.</p>
|
||||
|
||||
<p>Parallel usage with the same E-Mail address might lead to the following inconveniences:</p>
|
||||
|
||||
<ul>
|
||||
<li>Next to your Delta Chat notifications,
|
||||
you might also get notifications for (encrypted, so unreadable) chat mail messages
|
||||
in your other email app</li>
|
||||
<li>If Delta Chat is not running
|
||||
or “Advanced > Move automatically to the DeltaChat Folder” is disabled,
|
||||
encrypted Delta Chat messages might clutter the Inbox in your other E-Mail apps.</li>
|
||||
</ul>
|
||||
|
||||
<p><a href="https://support.delta.chat/t/sieve-rule-to-move-deltachat-mails-to-deltachat-folder/288/10">Sieve rules</a> can solve these problems.</p>
|
||||
|
||||
<h3 id="i-want-to-manage-my-own-server-for-delta-chat-what-do-you-recommend">
|
||||
|
||||
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
<ul>
|
||||
<li><a href="#яких-дозволів-потребує-delta-chat">Яких дозволів потребує Delta Chat?</a></li>
|
||||
<li><a href="#чи-підтримує-delta-chat-роботу-з-моїм-провайдером-електронної-пошти">Чи підтримує Delta Chat роботу з <em>моїм</em> провайдером електронної пошти?</a></li>
|
||||
<li><a href="#can-i-use-delta-chat-in-parallel-with-other-e-mail-apps">Can I use Delta Chat in parallel with other E-Mail apps?</a></li>
|
||||
<li><a href="#я-хочу-керувати-власним-сервером-для-delta-chat-що-ви-порекомендуєте">Я хочу керувати власним сервером для Delta Chat. Що ви порекомендуєте?</a></li>
|
||||
<li><a href="#чому-я-маю-вводити-пароль-до-моєї-електронної-пошти-у-delta-chat-чи-це-безпечно">Чому я маю вводити пароль до моєї електронної пошти у Delta Chat? Чи це безпечно?</a></li>
|
||||
<li><a href="#які-повідомлення-відображаються-у-delta-chat">Які повідомлення відображаються у Delta Chat?</a></li>
|
||||
@@ -358,7 +359,11 @@
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Увімкнути “повідомлення, що зникають” можна в налаштуваннях чату, у верхньому правому куті вікна чату, вибравши проміжок часу від 1 хвилини до 5 тижнів.</p>
|
||||
<p>You can turn on “disappearing messages”
|
||||
in the settings of a chat,
|
||||
at the top right of the chat window,
|
||||
by selecting a time span
|
||||
between 5 minutes and 1 year.</p>
|
||||
|
||||
<p>Доки налаштування не буде знову вимкнено, додаток Delta Chat кожного учасника чату піклується про видалення повідомлень через вибраний проміжок часу. Проміжок часу починається коли одержувач вперше побачив повідомлення в Delta Chat. Повідомлення видаляються як з кожної поштової скриньки на сервері, так і в самому додатку.</p>
|
||||
|
||||
@@ -606,7 +611,7 @@ Push-сповіщення автоматично активуються для
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Delta Chat використовує [безпечну підмножину стандарту OpenPGP] (#openpgp-secure) для забезпечення автоматичного наскрізного шифрування за допомогою цих протоколів:</p>
|
||||
<p>Delta Chat використовує <a href="#openpgp-secure">безпечну підмножину стандарту OpenPGP</a> для забезпечення автоматичного наскрізного шифрування за допомогою цих протоколів:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
@@ -616,7 +621,7 @@ Push-сповіщення автоматично активуються для
|
||||
<p><a href="https://autocrypt.org">Autocrypt</a> використовується для автоматичного встановлення наскрізного шифрування між контактами і всіма учасниками групового чату.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>[Поширення контакту в чаті] (https://github.com/chatmail/core/blob/main/spec.md#attaching-a-contact-to-a-message) дозволяє отримувачам використовувати наскрізне шифрування з контактом.</p>
|
||||
<p><a href="https://github.com/chatmail/core/blob/main/spec.md#attaching-a-contact-to-a-message">Поширення контакту в чаті</a> дозволяє отримувачам використовувати наскрізне шифрування з контактом.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -642,7 +647,10 @@ Push-сповіщення автоматично активуються для
|
||||
|
||||
<p>Якщо ви використовуєте стандартні <a href="https://chatmail.at/relays">ретранслятори чату</a>, неможливо отримувати або надсилати повідомлення без наскрізного шифрування.</p>
|
||||
|
||||
<p>Якщо ви створите профіль за допомогою класичного поштового сервера, ви зможете надсилати та отримувати повідомлення без наскрізного шифрування. Такі повідомлення без наскрізного шифрування позначаються значком електронної пошти <img style="vertical-align:middle; width:1.2em; margin:1px" src="../email-icon.png" alt="email" />.</p>
|
||||
<p>If you instead create a profile using a classic e-mail server,
|
||||
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
|
||||
<img style="vertical-align:middle; width:1.2em; margin:1px" src="../email-icon.png" alt="email" />.</p>
|
||||
|
||||
<h3 id="howtoe2ee">
|
||||
|
||||
@@ -687,7 +695,7 @@ Push-сповіщення автоматично активуються для
|
||||
|
||||
</h3>
|
||||
|
||||
<p>У профілі контакту може відображатися зелена галочка <img style="vertical-align:middle; width:1.5em; margin:1px" src="../green-checkmark.png" alt="green checkmark" /> і рядок “Представлений”. Кожен контакт із зеленою галочкою або зробив пряме [QR-сканування] (#howtoe2ee) з вами або був представлений іншим контактом, позначеним зеленою галочкою. Знайомство відбувається автоматично під час додавання учасників до груп. Той, хто додає контакт із зеленою галочкою до групи, в якій є лише учасники із зеленою галочкою стає представником. У профілі контакту ви можете кілька разів натиснути на текст “Представлений …” поки не потрапите до того, з ким ви безпосередньо зробили [QR-сканування] (#howtoe2ee).</p>
|
||||
<p>У профілі контакту може відображатися зелена галочка <img style="vertical-align:middle; width:1.5em; margin:1px" src="../green-checkmark.png" alt="green checkmark" /> і рядок “Представлений”. Кожен контакт із зеленою галочкою або зробив пряме <a href="#howtoe2ee">QR-сканування</a> з вами або був представлений іншим контактом, позначеним зеленою галочкою. Знайомство відбувається автоматично під час додавання учасників до груп. Той, хто додає контакт із зеленою галочкою до групи, в якій є лише учасники із зеленою галочкою стає представником. У профілі контакту ви можете кілька разів натиснути на текст “Представлений …” поки не потрапите до того, з ким ви безпосередньо зробили <a href="#howtoe2ee">QR-сканування</a>.</p>
|
||||
|
||||
<p>Для більш детального обговорення “гарантованого наскрізного шифрування” будь ласка, перегляньте <a href="https://securejoin.delta.chat/en/latest/new.html">Протоколи безпечного приєднання</a> і, зокрема, прочитайте про “Перевірені групи”, технічний термін того, що тут називається чатами з “зеленою галочкою” або “гарантованим наскрізним шифруванням”.</p>
|
||||
|
||||
@@ -802,7 +810,7 @@ Delta Chat скоріше використовує реалізацію OpenPGP
|
||||
|
||||
<p>Ні, поки ще ні.</p>
|
||||
|
||||
<p>Месенджер Signal запровадив [“Запечатаного відправника” у 2018 році] (https://signal.org/blog/sealed-sender/) щоб їхня серверна інфраструктура не знала, хто надсилає повідомлення певній групі одержувачів. Це особливо важливо, оскільки сервер Signal знає номер мобільного телефону кожного акаунта, який зазвичай асоціюється з паспортними даними.</p>
|
||||
<p>Месенджер Signal запровадив <a href="https://signal.org/blog/sealed-sender/">“Запечатаного відправника” у 2018 році</a> щоб їхня серверна інфраструктура не знала, хто надсилає повідомлення певній групі одержувачів. Це особливо важливо, оскільки сервер Signal знає номер мобільного телефону кожного акаунта, який зазвичай асоціюється з паспортними даними.</p>
|
||||
|
||||
<p>Навіть якщо <a href="https://chatmail.at/relays">чат-мейл релей</a> не запитує ніяких приватних даних (в тому числі номерів телефонів), все одно може мати сенс захистити реляційні метадані між адресами. Ми не передбачаємо великих проблем у використанні випадкових одноразових адрес електронної пошти для запечатаних відправлень але реалізація такої можливості ще не є пріоритетною.</p>
|
||||
|
||||
@@ -1256,6 +1264,29 @@ Delta Chat скоріше використовує реалізацію OpenPGP
|
||||
Проте для коректної роботи деяких провайдерів потрібні специфічні налаштування. Дивіться наш <a href="https://providers.delta.chat">огляд провайдерів</a></li>
|
||||
</ul>
|
||||
|
||||
<h3 id="can-i-use-delta-chat-in-parallel-with-other-e-mail-apps">
|
||||
|
||||
|
||||
Can I use Delta Chat in parallel with other E-Mail apps? <a href="#can-i-use-delta-chat-in-parallel-with-other-e-mail-apps" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Yes, but it is not recommended.</p>
|
||||
|
||||
<p>Parallel usage with the same E-Mail address might lead to the following inconveniences:</p>
|
||||
|
||||
<ul>
|
||||
<li>Next to your Delta Chat notifications,
|
||||
you might also get notifications for (encrypted, so unreadable) chat mail messages
|
||||
in your other email app</li>
|
||||
<li>If Delta Chat is not running
|
||||
or “Advanced > Move automatically to the DeltaChat Folder” is disabled,
|
||||
encrypted Delta Chat messages might clutter the Inbox in your other E-Mail apps.</li>
|
||||
</ul>
|
||||
|
||||
<p><a href="https://support.delta.chat/t/sieve-rule-to-move-deltachat-mails-to-deltachat-folder/288/10">Sieve rules</a> can solve these problems.</p>
|
||||
|
||||
<h3 id="я-хочу-керувати-власним-сервером-для-delta-chat-що-ви-порекомендуєте">
|
||||
|
||||
|
||||
@@ -1265,7 +1296,7 @@ Delta Chat скоріше використовує реалізацію OpenPGP
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>Більшість поштових серверів будуть працювати добре. Але ми особисто рекомендуємо використовувати сервер ретрансляції чатової пошти, як описано [в цій статті] (https://delta.chat/en/2023-12-13-chatmail).</li>
|
||||
<li>Більшість поштових серверів будуть працювати добре. Але ми особисто рекомендуємо використовувати сервер ретрансляції чатової пошти, як описано <a href="https://delta.chat/en/2023-12-13-chatmail">в цій статті</a>.</li>
|
||||
<li>Ви можете знайти <a href="https://github.com/chatmail/relay">посібник зі встановлення на GitHub</a>.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
<ul>
|
||||
<li><a href="#delta-chat-需要哪些权限">Delta Chat 需要哪些权限?</a></li>
|
||||
<li><a href="#delta-chat-可用于-我的-电子邮件提供商吗">Delta Chat 可用于 <em>我的</em> 电子邮件提供商吗?</a></li>
|
||||
<li><a href="#can-i-use-delta-chat-in-parallel-with-other-e-mail-apps">Can I use Delta Chat in parallel with other E-Mail apps?</a></li>
|
||||
<li><a href="#i-want-to-manage-my-own-server-for-delta-chat-what-do-you-recommend">I want to manage my own server for Delta Chat. What do you recommend?</a></li>
|
||||
<li><a href="#为什么我必须在-delta-chat-中输入我的电子邮件密码-这样安全吗">为什么我必须在 Delta Chat 中输入我的电子邮件密码? 这样安全吗?</a></li>
|
||||
<li><a href="#哪些消息会在-delta-chat-中出现">哪些消息会在 Delta Chat 中出现?</a></li>
|
||||
@@ -394,7 +395,11 @@
|
||||
|
||||
</h3>
|
||||
|
||||
<p>您可以在聊天窗口右上角的聊天设置中通过选择 1 分钟到 5 周之间的时间跨度打开“消息定时销毁”。</p>
|
||||
<p>You can turn on “disappearing messages”
|
||||
in the settings of a chat,
|
||||
at the top right of the chat window,
|
||||
by selecting a time span
|
||||
between 5 minutes and 1 year.</p>
|
||||
|
||||
<p>在再次关闭该设置之前,
|
||||
每个聊天成员的 Delta Chat 应用都会负责
|
||||
@@ -744,8 +749,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.</p>
|
||||
|
||||
<p>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
|
||||
<img style="vertical-align:middle; width:1.2em; margin:1px" src="../email-icon.png" alt="email" />.</p>
|
||||
|
||||
<h3 id="howtoe2ee">
|
||||
@@ -1540,6 +1545,29 @@ It should be available again in a few months.</p>
|
||||
不过,某些提供商需要一些特殊设置才能正常工作,请参阅<a href="https://providers.delta.chat">提供商概览</a></li>
|
||||
</ul>
|
||||
|
||||
<h3 id="can-i-use-delta-chat-in-parallel-with-other-e-mail-apps">
|
||||
|
||||
|
||||
Can I use Delta Chat in parallel with other E-Mail apps? <a href="#can-i-use-delta-chat-in-parallel-with-other-e-mail-apps" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Yes, but it is not recommended.</p>
|
||||
|
||||
<p>Parallel usage with the same E-Mail address might lead to the following inconveniences:</p>
|
||||
|
||||
<ul>
|
||||
<li>Next to your Delta Chat notifications,
|
||||
you might also get notifications for (encrypted, so unreadable) chat mail messages
|
||||
in your other email app</li>
|
||||
<li>If Delta Chat is not running
|
||||
or “Advanced > Move automatically to the DeltaChat Folder” is disabled,
|
||||
encrypted Delta Chat messages might clutter the Inbox in your other E-Mail apps.</li>
|
||||
</ul>
|
||||
|
||||
<p><a href="https://support.delta.chat/t/sieve-rule-to-move-deltachat-mails-to-deltachat-folder/288/10">Sieve rules</a> can solve these problems.</p>
|
||||
|
||||
<h3 id="i-want-to-manage-my-own-server-for-delta-chat-what-do-you-recommend">
|
||||
|
||||
|
||||
|
||||
@@ -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<Integer, SettableFuture<JsonNode>> 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> T callForResult(TypeReference<T> 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<JsonNode> 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<JsonNode> 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;
|
||||
}
|
||||
}
|
||||
@@ -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> T callForResult(TypeReference<T> 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<Integer>(){}, "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<Integer> 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<Integer>(){}, "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.
|
||||
* <p>
|
||||
* This function is useful because the key-contacts migration could fail due to bugs
|
||||
* and then the account will not work properly.
|
||||
* <p>
|
||||
* 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<String>(){}, "get_migration_error", mapper.valueToTree(accountId));
|
||||
}
|
||||
|
||||
public Integer draftSelfReport(Integer accountId) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<Integer>(){}, "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<String>(){}, "get_config", mapper.valueToTree(accountId), mapper.valueToTree(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures a new email account using the provided parameters
|
||||
* and adds it as a transport.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* This function stops and starts IO as needed.
|
||||
* <p>
|
||||
* Usually it will be enough to only set `addr` and `password`,
|
||||
* and all the other settings will be autoconfigured.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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<Integer>(){}, "create_group_chat_unencrypted", mapper.valueToTree(accountId), mapper.valueToTree(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new **broadcast channel**
|
||||
* (called "Channel" in the UI).
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* After creation, the chat contains no recipients and is in _unpromoted_ state;
|
||||
* see [`CommandApi::create_group_chat`] for more information on the unpromoted state.
|
||||
* <p>
|
||||
* Returns the created chat's id.
|
||||
*/
|
||||
public Integer createBroadcast(Integer accountId, String chatName) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<Integer>(){}, "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<Integer>(){}, "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<VcardContact> parseVcard(String path) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<java.util.List<VcardContact>>(){}, "parse_vcard", mapper.valueToTree(path));
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports contacts from a vCard file located at the given path.
|
||||
* <p>
|
||||
* Returns the ids of created/modified contacts in the order they appear in the vCard.
|
||||
*/
|
||||
public java.util.List<Integer> importVcard(Integer accountId, String path) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<java.util.List<Integer>>(){}, "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<Integer> contacts) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<String>(){}, "make_vcard", mapper.valueToTree(accountId), mapper.valueToTree(contacts));
|
||||
}
|
||||
|
||||
public void sendWebxdcRealtimeData(Integer accountId, Integer instanceMsgId, java.util.List<Integer> 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.
|
||||
* <p>
|
||||
* 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<Integer>(){}, "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<CallInfo>(){}, "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<String>(){}, "ice_servers", mapper.valueToTree(accountId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes an HTTP GET request and returns a response.
|
||||
* <p>
|
||||
* `url` is the HTTP or HTTPS URL.
|
||||
*/
|
||||
public HttpResponse getHttpResponse(Integer accountId, String url) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<HttpResponse>(){}, "get_http_response", mapper.valueToTree(accountId), mapper.valueToTree(url));
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a reaction to message.
|
||||
* <p>
|
||||
* 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<String> reaction) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<Integer>(){}, "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<Reactions>(){}, "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<Boolean>(){}, "can_send", mapper.valueToTree(accountId), mapper.valueToTree(chatId));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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); }
|
||||
|
||||
}
|
||||
@@ -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.
|
||||
* <p>
|
||||
* Can be used to manually answer the call even if incoming call event was missed.
|
||||
*/
|
||||
public String sdpOffer;
|
||||
/**
|
||||
* Call state.
|
||||
* <p>
|
||||
* For example, if the call is accepted, active, canceled, declined etc.
|
||||
*/
|
||||
public CallState state;
|
||||
}
|
||||
@@ -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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* Incoming calls cannot be canceled, on the receiver side canceled calls usually result in missed calls.
|
||||
*/
|
||||
public static class Canceled extends CallState {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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,
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/* Autogenerated file, do not edit manually */
|
||||
package chat.delta.rpc.types;
|
||||
|
||||
/**
|
||||
* Login parameters entered by the user.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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<Reaction> reactions;
|
||||
/* Map from a contact to it's reaction to message. */
|
||||
public java.util.Map<String, java.util.List<String>> reactionsByContact;
|
||||
}
|
||||
@@ -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,
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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<T> extends Future<T> {
|
||||
void addListener(Listener<T> listener);
|
||||
|
||||
public interface Listener<T> {
|
||||
public void onSuccess(T result);
|
||||
public void onFailure(ExecutionException e);
|
||||
}
|
||||
}
|
||||
@@ -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<T> implements ListenableFuture<T> {
|
||||
|
||||
private final List<Listener<T>> 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<T> other) {
|
||||
other.addListener(new Listener<T>() {
|
||||
@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<T> listener) {
|
||||
synchronized (this) {
|
||||
listeners.add(listener);
|
||||
|
||||
if (!completed) return;
|
||||
}
|
||||
|
||||
notifyListener(listener);
|
||||
}
|
||||
|
||||
private void notifyAllListeners() {
|
||||
List<Listener<T>> localListeners;
|
||||
|
||||
synchronized (this) {
|
||||
localListeners = new LinkedList<>(listeners);
|
||||
}
|
||||
|
||||
for (Listener<T> listener : localListeners) {
|
||||
notifyListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyListener(Listener<T> listener) {
|
||||
if (exception != null) listener.onFailure(new ExecutionException(exception));
|
||||
else listener.onSuccess(result);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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<Integer, String[]> reactionsByContact;
|
||||
// Unique reactions, sorted in descending order.
|
||||
private final ArrayList<Reaction> reactions;
|
||||
|
||||
public Reactions(HashMap<Integer, String[]> reactionsByContact, ArrayList<Reaction> reactions) {
|
||||
this.reactionsByContact = reactionsByContact;
|
||||
this.reactions = reactions;
|
||||
}
|
||||
|
||||
public Map<Integer, String[]> getReactionsByContact() {
|
||||
return reactionsByContact;
|
||||
}
|
||||
|
||||
public List<Reaction> getReactions() {
|
||||
return reactions;
|
||||
}
|
||||
}
|
||||
@@ -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<Integer, SettableFuture<JsonElement>> 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<JsonElement> 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<JsonElement> 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<JsonElement> 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<VcardContact> parseVcard(String path) throws RpcException {
|
||||
TypeToken<List<VcardContact>> listType = new TypeToken<List<VcardContact>>(){};
|
||||
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<Integer> importVcard(int accountId, String path) throws RpcException {
|
||||
TypeToken<List<Integer>> listType = new TypeToken<List<Integer>>(){};
|
||||
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<Integer> 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<Integer> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,6 @@ import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -221,16 +220,11 @@ public class AllMediaDocumentsFragment
|
||||
|
||||
private class ActionModeCallback implements ActionMode.Callback {
|
||||
|
||||
private int originalStatusBarColor;
|
||||
|
||||
@Override
|
||||
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
|
||||
mode.getMenuInflater().inflate(R.menu.profile_context, menu);
|
||||
mode.setTitle("1");
|
||||
|
||||
Window window = getActivity().getWindow();
|
||||
originalStatusBarColor = window.getStatusBarColor();
|
||||
window.setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
|
||||
setCorrectMenuVisibility(menu);
|
||||
return true;
|
||||
}
|
||||
@@ -279,8 +273,6 @@ public class AllMediaDocumentsFragment
|
||||
public void onDestroyActionMode(ActionMode mode) {
|
||||
actionMode = null;
|
||||
getListAdapter().clearSelection();
|
||||
|
||||
getActivity().getWindow().setStatusBarColor(originalStatusBarColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -212,16 +211,11 @@ public class AllMediaGalleryFragment
|
||||
|
||||
private class ActionModeCallback implements ActionMode.Callback {
|
||||
|
||||
private int originalStatusBarColor;
|
||||
|
||||
@Override
|
||||
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
|
||||
mode.getMenuInflater().inflate(R.menu.profile_context, menu);
|
||||
mode.setTitle("1");
|
||||
|
||||
Window window = getActivity().getWindow();
|
||||
originalStatusBarColor = window.getStatusBarColor();
|
||||
window.setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
|
||||
setCorrectMenuVisibility(menu);
|
||||
return true;
|
||||
}
|
||||
@@ -266,8 +260,6 @@ public class AllMediaGalleryFragment
|
||||
public void onDestroyActionMode(ActionMode mode) {
|
||||
actionMode = null;
|
||||
getListAdapter().clearSelection();
|
||||
|
||||
getActivity().getWindow().setStatusBarColor(originalStatusBarColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -79,6 +79,7 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
|
||||
|
||||
//noinspection ConstantConditions
|
||||
this.getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
getSupportActionBar().setElevation(0); // TODO: use custom toolbar instead
|
||||
|
||||
if (icicle == null) {
|
||||
initFragment(R.id.fragment, new ApplicationPreferenceFragment());
|
||||
|
||||
@@ -7,10 +7,12 @@ import android.view.MenuItem;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import androidx.activity.EdgeToEdge;
|
||||
import androidx.annotation.IdRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.view.WindowCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||
@@ -31,7 +33,9 @@ public abstract class BaseActionBarActivity extends AppCompatActivity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
onPreCreate();
|
||||
EdgeToEdge.enable(this); // docs says to use: WindowCompat.enableEdgeToEdge(getWindow()); but it is not available
|
||||
super.onCreate(savedInstanceState);
|
||||
WindowCompat.getInsetsController(getWindow(), getWindow().getDecorView()).setAppearanceLightStatusBars(false); // force white text in status bar
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -10,9 +10,7 @@ import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.view.Menu;
|
||||
@@ -401,8 +399,6 @@ public abstract class BaseConversationListFragment extends Fragment implements A
|
||||
|
||||
mode.setTitle("1");
|
||||
|
||||
requireActivity().getWindow().setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -445,10 +441,6 @@ public abstract class BaseConversationListFragment extends Fragment implements A
|
||||
actionMode = null;
|
||||
getListAdapter().initializeBatchMode(false);
|
||||
|
||||
TypedArray color = requireActivity().getTheme().obtainStyledAttributes(new int[]{android.R.attr.statusBarColor});
|
||||
requireActivity().getWindow().setStatusBarColor(color.getColor(0, Color.BLACK));
|
||||
color.recycle();
|
||||
|
||||
Context context = getContext();
|
||||
if (context != null) {
|
||||
fab.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_add_white_24dp));
|
||||
|
||||
@@ -33,6 +33,7 @@ public class BlockedContactsActivity extends PassphraseRequiredActionBarActivity
|
||||
setContentView(R.layout.activity_blocked_contacts);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
getSupportActionBar().setTitle(R.string.pref_blocked_contacts);
|
||||
getSupportActionBar().setElevation(0); // TODO: use custom toolbar instead
|
||||
initFragment(R.id.fragment, new BlockedAndShareContactsFragment(), getIntent().getExtras());
|
||||
}
|
||||
|
||||
|
||||
@@ -23,8 +23,6 @@ import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
@@ -35,7 +33,6 @@ import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
@@ -136,7 +133,6 @@ public class ContactSelectionListFragment extends Fragment
|
||||
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
|
||||
MenuInflater inflater = getActivity().getMenuInflater();
|
||||
inflater.inflate(R.menu.contact_list, menu);
|
||||
getActivity().getWindow().setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
|
||||
setCorrectMenuVisibility(menu);
|
||||
actionMode.setTitle("1");
|
||||
return true;
|
||||
@@ -167,10 +163,6 @@ public class ContactSelectionListFragment extends Fragment
|
||||
public void onDestroyActionMode(ActionMode actionMode) {
|
||||
ContactSelectionListFragment.this.actionMode = null;
|
||||
getContactSelectionListAdapter().resetActionModeSelection();
|
||||
|
||||
TypedArray color = getActivity().getTheme().obtainStyledAttributes(new int[]{android.R.attr.statusBarColor});
|
||||
getActivity().getWindow().setStatusBarColor(color.getColor(0, Color.BLACK));
|
||||
color.recycle();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -927,6 +940,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
supportActionBar.setCustomView(R.layout.conversation_title_view);
|
||||
supportActionBar.setDisplayShowCustomEnabled(true);
|
||||
supportActionBar.setDisplayShowTitleEnabled(false);
|
||||
supportActionBar.setElevation(0); // TODO: use custom toolbar instead
|
||||
|
||||
Toolbar parent = (Toolbar) supportActionBar.getCustomView().getParent();
|
||||
parent.setPadding(0,0,0,0);
|
||||
@@ -971,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:
|
||||
@@ -1011,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) {
|
||||
@@ -1463,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));
|
||||
}
|
||||
|
||||
|
||||
@@ -77,9 +77,8 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
|
||||
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<DcMsg> batchSelected = Collections.synchronizedSet(new HashSet<DcMsg>());
|
||||
|
||||
@@ -279,7 +278,6 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
|
||||
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 <V extends View & BindableConversationItem>
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@ import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.widget.TextView;
|
||||
@@ -67,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;
|
||||
@@ -368,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:
|
||||
@@ -378,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() {
|
||||
@@ -759,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());
|
||||
}
|
||||
@@ -877,8 +872,6 @@ public class ConversationFragment extends MessageSelectorFragment
|
||||
|
||||
private class ActionModeCallback implements ActionMode.Callback {
|
||||
|
||||
private int statusBarColor;
|
||||
|
||||
@Override
|
||||
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
|
||||
MenuInflater inflater = mode.getMenuInflater();
|
||||
@@ -886,10 +879,6 @@ public class ConversationFragment extends MessageSelectorFragment
|
||||
|
||||
mode.setTitle("1");
|
||||
|
||||
Window window = getActivity().getWindow();
|
||||
statusBarColor = window.getStatusBarColor();
|
||||
window.setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
|
||||
|
||||
Util.redMenuItem(menu, R.id.menu_context_delete_message);
|
||||
setCorrectMenuVisibility(menu);
|
||||
ConversationAdaptiveActionsToolbar.adjustMenuActions(menu, 10, requireActivity().getWindow().getDecorView().getMeasuredWidth());
|
||||
@@ -906,8 +895,6 @@ public class ConversationFragment extends MessageSelectorFragment
|
||||
((ConversationAdapter)list.getAdapter()).clearSelection();
|
||||
list.getAdapter().notifyDataSetChanged();
|
||||
|
||||
getActivity().getWindow().setStatusBarColor(statusBarColor);
|
||||
|
||||
actionMode = null;
|
||||
hideAddReactionView();
|
||||
}
|
||||
|
||||
@@ -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<WebxdcView> webxdcViewStub;
|
||||
private Stub<BorderlessImageView> stickerStub;
|
||||
private Stub<VcardView> vcardViewStub;
|
||||
private Stub<CallItemView> 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<Integer> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ public class ConversationListArchiveActivity extends PassphraseRequiredActionBar
|
||||
protected void onCreate(Bundle icicle, boolean ready) {
|
||||
setContentView(R.layout.activity_conversation_list_archive);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
getSupportActionBar().setElevation(0); // TODO: use custom toolbar instead
|
||||
if (isRelayingMessageContent(this)) {
|
||||
getSupportActionBar().setTitle(isSharing(this) ? R.string.chat_share_with_title : R.string.forward_to);
|
||||
getSupportActionBar().setSubtitle(R.string.chat_archived_label);
|
||||
|
||||
@@ -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<DcMsg> 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() {
|
||||
}
|
||||
}
|
||||
@@ -79,6 +79,7 @@ public class CreateProfileActivity extends BaseActionBarActivity {
|
||||
getSupportActionBar().setTitle(R.string.pref_profile_info_headline);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(!this.fromWelcome);
|
||||
getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_close_white_24dp);
|
||||
getSupportActionBar().setElevation(0); // TODO: use custom toolbar instead
|
||||
|
||||
attachmentManager = new AttachmentManager(this, () -> {});
|
||||
avatarChanged = false;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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()));
|
||||
|
||||
@@ -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
|
||||
{
|
||||
@@ -80,6 +82,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
|
||||
unencrypted = getIntent().getBooleanExtra(UNENCRYPTED, false);
|
||||
Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true);
|
||||
getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_close_white_24dp);
|
||||
getSupportActionBar().setElevation(0); // TODO: use custom toolbar instead
|
||||
|
||||
groupChatId = getIntent().getIntExtra(EDIT_GROUP_CHAT_ID, 0);
|
||||
attachmentManager = new AttachmentManager(this, () -> {});
|
||||
@@ -339,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);
|
||||
|
||||
@@ -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
|
||||
@@ -100,6 +104,7 @@ public class InstantOnboardingActivity extends BaseActionBarActivity implements
|
||||
|
||||
Objects.requireNonNull(getSupportActionBar()).setTitle(R.string.onboarding_create_instant_account);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
getSupportActionBar().setElevation(0); // TODO: use custom toolbar instead
|
||||
|
||||
boolean fromWelcome = getIntent().getBooleanExtra(FROM_WELCOME, false);
|
||||
if (DcHelper.getContext(this).isConfigured() == 1) {
|
||||
@@ -421,7 +426,6 @@ public class InstantOnboardingActivity extends BaseActionBarActivity implements
|
||||
}
|
||||
|
||||
private void progressSuccess() {
|
||||
DcHelper.getEventCenter(this).endCaptureNextError();
|
||||
if (progressDialog != null) {
|
||||
progressDialog.dismiss();
|
||||
}
|
||||
@@ -480,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();
|
||||
@@ -495,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();
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ public class LogViewActivity extends BaseActionBarActivity {
|
||||
transaction.commit();
|
||||
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
getSupportActionBar().setElevation(0); // TODO: use custom toolbar instead
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -3,14 +3,12 @@ package org.thoughtcrime.securesms;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -249,8 +247,6 @@ public class ProfileFragment extends Fragment
|
||||
|
||||
private class ActionModeCallback implements ActionMode.Callback {
|
||||
|
||||
private int originalStatusBarColor;
|
||||
|
||||
@Override
|
||||
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
|
||||
mode.getMenuInflater().inflate(R.menu.profile_context, menu);
|
||||
@@ -263,9 +259,6 @@ public class ProfileFragment extends Fragment
|
||||
menu.findItem(R.id.menu_select_all).setVisible(false);
|
||||
mode.setTitle("1");
|
||||
|
||||
Window window = requireActivity().getWindow();
|
||||
originalStatusBarColor = window.getStatusBarColor();
|
||||
window.setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -306,7 +299,6 @@ public class ProfileFragment extends Fragment
|
||||
public void onDestroyActionMode(ActionMode mode) {
|
||||
actionMode = null;
|
||||
adapter.clearSelection();
|
||||
requireActivity().getWindow().setStatusBarColor(originalStatusBarColor);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -135,6 +139,7 @@ public class RegistrationActivity extends BaseActionBarActivity implements DcEve
|
||||
actionBar.setTitle(R.string.login_header);
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
actionBar.setHomeAsUpIndicator(R.drawable.ic_close_white_24dp);
|
||||
actionBar.setElevation(0); // TODO: use custom toolbar instead
|
||||
}
|
||||
|
||||
emailInput.addTextChangedListener(new TextWatcher() {
|
||||
@@ -562,6 +567,7 @@ public class RegistrationActivity extends BaseActionBarActivity implements DcEve
|
||||
return;
|
||||
}
|
||||
|
||||
cancelled = false;
|
||||
setupConfig();
|
||||
|
||||
if (progressDialog != null) {
|
||||
@@ -573,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();
|
||||
}
|
||||
|
||||
@@ -583,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);
|
||||
@@ -612,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();
|
||||
}
|
||||
@@ -630,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) {
|
||||
|
||||
@@ -34,6 +34,7 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.core.content.pm.ShortcutManagerCompat;
|
||||
|
||||
import com.b44t.messenger.DcContext;
|
||||
|
||||
@@ -217,6 +218,16 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity implement
|
||||
int chatId = intent.getIntExtra(EXTRA_CHAT_ID, -1);
|
||||
String msgType = intent.getStringExtra(EXTRA_MSG_TYPE);
|
||||
|
||||
// the intent coming from shortcuts in the share selector might not include the custom extras but the shortcut ID
|
||||
String shortcutId = intent.getStringExtra(ShortcutManagerCompat.EXTRA_SHORTCUT_ID);
|
||||
if ((chatId == -1 || accId == -1) && shortcutId != null && shortcutId.startsWith("chat-")) {
|
||||
String[] args = shortcutId.split("-");
|
||||
if (args.length == 3) {
|
||||
accId = Integer.parseInt(args[1]);
|
||||
chatId = Integer.parseInt(args[2]);
|
||||
}
|
||||
}
|
||||
|
||||
String[] extraEmail = getIntent().getStringArrayExtra(Intent.EXTRA_EMAIL);
|
||||
/*
|
||||
usually, external app will try to start "e-mail sharing" intent, providing it:
|
||||
|
||||
@@ -55,6 +55,7 @@ public class WebViewActivity extends PassphraseRequiredActionBarActivity
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
if (actionBar != null) {
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
actionBar.setElevation(0); // TODO: use custom toolbar instead
|
||||
}
|
||||
|
||||
webView = findViewById(R.id.webview);
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -48,6 +50,7 @@ public class WebxdcStoreActivity extends PassphraseRequiredActionBarActivity {
|
||||
if (actionBar != null) {
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
actionBar.setTitle(R.string.webxdc_apps);
|
||||
actionBar.setElevation(0); // TODO: use custom toolbar instead
|
||||
}
|
||||
|
||||
webView.setWebViewClient(new WebViewClient() {
|
||||
@@ -58,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);
|
||||
@@ -107,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());
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -168,8 +165,6 @@ public class DcHelper {
|
||||
dcContext.setStockTranslation(72, context.getString(R.string.systemmsg_unknown_sender_for_chat));
|
||||
dcContext.setStockTranslation(73, context.getString(R.string.systemmsg_subject_for_new_contact));
|
||||
dcContext.setStockTranslation(74, context.getString(R.string.systemmsg_failed_sending_to));
|
||||
dcContext.setStockTranslation(82, context.getString(R.string.videochat_invitation));
|
||||
dcContext.setStockTranslation(83, context.getString(R.string.videochat_invitation_body));
|
||||
dcContext.setStockTranslation(84, context.getString(R.string.configuration_failed_with_error));
|
||||
dcContext.setStockTranslation(85, context.getString(R.string.devicemsg_bad_time));
|
||||
dcContext.setStockTranslation(86, context.getString(R.string.devicemsg_update_reminder));
|
||||
@@ -247,6 +242,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 +411,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();
|
||||
|
||||
@@ -128,7 +128,7 @@ public class DirectShareUtil {
|
||||
|
||||
Recipient recipient = new Recipient(context, chat);
|
||||
Bitmap avatar = getIconForShortcut(context, recipient);
|
||||
results.add(new ShortcutInfoCompat.Builder(context, Integer.toString(chat.getId()))
|
||||
results.add(new ShortcutInfoCompat.Builder(context, "chat-" + dcContext.getAccountId() + "-" + chat.getId())
|
||||
.setShortLabel(chat.getName())
|
||||
.setLongLived(true)
|
||||
.setRank(i+1)
|
||||
|
||||
@@ -42,6 +42,7 @@ public class NewContactActivity extends PassphraseRequiredActionBarActivity
|
||||
actionBar.setTitle(R.string.menu_new_classic_contact);
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
actionBar.setHomeAsUpIndicator(R.drawable.ic_close_white_24dp);
|
||||
actionBar.setElevation(0); // TODO: use custom toolbar instead
|
||||
}
|
||||
|
||||
nameInput = ViewUtil.findById(this, R.id.name_text);
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
package org.thoughtcrime.securesms.glide.webp;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.bumptech.glide.load.Options;
|
||||
import com.bumptech.glide.load.engine.Resource;
|
||||
import com.bumptech.glide.load.resource.drawable.DrawableResource;
|
||||
import com.bumptech.glide.load.resource.transcode.ResourceTranscoder;
|
||||
import com.github.penfeizhou.animation.webp.WebPDrawable;
|
||||
import com.github.penfeizhou.animation.webp.decode.WebPDecoder;
|
||||
|
||||
public class WebpDrawableTranscoder implements ResourceTranscoder<WebPDecoder, Drawable> {
|
||||
@Nullable
|
||||
@Override
|
||||
public Resource<Drawable> transcode(@NonNull Resource<WebPDecoder> toTranscode, @NonNull Options options) {
|
||||
final WebPDrawable webPDrawable = new WebPDrawable(toTranscode.get());
|
||||
webPDrawable.setAutoPlay(true);
|
||||
return new DrawableResource<Drawable>(webPDrawable) {
|
||||
@NonNull
|
||||
@Override
|
||||
public Class<Drawable> getResourceClass() {
|
||||
return Drawable.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return webPDrawable.getMemorySize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recycle() {
|
||||
webPDrawable.stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
super.initialize();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
package org.thoughtcrime.securesms.glide.webp;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.bumptech.glide.load.Options;
|
||||
import com.bumptech.glide.load.ResourceDecoder;
|
||||
import com.bumptech.glide.load.engine.Resource;
|
||||
import com.github.penfeizhou.animation.io.StreamReader;
|
||||
import com.github.penfeizhou.animation.loader.ByteBufferLoader;
|
||||
import com.github.penfeizhou.animation.loader.Loader;
|
||||
import com.github.penfeizhou.animation.webp.decode.WebPDecoder;
|
||||
import com.github.penfeizhou.animation.webp.decode.WebPParser;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class WebpLoader implements ResourceDecoder<InputStream, WebPDecoder> {
|
||||
|
||||
@Override
|
||||
public boolean handles(@NonNull InputStream source, @NonNull Options options) {
|
||||
return WebPParser.isAWebP(new StreamReader(source));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Resource<WebPDecoder> decode(@NonNull final InputStream source, int width, int height, @NonNull Options options) throws IOException {
|
||||
byte[] data = inputStreamToBytes(source);
|
||||
if (data == null) {
|
||||
return null;
|
||||
}
|
||||
ByteBuffer byteBuffer = ByteBuffer.wrap(data);
|
||||
Loader loader = new ByteBufferLoader() {
|
||||
@Override
|
||||
public ByteBuffer getByteBuffer() {
|
||||
byteBuffer.position(0);
|
||||
return byteBuffer;
|
||||
}
|
||||
};
|
||||
return new WebPDecoderResource(new WebPDecoder(loader, null), byteBuffer.limit());
|
||||
}
|
||||
|
||||
private static byte[] inputStreamToBytes(InputStream is) {
|
||||
final int bufferSize = 16384;
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream(bufferSize);
|
||||
try {
|
||||
int nRead;
|
||||
byte[] data = new byte[bufferSize];
|
||||
while ((nRead = is.read(data)) != -1) {
|
||||
buffer.write(data, 0, nRead);
|
||||
}
|
||||
buffer.flush();
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
return buffer.toByteArray();
|
||||
}
|
||||
|
||||
private static class WebPDecoderResource implements Resource<WebPDecoder> {
|
||||
private final WebPDecoder decoder;
|
||||
private final int size;
|
||||
|
||||
WebPDecoderResource(WebPDecoder decoder, int size) {
|
||||
this.decoder = decoder;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Class<WebPDecoder> getResourceClass() {
|
||||
return WebPDecoder.class;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public WebPDecoder get() {
|
||||
return this.decoder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return this.size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recycle() {
|
||||
this.decoder.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ import com.bumptech.glide.Registry;
|
||||
import com.bumptech.glide.annotation.GlideModule;
|
||||
import com.bumptech.glide.load.model.UnitModelLoader;
|
||||
import com.bumptech.glide.module.AppGlideModule;
|
||||
import com.github.penfeizhou.animation.webp.decode.WebPDecoder;
|
||||
|
||||
import com.caverock.androidsvg.SVG;
|
||||
|
||||
@@ -26,8 +25,6 @@ import org.thoughtcrime.securesms.glide.lottie.LottieDecoder;
|
||||
import org.thoughtcrime.securesms.glide.lottie.LottieDrawableTranscoder;
|
||||
import org.thoughtcrime.securesms.glide.svg.SvgDecoder;
|
||||
import org.thoughtcrime.securesms.glide.svg.SvgDrawableTranscoder;
|
||||
import org.thoughtcrime.securesms.glide.webp.WebpDrawableTranscoder;
|
||||
import org.thoughtcrime.securesms.glide.webp.WebpLoader;
|
||||
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri;
|
||||
|
||||
import java.io.File;
|
||||
@@ -64,10 +61,6 @@ public class SignalGlideModule extends AppGlideModule {
|
||||
registry.append(DecryptableUri.class, InputStream.class, new DecryptableStreamUriLoader.Factory(context));
|
||||
//registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory());
|
||||
|
||||
registry
|
||||
.prepend(InputStream.class, WebPDecoder.class, new WebpLoader())
|
||||
.register(WebPDecoder.class, Drawable.class, new WebpDrawableTranscoder());
|
||||
|
||||
registry
|
||||
.register(LottieComposition.class, LottieDrawable.class, new LottieDrawableTranscoder())
|
||||
.append(InputStream.class, LottieComposition.class, new LottieDecoder());
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user