Compare commits

..

15 Commits

Author SHA1 Message Date
copilot-swe-agent[bot] 469259f469 Fix LocationListenerCompat compilation error - use correct interface for LocationManagerCompat
Co-authored-by: adbenitez <24558636+adbenitez@users.noreply.github.com>
2025-11-24 21:53:16 +00:00
copilot-swe-agent[bot] 9dcd75fe54 Use LocationManagerCompat for proper location updates on modern Android
Co-authored-by: adbenitez <24558636+adbenitez@users.noreply.github.com>
2025-11-24 21:47:02 +00:00
copilot-swe-agent[bot] adffc4f6f8 Fix foreground service for Android 14+ and add NETWORK_PROVIDER fallback
Co-authored-by: adbenitez <24558636+adbenitez@users.noreply.github.com>
2025-11-24 21:22:29 +00:00
copilot-swe-agent[bot] 7633338359 Fix PermissionsBuilder method chaining - request and execute must be separate calls
Co-authored-by: adbenitez <24558636+adbenitez@users.noreply.github.com>
2025-11-24 20:43:58 +00:00
adb 2f4d239e2b Merge branch 'main' into copilot/allow-location-sharing-again 2025-11-24 21:38:50 +01:00
copilot-swe-agent[bot] ca65424653 Ensure foreground service requirements are met even on error
Co-authored-by: adbenitez <24558636+adbenitez@users.noreply.github.com>
2025-11-24 20:22:58 +00:00
copilot-swe-agent[bot] 6e48933a8f Remove orphaned code from LocationBackgroundService
Co-authored-by: adbenitez <24558636+adbenitez@users.noreply.github.com>
2025-11-24 20:21:00 +00:00
copilot-swe-agent[bot] df50a6d608 Fix method call, thread safety, and service initialization order
Co-authored-by: adbenitez <24558636+adbenitez@users.noreply.github.com>
2025-11-24 20:19:30 +00:00
copilot-swe-agent[bot] b3abc39059 Add FLAG_IMMUTABLE and improve foreground service initialization
Co-authored-by: adbenitez <24558636+adbenitez@users.noreply.github.com>
2025-11-24 20:17:30 +00:00
copilot-swe-agent[bot] 61fc7019b2 Improve foreground service lifecycle handling
Co-authored-by: adbenitez <24558636+adbenitez@users.noreply.github.com>
2025-11-24 20:15:09 +00:00
copilot-swe-agent[bot] b8d6c0b481 Fix service binding logic and foreground service lifecycle
Co-authored-by: adbenitez <24558636+adbenitez@users.noreply.github.com>
2025-11-24 20:13:51 +00:00
copilot-swe-agent[bot] 8675f816de Fix code review feedback: improve error handling and service logic
Co-authored-by: adbenitez <24558636+adbenitez@users.noreply.github.com>
2025-11-24 20:12:34 +00:00
copilot-swe-agent[bot] c9af561868 Add FOREGROUND_SERVICE_LOCATION permission
Co-authored-by: adbenitez <24558636+adbenitez@users.noreply.github.com>
2025-11-24 20:10:28 +00:00
copilot-swe-agent[bot] db10790ecd Implement foreground notification for location sharing
Co-authored-by: adbenitez <24558636+adbenitez@users.noreply.github.com>
2025-11-24 20:07:35 +00:00
copilot-swe-agent[bot] 09f389d6de Initial plan 2025-11-24 20:00:57 +00:00
168 changed files with 2522 additions and 2446 deletions
+1 -12
View File
@@ -60,7 +60,7 @@ jobs:
./gradlew assembleGplayRelease
mv build/outputs/apk/gplay/release/*universal* build/outputs/apk/foss/release/ArcaneChat-gplay.apk
- name: Release on GitHub
- name: Release
uses: softprops/action-gh-release@v1
with:
token: "${{ secrets.GITHUB_TOKEN }}"
@@ -68,14 +68,3 @@ jobs:
prerelease: ${{ contains(github.event.ref, '-beta') }}
fail_on_unmatched_files: true
files: build/outputs/apk/foss/release/*.apk
- name: Release on ZapStore
run: |
export CHECKSUM=6e2c7cf6da53c3f1a78b523a6aacd6316dce3d74ace6f859c2676729ee439990
curl -sL https://cdn.zapstore.dev/$CHECKSUM -o zapstore
if echo "$CHECKSUM zapstore" | sha256sum -c --status; then
chmod +x zapstore
SIGN_WITH=${{ secrets.NOSTR_KEY }} ./zapstore publish --indexer-mode
else
echo "ERROR: checksum doesn't match!"
fi
+2 -13
View File
@@ -1,30 +1,19 @@
# Delta Chat Android Changelog
## v2.33.0
2025-12
## Unreleased
* Target Android 16
* Change color of links in text messages
* Improve edge-to-edge support
* Metadata protection: protect message recipients
* Allow to withdraw channel invite links and QR codes
* Allow to open externally links clicked inside in-chat apps
* Do not show "1 member" when the process of joining the group is not finished
* Make search case-insensitive for non-ASCII chat and contact names
* Improve handling of video recoding
* Send .webm videos as file, they are not supported by all platforms
* Tweak advanced section and wording of some advanced options
* Fix: avoid crash in push notifications handling
* Fix: avoid freezing in background
* Fix: clean up web storage of deleted in-chat apps
* Fix: avoid crash when exporting some files with wrong image MIME type
* Expose new "Multi-device mode" option instead of "Delete from server" for chatmail profiles
* Opened in-chat apps got a 'About Apps' menu item
* Avoid gray avatar on profile creation
* Avoid last item in chat list being covered by the floating button
* Add disk usage statistics to log
* New experimental feature: several addresses per profile
* Update to core 2.33.0
* Update to core 2.28.0
## v2.25.0
2025-11
+4 -5
View File
@@ -21,7 +21,7 @@ android {
}
namespace "org.thoughtcrime.securesms"
flavorDimensions "none"
compileSdk 36
compileSdk 35
// Set NDK version to strip native libraries.
// Even though we compile our libraries outside Gradle with `scripts/ndk-make.sh`,
@@ -33,14 +33,14 @@ android {
useLibrary 'org.apache.http.legacy'
defaultConfig {
versionCode 30000733
versionName "2.33.0"
versionCode 30000732
versionName "2.25.0"
applicationId "chat.delta.lite"
multiDexEnabled true
minSdkVersion 21
targetSdkVersion 36
targetSdkVersion 35
vectorDrawables.useSupportLibrary = true
@@ -211,7 +211,6 @@ dependencies {
implementation "io.noties.markwon:inline-parser:$markwon_version"
implementation 'com.airbnb.android:lottie:4.2.2' // Lottie animations support.
implementation 'androidx.concurrent:concurrent-futures:1.3.0'
implementation 'androidx.sharetarget:sharetarget:1.2.0'
implementation 'androidx.webkit:webkit:1.14.0'
implementation 'androidx.multidex:multidex:2.0.1'
@@ -1,36 +0,0 @@
ArcaneChat — децентрализованный и защищённый мессенджер, удобный для друзей и семьи.
• Анонимность. Мгновенный вход без номера телефона, e-mail или других личных данных.
• Гибкость. Поддерживает несколько профилей чатов и легко настраивается на нескольких устройствах.
• Расширяемость. В чатах можно использовать мини-приложения: списки покупок, календари или игры.
• Надёжность. Работает даже при плохом соединении и в сложных сетевых условиях.
• Безопасность. Проверенное сквозное шифрование, защищённое от сетевых и серверных атак.
• Самостоятельность. Может работать с вашим собственным e-mail-адресом или сервером.
ArcaneChat — клиент Delta Chat, разработанный с акцентом на удобство, качественный UX и экономию трафика. Также приложение часто экспериментирует с новыми функциями, которые со временем могут быть добавлены в официальный клиент Delta Chat.
<b>Основные отличия от официального клиента Delta Chat:</b>
<ul>
<li>Поддержка некоторых стилей markdown в текстовых сообщениях (жирный, курсив, зачёркнутый и т.д.)</li>
<li>Поддержка отображения анимированных стикеров Telegram (.tgs-файлы)</li>
<li>Поддержка предпросмотра SVG-изображений</li>
<li>Несколько цветовых тем/скинов</li>
<li>Возможность отключать профили, полностью отключая им доступ в сеть для экономии трафика</li>
<li>На панели переключения профилей видно состояние подключения каждого профиля</li>
<li>Дополнительная опция для обмена местоположением на 12 часов</li>
<li>Нажатие на сообщение с POI открывает его на карте</li>
<li>Статус «был(а) в сети» отображается в списке контактов, как в WhatsApp, Telegram и т.д.</li>
<li>Видео воспроизводятся по кругу — удобно для коротких GIF-видео</li>
<li>У чата «Device Messages» в списке чатов отображается значок подтверждения</li>
<li>В режиме «низкое качество» голосовые сообщения сжимаются сильнее для экономии трафика</li>
<li>Автоматическая загрузка сообщений по умолчанию ограничена 640KB</li>
<li>Отображаемое имя профиля всегда видно в заголовке приложения вместо названия приложения</li>
<li>Для разработчиков мини-приложений: доступны дополнительные возможности WebXDC API, см. https://github.com/ArcaneChat/android/#webxdc</li>
<li>Более удобная организация настроек с дополнительным разделом «Privacy»</li>
</ul>
@@ -1 +0,0 @@
⚡ Быстрые зашифрованные чаты для семьи 🎉
@@ -1 +0,0 @@
ArcaneChat
+1 -1
View File
@@ -18,7 +18,7 @@
build-tools-35-0-0
cmdline-tools-latest
platform-tools
platforms-android-36
platforms-android-35
ndk-27-2-12479018
]);
rust-version = pkgs.lib.removeSuffix "\n"
-83
View File
@@ -1,83 +0,0 @@
.PHONY: apk
apk:
./scripts/rebrand.sh
./gradlew --offline assembleGplayRelease
./scripts/undo_rebrand.sh
.PHONY: aab
aab:
./scripts/rebrand.sh
sed -i 's/signingConfigs.releaseApk/signingConfigs.releaseBundle/g' build.gradle
./gradlew --offline bundleGplayRelease
sed -i 's/signingConfigs.releaseBundle/signingConfigs.releaseApk/g' build.gradle
./scripts/undo_rebrand.sh
.PHONY: foss
foss:
./scripts/rebrand.sh
./gradlew --offline assembleFossRelease
./scripts/undo_rebrand.sh
.PHONY: install
install:
adb -d install -r build/outputs/apk/gplay/release/*universal*.apk
.PHONY: emulator-install
emulator-install:
adb install -r build/outputs/apk/gplay/release/*universal*.apk
.PHONY: fetch
fetch:
git fetch upstream
.PHONY: clean
clean:
./gradlew --offline clean
# CORE:
.PHONY: fetch-core
fetch-core:
cd ../core && git fetch upstream
.PHONY: core
core:
rmdir jni/deltachat-core-rust; mv ../core jni/deltachat-core-rust; true
./scripts/ndk-make.sh; true
./scripts/undo_rebrand.sh
mv jni/deltachat-core-rust ../core
mkdir jni/deltachat-core-rust
.PHONY: core-fast
core-fast:
rmdir jni/deltachat-core-rust; mv ../core jni/deltachat-core-rust; true
./scripts/ndk-make.sh arm64-v8a; true
./scripts/undo_rebrand.sh
mv jni/deltachat-core-rust ../core
mkdir jni/deltachat-core-rust
.PHONY: core-v7
core-v7:
rmdir jni/deltachat-core-rust; mv ../core jni/deltachat-core-rust; true
./scripts/ndk-make.sh armeabi-v7a; true
./scripts/undo_rebrand.sh
mv jni/deltachat-core-rust ../core
mkdir jni/deltachat-core-rust
.PHONY: core-x86
core-x86:
rmdir jni/deltachat-core-rust; mv ../core jni/deltachat-core-rust; true
./scripts/ndk-make.sh x86; true
./scripts/undo_rebrand.sh
mv jni/deltachat-core-rust ../core
mkdir jni/deltachat-core-rust
.PHONY: link
link:
rmdir jni/deltachat-core-rust; mv ../core jni/deltachat-core-rust; true
.PHONY: unlink
unlink:
mv jni/deltachat-core-rust ../core
mkdir jni/deltachat-core-rust
-1
View File
@@ -1,2 +1 @@
rm src/main/assets/help/*.png
../deltachat-pages/tools/create-local-help.py ../deltachat-pages/result src/main/assets/help
@@ -41,7 +41,7 @@ public class OnboardingTest {
}
onView(withText(R.string.scan_invitation_code)).check(matches(isClickable()));
onView(withText(R.string.import_backup_title)).check(matches(isClickable()));
onView(withText(R.string.manual_account_setup_option)).perform(click());
onView(withText(R.string.login_header)).perform(click());
onView(withHint(R.string.email_address)).perform(replaceText(BuildConfig.TEST_ADDR));
onView(withHint(R.string.existing_password)).perform(replaceText(BuildConfig.TEST_MAIL_PW));
onView(withContentDescription(R.string.ok)).perform(click());
-14
View File
@@ -1,14 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
<application>
<service
android:name=".connect.KeepAliveService"
android:foregroundServiceType="specialUse"
android:enabled="true" />
</application>
</manifest>
-5
View File
@@ -10,11 +10,6 @@
<meta-data android:name="firebase_messaging_auto_init_enabled" android:value="false" />
<application>
<service
android:name=".connect.KeepAliveService"
android:foregroundServiceType="dataSync"
android:enabled="true" />
<service
android:name=".notifications.FcmReceiveService"
android:foregroundServiceType="dataSync"
+8 -6
View File
@@ -13,6 +13,7 @@
<uses-feature android:name="android.hardware.touchscreen" android:required="false"/>
<!-- dangerous permissions - we need to as the user with a PermissionsRequest -->
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
@@ -38,6 +39,7 @@
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
<!-- force compiling emojipicker on sdk<21; runtime checks are required then -->
<uses-sdk tools:overrideLibrary="androidx.emoji2.emojipicker"/>
@@ -54,7 +56,6 @@
android:requestLegacyExternalStorage="true"
tools:targetApi="TIRAMISU"
android:hasFragileUserData="true"
android:enableOnBackInvokedCallback="false"
>
<!-- android car support, see https://developer.android.com/training/auto/start/,
@@ -233,17 +234,13 @@
android:theme="@style/TextSecure.LightNoActionBar"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".relay.EditRelayActivity"
<activity android:name=".EditTransportActivity"
android:launchMode="singleTask"
android:windowSoftInputMode="stateUnchanged"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
android:exported="true">
</activity>
<activity android:name=".relay.RelayListActivity"
android:windowSoftInputMode="stateHidden"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".proxy.ProxySettingsActivity"
android:label="@string/proxy_settings"
android:windowSoftInputMode="stateHidden"
@@ -391,6 +388,11 @@
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize">
</activity>
<service
android:name=".connect.KeepAliveService"
android:foregroundServiceType="dataSync"
android:enabled="true" />
<service
android:name=".geolocation.LocationBackgroundService"
android:foregroundServiceType="location" />
+11 -11
View File
@@ -57,7 +57,7 @@
<li><a href="#experimental-features">Experimental Features</a></li>
<li><a href="#statssending">What is “Send statistics to Delta Chats developers”?</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="#classic-email">How can I configure a chat profile with a classic email address as relay?</a></li>
<li><a href="#classic-email">How can I configure a chat profile with a classic email address as transport?</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="#mám-zájem-o-technické-podrobnosti-kde-najdu-víc">Mám zájem o technické podrobnosti. Kde najdu víc?</a></li>
</ul>
@@ -649,7 +649,7 @@ This makes Delta Chat a truly extensible messenger.</p>
<p>In-chat apps can not send data to the Internet, or download anything.</p>
</li>
<li>
<p>An in-chat app can only exchange data within a chat, with its
<p>An in-chat app can only exchange data within a Delta Chat chat, with its
copies on the devices of your chat partners. Other than that, its completely
isolated from the Internet.</p>
</li>
@@ -1055,7 +1055,7 @@ while chatmail apps and relays pervasively enforce end-to-end encryption and sec
</li>
<li>
<p>Non-chatmail apps use email servers as a long-term message archive
while chatmail clients use email servers for ephemeral instant message relay.</p>
while chatmail clients use email servers for ephemeral instant message transport.</p>
</li>
<li>
<p>Supporting the full variety of classic email setups
@@ -1067,7 +1067,7 @@ and complicate making chatmail-based messaging more resilient, reliable and fast
<h3 id="classic-email">
How can I configure a chat profile with a classic email address as relay? <a href="#classic-email" class="anchor"></a>
How can I configure a chat profile with a classic email address as transport? <a href="#classic-email" class="anchor"></a>
</h3>
@@ -1076,7 +1076,7 @@ and complicate making chatmail-based messaging more resilient, reliable and fast
unless you are prepared to deal with encrypted messages in the inbox,
double notifications, accidentally deleted emails or similar annoyances.</p>
<p>You can configure a email address for chatting at <strong>New Profile → Use Other Server → Use Classic Mail as Relay</strong>.
<p>You can configure a email address for chatting at <strong>New Profile → Use Other Server → Use Classic Mail as Transport</strong>.
Note that classic email providers will generally not support <a href="#instant-delivery">Push Notifications</a>
and have other limitations, see <a href="https://providers.delta.chat">Provider Overview</a>.
Chatmail uses the default INBOX for relay; ensure the provider setup does too.
@@ -1435,12 +1435,12 @@ the connection is safe.</p>
<p>No.</p>
<p>Delta Chat generates secure OpenPGP keys according to the Autocrypt specification 1.1.
We do not recommend or offer users to perform manual key management.
We want to ensure that security audits can focus on a few proven cryptographic algorithms
instead of the full breadth of possible algorithms allowed with OpenPGP.
If you want to extract your OpenPGP key, there only is an expert method:
you need to look it up in the “keypairs” SQLite table of a profile backup tar-file.</p>
<p>Delta Chat generates secure OpenPGP keys according to the Autocrypt specification 1.1.
You can export your private key but you can not import additional private keys.</p>
<p>In general, we do not recommend or offer users to perform manual key management.
We want to ensure that security audits can focus on a few proven cryptographic algorithms
instead of the full breadth of possible algorithms allowed with OpenPGP.</p>
<h3 id="security-audits">
+102 -85
View File
@@ -16,23 +16,23 @@
<li><a href="#edit">Schreibfehler korrigieren und Nachrichten nach dem Senden löschen</a></li>
<li><a href="#ephemeralmsgs">Wie funktionieren “Verschwindende Nachrichten”?</a></li>
<li><a href="#delold">Was passiert, wenn ich “Alte Nachrichten vom Gerät löschen” aktiviere?</a></li>
<li><a href="#remove-account">Wie kann ich mein Chat-Profil löschen?</a></li>
<li><a href="#remove-account">How can I delete my chat profile?</a></li>
</ul>
</li>
<li><a href="#groups">Gruppen</a>
<li><a href="#groups">Groups</a>
<ul>
<li><a href="#eine-gruppe-anlegen">Eine Gruppe anlegen</a></li>
<li><a href="#addmembers">Mitglieder hinzufügen und entfernen</a></li>
<li><a href="#addmembers">Add and remove members</a></li>
<li><a href="#ich-habe-mich-selbst-versehentlich-gelöscht">Ich habe mich selbst versehentlich gelöscht.</a></li>
<li><a href="#ich-möchte-keine-nachrichten-einer-gruppe-mehr-empfangen">Ich möchte keine Nachrichten einer Gruppe mehr empfangen.</a></li>
<li><a href="#eine-gruppe-klonen">Eine Gruppe klonen</a></li>
<li><a href="#cloning-a-group">Cloning a group</a></li>
</ul>
</li>
<li><a href="#webxdc">In-Chat-Apps</a>
<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>
<li><a href="#wie-privat-sind-in-chat-apps">Wie privat sind In-Chat-Apps?</a></li>
<li><a href="#create-xdc">Wie kann mich meine eigene In-Chat-Apps erstellen?</a></li>
<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>
</ul>
</li>
<li><a href="#instant-delivery">Sofortige Nachrichtenzustellung und Push-Benachrichtigungen</a>
@@ -54,10 +54,10 @@
</li>
<li><a href="#erweitert">Erweitert</a>
<ul>
<li><a href="#experimentelle-features">Experimentelle Features</a></li>
<li><a href="#statssending">Was ist “Statistik an Delta Chat Entwickler senden”?</a></li>
<li><a href="#kann-ich-eine-klassische-e-mail-adresse-mit-delta-chat-verwenden">Kann ich eine klassische E-Mail-Adresse mit Delta Chat verwenden?</a></li>
<li><a href="#classic-email">Wie kann ich ein Chat-Profil mit einer klassischen E-Mail-Adresse als Relay konfigurieren?</a></li>
<li><a href="#experimental-features">Experimental Features</a></li>
<li><a href="#statssending">What is “Send statistics to Delta Chats developers”?</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="#classic-email">How can I configure a chat profile with a classic email address as transport?</a></li>
<li><a href="#ich-möchte-meinen-eigenen-server-für-delta-chat-verwalten-gibt-es-empfehlungen">Ich möchte meinen eigenen Server für Delta Chat verwalten. Gibt es Empfehlungen?</a></li>
<li><a href="#ich-bin-an-technischen-details-interessiert-gibt-es-hierzu-weitere-infos">Ich bin an technischen Details interessiert. Gibt es hierzu weitere Infos?</a></li>
</ul>
@@ -65,8 +65,8 @@
<li><a href="#e2ee">Verschlüsselung und Sicherheit</a>
<ul>
<li><a href="#welche-standards-werden-für-die-ende-zu-ende-verschlüsselung-verwendet">Welche Standards werden für die Ende-zu-Ende-Verschlüsselung verwendet?</a></li>
<li><a href="#whene2e">Wie kann ich wissen, ob Nachrichten Ende-zu-Ende-verschlüsselt sind?</a></li>
<li><a href="#kann-ich-nachrichten-ohne-ende-zu-ende-verschlüsselung-empfangen-oder-senden">Kann ich Nachrichten ohne Ende-zu-Ende-Verschlüsselung empfangen oder senden?</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="#e2eeguarantee">Was bedeutet das grüne Häkchen in einem Kontaktprofil?</a></li>
<li><a href="#sind-anhänge-bilder-dateien-audio-usw-ende-zu-ende-verschlüsselt">Sind Anhänge (Bilder, Dateien, Audio usw.) Ende-zu-Ende-verschlüsselt?</a></li>
<li><a href="#openpgp-secure">Ist OpenPGP sicher?</a></li>
@@ -102,26 +102,30 @@
</h2>
<p>Delta Chat ist eine zuverlässige, dezentralisierte und sichere Instant-Messaging-App, verfügbar für Mobile- und Desktop-Plattformen.</p>
<p>Delta Chat is a reliable, decentralized and secure instant messaging app,
available for mobile and desktop platforms.</p>
<ul>
<li>
<p>Einfache Erstellung von <strong>privaten Chat-Profile</strong> mit sicheren, schnellen und interoperablen <a href="https://chatmail.at/relays">Chatmail-Servern</a>,
die sofortige Push-Benachrichtigungen für iOS- und Android-Geräte bieten.</p>
<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>
</li>
<li>
<p>Durchgängige <a href="#multiple-accounts">Mehrprofil</a>- und <a href="#multiclient">Mehrgeräte</a>-Unterstützung auf allen Plattformen und zwischen verschiedenen <a href="https://chatmail.at/clients">Chatmail Apps</a></p>
<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>
</li>
<li>
<p>Interaktive <a href="#webxdc">In-Chats-Apps</a> zum Spielen und für die Zusammenarbeit</p>
<p>Interactive <a href="#webxdc">in-chat apps</a> for gaming and collaboration</p>
</li>
<li>
<p><a href="#security-audits">Geprüfte Ende-zu-Ende-Verschlüsselung</a>,
sicher gegen Netzwerk- und Serverangriffe.</p>
<p><a href="#security-audits">Audited end-to-end encryption</a>
safe against network and server attacks.</p>
</li>
<li>
<p>Freie und quelloffene Software, sowohl app- als auch serverseitig,
basierend auf <a href="https://github.com/chatmail/core/blob/main/standards.md#standards-used-in-delta-chat">Internet-Standards</a>.</p>
<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>
</li>
</ul>
@@ -133,35 +137,41 @@ basierend auf <a href="https://github.com/chatmail/core/blob/main/standards.md#s
</h3>
<p>Beachte zunächst, dass Delta Chat ein privater Messenger ist.
Es gibt keine öffentliches Verzeichnis, du entscheiden selbst über deine Kontakte.</p>
<ul>
<li>Wenn du <strong>persönlich</strong> mit deinen Freunden oder Familie zusammen bist,
tippe auf das <strong>QR-Code</strong>-Symbol <img style="vertical-align:middle; height:1.3em; margin:1px" src="../qr-icon.png" />
auf dem Hauptbildschirm.<br />
Bitte deinen Chatpartner den QR-Code mit Delta Chat zu <strong>scannen</strong>.</li>
</ul>
<p>Für eine Kontaktaufnahme <strong>aus der Ferne</strong>, klicke im selben Bildschirm auf “Kopieren” oder “Teilen” und sende den <strong>Einladungslink</strong> über einen anderen privaten Chat.</p>
<p>Wartet nun, bis die Verbindung hergestellt ist.</p>
<p>First, note that Delta Chat is a private messenger.
There is no public discovery, <em>you</em> decide about your contacts.</p>
<ul>
<li>
<p>Wenn beide Seiten online sind, wird ein Chat angezeigt und ihr könnt sicher miteinander chatten.</p>
<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>
</li>
<li>
<p>Wenn eine Seite offline ist oder eine schlechte Netzwerkverbindung hat,
wird die Chat-Funktion verzögert, bis die Verbindung wiederhergestellt ist.</p>
<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>
</li>
</ul>
<p>Glückwunsch!
Du verwendest jetzt automatisch eine <a href="#e2ee">Ende-zu-Ende-Verschlüsselung</a>
mit deinem Kontakt.
Wenn man sich gegenseitig zu <a href="#groups">Gruppen</a> hinzufügt,
wird eine Ende-zu-Ende-Verschlüsselung zwischen allen Mitgliedern eingerichtet.</p>
<p>Now wait while connection gets established.</p>
<ul>
<li>
<p>If both sides are online, they will soon see a chat
and can start messaging securely.</p>
</li>
<li>
<p>If one side is offline or in bad network,
the ability to chat is delayed until connectivity is restored.</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>
<h3 id="warum-ist-ein-chat-als-anfrage-markiert">
@@ -197,11 +207,11 @@ receive messages from this person, consider <strong>blocking</strong> them.</p>
</h3>
<p>Füge den ersten Kontakt zum Chat des zweiten Kontakts hinzu, indem du auf <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Anhängen → Kontakt</strong> klickst.
Du kannst auch eine kurze Nachricht hinzufügen.</p>
<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>Der zweite Kontakt erhält dann die <strong>Kontaktdaten</strong> und
kann darauf tippen, um mit dem ersten Kontakt zu chatten.</p>
<p>The second contact will receive a <strong>card</strong> then
and can tap it to start chatting with the first contact.</p>
<h3 id="unterstützt-delta-chat-bilder-videos-und-dateianhänge">
@@ -421,7 +431,9 @@ als auch in den Apps selbst gelöscht.</p>
böswillige Chatpartner können Fotos machen,
oder auf andere Weise Nachrichten vor dem Löschen speichern, kopieren oder weiterleiten.</p>
<p>Abgesehen davon, wenn ein Chat-Partner Delta Chat deinstalliert, kann es länger dauern, bis die (ohnehin verschlüsselten) Nachrichten vom Server gelöscht werden.</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>
<h3 id="delold">
@@ -439,7 +451,7 @@ oder auf andere Weise Nachrichten vor dem Löschen speichern, kopieren oder weit
<h3 id="remove-account">
Wie kann ich mein Chat-Profil löschen? <a href="#remove-account" class="anchor"></a>
How can I delete my chat profile? <a href="#remove-account" class="anchor"></a>
</h3>
@@ -458,7 +470,7 @@ or the respective page from your chosen <a href="https://chatmail.at/relays">3rd
<h2 id="groups">
Gruppen <a href="#groups" class="anchor"></a>
Groups <a href="#groups" class="anchor"></a>
</h2>
@@ -490,7 +502,7 @@ and <a href="#edit">delete their own messages</a> from all members devices.</
<h3 id="addmembers">
Mitglieder hinzufügen und entfernen <a href="#addmembers" class="anchor"></a>
Add and remove members <a href="#addmembers" class="anchor"></a>
</h3>
@@ -550,10 +562,10 @@ Wenn du der Gruppe später erneut beitreten möchtest, bitten ein anderes Gruppe
</li>
</ul>
<h3 id="eine-gruppe-klonen">
<h3 id="cloning-a-group">
Eine Gruppe klonen <a href="#eine-gruppe-klonen" class="anchor"></a>
Cloning a group <a href="#cloning-a-group" class="anchor"></a>
</h3>
@@ -577,7 +589,7 @@ which continues to work as before.</p>
<h2 id="webxdc">
In-Chat-Apps <a href="#webxdc" class="anchor"></a>
In-chat apps <a href="#webxdc" class="anchor"></a>
</h2>
@@ -585,10 +597,10 @@ which continues to work as before.</p>
<p>You can send apps to a chat - games, editors, polls and other tools.
This makes Delta Chat a truly extensible messenger.</p>
<h3 id="wo-bekomme-ich-in-chat-apps">
<h3 id="where-can-i-get-in-chat-apps">
Wo bekomme ich In-Chat-Apps? <a href="#wo-bekomme-ich-in-chat-apps" class="anchor"></a>
Where can I get in-chat apps? <a href="#where-can-i-get-in-chat-apps" class="anchor"></a>
</h3>
@@ -602,10 +614,10 @@ This makes Delta Chat a truly extensible messenger.</p>
</li>
</ul>
<h3 id="wie-privat-sind-in-chat-apps">
<h3 id="how-private-are-in-chat-apps">
Wie privat sind In-Chat-Apps? <a href="#wie-privat-sind-in-chat-apps" class="anchor"></a>
How private are in-chat apps? <a href="#how-private-are-in-chat-apps" class="anchor"></a>
</h3>
@@ -615,7 +627,7 @@ This makes Delta Chat a truly extensible messenger.</p>
<p>In-chat apps can not send data to the Internet, or download anything.</p>
</li>
<li>
<p>An in-chat app can only exchange data within a chat, with its
<p>An in-chat app can only exchange data within a Delta Chat chat, with its
copies on the devices of your chat partners. Other than that, its completely
isolated from the Internet.</p>
</li>
@@ -631,7 +643,7 @@ trust the people you chat with, you can trust the in-chat app as well.</p>
<h3 id="create-xdc">
Wie kann mich meine eigene In-Chat-Apps erstellen? <a href="#create-xdc" class="anchor"></a>
How can I create my own in-chat apps? <a href="#create-xdc" class="anchor"></a>
</h3>
@@ -898,7 +910,7 @@ versuche, einen <strong>Mobilen Hotspot</strong> auf einem Gerät zu öffnen und
<ul>
<li>Auf dem alten Gerät, gehe zu “Einstellungen → Chats und Medien → Chats auf externem Speicher speichern”. Gib deine PIN, dein Muster oder dein Passwort zum Entsperren des Bildschirms ein. Anschließend kannst du auf “Backup starten” klicken. Dadurch wird die Backup-Datei auf deinem Gerät gespeichert. Jetzt musst du sie auf das andere Gerät übertragen.</li>
<li>Auf dem neuen Gerät, auf dem Anmeldebildschirm, wähle “Ich habe bereits ein Profil” und dann “Wiederherstellen aus Backup”. Nach dem Import sind deine Chats, Medien und Einstellungen auf das neue Gerät kopiert.
<li>Auf dem neuen Gerät, auf dem Anmeldebildschirm, wählen, anstatt sich bei Ihrem E-Mail-Konto anzumelden, “Wiederherstellen aus Backup”. Nach dem Import sollten Ihre Unterhaltungen, Verschlüsselungsschlüssel und Medien auf das neue Gerät kopiert sein.
<ul>
<li><strong>Wenn du iOS verwendest</strong> und auf Schwierigkeiten stößt, hilft dir vielleicht <a href="https://support.delta.chat/t/import-backup-to-ios/1628">diese Anleitung</a>.</li>
</ul>
@@ -928,18 +940,18 @@ versuche, einen <strong>Mobilen Hotspot</strong> auf einem Gerät zu öffnen und
</h2>
<h3 id="experimentelle-features">
<h3 id="experimental-features">
Experimentelle Features <a href="#experimentelle-features" class="anchor"></a>
Experimental Features <a href="#experimental-features" class="anchor"></a>
</h3>
<p>Unter <strong>Einstellungen → Erweitert → Experimentelle Features</strong>
kannst du unfertige Features ausprobieren, an denen gearbeitet wird.</p>
<p>At <strong>Settings → Advanced → Experimental Features</strong>
you can try out features we are working on.</p>
<p>Die Features können <strong>instabil</strong> sein und <strong>geändert oder entfernt</strong> werden.</p>
<p>The features may be <strong>unstable</strong> and may be <strong>changed or removed</strong>.</p>
<p>You can find more information
and give feedback in the <a href="https://support.delta.chat">Forum</a>.</p>
@@ -947,7 +959,7 @@ and give feedback in the <a href="https://support.delta.chat">Forum</a>.</p>
<h3 id="statssending">
Was ist “Statistik an Delta Chat Entwickler senden”? <a href="#statssending" class="anchor"></a>
What is “Send statistics to Delta Chats developers”? <a href="#statssending" class="anchor"></a>
</h3>
@@ -972,10 +984,10 @@ weekly statistics will be automatically sent to a bot.</p>
<p>We will <em>not</em> collect any personally identifiable information about you.</p>
<h3 id="kann-ich-eine-klassische-e-mail-adresse-mit-delta-chat-verwenden">
<h3 id="can-i-use-a-classic-email-address-with-delta-chat">
Kann ich eine klassische E-Mail-Adresse mit Delta Chat verwenden? <a href="#kann-ich-eine-klassische-e-mail-adresse-mit-delta-chat-verwenden" class="anchor"></a>
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>
</h3>
@@ -992,7 +1004,7 @@ while chatmail apps and relays pervasively enforce end-to-end encryption and sec
</li>
<li>
<p>Non-chatmail apps use email servers as a long-term message archive
while chatmail clients use email servers for ephemeral instant message relay.</p>
while chatmail clients use email servers for ephemeral instant message transport.</p>
</li>
<li>
<p>Supporting the full variety of classic email setups
@@ -1004,7 +1016,7 @@ and complicate making chatmail-based messaging more resilient, reliable and fast
<h3 id="classic-email">
Wie kann ich ein Chat-Profil mit einer klassischen E-Mail-Adresse als Relay konfigurieren? <a href="#classic-email" class="anchor"></a>
How can I configure a chat profile with a classic email address as transport? <a href="#classic-email" class="anchor"></a>
</h3>
@@ -1013,7 +1025,7 @@ and complicate making chatmail-based messaging more resilient, reliable and fast
unless you are prepared to deal with encrypted messages in the inbox,
double notifications, accidentally deleted emails or similar annoyances.</p>
<p>You can configure a email address for chatting at <strong>New Profile → Use Other Server → Use Classic Mail as Relay</strong>.
<p>You can configure a email address for chatting at <strong>New Profile → Use Other Server → Use Classic Mail as Transport</strong>.
Note that classic email providers will generally not support <a href="#instant-delivery">Push Notifications</a>
and have other limitations, see <a href="https://providers.delta.chat">Provider Overview</a>.
Chatmail uses the default INBOX for relay; ensure the provider setup does too.
@@ -1086,7 +1098,7 @@ ermöglicht es den Empfängern, eine Ende-zu-Ende-Verschlüsselung mit dem Konta
<h3 id="whene2e">
Wie kann ich wissen, ob Nachrichten Ende-zu-Ende-verschlüsselt sind? <a href="#whene2e" class="anchor"></a>
How can I know if messages are end-to-end encrypted? <a href="#whene2e" class="anchor"></a>
</h3>
@@ -1094,10 +1106,10 @@ ermöglicht es den Empfängern, eine Ende-zu-Ende-Verschlüsselung mit dem Konta
<p>Alle Nachrichten in Delta Chat sind <strong>standardmäßig Ende-zu-Ende-verschlüsselt</strong>.
Seit der Veröffentlichung von Delta Chat Version 2 (Juli 2025) gibt es keine Schlösser oder ähnliche Markierungen mehr an EndezuEnde-verschlüsselten Nachrichten.</p>
<h3 id="kann-ich-nachrichten-ohne-ende-zu-ende-verschlüsselung-empfangen-oder-senden">
<h3 id="can-i-still-receive-or-send-messages-without-end-to-end-encryption">
Kann ich Nachrichten ohne Ende-zu-Ende-Verschlüsselung empfangen oder senden? <a href="#kann-ich-nachrichten-ohne-ende-zu-ende-verschlüsselung-empfangen-oder-senden" class="anchor"></a>
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>
</h3>
@@ -1364,12 +1376,11 @@ ist die Verbindung sicher.</p>
<p>Nein.</p>
<p>Delta Chat generates secure OpenPGP keys according to the Autocrypt specification 1.1.
We do not recommend or offer users to perform manual key management.
We want to ensure that security audits can focus on a few proven cryptographic algorithms
instead of the full breadth of possible algorithms allowed with OpenPGP.
If you want to extract your OpenPGP key, there only is an expert method:
you need to look it up in the “keypairs” SQLite table of a profile backup tar-file.</p>
<p>Delta Chat erzeugt sichere OpenPGP-Schlüssel gemäß der Autocrypt-Spezifikation 1.1.
Du kannst deinen privaten Schlüssel exportieren, aber du kannst keinen weiteren privaten Schlüssel importieren.</p>
<p>Im Allgemeinen empfehlen wir, die Schlüsselverwaltung nicht manuell vorzunehmen, und bieten dies auch nicht an.
Wir wollen sicherstellen, dass sich Sicherheitsaudits auf wenige, bewährte kryptographische Algorithmen konzentrieren können - statt einen Strauß möglicher Algorithmen, die mit OpenPGP erlaubt sind.</p>
<h3 id="security-audits">
@@ -1454,7 +1465,8 @@ e.g. you need to grant camera permission if you want to <a href="#howtoe2ee">sca
<p>Falls nicht verfügbar, verwende den <strong>Mirror</strong> auf <a href="https://deltachat.github.io/deltachat-pages">https://deltachat.github.io/deltachat-pages</a></p>
</li>
<li>
<p>Öffne einen der folgenden <strong>App-Stores und suchen Sie nach „Delta Chat:</strong> Google Play Store, F-Droid, Huawei App Gallery, iOS und macOS App Store, Microsoft Store</p>
<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>
</li>
<li>
<p>Im <strong>Paketmanager</strong> Ihrer Linux-Distribution nachschauen</p>
@@ -1489,10 +1501,15 @@ Die zweite Förderung 2019/2020 (~$300K) half uns bei der Erstellung der iOS-Ve
<p>Die <a href="https://nlnet.nl/">NLnet-Stiftung</a> bewilligte 2019/2020 46K EUR für die Fertigstellung von Rust-/Python-Bindungs und die Einrichtung eines Chat-Bot-Ökosystems.</p>
</li>
<li>
<p>Im Jahr 2021 erhielten wir weitere EU-Mittel für zwei “Next-Generation-Internet”-Anträge, nämlich für <a href="https://dapsi.ngi.eu/hall-of-fame/eppd/">EPPD - E-Mail-Provider-Portabilitätsverzeichnis</a> (~97K EUR) und <a href="https://nlnet.nl/project/EmailPorting/">AEAP - E-Mail-Adressportierung</a> (~90K EUR). Ziel sind bessere Unterstützung von Mehrfachkonten, verbesserten QR-Code-Kontakt- und -Gruppen-Setups sowie Netzwerkverbesserungen auf allen Plattformen.</p>
<p>In 2021 we received further EU funding for two Next-Generation-Internet
proposals, namely for <a href="https://dapsi.ngi.eu/hall-of-fame/eppd/">EPPD - email provider portability directory</a> (~97K EUR) and <a href="https://nlnet.nl/project/EmailPorting/">AEAP - email address porting</a> (~90K EUR) which resulted in better multi-profile support, improved QR-code contact and group setups and many networking improvements on all platforms.</p>
</li>
<li>
<p>Von Ende 2021 bis März 2023 erhielten wir eine <em>Internet-Freedom</em>-Finanzierung (500K USD) vom U.S. Bureau of Democracy, Human Rights and Labor (DRL). Diese Finanzierung unterstützte unsere langjährigen Ziele, Delta Chat benutzerfreundlicher und kompatibel mit einer breiten Palette von E-Mail-Servern weltweit zu machen, sowie widerstandsfähiger und sicherer an Orten, die häufig von Internetzensur und Abschaltungen betroffen sind.</p>
<p>From End 2021 till March 2023 we received <em>Internet Freedom</em> funding (500K USD) from the
U.S. Bureau of Democracy, Human Rights and Labor (DRL).
This funding supported our long-running goals to make Delta Chat more usable
and compatible with a wide range of email servers world-wide, and more resilient and secure
in places often affected by internet censorship and shutdowns.</p>
</li>
<li>
<p>2023-2024 schlossen wir erfolgreich das vom OTF finanzierte
Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

+11 -11
View File
@@ -57,7 +57,7 @@
<li><a href="#experimental-features">Experimental Features</a></li>
<li><a href="#statssending">What is “Send statistics to Delta Chats developers”?</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="#classic-email">How can I configure a chat profile with a classic email address as relay?</a></li>
<li><a href="#classic-email">How can I configure a chat profile with a classic email address as transport?</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="#im-interested-in-the-technical-details-can-you-tell-me-more">Im interested in the technical details. Can you tell me more?</a></li>
</ul>
@@ -650,7 +650,7 @@ This makes Delta Chat a truly extensible messenger.</p>
<p>In-chat apps can not send data to the Internet, or download anything.</p>
</li>
<li>
<p>An in-chat app can only exchange data within a chat, with its
<p>An in-chat app can only exchange data within a Delta Chat chat, with its
copies on the devices of your chat partners. Other than that, its completely
isolated from the Internet.</p>
</li>
@@ -1057,7 +1057,7 @@ while chatmail apps and relays pervasively enforce end-to-end encryption and sec
</li>
<li>
<p>Non-chatmail apps use email servers as a long-term message archive
while chatmail clients use email servers for ephemeral instant message relay.</p>
while chatmail clients use email servers for ephemeral instant message transport.</p>
</li>
<li>
<p>Supporting the full variety of classic email setups
@@ -1069,7 +1069,7 @@ and complicate making chatmail-based messaging more resilient, reliable and fast
<h3 id="classic-email">
How can I configure a chat profile with a classic email address as relay? <a href="#classic-email" class="anchor"></a>
How can I configure a chat profile with a classic email address as transport? <a href="#classic-email" class="anchor"></a>
</h3>
@@ -1078,7 +1078,7 @@ and complicate making chatmail-based messaging more resilient, reliable and fast
unless you are prepared to deal with encrypted messages in the inbox,
double notifications, accidentally deleted emails or similar annoyances.</p>
<p>You can configure a email address for chatting at <strong>New Profile → Use Other Server → Use Classic Mail as Relay</strong>.
<p>You can configure a email address for chatting at <strong>New Profile → Use Other Server → Use Classic Mail as Transport</strong>.
Note that classic email providers will generally not support <a href="#instant-delivery">Push Notifications</a>
and have other limitations, see <a href="https://providers.delta.chat">Provider Overview</a>.
Chatmail uses the default INBOX for relay; ensure the provider setup does too.
@@ -1437,12 +1437,12 @@ the connection is safe.</p>
<p>No.</p>
<p>Delta Chat generates secure OpenPGP keys according to the Autocrypt specification 1.1.
We do not recommend or offer users to perform manual key management.
We want to ensure that security audits can focus on a few proven cryptographic algorithms
instead of the full breadth of possible algorithms allowed with OpenPGP.
If you want to extract your OpenPGP key, there only is an expert method:
you need to look it up in the “keypairs” SQLite table of a profile backup tar-file.</p>
<p>Delta Chat generates secure OpenPGP keys according to the Autocrypt specification 1.1.
You can export your private key but you can not import additional private keys.</p>
<p>In general, we do not recommend or offer users to perform manual key management.
We want to ensure that security audits can focus on a few proven cryptographic algorithms
instead of the full breadth of possible algorithms allowed with OpenPGP.</p>
<h3 id="security-audits">
+11 -11
View File
@@ -57,7 +57,7 @@
<li><a href="#experimental-features">Experimental Features</a></li>
<li><a href="#statssending">What is “Send statistics to Delta Chats developers”?</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="#classic-email">How can I configure a chat profile with a classic email address as relay?</a></li>
<li><a href="#classic-email">How can I configure a chat profile with a classic email address as transport?</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="#estoy-interesado-en-los-detalles-técnicos-pueden-decirme-más">Estoy interesado en los detalles técnicos. ¿Pueden decirme más?</a></li>
</ul>
@@ -648,7 +648,7 @@ This makes Delta Chat a truly extensible messenger.</p>
<p>In-chat apps can not send data to the Internet, or download anything.</p>
</li>
<li>
<p>An in-chat app can only exchange data within a chat, with its
<p>An in-chat app can only exchange data within a Delta Chat chat, with its
copies on the devices of your chat partners. Other than that, its completely
isolated from the Internet.</p>
</li>
@@ -1055,7 +1055,7 @@ while chatmail apps and relays pervasively enforce end-to-end encryption and sec
</li>
<li>
<p>Non-chatmail apps use email servers as a long-term message archive
while chatmail clients use email servers for ephemeral instant message relay.</p>
while chatmail clients use email servers for ephemeral instant message transport.</p>
</li>
<li>
<p>Supporting the full variety of classic email setups
@@ -1067,7 +1067,7 @@ and complicate making chatmail-based messaging more resilient, reliable and fast
<h3 id="classic-email">
How can I configure a chat profile with a classic email address as relay? <a href="#classic-email" class="anchor"></a>
How can I configure a chat profile with a classic email address as transport? <a href="#classic-email" class="anchor"></a>
</h3>
@@ -1076,7 +1076,7 @@ and complicate making chatmail-based messaging more resilient, reliable and fast
unless you are prepared to deal with encrypted messages in the inbox,
double notifications, accidentally deleted emails or similar annoyances.</p>
<p>You can configure a email address for chatting at <strong>New Profile → Use Other Server → Use Classic Mail as Relay</strong>.
<p>You can configure a email address for chatting at <strong>New Profile → Use Other Server → Use Classic Mail as Transport</strong>.
Note that classic email providers will generally not support <a href="#instant-delivery">Push Notifications</a>
and have other limitations, see <a href="https://providers.delta.chat">Provider Overview</a>.
Chatmail uses the default INBOX for relay; ensure the provider setup does too.
@@ -1428,12 +1428,12 @@ in collaboration with other OpenPGP implementers.</p>
<p>No.</p>
<p>Delta Chat generates secure OpenPGP keys according to the Autocrypt specification 1.1.
We do not recommend or offer users to perform manual key management.
We want to ensure that security audits can focus on a few proven cryptographic algorithms
instead of the full breadth of possible algorithms allowed with OpenPGP.
If you want to extract your OpenPGP key, there only is an expert method:
you need to look it up in the “keypairs” SQLite table of a profile backup tar-file.</p>
<p>Delta Chat generates secure OpenPGP keys according to the Autocrypt specification 1.1.
You can export your private key but you can not import additional private keys.</p>
<p>In general, we do not recommend or offer users to perform manual key management.
We want to ensure that security audits can focus on a few proven cryptographic algorithms
instead of the full breadth of possible algorithms allowed with OpenPGP.</p>
<h3 id="security-audits">
+11 -11
View File
@@ -57,7 +57,7 @@
<li><a href="#experimental-features">Experimental Features</a></li>
<li><a href="#statssending">What is “Send statistics to Delta Chats developers”?</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="#classic-email">How can I configure a chat profile with a classic email address as relay?</a></li>
<li><a href="#classic-email">How can I configure a chat profile with a classic email address as transport?</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="#les-détails-techniques-mintéressent-pouvez-vous-men-dire-plus-">Les détails techniques mintéressent. Pouvez-vous men dire plus ?</a></li>
</ul>
@@ -641,7 +641,7 @@ This makes Delta Chat a truly extensible messenger.</p>
<p>In-chat apps can not send data to the Internet, or download anything.</p>
</li>
<li>
<p>An in-chat app can only exchange data within a chat, with its
<p>An in-chat app can only exchange data within a Delta Chat chat, with its
copies on the devices of your chat partners. Other than that, its completely
isolated from the Internet.</p>
</li>
@@ -1042,7 +1042,7 @@ while chatmail apps and relays pervasively enforce end-to-end encryption and sec
</li>
<li>
<p>Non-chatmail apps use email servers as a long-term message archive
while chatmail clients use email servers for ephemeral instant message relay.</p>
while chatmail clients use email servers for ephemeral instant message transport.</p>
</li>
<li>
<p>Supporting the full variety of classic email setups
@@ -1054,7 +1054,7 @@ and complicate making chatmail-based messaging more resilient, reliable and fast
<h3 id="classic-email">
How can I configure a chat profile with a classic email address as relay? <a href="#classic-email" class="anchor"></a>
How can I configure a chat profile with a classic email address as transport? <a href="#classic-email" class="anchor"></a>
</h3>
@@ -1063,7 +1063,7 @@ and complicate making chatmail-based messaging more resilient, reliable and fast
unless you are prepared to deal with encrypted messages in the inbox,
double notifications, accidentally deleted emails or similar annoyances.</p>
<p>You can configure a email address for chatting at <strong>New Profile → Use Other Server → Use Classic Mail as Relay</strong>.
<p>You can configure a email address for chatting at <strong>New Profile → Use Other Server → Use Classic Mail as Transport</strong>.
Note that classic email providers will generally not support <a href="#instant-delivery">Push Notifications</a>
and have other limitations, see <a href="https://providers.delta.chat">Provider Overview</a>.
Chatmail uses the default INBOX for relay; ensure the provider setup does too.
@@ -1422,12 +1422,12 @@ the connection is safe.</p>
<p>No.</p>
<p>Delta Chat generates secure OpenPGP keys according to the Autocrypt specification 1.1.
We do not recommend or offer users to perform manual key management.
We want to ensure that security audits can focus on a few proven cryptographic algorithms
instead of the full breadth of possible algorithms allowed with OpenPGP.
If you want to extract your OpenPGP key, there only is an expert method:
you need to look it up in the “keypairs” SQLite table of a profile backup tar-file.</p>
<p>Delta Chat generates secure OpenPGP keys according to the Autocrypt specification 1.1.
You can export your private key but you can not import additional private keys.</p>
<p>In general, we do not recommend or offer users to perform manual key management.
We want to ensure that security audits can focus on a few proven cryptographic algorithms
instead of the full breadth of possible algorithms allowed with OpenPGP.</p>
<h3 id="security-audits">
+11 -11
View File
@@ -57,7 +57,7 @@
<li><a href="#experimental-features">Experimental Features</a></li>
<li><a href="#statssending">What is “Send statistics to Delta Chats developers”?</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="#classic-email">How can I configure a chat profile with a classic email address as relay?</a></li>
<li><a href="#classic-email">How can I configure a chat profile with a classic email address as transport?</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="#im-interested-in-the-technical-details-can-you-tell-me-more">Im interested in the technical details. Can you tell me more?</a></li>
</ul>
@@ -650,7 +650,7 @@ This makes Delta Chat a truly extensible messenger.</p>
<p>In-chat apps can not send data to the Internet, or download anything.</p>
</li>
<li>
<p>An in-chat app can only exchange data within a chat, with its
<p>An in-chat app can only exchange data within a Delta Chat chat, with its
copies on the devices of your chat partners. Other than that, its completely
isolated from the Internet.</p>
</li>
@@ -1057,7 +1057,7 @@ while chatmail apps and relays pervasively enforce end-to-end encryption and sec
</li>
<li>
<p>Non-chatmail apps use email servers as a long-term message archive
while chatmail clients use email servers for ephemeral instant message relay.</p>
while chatmail clients use email servers for ephemeral instant message transport.</p>
</li>
<li>
<p>Supporting the full variety of classic email setups
@@ -1069,7 +1069,7 @@ and complicate making chatmail-based messaging more resilient, reliable and fast
<h3 id="classic-email">
How can I configure a chat profile with a classic email address as relay? <a href="#classic-email" class="anchor"></a>
How can I configure a chat profile with a classic email address as transport? <a href="#classic-email" class="anchor"></a>
</h3>
@@ -1078,7 +1078,7 @@ and complicate making chatmail-based messaging more resilient, reliable and fast
unless you are prepared to deal with encrypted messages in the inbox,
double notifications, accidentally deleted emails or similar annoyances.</p>
<p>You can configure a email address for chatting at <strong>New Profile → Use Other Server → Use Classic Mail as Relay</strong>.
<p>You can configure a email address for chatting at <strong>New Profile → Use Other Server → Use Classic Mail as Transport</strong>.
Note that classic email providers will generally not support <a href="#instant-delivery">Push Notifications</a>
and have other limitations, see <a href="https://providers.delta.chat">Provider Overview</a>.
Chatmail uses the default INBOX for relay; ensure the provider setup does too.
@@ -1437,12 +1437,12 @@ the connection is safe.</p>
<p>No.</p>
<p>Delta Chat generates secure OpenPGP keys according to the Autocrypt specification 1.1.
We do not recommend or offer users to perform manual key management.
We want to ensure that security audits can focus on a few proven cryptographic algorithms
instead of the full breadth of possible algorithms allowed with OpenPGP.
If you want to extract your OpenPGP key, there only is an expert method:
you need to look it up in the “keypairs” SQLite table of a profile backup tar-file.</p>
<p>Delta Chat generates secure OpenPGP keys according to the Autocrypt specification 1.1.
You can export your private key but you can not import additional private keys.</p>
<p>In general, we do not recommend or offer users to perform manual key management.
We want to ensure that security audits can focus on a few proven cryptographic algorithms
instead of the full breadth of possible algorithms allowed with OpenPGP.</p>
<h3 id="security-audits">
+54 -54
View File
@@ -19,20 +19,20 @@
<li><a href="#remove-account">Come posso eliminare il mio profilo chat?</a></li>
</ul>
</li>
<li><a href="#groups">Gruppi</a>
<li><a href="#gruppi">Gruppi</a>
<ul>
<li><a href="#creazione-di-un-gruppo">Creazione di un gruppo</a></li>
<li><a href="#addmembers">Aggiungi e rimuovi membri</a></li>
<li><a href="#mi-sono-cancellato-per-sbaglio">Mi sono cancellato per sbaglio.</a></li>
<li><a href="#non-desidero-più-ricevere-i-messaggi-di-un-gruppo">Non desidero più ricevere i messaggi di un gruppo.</a></li>
<li><a href="#clonazione-di-un-gruppo">Clonazione di un gruppo</a></li>
<li><a href="#cloning-a-group">Cloning a group</a></li>
</ul>
</li>
<li><a href="#webxdc">Apps in chat</a>
<li><a href="#webxdc">In-chat apps</a>
<ul>
<li><a href="#dove-posso-trovare-le-apps-in-chat">Dove posso trovare le apps in chat?</a></li>
<li><a href="#quanto-sono-private-le-apps-di-chat">Quanto sono private le apps di chat?</a></li>
<li><a href="#create-xdc">Come posso creare le mie app di chat?</a></li>
<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>
</ul>
</li>
<li><a href="#instant-delivery">Consegna messaggi istantanei e Notifiche Push</a>
@@ -57,7 +57,7 @@
<li><a href="#experimental-features">Experimental Features</a></li>
<li><a href="#statssending">What is “Send statistics to Delta Chats developers”?</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="#classic-email">How can I configure a chat profile with a classic email address as relay?</a></li>
<li><a href="#classic-email">How can I configure a chat profile with a classic email address as transport?</a></li>
<li><a href="#vorrei-gestire-il-mio-server-per-delta-chat-cosa-mi-consigliate">Vorrei gestire il mio server per Delta Chat. Cosa mi consigliate?</a></li>
<li><a href="#sono-interessato-ai-dettagli-tecnici-mi-puoi-dire-di-più">Sono interessato ai dettagli tecnici. Mi puoi dire di più?</a></li>
</ul>
@@ -489,10 +489,10 @@ Ciò attiverà comunque leliminazione automatica di tutti i dati di indirizzo
Per maggiori informazioni, consulta <a href="https://nine.testrun.org/info.html#account-deletion">nine.testrun.org cancellazione dellindirizzo</a>
o la pagina corrispondente del <a href="https://chatmail.at/relays">server chatmail di 3e parti</a> da te scelto.</p>
<h2 id="groups">
<h2 id="gruppi">
Gruppi <a href="#groups" class="anchor"></a>
Gruppi <a href="#gruppi" class="anchor"></a>
</h2>
@@ -535,23 +535,23 @@ ed <a href="#edit">eliminare i propri messaggi</a> dai dispositivi di tutti i me
Per questo motivo, tutti possono eliminare qualsiasi membro o aggiungerne di nuovi.</p>
</li>
<li>
<p>Per <strong>aggiungere o eliminare membri</strong>, tocca il nome del gruppo nella chat e seleziona il membro da aggiungere o rimuovere.</p>
<p>To <strong>add or delete members</strong>, tap the group name in the chat and select the member to add or remove.</p>
</li>
<li>
<p>Se il membro non è ancora nella tua lista contatti, ma è <strong>faccia a faccia</strong> con te,
dalla stessa schermata, mostra un <strong>codice QR</strong>.
Chiedi al tuo interlocutore di <strong>scansionare</strong> limmagine QR con la sua app Delta Chat toccando
<img style="vertical-align:middle; height:1.3em; margin:1px" src="../qr-icon.png" /> nella schermata principale.</p>
<p>If the member is not yet in your contact list, but <strong>face to face</strong> with you,
from the same screen, show a <strong>QR code</strong>.<br />
Ask your chat partner to <strong>scan</strong> the QR image with their Delta Chat app by tapping
<img style="vertical-align:middle; height:1.3em; margin:1px" src="../qr-icon.png" /> on the main screen.</p>
</li>
<li>
<p>Per aggiungere un membro <strong>da remoto</strong>,
clicca su “Copia” o “Condividi” e invia il <strong>link di invito</strong>
tramite unaltra chat privata al nuovo membro.</p>
<p>For a <strong>remote</strong> member addition,
click “Copy” orShare” and send the <strong>invite link</strong>
through another private chat to the new member.</p>
</li>
</ul>
<p>Il codice QR e il link di invito possono essere utilizzati per aggiungere più membri.
Tuttavia, poiché i gruppi sono <a href="#groups">destinati a persone fidate</a>, evita di condividerli pubblicamente.</p>
<p>QR code and invite link can be used to add several members.
However, since groups are <a href="#groups">meant for trusted people</a>, avoid sharing them publicly.</p>
<h3 id="mi-sono-cancellato-per-sbaglio">
@@ -585,88 +585,88 @@ puoi ancora scrivere, ma non viene più notificato alcun nuovo messaggio.</p>
</li>
</ul>
<h3 id="clonazione-di-un-gruppo">
<h3 id="cloning-a-group">
Clonazione di un gruppo <a href="#clonazione-di-un-gruppo" class="anchor"></a>
Cloning a group <a href="#cloning-a-group" class="anchor"></a>
</h3>
<p>Puoi duplicare un gruppo per avviare una discussione separata
o per escludere membri senza che se ne accorgano.</p>
<p>You can duplicate a group to start a separate discussion
or to exclude members without them noticing.</p>
<ul>
<li>
<p>Apri il profilo del gruppo e tocca <strong>Clona Chat</strong> (Android/iOS),
oppure fai clic con il pulsante destro del mouse sul gruppo nellelenco delle chat (Desktop).</p>
<p>Open the group profile and tap <strong>Clone Chat</strong> (Android/iOS),
or right-click the group in the chat list (Desktop).</p>
</li>
<li>
<p>Imposta un nuovo nome, scegli un avatar e modifica lelenco dei membri, se necessario.</p>
<p>Set a new name, choose an avatar, and adjust the member list if needed.</p>
</li>
</ul>
<p>Il nuovo gruppo è <strong>completamente indipendente</strong> dalloriginale,
che continua a funzionare come prima.</p>
<p>The new group is <strong>fully independent</strong> from the original,
which continues to work as before.</p>
<h2 id="webxdc">
Apps in chat <a href="#webxdc" class="anchor"></a>
In-chat apps <a href="#webxdc" class="anchor"></a>
</h2>
<p>È possibile inviare apps a una chat: giochi, editor, sondaggi e altri strumenti.
Questo rende Delta Chat un servizio di messaggistica davvero espandibile.</p>
<p>You can send apps to a chat - games, editors, polls and other tools.
This makes Delta Chat a truly extensible messenger.</p>
<h3 id="dove-posso-trovare-le-apps-in-chat">
<h3 id="where-can-i-get-in-chat-apps">
Dove posso trovare le apps in chat? <a href="#dove-posso-trovare-le-apps-in-chat" class="anchor"></a>
Where can I get in-chat apps? <a href="#where-can-i-get-in-chat-apps" class="anchor"></a>
</h3>
<ul>
<li>
<p>In una chat, utilizzando <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Pulsante Allegato → Apps</strong></p>
<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>
</li>
<li>
<p>Puoi anche <a href="#create-xdc">creare la tua app</a> e allegarla usando <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Pulsante Allegato → File</strong></p>
<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>
</li>
</ul>
<h3 id="quanto-sono-private-le-apps-di-chat">
<h3 id="how-private-are-in-chat-apps">
Quanto sono private le apps di chat? <a href="#quanto-sono-private-le-apps-di-chat" class="anchor"></a>
How private are in-chat apps? <a href="#how-private-are-in-chat-apps" class="anchor"></a>
</h3>
<ul>
<li>
<p>Le apps di chat non possono inviare dati a Internet né scaricare nulla.</p>
<p>In-chat apps can not send data to the Internet, or download anything.</p>
</li>
<li>
<p>Unapp in-chat può scambiare dati solo allinterno di una chat Delta Chat, con le sue
copie sui dispositivi dei tuoi interlocutori. A parte questo, è completamente
isolata da Internet.</p>
<p>An in-chat app can only exchange data within a Delta Chat chat, with its
copies on the devices of your chat partners. Other than that, its completely
isolated from the Internet.</p>
</li>
<li>
<p>La privacy offerta da unapp di chat è la privacy della tua chat: finché
ti fidi delle persone con cui chatti, puoi fidarti anche dellapp di chat.</p>
<p>The privacy an in-chat app offers is the privacy of your chat - as long as you
trust the people you chat with, you can trust the in-chat app as well.</p>
</li>
<li>
<p>questo significa anche: proprio come per i link web, non aprire app provenienti da contatti non attendibili.</p>
<p>This also means: Just like for web links, do not open apps from untrusted contacts.</p>
</li>
</ul>
<h3 id="create-xdc">
Come posso creare le mie app di chat? <a href="#create-xdc" class="anchor"></a>
How can I create my own in-chat apps? <a href="#create-xdc" class="anchor"></a>
</h3>
@@ -1053,7 +1053,7 @@ while chatmail apps and relays pervasively enforce end-to-end encryption and sec
</li>
<li>
<p>Non-chatmail apps use email servers as a long-term message archive
while chatmail clients use email servers for ephemeral instant message relay.</p>
while chatmail clients use email servers for ephemeral instant message transport.</p>
</li>
<li>
<p>Supporting the full variety of classic email setups
@@ -1065,7 +1065,7 @@ and complicate making chatmail-based messaging more resilient, reliable and fast
<h3 id="classic-email">
How can I configure a chat profile with a classic email address as relay? <a href="#classic-email" class="anchor"></a>
How can I configure a chat profile with a classic email address as transport? <a href="#classic-email" class="anchor"></a>
</h3>
@@ -1074,7 +1074,7 @@ and complicate making chatmail-based messaging more resilient, reliable and fast
unless you are prepared to deal with encrypted messages in the inbox,
double notifications, accidentally deleted emails or similar annoyances.</p>
<p>You can configure a email address for chatting at <strong>New Profile → Use Other Server → Use Classic Mail as Relay</strong>.
<p>You can configure a email address for chatting at <strong>New Profile → Use Other Server → Use Classic Mail as Transport</strong>.
Note that classic email providers will generally not support <a href="#instant-delivery">Push Notifications</a>
and have other limitations, see <a href="https://providers.delta.chat">Provider Overview</a>.
Chatmail uses the default INBOX for relay; ensure the provider setup does too.
@@ -1431,12 +1431,12 @@ la connessione è sicura.</p>
<p>No.</p>
<p>Delta Chat generates secure OpenPGP keys according to the Autocrypt specification 1.1.
We do not recommend or offer users to perform manual key management.
We want to ensure that security audits can focus on a few proven cryptographic algorithms
instead of the full breadth of possible algorithms allowed with OpenPGP.
If you want to extract your OpenPGP key, there only is an expert method:
you need to look it up in the “keypairs” SQLite table of a profile backup tar-file.</p>
<p>Delta Chat genera chiavi OpenPGP sicure in conformità alle specifiche di Autocrypt 1.1.
Puoi esportare le tue chiavi private ma non puoi importare chiavi private aggiuntive.</p>
<p>In generale, non raccomandiamo o proponiamo agli utenti di gestire manualmente le chiavi.
Noi vogliamo assicurare che gli audits di sicurezza si possano focalizzare su pochi algoritmi crittografici comprovati
invece che sullintera estensione dei possibili algoritmi consentiti con OpenPGP.</p>
<h3 id="security-audits">
Binary file not shown.

After

Width:  |  Height:  |  Size: 778 B

+11 -11
View File
@@ -57,7 +57,7 @@
<li><a href="#experimental-features">Experimental Features</a></li>
<li><a href="#statssending">What is “Send statistics to Delta Chats developers”?</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="#classic-email">How can I configure a chat profile with a classic email address as relay?</a></li>
<li><a href="#classic-email">How can I configure a chat profile with a classic email address as transport?</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="#ik-wil-graag-meer-weten-over-de-gebruikte-technieken-waar-kan-ik-meer-informatie-vinden">Ik wil graag meer weten over de gebruikte technieken. Waar kan ik meer informatie vinden?</a></li>
</ul>
@@ -649,7 +649,7 @@ This makes Delta Chat a truly extensible messenger.</p>
<p>In-chat apps can not send data to the Internet, or download anything.</p>
</li>
<li>
<p>An in-chat app can only exchange data within a chat, with its
<p>An in-chat app can only exchange data within a Delta Chat chat, with its
copies on the devices of your chat partners. Other than that, its completely
isolated from the Internet.</p>
</li>
@@ -1055,7 +1055,7 @@ while chatmail apps and relays pervasively enforce end-to-end encryption and sec
</li>
<li>
<p>Non-chatmail apps use email servers as a long-term message archive
while chatmail clients use email servers for ephemeral instant message relay.</p>
while chatmail clients use email servers for ephemeral instant message transport.</p>
</li>
<li>
<p>Supporting the full variety of classic email setups
@@ -1067,7 +1067,7 @@ and complicate making chatmail-based messaging more resilient, reliable and fast
<h3 id="classic-email">
How can I configure a chat profile with a classic email address as relay? <a href="#classic-email" class="anchor"></a>
How can I configure a chat profile with a classic email address as transport? <a href="#classic-email" class="anchor"></a>
</h3>
@@ -1076,7 +1076,7 @@ and complicate making chatmail-based messaging more resilient, reliable and fast
unless you are prepared to deal with encrypted messages in the inbox,
double notifications, accidentally deleted emails or similar annoyances.</p>
<p>You can configure a email address for chatting at <strong>New Profile → Use Other Server → Use Classic Mail as Relay</strong>.
<p>You can configure a email address for chatting at <strong>New Profile → Use Other Server → Use Classic Mail as Transport</strong>.
Note that classic email providers will generally not support <a href="#instant-delivery">Push Notifications</a>
and have other limitations, see <a href="https://providers.delta.chat">Provider Overview</a>.
Chatmail uses the default INBOX for relay; ensure the provider setup does too.
@@ -1435,12 +1435,12 @@ the connection is safe.</p>
<p>No.</p>
<p>Delta Chat generates secure OpenPGP keys according to the Autocrypt specification 1.1.
We do not recommend or offer users to perform manual key management.
We want to ensure that security audits can focus on a few proven cryptographic algorithms
instead of the full breadth of possible algorithms allowed with OpenPGP.
If you want to extract your OpenPGP key, there only is an expert method:
you need to look it up in the “keypairs” SQLite table of a profile backup tar-file.</p>
<p>Delta Chat generates secure OpenPGP keys according to the Autocrypt specification 1.1.
You can export your private key but you can not import additional private keys.</p>
<p>In general, we do not recommend or offer users to perform manual key management.
We want to ensure that security audits can focus on a few proven cryptographic algorithms
instead of the full breadth of possible algorithms allowed with OpenPGP.</p>
<h3 id="security-audits">
+8 -11
View File
@@ -57,7 +57,7 @@
<li><a href="#experimental-features">Experimental Features</a></li>
<li><a href="#statssending">What is “Send statistics to Delta Chats developers”?</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="#classic-email">How can I configure a chat profile with a classic email address as relay?</a></li>
<li><a href="#classic-email">How can I configure a chat profile with a classic email address as transport?</a></li>
<li><a href="#chcę-zarządzać-własnym-serwerem-dla-delta-chat-co-polecacie">Chcę zarządzać własnym serwerem dla Delta Chat. Co polecacie?</a></li>
<li><a href="#interesują-mnie-szczegóły-techniczne-możesz-powiedzieć-mi-coś-więcej">Interesują mnie szczegóły techniczne. Możesz powiedzieć mi coś więcej?</a></li>
</ul>
@@ -622,7 +622,7 @@ This makes Delta Chat a truly extensible messenger.</p>
<p>In-chat apps can not send data to the Internet, or download anything.</p>
</li>
<li>
<p>An in-chat app can only exchange data within a chat, with its
<p>An in-chat app can only exchange data within a Delta Chat chat, with its
copies on the devices of your chat partners. Other than that, its completely
isolated from the Internet.</p>
</li>
@@ -972,7 +972,7 @@ while chatmail apps and relays pervasively enforce end-to-end encryption and sec
</li>
<li>
<p>Non-chatmail apps use email servers as a long-term message archive
while chatmail clients use email servers for ephemeral instant message relay.</p>
while chatmail clients use email servers for ephemeral instant message transport.</p>
</li>
<li>
<p>Supporting the full variety of classic email setups
@@ -984,7 +984,7 @@ and complicate making chatmail-based messaging more resilient, reliable and fast
<h3 id="classic-email">
How can I configure a chat profile with a classic email address as relay? <a href="#classic-email" class="anchor"></a>
How can I configure a chat profile with a classic email address as transport? <a href="#classic-email" class="anchor"></a>
</h3>
@@ -993,7 +993,7 @@ and complicate making chatmail-based messaging more resilient, reliable and fast
unless you are prepared to deal with encrypted messages in the inbox,
double notifications, accidentally deleted emails or similar annoyances.</p>
<p>You can configure a email address for chatting at <strong>New Profile → Use Other Server → Use Classic Mail as Relay</strong>.
<p>You can configure a email address for chatting at <strong>New Profile → Use Other Server → Use Classic Mail as Transport</strong>.
Note that classic email providers will generally not support <a href="#instant-delivery">Push Notifications</a>
and have other limitations, see <a href="https://providers.delta.chat">Provider Overview</a>.
Chatmail uses the default INBOX for relay; ensure the provider setup does too.
@@ -1278,12 +1278,9 @@ but an implementation has not been agreed as a priority yet.</p>
<p>Nie.</p>
<p>Delta Chat generates secure OpenPGP keys according to the Autocrypt specification 1.1.
We do not recommend or offer users to perform manual key management.
We want to ensure that security audits can focus on a few proven cryptographic algorithms
instead of the full breadth of possible algorithms allowed with OpenPGP.
If you want to extract your OpenPGP key, there only is an expert method:
you need to look it up in the “keypairs” SQLite table of a profile backup tar-file.</p>
<p>Delta Chat generuje bezpieczne klucze OpenPGP zgodnie ze specyfikacją Autocrypt 1.1. Możesz wyeksportować swój prywatny klucz, ale nie możesz zaimportować dodatkowych kluczy prywatnych.</p>
<p>Generalnie nie zalecamy ani nie oferujemy użytkownikom wykonywania ręcznego zarządzania kluczami. Chcemy się upewnić, że audyty bezpieczeństwa mogą skupić się na kilku sprawdzonych algorytmach kryptograficznych, a nie na pełnym zakresie możliwych algorytmów dozwolonych w OpenPGP.</p>
<h3 id="security-audits">
+11 -11
View File
@@ -57,7 +57,7 @@
<li><a href="#experimental-features">Experimental Features</a></li>
<li><a href="#statssending">What is “Send statistics to Delta Chats developers”?</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="#classic-email">How can I configure a chat profile with a classic email address as relay?</a></li>
<li><a href="#classic-email">How can I configure a chat profile with a classic email address as transport?</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="#estou-interessado-nos-detalhes-técnicos-pode-me-dizer-mais">Estou interessado nos detalhes técnicos. Pode me dizer mais?</a></li>
</ul>
@@ -646,7 +646,7 @@ This makes Delta Chat a truly extensible messenger.</p>
<p>In-chat apps can not send data to the Internet, or download anything.</p>
</li>
<li>
<p>An in-chat app can only exchange data within a chat, with its
<p>An in-chat app can only exchange data within a Delta Chat chat, with its
copies on the devices of your chat partners. Other than that, its completely
isolated from the Internet.</p>
</li>
@@ -1053,7 +1053,7 @@ while chatmail apps and relays pervasively enforce end-to-end encryption and sec
</li>
<li>
<p>Non-chatmail apps use email servers as a long-term message archive
while chatmail clients use email servers for ephemeral instant message relay.</p>
while chatmail clients use email servers for ephemeral instant message transport.</p>
</li>
<li>
<p>Supporting the full variety of classic email setups
@@ -1065,7 +1065,7 @@ and complicate making chatmail-based messaging more resilient, reliable and fast
<h3 id="classic-email">
How can I configure a chat profile with a classic email address as relay? <a href="#classic-email" class="anchor"></a>
How can I configure a chat profile with a classic email address as transport? <a href="#classic-email" class="anchor"></a>
</h3>
@@ -1074,7 +1074,7 @@ and complicate making chatmail-based messaging more resilient, reliable and fast
unless you are prepared to deal with encrypted messages in the inbox,
double notifications, accidentally deleted emails or similar annoyances.</p>
<p>You can configure a email address for chatting at <strong>New Profile → Use Other Server → Use Classic Mail as Relay</strong>.
<p>You can configure a email address for chatting at <strong>New Profile → Use Other Server → Use Classic Mail as Transport</strong>.
Note that classic email providers will generally not support <a href="#instant-delivery">Push Notifications</a>
and have other limitations, see <a href="https://providers.delta.chat">Provider Overview</a>.
Chatmail uses the default INBOX for relay; ensure the provider setup does too.
@@ -1433,12 +1433,12 @@ the connection is safe.</p>
<p>No.</p>
<p>Delta Chat generates secure OpenPGP keys according to the Autocrypt specification 1.1.
We do not recommend or offer users to perform manual key management.
We want to ensure that security audits can focus on a few proven cryptographic algorithms
instead of the full breadth of possible algorithms allowed with OpenPGP.
If you want to extract your OpenPGP key, there only is an expert method:
you need to look it up in the “keypairs” SQLite table of a profile backup tar-file.</p>
<p>Delta Chat generates secure OpenPGP keys according to the Autocrypt specification 1.1.
You can export your private key but you can not import additional private keys.</p>
<p>In general, we do not recommend or offer users to perform manual key management.
We want to ensure that security audits can focus on a few proven cryptographic algorithms
instead of the full breadth of possible algorithms allowed with OpenPGP.</p>
<h3 id="security-audits">
+213 -212
View File
@@ -2,13 +2,13 @@
<html lang="ru"><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="#что-такое-delta-chat">Что такое Delta Chat?</a>
<ul>
<li><a href="#howtoe2ee">Как найти людей для общения?</a></li>
<li><a href="#почему-чат-помечен-как-запрос">Почему чат помечен как “Запрос”?</a></li>
<li><a href="#как-я-могу-связать-двух-своих-друзей-друг-с-другом">Как я могу связать двух своих друзей друг с другом?</a></li>
<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="#поддерживает-ли-delta-chat-изображения-видео-и-другие-вложения">Поддерживает ли Delta Chat изображения, видео и другие вложения?</a></li>
<li><a href="#multiple-accounts">Что такое профили? Как я могу переключатся между ними?</a></li>
<li><a href="#кто-видит-изображение-моего-профиля">Кто видит изображение моего профиля?</a></li>
<li><a href="#signature">Могу ли я установить статус/подпись в Delta Chat?</a></li>
<li><a href="#signature">Can I set a Bio/Status with Delta Chat?</a></li>
<li><a href="#что-означают-закрепить-отключить-уведомления-и-отправить-в-архив">Что означают: Закрепить, Отключить уведомления и Отправить в архив?</a></li>
<li><a href="#save">Как работают “Сохраненные сообщения”?</a></li>
<li><a href="#что-означает-зеленая-точка">Что означает зеленая точка?</a></li>
@@ -16,21 +16,21 @@
<li><a href="#edit">Исправление опечаток и удаление сообщений после отправки</a></li>
<li><a href="#ephemeralmsgs">Как работают исчезающие сообщения?</a></li>
<li><a href="#delold">Что произойдет, если я включу функцию “Удалять старые сообщения с устройства”?</a></li>
<li><a href="#remove-account">Как удалить свой профиль в чате?</a></li>
<li><a href="#remove-account">How can I delete my chat profile?</a></li>
</ul>
</li>
<li><a href="#groups">Группы</a>
<li><a href="#groups">Groups</a>
<ul>
<li><a href="#создание-группы">Создание группы</a></li>
<li><a href="#addmembers">Добавление и удаление участников</a></li>
<li><a href="#addmembers">Add and remove members</a></li>
<li><a href="#я-случайно-удалил-самого-себя">Я случайно удалил самого себя.</a></li>
<li><a href="#я-больше-не-хочу-получать-сообщения-группы">Я больше не хочу получать сообщения группы.</a></li>
<li><a href="#клонирование-группы">Клонирование группы</a></li>
<li><a href="#cloning-a-group">Cloning a group</a></li>
</ul>
</li>
<li><a href="#webxdc">Встроенные приложения чата</a>
<li><a href="#webxdc">In-chat apps</a>
<ul>
<li><a href="#где-можно-найти-встроенные-приложения">Где можно найти встроенные приложения?</a></li>
<li><a href="#where-can-i-get-in-chat-apps">Where can I get in-chat apps?</a></li>
<li><a href="#насколько-конфиденциальны-приложения-внутри-чата">Насколько конфиденциальны приложения внутри чата?</a></li>
<li><a href="#create-xdc">Как создать собственные приложения внутри чата?</a></li>
</ul>
@@ -55,9 +55,9 @@
<li><a href="#расширенные">Расширенные</a>
<ul>
<li><a href="#экспериментальные-функции">Экспериментальные функции</a></li>
<li><a href="#statssending">Что означает “Отправлять статистику разработчикам Delta Chat”?</a></li>
<li><a href="#statssending">What is “Send statistics to Delta Chats developers”?</a></li>
<li><a href="#могу-ли-я-использовать-обычный-адрес-электронной-почты-с-delta-chat">Могу ли я использовать обычный адрес электронной почты с Delta Chat?</a></li>
<li><a href="#classic-email">Как настроить профиль чата с использованием классического адреса электронной почты в качестве транспорта?</a></li>
<li><a href="#classic-email">How can I configure a chat profile with a classic email address as transport?</a></li>
<li><a href="#я-хочу-управлять-своим-собственным-сервером-для-delta-chat-что-вы-посоветуете">Я хочу управлять своим собственным сервером для Delta Chat. Что вы посоветуете?</a></li>
<li><a href="#меня-интересуют-технические-детали-можете-рассказать-больше">Меня интересуют технические детали. Можете рассказать больше?</a></li>
</ul>
@@ -107,84 +107,84 @@
<ul>
<li>
<p>Мгновенное создание <strong>приватных профилей чата</strong>
с безопасными и совместимыми <a href="https://chatmail.at/relays">релеями chatmail</a>
которые обеспечивают мгновенную доставку сообщений, а также Push-уведомления для устройств iOS и Android.</p>
<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>
</li>
<li>
<p>Повсеместная поддержка <a href="#multiple-accounts">мультипрофиля</a> и
поддержка <a href="#multiclient">multi-device</a> на всех платформах
и между различными приложениями <a href="https://chatmail.at/clients">chatmail</a>.</p>
<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>
</li>
<li>
<p>Интерактивные <a href="#webxdc">приложения чата</a> для игр и совместной работы</p>
<p>Interactive <a href="#webxdc">in-chat apps</a> for gaming and collaboration</p>
</li>
<li>
<p><a href="#security-audits">Проверенное сквозное шифрование</a>
защита от сетевых и серверных атак.</p>
<p><a href="#security-audits">Audited end-to-end encryption</a>
safe against network and server attacks.</p>
</li>
<li>
<p>Бесплатное программное обеспечение с открытым исходным кодом, как на стороне приложений, так и на стороне сервера,
построенное на <a href="https://github.com/chatmail/core/blob/main/standards.md#standards-used-in-delta-chat">Интернет-стандартах</a>.</p>
<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>
</li>
</ul>
<h3 id="howtoe2ee">
Как найти людей для общения? <a href="#howtoe2ee" class="anchor"></a>
How can I find people to chat with? <a href="#howtoe2ee" class="anchor"></a>
</h3>
<p>Во-первых, обратите внимание, что Delta Chat — это приватный мессенджер.
Публичного поиска контактов нет, вы сами решаете, с кем общаться.</p>
<p>First, note that Delta Chat is a private messenger.
There is no public discovery, <em>you</em> decide about your contacts.</p>
<ul>
<li>
<p>Если вы находитесь <strong>рядом</strong> с другом или членом семьи,
нажмите значок <strong>QR-код</strong> <img style="vertical-align:middle; height:1.3em; margin:1px" src="../qr-icon.png" />
на главном экране.<br />
Попросите вашего собеседника <strong>отсканировать</strong> QR-код
с помощью приложения Delta Chat.</p>
<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>
</li>
<li>
<p>Для <strong>удалённой</strong> настройки контакта,
на том же экране,
нажмите “Копировать” или “Поделиться” и отправьте <strong>ссылку-приглашение</strong>
через другой приватный чат.</p>
<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>
</li>
</ul>
<p>Теперь подождите, пока устанавливается соединение.</p>
<p>Now wait while connection gets established.</p>
<ul>
<li>
<p>Если оба пользователя онлайн, вскоре они увидят чат
и смогут начать безопасное общение.</p>
<p>If both sides are online, they will soon see a chat
and can start messaging securely.</p>
</li>
<li>
<p>Если один из пользователей не в сети или имеет плохое соединение,
возможность общаться появится после восстановления соединения.</p>
<p>If one side is offline or in bad network,
the ability to chat is delayed until connectivity is restored.</p>
</li>
</ul>
<p>Поздравляем!
Теперь вы будете автоматически использовать <a href="#e2ee">сквозное шифрование</a> с этим контактом.
Если вы добавите друг друга в <a href="#groups">группы</a>, сквозное шифрование будет установлено между всеми участниками.</p>
<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>
<h3 id="почему-чат-помечен-как-запрос">
<h3 id="why-is-a-chat-marked-as-request">
Почему чат помечен как “Запрос”? <a href="#почему-чат-помечен-как-запрос" class="anchor"></a>
Why is a chat marked as “Request”? <a href="#why-is-a-chat-marked-as-request" class="anchor"></a>
</h3>
<p>Поскольку это приватный мессенджер,
писать вам могут только друзья и члены семьи, с которыми вы <a href="#howtoe2ee">поделились QR-кодом или ссылкой-приглашением.</a></p>
<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>Ваши друзья могут поделиться вашим контактом с другими друзьями, это отображается как <strong>запрос</strong>.</p>
<p>Your friends may share your contact with other friends, this appears as a <strong>request</strong>.</p>
<p>— Нужно <strong>принять</strong> запрос, прежде чем ответить.</p>
@@ -196,19 +196,19 @@
получать сообщения от этого человека, подумайте о его <strong>блокировке</strong>.</li>
</ul>
<h3 id="как-я-могу-связать-двух-своих-друзей-друг-с-другом">
<h3 id="how-can-i-put-two-of-my-friends-in-contact-with-each-other">
Как я могу связать двух своих друзей друг с другом? <a href="#как-я-могу-связать-двух-своих-друзей-друг-с-другом" class="anchor"></a>
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>
</h3>
<p>Прикрепите первый контакт к чату второго используя кнопку <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Вложение → Контакт</strong>.
Вы также можете добавить небольшое вступительное сообщение.</p>
<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>Второй контакт получит <strong>карточку</strong>
на которую можно нажать, чтобы начать общение с первым контактом.</p>
<p>The second contact will receive a <strong>card</strong> then
and can tap it to start chatting with the first contact.</p>
<h3 id="поддерживает-ли-delta-chat-изображения-видео-и-другие-вложения">
@@ -220,8 +220,8 @@
<ul>
<li>
<p>Да. Изображения, видео, файлы, голосовые сообщения и т.д. можно отправлять с помощью кнопок <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Вложение</strong>
или <img style="vertical-align:middle; width:0.8em; margin:1px" src="../mic.png" alt="Microphone" /> <strong>Голосовое сообщение</strong>.</p>
<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>Attachment-</strong>
or <img style="vertical-align:middle; width:0.8em; margin:1px" src="../mic.png" alt="Microphone" /> <strong>Voice Message</strong> buttons</p>
</li>
<li>
<p>Для лучшей производительности изображения по умолчанию оптимизируются и отправляются в меньшем размере, но вы можете отправить их как “файл”, чтобы сохранить оригинал.</p>
@@ -236,16 +236,16 @@
</h3>
<p>Профиль - это <strong>имя, фотография</strong> и некоторая дополнительная информация для шифрования сообщений.
Профиль живет только на вашем устройстве (устройствах)
и использует сервер только для передачи сообщений.</p>
<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>При первой установке Delta Chat создаётся первый профиль.</p>
<p>Позже, вы можете нажать на изображение вашего профиля в верхнем левом углу, чтобы <strong>Добавить профили</strong>
или <strong>Сменить профили</strong>.</p>
<p>Возможно, вы захотите использовать разные профили для политической деятельности, общения с семьёй или работы.</p>
<p>You may want to use separate profiles for political, family or work related activities.</p>
<p>Вы также можете изучить <a href="#multiclient">как использовать один и тот же профиль на нескольких устройствах</a>.</p>
@@ -271,15 +271,15 @@
<h3 id="signature">
Могу ли я установить статус/подпись в Delta Chat? <a href="#signature" class="anchor"></a>
Can I set a Bio/Status with Delta Chat? <a href="#signature" class="anchor"></a>
</h3>
<p>Да,
вы можете сделать это в разделе <strong>Настройки → Профиль → О себе</strong>.
После отправки сообщения контакту,
они увидят его при просмотре ваших контактных данных.</p>
<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>
<h3 id="что-означают-закрепить-отключить-уведомления-и-отправить-в-архив">
@@ -353,12 +353,13 @@
</h3>
<p>Иногда рядом с аватаром контакта можно увидеть <strong>зелёную точку</strong>. <img style="vertical-align:middle; width:1.2em; margin:1px" src="../green-dot.png" alt="" />
Это означает, что вы <strong>недавно видели</strong> этого человека в течение последних 10 минут,
например, потому что он вам написал или отправил подтверждение прочтения.</p>
<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>Таким образом, это не индикатор онлайн-статуса в реальном времени
и другие пользователи не всегда будут видеть, что вы “онлайн”.</p>
<p>So this is not a real time online status
and others will as well not always see that you are “online”.</p>
<h3 id="что-означают-галочки-рядом-с-исходящими-сообщениями">
@@ -370,21 +371,21 @@
<ul>
<li>
<p><strong>Одна галочка</strong> <img style="vertical-align:middle; width:1.5em; margin:1px" src="../tick1.png" alt="" />
означает, что сообщение было успешно отправлено вашему провайдеру.</p>
<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 your provider.</p>
</li>
<li>
<p><strong>Две галочки</strong> <img style="vertical-align:middle; width:1.5em; margin:1px" src="../tick2.png" alt="" />
означают, что по крайней мере одно устройство получателя
сообщило об успешном получении сообщения.</p>
<p><strong>Two ticks</strong> <img style="vertical-align:middle; width:1.5em; margin:1px" src="../tick2.png" alt="" />
mean that at least one recipients device
reported back to having received the message.</p>
</li>
<li>
<p>Получатели могли отключить подтверждения прочтения,
поэтому даже если вы видите только одну галочку, сообщение могло быть прочитано.</p>
<p>Recipients may have disabled read-receipts,
so even if you see only one tick, the message may have been read.</p>
</li>
<li>
<p>И наоборот, две галочки не обязательно означают
что человек прочитал или понял сообщение ;)</p>
<p>The other way round, two ticks do not automatically mean
that a human has read or understood the message ;)</p>
</li>
</ul>
@@ -429,24 +430,24 @@
выбрав временной интервал
от 5 минут до 1 года.</p>
<p>Пока эта настройка не будет отключена,
приложение Delta Chat каждого участника чата позаботится
об удалении сообщений
по истечении выбранного периода времени.
Отсчёт времени начинается
с момента первого просмотра сообщения получателем в Delta Chat.
Сообщения будут удалены
как на серверах,
так и в самих приложениях.</p>
<p>Until the setting is turned off again,
each chat members 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>Обратите внимание, что на исчезающие сообщения можно полагаться
только до тех пор, пока вы доверяете своим собеседникам;
злонамеренные собеседники могут делать фотографии,
или иным образом сохранить, скопировать или переслать сообщения перед удалением.</p>
<p>Кроме того,
если один из собеседников удалит Delta Chat,
(зашифрованные) сообщения могут дольше оставаться на сервере перед удалением.</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>
<h3 id="delold">
@@ -467,39 +468,39 @@
<h3 id="remove-account">
Как удалить свой профиль в чате? <a href="#remove-account" class="anchor"></a>
How can I delete my chat profile? <a href="#remove-account" class="anchor"></a>
</h3>
<p>Если вы используете несколько профилей чата,
вы можете удалить отдельные из них в верхнем переключателе профилей (на Android и iOS),
или в боковой панели щелчком правой кнопкой мыши (в настольном приложении).
Профили чата удаляются только с устройства, на котором была запущена операция удаления.
Профили чата на других устройствах будут продолжать полностью функционировать.</p>
<p>If you are using more than one chat profile,
you can remove single ones in the top profile switcher menu (on Android and iOS),
or in the sidebar with a right click (in the Desktop app).
Chat profiles are only removed on the device where deletion was triggered.
Chat profiles on other devices will continue to fully function.</p>
<p>Если вы используете один профиль чата по умолчанию, вы можете просто удалить приложение.
Это автоматически инициирует удаление всех связанных данных об адресе на сервере chatmail.
Подробную информацию смотрите на странице <a href="https://nine.testrun.org/info.html#account-deletion">nine.testrun.org address-deletion</a>
или на соответствующей странице выбранного вами <a href="https://chatmail.at/relays">стороннего сервера chatmail</a>.</p>
<p>If you use a single default chat profile you can simply uninstall the app.
This will still automatically trigger deletion of all associated address data on the chatmail server.
For more info, please refer to <a href="https://nine.testrun.org/info.html#account-deletion">nine.testrun.org address-deletion</a>
or the respective page from your chosen <a href="https://chatmail.at/relays">3rd party chatmail server</a>.</p>
<h2 id="groups">
Группы <a href="#groups" class="anchor"></a>
Groups <a href="#groups" class="anchor"></a>
</h2>
<p>Группы позволяют нескольким пользователям общаться друг с другом конфиденциально <strong>на равных правах</strong>.</p>
<p>Groups let several people chat together privately with <strong>equal rights</strong>.</p>
<p>Любой может
изменить название группы или аватар,
<a href="#addmembers">добавить или удалить участников</a>,
включить <a href="#ephemeralmsgs">исчезающие сообщения</a>,
и <a href="#edit">удалять собственные сообщения</a> со всех устройств участников.</p>
<p>Anyone can
change the group name or avatar,
<a href="#addmembers">add or remove members</a>,
set <a href="#ephemeralmsgs">disappearing messages</a>,
and <a href="#edit">delete their own messages</a> from all members devices.</p>
<p>Поскольку все участники имеют одинаковые права, группы лучше всего подходят для общения с <strong>проверенными друзьями и семьёй</strong>.</p>
<p>Because all members have the same rights, groups work best among <strong>trusted friends and family</strong>.</p>
<h3 id="создание-группы">
@@ -518,34 +519,34 @@
<h3 id="addmembers">
Добавление и удаление участников <a href="#addmembers" class="anchor"></a>
Add and remove members <a href="#addmembers" class="anchor"></a>
</h3>
<ul>
<li>
<p>У всех участников группы <strong>одинаковые права</strong>.
Поэтому каждый может удалить любого участника или добавить новых.</p>
<p>All group members have the <strong>same rights</strong>.
For this reason, everyone can delete any member or add new ones.</p>
</li>
<li>
<p>Чтобы <strong>добавлять или удалять участников</strong>, коснитесь названия группы в чате и выберите участника, которого нужно добавить или удалить.</p>
<p>To <strong>add or delete members</strong>, tap the group name in the chat and select the member to add or remove.</p>
</li>
<li>
<p>Если участника еще нет в вашем списке контактов, но он находится с <strong>вами лично</strong>,
на том же экране покажите <strong>QR-код</strong>.<br />
Попросите его <strong>отсканировать</strong> QR-код приложением Delta Chat, нажав
<img style="vertical-align:middle; height:1.3em; margin:1px" src="../qr-icon.png" /> на главном экране.</p>
<p>If the member is not yet in your contact list, but <strong>face to face</strong> with you,
from the same screen, show a <strong>QR code</strong>.<br />
Ask your chat partner to <strong>scan</strong> the QR image with their Delta Chat app by tapping
<img style="vertical-align:middle; height:1.3em; margin:1px" src="../qr-icon.png" /> on the main screen.</p>
</li>
<li>
<p>Для <strong>удалённого</strong> добавления участника,
нажмите “Копировать” или “Поделиться” и отправьте <strong>ссылку-приглашение</strong>
через другой приватный чат новому участнику.</p>
<p>For a <strong>remote</strong> member addition,
click “Copy” or “Share” and send the <strong>invite link</strong>
through another private chat to the new member.</p>
</li>
</ul>
<p>QR-код и ссылку-приглашение можно использовать для добавления нескольких участников.
Однако, поскольку группы <a href="#groups">предназначены для проверенных людей</a>, не распространяйте их публично.</p>
<p>QR code and invite link can be used to add several members.
However, since groups are <a href="#groups">meant for trusted people</a>, avoid sharing them publicly.</p>
<h3 id="я-случайно-удалил-самого-себя">
@@ -578,55 +579,55 @@
</li>
</ul>
<h3 id="клонирование-группы">
<h3 id="cloning-a-group">
Клонирование группы <a href="#клонирование-группы" class="anchor"></a>
Cloning a group <a href="#cloning-a-group" class="anchor"></a>
</h3>
<p>Вы можете дублировать группу, чтобы начать отдельное обсуждение
или исключить участников, незаметно для них.</p>
<p>You can duplicate a group to start a separate discussion
or to exclude members without them noticing.</p>
<ul>
<li>
<p>Откройте профиль группы и нажмите <strong>Клонировать чат</strong> (Android/iOS),
или щелкните правой кнопкой мыши по группе в списке чатов (приложение для ПК).</p>
<p>Open the group profile and tap <strong>Clone Chat</strong> (Android/iOS),
or right-click the group in the chat list (Desktop).</p>
</li>
<li>
<p>Установите новое имя, выберите аватар и при необходимости отредактируйте список участников.</p>
<p>Set a new name, choose an avatar, and adjust the member list if needed.</p>
</li>
</ul>
<p>Новая группа <strong>полностью независима</strong> от исходной,
которая продолжает работать как прежде.</p>
<p>The new group is <strong>fully independent</strong> from the original,
which continues to work as before.</p>
<h2 id="webxdc">
Встроенные приложения чата <a href="#webxdc" class="anchor"></a>
In-chat apps <a href="#webxdc" class="anchor"></a>
</h2>
<p>Вы можете отправлять приложения в чат - игры, редакторы, опросы и другие инструменты.
Это делает Delta Chat по-настоящему расширяемым мессенджером.</p>
<p>You can send apps to a chat - games, editors, polls and other tools.
This makes Delta Chat a truly extensible messenger.</p>
<h3 id="где-можно-найти-встроенные-приложения">
<h3 id="where-can-i-get-in-chat-apps">
Где можно найти встроенные приложения? <a href="#где-можно-найти-встроенные-приложения" class="anchor"></a>
Where can I get in-chat apps? <a href="#where-can-i-get-in-chat-apps" class="anchor"></a>
</h3>
<ul>
<li>
<p>В чате используйте кнопку <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Вложение → Приложения</strong>.</p>
<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>
</li>
<li>
<p>Вы также можете <a href="#create-xdc">создать собственное приложение</a> и прикрепить его с помощью кнопки <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Вложение → Файл</strong>.</p>
<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>
</li>
</ul>
@@ -640,19 +641,19 @@
<ul>
<li>
<p>Встроенные приложения не могут отправлять данные в Интернет или что-либо загружать.</p>
<p>In-chat apps can not send data to the Internet, or download anything.</p>
</li>
<li>
<p>Встроенное приложение может обмениваться данными только внутри чата Delta Chat с его
копиями на устройствах ваших собеседников. В остальном оно полностью
изолировано от Интернета.</p>
<p>An in-chat app can only exchange data within a Delta Chat chat, with its
copies on the devices of your chat partners. Other than that, its completely
isolated from the Internet.</p>
</li>
<li>
<p>Конфиденциальность встроенного приложения соответствует конфиденциальности вашего чата
— пока вы доверяете людям, с которыми общаетесь, можете доверять и встроенному приложению.</p>
<p>The privacy an in-chat app offers is the privacy of your chat - as long as you
trust the people you chat with, you can trust the in-chat app as well.</p>
</li>
<li>
<p>Это также означает: как и в случае с веб-ссылками, не открывайте приложения от ненадежных контактов.</p>
<p>This also means: Just like for web links, do not open apps from untrusted contacts.</p>
</li>
</ul>
@@ -666,19 +667,19 @@
<ul>
<li>
<p>Встроенные приложения - это ZIP-файлы с расширением .xdc, содержащие HTML-, CSS- и JavaScript-код.</p>
<p>In-chat apps are zip files with <code class="language-plaintext highlighter-rouge">.xdc</code> extension containing html, css, and javascript code.</p>
</li>
<li>
<p>Вы можете расширить пример приложения <a href="https://github.com/webxdc/hello">Hello World</a>
чтобы начать работу.</p>
<p>You can extend the <a href="https://github.com/webxdc/hello">Hello World example app</a>
to get started.</p>
</li>
<li>
<p>Всю остальную информацию вы найдёте в
<a href="https://webxdc.org/docs">документации Webxdc</a>.</p>
<p>All else you need to know is written in the
<a href="https://webxdc.org/docs">Webxdc documentation</a>.</p>
</li>
<li>
<p>Если у вас есть вопросы, вы можете обратиться к другим пользователям с опытом
на форуме <a href="https://support.delta.chat/c/webxdc/20">Delta Chat</a>.</p>
<p>If you have question, you can ask others with experience
in the <a href="https://support.delta.chat/c/webxdc/20">Delta Chat Forum</a>.</p>
</li>
</ul>
@@ -773,9 +774,9 @@ Push-уведомления автоматически активируются
</h3>
<p>Поддержка push-уведомлений в Delta Chat предотвращает утечку личной информации.
Она не передаёт данные профиля, IP-адрес или содержимое сообщений (даже зашифрованных)
ни одной системе, участвующей в доставке уведомлений.</p>
<p>Delta Chat Push Notification support avoids leakage of private information.
It does not leak profile data, IP address or message content (not even encrypted)
to any system involved in the delivery of Push Notifications.</p>
<p>Вот как приложения Delta Chat выполняют доставку Push-уведомлений:</p>
@@ -785,21 +786,21 @@ Push-уведомления автоматически активируются
на сервере <a href="https://delta.chat/chatmail">chatmail</a>.</p>
</li>
<li>
<p>Когда сервер <a href="https://delta.chat/chatmail">chatmail</a> получает сообщение для пользователя Delta Chat,
он пересылает зашифрованный токен устройства центральному прокси-серверу уведомлений Delta Chat.</p>
<p>When a <a href="https://delta.chat/chatmail">chatmail</a> server receives a message for a Delta Chat user
it forwards the encrypted device token to the central Delta Chat notification proxy.</p>
</li>
<li>
<p>Центральный прокси-сервер уведомлений Delta Chat расшифровывает токен устройства
и пересылает его соответствующему сервису push-уведомлений (Apple, Google и т.д.),
не зная IP-адреса или данных профиля пользователей Delta Chat.</p>
<p>The central Delta Chat notification proxy decrypts the device token
and forwards it to the respective Push service (Apple, Google, etc.),
without ever knowing the IP or profile data of Delta Chat users.</p>
</li>
<li>
<p>Центральный сервис push-уведомлений (Apple, Google и т.д.)
пробуждает приложение Delta Chat на вашем устройстве
для проверки новых сообщений в фоновом режиме.
Он не знает о данных профиля устройства, которое он пробуждает.
Центральные сервисы Apple/Google Push никогда не видят никаких данных профиля (отправителя или получателя),
а также не видят содержимого сообщений (в том числе в зашифрованном виде).</p>
<p>The central Push Service (Apple, Google, etc.)
wakes up the Delta Chat app on your device
to check for new messages in the background.
It does not know about the profile data of the device it wakes up.
The central Apple/Google Push services never see any profile data (sender or receiver)
and also never see any message content (also not in encrypted forms).</p>
</li>
</ul>
@@ -993,41 +994,41 @@ PIN-код разблокировки экрана, графический кл
</h3>
<p>В разделе <strong>Настройки → Дополнительно → Экспериментальные функции</strong>
вы можете опробовать функции, над которыми мы работаем.</p>
<p>At <strong>Settings → Advanced → Experimental Features</strong>
you can try out features we are working on.</p>
<p>Эти функции могут быть <strong>нестабильными</strong> и могут быть <strong>изменены или удалены</strong>.</p>
<p>The features may be <strong>unstable</strong> and may be <strong>changed or removed</strong>.</p>
<p>Вы можете найти дополнительную информацию
и оставить отзыв на <a href="https://support.delta.chat">Форуме</a>.</p>
<p>You can find more information
and give feedback in the <a href="https://support.delta.chat">Forum</a>.</p>
<h3 id="statssending">
Что означает “Отправлять статистику разработчикам Delta Chat”? <a href="#statssending" class="anchor"></a>
What is “Send statistics to Delta Chats developers”? <a href="#statssending" class="anchor"></a>
</h3>
<p>Мы хотели бы улучшить Delta Chat с вашей помощью,
поэтому Delta Chat для Android спрашивает, хотите ли вы
отправлять анонимную статистику использования.</p>
<p>We would like to improve Delta Chat with your help,
which is why Delta Chat for Android asks whether you want
to send anonymous usage statistics.</p>
<p>Вы можете включить или отключить эту функцию
в разделе <strong>Настройки → Дополнительно → Отправить статистику разработчикам Delta Chat</strong>.</p>
<p>You can turn it on and off at
<strong>Settings → Advanced → Send statistics to Delta Chats developers</strong>.</p>
<p>При включении
еженедельная статистика будет автоматически отправляться боту.</p>
<p>When you turn it on,
weekly statistics will be automatically sent to a bot.</p>
<p>Нас интересует, например, следующая статистика:</p>
<p>We are interested e.g. in statistics like:</p>
<ul>
<li>Сколько контактов добавляется путём личного сканирования QR-кода?</li>
<li>Какие версии Delta Chat используются?</li>
<li>Сколько сообщений в незашифрованном виде?</li>
<li>How many contacts are introduced by personally scanning a QR code?</li>
<li>Which versions of Delta Chat are being used?</li>
<li>How many messages are unencrypted?</li>
</ul>
<p>Мы <em>не</em> собираем какую-либо информацию, позволяющую идентифицировать вас лично.</p>
<p>We will <em>not</em> collect any personally identifiable information about you.</p>
<h3 id="могу-ли-я-использовать-обычный-адрес-электронной-почты-с-delta-chat">
@@ -1037,45 +1038,45 @@ PIN-код разблокировки экрана, графический кл
</h3>
<p>Да, но только если адрес электронной почты используется исключительно <a href="https://chatmail.at/clients">chatmail клиентами</a>.</p>
<p>Yes, but only if the email address is used exclusively by <a href="https://chatmail.at/clients">chatmail clients</a>.</p>
<p>Не поддерживается совместное использование адреса электронной почты с приложениями, не являющимися клиентами chatmail или веб-интерфейсами для работы с почтой,
по следующим причинам:</p>
<p>It is not supported to share usage of an email address with non-chatmail apps or web-based mailers,
for the following reasons:</p>
<ul>
<li>
<p>Приложения, не являющиеся клиентами chatmail, в основном не обеспечивают автоматическое сквозное шифрование электронной почты для своих пользователей,
тогда как приложения и релеи chatmail повсеместно применяют сквозное шифрование и стандарты безопасности.</p>
<p>Non-chatmail apps are largely not accomplishing automatic end-to-end email encryption for their users,
while chatmail apps and relays pervasively enforce end-to-end encryption and security standards.</p>
</li>
<li>
<p>Приложения, не являющиеся клиентами chatmail, используют серверы электронной почты в качестве долгосрочного архива сообщений,
тогда как клиенты chatmail используют почтовые серверы для передачи мгновенных сообщений с коротким сроком жизни.</p>
<p>Non-chatmail apps use email servers as a long-term message archive
while chatmail clients use email servers for ephemeral instant message transport.</p>
</li>
<li>
<p>Поддержка всего разнообразия классических настроек электронной почты
потребует значительных усилий по разработке и сопровождению,
а также усложнит повышение устойчивости, надёжности и скорости обмена сообщениями на основе chatmail.</p>
<p>Supporting the full variety of classic email setups
would require considerable development and maintenance efforts,
and complicate making chatmail-based messaging more resilient, reliable and fast.</p>
</li>
</ul>
<h3 id="classic-email">
Как настроить профиль чата с использованием классического адреса электронной почты в качестве транспорта? <a href="#classic-email" class="anchor"></a>
How can I configure a chat profile with a classic email address as transport? <a href="#classic-email" class="anchor"></a>
</h3>
<p>Прежде всего, <strong>не используйте те же классические адреса электронной почты, которые используются в обычных приложениях для отправки писем</strong>
если вы не готовы к зашифрованным сообщениям во входящих,
двойным уведомлениям, случайному удалению писем или подобным неудобствам.</p>
<p>First off, <strong>please do not use the same classic email address also from non-chatmail classic email apps</strong>
unless you are prepared to deal with encrypted messages in the inbox,
double notifications, accidentally deleted emails or similar annoyances.</p>
<p>Вы можете настроить адрес электронной почты для чата в разделе <strong>Новый профиль → Использовать другой сервер → Использовать классическую почту в качестве транспорта</strong>.
Обратите внимание, что классические почтовые провайдеры обычно не поддерживают <a href="#instant-delivery">Push-уведомления</a>
и имеют другие ограничения, см. раздел <a href="https://providers.delta.chat">Обзор провайдеров</a>.
Chatmail использует INBOX по умолчанию для ретрансляции; убедитесь, что провайдер также настроен.
Профиль чата, использующий классический адрес электронной почты, позволяет отправлять и получать незашифрованные сообщения.
Эти сообщения и чаты, в которых они появляются, помечаются значком электронной почты
<p>You can configure a email address for chatting at <strong>New Profile → Use Other Server → Use Classic Mail as Transport</strong>.
Note that classic email providers will generally not support <a href="#instant-delivery">Push Notifications</a>
and have other limitations, see <a href="https://providers.delta.chat">Provider Overview</a>.
Chatmail uses the default INBOX for relay; ensure the provider setup does too.
A chat profile using a classic email address allows to to send and receive unencrypted messages.
These messages, and the chats they appear in, are marked with an email icon
<img style="vertical-align:middle; width:1.2em; margin:1px" src="../email-icon.png" alt="email" />.</p>
<h3 id="я-хочу-управлять-своим-собственным-сервером-для-delta-chat-что-вы-посоветуете">
@@ -1088,7 +1089,7 @@ Chatmail использует INBOX по умолчанию для ретран
<p>Подойдет любая корректная настройка почтового сервера, за исключением случаев, когда для корректной работы устройств ваших пользователей требуются <a href="#instant-delivery">Push-уведомления</a> Google/Apple.</p>
<p>Мы обычно рекомендуем <a href="https://chatmail.at/doc/relay/getting_started.html">настроить chatmail релей</a>.
<p>Мы обычно рекомендуем <a href="https://chatmail.at/doc/relay/getting_started.html">настроить chatmail relay</a>.
<a href="https://chatmail.at">Chatmail</a> — это проект, поддерживаемый сообществом который охватывает как настройку релеев, так
и <a href="https://github.com/chatmail/core">основные разработки на Rust</a>
которые обеспечивают работу <a href="https://chatmail.at/clients">клиентов chatmail</a> наиболее известным из которых является Delta Chat.</p>
@@ -1162,7 +1163,7 @@ Chatmail использует INBOX по умолчанию для ретран
</h3>
<p>Если вы используете стандартные <a href="https://chatmail.at/relays">релеи chatmail</a>,
<p>Если вы используете стандартные <a href="https://chatmail.at/relays">ретрансляторы chatmail</a>,
невозможно получать или отправлять сообщения без сквозного шифрования.</p>
<p>Если вы вместо этого используете <a href="#classic-email">классический почтовый сервер</a>,
@@ -1428,12 +1429,12 @@ Delta Chat показывает там два отпечатка.
<p>Нет.</p>
<p>Delta Chat генерирует безопасные ключи OpenPGP в соответствии со спецификацией Autocrypt 1.1.
Мы не рекомендуем и не предлагаем пользователям управлять ключами вручную.
Мы хотим, чтобы аудиты безопасности могли сосредоточиться на нескольких проверенных криптографических алгоритмах
а не на всем многообразии возможных алгоритмов, разрешенных в OpenPGP.
Если вы хотите извлечь свой ключ OpenPGP, существует только экспертный метод:
вам нужно найти его в SQLite-таблице “keypairs” в tar-файле резервной копии профиля.</p>
<p>Delta Chat генерирует безопасные ключи OpenPGP в соответствии со спецификацией Autocrypt 1.1.
Вы можете экспортировать свой закрытый ключ, но не можете импортировать дополнительные закрытые ключи.</p>
<p>В целом, мы не рекомендуем и не предлагаем пользователям выполнять ручное управление ключами.
Мы стремимся к тому, чтобы аудиты безопасности могли сосредоточиться на нескольких проверенных криптографических алгоритмах,
а не на всем разнообразии возможных алгоритмов, доступных с OpenPGP.</p>
<h3 id="security-audits">
+11 -11
View File
@@ -57,7 +57,7 @@
<li><a href="#experimental-features">Experimental Features</a></li>
<li><a href="#statssending">What is “Send statistics to Delta Chats developers”?</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="#classic-email">How can I configure a chat profile with a classic email address as relay?</a></li>
<li><a href="#classic-email">How can I configure a chat profile with a classic email address as transport?</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="#zaujímajú-ma-technické-detaily-môžete-mi-povedať-viac">Zaujímajú ma technické detaily. Môžete mi povedať viac?</a></li>
</ul>
@@ -650,7 +650,7 @@ This makes Delta Chat a truly extensible messenger.</p>
<p>In-chat apps can not send data to the Internet, or download anything.</p>
</li>
<li>
<p>An in-chat app can only exchange data within a chat, with its
<p>An in-chat app can only exchange data within a Delta Chat chat, with its
copies on the devices of your chat partners. Other than that, its completely
isolated from the Internet.</p>
</li>
@@ -1057,7 +1057,7 @@ while chatmail apps and relays pervasively enforce end-to-end encryption and sec
</li>
<li>
<p>Non-chatmail apps use email servers as a long-term message archive
while chatmail clients use email servers for ephemeral instant message relay.</p>
while chatmail clients use email servers for ephemeral instant message transport.</p>
</li>
<li>
<p>Supporting the full variety of classic email setups
@@ -1069,7 +1069,7 @@ and complicate making chatmail-based messaging more resilient, reliable and fast
<h3 id="classic-email">
How can I configure a chat profile with a classic email address as relay? <a href="#classic-email" class="anchor"></a>
How can I configure a chat profile with a classic email address as transport? <a href="#classic-email" class="anchor"></a>
</h3>
@@ -1078,7 +1078,7 @@ and complicate making chatmail-based messaging more resilient, reliable and fast
unless you are prepared to deal with encrypted messages in the inbox,
double notifications, accidentally deleted emails or similar annoyances.</p>
<p>You can configure a email address for chatting at <strong>New Profile → Use Other Server → Use Classic Mail as Relay</strong>.
<p>You can configure a email address for chatting at <strong>New Profile → Use Other Server → Use Classic Mail as Transport</strong>.
Note that classic email providers will generally not support <a href="#instant-delivery">Push Notifications</a>
and have other limitations, see <a href="https://providers.delta.chat">Provider Overview</a>.
Chatmail uses the default INBOX for relay; ensure the provider setup does too.
@@ -1437,12 +1437,12 @@ the connection is safe.</p>
<p>No.</p>
<p>Delta Chat generates secure OpenPGP keys according to the Autocrypt specification 1.1.
We do not recommend or offer users to perform manual key management.
We want to ensure that security audits can focus on a few proven cryptographic algorithms
instead of the full breadth of possible algorithms allowed with OpenPGP.
If you want to extract your OpenPGP key, there only is an expert method:
you need to look it up in the “keypairs” SQLite table of a profile backup tar-file.</p>
<p>Delta Chat generates secure OpenPGP keys according to the Autocrypt specification 1.1.
You can export your private key but you can not import additional private keys.</p>
<p>In general, we do not recommend or offer users to perform manual key management.
We want to ensure that security audits can focus on a few proven cryptographic algorithms
instead of the full breadth of possible algorithms allowed with OpenPGP.</p>
<h3 id="security-audits">
+11 -11
View File
@@ -57,7 +57,7 @@
<li><a href="#experimental-features">Experimental Features</a></li>
<li><a href="#statssending">What is “Send statistics to Delta Chats developers”?</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="#classic-email">How can I configure a chat profile with a classic email address as relay?</a></li>
<li><a href="#classic-email">How can I configure a chat profile with a classic email address as transport?</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="#më-interesojnë-hollësitë-teknike-mund-të-më-tregoni-diçka-më-tepër">Më interesojnë hollësitë teknike. Mund të më tregoni diçka më tepër?</a></li>
</ul>
@@ -652,7 +652,7 @@ This makes Delta Chat a truly extensible messenger.</p>
<p>In-chat apps can not send data to the Internet, or download anything.</p>
</li>
<li>
<p>An in-chat app can only exchange data within a chat, with its
<p>An in-chat app can only exchange data within a Delta Chat chat, with its
copies on the devices of your chat partners. Other than that, its completely
isolated from the Internet.</p>
</li>
@@ -1061,7 +1061,7 @@ while chatmail apps and relays pervasively enforce end-to-end encryption and sec
</li>
<li>
<p>Non-chatmail apps use email servers as a long-term message archive
while chatmail clients use email servers for ephemeral instant message relay.</p>
while chatmail clients use email servers for ephemeral instant message transport.</p>
</li>
<li>
<p>Supporting the full variety of classic email setups
@@ -1073,7 +1073,7 @@ and complicate making chatmail-based messaging more resilient, reliable and fast
<h3 id="classic-email">
How can I configure a chat profile with a classic email address as relay? <a href="#classic-email" class="anchor"></a>
How can I configure a chat profile with a classic email address as transport? <a href="#classic-email" class="anchor"></a>
</h3>
@@ -1082,7 +1082,7 @@ and complicate making chatmail-based messaging more resilient, reliable and fast
unless you are prepared to deal with encrypted messages in the inbox,
double notifications, accidentally deleted emails or similar annoyances.</p>
<p>You can configure a email address for chatting at <strong>New Profile → Use Other Server → Use Classic Mail as Relay</strong>.
<p>You can configure a email address for chatting at <strong>New Profile → Use Other Server → Use Classic Mail as Transport</strong>.
Note that classic email providers will generally not support <a href="#instant-delivery">Push Notifications</a>
and have other limitations, see <a href="https://providers.delta.chat">Provider Overview</a>.
Chatmail uses the default INBOX for relay; ensure the provider setup does too.
@@ -1441,12 +1441,12 @@ the connection is safe.</p>
<p>No.</p>
<p>Delta Chat generates secure OpenPGP keys according to the Autocrypt specification 1.1.
We do not recommend or offer users to perform manual key management.
We want to ensure that security audits can focus on a few proven cryptographic algorithms
instead of the full breadth of possible algorithms allowed with OpenPGP.
If you want to extract your OpenPGP key, there only is an expert method:
you need to look it up in the “keypairs” SQLite table of a profile backup tar-file.</p>
<p>Delta Chat generates secure OpenPGP keys according to the Autocrypt specification 1.1.
You can export your private key but you can not import additional private keys.</p>
<p>In general, we do not recommend or offer users to perform manual key management.
We want to ensure that security audits can focus on a few proven cryptographic algorithms
instead of the full breadth of possible algorithms allowed with OpenPGP.</p>
<h3 id="security-audits">
+67 -59
View File
@@ -8,7 +8,7 @@
<li><a href="#чи-підтримує-delta-chat-вкладення-у-вигляді-фото-відео-тощо">Чи підтримує Delta Chat вкладення у вигляді фото, відео тощо?</a></li>
<li><a href="#multiple-accounts">Що таке профілі? Як я можу перемикатися між ними?</a></li>
<li><a href="#хто-бачить-моє-зображення-профілю">Хто бачить моє зображення профілю?</a></li>
<li><a href="#signature">Чи можу я встановити біографію/статус у Delta Chat?</a></li>
<li><a href="#signature">Can I set a Bio/Status with Delta Chat?</a></li>
<li><a href="#що-значить-закріплення-приглушення-архівування">Що значить Закріплення, Приглушення, Архівування?</a></li>
<li><a href="#save">Як працюють “Збережені повідомлення”?</a></li>
<li><a href="#що-означає-зелена-точка">Що означає зелена точка?</a></li>
@@ -16,15 +16,16 @@
<li><a href="#edit">Виправлення помилок та видалення повідомлень після надсилання</a></li>
<li><a href="#ephemeralmsgs">Як працюють повідомлення, що зникають?</a></li>
<li><a href="#delold">Що станеться, якщо я ввімкну «Видаляти старі повідомлення з пристрою»?</a></li>
<li><a href="#remove-account">How can I delete my chat profile?</a></li>
</ul>
</li>
<li><a href="#groups">Групи</a>
<li><a href="#groups">Groups</a>
<ul>
<li><a href="#створення-групи">Створення групи</a></li>
<li><a href="#addmembers">Додавання та видалення учасників</a></li>
<li><a href="#addmembers">Add and remove members</a></li>
<li><a href="#я-випадково-себе-видалив">Я випадково себе видалив</a></li>
<li><a href="#я-більше-не-хочу-отримувати-повідомлення-групи">Я більше не хочу отримувати повідомлення групи.</a></li>
<li><a href="#клонування-групи">Клонування групи</a></li>
<li><a href="#cloning-a-group">Cloning a group</a></li>
</ul>
</li>
<li><a href="#webxdc">In-chat apps</a>
@@ -53,10 +54,10 @@
</li>
<li><a href="#advanced">Advanced</a>
<ul>
<li><a href="#експериментальні-функції">Експериментальні функції</a></li>
<li><a href="#experimental-features">Experimental Features</a></li>
<li><a href="#statssending">What is “Send statistics to Delta Chats developers”?</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="#classic-email">How can I configure a chat profile with a classic email address as relay?</a></li>
<li><a href="#classic-email">How can I configure a chat profile with a classic email address as transport?</a></li>
<li><a href="#я-хочу-керувати-власним-сервером-для-delta-chat-що-ви-порекомендуєте">Я хочу керувати власним сервером для Delta Chat. Що ви порекомендуєте?</a></li>
<li><a href="#мене-цікавлять-технічні-деталі-можете-розповісти-більше">Мене цікавлять технічні деталі. Можете розповісти більше?</a></li>
</ul>
@@ -64,8 +65,8 @@
<li><a href="#e2ee">Шифрування та безпека</a>
<ul>
<li><a href="#які-стандарти-використовуються-для-наскрізного-шифрування">Які стандарти використовуються для наскрізного шифрування?</a></li>
<li><a href="#whene2e">Як дізнатися, чи повідомлення зашифровано наскрізним шифруванням?</a></li>
<li><a href="#чи-можу-я-отримувати-та-надсилати-пошту-без-наскрізного-шифрування">Чи можу я отримувати та надсилати пошту без наскрізного шифрування?</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="#e2eeguarantee">Що означає зелена галочка в профілі контакту?</a></li>
<li><a href="#чи-зашифровані-наскрізно-вкладення-зображення-файли-аудіо-тощо">Чи зашифровані наскрізно вкладення (зображення, файли, аудіо тощо)?</a></li>
<li><a href="#openpgp-secure">Чи безпечний OpenPGP?</a></li>
@@ -111,17 +112,20 @@
які пропонують миттєву доставку повідомлень та push-сповіщення для пристроїв iOS та Android.</p>
</li>
<li>
<p>Повсюдна підтримка багатьох <a href="#multiple-accounts">профілів</a> та <a href="#multiclient">пристроїв</a> на всіх платформах та між різними <a href="https://chatmail.at/clients">поштовими програмами</a>.</p>
<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>
</li>
<li>
<p>Інтерактивні <a href="https://webxdc.org/">веб-застосунки у чатах</a> для ігор та співпраці</p>
<p>Interactive <a href="#webxdc">in-chat apps</a> for gaming and collaboration</p>
</li>
<li>
<p><a href="#security-audits">Аудитоване наскрізне шифрування</a>
захищене від мережевих та серверних атак.</p>
<p><a href="#security-audits">Audited end-to-end encryption</a>
safe against network and server attacks.</p>
</li>
<li>
<p>Вільне програмне забезпечення з відкритим вихідним кодом, як застосунок, так серверна частина, побудоване на основі <a href="https://github.com/chatmail/core/blob/main/standards.md#standards-used-in-delta-chat">Інтернет-стандартів</a>.</p>
<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>
</li>
</ul>
@@ -133,7 +137,8 @@
</h3>
<p>По-перше, зверніть увагу, що Delta Chat - це приватний месенджер. Тут немає публічного розкриття, <em>ви</em> самі вирішуєте, з ким спілкуватися.</p>
<p>First, note that Delta Chat is a private messenger.
There is no public discovery, <em>you</em> decide about your contacts.</p>
<ul>
<li>
@@ -151,7 +156,7 @@ through another private chat.</p>
</li>
</ul>
<p>Зараз зачекайте, поки встановлюється з’єднання.</p>
<p>Now wait while connection gets established.</p>
<ul>
<li>
@@ -164,9 +169,9 @@ the ability to chat is delayed until connectivity is restored.</p>
</li>
</ul>
<p>Вітаємо!
Тепер Ви автоматично використовуватимете <a href="#e2ee">наскрізне шифрування</a> з цим контактом.
Якщо ви додасте один одного у <a href="#groups">групи</a>, наскрізне шифрування буде встановлено між усіма учасниками.</p>
<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>
<h3 id="why-is-a-chat-marked-as-request">
@@ -241,7 +246,7 @@ and uses the server only to relay messages.</p>
<p>Пізніше ви можете натиснути на зображення вашого профілю у верхньому лівому кутку, щоб вибрати <strong>Додати профілі</strong> або <strong>Переключити профілі</strong>.</p>
<p>Ви можете використовувати окремі профілі для політичної, сімейної або робочої діяльності.</p>
<p>You may want to use separate profiles for political, family or work related activities.</p>
<p>Ви також можете дізнатися <a href="#multiclient">як використовувати один і той самий профіль на декількох пристроях</a>.</p>
@@ -265,7 +270,7 @@ and uses the server only to relay messages.</p>
<h3 id="signature">
Чи можу я встановити біографію/статус у Delta Chat? <a href="#signature" class="anchor"></a>
Can I set a Bio/Status with Delta Chat? <a href="#signature" class="anchor"></a>
</h3>
@@ -442,8 +447,14 @@ the (anyway encrypted) messages may take longer to get deleted from their server
<li>Щоб увімкнути його, перейдіть до «видалити старі повідомлення з пристрою» в налаштуваннях «Чатів та медіа» . Ви можете встановити часові рамки від «через годину» до «через рік»;
Таким чином, <em>усі</em> повідомлення будуть видалені з вашого пристрою, як тільки вони будуть старішими за це.</li>
</ul>
<p>Як я можу видалити свій профіль у Delta Chat? {#remove-account}</p>
<h3 id="remove-account">
How can I delete my chat profile? <a href="#remove-account" class="anchor"></a>
</h3>
<p>If you are using more than one chat profile,
you can remove single ones in the top profile switcher menu (on Android and iOS),
@@ -459,12 +470,12 @@ or the respective page from your chosen <a href="https://chatmail.at/relays">3rd
<h2 id="groups">
Групи <a href="#groups" class="anchor"></a>
Groups <a href="#groups" class="anchor"></a>
</h2>
<p>Групи дозволяють кільком людям спілкуватися у приватному чаті з <strong>рівними правами</strong>.</p>
<p>Groups let several people chat together privately with <strong>equal rights</strong>.</p>
<p>Anyone can
change the group name or avatar,
@@ -472,7 +483,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 members devices.</p>
<p>Оскільки усі учасники мають однакові права, групи найкраще працюють серед <strong>довірених друзів та родичів</strong>.</p>
<p>Because all members have the same rights, groups work best among <strong>trusted friends and family</strong>.</p>
<h3 id="створення-групи">
@@ -491,15 +502,15 @@ and <a href="#edit">delete their own messages</a> from all members devices.</
<h3 id="addmembers">
Додавання та видалення учасників <a href="#addmembers" class="anchor"></a>
Add and remove members <a href="#addmembers" class="anchor"></a>
</h3>
<ul>
<li>
<p>Усі учасники групи мають <strong>однакові права</strong>.
Тому кожен може видалити будь-якого учасника або додати нових.</p>
<p>All group members have the <strong>same rights</strong>.
For this reason, everyone can delete any member or add new ones.</p>
</li>
<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>
@@ -549,10 +560,10 @@ However, since groups are <a href="#groups">meant for trusted people</a>, avoid
</li>
</ul>
<h3 id="клонування-групи">
<h3 id="cloning-a-group">
Клонування групи <a href="#клонування-групи" class="anchor"></a>
Cloning a group <a href="#cloning-a-group" class="anchor"></a>
</h3>
@@ -570,8 +581,8 @@ or right-click the group in the chat list (Desktop).</p>
</li>
</ul>
<p>Нова група є <strong>цілком незалежною</strong> від оригінальної,
котра продовжує працювати як раніше.</p>
<p>The new group is <strong>fully independent</strong> from the original,
which continues to work as before.</p>
<h2 id="webxdc">
@@ -614,7 +625,7 @@ This makes Delta Chat a truly extensible messenger.</p>
<p>In-chat apps can not send data to the Internet, or download anything.</p>
</li>
<li>
<p>An in-chat app can only exchange data within a chat, with its
<p>An in-chat app can only exchange data within a Delta Chat chat, with its
copies on the devices of your chat partners. Other than that, its completely
isolated from the Internet.</p>
</li>
@@ -644,8 +655,8 @@ trust the people you chat with, you can trust the in-chat app as well.</p>
to get started.</p>
</li>
<li>
<p>Все інше, що Вам потрібно знати, написано у
<a href="https://webxdc.org/docs">документації Webxdc</a>.</p>
<p>All else you need to know is written in the
<a href="https://webxdc.org/docs">Webxdc documentation</a>.</p>
</li>
<li>
<p>If you have question, you can ask others with experience
@@ -900,10 +911,10 @@ Welcome to the power of the interoperable chatmail relay network :)</p>
</h2>
<h3 id="експериментальні-функції">
<h3 id="experimental-features">
Експериментальні функції <a href="#експериментальні-функції" class="anchor"></a>
Experimental Features <a href="#experimental-features" class="anchor"></a>
</h3>
@@ -911,10 +922,10 @@ Welcome to the power of the interoperable chatmail relay network :)</p>
<p>At <strong>Settings → Advanced → Experimental Features</strong>
you can try out features we are working on.</p>
<p>Ці функції можуть бути <strong>нестабільними</strong> та можуть бути <strong>змінені або видалені</strong>.</p>
<p>The features may be <strong>unstable</strong> and may be <strong>changed or removed</strong>.</p>
<p>Ви можете знайти додаткову інформацію
та залишити відгук на <a href="https://support.delta.chat">форумі</a>.</p>
<p>You can find more information
and give feedback in the <a href="https://support.delta.chat">Forum</a>.</p>
<h3 id="statssending">
@@ -931,8 +942,8 @@ to send anonymous usage statistics.</p>
<p>You can turn it on and off at
<strong>Settings → Advanced → Send statistics to Delta Chats developers</strong>.</p>
<p>Коли Ви увімкнете цю функцію,
щотижнева статистика буде автоматично надсилатися боту.</p>
<p>When you turn it on,
weekly statistics will be automatically sent to a bot.</p>
<p>We are interested e.g. in statistics like:</p>
@@ -942,7 +953,7 @@ to send anonymous usage statistics.</p>
<li>How many messages are unencrypted?</li>
</ul>
<p>Ми <em>не</em> будемо збирати жодних персональних даних, які б могли ідентифікувати Вас особисто.</p>
<p>We will <em>not</em> collect any personally identifiable information about you.</p>
<h3 id="can-i-use-a-classic-email-address-with-delta-chat">
@@ -964,7 +975,7 @@ while chatmail apps and relays pervasively enforce end-to-end encryption and sec
</li>
<li>
<p>Non-chatmail apps use email servers as a long-term message archive
while chatmail clients use email servers for ephemeral instant message relay.</p>
while chatmail clients use email servers for ephemeral instant message transport.</p>
</li>
<li>
<p>Supporting the full variety of classic email setups
@@ -976,7 +987,7 @@ and complicate making chatmail-based messaging more resilient, reliable and fast
<h3 id="classic-email">
How can I configure a chat profile with a classic email address as relay? <a href="#classic-email" class="anchor"></a>
How can I configure a chat profile with a classic email address as transport? <a href="#classic-email" class="anchor"></a>
</h3>
@@ -985,7 +996,7 @@ and complicate making chatmail-based messaging more resilient, reliable and fast
unless you are prepared to deal with encrypted messages in the inbox,
double notifications, accidentally deleted emails or similar annoyances.</p>
<p>You can configure a email address for chatting at <strong>New Profile → Use Other Server → Use Classic Mail as Relay</strong>.
<p>You can configure a email address for chatting at <strong>New Profile → Use Other Server → Use Classic Mail as Transport</strong>.
Note that classic email providers will generally not support <a href="#instant-delivery">Push Notifications</a>
and have other limitations, see <a href="https://providers.delta.chat">Provider Overview</a>.
Chatmail uses the default INBOX for relay; ensure the provider setup does too.
@@ -1056,17 +1067,17 @@ that power <a href="https://chatmail.at/clients">chatmail clients</a> of which D
<h3 id="whene2e">
Як дізнатися, чи повідомлення зашифровано наскрізним шифруванням? <a href="#whene2e" class="anchor"></a>
How can I know if messages are end-to-end encrypted? <a href="#whene2e" class="anchor"></a>
</h3>
<p>Всі повідомлення в Delta Chat за замовчуванням <strong>наскрізно зашифровані</strong>. Починаючи з версії 2 Delta Chat (липень 2025 року) на наскрізних зашифрованих повідомленнях більше немає замків або інших подібних маркерів.</p>
<h3 id="чи-можу-я-отримувати-та-надсилати-пошту-без-наскрізного-шифрування">
<h3 id="can-i-still-receive-or-send-messages-without-end-to-end-encryption">
Чи можу я отримувати та надсилати пошту без наскрізного шифрування? <a href="#чи-можу-я-отримувати-та-надсилати-пошту-без-наскрізного-шифрування" class="anchor"></a>
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>
</h3>
@@ -1183,11 +1194,11 @@ even if the message was not end-to-end encrypted.</p>
<p>Servers can therefore only see:</p>
<ul>
<li>адреси відправника та одержувача</li>
<li>та розмір повідомлення.</li>
<li>the sender and receiver addresses</li>
<li>and the message size.</li>
</ul>
<p>За замовчуванням адреси генеруються випадковим чином.</p>
<p>By default, the addresses are randomly generated.</p>
<p>Усі інші метадані повідомлень, контактів і груп містяться в наскрізно зашифрованій частині повідомлень.</p>
@@ -1273,12 +1284,9 @@ but an implementation has not been agreed as a priority yet.</p>
<p>Ні.</p>
<p>Delta Chat generates secure OpenPGP keys according to the Autocrypt specification 1.1.
We do not recommend or offer users to perform manual key management.
We want to ensure that security audits can focus on a few proven cryptographic algorithms
instead of the full breadth of possible algorithms allowed with OpenPGP.
If you want to extract your OpenPGP key, there only is an expert method:
you need to look it up in the “keypairs” SQLite table of a profile backup tar-file.</p>
<p>Delta Chat генерує безпечні ключі OpenPGP відповідно до специфікації Autocrypt 1.1. Ви можете експортувати свій приватний ключ, але не можете імпортувати додаткові приватні ключі.</p>
<p>Загалом, ми не рекомендуємо і не пропонуємо користувачам керувати ключами вручну. Ми хочемо гарантувати, що аудит безпеки може зосередитися на декількох перевірених криптографічних алгоритмах а не на всій широті можливих алгоритмів, дозволених у OpenPGP.</p>
<h3 id="security-audits">
@@ -1337,7 +1345,7 @@ you need to look it up in the “keypairs” SQLite table of a profile backup ta
<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>Дивіться <a href="https://delta.chat/en/gdpr#24-app-permissions">політику конфіденційності</a> для детального огляду.</p>
<p>See <a href="https://delta.chat/en/gdpr#24-app-permissions">Privacy Policy</a> for a detailed overview.</p>
<h3 id="де-мої-друзі-можуть-знайти-delta-chat">
+11 -11
View File
@@ -57,7 +57,7 @@
<li><a href="#experimental-features">Experimental Features</a></li>
<li><a href="#statssending">What is “Send statistics to Delta Chats developers”?</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="#classic-email">How can I configure a chat profile with a classic email address as relay?</a></li>
<li><a href="#classic-email">How can I configure a chat profile with a classic email address as transport?</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="#我对技术细节很感兴趣能告诉我更多吗">我对技术细节很感兴趣。能告诉我更多吗?</a></li>
</ul>
@@ -637,7 +637,7 @@ This makes Delta Chat a truly extensible messenger.</p>
<p>In-chat apps can not send data to the Internet, or download anything.</p>
</li>
<li>
<p>An in-chat app can only exchange data within a chat, with its
<p>An in-chat app can only exchange data within a Delta Chat chat, with its
copies on the devices of your chat partners. Other than that, its completely
isolated from the Internet.</p>
</li>
@@ -1033,7 +1033,7 @@ while chatmail apps and relays pervasively enforce end-to-end encryption and sec
</li>
<li>
<p>Non-chatmail apps use email servers as a long-term message archive
while chatmail clients use email servers for ephemeral instant message relay.</p>
while chatmail clients use email servers for ephemeral instant message transport.</p>
</li>
<li>
<p>Supporting the full variety of classic email setups
@@ -1045,7 +1045,7 @@ and complicate making chatmail-based messaging more resilient, reliable and fast
<h3 id="classic-email">
How can I configure a chat profile with a classic email address as relay? <a href="#classic-email" class="anchor"></a>
How can I configure a chat profile with a classic email address as transport? <a href="#classic-email" class="anchor"></a>
</h3>
@@ -1054,7 +1054,7 @@ and complicate making chatmail-based messaging more resilient, reliable and fast
unless you are prepared to deal with encrypted messages in the inbox,
double notifications, accidentally deleted emails or similar annoyances.</p>
<p>You can configure a email address for chatting at <strong>New Profile → Use Other Server → Use Classic Mail as Relay</strong>.
<p>You can configure a email address for chatting at <strong>New Profile → Use Other Server → Use Classic Mail as Transport</strong>.
Note that classic email providers will generally not support <a href="#instant-delivery">Push Notifications</a>
and have other limitations, see <a href="https://providers.delta.chat">Provider Overview</a>.
Chatmail uses the default INBOX for relay; ensure the provider setup does too.
@@ -1410,12 +1410,12 @@ Delta Chat 在此处显示两个指纹。
<p>不。</p>
<p>Delta Chat generates secure OpenPGP keys according to the Autocrypt specification 1.1.
We do not recommend or offer users to perform manual key management.
We want to ensure that security audits can focus on a few proven cryptographic algorithms
instead of the full breadth of possible algorithms allowed with OpenPGP.
If you want to extract your OpenPGP key, there only is an expert method:
you need to look it up in the “keypairs” SQLite table of a profile backup tar-file.</p>
<p>Delta Chat 采用 Autocrypt 1.1 标准规范生成 OpenPGP 加密密钥。
用户虽可导出自身私钥进行备份,但系统设计上不支持导入其他私钥。</p>
<p>基于安全考量,系统默认不开放手动密钥管理功能。
此项设计旨在让安全审计工作聚焦于少量成熟加密算法(如 Autocrypt 标准),
避免因支持 OpenPGP 协议所允许的所有算法而增加潜在安全风险。</p>
<h3 id="security-audits">
@@ -8,7 +8,7 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
@JsonTypeInfo(use=Id.NAME, include=As.PROPERTY, property="kind")
@JsonSubTypes({@Type(value = EventType.Info.class, name="Info"), @Type(value = EventType.SmtpConnected.class, name="SmtpConnected"), @Type(value = EventType.ImapConnected.class, name="ImapConnected"), @Type(value = EventType.SmtpMessageSent.class, name="SmtpMessageSent"), @Type(value = EventType.ImapMessageDeleted.class, name="ImapMessageDeleted"), @Type(value = EventType.ImapMessageMoved.class, name="ImapMessageMoved"), @Type(value = EventType.ImapInboxIdle.class, name="ImapInboxIdle"), @Type(value = EventType.NewBlobFile.class, name="NewBlobFile"), @Type(value = EventType.DeletedBlobFile.class, name="DeletedBlobFile"), @Type(value = EventType.Warning.class, name="Warning"), @Type(value = EventType.Error.class, name="Error"), @Type(value = EventType.ErrorSelfNotInGroup.class, name="ErrorSelfNotInGroup"), @Type(value = EventType.MsgsChanged.class, name="MsgsChanged"), @Type(value = EventType.ReactionsChanged.class, name="ReactionsChanged"), @Type(value = EventType.IncomingReaction.class, name="IncomingReaction"), @Type(value = EventType.IncomingWebxdcNotify.class, name="IncomingWebxdcNotify"), @Type(value = EventType.IncomingMsg.class, name="IncomingMsg"), @Type(value = EventType.IncomingMsgBunch.class, name="IncomingMsgBunch"), @Type(value = EventType.MsgsNoticed.class, name="MsgsNoticed"), @Type(value = EventType.MsgDelivered.class, name="MsgDelivered"), @Type(value = EventType.MsgFailed.class, name="MsgFailed"), @Type(value = EventType.MsgRead.class, name="MsgRead"), @Type(value = EventType.MsgDeleted.class, name="MsgDeleted"), @Type(value = EventType.ChatModified.class, name="ChatModified"), @Type(value = EventType.ChatEphemeralTimerModified.class, name="ChatEphemeralTimerModified"), @Type(value = EventType.ChatDeleted.class, name="ChatDeleted"), @Type(value = EventType.ContactsChanged.class, name="ContactsChanged"), @Type(value = EventType.LocationChanged.class, name="LocationChanged"), @Type(value = EventType.ConfigureProgress.class, name="ConfigureProgress"), @Type(value = EventType.ImexProgress.class, name="ImexProgress"), @Type(value = EventType.ImexFileWritten.class, name="ImexFileWritten"), @Type(value = EventType.SecurejoinInviterProgress.class, name="SecurejoinInviterProgress"), @Type(value = EventType.SecurejoinJoinerProgress.class, name="SecurejoinJoinerProgress"), @Type(value = EventType.ConnectivityChanged.class, name="ConnectivityChanged"), @Type(value = EventType.SelfavatarChanged.class, name="SelfavatarChanged"), @Type(value = EventType.ConfigSynced.class, name="ConfigSynced"), @Type(value = EventType.WebxdcStatusUpdate.class, name="WebxdcStatusUpdate"), @Type(value = EventType.WebxdcRealtimeData.class, name="WebxdcRealtimeData"), @Type(value = EventType.WebxdcRealtimeAdvertisementReceived.class, name="WebxdcRealtimeAdvertisementReceived"), @Type(value = EventType.WebxdcInstanceDeleted.class, name="WebxdcInstanceDeleted"), @Type(value = EventType.AccountsBackgroundFetchDone.class, name="AccountsBackgroundFetchDone"), @Type(value = EventType.ChatlistChanged.class, name="ChatlistChanged"), @Type(value = EventType.ChatlistItemChanged.class, name="ChatlistItemChanged"), @Type(value = EventType.AccountsChanged.class, name="AccountsChanged"), @Type(value = EventType.AccountsItemChanged.class, name="AccountsItemChanged"), @Type(value = EventType.EventChannelOverflow.class, name="EventChannelOverflow"), @Type(value = EventType.IncomingCall.class, name="IncomingCall"), @Type(value = EventType.IncomingCallAccepted.class, name="IncomingCallAccepted"), @Type(value = EventType.OutgoingCallAccepted.class, name="OutgoingCallAccepted"), @Type(value = EventType.CallEnded.class, name="CallEnded"), @Type(value = EventType.TransportsModified.class, name="TransportsModified")})
@JsonSubTypes({@Type(value = EventType.Info.class, name="Info"), @Type(value = EventType.SmtpConnected.class, name="SmtpConnected"), @Type(value = EventType.ImapConnected.class, name="ImapConnected"), @Type(value = EventType.SmtpMessageSent.class, name="SmtpMessageSent"), @Type(value = EventType.ImapMessageDeleted.class, name="ImapMessageDeleted"), @Type(value = EventType.ImapMessageMoved.class, name="ImapMessageMoved"), @Type(value = EventType.ImapInboxIdle.class, name="ImapInboxIdle"), @Type(value = EventType.NewBlobFile.class, name="NewBlobFile"), @Type(value = EventType.DeletedBlobFile.class, name="DeletedBlobFile"), @Type(value = EventType.Warning.class, name="Warning"), @Type(value = EventType.Error.class, name="Error"), @Type(value = EventType.ErrorSelfNotInGroup.class, name="ErrorSelfNotInGroup"), @Type(value = EventType.MsgsChanged.class, name="MsgsChanged"), @Type(value = EventType.ReactionsChanged.class, name="ReactionsChanged"), @Type(value = EventType.IncomingReaction.class, name="IncomingReaction"), @Type(value = EventType.IncomingWebxdcNotify.class, name="IncomingWebxdcNotify"), @Type(value = EventType.IncomingMsg.class, name="IncomingMsg"), @Type(value = EventType.IncomingMsgBunch.class, name="IncomingMsgBunch"), @Type(value = EventType.MsgsNoticed.class, name="MsgsNoticed"), @Type(value = EventType.MsgDelivered.class, name="MsgDelivered"), @Type(value = EventType.MsgFailed.class, name="MsgFailed"), @Type(value = EventType.MsgRead.class, name="MsgRead"), @Type(value = EventType.MsgDeleted.class, name="MsgDeleted"), @Type(value = EventType.ChatModified.class, name="ChatModified"), @Type(value = EventType.ChatEphemeralTimerModified.class, name="ChatEphemeralTimerModified"), @Type(value = EventType.ChatDeleted.class, name="ChatDeleted"), @Type(value = EventType.ContactsChanged.class, name="ContactsChanged"), @Type(value = EventType.LocationChanged.class, name="LocationChanged"), @Type(value = EventType.ConfigureProgress.class, name="ConfigureProgress"), @Type(value = EventType.ImexProgress.class, name="ImexProgress"), @Type(value = EventType.ImexFileWritten.class, name="ImexFileWritten"), @Type(value = EventType.SecurejoinInviterProgress.class, name="SecurejoinInviterProgress"), @Type(value = EventType.SecurejoinJoinerProgress.class, name="SecurejoinJoinerProgress"), @Type(value = EventType.ConnectivityChanged.class, name="ConnectivityChanged"), @Type(value = EventType.SelfavatarChanged.class, name="SelfavatarChanged"), @Type(value = EventType.ConfigSynced.class, name="ConfigSynced"), @Type(value = EventType.WebxdcStatusUpdate.class, name="WebxdcStatusUpdate"), @Type(value = EventType.WebxdcRealtimeData.class, name="WebxdcRealtimeData"), @Type(value = EventType.WebxdcRealtimeAdvertisementReceived.class, name="WebxdcRealtimeAdvertisementReceived"), @Type(value = EventType.WebxdcInstanceDeleted.class, name="WebxdcInstanceDeleted"), @Type(value = EventType.AccountsBackgroundFetchDone.class, name="AccountsBackgroundFetchDone"), @Type(value = EventType.ChatlistChanged.class, name="ChatlistChanged"), @Type(value = EventType.ChatlistItemChanged.class, name="ChatlistItemChanged"), @Type(value = EventType.AccountsChanged.class, name="AccountsChanged"), @Type(value = EventType.AccountsItemChanged.class, name="AccountsItemChanged"), @Type(value = EventType.EventChannelOverflow.class, name="EventChannelOverflow"), @Type(value = EventType.IncomingCall.class, name="IncomingCall"), @Type(value = EventType.IncomingCallAccepted.class, name="IncomingCallAccepted"), @Type(value = EventType.OutgoingCallAccepted.class, name="OutgoingCallAccepted"), @Type(value = EventType.CallEnded.class, name="CallEnded")})
public abstract class EventType {
/**
@@ -409,12 +409,4 @@ public abstract class EventType {
public Integer msg_id;
}
/**
* One or more transports has changed.
* <p>
* This event is used for tests to detect when transport synchronization messages arrives. UIs don't need to use it, it is unlikely that user modifies transports on multiple devices simultaneously.
*/
public static class TransportsModified extends EventType {
}
}
@@ -70,9 +70,6 @@ public class AllMediaDocumentsFragment
this.noMedia = ViewUtil.findById(view, R.id.no_documents);
this.gridManager = new StickyHeaderGridLayoutManager(1);
// add padding to avoid content hidden behind system bars
ViewUtil.applyWindowInsets(recyclerView, true, false, true, true);
this.recyclerView.setAdapter(new AllMediaDocumentsAdapter(getContext(),
new BucketedThreadMediaLoader.BucketedThreadMedia(getContext()),
this));
@@ -66,9 +66,6 @@ public class AllMediaGalleryFragment
this.noMedia = ViewUtil.findById(view, R.id.no_images);
this.gridManager = new StickyHeaderGridLayoutManager(getCols());
// add padding to avoid content hidden behind system bars
ViewUtil.applyWindowInsets(recyclerView, true, false, true, true);
this.recyclerView.setAdapter(new AllMediaGalleryAdapter(getContext(),
GlideApp.with(this),
new BucketedThreadMediaLoader.BucketedThreadMedia(getContext()),
@@ -45,7 +45,6 @@ import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.Prefs;
import org.thoughtcrime.securesms.util.SignalProtocolLoggerProvider;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.webxdc.WebxdcGarbageCollectionWorker;
import java.io.File;
import java.io.PrintWriter;
@@ -241,18 +240,6 @@ public class ApplicationContext extends MultiDexApplication {
ExistingPeriodicWorkPolicy.KEEP,
fetchWorkRequest);
}
PeriodicWorkRequest webxdcGarbageCollectionRequest = new PeriodicWorkRequest.Builder(
WebxdcGarbageCollectionWorker.class,
PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS,
TimeUnit.MILLISECONDS,
PeriodicWorkRequest.MIN_PERIODIC_FLEX_MILLIS,
TimeUnit.MILLISECONDS)
.build();
WorkManager.getInstance(this).enqueueUniquePeriodicWork(
"WebxdcGarbageCollectionWorker",
ExistingPeriodicWorkPolicy.KEEP,
webxdcGarbageCollectionRequest);
}
public JobManager getJobManager() {
@@ -49,7 +49,6 @@ import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.IntentUtils;
import org.thoughtcrime.securesms.util.Prefs;
import org.thoughtcrime.securesms.util.ScreenLockUtil;
import org.thoughtcrime.securesms.util.ViewUtil;
/**
* The Activity for application preference display and management.
@@ -80,9 +79,7 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
//noinspection ConstantConditions
this.getSupportActionBar().setDisplayHomeAsUpEnabled(true);
// add padding to avoid content hidden behind system bars
ViewUtil.applyWindowInsets(findViewById(R.id.fragment));
getSupportActionBar().setElevation(0); // TODO: use custom toolbar instead
if (icicle == null) {
initFragment(R.id.fragment, new ApplicationPreferenceFragment());
@@ -1,6 +1,5 @@
package org.thoughtcrime.securesms;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
@@ -18,7 +17,6 @@ import androidx.fragment.app.Fragment;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.Prefs;
import org.thoughtcrime.securesms.util.ViewUtil;
import java.lang.reflect.Field;
@@ -35,24 +33,9 @@ public abstract class BaseActionBarActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
onPreCreate();
EdgeToEdge.enable(this); // docs says to use: WindowCompat.enableEdgeToEdge(getWindow()); but it is not available
super.onCreate(savedInstanceState);
// Only enable Edge-to-Edge on API 30+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
// docs says to use: WindowCompat.enableEdgeToEdge(getWindow());
// but it actually makes things worse, the next takes care of setting the 3-buttons navigation bar background
EdgeToEdge.enable(this);
// force white text in status bar so it visible over background color
WindowCompat.getInsetsController(getWindow(), getWindow().getDecorView()).setAppearanceLightStatusBars(false);
}
}
@Override
protected void onPostCreate(@Nullable Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// Apply adjustments to the toolbar for edge-to-edge display
ViewUtil.adjustToolbarForE2E(this);
WindowCompat.getInsetsController(getWindow(), getWindow().getDecorView()).setAppearanceLightStatusBars(false); // force white text in status bar
}
@Override
@@ -1,10 +1,10 @@
package org.thoughtcrime.securesms;
import static org.thoughtcrime.securesms.util.ShareUtil.acquireRelayMessageContent;
import static org.thoughtcrime.securesms.util.ShareUtil.getSharedText;
import static org.thoughtcrime.securesms.util.ShareUtil.getSharedUris;
import static org.thoughtcrime.securesms.util.ShareUtil.isForwarding;
import static org.thoughtcrime.securesms.util.ShareUtil.isRelayingMessageContent;
import static org.thoughtcrime.securesms.util.RelayUtil.acquireRelayMessageContent;
import static org.thoughtcrime.securesms.util.RelayUtil.getSharedText;
import static org.thoughtcrime.securesms.util.RelayUtil.getSharedUris;
import static org.thoughtcrime.securesms.util.RelayUtil.isForwarding;
import static org.thoughtcrime.securesms.util.RelayUtil.isRelayingMessageContent;
import android.annotation.SuppressLint;
import android.app.Activity;
@@ -36,7 +36,7 @@ import org.thoughtcrime.securesms.components.registration.PulsingFloatingActionB
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.connect.DirectShareUtil;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.ShareUtil;
import org.thoughtcrime.securesms.util.RelayUtil;
import org.thoughtcrime.securesms.util.SendRelayedMessageUtil;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.task.SnackbarAsyncTask;
@@ -382,7 +382,7 @@ public abstract class BaseConversationListFragment extends Fragment implements A
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
if (isRelayingMessageContent(getActivity())) {
if (ShareUtil.getSharedContactId(getActivity()) != 0) {
if (RelayUtil.getSharedContactId(getActivity()) != 0) {
return false; // no sharing of a contact to multiple recipients at the same time, we can reconsider when that becomes a real-world need
}
Context context = getContext();
@@ -33,6 +33,7 @@ public class BlockedContactsActivity extends PassphraseRequiredActionBarActivity
setContentView(R.layout.activity_blocked_contacts);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setTitle(R.string.pref_blocked_contacts);
getSupportActionBar().setElevation(0); // TODO: use custom toolbar instead
initFragment(R.id.fragment, new BlockedAndShareContactsFragment(), getIntent().getExtras());
}
@@ -59,10 +60,6 @@ public class BlockedContactsActivity extends PassphraseRequiredActionBarActivity
View view = inflater.inflate(R.layout.contact_selection_list_fragment, container, false);
recyclerView = ViewUtil.findById(view, R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
// add padding to avoid content hidden behind system bars
ViewUtil.applyWindowInsets(recyclerView);
emptyStateView = ViewUtil.findById(view, android.R.id.empty);
emptyStateView.setText(R.string.blocked_empty_hint);
return view;
@@ -17,11 +17,15 @@
package org.thoughtcrime.securesms;
import static org.thoughtcrime.securesms.util.ShareUtil.isRelayingMessageContent;
import static org.thoughtcrime.securesms.util.RelayUtil.isRelayingMessageContent;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.util.SparseIntArray;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -47,11 +51,13 @@ import com.b44t.messenger.DcEvent;
import org.thoughtcrime.securesms.connect.DcContactsLoader;
import org.thoughtcrime.securesms.connect.DcEventCenter;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.contacts.ContactAccessor;
import org.thoughtcrime.securesms.contacts.ContactSelectionListAdapter;
import org.thoughtcrime.securesms.contacts.ContactSelectionListItem;
import org.thoughtcrime.securesms.contacts.NewContactActivity;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.qr.QrActivity;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil;
@@ -106,6 +112,13 @@ public class ContactSelectionListFragment extends Fragment
public void onStart() {
super.onStart();
this.getLoaderManager().initLoader(0, null, this);
if (dcContext.getConfigInt("ui.android.show_system_contacts") != 0 && !dcContext.isChatmail()) {
Permissions.with(this)
.request(Manifest.permission.READ_CONTACTS)
.ifNecessary()
.onAllGranted(this::handleContactPermissionGranted)
.execute();
}
}
@Override
@@ -113,10 +126,6 @@ public class ContactSelectionListFragment extends Fragment
View view = inflater.inflate(R.layout.contact_selection_list_fragment, container, false);
recyclerView = ViewUtil.findById(view, R.id.recycler_view);
// add padding to avoid content hidden behind system bars
ViewUtil.applyWindowInsets(recyclerView, true, false, true, true);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
actionModeCallback = new ActionMode.Callback() {
@Override
@@ -274,6 +283,38 @@ public class ContactSelectionListFragment extends Fragment
((ContactSelectionListAdapter) recyclerView.getAdapter()).changeData(null);
}
@SuppressLint("StaticFieldLeak")
private void handleContactPermissionGranted() {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... voids) {
loadSystemContacts();
return null;
}
}.execute();
}
private void loadSystemContacts() {
Thread thread = new Thread() {
@Override
public void run() {
try {
ContactAccessor contactAccessor = ContactAccessor.getInstance();
String allSystemContacts = contactAccessor.getAllSystemContactsAsString(getContext());
if (!allSystemContacts.isEmpty()) {
dcContext.addAddressBook(allSystemContacts);
}
} catch (SecurityException e) {
Log.e(TAG, "Caught a weird bug in the Android OS https://github.com/deltachat/deltachat-android/issues/1639: " + e);
e.printStackTrace();
}
}
};
thread.start();
}
private class ListClickListener implements ContactSelectionListAdapter.ItemClickListener {
@Override
public void onItemClick(ContactSelectionListItem contact, boolean handleActionMode)
@@ -17,9 +17,12 @@
package org.thoughtcrime.securesms;
import static org.thoughtcrime.securesms.TransportOption.Type;
import static org.thoughtcrime.securesms.util.ShareUtil.getSharedText;
import static org.thoughtcrime.securesms.util.ShareUtil.isForwarding;
import static org.thoughtcrime.securesms.util.ShareUtil.isSharing;
import static org.thoughtcrime.securesms.util.RelayUtil.getSharedHtml;
import static org.thoughtcrime.securesms.util.RelayUtil.getSharedSubject;
import static org.thoughtcrime.securesms.util.RelayUtil.getSharedText;
import static org.thoughtcrime.securesms.util.RelayUtil.getSharedType;
import static org.thoughtcrime.securesms.util.RelayUtil.isForwarding;
import static org.thoughtcrime.securesms.util.RelayUtil.isSharing;
import android.Manifest;
import android.annotation.SuppressLint;
@@ -106,7 +109,7 @@ import org.thoughtcrime.securesms.scribbles.ScribbleActivity;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.MediaUtil;
import org.thoughtcrime.securesms.util.Prefs;
import org.thoughtcrime.securesms.util.ShareUtil;
import org.thoughtcrime.securesms.util.RelayUtil;
import org.thoughtcrime.securesms.util.SendRelayedMessageUtil;
import org.thoughtcrime.securesms.util.ServiceUtil;
import org.thoughtcrime.securesms.util.Util;
@@ -745,18 +748,18 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
}
private void handleSharing() {
ArrayList<Uri> uriList = ShareUtil.getSharedUris(this);
int sharedContactId = ShareUtil.getSharedContactId(this);
ArrayList<Uri> uriList = RelayUtil.getSharedUris(this);
int sharedContactId = RelayUtil.getSharedContactId(this);
if (uriList.size() > 1) {
askSendingFiles(uriList, () -> SendRelayedMessageUtil.immediatelyRelay(this, chatId));
} else {
if (sharedContactId != 0) {
addAttachmentContactInfo(sharedContactId);
} else if (ShareUtil.getSharedHtml(this) != null || ShareUtil.getSharedSubject(this) != null || ("sticker".equals(ShareUtil.getSharedType(this)) && !uriList.isEmpty())) {
} else if (getSharedHtml(this) != null || getSharedSubject(this) != null || ("sticker".equals(getSharedType(this)) && !uriList.isEmpty())) {
SendRelayedMessageUtil.immediatelyRelay(this, chatId);
} else {
Uri uri = uriList.isEmpty()? null : uriList.get(0);
dcContext.setDraft(chatId, SendRelayedMessageUtil.createMessage(this, uri, ShareUtil.getSharedType(this), null, null, getSharedText(this)));
dcContext.setDraft(chatId, SendRelayedMessageUtil.createMessage(this, uri, getSharedType(this), null, null, getSharedText(this)));
}
initializeDraft();
}
@@ -772,7 +775,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
isEditing = false;
final SettableFuture<Boolean> future = new SettableFuture<>();
DcMsg draft = dcContext.getDraft(chatId);
final String sharedText = ShareUtil.getSharedText(this);
final String sharedText = RelayUtil.getSharedText(this);
if (!draft.isOk()) {
if (TextUtils.isEmpty(sharedText)) {
@@ -880,11 +883,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
ImageButton quickCameraToggle = ViewUtil.findById(this, R.id.quick_camera_toggle);
// apply padding top to avoid drawing behind top bar
ViewUtil.applyWindowInsets(findViewById(R.id.fragment_content), false, true, false, false);
// apply padding to root to avoid collision with system bars
ViewUtil.applyWindowInsets(findViewById(R.id.root_layout), true, false, true, true);
container.addOnKeyboardShownListener(this);
container.addOnKeyboardHiddenListener(backgroundView);
container.addOnKeyboardShownListener(backgroundView);
@@ -942,6 +940,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
supportActionBar.setCustomView(R.layout.conversation_title_view);
supportActionBar.setDisplayShowCustomEnabled(true);
supportActionBar.setDisplayShowTitleEnabled(false);
supportActionBar.setElevation(0); // TODO: use custom toolbar instead
Toolbar parent = (Toolbar) supportActionBar.getCustomView().getParent();
parent.setPadding(0,0,0,0);
@@ -17,7 +17,7 @@
package org.thoughtcrime.securesms;
import static com.b44t.messenger.DcContact.DC_CONTACT_ID_SELF;
import static org.thoughtcrime.securesms.util.ShareUtil.setForwardingMessageIds;
import static org.thoughtcrime.securesms.util.RelayUtil.setForwardingMessageIds;
import android.annotation.SuppressLint;
import android.app.Activity;
@@ -60,13 +60,13 @@ import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.reactions.AddReactionView;
import org.thoughtcrime.securesms.reactions.ReactionsDetailsFragment;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.relay.EditRelayActivity;
import org.thoughtcrime.securesms.util.AccessibilityUtil;
import org.thoughtcrime.securesms.util.Debouncer;
import org.thoughtcrime.securesms.util.StickyHeaderDecoration;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.views.ConversationAdaptiveActionsToolbar;
import org.thoughtcrime.securesms.calls.CallUtil;
import java.util.Collections;
import java.util.LinkedList;
@@ -785,9 +785,7 @@ public class ConversationFragment extends MessageSelectorFragment
&& messageRecord.getText().contains(self_mail)
&& getListAdapter().getChat().isDeviceTalk()) {
// This is a device message informing the user that the password is wrong
Intent intent = new Intent(getActivity(), EditRelayActivity.class);
intent.putExtra(EditRelayActivity.EXTRA_ADDR, self_mail);
startActivity(intent);
startActivity(new Intent(getActivity(), EditTransportActivity.class));
}
}
}
@@ -20,13 +20,13 @@ import static org.thoughtcrime.securesms.ConversationActivity.CHAT_ID_EXTRA;
import static org.thoughtcrime.securesms.ConversationActivity.STARTING_POSITION_EXTRA;
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_PROXY_ENABLED;
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_PROXY_URL;
import static org.thoughtcrime.securesms.util.ShareUtil.acquireRelayMessageContent;
import static org.thoughtcrime.securesms.util.ShareUtil.getDirectSharingChatId;
import static org.thoughtcrime.securesms.util.ShareUtil.getSharedTitle;
import static org.thoughtcrime.securesms.util.ShareUtil.isDirectSharing;
import static org.thoughtcrime.securesms.util.ShareUtil.isForwarding;
import static org.thoughtcrime.securesms.util.ShareUtil.isRelayingMessageContent;
import static org.thoughtcrime.securesms.util.ShareUtil.resetRelayingMessageContent;
import static org.thoughtcrime.securesms.util.RelayUtil.acquireRelayMessageContent;
import static org.thoughtcrime.securesms.util.RelayUtil.getDirectSharingChatId;
import static org.thoughtcrime.securesms.util.RelayUtil.getSharedTitle;
import static org.thoughtcrime.securesms.util.RelayUtil.isDirectSharing;
import static org.thoughtcrime.securesms.util.RelayUtil.isForwarding;
import static org.thoughtcrime.securesms.util.RelayUtil.isRelayingMessageContent;
import static org.thoughtcrime.securesms.util.RelayUtil.resetRelayingMessageContent;
import android.Manifest;
import android.content.Intent;
@@ -76,7 +76,7 @@ import org.thoughtcrime.securesms.search.SearchFragment;
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.Prefs;
import org.thoughtcrime.securesms.util.ShareUtil;
import org.thoughtcrime.securesms.util.RelayUtil;
import org.thoughtcrime.securesms.util.SaveAttachmentTask;
import org.thoughtcrime.securesms.util.SendRelayedMessageUtil;
import org.thoughtcrime.securesms.util.StorageUtil;
@@ -159,9 +159,6 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
searchAction = findViewById(R.id.search_action);
fragmentContainer = findViewById(R.id.fragment_container);
// add margin to avoid content hidden behind system bars
ViewUtil.applyWindowInsetsAsMargin(searchToolbar, true, true, true, false);
Bundle bundle = new Bundle();
conversationListFragment = initFragment(R.id.fragment_container, new ConversationListFragment(), bundle);
@@ -363,7 +360,7 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
if (isRelayingMessageContent(this)) {
inflater.inflate(R.menu.forwarding_menu, menu);
menu.findItem(R.id.menu_export_attachment).setVisible(
ShareUtil.isFromWebxdc(this) && ShareUtil.getSharedUris(this).size() == 1
RelayUtil.isFromWebxdc(this) && RelayUtil.getSharedUris(this).size() == 1
);
} else {
inflater.inflate(R.menu.text_secure_normal, menu);
@@ -473,7 +470,7 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
}
private void performSave() {
ArrayList<Uri> uriList = ShareUtil.getSharedUris(this);
ArrayList<Uri> uriList = RelayUtil.getSharedUris(this);
Uri uri = uriList.get(0);
String mimeType = PersistentBlobProvider.getMimeType(this, uri);
String fileName = PersistentBlobProvider.getFileName(this, uri);
@@ -2,9 +2,9 @@ package org.thoughtcrime.securesms;
import static org.thoughtcrime.securesms.ConversationActivity.CHAT_ID_EXTRA;
import static org.thoughtcrime.securesms.ConversationActivity.FROM_ARCHIVED_CHATS_EXTRA;
import static org.thoughtcrime.securesms.util.ShareUtil.acquireRelayMessageContent;
import static org.thoughtcrime.securesms.util.ShareUtil.isRelayingMessageContent;
import static org.thoughtcrime.securesms.util.ShareUtil.isSharing;
import static org.thoughtcrime.securesms.util.RelayUtil.acquireRelayMessageContent;
import static org.thoughtcrime.securesms.util.RelayUtil.isRelayingMessageContent;
import static org.thoughtcrime.securesms.util.RelayUtil.isSharing;
import android.content.Intent;
import android.os.Bundle;
@@ -23,6 +23,7 @@ public class ConversationListArchiveActivity extends PassphraseRequiredActionBar
protected void onCreate(Bundle icicle, boolean ready) {
setContentView(R.layout.activity_conversation_list_archive);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setElevation(0); // TODO: use custom toolbar instead
if (isRelayingMessageContent(this)) {
getSupportActionBar().setTitle(isSharing(this) ? R.string.chat_share_with_title : R.string.forward_to);
getSupportActionBar().setSubtitle(R.string.chat_archived_label);
@@ -48,7 +48,7 @@ import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.notifications.FcmReceiveService;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.util.Prefs;
import org.thoughtcrime.securesms.util.ShareUtil;
import org.thoughtcrime.securesms.util.RelayUtil;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil;
@@ -108,9 +108,6 @@ public class ConversationListFragment extends BaseConversationListFragment
emptyState = ViewUtil.findById(view, R.id.empty_state);
emptySearch = ViewUtil.findById(view, R.id.empty_search);
// add padding to avoid content hidden behind system bars
ViewUtil.applyWindowInsets(list, true, archive, true, true);
if (archive) {
fab.setVisibility(View.GONE);
TextView emptyTitle = ViewUtil.findById(view, R.id.empty_title);
@@ -118,8 +115,6 @@ public class ConversationListFragment extends BaseConversationListFragment
} else {
fab.setVisibility(View.VISIBLE);
}
// Apply insets to prevent fab from being covered by system bars
ViewUtil.applyWindowInsetsAsMargin(fab);
list.setHasFixedSize(true);
list.setLayoutManager(new LinearLayoutManager(getActivity()));
@@ -264,7 +259,7 @@ public class ConversationListFragment extends BaseConversationListFragment
int listflags = 0;
if (archive) {
listflags |= DcContext.DC_GCL_ARCHIVED_ONLY;
} else if (ShareUtil.isRelayingMessageContent(getActivity())) {
} else if (RelayUtil.isRelayingMessageContent(getActivity())) {
listflags |= DcContext.DC_GCL_FOR_FORWARDING;
} else {
listflags |= DcContext.DC_GCL_ADD_ALLDONE_HINT;
@@ -79,6 +79,7 @@ public class CreateProfileActivity extends BaseActionBarActivity {
getSupportActionBar().setTitle(R.string.pref_profile_info_headline);
getSupportActionBar().setDisplayHomeAsUpEnabled(!this.fromWelcome);
getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_close_white_24dp);
getSupportActionBar().setElevation(0); // TODO: use custom toolbar instead
attachmentManager = new AttachmentManager(this, () -> {});
avatarChanged = false;
@@ -184,9 +185,6 @@ public class CreateProfileActivity extends BaseActionBarActivity {
this.container = ViewUtil.findById(this, R.id.container);
this.statusView = ViewUtil.findById(this, R.id.status_text);
// add padding to avoid content hidden behind system bars
ViewUtil.applyWindowInsets(container);
if (fromWelcome) {
loginSuccessText.setText(R.string.set_name_and_avatar_explain);
ViewUtil.findById(this, R.id.status_text_layout).setVisibility(View.GONE);
@@ -1,4 +1,4 @@
package org.thoughtcrime.securesms.relay;
package org.thoughtcrime.securesms;
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_PROXY_ENABLED;
import static org.thoughtcrime.securesms.connect.DcHelper.getContext;
@@ -10,7 +10,6 @@ import android.os.Bundle;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.util.Patterns;
import android.view.Menu;
import android.view.MenuInflater;
@@ -33,15 +32,11 @@ import com.b44t.messenger.DcEvent;
import com.b44t.messenger.DcProvider;
import com.google.android.material.textfield.TextInputEditText;
import org.thoughtcrime.securesms.BaseActionBarActivity;
import org.thoughtcrime.securesms.ConversationListActivity;
import org.thoughtcrime.securesms.LogViewActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.WelcomeActivity;
import org.thoughtcrime.securesms.connect.DcEventCenter;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.proxy.ProxySettingsActivity;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.IntentUtils;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil;
@@ -55,7 +50,7 @@ import chat.delta.rpc.types.EnteredCertificateChecks;
import chat.delta.rpc.types.EnteredLoginParam;
import chat.delta.rpc.types.Socket;
public class EditRelayActivity extends BaseActionBarActivity implements DcEventCenter.DcEventDelegate {
public class EditTransportActivity extends BaseActionBarActivity implements DcEventCenter.DcEventDelegate {
private enum VerificationType {
EMAIL,
@@ -63,8 +58,7 @@ public class EditRelayActivity extends BaseActionBarActivity implements DcEventC
PORT,
}
private static final String TAG = EditRelayActivity.class.getSimpleName();
public final static String EXTRA_ADDR = "extra_addr";
private final DynamicTheme dynamicTheme = new DynamicTheme();
private TextInputEditText emailInput;
private TextInputEditText passwordInput;
@@ -91,15 +85,12 @@ public class EditRelayActivity extends BaseActionBarActivity implements DcEventC
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
dynamicTheme.onCreate(this);
rpc = DcHelper.getRpc(this);
accId = DcHelper.getContext(this).getAccountId();
setContentView(R.layout.activity_edittransport);
// add padding to avoid content hidden behind system bars
ViewUtil.applyWindowInsets(findViewById(R.id.content_container));
emailInput = findViewById(R.id.email_text);
passwordInput = findViewById(R.id.password_text);
@@ -127,26 +118,11 @@ public class EditRelayActivity extends BaseActionBarActivity implements DcEventC
startActivity(new Intent(this, ProxySettingsActivity.class));
});
String addr = getIntent().getStringExtra(EXTRA_ADDR);
EnteredLoginParam config = null;
try {
List<EnteredLoginParam> relays = rpc.listTransports(accId);
for (EnteredLoginParam relay : relays) {
if (addr != null && addr.equals(relay.addr)) {
config = relay;
break;
}
}
if (config == null && !relays.isEmpty()) {
Log.e(TAG, "Error got unknown address: " + addr);
finish();
return;
};
} catch (RpcException e) {
Log.e(TAG, "Error calling Rpc.listTransports()", e);
finish();
return;
}
if (!relays.isEmpty()) config = relays.get(0);
} catch (RpcException ignored) {}
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
@@ -155,6 +131,7 @@ public class EditRelayActivity extends BaseActionBarActivity implements DcEventC
);
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeAsUpIndicator(R.drawable.ic_close_white_24dp);
actionBar.setElevation(0); // TODO: use custom toolbar instead
}
if (config != null) emailInput.setEnabled(false);
@@ -238,6 +215,7 @@ public class EditRelayActivity extends BaseActionBarActivity implements DcEventC
@Override
public void onResume() {
super.onResume();
dynamicTheme.onResume(this);
proxySwitch.setChecked(DcHelper.getInt(this, CONFIG_PROXY_ENABLED) == 1);
}
@@ -80,6 +80,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
unencrypted = getIntent().getBooleanExtra(UNENCRYPTED, false);
Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_close_white_24dp);
getSupportActionBar().setElevation(0); // TODO: use custom toolbar instead
groupChatId = getIntent().getIntExtra(EDIT_GROUP_CHAT_ID, 0);
attachmentManager = new AttachmentManager(this, () -> {});
@@ -142,11 +143,6 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
groupName = ViewUtil.findById(this, R.id.group_name);
TextView chatHints = ViewUtil.findById(this, R.id.chat_hints);
// add padding to avoid content hidden behind system bars
ViewUtil.applyWindowInsets(lv, false, false, false, true);
// apply padding to root to avoid collision with system bars
ViewUtil.applyWindowInsets(findViewById(R.id.root_layout), true, false, true, false);
initializeAvatarView();
SelectedContactsAdapter adapter = new SelectedContactsAdapter(this, GlideApp.with(this), broadcast, unencrypted);
@@ -51,12 +51,10 @@ import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.profiles.AvatarHelper;
import org.thoughtcrime.securesms.proxy.ProxySettingsActivity;
import org.thoughtcrime.securesms.qr.RegistrationQrActivity;
import org.thoughtcrime.securesms.relay.EditRelayActivity;
import org.thoughtcrime.securesms.scribbles.ScribbleActivity;
import org.thoughtcrime.securesms.util.IntentUtils;
import org.thoughtcrime.securesms.util.Prefs;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.views.ProgressDialog;
import java.io.File;
@@ -106,6 +104,7 @@ public class InstantOnboardingActivity extends BaseActionBarActivity implements
Objects.requireNonNull(getSupportActionBar()).setTitle(R.string.onboarding_create_instant_account);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setElevation(0); // TODO: use custom toolbar instead
boolean fromWelcome = getIntent().getBooleanExtra(FROM_WELCOME, false);
if (DcHelper.getContext(this).isConfigured() == 1) {
@@ -331,9 +330,6 @@ public class InstantOnboardingActivity extends BaseActionBarActivity implements
this.privacyPolicyBtn = findViewById(R.id.privacy_policy_button);
this.signUpBtn = findViewById(R.id.signup_button);
// add padding to avoid content hidden behind system bars
ViewUtil.applyWindowInsets(findViewById(R.id.container));
privacyPolicyBtn.setOnClickListener(view -> {
if (!isDcLogin) {
IntentUtils.showInBrowser(this, "https://" + providerHost + "/privacy.html");
@@ -346,13 +342,18 @@ public class InstantOnboardingActivity extends BaseActionBarActivity implements
IntentUtils.showInBrowser(this, INSTANCES_URL);
});
findViewById(R.id.login_button).setOnClickListener((v) -> {
startActivity(new Intent(this, EditRelayActivity.class));
startRegistrationActivity();
});
findViewById(R.id.scan_qr_button).setOnClickListener((v) -> {
new IntentIntegrator(this).setCaptureActivity(RegistrationQrActivity.class).initiateScan();
});
}
private void startRegistrationActivity() {
Intent intent = new Intent(this, EditTransportActivity.class);
startActivity(intent);
}
private void updateProvider() {
if (isDcLogin) {
signUpBtn.setText(R.string.login_title);
@@ -36,6 +36,7 @@ public class LogViewActivity extends BaseActionBarActivity {
transaction.commit();
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setElevation(0); // TODO: use custom toolbar instead
}
@Override
@@ -37,11 +37,12 @@ import androidx.annotation.NonNull;
import androidx.core.content.PermissionChecker;
import androidx.fragment.app.Fragment;
import com.b44t.messenger.DcContext;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.notifications.FcmReceiveService;
import org.thoughtcrime.securesms.util.Prefs;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil;
import java.io.BufferedReader;
import java.io.BufferedWriter;
@@ -54,9 +55,6 @@ import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import chat.delta.rpc.Rpc;
import chat.delta.rpc.RpcException;
public class LogViewFragment extends Fragment {
private EditText logPreview;
@@ -79,10 +77,6 @@ public class LogViewFragment extends Fragment {
super.onViewCreated(view, savedInstanceState);
logPreview = (EditText) getView().findViewById(R.id.log_preview);
// add padding to avoid content hidden behind system bars
ViewUtil.applyWindowInsets(getView().findViewById(R.id.content_container), true, false, true, true);
new PopulateLogcatAsyncTask(this).execute();
}
@@ -130,7 +124,10 @@ public class LogViewFragment extends Fragment {
}
private static String grabLogcat(LogViewFragment fragment) {
String command = "logcat -v threadtime -d -t 10000 *:I";
String command = "logcat -v threadtime -d -t 10000";
if (!Prefs.isDeveloperModeEnabled(fragment.getActivity())) {
command += " *:I";
}
try {
final Process process = Runtime.getRuntime().exec(command);
final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
@@ -214,6 +211,7 @@ public class LogViewFragment extends Fragment {
PowerManager powerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
final PackageManager pm = context.getPackageManager();
final StringBuilder builder = new StringBuilder();
final DcContext dcContext = DcHelper.getContext(context);
builder.append("device=")
.append(Build.MANUFACTURER).append(" ")
@@ -268,16 +266,8 @@ public class LogViewFragment extends Fragment {
builder.append("Unknown\n");
}
final Rpc rpc = DcHelper.getRpc(context);
final int accId = DcHelper.getContext(context).getAccountId();
builder.append("\n");
try {
builder.append(rpc.getStorageUsageReportString(accId));
} catch (RpcException e) {
builder.append(e);
}
builder.append(DcHelper.getContext(context).getInfo());
builder.append(dcContext.getInfo());
return builder.toString();
}
@@ -18,8 +18,8 @@ package org.thoughtcrime.securesms;
import static org.thoughtcrime.securesms.ConversationActivity.CHAT_ID_EXTRA;
import static org.thoughtcrime.securesms.ConversationActivity.TEXT_EXTRA;
import static org.thoughtcrime.securesms.util.ShareUtil.acquireRelayMessageContent;
import static org.thoughtcrime.securesms.util.ShareUtil.isRelayingMessageContent;
import static org.thoughtcrime.securesms.util.RelayUtil.acquireRelayMessageContent;
import static org.thoughtcrime.securesms.util.RelayUtil.isRelayingMessageContent;
import android.content.Intent;
import android.net.Uri;
@@ -28,7 +28,7 @@ import org.thoughtcrime.securesms.connect.DcEventCenter;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
import org.thoughtcrime.securesms.util.Prefs;
import org.thoughtcrime.securesms.util.ShareUtil;
import org.thoughtcrime.securesms.util.RelayUtil;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil;
@@ -393,9 +393,9 @@ public class ProfileActivity extends PassphraseRequiredActionBarActivity
Intent composeIntent = new Intent();
DcContact dcContact = dcContext.getContact(contactId);
if (dcContact.isKeyContact()) {
ShareUtil.setSharedContactId(composeIntent, contactId);
RelayUtil.setSharedContactId(composeIntent, contactId);
} else {
ShareUtil.setSharedText(composeIntent, dcContact.getAddr());
RelayUtil.setSharedText(composeIntent, dcContact.getAddr());
}
ConversationListRelayingActivity.start(this, composeIntent);
}
@@ -68,10 +68,6 @@ public class ProfileFragment extends Fragment
adapter = new ProfileAdapter(this, GlideApp.with(this), this);
RecyclerView list = ViewUtil.findById(view, R.id.recycler_view);
// add padding to avoid content hidden behind system bars
ViewUtil.applyWindowInsets(list);
list.setAdapter(adapter);
list.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false));
@@ -39,7 +39,7 @@ import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
import org.thoughtcrime.securesms.util.MailtoUtil;
import org.thoughtcrime.securesms.util.MediaUtil;
import org.thoughtcrime.securesms.util.ShareUtil;
import org.thoughtcrime.securesms.util.RelayUtil;
import java.util.ArrayList;
import java.util.List;
@@ -274,7 +274,7 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity implement
startActivity(composeIntent);
} else {
composeIntent = getBaseShareIntent(ConversationListRelayingActivity.class);
ShareUtil.setIsFromWebxdc(composeIntent, ShareUtil.isFromWebxdc(this));
RelayUtil.setIsFromWebxdc(composeIntent, RelayUtil.isFromWebxdc(this));
ConversationListRelayingActivity.start(this, composeIntent);
}
finish();
@@ -283,11 +283,11 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity implement
private Intent getBaseShareIntent(final @NonNull Class<?> target) {
final Intent intent = new Intent(this, target);
ShareUtil.setSharedTitle(intent, ShareUtil.getSharedTitle(this));
ShareUtil.setSharedType(intent, ShareUtil.getSharedType(this));
ShareUtil.setSharedSubject(intent, ShareUtil.getSharedSubject(this));
ShareUtil.setSharedHtml(intent, ShareUtil.getSharedHtml(this));
ShareUtil.setSharedUris(intent, resolvedExtras);
RelayUtil.setSharedTitle(intent, RelayUtil.getSharedTitle(this));
RelayUtil.setSharedType(intent, RelayUtil.getSharedType(this));
RelayUtil.setSharedSubject(intent, RelayUtil.getSharedSubject(this));
RelayUtil.setSharedHtml(intent, RelayUtil.getSharedHtml(this));
RelayUtil.setSharedUris(intent, resolvedExtras);
String text = getIntent().getStringExtra(Intent.EXTRA_TEXT);
if (text==null) {
@@ -298,7 +298,7 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity implement
}
if (text != null) {
ShareUtil.setSharedText(intent, text.toString());
RelayUtil.setSharedText(intent, text.toString());
}
if (resolvedExtras.size() > 0) {
@@ -26,7 +26,6 @@ import org.thoughtcrime.securesms.qr.QrCodeHandler;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.IntentUtils;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil;
import java.net.IDN;
@@ -38,9 +37,6 @@ public class WebViewActivity extends PassphraseRequiredActionBarActivity
protected WebView webView;
/** Return true the window content should display fullscreen/edge-to-edge ex. in the integrated maps app */
protected boolean immersiveMode() { return false; }
protected boolean shouldAskToOpenLink() { return false; }
protected void toggleFakeProxy(boolean enable) {
@@ -66,18 +62,10 @@ public class WebViewActivity extends PassphraseRequiredActionBarActivity
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setElevation(0); // TODO: use custom toolbar instead
}
webView = findViewById(R.id.webview);
if(immersiveMode()) {
// set a shadow in the status bar to make it more readable
findViewById(R.id.status_bar_background).setBackgroundResource(R.drawable.search_toolbar_shadow);
} else {
// add padding to avoid content hidden behind system bars
ViewUtil.applyWindowInsets(findViewById(R.id.content_container));
}
webView.setWebViewClient(new WebViewClient() {
// IMPORTANT: this is will likely not be called inside iframes unless target=_blank is used in the anchor/link tag.
// `shouldOverrideUrlLoading()` is called when the user clicks a URL,
@@ -91,20 +79,7 @@ public class WebViewActivity extends PassphraseRequiredActionBarActivity
// so, to support all systems, for now, using the old one seems to be the simplest way.
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url != null) {
String schema = url.split(":")[0].toLowerCase();
switch (schema) {
case "http":
case "https":
case "gemini":
case "tel":
case "sms":
case "mailto":
case "openpgp4fpr":
case "geo":
return openOnlineUrl(url);
}
}
if (url != null) return openOnlineUrl(url);
return true; // returning `true` aborts loading
}
@@ -127,6 +127,9 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE
public static void openWebxdcActivity(Context context, int msgId, boolean hideActionBar, String href) {
if (!Util.isClickedRecently()) {
if (Prefs.isDeveloperModeEnabled(context)) {
WebView.setWebContentsDebuggingEnabled(true);
}
context.startActivity(getWebxdcIntent(context, msgId, hideActionBar, href));
}
}
@@ -157,18 +160,14 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE
.getIntents();
}
@Override
protected boolean immersiveMode() { return hideActionBar; }
@Override
protected void onCreate(Bundle state, boolean ready) {
Bundle b = getIntent().getExtras();
hideActionBar = b.getBoolean(EXTRA_HIDE_ACTION_BAR, false);
super.onCreate(state, ready);
rpc = DcHelper.getRpc(this);
initTTS();
Bundle b = getIntent().getExtras();
hideActionBar = b.getBoolean(EXTRA_HIDE_ACTION_BAR, false);
webView.setWebChromeClient(new WebChromeClient() {
@Override
@@ -25,7 +25,6 @@ import org.thoughtcrime.securesms.util.JsonUtils;
import org.thoughtcrime.securesms.util.MediaUtil;
import org.thoughtcrime.securesms.util.Prefs;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil;
import java.io.ByteArrayInputStream;
import java.util.HashMap;
@@ -47,13 +46,11 @@ public class WebxdcStoreActivity extends PassphraseRequiredActionBarActivity {
dcContext = DcHelper.getContext(this);
WebView webView = findViewById(R.id.webview);
// add padding to avoid content hidden behind system bars
ViewUtil.applyWindowInsets(findViewById(R.id.content_container));
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setTitle(R.string.webxdc_apps);
actionBar.setElevation(0); // TODO: use custom toolbar instead
}
webView.setWebViewClient(new WebViewClient() {
@@ -39,7 +39,6 @@ import org.thoughtcrime.securesms.service.NotificationController;
import org.thoughtcrime.securesms.util.StorageUtil;
import org.thoughtcrime.securesms.util.StreamUtil;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.views.ProgressDialog;
import java.io.File;
@@ -64,9 +63,6 @@ public class WelcomeActivity extends BaseActionBarActivity implements DcEventCen
super.onCreate(bundle);
setContentView(R.layout.welcome_activity);
// add padding to avoid content hidden behind system bars
ViewUtil.applyWindowInsets(findViewById(R.id.content_container));
findViewById(R.id.signup_button).setOnClickListener((v) -> startInstantOnboardingActivity());
findViewById(R.id.add_as_second_device_button).setOnClickListener((v) -> startAddAsSecondDeviceActivity());
findViewById(R.id.backup_button).setOnClickListener((v) -> startImportBackup());
@@ -35,7 +35,7 @@ import org.thoughtcrime.securesms.qr.QrActivity;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.FileUtils;
import org.thoughtcrime.securesms.util.MediaUtil;
import org.thoughtcrime.securesms.util.ShareUtil;
import org.thoughtcrime.securesms.util.RelayUtil;
import org.thoughtcrime.securesms.util.Util;
import java.io.File;
@@ -299,17 +299,17 @@ public class DcHelper {
public static void sendToChat(Context activity, byte[] data, String type, String fileName, String html, String subject, String text) {
Intent intent = new Intent(activity, ShareActivity.class);
intent.setAction(Intent.ACTION_SEND);
ShareUtil.setIsFromWebxdc(intent, true);
RelayUtil.setIsFromWebxdc(intent, true);
if (data != null) {
String mimeType = "application/octet-stream";
Uri uri = PersistentBlobProvider.getInstance().create(activity, data, mimeType, fileName);
intent.setType(mimeType);
intent.putExtra(Intent.EXTRA_STREAM, uri);
ShareUtil.setSharedType(intent, type);
ShareUtil.setSharedTitle(intent, activity.getString(R.string.send_file_to, fileName));
RelayUtil.setSharedType(intent, type);
RelayUtil.setSharedTitle(intent, activity.getString(R.string.send_file_to, fileName));
} else {
ShareUtil.setSharedTitle(intent, activity.getString(R.string.send_message_to));
RelayUtil.setSharedTitle(intent, activity.getString(R.string.send_message_to));
}
if (text != null) {
@@ -317,13 +317,13 @@ public class DcHelper {
}
if (subject != null) {
ShareUtil.setSharedSubject(intent, subject);
RelayUtil.setSharedSubject(intent, subject);
}
if (html != null) {
String mimeType = "application/octet-stream";
Uri uri = PersistentBlobProvider.getInstance().create(activity, html.getBytes(), mimeType, "index.html");
ShareUtil.setSharedHtml(intent, uri);
RelayUtil.setSharedHtml(intent, uri);
}
activity.startActivity(intent);
@@ -77,17 +77,11 @@ public class KeepAliveService extends Service {
return null;
}
@Override
public void onDestroy() {
Log.i("DeltaChat", "*** KeepAliveService.onDestroy()");
// the service will be restarted due to START_STICKY automatically, there's nothing more to do.
}
@Override
public void onTimeout(int startId, int fgsType) {
stopSelf();
}
static public KeepAliveService getInstance()
{
return s_this; // may be null
@@ -42,11 +42,9 @@ public class NewContactActivity extends PassphraseRequiredActionBarActivity
actionBar.setTitle(R.string.menu_new_classic_contact);
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeAsUpIndicator(R.drawable.ic_close_white_24dp);
actionBar.setElevation(0); // TODO: use custom toolbar instead
}
// add padding to avoid content hidden behind system bars
ViewUtil.applyWindowInsets(findViewById(R.id.content_container));
nameInput = ViewUtil.findById(this, R.id.name_text);
addrInput = ViewUtil.findById(this, R.id.email_text);
addrInput.setText(getIntent().getStringExtra(ADDR_EXTRA));
@@ -5,9 +5,12 @@ import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.location.Location;
import android.os.Build;
import android.os.IBinder;
import android.util.Log;
import androidx.core.content.ContextCompat;
import org.thoughtcrime.securesms.connect.DcHelper;
import java.util.LinkedList;
@@ -23,11 +26,13 @@ public class DcLocationManager implements Observer {
private final Context context;
private DcLocation dcLocation = DcLocation.getInstance();
private final LinkedList<Integer> pendingShareLastLocation = new LinkedList<>();
private boolean serviceBound = false;
private final ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(TAG, "background service connected");
serviceBinder = (LocationBackgroundService.LocationBackgroundServiceBinder) service;
serviceBound = true;
while (!pendingShareLastLocation.isEmpty()) {
shareLastLocation(pendingShareLastLocation.pop());
}
@@ -37,6 +42,7 @@ public class DcLocationManager implements Observer {
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG, "background service disconnected");
serviceBinder = null;
serviceBound = false;
}
};
@@ -49,19 +55,29 @@ public class DcLocationManager implements Observer {
}
public void startLocationEngine() {
if (serviceBinder == null) {
if (serviceBinder == null || !serviceBound) {
Intent intent = new Intent(context.getApplicationContext(), LocationBackgroundService.class);
// Start as foreground service
ContextCompat.startForegroundService(context, intent);
// Then bind to it
context.bindService(intent, serviceConnection, BIND_AUTO_CREATE);
}
}
public void stopLocationEngine() {
if (serviceBinder == null) {
if (serviceBinder == null || !serviceBound) {
return;
}
context.unbindService(serviceConnection);
serviceBinder.stop();
try {
context.unbindService(serviceConnection);
if (serviceBinder != null) {
serviceBinder.stop();
}
} catch (IllegalArgumentException e) {
Log.w(TAG, "Service not registered", e);
}
serviceBinder = null;
serviceBound = false;
}
public void stopSharingLocation(int chatId) {
@@ -1,18 +1,36 @@
package org.thoughtcrime.securesms.geolocation;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.ServiceInfo;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Binder;
import android.os.Bundle;
import android.os.Build;
import android.os.IBinder;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.core.app.NotificationCompat;
import androidx.core.app.ServiceCompat;
import androidx.core.content.ContextCompat;
import androidx.core.location.LocationListenerCompat;
import androidx.core.location.LocationManagerCompat;
import androidx.core.location.LocationRequestCompat;
import org.thoughtcrime.securesms.ConversationListActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.notifications.NotificationCenter;
import org.thoughtcrime.securesms.util.IntentUtils;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
public class LocationBackgroundService extends Service {
@@ -22,6 +40,7 @@ public class LocationBackgroundService extends Service {
private static final int LOCATION_INTERVAL = 1000;
private static final float LOCATION_DISTANCE = 25F;
ServiceLocationListener locationListener;
private final AtomicBoolean isForeground = new AtomicBoolean(false);
private final IBinder mBinder = new LocationBackgroundServiceBinder();
@@ -37,12 +56,21 @@ public class LocationBackgroundService extends Service {
@Override
public void onCreate() {
super.onCreate();
locationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
if (locationManager == null) {
Log.e(TAG, "Unable to initialize location service");
// Must start foreground to avoid crash, then stop immediately
initializeForegroundService();
stopForeground(true);
stopSelf();
return;
}
// Initialize foreground service after successful location manager setup
initializeForegroundService();
locationListener = new ServiceLocationListener();
Location lastLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (lastLocation != null) {
@@ -51,14 +79,19 @@ public class LocationBackgroundService extends Service {
DcLocation.getInstance().updateLocation(lastLocation);
}
}
//requestLocationUpdate(LocationManager.NETWORK_PROVIDER);
// Request location updates from both GPS and network providers for better coverage
requestLocationUpdate(LocationManager.GPS_PROVIDER);
requestLocationUpdate(LocationManager.NETWORK_PROVIDER);
initialLocationUpdate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
// Ensure foreground notification is shown (handles edge cases)
initializeForegroundService();
return START_STICKY;
}
@@ -66,23 +99,93 @@ public class LocationBackgroundService extends Service {
public void onDestroy() {
super.onDestroy();
if (locationManager == null) {
// Stop foreground notification
stopForeground(true);
if (locationManager == null || locationListener == null) {
return;
}
try {
locationManager.removeUpdates(locationListener);
LocationManagerCompat.removeUpdates(locationManager, locationListener);
} catch (Exception ex) {
Log.i(TAG, "fail to remove location listeners, ignore", ex);
}
}
private void initializeForegroundService() {
if (isForeground.compareAndSet(false, true)) {
createNotificationChannel();
Notification notification = createNotification();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
// Android 14+ requires foregroundServiceType in startForeground
ServiceCompat.startForeground(this, NotificationCenter.ID_LOCATION, notification,
ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION);
} else {
startForeground(NotificationCenter.ID_LOCATION, notification);
}
Log.d(TAG, "Foreground service started with notification");
}
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
NotificationCenter.CH_LOCATION,
getString(R.string.location),
NotificationManager.IMPORTANCE_LOW
);
channel.setDescription("Location sharing notification");
NotificationManager notificationManager = getSystemService(NotificationManager.class);
if (notificationManager != null) {
notificationManager.createNotificationChannel(channel);
}
}
}
private Notification createNotification() {
Intent intent = new Intent(this, ConversationListActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(
this,
0,
intent,
IntentUtils.FLAG_IMMUTABLE()
);
return new NotificationCompat.Builder(this, NotificationCenter.CH_LOCATION)
.setContentTitle(getString(R.string.location_sharing_notification_title))
.setContentText(getString(R.string.location_sharing_notification_text))
.setSmallIcon(R.drawable.ic_location_on_white_24dp)
.setContentIntent(pendingIntent)
.setOngoing(true)
.setPriority(NotificationCompat.PRIORITY_LOW)
.build();
}
private void requestLocationUpdate(String provider) {
try {
locationManager.requestLocationUpdates(
provider, LOCATION_INTERVAL, LOCATION_DISTANCE,
locationListener);
} catch (SecurityException | IllegalArgumentException ex) {
// Check if provider is available
if (!locationManager.isProviderEnabled(provider)) {
Log.w(TAG, String.format("Provider %s is not enabled", provider));
return;
}
// Use LocationManagerCompat for better compatibility with modern Android
LocationRequestCompat locationRequest = new LocationRequestCompat.Builder(LOCATION_INTERVAL)
.setMinUpdateDistanceMeters(LOCATION_DISTANCE)
.setQuality(LocationRequestCompat.QUALITY_HIGH_ACCURACY)
.build();
Executor executor = ContextCompat.getMainExecutor(this);
LocationManagerCompat.requestLocationUpdates(
locationManager,
provider,
locationRequest,
executor,
locationListener
);
Log.d(TAG, String.format("Requested location updates from %s provider", provider));
} catch (SecurityException | IllegalArgumentException ex) {
Log.e(TAG, String.format("Unable to request %s provider based location updates.", provider), ex);
}
}
@@ -93,9 +196,16 @@ public class LocationBackgroundService extends Service {
if (gpsLocation != null && System.currentTimeMillis() - gpsLocation.getTime() < INITIAL_TIMEOUT) {
locationListener.onLocationChanged(gpsLocation);
}
// Also try network provider for initial location
Location networkLocation = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
if (networkLocation != null && System.currentTimeMillis() - networkLocation.getTime() < INITIAL_TIMEOUT) {
// Use network location if GPS location is not available or network location is newer
if (gpsLocation == null || networkLocation.getTime() > gpsLocation.getTime()) {
locationListener.onLocationChanged(networkLocation);
}
}
} catch (NullPointerException | SecurityException e) {
e.printStackTrace();
Log.e(TAG, "Error getting initial location", e);
}
}
@@ -110,30 +220,22 @@ public class LocationBackgroundService extends Service {
}
}
private class ServiceLocationListener implements LocationListener {
private class ServiceLocationListener implements LocationListenerCompat {
@Override
public void onLocationChanged(@NonNull Location location) {
Log.d(TAG, "onLocationChanged: " + location);
if (location == null) {
return;
}
DcLocation.getInstance().updateLocation(location);
}
@Override
public void onProviderDisabled(@NonNull String provider) {
Log.e(TAG, "onProviderDisabled: " + provider);
Log.w(TAG, "onProviderDisabled: " + provider);
}
@Override
public void onProviderEnabled(@NonNull String provider) {
Log.e(TAG, "onProviderEnabled: " + provider);
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
Log.e(TAG, "onStatusChanged: " + provider + " status: " + status);
Log.d(TAG, "onProviderEnabled: " + provider);
}
}
@@ -484,7 +484,7 @@ public class AttachmentManager {
// for rationale dialog requirements
Permissions.PermissionsBuilder permissionsBuilder = Permissions.with(activity)
.ifNecessary()
.withRationaleDialog("To share your live location with chat members, allow ArcaneChat to use your location data.\n\nTo make live location work gaplessly, location data is used even when the app is closed or not in use.", R.drawable.ic_location_on_white_24dp)
.withRationaleDialog("To share your live location with chat members, allow ArcaneChat to use your location data.", R.drawable.ic_location_on_white_24dp)
.withPermanentDenialDialog(activity.getString(R.string.perm_explain_access_to_location_denied))
.onAllGranted(() -> {
ShareLocationDialog.show(activity, durationInSeconds -> {
@@ -495,11 +495,7 @@ public class AttachmentManager {
}
});
});
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
permissionsBuilder.request(Manifest.permission.ACCESS_BACKGROUND_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION);
} else {
permissionsBuilder.request(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION);
}
permissionsBuilder.request(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION);
permissionsBuilder.execute();
}
@@ -218,6 +218,7 @@ public class NotificationCenter {
public static final int ID_MSG_SUMMARY = 2;
public static final int ID_GENERIC = 3;
public static final int ID_FETCH = 4;
public static final int ID_LOCATION = 5;
public static final int ID_MSG_OFFSET = 0; // msgId is added - as msgId start at 10, there are no conflicts with lower numbers
@@ -243,6 +244,7 @@ public class NotificationCenter {
public static final String CH_MSG_VERSION = "5";
public static final String CH_PERMANENT = "dc_fg_notification_ch";
public static final String CH_GENERIC = "ch_generic";
public static final String CH_LOCATION = "ch_location";
public static final String CH_CALLS_PREFIX = "call_chan";
private boolean notificationChannelsSupported() {
@@ -7,7 +7,9 @@ import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_MVBOX_MOVE;
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_ONLY_FETCH_MVBOX;
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_SHOW_EMAILS;
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_WEBXDC_REALTIME_ENABLED;
import static org.thoughtcrime.securesms.connect.DcHelper.getRpc;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -15,6 +17,7 @@ import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.webkit.WebView;
import android.widget.EditText;
import androidx.annotation.NonNull;
@@ -25,10 +28,12 @@ import androidx.preference.ListPreference;
import androidx.preference.Preference;
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
import org.thoughtcrime.securesms.ConversationActivity;
import org.thoughtcrime.securesms.LogViewActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.relay.RelayListActivity;
import org.thoughtcrime.securesms.EditTransportActivity;
import org.thoughtcrime.securesms.connect.DcEventCenter;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.proxy.ProxySettingsActivity;
import org.thoughtcrime.securesms.util.Prefs;
import org.thoughtcrime.securesms.util.ScreenLockUtil;
@@ -42,6 +47,8 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.util.Objects;
import chat.delta.rpc.RpcException;
public class AdvancedPreferenceFragment extends ListSummaryPreferenceFragment
implements DcEventCenter.DcEventDelegate
@@ -138,6 +145,14 @@ public class AdvancedPreferenceFragment extends ListSummaryPreferenceFragment
}
updateWebxdcStoreSummary();
Preference developerModeEnabled = this.findPreference("pref_developer_mode_enabled");
if (developerModeEnabled != null) {
developerModeEnabled.setOnPreferenceChangeListener((preference, newValue) -> {
WebView.setWebContentsDebuggingEnabled((Boolean) newValue);
return true;
});
}
Preference proxySettings = this.findPreference("proxy_settings_button");
if (proxySettings != null) {
proxySettings.setOnPreferenceClickListener((preference) -> {
@@ -146,19 +161,21 @@ public class AdvancedPreferenceFragment extends ListSummaryPreferenceFragment
});
}
Preference relayListBtn = this.findPreference("pref_relay_list_button");
if (relayListBtn != null) {
relayListBtn.setOnPreferenceClickListener(((preference) -> {
boolean result = ScreenLockUtil.applyScreenLock(requireActivity(), getString(R.string.transports), getString(R.string.enter_system_secret_to_continue), REQUEST_CODE_CONFIRM_CREDENTIALS_ACCOUNT);
Preference passwordAndAccount = this.findPreference("password_account_settings_button");
if (passwordAndAccount != null) {
passwordAndAccount.setOnPreferenceClickListener(((preference) -> {
boolean result = ScreenLockUtil.applyScreenLock(requireActivity(), getString(R.string.edit_transport), getString(R.string.enter_system_secret_to_continue), REQUEST_CODE_CONFIRM_CREDENTIALS_ACCOUNT);
if (!result) {
openRelayListActivity();
openRegistrationActivity();
}
return true;
}));
}
if (dcContext.isChatmail()) {
findPreference("pref_category_legacy").setVisible(false);
showEmails.setVisible(false);
mvboxMoveCheckbox.setVisible(false);
onlyFetchMvboxCheckbox.setVisible(false);
}
}
@@ -186,7 +203,7 @@ public class AdvancedPreferenceFragment extends ListSummaryPreferenceFragment
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && requestCode == REQUEST_CODE_CONFIRM_CREDENTIALS_ACCOUNT) {
openRelayListActivity();
openRegistrationActivity();
}
}
@@ -253,8 +270,8 @@ public class AdvancedPreferenceFragment extends ListSummaryPreferenceFragment
}
}
private void openRelayListActivity() {
Intent intent = new Intent(requireActivity(), RelayListActivity.class);
private void openRegistrationActivity() {
Intent intent = new Intent(requireActivity(), EditTransportActivity.class);
startActivity(intent);
}
@@ -70,7 +70,9 @@ public class ChatBackgroundActivity extends PassphraseRequiredActionBarActivity
actionBar.setTitle(R.string.pref_background);
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeAsUpIndicator(R.drawable.ic_close_white_24dp);
actionBar.setElevation(0); // TODO: use custom toolbar instead
}
}
@Override
@@ -30,6 +30,7 @@ public class PrivacyPreferenceFragment extends ListSummaryPreferenceFragment {
private static final String TAG = PrivacyPreferenceFragment.class.getSimpleName();
private CheckBoxPreference readReceiptsCheckbox;
private CheckBoxPreference showSystemContacts;
private ListPreference autoDelDevice;
private ListPreference autoDelServer;
@@ -38,6 +39,13 @@ public class PrivacyPreferenceFragment extends ListSummaryPreferenceFragment {
public void onCreate(Bundle paramBundle) {
super.onCreate(paramBundle);
showSystemContacts = (CheckBoxPreference) this.findPreference("pref_show_system_contacts");
showSystemContacts.setOnPreferenceChangeListener((preference, newValue) -> {
boolean enabled = (Boolean) newValue;
dcContext.setConfigInt("ui.android.show_system_contacts", enabled? 1 : 0);
return true;
});
readReceiptsCheckbox = (CheckBoxPreference) this.findPreference("pref_read_receipts");
readReceiptsCheckbox.setOnPreferenceChangeListener(new ReadReceiptToggleListener());
@@ -54,6 +62,10 @@ public class PrivacyPreferenceFragment extends ListSummaryPreferenceFragment {
Preference screenSecurity = this.findPreference(Prefs.SCREEN_SECURITY_PREF);
screenSecurity.setOnPreferenceChangeListener(new ScreenShotSecurityListener());
if (dcContext.isChatmail()) {
showSystemContacts.setVisible(false);
}
}
@Override
@@ -66,6 +78,7 @@ public class PrivacyPreferenceFragment extends ListSummaryPreferenceFragment {
super.onResume();
((ApplicationPreferencesActivity)getActivity()).getSupportActionBar().setTitle(R.string.pref_privacy);
showSystemContacts.setChecked(0!=dcContext.getConfigInt("ui.android.show_system_contacts"));
readReceiptsCheckbox.setChecked(0 != dcContext.getConfigInt("mdns_enabled"));
initAutodelFromCore();
}
@@ -28,37 +28,35 @@ import org.thoughtcrime.securesms.BaseActionBarActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.connect.DcEventCenter;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil;
import java.util.LinkedList;
public class ProxySettingsActivity extends BaseActionBarActivity
implements ProxyListAdapter.ItemClickListener, DcEventCenter.DcEventDelegate {
private final DynamicTheme dynamicTheme = new DynamicTheme();
private SwitchCompat proxySwitch;
private ProxyListAdapter adapter;
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
dynamicTheme.onCreate(this);
setContentView(R.layout.proxy_settings_activity);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setTitle(R.string.proxy_settings);
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setElevation(0); // TODO: use custom toolbar instead
}
proxySwitch = findViewById(R.id.proxy_switch);
ListView proxyList = findViewById(R.id.proxy_list);
ViewUtil.applyWindowInsets(proxySwitch, true, false, true, false);
ViewUtil.applyWindowInsets(proxyList, true, false, true, true);
adapter = new ProxyListAdapter(this);
adapter.setItemClickListener(this);
proxySwitch = findViewById(R.id.proxy_switch);
proxySwitch.setChecked(DcHelper.getInt(this, CONFIG_PROXY_ENABLED) == 1);
proxySwitch.setOnClickListener(l -> {
if (proxySwitch.isChecked() && adapter.getCount() == 0) {
@@ -69,6 +67,7 @@ public class ProxySettingsActivity extends BaseActionBarActivity
}
});
ListView proxyList = findViewById(R.id.proxy_list);
proxyList.setAdapter(adapter);
proxyList.addHeaderView(View.inflate(this, R.layout.proxy_list_header, null), null, false);
View footer = View.inflate(this, R.layout.proxy_list_footer, null);
@@ -86,6 +85,12 @@ public class ProxySettingsActivity extends BaseActionBarActivity
handleOpenProxyUrl();
}
@Override
public void onResume() {
super.onResume();
dynamicTheme.onResume(this);
}
@Override
public void onDestroy() {
super.onDestroy();
@@ -24,7 +24,6 @@ import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.service.GenericForegroundService;
import org.thoughtcrime.securesms.service.NotificationController;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil;
public class BackupTransferActivity extends BaseActionBarActivity {
@@ -86,9 +85,7 @@ public class BackupTransferActivity extends BaseActionBarActivity {
supportActionBar.setDisplayHomeAsUpEnabled(true);
supportActionBar.setHomeAsUpIndicator(R.drawable.ic_close_white_24dp);
supportActionBar.setTitle(title);
// add padding to avoid content hidden behind system bars
ViewUtil.applyWindowInsets(findViewById(R.id.backup_provider_fragment));
supportActionBar.setElevation(0); // TODO: use custom toolbar instead
}
@Override
@@ -44,8 +44,6 @@ import java.io.InputStream;
public class QrActivity extends BaseActionBarActivity implements View.OnClickListener {
private final static String TAG = QrActivity.class.getSimpleName();
public final static String EXTRA_SCAN_RELAY = "scan_relay";
private final static int REQUEST_CODE_IMAGE = 46243;
private final static int TAB_SHOW = 0;
private final static int TAB_SCAN = 1;
@@ -53,7 +51,6 @@ public class QrActivity extends BaseActionBarActivity implements View.OnClickLis
private TabLayout tabLayout;
private ViewPager viewPager;
private QrShowFragment qrShowFragment;
private boolean scanRelay;
@Override
protected void onPreCreate() {
@@ -64,10 +61,8 @@ public class QrActivity extends BaseActionBarActivity implements View.OnClickLis
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_qr);
scanRelay = getIntent().getBooleanExtra(EXTRA_SCAN_RELAY, false);
qrShowFragment = new QrShowFragment(this);
tabLayout = ViewUtil.findById(this, R.id.tab_layout);
viewPager = ViewUtil.findById(this, R.id.pager);
@@ -76,11 +71,10 @@ public class QrActivity extends BaseActionBarActivity implements View.OnClickLis
setSupportActionBar(ViewUtil.findById(this, R.id.toolbar));
assert getSupportActionBar() != null;
getSupportActionBar().setTitle(scanRelay? R.string.add_transport : R.string.menu_new_contact);
getSupportActionBar().setTitle(R.string.menu_new_contact);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
viewPager.setCurrentItem(scanRelay? TAB_SCAN : TAB_SHOW);
if (scanRelay) tabLayout.setVisibility(View.GONE);
viewPager.setCurrentItem(TAB_SHOW);
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
@@ -108,13 +102,7 @@ public class QrActivity extends BaseActionBarActivity implements View.OnClickLis
.ifNecessary()
.withPermanentDenialDialog(getString(R.string.perm_explain_access_to_camera_denied))
.onAllGranted(() -> ((QrScanFragment) adapter.getItem(TAB_SCAN)).handleQrScanWithPermissions(QrActivity.this))
.onAnyDenied(() -> {
if (scanRelay) {
finish();
} else {
viewPager.setCurrentItem(TAB_SHOW);
}
})
.onAnyDenied(() -> viewPager.setCurrentItem(TAB_SHOW))
.execute();
}
}
@@ -161,11 +149,7 @@ public class QrActivity extends BaseActionBarActivity implements View.OnClickLis
if (permissions.length > 0
&& Manifest.permission.CAMERA.equals(permissions[0])
&& grantResults[0] == PackageManager.PERMISSION_DENIED) {
if (scanRelay) {
finish();
} else {
viewPager.setCurrentItem(TAB_SHOW);
}
viewPager.setCurrentItem(TAB_SHOW);
// Workaround because sometimes something else requested the permissions before this class
// (probably the CameraView) and then this class didn't notice when it was denied
}
@@ -1,9 +1,7 @@
package org.thoughtcrime.securesms.qr;
import android.app.Activity;
import android.content.DialogInterface;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.StringRes;
@@ -19,25 +17,15 @@ import org.thoughtcrime.securesms.connect.AccountManager;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.util.IntentUtils;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.views.ProgressDialog;
import chat.delta.rpc.Rpc;
import chat.delta.rpc.RpcException;
public class QrCodeHandler {
private static final String TAG = QrCodeHandler.class.getSimpleName();
private final Activity activity;
private final DcContext dcContext;
private final Rpc rpc;
private final int accId;
public QrCodeHandler(Activity activity) {
this.activity = activity;
dcContext = DcHelper.getContext(activity);
rpc = DcHelper.getRpc(activity);
accId = dcContext.getAccountId();
}
public void onScanPerformed(IntentResult scanResult) {
@@ -79,7 +67,10 @@ public class QrCodeHandler {
case DcContext.DC_QR_ACCOUNT:
case DcContext.DC_QR_LOGIN:
final String scope = qrParsed.getText1();
setAddTransportDialog(activity, builder, rawString, scope);
builder.setMessage(activity.getString(qrParsed.getState() == DcContext.DC_QR_ACCOUNT ? R.string.qraccount_ask_create_and_login_another : R.string.qrlogin_ask_login_another, scope));
builder.setPositiveButton(R.string.ok, (dialog, which) -> {
AccountManager.getInstance().addAccountFromQr(activity, rawString);
});
builder.setNegativeButton(R.string.cancel, null);
builder.setCancelable(false);
break;
@@ -255,43 +246,4 @@ public class QrCodeHandler {
});
builder.setNegativeButton(android.R.string.cancel, null);
}
private void setAddTransportDialog(Activity activity, AlertDialog.Builder builder, String qrData, String transportName) {
builder.setTitle(R.string.confirm_add_transport);
builder.setMessage(transportName);
builder.setPositiveButton(R.string.ok, (d, w) -> {
ProgressDialog progressDialog = new ProgressDialog(activity);
progressDialog.setMessage(activity.getResources().getString(R.string.one_moment));
progressDialog.setCanceledOnTouchOutside(false);
progressDialog.setCancelable(false);
String cancel = activity.getResources().getString(android.R.string.cancel);
progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, cancel, (d2, w2) -> {
dcContext.stopOngoingProcess();
});
progressDialog.show();
Util.runOnAnyBackgroundThread(() -> {
String error = null;
try {
rpc.addTransportFromQr(accId, qrData);
} catch (RpcException e) {
Log.w(TAG, e);
error = e.getMessage();
}
final String finalError = error;
Util.runOnMain(() -> {
if (!progressDialog.isShowing()) return; // canceled dialog, nothing to do
if (finalError != null) {
Toast.makeText(activity, finalError, Toast.LENGTH_LONG).show();
}
try {
progressDialog.dismiss();
} catch (IllegalArgumentException e) {
// see https://stackoverflow.com/a/5102572/4557005
Log.w(TAG, e);
}
});
});
});
}
}
@@ -18,7 +18,6 @@ import com.journeyapps.barcodescanner.CompoundBarcodeView;
import com.journeyapps.barcodescanner.DecoratedBarcodeView;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.util.ViewUtil;
public class QrScanFragment extends Fragment {
@@ -39,9 +38,6 @@ public class QrScanFragment extends Fragment {
barcodeScannerView = view.findViewById(R.id.zxing_barcode_scanner);
barcodeScannerView.setStatusText(getString(R.string.qrscan_hint) + "\n ");
// add padding to avoid content hidden behind system bars
ViewUtil.applyWindowInsets(barcodeScannerView.getStatusView());
return view;
}
@@ -5,17 +5,19 @@ import android.view.Menu;
import android.view.MenuItem;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import com.b44t.messenger.DcContext;
import org.thoughtcrime.securesms.BaseActionBarActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.connect.DcEventCenter;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil;
public class QrShowActivity extends BaseActionBarActivity {
public class QrShowActivity extends AppCompatActivity {
private final DynamicTheme dynamicTheme = new DynamicTheme();
public final static String CHAT_ID = "chat_id";
@@ -27,13 +29,11 @@ public class QrShowActivity extends BaseActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
dynamicTheme.onCreate(this);
setContentView(R.layout.activity_qr_show);
fragment = (QrShowFragment)getSupportFragmentManager().findFragmentById(R.id.qrScannerFragment);
// add padding to avoid content hidden behind system bars
ViewUtil.applyWindowInsets(findViewById(R.id.qrScannerFragment), false, true, false, false);
dcContext = DcHelper.getContext(this);
dcEventCenter = DcHelper.getEventCenter(this);
@@ -74,6 +74,12 @@ public class QrShowActivity extends BaseActionBarActivity {
return super.onCreateOptionsMenu(menu);
}
@Override
protected void onResume() {
super.onResume();
dynamicTheme.onResume(this);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
super.onOptionsItemSelected(item);
@@ -19,7 +19,6 @@ import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil;
public class RegistrationQrActivity extends BaseActionBarActivity {
@@ -43,9 +42,7 @@ public class RegistrationQrActivity extends BaseActionBarActivity {
getSupportActionBar().setTitle(R.string.scan_invitation_code);
}
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
// add padding to avoid content hidden behind system bars
ViewUtil.applyWindowInsets(findViewById(R.id.layout_container), true, false, true, true);
getSupportActionBar().setElevation(0); // TODO: use custom toolbar instead
barcodeScannerView = findViewById(R.id.zxing_barcode_scanner);
barcodeScannerView.setStatusText(getString(R.string.qrscan_hint) + "\n ");
@@ -1,180 +0,0 @@
package org.thoughtcrime.securesms.relay;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.MenuItem;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.b44t.messenger.DcContext;
import com.b44t.messenger.DcEvent;
import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentResult;
import org.thoughtcrime.securesms.BaseActionBarActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.registration.PulsingFloatingActionButton;
import org.thoughtcrime.securesms.connect.DcEventCenter;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.qr.QrActivity;
import org.thoughtcrime.securesms.qr.QrCodeHandler;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil;
import java.util.List;
import chat.delta.rpc.Rpc;
import chat.delta.rpc.RpcException;
import chat.delta.rpc.types.EnteredLoginParam;
public class RelayListActivity extends BaseActionBarActivity
implements RelayListAdapter.OnRelayClickListener, DcEventCenter.DcEventDelegate {
private static final String TAG = RelayListActivity.class.getSimpleName();
private RelayListAdapter adapter;
private Rpc rpc;
private int accId;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_relay_list);
rpc = DcHelper.getRpc(this);
accId = DcHelper.getContext(this).getAccountId();
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setTitle(R.string.transports);
actionBar.setDisplayHomeAsUpEnabled(true);
}
RecyclerView recyclerView = findViewById(R.id.relay_list);
PulsingFloatingActionButton fabAdd = findViewById(R.id.fab_add_relay);
// add padding to avoid content hidden behind system bars
ViewUtil.applyWindowInsets(recyclerView);
// Apply insets to prevent fab from being covered by system bars
ViewUtil.applyWindowInsetsAsMargin(fabAdd);
fabAdd.setOnClickListener(v -> {
new IntentIntegrator(this).setCaptureActivity(QrActivity.class).addExtra(QrActivity.EXTRA_SCAN_RELAY, true).initiateScan();
});
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
// Add the default divider (uses the themes `android.R.attr.listDivider`)
DividerItemDecoration divider = new DividerItemDecoration(
recyclerView.getContext(),
layoutManager.getOrientation());
recyclerView.addItemDecoration(divider);
recyclerView.setLayoutManager(layoutManager);
adapter = new RelayListAdapter(this);
recyclerView.setAdapter(adapter);
loadRelays();
DcEventCenter eventCenter = DcHelper.getEventCenter(this);
eventCenter.addObserver(DcContext.DC_EVENT_CONFIGURE_PROGRESS, this);
}
@Override
public void onDestroy() {
super.onDestroy();
DcHelper.getEventCenter(this).removeObservers(this);
}
private void loadRelays() {
Util.runOnAnyBackgroundThread(() -> {
String mainRelayAddr = "";
try {
mainRelayAddr = rpc.getConfig(accId, DcHelper.CONFIG_CONFIGURED_ADDRESS);
} catch (RpcException e) {
Log.e(TAG, "RPC.getConfig() failed", e);
}
String finalMainRelayAddr = mainRelayAddr;
try {
List<EnteredLoginParam> relays = rpc.listTransports(accId);
Util.runOnMain(() -> adapter.setRelays(relays, finalMainRelayAddr));
} catch (RpcException e) {
Log.e(TAG, "RPC.listTransports() failed", e);
Util.runOnMain(() -> adapter.setRelays(null, finalMainRelayAddr));
}
});
}
@Override
public void onRelayClick(EnteredLoginParam relay) {
if (relay.addr != null && !relay.addr.equals(adapter.getMainRelay())) {
Util.runOnAnyBackgroundThread(() -> {
try {
rpc.setConfig(accId, DcHelper.CONFIG_CONFIGURED_ADDRESS, relay.addr);
} catch (RpcException e) {
Log.e(TAG, "RPC.setConfig() failed", e);
}
loadRelays();
});
}
}
@Override
public void onRelayEdit(EnteredLoginParam relay) {
Intent intent = new Intent(this, EditRelayActivity.class);
intent.putExtra(EditRelayActivity.EXTRA_ADDR, relay.addr);
startActivity(intent);
}
@Override
public void onRelayDelete(EnteredLoginParam relay) {
new AlertDialog.Builder(this)
.setTitle(R.string.remove_transport)
.setMessage(getString(R.string.confirm_remove_transport, relay.addr))
.setPositiveButton(R.string.ok, (dialog, which) -> {
try {
rpc.deleteTransport(accId, relay.addr);
loadRelays();
} catch (RpcException e) {
Log.e(TAG, "RPC.deleteTransport() failed", e);
}
})
.setNegativeButton(R.string.cancel, null)
.show();
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == IntentIntegrator.REQUEST_CODE) {
IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
QrCodeHandler qrCodeHandler = new QrCodeHandler(this);
qrCodeHandler.onScanPerformed(scanResult);
}
}
@Override
public void handleEvent(@NonNull DcEvent event) {
int eventId = event.getId();
if (eventId == DcContext.DC_EVENT_CONFIGURE_PROGRESS && event.getData1Int() == 1000) {
loadRelays();
}
}
}
@@ -1,108 +0,0 @@
package org.thoughtcrime.securesms.relay;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import org.thoughtcrime.securesms.R;
import java.util.ArrayList;
import java.util.List;
import chat.delta.rpc.types.EnteredLoginParam;
public class RelayListAdapter extends RecyclerView.Adapter<RelayListAdapter.RelayViewHolder> {
private List<EnteredLoginParam> relays = new ArrayList<>();
private final OnRelayClickListener listener;
private String mainRelayAddr;
public interface OnRelayClickListener {
void onRelayClick(EnteredLoginParam relay);
void onRelayEdit(EnteredLoginParam relay);
void onRelayDelete(EnteredLoginParam relay);
}
public RelayListAdapter(OnRelayClickListener listener) {
this.listener = listener;
}
public String getMainRelay() {
return mainRelayAddr;
}
public void setRelays(@Nullable List<EnteredLoginParam> relays, String mainRelayAddr) {
this.relays = relays != null ? relays : new ArrayList<>();
this.mainRelayAddr = mainRelayAddr;
notifyDataSetChanged();
}
@NonNull
@Override
public RelayViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.relay_list_item, parent, false);
return new RelayViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull RelayViewHolder holder, int position) {
EnteredLoginParam relay = relays.get(position);
boolean isMain = relay.addr != null && relay.addr.equals(mainRelayAddr);
holder.bind(relay, isMain, listener);
}
@Override
public int getItemCount() {
return relays.size();
}
public static class RelayViewHolder extends RecyclerView.ViewHolder {
private final TextView titleText;
private final TextView subtitleText;
private final ImageView mainIndicator;
private final ImageView editButton;
private final ImageView deleteButton;
public RelayViewHolder(@NonNull View itemView) {
super(itemView);
titleText = itemView.findViewById(R.id.title);
subtitleText = itemView.findViewById(R.id.subtitle);
mainIndicator = itemView.findViewById(R.id.main_indicator);
editButton = itemView.findViewById(R.id.edit_button);
deleteButton = itemView.findViewById(R.id.delete_button);
}
public void bind(EnteredLoginParam relay, boolean isMain, OnRelayClickListener listener) {
String[] parts = relay.addr.split("@");
titleText.setText(parts.length == 2? parts[1] : parts[0]);
subtitleText.setText(parts.length == 2? parts[0] : "");
mainIndicator.setVisibility(isMain ? View.VISIBLE : View.INVISIBLE);
deleteButton.setVisibility(isMain ? View.GONE : View.VISIBLE);
itemView.setOnClickListener(v -> {
if (listener != null) {
listener.onRelayClick(relay);
}
});
editButton.setOnClickListener(v -> {
if (listener != null) {
listener.onRelayEdit(relay);
}
});
deleteButton.setOnClickListener(v -> {
if (listener != null) {
listener.onRelayDelete(relay);
}
});
}
}
}
@@ -1,7 +1,7 @@
package org.thoughtcrime.securesms.search;
import static org.thoughtcrime.securesms.util.ShareUtil.isRelayingMessageContent;
import static org.thoughtcrime.securesms.util.RelayUtil.isRelayingMessageContent;
import android.content.res.Configuration;
import android.os.Bundle;
@@ -39,4 +39,12 @@ public class IntentUtils {
return 0;
}
}
public static int FLAG_IMMUTABLE() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return PendingIntent.FLAG_IMMUTABLE;
} else {
return 0;
}
}
}
@@ -166,6 +166,10 @@ public class Prefs {
return true;
}
public static boolean isDeveloperModeEnabled(Context context) {
return getBooleanPreference(context, "pref_developer_mode_enabled", false);
}
public static boolean isNewBroadcastAvailable(Context context) {
return true;
}
@@ -13,7 +13,7 @@ import androidx.annotation.NonNull;
import java.util.ArrayList;
public class ShareUtil {
public class RelayUtil {
private static final String FORWARDED_MESSAGE_IDS = "forwarded_message_ids";
private static final String SHARED_URIS = "shared_uris";
private static final String SHARED_CONTACT_ID = "shared_contact_id";
@@ -152,32 +152,13 @@ public class SaveAttachmentTask extends ProgressDialogAsyncTask<SaveAttachmentTa
return StorageUtil.getVideoUri();
} else if (contentType.startsWith("audio/")) {
return StorageUtil.getAudioUri();
} else if (isMediaStoreImageType(contentType)) {
} else if (contentType.startsWith("image/")) {
return StorageUtil.getImageUri();
} else {
return StorageUtil.getDownloadUri();
}
}
/**
* Checks if the content type is a standard image format supported by Android's MediaStore.
* Non-standard image formats (like XCF, PSD, etc.) should be saved to Downloads instead.
*/
private boolean isMediaStoreImageType(@NonNull String contentType) {
if (!contentType.startsWith("image/")) {
return false;
}
return contentType.equals("image/jpeg") ||
contentType.equals("image/jpg") ||
contentType.equals("image/png") ||
contentType.equals("image/gif") ||
contentType.equals("image/webp") ||
contentType.equals("image/bmp") ||
contentType.equals("image/heic") ||
contentType.equals("image/heif") ||
contentType.equals("image/avif");
}
private @Nullable File ensureExternalPath(@Nullable File path) {
if (path != null && path.exists()) {
return path;
@@ -216,7 +197,7 @@ public class SaveAttachmentTask extends ProgressDialogAsyncTask<SaveAttachmentTa
storage = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES);
} else if (contentType.startsWith("audio/")) {
storage = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC);
} else if (isMediaStoreImageType(contentType)) {
} else if (contentType.startsWith("image/")) {
storage = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
}
@@ -1,11 +1,14 @@
package org.thoughtcrime.securesms.util;
import static org.thoughtcrime.securesms.util.ShareUtil.getForwardedMessageIDs;
import static org.thoughtcrime.securesms.util.ShareUtil.getSharedText;
import static org.thoughtcrime.securesms.util.ShareUtil.getSharedUris;
import static org.thoughtcrime.securesms.util.ShareUtil.isForwarding;
import static org.thoughtcrime.securesms.util.ShareUtil.isSharing;
import static org.thoughtcrime.securesms.util.ShareUtil.resetRelayingMessageContent;
import static org.thoughtcrime.securesms.util.RelayUtil.getForwardedMessageIDs;
import static org.thoughtcrime.securesms.util.RelayUtil.getSharedText;
import static org.thoughtcrime.securesms.util.RelayUtil.getSharedSubject;
import static org.thoughtcrime.securesms.util.RelayUtil.getSharedHtml;
import static org.thoughtcrime.securesms.util.RelayUtil.getSharedType;
import static org.thoughtcrime.securesms.util.RelayUtil.getSharedUris;
import static org.thoughtcrime.securesms.util.RelayUtil.isForwarding;
import static org.thoughtcrime.securesms.util.RelayUtil.isSharing;
import static org.thoughtcrime.securesms.util.RelayUtil.resetRelayingMessageContent;
import android.app.Activity;
import android.content.ContentResolver;
@@ -66,9 +69,9 @@ public class SendRelayedMessageUtil {
} else if (isSharing(activity)) {
ArrayList<Uri> sharedUris = getSharedUris(activity);
String sharedText = getSharedText(activity);
String subject = ShareUtil.getSharedSubject(activity);
String sharedHtml = getHtml(activity, ShareUtil.getSharedHtml(activity));
String msgType = ShareUtil.getSharedType(activity);
String subject = getSharedSubject(activity);
String sharedHtml = getHtml(activity, getSharedHtml(activity));
String msgType = getSharedType(activity);
resetRelayingMessageContent(activity);
Util.runOnAnyBackgroundThread(() -> {
for (long chatId : chatIds) {
@@ -41,14 +41,10 @@ import androidx.annotation.IdRes;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.util.views.Stub;
import chat.delta.util.ListenableFuture;
@@ -298,208 +294,4 @@ public class ViewUtil {
}
return selection;
}
/**
* Get combined insets from status bar, navigation bar and display cutout areas.
*
* @param windowInsets The window insets to extract from
* @return Combined insets using the maximum values from system bars and display cutout
*/
private static Insets getCombinedInsets(@NonNull WindowInsetsCompat windowInsets) {
Insets systemBars = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
Insets displayCutout = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout());
return Insets.max(systemBars, displayCutout);
}
/**
* Apply window insets to a view by adding margin to avoid drawing it behind system bars.
* Convenience method that applies insets to all sides.
*
* @param view The view to apply insets to
*/
public static void applyWindowInsetsAsMargin(@NonNull View view) {
applyWindowInsetsAsMargin(view, true, true, true, true);
}
/**
* Apply window insets to a view by adding margin to avoid drawing it behind system bars.
*
* This method stores the original margin values in view tags to ensure that
* margin doesn't accumulate on multiple inset applications.
*
* @param view The view to apply insets to
* @param left Whether to apply left inset
* @param top Whether to apply top inset
* @param right Whether to apply right inset
* @param bottom Whether to apply bottom inset
*/
public static void applyWindowInsetsAsMargin(@NonNull View view, boolean left, boolean top, boolean right, boolean bottom) {
// Only enable on API 30+ where WindowInsets APIs work correctly
if (Build.VERSION.SDK_INT < VERSION_CODES.R) return;
// Store the original margin as a tag only if not already stored
// This prevents losing the true original margin on subsequent calls
if (view.getTag(R.id.tag_window_insets_margin_left) == null) {
ViewGroup.LayoutParams params = view.getLayoutParams();
if (params instanceof ViewGroup.MarginLayoutParams) {
ViewGroup.MarginLayoutParams marginParams = (ViewGroup.MarginLayoutParams) params;
view.setTag(R.id.tag_window_insets_margin_left, marginParams.leftMargin);
view.setTag(R.id.tag_window_insets_margin_top, marginParams.topMargin);
view.setTag(R.id.tag_window_insets_margin_right, marginParams.rightMargin);
view.setTag(R.id.tag_window_insets_margin_bottom, marginParams.bottomMargin);
}
}
ViewCompat.setOnApplyWindowInsetsListener(view, (v, windowInsets) -> {
Insets insets = getCombinedInsets(windowInsets);
// Retrieve the original margin values from tags with null checks
Integer leftTag = (Integer) v.getTag(R.id.tag_window_insets_margin_left);
Integer topTag = (Integer) v.getTag(R.id.tag_window_insets_margin_top);
Integer rightTag = (Integer) v.getTag(R.id.tag_window_insets_margin_right);
Integer bottomTag = (Integer) v.getTag(R.id.tag_window_insets_margin_bottom);
int baseMarginLeft = leftTag != null ? leftTag : 0;
int baseMarginTop = topTag != null ? topTag : 0;
int baseMarginRight = rightTag != null ? rightTag : 0;
int baseMarginBottom = bottomTag != null ? bottomTag : 0;
ViewGroup.LayoutParams layoutParams = v.getLayoutParams();
if (layoutParams instanceof ViewGroup.MarginLayoutParams) {
ViewGroup.MarginLayoutParams marginParams = (ViewGroup.MarginLayoutParams) layoutParams;
marginParams.leftMargin = baseMarginLeft + insets.left;
marginParams.topMargin = baseMarginTop + insets.top;
marginParams.rightMargin = baseMarginRight + insets.right;
marginParams.bottomMargin = baseMarginBottom + insets.bottom;
v.setLayoutParams(marginParams);
}
return windowInsets;
});
// Request the initial insets to be dispatched if the view is attached
if (view.isAttachedToWindow()) {
ViewCompat.requestApplyInsets(view);
}
}
/**
* Apply window insets to a view by adding padding to avoid drawing elements behind system bars.
* Convenience method that applies insets to all sides.
*
* @param view The view to apply insets to
*/
public static void applyWindowInsets(@NonNull View view) {
applyWindowInsets(view, true, true, true, true);
}
/**
* Apply window insets to a view by adding padding to avoid drawing elements behind system bars.
*
* This method stores the original padding values in view tags to ensure that
* padding doesn't accumulate on multiple inset applications.
*
* @param view The view to apply insets to
* @param left Whether to apply left inset
* @param top Whether to apply top inset
* @param right Whether to apply right inset
* @param bottom Whether to apply bottom inset
*/
public static void applyWindowInsets(@NonNull View view, boolean left, boolean top, boolean right, boolean bottom) {
// Only enable on API 30+ where WindowInsets APIs work correctly
if (Build.VERSION.SDK_INT < VERSION_CODES.R) return;
// Store the original padding as a tag only if not already stored
// This prevents losing the true original padding on subsequent calls
if (view.getTag(R.id.tag_window_insets_padding_left) == null) {
view.setTag(R.id.tag_window_insets_padding_left, view.getPaddingLeft());
view.setTag(R.id.tag_window_insets_padding_top, view.getPaddingTop());
view.setTag(R.id.tag_window_insets_padding_right, view.getPaddingRight());
view.setTag(R.id.tag_window_insets_padding_bottom, view.getPaddingBottom());
}
ViewCompat.setOnApplyWindowInsetsListener(view, (v, windowInsets) -> {
Insets insets = getCombinedInsets(windowInsets);
// Retrieve the original padding values from tags with null checks
Integer leftTag = (Integer) v.getTag(R.id.tag_window_insets_padding_left);
Integer topTag = (Integer) v.getTag(R.id.tag_window_insets_padding_top);
Integer rightTag = (Integer) v.getTag(R.id.tag_window_insets_padding_right);
Integer bottomTag = (Integer) v.getTag(R.id.tag_window_insets_padding_bottom);
int basePaddingLeft = leftTag != null ? leftTag : 0;
int basePaddingTop = topTag != null ? topTag : 0;
int basePaddingRight = rightTag != null ? rightTag : 0;
int basePaddingBottom = bottomTag != null ? bottomTag : 0;
v.setPadding(
left ? basePaddingLeft + insets.left : basePaddingLeft,
top ? basePaddingTop + insets.top : basePaddingTop,
right ? basePaddingRight + insets.right : basePaddingRight,
bottom ? basePaddingBottom + insets.bottom : basePaddingBottom
);
return windowInsets;
});
// Request the initial insets to be dispatched if the view is attached
if (view.isAttachedToWindow()) {
ViewCompat.requestApplyInsets(view);
}
}
/**
* Apply the top status bar inset as the height of a view.
*/
private static void applyTopInsetAsHeight(@NonNull View view) {
ViewCompat.setOnApplyWindowInsetsListener(view, (v, windowInsets) -> {
Insets insets = getCombinedInsets(windowInsets);
android.view.ViewGroup.LayoutParams params = v.getLayoutParams();
if (params != null) {
params.height = insets.top;
v.setLayoutParams(params);
}
return windowInsets;
});
// Request the initial insets to be dispatched if the view is attached
if (view.isAttachedToWindow()) {
ViewCompat.requestApplyInsets(view);
}
}
/**
* Apply adjustments to the activity's custom toolbar or set height of R.id.status_bar_background for proper Edge-to-Edge display.
*
* @param activity The activity to apply the adjustments to
*/
public static void adjustToolbarForE2E(@NonNull AppCompatActivity activity) {
// Only enable on API 30+ where WindowInsets APIs work correctly
if (Build.VERSION.SDK_INT < VERSION_CODES.R) return;
// The toolbar/app bar should extend behind the status bar with padding applied
View toolbar = activity.findViewById(R.id.toolbar);
if (toolbar != null) {
// Check if toolbar is inside an AppBarLayout
View parent = (View) toolbar.getParent();
if (parent instanceof com.google.android.material.appbar.AppBarLayout) {
ViewUtil.applyWindowInsets(parent, true, true, true, false);
} else {
ViewUtil.applyWindowInsets(toolbar, true, true, true, false);
}
}
// For activities without a custom toolbar, apply insets to status_bar_background view
View statusBarBackground = activity.findViewById(R.id.status_bar_background);
if (statusBarBackground != null) {
ViewUtil.applyTopInsetAsHeight(statusBarBackground);
ActionBar actionBar = activity.getSupportActionBar();
if (actionBar != null) {
// elevation is set via status_bar_background view
// otherwise there is a drop-shadow at the top
actionBar.setElevation(0);
}
}
}
}
@@ -1,76 +0,0 @@
package org.thoughtcrime.securesms.webxdc;
import android.content.Context;
import android.util.Log;
import android.webkit.WebStorage;
import androidx.annotation.NonNull;
import androidx.concurrent.futures.CallbackToFutureAdapter;
import androidx.work.ListenableWorker;
import androidx.work.WorkerParameters;
import chat.delta.rpc.Rpc;
import chat.delta.rpc.RpcException;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.Collections;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.thoughtcrime.securesms.connect.DcHelper;
public class WebxdcGarbageCollectionWorker extends ListenableWorker {
private static final String TAG = WebxdcGarbageCollectionWorker.class.getSimpleName();
private Rpc rpc;
public WebxdcGarbageCollectionWorker(Context context, WorkerParameters params) {
super(context, params);
rpc = DcHelper.getRpc(context);
}
@Override
public @NonNull ListenableFuture<Result> startWork() {
Log.i(TAG, "Running Webxdc storage garbage collection...");
final Pattern WEBXDC_URL_PATTERN =
Pattern.compile("^https?://acc(\\d+)-msg(\\d+)\\.localhost/?");
return CallbackToFutureAdapter.getFuture(completer -> {
WebStorage webStorage = WebStorage.getInstance();
webStorage.getOrigins((origins) -> {
if (origins == null || origins.isEmpty()) {
Log.i(TAG, "Done, no WebView origins found.");
completer.set(Result.success());
return;
}
for (Object key : origins.keySet()) {
String url = (String)key;
Matcher m = WEBXDC_URL_PATTERN.matcher(url);
if (m.matches()) {
int accId = Integer.parseInt(m.group(1));
int msgId = Integer.parseInt(m.group(2));
try {
if (rpc.getExistingMsgIds(accId, Collections.singletonList(msgId)).isEmpty()) {
webStorage.deleteOrigin(url);
Log.i(TAG, String.format("Deleted webxdc origin: %s", url));
} else {
Log.i(TAG, String.format("Existing webxdc origin: %s", url));
}
} catch (RpcException e) {
Log.e(TAG, "error calling rpc.getExistingMsgIds()", e);
completer.set(Result.failure());
return;
}
} else { // old webxdc URL schemes, etc
webStorage.deleteOrigin(url);
Log.i(TAG, String.format("Deleted unknown origin: %s", url));
}
}
Log.i(TAG, "Done running Webxdc storage garbage collection.");
completer.set(Result.success());
});
return "Webxdc Garbage Collector";
});
}
}
@@ -1,14 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<FrameLayout
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:background="?attr/colorPrimary"
android:fitsSystemWindows="true"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/status_bar_background"/>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:attr/windowBackground"
android:id="@+id/fragment" />
</FrameLayout>
</RelativeLayout>
@@ -1,14 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<FrameLayout
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:background="?attr/colorPrimary"
android:fitsSystemWindows="true"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/status_bar_background"/>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:attr/windowBackground"
android:id="@+id/fragment" />
</FrameLayout>
</RelativeLayout>
@@ -1,14 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<FrameLayout
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:background="?attr/colorPrimary"
android:fitsSystemWindows="true"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/status_bar_background"/>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:attr/windowBackground"
android:id="@+id/fragment" />
</FrameLayout>
</RelativeLayout>
@@ -1,21 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:fitsSystemWindows="true"
android:background="?attr/colorPrimary"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".EditTransportActivity">
<include layout="@layout/status_bar_background"/>
android:layout_height="match_parent">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
android:fillViewport="true"
android:background="?android:attr/windowBackground"
tools:context=".EditTransportActivity">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/content_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true">
@@ -395,4 +395,4 @@
</ScrollView>
</FrameLayout>
</RelativeLayout>
+4 -1
View File
@@ -3,11 +3,14 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:fitsSystemWindows="true"
android:background="?attr/colorPrimary"
xmlns:app="http://schemas.android.com/apk/res-auto">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
app:elevation="0dp">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
+4 -4
View File
@@ -1,15 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<FrameLayout
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:background="?attr/colorPrimary"
android:fitsSystemWindows="true"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/status_bar_background"/>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:name="org.thoughtcrime.securesms.qr.QrShowFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/qrScannerFragment" />
</FrameLayout>
</RelativeLayout>
@@ -1,14 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout_container"
android:fitsSystemWindows="true"
android:background="?attr/colorPrimary"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:attr/windowBackground"
android:orientation="vertical"
android:gravity="center_horizontal">
<include layout="@layout/status_bar_background"/>
<LinearLayout
android:id="@+id/top_text"
android:layout_width="match_parent"
@@ -90,4 +94,4 @@
</LinearLayout>
</FrameLayout>
</RelativeLayout>
@@ -1,14 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout_container"
android:background="?attr/colorPrimary"
android:fitsSystemWindows="true"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:attr/windowBackground"
android:orientation="vertical"
android:gravity="center_horizontal">
<include layout="@layout/status_bar_background"/>
<androidx.legacy.widget.Space
android:layout_weight="2"
android:layout_width="match_parent"
@@ -36,3 +40,5 @@
android:layout_height="0dp"/>
</LinearLayout>
</RelativeLayout>
@@ -1,31 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/status_bar_background"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/relay_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingBottom="88dp"
android:scrollbars="vertical"
tools:listitem="@layout/relay_list_item" />
<org.thoughtcrime.securesms.components.registration.PulsingFloatingActionButton
android:id="@+id/fab_add_relay"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
app:backgroundTint="?attr/fab_color"
android:src="@drawable/ic_add_white_24dp"
android:focusable="true"
android:contentDescription="@string/add_transport"/>
</FrameLayout>
@@ -2,11 +2,11 @@
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout_container"
android:fitsSystemWindows="true"
android:background="?attr/colorPrimary"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/status_bar_background"/>
<org.thoughtcrime.securesms.components.ScaleStableImageView
android:id="@+id/preview"
android:scaleType="centerCrop"
@@ -45,4 +45,4 @@
</LinearLayout>
</FrameLayout>
</FrameLayout>
+4 -1
View File
@@ -3,11 +3,14 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:fitsSystemWindows="true"
android:background="?attr/colorPrimary"
xmlns:app="http://schemas.android.com/apk/res-auto">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
app:elevation="0dp">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:background="?attr/colorPrimary"
android:fitsSystemWindows="true"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/status_bar_background"/>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -2,13 +2,15 @@
<LinearLayout android:layout_gravity="center"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:fitsSystemWindows="true"
android:background="?attr/colorPrimary"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<org.thoughtcrime.securesms.components.ContactFilterToolbar
android:id="@+id/toolbar"
android:layout_height="wrap_content"
android:layout_height="?attr/actionBarSize"
android:layout_width="match_parent"
android:minHeight="?attr/actionBarSize"
android:background="?attr/colorPrimary"
@@ -16,9 +18,16 @@
android:theme="?attr/actionBarStyle"
app:contentInsetStartWithNavigation="0dp"/>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:attr/windowBackground">
<fragment android:id="@+id/contact_selection_list_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="org.thoughtcrime.securesms.ContactSelectionListFragment" />
</LinearLayout>
</FrameLayout>
</LinearLayout>
@@ -2,12 +2,10 @@
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/root_layout"
android:background="?attr/input_panel_bg_color"
android:fitsSystemWindows="true"
android:background="?attr/colorPrimary"
android:layout_height="match_parent" android:layout_width="match_parent">
<include layout="@layout/status_bar_background"/>
<org.thoughtcrime.securesms.components.ScaleStableImageView
android:id="@+id/conversation_background"
android:layout_width="match_parent"

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