mirror of
https://github.com/ArcaneChat/android.git
synced 2026-07-03 14:05:24 +02:00
Compare commits
147 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0ac9bea63c | |||
| 2bb3ad546e | |||
| 41a6b9a6c9 | |||
| fb7c119afc | |||
| 5910fc245a | |||
| 7d8887eddd | |||
| 37471ae9fa | |||
| 29a4a4712c | |||
| 644bd1f594 | |||
| ed6eca8920 | |||
| 47512f786e | |||
| add51186e6 | |||
| 52f63b28ba | |||
| 889c9aab45 | |||
| de5940e709 | |||
| 6e184f735d | |||
| c33ff20d0a | |||
| c67c3c8972 | |||
| f98a5178b3 | |||
| 6dfccdab84 | |||
| 40faa3d43e | |||
| 74f6853815 | |||
| cef6817187 | |||
| 6f547dfb66 | |||
| d6e05f61ac | |||
| 55649b0c4b | |||
| 4d9f8dd244 | |||
| 3880da8a08 | |||
| 5e8666835d | |||
| 2f5619141e | |||
| 4a07d7fd9d | |||
| 1493583db7 | |||
| dc363a0281 | |||
| fcffe3922a | |||
| d546d8041f | |||
| 267caf9b03 | |||
| d55ad1f32a | |||
| be07043b47 | |||
| cc3e6bcd9d | |||
| 43654fdadb | |||
| 774add2380 | |||
| 1133a6e624 | |||
| 0aad1b3d76 | |||
| b58a9d0bab | |||
| 54a74a8586 | |||
| f25474947b | |||
| 9ebd8e4a37 | |||
| 975ad2e149 | |||
| e6350aaec2 | |||
| d373537d6d | |||
| 960581e5f2 | |||
| fccf8f402e | |||
| e0459978f7 | |||
| 72bd7376ca | |||
| 94fbdcde05 | |||
| 89d77e7638 | |||
| d9edee117f | |||
| 6cfdb87924 | |||
| 613940577c | |||
| 43a3e21495 | |||
| b5375b8c0e | |||
| 39aec04fea | |||
| 94e2c8dbed | |||
| da45c7bc1c | |||
| d180704d52 | |||
| 653c8688b7 | |||
| 9a382a4948 | |||
| dcaa19b29d | |||
| 11845da65f | |||
| 82262cb166 | |||
| e85ae5247a | |||
| 74e14bd0ea | |||
| 40cdeee47a | |||
| 844231e5e7 | |||
| 0ccf0a9309 | |||
| 5040fb4634 | |||
| a57122a902 | |||
| 4313e8824b | |||
| 464cba299a | |||
| 102c3fd82a | |||
| dc31eee4bc | |||
| 875f0e5c86 | |||
| 2b36e2dc26 | |||
| 6a9c3ab8ca | |||
| 2ab544b18e | |||
| 2630e22421 | |||
| 1b7e32ab44 | |||
| 8436909977 | |||
| 9dd44c24b3 | |||
| 5d0e85b30d | |||
| 5193dfa412 | |||
| 96490e23f8 | |||
| 7959b07d45 | |||
| c4ae7927ad | |||
| ba0515ebc5 | |||
| 349bab9510 | |||
| e26f803d1f | |||
| 60ab7f2826 | |||
| 67d2c89bcc | |||
| e511237e5e | |||
| f249fd6174 | |||
| 6db45c1911 | |||
| 06a1114744 | |||
| 3afff5625b | |||
| cef8ddeedb | |||
| 2f0ac973c0 | |||
| 9465776715 | |||
| 39685a575d | |||
| 8601736387 | |||
| 98d8572baf | |||
| 917e764b6f | |||
| 52263150c8 | |||
| c2aba94b34 | |||
| 1278dfd395 | |||
| 44a688470f | |||
| e9a09d9c72 | |||
| abc49a3b95 | |||
| cdd4e5eccd | |||
| fa8ed2b881 | |||
| 0731fe9447 | |||
| d3567d9f0c | |||
| 66ab1f8051 | |||
| 872fd17f5e | |||
| af49018911 | |||
| f870e9c8fd | |||
| d5982ba09f | |||
| 22d70d7bd4 | |||
| 09bdc32a9c | |||
| 7763ba17bf | |||
| 965204c46f | |||
| 815e4def6f | |||
| dc3ca8ff70 | |||
| 3bccb3fb84 | |||
| 402d93b5a4 | |||
| 927dc46431 | |||
| 87c32b1904 | |||
| bb97213460 | |||
| 9ca9bf1acd | |||
| 885c902b14 | |||
| 61bf5aaad4 | |||
| 5d76586ac1 | |||
| beb45af440 | |||
| 87a21eb0f2 | |||
| dea51cd356 | |||
| ed540e5584 | |||
| 9f80c9f35f | |||
| 5dec1b24cd |
@@ -1,20 +0,0 @@
|
||||
name: add artifact links to pull request
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ["Upload Preview APK"]
|
||||
types: [completed]
|
||||
|
||||
jobs:
|
||||
artifacts-url-comments:
|
||||
name: add artifact links to pull request
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
||||
steps:
|
||||
- name: add artifact links to pull request
|
||||
uses: tonyhallett/artifacts-url-comments@v1.1.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
prefix: "**To test the changes in this pull request, install this apk:**"
|
||||
format: "[📦 {name}]({url})"
|
||||
addTo: pull
|
||||
@@ -10,21 +10,24 @@ on:
|
||||
- 'jni/dc_wrapper.c'
|
||||
- 'scripts/ndk-make.sh'
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
submodules: recursive
|
||||
persist-credentials: false
|
||||
|
||||
- uses: android-actions/setup-android@v3
|
||||
- uses: nttld/setup-ndk@v1
|
||||
- uses: android-actions/setup-android@40fd30fb8d7440372e1316f5d1809ec01dcd3699 # v4.0.1
|
||||
- uses: nttld/setup-ndk@ed92fe6cadad69be94a966a7ee3271275e62f779 # v1.6.0
|
||||
id: setup-ndk
|
||||
with:
|
||||
ndk-version: r27
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
|
||||
with:
|
||||
workspaces: jni/deltachat-core-rust
|
||||
|
||||
@@ -34,7 +37,7 @@ jobs:
|
||||
|
||||
- name: Cache compiled core
|
||||
id: cache-core
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
with:
|
||||
path: |
|
||||
jni/arm64-v8a
|
||||
|
||||
@@ -5,6 +5,8 @@ on:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
|
||||
permissions: {}
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
||||
@@ -16,12 +18,16 @@ jobs:
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/setup-java@v5
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
||||
with:
|
||||
java-version: 17
|
||||
distribution: temurin
|
||||
- uses: actions/cache@v4
|
||||
- name: Restore Gradle cache
|
||||
id: gradle-cache
|
||||
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
@@ -30,6 +36,14 @@ jobs:
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
- name: Validate Gradle Wrapper
|
||||
uses: gradle/actions/wrapper-validation@v4
|
||||
uses: gradle/actions/wrapper-validation@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0
|
||||
- name: Check formatting
|
||||
run: ./gradlew spotlessCheck
|
||||
- name: Save Gradle cache
|
||||
if: github.event_name == 'push' && steps.gradle-cache.outputs.cache-hit != 'true'
|
||||
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
|
||||
|
||||
@@ -6,24 +6,31 @@ concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Upload Preview APK
|
||||
if: github.event.pull_request.head.repo.full_name == github.repository
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
submodules: recursive
|
||||
persist-credentials: false
|
||||
|
||||
- name: Validate Fastlane Metadata
|
||||
uses: ashutoshgngwr/validate-fastlane-supply-metadata@v2
|
||||
uses: ashutoshgngwr/validate-fastlane-supply-metadata@c8857fdbbd3e00f9a5cbe8604bcecfa95ce8fef8 # v2.1.0
|
||||
|
||||
- uses: actions/setup-java@v5
|
||||
- uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
||||
with:
|
||||
java-version: 17
|
||||
distribution: 'temurin'
|
||||
|
||||
- uses: actions/cache@v4
|
||||
- uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
@@ -33,15 +40,15 @@ jobs:
|
||||
${{ runner.os }}-gradle-
|
||||
|
||||
- name: Validate Gradle Wrapper
|
||||
uses: gradle/actions/wrapper-validation@v4
|
||||
uses: gradle/actions/wrapper-validation@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0
|
||||
|
||||
- uses: android-actions/setup-android@v3
|
||||
- uses: nttld/setup-ndk@v1
|
||||
- uses: android-actions/setup-android@40fd30fb8d7440372e1316f5d1809ec01dcd3699 # v4.0.1
|
||||
- uses: nttld/setup-ndk@ed92fe6cadad69be94a966a7ee3271275e62f779 # v1.6.0
|
||||
id: setup-ndk
|
||||
with:
|
||||
ndk-version: r27
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
|
||||
with:
|
||||
workspaces: jni/deltachat-core-rust
|
||||
|
||||
@@ -51,7 +58,7 @@ jobs:
|
||||
|
||||
- name: Restore compiled core
|
||||
id: core-cache
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
with:
|
||||
path: |
|
||||
jni/arm64-v8a
|
||||
@@ -70,7 +77,22 @@ jobs:
|
||||
run: ./gradlew --no-daemon -PABI_FILTER=arm64-v8a assembleFossDebug
|
||||
|
||||
- name: Upload APK
|
||||
uses: actions/upload-artifact@v4
|
||||
id: upload
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: app-preview.apk
|
||||
path: 'build/outputs/apk/foss/debug/*.apk'
|
||||
|
||||
- name: Add artifact links to PR
|
||||
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
||||
env:
|
||||
ARTIFACT_URL: ${{ steps.upload.outputs.artifact-url }}
|
||||
with:
|
||||
script: |
|
||||
const url = process.env.ARTIFACT_URL;
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.issue.number,
|
||||
body: `**To test the changes in this pull request, install this apk:**\n\n[📦 app-preview.apk](${url})`,
|
||||
});
|
||||
|
||||
@@ -23,18 +23,18 @@ jobs:
|
||||
name: Upload Release APK
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
submodules: recursive
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
|
||||
with:
|
||||
working-directory: jni/deltachat-core-rust
|
||||
- uses: actions/setup-java@v3
|
||||
- uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
||||
with:
|
||||
java-version: 17
|
||||
distribution: 'temurin'
|
||||
- uses: android-actions/setup-android@v3
|
||||
- uses: nttld/setup-ndk@v1
|
||||
- uses: android-actions/setup-android@40fd30fb8d7440372e1316f5d1809ec01dcd3699 # v4.0.1
|
||||
- uses: nttld/setup-ndk@ed92fe6cadad69be94a966a7ee3271275e62f779 # v1.6.0
|
||||
id: setup-ndk
|
||||
with:
|
||||
ndk-version: r27
|
||||
@@ -63,7 +63,7 @@ jobs:
|
||||
mv build/outputs/mapping/gplayRelease/mapping.txt build/outputs/mapping/fossRelease/mapping-gplay.txt
|
||||
|
||||
- name: Release on GitHub
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
|
||||
with:
|
||||
token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
body: '[<img src="store/get-it-on-gplay.png" alt="Get it on Google Play" height="48">](https://play.google.com/store/apps/details?id=com.github.arcanechat) [<img src="store/get-it-on-fdroid.png" alt="Get it on F-Droid" height="48">](https://f-droid.org/packages/chat.delta.lite) [<img src="store/get-it-on-github.png" alt="Get it on GitHub" height="48">](https://github.com/ArcaneChat/android/releases/latest/download/ArcaneChat-gplay.apk)'
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
name: GitHub Actions Security Analysis with zizmor
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["main"]
|
||||
pull_request:
|
||||
branches: ["**"]
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
zizmor:
|
||||
name: Run zizmor
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
security-events: write # Required for upload-sarif (used by zizmor-action) to upload SARIF files.
|
||||
contents: read
|
||||
actions: read
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Run zizmor
|
||||
uses: zizmorcore/zizmor-action@b1d7e1fb5de872772f31590499237e7cce841e8e # v0.5.3
|
||||
@@ -0,0 +1,6 @@
|
||||
rules:
|
||||
unpinned-uses:
|
||||
config:
|
||||
policies:
|
||||
actions/*: ref-pin
|
||||
dependabot/*: ref-pin
|
||||
+12
@@ -243,3 +243,15 @@ $ANDROID_NDK_ROOT/ndk-stack --sym obj/local/armeabi-v7a --dump crash.txt > decod
|
||||
`obj/local/armeabi-v7a` is the extracted path from `deltachat-gplay-release-X.X.X.apk-symbols.zip` file from https://download.delta.chat/android/symbols/
|
||||
|
||||
Replace `armeabi-v7a` by the correct architecture the logs come from (can be guessed by trial and error)
|
||||
|
||||
|
||||
### Deobfuscating Java Stack Traces
|
||||
|
||||
Because the app uses code minification (ProGuard/R8), Java stack traces in crash reports are obfuscated.
|
||||
To decode them, use `retrace` with the `mapping.txt` file that is included in the symbols zip:
|
||||
|
||||
```
|
||||
retrace mapping.txt crash.txt > decoded-crash.txt
|
||||
```
|
||||
|
||||
`mapping.txt` is extracted from the same `deltachat-gplay-release-X.X.X.apk-symbols.zip` file available at https://download.delta.chat/android/symbols/
|
||||
|
||||
+36
-1
@@ -1,9 +1,44 @@
|
||||
# Delta Chat Android Changelog
|
||||
|
||||
## Unreleased
|
||||
## v2.50.0
|
||||
2026-05
|
||||
|
||||
* Better incoming call system integration
|
||||
* Calls are not experimental anymore and don't need to be manually enabled
|
||||
* Calls can be answered by tapping messages
|
||||
* Notify the user when they try to make a call while the device is offline
|
||||
* Channels are no longer experimental and are available by default
|
||||
* Display a permanent notification when doing location streaming and get rid of dangerous "Access Location in Background" permission
|
||||
* Autoplay all voice messages in a chat
|
||||
* Allow to share location for 24 hours
|
||||
* Allow mini-apps to play audio without user interaction
|
||||
* Allow to paste and open invitation links from search
|
||||
* Mark chats as unread (long tap a chat and select the corresponding option from the three-dot-menu)
|
||||
* Add "Mark all as read" option to profile menu in the profile switcher
|
||||
* Fix process of upgrading from a very old version of the app
|
||||
* Show more recent added stickers at the top of the sticker picker
|
||||
* Allow to open links in messages via actions in TalkBack menu
|
||||
* Allow to open map if user clicks "Location streaming enabled" system message
|
||||
* Allow to disable incoming calls notifications
|
||||
* Add an option to process unencrypted messages; by default, only encrypted messages can be sent or received
|
||||
* Fix: do not accidentally set draft in chats that don't allow sending messages
|
||||
* Fix swipe navigation between tabs in RTL languages
|
||||
* Remove "Move to DeltaChat folder", in case you are using the option, a device message shows how to proceed
|
||||
* Remove "Only fetch from DeltaChat folder" option, the functionality is preserved for existing profiles
|
||||
* Remove "Delete Messages from Server" option, this is now up to the server:
|
||||
Chatmail handles that automatically, classic email servers used as relay often have lots of storage or options themselves
|
||||
* Remove "Show Email" options, all messages are shown by default, shared usage of email account is not supported
|
||||
* Allow otherwise invalid TLS connections if the key is unchanged
|
||||
* Adapt quota warning to automatic cleanup.
|
||||
* Don't show non-delivery-notfications in broadcast channels
|
||||
* Resend the last 10 messages to new broadcast channel member
|
||||
* Enable PQC (Post-Quantum Cryptography) support. We do not generate PQC keys yet, this step is needed for forward compatibility
|
||||
* Improve avatar quality
|
||||
* Fix: avoid invalid empty "~" notifications when some peer is streaming location
|
||||
* Fix: Improve detection of stickers
|
||||
* Fix text direction issues for RTL languages in "Show full message" view
|
||||
* Fix: Reconnect when removing a relay
|
||||
* Update to core 2.50.0
|
||||
|
||||
## v2.49.0
|
||||
2026-04
|
||||
|
||||
+4
-3
@@ -34,8 +34,8 @@ android {
|
||||
useLibrary 'org.apache.http.legacy'
|
||||
|
||||
defaultConfig {
|
||||
versionCode 30000742
|
||||
versionName "2.49.0"
|
||||
versionCode 30000743
|
||||
versionName "2.50.0"
|
||||
|
||||
applicationId "chat.delta.lite"
|
||||
multiDexEnabled true
|
||||
@@ -223,7 +223,7 @@ spotless {
|
||||
}
|
||||
format 'xml', {
|
||||
target 'src/*/res/**/*.xml', 'src/*/AndroidManifest.xml'
|
||||
targetExclude 'src/*/res/values*/strings.xml' // line-break changes invalidate translations
|
||||
targetExclude 'src/*/res/values*/strings*.xml' // line-break changes invalidate translations
|
||||
eclipseWtp('xml').configFile('spotless/eclipse-wtp-xml.prefs')
|
||||
trimTrailingWhitespace()
|
||||
endWithNewline()
|
||||
@@ -307,6 +307,7 @@ dependencies {
|
||||
exclude group: 'com.google.firebase', module: 'firebase-analytics'
|
||||
exclude group: 'com.google.firebase', module: 'firebase-measurement-connector'
|
||||
}
|
||||
gplayImplementation 'com.google.android.gms:play-services-location:21.3.0'
|
||||
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
testImplementation 'org.assertj:assertj-core:3.27.3'
|
||||
|
||||
@@ -25,7 +25,7 @@ ArcaneChat is a Delta Chat client and was created with a focus on usability, goo
|
||||
<li>Multiple color themes/skins</li>
|
||||
<li>It is possible to disable profiles to completely disconnect them saving data/bandwidth</li>
|
||||
<li>You can easily see the connection status of all your profiles in the profile switcher</li>
|
||||
<li>Extra option to share location for 12 hours</li>
|
||||
<li>Extra option to share location for 24 hours</li>
|
||||
<li>Clicking on a message with a POI location, will open the POI on the map</li>
|
||||
<li>Last-seen status of contacts is shown in your contact list, like in WhatsApp, Telegram, etc.</li>
|
||||
<li>Videos are played in loop, useful for short GIF videos</li>
|
||||
|
||||
+1
-6
@@ -1393,6 +1393,7 @@ JNIEXPORT jint Java_com_b44t_messenger_DcMsg_getId(JNIEnv *env, jobject obj)
|
||||
return dc_msg_get_id(get_dc_msg(env, obj));
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jstring Java_com_b44t_messenger_DcMsg_getText(JNIEnv *env, jobject obj)
|
||||
{
|
||||
char* temp = dc_msg_get_text(get_dc_msg(env, obj));
|
||||
@@ -1642,12 +1643,6 @@ JNIEXPORT void Java_com_b44t_messenger_DcMsg_setHtml(JNIEnv *env, jobject obj, j
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT void Java_com_b44t_messenger_DcMsg_forceSticker(JNIEnv *env, jobject obj)
|
||||
{
|
||||
dc_msg_force_sticker(get_dc_msg(env, obj));
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jstring Java_com_b44t_messenger_DcMsg_getPOILocation(JNIEnv *env, jobject obj)
|
||||
{
|
||||
char* temp = dc_msg_get_poi_location(get_dc_msg(env, obj));
|
||||
|
||||
+1
-1
Submodule jni/deltachat-core-rust updated: 570119830f...ad50c27fab
@@ -34,6 +34,7 @@ cd ../..
|
||||
SYMBOLS_ZIP="$APK-symbols.zip"
|
||||
rm $SYMBOLS_ZIP
|
||||
zip -r $SYMBOLS_ZIP obj
|
||||
zip $SYMBOLS_ZIP build/outputs/mapping/gplayRelease/mapping.txt
|
||||
ls -l $SYMBOLS_ZIP
|
||||
rsync --progress $SYMBOLS_ZIP jekyll@download.delta.chat:/var/www/html/download/android/symbols/
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ public class EnterChatsBenchmark {
|
||||
// PLEASE BACKUP YOUR ACCOUNT BEFORE RUNNING THIS!
|
||||
// ==============================================================================================
|
||||
|
||||
private static final String TAG = EnterChatsBenchmark.class.getSimpleName();
|
||||
private static final String TAG = "EnterChatsBenchmark";
|
||||
|
||||
@Rule
|
||||
public ActivityScenarioRule<ConversationListActivity> activityRule =
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package org.thoughtcrime.securesms.geolocation;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
/** Non-GMS, always uses the platform LocationManager. */
|
||||
public final class LocationSourceFactory {
|
||||
|
||||
private static final String TAG = "LocationSourceFactory";
|
||||
|
||||
private LocationSourceFactory() {}
|
||||
|
||||
public static LocationSource create(Context context) {
|
||||
Log.i(TAG, "Non-GMS build, Using platform LocationManager");
|
||||
return new PlatformLocationSource();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package org.thoughtcrime.securesms.geolocation;
|
||||
|
||||
import android.content.Context;
|
||||
import android.location.Location;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
import androidx.annotation.NonNull;
|
||||
import com.google.android.gms.location.FusedLocationProviderClient;
|
||||
import com.google.android.gms.location.LocationCallback;
|
||||
import com.google.android.gms.location.LocationRequest;
|
||||
import com.google.android.gms.location.LocationResult;
|
||||
import com.google.android.gms.location.LocationServices;
|
||||
import com.google.android.gms.location.Priority;
|
||||
|
||||
public class GmsLocationSource implements LocationSource {
|
||||
|
||||
private static final String TAG = "GmsLocationSource";
|
||||
private static final long UPDATE_INTERVAL_MS = 3_000;
|
||||
private static final long FASTEST_INTERVAL_MS = 1_000;
|
||||
|
||||
private FusedLocationProviderClient client;
|
||||
private LocationCallback locationCallback;
|
||||
|
||||
@Override
|
||||
public void startUpdates(@NonNull Context context, @NonNull Callback callback) {
|
||||
client = LocationServices.getFusedLocationProviderClient(context);
|
||||
|
||||
LocationRequest request =
|
||||
new LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, UPDATE_INTERVAL_MS)
|
||||
.setMinUpdateIntervalMillis(FASTEST_INTERVAL_MS)
|
||||
.setMinUpdateDistanceMeters(0)
|
||||
.setWaitForAccurateLocation(false)
|
||||
.build();
|
||||
|
||||
locationCallback =
|
||||
new LocationCallback() {
|
||||
@Override
|
||||
public void onLocationResult(@NonNull LocationResult result) {
|
||||
Location loc = result.getLastLocation();
|
||||
if (loc != null) {
|
||||
callback.onLocationUpdate(loc);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
client.requestLocationUpdates(request, locationCallback, Looper.getMainLooper());
|
||||
} catch (SecurityException e) {
|
||||
Log.e(TAG, "Missing location permission", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopUpdates() {
|
||||
if (client != null && locationCallback != null) {
|
||||
client.removeLocationUpdates(locationCallback);
|
||||
client = null;
|
||||
locationCallback = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.thoughtcrime.securesms.geolocation;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import com.google.android.gms.common.ConnectionResult;
|
||||
import com.google.android.gms.common.GoogleApiAvailability;
|
||||
|
||||
/**
|
||||
* Prefers FusedLocationProviderClient, falls back to platform LocationManager if Play Services are
|
||||
* somehow unavailable.
|
||||
*/
|
||||
public final class LocationSourceFactory {
|
||||
|
||||
private static final String TAG = "LocationSourceFactory";
|
||||
|
||||
private LocationSourceFactory() {}
|
||||
|
||||
public static LocationSource create(Context context) {
|
||||
if (isGmsAvailable(context)) {
|
||||
Log.i(TAG, "Using FusedLocationProviderClient");
|
||||
return new GmsLocationSource();
|
||||
}
|
||||
Log.i(TAG, "GMS unavailable, falling back to LocationManager");
|
||||
return new PlatformLocationSource();
|
||||
}
|
||||
|
||||
private static boolean isGmsAvailable(Context context) {
|
||||
try {
|
||||
return GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context)
|
||||
== ConnectionResult.SUCCESS;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ import org.thoughtcrime.securesms.service.FetchForegroundService;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
public class FcmReceiveService extends FirebaseMessagingService {
|
||||
private static final String TAG = FcmReceiveService.class.getSimpleName();
|
||||
private static final String TAG = "FcmReceiveService";
|
||||
private static final Object INIT_LOCK = new Object();
|
||||
private static boolean initialized;
|
||||
private static volatile boolean triedRegistering;
|
||||
|
||||
@@ -71,6 +71,8 @@
|
||||
android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CAMERA" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_PHONE_CALL" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.MANAGE_OWN_CALLS" />
|
||||
|
||||
<!-- force compiling libs on older sdk than supported; runtime checks are required -->
|
||||
@@ -81,7 +83,6 @@
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
tools:replace="android:allowBackup"
|
||||
android:allowBackup="false"
|
||||
android:theme="@style/TextSecure.LightTheme"
|
||||
android:largeHeap="true"
|
||||
@@ -464,10 +465,6 @@
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize">
|
||||
</activity>
|
||||
|
||||
<service
|
||||
android:name=".geolocation.LocationBackgroundService"
|
||||
android:foregroundServiceType="location" />
|
||||
|
||||
<service
|
||||
android:name=".service.GenericForegroundService"
|
||||
android:foregroundServiceType="dataSync" />
|
||||
@@ -476,6 +473,11 @@
|
||||
android:name=".service.FetchForegroundService"
|
||||
android:foregroundServiceType="dataSync" />
|
||||
|
||||
<service
|
||||
android:name=".geolocation.LocationStreamingService"
|
||||
android:foregroundServiceType="location"
|
||||
android:exported="false" />
|
||||
|
||||
<service
|
||||
android:name=".service.AudioPlaybackService"
|
||||
android:foregroundServiceType="mediaPlayback"
|
||||
@@ -489,7 +491,7 @@
|
||||
android:name=".calls.CallService"
|
||||
android:enabled="true"
|
||||
android:exported="false"
|
||||
android:foregroundServiceType="camera|microphone" />
|
||||
android:foregroundServiceType="camera|microphone|phoneCall" />
|
||||
|
||||
<receiver
|
||||
android:name=".notifications.MarkReadReceiver"
|
||||
|
||||
@@ -29,6 +29,21 @@
|
||||
<li><a href="#how-many-members-can-participate-in-a-single-group">How many members can participate in a single group?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#channels">Channels</a>
|
||||
<ul>
|
||||
<li><a href="#subscribe-to-a-channel">Subscribe to a channel</a></li>
|
||||
<li><a href="#create-a-channel">Create a channel</a></li>
|
||||
<li><a href="#how-many-subscribers-can-a-channel-have">How many subscribers can a channel have?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#calls">Calls</a>
|
||||
<ul>
|
||||
<li><a href="#place-a-call">Place a call</a></li>
|
||||
<li><a href="#accept-or-reject-a-call">Accept or reject a call</a></li>
|
||||
<li><a href="#during-a-call">During a call</a></li>
|
||||
<li><a href="#missed-calls-and-notifications">Missed calls and notifications</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#webxdc">In-chat apps</a>
|
||||
<ul>
|
||||
<li><a href="#where-can-i-get-in-chat-apps">Where can I get in-chat apps?</a></li>
|
||||
@@ -628,6 +643,197 @@ but more than 150 is not recommended.</p>
|
||||
where Delta Chat is a private messenger for chatting with <a href="#groups">equal rights</a>.
|
||||
See <a href="https://en.wikipedia.org/wiki/Dunbar%27s_number">Dunbar’s number</a> for more insights.</p>
|
||||
|
||||
<h2 id="channels">
|
||||
|
||||
|
||||
Channels <a href="#channels" class="anchor"></a>
|
||||
|
||||
|
||||
</h2>
|
||||
|
||||
<p>Channels are a one-to-many tool for broadcasting messages.</p>
|
||||
|
||||
<h3 id="subscribe-to-a-channel">
|
||||
|
||||
|
||||
Subscribe to a channel <a href="#subscribe-to-a-channel" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>Scan the <img style="vertical-align:middle; height:1.3em; margin:1px" src="../qr-icon.png" /> <strong>QR code</strong>
|
||||
or tap the <strong>invite link</strong> you got from the channel owner.</li>
|
||||
</ul>
|
||||
|
||||
<p>That’s all!
|
||||
You will receive a few of the messages from the channel history
|
||||
and, from that point on, all new messages from the channel.</p>
|
||||
|
||||
<p><strong>Don’t worry,</strong> if that does not happen immediately.
|
||||
Once the channel owner comes online, your join request will be processed.</p>
|
||||
|
||||
<p>As all of Delta Chat, also Channels are private and decentralized,
|
||||
there is no public discovery.</p>
|
||||
|
||||
<p>Other channel subscribers will not see that you subscribed and cannot message you.
|
||||
The channel owner, however, can message you.
|
||||
They will also see that you read a message unless you have read receipts disabled.</p>
|
||||
|
||||
<p>If you do not want to share your main profile,
|
||||
you can also create a <a href="#multiple-accounts">dedicated profile</a> for joining a channel.</p>
|
||||
|
||||
<h3 id="create-a-channel">
|
||||
|
||||
|
||||
Create a channel <a href="#create-a-channel" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>Tap <strong>New Chat</strong> and choose <strong>New Channel</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Enter a <strong>name</strong>, optionally set an <strong>image</strong> and <strong>description</strong>, and hit the <strong>Create</strong> button.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>You can now send and manage messages as usual.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>From the channel’s profile, <strong>share the QR code or invite link with others</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Subscribers will receive your messages,
|
||||
but they cannot send messages in your channel.
|
||||
When subscribing, they will receive <strong>a few of the latest messages of the channel history</strong>.</p>
|
||||
|
||||
<p>You can see the <strong>view count</strong> beside each message.
|
||||
Note that this only counts subscribers who have read receipts enabled,
|
||||
so the real view count may be larger.</p>
|
||||
|
||||
<h3 id="how-many-subscribers-can-a-channel-have">
|
||||
|
||||
|
||||
How many subscribers can a channel have? <a href="#how-many-subscribers-can-a-channel-have" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Channels are designed for much larger audiences than <a href="#groups">groups</a>.</p>
|
||||
|
||||
<p>The practical limit depends on the used <a href="#relays">relay</a>,
|
||||
so there is no single fixed number that applies everywhere.</p>
|
||||
|
||||
<p>For really large channels with several tens of thousands of subscribers,
|
||||
we recommend using a <a href="#multiple-accounts">dedicated profile</a> for the channel
|
||||
and checking whether the relay is suitable.</p>
|
||||
|
||||
<p>But don’t be too hesitant: Delta Chat is designed to be relay-agnostic,
|
||||
so you can change your relay at any point easily -
|
||||
your existing subscribers will not even notice.
|
||||
You only have to update the invite link you share with new subscribers in that case.</p>
|
||||
|
||||
<h2 id="calls">
|
||||
|
||||
|
||||
Calls <a href="#calls" class="anchor"></a>
|
||||
|
||||
|
||||
</h2>
|
||||
|
||||
<p>Delta Chat supports one-to-one <strong>audio calls</strong> and <strong>video calls</strong>.</p>
|
||||
|
||||
<p>Calls are supported on Desktop, Ubuntu Touch, iOS and Android 8 and newer.</p>
|
||||
|
||||
<h3 id="place-a-call">
|
||||
|
||||
|
||||
Place a call <a href="#place-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>In a one-to-one chat, tap the 📞 <strong>call icon</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>This opens a small menu
|
||||
where you can choose whether to place an <strong>Audio Call</strong> or a <strong>Video Call</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="accept-or-reject-a-call">
|
||||
|
||||
|
||||
Accept or reject a call <a href="#accept-or-reject-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>When someone calls you,
|
||||
Delta Chat shows an <strong>incoming call screen</strong> or notification.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Tap <strong>Accept</strong> to answer
|
||||
or <strong>Decline</strong> to reject the call.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="during-a-call">
|
||||
|
||||
|
||||
During a call <a href="#during-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>You can <strong>mute</strong> your microphone.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>You can <strong>enable or disable your camera</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>On mobile, you can <strong>switch between front and back cameras</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Depending on the device, you can also select the audio output or use picture-in-picture.
|
||||
On desktop, the call is using a dedicated window
|
||||
and you can continue using the main Delta Chat window as usual.</p>
|
||||
|
||||
<h3 id="missed-calls-and-notifications">
|
||||
|
||||
|
||||
Missed calls and notifications <a href="#missed-calls-and-notifications" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>If you do not answer, do not hear the ringing, or do not have your device at hand,
|
||||
the call appears as a <strong>missed call</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Only your accepted contacts</strong> can make your device ring.
|
||||
Contact requests will appear as usual and will not ring.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>At <strong>Settings → Notifications → Calls</strong>,
|
||||
you can disable the special call ringing screen completely.
|
||||
If you do so, you will not be disturbed by any ringing notification,
|
||||
you can still pick up the call by tapping the incoming call message bubble in its chat.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="webxdc">
|
||||
|
||||
|
||||
@@ -1425,23 +1631,20 @@ can not be identified easily.</p>
|
||||
|
||||
</h3>
|
||||
|
||||
<p>The used <a href="#relays">relay</a> needs to know your IP Address,
|
||||
as well as sometimes your contact’s devices if you have a <a href="#experiments">call</a>
|
||||
<p>The used <a href="#relays">relays</a> need to know your IP Address,
|
||||
as well as sometimes your contact’s devices if you have a <a href="#calls">call</a>
|
||||
or use <a href="#webxdc">apps</a> together.</p>
|
||||
|
||||
<p>IP Addresses are needed for connectivity and efficiency.
|
||||
They are neither persisted nor exposed.
|
||||
Note that the IP Address
|
||||
is not like a detailed address you give to a delivery service,
|
||||
but much more coarse, often defining region or country only.</p>
|
||||
Delta Chat neither persists nor exposes them.
|
||||
Note that IP Addresses
|
||||
are not like an address you give to a delivery service,
|
||||
but typically less precise, often defining city or region only.</p>
|
||||
|
||||
<p>As this is just how the internet and other messengers work by default,
|
||||
we do not offer options here or ask upfront questions.</p>
|
||||
|
||||
<p>If you see your IP Address as a security or privacy risk,
|
||||
we recommend to use a VPN, in combination with system lockdown mode.
|
||||
Hunting down options in all apps on your system will leave gaps.
|
||||
For example, tapping a link exposes IP Addresses to unknown parties and is the by far larger risk here.</p>
|
||||
<p>If you see your IP Address as a risk,
|
||||
we recommend to use a VPN for the whole system.
|
||||
Per-app options leave gaps across your system.
|
||||
For example, tapping a link can expose IP Addresses to unknown parties, which is by far the larger risk.</p>
|
||||
|
||||
<h3 id="sealedsender">
|
||||
|
||||
|
||||
@@ -29,6 +29,21 @@
|
||||
<li><a href="#wie-viele-mitglieder-können-in-einer-einzelnen-gruppe-sein">Wie viele Mitglieder können in einer einzelnen Gruppe sein?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#channels">Kanäle</a>
|
||||
<ul>
|
||||
<li><a href="#einem-kanal-beitreten">Einem Kanal beitreten</a></li>
|
||||
<li><a href="#einen-kanal-erstellen">Einen Kanal erstellen</a></li>
|
||||
<li><a href="#wie-viele-empfänger-kann-ein-kanal-haben">Wie viele Empfänger kann ein Kanal haben?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#calls">Anrufe</a>
|
||||
<ul>
|
||||
<li><a href="#jemanden-anrufen">Jemanden anrufen</a></li>
|
||||
<li><a href="#einen-anruf-annehmen-oder-ablehnen">Einen Anruf annehmen oder ablehnen</a></li>
|
||||
<li><a href="#während-des-anrufs">Während des Anrufs</a></li>
|
||||
<li><a href="#verpasste-anrufe-und-benachrichtigungen">Verpasste Anrufe und Benachrichtigungen</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#webxdc">In-Chat-Apps</a>
|
||||
<ul>
|
||||
<li><a href="#wo-bekomme-ich-in-chat-apps">Wo bekomme ich In-Chat-Apps?</a></li>
|
||||
@@ -584,6 +599,197 @@ aber mehr als 150 sind nicht empfohlen.</p>
|
||||
|
||||
<p>Wenn Gruppen größer werden, können sie sozial instabil werden und benötigen möglicherweise eine Hierarchie - und Delta Chat ist ein privater Messenger für Chats mit <a href="#groups">gleichen Rechten</a>. Vgl. <a href="https://de.wikipedia.org/wiki/Dunbar-Zahl">Dunbar-Zahl</a>.</p>
|
||||
|
||||
<h2 id="channels">
|
||||
|
||||
|
||||
Kanäle <a href="#channels" class="anchor"></a>
|
||||
|
||||
|
||||
</h2>
|
||||
|
||||
<p>Kanäle dienen der Verbreitung von Nachrichten an viele Empfänger.</p>
|
||||
|
||||
<h3 id="einem-kanal-beitreten">
|
||||
|
||||
|
||||
Einem Kanal beitreten <a href="#einem-kanal-beitreten" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>Scan the <img style="vertical-align:middle; height:1.3em; margin:1px" src="../qr-icon.png" /> <strong>QR code</strong>
|
||||
or tap the <strong>invite link</strong> you got from the channel owner.</li>
|
||||
</ul>
|
||||
|
||||
<p>That’s all!
|
||||
You will receive a few of the messages from the channel history
|
||||
and, from that point on, all new messages from the channel.</p>
|
||||
|
||||
<p><strong>Don’t worry,</strong> if that does not happen immediately.
|
||||
Once the channel owner comes online, your join request will be processed.</p>
|
||||
|
||||
<p>As all of Delta Chat, also Channels are private and decentralized,
|
||||
there is no public discovery.</p>
|
||||
|
||||
<p>Other channel subscribers will not see that you subscribed and cannot message you.
|
||||
The channel owner, however, can message you.
|
||||
They will also see that you read a message unless you have read receipts disabled.</p>
|
||||
|
||||
<p>If you do not want to share your main profile,
|
||||
you can also create a <a href="#multiple-accounts">dedicated profile</a> for joining a channel.</p>
|
||||
|
||||
<h3 id="einen-kanal-erstellen">
|
||||
|
||||
|
||||
Einen Kanal erstellen <a href="#einen-kanal-erstellen" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>Tap <strong>New Chat</strong> and choose <strong>New Channel</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Enter a <strong>name</strong>, optionally set an <strong>image</strong> and <strong>description</strong>, and hit the <strong>Create</strong> button.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>You can now send and manage messages as usual.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>From the channel’s profile, <strong>share the QR code or invite link with others</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Subscribers will receive your messages,
|
||||
but they cannot send messages in your channel.
|
||||
When subscribing, they will receive <strong>a few of the latest messages of the channel history</strong>.</p>
|
||||
|
||||
<p>You can see the <strong>view count</strong> beside each message.
|
||||
Note that this only counts subscribers who have read receipts enabled,
|
||||
so the real view count may be larger.</p>
|
||||
|
||||
<h3 id="wie-viele-empfänger-kann-ein-kanal-haben">
|
||||
|
||||
|
||||
Wie viele Empfänger kann ein Kanal haben? <a href="#wie-viele-empfänger-kann-ein-kanal-haben" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Channels are designed for much larger audiences than <a href="#groups">groups</a>.</p>
|
||||
|
||||
<p>The practical limit depends on the used <a href="#relays">relay</a>,
|
||||
so there is no single fixed number that applies everywhere.</p>
|
||||
|
||||
<p>For really large channels with several tens of thousands of subscribers,
|
||||
we recommend using a <a href="#multiple-accounts">dedicated profile</a> for the channel
|
||||
and checking whether the relay is suitable.</p>
|
||||
|
||||
<p>But don’t be too hesitant: Delta Chat is designed to be relay-agnostic,
|
||||
so you can change your relay at any point easily -
|
||||
your existing subscribers will not even notice.
|
||||
You only have to update the invite link you share with new subscribers in that case.</p>
|
||||
|
||||
<h2 id="calls">
|
||||
|
||||
|
||||
Anrufe <a href="#calls" class="anchor"></a>
|
||||
|
||||
|
||||
</h2>
|
||||
|
||||
<p>Delta Chat supports one-to-one <strong>audio calls</strong> and <strong>video calls</strong>.</p>
|
||||
|
||||
<p>Calls are supported on Desktop, Ubuntu Touch, iOS and Android 8 and newer.</p>
|
||||
|
||||
<h3 id="jemanden-anrufen">
|
||||
|
||||
|
||||
Jemanden anrufen <a href="#jemanden-anrufen" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>In a one-to-one chat, tap the 📞 <strong>call icon</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>This opens a small menu
|
||||
where you can choose whether to place an <strong>Audio Call</strong> or a <strong>Video Call</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="einen-anruf-annehmen-oder-ablehnen">
|
||||
|
||||
|
||||
Einen Anruf annehmen oder ablehnen <a href="#einen-anruf-annehmen-oder-ablehnen" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>When someone calls you,
|
||||
Delta Chat shows an <strong>incoming call screen</strong> or notification.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Tap <strong>Accept</strong> to answer
|
||||
or <strong>Decline</strong> to reject the call.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="während-des-anrufs">
|
||||
|
||||
|
||||
Während des Anrufs <a href="#während-des-anrufs" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>You can <strong>mute</strong> your microphone.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>You can <strong>enable or disable your camera</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>On mobile, you can <strong>switch between front and back cameras</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Depending on the device, you can also select the audio output or use picture-in-picture.
|
||||
On desktop, the call is using a dedicated window
|
||||
and you can continue using the main Delta Chat window as usual.</p>
|
||||
|
||||
<h3 id="verpasste-anrufe-und-benachrichtigungen">
|
||||
|
||||
|
||||
Verpasste Anrufe und Benachrichtigungen <a href="#verpasste-anrufe-und-benachrichtigungen" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>If you do not answer, do not hear the ringing, or do not have your device at hand,
|
||||
the call appears as a <strong>missed call</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Only your accepted contacts</strong> can make your device ring.
|
||||
Contact requests will appear as usual and will not ring.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>At <strong>Settings → Notifications → Calls</strong>,
|
||||
you can disable the special call ringing screen completely.
|
||||
If you do so, you will not be disturbed by any ringing notification,
|
||||
you can still pick up the call by tapping the incoming call message bubble in its chat.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="webxdc">
|
||||
|
||||
|
||||
@@ -1329,23 +1535,16 @@ im Falle einer Beschlagnahmung des Geräts nicht ohne Weiteres identifiziert wer
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Das verwendete <a href="#relays">Relay</a> muss Ihre IP-Adresse kennen,
|
||||
sowie manchmal auch die Geräte Ihrer Kontakte, wenn Sie einen <a href="#experiments">Anruf</a> tätigen
|
||||
oder gemeinsam <a href="#webxdc">Apps</a> verwenden.</p>
|
||||
<p>Die verwendeten <a href="#relays">Relays</a> müssen deine IP-Adresse kennen,
|
||||
sowie manchmal auch die Geräte deiner Kontakte, wenn du einen <a href="#calls">Anruf</a> tätigst
|
||||
oder ihr gemeinsam <a href="#webxdc">Apps</a> verwendet.</p>
|
||||
|
||||
<p>IP-Adressen sind für Verbindungen und für Effizienz erforderlich.
|
||||
Sie werden weder gespeichert noch offengelegt.
|
||||
Beachten Sie, dass die IP-Adresse
|
||||
nicht mit einer Adresse, die Sie einem Lieferdienst geben, vergleichbar ist -
|
||||
sondern viel gröber ist und oft nur die Region oder das Land angibt.</p>
|
||||
Sie werden von Delta Chat weder gespeichert noch offengelegt.
|
||||
IP-Adressen sind nicht mit einer Adresse, die du einem Lieferdienst gibst, vergleichbar - sondern viel gröber und oft nur die Stadt oder die Region beschreibend.</p>
|
||||
|
||||
<p>Da dies die Standardfunktion des Internets und anderer Messenger ist,
|
||||
bieten wir hier keine Optionen an und stellen auch keine Fragen im Voraus.</p>
|
||||
|
||||
<p>Wenn Sie Ihre IP-Adresse als Sicherheits- oder Datenschutzrisiko betrachten,
|
||||
empfehlen wir Ihnen, ein VPN in Kombination mit dem System-Lockdown-Modus zu verwenden.
|
||||
Alle einzelnen Apps auf Ihrem System nach IP-Optionen abzusuchen wird nicht zufriedenstellen sein;
|
||||
beispielsweise legt das Antippen eines Links IP-Adressen gegenüber unbekannten Parteien offen und stellt hier das weitaus größere Risiko dar.</p>
|
||||
<p>Wenn du deine IP-Adresse als Risiko betrachtest, empfehlen wir, ein VPN für das gesamte System zu verwenden.
|
||||
Einstellungen auf App-Ebene hinterlassen Lücken überall im System. Wenn man beispielsweise auf einen Link tippt, können IP-Adressen an Unbekannte weitergegeben werden, was bei weitem das größere Risiko darstellt</p>
|
||||
|
||||
<h3 id="sealedsender">
|
||||
|
||||
|
||||
@@ -29,6 +29,21 @@
|
||||
<li><a href="#how-many-members-can-participate-in-a-single-group">How many members can participate in a single group?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#channels">Channels</a>
|
||||
<ul>
|
||||
<li><a href="#subscribe-to-a-channel">Subscribe to a channel</a></li>
|
||||
<li><a href="#create-a-channel">Create a channel</a></li>
|
||||
<li><a href="#how-many-subscribers-can-a-channel-have">How many subscribers can a channel have?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#calls">Calls</a>
|
||||
<ul>
|
||||
<li><a href="#place-a-call">Place a call</a></li>
|
||||
<li><a href="#accept-or-reject-a-call">Accept or reject a call</a></li>
|
||||
<li><a href="#during-a-call">During a call</a></li>
|
||||
<li><a href="#missed-calls-and-notifications">Missed calls and notifications</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#webxdc">In-chat apps</a>
|
||||
<ul>
|
||||
<li><a href="#where-can-i-get-in-chat-apps">Where can I get in-chat apps?</a></li>
|
||||
@@ -627,6 +642,197 @@ but more than 150 is not recommended.</p>
|
||||
where Delta Chat is a private messenger for chatting with <a href="#groups">equal rights</a>.
|
||||
See <a href="https://en.wikipedia.org/wiki/Dunbar%27s_number">Dunbar’s number</a> for more insights.</p>
|
||||
|
||||
<h2 id="channels">
|
||||
|
||||
|
||||
Channels <a href="#channels" class="anchor"></a>
|
||||
|
||||
|
||||
</h2>
|
||||
|
||||
<p>Channels are a one-to-many tool for broadcasting messages.</p>
|
||||
|
||||
<h3 id="subscribe-to-a-channel">
|
||||
|
||||
|
||||
Subscribe to a channel <a href="#subscribe-to-a-channel" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>Scan the <img style="vertical-align:middle; height:1.3em; margin:1px" src="../qr-icon.png" /> <strong>QR code</strong>
|
||||
or tap the <strong>invite link</strong> you got from the channel owner.</li>
|
||||
</ul>
|
||||
|
||||
<p>That’s all!
|
||||
You will receive a few of the messages from the channel history
|
||||
and, from that point on, all new messages from the channel.</p>
|
||||
|
||||
<p><strong>Don’t worry,</strong> if that does not happen immediately.
|
||||
Once the channel owner comes online, your join request will be processed.</p>
|
||||
|
||||
<p>As all of Delta Chat, also Channels are private and decentralized,
|
||||
there is no public discovery.</p>
|
||||
|
||||
<p>Other channel subscribers will not see that you subscribed and cannot message you.
|
||||
The channel owner, however, can message you.
|
||||
They will also see that you read a message unless you have read receipts disabled.</p>
|
||||
|
||||
<p>If you do not want to share your main profile,
|
||||
you can also create a <a href="#multiple-accounts">dedicated profile</a> for joining a channel.</p>
|
||||
|
||||
<h3 id="create-a-channel">
|
||||
|
||||
|
||||
Create a channel <a href="#create-a-channel" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>Tap <strong>New Chat</strong> and choose <strong>New Channel</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Enter a <strong>name</strong>, optionally set an <strong>image</strong> and <strong>description</strong>, and hit the <strong>Create</strong> button.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>You can now send and manage messages as usual.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>From the channel’s profile, <strong>share the QR code or invite link with others</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Subscribers will receive your messages,
|
||||
but they cannot send messages in your channel.
|
||||
When subscribing, they will receive <strong>a few of the latest messages of the channel history</strong>.</p>
|
||||
|
||||
<p>You can see the <strong>view count</strong> beside each message.
|
||||
Note that this only counts subscribers who have read receipts enabled,
|
||||
so the real view count may be larger.</p>
|
||||
|
||||
<h3 id="how-many-subscribers-can-a-channel-have">
|
||||
|
||||
|
||||
How many subscribers can a channel have? <a href="#how-many-subscribers-can-a-channel-have" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Channels are designed for much larger audiences than <a href="#groups">groups</a>.</p>
|
||||
|
||||
<p>The practical limit depends on the used <a href="#relays">relay</a>,
|
||||
so there is no single fixed number that applies everywhere.</p>
|
||||
|
||||
<p>For really large channels with several tens of thousands of subscribers,
|
||||
we recommend using a <a href="#multiple-accounts">dedicated profile</a> for the channel
|
||||
and checking whether the relay is suitable.</p>
|
||||
|
||||
<p>But don’t be too hesitant: Delta Chat is designed to be relay-agnostic,
|
||||
so you can change your relay at any point easily -
|
||||
your existing subscribers will not even notice.
|
||||
You only have to update the invite link you share with new subscribers in that case.</p>
|
||||
|
||||
<h2 id="calls">
|
||||
|
||||
|
||||
Calls <a href="#calls" class="anchor"></a>
|
||||
|
||||
|
||||
</h2>
|
||||
|
||||
<p>Delta Chat supports one-to-one <strong>audio calls</strong> and <strong>video calls</strong>.</p>
|
||||
|
||||
<p>Calls are supported on Desktop, Ubuntu Touch, iOS and Android 8 and newer.</p>
|
||||
|
||||
<h3 id="place-a-call">
|
||||
|
||||
|
||||
Place a call <a href="#place-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>In a one-to-one chat, tap the 📞 <strong>call icon</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>This opens a small menu
|
||||
where you can choose whether to place an <strong>Audio Call</strong> or a <strong>Video Call</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="accept-or-reject-a-call">
|
||||
|
||||
|
||||
Accept or reject a call <a href="#accept-or-reject-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>When someone calls you,
|
||||
Delta Chat shows an <strong>incoming call screen</strong> or notification.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Tap <strong>Accept</strong> to answer
|
||||
or <strong>Decline</strong> to reject the call.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="during-a-call">
|
||||
|
||||
|
||||
During a call <a href="#during-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>You can <strong>mute</strong> your microphone.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>You can <strong>enable or disable your camera</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>On mobile, you can <strong>switch between front and back cameras</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Depending on the device, you can also select the audio output or use picture-in-picture.
|
||||
On desktop, the call is using a dedicated window
|
||||
and you can continue using the main Delta Chat window as usual.</p>
|
||||
|
||||
<h3 id="missed-calls-and-notifications">
|
||||
|
||||
|
||||
Missed calls and notifications <a href="#missed-calls-and-notifications" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>If you do not answer, do not hear the ringing, or do not have your device at hand,
|
||||
the call appears as a <strong>missed call</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Only your accepted contacts</strong> can make your device ring.
|
||||
Contact requests will appear as usual and will not ring.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>At <strong>Settings → Notifications → Calls</strong>,
|
||||
you can disable the special call ringing screen completely.
|
||||
If you do so, you will not be disturbed by any ringing notification,
|
||||
you can still pick up the call by tapping the incoming call message bubble in its chat.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="webxdc">
|
||||
|
||||
|
||||
@@ -1425,23 +1631,20 @@ can not be identified easily.</p>
|
||||
|
||||
</h3>
|
||||
|
||||
<p>The used <a href="#relays">relay</a> needs to know your IP Address,
|
||||
as well as sometimes your contact’s devices if you have a <a href="#experiments">call</a>
|
||||
<p>The used <a href="#relays">relays</a> need to know your IP Address,
|
||||
as well as sometimes your contact’s devices if you have a <a href="#calls">call</a>
|
||||
or use <a href="#webxdc">apps</a> together.</p>
|
||||
|
||||
<p>IP Addresses are needed for connectivity and efficiency.
|
||||
They are neither persisted nor exposed.
|
||||
Note that the IP Address
|
||||
is not like a detailed address you give to a delivery service,
|
||||
but much more coarse, often defining region or country only.</p>
|
||||
Delta Chat neither persists nor exposes them.
|
||||
Note that IP Addresses
|
||||
are not like an address you give to a delivery service,
|
||||
but typically less precise, often defining city or region only.</p>
|
||||
|
||||
<p>As this is just how the internet and other messengers work by default,
|
||||
we do not offer options here or ask upfront questions.</p>
|
||||
|
||||
<p>If you see your IP Address as a security or privacy risk,
|
||||
we recommend to use a VPN, in combination with system lockdown mode.
|
||||
Hunting down options in all apps on your system will leave gaps.
|
||||
For example, tapping a link exposes IP Addresses to unknown parties and is the by far larger risk here.</p>
|
||||
<p>If you see your IP Address as a risk,
|
||||
we recommend to use a VPN for the whole system.
|
||||
Per-app options leave gaps across your system.
|
||||
For example, tapping a link can expose IP Addresses to unknown parties, which is by far the larger risk.</p>
|
||||
|
||||
<h3 id="sealedsender">
|
||||
|
||||
|
||||
+377
-176
@@ -2,38 +2,53 @@
|
||||
<html lang="es"><head><meta charset="UTF-8" /><meta name="viewport" content="initial-scale=1.0" /><link rel="stylesheet" href="../help.css" /></head><body><ul id="top">
|
||||
<li><a href="#qué-es-delta-chat">¿Qué es Delta Chat?</a>
|
||||
<ul>
|
||||
<li><a href="#howtoe2ee">How can I find people to chat with?</a></li>
|
||||
<li><a href="#why-is-a-chat-marked-as-request">Why is a chat marked as “Request”?</a></li>
|
||||
<li><a href="#how-can-i-put-two-of-my-friends-in-contact-with-each-other">How can I put two of my friends in contact with each other?</a></li>
|
||||
<li><a href="#howtoe2ee">¿Cómo puedo encontrar gente para chatear?</a></li>
|
||||
<li><a href="#por-qué-un-chat-aparece-marcado-como-solicitud">¿Por qué un chat aparece marcado como “Solicitud”?</a></li>
|
||||
<li><a href="#cómo-puedo-poner-en-contacto-a-dos-de-mis-amigos-entre-ellos">¿Cómo puedo poner en contacto a dos de mis amigos entre ellos?</a></li>
|
||||
<li><a href="#multiple-accounts">¿Qué son los perfiles? ¿Cómo puedo cambiar entre ellos?</a></li>
|
||||
<li><a href="#quién-ve-mi-foto-de-perfil">¿Quién ve mi foto de perfil?</a></li>
|
||||
<li><a href="#signature">Can I set a Bio/Status with Delta Chat?</a></li>
|
||||
<li><a href="#signature">¿Puedo establecer una Bio/Estado en Delta Chat?</a></li>
|
||||
<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="#qué-significan-las-marcas-que-se-muestran-junto-a-los-mensajes-salientes">¿Qué significan las marcas que se muestran junto a los mensajes salientes?</a></li>
|
||||
<li><a href="#edit">Corregir errores y borrar mensajes después de enviar</a></li>
|
||||
<li><a href="#mediaquality">How is media quality handled?</a></li>
|
||||
<li><a href="#mediaquality">¿Cómo se gestiona la calidad de los archivos multimedia?</a></li>
|
||||
<li><a href="#ephemeralmsgs">¿Cómo funciona la desaparición de mensajes?</a></li>
|
||||
<li><a href="#delold">¿Qué pasa si activo “Borrar mensajes del dispositivo”?</a></li>
|
||||
<li><a href="#remove-account">How can I delete my chat profile?</a></li>
|
||||
<li><a href="#remove-account">¿Cómo puedo borrar mi perfil?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#groups">Groups</a>
|
||||
<li><a href="#groups">Grupos</a>
|
||||
<ul>
|
||||
<li><a href="#creación-de-un-grupo">Creación de un grupo</a></li>
|
||||
<li><a href="#addmembers">Add and remove members</a></li>
|
||||
<li><a href="#addmembers">Añadir y eliminar miembros</a></li>
|
||||
<li><a href="#me-he-eliminado-por-accidente">Me he eliminado por accidente.</a></li>
|
||||
<li><a href="#no-quiero-recibir-más-los-mensajes-de-un-grupo">No quiero recibir más los mensajes de un grupo.</a></li>
|
||||
<li><a href="#cloning-a-group">Cloning a group</a></li>
|
||||
<li><a href="#how-many-members-can-participate-in-a-single-group">How many members can participate in a single group?</a></li>
|
||||
<li><a href="#clonar-un-grupo">Clonar un grupo</a></li>
|
||||
<li><a href="#cuántos-miembros-pueden-participar-en-un-solo-grupo">¿Cuántos miembros pueden participar en un solo grupo?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#webxdc">In-chat apps</a>
|
||||
<li><a href="#channels">Channels</a>
|
||||
<ul>
|
||||
<li><a href="#where-can-i-get-in-chat-apps">Where can I get in-chat apps?</a></li>
|
||||
<li><a href="#how-private-are-in-chat-apps">How private are in-chat apps?</a></li>
|
||||
<li><a href="#create-xdc">How can I create my own in-chat apps?</a></li>
|
||||
<li><a href="#subscribe-to-a-channel">Subscribe to a channel</a></li>
|
||||
<li><a href="#create-a-channel">Create a channel</a></li>
|
||||
<li><a href="#how-many-subscribers-can-a-channel-have">How many subscribers can a channel have?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#calls">Calls</a>
|
||||
<ul>
|
||||
<li><a href="#place-a-call">Place a call</a></li>
|
||||
<li><a href="#accept-or-reject-a-call">Accept or reject a call</a></li>
|
||||
<li><a href="#during-a-call">During a call</a></li>
|
||||
<li><a href="#missed-calls-and-notifications">Missed calls and notifications</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#webxdc">Aplicaciones en chats</a>
|
||||
<ul>
|
||||
<li><a href="#dónde-puedo-conseguir-aplicaciones-para-el-chat">¿Dónde puedo conseguir aplicaciones para el chat?</a></li>
|
||||
<li><a href="#cómo-de-privadas-son-las-aplicaciones-en-el-chat">¿Cómo de privadas son las aplicaciones en el chat?</a></li>
|
||||
<li><a href="#create-xdc">¿Cómo puedo crear mis propias aplicaciones para el chat?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#instant-delivery">Entrega de mensajes instantáneos y notificaciones Push</a>
|
||||
@@ -57,7 +72,7 @@
|
||||
<ul>
|
||||
<li><a href="#experiments">Experimental Features</a></li>
|
||||
<li><a href="#relays">What are Relays?</a></li>
|
||||
<li><a href="#can-i-use-a-classic-email-address-with-delta-chat">Can I use a classic email address with Delta Chat?</a></li>
|
||||
<li><a href="#puedo-utilizar-una-dirección-de-email-clásico-con-delta-chat">¿Puedo utilizar una dirección de email clásico con Delta Chat?</a></li>
|
||||
<li><a href="#classic-email">How can I configure a chat profile with a classic email address as relay?</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="#statssending">What is “Send statistics to Delta Chat’s developers”?</a></li>
|
||||
@@ -67,8 +82,8 @@
|
||||
<li><a href="#e2ee">Cifrado y seguridad</a>
|
||||
<ul>
|
||||
<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">How can I know if messages are end-to-end encrypted?</a></li>
|
||||
<li><a href="#can-i-still-receive-or-send-messages-without-end-to-end-encryption">Can I still receive or send messages without end-to-end encryption?</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="#puedo-enviar-o-recibir-mensajes-sin-cifrado-de-extremo-a-extremo">¿Puedo enviar o recibir mensajes sin cifrado de extremo a extremo?</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>
|
||||
@@ -77,11 +92,11 @@
|
||||
<li><a href="#tls">Are messages marked with the mail icon exposed on the Internet?</a></li>
|
||||
<li><a href="#message-metadata">¿Cómo Delta Chat protege los metadatos en los mensajes?</a></li>
|
||||
<li><a href="#device-seizure">¿Cómo proteger los metadatos y los contactos cuando se incauta un dispositivo?</a></li>
|
||||
<li><a href="#who-sees-my-ip-address">Who sees my IP Address?</a></li>
|
||||
<li><a href="#sealedsender">Does Delta Chat support “Sealed Sender”?</a></li>
|
||||
<li><a href="#quién-puede-ver-mi-dirección-ip">¿Quién puede ver mi dirección IP?</a></li>
|
||||
<li><a href="#sealedsender">¿Soporta Delta Chat “Sealed Sender”?</a></li>
|
||||
<li><a href="#pfs">¿Soporta Delta Chat 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">¿Soporta Delta Chat criptografía postcuántica?</a></li>
|
||||
<li><a href="#cómo-puedo-comprobar-manualmente-la-información-de-cifrado">¿Cómo puedo comprobar manualmente la información de cifrado?</a></li>
|
||||
<li><a href="#importkey">¿Puedo reutilizar mi clave privada existente?</a></li>
|
||||
<li><a href="#security-audits">¿Se auditó Delta Chat de forma independiente en busca de vulnerabilidades de seguridad?</a></li>
|
||||
</ul>
|
||||
@@ -89,7 +104,7 @@
|
||||
<li><a href="#miscelaneo">Miscelaneo</a>
|
||||
<ul>
|
||||
<li><a href="#qué-permisos-necesita-delta-chat">¿Qué permisos necesita Delta Chat?</a></li>
|
||||
<li><a href="#where-can-my-friends-find-delta-chat">Where can my friends find Delta Chat?</a></li>
|
||||
<li><a href="#dónde-pueden-encontrar-mis-amigos-delta-chat">¿Dónde pueden encontrar mis amigos Delta Chat?</a></li>
|
||||
<li><a href="#cómo-se-financia-el-desarrollo-de-delta-chat">¿Cómo se financia el desarrollo de Delta Chat?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
@@ -109,85 +124,85 @@
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>Instant creation of <strong>private chat profiles</strong>
|
||||
with secure and interoperable <a href="https://chatmail.at/relays">chatmail relays</a>
|
||||
that offer instant message delivery, and Push Notifications for iOS and Android devices.</p>
|
||||
<p>Creación instantánea de <strong>perfiles de chat privados</strong>
|
||||
con <a href="https://chatmail.at/relays">servidores de chatmail</a> seguros e interoperables
|
||||
que ofrecen un envío instantáneo de mensajes y Notificaciones Push en dispositivos Android e iOS.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Pervasive <a href="#multiple-accounts">multi-profile</a> and
|
||||
<a href="#multiclient">multi-device</a> support on all platforms
|
||||
and between different <a href="https://chatmail.at/clients">chatmail apps</a>.</p>
|
||||
<p>Soporte generalizado <a href="#multiple-accounts">multiperfil</a> y
|
||||
soporte <a href="#multiclient">multidispositivo</a> en todas las plataformas
|
||||
y entre diferentes <a href="https://chatmail.at/clients">aplicaciones de chatmail</a>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Interactive <a href="#webxdc">in-chat apps</a> for gaming and collaboration</p>
|
||||
<p>Aplicaciones interactivas <a href="#webxdc">en el chat</a> para juegos y colaboración</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="#security-audits">Audited end-to-end encryption</a>
|
||||
safe against network and server attacks.</p>
|
||||
<p><a href="#security-audits">Cifrado de extremo a extremo auditado</a>
|
||||
seguro contra ataques a la red y al servidor.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Free and Open Source software, both app and server side,
|
||||
built on <a href="https://github.com/chatmail/core/blob/main/standards.md#standards-used-in-delta-chat">Internet Standards</a>.</p>
|
||||
<p>Software gratuito y de código abierto, tanto las aplicaciones como los servidores,
|
||||
construido sobre <a href="https://github.com/chatmail/core/blob/main/standards.md#standards-used-in-delta-chat">estándares de internet</a>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="howtoe2ee">
|
||||
|
||||
|
||||
How can I find people to chat with? <a href="#howtoe2ee" class="anchor"></a>
|
||||
¿Cómo puedo encontrar gente para chatear? <a href="#howtoe2ee" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>First, note that Delta Chat is a private messenger.
|
||||
There is no public discovery, <em>you</em> decide about your contacts.</p>
|
||||
<p>En primer lugar, ten en cuenta que Delta Chat es un sistema de mensajería privado.
|
||||
No hay descubrimiento público, <em>tú</em> decides sobre tus contactos.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>If you are <strong>face to face</strong> with your friend or family,
|
||||
tap the <strong>QR Code</strong> icon <img style="vertical-align:middle; height:1.3em; margin:1px" src="../qr-icon.png" />
|
||||
on the main screen.<br />
|
||||
Ask your chat partner to <strong>scan</strong> the QR image
|
||||
with their Delta Chat app.</p>
|
||||
<p>Si estas <strong>cara a cara</strong> con tus amigos o familia,
|
||||
pulsa el icono del <strong>Código QR</strong> <img style="vertical-align:middle; height:1.3em; margin:1px" src="../qr-icon.png" />
|
||||
en la pantalla principal.
|
||||
Pídele a la otra persona que <strong>escanee</strong> el código QR
|
||||
con su aplicación de Delta Chat.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>For a <strong>remote</strong> contact setup,
|
||||
from the same screen,
|
||||
click “Copy” or “Share” and send the <strong>invite link</strong>
|
||||
through another private chat.</p>
|
||||
<p>Para configurar un contacto <strong>a distancia</strong>,
|
||||
desde la misma pantalla,
|
||||
haga clic en “Copiar” o “Compartir” y envíe el <strong>enlace de invitación</strong>
|
||||
a través de otro chat privado.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Now wait while connection gets established.</p>
|
||||
<p>Espera mientras la conexión se establece.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>If both sides are online, they will soon see a chat
|
||||
and can start messaging securely.</p>
|
||||
<p>Si ambas partes están en línea, pronto verán un chat
|
||||
y podrán empezar a mensajearse de forma segura.</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>Si una de las partes no está conectada o tiene una mala conexión,
|
||||
la capacidad de chatear se retrasará hasta que la conectividad se haya restaurado.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Congratulations!
|
||||
You now will automatically use <a href="#e2ee">end-to-end encryption</a> with this contact.
|
||||
If you add each other to <a href="#groups">groups</a>, end-to-end encryption will be established among all members.</p>
|
||||
<p>¡Enhorabuena!
|
||||
Ahora estás utilizando automáticamente el <a href="#e2ee">cifrado de extremo a extremo</a> con este contacto.
|
||||
Si os añadís mutuamente a <a href="#groups">grupos</a>, el cifrado de extremo a extremo se establecerá entre todos los miembros.</p>
|
||||
|
||||
<h3 id="why-is-a-chat-marked-as-request">
|
||||
<h3 id="por-qué-un-chat-aparece-marcado-como-solicitud">
|
||||
|
||||
|
||||
Why is a chat marked as “Request”? <a href="#why-is-a-chat-marked-as-request" class="anchor"></a>
|
||||
¿Por qué un chat aparece marcado como “Solicitud”? <a href="#por-qué-un-chat-aparece-marcado-como-solicitud" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>As being a private messenger,
|
||||
only friends and family you <a href="#howtoe2ee">share your QR code or invite link with</a> can write to you.</p>
|
||||
<p>Al ser un sistema de mensajería privada
|
||||
solo los amigos y familiares con los que <a href="#howtoe2ee">compartas tu código QR o enlace de invitación</a> pueden escribirte.</p>
|
||||
|
||||
<p>Your friends may share your contact with other friends,
|
||||
this appears as <b style="border: 1px solid currentColor; padding: 0 3px; font-size:90%">Request</b></p>
|
||||
<p>Tus amigos pueden compartir tu contacto con otros amigos,
|
||||
esto aparecerá como <b style="border: 1px solid currentColor; padding: 0 3px; font-size:90%">Solicitud</b></p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
@@ -201,10 +216,10 @@ this appears as <b style="border: 1px solid currentColor; padding: 0 3px; font-s
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="how-can-i-put-two-of-my-friends-in-contact-with-each-other">
|
||||
<h3 id="cómo-puedo-poner-en-contacto-a-dos-de-mis-amigos-entre-ellos">
|
||||
|
||||
|
||||
How can I put two of my friends in contact with each other? <a href="#how-can-i-put-two-of-my-friends-in-contact-with-each-other" class="anchor"></a>
|
||||
¿Cómo puedo poner en contacto a dos de mis amigos entre ellos? <a href="#cómo-puedo-poner-en-contacto-a-dos-de-mis-amigos-entre-ellos" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
@@ -223,16 +238,16 @@ and can tap it to start chatting with the first contact.</p>
|
||||
|
||||
</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 the server only to relay messages.</p>
|
||||
<p>Un perfil es <strong>un nombre, una foto</strong> y alguna información adicional para cifrar los mensajes.
|
||||
Un perfil se almacena únicamente en tu dispositivo (o dispositivos)
|
||||
y solo utiliza el servidor para enviar 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.</p>
|
||||
<p>Puede utilizar perfiles diferentes para actividades políticas, familiares o laborales.</p>
|
||||
|
||||
<p>Quizás quieres aprender <a href="#multiclient">cómo se usa el mismo perfil en múltiples dispositivos</a>.</p>
|
||||
|
||||
@@ -252,15 +267,15 @@ o los agrega a través de un código QR, ellos lo verán automáticamente como s
|
||||
<h3 id="signature">
|
||||
|
||||
|
||||
Can I set a Bio/Status with Delta Chat? <a href="#signature" class="anchor"></a>
|
||||
¿Puedo establecer una Bio/Estado en Delta Chat? <a href="#signature" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Yes,
|
||||
you can do so under <strong>Settings → Profile → Bio</strong>.
|
||||
Once you sent a message to a contact,
|
||||
they will see it when they view your contact details.</p>
|
||||
<p>Sí,
|
||||
es posible hacerlo en <strong>Ajustes → Perfil → Texto de firma</strong>.
|
||||
Una vez que hayas enviado un mensaje a un contacto,
|
||||
este lo verá cuando consulte tus datos de contacto.</p>
|
||||
|
||||
<h3 id="qué-significa-fijar-mutear-archivar">
|
||||
|
||||
@@ -280,7 +295,7 @@ they will see it when they view your contact details.</p>
|
||||
<p><strong>Chats muteados</strong> si no quieres recibir notificaciones de ellos. Chats muteados se mantienen en su lugar e inclusive puedes fijarlos.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Archivar chats</strong> si no deseas verlos en tu lista de chats. Los chats archivados siguen siendo accesibles arriba de la lista de chats o a través de la búsqueda.</p>
|
||||
<p><strong>Archivar chats</strong> si no deseas verlos en tu lista de chats. Los chats archivados siguen siendo accesibles arriba de la lista de chats o a través de la búsqueda y aparecen marcados como <b style="border: 1px solid currentColor; padding: 0 3px; font-size:90%">Archivado</b>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Cuando un chat archivado recibe un nuevo mensaje, a menos que esté silenciado, <strong>saldrá del archivo</strong> y volverá a aparecer en tu lista de chats.
|
||||
@@ -352,16 +367,16 @@ and others will as well not always see that you are “online”.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p><strong>One tick</strong> <img style="vertical-align:middle; width:1.5em; margin:1px" src="../tick1.png" alt="" />
|
||||
means that the message was sent successfully to the <a href="#relays">relay</a>.</p>
|
||||
<p><strong>Un tick</strong> <img style="vertical-align:middle; width:1.5em; margin:1px" src="../tick1.png" alt="" />
|
||||
significa que el mensaje se ha enviado correctamente al <a href="#relays">servidor</a>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Two ticks</strong> <img style="vertical-align:middle; width:1.5em; margin:1px" src="../tick2.png" alt="" />
|
||||
indicate your contact has read the message.</p>
|
||||
<p><strong>Dos ticks</strong> <img style="vertical-align:middle; width:1.5em; margin:1px" src="../tick2.png" alt="" />
|
||||
indican que tu contacto ha leído el mensaje.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>In <a href="#groups">groups</a> the second tick means that at least one member has reported back having read the message.</p>
|
||||
<p>En los <a href="#groups">grupos</a> el segundo tick indica que, al menos, uno de los miembros ha leído el mensaje.</p>
|
||||
|
||||
<p>You will only get the second tick if both you and one of the recipients who read the message
|
||||
has <strong>Settings → Chats → Read Receipts</strong> enabled.</p>
|
||||
@@ -396,13 +411,12 @@ who could have already replied, forwarded, saved, screenshotted or otherwise cop
|
||||
<h3 id="mediaquality">
|
||||
|
||||
|
||||
How is media quality handled? <a href="#mediaquality" class="anchor"></a>
|
||||
¿Cómo se gestiona la calidad de los archivos multimedia? <a href="#mediaquality" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Images, videos, files, voice messages etc. can be sent using the <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Attach-</strong>
|
||||
or <img style="vertical-align:middle; width:0.8em; margin:1px" src="../mic.png" alt="Microphone" /> <strong>Voice Message</strong> buttons.</p>
|
||||
<p>Imágenes, vídeos, archivos, mensajes de voz, etc., pueden enviarse utilizando los botones de <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Adjuntar</strong> o <img style="vertical-align:middle; width:0.8em; margin:1px" src="../mic.png" alt="Microphone" /> <strong>Mensaje de Voz</strong>.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
@@ -460,8 +474,8 @@ the (anyway encrypted) messages may take longer to get deleted from their server
|
||||
|
||||
</h3>
|
||||
|
||||
<p>If you want to save storage on your device, you can choose to delete old
|
||||
messages automatically.</p>
|
||||
<p>Si quieres ahorrar espacio en tu dispositivo, puedes elegir borrar los mensajes antiguos
|
||||
automáticamente.</p>
|
||||
|
||||
<p>To turn it on, go to <strong>Settings → Chats → Delete Message from Device</strong>.
|
||||
You can set a timeframe between “after an hour” and “after a year”;
|
||||
@@ -471,7 +485,7 @@ older than that.</p>
|
||||
<h3 id="remove-account">
|
||||
|
||||
|
||||
How can I delete my chat profile? <a href="#remove-account" class="anchor"></a>
|
||||
¿Cómo puedo borrar mi perfil? <a href="#remove-account" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
@@ -490,12 +504,12 @@ or the respective page from your chosen <a href="https://chatmail.at/relays">3rd
|
||||
<h2 id="groups">
|
||||
|
||||
|
||||
Groups <a href="#groups" class="anchor"></a>
|
||||
Grupos <a href="#groups" class="anchor"></a>
|
||||
|
||||
|
||||
</h2>
|
||||
|
||||
<p>Groups let several people chat together privately with <strong>equal rights</strong>.</p>
|
||||
<p>Los grupos permiten a varias personas chatear juntas en privado con <strong>igualdad de derechos</strong>.</p>
|
||||
|
||||
<p>Anyone can
|
||||
change the group name or avatar,
|
||||
@@ -503,7 +517,7 @@ change the group name or avatar,
|
||||
set <a href="#ephemeralmsgs">disappearing messages</a>,
|
||||
and <a href="#edit">delete their own messages</a> from all member’s devices.</p>
|
||||
|
||||
<p>Because all members have the same rights, groups work best among <strong>trusted friends and family</strong>.</p>
|
||||
<p>Como todos los miembros tienen los mismos derechos, los grupos funcionan mejor entre <strong>amigos de confianza y familiares</strong>.</p>
|
||||
|
||||
<h3 id="creación-de-un-grupo">
|
||||
|
||||
@@ -528,17 +542,17 @@ and <a href="#edit">delete their own messages</a> from all member’s devices.</
|
||||
<h3 id="addmembers">
|
||||
|
||||
|
||||
Add and remove members <a href="#addmembers" class="anchor"></a>
|
||||
Añadir y eliminar miembros <a href="#addmembers" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>All group members have the <strong>same rights</strong>.
|
||||
For this reason, everyone can delete any member or add new ones.</p>
|
||||
<p>Todos los miembros del grupo tienen los <strong>mismos derechos</strong>.
|
||||
Por esta razón, todos pueden eliminar a cualquier miembro o añadir otros nuevos.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>To <strong>add or delete members</strong>, tap the group name in the chat and select the member to add or remove.</p>
|
||||
<p>Para <strong>añadir o eliminar miembros</strong>, pulsa el nombre del grupo en el chat y selecciona el miembro a añadir o eliminar.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>If the member is not yet in your contact list, but <strong>face to face</strong> with you,
|
||||
@@ -583,84 +597,275 @@ Si desea unirse al grupo nuevamente más tarde, pídale a otro miembro del grupo
|
||||
<p>Como alternativa, también puede “silenciar” a un grupo, lo que significa que recibirá todos los mensajes y
|
||||
aún puede escribir, pero ya no se le notifican nuevos mensajes.</p>
|
||||
|
||||
<h3 id="cloning-a-group">
|
||||
<h3 id="clonar-un-grupo">
|
||||
|
||||
|
||||
Cloning a group <a href="#cloning-a-group" class="anchor"></a>
|
||||
Clonar un grupo <a href="#clonar-un-grupo" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>You can duplicate a group to start a separate discussion
|
||||
or to exclude members without them noticing.</p>
|
||||
<p>Puedes duplicar un grupo para empezar una discusión separada
|
||||
o para excluir a miembros sin notificárselo.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>Open the group profile and tap <strong>Clone Chat</strong> (Android/iOS),
|
||||
or right-click the group in the chat list (Desktop).</p>
|
||||
<p>Abre el perfil del grupo y pulsa <strong>Clonar Chat</strong> (Android/iOS),
|
||||
o haz clic derecho en el grupo en la lista de chats (Escritorio).</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Set a new name, choose an avatar, and adjust the member list if needed.</p>
|
||||
<p>Establece un nuevo nombre, elige un avatar y ajusta la lista de miembros si es necesario.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>The new group is <strong>fully independent</strong> from the original,
|
||||
which continues to work as before.</p>
|
||||
<p>El nuevo grupo es <strong>completamente independiente</strong> del original,
|
||||
que continúa funcionando como antes.</p>
|
||||
|
||||
<h3 id="how-many-members-can-participate-in-a-single-group">
|
||||
<h3 id="cuántos-miembros-pueden-participar-en-un-solo-grupo">
|
||||
|
||||
|
||||
How many members can participate in a single group? <a href="#how-many-members-can-participate-in-a-single-group" class="anchor"></a>
|
||||
¿Cuántos miembros pueden participar en un solo grupo? <a href="#cuántos-miembros-pueden-participar-en-un-solo-grupo" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>There is no strict technical limit,
|
||||
but more than 150 is not recommended.</p>
|
||||
<p>No hay una limitación técnica,
|
||||
pero no se recomiendan más de 150.</p>
|
||||
|
||||
<p>As groups get larger, they can become socially unstable and may need a hierarchy -
|
||||
where Delta Chat is a private messenger for chatting with <a href="#groups">equal rights</a>.
|
||||
See <a href="https://en.wikipedia.org/wiki/Dunbar%27s_number">Dunbar’s number</a> for more insights.</p>
|
||||
|
||||
<h2 id="webxdc">
|
||||
<h2 id="channels">
|
||||
|
||||
|
||||
In-chat apps <a href="#webxdc" class="anchor"></a>
|
||||
Channels <a href="#channels" class="anchor"></a>
|
||||
|
||||
|
||||
</h2>
|
||||
|
||||
<p>You can send apps to a chat - games, editors, polls and other tools.
|
||||
This makes Delta Chat a truly extensible messenger.</p>
|
||||
<p>Channels are a one-to-many tool for broadcasting messages.</p>
|
||||
|
||||
<h3 id="where-can-i-get-in-chat-apps">
|
||||
<h3 id="subscribe-to-a-channel">
|
||||
|
||||
|
||||
Where can I get in-chat apps? <a href="#where-can-i-get-in-chat-apps" class="anchor"></a>
|
||||
Subscribe to a channel <a href="#subscribe-to-a-channel" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>Scan the <img style="vertical-align:middle; height:1.3em; margin:1px" src="../qr-icon.png" /> <strong>QR code</strong>
|
||||
or tap the <strong>invite link</strong> you got from the channel owner.</li>
|
||||
</ul>
|
||||
|
||||
<p>That’s all!
|
||||
You will receive a few of the messages from the channel history
|
||||
and, from that point on, all new messages from the channel.</p>
|
||||
|
||||
<p><strong>Don’t worry,</strong> if that does not happen immediately.
|
||||
Once the channel owner comes online, your join request will be processed.</p>
|
||||
|
||||
<p>As all of Delta Chat, also Channels are private and decentralized,
|
||||
there is no public discovery.</p>
|
||||
|
||||
<p>Other channel subscribers will not see that you subscribed and cannot message you.
|
||||
The channel owner, however, can message you.
|
||||
They will also see that you read a message unless you have read receipts disabled.</p>
|
||||
|
||||
<p>If you do not want to share your main profile,
|
||||
you can also create a <a href="#multiple-accounts">dedicated profile</a> for joining a channel.</p>
|
||||
|
||||
<h3 id="create-a-channel">
|
||||
|
||||
|
||||
Create a channel <a href="#create-a-channel" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>In a chat, using <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Attachment Button → Apps</strong></p>
|
||||
<p>Tap <strong>New Chat</strong> and choose <strong>New Channel</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>You can also <a href="#create-xdc">create your own app</a> and attach it using <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Attachment Button → File</strong></p>
|
||||
<p>Enter a <strong>name</strong>, optionally set an <strong>image</strong> and <strong>description</strong>, and hit the <strong>Create</strong> button.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>You can now send and manage messages as usual.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>From the channel’s profile, <strong>share the QR code or invite link with others</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Subscribers will receive your messages,
|
||||
but they cannot send messages in your channel.
|
||||
When subscribing, they will receive <strong>a few of the latest messages of the channel history</strong>.</p>
|
||||
|
||||
<p>You can see the <strong>view count</strong> beside each message.
|
||||
Note that this only counts subscribers who have read receipts enabled,
|
||||
so the real view count may be larger.</p>
|
||||
|
||||
<h3 id="how-many-subscribers-can-a-channel-have">
|
||||
|
||||
|
||||
How many subscribers can a channel have? <a href="#how-many-subscribers-can-a-channel-have" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Channels are designed for much larger audiences than <a href="#groups">groups</a>.</p>
|
||||
|
||||
<p>The practical limit depends on the used <a href="#relays">relay</a>,
|
||||
so there is no single fixed number that applies everywhere.</p>
|
||||
|
||||
<p>For really large channels with several tens of thousands of subscribers,
|
||||
we recommend using a <a href="#multiple-accounts">dedicated profile</a> for the channel
|
||||
and checking whether the relay is suitable.</p>
|
||||
|
||||
<p>But don’t be too hesitant: Delta Chat is designed to be relay-agnostic,
|
||||
so you can change your relay at any point easily -
|
||||
your existing subscribers will not even notice.
|
||||
You only have to update the invite link you share with new subscribers in that case.</p>
|
||||
|
||||
<h2 id="calls">
|
||||
|
||||
|
||||
Calls <a href="#calls" class="anchor"></a>
|
||||
|
||||
|
||||
</h2>
|
||||
|
||||
<p>Delta Chat supports one-to-one <strong>audio calls</strong> and <strong>video calls</strong>.</p>
|
||||
|
||||
<p>Calls are supported on Desktop, Ubuntu Touch, iOS and Android 8 and newer.</p>
|
||||
|
||||
<h3 id="place-a-call">
|
||||
|
||||
|
||||
Place a call <a href="#place-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>In a one-to-one chat, tap the 📞 <strong>call icon</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>This opens a small menu
|
||||
where you can choose whether to place an <strong>Audio Call</strong> or a <strong>Video Call</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="how-private-are-in-chat-apps">
|
||||
<h3 id="accept-or-reject-a-call">
|
||||
|
||||
|
||||
How private are in-chat apps? <a href="#how-private-are-in-chat-apps" class="anchor"></a>
|
||||
Accept or reject a call <a href="#accept-or-reject-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>In-chat apps can not send data to the Internet, or download anything.</p>
|
||||
<p>When someone calls you,
|
||||
Delta Chat shows an <strong>incoming call screen</strong> or notification.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Tap <strong>Accept</strong> to answer
|
||||
or <strong>Decline</strong> to reject the call.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="during-a-call">
|
||||
|
||||
|
||||
During a call <a href="#during-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>You can <strong>mute</strong> your microphone.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>You can <strong>enable or disable your camera</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>On mobile, you can <strong>switch between front and back cameras</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Depending on the device, you can also select the audio output or use picture-in-picture.
|
||||
On desktop, the call is using a dedicated window
|
||||
and you can continue using the main Delta Chat window as usual.</p>
|
||||
|
||||
<h3 id="missed-calls-and-notifications">
|
||||
|
||||
|
||||
Missed calls and notifications <a href="#missed-calls-and-notifications" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>If you do not answer, do not hear the ringing, or do not have your device at hand,
|
||||
the call appears as a <strong>missed call</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Only your accepted contacts</strong> can make your device ring.
|
||||
Contact requests will appear as usual and will not ring.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>At <strong>Settings → Notifications → Calls</strong>,
|
||||
you can disable the special call ringing screen completely.
|
||||
If you do so, you will not be disturbed by any ringing notification,
|
||||
you can still pick up the call by tapping the incoming call message bubble in its chat.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="webxdc">
|
||||
|
||||
|
||||
Aplicaciones en chats <a href="#webxdc" class="anchor"></a>
|
||||
|
||||
|
||||
</h2>
|
||||
|
||||
<p>Puedes enviar aplicaciones a un chat: juegos, editores, encuestas y otras herramientas.
|
||||
Esto convierte a Delta Chat en una aplicación de mensajería realmente ampliable.</p>
|
||||
|
||||
<h3 id="dónde-puedo-conseguir-aplicaciones-para-el-chat">
|
||||
|
||||
|
||||
¿Dónde puedo conseguir aplicaciones para el chat? <a href="#dónde-puedo-conseguir-aplicaciones-para-el-chat" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>En un chat, utilizando <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Botón Adjuntar → Aplicaciones</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>También puedes <a href="#create-xdc">crear tu propia aplicación</a> y adjuntarla utilizando <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Botón Adjuntar → Archivo</strong></p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="cómo-de-privadas-son-las-aplicaciones-en-el-chat">
|
||||
|
||||
|
||||
¿Cómo de privadas son las aplicaciones en el chat? <a href="#cómo-de-privadas-son-las-aplicaciones-en-el-chat" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>Las aplicaciones en el chat no pueden enviar datos a Internet ni descargar nada.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>An in-chat app can only exchange data within a chat, with its
|
||||
@@ -672,29 +877,28 @@ isolated from the Internet.</p>
|
||||
trust the people you chat with, you can trust the in-chat app as well.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>This also means: Just like for web links, do not open apps from untrusted contacts.</p>
|
||||
<p>Esto también significa que, al igual que con los enlaces web, no debes abrir aplicaciones de contactos en los que no confíes.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="create-xdc">
|
||||
|
||||
|
||||
How can I create my own in-chat apps? <a href="#create-xdc" class="anchor"></a>
|
||||
¿Cómo puedo crear mis propias aplicaciones para el chat? <a href="#create-xdc" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>In-chat apps are zip files with <code class="language-plaintext highlighter-rouge">.xdc</code> extension containing html, css, and javascript code.</p>
|
||||
<p>Las aplicaciones de chat son archivos zip con extensión <code class="language-plaintext highlighter-rouge">.xdc</code> que contienen código html, css y javascript.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>You can extend the <a href="https://github.com/webxdc/hello">Hello World example app</a>
|
||||
to get started.</p>
|
||||
<p>Para empezar, puedes ampliar la <a href="https://github.com/webxdc/hello">aplicación de ejemplo Hola, Mundo</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p>All else you need to know is written in the
|
||||
<a href="https://webxdc.org/docs">Webxdc documentation</a>.</p>
|
||||
<p>Todo lo que necesitas saber lo puedes encontrar en
|
||||
la <a href="https://webxdc.org/docs">documentación de Webxdc</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p>If you have question, you can ask others with experience
|
||||
@@ -871,21 +1075,21 @@ Welcome to the power of the interoperable chatmail relay network :)</p>
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Yes. You can use the same profile on different devices:</p>
|
||||
<p>Sí. Puedes utilizar el mismo perfil en diferentes dispositivos.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>Asegurate que ambos dispositivos estén en la misma Wi-Fi o red</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>On the first device, go to <strong>Settings → Add Second Device</strong>, unlock the screen if needed
|
||||
and wait a moment until a QR code is shown</p>
|
||||
<p>En el primer dispositivo, ve a <strong>Ajustes → Añadir segundo dispositivo</strong>, desbloquea la pantalla si es necesario,
|
||||
y espera un momento hasta que aparezca un código QR</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>En el otro dispositivo, <a href="https://get.delta.chat">instala Delta Chat</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p>On the second device, start Delta Chat, select <strong>Add as Second Device</strong>, and scan the QR code from the old device</p>
|
||||
<p>En el segundo dispositivo, abre Delta Chat, selecciona **Añadir desde otro dispositivo” y escanea el código QR del primer dispositivo</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>La transferencia debería comenzar después de unos segundos y durante la transferencia ambos dispositivos mostrarán el <strong>progreso</strong>.
|
||||
@@ -946,8 +1150,8 @@ Do not exit Delta Chat.
|
||||
You can use multiple profiles per device, just <a href="#multiple-accounts">add another profile</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p>If you still have problems or if you <strong>cannot scan a QR code</strong>
|
||||
try the <strong>manual transfer</strong> described below</p>
|
||||
<p>Si todavía tienes problemas o si <strong>no puedes escanear el código QR</strong>
|
||||
utiliza la <strong>transferencia manual</strong> descrita debajo</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -1048,7 +1252,7 @@ If you have multiple relays, you will receive messages on all of them.
|
||||
Contacts learn your current relays automatically when you message them.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Tap on a relay to set it as <strong>used for sending</strong>.</p>
|
||||
<p>Pulsa en un retransmisor para establecerlo como <strong>usado para enviar</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>If you <strong>remove</strong> a relay,
|
||||
@@ -1057,17 +1261,17 @@ To stay reachable in the meantime, choose <strong>Hide from Contacts</strong> in
|
||||
instead of removing it right away.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>To <strong>show</strong> a hidden relay again, tap on it.</p>
|
||||
<p>Para <strong>mostrar</strong> de nuevo un retransmisor oculto, pulsa en él.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>For more details and future possibilities of relays,
|
||||
you can follow discussions in the <a href="https://support.delta.chat">Forum</a>.</p>
|
||||
|
||||
<h3 id="can-i-use-a-classic-email-address-with-delta-chat">
|
||||
<h3 id="puedo-utilizar-una-dirección-de-email-clásico-con-delta-chat">
|
||||
|
||||
|
||||
Can I use a classic email address with Delta Chat? <a href="#can-i-use-a-classic-email-address-with-delta-chat" class="anchor"></a>
|
||||
¿Puedo utilizar una dirección de email clásico con Delta Chat? <a href="#puedo-utilizar-una-dirección-de-email-clásico-con-delta-chat" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
@@ -1141,27 +1345,27 @@ that power <a href="https://chatmail.at/clients">chatmail clients</a> of which D
|
||||
which is why Delta Chat for Android asks whether you want
|
||||
to send anonymous usage statistics.</p>
|
||||
|
||||
<p>You can turn it on and off at
|
||||
<strong>Settings → Advanced → Send statistics to Delta Chat’s developers</strong>.</p>
|
||||
<p>Puedes activarlo y desactivarlo en
|
||||
<strong>Ajustes → Avanzado → Enviar estadísticas a los desarrolladores de Delta Chat</strong>.</p>
|
||||
|
||||
<p>When you turn it on,
|
||||
weekly statistics will be automatically sent to a bot.</p>
|
||||
<p>Cuando lo activas,
|
||||
las estadísticas semanales se envían automáticamente a un bot.</p>
|
||||
|
||||
<p>We are interested e.g. in statistics like:</p>
|
||||
<p>Estamos interesados en estadísticas como, p. ej.:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>How many contacts are introduced by personally scanning a QR code?</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Which versions of Delta Chat are being used?</p>
|
||||
<p>¿Qué versiones de Delta Chat están siendo utilizadas?</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>What errors occur for users?</p>
|
||||
<p>¿Qué errores se producen para los usuarios?</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>We will <em>not</em> collect any personally identifiable information about you.</p>
|
||||
<p>Nosotros <em>no</em> recopilaremos ninguna información de carácter personal sobre ti.</p>
|
||||
|
||||
<h3 id="estoy-interesado-en-los-detalles-técnicos-pueden-decirme-más">
|
||||
|
||||
@@ -1212,12 +1416,12 @@ enables receivers to use end-to-end encryption with the contact.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Delta Chat does not query, publish or interact with any OpenPGP key servers.</p>
|
||||
<p>Delta Chat no consulta, publica o interacciona con ningún servidor de claves OpenPGP.</p>
|
||||
|
||||
<h3 id="whene2e">
|
||||
|
||||
|
||||
How can I know if messages are end-to-end encrypted? <a href="#whene2e" class="anchor"></a>
|
||||
¿Cómo puedo saber si los mensajes están cifrados de extremo a extremo? <a href="#whene2e" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
@@ -1226,10 +1430,10 @@ enables receivers to use end-to-end encryption with the contact.</p>
|
||||
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>
|
||||
|
||||
<h3 id="can-i-still-receive-or-send-messages-without-end-to-end-encryption">
|
||||
<h3 id="puedo-enviar-o-recibir-mensajes-sin-cifrado-de-extremo-a-extremo">
|
||||
|
||||
|
||||
Can I still receive or send messages without end-to-end encryption? <a href="#can-i-still-receive-or-send-messages-without-end-to-end-encryption" class="anchor"></a>
|
||||
¿Puedo enviar o recibir mensajes sin cifrado de extremo a extremo? <a href="#puedo-enviar-o-recibir-mensajes-sin-cifrado-de-extremo-a-extremo" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
@@ -1409,41 +1613,38 @@ 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>
|
||||
|
||||
<h3 id="who-sees-my-ip-address">
|
||||
<h3 id="quién-puede-ver-mi-dirección-ip">
|
||||
|
||||
|
||||
Who sees my IP Address? <a href="#who-sees-my-ip-address" class="anchor"></a>
|
||||
¿Quién puede ver mi dirección IP? <a href="#quién-puede-ver-mi-dirección-ip" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>The used <a href="#relays">relay</a> needs to know your IP Address,
|
||||
as well as sometimes your contact’s devices if you have a <a href="#experiments">call</a>
|
||||
<p>The used <a href="#relays">relays</a> need to know your IP Address,
|
||||
as well as sometimes your contact’s devices if you have a <a href="#calls">call</a>
|
||||
or use <a href="#webxdc">apps</a> together.</p>
|
||||
|
||||
<p>IP Addresses are needed for connectivity and efficiency.
|
||||
They are neither persisted nor exposed.
|
||||
Note that the IP Address
|
||||
is not like a detailed address you give to a delivery service,
|
||||
but much more coarse, often defining region or country only.</p>
|
||||
Delta Chat neither persists nor exposes them.
|
||||
Note that IP Addresses
|
||||
are not like an address you give to a delivery service,
|
||||
but typically less precise, often defining city or region only.</p>
|
||||
|
||||
<p>As this is just how the internet and other messengers work by default,
|
||||
we do not offer options here or ask upfront questions.</p>
|
||||
|
||||
<p>If you see your IP Address as a security or privacy risk,
|
||||
we recommend to use a VPN, in combination with system lockdown mode.
|
||||
Hunting down options in all apps on your system will leave gaps.
|
||||
For example, tapping a link exposes IP Addresses to unknown parties and is the by far larger risk here.</p>
|
||||
<p>If you see your IP Address as a risk,
|
||||
we recommend to use a VPN for the whole system.
|
||||
Per-app options leave gaps across your system.
|
||||
For example, tapping a link can expose IP Addresses to unknown parties, which is by far the larger risk.</p>
|
||||
|
||||
<h3 id="sealedsender">
|
||||
|
||||
|
||||
Does Delta Chat support “Sealed Sender”? <a href="#sealedsender" class="anchor"></a>
|
||||
¿Soporta Delta Chat “Sealed Sender”? <a href="#sealedsender" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>No, not yet.</p>
|
||||
<p>No, todavía no.</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.
|
||||
@@ -1464,7 +1665,7 @@ but an implementation has not been agreed as a priority yet.</p>
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Not yet, but it’s coming with <a href="https://autocrypt2.org">Autocrypt v2</a>.</p>
|
||||
<p>Todavía no, pero llegará con <a href="https://autocrypt2.org">Autocrypt v2</a>.</p>
|
||||
|
||||
<p>Delta Chat today doesn’t support Perfect Forward Secrecy (PFS).
|
||||
This means that if your private decryption key is leaked,
|
||||
@@ -1482,12 +1683,12 @@ This approach is specified in the <a href="https://datatracker.ietf.org/doc/draf
|
||||
<h3 id="pqc">
|
||||
|
||||
|
||||
Does Delta Chat support Post-Quantum-Cryptography? <a href="#pqc" class="anchor"></a>
|
||||
¿Soporta Delta Chat criptografía postcuántica? <a href="#pqc" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Not yet, but it’s coming with <a href="https://autocrypt2.org">Autocrypt v2</a>.</p>
|
||||
<p>Todavía no, pero llegará con <a href="https://autocrypt2.org">Autocrypt v2</a>.</p>
|
||||
|
||||
<p><a href="https://autocrypt2.org">Autocrypt v2</a>, scheduled for full implementation in 2026,
|
||||
will bring post-quantum resistant encryption to protect against quantum computer attacks.
|
||||
@@ -1495,10 +1696,10 @@ Delta Chat uses the Rust OpenPGP library <a href="https://github.com/rpgp/rpgp">
|
||||
which supports the latest <a href="https://datatracker.ietf.org/doc/draft-ietf-openpgp-pqc/">IETF Post-Quantum-Cryptography OpenPGP draft</a>.
|
||||
The implementation is specified in the <a href="https://datatracker.ietf.org/doc/draft-autocrypt-openpgp-v2-cert/">Autocrypt v2 OpenPGP Certificates</a> draft.</p>
|
||||
|
||||
<h3 id="how-can-i-manually-check-encryption-information">
|
||||
<h3 id="cómo-puedo-comprobar-manualmente-la-información-de-cifrado">
|
||||
|
||||
|
||||
How can I manually check encryption information? <a href="#how-can-i-manually-check-encryption-information" class="anchor"></a>
|
||||
¿Cómo puedo comprobar manualmente la información de cifrado? <a href="#cómo-puedo-comprobar-manualmente-la-información-de-cifrado" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
@@ -1614,37 +1815,37 @@ You can read the <a href="https://delta.chat/assets/blog/2019-first-security-rev
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Some features require certain permissions,
|
||||
e.g. you need to grant camera permission if you want to <a href="#howtoe2ee">scan an invite QR code</a>.</p>
|
||||
<p>Algunas características requieren ciertos permisos,
|
||||
p. ej., tienes que conceder permiso de acceso a la cámara si quieres <a href="#howtoe2ee">escanear un código QR de invitación</a>.</p>
|
||||
|
||||
<p>See <a href="https://delta.chat/en/gdpr#24-app-permissions">Privacy Policy</a> for a detailed overview.</p>
|
||||
<p>Consulta la <a href="https://delta.chat/en/gdpr#24-app-permissions">Política de privacidad</a> para obtener información detallada.</p>
|
||||
|
||||
<h3 id="where-can-my-friends-find-delta-chat">
|
||||
<h3 id="dónde-pueden-encontrar-mis-amigos-delta-chat">
|
||||
|
||||
|
||||
Where can my friends find Delta Chat? <a href="#where-can-my-friends-find-delta-chat" class="anchor"></a>
|
||||
¿Dónde pueden encontrar mis amigos Delta Chat? <a href="#dónde-pueden-encontrar-mis-amigos-delta-chat" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Delta Chat is available for all major and some minor platforms:</p>
|
||||
<p>Delta Chat está disponible para todas las plataformas principales y algunas secundarias:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>The <strong>official website</strong>, <a href="https://delta.chat/download">https://delta.chat/download</a> shows all options in detail</p>
|
||||
<p>La <strong>página web oficial</strong>, <a href="https://delta.chat/download">https://delta.chat/download</a>, muestra todas las opciones en detalle.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>If unavailable, use the <strong>mirror</strong> at <a href="https://deltachat.github.io/deltachat-pages">https://deltachat.github.io/deltachat-pages</a></p>
|
||||
<p>Si no está disponible, utiliza el <strong>mirror</strong> en <a href="https://deltachat.github.io/deltachat-pages">https://deltachat.github.io/deltachat-pages</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Open one of the following <strong>app stores and search for “Delta Chat”:</strong>
|
||||
Google Play Store, F-Droid, Huawei App Gallery, iOS and macOS App Store, Microsoft Store</p>
|
||||
<p>Abre una de las siguientes <strong>tiendas de aplicaciones y busca “Delta Chat”:</strong>
|
||||
Google Play Store, F-Droid, Huawei App Gallery, iOS y macOS App Store, Microsoft Store</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Check the <strong>package manager</strong> of your Linux distributions</p>
|
||||
<p>Comprueba el <strong>gestor de paquetes</strong> de tu distribución de Linux</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Android APKs</strong> are also available on <a href="https://github.com/deltachat/deltachat-android/releases">https://github.com/deltachat/deltachat-android/releases</a></p>
|
||||
<p>Las <strong>Android APKs</strong> están también disponibles en <a href="https://github.com/deltachat/deltachat-android/releases">https://github.com/deltachat/deltachat-android/releases</a></p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
@@ -29,6 +29,21 @@
|
||||
<li><a href="#zenbat-kide-izan-ditzake-talde-batek">Zenbat kide izan ditzake talde batek?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#channels">Channels</a>
|
||||
<ul>
|
||||
<li><a href="#subscribe-to-a-channel">Subscribe to a channel</a></li>
|
||||
<li><a href="#create-a-channel">Create a channel</a></li>
|
||||
<li><a href="#how-many-subscribers-can-a-channel-have">How many subscribers can a channel have?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#calls">Calls</a>
|
||||
<ul>
|
||||
<li><a href="#place-a-call">Place a call</a></li>
|
||||
<li><a href="#accept-or-reject-a-call">Accept or reject a call</a></li>
|
||||
<li><a href="#during-a-call">During a call</a></li>
|
||||
<li><a href="#missed-calls-and-notifications">Missed calls and notifications</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#webxdc">Txat barruko aplikazioak</a>
|
||||
<ul>
|
||||
<li><a href="#non-lortu-ditzaket-txat-barruko-aplikazioak">Non lortu ditzaket txat barruko aplikazioak?</a></li>
|
||||
@@ -624,6 +639,197 @@ baina ez da komeni 150 baino gehiago izatea.</p>
|
||||
Delta Chat <a href="#groups">eskubide berberekin</a> txateatzeko aukera ematen duen mezularitza pribatuko zerbitzu bat da.
|
||||
Informazio gehiago nahi baduzu, kontsultatu <a href="https://en.wikipedia.org/wiki/Dunbar%27s_number">Dunbarren zenbakia</a>.</p>
|
||||
|
||||
<h2 id="channels">
|
||||
|
||||
|
||||
Channels <a href="#channels" class="anchor"></a>
|
||||
|
||||
|
||||
</h2>
|
||||
|
||||
<p>Channels are a one-to-many tool for broadcasting messages.</p>
|
||||
|
||||
<h3 id="subscribe-to-a-channel">
|
||||
|
||||
|
||||
Subscribe to a channel <a href="#subscribe-to-a-channel" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>Scan the <img style="vertical-align:middle; height:1.3em; margin:1px" src="../qr-icon.png" /> <strong>QR code</strong>
|
||||
or tap the <strong>invite link</strong> you got from the channel owner.</li>
|
||||
</ul>
|
||||
|
||||
<p>That’s all!
|
||||
You will receive a few of the messages from the channel history
|
||||
and, from that point on, all new messages from the channel.</p>
|
||||
|
||||
<p><strong>Don’t worry,</strong> if that does not happen immediately.
|
||||
Once the channel owner comes online, your join request will be processed.</p>
|
||||
|
||||
<p>As all of Delta Chat, also Channels are private and decentralized,
|
||||
there is no public discovery.</p>
|
||||
|
||||
<p>Other channel subscribers will not see that you subscribed and cannot message you.
|
||||
The channel owner, however, can message you.
|
||||
They will also see that you read a message unless you have read receipts disabled.</p>
|
||||
|
||||
<p>If you do not want to share your main profile,
|
||||
you can also create a <a href="#multiple-accounts">dedicated profile</a> for joining a channel.</p>
|
||||
|
||||
<h3 id="create-a-channel">
|
||||
|
||||
|
||||
Create a channel <a href="#create-a-channel" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>Tap <strong>New Chat</strong> and choose <strong>New Channel</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Enter a <strong>name</strong>, optionally set an <strong>image</strong> and <strong>description</strong>, and hit the <strong>Create</strong> button.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>You can now send and manage messages as usual.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>From the channel’s profile, <strong>share the QR code or invite link with others</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Subscribers will receive your messages,
|
||||
but they cannot send messages in your channel.
|
||||
When subscribing, they will receive <strong>a few of the latest messages of the channel history</strong>.</p>
|
||||
|
||||
<p>You can see the <strong>view count</strong> beside each message.
|
||||
Note that this only counts subscribers who have read receipts enabled,
|
||||
so the real view count may be larger.</p>
|
||||
|
||||
<h3 id="how-many-subscribers-can-a-channel-have">
|
||||
|
||||
|
||||
How many subscribers can a channel have? <a href="#how-many-subscribers-can-a-channel-have" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Channels are designed for much larger audiences than <a href="#groups">groups</a>.</p>
|
||||
|
||||
<p>The practical limit depends on the used <a href="#relays">relay</a>,
|
||||
so there is no single fixed number that applies everywhere.</p>
|
||||
|
||||
<p>For really large channels with several tens of thousands of subscribers,
|
||||
we recommend using a <a href="#multiple-accounts">dedicated profile</a> for the channel
|
||||
and checking whether the relay is suitable.</p>
|
||||
|
||||
<p>But don’t be too hesitant: Delta Chat is designed to be relay-agnostic,
|
||||
so you can change your relay at any point easily -
|
||||
your existing subscribers will not even notice.
|
||||
You only have to update the invite link you share with new subscribers in that case.</p>
|
||||
|
||||
<h2 id="calls">
|
||||
|
||||
|
||||
Calls <a href="#calls" class="anchor"></a>
|
||||
|
||||
|
||||
</h2>
|
||||
|
||||
<p>Delta Chat supports one-to-one <strong>audio calls</strong> and <strong>video calls</strong>.</p>
|
||||
|
||||
<p>Calls are supported on Desktop, Ubuntu Touch, iOS and Android 8 and newer.</p>
|
||||
|
||||
<h3 id="place-a-call">
|
||||
|
||||
|
||||
Place a call <a href="#place-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>In a one-to-one chat, tap the 📞 <strong>call icon</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>This opens a small menu
|
||||
where you can choose whether to place an <strong>Audio Call</strong> or a <strong>Video Call</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="accept-or-reject-a-call">
|
||||
|
||||
|
||||
Accept or reject a call <a href="#accept-or-reject-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>When someone calls you,
|
||||
Delta Chat shows an <strong>incoming call screen</strong> or notification.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Tap <strong>Accept</strong> to answer
|
||||
or <strong>Decline</strong> to reject the call.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="during-a-call">
|
||||
|
||||
|
||||
During a call <a href="#during-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>You can <strong>mute</strong> your microphone.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>You can <strong>enable or disable your camera</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>On mobile, you can <strong>switch between front and back cameras</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Depending on the device, you can also select the audio output or use picture-in-picture.
|
||||
On desktop, the call is using a dedicated window
|
||||
and you can continue using the main Delta Chat window as usual.</p>
|
||||
|
||||
<h3 id="missed-calls-and-notifications">
|
||||
|
||||
|
||||
Missed calls and notifications <a href="#missed-calls-and-notifications" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>If you do not answer, do not hear the ringing, or do not have your device at hand,
|
||||
the call appears as a <strong>missed call</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Only your accepted contacts</strong> can make your device ring.
|
||||
Contact requests will appear as usual and will not ring.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>At <strong>Settings → Notifications → Calls</strong>,
|
||||
you can disable the special call ringing screen completely.
|
||||
If you do so, you will not be disturbed by any ringing notification,
|
||||
you can still pick up the call by tapping the incoming call message bubble in its chat.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="webxdc">
|
||||
|
||||
|
||||
@@ -1431,26 +1637,20 @@ txat-kontaktuak ezin izango dira erraz identifikatu.</p>
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Erabiltzen duzun <a href="#relays">erreleak</a> zure IP helbidea jakin behar du,
|
||||
eta, batzuetan, baita zure kontaktuen gailuena ere; adibidez,
|
||||
kontaktu horiekin <a href="#experiments">deiak</a> egiten badituzu edo
|
||||
<a href="#webxdc">aplikazioak</a> erabiltzen badituzu.</p>
|
||||
<p>The used <a href="#relays">relays</a> need to know your IP Address,
|
||||
as well as sometimes your contact’s devices if you have a <a href="#calls">call</a>
|
||||
or use <a href="#webxdc">apps</a> together.</p>
|
||||
|
||||
<p>IP helbideak ezinbestekoak dira konektibitaterako eta eraginkortasunerako.
|
||||
Ez dira gordetzen, ez argitara ematen.
|
||||
Kontuan izan IP helbidea ez dela mezularitzako zerbitzuei-eta eman ohi zaiena
|
||||
bezalako helbide zehatz bat; askoz orokorragoa da, eta askotan eskualdea edo
|
||||
herrialdea baizik ez du identifikatzen.</p>
|
||||
<p>IP Addresses are needed for connectivity and efficiency.
|
||||
Delta Chat neither persists nor exposes them.
|
||||
Note that IP Addresses
|
||||
are not like an address you give to a delivery service,
|
||||
but typically less precise, often defining city or region only.</p>
|
||||
|
||||
<p>Internetek eta beste mezularitza-aplikazioek horrela funtzionatzen dutenez,
|
||||
ez dugu horren gaineko bestelako aukerarik eskaintzen, ez galderarik egiten.</p>
|
||||
|
||||
<p>Uste baduzu zure IP helbidea jakiteak zure segurtasuna edo pribatutasuna
|
||||
arriskuan jar ditzakeela, zera gomendatuko genizuke, VPN bat erabiltzea,
|
||||
sistema blokeatzeko moduarekin batera. Zure sistemako aplikazio guztietan
|
||||
alternatibak bilatzeak segurtasun-zuloak utziko ditu; adibidez, esteka batean klik egindakoan,
|
||||
IP helbideak agerian geratzen zaizkie hirugarren ezezagunei, eta
|
||||
hori askoz arriskutsuagoa da.</p>
|
||||
<p>If you see your IP Address as a risk,
|
||||
we recommend to use a VPN for the whole system.
|
||||
Per-app options leave gaps across your system.
|
||||
For example, tapping a link can expose IP Addresses to unknown parties, which is by far the larger risk.</p>
|
||||
|
||||
<h3 id="sealedsender">
|
||||
|
||||
|
||||
@@ -29,6 +29,21 @@
|
||||
<li><a href="#how-many-members-can-participate-in-a-single-group">How many members can participate in a single group?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#channels">Channels</a>
|
||||
<ul>
|
||||
<li><a href="#subscribe-to-a-channel">Subscribe to a channel</a></li>
|
||||
<li><a href="#create-a-channel">Create a channel</a></li>
|
||||
<li><a href="#how-many-subscribers-can-a-channel-have">How many subscribers can a channel have?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#calls">Calls</a>
|
||||
<ul>
|
||||
<li><a href="#place-a-call">Place a call</a></li>
|
||||
<li><a href="#accept-or-reject-a-call">Accept or reject a call</a></li>
|
||||
<li><a href="#during-a-call">During a call</a></li>
|
||||
<li><a href="#missed-calls-and-notifications">Missed calls and notifications</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#webxdc">In-chat apps</a>
|
||||
<ul>
|
||||
<li><a href="#where-can-i-get-in-chat-apps">Where can I get in-chat apps?</a></li>
|
||||
@@ -547,6 +562,197 @@ but more than 150 is not recommended.</p>
|
||||
where Delta Chat is a private messenger for chatting with <a href="#groups">equal rights</a>.
|
||||
See <a href="https://en.wikipedia.org/wiki/Dunbar%27s_number">Dunbar’s number</a> for more insights.</p>
|
||||
|
||||
<h2 id="channels">
|
||||
|
||||
|
||||
Channels <a href="#channels" class="anchor"></a>
|
||||
|
||||
|
||||
</h2>
|
||||
|
||||
<p>Channels are a one-to-many tool for broadcasting messages.</p>
|
||||
|
||||
<h3 id="subscribe-to-a-channel">
|
||||
|
||||
|
||||
Subscribe to a channel <a href="#subscribe-to-a-channel" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>Scan the <img style="vertical-align:middle; height:1.3em; margin:1px" src="../qr-icon.png" /> <strong>QR code</strong>
|
||||
or tap the <strong>invite link</strong> you got from the channel owner.</li>
|
||||
</ul>
|
||||
|
||||
<p>That’s all!
|
||||
You will receive a few of the messages from the channel history
|
||||
and, from that point on, all new messages from the channel.</p>
|
||||
|
||||
<p><strong>Don’t worry,</strong> if that does not happen immediately.
|
||||
Once the channel owner comes online, your join request will be processed.</p>
|
||||
|
||||
<p>As all of Delta Chat, also Channels are private and decentralized,
|
||||
there is no public discovery.</p>
|
||||
|
||||
<p>Other channel subscribers will not see that you subscribed and cannot message you.
|
||||
The channel owner, however, can message you.
|
||||
They will also see that you read a message unless you have read receipts disabled.</p>
|
||||
|
||||
<p>If you do not want to share your main profile,
|
||||
you can also create a <a href="#multiple-accounts">dedicated profile</a> for joining a channel.</p>
|
||||
|
||||
<h3 id="create-a-channel">
|
||||
|
||||
|
||||
Create a channel <a href="#create-a-channel" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>Tap <strong>New Chat</strong> and choose <strong>New Channel</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Enter a <strong>name</strong>, optionally set an <strong>image</strong> and <strong>description</strong>, and hit the <strong>Create</strong> button.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>You can now send and manage messages as usual.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>From the channel’s profile, <strong>share the QR code or invite link with others</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Subscribers will receive your messages,
|
||||
but they cannot send messages in your channel.
|
||||
When subscribing, they will receive <strong>a few of the latest messages of the channel history</strong>.</p>
|
||||
|
||||
<p>You can see the <strong>view count</strong> beside each message.
|
||||
Note that this only counts subscribers who have read receipts enabled,
|
||||
so the real view count may be larger.</p>
|
||||
|
||||
<h3 id="how-many-subscribers-can-a-channel-have">
|
||||
|
||||
|
||||
How many subscribers can a channel have? <a href="#how-many-subscribers-can-a-channel-have" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Channels are designed for much larger audiences than <a href="#groups">groups</a>.</p>
|
||||
|
||||
<p>The practical limit depends on the used <a href="#relays">relay</a>,
|
||||
so there is no single fixed number that applies everywhere.</p>
|
||||
|
||||
<p>For really large channels with several tens of thousands of subscribers,
|
||||
we recommend using a <a href="#multiple-accounts">dedicated profile</a> for the channel
|
||||
and checking whether the relay is suitable.</p>
|
||||
|
||||
<p>But don’t be too hesitant: Delta Chat is designed to be relay-agnostic,
|
||||
so you can change your relay at any point easily -
|
||||
your existing subscribers will not even notice.
|
||||
You only have to update the invite link you share with new subscribers in that case.</p>
|
||||
|
||||
<h2 id="calls">
|
||||
|
||||
|
||||
Calls <a href="#calls" class="anchor"></a>
|
||||
|
||||
|
||||
</h2>
|
||||
|
||||
<p>Delta Chat supports one-to-one <strong>audio calls</strong> and <strong>video calls</strong>.</p>
|
||||
|
||||
<p>Calls are supported on Desktop, Ubuntu Touch, iOS and Android 8 and newer.</p>
|
||||
|
||||
<h3 id="place-a-call">
|
||||
|
||||
|
||||
Place a call <a href="#place-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>In a one-to-one chat, tap the 📞 <strong>call icon</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>This opens a small menu
|
||||
where you can choose whether to place an <strong>Audio Call</strong> or a <strong>Video Call</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="accept-or-reject-a-call">
|
||||
|
||||
|
||||
Accept or reject a call <a href="#accept-or-reject-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>When someone calls you,
|
||||
Delta Chat shows an <strong>incoming call screen</strong> or notification.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Tap <strong>Accept</strong> to answer
|
||||
or <strong>Decline</strong> to reject the call.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="during-a-call">
|
||||
|
||||
|
||||
During a call <a href="#during-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>You can <strong>mute</strong> your microphone.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>You can <strong>enable or disable your camera</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>On mobile, you can <strong>switch between front and back cameras</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Depending on the device, you can also select the audio output or use picture-in-picture.
|
||||
On desktop, the call is using a dedicated window
|
||||
and you can continue using the main Delta Chat window as usual.</p>
|
||||
|
||||
<h3 id="missed-calls-and-notifications">
|
||||
|
||||
|
||||
Missed calls and notifications <a href="#missed-calls-and-notifications" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>If you do not answer, do not hear the ringing, or do not have your device at hand,
|
||||
the call appears as a <strong>missed call</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Only your accepted contacts</strong> can make your device ring.
|
||||
Contact requests will appear as usual and will not ring.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>At <strong>Settings → Notifications → Calls</strong>,
|
||||
you can disable the special call ringing screen completely.
|
||||
If you do so, you will not be disturbed by any ringing notification,
|
||||
you can still pick up the call by tapping the incoming call message bubble in its chat.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="webxdc">
|
||||
|
||||
|
||||
@@ -1338,23 +1544,20 @@ can not be identified easily.</p>
|
||||
|
||||
</h3>
|
||||
|
||||
<p>The used <a href="#relays">relay</a> needs to know your IP Address,
|
||||
as well as sometimes your contact’s devices if you have a <a href="#experiments">call</a>
|
||||
<p>The used <a href="#relays">relays</a> need to know your IP Address,
|
||||
as well as sometimes your contact’s devices if you have a <a href="#calls">call</a>
|
||||
or use <a href="#webxdc">apps</a> together.</p>
|
||||
|
||||
<p>IP Addresses are needed for connectivity and efficiency.
|
||||
They are neither persisted nor exposed.
|
||||
Note that the IP Address
|
||||
is not like a detailed address you give to a delivery service,
|
||||
but much more coarse, often defining region or country only.</p>
|
||||
Delta Chat neither persists nor exposes them.
|
||||
Note that IP Addresses
|
||||
are not like an address you give to a delivery service,
|
||||
but typically less precise, often defining city or region only.</p>
|
||||
|
||||
<p>As this is just how the internet and other messengers work by default,
|
||||
we do not offer options here or ask upfront questions.</p>
|
||||
|
||||
<p>If you see your IP Address as a security or privacy risk,
|
||||
we recommend to use a VPN, in combination with system lockdown mode.
|
||||
Hunting down options in all apps on your system will leave gaps.
|
||||
For example, tapping a link exposes IP Addresses to unknown parties and is the by far larger risk here.</p>
|
||||
<p>If you see your IP Address as a risk,
|
||||
we recommend to use a VPN for the whole system.
|
||||
Per-app options leave gaps across your system.
|
||||
For example, tapping a link can expose IP Addresses to unknown parties, which is by far the larger risk.</p>
|
||||
|
||||
<h3 id="sealedsender">
|
||||
|
||||
|
||||
@@ -29,6 +29,21 @@
|
||||
<li><a href="#how-many-members-can-participate-in-a-single-group">How many members can participate in a single group?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#channels">Channels</a>
|
||||
<ul>
|
||||
<li><a href="#subscribe-to-a-channel">Subscribe to a channel</a></li>
|
||||
<li><a href="#create-a-channel">Create a channel</a></li>
|
||||
<li><a href="#how-many-subscribers-can-a-channel-have">How many subscribers can a channel have?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#calls">Calls</a>
|
||||
<ul>
|
||||
<li><a href="#place-a-call">Place a call</a></li>
|
||||
<li><a href="#accept-or-reject-a-call">Accept or reject a call</a></li>
|
||||
<li><a href="#during-a-call">During a call</a></li>
|
||||
<li><a href="#missed-calls-and-notifications">Missed calls and notifications</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#webxdc">In-chat apps</a>
|
||||
<ul>
|
||||
<li><a href="#where-can-i-get-in-chat-apps">Where can I get in-chat apps?</a></li>
|
||||
@@ -627,6 +642,197 @@ but more than 150 is not recommended.</p>
|
||||
where Delta Chat is a private messenger for chatting with <a href="#groups">equal rights</a>.
|
||||
See <a href="https://en.wikipedia.org/wiki/Dunbar%27s_number">Dunbar’s number</a> for more insights.</p>
|
||||
|
||||
<h2 id="channels">
|
||||
|
||||
|
||||
Channels <a href="#channels" class="anchor"></a>
|
||||
|
||||
|
||||
</h2>
|
||||
|
||||
<p>Channels are a one-to-many tool for broadcasting messages.</p>
|
||||
|
||||
<h3 id="subscribe-to-a-channel">
|
||||
|
||||
|
||||
Subscribe to a channel <a href="#subscribe-to-a-channel" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>Scan the <img style="vertical-align:middle; height:1.3em; margin:1px" src="../qr-icon.png" /> <strong>QR code</strong>
|
||||
or tap the <strong>invite link</strong> you got from the channel owner.</li>
|
||||
</ul>
|
||||
|
||||
<p>That’s all!
|
||||
You will receive a few of the messages from the channel history
|
||||
and, from that point on, all new messages from the channel.</p>
|
||||
|
||||
<p><strong>Don’t worry,</strong> if that does not happen immediately.
|
||||
Once the channel owner comes online, your join request will be processed.</p>
|
||||
|
||||
<p>As all of Delta Chat, also Channels are private and decentralized,
|
||||
there is no public discovery.</p>
|
||||
|
||||
<p>Other channel subscribers will not see that you subscribed and cannot message you.
|
||||
The channel owner, however, can message you.
|
||||
They will also see that you read a message unless you have read receipts disabled.</p>
|
||||
|
||||
<p>If you do not want to share your main profile,
|
||||
you can also create a <a href="#multiple-accounts">dedicated profile</a> for joining a channel.</p>
|
||||
|
||||
<h3 id="create-a-channel">
|
||||
|
||||
|
||||
Create a channel <a href="#create-a-channel" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>Tap <strong>New Chat</strong> and choose <strong>New Channel</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Enter a <strong>name</strong>, optionally set an <strong>image</strong> and <strong>description</strong>, and hit the <strong>Create</strong> button.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>You can now send and manage messages as usual.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>From the channel’s profile, <strong>share the QR code or invite link with others</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Subscribers will receive your messages,
|
||||
but they cannot send messages in your channel.
|
||||
When subscribing, they will receive <strong>a few of the latest messages of the channel history</strong>.</p>
|
||||
|
||||
<p>You can see the <strong>view count</strong> beside each message.
|
||||
Note that this only counts subscribers who have read receipts enabled,
|
||||
so the real view count may be larger.</p>
|
||||
|
||||
<h3 id="how-many-subscribers-can-a-channel-have">
|
||||
|
||||
|
||||
How many subscribers can a channel have? <a href="#how-many-subscribers-can-a-channel-have" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Channels are designed for much larger audiences than <a href="#groups">groups</a>.</p>
|
||||
|
||||
<p>The practical limit depends on the used <a href="#relays">relay</a>,
|
||||
so there is no single fixed number that applies everywhere.</p>
|
||||
|
||||
<p>For really large channels with several tens of thousands of subscribers,
|
||||
we recommend using a <a href="#multiple-accounts">dedicated profile</a> for the channel
|
||||
and checking whether the relay is suitable.</p>
|
||||
|
||||
<p>But don’t be too hesitant: Delta Chat is designed to be relay-agnostic,
|
||||
so you can change your relay at any point easily -
|
||||
your existing subscribers will not even notice.
|
||||
You only have to update the invite link you share with new subscribers in that case.</p>
|
||||
|
||||
<h2 id="calls">
|
||||
|
||||
|
||||
Calls <a href="#calls" class="anchor"></a>
|
||||
|
||||
|
||||
</h2>
|
||||
|
||||
<p>Delta Chat supports one-to-one <strong>audio calls</strong> and <strong>video calls</strong>.</p>
|
||||
|
||||
<p>Calls are supported on Desktop, Ubuntu Touch, iOS and Android 8 and newer.</p>
|
||||
|
||||
<h3 id="place-a-call">
|
||||
|
||||
|
||||
Place a call <a href="#place-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>In a one-to-one chat, tap the 📞 <strong>call icon</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>This opens a small menu
|
||||
where you can choose whether to place an <strong>Audio Call</strong> or a <strong>Video Call</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="accept-or-reject-a-call">
|
||||
|
||||
|
||||
Accept or reject a call <a href="#accept-or-reject-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>When someone calls you,
|
||||
Delta Chat shows an <strong>incoming call screen</strong> or notification.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Tap <strong>Accept</strong> to answer
|
||||
or <strong>Decline</strong> to reject the call.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="during-a-call">
|
||||
|
||||
|
||||
During a call <a href="#during-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>You can <strong>mute</strong> your microphone.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>You can <strong>enable or disable your camera</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>On mobile, you can <strong>switch between front and back cameras</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Depending on the device, you can also select the audio output or use picture-in-picture.
|
||||
On desktop, the call is using a dedicated window
|
||||
and you can continue using the main Delta Chat window as usual.</p>
|
||||
|
||||
<h3 id="missed-calls-and-notifications">
|
||||
|
||||
|
||||
Missed calls and notifications <a href="#missed-calls-and-notifications" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>If you do not answer, do not hear the ringing, or do not have your device at hand,
|
||||
the call appears as a <strong>missed call</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Only your accepted contacts</strong> can make your device ring.
|
||||
Contact requests will appear as usual and will not ring.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>At <strong>Settings → Notifications → Calls</strong>,
|
||||
you can disable the special call ringing screen completely.
|
||||
If you do so, you will not be disturbed by any ringing notification,
|
||||
you can still pick up the call by tapping the incoming call message bubble in its chat.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="webxdc">
|
||||
|
||||
|
||||
@@ -1425,23 +1631,20 @@ can not be identified easily.</p>
|
||||
|
||||
</h3>
|
||||
|
||||
<p>The used <a href="#relays">relay</a> needs to know your IP Address,
|
||||
as well as sometimes your contact’s devices if you have a <a href="#experiments">call</a>
|
||||
<p>The used <a href="#relays">relays</a> need to know your IP Address,
|
||||
as well as sometimes your contact’s devices if you have a <a href="#calls">call</a>
|
||||
or use <a href="#webxdc">apps</a> together.</p>
|
||||
|
||||
<p>IP Addresses are needed for connectivity and efficiency.
|
||||
They are neither persisted nor exposed.
|
||||
Note that the IP Address
|
||||
is not like a detailed address you give to a delivery service,
|
||||
but much more coarse, often defining region or country only.</p>
|
||||
Delta Chat neither persists nor exposes them.
|
||||
Note that IP Addresses
|
||||
are not like an address you give to a delivery service,
|
||||
but typically less precise, often defining city or region only.</p>
|
||||
|
||||
<p>As this is just how the internet and other messengers work by default,
|
||||
we do not offer options here or ask upfront questions.</p>
|
||||
|
||||
<p>If you see your IP Address as a security or privacy risk,
|
||||
we recommend to use a VPN, in combination with system lockdown mode.
|
||||
Hunting down options in all apps on your system will leave gaps.
|
||||
For example, tapping a link exposes IP Addresses to unknown parties and is the by far larger risk here.</p>
|
||||
<p>If you see your IP Address as a risk,
|
||||
we recommend to use a VPN for the whole system.
|
||||
Per-app options leave gaps across your system.
|
||||
For example, tapping a link can expose IP Addresses to unknown parties, which is by far the larger risk.</p>
|
||||
|
||||
<h3 id="sealedsender">
|
||||
|
||||
|
||||
@@ -29,6 +29,21 @@
|
||||
<li><a href="#quanti-membri-possono-partecipare-a-un-singolo-gruppo">Quanti membri possono partecipare a un singolo gruppo?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#channels">Channels</a>
|
||||
<ul>
|
||||
<li><a href="#subscribe-to-a-channel">Subscribe to a channel</a></li>
|
||||
<li><a href="#create-a-channel">Create a channel</a></li>
|
||||
<li><a href="#how-many-subscribers-can-a-channel-have">How many subscribers can a channel have?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#calls">Calls</a>
|
||||
<ul>
|
||||
<li><a href="#place-a-call">Place a call</a></li>
|
||||
<li><a href="#accept-or-reject-a-call">Accept or reject a call</a></li>
|
||||
<li><a href="#during-a-call">During a call</a></li>
|
||||
<li><a href="#missed-calls-and-notifications">Missed calls and notifications</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#webxdc">Apps in chat</a>
|
||||
<ul>
|
||||
<li><a href="#dove-posso-trovare-le-apps-in-chat">Dove posso trovare le apps in chat?</a></li>
|
||||
@@ -620,6 +635,197 @@ ma non è consigliabile superare i 150.</p>
|
||||
dove Delta Chat è un servizio di messaggistica privato per chattare con <a href="#groups">uguali diritti</a>.
|
||||
Vedi <a href="https://en.wikipedia.org/wiki/Dunbar%27s_number">numero di Dunbar</a> per ulteriori approfondimenti.</p>
|
||||
|
||||
<h2 id="channels">
|
||||
|
||||
|
||||
Channels <a href="#channels" class="anchor"></a>
|
||||
|
||||
|
||||
</h2>
|
||||
|
||||
<p>Channels are a one-to-many tool for broadcasting messages.</p>
|
||||
|
||||
<h3 id="subscribe-to-a-channel">
|
||||
|
||||
|
||||
Subscribe to a channel <a href="#subscribe-to-a-channel" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>Scan the <img style="vertical-align:middle; height:1.3em; margin:1px" src="../qr-icon.png" /> <strong>QR code</strong>
|
||||
or tap the <strong>invite link</strong> you got from the channel owner.</li>
|
||||
</ul>
|
||||
|
||||
<p>That’s all!
|
||||
You will receive a few of the messages from the channel history
|
||||
and, from that point on, all new messages from the channel.</p>
|
||||
|
||||
<p><strong>Don’t worry,</strong> if that does not happen immediately.
|
||||
Once the channel owner comes online, your join request will be processed.</p>
|
||||
|
||||
<p>As all of Delta Chat, also Channels are private and decentralized,
|
||||
there is no public discovery.</p>
|
||||
|
||||
<p>Other channel subscribers will not see that you subscribed and cannot message you.
|
||||
The channel owner, however, can message you.
|
||||
They will also see that you read a message unless you have read receipts disabled.</p>
|
||||
|
||||
<p>If you do not want to share your main profile,
|
||||
you can also create a <a href="#multiple-accounts">dedicated profile</a> for joining a channel.</p>
|
||||
|
||||
<h3 id="create-a-channel">
|
||||
|
||||
|
||||
Create a channel <a href="#create-a-channel" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>Tap <strong>New Chat</strong> and choose <strong>New Channel</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Enter a <strong>name</strong>, optionally set an <strong>image</strong> and <strong>description</strong>, and hit the <strong>Create</strong> button.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>You can now send and manage messages as usual.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>From the channel’s profile, <strong>share the QR code or invite link with others</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Subscribers will receive your messages,
|
||||
but they cannot send messages in your channel.
|
||||
When subscribing, they will receive <strong>a few of the latest messages of the channel history</strong>.</p>
|
||||
|
||||
<p>You can see the <strong>view count</strong> beside each message.
|
||||
Note that this only counts subscribers who have read receipts enabled,
|
||||
so the real view count may be larger.</p>
|
||||
|
||||
<h3 id="how-many-subscribers-can-a-channel-have">
|
||||
|
||||
|
||||
How many subscribers can a channel have? <a href="#how-many-subscribers-can-a-channel-have" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Channels are designed for much larger audiences than <a href="#groups">groups</a>.</p>
|
||||
|
||||
<p>The practical limit depends on the used <a href="#relays">relay</a>,
|
||||
so there is no single fixed number that applies everywhere.</p>
|
||||
|
||||
<p>For really large channels with several tens of thousands of subscribers,
|
||||
we recommend using a <a href="#multiple-accounts">dedicated profile</a> for the channel
|
||||
and checking whether the relay is suitable.</p>
|
||||
|
||||
<p>But don’t be too hesitant: Delta Chat is designed to be relay-agnostic,
|
||||
so you can change your relay at any point easily -
|
||||
your existing subscribers will not even notice.
|
||||
You only have to update the invite link you share with new subscribers in that case.</p>
|
||||
|
||||
<h2 id="calls">
|
||||
|
||||
|
||||
Calls <a href="#calls" class="anchor"></a>
|
||||
|
||||
|
||||
</h2>
|
||||
|
||||
<p>Delta Chat supports one-to-one <strong>audio calls</strong> and <strong>video calls</strong>.</p>
|
||||
|
||||
<p>Calls are supported on Desktop, Ubuntu Touch, iOS and Android 8 and newer.</p>
|
||||
|
||||
<h3 id="place-a-call">
|
||||
|
||||
|
||||
Place a call <a href="#place-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>In a one-to-one chat, tap the 📞 <strong>call icon</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>This opens a small menu
|
||||
where you can choose whether to place an <strong>Audio Call</strong> or a <strong>Video Call</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="accept-or-reject-a-call">
|
||||
|
||||
|
||||
Accept or reject a call <a href="#accept-or-reject-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>When someone calls you,
|
||||
Delta Chat shows an <strong>incoming call screen</strong> or notification.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Tap <strong>Accept</strong> to answer
|
||||
or <strong>Decline</strong> to reject the call.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="during-a-call">
|
||||
|
||||
|
||||
During a call <a href="#during-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>You can <strong>mute</strong> your microphone.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>You can <strong>enable or disable your camera</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>On mobile, you can <strong>switch between front and back cameras</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Depending on the device, you can also select the audio output or use picture-in-picture.
|
||||
On desktop, the call is using a dedicated window
|
||||
and you can continue using the main Delta Chat window as usual.</p>
|
||||
|
||||
<h3 id="missed-calls-and-notifications">
|
||||
|
||||
|
||||
Missed calls and notifications <a href="#missed-calls-and-notifications" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>If you do not answer, do not hear the ringing, or do not have your device at hand,
|
||||
the call appears as a <strong>missed call</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Only your accepted contacts</strong> can make your device ring.
|
||||
Contact requests will appear as usual and will not ring.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>At <strong>Settings → Notifications → Calls</strong>,
|
||||
you can disable the special call ringing screen completely.
|
||||
If you do so, you will not be disturbed by any ringing notification,
|
||||
you can still pick up the call by tapping the incoming call message bubble in its chat.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="webxdc">
|
||||
|
||||
|
||||
@@ -1412,23 +1618,20 @@ non possono essere identificati facilmente.</p>
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Il <a href="#relays">ripetitore</a> utilizzato deve conoscere il tuo indirizzo IP,
|
||||
e talvolta anche i dispositivi dei tuoi contatti se avete una <a href="#experiments">chiamata</a>
|
||||
o utilizzate <a href="#webxdc">apps</a> insieme.</p>
|
||||
<p>The used <a href="#relays">relays</a> need to know your IP Address,
|
||||
as well as sometimes your contact’s devices if you have a <a href="#calls">call</a>
|
||||
or use <a href="#webxdc">apps</a> together.</p>
|
||||
|
||||
<p>Gli indirizzi IP sono necessari per la connettività e l’efficienza.
|
||||
Non sono né persistenti né esposti.
|
||||
Si noti che l’indirizzo IP
|
||||
non è come un indirizzo dettagliato che si fornisce a un servizio di consegna,
|
||||
ma molto più generico, che spesso definisce solo la regione o il paese.</p>
|
||||
<p>IP Addresses are needed for connectivity and efficiency.
|
||||
Delta Chat neither persists nor exposes them.
|
||||
Note that IP Addresses
|
||||
are not like an address you give to a delivery service,
|
||||
but typically less precise, often defining city or region only.</p>
|
||||
|
||||
<p>Poiché questo è il modo in cui Internet e altri servizi di messaggistica funzionano di default,
|
||||
non offriamo opzioni né poniamo domande in anticipo.</p>
|
||||
|
||||
<p>Se ritieni che il tuo indirizzo IP rappresenti un rischio per la sicurezza o la privacy,
|
||||
ti consigliamo di utilizzare una VPN, in combinazione con la modalità di blocco del sistema.
|
||||
Esplorare le opzioni in tutte le app del tuo sistema lascerà delle lacune.
|
||||
Ad esempio, cliccare su un link espone gli indirizzi IP a sconosciuti e rappresenta il rischio di gran lunga maggiore.</p>
|
||||
<p>If you see your IP Address as a risk,
|
||||
we recommend to use a VPN for the whole system.
|
||||
Per-app options leave gaps across your system.
|
||||
For example, tapping a link can expose IP Addresses to unknown parties, which is by far the larger risk.</p>
|
||||
|
||||
<h3 id="sealedsender">
|
||||
|
||||
|
||||
@@ -29,6 +29,21 @@
|
||||
<li><a href="#how-many-members-can-participate-in-a-single-group">How many members can participate in a single group?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#channels">Channels</a>
|
||||
<ul>
|
||||
<li><a href="#subscribe-to-a-channel">Subscribe to a channel</a></li>
|
||||
<li><a href="#create-a-channel">Create a channel</a></li>
|
||||
<li><a href="#how-many-subscribers-can-a-channel-have">How many subscribers can a channel have?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#calls">Calls</a>
|
||||
<ul>
|
||||
<li><a href="#place-a-call">Place a call</a></li>
|
||||
<li><a href="#accept-or-reject-a-call">Accept or reject a call</a></li>
|
||||
<li><a href="#during-a-call">During a call</a></li>
|
||||
<li><a href="#missed-calls-and-notifications">Missed calls and notifications</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#webxdc">In-chat apps</a>
|
||||
<ul>
|
||||
<li><a href="#where-can-i-get-in-chat-apps">Where can I get in-chat apps?</a></li>
|
||||
@@ -622,6 +637,197 @@ but more than 150 is not recommended.</p>
|
||||
where Delta Chat is a private messenger for chatting with <a href="#groups">equal rights</a>.
|
||||
See <a href="https://en.wikipedia.org/wiki/Dunbar%27s_number">Dunbar’s number</a> for more insights.</p>
|
||||
|
||||
<h2 id="channels">
|
||||
|
||||
|
||||
Channels <a href="#channels" class="anchor"></a>
|
||||
|
||||
|
||||
</h2>
|
||||
|
||||
<p>Channels are a one-to-many tool for broadcasting messages.</p>
|
||||
|
||||
<h3 id="subscribe-to-a-channel">
|
||||
|
||||
|
||||
Subscribe to a channel <a href="#subscribe-to-a-channel" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>Scan the <img style="vertical-align:middle; height:1.3em; margin:1px" src="../qr-icon.png" /> <strong>QR code</strong>
|
||||
or tap the <strong>invite link</strong> you got from the channel owner.</li>
|
||||
</ul>
|
||||
|
||||
<p>That’s all!
|
||||
You will receive a few of the messages from the channel history
|
||||
and, from that point on, all new messages from the channel.</p>
|
||||
|
||||
<p><strong>Don’t worry,</strong> if that does not happen immediately.
|
||||
Once the channel owner comes online, your join request will be processed.</p>
|
||||
|
||||
<p>As all of Delta Chat, also Channels are private and decentralized,
|
||||
there is no public discovery.</p>
|
||||
|
||||
<p>Other channel subscribers will not see that you subscribed and cannot message you.
|
||||
The channel owner, however, can message you.
|
||||
They will also see that you read a message unless you have read receipts disabled.</p>
|
||||
|
||||
<p>If you do not want to share your main profile,
|
||||
you can also create a <a href="#multiple-accounts">dedicated profile</a> for joining a channel.</p>
|
||||
|
||||
<h3 id="create-a-channel">
|
||||
|
||||
|
||||
Create a channel <a href="#create-a-channel" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>Tap <strong>New Chat</strong> and choose <strong>New Channel</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Enter a <strong>name</strong>, optionally set an <strong>image</strong> and <strong>description</strong>, and hit the <strong>Create</strong> button.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>You can now send and manage messages as usual.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>From the channel’s profile, <strong>share the QR code or invite link with others</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Subscribers will receive your messages,
|
||||
but they cannot send messages in your channel.
|
||||
When subscribing, they will receive <strong>a few of the latest messages of the channel history</strong>.</p>
|
||||
|
||||
<p>You can see the <strong>view count</strong> beside each message.
|
||||
Note that this only counts subscribers who have read receipts enabled,
|
||||
so the real view count may be larger.</p>
|
||||
|
||||
<h3 id="how-many-subscribers-can-a-channel-have">
|
||||
|
||||
|
||||
How many subscribers can a channel have? <a href="#how-many-subscribers-can-a-channel-have" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Channels are designed for much larger audiences than <a href="#groups">groups</a>.</p>
|
||||
|
||||
<p>The practical limit depends on the used <a href="#relays">relay</a>,
|
||||
so there is no single fixed number that applies everywhere.</p>
|
||||
|
||||
<p>For really large channels with several tens of thousands of subscribers,
|
||||
we recommend using a <a href="#multiple-accounts">dedicated profile</a> for the channel
|
||||
and checking whether the relay is suitable.</p>
|
||||
|
||||
<p>But don’t be too hesitant: Delta Chat is designed to be relay-agnostic,
|
||||
so you can change your relay at any point easily -
|
||||
your existing subscribers will not even notice.
|
||||
You only have to update the invite link you share with new subscribers in that case.</p>
|
||||
|
||||
<h2 id="calls">
|
||||
|
||||
|
||||
Calls <a href="#calls" class="anchor"></a>
|
||||
|
||||
|
||||
</h2>
|
||||
|
||||
<p>Delta Chat supports one-to-one <strong>audio calls</strong> and <strong>video calls</strong>.</p>
|
||||
|
||||
<p>Calls are supported on Desktop, Ubuntu Touch, iOS and Android 8 and newer.</p>
|
||||
|
||||
<h3 id="place-a-call">
|
||||
|
||||
|
||||
Place a call <a href="#place-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>In a one-to-one chat, tap the 📞 <strong>call icon</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>This opens a small menu
|
||||
where you can choose whether to place an <strong>Audio Call</strong> or a <strong>Video Call</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="accept-or-reject-a-call">
|
||||
|
||||
|
||||
Accept or reject a call <a href="#accept-or-reject-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>When someone calls you,
|
||||
Delta Chat shows an <strong>incoming call screen</strong> or notification.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Tap <strong>Accept</strong> to answer
|
||||
or <strong>Decline</strong> to reject the call.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="during-a-call">
|
||||
|
||||
|
||||
During a call <a href="#during-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>You can <strong>mute</strong> your microphone.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>You can <strong>enable or disable your camera</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>On mobile, you can <strong>switch between front and back cameras</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Depending on the device, you can also select the audio output or use picture-in-picture.
|
||||
On desktop, the call is using a dedicated window
|
||||
and you can continue using the main Delta Chat window as usual.</p>
|
||||
|
||||
<h3 id="missed-calls-and-notifications">
|
||||
|
||||
|
||||
Missed calls and notifications <a href="#missed-calls-and-notifications" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>If you do not answer, do not hear the ringing, or do not have your device at hand,
|
||||
the call appears as a <strong>missed call</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Only your accepted contacts</strong> can make your device ring.
|
||||
Contact requests will appear as usual and will not ring.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>At <strong>Settings → Notifications → Calls</strong>,
|
||||
you can disable the special call ringing screen completely.
|
||||
If you do so, you will not be disturbed by any ringing notification,
|
||||
you can still pick up the call by tapping the incoming call message bubble in its chat.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="webxdc">
|
||||
|
||||
|
||||
@@ -1419,23 +1625,20 @@ can not be identified easily.</p>
|
||||
|
||||
</h3>
|
||||
|
||||
<p>The used <a href="#relays">relay</a> needs to know your IP Address,
|
||||
as well as sometimes your contact’s devices if you have a <a href="#experiments">call</a>
|
||||
<p>The used <a href="#relays">relays</a> need to know your IP Address,
|
||||
as well as sometimes your contact’s devices if you have a <a href="#calls">call</a>
|
||||
or use <a href="#webxdc">apps</a> together.</p>
|
||||
|
||||
<p>IP Addresses are needed for connectivity and efficiency.
|
||||
They are neither persisted nor exposed.
|
||||
Note that the IP Address
|
||||
is not like a detailed address you give to a delivery service,
|
||||
but much more coarse, often defining region or country only.</p>
|
||||
Delta Chat neither persists nor exposes them.
|
||||
Note that IP Addresses
|
||||
are not like an address you give to a delivery service,
|
||||
but typically less precise, often defining city or region only.</p>
|
||||
|
||||
<p>As this is just how the internet and other messengers work by default,
|
||||
we do not offer options here or ask upfront questions.</p>
|
||||
|
||||
<p>If you see your IP Address as a security or privacy risk,
|
||||
we recommend to use a VPN, in combination with system lockdown mode.
|
||||
Hunting down options in all apps on your system will leave gaps.
|
||||
For example, tapping a link exposes IP Addresses to unknown parties and is the by far larger risk here.</p>
|
||||
<p>If you see your IP Address as a risk,
|
||||
we recommend to use a VPN for the whole system.
|
||||
Per-app options leave gaps across your system.
|
||||
For example, tapping a link can expose IP Addresses to unknown parties, which is by far the larger risk.</p>
|
||||
|
||||
<h3 id="sealedsender">
|
||||
|
||||
|
||||
+275
-124
@@ -2,18 +2,18 @@
|
||||
<html lang="pl"><head><meta charset="UTF-8" /><meta name="viewport" content="initial-scale=1.0" /><link rel="stylesheet" href="../help.css" /></head><body><ul id="top">
|
||||
<li><a href="#czym-jest-delta-chat">Czym jest Delta Chat?</a>
|
||||
<ul>
|
||||
<li><a href="#howtoe2ee">How can I find people to chat with?</a></li>
|
||||
<li><a href="#why-is-a-chat-marked-as-request">Why is a chat marked as “Request”?</a></li>
|
||||
<li><a href="#how-can-i-put-two-of-my-friends-in-contact-with-each-other">How can I put two of my friends in contact with each other?</a></li>
|
||||
<li><a href="#howtoe2ee">Jak znaleźć osoby do czatu?</a></li>
|
||||
<li><a href="#dlaczego-czat-jest-oznaczony-jako-prośba">Dlaczego czat jest oznaczony jako „Prośba”?</a></li>
|
||||
<li><a href="#jak-mogę-skontaktować-ze-sobą-dwóch-znajomych">Jak mogę skontaktować ze sobą dwóch znajomych?</a></li>
|
||||
<li><a href="#multiple-accounts">Czym są profile? Jak mogę przełączać się między nimi?</a></li>
|
||||
<li><a href="#kto-widzi-moje-zdjęcie-profilowe">Kto widzi moje zdjęcie profilowe?</a></li>
|
||||
<li><a href="#signature">Can I set a Bio/Status with Delta Chat?</a></li>
|
||||
<li><a href="#signature">Czy w Delta Chat mogę ustawić biografię/status?</a></li>
|
||||
<li><a href="#co-oznacza-przypinanie-wyciszanie-i-archiwizowanie">Co oznacza przypinanie, wyciszanie i archiwizowanie?</a></li>
|
||||
<li><a href="#save">Jak działają „Zapisane wiadomości”?</a></li>
|
||||
<li><a href="#co-oznacza-zielona-kropka">Co oznacza zielona kropka?</a></li>
|
||||
<li><a href="#co-oznaczają-znaczniki-wyświetlane-obok-wiadomości-wychodzących">Co oznaczają znaczniki wyświetlane obok wiadomości wychodzących?</a></li>
|
||||
<li><a href="#edit">Poprawianie literówek i usuwanie wiadomości po wysłaniu</a></li>
|
||||
<li><a href="#mediaquality">How is media quality handled?</a></li>
|
||||
<li><a href="#mediaquality">Jak obsługiwana jest jakość multimediów?</a></li>
|
||||
<li><a href="#ephemeralmsgs">Jak działają znikające wiadomości?</a></li>
|
||||
<li><a href="#delold">Co się stanie, jeśli włączę opcję „Usuń wiadomości z urządzenia”?</a></li>
|
||||
<li><a href="#remove-account">How can I delete my chat profile?</a></li>
|
||||
@@ -29,6 +29,21 @@
|
||||
<li><a href="#how-many-members-can-participate-in-a-single-group">How many members can participate in a single group?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#channels">Channels</a>
|
||||
<ul>
|
||||
<li><a href="#subscribe-to-a-channel">Subscribe to a channel</a></li>
|
||||
<li><a href="#create-a-channel">Create a channel</a></li>
|
||||
<li><a href="#how-many-subscribers-can-a-channel-have">How many subscribers can a channel have?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#calls">Calls</a>
|
||||
<ul>
|
||||
<li><a href="#place-a-call">Place a call</a></li>
|
||||
<li><a href="#accept-or-reject-a-call">Accept or reject a call</a></li>
|
||||
<li><a href="#during-a-call">During a call</a></li>
|
||||
<li><a href="#missed-calls-and-notifications">Missed calls and notifications</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#webxdc">In-chat apps</a>
|
||||
<ul>
|
||||
<li><a href="#where-can-i-get-in-chat-apps">Where can I get in-chat apps?</a></li>
|
||||
@@ -107,87 +122,67 @@
|
||||
|
||||
<p>Delta Chat to niezawodna, zdecentralizowana i bezpieczna aplikacja do błyskawicznego przesyłania wiadomości, dostępna na platformy mobilne i stacjonarne.</p>
|
||||
|
||||
<p>Natychmiastowe tworzenie <strong>prywatnych profili czatu</strong> z bezpiecznymi i interoperacyjnymi <a href="https://chatmail.at/relays">przekaźnikami chatmail</a>, które oferują natychmiastowe dostarczanie wiadomości oraz powiadomienia push dla urządzeń z systemem iOS i Android.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>Instant creation of <strong>private chat profiles</strong>
|
||||
with secure and interoperable <a href="https://chatmail.at/relays">chatmail relays</a>
|
||||
that offer instant message delivery, and Push Notifications for iOS and Android devices.</p>
|
||||
<p>Wszechstronna obsługa <a href="#multiple-accounts">wielu profili</a> i <a href="#multiclient">wielu urządzeń</a> na wszystkich platformach i między różnymi <a href="https://chatmail.at/clients">aplikacjami chatmail</a>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Pervasive <a href="#multiple-accounts">multi-profile</a> and
|
||||
<a href="#multiclient">multi-device</a> support on all platforms
|
||||
and between different <a href="https://chatmail.at/clients">chatmail apps</a>.</p>
|
||||
<p>Interaktywne <a href="#webxdc">aplikacje do czatu</a> w grach i do współpracy</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Interactive <a href="#webxdc">in-chat apps</a> for gaming and collaboration</p>
|
||||
<p><a href="#security-audits">Audytowne szyfrowanie end-to-end</a> zabezpieczające przed atakami sieciowymi i serwerowymi.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="#security-audits">Audited end-to-end encryption</a>
|
||||
safe against network and server attacks.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Free and Open Source software, both app and server side,
|
||||
built on <a href="https://github.com/chatmail/core/blob/main/standards.md#standards-used-in-delta-chat">Internet Standards</a>.</p>
|
||||
<p>Bezpłatne i otwartoźródłowe oprogramowanie zarówno po stronie aplikacji, jak i serwera, stworzone w oparciu o <a href="https://github.com/chatmail/core/blob/main/standards.md#standards-used-in-delta-chat">standardy internetowe</a>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="howtoe2ee">
|
||||
|
||||
|
||||
How can I find people to chat with? <a href="#howtoe2ee" class="anchor"></a>
|
||||
Jak znaleźć osoby do czatu? <a href="#howtoe2ee" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>First, note that Delta Chat is a private messenger.
|
||||
There is no public discovery, <em>you</em> decide about your contacts.</p>
|
||||
<p>Najpierw pamiętaj, że Delta Chat to prywatny komunikator. Nie ma możliwości publicznego wyszukiwania, sam decydujesz o swoich kontaktach.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>If you are <strong>face to face</strong> with your friend or family,
|
||||
tap the <strong>QR Code</strong> icon <img style="vertical-align:middle; height:1.3em; margin:1px" src="../qr-icon.png" />
|
||||
on the main screen.<br />
|
||||
Ask your chat partner to <strong>scan</strong> the QR image
|
||||
with their Delta Chat app.</p>
|
||||
<p>Jeśli jesteś twarzą w twarz ze znajomym lub rodziną, dotknij ikony <img style="vertical-align:middle; height:1.3em; margin:1px" src="../qr-icon.png" /> <strong>kodu QR</strong> na ekranie głównym.
|
||||
Poproś partnera czatu o <strong>zeskanowanie</strong> obrazu QR za pomocą aplikacji Delta Chat.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>For a <strong>remote</strong> contact setup,
|
||||
from the same screen,
|
||||
click “Copy” or “Share” and send the <strong>invite link</strong>
|
||||
through another private chat.</p>
|
||||
<p>Aby skonfigurować kontakt <strong>zdalny</strong>, na tym samym ekranie naciśnij „Kopiuj” lub „Udostępnij” i wyślij <strong>link zaproszenia</strong> za pośrednictwem innego prywatnego czatu.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Now wait while connection gets established.</p>
|
||||
<p>Poczekaj, aż połączenie zostanie nawiązane.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>If both sides are online, they will soon see a chat
|
||||
and can start messaging securely.</p>
|
||||
<p>Jeśli obie strony są online, wkrótce zobaczą czat i będą mogły bezpiecznie wysyłać wiadomości.</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>Jeśli jedna ze stron jest offline lub ma słaby zasięg, możliwość czatowania zostanie wstrzymana do czasu przywrócenia połączenia.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Congratulations!
|
||||
You now will automatically use <a href="#e2ee">end-to-end encryption</a> with this contact.
|
||||
If you add each other to <a href="#groups">groups</a>, end-to-end encryption will be established among all members.</p>
|
||||
<p>Gratulacje! Teraz będziesz automatycznie korzystać z <a href="#e2ee">szyfrowania typu end-to-end</a> dla tego kontaktu. Jeśli dodacie się nawzajem do <a href="#groups">grup</a>, szyfrowanie typu end-to-end zostanie nawiązane między wszystkimi członkami.</p>
|
||||
|
||||
<h3 id="why-is-a-chat-marked-as-request">
|
||||
<h3 id="dlaczego-czat-jest-oznaczony-jako-prośba">
|
||||
|
||||
|
||||
Why is a chat marked as “Request”? <a href="#why-is-a-chat-marked-as-request" class="anchor"></a>
|
||||
Dlaczego czat jest oznaczony jako „Prośba”? <a href="#dlaczego-czat-jest-oznaczony-jako-prośba" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>As being a private messenger,
|
||||
only friends and family you <a href="#howtoe2ee">share your QR code or invite link with</a> can write to you.</p>
|
||||
<p>Ponieważ jest to prywatny komunikator, tylko znajomi i rodzina, którym <a href="#howtoe2ee">udostępnisz swój kod QR lub link zaproszenia</a>, mogą do ciebie pisać.</p>
|
||||
|
||||
<p>Your friends may share your contact with other friends,
|
||||
this appears as <b style="border: 1px solid currentColor; padding: 0 3px; font-size:90%">Request</b></p>
|
||||
<p>Twoi znajomi mogą udostępniać twoje dane kontaktowe innym znajomym, co jest oznaczone jako <b style="border: 1px solid currentColor; padding: 0 3px; font-size:90%">Prośba</b></p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
@@ -201,19 +196,17 @@ this appears as <b style="border: 1px solid currentColor; padding: 0 3px; font-s
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="how-can-i-put-two-of-my-friends-in-contact-with-each-other">
|
||||
<h3 id="jak-mogę-skontaktować-ze-sobą-dwóch-znajomych">
|
||||
|
||||
|
||||
How can I put two of my friends in contact with each other? <a href="#how-can-i-put-two-of-my-friends-in-contact-with-each-other" class="anchor"></a>
|
||||
Jak mogę skontaktować ze sobą dwóch znajomych? <a href="#jak-mogę-skontaktować-ze-sobą-dwóch-znajomych" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Attach the first contact to the chat of the second using <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Attachment Button → Contact</strong>.
|
||||
You can also add a little introduction message.</p>
|
||||
<p>Dołącz pierwszy kontakt do czatu drugiego, używając przycisku <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Dołączania → Kontakt</strong>. Możesz również dodać krótką wiadomość powitalną.</p>
|
||||
|
||||
<p>The second contact will receive a <strong>card</strong> then
|
||||
and can tap it to start chatting with the first contact.</p>
|
||||
<p>Drugi kontakt otrzyma wtedy <strong>kartkę</strong> i może ją nacisnąć, aby rozpocząć czat z pierwszym kontaktem.</p>
|
||||
|
||||
<h3 id="multiple-accounts">
|
||||
|
||||
@@ -223,15 +216,13 @@ and can tap it to start chatting with the first contact.</p>
|
||||
|
||||
</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 the server only to relay messages.</p>
|
||||
<p>Profil składa się z <strong>nazwy, zdjęcia</strong> i dodatkowych informacji służących do szyfrowania wiadomości. Profil jest dostępny tylko na twoim urządzeniu (urządzeniach) i korzysta z serwera wyłącznie do przekazywania wiadomości.</p>
|
||||
|
||||
<p>Podczas pierwszej instalacji Delta Chat tworzony jest pierwszy profil.</p>
|
||||
|
||||
<p>Później możesz dotknąć swojego zdjęcia profilowego w lewym górnym rogu, aby <strong>Dodać profile</strong> lub <strong>Przełączyć profile</strong>.</p>
|
||||
|
||||
<p>You may want to use separate profiles for political, family or work related activities.</p>
|
||||
<p>Możesz używać osobnych profili dla aktywności politycznych, rodzinnych lub zawodowych.</p>
|
||||
|
||||
<p>Możesz także dowiedzieć się, <a href="#multiclient">jak używać tego samego profilu na wielu urządzeniach</a>.</p>
|
||||
|
||||
@@ -243,22 +234,19 @@ and uses the server only to relay messages.</p>
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Możesz dodać zdjęcie profilowe w swoich ustawieniach. Jeśli napiszesz do swoich kontaktów lub dodasz je za pomocą kodu QR, automatycznie zobaczą je jako Twoje zdjęcie profilowe.</p>
|
||||
<p>Możesz dodać zdjęcie profilowe w swoich ustawieniach. Jeśli napiszesz do swoich kontaktów lub dodasz je za pomocą kodu QR, automatycznie zobaczą je jako twoje zdjęcie profilowe.</p>
|
||||
|
||||
<p>Ze względów prywatności nikt nie widzi Twojego zdjęcia profilowego, dopóki nie napiszesz do niego wiadomości.</p>
|
||||
<p>Ze względów prywatności nikt nie widzi twojego zdjęcia profilowego, dopóki nie napiszesz do niego wiadomości.</p>
|
||||
|
||||
<h3 id="signature">
|
||||
|
||||
|
||||
Can I set a Bio/Status with Delta Chat? <a href="#signature" class="anchor"></a>
|
||||
Czy w Delta Chat mogę ustawić biografię/status? <a href="#signature" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Yes,
|
||||
you can do so under <strong>Settings → Profile → Bio</strong>.
|
||||
Once you sent a message to a contact,
|
||||
they will see it when they view your contact details.</p>
|
||||
<p>Tak, możesz to zrobić w <strong>Ustawieniach → Profil → Biografia</strong>. Po wysłaniu wiadomości do kontaktu zostanie ona wyświetlona, gdy będzie on przeglądał twoje dane kontaktowe.</p>
|
||||
|
||||
<h3 id="co-oznacza-przypinanie-wyciszanie-i-archiwizowanie">
|
||||
|
||||
@@ -278,7 +266,7 @@ they will see it when they view your contact details.</p>
|
||||
<p><strong>Wycisz czaty</strong>, jeśli nie chcesz otrzymywać z nich powiadomień. Wyciszone czaty pozostają na swoim miejscu i możesz też przypiąć wyciszony czat.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Archiwizuj czaty</strong>, jeśli nie chcesz ich już widzieć na liście czatów. Zarchiwizowane czaty pozostają dostępne nad listą czatów lub poprzez wyszukiwanie.</p>
|
||||
<p><strong>Archiwizuj czaty</strong>, jeśli nie chcesz ich już widzieć na liście czatów. Pozostają dostępne nad listą czatów lub poprzez wyszukiwanie i są oznaczone jako <b style="border: 1px solid currentColor; padding: 0 3px; font-size:90%">Zarchiwizowane</b></p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Gdy zarchiwizowany czat otrzyma nową wiadomość, o ile nie zostanie wyciszony, <strong>wyskoczy z archiwum</strong> i wróci na twoją listę czatów.
|
||||
@@ -309,7 +297,7 @@ they will see it when they view your contact details.</p>
|
||||
<p>Później otwórz czat „Zapisane wiadomości” — zobaczysz tam zapisane wiadomości. Naciskając <img style="vertical-align:middle; width:1.2em; margin:1px" src="../go-to-original.png" alt="ikona strzałki w prawo" />, możesz wrócić do oryginalnej wiadomości w oryginalnym czacie</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Na koniec możesz również użyć „Zapisz wiadomości”, aby robić <strong>osobiste notatki</strong> — otwórz czat, wpisz coś, dodaj zdjęcie lub wiadomość głosową itp.</p>
|
||||
<p>Na koniec możesz również użyć „Zapisanych wiadomości”, aby robić <strong>osobiste notatki</strong> — otwórz czat, wpisz coś, dodaj zdjęcie lub wiadomość głosową itp.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Ponieważ „Zapisane wiadomości” są zsynchronizowane, mogą być bardzo przydatne do przesyłania danych między urządzeniami</p>
|
||||
@@ -326,13 +314,9 @@ they will see it when they view your contact details.</p>
|
||||
|
||||
</h3>
|
||||
|
||||
<p>You can sometimes see a <strong>green dot</strong> <img style="vertical-align:middle; width:1.2em; margin:1px" src="../green-dot.png" alt="" />
|
||||
next to the avatar of a contact.
|
||||
It means they were <strong>recently seen by you</strong> in the last 10 minutes,
|
||||
e.g. because they messaged you or sent a read receipt.</p>
|
||||
<p>Czasami można zobaczyć <strong>zieloną kropkę</strong> <img style="vertical-align:middle; width:1.2em; margin:1px" src="../green-dot.png" alt="" /> obok awatara kontaktu. Oznacza to, że był on <strong>niedawno widziany przez ciebie</strong> w ciągu ostatnich 10 minut, np. wysłał ci wiadomość lub potwierdzenie odczytu.</p>
|
||||
|
||||
<p>So this is not a real time online status
|
||||
and others will as well not always see that you are “online”.</p>
|
||||
<p>Nie jest to więc status online w czasie rzeczywistym i inni również nie zawsze zobaczą, że jesteś „online”.</p>
|
||||
|
||||
<h3 id="co-oznaczają-znaczniki-wyświetlane-obok-wiadomości-wychodzących">
|
||||
|
||||
@@ -344,19 +328,16 @@ and others will as well not always see that you are “online”.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p><strong>One tick</strong> <img style="vertical-align:middle; width:1.5em; margin:1px" src="../tick1.png" alt="" />
|
||||
means that the message was sent successfully to the <a href="#relays">relay</a>.</p>
|
||||
<p><strong>Jeden znacznik</strong> <img style="vertical-align:middle; width:1.5em; margin:1px" src="../tick1.png" alt="" /> oznacza, że wiadomość została pomyślnie wysłana do <a href="#relays">przekaźnika</a>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Two ticks</strong> <img style="vertical-align:middle; width:1.5em; margin:1px" src="../tick2.png" alt="" />
|
||||
indicate your contact has read the message.</p>
|
||||
<p><strong>Dwa znaczniki</strong> <img style="vertical-align:middle; width:1.5em; margin:1px" src="../tick2.png" alt="" /> oznaczają, że twój kontakt przeczytał wiadomość.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>In <a href="#groups">groups</a> the second tick means that at least one member has reported back having read the message.</p>
|
||||
<p>W <a href="#groups">grupach</a> drugi znacznik oznacza, że co najmniej jeden członek potwierdził przeczytanie wiadomości.</p>
|
||||
|
||||
<p>You will only get the second tick if both you and one of the recipients who read the message
|
||||
has <strong>Settings → Chats → Read Receipts</strong> enabled.</p>
|
||||
<p>Drugi znacznik pojawi się tylko wtedy, gdy ty i jeden z odbiorców, którzy przeczytali wiadomość, macie włączoną opcję <strong>Ustawienia → Czaty → Potwierdzenie odczytu</strong>.</p>
|
||||
|
||||
<h3 id="edit">
|
||||
|
||||
@@ -382,26 +363,22 @@ has <strong>Settings → Chats → Read Receipts</strong> enabled.</p>
|
||||
<h3 id="mediaquality">
|
||||
|
||||
|
||||
How is media quality handled? <a href="#mediaquality" class="anchor"></a>
|
||||
Jak obsługiwana jest jakość multimediów? <a href="#mediaquality" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Images, videos, files, voice messages etc. can be sent using the <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Attach-</strong>
|
||||
or <img style="vertical-align:middle; width:0.8em; margin:1px" src="../mic.png" alt="Microphone" /> <strong>Voice Message</strong> buttons.</p>
|
||||
<p>Obrazy, filmy, pliki, wiadomości głosowe itp. można wysyłać za pomocą przycisków: <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Załącz</strong> lub <img style="vertical-align:middle; width:0.8em; margin:1px" src="../mic.png" alt="Microphone" /><strong>Wiadomość głosowa</strong>.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>By default, compression ensures <strong>fast, efficient delivery</strong> that respects everyone’s data limits and storage.
|
||||
This is ideal for everyday communication.</p>
|
||||
<p>Domyślnie kompresja zapewnia <strong>szybką i wydajną dostawę</strong>, respektując limity danych i pamięci wszystkich użytkowników. Jest to idealne rozwiązanie do codziennej komunikacji.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>In regions with worse connectivity,
|
||||
you can choose higher compression at <strong>Settings → Chats → Outgoing Media Quality</strong>.</p>
|
||||
<p>W regionach o słabszej łączności można wybrać wyższą kompresję w <strong>Ustawieniach → Czaty → Jakość mediów wychodzących</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>If you specifically need to send media in its <strong>original quality</strong>, use <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Attach → File</strong> in the chat.
|
||||
Please use this method sparingly, as sending original files will significantly increase data usage for you and all recipients in the chat.</p>
|
||||
<p>Jeśli chcesz wysłać multimedia w <strong>oryginalnej jakości</strong>, użyj w czacie opcji <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Załącz → Plik</strong>. Używaj tej metody oszczędnie, ponieważ wysyłanie oryginalnych plików znacznie zwiększy zużycie danych przez ciebie i wszystkich odbiorców na czacie.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -415,21 +392,11 @@ Please use this method sparingly, as sending original files will significantly i
|
||||
|
||||
<p>Możesz włączyć „znikające wiadomości” w ustawieniach czatu, w prawym górnym rogu okna czatu, wybierając przedział czasu od 5 minut do 1 roku.</p>
|
||||
|
||||
<p>Until the setting is turned off again,
|
||||
each chat member’s Delta Chat app takes care
|
||||
of deleting the messages
|
||||
after the selected time span.
|
||||
The time span begins
|
||||
when the receiver first sees the message in Delta Chat.
|
||||
The messages are deleted both,
|
||||
on the servers,
|
||||
and in the apps itself.</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 serwerze, jak i w samej aplikacji.</p>
|
||||
|
||||
<p>Pamiętaj, że na znikających wiadomościach możesz polegać tylko wtedy, gdy ufasz swoim partnerom czatu; złośliwi partnerzy czatu mogą robić zdjęcia lub w inny sposób zapisywać, kopiować lub przesyłać dalej wiadomości przed usunięciem.</p>
|
||||
|
||||
<p>Apart from that,
|
||||
if one chat partner uninstalls Delta Chat,
|
||||
the (anyway encrypted) messages may take longer to get deleted from their server.</p>
|
||||
<p>Poza tym, jeśli jeden z uczestników czatu odinstaluje aplikację Delta Chat, usunięcie (i tak zaszyfrowanych) wiadomości z jego serwera może potrwać dłużej.</p>
|
||||
|
||||
<h3 id="delold">
|
||||
|
||||
@@ -439,9 +406,9 @@ the (anyway encrypted) messages may take longer to get deleted from their server
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Jeśli chcesz zaoszczędzić miejsce na urządzeniu, możesz wybrać opcję automatycznego usuwania starych wiadomości.</p>
|
||||
<p>Jeśli chcesz zaoszczędzić miejsce na swoim urządzeniu, możesz wybrać opcję automatycznego usuwania starych wiadomości.</p>
|
||||
|
||||
<p>Aby ją włączyć, przejdź do „Usuń wiadomości z urządzenia” w ustawieniach w sekcji „Czaty i media”. Możesz ustawić przedział czasowy pomiędzy „po 1 godzinie” a „po 1 roku”; w ten sposób <em>wszystkie</em> wiadomości zostaną usunięte z urządzenia, gdy tylko staną się starsze.</p>
|
||||
<p>Aby ją włączyć, przejdź do <strong>Ustawienia → Czaty → Usuń wiadomości z urządzenia</strong> . Możesz ustawić przedział czasowy pomiędzy „po 1 godzinie” a „po 1 roku”; w ten sposób <em>wszystkie</em> wiadomości zostaną usunięte z urządzenia, gdy tylko staną się starsze.</p>
|
||||
|
||||
<h3 id="remove-account">
|
||||
|
||||
@@ -493,10 +460,10 @@ and <a href="#edit">delete their own messages</a> from all member’s devices.</
|
||||
<p>Wybierz <strong>Nowy czat</strong>, a następnie <strong>Nowa grupa</strong> z menu w prawym górnym rogu lub naciśnij odpowiedni przycisk na Androidzie / iOS.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Na następnym ekranie wybierz <strong>członków grupy</strong> i zdefiniuj <strong>nazwę grupy</strong>. Możesz też wybrać awatar <strong>grupy</strong>.</p>
|
||||
<p>Na następnym ekranie wybierz <strong>członków grupy</strong> i zdefiniuj <strong>nazwę grupy</strong>. Możesz też wybrać <strong>awatar grupy</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Zaraz po napisaniu pierwszej wiadomości w grupie wszyscy członkowie zostaną poinformowani o nowej grupie i mogą odpowiedzieć w grupie (jeżeli nie napiszesz wiadomości w grupie, grupa jest niewidoczna dla członków).</p>
|
||||
<p>Gdy tylko napiszesz <strong>pierwszą wiadomość</strong> w grupie, wszyscy członkowie zostaną poinformowani o nowej grupie i będą mogli odpowiadać w grupie (dopóki nie napiszesz wiadomości w grupie, grupa będzie niewidoczna dla członków).</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -539,8 +506,7 @@ However, since groups are <a href="#groups">meant for trusted people</a>, avoid
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Ponieważ nie jesteś członkiem grupy, nie możesz dodać siebie ponownie.
|
||||
Jednak nie ma problemu, po prostu poproś dowolnego członka grupy na normalnym czacie, aby dodał cię ponownie.</p>
|
||||
<p>Ponieważ nie jesteś członkiem grupy, nie możesz dodać siebie ponownie. Jednak nie ma problemu, po prostu poproś dowolnego członka grupy na normalnym czacie, aby dodał cię ponownie.</p>
|
||||
|
||||
<h3 id="nie-chcę-już-otrzymywać-wiadomości-od-grupy">
|
||||
|
||||
@@ -555,8 +521,7 @@ However, since groups are <a href="#groups">meant for trusted people</a>, avoid
|
||||
Jeśli później będziesz chciał ponownie dołączyć do grupy, poproś innego członka grupy, aby dodał cię do grupy.</li>
|
||||
</ul>
|
||||
|
||||
<p>Alternatywnie możesz też „Wyłączyć powiadomienia” dla grupy dzięki temu otrzymasz wszystkie wiadomości i
|
||||
nadal będziesz mógł pisać, ale nie będziesz już powiadamiany o żadnych nowych wiadomościach.</p>
|
||||
<p>Alternatywnie możesz też „Wyłączyć powiadomienia” dla grupy, dzięki temu otrzymasz wszystkie wiadomości i nadal będziesz mógł pisać, ale nie będziesz już powiadamiany o żadnych nowych wiadomościach.</p>
|
||||
|
||||
<h3 id="cloning-a-group">
|
||||
|
||||
@@ -597,6 +562,197 @@ but more than 150 is not recommended.</p>
|
||||
where Delta Chat is a private messenger for chatting with <a href="#groups">equal rights</a>.
|
||||
See <a href="https://en.wikipedia.org/wiki/Dunbar%27s_number">Dunbar’s number</a> for more insights.</p>
|
||||
|
||||
<h2 id="channels">
|
||||
|
||||
|
||||
Channels <a href="#channels" class="anchor"></a>
|
||||
|
||||
|
||||
</h2>
|
||||
|
||||
<p>Channels are a one-to-many tool for broadcasting messages.</p>
|
||||
|
||||
<h3 id="subscribe-to-a-channel">
|
||||
|
||||
|
||||
Subscribe to a channel <a href="#subscribe-to-a-channel" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>Scan the <img style="vertical-align:middle; height:1.3em; margin:1px" src="../qr-icon.png" /> <strong>QR code</strong>
|
||||
or tap the <strong>invite link</strong> you got from the channel owner.</li>
|
||||
</ul>
|
||||
|
||||
<p>That’s all!
|
||||
You will receive a few of the messages from the channel history
|
||||
and, from that point on, all new messages from the channel.</p>
|
||||
|
||||
<p><strong>Don’t worry,</strong> if that does not happen immediately.
|
||||
Once the channel owner comes online, your join request will be processed.</p>
|
||||
|
||||
<p>As all of Delta Chat, also Channels are private and decentralized,
|
||||
there is no public discovery.</p>
|
||||
|
||||
<p>Other channel subscribers will not see that you subscribed and cannot message you.
|
||||
The channel owner, however, can message you.
|
||||
They will also see that you read a message unless you have read receipts disabled.</p>
|
||||
|
||||
<p>If you do not want to share your main profile,
|
||||
you can also create a <a href="#multiple-accounts">dedicated profile</a> for joining a channel.</p>
|
||||
|
||||
<h3 id="create-a-channel">
|
||||
|
||||
|
||||
Create a channel <a href="#create-a-channel" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>Tap <strong>New Chat</strong> and choose <strong>New Channel</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Enter a <strong>name</strong>, optionally set an <strong>image</strong> and <strong>description</strong>, and hit the <strong>Create</strong> button.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>You can now send and manage messages as usual.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>From the channel’s profile, <strong>share the QR code or invite link with others</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Subscribers will receive your messages,
|
||||
but they cannot send messages in your channel.
|
||||
When subscribing, they will receive <strong>a few of the latest messages of the channel history</strong>.</p>
|
||||
|
||||
<p>You can see the <strong>view count</strong> beside each message.
|
||||
Note that this only counts subscribers who have read receipts enabled,
|
||||
so the real view count may be larger.</p>
|
||||
|
||||
<h3 id="how-many-subscribers-can-a-channel-have">
|
||||
|
||||
|
||||
How many subscribers can a channel have? <a href="#how-many-subscribers-can-a-channel-have" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Channels are designed for much larger audiences than <a href="#groups">groups</a>.</p>
|
||||
|
||||
<p>The practical limit depends on the used <a href="#relays">relay</a>,
|
||||
so there is no single fixed number that applies everywhere.</p>
|
||||
|
||||
<p>For really large channels with several tens of thousands of subscribers,
|
||||
we recommend using a <a href="#multiple-accounts">dedicated profile</a> for the channel
|
||||
and checking whether the relay is suitable.</p>
|
||||
|
||||
<p>But don’t be too hesitant: Delta Chat is designed to be relay-agnostic,
|
||||
so you can change your relay at any point easily -
|
||||
your existing subscribers will not even notice.
|
||||
You only have to update the invite link you share with new subscribers in that case.</p>
|
||||
|
||||
<h2 id="calls">
|
||||
|
||||
|
||||
Calls <a href="#calls" class="anchor"></a>
|
||||
|
||||
|
||||
</h2>
|
||||
|
||||
<p>Delta Chat supports one-to-one <strong>audio calls</strong> and <strong>video calls</strong>.</p>
|
||||
|
||||
<p>Calls are supported on Desktop, Ubuntu Touch, iOS and Android 8 and newer.</p>
|
||||
|
||||
<h3 id="place-a-call">
|
||||
|
||||
|
||||
Place a call <a href="#place-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>In a one-to-one chat, tap the 📞 <strong>call icon</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>This opens a small menu
|
||||
where you can choose whether to place an <strong>Audio Call</strong> or a <strong>Video Call</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="accept-or-reject-a-call">
|
||||
|
||||
|
||||
Accept or reject a call <a href="#accept-or-reject-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>When someone calls you,
|
||||
Delta Chat shows an <strong>incoming call screen</strong> or notification.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Tap <strong>Accept</strong> to answer
|
||||
or <strong>Decline</strong> to reject the call.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="during-a-call">
|
||||
|
||||
|
||||
During a call <a href="#during-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>You can <strong>mute</strong> your microphone.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>You can <strong>enable or disable your camera</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>On mobile, you can <strong>switch between front and back cameras</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Depending on the device, you can also select the audio output or use picture-in-picture.
|
||||
On desktop, the call is using a dedicated window
|
||||
and you can continue using the main Delta Chat window as usual.</p>
|
||||
|
||||
<h3 id="missed-calls-and-notifications">
|
||||
|
||||
|
||||
Missed calls and notifications <a href="#missed-calls-and-notifications" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>If you do not answer, do not hear the ringing, or do not have your device at hand,
|
||||
the call appears as a <strong>missed call</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Only your accepted contacts</strong> can make your device ring.
|
||||
Contact requests will appear as usual and will not ring.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>At <strong>Settings → Notifications → Calls</strong>,
|
||||
you can disable the special call ringing screen completely.
|
||||
If you do so, you will not be disturbed by any ringing notification,
|
||||
you can still pick up the call by tapping the incoming call message bubble in its chat.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="webxdc">
|
||||
|
||||
|
||||
@@ -849,8 +1005,7 @@ Welcome to the power of the interoperable chatmail relay network :)</p>
|
||||
<p>Sprawdź dokładnie, czy oba urządzenia są w tym <strong>samym Wi-Fi lub tej samej sieci</strong></p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Na <strong>Windowsie</strong>, przejdź do “Panel sterowania / Sieć i internet” i upewnij się, że <strong>Sieć prywatna</strong> jest wybrana jako “Typ profilu sieci”
|
||||
(po przeniesieniu możesz wrócić do pierwotnej wartości)</p>
|
||||
<p>Na <strong>Windowsie</strong>, przejdź do „Panel sterowania / Sieć i internet” i upewnij się, że <strong>Sieć prywatna</strong> jest wybrana jako „Typ profilu sieci” (po przeniesieniu możesz wrócić do pierwotnej wartości)</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>W systemie <strong>iOS</strong> upewnij się, że jest przydzielony dostęp do opcji „Ustawienia » Aplikacje » Delta Chat » <strong>Sieć lokalna</strong>”</p>
|
||||
@@ -894,15 +1049,14 @@ Welcome to the power of the interoperable chatmail relay network :)</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>Na starym urządzeniu przejdź do <strong>Ustawienia → Czaty i media → Eksport kopii zapasowej</strong>. Wprowadź swój PIN odblokowania ekranu, wzór lub hasło. Następnie możesz nacisnąć „Utwórz kopię”. Spowoduje to zapisanie pliku kopii zapasowej na urządzeniu. Teraz musisz jakoś przenieść go na inne urządzenie.</p>
|
||||
<p>Na starym urządzeniu przejdź do <strong>Ustawienia → Czaty → Eksport kopii zapasowej</strong>. Wprowadź swój PIN odblokowania ekranu, wzór lub hasło. Następnie możesz nacisnąć „Utwórz kopię”. Spowoduje to zapisanie pliku kopii zapasowej na urządzeniu. Teraz musisz jakoś przenieść go na inne urządzenie.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Na nowym urządzeniu, na ekranie logowania, zamiast logować się na swoje konto e-mail, wybierz <strong>Przywróć z kopii zapasowej</strong>. Po zaimportowaniu Twoje rozmowy, klucze szyfrujące i multimedia powinny zostać skopiowane na nowe urządzenie.
|
||||
Jeśli korzystasz z iOS i napotykasz trudności, może <a href="https://support.delta.chat/t/import-backup-to-ios/1628">ten poradnik</a> Ci pomoże.</p>
|
||||
<p>Na nowym urządzeniu wybierz: <strong>Mam już profil → Przywróć z kopii zapasowej</strong>. Jeśli korzystasz z iOS i napotykasz trudności, może <a href="https://support.delta.chat/t/import-backup-to-ios/1628">ten poradnik</a> ci pomoże.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Jesteś teraz zsynchronizowany i możesz używać obu urządzeń do wysyłania i odbierania wiadomości zaszyfrowanych end-to-end w komunikacji ze swoimi partnerami.</p>
|
||||
<p>Jesteś teraz zsynchronizowany i w komunikacji ze swoimi partnerami możesz używać obu urządzeń do wysyłania i odbierania wiadomości zaszyfrowanych metodą end-to-end.</p>
|
||||
|
||||
<h3 id="czy-są-jakieś-plany-wprowadzenia-klienta-web-delta-chat">
|
||||
|
||||
@@ -1289,23 +1443,20 @@ can not be identified easily.</p>
|
||||
|
||||
</h3>
|
||||
|
||||
<p>The used <a href="#relays">relay</a> needs to know your IP Address,
|
||||
as well as sometimes your contact’s devices if you have a <a href="#experiments">call</a>
|
||||
<p>The used <a href="#relays">relays</a> need to know your IP Address,
|
||||
as well as sometimes your contact’s devices if you have a <a href="#calls">call</a>
|
||||
or use <a href="#webxdc">apps</a> together.</p>
|
||||
|
||||
<p>IP Addresses are needed for connectivity and efficiency.
|
||||
They are neither persisted nor exposed.
|
||||
Note that the IP Address
|
||||
is not like a detailed address you give to a delivery service,
|
||||
but much more coarse, often defining region or country only.</p>
|
||||
Delta Chat neither persists nor exposes them.
|
||||
Note that IP Addresses
|
||||
are not like an address you give to a delivery service,
|
||||
but typically less precise, often defining city or region only.</p>
|
||||
|
||||
<p>As this is just how the internet and other messengers work by default,
|
||||
we do not offer options here or ask upfront questions.</p>
|
||||
|
||||
<p>If you see your IP Address as a security or privacy risk,
|
||||
we recommend to use a VPN, in combination with system lockdown mode.
|
||||
Hunting down options in all apps on your system will leave gaps.
|
||||
For example, tapping a link exposes IP Addresses to unknown parties and is the by far larger risk here.</p>
|
||||
<p>If you see your IP Address as a risk,
|
||||
we recommend to use a VPN for the whole system.
|
||||
Per-app options leave gaps across your system.
|
||||
For example, tapping a link can expose IP Addresses to unknown parties, which is by far the larger risk.</p>
|
||||
|
||||
<h3 id="sealedsender">
|
||||
|
||||
|
||||
@@ -29,6 +29,21 @@
|
||||
<li><a href="#quantos-membros-podem-participar-em-um-único-grupo">Quantos membros podem participar em um único grupo?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#channels">Channels</a>
|
||||
<ul>
|
||||
<li><a href="#subscribe-to-a-channel">Subscribe to a channel</a></li>
|
||||
<li><a href="#create-a-channel">Create a channel</a></li>
|
||||
<li><a href="#how-many-subscribers-can-a-channel-have">How many subscribers can a channel have?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#calls">Calls</a>
|
||||
<ul>
|
||||
<li><a href="#place-a-call">Place a call</a></li>
|
||||
<li><a href="#accept-or-reject-a-call">Accept or reject a call</a></li>
|
||||
<li><a href="#during-a-call">During a call</a></li>
|
||||
<li><a href="#missed-calls-and-notifications">Missed calls and notifications</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#webxdc">Aplicativos embutidos</a>
|
||||
<ul>
|
||||
<li><a href="#onde-posso-obter-aplicativos-embutidos">Onde posso obter aplicativos embutidos?</a></li>
|
||||
@@ -622,6 +637,197 @@ mas não é recomendável mais de 150.</p>
|
||||
mas o Delta Chat é um mensageiro privado para conversar com <a href="#groups">direitos iguais</a>.
|
||||
Consulte o <a href="https://pt.wikipedia.org/wiki/N%C3%BAmero_de_Dunbar">Número de Dunbar</a> para obter mais informações.</p>
|
||||
|
||||
<h2 id="channels">
|
||||
|
||||
|
||||
Channels <a href="#channels" class="anchor"></a>
|
||||
|
||||
|
||||
</h2>
|
||||
|
||||
<p>Channels are a one-to-many tool for broadcasting messages.</p>
|
||||
|
||||
<h3 id="subscribe-to-a-channel">
|
||||
|
||||
|
||||
Subscribe to a channel <a href="#subscribe-to-a-channel" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>Scan the <img style="vertical-align:middle; height:1.3em; margin:1px" src="../qr-icon.png" /> <strong>QR code</strong>
|
||||
or tap the <strong>invite link</strong> you got from the channel owner.</li>
|
||||
</ul>
|
||||
|
||||
<p>That’s all!
|
||||
You will receive a few of the messages from the channel history
|
||||
and, from that point on, all new messages from the channel.</p>
|
||||
|
||||
<p><strong>Don’t worry,</strong> if that does not happen immediately.
|
||||
Once the channel owner comes online, your join request will be processed.</p>
|
||||
|
||||
<p>As all of Delta Chat, also Channels are private and decentralized,
|
||||
there is no public discovery.</p>
|
||||
|
||||
<p>Other channel subscribers will not see that you subscribed and cannot message you.
|
||||
The channel owner, however, can message you.
|
||||
They will also see that you read a message unless you have read receipts disabled.</p>
|
||||
|
||||
<p>If you do not want to share your main profile,
|
||||
you can also create a <a href="#multiple-accounts">dedicated profile</a> for joining a channel.</p>
|
||||
|
||||
<h3 id="create-a-channel">
|
||||
|
||||
|
||||
Create a channel <a href="#create-a-channel" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>Tap <strong>New Chat</strong> and choose <strong>New Channel</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Enter a <strong>name</strong>, optionally set an <strong>image</strong> and <strong>description</strong>, and hit the <strong>Create</strong> button.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>You can now send and manage messages as usual.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>From the channel’s profile, <strong>share the QR code or invite link with others</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Subscribers will receive your messages,
|
||||
but they cannot send messages in your channel.
|
||||
When subscribing, they will receive <strong>a few of the latest messages of the channel history</strong>.</p>
|
||||
|
||||
<p>You can see the <strong>view count</strong> beside each message.
|
||||
Note that this only counts subscribers who have read receipts enabled,
|
||||
so the real view count may be larger.</p>
|
||||
|
||||
<h3 id="how-many-subscribers-can-a-channel-have">
|
||||
|
||||
|
||||
How many subscribers can a channel have? <a href="#how-many-subscribers-can-a-channel-have" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Channels are designed for much larger audiences than <a href="#groups">groups</a>.</p>
|
||||
|
||||
<p>The practical limit depends on the used <a href="#relays">relay</a>,
|
||||
so there is no single fixed number that applies everywhere.</p>
|
||||
|
||||
<p>For really large channels with several tens of thousands of subscribers,
|
||||
we recommend using a <a href="#multiple-accounts">dedicated profile</a> for the channel
|
||||
and checking whether the relay is suitable.</p>
|
||||
|
||||
<p>But don’t be too hesitant: Delta Chat is designed to be relay-agnostic,
|
||||
so you can change your relay at any point easily -
|
||||
your existing subscribers will not even notice.
|
||||
You only have to update the invite link you share with new subscribers in that case.</p>
|
||||
|
||||
<h2 id="calls">
|
||||
|
||||
|
||||
Calls <a href="#calls" class="anchor"></a>
|
||||
|
||||
|
||||
</h2>
|
||||
|
||||
<p>Delta Chat supports one-to-one <strong>audio calls</strong> and <strong>video calls</strong>.</p>
|
||||
|
||||
<p>Calls are supported on Desktop, Ubuntu Touch, iOS and Android 8 and newer.</p>
|
||||
|
||||
<h3 id="place-a-call">
|
||||
|
||||
|
||||
Place a call <a href="#place-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>In a one-to-one chat, tap the 📞 <strong>call icon</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>This opens a small menu
|
||||
where you can choose whether to place an <strong>Audio Call</strong> or a <strong>Video Call</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="accept-or-reject-a-call">
|
||||
|
||||
|
||||
Accept or reject a call <a href="#accept-or-reject-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>When someone calls you,
|
||||
Delta Chat shows an <strong>incoming call screen</strong> or notification.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Tap <strong>Accept</strong> to answer
|
||||
or <strong>Decline</strong> to reject the call.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="during-a-call">
|
||||
|
||||
|
||||
During a call <a href="#during-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>You can <strong>mute</strong> your microphone.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>You can <strong>enable or disable your camera</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>On mobile, you can <strong>switch between front and back cameras</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Depending on the device, you can also select the audio output or use picture-in-picture.
|
||||
On desktop, the call is using a dedicated window
|
||||
and you can continue using the main Delta Chat window as usual.</p>
|
||||
|
||||
<h3 id="missed-calls-and-notifications">
|
||||
|
||||
|
||||
Missed calls and notifications <a href="#missed-calls-and-notifications" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>If you do not answer, do not hear the ringing, or do not have your device at hand,
|
||||
the call appears as a <strong>missed call</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Only your accepted contacts</strong> can make your device ring.
|
||||
Contact requests will appear as usual and will not ring.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>At <strong>Settings → Notifications → Calls</strong>,
|
||||
you can disable the special call ringing screen completely.
|
||||
If you do so, you will not be disturbed by any ringing notification,
|
||||
you can still pick up the call by tapping the incoming call message bubble in its chat.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="webxdc">
|
||||
|
||||
|
||||
@@ -1420,23 +1626,20 @@ can not be identified easily.</p>
|
||||
|
||||
</h3>
|
||||
|
||||
<p>The used <a href="#relays">relay</a> needs to know your IP Address,
|
||||
as well as sometimes your contact’s devices if you have a <a href="#experiments">call</a>
|
||||
<p>The used <a href="#relays">relays</a> need to know your IP Address,
|
||||
as well as sometimes your contact’s devices if you have a <a href="#calls">call</a>
|
||||
or use <a href="#webxdc">apps</a> together.</p>
|
||||
|
||||
<p>IP Addresses are needed for connectivity and efficiency.
|
||||
They are neither persisted nor exposed.
|
||||
Note that the IP Address
|
||||
is not like a detailed address you give to a delivery service,
|
||||
but much more coarse, often defining region or country only.</p>
|
||||
Delta Chat neither persists nor exposes them.
|
||||
Note that IP Addresses
|
||||
are not like an address you give to a delivery service,
|
||||
but typically less precise, often defining city or region only.</p>
|
||||
|
||||
<p>As this is just how the internet and other messengers work by default,
|
||||
we do not offer options here or ask upfront questions.</p>
|
||||
|
||||
<p>If you see your IP Address as a security or privacy risk,
|
||||
we recommend to use a VPN, in combination with system lockdown mode.
|
||||
Hunting down options in all apps on your system will leave gaps.
|
||||
For example, tapping a link exposes IP Addresses to unknown parties and is the by far larger risk here.</p>
|
||||
<p>If you see your IP Address as a risk,
|
||||
we recommend to use a VPN for the whole system.
|
||||
Per-app options leave gaps across your system.
|
||||
For example, tapping a link can expose IP Addresses to unknown parties, which is by far the larger risk.</p>
|
||||
|
||||
<h3 id="sealedsender">
|
||||
|
||||
|
||||
@@ -29,6 +29,21 @@
|
||||
<li><a href="#сколько-участников-может-быть-в-одной-группе">Сколько участников может быть в одной группе?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#channels">Channels</a>
|
||||
<ul>
|
||||
<li><a href="#subscribe-to-a-channel">Subscribe to a channel</a></li>
|
||||
<li><a href="#create-a-channel">Create a channel</a></li>
|
||||
<li><a href="#how-many-subscribers-can-a-channel-have">How many subscribers can a channel have?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#calls">Calls</a>
|
||||
<ul>
|
||||
<li><a href="#place-a-call">Place a call</a></li>
|
||||
<li><a href="#accept-or-reject-a-call">Accept or reject a call</a></li>
|
||||
<li><a href="#during-a-call">During a call</a></li>
|
||||
<li><a href="#missed-calls-and-notifications">Missed calls and notifications</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#webxdc">Встроенные приложения чата</a>
|
||||
<ul>
|
||||
<li><a href="#где-можно-найти-встроенные-приложения">Где можно найти встроенные приложения?</a></li>
|
||||
@@ -622,6 +637,197 @@
|
||||
в то время как Delta Chat - это приватный мессенджер для общения на <a href="#groups">равных правах</a>.
|
||||
Смотрите <a href="https://en.wikipedia.org/wiki/Dunbar%27s_number">число Данбара</a> для более глубокого понимания.</p>
|
||||
|
||||
<h2 id="channels">
|
||||
|
||||
|
||||
Channels <a href="#channels" class="anchor"></a>
|
||||
|
||||
|
||||
</h2>
|
||||
|
||||
<p>Channels are a one-to-many tool for broadcasting messages.</p>
|
||||
|
||||
<h3 id="subscribe-to-a-channel">
|
||||
|
||||
|
||||
Subscribe to a channel <a href="#subscribe-to-a-channel" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>Scan the <img style="vertical-align:middle; height:1.3em; margin:1px" src="../qr-icon.png" /> <strong>QR code</strong>
|
||||
or tap the <strong>invite link</strong> you got from the channel owner.</li>
|
||||
</ul>
|
||||
|
||||
<p>That’s all!
|
||||
You will receive a few of the messages from the channel history
|
||||
and, from that point on, all new messages from the channel.</p>
|
||||
|
||||
<p><strong>Don’t worry,</strong> if that does not happen immediately.
|
||||
Once the channel owner comes online, your join request will be processed.</p>
|
||||
|
||||
<p>As all of Delta Chat, also Channels are private and decentralized,
|
||||
there is no public discovery.</p>
|
||||
|
||||
<p>Other channel subscribers will not see that you subscribed and cannot message you.
|
||||
The channel owner, however, can message you.
|
||||
They will also see that you read a message unless you have read receipts disabled.</p>
|
||||
|
||||
<p>If you do not want to share your main profile,
|
||||
you can also create a <a href="#multiple-accounts">dedicated profile</a> for joining a channel.</p>
|
||||
|
||||
<h3 id="create-a-channel">
|
||||
|
||||
|
||||
Create a channel <a href="#create-a-channel" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>Tap <strong>New Chat</strong> and choose <strong>New Channel</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Enter a <strong>name</strong>, optionally set an <strong>image</strong> and <strong>description</strong>, and hit the <strong>Create</strong> button.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>You can now send and manage messages as usual.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>From the channel’s profile, <strong>share the QR code or invite link with others</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Subscribers will receive your messages,
|
||||
but they cannot send messages in your channel.
|
||||
When subscribing, they will receive <strong>a few of the latest messages of the channel history</strong>.</p>
|
||||
|
||||
<p>You can see the <strong>view count</strong> beside each message.
|
||||
Note that this only counts subscribers who have read receipts enabled,
|
||||
so the real view count may be larger.</p>
|
||||
|
||||
<h3 id="how-many-subscribers-can-a-channel-have">
|
||||
|
||||
|
||||
How many subscribers can a channel have? <a href="#how-many-subscribers-can-a-channel-have" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Channels are designed for much larger audiences than <a href="#groups">groups</a>.</p>
|
||||
|
||||
<p>The practical limit depends on the used <a href="#relays">relay</a>,
|
||||
so there is no single fixed number that applies everywhere.</p>
|
||||
|
||||
<p>For really large channels with several tens of thousands of subscribers,
|
||||
we recommend using a <a href="#multiple-accounts">dedicated profile</a> for the channel
|
||||
and checking whether the relay is suitable.</p>
|
||||
|
||||
<p>But don’t be too hesitant: Delta Chat is designed to be relay-agnostic,
|
||||
so you can change your relay at any point easily -
|
||||
your existing subscribers will not even notice.
|
||||
You only have to update the invite link you share with new subscribers in that case.</p>
|
||||
|
||||
<h2 id="calls">
|
||||
|
||||
|
||||
Calls <a href="#calls" class="anchor"></a>
|
||||
|
||||
|
||||
</h2>
|
||||
|
||||
<p>Delta Chat supports one-to-one <strong>audio calls</strong> and <strong>video calls</strong>.</p>
|
||||
|
||||
<p>Calls are supported on Desktop, Ubuntu Touch, iOS and Android 8 and newer.</p>
|
||||
|
||||
<h3 id="place-a-call">
|
||||
|
||||
|
||||
Place a call <a href="#place-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>In a one-to-one chat, tap the 📞 <strong>call icon</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>This opens a small menu
|
||||
where you can choose whether to place an <strong>Audio Call</strong> or a <strong>Video Call</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="accept-or-reject-a-call">
|
||||
|
||||
|
||||
Accept or reject a call <a href="#accept-or-reject-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>When someone calls you,
|
||||
Delta Chat shows an <strong>incoming call screen</strong> or notification.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Tap <strong>Accept</strong> to answer
|
||||
or <strong>Decline</strong> to reject the call.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="during-a-call">
|
||||
|
||||
|
||||
During a call <a href="#during-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>You can <strong>mute</strong> your microphone.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>You can <strong>enable or disable your camera</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>On mobile, you can <strong>switch between front and back cameras</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Depending on the device, you can also select the audio output or use picture-in-picture.
|
||||
On desktop, the call is using a dedicated window
|
||||
and you can continue using the main Delta Chat window as usual.</p>
|
||||
|
||||
<h3 id="missed-calls-and-notifications">
|
||||
|
||||
|
||||
Missed calls and notifications <a href="#missed-calls-and-notifications" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>If you do not answer, do not hear the ringing, or do not have your device at hand,
|
||||
the call appears as a <strong>missed call</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Only your accepted contacts</strong> can make your device ring.
|
||||
Contact requests will appear as usual and will not ring.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>At <strong>Settings → Notifications → Calls</strong>,
|
||||
you can disable the special call ringing screen completely.
|
||||
If you do so, you will not be disturbed by any ringing notification,
|
||||
you can still pick up the call by tapping the incoming call message bubble in its chat.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="webxdc">
|
||||
|
||||
|
||||
@@ -1418,25 +1624,20 @@ Delta Chat вместо этого использует реализацию Ope
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Используемый <a href="#relays">релей</a> должен знать ваш IP-адрес,
|
||||
а также иногда устройства ваших контактов, если вы проводите совместные <a href="#experiments">звонки</a>
|
||||
или используете <a href="#webxdc">приложения</a>.</p>
|
||||
<p>The used <a href="#relays">relays</a> need to know your IP Address,
|
||||
as well as sometimes your contact’s devices if you have a <a href="#calls">call</a>
|
||||
or use <a href="#webxdc">apps</a> together.</p>
|
||||
|
||||
<p>IP-адреса необходимы для обеспечения соединения и эффективности.
|
||||
Они не сохраняются и не передаются третьим лицам.
|
||||
Обратите внимание, что IP-адрес</p>
|
||||
<ul>
|
||||
<li>это не подробный адрес, который вы указываете службе доставки,
|
||||
а скорее приблизительный, обычно определяющий регион или страну.</li>
|
||||
</ul>
|
||||
<p>IP Addresses are needed for connectivity and efficiency.
|
||||
Delta Chat neither persists nor exposes them.
|
||||
Note that IP Addresses
|
||||
are not like an address you give to a delivery service,
|
||||
but typically less precise, often defining city or region only.</p>
|
||||
|
||||
<p>Поскольку именно так по умолчанию работает интернет и другие мессенджеры,
|
||||
мы не предлагаем здесь никаких настроек и не задаём предварительных вопросов</p>
|
||||
|
||||
<p>Если вы считаете свой IP-адрес угрозой безопасности или конфиденциальности,
|
||||
мы рекомендуем использовать VPN в сочетании с режимом блокировки системы.
|
||||
Поиск настроек во всех приложениях на вашем устройстве оставит уязвимости.
|
||||
Например, нажатие на ссылку раскрывает IP-адрес неизвестным лицам и представляет собой гораздо больший риск в данном случае.</p>
|
||||
<p>If you see your IP Address as a risk,
|
||||
we recommend to use a VPN for the whole system.
|
||||
Per-app options leave gaps across your system.
|
||||
For example, tapping a link can expose IP Addresses to unknown parties, which is by far the larger risk.</p>
|
||||
|
||||
<h3 id="sealedsender">
|
||||
|
||||
|
||||
@@ -29,6 +29,21 @@
|
||||
<li><a href="#how-many-members-can-participate-in-a-single-group">How many members can participate in a single group?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#channels">Channels</a>
|
||||
<ul>
|
||||
<li><a href="#subscribe-to-a-channel">Subscribe to a channel</a></li>
|
||||
<li><a href="#create-a-channel">Create a channel</a></li>
|
||||
<li><a href="#how-many-subscribers-can-a-channel-have">How many subscribers can a channel have?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#calls">Calls</a>
|
||||
<ul>
|
||||
<li><a href="#place-a-call">Place a call</a></li>
|
||||
<li><a href="#accept-or-reject-a-call">Accept or reject a call</a></li>
|
||||
<li><a href="#during-a-call">During a call</a></li>
|
||||
<li><a href="#missed-calls-and-notifications">Missed calls and notifications</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#webxdc">In-chat apps</a>
|
||||
<ul>
|
||||
<li><a href="#where-can-i-get-in-chat-apps">Where can I get in-chat apps?</a></li>
|
||||
@@ -627,6 +642,197 @@ but more than 150 is not recommended.</p>
|
||||
where Delta Chat is a private messenger for chatting with <a href="#groups">equal rights</a>.
|
||||
See <a href="https://en.wikipedia.org/wiki/Dunbar%27s_number">Dunbar’s number</a> for more insights.</p>
|
||||
|
||||
<h2 id="channels">
|
||||
|
||||
|
||||
Channels <a href="#channels" class="anchor"></a>
|
||||
|
||||
|
||||
</h2>
|
||||
|
||||
<p>Channels are a one-to-many tool for broadcasting messages.</p>
|
||||
|
||||
<h3 id="subscribe-to-a-channel">
|
||||
|
||||
|
||||
Subscribe to a channel <a href="#subscribe-to-a-channel" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>Scan the <img style="vertical-align:middle; height:1.3em; margin:1px" src="../qr-icon.png" /> <strong>QR code</strong>
|
||||
or tap the <strong>invite link</strong> you got from the channel owner.</li>
|
||||
</ul>
|
||||
|
||||
<p>That’s all!
|
||||
You will receive a few of the messages from the channel history
|
||||
and, from that point on, all new messages from the channel.</p>
|
||||
|
||||
<p><strong>Don’t worry,</strong> if that does not happen immediately.
|
||||
Once the channel owner comes online, your join request will be processed.</p>
|
||||
|
||||
<p>As all of Delta Chat, also Channels are private and decentralized,
|
||||
there is no public discovery.</p>
|
||||
|
||||
<p>Other channel subscribers will not see that you subscribed and cannot message you.
|
||||
The channel owner, however, can message you.
|
||||
They will also see that you read a message unless you have read receipts disabled.</p>
|
||||
|
||||
<p>If you do not want to share your main profile,
|
||||
you can also create a <a href="#multiple-accounts">dedicated profile</a> for joining a channel.</p>
|
||||
|
||||
<h3 id="create-a-channel">
|
||||
|
||||
|
||||
Create a channel <a href="#create-a-channel" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>Tap <strong>New Chat</strong> and choose <strong>New Channel</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Enter a <strong>name</strong>, optionally set an <strong>image</strong> and <strong>description</strong>, and hit the <strong>Create</strong> button.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>You can now send and manage messages as usual.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>From the channel’s profile, <strong>share the QR code or invite link with others</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Subscribers will receive your messages,
|
||||
but they cannot send messages in your channel.
|
||||
When subscribing, they will receive <strong>a few of the latest messages of the channel history</strong>.</p>
|
||||
|
||||
<p>You can see the <strong>view count</strong> beside each message.
|
||||
Note that this only counts subscribers who have read receipts enabled,
|
||||
so the real view count may be larger.</p>
|
||||
|
||||
<h3 id="how-many-subscribers-can-a-channel-have">
|
||||
|
||||
|
||||
How many subscribers can a channel have? <a href="#how-many-subscribers-can-a-channel-have" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Channels are designed for much larger audiences than <a href="#groups">groups</a>.</p>
|
||||
|
||||
<p>The practical limit depends on the used <a href="#relays">relay</a>,
|
||||
so there is no single fixed number that applies everywhere.</p>
|
||||
|
||||
<p>For really large channels with several tens of thousands of subscribers,
|
||||
we recommend using a <a href="#multiple-accounts">dedicated profile</a> for the channel
|
||||
and checking whether the relay is suitable.</p>
|
||||
|
||||
<p>But don’t be too hesitant: Delta Chat is designed to be relay-agnostic,
|
||||
so you can change your relay at any point easily -
|
||||
your existing subscribers will not even notice.
|
||||
You only have to update the invite link you share with new subscribers in that case.</p>
|
||||
|
||||
<h2 id="calls">
|
||||
|
||||
|
||||
Calls <a href="#calls" class="anchor"></a>
|
||||
|
||||
|
||||
</h2>
|
||||
|
||||
<p>Delta Chat supports one-to-one <strong>audio calls</strong> and <strong>video calls</strong>.</p>
|
||||
|
||||
<p>Calls are supported on Desktop, Ubuntu Touch, iOS and Android 8 and newer.</p>
|
||||
|
||||
<h3 id="place-a-call">
|
||||
|
||||
|
||||
Place a call <a href="#place-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>In a one-to-one chat, tap the 📞 <strong>call icon</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>This opens a small menu
|
||||
where you can choose whether to place an <strong>Audio Call</strong> or a <strong>Video Call</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="accept-or-reject-a-call">
|
||||
|
||||
|
||||
Accept or reject a call <a href="#accept-or-reject-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>When someone calls you,
|
||||
Delta Chat shows an <strong>incoming call screen</strong> or notification.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Tap <strong>Accept</strong> to answer
|
||||
or <strong>Decline</strong> to reject the call.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="during-a-call">
|
||||
|
||||
|
||||
During a call <a href="#during-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>You can <strong>mute</strong> your microphone.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>You can <strong>enable or disable your camera</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>On mobile, you can <strong>switch between front and back cameras</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Depending on the device, you can also select the audio output or use picture-in-picture.
|
||||
On desktop, the call is using a dedicated window
|
||||
and you can continue using the main Delta Chat window as usual.</p>
|
||||
|
||||
<h3 id="missed-calls-and-notifications">
|
||||
|
||||
|
||||
Missed calls and notifications <a href="#missed-calls-and-notifications" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>If you do not answer, do not hear the ringing, or do not have your device at hand,
|
||||
the call appears as a <strong>missed call</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Only your accepted contacts</strong> can make your device ring.
|
||||
Contact requests will appear as usual and will not ring.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>At <strong>Settings → Notifications → Calls</strong>,
|
||||
you can disable the special call ringing screen completely.
|
||||
If you do so, you will not be disturbed by any ringing notification,
|
||||
you can still pick up the call by tapping the incoming call message bubble in its chat.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="webxdc">
|
||||
|
||||
|
||||
@@ -1425,23 +1631,20 @@ can not be identified easily.</p>
|
||||
|
||||
</h3>
|
||||
|
||||
<p>The used <a href="#relays">relay</a> needs to know your IP Address,
|
||||
as well as sometimes your contact’s devices if you have a <a href="#experiments">call</a>
|
||||
<p>The used <a href="#relays">relays</a> need to know your IP Address,
|
||||
as well as sometimes your contact’s devices if you have a <a href="#calls">call</a>
|
||||
or use <a href="#webxdc">apps</a> together.</p>
|
||||
|
||||
<p>IP Addresses are needed for connectivity and efficiency.
|
||||
They are neither persisted nor exposed.
|
||||
Note that the IP Address
|
||||
is not like a detailed address you give to a delivery service,
|
||||
but much more coarse, often defining region or country only.</p>
|
||||
Delta Chat neither persists nor exposes them.
|
||||
Note that IP Addresses
|
||||
are not like an address you give to a delivery service,
|
||||
but typically less precise, often defining city or region only.</p>
|
||||
|
||||
<p>As this is just how the internet and other messengers work by default,
|
||||
we do not offer options here or ask upfront questions.</p>
|
||||
|
||||
<p>If you see your IP Address as a security or privacy risk,
|
||||
we recommend to use a VPN, in combination with system lockdown mode.
|
||||
Hunting down options in all apps on your system will leave gaps.
|
||||
For example, tapping a link exposes IP Addresses to unknown parties and is the by far larger risk here.</p>
|
||||
<p>If you see your IP Address as a risk,
|
||||
we recommend to use a VPN for the whole system.
|
||||
Per-app options leave gaps across your system.
|
||||
For example, tapping a link can expose IP Addresses to unknown parties, which is by far the larger risk.</p>
|
||||
|
||||
<h3 id="sealedsender">
|
||||
|
||||
|
||||
@@ -29,6 +29,21 @@
|
||||
<li><a href="#how-many-members-can-participate-in-a-single-group">How many members can participate in a single group?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#channels">Channels</a>
|
||||
<ul>
|
||||
<li><a href="#subscribe-to-a-channel">Subscribe to a channel</a></li>
|
||||
<li><a href="#create-a-channel">Create a channel</a></li>
|
||||
<li><a href="#how-many-subscribers-can-a-channel-have">How many subscribers can a channel have?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#calls">Calls</a>
|
||||
<ul>
|
||||
<li><a href="#place-a-call">Place a call</a></li>
|
||||
<li><a href="#accept-or-reject-a-call">Accept or reject a call</a></li>
|
||||
<li><a href="#during-a-call">During a call</a></li>
|
||||
<li><a href="#missed-calls-and-notifications">Missed calls and notifications</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#webxdc">In-chat apps</a>
|
||||
<ul>
|
||||
<li><a href="#where-can-i-get-in-chat-apps">Where can I get in-chat apps?</a></li>
|
||||
@@ -627,6 +642,197 @@ but more than 150 is not recommended.</p>
|
||||
where Delta Chat is a private messenger for chatting with <a href="#groups">equal rights</a>.
|
||||
See <a href="https://en.wikipedia.org/wiki/Dunbar%27s_number">Dunbar’s number</a> for more insights.</p>
|
||||
|
||||
<h2 id="channels">
|
||||
|
||||
|
||||
Channels <a href="#channels" class="anchor"></a>
|
||||
|
||||
|
||||
</h2>
|
||||
|
||||
<p>Channels are a one-to-many tool for broadcasting messages.</p>
|
||||
|
||||
<h3 id="subscribe-to-a-channel">
|
||||
|
||||
|
||||
Subscribe to a channel <a href="#subscribe-to-a-channel" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>Scan the <img style="vertical-align:middle; height:1.3em; margin:1px" src="../qr-icon.png" /> <strong>QR code</strong>
|
||||
or tap the <strong>invite link</strong> you got from the channel owner.</li>
|
||||
</ul>
|
||||
|
||||
<p>That’s all!
|
||||
You will receive a few of the messages from the channel history
|
||||
and, from that point on, all new messages from the channel.</p>
|
||||
|
||||
<p><strong>Don’t worry,</strong> if that does not happen immediately.
|
||||
Once the channel owner comes online, your join request will be processed.</p>
|
||||
|
||||
<p>As all of Delta Chat, also Channels are private and decentralized,
|
||||
there is no public discovery.</p>
|
||||
|
||||
<p>Other channel subscribers will not see that you subscribed and cannot message you.
|
||||
The channel owner, however, can message you.
|
||||
They will also see that you read a message unless you have read receipts disabled.</p>
|
||||
|
||||
<p>If you do not want to share your main profile,
|
||||
you can also create a <a href="#multiple-accounts">dedicated profile</a> for joining a channel.</p>
|
||||
|
||||
<h3 id="create-a-channel">
|
||||
|
||||
|
||||
Create a channel <a href="#create-a-channel" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>Tap <strong>New Chat</strong> and choose <strong>New Channel</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Enter a <strong>name</strong>, optionally set an <strong>image</strong> and <strong>description</strong>, and hit the <strong>Create</strong> button.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>You can now send and manage messages as usual.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>From the channel’s profile, <strong>share the QR code or invite link with others</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Subscribers will receive your messages,
|
||||
but they cannot send messages in your channel.
|
||||
When subscribing, they will receive <strong>a few of the latest messages of the channel history</strong>.</p>
|
||||
|
||||
<p>You can see the <strong>view count</strong> beside each message.
|
||||
Note that this only counts subscribers who have read receipts enabled,
|
||||
so the real view count may be larger.</p>
|
||||
|
||||
<h3 id="how-many-subscribers-can-a-channel-have">
|
||||
|
||||
|
||||
How many subscribers can a channel have? <a href="#how-many-subscribers-can-a-channel-have" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Channels are designed for much larger audiences than <a href="#groups">groups</a>.</p>
|
||||
|
||||
<p>The practical limit depends on the used <a href="#relays">relay</a>,
|
||||
so there is no single fixed number that applies everywhere.</p>
|
||||
|
||||
<p>For really large channels with several tens of thousands of subscribers,
|
||||
we recommend using a <a href="#multiple-accounts">dedicated profile</a> for the channel
|
||||
and checking whether the relay is suitable.</p>
|
||||
|
||||
<p>But don’t be too hesitant: Delta Chat is designed to be relay-agnostic,
|
||||
so you can change your relay at any point easily -
|
||||
your existing subscribers will not even notice.
|
||||
You only have to update the invite link you share with new subscribers in that case.</p>
|
||||
|
||||
<h2 id="calls">
|
||||
|
||||
|
||||
Calls <a href="#calls" class="anchor"></a>
|
||||
|
||||
|
||||
</h2>
|
||||
|
||||
<p>Delta Chat supports one-to-one <strong>audio calls</strong> and <strong>video calls</strong>.</p>
|
||||
|
||||
<p>Calls are supported on Desktop, Ubuntu Touch, iOS and Android 8 and newer.</p>
|
||||
|
||||
<h3 id="place-a-call">
|
||||
|
||||
|
||||
Place a call <a href="#place-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>In a one-to-one chat, tap the 📞 <strong>call icon</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>This opens a small menu
|
||||
where you can choose whether to place an <strong>Audio Call</strong> or a <strong>Video Call</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="accept-or-reject-a-call">
|
||||
|
||||
|
||||
Accept or reject a call <a href="#accept-or-reject-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>When someone calls you,
|
||||
Delta Chat shows an <strong>incoming call screen</strong> or notification.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Tap <strong>Accept</strong> to answer
|
||||
or <strong>Decline</strong> to reject the call.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="during-a-call">
|
||||
|
||||
|
||||
During a call <a href="#during-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>You can <strong>mute</strong> your microphone.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>You can <strong>enable or disable your camera</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>On mobile, you can <strong>switch between front and back cameras</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Depending on the device, you can also select the audio output or use picture-in-picture.
|
||||
On desktop, the call is using a dedicated window
|
||||
and you can continue using the main Delta Chat window as usual.</p>
|
||||
|
||||
<h3 id="missed-calls-and-notifications">
|
||||
|
||||
|
||||
Missed calls and notifications <a href="#missed-calls-and-notifications" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>If you do not answer, do not hear the ringing, or do not have your device at hand,
|
||||
the call appears as a <strong>missed call</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Only your accepted contacts</strong> can make your device ring.
|
||||
Contact requests will appear as usual and will not ring.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>At <strong>Settings → Notifications → Calls</strong>,
|
||||
you can disable the special call ringing screen completely.
|
||||
If you do so, you will not be disturbed by any ringing notification,
|
||||
you can still pick up the call by tapping the incoming call message bubble in its chat.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="webxdc">
|
||||
|
||||
|
||||
@@ -1427,23 +1633,20 @@ can not be identified easily.</p>
|
||||
|
||||
</h3>
|
||||
|
||||
<p>The used <a href="#relays">relay</a> needs to know your IP Address,
|
||||
as well as sometimes your contact’s devices if you have a <a href="#experiments">call</a>
|
||||
<p>The used <a href="#relays">relays</a> need to know your IP Address,
|
||||
as well as sometimes your contact’s devices if you have a <a href="#calls">call</a>
|
||||
or use <a href="#webxdc">apps</a> together.</p>
|
||||
|
||||
<p>IP Addresses are needed for connectivity and efficiency.
|
||||
They are neither persisted nor exposed.
|
||||
Note that the IP Address
|
||||
is not like a detailed address you give to a delivery service,
|
||||
but much more coarse, often defining region or country only.</p>
|
||||
Delta Chat neither persists nor exposes them.
|
||||
Note that IP Addresses
|
||||
are not like an address you give to a delivery service,
|
||||
but typically less precise, often defining city or region only.</p>
|
||||
|
||||
<p>As this is just how the internet and other messengers work by default,
|
||||
we do not offer options here or ask upfront questions.</p>
|
||||
|
||||
<p>If you see your IP Address as a security or privacy risk,
|
||||
we recommend to use a VPN, in combination with system lockdown mode.
|
||||
Hunting down options in all apps on your system will leave gaps.
|
||||
For example, tapping a link exposes IP Addresses to unknown parties and is the by far larger risk here.</p>
|
||||
<p>If you see your IP Address as a risk,
|
||||
we recommend to use a VPN for the whole system.
|
||||
Per-app options leave gaps across your system.
|
||||
For example, tapping a link can expose IP Addresses to unknown parties, which is by far the larger risk.</p>
|
||||
|
||||
<h3 id="sealedsender">
|
||||
|
||||
|
||||
@@ -28,6 +28,21 @@
|
||||
<li><a href="#how-many-members-can-participate-in-a-single-group">How many members can participate in a single group?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#channels">Channels</a>
|
||||
<ul>
|
||||
<li><a href="#subscribe-to-a-channel">Subscribe to a channel</a></li>
|
||||
<li><a href="#create-a-channel">Create a channel</a></li>
|
||||
<li><a href="#how-many-subscribers-can-a-channel-have">How many subscribers can a channel have?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#calls">Calls</a>
|
||||
<ul>
|
||||
<li><a href="#place-a-call">Place a call</a></li>
|
||||
<li><a href="#accept-or-reject-a-call">Accept or reject a call</a></li>
|
||||
<li><a href="#during-a-call">During a call</a></li>
|
||||
<li><a href="#missed-calls-and-notifications">Missed calls and notifications</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#webxdc">In-chat apps</a>
|
||||
<ul>
|
||||
<li><a href="#where-can-i-get-in-chat-apps">Where can I get in-chat apps?</a></li>
|
||||
@@ -582,6 +597,197 @@ but more than 150 is not recommended.</p>
|
||||
where Delta Chat is a private messenger for chatting with <a href="#groups">equal rights</a>.
|
||||
See <a href="https://en.wikipedia.org/wiki/Dunbar%27s_number">Dunbar’s number</a> for more insights.</p>
|
||||
|
||||
<h2 id="channels">
|
||||
|
||||
|
||||
Channels <a href="#channels" class="anchor"></a>
|
||||
|
||||
|
||||
</h2>
|
||||
|
||||
<p>Channels are a one-to-many tool for broadcasting messages.</p>
|
||||
|
||||
<h3 id="subscribe-to-a-channel">
|
||||
|
||||
|
||||
Subscribe to a channel <a href="#subscribe-to-a-channel" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>Scan the <img style="vertical-align:middle; height:1.3em; margin:1px" src="../qr-icon.png" /> <strong>QR code</strong>
|
||||
or tap the <strong>invite link</strong> you got from the channel owner.</li>
|
||||
</ul>
|
||||
|
||||
<p>That’s all!
|
||||
You will receive a few of the messages from the channel history
|
||||
and, from that point on, all new messages from the channel.</p>
|
||||
|
||||
<p><strong>Don’t worry,</strong> if that does not happen immediately.
|
||||
Once the channel owner comes online, your join request will be processed.</p>
|
||||
|
||||
<p>As all of Delta Chat, also Channels are private and decentralized,
|
||||
there is no public discovery.</p>
|
||||
|
||||
<p>Other channel subscribers will not see that you subscribed and cannot message you.
|
||||
The channel owner, however, can message you.
|
||||
They will also see that you read a message unless you have read receipts disabled.</p>
|
||||
|
||||
<p>If you do not want to share your main profile,
|
||||
you can also create a <a href="#multiple-accounts">dedicated profile</a> for joining a channel.</p>
|
||||
|
||||
<h3 id="create-a-channel">
|
||||
|
||||
|
||||
Create a channel <a href="#create-a-channel" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>Tap <strong>New Chat</strong> and choose <strong>New Channel</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Enter a <strong>name</strong>, optionally set an <strong>image</strong> and <strong>description</strong>, and hit the <strong>Create</strong> button.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>You can now send and manage messages as usual.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>From the channel’s profile, <strong>share the QR code or invite link with others</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Subscribers will receive your messages,
|
||||
but they cannot send messages in your channel.
|
||||
When subscribing, they will receive <strong>a few of the latest messages of the channel history</strong>.</p>
|
||||
|
||||
<p>You can see the <strong>view count</strong> beside each message.
|
||||
Note that this only counts subscribers who have read receipts enabled,
|
||||
so the real view count may be larger.</p>
|
||||
|
||||
<h3 id="how-many-subscribers-can-a-channel-have">
|
||||
|
||||
|
||||
How many subscribers can a channel have? <a href="#how-many-subscribers-can-a-channel-have" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Channels are designed for much larger audiences than <a href="#groups">groups</a>.</p>
|
||||
|
||||
<p>The practical limit depends on the used <a href="#relays">relay</a>,
|
||||
so there is no single fixed number that applies everywhere.</p>
|
||||
|
||||
<p>For really large channels with several tens of thousands of subscribers,
|
||||
we recommend using a <a href="#multiple-accounts">dedicated profile</a> for the channel
|
||||
and checking whether the relay is suitable.</p>
|
||||
|
||||
<p>But don’t be too hesitant: Delta Chat is designed to be relay-agnostic,
|
||||
so you can change your relay at any point easily -
|
||||
your existing subscribers will not even notice.
|
||||
You only have to update the invite link you share with new subscribers in that case.</p>
|
||||
|
||||
<h2 id="calls">
|
||||
|
||||
|
||||
Calls <a href="#calls" class="anchor"></a>
|
||||
|
||||
|
||||
</h2>
|
||||
|
||||
<p>Delta Chat supports one-to-one <strong>audio calls</strong> and <strong>video calls</strong>.</p>
|
||||
|
||||
<p>Calls are supported on Desktop, Ubuntu Touch, iOS and Android 8 and newer.</p>
|
||||
|
||||
<h3 id="place-a-call">
|
||||
|
||||
|
||||
Place a call <a href="#place-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>In a one-to-one chat, tap the 📞 <strong>call icon</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>This opens a small menu
|
||||
where you can choose whether to place an <strong>Audio Call</strong> or a <strong>Video Call</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="accept-or-reject-a-call">
|
||||
|
||||
|
||||
Accept or reject a call <a href="#accept-or-reject-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>When someone calls you,
|
||||
Delta Chat shows an <strong>incoming call screen</strong> or notification.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Tap <strong>Accept</strong> to answer
|
||||
or <strong>Decline</strong> to reject the call.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="during-a-call">
|
||||
|
||||
|
||||
During a call <a href="#during-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>You can <strong>mute</strong> your microphone.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>You can <strong>enable or disable your camera</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>On mobile, you can <strong>switch between front and back cameras</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Depending on the device, you can also select the audio output or use picture-in-picture.
|
||||
On desktop, the call is using a dedicated window
|
||||
and you can continue using the main Delta Chat window as usual.</p>
|
||||
|
||||
<h3 id="missed-calls-and-notifications">
|
||||
|
||||
|
||||
Missed calls and notifications <a href="#missed-calls-and-notifications" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>If you do not answer, do not hear the ringing, or do not have your device at hand,
|
||||
the call appears as a <strong>missed call</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Only your accepted contacts</strong> can make your device ring.
|
||||
Contact requests will appear as usual and will not ring.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>At <strong>Settings → Notifications → Calls</strong>,
|
||||
you can disable the special call ringing screen completely.
|
||||
If you do so, you will not be disturbed by any ringing notification,
|
||||
you can still pick up the call by tapping the incoming call message bubble in its chat.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="webxdc">
|
||||
|
||||
|
||||
@@ -1268,23 +1474,20 @@ can not be identified easily.</p>
|
||||
|
||||
</h3>
|
||||
|
||||
<p>The used <a href="#relays">relay</a> needs to know your IP Address,
|
||||
as well as sometimes your contact’s devices if you have a <a href="#experiments">call</a>
|
||||
<p>The used <a href="#relays">relays</a> need to know your IP Address,
|
||||
as well as sometimes your contact’s devices if you have a <a href="#calls">call</a>
|
||||
or use <a href="#webxdc">apps</a> together.</p>
|
||||
|
||||
<p>IP Addresses are needed for connectivity and efficiency.
|
||||
They are neither persisted nor exposed.
|
||||
Note that the IP Address
|
||||
is not like a detailed address you give to a delivery service,
|
||||
but much more coarse, often defining region or country only.</p>
|
||||
Delta Chat neither persists nor exposes them.
|
||||
Note that IP Addresses
|
||||
are not like an address you give to a delivery service,
|
||||
but typically less precise, often defining city or region only.</p>
|
||||
|
||||
<p>As this is just how the internet and other messengers work by default,
|
||||
we do not offer options here or ask upfront questions.</p>
|
||||
|
||||
<p>If you see your IP Address as a security or privacy risk,
|
||||
we recommend to use a VPN, in combination with system lockdown mode.
|
||||
Hunting down options in all apps on your system will leave gaps.
|
||||
For example, tapping a link exposes IP Addresses to unknown parties and is the by far larger risk here.</p>
|
||||
<p>If you see your IP Address as a risk,
|
||||
we recommend to use a VPN for the whole system.
|
||||
Per-app options leave gaps across your system.
|
||||
For example, tapping a link can expose IP Addresses to unknown parties, which is by far the larger risk.</p>
|
||||
|
||||
<h3 id="sealedsender">
|
||||
|
||||
|
||||
@@ -32,6 +32,21 @@
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#channels">Channels</a>
|
||||
<ul>
|
||||
<li><a href="#subscribe-to-a-channel">Subscribe to a channel</a></li>
|
||||
<li><a href="#create-a-channel">Create a channel</a></li>
|
||||
<li><a href="#how-many-subscribers-can-a-channel-have">How many subscribers can a channel have?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#calls">Calls</a>
|
||||
<ul>
|
||||
<li><a href="#place-a-call">Place a call</a></li>
|
||||
<li><a href="#accept-or-reject-a-call">Accept or reject a call</a></li>
|
||||
<li><a href="#during-a-call">During a call</a></li>
|
||||
<li><a href="#missed-calls-and-notifications">Missed calls and notifications</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#webxdc">Webxdc 应用</a>
|
||||
<ul>
|
||||
<li><a href="#我在哪里可以获得-webxdc-应用">我在哪里可以获得 Webxdc 应用?</a></li>
|
||||
@@ -621,6 +636,197 @@ Please use this method sparingly, as sending original files will significantly i
|
||||
其中Delta Chat 是与<a href="#groups">平等权利</a> 聊天的私人信使。
|
||||
相关知识,请参阅<a href="https://en.wikipedia.org/wiki/Dunbar%27s_number">邓巴数</a>。</p>
|
||||
|
||||
<h2 id="channels">
|
||||
|
||||
|
||||
Channels <a href="#channels" class="anchor"></a>
|
||||
|
||||
|
||||
</h2>
|
||||
|
||||
<p>Channels are a one-to-many tool for broadcasting messages.</p>
|
||||
|
||||
<h3 id="subscribe-to-a-channel">
|
||||
|
||||
|
||||
Subscribe to a channel <a href="#subscribe-to-a-channel" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>Scan the <img style="vertical-align:middle; height:1.3em; margin:1px" src="../qr-icon.png" /> <strong>QR code</strong>
|
||||
or tap the <strong>invite link</strong> you got from the channel owner.</li>
|
||||
</ul>
|
||||
|
||||
<p>That’s all!
|
||||
You will receive a few of the messages from the channel history
|
||||
and, from that point on, all new messages from the channel.</p>
|
||||
|
||||
<p><strong>Don’t worry,</strong> if that does not happen immediately.
|
||||
Once the channel owner comes online, your join request will be processed.</p>
|
||||
|
||||
<p>As all of Delta Chat, also Channels are private and decentralized,
|
||||
there is no public discovery.</p>
|
||||
|
||||
<p>Other channel subscribers will not see that you subscribed and cannot message you.
|
||||
The channel owner, however, can message you.
|
||||
They will also see that you read a message unless you have read receipts disabled.</p>
|
||||
|
||||
<p>If you do not want to share your main profile,
|
||||
you can also create a <a href="#multiple-accounts">dedicated profile</a> for joining a channel.</p>
|
||||
|
||||
<h3 id="create-a-channel">
|
||||
|
||||
|
||||
Create a channel <a href="#create-a-channel" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>Tap <strong>New Chat</strong> and choose <strong>New Channel</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Enter a <strong>name</strong>, optionally set an <strong>image</strong> and <strong>description</strong>, and hit the <strong>Create</strong> button.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>You can now send and manage messages as usual.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>From the channel’s profile, <strong>share the QR code or invite link with others</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Subscribers will receive your messages,
|
||||
but they cannot send messages in your channel.
|
||||
When subscribing, they will receive <strong>a few of the latest messages of the channel history</strong>.</p>
|
||||
|
||||
<p>You can see the <strong>view count</strong> beside each message.
|
||||
Note that this only counts subscribers who have read receipts enabled,
|
||||
so the real view count may be larger.</p>
|
||||
|
||||
<h3 id="how-many-subscribers-can-a-channel-have">
|
||||
|
||||
|
||||
How many subscribers can a channel have? <a href="#how-many-subscribers-can-a-channel-have" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Channels are designed for much larger audiences than <a href="#groups">groups</a>.</p>
|
||||
|
||||
<p>The practical limit depends on the used <a href="#relays">relay</a>,
|
||||
so there is no single fixed number that applies everywhere.</p>
|
||||
|
||||
<p>For really large channels with several tens of thousands of subscribers,
|
||||
we recommend using a <a href="#multiple-accounts">dedicated profile</a> for the channel
|
||||
and checking whether the relay is suitable.</p>
|
||||
|
||||
<p>But don’t be too hesitant: Delta Chat is designed to be relay-agnostic,
|
||||
so you can change your relay at any point easily -
|
||||
your existing subscribers will not even notice.
|
||||
You only have to update the invite link you share with new subscribers in that case.</p>
|
||||
|
||||
<h2 id="calls">
|
||||
|
||||
|
||||
Calls <a href="#calls" class="anchor"></a>
|
||||
|
||||
|
||||
</h2>
|
||||
|
||||
<p>Delta Chat supports one-to-one <strong>audio calls</strong> and <strong>video calls</strong>.</p>
|
||||
|
||||
<p>Calls are supported on Desktop, Ubuntu Touch, iOS and Android 8 and newer.</p>
|
||||
|
||||
<h3 id="place-a-call">
|
||||
|
||||
|
||||
Place a call <a href="#place-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>In a one-to-one chat, tap the 📞 <strong>call icon</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>This opens a small menu
|
||||
where you can choose whether to place an <strong>Audio Call</strong> or a <strong>Video Call</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="accept-or-reject-a-call">
|
||||
|
||||
|
||||
Accept or reject a call <a href="#accept-or-reject-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>When someone calls you,
|
||||
Delta Chat shows an <strong>incoming call screen</strong> or notification.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Tap <strong>Accept</strong> to answer
|
||||
or <strong>Decline</strong> to reject the call.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="during-a-call">
|
||||
|
||||
|
||||
During a call <a href="#during-a-call" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>You can <strong>mute</strong> your microphone.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>You can <strong>enable or disable your camera</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>On mobile, you can <strong>switch between front and back cameras</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Depending on the device, you can also select the audio output or use picture-in-picture.
|
||||
On desktop, the call is using a dedicated window
|
||||
and you can continue using the main Delta Chat window as usual.</p>
|
||||
|
||||
<h3 id="missed-calls-and-notifications">
|
||||
|
||||
|
||||
Missed calls and notifications <a href="#missed-calls-and-notifications" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>If you do not answer, do not hear the ringing, or do not have your device at hand,
|
||||
the call appears as a <strong>missed call</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Only your accepted contacts</strong> can make your device ring.
|
||||
Contact requests will appear as usual and will not ring.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>At <strong>Settings → Notifications → Calls</strong>,
|
||||
you can disable the special call ringing screen completely.
|
||||
If you do so, you will not be disturbed by any ringing notification,
|
||||
you can still pick up the call by tapping the incoming call message bubble in its chat.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="webxdc">
|
||||
|
||||
|
||||
@@ -1414,22 +1620,20 @@ Delta Chat 应用程序不会在服务器上存储任何有关联系人或群组
|
||||
|
||||
</h4>
|
||||
|
||||
<p>使用的 <a href="#relays">中继服务器</a> 需要知道您的 IP 地址、
|
||||
有时还需要知道联系人的设备(如果你们有 <a href="#experiments">通话</a>),或一起使用 <a href="#webxdc">Webxdc应用程序</a>。</p>
|
||||
<p>The used <a href="#relays">relays</a> need to know your IP Address,
|
||||
as well as sometimes your contact’s devices if you have a <a href="#calls">call</a>
|
||||
or use <a href="#webxdc">apps</a> together.</p>
|
||||
|
||||
<p>IP 地址是连接和提高效率所必需的。
|
||||
它们既不会持久存在,也不会暴露。
|
||||
请注意,IP 地址
|
||||
不像你给快递服务的详细地址、
|
||||
而是更粗略,通常只定义地区或国家。</p>
|
||||
<p>IP Addresses are needed for connectivity and efficiency.
|
||||
Delta Chat neither persists nor exposes them.
|
||||
Note that IP Addresses
|
||||
are not like an address you give to a delivery service,
|
||||
but typically less precise, often defining city or region only.</p>
|
||||
|
||||
<p>这只是互联网和其他信使的默认工作方式、
|
||||
我们在此不提供选项,也不预先提问。</p>
|
||||
|
||||
<p>如果你认为你的 IP 地址存在安全或隐私风险、
|
||||
我们建议使用 VPN 并结合系统锁定模式。
|
||||
在系统的所有应用程序中查找选项会留下漏洞。
|
||||
例如,点击链接会将 IP 地址暴露给未知方,这是目前最大的风险。</p>
|
||||
<p>If you see your IP Address as a risk,
|
||||
we recommend to use a VPN for the whole system.
|
||||
Per-app options leave gaps across your system.
|
||||
For example, tapping a link can expose IP Addresses to unknown parties, which is by far the larger risk.</p>
|
||||
|
||||
<p>###Delta Chat 是否支持 “密封发件人”?{#sealedsender}</p>
|
||||
|
||||
|
||||
@@ -443,10 +443,19 @@ public class Rpc {
|
||||
}
|
||||
|
||||
/**
|
||||
* Estimate the number of messages that will be deleted
|
||||
* by the set_config()-options `delete_device_after` or `delete_server_after`.
|
||||
* Estimates the number of messages that will be deleted
|
||||
* by the `set_config()`-option `delete_device_after`.
|
||||
* <p>
|
||||
* This is typically used to show the estimated impact to the user
|
||||
* before actually enabling deletion of old messages.
|
||||
* <p>
|
||||
* Messages in the "Saved Messages" chat are not counted as they will not be deleted automatically.
|
||||
* <p>
|
||||
* Parameters:
|
||||
* - `from_server`: Deprecated, pass `false` here
|
||||
* - `seconds`: Count messages older than the given number of seconds.
|
||||
* <p>
|
||||
* Returns the number of messages that are older than the given number of seconds.
|
||||
*/
|
||||
public Integer estimateAutoDeletionCount(Integer accountId, Boolean fromServer, Integer seconds) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<Integer>(){}, "estimate_auto_deletion_count", mapper.valueToTree(accountId), mapper.valueToTree(fromServer), mapper.valueToTree(seconds));
|
||||
@@ -913,8 +922,22 @@ public class Rpc {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all messages of a particular chat.
|
||||
* Get all message IDs belonging to a chat.
|
||||
* <p>
|
||||
* The list is already sorted and starts with the oldest message.
|
||||
* Clients should not try to re-sort the list as this would be an expensive action
|
||||
* and would result in inconsistencies between clients.
|
||||
* Note that the messages are not necessarily sorted by their ID or by their displayed timestamp;
|
||||
* UIs need to handle both the case of descending message IDs
|
||||
* and of decreasing timestamps.
|
||||
* <p>
|
||||
* Optionally, 'daymarkers' added to the ID array may help to
|
||||
* implement virtual lists.
|
||||
* <p>
|
||||
* Parameters:
|
||||
* <p>
|
||||
* * chat_id The chat ID of which the messages IDs should be queried.
|
||||
* * _info_only: Deprecated, pass `false` here.
|
||||
* * `add_daymarker` - If `true`, add day markers as `DC_MSG_ID_DAYMARKER` to the result,
|
||||
* e.g. [1234, 1237, 9, 1239]. The day marker timestamp is the midnight one for the
|
||||
* corresponding (following) day in the local timezone.
|
||||
@@ -932,6 +955,14 @@ public class Rpc {
|
||||
return transport.callForResult(new TypeReference<java.util.List<Integer>>(){}, "get_existing_msg_ids", mapper.valueToTree(accountId), mapper.valueToTree(msgIds));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all messages belonging to a chat.
|
||||
* <p>
|
||||
* Similar to `get_message_ids` / `getMessageIds`,
|
||||
* see that function for details.
|
||||
* The difference is that this function here returns a list of `MessageListItem`,
|
||||
* which is an enum of a message or a daymarker.
|
||||
*/
|
||||
public java.util.List<MessageListItem> getMessageListItems(Integer accountId, Integer chatId, Boolean infoOnly, Boolean addDaymarker) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<java.util.List<MessageListItem>>(){}, "get_message_list_items", mapper.valueToTree(accountId), mapper.valueToTree(chatId), mapper.valueToTree(infoOnly), mapper.valueToTree(addDaymarker));
|
||||
}
|
||||
@@ -1181,11 +1212,6 @@ public class Rpc {
|
||||
return transport.callForResult(new TypeReference<String>(){}, "make_vcard", mapper.valueToTree(accountId), mapper.valueToTree(contacts));
|
||||
}
|
||||
|
||||
/** Sets vCard containing the given contacts to the message draft. */
|
||||
public void setDraftVcard(Integer accountId, Integer msgId, java.util.List<Integer> contacts) throws RpcException {
|
||||
transport.call("set_draft_vcard", mapper.valueToTree(accountId), mapper.valueToTree(msgId), mapper.valueToTree(contacts));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the [`ChatId`] for the 1:1 chat with `contact_id` if it exists.
|
||||
* <p>
|
||||
@@ -1328,10 +1354,47 @@ public class Rpc {
|
||||
return transport.callForResult(new TypeReference<String>(){}, "get_connectivity_html", mapper.valueToTree(accountId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets current location.
|
||||
* <p>
|
||||
* Returns true if location streaming is currently
|
||||
* enabled and locations should be updated.
|
||||
* <p>
|
||||
* Location is represented as latitude and longitude in degrees
|
||||
* and horizontal accuracy in meters.
|
||||
*/
|
||||
public Boolean setLocation(Float latitude, Float longitude, Float accuracy) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<Boolean>(){}, "set_location", mapper.valueToTree(latitude), mapper.valueToTree(longitude), mapper.valueToTree(accuracy));
|
||||
}
|
||||
|
||||
public java.util.List<Location> getLocations(Integer accountId, Integer chatId, Integer contactId, Integer timestampBegin, Integer timestampEnd) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<java.util.List<Location>>(){}, "get_locations", mapper.valueToTree(accountId), mapper.valueToTree(chatId), mapper.valueToTree(contactId), mapper.valueToTree(timestampBegin), mapper.valueToTree(timestampEnd));
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables location streaming in chat identified by `chat_id` for `seconds` seconds.
|
||||
* <p>
|
||||
* Pass 0 as the number of seconds to disable location streaming in the chat.
|
||||
*/
|
||||
public void sendLocationsToChat(Integer accountId, Integer chatId, Integer seconds) throws RpcException {
|
||||
transport.call("send_locations_to_chat", mapper.valueToTree(accountId), mapper.valueToTree(chatId), mapper.valueToTree(seconds));
|
||||
}
|
||||
|
||||
/** Returns whether any chat is sending locations. */
|
||||
public Boolean isSendingLocations(Integer accountId) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<Boolean>(){}, "is_sending_locations", mapper.valueToTree(accountId));
|
||||
}
|
||||
|
||||
/** Returns whether `chat_id` is sending locations. */
|
||||
public Boolean isSendingLocationsToChat(Integer accountId, Integer chatId) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<Boolean>(){}, "is_sending_locations_to_chat", mapper.valueToTree(accountId), mapper.valueToTree(chatId));
|
||||
}
|
||||
|
||||
/** Stops sending locations to all chats. */
|
||||
public void stopSendingLocations() throws RpcException {
|
||||
transport.call("stop_sending_locations");
|
||||
}
|
||||
|
||||
public void sendWebxdcStatusUpdate(Integer accountId, Integer instanceMsgId, String updateStr, String descr) throws RpcException {
|
||||
transport.call("send_webxdc_status_update", mapper.valueToTree(accountId), mapper.valueToTree(instanceMsgId), mapper.valueToTree(updateStr), mapper.valueToTree(descr));
|
||||
}
|
||||
@@ -1467,17 +1530,18 @@ public class Rpc {
|
||||
transport.call("resend_messages", mapper.valueToTree(accountId), mapper.valueToTree(messageIds));
|
||||
}
|
||||
|
||||
/** @deprecated as of 2026-04; use `send_msg` with `Viewtype::Sticker` instead. */
|
||||
public Integer sendSticker(Integer accountId, Integer chatId, String stickerPath) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<Integer>(){}, "send_sticker", mapper.valueToTree(accountId), mapper.valueToTree(chatId), mapper.valueToTree(stickerPath));
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a reaction to message.
|
||||
* Sends 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.
|
||||
* A reaction is a string that represents an emoji.
|
||||
* You can call this function again to change the emoji;
|
||||
* the last sent reaction overrides all previously sent reactions.
|
||||
* It is possible to remove the reaction 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));
|
||||
|
||||
@@ -12,6 +12,13 @@ public class EnteredLoginParam {
|
||||
/** 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 folder.
|
||||
* <p>
|
||||
* Defaults to "INBOX" if not set. Should not be an empty string.
|
||||
*/
|
||||
@com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
|
||||
public String imapFolder;
|
||||
/** Imap server port. */
|
||||
@com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
|
||||
public Integer imapPort;
|
||||
|
||||
@@ -5,6 +5,6 @@ package chat.delta.rpc.types;
|
||||
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. */
|
||||
/** Map from a contact to it's reaction to message. There is only a single reaction per contact, but this contains a list of reactions for historical reasons. */
|
||||
public java.util.Map<String, java.util.List<String>> reactionsByContact;
|
||||
}
|
||||
@@ -14,7 +14,7 @@ public enum Viewtype {
|
||||
Gif,
|
||||
|
||||
/**
|
||||
* Message containing a sticker, similar to image. NB: When sending, the message viewtype may be changed to `Image` by some heuristics like checking for transparent pixels. Use `Message::force_sticker()` to disable them.
|
||||
* Message containing a sticker, similar to image.
|
||||
* <p>
|
||||
* If possible, the ui should display the image without borders in a transparent way. A click on a sticker will offer to install the sticker set in some future.
|
||||
*/
|
||||
|
||||
@@ -15,6 +15,10 @@ public class WebxdcMessageInfo {
|
||||
public String icon;
|
||||
/** True if full internet access should be granted to the app. */
|
||||
public Boolean internetAccess;
|
||||
/** Define if the local user is the one who initially shared the webxdc application in the chat. */
|
||||
public Boolean isAppSender;
|
||||
/** Define if the app runs in a broadcasting context. */
|
||||
public Boolean isBroadcast;
|
||||
/**
|
||||
* The name of the app.
|
||||
* <p>
|
||||
|
||||
@@ -59,8 +59,6 @@ public class DcMsg {
|
||||
public static final int DC_VIDEOCHATTYPE_UNKNOWN = 0;
|
||||
public static final int DC_VIDEOCHATTYPE_BASICWEBRTC = 1;
|
||||
|
||||
private static final String TAG = DcMsg.class.getSimpleName();
|
||||
|
||||
public DcMsg(DcContext context, int viewtype) {
|
||||
msgCPtr = context.createMsgCPtr(viewtype);
|
||||
}
|
||||
@@ -196,8 +194,6 @@ public class DcMsg {
|
||||
|
||||
public native void setHtml(String text);
|
||||
|
||||
public native void forceSticker();
|
||||
|
||||
public native void setFileAndDeduplicate(String file, String name, String filemime);
|
||||
|
||||
public native void setDimension(int width, int height);
|
||||
|
||||
@@ -4,7 +4,6 @@ import android.content.ComponentName;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.MenuItem;
|
||||
import android.view.ViewGroup;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
@@ -12,21 +11,23 @@ import androidx.appcompat.view.ActionMode;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentStatePagerAdapter;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.media3.session.MediaController;
|
||||
import androidx.media3.session.SessionCommand;
|
||||
import androidx.media3.session.SessionToken;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter;
|
||||
import androidx.viewpager2.widget.ViewPager2;
|
||||
import com.b44t.messenger.DcChat;
|
||||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.DcEvent;
|
||||
import com.b44t.messenger.DcMsg;
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import com.google.android.material.tabs.TabLayoutMediator;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import java.util.ArrayList;
|
||||
import org.thoughtcrime.securesms.components.audioplay.AudioPlaybackViewModel;
|
||||
import org.thoughtcrime.securesms.components.audioplay.ChatAudioQueueProvider;
|
||||
import org.thoughtcrime.securesms.connect.DcEventCenter;
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
import org.thoughtcrime.securesms.service.AudioPlaybackService;
|
||||
@@ -35,7 +36,7 @@ import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
|
||||
public class AllMediaActivity extends PassphraseRequiredActionBarActivity
|
||||
implements DcEventCenter.DcEventDelegate {
|
||||
private static final String TAG = AllMediaActivity.class.getSimpleName();
|
||||
private static final String TAG = "AllMediaActivity";
|
||||
|
||||
public static final String CHAT_ID_EXTRA = "chat_id";
|
||||
public static final String CONTACT_ID_EXTRA = "contact_id";
|
||||
@@ -54,7 +55,6 @@ public class AllMediaActivity extends PassphraseRequiredActionBarActivity
|
||||
this.type3 = type3;
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
private DcContext dcContext;
|
||||
private int chatId;
|
||||
@@ -63,7 +63,7 @@ public class AllMediaActivity extends PassphraseRequiredActionBarActivity
|
||||
private final ArrayList<TabData> tabs = new ArrayList<>();
|
||||
private Toolbar toolbar;
|
||||
private TabLayout tabLayout;
|
||||
private ViewPager viewPager;
|
||||
private ViewPager2 viewPager;
|
||||
|
||||
private @Nullable MediaController mediaController;
|
||||
private ListenableFuture<MediaController> mediaControllerFuture;
|
||||
@@ -97,8 +97,20 @@ public class AllMediaActivity extends PassphraseRequiredActionBarActivity
|
||||
isGlobalGallery() ? R.string.menu_all_media : R.string.apps_and_media);
|
||||
}
|
||||
|
||||
this.tabLayout.setupWithViewPager(viewPager);
|
||||
this.viewPager.setAdapter(new AllMediaPagerAdapter(getSupportFragmentManager()));
|
||||
AllMediaPagerAdapter adapter = new AllMediaPagerAdapter(this);
|
||||
this.viewPager.setAdapter(adapter);
|
||||
this.viewPager.registerOnPageChangeCallback(
|
||||
new ViewPager2.OnPageChangeCallback() {
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
adapter.onPageChanged(position);
|
||||
}
|
||||
});
|
||||
new TabLayoutMediator(
|
||||
this.tabLayout,
|
||||
this.viewPager,
|
||||
(tab, position) -> tab.setText(getString(tabs.get(position).title)))
|
||||
.attach();
|
||||
if (getIntent().getBooleanExtra(FORCE_GALLERY, false)) {
|
||||
this.viewPager.setCurrentItem(1, false);
|
||||
}
|
||||
@@ -107,7 +119,9 @@ public class AllMediaActivity extends PassphraseRequiredActionBarActivity
|
||||
eventCenter.addObserver(DcContext.DC_EVENT_CHAT_MODIFIED, this);
|
||||
eventCenter.addObserver(DcContext.DC_EVENT_CONTACTS_CHANGED, this);
|
||||
|
||||
int accountId = DcHelper.getAccounts(this).getSelectedAccount().getAccountId();
|
||||
playbackViewModel = new ViewModelProvider(this).get(AudioPlaybackViewModel.class);
|
||||
playbackViewModel.setQueueProvider(new ChatAudioQueueProvider(this, chatId, accountId));
|
||||
initializeMediaController();
|
||||
}
|
||||
|
||||
@@ -119,6 +133,7 @@ public class AllMediaActivity extends PassphraseRequiredActionBarActivity
|
||||
mediaController = null;
|
||||
playbackViewModel.setMediaController(null);
|
||||
}
|
||||
playbackViewModel.setQueueProvider(null);
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@@ -182,31 +197,16 @@ public class AllMediaActivity extends PassphraseRequiredActionBarActivity
|
||||
return contactId == 0 && chatId == 0;
|
||||
}
|
||||
|
||||
private class AllMediaPagerAdapter extends FragmentStatePagerAdapter {
|
||||
private Object currentFragment = null;
|
||||
private class AllMediaPagerAdapter extends FragmentStateAdapter {
|
||||
private int currentPosition = -1;
|
||||
|
||||
AllMediaPagerAdapter(FragmentManager fragmentManager) {
|
||||
super(fragmentManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
|
||||
super.setPrimaryItem(container, position, object);
|
||||
if (currentFragment != null && currentFragment != object) {
|
||||
ActionMode action = null;
|
||||
if (currentFragment instanceof MessageSelectorFragment) {
|
||||
action = ((MessageSelectorFragment) currentFragment).getActionMode();
|
||||
}
|
||||
if (action != null) {
|
||||
action.finish();
|
||||
}
|
||||
}
|
||||
currentFragment = object;
|
||||
AllMediaPagerAdapter(FragmentActivity activity) {
|
||||
super(activity);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Fragment getItem(int position) {
|
||||
public Fragment createFragment(int position) {
|
||||
TabData data = tabs.get(position);
|
||||
Fragment fragment;
|
||||
Bundle args = new Bundle();
|
||||
@@ -229,13 +229,24 @@ public class AllMediaActivity extends PassphraseRequiredActionBarActivity
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
public int getItemCount() {
|
||||
return tabs.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getPageTitle(int position) {
|
||||
return getString(tabs.get(position).title);
|
||||
private void onPageChanged(int newPosition) {
|
||||
if (currentPosition != -1 && currentPosition != newPosition) {
|
||||
for (Fragment fragment : getSupportFragmentManager().getFragments()) {
|
||||
if (!(fragment instanceof MessageSelectorFragment)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ActionMode action = ((MessageSelectorFragment) fragment).getActionMode();
|
||||
if (action != null) {
|
||||
action.finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
currentPosition = newPosition;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,6 @@ import org.thoughtcrime.securesms.connect.KeepAliveService;
|
||||
import org.thoughtcrime.securesms.connect.NetworkStateReceiver;
|
||||
import org.thoughtcrime.securesms.crypto.DatabaseSecret;
|
||||
import org.thoughtcrime.securesms.crypto.DatabaseSecretProvider;
|
||||
import org.thoughtcrime.securesms.geolocation.DcLocationManager;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobManager;
|
||||
import org.thoughtcrime.securesms.notifications.FcmReceiveService;
|
||||
import org.thoughtcrime.securesms.notifications.InChatSounds;
|
||||
@@ -53,7 +52,7 @@ import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.webxdc.WebxdcGarbageCollectionWorker;
|
||||
|
||||
public class ApplicationContext extends MultiDexApplication {
|
||||
private static final String TAG = ApplicationContext.class.getSimpleName();
|
||||
private static final String TAG = "ApplicationContext";
|
||||
private static final Object initLock = new Object();
|
||||
private static volatile boolean isInitialized = false;
|
||||
|
||||
@@ -61,7 +60,6 @@ public class ApplicationContext extends MultiDexApplication {
|
||||
private Rpc rpc;
|
||||
private DcContext dcContext;
|
||||
|
||||
private DcLocationManager dcLocationManager;
|
||||
private DcEventCenter eventCenter;
|
||||
private NotificationCenter notificationCenter;
|
||||
private JobManager jobManager;
|
||||
@@ -126,15 +124,6 @@ public class ApplicationContext extends MultiDexApplication {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get DcLocationManager instance, waiting for initialization if necessary. This method is
|
||||
* thread-safe and will block until initialization is complete.
|
||||
*/
|
||||
public DcLocationManager getLocationManager() {
|
||||
ensureInitialized();
|
||||
return dcLocationManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get DcEventCenter instance, waiting for initialization if necessary. This method is thread-safe
|
||||
* and will block until initialization is complete.
|
||||
@@ -229,7 +218,7 @@ public class ApplicationContext extends MultiDexApplication {
|
||||
Log.i(TAG, "DcAccounts created");
|
||||
rpc = new Rpc(new FFITransport(dcAccounts.getJsonrpcInstance()));
|
||||
Log.i(TAG, "Rpc created");
|
||||
AccountManager.getInstance().migrateToDcAccounts(this);
|
||||
AccountManager.getInstance().migrateToDcAccounts(this, dcAccounts);
|
||||
|
||||
int[] allAccounts = dcAccounts.getAll();
|
||||
Log.i(TAG, "Number of profiles: " + allAccounts.length);
|
||||
@@ -266,12 +255,6 @@ public class ApplicationContext extends MultiDexApplication {
|
||||
// 2025-12-16: The setting was removed.
|
||||
// Revert it to the default if it was changed in the past.
|
||||
ac.setConfigInt("webxdc_realtime_enabled", 1);
|
||||
|
||||
// 2025-11-12: this is needed until core starts ignoring "delete_server_after" for
|
||||
// chatmail
|
||||
if (ac.isChatmail()) {
|
||||
ac.setConfig("delete_server_after", null); // reset
|
||||
}
|
||||
}
|
||||
if (allAccounts.length == 0) {
|
||||
try {
|
||||
@@ -282,7 +265,6 @@ public class ApplicationContext extends MultiDexApplication {
|
||||
}
|
||||
dcContext = dcAccounts.getSelectedAccount();
|
||||
notificationCenter = new NotificationCenter(this);
|
||||
dcLocationManager = new DcLocationManager(this, dcContext);
|
||||
|
||||
isInitialized = true;
|
||||
initLock.notifyAll();
|
||||
|
||||
@@ -20,7 +20,7 @@ import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
|
||||
public abstract class BaseActionBarActivity extends AppCompatActivity {
|
||||
|
||||
private static final String TAG = BaseActionBarActivity.class.getSimpleName();
|
||||
private static final String TAG = "BaseActionBarActivity";
|
||||
protected DynamicTheme dynamicTheme = new DynamicTheme();
|
||||
|
||||
protected void onPreCreate() {
|
||||
|
||||
@@ -13,6 +13,7 @@ import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
@@ -26,6 +27,8 @@ import androidx.core.content.pm.ShortcutInfoCompat;
|
||||
import androidx.core.content.pm.ShortcutManagerCompat;
|
||||
import androidx.core.graphics.drawable.IconCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import chat.delta.rpc.Rpc;
|
||||
import chat.delta.rpc.RpcException;
|
||||
import com.b44t.messenger.DcChat;
|
||||
import com.b44t.messenger.DcContact;
|
||||
import com.b44t.messenger.DcContext;
|
||||
@@ -44,6 +47,7 @@ import org.thoughtcrime.securesms.util.task.SnackbarAsyncTask;
|
||||
import org.thoughtcrime.securesms.util.views.ProgressDialog;
|
||||
|
||||
public abstract class BaseConversationListFragment extends Fragment implements ActionMode.Callback {
|
||||
private static final String TAG = "BaseConversationListFragment";
|
||||
protected ActionMode actionMode;
|
||||
protected PulsingFloatingActionButton fab;
|
||||
|
||||
@@ -170,6 +174,17 @@ public abstract class BaseConversationListFragment extends Fragment implements A
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean areSomeSelectedChatsFresh() {
|
||||
DcContext dcContext = DcHelper.getContext(requireActivity());
|
||||
final Set<Long> selectedChats = getListAdapter().getBatchSelections();
|
||||
for (long chatId : selectedChats) {
|
||||
if (dcContext.getFreshMsgCount((int) chatId) > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void handlePinAllSelected() {
|
||||
final DcContext dcContext = DcHelper.getContext(requireActivity());
|
||||
final Set<Long> selectedConversations =
|
||||
@@ -229,6 +244,26 @@ public abstract class BaseConversationListFragment extends Fragment implements A
|
||||
}
|
||||
}
|
||||
|
||||
private void handleMarkfreshSelected() {
|
||||
final Set<Long> selectedConversations =
|
||||
new HashSet<Long>(getListAdapter().getBatchSelections());
|
||||
|
||||
final Rpc rpc = DcHelper.getRpc(requireActivity());
|
||||
try {
|
||||
int accId = rpc.getSelectedAccountId();
|
||||
for (long chatId : selectedConversations) {
|
||||
rpc.markfreshChat(accId, (int) chatId);
|
||||
}
|
||||
} catch (RpcException e) {
|
||||
Log.e(TAG, "RPC error", e);
|
||||
}
|
||||
|
||||
if (actionMode != null) {
|
||||
actionMode.finish();
|
||||
actionMode = null;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private void handleArchiveAllSelected() {
|
||||
final DcContext dcContext = DcHelper.getContext(requireActivity());
|
||||
@@ -388,9 +423,18 @@ public abstract class BaseConversationListFragment extends Fragment implements A
|
||||
.setIcon(IconCompat.createWithAdaptiveBitmap(avatar))
|
||||
.setIntent(intent)
|
||||
.build();
|
||||
|
||||
boolean success;
|
||||
try {
|
||||
success = ShortcutManagerCompat.requestPinShortcut(activity, shortcutInfoCompat, null);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "ErrAddToHomescreen: requestPinShortcut() failed", e);
|
||||
success = false;
|
||||
}
|
||||
boolean finalSuccess = success;
|
||||
Util.runOnMain(
|
||||
() -> {
|
||||
if (!ShortcutManagerCompat.requestPinShortcut(activity, shortcutInfoCompat, null)) {
|
||||
if (!finalSuccess) {
|
||||
Toast.makeText(
|
||||
activity,
|
||||
"ErrAddToHomescreen: requestPinShortcut() failed",
|
||||
@@ -409,6 +453,7 @@ public abstract class BaseConversationListFragment extends Fragment implements A
|
||||
if (!isRelayingMessageContent(requireActivity())) {
|
||||
final int selectedCount = getListAdapter().getBatchSelections().size();
|
||||
menu.findItem(R.id.menu_add_to_home_screen).setVisible(selectedCount == 1);
|
||||
|
||||
MenuItem archiveItem = menu.findItem(R.id.menu_archive_selected);
|
||||
if (offerToArchive()) {
|
||||
archiveItem.setIcon(R.drawable.ic_archive_white_24dp);
|
||||
@@ -417,6 +462,7 @@ public abstract class BaseConversationListFragment extends Fragment implements A
|
||||
archiveItem.setIcon(R.drawable.ic_unarchive_white_24dp);
|
||||
archiveItem.setTitle(R.string.menu_unarchive_chat);
|
||||
}
|
||||
|
||||
MenuItem pinItem = menu.findItem(R.id.menu_pin_selected);
|
||||
if (areSomeSelectedChatsUnpinned()) {
|
||||
pinItem.setIcon(R.drawable.ic_pin_white);
|
||||
@@ -425,12 +471,17 @@ public abstract class BaseConversationListFragment extends Fragment implements A
|
||||
pinItem.setIcon(R.drawable.ic_unpin_white);
|
||||
pinItem.setTitle(R.string.unpin_chat);
|
||||
}
|
||||
|
||||
MenuItem muteItem = menu.findItem(R.id.menu_mute_selected);
|
||||
if (areSomeSelectedChatsUnmuted()) {
|
||||
muteItem.setTitle(R.string.menu_mute);
|
||||
} else {
|
||||
muteItem.setTitle(R.string.menu_unmute);
|
||||
}
|
||||
|
||||
final boolean someAreFresh = areSomeSelectedChatsFresh();
|
||||
menu.findItem(R.id.menu_marknoticed_selected).setVisible(someAreFresh);
|
||||
menu.findItem(R.id.menu_markfresh_selected).setVisible(!someAreFresh);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -484,6 +535,9 @@ public abstract class BaseConversationListFragment extends Fragment implements A
|
||||
} else if (itemId == R.id.menu_marknoticed_selected) {
|
||||
handleMarknoticedSelected();
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_markfresh_selected) {
|
||||
handleMarkfreshSelected();
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_add_to_home_screen) {
|
||||
handleAddToHomeScreen();
|
||||
return true;
|
||||
|
||||
@@ -29,7 +29,7 @@ import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
*/
|
||||
public abstract class ContactSelectionActivity extends PassphraseRequiredActionBarActivity
|
||||
implements ContactSelectionListFragment.OnContactSelectedListener {
|
||||
private static final String TAG = ContactSelectionActivity.class.getSimpleName();
|
||||
private static final String TAG = "ContactSelectionActivity";
|
||||
|
||||
protected ContactSelectionListFragment contactsFragment;
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
*/
|
||||
public class ContactSelectionListFragment extends Fragment
|
||||
implements LoaderManager.LoaderCallbacks<DcContactsLoader.Ret>, DcEventCenter.DcEventDelegate {
|
||||
private static final String TAG = ContactSelectionListFragment.class.getSimpleName();
|
||||
private static final String TAG = "ContactSelectionListFragment";
|
||||
|
||||
public static final String MULTI_SELECT = "multi_select";
|
||||
public static final String SELECT_UNENCRYPTED_EXTRA = "select_unencrypted_extra";
|
||||
|
||||
@@ -101,6 +101,7 @@ import org.thoughtcrime.securesms.components.ScaleStableImageView;
|
||||
import org.thoughtcrime.securesms.components.SendButton;
|
||||
import org.thoughtcrime.securesms.components.audioplay.AudioPlaybackViewModel;
|
||||
import org.thoughtcrime.securesms.components.audioplay.AudioView;
|
||||
import org.thoughtcrime.securesms.components.audioplay.ChatAudioQueueProvider;
|
||||
import org.thoughtcrime.securesms.components.emoji.MediaKeyboard;
|
||||
import org.thoughtcrime.securesms.connect.AccountManager;
|
||||
import org.thoughtcrime.securesms.connect.DcEventCenter;
|
||||
@@ -148,7 +149,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
InputPanel.Listener,
|
||||
InputPanel.MediaListener,
|
||||
AudioView.OnActionListener {
|
||||
private static final String TAG = ConversationActivity.class.getSimpleName();
|
||||
private static final String TAG = "ConversationActivity";
|
||||
|
||||
public static final String ACCOUNT_ID_EXTRA = "account_id";
|
||||
public static final String CHAT_ID_EXTRA = "chat_id";
|
||||
@@ -199,7 +200,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
private final boolean isSecureText = true;
|
||||
private boolean isDefaultSms = true;
|
||||
private boolean isSecurityInitialized = false;
|
||||
private boolean successfulForwardingAttempt = false;
|
||||
private boolean isEditing = false;
|
||||
private boolean switchedProfile = false;
|
||||
|
||||
@@ -223,7 +223,9 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
initializeViews();
|
||||
initializeResources();
|
||||
|
||||
int accountId = DcHelper.getAccounts(this).getSelectedAccount().getAccountId();
|
||||
playbackViewModel = new ViewModelProvider(this).get(AudioPlaybackViewModel.class);
|
||||
playbackViewModel.setQueueProvider(new ChatAudioQueueProvider(this, chatId, accountId));
|
||||
initializeMediaController();
|
||||
|
||||
initializeSecurity(false, isDefaultSms)
|
||||
@@ -413,6 +415,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
mediaController = null;
|
||||
playbackViewModel.setMediaController(null);
|
||||
}
|
||||
playbackViewModel.setQueueProvider(null);
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@@ -632,12 +635,12 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_start_audio_call) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
CallUtil.startAudioCall(context, chatId);
|
||||
CallUtil.startAudioCall(this, chatId);
|
||||
}
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_start_video_call) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
CallUtil.startVideoCall(context, chatId);
|
||||
CallUtil.startVideoCall(this, chatId);
|
||||
}
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_all_media) {
|
||||
@@ -672,8 +675,14 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
}
|
||||
|
||||
public void setDraftText(String txt) {
|
||||
composeText.setText(txt);
|
||||
composeText.setSelection(composeText.getText().length());
|
||||
try {
|
||||
if (rpc.canSend(rpc.getSelectedAccountId(), chatId)) {
|
||||
composeText.setText(txt);
|
||||
composeText.setSelection(composeText.getText().length());
|
||||
}
|
||||
} catch (RpcException e) {
|
||||
Log.e(TAG, "Rpc error", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void hideSoftKeyboard() {
|
||||
@@ -836,20 +845,17 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
if (dcChat.isSelfTalk()) {
|
||||
SendRelayedMessageUtil.immediatelyRelay(this, chatId);
|
||||
} else {
|
||||
String name = dcChat.getName();
|
||||
if (!dcChat.isMultiUser()) {
|
||||
int[] contactIds = dcContext.getChatContacts(chatId);
|
||||
if (contactIds.length == 1 || contactIds.length == 2) {
|
||||
name = dcContext.getContact(contactIds[0]).getDisplayName();
|
||||
}
|
||||
}
|
||||
int messageIds[] = ShareUtil.getForwardedMessageIDs(this);
|
||||
int messageCount = messageIds == null ? 0 : messageIds.length;
|
||||
new AlertDialog.Builder(this)
|
||||
.setMessage(getString(R.string.ask_forward, name))
|
||||
.setMessage(
|
||||
getResources()
|
||||
.getQuantityString(
|
||||
R.plurals.ask_forward_messages, messageCount, messageCount, dcChat.getName()))
|
||||
.setPositiveButton(
|
||||
R.string.ok,
|
||||
R.string.forward,
|
||||
(dialogInterface, i) -> {
|
||||
SendRelayedMessageUtil.immediatelyRelay(this, chatId);
|
||||
successfulForwardingAttempt = true;
|
||||
})
|
||||
.setNegativeButton(R.string.cancel, (dialogInterface, i) -> finish())
|
||||
.setOnCancelListener(dialog -> finish())
|
||||
@@ -1119,6 +1125,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
if (chatId == DcChat.DC_CHAT_NO_CHAT)
|
||||
throw new IllegalStateException("can't display a conversation for no chat.");
|
||||
dcChat = DcHelper.getContext(context).getChat(chatId);
|
||||
attachmentTypeSelector = null;
|
||||
recipient = new Recipient(this, dcChat);
|
||||
glideRequests = GlideApp.with(this);
|
||||
|
||||
@@ -1267,6 +1274,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
|
||||
DcContext dcContext = DcHelper.getContext(context);
|
||||
final int currentChatId = dcChat.getId();
|
||||
final boolean canSend = dcChat.canSend();
|
||||
Util.runOnAnyBackgroundThread(
|
||||
() -> {
|
||||
DcMsg msg = null;
|
||||
@@ -1389,7 +1397,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dcContext.setDraft(currentChatId, msg);
|
||||
// set or clear draft if user can't send in chat since they can't delete it otherwise
|
||||
dcContext.setDraft(currentChatId, canSend ? msg : null);
|
||||
}
|
||||
future.set(currentChatId);
|
||||
});
|
||||
@@ -1611,7 +1620,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
msg.setQuote(quote.get().getQuotedMsg());
|
||||
}
|
||||
msg.setFileAndDeduplicate(path, null, null);
|
||||
msg.forceSticker();
|
||||
dcContext.sendMsg(chatId, msg);
|
||||
}
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ import org.thoughtcrime.securesms.util.views.ConversationAdaptiveActionsToolbar;
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
public class ConversationFragment extends MessageSelectorFragment {
|
||||
private static final String TAG = ConversationFragment.class.getSimpleName();
|
||||
private static final String TAG = "ConversationFragment";
|
||||
|
||||
private static final int SCROLL_ANIMATION_THRESHOLD = 50;
|
||||
|
||||
@@ -944,6 +944,8 @@ public class ConversationFragment extends MessageSelectorFragment {
|
||||
WebxdcActivity.openWebxdcActivity(
|
||||
getContext(), messageRecord.getParent(), messageRecord.getWebxdcHref());
|
||||
}
|
||||
} else if (messageRecord.getInfoType() == DcMsg.DC_INFO_LOCATIONSTREAMING_ENABLED) {
|
||||
WebxdcActivity.openMaps(getContext(), (int) chatId);
|
||||
} else if (messageRecord.getInfoType() == DcMsg.DC_INFO_CHAT_DESCRIPTION_CHANGED) {
|
||||
Intent intent = new Intent(getContext(), ProfileActivity.class);
|
||||
intent.putExtra(ProfileActivity.CHAT_ID_EXTRA, (int) chatId);
|
||||
|
||||
@@ -24,6 +24,7 @@ import android.graphics.PorterDuff;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.text.Spannable;
|
||||
import android.text.Spanned;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
@@ -36,6 +37,7 @@ import androidx.annotation.DimenRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import chat.delta.rpc.RpcException;
|
||||
import chat.delta.rpc.types.CallInfo;
|
||||
import chat.delta.rpc.types.CallState;
|
||||
@@ -44,6 +46,7 @@ import chat.delta.rpc.types.VcardContact;
|
||||
import com.b44t.messenger.DcChat;
|
||||
import com.b44t.messenger.DcContact;
|
||||
import com.b44t.messenger.DcMsg;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.thoughtcrime.securesms.calls.CallCoordinator;
|
||||
@@ -72,6 +75,7 @@ import org.thoughtcrime.securesms.mms.VcardSlide;
|
||||
import org.thoughtcrime.securesms.reactions.ReactionsConversationView;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.Linkifier;
|
||||
import org.thoughtcrime.securesms.util.LongClickCopySpan;
|
||||
import org.thoughtcrime.securesms.util.LongClickMovementMethod;
|
||||
import org.thoughtcrime.securesms.util.MarkdownUtil;
|
||||
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||
@@ -86,7 +90,7 @@ import org.thoughtcrime.securesms.util.views.Stub;
|
||||
* @author Moxie Marlinspike
|
||||
*/
|
||||
public class ConversationItem extends BaseConversationItem {
|
||||
private static final String TAG = ConversationItem.class.getSimpleName();
|
||||
private static final String TAG = "ConversationItem";
|
||||
|
||||
private static final Rect SWIPE_RECT = new Rect();
|
||||
|
||||
@@ -120,6 +124,9 @@ public class ConversationItem extends BaseConversationItem {
|
||||
private Stub<CallItemView> callViewStub;
|
||||
private @Nullable EventListener eventListener;
|
||||
|
||||
// IDs of accessibility actions registered via ViewCompat.addAccessibilityAction
|
||||
private final List<Integer> linkActionIds = new ArrayList<>();
|
||||
|
||||
private int measureCalls;
|
||||
|
||||
private int incomingBubbleColor;
|
||||
@@ -424,6 +431,12 @@ public class ConversationItem extends BaseConversationItem {
|
||||
bodyText.setClickable(false);
|
||||
bodyText.setFocusable(false);
|
||||
|
||||
// Remove any link actions registered for the previous message binding
|
||||
for (int id : linkActionIds) {
|
||||
ViewCompat.removeAccessibilityAction(this, id);
|
||||
}
|
||||
linkActionIds.clear();
|
||||
|
||||
String subject = messageRecord.getSubject();
|
||||
String text = messageRecord.getText();
|
||||
|
||||
@@ -433,12 +446,33 @@ public class ConversationItem extends BaseConversationItem {
|
||||
if (messageRecord.getType() == DcMsg.DC_MSG_CALL || text.isEmpty()) {
|
||||
bodyText.setVisibility(View.GONE);
|
||||
} else {
|
||||
Spannable spannable = (Spannable) MarkdownUtil.toMarkdown(context, text);
|
||||
Spannable spannable = MarkdownUtil.toMarkdown(context, text);
|
||||
if (batchSelected.isEmpty()) {
|
||||
spannable = Linkifier.linkify(spannable);
|
||||
Linkifier.linkify(spannable);
|
||||
}
|
||||
bodyText.setText(spannable);
|
||||
bodyText.setVisibility(View.VISIBLE);
|
||||
|
||||
// Register a TalkBack "Actions" entry for each link in the message
|
||||
Spanned spanned = (Spanned) spannable;
|
||||
final TextView tv = bodyText;
|
||||
for (LongClickCopySpan span :
|
||||
spanned.getSpans(0, spanned.length(), LongClickCopySpan.class)) {
|
||||
int start = spanned.getSpanStart(span);
|
||||
int end = spanned.getSpanEnd(span);
|
||||
if (start >= 0 && end > start && end <= spanned.length()) {
|
||||
String linkText = spanned.subSequence(start, end).toString();
|
||||
String label = context.getString(R.string.open_link, linkText);
|
||||
linkActionIds.add(
|
||||
ViewCompat.addAccessibilityAction(
|
||||
this,
|
||||
label,
|
||||
(v, args) -> {
|
||||
span.onClick(tv);
|
||||
return true;
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int downloadState = messageRecord.getDownloadState();
|
||||
@@ -1062,7 +1096,18 @@ public class ConversationItem extends BaseConversationItem {
|
||||
if (!messageRecord.isOutgoing() && callInfo.state instanceof CallState.Alerting) {
|
||||
int callId = messageRecord.getId();
|
||||
CallCoordinator coordinator = CallCoordinator.getInstance(context);
|
||||
coordinator.showIncomingCallScreen(callId);
|
||||
|
||||
if (coordinator.hasActiveCall()) {
|
||||
coordinator.showIncomingCallScreen(callId);
|
||||
} else {
|
||||
if (callInfo.sdpOffer == null) {
|
||||
Toast.makeText(context, R.string.error, Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
int accId = dcContext.getAccountId();
|
||||
coordinator.handleIncomingCallFromConversation(
|
||||
accId, callId, callInfo.sdpOffer, callInfo.hasVideo);
|
||||
}
|
||||
} else {
|
||||
if (callInfo.hasVideo) {
|
||||
CallUtil.startVideoCall(getContext(), chatId);
|
||||
|
||||
@@ -69,6 +69,7 @@ import org.thoughtcrime.securesms.components.SearchToolbar;
|
||||
import org.thoughtcrime.securesms.connect.AccountManager;
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
import org.thoughtcrime.securesms.connect.DirectShareUtil;
|
||||
import org.thoughtcrime.securesms.geolocation.LocationStreamingService;
|
||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||
import org.thoughtcrime.securesms.providers.PersistentBlobProvider;
|
||||
@@ -90,7 +91,7 @@ import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
|
||||
public class ConversationListActivity extends PassphraseRequiredActionBarActivity
|
||||
implements ConversationListFragment.ConversationSelectedListener {
|
||||
private static final String TAG = ConversationListActivity.class.getSimpleName();
|
||||
private static final String TAG = "ConversationListActivity";
|
||||
private static final String OPENPGP4FPR = "openpgp4fpr";
|
||||
private static final String NDK_ARCH_WARNED = "ndk_arch_warned";
|
||||
public static final String CLEAR_NOTIFICATIONS = "clear_notifications";
|
||||
@@ -449,6 +450,9 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
||||
refreshTitle();
|
||||
invalidateOptionsMenu();
|
||||
DirectShareUtil.triggerRefreshDirectShare(this);
|
||||
if (DcHelper.getContext(this).isSendingLocationsToChat(0)) {
|
||||
LocationStreamingService.ensureRunning(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -603,6 +607,13 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
||||
}
|
||||
}
|
||||
|
||||
public void handleQrFromSearch(String rawQrString) {
|
||||
qrData = rawQrString;
|
||||
new QrCodeHandler(this)
|
||||
.handleQrData(
|
||||
rawQrString, SecurejoinSource.Scan, SecurejoinUiPath.QrIcon, relayLockLauncher);
|
||||
}
|
||||
|
||||
private void handleResetRelaying() {
|
||||
resetRelayingMessageContent(this);
|
||||
refreshTitle();
|
||||
@@ -688,7 +699,11 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
||||
// Util.copy(inputStream, new FileOutputStream(outputFile));
|
||||
// msg.setFile(outputFile, "image/jpeg");
|
||||
|
||||
msg.setText(getString(R.string.update_2_46ac, "https://arcanechat.me/#contribute", "https://i.delta.chat/#0A45953086F0C166D3BAF1D4BB2025496E4C2704&x=MVPi07rQBEmHO4FRb3brpwDe&j=n8mkKqu42WAKKUCx1bQOVh23&s=AM1YCd_2hKuiSiTEb-2177On&a=arcanechat%40arcanechat.me&n=ArcaneChat&b=ArcaneChat+Channel"));
|
||||
msg.setText(
|
||||
getString(
|
||||
R.string.update_2_46ac,
|
||||
"https://arcanechat.me/#contribute",
|
||||
"https://i.delta.chat/#0A45953086F0C166D3BAF1D4BB2025496E4C2704&x=MVPi07rQBEmHO4FRb3brpwDe&j=n8mkKqu42WAKKUCx1bQOVh23&s=AM1YCd_2hKuiSiTEb-2177On&a=arcanechat%40arcanechat.me&n=ArcaneChat&b=ArcaneChat+Channel"));
|
||||
}
|
||||
dcContext.addDeviceMsg(deviceMsgLabel, msg);
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@ import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@@ -56,12 +55,11 @@ public class ConversationListFragment extends BaseConversationListFragment
|
||||
public static final String ARCHIVE = "archive";
|
||||
public static final String RELOAD_LIST = "reload_list";
|
||||
|
||||
private static final String TAG = ConversationListFragment.class.getSimpleName();
|
||||
private static final String TAG = "ConversationListFragment";
|
||||
|
||||
private RecyclerView list;
|
||||
private View emptyState;
|
||||
private TextView emptySearch;
|
||||
private final String queryFilter = "";
|
||||
private boolean archive;
|
||||
private Timer reloadTimer;
|
||||
private boolean chatlistJustLoaded;
|
||||
@@ -285,22 +283,17 @@ public class ConversationListFragment extends BaseConversationListFragment
|
||||
Log.w(TAG, "Ignoring call to loadChatlist()");
|
||||
return;
|
||||
}
|
||||
DcChatlist chatlist =
|
||||
DcHelper.getContext(context)
|
||||
.getChatlist(listflags, queryFilter.isEmpty() ? null : queryFilter, 0);
|
||||
long startMs = System.currentTimeMillis();
|
||||
DcChatlist chatlist = DcHelper.getContext(context).getChatlist(listflags, null, 0);
|
||||
Log.i(TAG, "⏰ getChatlist(): " + (System.currentTimeMillis() - startMs) + "ms");
|
||||
|
||||
Util.runOnMain(
|
||||
() -> {
|
||||
if (chatlist.getCnt() <= 0 && TextUtils.isEmpty(queryFilter)) {
|
||||
if (chatlist.getCnt() <= 0) {
|
||||
list.setVisibility(View.INVISIBLE);
|
||||
emptyState.setVisibility(View.VISIBLE);
|
||||
emptySearch.setVisibility(View.INVISIBLE);
|
||||
fab.startPulse(3 * 1000);
|
||||
} else if (chatlist.getCnt() <= 0 && !TextUtils.isEmpty(queryFilter)) {
|
||||
list.setVisibility(View.INVISIBLE);
|
||||
emptyState.setVisibility(View.GONE);
|
||||
emptySearch.setVisibility(View.VISIBLE);
|
||||
emptySearch.setText(getString(R.string.search_no_result_for_x, queryFilter));
|
||||
} else {
|
||||
list.setVisibility(View.VISIBLE);
|
||||
emptyState.setVisibility(View.GONE);
|
||||
|
||||
@@ -44,9 +44,11 @@ import org.thoughtcrime.securesms.components.AvatarView;
|
||||
import org.thoughtcrime.securesms.components.DeliveryStatusView;
|
||||
import org.thoughtcrime.securesms.components.FromTextView;
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.GeneratedContactPhoto;
|
||||
import org.thoughtcrime.securesms.database.model.ThreadRecord;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.search.QrInviteData;
|
||||
import org.thoughtcrime.securesms.util.DateUtils;
|
||||
import org.thoughtcrime.securesms.util.ThemeUtil;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
@@ -222,6 +224,40 @@ public class ConversationListItem extends RelativeLayout
|
||||
avatar.setSeenRecently(false);
|
||||
}
|
||||
|
||||
public void bind(@NonNull QrInviteData inviteData, @NonNull GlideRequests glideRequests) {
|
||||
this.selectedThreads = Collections.emptySet();
|
||||
|
||||
fromView.setText(inviteData.getDisplayTitle());
|
||||
fromView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
|
||||
subjectView.setVisibility(VISIBLE);
|
||||
subjectView.setText(inviteData.getDisplaySubtitle());
|
||||
subjectView.setTypeface(LIGHT_TYPEFACE);
|
||||
subjectView.setTextColor(
|
||||
ThemeUtil.getThemedColor(getContext(), R.attr.conversation_list_item_subject_color));
|
||||
|
||||
dateView.setText("");
|
||||
dateView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
|
||||
archivedBadgeView.setVisibility(GONE);
|
||||
requestBadgeView.setVisibility(GONE);
|
||||
unreadIndicator.setVisibility(GONE);
|
||||
deliveryStatusIndicator.setNone();
|
||||
|
||||
setBatchState(false);
|
||||
|
||||
if (inviteData.getContactId() > 0) {
|
||||
DcContext dcContext = DcHelper.getContext(getContext());
|
||||
DcContact contact = dcContext.getContact(inviteData.getContactId());
|
||||
Recipient recipient = new Recipient(getContext(), contact);
|
||||
avatar.setAvatar(glideRequests, recipient, false);
|
||||
avatar.setSeenRecently(contact.wasSeenRecently());
|
||||
} else {
|
||||
avatar.setImageDrawable(
|
||||
new GeneratedContactPhoto("+")
|
||||
.asDrawable(getContext(), ThemeUtil.getDummyContactColor(getContext())));
|
||||
avatar.setSeenRecently(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unbind() {}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
public class CreateProfileActivity extends BaseActionBarActivity {
|
||||
|
||||
private static final String TAG = CreateProfileActivity.class.getSimpleName();
|
||||
private static final String TAG = "CreateProfileActivity";
|
||||
|
||||
private static final int REQUEST_CODE_AVATAR = 1;
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
|
||||
public class EphemeralMessagesDialog {
|
||||
|
||||
private static final String TAG = EphemeralMessagesDialog.class.getSimpleName();
|
||||
private static final String TAG = "EphemeralMessagesDialog";
|
||||
|
||||
public static void show(
|
||||
final Context context,
|
||||
|
||||
@@ -46,7 +46,7 @@ import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
|
||||
implements ItemClickListener {
|
||||
|
||||
private static final String TAG = GroupCreateActivity.class.getSimpleName();
|
||||
private static final String TAG = "GroupCreateActivity";
|
||||
public static final String EDIT_GROUP_CHAT_ID = "edit_group_chat_id";
|
||||
public static final String CREATE_BROADCAST = "create_broadcast";
|
||||
public static final String UNENCRYPTED = "unencrypted";
|
||||
@@ -307,8 +307,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
|
||||
|
||||
private boolean showGroupNameEmptyToast(String groupName) {
|
||||
if (groupName == null) {
|
||||
Toast.makeText(this, getString(R.string.group_please_enter_group_name), Toast.LENGTH_LONG)
|
||||
.show();
|
||||
Toast.makeText(this, getString(R.string.please_enter_chat_name), Toast.LENGTH_LONG).show();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -65,7 +65,7 @@ import org.thoughtcrime.securesms.util.views.ProgressDialog;
|
||||
public class InstantOnboardingActivity extends BaseActionBarActivity
|
||||
implements DcEventCenter.DcEventDelegate {
|
||||
|
||||
private static final String TAG = InstantOnboardingActivity.class.getSimpleName();
|
||||
private static final String TAG = "InstantOnboardingActivity";
|
||||
private static final String DCACCOUNT = "dcaccount";
|
||||
private static final String DCLOGIN = "dclogin";
|
||||
private static final String INSTANCES_URL = "https://chatmail.at/relays";
|
||||
|
||||
@@ -18,7 +18,7 @@ import org.thoughtcrime.securesms.util.FileProviderUtil;
|
||||
|
||||
public class LogViewActivity extends BaseActionBarActivity {
|
||||
|
||||
private static final String TAG = LogViewActivity.class.getSimpleName();
|
||||
private static final String TAG = "LogViewActivity";
|
||||
|
||||
LogViewFragment logViewFragment;
|
||||
|
||||
|
||||
@@ -33,14 +33,13 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.FrameLayout;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.loader.app.LoaderManager;
|
||||
import androidx.loader.content.Loader;
|
||||
import androidx.viewpager.widget.PagerAdapter;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.viewpager2.widget.ViewPager2;
|
||||
import com.b44t.messenger.DcChat;
|
||||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.DcMediaGalleryElement;
|
||||
@@ -48,7 +47,6 @@ import com.b44t.messenger.DcMsg;
|
||||
import java.io.IOException;
|
||||
import java.util.WeakHashMap;
|
||||
import org.thoughtcrime.securesms.components.MediaView;
|
||||
import org.thoughtcrime.securesms.components.viewpager.ExtendedOnPageChangedListener;
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.loaders.PagingMediaLoader;
|
||||
@@ -69,7 +67,7 @@ import org.thoughtcrime.securesms.util.Util;
|
||||
public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
implements RecipientModifiedListener, LoaderManager.LoaderCallbacks<DcMediaGalleryElement> {
|
||||
|
||||
private static final String TAG = MediaPreviewActivity.class.getSimpleName();
|
||||
private static final String TAG = "MediaPreviewActivity";
|
||||
|
||||
public static final String ACTIVITY_TITLE_EXTRA = "activity_title";
|
||||
public static final String EDIT_AVATAR_CHAT_ID = "avatar_for_chat_id";
|
||||
@@ -88,7 +86,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
@Nullable private DcMsg messageRecord;
|
||||
private DcContext dcContext;
|
||||
private MediaItem initialMedia;
|
||||
private ViewPager mediaPager;
|
||||
private ViewPager2 mediaPager;
|
||||
private Recipient conversationRecipient;
|
||||
private boolean leftIsRecent;
|
||||
|
||||
@@ -190,7 +188,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
private void initializeViews() {
|
||||
mediaPager = findViewById(R.id.media_pager);
|
||||
mediaPager.setOffscreenPageLimit(1);
|
||||
mediaPager.addOnPageChangeListener(new ViewPagerListener());
|
||||
mediaPager.registerOnPageChangeCallback(new ViewPagerListener());
|
||||
}
|
||||
|
||||
private void initializeResources() {
|
||||
@@ -260,10 +258,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
|
||||
private int cleanupMedia() {
|
||||
int restartItem = mediaPager.getCurrentItem();
|
||||
|
||||
mediaPager.removeAllViews();
|
||||
mediaPager.setAdapter(null);
|
||||
|
||||
return restartItem;
|
||||
}
|
||||
|
||||
@@ -483,22 +478,25 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
DcMediaPagerAdapter adapter =
|
||||
new DcMediaPagerAdapter(this, GlideApp.with(this), getWindow(), data, leftIsRecent);
|
||||
mediaPager.setAdapter(adapter);
|
||||
adapter.setActive(true);
|
||||
mediaPager.setAdapter(adapter);
|
||||
|
||||
if (restartItem < 0) mediaPager.setCurrentItem(data.getPosition());
|
||||
else mediaPager.setCurrentItem(restartItem);
|
||||
if (restartItem < 0) mediaPager.setCurrentItem(data.getPosition(), false);
|
||||
else mediaPager.setCurrentItem(restartItem, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(Loader<DcMediaGalleryElement> loader) {}
|
||||
|
||||
private class ViewPagerListener extends ExtendedOnPageChangedListener {
|
||||
private class ViewPagerListener extends ViewPager2.OnPageChangeCallback {
|
||||
|
||||
private Integer currentPage = null;
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
super.onPageSelected(position);
|
||||
if (currentPage != null && currentPage != position) onPageUnselected(currentPage);
|
||||
currentPage = position;
|
||||
|
||||
MediaItemAdapter adapter = (MediaItemAdapter) mediaPager.getAdapter();
|
||||
|
||||
@@ -510,8 +508,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageUnselected(int position) {
|
||||
private void onPageUnselected(int position) {
|
||||
MediaItemAdapter adapter = (MediaItemAdapter) mediaPager.getAdapter();
|
||||
|
||||
if (adapter != null) {
|
||||
@@ -526,7 +523,9 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
}
|
||||
}
|
||||
|
||||
private static class SingleItemPagerAdapter extends PagerAdapter implements MediaItemAdapter {
|
||||
private static class SingleItemPagerAdapter
|
||||
extends RecyclerView.Adapter<SingleItemPagerAdapter.MediaViewHolder>
|
||||
implements MediaItemAdapter {
|
||||
|
||||
private final GlideRequests glideRequests;
|
||||
private final Window window;
|
||||
@@ -555,37 +554,29 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
public int getItemCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
|
||||
return view == object;
|
||||
public MediaViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
return new MediaViewHolder(inflater.inflate(R.layout.media_view_page, parent, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull Object instantiateItem(@NonNull ViewGroup container, int position) {
|
||||
View itemView = inflater.inflate(R.layout.media_view_page, container, false);
|
||||
MediaView mediaView = itemView.findViewById(R.id.media_view);
|
||||
|
||||
public void onBindViewHolder(@NonNull MediaViewHolder holder, int position) {
|
||||
try {
|
||||
mediaView.set(glideRequests, window, uri, name, mediaType, size, true);
|
||||
holder.mediaView.set(glideRequests, window, uri, name, mediaType, size, true);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
|
||||
container.addView(itemView);
|
||||
|
||||
return itemView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
|
||||
MediaView mediaView = ((FrameLayout) object).findViewById(R.id.media_view);
|
||||
mediaView.cleanup();
|
||||
|
||||
container.removeView((FrameLayout) object);
|
||||
public void onViewRecycled(@NonNull MediaViewHolder holder) {
|
||||
super.onViewRecycled(holder);
|
||||
holder.mediaView.cleanup();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -595,9 +586,20 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
|
||||
@Override
|
||||
public void pause(int position) {}
|
||||
|
||||
static class MediaViewHolder extends RecyclerView.ViewHolder {
|
||||
final MediaView mediaView;
|
||||
|
||||
MediaViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
mediaView = itemView.findViewById(R.id.media_view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class DcMediaPagerAdapter extends PagerAdapter implements MediaItemAdapter {
|
||||
private static class DcMediaPagerAdapter
|
||||
extends RecyclerView.Adapter<DcMediaPagerAdapter.MediaViewHolder>
|
||||
implements MediaItemAdapter {
|
||||
|
||||
private final WeakHashMap<Integer, MediaView> mediaViews = new WeakHashMap<>();
|
||||
|
||||
@@ -630,21 +632,20 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
public int getItemCount() {
|
||||
if (!active) return 0;
|
||||
else return gallery.getCount();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
|
||||
return view == object;
|
||||
public MediaViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View itemView = LayoutInflater.from(context).inflate(R.layout.media_view_page, parent, false);
|
||||
return new MediaViewHolder(itemView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull Object instantiateItem(@NonNull ViewGroup container, int position) {
|
||||
View itemView =
|
||||
LayoutInflater.from(context).inflate(R.layout.media_view_page, container, false);
|
||||
MediaView mediaView = itemView.findViewById(R.id.media_view);
|
||||
public void onBindViewHolder(@NonNull MediaViewHolder holder, int position) {
|
||||
boolean autoplay = position == autoPlayPosition;
|
||||
int cursorPosition = getCursorPosition(position);
|
||||
|
||||
@@ -656,7 +657,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
|
||||
try {
|
||||
//noinspection ConstantConditions
|
||||
mediaView.set(
|
||||
holder.mediaView.set(
|
||||
glideRequests,
|
||||
window,
|
||||
Uri.fromFile(msg.getFileAsFile()),
|
||||
@@ -668,19 +669,17 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
|
||||
mediaViews.put(position, mediaView);
|
||||
container.addView(itemView);
|
||||
|
||||
return itemView;
|
||||
mediaViews.put(position, holder.mediaView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
|
||||
MediaView mediaView = ((FrameLayout) object).findViewById(R.id.media_view);
|
||||
mediaView.cleanup();
|
||||
|
||||
mediaViews.remove(position);
|
||||
container.removeView((FrameLayout) object);
|
||||
public void onViewRecycled(@NonNull MediaViewHolder holder) {
|
||||
super.onViewRecycled(holder);
|
||||
int pos = holder.getBindingAdapterPosition();
|
||||
if (pos != RecyclerView.NO_POSITION) {
|
||||
mediaViews.remove(pos);
|
||||
}
|
||||
holder.mediaView.cleanup();
|
||||
}
|
||||
|
||||
public MediaItem getMediaItemFor(int position) {
|
||||
@@ -710,6 +709,15 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
if (leftIsRecent) return position;
|
||||
else return gallery.getCount() - 1 - position;
|
||||
}
|
||||
|
||||
static class MediaViewHolder extends RecyclerView.ViewHolder {
|
||||
final MediaView mediaView;
|
||||
|
||||
MediaViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
mediaView = itemView.findViewById(R.id.media_view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class MediaItem {
|
||||
@@ -742,7 +750,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
}
|
||||
}
|
||||
|
||||
interface MediaItemAdapter {
|
||||
private interface MediaItemAdapter {
|
||||
MediaItem getMediaItemFor(int position);
|
||||
|
||||
void pause(int position);
|
||||
|
||||
@@ -41,7 +41,7 @@ import org.thoughtcrime.securesms.qr.QrCodeHandler;
|
||||
*/
|
||||
public class NewConversationActivity extends ContactSelectionActivity {
|
||||
|
||||
private static final String TAG = NewConversationActivity.class.getSimpleName();
|
||||
private static final String TAG = "NewConversationActivity";
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle bundle, boolean ready) {
|
||||
|
||||
@@ -7,7 +7,7 @@ import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
import org.thoughtcrime.securesms.service.GenericForegroundService;
|
||||
|
||||
public abstract class PassphraseRequiredActionBarActivity extends BaseActionBarActivity {
|
||||
private static final String TAG = PassphraseRequiredActionBarActivity.class.getSimpleName();
|
||||
private static final String TAG = "PassphraseRequiredActionBarActivity";
|
||||
|
||||
@Override
|
||||
protected final void onCreate(Bundle savedInstanceState) {
|
||||
|
||||
@@ -29,7 +29,7 @@ import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
public class ProfileAdapter extends RecyclerView.Adapter {
|
||||
private static final String TAG = ProfileAdapter.class.getSimpleName();
|
||||
private static final String TAG = "ProfileAdapter";
|
||||
|
||||
public static final int ITEM_AVATAR = 10;
|
||||
public static final int ITEM_DIVIDER = 20;
|
||||
|
||||
@@ -38,7 +38,7 @@ import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
public class ProfileFragment extends Fragment
|
||||
implements ProfileAdapter.ItemClickListener, DcEventCenter.DcEventDelegate {
|
||||
|
||||
private static final String TAG = ProfileFragment.class.getSimpleName();
|
||||
private static final String TAG = "ProfileFragment";
|
||||
public static final String CHAT_ID_EXTRA = "chat_id";
|
||||
public static final String CONTACT_ID_EXTRA = "contact_id";
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ import org.thoughtcrime.securesms.providers.PersistentBlobProvider;
|
||||
|
||||
public class ResolveMediaTask extends AsyncTask<Uri, Void, Uri> {
|
||||
|
||||
private static final String TAG = ResolveMediaTask.class.getSimpleName();
|
||||
private static final String TAG = "ResolveMediaTask";
|
||||
|
||||
interface OnMediaResolvedListener {
|
||||
void onMediaResolved(Uri uri);
|
||||
|
||||
@@ -47,7 +47,7 @@ import org.thoughtcrime.securesms.util.ShareUtil;
|
||||
*/
|
||||
public class ShareActivity extends PassphraseRequiredActionBarActivity
|
||||
implements ResolveMediaTask.OnMediaResolvedListener {
|
||||
private static final String TAG = ShareActivity.class.getSimpleName();
|
||||
private static final String TAG = "ShareActivity";
|
||||
|
||||
public static final String EXTRA_ACC_ID = "acc_id";
|
||||
public static final String EXTRA_CHAT_ID = "chat_id";
|
||||
|
||||
@@ -18,22 +18,19 @@ public class ShareLocationDialog {
|
||||
switch (which) {
|
||||
default:
|
||||
case 0:
|
||||
shareLocationUnit = 5 * 60;
|
||||
break;
|
||||
case 1:
|
||||
shareLocationUnit = 30 * 60;
|
||||
break;
|
||||
case 2:
|
||||
case 1:
|
||||
shareLocationUnit = 60 * 60;
|
||||
break;
|
||||
case 3:
|
||||
case 2:
|
||||
shareLocationUnit = 2 * 60 * 60;
|
||||
break;
|
||||
case 4:
|
||||
case 3:
|
||||
shareLocationUnit = 6 * 60 * 60;
|
||||
break;
|
||||
case 5:
|
||||
shareLocationUnit = 12 * 60 * 60;
|
||||
case 4:
|
||||
shareLocationUnit = 24 * 60 * 60;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
|
||||
public class WebViewActivity extends PassphraseRequiredActionBarActivity
|
||||
implements SearchView.OnQueryTextListener, WebView.FindListener {
|
||||
private static final String TAG = WebViewActivity.class.getSimpleName();
|
||||
private static final String TAG = "WebViewActivity";
|
||||
// Regex to extract the host from a URL for IDN conversion.
|
||||
private static final Pattern URL_PATTERN =
|
||||
Pattern.compile("^((?:[a-zA-Z0-9]+://)?)([^/?#]+)(.*)$");
|
||||
|
||||
@@ -59,7 +59,7 @@ import org.thoughtcrime.securesms.util.MediaUtil;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcEventDelegate {
|
||||
private static final String TAG = WebxdcActivity.class.getSimpleName();
|
||||
private static final String TAG = "WebxdcActivity";
|
||||
private static final String EXTRA_ACCOUNT_ID = "accountId";
|
||||
private static final String EXTRA_APP_MSG_ID = "appMessageId";
|
||||
private static final String EXTRA_HIDE_ACTION_BAR = "hideActionBar";
|
||||
@@ -240,6 +240,7 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE
|
||||
|
||||
WebSettings webSettings = webView.getSettings();
|
||||
webSettings.setJavaScriptEnabled(true);
|
||||
webSettings.setMediaPlaybackRequiresUserGesture(false);
|
||||
webSettings.setAllowFileAccess(false);
|
||||
webSettings.setBlockNetworkLoads(!internetAccess);
|
||||
webSettings.setAllowContentAccess(false);
|
||||
@@ -542,11 +543,25 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE
|
||||
.build();
|
||||
|
||||
Toast.makeText(context, R.string.one_moment, Toast.LENGTH_SHORT).show();
|
||||
if (!ShortcutManagerCompat.requestPinShortcut(context, shortcutInfoCompat, null)) {
|
||||
Toast.makeText(
|
||||
context, "ErrAddToHomescreen: requestPinShortcut() failed", Toast.LENGTH_LONG)
|
||||
.show();
|
||||
}
|
||||
Util.runOnAnyBackgroundThread(
|
||||
() -> {
|
||||
boolean success;
|
||||
try {
|
||||
success = ShortcutManagerCompat.requestPinShortcut(context, shortcutInfoCompat, null);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "ErrAddToHomescreen: requestPinShortcut() failed", e);
|
||||
success = false;
|
||||
}
|
||||
if (!success) {
|
||||
Util.runOnMain(
|
||||
() ->
|
||||
Toast.makeText(
|
||||
context,
|
||||
"ErrAddToHomescreen: requestPinShortcut() failed",
|
||||
Toast.LENGTH_LONG)
|
||||
.show());
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
Toast.makeText(context, "ErrAddToHomescreen: " + e, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
|
||||
public class WebxdcStoreActivity extends PassphraseRequiredActionBarActivity {
|
||||
private static final String TAG = WebxdcStoreActivity.class.getSimpleName();
|
||||
private static final String TAG = "WebxdcStoreActivity";
|
||||
|
||||
private DcContext dcContext;
|
||||
private Rpc rpc;
|
||||
|
||||
@@ -48,7 +48,7 @@ public class WelcomeActivity extends BaseActionBarActivity
|
||||
implements DcEventCenter.DcEventDelegate {
|
||||
public static final String BACKUP_QR_EXTRA = "backup_qr_extra";
|
||||
public static final int PICK_BACKUP = 20574;
|
||||
private static final String TAG = WelcomeActivity.class.getSimpleName();
|
||||
private static final String TAG = "WelcomeActivity";
|
||||
public static final String TMP_BACKUP_FILE = "tmp-backup-file";
|
||||
|
||||
private ProgressDialog progressDialog = null;
|
||||
|
||||
@@ -41,7 +41,7 @@ import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
|
||||
public class AccountSelectionListFragment extends DialogFragment
|
||||
implements DcEventCenter.DcEventDelegate {
|
||||
private static final String TAG = AccountSelectionListFragment.class.getSimpleName();
|
||||
private static final String TAG = "AccountSelectionListFragment";
|
||||
private static final String ARG_SELECT_ONLY = "select_only";
|
||||
private RecyclerView recyclerView;
|
||||
private AccountSelectionListAdapter adapter;
|
||||
@@ -157,6 +157,12 @@ public class AccountSelectionListFragment extends DialogFragment
|
||||
onSetTag(accountId);
|
||||
} else if (itemId == R.id.menu_move_to_top) {
|
||||
onMoveToTop(accountId);
|
||||
} else if (itemId == R.id.menu_mark_all_as_read) {
|
||||
try {
|
||||
DcHelper.getRpc(requireActivity()).marknoticedAllChats(accountId);
|
||||
} catch (RpcException e) {
|
||||
Log.e(TAG, "Error calling rpc.marknoticedAllChats()", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ import org.thoughtcrime.securesms.util.Prefs;
|
||||
|
||||
public class AudioCodec {
|
||||
|
||||
private static final String TAG = AudioCodec.class.getSimpleName();
|
||||
private static final String TAG = "AudioCodec";
|
||||
|
||||
private static final int SAMPLE_RATE_BALANCED = 44100;
|
||||
private static final int BIT_RATE_BALANCED = 32000;
|
||||
@@ -196,7 +196,7 @@ public class AudioCodec {
|
||||
setFinished();
|
||||
}
|
||||
},
|
||||
AudioCodec.class.getSimpleName())
|
||||
"AudioCodec")
|
||||
.start();
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
public class AudioRecorder {
|
||||
|
||||
private static final String TAG = AudioRecorder.class.getSimpleName();
|
||||
private static final String TAG = "AudioRecorder";
|
||||
|
||||
private static final ExecutorService executor = ThreadUtil.newDynamicSingleThreadedExecutor();
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ import org.thoughtcrime.securesms.R;
|
||||
/** Bottom sheet dialog for selecting audio output device */
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
public class AudioDevicePickerDialog extends BottomSheetDialog {
|
||||
private static final String TAG = AudioDevicePickerDialog.class.getSimpleName();
|
||||
private static final String TAG = "AudioDevicePickerDialog";
|
||||
|
||||
public interface OnDeviceSelectedListener {
|
||||
void onDeviceSelected(CallEndpointCompat endpoint);
|
||||
|
||||
@@ -6,11 +6,13 @@ import android.app.PictureInPictureParams;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.PowerManager;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
import android.util.Rational;
|
||||
import android.view.View;
|
||||
@@ -22,7 +24,9 @@ import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import androidx.activity.OnBackPressedCallback;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.cardview.widget.CardView;
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
@@ -51,9 +55,10 @@ import org.webrtc.VideoTrack;
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
public class CallActivity extends AppCompatActivity {
|
||||
|
||||
private static final String TAG = CallActivity.class.getSimpleName();
|
||||
private static final String TAG = "CallActivity";
|
||||
private static final int MIC_PERMISSION_REQUEST_CODE = 1001;
|
||||
private static final int CAMERA_PERMISSION_REQUEST_CODE = 1002;
|
||||
private static final int CAMERA_MID_CALL_PERMISSION_REQUEST_CODE = 1003;
|
||||
|
||||
public static final String ACTION_ANSWER_CALL = BuildConfig.APPLICATION_ID + ".ANSWER_CALL";
|
||||
public static final String ACTION_DECLINE_CALL = BuildConfig.APPLICATION_ID + ".DECLINE_CALL";
|
||||
@@ -99,6 +104,7 @@ public class CallActivity extends AppCompatActivity {
|
||||
private boolean awaitingPermissionResult = false;
|
||||
private boolean pausedWhileAwaitingPermission = false;
|
||||
private boolean intentHandled = false;
|
||||
private boolean doNotAutoFinish = false;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
@@ -227,6 +233,7 @@ public class CallActivity extends AppCompatActivity {
|
||||
Log.d(TAG, "Resuming existing call");
|
||||
} else if (!coordinator.isIncomingCall()) {
|
||||
Log.d(TAG, "Starting outgoing call");
|
||||
coordinator.ensureServiceStarted();
|
||||
viewModel.startOutgoingCallWhenReady();
|
||||
}
|
||||
}
|
||||
@@ -374,6 +381,18 @@ public class CallActivity extends AppCompatActivity {
|
||||
videoButton.setOnClickListener(
|
||||
v -> {
|
||||
if (viewModel != null) {
|
||||
Boolean currentEnabled = viewModel.getVideoEnabled().getValue();
|
||||
boolean needToEnable = currentEnabled == null || !currentEnabled;
|
||||
|
||||
if (needToEnable && !hasCameraPermission()) {
|
||||
awaitingPermissionResult = true;
|
||||
ActivityCompat.requestPermissions(
|
||||
this,
|
||||
new String[] {Manifest.permission.CAMERA},
|
||||
CAMERA_MID_CALL_PERMISSION_REQUEST_CODE);
|
||||
return;
|
||||
}
|
||||
|
||||
viewModel.toggleVideo();
|
||||
}
|
||||
});
|
||||
@@ -634,7 +653,7 @@ public class CallActivity extends AppCompatActivity {
|
||||
new Handler(Looper.getMainLooper())
|
||||
.postDelayed(
|
||||
() -> {
|
||||
if (!isFinishing()) {
|
||||
if (!isFinishing() && !doNotAutoFinish) {
|
||||
finish();
|
||||
}
|
||||
},
|
||||
@@ -643,7 +662,9 @@ public class CallActivity extends AppCompatActivity {
|
||||
|
||||
case ENDED:
|
||||
statusText.setText(R.string.call_ended);
|
||||
finish();
|
||||
if (!doNotAutoFinish) {
|
||||
finish();
|
||||
}
|
||||
break;
|
||||
|
||||
case ERROR:
|
||||
@@ -656,7 +677,7 @@ public class CallActivity extends AppCompatActivity {
|
||||
new Handler(Looper.getMainLooper())
|
||||
.postDelayed(
|
||||
() -> {
|
||||
if (!isFinishing()) {
|
||||
if (!isFinishing() && !doNotAutoFinish) {
|
||||
finish();
|
||||
}
|
||||
},
|
||||
@@ -842,16 +863,28 @@ public class CallActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
private void handleMicPermissionDenied() {
|
||||
Toast.makeText(this, R.string.call_requires_mic_permission, Toast.LENGTH_LONG).show();
|
||||
|
||||
CallCoordinator coordinator = CallCoordinator.getInstance(getApplication());
|
||||
if (coordinator.hasActiveCall()
|
||||
&& coordinator.isIncomingCall()
|
||||
&& !coordinator.hasOngoingCall()) {
|
||||
coordinator.declineCall();
|
||||
|
||||
if (coordinator.hasActiveCall() && !coordinator.hasOngoingCall()) {
|
||||
if (coordinator.isIncomingCall()) {
|
||||
coordinator.declineCall();
|
||||
} else {
|
||||
coordinator.hangUp();
|
||||
}
|
||||
}
|
||||
|
||||
finish();
|
||||
if (!shouldShowRequestPermissionRationale(Manifest.permission.RECORD_AUDIO)) {
|
||||
doNotAutoFinish = true;
|
||||
showPermissionSettingsDialog(
|
||||
getString(R.string.call_requires_mic_permission),
|
||||
() -> {
|
||||
doNotAutoFinish = false;
|
||||
if (!isFinishing()) finish();
|
||||
});
|
||||
} else {
|
||||
Toast.makeText(this, R.string.call_requires_mic_permission, Toast.LENGTH_LONG).show();
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
private void proceedAfterPermissions() {
|
||||
@@ -878,6 +911,22 @@ public class CallActivity extends AppCompatActivity {
|
||||
|
||||
CallCoordinator coordinator = CallCoordinator.getInstance(getApplication());
|
||||
|
||||
if (requestCode == CAMERA_MID_CALL_PERMISSION_REQUEST_CODE) {
|
||||
boolean cameraGranted =
|
||||
grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED;
|
||||
|
||||
if (cameraGranted && viewModel != null) {
|
||||
viewModel.toggleVideo();
|
||||
} else {
|
||||
if (!shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) {
|
||||
showPermissionSettingsDialog(getString(R.string.call_requires_camera_permission), null);
|
||||
} else {
|
||||
Toast.makeText(this, R.string.call_requires_camera_permission, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (requestCode == MIC_PERMISSION_REQUEST_CODE) {
|
||||
boolean micGranted =
|
||||
grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED;
|
||||
@@ -893,9 +942,17 @@ public class CallActivity extends AppCompatActivity {
|
||||
|
||||
if (!cameraGranted) {
|
||||
Log.w(TAG, "Camera permission denied, switching to audio-only");
|
||||
Toast.makeText(
|
||||
this, "Starting audio-only call (camera permission denied)", Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
if (!shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) {
|
||||
Toast.makeText(
|
||||
this,
|
||||
"Camera permission permanently denied. Enable in app settings for video calls.",
|
||||
Toast.LENGTH_LONG)
|
||||
.show();
|
||||
} else {
|
||||
Toast.makeText(
|
||||
this, "Starting audio-only call (camera permission denied)", Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
}
|
||||
coordinator.setStartsWithVideo(false);
|
||||
}
|
||||
}
|
||||
@@ -903,6 +960,34 @@ public class CallActivity extends AppCompatActivity {
|
||||
proceedAfterPermissions();
|
||||
}
|
||||
|
||||
private void showPermissionSettingsDialog(String message, @Nullable Runnable onDismissAction) {
|
||||
if (isFinishing() || isDestroyed()) {
|
||||
if (onDismissAction != null) onDismissAction.run();
|
||||
return;
|
||||
}
|
||||
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle("Permission Required")
|
||||
.setMessage(message)
|
||||
.setPositiveButton(
|
||||
"Open Settings",
|
||||
(dialog, which) -> {
|
||||
Intent intent =
|
||||
new Intent(
|
||||
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
|
||||
Uri.fromParts("package", getPackageName(), null));
|
||||
startActivity(intent);
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setOnDismissListener(
|
||||
dialog -> {
|
||||
if (onDismissAction != null) {
|
||||
onDismissAction.run();
|
||||
}
|
||||
})
|
||||
.show();
|
||||
}
|
||||
|
||||
// Picture-in-Picture
|
||||
|
||||
@Override
|
||||
|
||||
@@ -23,6 +23,7 @@ import android.os.Looper;
|
||||
import android.telecom.DisconnectCause;
|
||||
import android.util.Log;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.core.app.NotificationManagerCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
@@ -32,6 +33,7 @@ import androidx.core.telecom.CallControlScope;
|
||||
import androidx.core.telecom.CallEndpointCompat;
|
||||
import androidx.core.telecom.CallException;
|
||||
import androidx.core.telecom.CallsManager;
|
||||
import androidx.core.util.Pair;
|
||||
import androidx.lifecycle.FlowLiveDataConversions;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MediatorLiveData;
|
||||
@@ -63,7 +65,7 @@ import org.webrtc.VideoTrack;
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
public class CallCoordinator implements DcEventCenter.DcEventDelegate {
|
||||
private static final String TAG = CallCoordinator.class.getSimpleName();
|
||||
private static final String TAG = "CallCoordinator";
|
||||
|
||||
// Notification channels
|
||||
private static final String CHANNEL_ID_INCOMING = "voip_incoming_calls";
|
||||
@@ -97,6 +99,7 @@ public class CallCoordinator implements DcEventCenter.DcEventDelegate {
|
||||
private final MutableLiveData<Boolean> outgoingCallPlaced = new MutableLiveData<>(false);
|
||||
private final MutableLiveData<Boolean> answeredElsewhere = new MutableLiveData<>(false);
|
||||
private final MutableLiveData<Boolean> isFrontCamera = new MutableLiveData<>(true);
|
||||
private final MutableLiveData<Boolean> mediaCaptureReady = new MutableLiveData<>(false);
|
||||
|
||||
// Audio Routing Support
|
||||
private final MediatorLiveData<CallEndpointCompat> currentAudioEndpoint =
|
||||
@@ -119,6 +122,7 @@ public class CallCoordinator implements DcEventCenter.DcEventDelegate {
|
||||
private String pendingOfferSdp;
|
||||
private boolean hasNotifiedBackend = false;
|
||||
private boolean hasAutoSelectedEarpiece = false;
|
||||
private boolean pendingMediaCapture = false;
|
||||
|
||||
private CallControlScope activeCallControlScope;
|
||||
private CallViewModel activeCallViewModel;
|
||||
@@ -215,7 +219,8 @@ public class CallCoordinator implements DcEventCenter.DcEventDelegate {
|
||||
calleeName = "Unknown";
|
||||
}
|
||||
|
||||
showOrUpdateOngoingNotification("Calling " + calleeName + "...");
|
||||
showOrUpdateOngoingNotification(
|
||||
appContext.getString(R.string.calling_person, calleeName));
|
||||
}
|
||||
|
||||
// Initialize call
|
||||
@@ -227,6 +232,11 @@ public class CallCoordinator implements DcEventCenter.DcEventDelegate {
|
||||
mainHandler.removeCallbacks(outgoingRingtoneRunnable);
|
||||
mainHandler.postDelayed(outgoingRingtoneRunnable, 1500);
|
||||
}
|
||||
|
||||
if (pendingMediaCapture) {
|
||||
pendingMediaCapture = false;
|
||||
callService.startMediaCapture();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -335,6 +345,10 @@ public class CallCoordinator implements DcEventCenter.DcEventDelegate {
|
||||
return isFrontCamera;
|
||||
}
|
||||
|
||||
public LiveData<Boolean> getMediaCaptureReady() {
|
||||
return mediaCaptureReady;
|
||||
}
|
||||
|
||||
// State Update Methods (CallService)
|
||||
|
||||
public void updateConnectionState(PeerConnection.PeerConnectionState state) {
|
||||
@@ -374,6 +388,11 @@ public class CallCoordinator implements DcEventCenter.DcEventDelegate {
|
||||
isFrontCamera.postValue(front);
|
||||
}
|
||||
|
||||
public void updateMediaCaptureReady(boolean ready) {
|
||||
Log.d(TAG, "updateMediaCaptureReady: " + ready);
|
||||
mediaCaptureReady.postValue(ready);
|
||||
}
|
||||
|
||||
public void reportError(String error) {
|
||||
Log.e(TAG, "reportError: " + error);
|
||||
errorMessage.postValue(error);
|
||||
@@ -386,7 +405,8 @@ public class CallCoordinator implements DcEventCenter.DcEventDelegate {
|
||||
if (callService != null) {
|
||||
callService.startMediaCapture();
|
||||
} else {
|
||||
Log.w(TAG, "Cannot start media capture, service not ready");
|
||||
Log.d(TAG, "Service not ready, deferring media capture");
|
||||
pendingMediaCapture = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -402,6 +422,15 @@ public class CallCoordinator implements DcEventCenter.DcEventDelegate {
|
||||
callService.stopRingtone();
|
||||
}
|
||||
|
||||
// Promote the service to foreground immediately. Waiting until onIncomingCallAccepted
|
||||
// on executor pool thread is too late on stricter OEM.
|
||||
//
|
||||
// Do not cancel() but use showOrUpdateOngoingNotification to replace incoming
|
||||
// notification without a gap.
|
||||
String callerName = displayName.getValue();
|
||||
if (callerName == null) callerName = "Unknown";
|
||||
showOrUpdateOngoingNotification(appContext.getString(R.string.call_with, callerName));
|
||||
|
||||
// Notify Android system with CallControlScope
|
||||
CallControlScope scope = activeCallControlScope;
|
||||
if (scope != null) {
|
||||
@@ -425,8 +454,6 @@ public class CallCoordinator implements DcEventCenter.DcEventDelegate {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
notificationManager.cancel(NOTIFICATION_ID_CALL);
|
||||
}
|
||||
|
||||
public void answerWebRTC() {
|
||||
@@ -643,11 +670,17 @@ public class CallCoordinator implements DcEventCenter.DcEventDelegate {
|
||||
public synchronized void setVideoEnabled(boolean enabled) {
|
||||
Log.d(TAG, "setVideoEnabled: " + enabled);
|
||||
|
||||
if (callService != null) {
|
||||
boolean success = callService.setVideoEnabled(enabled);
|
||||
if (!success && enabled) {
|
||||
enabled = false;
|
||||
reportError("Camera unavailable");
|
||||
}
|
||||
}
|
||||
|
||||
localVideoEnabled.postValue(enabled);
|
||||
|
||||
if (callService != null) {
|
||||
callService.setVideoEnabled(enabled);
|
||||
|
||||
callService.sendMutedState(Boolean.TRUE.equals(localAudioEnabled.getValue()), enabled);
|
||||
}
|
||||
}
|
||||
@@ -867,32 +900,15 @@ public class CallCoordinator implements DcEventCenter.DcEventDelegate {
|
||||
int accId, int callId, String offerSdp, boolean startsWithVideo) {
|
||||
Log.d(TAG, "onIncomingCall: accId=" + accId + ", callId=" + callId);
|
||||
|
||||
if (hasActiveCall()) {
|
||||
Log.w(TAG, "Already have an active call, ignoring incoming call");
|
||||
return;
|
||||
}
|
||||
Pair<DcChat, String> result = setupIncomingCallState(accId, callId, offerSdp, startsWithVideo);
|
||||
if (result == null) return;
|
||||
|
||||
resetLiveDataForNewCall();
|
||||
|
||||
this.activeAccId = accId;
|
||||
this.activeCallId = callId;
|
||||
this.isIncomingCall = true;
|
||||
this.startsWithVideo = startsWithVideo;
|
||||
this.pendingOfferSdp = offerSdp;
|
||||
|
||||
// Get caller info
|
||||
DcContext dcContext = ApplicationContext.getDcAccounts().getAccount(accId);
|
||||
int chatId = dcContext.getMsg(callId).getChatId();
|
||||
this.activeChatId = chatId;
|
||||
DcChat dcChat = dcContext.getChat(chatId);
|
||||
String callerName = getNameFromChat(dcChat);
|
||||
DcChat dcChat = result.first;
|
||||
String callerName = result.second;
|
||||
Icon callerIcon = getIconFromChat(this.appContext, dcChat);
|
||||
|
||||
displayName.postValue(callerName);
|
||||
displayIcon.postValue(callerIcon);
|
||||
|
||||
this.preferredStartingEndpoint = getPreferredStartingEndpoint(startsWithVideo);
|
||||
|
||||
// Add to CallsManager
|
||||
CallAttributesCompat callAttributes = createCallAttributes(callerName, callId, true);
|
||||
addCallToTelecom(callAttributes, callerName, callerIcon);
|
||||
@@ -903,6 +919,37 @@ public class CallCoordinator implements DcEventCenter.DcEventDelegate {
|
||||
startAndBindService();
|
||||
}
|
||||
|
||||
public synchronized void handleIncomingCallFromConversation(
|
||||
int accId, int callId, String offerSdp, boolean hasVideo) {
|
||||
Log.d(TAG, "handleIncomingCallFromConversation: accId=" + accId + ", callId=" + callId);
|
||||
|
||||
if (offerSdp == null || offerSdp.isEmpty()) {
|
||||
Log.e(TAG, "Cannot start incoming call: no SDP offer");
|
||||
return;
|
||||
}
|
||||
|
||||
Pair<DcChat, String> result = setupIncomingCallState(accId, callId, offerSdp, hasVideo);
|
||||
if (result == null) return;
|
||||
|
||||
DcChat dcChat = result.first;
|
||||
String callerName = result.second;
|
||||
|
||||
new Thread(
|
||||
() -> {
|
||||
Icon callerIcon = getIconFromChat(this.appContext, dcChat);
|
||||
displayIcon.postValue(callerIcon);
|
||||
})
|
||||
.start();
|
||||
|
||||
// Add to CallsManager
|
||||
CallAttributesCompat callAttributes = createCallAttributes(callerName, callId, true);
|
||||
addCallToTelecom(callAttributes, callerName, null);
|
||||
|
||||
startAndBindService();
|
||||
|
||||
launchCallActivity();
|
||||
}
|
||||
|
||||
private synchronized void onIncomingCallAccepted(int callId, boolean fromThisDevice) {
|
||||
Log.d(TAG, "onIncomingCallAccepted: callId=" + callId + ", fromThisDevice=" + fromThisDevice);
|
||||
|
||||
@@ -921,7 +968,7 @@ public class CallCoordinator implements DcEventCenter.DcEventDelegate {
|
||||
callerName = "Unknown";
|
||||
}
|
||||
|
||||
showOrUpdateOngoingNotification("Call with " + callerName);
|
||||
showOrUpdateOngoingNotification(appContext.getString(R.string.call_with, callerName));
|
||||
}
|
||||
|
||||
private synchronized void onCallAnsweredOnOtherDevice() {
|
||||
@@ -1008,7 +1055,7 @@ public class CallCoordinator implements DcEventCenter.DcEventDelegate {
|
||||
if (calleeName == null) {
|
||||
calleeName = "Unknown";
|
||||
}
|
||||
showOrUpdateOngoingNotification("Call with " + calleeName);
|
||||
showOrUpdateOngoingNotification(appContext.getString(R.string.call_with, calleeName));
|
||||
}
|
||||
|
||||
private synchronized void onCallEnded(int accId, int callId) {
|
||||
@@ -1101,6 +1148,14 @@ public class CallCoordinator implements DcEventCenter.DcEventDelegate {
|
||||
return;
|
||||
}
|
||||
|
||||
if (callService != null) {
|
||||
try {
|
||||
callService.stopForegroundAndDismiss();
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, "stopForegroundAndDismiss failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Clear state
|
||||
this.activeAccId = null;
|
||||
this.activeCallId = null;
|
||||
@@ -1113,6 +1168,7 @@ public class CallCoordinator implements DcEventCenter.DcEventDelegate {
|
||||
this.pendingOfferSdp = null;
|
||||
this.hasNotifiedBackend = false;
|
||||
this.hasAutoSelectedEarpiece = false;
|
||||
this.pendingMediaCapture = false;
|
||||
|
||||
mainHandler.removeCallbacks(outgoingRingtoneRunnable);
|
||||
|
||||
@@ -1178,6 +1234,7 @@ public class CallCoordinator implements DcEventCenter.DcEventDelegate {
|
||||
private void resetLiveDataForNewCall() {
|
||||
connectionState.postValue(PeerConnection.PeerConnectionState.NEW);
|
||||
answeredElsewhere.postValue(false); // clearLiveData() must not reset answeredElsewhere
|
||||
mediaCaptureReady.postValue(false);
|
||||
clearLiveData();
|
||||
}
|
||||
|
||||
@@ -1193,6 +1250,7 @@ public class CallCoordinator implements DcEventCenter.DcEventDelegate {
|
||||
outgoingCallPlaced.postValue(false);
|
||||
currentAudioEndpoint.postValue(null);
|
||||
availableAudioEndpoints.postValue(null);
|
||||
mediaCaptureReady.postValue(false);
|
||||
}
|
||||
|
||||
public synchronized void initiateOutgoingCall(int accId, int chatId, boolean startsWithVideo) {
|
||||
@@ -1203,16 +1261,6 @@ public class CallCoordinator implements DcEventCenter.DcEventDelegate {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check microphone permission
|
||||
if (!hasMicrophonePermission()) {
|
||||
Log.e(TAG, "Microphone permission not granted");
|
||||
|
||||
Intent intent = new Intent(appContext, CallActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
appContext.startActivity(intent);
|
||||
return;
|
||||
}
|
||||
|
||||
resetLiveDataForNewCall();
|
||||
|
||||
this.activeCallId = -1; // Placeholder call ID for Intent
|
||||
@@ -1238,7 +1286,9 @@ public class CallCoordinator implements DcEventCenter.DcEventDelegate {
|
||||
|
||||
this.preferredStartingEndpoint = getPreferredStartingEndpoint(startsWithVideo);
|
||||
|
||||
startAndBindService();
|
||||
if (hasMicrophonePermission()) {
|
||||
startAndBindService();
|
||||
}
|
||||
|
||||
launchCallActivity();
|
||||
}
|
||||
@@ -1270,6 +1320,43 @@ public class CallCoordinator implements DcEventCenter.DcEventDelegate {
|
||||
addCallToTelecom(callAttributes, calleeName, calleeIcon);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Pair<DcChat, String> setupIncomingCallState(
|
||||
int accId, int callId, String offerSdp, boolean startsWithVideo) {
|
||||
if (hasActiveCall()) {
|
||||
Log.w(TAG, "Already have an active call, ignoring incoming call");
|
||||
return null;
|
||||
}
|
||||
|
||||
resetLiveDataForNewCall();
|
||||
|
||||
this.activeAccId = accId;
|
||||
this.activeCallId = callId;
|
||||
this.isIncomingCall = true;
|
||||
this.startsWithVideo = startsWithVideo;
|
||||
this.pendingOfferSdp = offerSdp;
|
||||
|
||||
DcContext dcContext = ApplicationContext.getDcAccounts().getAccount(accId);
|
||||
int chatId = dcContext.getMsg(callId).getChatId();
|
||||
this.activeChatId = chatId;
|
||||
DcChat dcChat = dcContext.getChat(chatId);
|
||||
String callerName = getNameFromChat(dcChat);
|
||||
|
||||
displayName.postValue(callerName);
|
||||
|
||||
this.preferredStartingEndpoint = getPreferredStartingEndpoint(startsWithVideo);
|
||||
|
||||
return new Pair<>(dcChat, callerName);
|
||||
}
|
||||
|
||||
public synchronized void ensureServiceStarted() {
|
||||
if (isServiceBound || !hasActiveCall()) {
|
||||
return;
|
||||
}
|
||||
Log.d(TAG, "Starting service after permission grant");
|
||||
startAndBindService();
|
||||
}
|
||||
|
||||
private void addCallToTelecom(
|
||||
CallAttributesCompat callAttributes, String displayName, Icon icon) {
|
||||
try {
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.app.Notification;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.media.AudioAttributes;
|
||||
import android.media.AudioFocusRequest;
|
||||
import android.media.AudioManager;
|
||||
@@ -13,7 +14,9 @@ import android.media.ToneGenerator;
|
||||
import android.net.Uri;
|
||||
import android.os.Binder;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
@@ -33,7 +36,7 @@ import org.webrtc.VideoTrack;
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
public class CallService extends Service implements WebRTCClient.Callbacks {
|
||||
|
||||
private static final String TAG = CallService.class.getSimpleName();
|
||||
private static final String TAG = "CallService";
|
||||
|
||||
private final IBinder binder = new LocalBinder();
|
||||
|
||||
@@ -123,13 +126,13 @@ public class CallService extends Service implements WebRTCClient.Callbacks {
|
||||
}
|
||||
|
||||
/**
|
||||
* Start camera/microphone capture
|
||||
* Start media capture
|
||||
*
|
||||
* <p>Must be called when app is in foreground. Called by coordinator when ViewModel/Activity is
|
||||
* ready.
|
||||
*/
|
||||
public void startMediaCapture() {
|
||||
Log.d(TAG, "startMediaCapture (Camera/Microphone)");
|
||||
Log.d(TAG, "startMediaCapture");
|
||||
|
||||
if (webRTCClient != null && webRTCClient.hasLocalMediaStream()) {
|
||||
Log.w(TAG, "Media already initialized, skipping");
|
||||
@@ -150,7 +153,7 @@ public class CallService extends Service implements WebRTCClient.Callbacks {
|
||||
|
||||
boolean startsWithVideo = callCoordinator.isStartsWithVideo();
|
||||
|
||||
Log.d(TAG, "Creating media stream with video: " + startsWithVideo);
|
||||
Log.d(TAG, "Creating media stream");
|
||||
|
||||
mediaStreamManager.createMediaStream(
|
||||
new MediaStreamManager.Callback() {
|
||||
@@ -160,31 +163,22 @@ public class CallService extends Service implements WebRTCClient.Callbacks {
|
||||
|
||||
webRTCClient.setLocalMediaStream(stream);
|
||||
|
||||
callCoordinator.updateFrontCamera(mediaStreamManager.isFrontCamera());
|
||||
|
||||
callCoordinator.setVideoEnabled(startsWithVideo);
|
||||
|
||||
if (!stream.videoTracks.isEmpty()) {
|
||||
VideoTrack localTrack = stream.videoTracks.get(0);
|
||||
callCoordinator.updateLocalVideoTrack(localTrack);
|
||||
} else {
|
||||
Log.w(TAG, "No video track in stream, call will be audio-only");
|
||||
if (startsWithVideo) {
|
||||
callCoordinator.reportError("Camera unavailable, using audio only");
|
||||
}
|
||||
callCoordinator.setVideoEnabled(false);
|
||||
}
|
||||
|
||||
callCoordinator.setVideoEnabled(startsWithVideo);
|
||||
|
||||
callCoordinator.updateMediaCaptureReady(true);
|
||||
|
||||
Log.d(TAG, "Media capture complete, ready for call");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String error) {
|
||||
Log.e(TAG, "Failed to setup media: " + error);
|
||||
if (startsWithVideo) {
|
||||
callCoordinator.reportError("Camera/microphone error: " + error);
|
||||
}
|
||||
callCoordinator.setVideoEnabled(false);
|
||||
callCoordinator.reportError("Camera/microphone error: " + error);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -392,12 +386,30 @@ public class CallService extends Service implements WebRTCClient.Callbacks {
|
||||
}
|
||||
}
|
||||
|
||||
public void setVideoEnabled(boolean enabled) {
|
||||
public boolean setVideoEnabled(boolean enabled) {
|
||||
Log.d(TAG, "setVideoEnabled: " + enabled);
|
||||
|
||||
if (webRTCClient != null) {
|
||||
webRTCClient.setVideoEnabled(enabled);
|
||||
if (enabled) {
|
||||
if (mediaStreamManager != null) {
|
||||
boolean captureReady = mediaStreamManager.startVideoCapture();
|
||||
if (!captureReady) {
|
||||
Log.w(TAG, "Failed to start video capture");
|
||||
return false;
|
||||
}
|
||||
callCoordinator.updateFrontCamera(mediaStreamManager.isFrontCamera());
|
||||
}
|
||||
if (webRTCClient != null) {
|
||||
webRTCClient.setVideoEnabled(true);
|
||||
}
|
||||
} else {
|
||||
if (webRTCClient != null) {
|
||||
webRTCClient.setVideoEnabled(false);
|
||||
}
|
||||
if (mediaStreamManager != null) {
|
||||
mediaStreamManager.stopVideoCapture();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void sendMutedState(boolean audioEnabled, boolean videoEnabled) {
|
||||
@@ -432,6 +444,12 @@ public class CallService extends Service implements WebRTCClient.Callbacks {
|
||||
|
||||
disposeWebRTC();
|
||||
|
||||
try {
|
||||
stopForeground(STOP_FOREGROUND_REMOVE);
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, "stopForeground failed", e);
|
||||
}
|
||||
|
||||
stopService();
|
||||
}
|
||||
|
||||
@@ -494,13 +512,44 @@ public class CallService extends Service implements WebRTCClient.Callbacks {
|
||||
// Foreground Notification
|
||||
|
||||
public void startForegroundWithNotification(int id, Notification notification) {
|
||||
Log.d(TAG, "Starting foreground with notification id: " + id);
|
||||
startForeground(id, notification);
|
||||
// Always run on main thread
|
||||
if (Looper.myLooper() != Looper.getMainLooper()) {
|
||||
new Handler(Looper.getMainLooper())
|
||||
.post(() -> startForegroundWithNotification(id, notification));
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d(TAG, "Starting call FGS with notification id: " + id);
|
||||
try {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||
startForeground(id, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL);
|
||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
int types =
|
||||
ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE
|
||||
| ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA;
|
||||
startForeground(id, notification, types);
|
||||
} else {
|
||||
startForeground(id, notification);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "startForeground failed", e);
|
||||
if (callCoordinator != null) {
|
||||
callCoordinator.reportError("Failed to activate call FGS: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void stopForegroundAndDismiss() {
|
||||
Log.d(TAG, "Stopping foreground and dismissing notification");
|
||||
stopForeground(STOP_FOREGROUND_REMOVE);
|
||||
if (Looper.myLooper() != Looper.getMainLooper()) {
|
||||
new Handler(Looper.getMainLooper()).post(this::stopForegroundAndDismiss);
|
||||
return;
|
||||
}
|
||||
Log.d(TAG, "Stopping call FGS and dismissing notification");
|
||||
try {
|
||||
stopForeground(STOP_FOREGROUND_REMOVE);
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, "stopForeground failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
|
||||
@@ -5,13 +5,18 @@ import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.Network;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.core.telecom.CallEndpointCompat;
|
||||
import com.b44t.messenger.DcChat;
|
||||
import com.b44t.messenger.DcContext;
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
@@ -21,7 +26,7 @@ import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.BitmapUtil;
|
||||
|
||||
public class CallUtil {
|
||||
private static final String TAG = CallUtil.class.getSimpleName();
|
||||
private static final String TAG = "CallUtil";
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
public static void startAudioCall(Context context, int chatId) {
|
||||
@@ -52,8 +57,22 @@ public class CallUtil {
|
||||
return;
|
||||
}
|
||||
|
||||
int accId = DcHelper.getContext(context).getAccountId();
|
||||
coordinator.initiateOutgoingCall(accId, chatId, startsWithVideo);
|
||||
Runnable proceedWithCall =
|
||||
() -> {
|
||||
int accId = DcHelper.getContext(context).getAccountId();
|
||||
coordinator.initiateOutgoingCall(accId, chatId, startsWithVideo);
|
||||
};
|
||||
|
||||
if (!isNetworkAvailable(context)) {
|
||||
new AlertDialog.Builder(context)
|
||||
.setMessage(context.getString(R.string.call_requires_connection))
|
||||
.setPositiveButton(R.string.perm_continue, (dialog, which) -> proceedWithCall.run())
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show();
|
||||
return;
|
||||
}
|
||||
|
||||
proceedWithCall.run();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -138,4 +157,24 @@ public class CallUtil {
|
||||
}
|
||||
return iconRes;
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
private static boolean isNetworkAvailable(Context context) {
|
||||
ConnectivityManager manager =
|
||||
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
if (manager == null) return true;
|
||||
|
||||
boolean networkAvailable = false;
|
||||
Network network = manager.getActiveNetwork();
|
||||
if (network != null) {
|
||||
NetworkCapabilities caps = manager.getNetworkCapabilities(network);
|
||||
networkAvailable =
|
||||
caps != null && caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
|
||||
}
|
||||
|
||||
boolean serverConnected =
|
||||
DcHelper.getContext(context).getConnectivity() >= DcContext.DC_CONNECTIVITY_WORKING;
|
||||
|
||||
return networkAvailable || serverConnected;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ import org.webrtc.VideoTrack;
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
public class CallViewModel extends AndroidViewModel {
|
||||
|
||||
private static final String TAG = CallViewModel.class.getSimpleName();
|
||||
private static final String TAG = "CallViewModel";
|
||||
|
||||
private final CallCoordinator callCoordinator;
|
||||
|
||||
@@ -46,8 +46,8 @@ public class CallViewModel extends AndroidViewModel {
|
||||
private final MediatorLiveData<CallState> callState;
|
||||
|
||||
// Observer References for one-time observe
|
||||
private Observer<VideoTrack> answerCallObserver;
|
||||
private Observer<VideoTrack> startOutgoingCallObserver;
|
||||
private Observer<Boolean> answerCallObserver;
|
||||
private Observer<Boolean> startOutgoingCallObserver;
|
||||
|
||||
private final AtomicBoolean hasCallEnded = new AtomicBoolean(false);
|
||||
|
||||
@@ -211,25 +211,24 @@ public class CallViewModel extends AndroidViewModel {
|
||||
callCoordinator.startMediaCapture();
|
||||
|
||||
// Create one-time observer
|
||||
LiveData<VideoTrack> localTrack = callCoordinator.getLocalVideoTrack();
|
||||
LiveData<Boolean> mediaReady = callCoordinator.getMediaCaptureReady();
|
||||
|
||||
answerCallObserver =
|
||||
new Observer<VideoTrack>() {
|
||||
new Observer<Boolean>() {
|
||||
@Override
|
||||
public void onChanged(VideoTrack videoTrack) {
|
||||
if (videoTrack != null) {
|
||||
// Media is ready, remove observer
|
||||
localTrack.removeObserver(this);
|
||||
public void onChanged(Boolean ready) {
|
||||
if (Boolean.TRUE.equals(ready)) {
|
||||
mediaReady.removeObserver(this);
|
||||
answerCallObserver = null;
|
||||
|
||||
Log.d(TAG, "Local video ready, answering call (WebRTC)");
|
||||
Log.d(TAG, "Media capture ready, answering call (WebRTC)");
|
||||
|
||||
callCoordinator.answerWebRTC();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
localTrack.observeForever(answerCallObserver);
|
||||
mediaReady.observeForever(answerCallObserver);
|
||||
}
|
||||
|
||||
/** Start outgoing call with media capture Called by Activity for outgoing calls */
|
||||
@@ -244,30 +243,28 @@ public class CallViewModel extends AndroidViewModel {
|
||||
callCoordinator.startMediaCapture();
|
||||
|
||||
// Create one-time observer
|
||||
LiveData<VideoTrack> localTrack = callCoordinator.getLocalVideoTrack();
|
||||
VideoTrack currentValue = localTrack.getValue();
|
||||
LiveData<Boolean> mediaReady = callCoordinator.getMediaCaptureReady();
|
||||
|
||||
if (currentValue != null) {
|
||||
if (Boolean.TRUE.equals(mediaReady.getValue())) {
|
||||
Log.d(TAG, "Media already ready, starting call immediately");
|
||||
callCoordinator.startOutgoingCall();
|
||||
} else {
|
||||
startOutgoingCallObserver =
|
||||
new Observer<VideoTrack>() {
|
||||
new Observer<Boolean>() {
|
||||
@Override
|
||||
public void onChanged(VideoTrack videoTrack) {
|
||||
if (videoTrack != null) {
|
||||
// Media is ready, remove observer
|
||||
localTrack.removeObserver(this);
|
||||
public void onChanged(Boolean ready) {
|
||||
if (Boolean.TRUE.equals(ready)) {
|
||||
mediaReady.removeObserver(this);
|
||||
startOutgoingCallObserver = null;
|
||||
|
||||
Log.d(TAG, "Local video ready, starting outgoing call");
|
||||
Log.d(TAG, "Media capture ready, starting outgoing call");
|
||||
|
||||
callCoordinator.startOutgoingCall();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
localTrack.observeForever(startOutgoingCallObserver);
|
||||
mediaReady.observeForever(startOutgoingCallObserver);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -460,12 +457,12 @@ public class CallViewModel extends AndroidViewModel {
|
||||
Log.d(TAG, "CallViewModel cleared");
|
||||
|
||||
if (answerCallObserver != null) {
|
||||
callCoordinator.getLocalVideoTrack().removeObserver(answerCallObserver);
|
||||
callCoordinator.getMediaCaptureReady().removeObserver(answerCallObserver);
|
||||
answerCallObserver = null;
|
||||
}
|
||||
|
||||
if (startOutgoingCallObserver != null) {
|
||||
callCoordinator.getLocalVideoTrack().removeObserver(startOutgoingCallObserver);
|
||||
callCoordinator.getMediaCaptureReady().removeObserver(startOutgoingCallObserver);
|
||||
startOutgoingCallObserver = null;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,11 +24,15 @@ import org.webrtc.VideoTrack;
|
||||
|
||||
public class MediaStreamManager {
|
||||
|
||||
private static final String TAG = MediaStreamManager.class.getSimpleName();
|
||||
private static final String TAG = "MediaStreamManager";
|
||||
private static final String STREAM_ID = "local_stream";
|
||||
private static final String AUDIO_TRACK_ID = "audio_track";
|
||||
private static final String VIDEO_TRACK_ID = "video_track";
|
||||
|
||||
private static final int VIDEO_WIDTH = 1280;
|
||||
private static final int VIDEO_HEIGHT = 720;
|
||||
private static final int VIDEO_FPS = 30;
|
||||
|
||||
private final Context context;
|
||||
private final PeerConnectionFactory peerConnectionFactory;
|
||||
|
||||
@@ -37,6 +41,7 @@ public class MediaStreamManager {
|
||||
private AudioSource audioSource;
|
||||
private SurfaceTextureHelper surfaceTextureHelper;
|
||||
private volatile boolean isFrontCamera = true;
|
||||
private volatile boolean isCapturing = false;
|
||||
|
||||
public interface Callback {
|
||||
void onMediaStreamReady(MediaStream stream);
|
||||
@@ -56,9 +61,8 @@ public class MediaStreamManager {
|
||||
this.peerConnectionFactory = peerConnectionFactory;
|
||||
}
|
||||
|
||||
/** Create media stream with audio and optionally video */
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
public void createMediaStream(Callback callback) {
|
||||
/** Create a media stream with an audio track and a video track. */
|
||||
public synchronized void createMediaStream(Callback callback) {
|
||||
try {
|
||||
MediaStream mediaStream = peerConnectionFactory.createLocalMediaStream(STREAM_ID);
|
||||
|
||||
@@ -68,24 +72,11 @@ public class MediaStreamManager {
|
||||
AudioTrack audioTrack = peerConnectionFactory.createAudioTrack(AUDIO_TRACK_ID, audioSource);
|
||||
mediaStream.addTrack(audioTrack);
|
||||
|
||||
// Create video track
|
||||
videoCapturer = createVideoCapturer();
|
||||
if (videoCapturer == null) {
|
||||
callback.onError("No camera available");
|
||||
callback.onMediaStreamReady(mediaStream);
|
||||
return;
|
||||
}
|
||||
|
||||
videoSource = peerConnectionFactory.createVideoSource(videoCapturer.isScreencast());
|
||||
// Create video source and track
|
||||
videoSource = peerConnectionFactory.createVideoSource(false);
|
||||
VideoTrack videoTrack = peerConnectionFactory.createVideoTrack(VIDEO_TRACK_ID, videoSource);
|
||||
mediaStream.addTrack(videoTrack);
|
||||
|
||||
// Start capturing
|
||||
surfaceTextureHelper =
|
||||
SurfaceTextureHelper.create("CaptureThread", EglUtils.getEglBase().getEglBaseContext());
|
||||
videoCapturer.initialize(surfaceTextureHelper, context, videoSource.getCapturerObserver());
|
||||
videoCapturer.startCapture(1280, 720, 30);
|
||||
|
||||
callback.onMediaStreamReady(mediaStream);
|
||||
|
||||
} catch (Exception e) {
|
||||
@@ -94,6 +85,62 @@ public class MediaStreamManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the camera and start sending frames to VideoSource.
|
||||
*
|
||||
* @return true if the camera is capturing, false if it could not be started
|
||||
*/
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
public synchronized boolean startVideoCapture() {
|
||||
if (isCapturing) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (videoSource == null) {
|
||||
Log.e(TAG, "VideoSource not initialized");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (videoCapturer == null) {
|
||||
videoCapturer = createVideoCapturer();
|
||||
if (videoCapturer == null) {
|
||||
Log.w(TAG, "Cannot start video capture: no camera available");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (surfaceTextureHelper == null) {
|
||||
surfaceTextureHelper =
|
||||
SurfaceTextureHelper.create("CaptureThread", EglUtils.getEglBase().getEglBaseContext());
|
||||
}
|
||||
|
||||
videoCapturer.initialize(surfaceTextureHelper, context, videoSource.getCapturerObserver());
|
||||
}
|
||||
|
||||
videoCapturer.startCapture(VIDEO_WIDTH, VIDEO_HEIGHT, VIDEO_FPS);
|
||||
isCapturing = true;
|
||||
Log.d(TAG, "Video capture started");
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Stop the camera. The capturer is kept alive. */
|
||||
public synchronized void stopVideoCapture() {
|
||||
if (!isCapturing) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (videoCapturer != null) {
|
||||
try {
|
||||
videoCapturer.stopCapture();
|
||||
Log.d(TAG, "Video capture stopped");
|
||||
} catch (InterruptedException e) {
|
||||
Log.e(TAG, "Interrupted while stopping capture", e);
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
isCapturing = false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private VideoCapturer createVideoCapturer() {
|
||||
if (ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA)
|
||||
@@ -129,6 +176,14 @@ public class MediaStreamManager {
|
||||
}
|
||||
|
||||
public void switchCamera(@Nullable CameraSwitchCallback callback) {
|
||||
if (!isCapturing) {
|
||||
Log.w(TAG, "Cannot switch camera while not capturing");
|
||||
if (callback != null) {
|
||||
callback.onError("Camera not active");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(videoCapturer instanceof CameraVideoCapturer)) {
|
||||
Log.e(TAG, "switchCamera called but videoCapturer is not a CameraVideoCapturer");
|
||||
return;
|
||||
@@ -186,10 +241,12 @@ public class MediaStreamManager {
|
||||
}
|
||||
|
||||
/** Cleanup resources */
|
||||
public void dispose() {
|
||||
public synchronized void dispose() {
|
||||
if (videoCapturer != null) {
|
||||
try {
|
||||
videoCapturer.stopCapture();
|
||||
if (isCapturing) {
|
||||
videoCapturer.stopCapture();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
Log.e(TAG, "Error stopping capture", e);
|
||||
}
|
||||
@@ -197,6 +254,8 @@ public class MediaStreamManager {
|
||||
videoCapturer = null;
|
||||
}
|
||||
|
||||
isCapturing = false;
|
||||
|
||||
if (surfaceTextureHelper != null) {
|
||||
surfaceTextureHelper.dispose();
|
||||
surfaceTextureHelper = null;
|
||||
|
||||
@@ -26,6 +26,7 @@ import androidx.loader.app.LoaderManager;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||
import org.thoughtcrime.securesms.util.Prefs;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
|
||||
public class AttachmentTypeSelector extends PopupWindow {
|
||||
@@ -45,7 +46,7 @@ public class AttachmentTypeSelector extends PopupWindow {
|
||||
private final @NonNull ImageView imageButton;
|
||||
private final @NonNull ImageView documentButton;
|
||||
private final @NonNull ImageView contactButton;
|
||||
// private final @NonNull ImageView cameraButton;
|
||||
// private final @NonNull ImageView cameraButton;
|
||||
private final @NonNull ImageView videoButton;
|
||||
private final @NonNull ImageView locationButton;
|
||||
private final @NonNull ImageView webxdcButton;
|
||||
@@ -87,11 +88,13 @@ public class AttachmentTypeSelector extends PopupWindow {
|
||||
this.webxdcButton.setOnClickListener(new PropagatingClickListener(ADD_WEBXDC));
|
||||
this.recentRail.setListener(new RecentPhotoSelectedListener());
|
||||
|
||||
// disable location streaming button for now
|
||||
// if (!Prefs.isLocationStreamingEnabled(context)) {
|
||||
this.locationButton.setVisibility(View.GONE);
|
||||
ViewUtil.findById(layout, R.id.location_button_label).setVisibility(View.GONE);
|
||||
// }
|
||||
if (!Prefs.isLocationStreamingEnabled(context)) {
|
||||
ViewUtil.findById(layout, R.id.location_linear_layout).setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (DcHelper.getContext(context).getChat(chatId).isOutBroadcast()) {
|
||||
ViewUtil.findById(layout, R.id.webxdc_linear_layout).setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
setLocationButtonImage(context);
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.util.DateUtils;
|
||||
|
||||
public class CallItemView extends FrameLayout {
|
||||
private static final String TAG = CallItemView.class.getSimpleName();
|
||||
private static final String TAG = "CallItemView";
|
||||
|
||||
private final @NonNull ImageView icon;
|
||||
private final @NonNull TextView title;
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
package org.thoughtcrime.securesms.components;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
import org.thoughtcrime.securesms.components.viewpager.HackyViewPager;
|
||||
|
||||
/** An implementation of {@link ViewPager} that disables swiping when the view is disabled. */
|
||||
public class ControllableViewPager extends HackyViewPager {
|
||||
|
||||
public ControllableViewPager(@NonNull Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public ControllableViewPager(@NonNull Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent ev) {
|
||||
return isEnabled() && super.onTouchEvent(ev);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
return isEnabled() && super.onInterceptTouchEvent(ev);
|
||||
}
|
||||
}
|
||||
@@ -43,7 +43,7 @@ public class InputPanel extends ConstraintLayout
|
||||
KeyboardAwareLinearLayout.OnKeyboardShownListener,
|
||||
MediaKeyboard.MediaKeyboardListener {
|
||||
|
||||
private static final String TAG = InputPanel.class.getSimpleName();
|
||||
private static final String TAG = "InputPanel";
|
||||
|
||||
private static final int FADE_TIME = 150;
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
* been opened and what its height would be.
|
||||
*/
|
||||
public class KeyboardAwareLinearLayout extends LinearLayoutCompat {
|
||||
private static final String TAG = KeyboardAwareLinearLayout.class.getSimpleName();
|
||||
private static final String TAG = "KeyboardAwareLinearLayout";
|
||||
|
||||
private static final long KEYBOARD_DEBOUNCE = 150;
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
public class QuoteView extends FrameLayout implements RecipientForeverObserver {
|
||||
|
||||
private static final String TAG = QuoteView.class.getSimpleName();
|
||||
private static final String TAG = "QuoteView";
|
||||
|
||||
private static final int MESSAGE_TYPE_PREVIEW = 0;
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ public class ScaleStableImageView extends AppCompatImageView
|
||||
implements KeyboardAwareLinearLayout.OnKeyboardShownListener,
|
||||
KeyboardAwareLinearLayout.OnKeyboardHiddenListener {
|
||||
|
||||
private static final String TAG = ScaleStableImageView.class.getSimpleName();
|
||||
private static final String TAG = "ScaleStableImageView";
|
||||
|
||||
private Drawable defaultDrawable;
|
||||
private Drawable currentDrawable;
|
||||
|
||||
@@ -22,7 +22,7 @@ import org.thoughtcrime.securesms.animation.AnimationCompleteListener;
|
||||
|
||||
public class SearchToolbar extends LinearLayout {
|
||||
|
||||
private static final String TAG = SearchToolbar.class.getSimpleName();
|
||||
private static final String TAG = "SearchToolbar";
|
||||
private float x, y;
|
||||
private MenuItem searchItem;
|
||||
private EditText searchText;
|
||||
|
||||
@@ -30,7 +30,7 @@ import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
public class ThumbnailView extends FrameLayout {
|
||||
|
||||
private static final String TAG = ThumbnailView.class.getSimpleName();
|
||||
private static final String TAG = "ThumbnailView";
|
||||
private static final int WIDTH = 0;
|
||||
private static final int HEIGHT = 1;
|
||||
private static final int MIN_WIDTH = 0;
|
||||
|
||||
@@ -17,7 +17,7 @@ import org.thoughtcrime.securesms.mms.VcardSlide;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
|
||||
public class VcardView extends FrameLayout {
|
||||
private static final String TAG = VcardView.class.getSimpleName();
|
||||
private static final String TAG = "VcardView";
|
||||
|
||||
private final @NonNull AvatarView avatar;
|
||||
private final @NonNull TextView name;
|
||||
|
||||
+110
-37
@@ -6,22 +6,26 @@ import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.ViewModel;
|
||||
import androidx.media3.common.MediaItem;
|
||||
import androidx.media3.common.PlaybackException;
|
||||
import androidx.media3.common.Player;
|
||||
import androidx.media3.session.MediaController;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class AudioPlaybackViewModel extends ViewModel {
|
||||
private static final String TAG = AudioPlaybackViewModel.class.getSimpleName();
|
||||
private static final String TAG = "AudioPlaybackViewModel";
|
||||
|
||||
private static final int NON_MESSAGE_AUDIO_MSG_ID =
|
||||
0; // Audios not attached to a message doesn't have message id.
|
||||
@@ -34,6 +38,8 @@ public class AudioPlaybackViewModel extends ViewModel {
|
||||
private final ExecutorService extractionExecutor = Executors.newFixedThreadPool(2);
|
||||
|
||||
private @Nullable MediaController mediaController;
|
||||
private @Nullable ChatAudioQueueProvider queueProvider;
|
||||
private @Nullable Player.Listener playerListener;
|
||||
private final Handler handler;
|
||||
private boolean isUserSeeking = false;
|
||||
|
||||
@@ -47,6 +53,11 @@ public class AudioPlaybackViewModel extends ViewModel {
|
||||
}
|
||||
|
||||
public void setMediaController(@Nullable MediaController controller) {
|
||||
if (this.mediaController != null && playerListener != null) {
|
||||
this.mediaController.removeListener(playerListener);
|
||||
}
|
||||
playerListener = null;
|
||||
|
||||
this.mediaController = controller;
|
||||
if (mediaController != null && mediaController.isPlaying()) {
|
||||
startUpdateProgress();
|
||||
@@ -59,30 +70,41 @@ public class AudioPlaybackViewModel extends ViewModel {
|
||||
public void loadAudioAndPlay(int msgId, Uri audioUri) {
|
||||
if (mediaController == null) return;
|
||||
|
||||
// Set media item if we have a different audio.
|
||||
if (isDifferentAudio(msgId, audioUri)) {
|
||||
updateState(msgId, audioUri, AudioPlaybackState.PlaybackStatus.LOADING, 0, 0);
|
||||
String mediaId = String.valueOf(msgId);
|
||||
|
||||
MediaItem mediaItem =
|
||||
new MediaItem.Builder().setMediaId(String.valueOf(msgId)).setUri(audioUri).build();
|
||||
mediaController.setMediaItem(mediaItem);
|
||||
mediaController.prepare();
|
||||
MediaItem current = mediaController.getCurrentMediaItem();
|
||||
if (current != null && mediaId.equals(current.mediaId)) {
|
||||
mediaController.play();
|
||||
return;
|
||||
}
|
||||
|
||||
play(msgId, audioUri);
|
||||
updateState(msgId, audioUri, AudioPlaybackState.PlaybackStatus.LOADING, 0, 0);
|
||||
|
||||
List<MediaItem> items = null;
|
||||
int startIndex = -1;
|
||||
|
||||
if (queueProvider != null) {
|
||||
items = queueProvider.buildAudioQueue();
|
||||
startIndex = indexOfMediaId(items, mediaId);
|
||||
}
|
||||
|
||||
if (startIndex < 0) {
|
||||
items =
|
||||
Collections.singletonList(
|
||||
new MediaItem.Builder().setMediaId(mediaId).setUri(audioUri).build());
|
||||
startIndex = 0;
|
||||
}
|
||||
|
||||
mediaController.setMediaItems(items, startIndex, 0);
|
||||
mediaController.prepare();
|
||||
mediaController.play();
|
||||
}
|
||||
|
||||
private boolean isSameAudio(int msgId, Uri audioUri) {
|
||||
return !isDifferentAudio(msgId, audioUri);
|
||||
}
|
||||
|
||||
private boolean isDifferentAudio(int msgId, Uri audioUri) {
|
||||
AudioPlaybackState currentState = playbackState.getValue();
|
||||
|
||||
return currentState != null
|
||||
&& (msgId != currentState.getMsgId()
|
||||
|| currentState.getAudioUri() == null
|
||||
|| currentState.getAudioUri() != null && !currentState.getAudioUri().equals(audioUri));
|
||||
private static int indexOfMediaId(List<MediaItem> items, String mediaId) {
|
||||
for (int i = 0; i < items.size(); i++) {
|
||||
if (mediaId.equals(items.get(i).mediaId)) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public LiveData<Map<Integer, Long>> getDurations() {
|
||||
@@ -138,46 +160,72 @@ public class AudioPlaybackViewModel extends ViewModel {
|
||||
}
|
||||
}
|
||||
|
||||
public void pause(int msgId, Uri audioUri) {
|
||||
if (mediaController != null && isSameAudio(msgId, audioUri)) {
|
||||
public void pause(int msgId) {
|
||||
if (isCurrentItem(msgId)) {
|
||||
mediaController.pause();
|
||||
}
|
||||
}
|
||||
|
||||
public void play(int msgId, Uri audioUri) {
|
||||
if (mediaController != null && isSameAudio(msgId, audioUri)) {
|
||||
public void play(int msgId) {
|
||||
if (isCurrentItem(msgId)) {
|
||||
mediaController.play();
|
||||
}
|
||||
}
|
||||
|
||||
public void seekTo(long position, int msgId, Uri audioUri) {
|
||||
if (mediaController != null && isSameAudio(msgId, audioUri)) {
|
||||
public void seekTo(long position, int msgId) {
|
||||
if (isCurrentItem(msgId)) {
|
||||
mediaController.seekTo(position);
|
||||
}
|
||||
}
|
||||
|
||||
public void stop(int msgId, Uri audioUri) {
|
||||
if (mediaController != null && isSameAudio(msgId, audioUri)) {
|
||||
public void stop(int msgId) {
|
||||
if (isCurrentItem(msgId)) {
|
||||
mediaController.stop();
|
||||
mediaController.clearMediaItems();
|
||||
stopUpdateProgress();
|
||||
playbackState.setValue(AudioPlaybackState.idle());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isCurrentItem(int msgId) {
|
||||
if (mediaController == null) return false;
|
||||
MediaItem current = mediaController.getCurrentMediaItem();
|
||||
return current != null && String.valueOf(msgId).equals(current.mediaId);
|
||||
}
|
||||
|
||||
public void stopNonMessageAudioPlayback() {
|
||||
stopByIds(NON_MESSAGE_AUDIO_MSG_ID);
|
||||
}
|
||||
|
||||
// A special method for deleting message, where we only use message Ids
|
||||
public void stopByIds(int... msgIds) {
|
||||
AudioPlaybackState currentState = playbackState.getValue();
|
||||
if (mediaController == null) return;
|
||||
|
||||
if (mediaController != null && currentState != null) {
|
||||
AudioPlaybackState currentState = playbackState.getValue();
|
||||
boolean stoppedCurrent = false;
|
||||
|
||||
if (currentState != null) {
|
||||
for (int msgId : msgIds) {
|
||||
if (msgId == currentState.getMsgId()) {
|
||||
mediaController.stop();
|
||||
mediaController.clearMediaItems();
|
||||
stopUpdateProgress();
|
||||
playbackState.setValue(AudioPlaybackState.idle());
|
||||
stoppedCurrent = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!stoppedCurrent) {
|
||||
Set<String> deletedMediaIds = new HashSet<>();
|
||||
for (int msgId : msgIds) {
|
||||
deletedMediaIds.add(String.valueOf(msgId));
|
||||
}
|
||||
for (int i = mediaController.getMediaItemCount() - 1; i >= 0; i--) {
|
||||
MediaItem item = mediaController.getMediaItemAt(i);
|
||||
if (deletedMediaIds.contains(item.mediaId)) {
|
||||
mediaController.removeMediaItem(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -191,10 +239,10 @@ public class AudioPlaybackViewModel extends ViewModel {
|
||||
private void setupPlayerListener() {
|
||||
if (mediaController == null) return;
|
||||
|
||||
mediaController.addListener(
|
||||
playerListener =
|
||||
new Player.Listener() {
|
||||
@Override
|
||||
public void onEvents(Player player, Player.Events events) {
|
||||
public void onEvents(@NonNull Player player, @NonNull Player.Events events) {
|
||||
if (events.containsAny(Player.EVENT_IS_PLAYING_CHANGED)) {
|
||||
if (player.isPlaying()) {
|
||||
startUpdateProgress();
|
||||
@@ -203,20 +251,40 @@ public class AudioPlaybackViewModel extends ViewModel {
|
||||
}
|
||||
updateCurrentState(false);
|
||||
}
|
||||
if (events.containsAny(Player.EVENT_MEDIA_ITEM_TRANSITION)) {
|
||||
updateCurrentState(true);
|
||||
}
|
||||
if (events.containsAny(Player.EVENT_PLAYBACK_STATE_CHANGED)) {
|
||||
if (player.getPlaybackState() == Player.STATE_READY) {
|
||||
updateCurrentState(false);
|
||||
} else if (player.getPlaybackState() == Player.STATE_ENDED) {
|
||||
// This is to prevent automatically playing after the audio
|
||||
// has been play to the end once, then user dragged the seek bar again
|
||||
} else if (player.getPlaybackState() == Player.STATE_ENDED
|
||||
&& !player.hasNextMediaItem()) {
|
||||
mediaController.setPlayWhenReady(false);
|
||||
}
|
||||
}
|
||||
if (events.containsAny(Player.EVENT_PLAYER_ERROR)) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerError(@NonNull PlaybackException error) {
|
||||
Log.w(
|
||||
TAG,
|
||||
"Playback error on msgId="
|
||||
+ (mediaController.getCurrentMediaItem() != null
|
||||
? mediaController.getCurrentMediaItem().mediaId
|
||||
: "null"),
|
||||
error);
|
||||
|
||||
if (mediaController.hasNextMediaItem()) {
|
||||
mediaController.seekToNextMediaItem();
|
||||
mediaController.prepare();
|
||||
mediaController.play();
|
||||
} else {
|
||||
updateCurrentAudioState(AudioPlaybackState.PlaybackStatus.ERROR, 0, 0);
|
||||
mediaController.clearMediaItems();
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
mediaController.addListener(playerListener);
|
||||
}
|
||||
|
||||
private void updateCurrentState(boolean queryPlaying) {
|
||||
@@ -285,6 +353,11 @@ public class AudioPlaybackViewModel extends ViewModel {
|
||||
}
|
||||
}
|
||||
|
||||
// Playing Queue
|
||||
public void setQueueProvider(@Nullable ChatAudioQueueProvider provider) {
|
||||
this.queueProvider = provider;
|
||||
}
|
||||
|
||||
// Progress tracking
|
||||
private final Runnable progressRunnable =
|
||||
new Runnable() {
|
||||
|
||||
@@ -23,7 +23,7 @@ import org.thoughtcrime.securesms.util.DateUtils;
|
||||
|
||||
public class AudioView extends FrameLayout {
|
||||
|
||||
private static final String TAG = AudioView.class.getSimpleName();
|
||||
private static final String TAG = "AudioView";
|
||||
|
||||
private final @NonNull ImageView playPauseButton;
|
||||
private final AnimatedVectorDrawableCompat playToPauseDrawable;
|
||||
@@ -109,12 +109,12 @@ public class AudioView extends FrameLayout {
|
||||
|
||||
AudioPlaybackState state = viewModel.getPlaybackState().getValue();
|
||||
|
||||
if (state != null && msgId == state.getMsgId() && audioUri.equals(state.getAudioUri())) {
|
||||
if (state != null && msgId == state.getMsgId()) {
|
||||
// Same audio
|
||||
if (state.getStatus() == AudioPlaybackState.PlaybackStatus.PLAYING) {
|
||||
viewModel.pause(msgId, audioUri);
|
||||
viewModel.pause(msgId);
|
||||
} else {
|
||||
viewModel.play(msgId, audioUri);
|
||||
viewModel.play(msgId);
|
||||
}
|
||||
} else {
|
||||
// Different audio
|
||||
@@ -145,7 +145,7 @@ public class AudioView extends FrameLayout {
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||
viewModel.setUserSeeking(false);
|
||||
viewModel.seekTo(seekBar.getProgress(), msgId, audioUri);
|
||||
viewModel.seekTo(seekBar.getProgress(), msgId);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -305,7 +305,7 @@ public class AudioView extends FrameLayout {
|
||||
if (audioUri == null || state == null) return;
|
||||
|
||||
// Check if this state is about this message
|
||||
boolean isThisMessage = msgId == state.getMsgId() && audioUri.equals(state.getAudioUri());
|
||||
boolean isThisMessage = msgId == state.getMsgId();
|
||||
|
||||
if (isThisMessage) {
|
||||
updateUIForPlaybackState(state);
|
||||
@@ -340,13 +340,9 @@ public class AudioView extends FrameLayout {
|
||||
private void onDurationsChanged(Map<Integer, Long> durations) {
|
||||
AudioPlaybackState state = viewModel.getPlaybackState().getValue();
|
||||
|
||||
// When there is no playback happening, msgId can be -1 and audioUri is null
|
||||
if (state != null
|
||||
&& msgId >= 0
|
||||
&& msgId == state.getMsgId()
|
||||
&& audioUri != null
|
||||
&& audioUri.equals(state.getAudioUri())) {
|
||||
return; // Is playing this message
|
||||
// When there is no playback happening, msgId can be -1
|
||||
if (state != null && msgId >= 0 && msgId == state.getMsgId()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Long duration = durations.get(msgId);
|
||||
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
package org.thoughtcrime.securesms.components.audioplay;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.media3.common.MediaItem;
|
||||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.DcMsg;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
|
||||
public class ChatAudioQueueProvider {
|
||||
|
||||
private final Context context;
|
||||
private final int chatId;
|
||||
private final int accountId;
|
||||
|
||||
public ChatAudioQueueProvider(@NonNull Context context, int chatId, int accountId) {
|
||||
this.context = context.getApplicationContext();
|
||||
this.chatId = chatId;
|
||||
this.accountId = accountId;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public List<MediaItem> buildAudioQueue() {
|
||||
DcContext dcContext = DcHelper.getContext(context);
|
||||
int[] msgIds = dcContext.getChatMedia(chatId, DcMsg.DC_MSG_AUDIO, DcMsg.DC_MSG_VOICE, 0);
|
||||
|
||||
List<MediaItem> items = new ArrayList<>(msgIds.length);
|
||||
for (int msgId : msgIds) {
|
||||
String id = String.valueOf(msgId);
|
||||
items.add(
|
||||
new MediaItem.Builder()
|
||||
.setMediaId(id)
|
||||
.setUri(Uri.parse("dcmsg://" + accountId + "/" + id))
|
||||
.build());
|
||||
}
|
||||
return items;
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ import org.thoughtcrime.securesms.util.ResUtil;
|
||||
public class MediaKeyboard extends LinearLayout
|
||||
implements InputView, Consumer<EmojiViewItem>, StickerPickerView.StickerPickerListener {
|
||||
|
||||
private static final String TAG = MediaKeyboard.class.getSimpleName();
|
||||
private static final String TAG = "MediaKeyboard";
|
||||
|
||||
@Nullable private MediaKeyboardListener keyboardListener;
|
||||
private EmojiPickerView emojiPicker;
|
||||
|
||||
@@ -71,7 +71,7 @@ public class StickerPickerView extends RecyclerView {
|
||||
}
|
||||
|
||||
// Sort stickers just to provide consistent order
|
||||
Collections.sort(stickerFiles, (f1, f2) -> f1.getName().compareToIgnoreCase(f2.getName()));
|
||||
Collections.sort(stickerFiles, (f1, f2) -> f2.getName().compareToIgnoreCase(f1.getName()));
|
||||
|
||||
return stickerFiles;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import org.thoughtcrime.securesms.util.Prefs;
|
||||
|
||||
@SuppressLint("BatteryLife")
|
||||
public class DozeReminder {
|
||||
private static final String TAG = DozeReminder.class.getSimpleName();
|
||||
private static final String TAG = "DozeReminder";
|
||||
|
||||
public static boolean isEligible(Context context) {
|
||||
if (context == null) {
|
||||
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
package org.thoughtcrime.securesms.components.viewpager;
|
||||
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
|
||||
public abstract class ExtendedOnPageChangedListener implements ViewPager.OnPageChangeListener {
|
||||
|
||||
private Integer currentPage = null;
|
||||
|
||||
@Override
|
||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
if (currentPage != null && currentPage != position) onPageUnselected(currentPage);
|
||||
currentPage = position;
|
||||
}
|
||||
|
||||
public abstract void onPageUnselected(int position);
|
||||
|
||||
@Override
|
||||
public void onPageScrollStateChanged(int state) {}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package org.thoughtcrime.securesms.components.viewpager;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
|
||||
/**
|
||||
* Hacky fix for http://code.google.com/p/android/issues/detail?id=18990
|
||||
*
|
||||
* <p>ScaleGestureDetector seems to mess up the touch events, which means that ViewGroups which make
|
||||
* use of onInterceptTouchEvent throw a lot of IllegalArgumentException: pointerIndex out of range.
|
||||
*
|
||||
* <p>There's not much I can do in my code for now, but we can mask the result by just catching the
|
||||
* problem and ignoring it.
|
||||
*
|
||||
* @author Chris Banes
|
||||
*/
|
||||
public class HackyViewPager extends ViewPager {
|
||||
|
||||
private static final String TAG = HackyViewPager.class.getSimpleName();
|
||||
|
||||
public HackyViewPager(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public HackyViewPager(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
try {
|
||||
return super.onInterceptTouchEvent(ev);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.w(TAG, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ import org.thoughtcrime.securesms.accounts.AccountSelectionListFragment;
|
||||
|
||||
public class AccountManager {
|
||||
|
||||
private static final String TAG = AccountManager.class.getSimpleName();
|
||||
private static final String TAG = "AccountManager";
|
||||
private static final String LAST_ACCOUNT_ID = "last_account_id";
|
||||
private static AccountManager self;
|
||||
|
||||
@@ -38,7 +38,7 @@ public class AccountManager {
|
||||
return self;
|
||||
}
|
||||
|
||||
public void migrateToDcAccounts(ApplicationContext context) {
|
||||
public void migrateToDcAccounts(Context context, DcAccounts dcAccounts) {
|
||||
try {
|
||||
int selectAccountId = 0;
|
||||
|
||||
@@ -49,8 +49,7 @@ public class AccountManager {
|
||||
if (!file.isDirectory()
|
||||
&& file.getName().startsWith("messenger")
|
||||
&& file.getName().endsWith(".db")) {
|
||||
int accountId =
|
||||
ApplicationContext.getDcAccounts().migrateAccount(file.getAbsolutePath());
|
||||
int accountId = dcAccounts.migrateAccount(file.getAbsolutePath());
|
||||
if (accountId != 0) {
|
||||
String selName =
|
||||
PreferenceManager.getDefaultSharedPreferences(context)
|
||||
@@ -67,7 +66,7 @@ public class AccountManager {
|
||||
}
|
||||
|
||||
if (selectAccountId != 0) {
|
||||
ApplicationContext.getDcAccounts().selectAccount(selectAccountId);
|
||||
dcAccounts.selectAccount(selectAccountId);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error in migrateToDcAccounts()", e);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user