mirror of
https://github.com/ArcaneChat/android.git
synced 2026-07-03 14:05:24 +02:00
Compare commits
238 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ffa58aae34 | |||
| 24f5209c03 | |||
| 7fd96732d6 | |||
| 6e0759f719 | |||
| 63434e1e2f | |||
| 9c17bc412a | |||
| d40144d50c | |||
| 131c0f5a37 | |||
| 7086314d8b | |||
| d75b2c2bb7 | |||
| c46d174869 | |||
| 17e03f2903 | |||
| 2c12a34051 | |||
| 2d3dde2101 | |||
| d539f5ecf2 | |||
| b17d6be4fc | |||
| 3c737f2360 | |||
| 9ac5e714b8 | |||
| 94defa3091 | |||
| 052ada221e | |||
| 1d5e4cf2a9 | |||
| c46aef3ea0 | |||
| d30e141693 | |||
| 305940396e | |||
| 2ab567a9d3 | |||
| a9c488ff03 | |||
| 8817b50c95 | |||
| 84c3710a35 | |||
| be7be9bba4 | |||
| b50ae284fb | |||
| 97716d5c26 | |||
| e77253c843 | |||
| 6aed8d003f | |||
| 0083e60c49 | |||
| 0fc79fd845 | |||
| a7c3bc7ac5 | |||
| 83b16e5f4b | |||
| ee17c6d75e | |||
| c0525ac69c | |||
| e9d2a39098 | |||
| 4d6fd16767 | |||
| b398870823 | |||
| e68c50d614 | |||
| f6a27718a2 | |||
| f136fa3e3a | |||
| 8e55a3dbf3 | |||
| 923227a0e8 | |||
| 14ecafe0e2 | |||
| b93f8323ab | |||
| 77f43cde9a | |||
| e4d018393d | |||
| 9a816090de | |||
| 4b04aa65be | |||
| 489bb55788 | |||
| 9d244611bc | |||
| 3533916149 | |||
| 46bc3e7f72 | |||
| ed0f0107e3 | |||
| a855d7043a | |||
| 66fd795763 | |||
| 05da43484f | |||
| a58de2278b | |||
| 6743df23e9 | |||
| 35ec0d05e2 | |||
| 6ead7207ec | |||
| 0d5223036d | |||
| 640fc433b8 | |||
| 35d814c3f6 | |||
| f8b9d2b0d9 | |||
| 3390b865e0 | |||
| 883486da9c | |||
| d048203f45 | |||
| f9d70d1196 | |||
| 4413b7b4fb | |||
| 7a4f263a62 | |||
| 1a360d5282 | |||
| dc785fc116 | |||
| 009593f7cc | |||
| 884be3a93e | |||
| 9a25328787 | |||
| 2d8ec490b1 | |||
| 3b19ca99e1 | |||
| f751a48568 | |||
| 4549989a63 | |||
| 19e2c4e051 | |||
| 6f5e90be53 | |||
| 34fa0620ab | |||
| fe37af1a3f | |||
| 3459802d67 | |||
| b8bf847941 | |||
| 5b6024584a | |||
| 4833a44542 | |||
| eb93e2bb7e | |||
| 291700dfc7 | |||
| 7a4913b394 | |||
| 0dae71f4b7 | |||
| 08e4229533 | |||
| 101a31628d | |||
| 2a2ce883b4 | |||
| 5a0e26bdb5 | |||
| 0c9277dfd0 | |||
| 37886cf296 | |||
| df5ba2eced | |||
| 3c2ddb96b3 | |||
| e2a825dfb2 | |||
| 8d49c7e595 | |||
| 966d5dac24 | |||
| 7f684f4d2e | |||
| 1510f7f3a8 | |||
| 6916becf7f | |||
| ad5b496f5c | |||
| e647401db4 | |||
| 3113f9c3ab | |||
| a1e47865c5 | |||
| 3a5f9b3fed | |||
| 5ffbc19d03 | |||
| d9db4b818a | |||
| 693efdbd0f | |||
| 399b783437 | |||
| 4bc574dfbe | |||
| 294af0981d | |||
| e8c7014993 | |||
| 0edc8303c1 | |||
| 8c89c3e225 | |||
| a93c8ab055 | |||
| c5cb79d116 | |||
| b3c50b9571 | |||
| 41579de502 | |||
| e6f735b8bc | |||
| 70b6f2cdfa | |||
| c1e716d6a3 | |||
| dde59b4673 | |||
| 9d77920adf | |||
| 6f50ee0cfb | |||
| 4c86d6d49e | |||
| 963327dd64 | |||
| 5cba1ccd98 | |||
| de8e6b6852 | |||
| 811089f3b3 | |||
| e045a09d36 | |||
| a3a6919b08 | |||
| cbee839a43 | |||
| efdd92b6a1 | |||
| 75296e189a | |||
| 708a68119e | |||
| 1d5ab98892 | |||
| 07753e211d | |||
| 8135d96300 | |||
| d151e825da | |||
| d5289cc3df | |||
| af40a8b57e | |||
| 529139099e | |||
| b4aa18abae | |||
| a7cee63d1c | |||
| eda735925a | |||
| 46650c8cc3 | |||
| fbab156d22 | |||
| 539cb670f1 | |||
| 2a6aba110b | |||
| 0351a1e974 | |||
| d48ab128a0 | |||
| ef67585529 | |||
| 953e7c6da0 | |||
| ab5a9c9d60 | |||
| af91cf7413 | |||
| 6a618986d0 | |||
| 9eefcacbc1 | |||
| e245e29058 | |||
| 7d879f8d1f | |||
| f7963a56e9 | |||
| 0a73877c25 | |||
| 1b57880be3 | |||
| f54144e7e8 | |||
| b735759bd0 | |||
| a7199ecedf | |||
| 2cb529be32 | |||
| 235038027b | |||
| e8eb036594 | |||
| d531eb8b47 | |||
| a88a619099 | |||
| 00bc429f20 | |||
| 3f25d002e4 | |||
| 74c6f20c3e | |||
| 8728a0a39b | |||
| dcf5cf7f54 | |||
| 7f89ecea5c | |||
| 30a63dd13b | |||
| a5d2642c37 | |||
| 79e5eedab0 | |||
| 27da217eb7 | |||
| a0c71a5387 | |||
| 4d19a59cb6 | |||
| 819a9f415a | |||
| dff1ef3778 | |||
| 7131f5774e | |||
| aa572508dc | |||
| 1f880efb3f | |||
| 72ace5c156 | |||
| 2f34a6ffa4 | |||
| afdfe7bbaa | |||
| 14f43f2a79 | |||
| f3353cf6e9 | |||
| 722f2cad1e | |||
| b135093628 | |||
| be44789b01 | |||
| 233197095b | |||
| 494cb728c3 | |||
| 60e9a9101a | |||
| c23dac6f99 | |||
| 3965319ef4 | |||
| c4db7c515f | |||
| fbf88e102b | |||
| d5ea043893 | |||
| f70c79ba4a | |||
| 0b2a26e2f1 | |||
| b968ba67b3 | |||
| e234cc864b | |||
| b47e75eed6 | |||
| 6b684bf030 | |||
| ea89d37461 | |||
| 814af177d1 | |||
| 1ccbb7177f | |||
| 3118dbd32b | |||
| 1a5e062dac | |||
| 0bcaea6f01 | |||
| 8283a6c4ad | |||
| cd159bac6c | |||
| 21f917004f | |||
| 0abf2ff00c | |||
| 0ca92ec6b5 | |||
| e66fa53537 | |||
| a51013cc00 | |||
| 171500a97d | |||
| 9a4851961e | |||
| 8d7078f96f | |||
| c446440537 | |||
| 333e4c9eca | |||
| fb1f5df234 |
@@ -1 +1 @@
|
||||
blank_issues_enabled: true
|
||||
blank_issues_enabled: false
|
||||
|
||||
@@ -51,7 +51,7 @@ jobs:
|
||||
run: ./gradlew --no-daemon -PABI_FILTER=armeabi-v7a assembleFossDebug
|
||||
|
||||
- name: Upload APK
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: app-preview.apk
|
||||
path: 'build/outputs/apk/foss/debug/*.apk'
|
||||
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
- uses: nttld/setup-ndk@v1
|
||||
id: setup-ndk
|
||||
with:
|
||||
ndk-version: r23c
|
||||
ndk-version: r27
|
||||
|
||||
- name: Compile core
|
||||
env:
|
||||
@@ -49,11 +49,12 @@ jobs:
|
||||
- name: Build APK
|
||||
run: |
|
||||
mkdir -p ~/.gradle
|
||||
echo -n ${{ secrets.SIGNING_KEY }} | base64 -d >> ~/app.keystore
|
||||
echo "DC_RELEASE_STORE_FILE=$HOME/app.keystore" >> ~/.gradle/gradle.properties
|
||||
echo "DC_RELEASE_STORE_PASSWORD=${{ secrets.KEY_STORE_PASSWORD }}" >> ~/.gradle/gradle.properties
|
||||
echo "DC_RELEASE_KEY_ALIAS=${{ secrets.ALIAS }}" >> ~/.gradle/gradle.properties
|
||||
echo "DC_RELEASE_KEY_PASSWORD=${{ secrets.KEY_PASSWORD }}" >> ~/.gradle/gradle.properties
|
||||
echo -n ${{ secrets.KEYSTORE_FILE }} | base64 -d >> ~/keystore.jks
|
||||
echo "DC_RELEASE_STORE_FILE=$HOME/keystore.jks" >> ~/.gradle/gradle.properties
|
||||
echo "DC_RELEASE_STORE_PASSWORD=${{ secrets.KEYSTORE_PASSWORD }}" >> ~/.gradle/gradle.properties
|
||||
echo "DC_RELEASE_KEY_ALIAS_FDROID=${{ secrets.ALIAS_FDROID }}" >> ~/.gradle/gradle.properties
|
||||
echo "DC_RELEASE_KEY_ALIAS_GPLAY=${{ secrets.ALIAS_GPLAY }}" >> ~/.gradle/gradle.properties
|
||||
echo "DC_RELEASE_KEY_PASSWORD=${{ secrets.KEYSTORE_PASSWORD }}" >> ~/.gradle/gradle.properties
|
||||
./gradlew assembleFossRelease
|
||||
rm build/outputs/apk/foss/release/*universal*
|
||||
./gradlew assembleGplayRelease
|
||||
|
||||
@@ -1,5 +1,85 @@
|
||||
# ArcaneChat Android Changelog
|
||||
|
||||
## v1.52.0
|
||||
2025-01
|
||||
|
||||
* new group consistency algorithm
|
||||
* fix: don't show animated .webp stickers as static stickers
|
||||
* fix the chat shortcuts (created via long-press in launcher) to properly support multi-profile
|
||||
* fix some small bugs in certain android versions and special situations
|
||||
* avoid the app freezing in slow phones in some situations
|
||||
* improve menu in the help screen
|
||||
* update translations
|
||||
* update to core 1.155.0
|
||||
|
||||
## v1.50.5
|
||||
2025-01
|
||||
|
||||
* fix push-notifications handling for certain devices where it was not working correctly
|
||||
* update translations
|
||||
* using core 1.153.0
|
||||
|
||||
## v1.50.4
|
||||
2025-01
|
||||
|
||||
* properly send as animated stickers GIF files selected from keyboard
|
||||
* improve emoji picker in landscape mode and when changing from landscape to portrait
|
||||
* avoid crash when receiving push notifications if the user restricted the app from working in background
|
||||
* improve UI when attaching a file or image to easily recognize it is attached but not sent yet
|
||||
* avoid slow loading of in-chat apps in some devices when quickly re-opening an app after closing it
|
||||
* allow to select multiple images at once in the media picker via "Gallery" button
|
||||
* mark holiday notice messages as bot-generated
|
||||
* don't mark contacts as bot when receiving location-only and sync messages
|
||||
* prefer to encrypt even if peers have their preference to "no preference"
|
||||
* start ephemeral messages timers when the chat is archived or noticed
|
||||
* several bug fixes and updated translations
|
||||
* update to core 1.153.0
|
||||
|
||||
## v1.50.3
|
||||
2024-12
|
||||
|
||||
* Add in-chat apps picker to attachments options
|
||||
* Notify replies and reactions to your messages in muted chats (can be disabled in settings)
|
||||
* Cache HTTP GET requests (ex. when loading images from HTML messages)
|
||||
* update to core 1.152.0
|
||||
|
||||
## v1.50.2
|
||||
2024-12
|
||||
|
||||
* Encrypt notification tokens
|
||||
* update to core 1.151.5
|
||||
|
||||
## v1.50.0
|
||||
2024-12
|
||||
|
||||
* New emoji picker with support for more emojis
|
||||
* Webxdc apps can now trigger notifications
|
||||
* Webxdc apps can now deep-link to internal sections when you click their info-messages in chat
|
||||
* Add "Show in Chat" to the menu of opened Webxdc apps
|
||||
* Reverse order of messages in the notification group
|
||||
* Notify reactions to own messages
|
||||
* Improve the button to start Webxdc apps
|
||||
* Make account deletion confirmation dialog faster
|
||||
* Rename "Back up Chats to External Storage" to "Export Backup"
|
||||
* Improve compatibility with classic email clients in the outgoing messages
|
||||
* Removed internal font scaling setting in favor of the better system settings
|
||||
* Use privacy-preserving webxdc addresses
|
||||
* Use Rustls for connections with strict TLS
|
||||
* QR codes for adding contacts and joining groups provide help when opened in a normal browser
|
||||
* Mark Saved Messages chat as protected
|
||||
* Allow the user to replace maps integration
|
||||
* fix: Trim whitespace from scanned QR codes
|
||||
* fix quotes: Line-before-quote may be up to 120 character long instead of 80
|
||||
* fix: Prevent accidental wrong-password-notifications
|
||||
* fix: Remove footers from "Show Full Message..."
|
||||
* fix: Only add "member added/removed" messages if they actually do that
|
||||
* fix: Update state of message when fully downloading it
|
||||
* fix: send message: Do not fail if the message does not exist anymore
|
||||
* fix: Do not percent-encode dot when passing to autoconfig server (so, fix handling of some servers)
|
||||
* fix displaynames not being updated when intially scanned by a QR code
|
||||
* several bug fixes
|
||||
* update to core 1.151.3
|
||||
|
||||
## v1.48.3
|
||||
2024-10
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
## ArcaneChat Android Client
|
||||
|
||||
A [Delta Chat](https://delta.chat/) client for Android.
|
||||
A [Delta Chat](https://delta.chat/) client for Android. Learn more at: https://arcanechat.me
|
||||
|
||||
[<img src="store/get-it-on-fdroid.png" alt="Get it on F-Droid" height="48">](https://f-droid.org/packages/chat.delta.lite)
|
||||
[<img src="store/get-it-on-IzzyOnDroid.png" alt="Get it on IzzyOnDroid" height="48">](https://apt.izzysoft.de/fdroid/index/apk/chat.delta.lite)
|
||||
|
||||
+43
-24
@@ -1,5 +1,5 @@
|
||||
plugins {
|
||||
id 'com.android.application' version '8.1.4'
|
||||
id 'com.android.application' version '8.5.2'
|
||||
id 'com.google.gms.google-services' version '4.4.1'
|
||||
}
|
||||
|
||||
@@ -33,8 +33,8 @@ android {
|
||||
useLibrary 'org.apache.http.legacy'
|
||||
|
||||
defaultConfig {
|
||||
versionCode 30000697
|
||||
versionName "1.48.6"
|
||||
versionCode 30000706
|
||||
versionName "1.52.0"
|
||||
|
||||
applicationId "chat.delta.lite"
|
||||
multiDexEnabled true
|
||||
@@ -87,15 +87,45 @@ android {
|
||||
storeFile file(DC_DEBUG_STORE_FILE )
|
||||
}
|
||||
}
|
||||
release {
|
||||
releaseFdroid {
|
||||
// can be defined at `~/.gradle/gradle.properties` or at "Build/Generate signed APK"
|
||||
if(project.hasProperty("DC_RELEASE_STORE_FILE")) {
|
||||
storeFile file(DC_RELEASE_STORE_FILE)
|
||||
storePassword DC_RELEASE_STORE_PASSWORD
|
||||
keyAlias DC_RELEASE_KEY_ALIAS
|
||||
keyAlias DC_RELEASE_KEY_ALIAS_FDROID
|
||||
keyPassword DC_RELEASE_KEY_PASSWORD
|
||||
}
|
||||
}
|
||||
releaseApk {
|
||||
// can be defined at `~/.gradle/gradle.properties` or at "Build/Generate signed APK"
|
||||
if(project.hasProperty("DC_RELEASE_STORE_FILE")) {
|
||||
storeFile file(DC_RELEASE_STORE_FILE)
|
||||
storePassword DC_RELEASE_STORE_PASSWORD
|
||||
keyAlias DC_RELEASE_KEY_ALIAS_GPLAY
|
||||
keyPassword DC_RELEASE_KEY_PASSWORD
|
||||
}
|
||||
}
|
||||
releaseBundle {
|
||||
if(project.hasProperty("DC_BUNDLE_STORE_FILE")) {
|
||||
storeFile file(DC_BUNDLE_STORE_FILE)
|
||||
storePassword DC_BUNDLE_STORE_PASSWORD
|
||||
keyAlias DC_BUNDLE_KEY_ALIAS
|
||||
keyPassword DC_BUNDLE_STORE_PASSWORD
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
productFlavors {
|
||||
foss {
|
||||
dimension "none"
|
||||
buildConfigField "boolean", "USE_PLAY_SERVICES", "false"
|
||||
}
|
||||
gplay {
|
||||
dimension "none"
|
||||
apply plugin: "com.google.gms.google-services"
|
||||
buildConfigField "boolean", "USE_PLAY_SERVICES", "true"
|
||||
applicationId "com.github.arcanechat"
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
@@ -114,23 +144,12 @@ android {
|
||||
// nb: it is highly recommended to use the same settings in debug+release -
|
||||
// otherwise problems might be noticed delayed only
|
||||
minifyEnabled true
|
||||
signingConfig signingConfigs.release
|
||||
productFlavors.foss.signingConfig signingConfigs.releaseFdroid
|
||||
productFlavors.gplay.signingConfig signingConfigs.releaseApk
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
productFlavors {
|
||||
foss {
|
||||
dimension "none"
|
||||
buildConfigField "boolean", "USE_PLAY_SERVICES", "false"
|
||||
}
|
||||
gplay {
|
||||
dimension "none"
|
||||
apply plugin: "com.google.gms.google-services"
|
||||
buildConfigField "boolean", "USE_PLAY_SERVICES", "true"
|
||||
}
|
||||
}
|
||||
|
||||
if(!project.hasProperty("ABI_FILTER")) {
|
||||
splits {
|
||||
abi {
|
||||
@@ -190,7 +209,7 @@ dependencies {
|
||||
implementation 'com.airbnb.android:lottie:4.2.2' // Lottie animations support.
|
||||
|
||||
implementation 'androidx.sharetarget:sharetarget:1.2.0'
|
||||
implementation 'androidx.webkit:webkit:1.11.0'
|
||||
implementation 'androidx.webkit:webkit:1.12.1'
|
||||
implementation 'androidx.multidex:multidex:2.0.1'
|
||||
implementation 'androidx.appcompat:appcompat:1.7.0'
|
||||
implementation 'com.google.android.material:material:1.12.0'
|
||||
@@ -210,7 +229,7 @@ dependencies {
|
||||
implementation 'com.google.guava:guava:31.1-android'
|
||||
implementation 'com.google.android.exoplayer:exoplayer-core:2.19.1' // plays video and audio
|
||||
implementation 'com.google.android.exoplayer:exoplayer-ui:2.19.1'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.2.0'
|
||||
implementation 'com.google.zxing:core:3.3.0' // fixed version to support SDK<24
|
||||
implementation ('com.journeyapps:zxing-android-embedded:4.3.0') { transitive = false } // QR Code scanner
|
||||
implementation 'com.fasterxml.jackson.core:jackson-databind:2.11.1' // used as JSON library
|
||||
@@ -218,11 +237,11 @@ dependencies {
|
||||
implementation "me.leolin:ShortcutBadger:1.1.16" // display messagecount on the home screen icon.
|
||||
implementation 'com.jpardogo.materialtabstrip:library:1.0.9' // used in the emoji selector for the tab selection.
|
||||
implementation 'com.github.chrisbanes:PhotoView:2.1.3' // does the zooming on photos / media
|
||||
implementation 'com.github.penfeizhou.android.animation:glide-plugin:2.25.0' // APNG & animated webp support.
|
||||
implementation 'com.github.penfeizhou.android.animation:glide-plugin:3.0.2' // APNG & animated webp support.
|
||||
implementation 'com.caverock:androidsvg-aar:1.4' // SVG support.
|
||||
implementation 'com.github.bumptech.glide:glide:4.12.0'
|
||||
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
|
||||
annotationProcessor 'androidx.annotation:annotation:1.8.2'
|
||||
annotationProcessor 'androidx.annotation:annotation:1.9.1'
|
||||
implementation 'com.makeramen:roundedimageview:2.1.0' // crops the avatars to circles
|
||||
implementation 'com.pnikosis:materialish-progress:1.5' // used only in the "Progress Wheel" in Share Activity.
|
||||
implementation 'com.soundcloud.android:android-crop:1.0.1@aar' // used for profile and group avatar selection in Android SDK<19
|
||||
@@ -240,7 +259,7 @@ dependencies {
|
||||
// <https://github.com/cketti/SafeContentResolver>
|
||||
implementation 'de.cketti.safecontentresolver:safe-content-resolver-v14:1.0.0'
|
||||
|
||||
gplayImplementation('com.google.firebase:firebase-messaging:24.0.0') { // for PUSH notifications
|
||||
gplayImplementation('com.google.firebase:firebase-messaging:24.1.0') { // for PUSH notifications
|
||||
exclude group: 'com.google.firebase', module: 'firebase-core'
|
||||
exclude group: 'com.google.firebase', module: 'firebase-analytics'
|
||||
exclude group: 'com.google.firebase', module: 'firebase-measurement-connector'
|
||||
@@ -254,7 +273,7 @@ dependencies {
|
||||
testImplementation 'org.powermock:powermock-module-junit4-rule:1.6.1'
|
||||
testImplementation 'org.powermock:powermock-classloading-xstream:1.6.1'
|
||||
|
||||
androidTestImplementation 'androidx.test:runner:1.6.1'
|
||||
androidTestImplementation 'androidx.test:runner:1.6.2'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.6.1'
|
||||
androidTestImplementation 'androidx.test:rules:1.6.1'
|
||||
|
||||
@@ -17,19 +17,21 @@ ArcaneChat is a Delta Chat client and was created with a focus on usability, goo
|
||||
<b>Main differences with official Delta Chat client:</b>
|
||||
|
||||
<ul>
|
||||
<li>Basic markdown support (bold, italic, strike, etc.)</li>
|
||||
<li>Support for some markdown styles in text messages (bold, italic, strike, etc.)</li>
|
||||
<li>Support for displaying Telegram's animated stickers (.tgs files)</li>
|
||||
<li>Support for SVG images previews</li>
|
||||
<li>Multiple color themes/skins</li>
|
||||
<li>It is possible to disable accounts to completely disconnect them to save data/bandwidth</li>
|
||||
<li>It is possible to disable profiles to completely disconnect them saving data/bandwidth</li>
|
||||
<li>You can easily see the connection status of all your profiles in the profile switcher</li>
|
||||
<li>A videochat instance is set by default</li>
|
||||
<li>Replies to your messages in muted groups trigger notifications</li>
|
||||
<li>Location streaming feature enabled by default and extra option to share location for 12 hours</li>
|
||||
<li>Clicking on a message with a POI location, will open the POI on the map</li>
|
||||
<li>Last-seen status of contacts is shown in your contact list, like in WhatsApp, Telegram, etc.</li>
|
||||
<li>Videos are played in loop, useful for short GIF videos</li>
|
||||
<li>Verified icon is shown in the chat list for the "Device Messages" chat</li>
|
||||
<li>Voice messages have more aggressive compression in "worse quality" mode to save data plan</li>
|
||||
<li>Automatic download of messages limited to 640KB by default</li>
|
||||
<li>Account's display name is always shown in the app's title bar instead of the name of the app</li>
|
||||
<li>Profile's display name is always shown in the app's title bar instead of the name of the app</li>
|
||||
<li>Your avatar is visible to other users in Mailing Lists</li>
|
||||
<li>Can be selected as app to open .xdc files</li>
|
||||
<li>For mini-apps developers: there are some extra features in the WebXDC API, check https://github.com/ArcaneChat/android/#webxdc</li>
|
||||
|
||||
Generated
+26
-60
@@ -3,15 +3,15 @@
|
||||
"android": {
|
||||
"inputs": {
|
||||
"devshell": "devshell",
|
||||
"flake-utils": "flake-utils_2",
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1720988215,
|
||||
"narHash": "sha256-nQ0Zx0vAWJo0IOGNFjCOdIkDSgOpMa//GalR8tbTl3A=",
|
||||
"lastModified": 1733948466,
|
||||
"narHash": "sha256-o/uq/tU458Ykudi8Zk3sRga5iazkuSczt9wDOCUDOSU=",
|
||||
"owner": "tadfisher",
|
||||
"repo": "android-nixpkgs",
|
||||
"rev": "5a052c62cdb51b210bc0717177d5bd014cba3df1",
|
||||
"rev": "0bf99ffaea6a7c0948ae10cf2e40c2905e4e4d6b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -22,18 +22,17 @@
|
||||
},
|
||||
"devshell": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": [
|
||||
"android",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1717408969,
|
||||
"narHash": "sha256-Q0OEFqe35fZbbRPPRdrjTUUChKVhhWXz3T9ZSKmaoVY=",
|
||||
"lastModified": 1728330715,
|
||||
"narHash": "sha256-xRJ2nPOXb//u1jaBnDP56M7v5ldavjbtR6lfGqSvcKg=",
|
||||
"owner": "numtide",
|
||||
"repo": "devshell",
|
||||
"rev": "1ebbe68d57457c8cae98145410b164b5477761f4",
|
||||
"rev": "dd6b80932022cea34a019e2bb32f6fa9e494dfef",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -47,11 +46,11 @@
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1701680307,
|
||||
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -65,29 +64,11 @@
|
||||
"systems": "systems_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1710146030,
|
||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_3": {
|
||||
"inputs": {
|
||||
"systems": "systems_3"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1710146030,
|
||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -98,11 +79,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1720768451,
|
||||
"narHash": "sha256-EYekUHJE2gxeo2pM/zM9Wlqw1Uw2XTJXOSAO79ksc4Y=",
|
||||
"lastModified": 1733759999,
|
||||
"narHash": "sha256-463SNPWmz46iLzJKRzO3Q2b0Aurff3U1n0nYItxq7jU=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "7e7c39ea35c5cdd002cd4588b03a3fb9ece6fad9",
|
||||
"rev": "a73246e2eef4c6ed172979932bc80e1404ba2d56",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -114,11 +95,11 @@
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1723221148,
|
||||
"narHash": "sha256-7pjpeQlZUNQ4eeVntytU3jkw9dFK3k1Htgk2iuXjaD8=",
|
||||
"lastModified": 1733749988,
|
||||
"narHash": "sha256-+5qdtgXceqhK5ZR1YbP1fAUsweBIrhL38726oIEAtDs=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "154bcb95ad51bc257c2ce4043a725de6ca700ef6",
|
||||
"rev": "bc27f0fde01ce4e1bfec1ab122d72b7380278e68",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -130,11 +111,11 @@
|
||||
},
|
||||
"nixpkgs_3": {
|
||||
"locked": {
|
||||
"lastModified": 1718428119,
|
||||
"narHash": "sha256-WdWDpNaq6u1IPtxtYHHWpl5BmabtpmLnMAx0RdJ/vo8=",
|
||||
"lastModified": 1728538411,
|
||||
"narHash": "sha256-f0SBJz1eZ2yOuKUr5CA9BHULGXVSn6miBuUWdTyhUhU=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "e6cea36f83499eb4e9cd184c8a8e823296b50ad5",
|
||||
"rev": "b69de56fac8c2b6f8fd27f2eca01dcda8e0a4221",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -147,7 +128,7 @@
|
||||
"root": {
|
||||
"inputs": {
|
||||
"android": "android",
|
||||
"flake-utils": "flake-utils_3",
|
||||
"flake-utils": "flake-utils_2",
|
||||
"nixpkgs": "nixpkgs_2",
|
||||
"rust-overlay": "rust-overlay"
|
||||
}
|
||||
@@ -157,11 +138,11 @@
|
||||
"nixpkgs": "nixpkgs_3"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1723429325,
|
||||
"narHash": "sha256-4x/32xTCd+xCwFoI/kKSiCr5LQA2ZlyTRYXKEni5HR8=",
|
||||
"lastModified": 1733970833,
|
||||
"narHash": "sha256-sPEKtSaZk2CtfF9cdhtbY93S6qGq+d2PKI1fcoDfDaI=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "65e3dc0fe079fe8df087cd38f1fe6836a0373aad",
|
||||
"rev": "f7f4c59ccdf1bec3f1547d27398e9589aa94e3e8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -199,21 +180,6 @@
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_3": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
with sdkPkgs; [
|
||||
build-tools-33-0-1
|
||||
cmdline-tools-latest
|
||||
ndk-bundle
|
||||
platform-tools
|
||||
platforms-android-34
|
||||
ndk-27-0-11902837
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
# Privacy Policy ArcaneChat Apps
|
||||
|
||||
**This is the privacy policy for the ArcaneChat (Delta Chat client) apps.**
|
||||
|
||||
## Summary
|
||||
|
||||
ArcaneChat is an e-mail app that follows a strict privacy-by-design approach. All communication data remains on the end devices or on the e-mail servers selected by the user.
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Requirement</th>
|
||||
<th>Implementation</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Confidentiality</td>
|
||||
<td>
|
||||
<b>End-to-end encryption</b> by implementing <a href="https://autocrypt.org">Autocrypt</a> and <a href="https://securejoin.delta.chat/en/latest/new.html">Verified groups</a>. User-friendly end-to-end encryption means that the requirements of the GDPR are already implemented at the technical level, <b>Privacy by Design</b>.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Data minimization</td>
|
||||
<td><b>No upload</b> of contact lists from your phone.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Data avoidance</td>
|
||||
<td><b>No ArcaneChat servers</b>, no processing of personal data. All data remains with your e-mail provider.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Legal basis</td>
|
||||
<td>
|
||||
There is no need to obtain consent for address book matching, <a href="https://gdpr-info.eu/art-7-gdpr/">Art.7 GDPR</a>, as no address book data is transferred. Therefore, <b>no additional legal basis</b> is required.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Data to third parties</td>
|
||||
<td>We only receive the <b>token for the push notification</b> and forward it to the provider of your operating system. If you don't want to receive push notifications, we won't forward a token.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Data from third parties</td>
|
||||
<td>
|
||||
Easy implementation in companies: ArcaneChat does not process personal data on behalf of the controller and therefore <b>does not require any instruction or data processing agreement</b>. Easy connection with the own corporate e-mail server.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
DPIA
|
||||
</td>
|
||||
<td>
|
||||
No <b>data protection impact assessment</b> needs to be carried out for ArcaneChat <a href="https://gdpr-info.eu/art-35-gdpr/">Art.35 GDPR</a>, as no specific additional data is processed beyond the e-mail messenger process.
|
||||
|
||||
The risk to the rights and freedoms of natural persons is limited to the internal company data processing of the e-mail communication and that of the e-mail providers.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Documentation
|
||||
</td>
|
||||
<td>
|
||||
Inclusion of the measures implemented by ArcaneChat in the <b>record of processing activities</b> may have a positive impact on possible evidence, <a href="https://gdpr-info.eu/art-30-gdpr/">Art.30 GDPR</a> as well as certification processes, <a href="https://gdpr-info.eu/art-25-gdpr/">Art.25 (4) GDPR</a>,<a href="https://gdpr-info.eu/art-42-gdpr/">Art.42 GDPR</a>.
|
||||
|
||||
The <b>documentation of processing activities</b> related to Messenger communication is omitted and shifts only to the record of processing activities of your e-mail provider, <a href="https://gdpr-info.eu/art-30-gdpr/">Art.30(2) GDPR</a>.
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
## Detailed data protection information
|
||||
|
||||
### 1. Name and contact information of the data controller
|
||||
|
||||
Responsible for the processing of your personal data is
|
||||
```
|
||||
Asiel Diaz Benitez
|
||||
Reichsgrafen Str. 20
|
||||
79102 Freiburg
|
||||
Germany
|
||||
```
|
||||
E-mail: [adbenitez@duck.com](mailto:adbenitez@duck.com)
|
||||
|
||||
### 2. Processing when using the ArcaneChat e-mail messenger
|
||||
|
||||
All data is stored locally on your device or with your e-mail provider. Neither we nor ArcaneChat developers have any possibility to access the end user's data, as all communication and data processing takes place on the end user's device without ArcaneChat servers being involved. Only for the optional Push Notification (see 2.2) the Push Notification Token is processed by Delta Chat servers without them having any knowledge about the messages themselves, not even in encrypted form.
|
||||
|
||||
#### 2.1 Sign up with your e-mail provider
|
||||
|
||||
ArcaneChat communication works through your e-mail account. In order to establish the connection, the app needs the access data. These are only stored locally on your end device:
|
||||
|
||||
- e-mail address
|
||||
- your password
|
||||
|
||||
The legal basis for the processing is [Art.6 (1) lit.b GDPR](https://gdpr-info.eu/art-6-gdpr/), as you have a usage contract with us by using our services.
|
||||
|
||||
Security procedures are in place to protect the confidentiality of the data:
|
||||
Only the bare data needed to fulfil the user request of login are stored,
|
||||
encryption takes place as well as local sandboxing,
|
||||
see 2.3 for further details.
|
||||
|
||||
#### 2.2 Heartbeat push notification
|
||||
|
||||
Push notifications can be sent to the user's phone at regular intervals to enable receipt of messages while the ArcaneChat app is not currently active. Current messages can then be retrieved on the end device. The token is only created if the user wants reliable receipt of messages even when the app is not active.
|
||||
|
||||
In order to use push notifications, a unique identifier or token (Push Notification Token) is created after the app is downloaded and installed. This token allows Delta Chat servers to send notifications to the user's device. The token is generated and provided by the provider. The token is then stored on our systems and sent to the device at regular intervals to cause the app to retrieve new messages from the e-mail provider. Our systems have no knowledge of whether a message arrives or who may have sent a message.
|
||||
|
||||
The aforementioned data will only be processed with your consent, in accordance with [Art.6 (1) lit.a GDPR](https://gdpr-info.eu/art-6-gdpr/).
|
||||
|
||||
#### 2.3 Data in the app
|
||||
|
||||
The ArcaneChat app works in a data-saving way. All relevant data is stored exclusively on the respective end devices:
|
||||
|
||||
```
|
||||
- chat histories (text messages, voice messages, media, ...).
|
||||
- contacts
|
||||
- settings
|
||||
```
|
||||
ArcaneChat servers have no access to this data, not even in encrypted form, as data processing takes place only on the end devices.
|
||||
|
||||
#### 2.4 App permissions
|
||||
|
||||
Within the app, you can enter, manage, and edit various information, tasks, and activities. The app also requires the following permissions:
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Permission</th>
|
||||
<th>Reason</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Internet access</td>
|
||||
<td>This is needed to send the messages to the communication partner. </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Camera access</td>
|
||||
<td>
|
||||
This is needed for you to take photos and send them via the app. In addition, the camera access allows you to scan QR codes.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Microphone access (optional)</td>
|
||||
<td>
|
||||
This permission allows you to send voice messages.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Location access (optional)</td>
|
||||
<td>
|
||||
This is needed if you want to share your location with a communication partner.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Background location access (optional)</td>
|
||||
<td>
|
||||
This will be needed if you want to share your location over a certain period of time.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Contact access (optional)</td>
|
||||
<td>
|
||||
This allows you to load and save contacts from your phone book into the app. The contact data is stored locally in the app and not forwarded and stored on ArcaneChat server.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Storage (optional)
|
||||
</td>
|
||||
<td>You can save images and files from the app to your device.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
The processing and use of the above permissions are performed to provide the service. The internet access is necessary for the use, therefore the legal basis of the processing is [Art.6 (1) lit.a GDPR](https://gdpr-info.eu/art-6-gdpr/), as you have a usage contract with us by using our services.
|
||||
|
||||
The optional permissions only take place based on your consent according to [Art.6 (1) lit.a GDPR](https://gdpr-info.eu/art-6-gdpr/) and can also be reduced to individual services, e.g. only internet usage to send messages without pictures or location data. ArcaneChat does not receive any access to this data.
|
||||
|
||||
### 3. Platform dependent processing
|
||||
|
||||
Certain information is already processed automatically as soon as you use the app. We have listed below which personal data is processed exactly:
|
||||
|
||||
When you download the app, certain required information is transmitted to the app store you use ( e.g. Google Play or Apple App Store), in particular the username, the email address, the customer number of your account, the time of the download, payment information as well as the individual device identification number may be processed. The processing of this data is carried out exclusively by the respective app store and is beyond our control.
|
||||
|
||||
For the rest, we refer to the data protection policies of the respective app store providers or responsible parties of the operating systems. We do not collect and/or process any other data.
|
||||
|
||||
Your personal data will not be transferred to third parties for purposes other than those listed below.
|
||||
|
||||
# 4. Rights of the data subject
|
||||
|
||||
As a data subject of a processing of personal data, you have the right to
|
||||
|
||||
1. request information about your personal data processed by us in accordance with [Art.15 GDPR](https://gdpr-info.eu/art-15-gdpr/). In particular, you can request information about the processing purposes, the category of personal data, the categories of recipients to whom your data have been or will be disclosed, the planned storage period, the existence of a right to rectification, erasure, restriction of processing or objection, the existence of a right of complaint, the origin of your data if it has not been collected by us, as well as the existence of automated decision-making including profiling and, if applicable, meaningful information about its details;
|
||||
2. in accordance with [Art.16 GDPR](https://gdpr-info.eu/art-16-gdpr/) of the GDPR, immediately request the correction of inaccurate or incomplete personal data stored by us;
|
||||
3. pursuant to [Art.17 GDPR](https://gdpr-info.eu/art-17-gdpr/) of the GDPR, to request the erasure of your personal data stored by us, unless the processing is necessary for the exercise of the right to freedom of expression and information, for compliance with a legal obligation, for reasons of public interest, or for the establishment, exercise or defence of legal claims;
|
||||
4. pursuant to [Art.18 GDPR](https://gdpr-info.eu/art-18-gdpr/), to request the restriction of the processing of your personal data, insofar as the accuracy of the data is disputed by you, the processing is unlawful, but you object to its erasure and we no longer require the data, but you need it for the assertion, exercise or defence of legal claims or you have objected to the processing pursuant to [Art.21 GDPR](https://gdpr-info.eu/art-21-gdpr/);
|
||||
5. pursuant to [Art.20 GDPR](https://gdpr-info.eu/art-20-gdpr/), to receive your personal data that you have provided to us in a structured, common and machine-readable format or to request that it be transferred to another controller;
|
||||
6. in accordance with [Art.7 (3) GDPR](https://gdpr-info.eu/art-7-gdpr/), to revoke your consent given to us at any time. This has the consequence that we may no longer continue the data processing based on this consent in the future; and
|
||||
7. complain to a supervisory authority in accordance with [Art.77 GDPR](https://gdpr-info.eu/art-77-gdpr/) of the GDPR. As a rule, you can contact the supervisory authority of your usual place of residence or workplace.
|
||||
|
||||
|
||||
# 5. Up-to-dateness and modification of this data protection declaration
|
||||
|
||||
This data protection declaration is valid as of January 2025. Due to the further development of our website and offers or due to changed legal or official requirements, it may become necessary to revise this data protection declaration from time to time.
|
||||
@@ -28,7 +28,7 @@
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:922391085500:android:6f54e2c4e49405673e2bb9",
|
||||
"android_client_info": {
|
||||
"package_name": "chat.delta.lite.beta"
|
||||
"package_name": "com.github.arcanechat.beta"
|
||||
}
|
||||
},
|
||||
"oauth_client": [],
|
||||
@@ -47,7 +47,7 @@
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:922391085500:android:aff82fbc40c8172e3e2bb9",
|
||||
"android_client_info": {
|
||||
"package_name": "chat.delta.lite"
|
||||
"package_name": "com.github.arcanechat"
|
||||
}
|
||||
},
|
||||
"oauth_client": [],
|
||||
@@ -66,7 +66,7 @@
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:922391085500:android:92b4cf12669cc2083e2bb9",
|
||||
"android_client_info": {
|
||||
"package_name": "com.github.arcanechat"
|
||||
"package_name": "chat.delta.lite"
|
||||
}
|
||||
},
|
||||
"oauth_client": [],
|
||||
@@ -85,7 +85,7 @@
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:922391085500:android:228a205b8aa2bacc3e2bb9",
|
||||
"android_client_info": {
|
||||
"package_name": "com.github.arcanechat.beta"
|
||||
"package_name": "chat.delta.lite.beta"
|
||||
}
|
||||
},
|
||||
"oauth_client": [],
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionSha256Sum=ff7bf6a86f09b9b2c40bb8f48b25fc19cf2b2664fd1d220cd7ab833ec758d0d7
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
|
||||
distributionSha256Sum=544c35d6bd849ae8a5ed0bcea39ba677dc40f49df7d1835561582da2009b961d
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
||||
networkTimeout=10000
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
+24
-20
@@ -702,12 +702,6 @@ JNIEXPORT jboolean Java_com_b44t_messenger_DcContext_resendMsgs(JNIEnv *env, job
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jint Java_com_b44t_messenger_DcContext_prepareMsg(JNIEnv *env, jobject obj, jint chat_id, jobject msg)
|
||||
{
|
||||
return dc_prepare_msg(get_dc_context(env, obj), chat_id, get_dc_msg(env, msg));
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jint Java_com_b44t_messenger_DcContext_sendMsg(JNIEnv *env, jobject obj, jint chat_id, jobject msg)
|
||||
{
|
||||
return dc_send_msg(get_dc_context(env, obj), chat_id, get_dc_msg(env, msg));
|
||||
@@ -729,12 +723,10 @@ JNIEXPORT jint Java_com_b44t_messenger_DcContext_sendVideochatInvitation(JNIEnv
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jboolean Java_com_b44t_messenger_DcContext_sendWebxdcStatusUpdate(JNIEnv *env, jobject obj, jint msg_id, jstring payload, jstring descr)
|
||||
JNIEXPORT jboolean Java_com_b44t_messenger_DcContext_sendWebxdcStatusUpdate(JNIEnv *env, jobject obj, jint msg_id, jstring payload)
|
||||
{
|
||||
CHAR_REF(payload);
|
||||
CHAR_REF(descr);
|
||||
jboolean ret = dc_send_webxdc_status_update(get_dc_context(env, obj), msg_id, payloadPtr, descrPtr) != 0;
|
||||
CHAR_UNREF(descr);
|
||||
jboolean ret = dc_send_webxdc_status_update(get_dc_context(env, obj), msg_id, payloadPtr, NULL) != 0;
|
||||
CHAR_UNREF(payload);
|
||||
return ret;
|
||||
}
|
||||
@@ -1372,12 +1364,6 @@ JNIEXPORT jint Java_com_b44t_messenger_DcMsg_getId(JNIEnv *env, jobject obj)
|
||||
return dc_msg_get_id(get_dc_msg(env, obj));
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jboolean Java_com_b44t_messenger_DcMsg_isOutgoing(JNIEnv *env, jobject obj)
|
||||
{
|
||||
return (jboolean)(dc_msg_is_outgoing(get_dc_msg(env, obj))!=0);
|
||||
}
|
||||
|
||||
JNIEXPORT jint Java_com_b44t_messenger_DcMsg_getSenderColor(JNIEnv *env, jobject obj)
|
||||
{
|
||||
return dc_msg_get_sender_color(get_dc_msg(env, obj));
|
||||
@@ -1575,15 +1561,18 @@ JNIEXPORT jstring Java_com_b44t_messenger_DcMsg_getWebxdcInfoJson(JNIEnv *env, j
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jboolean Java_com_b44t_messenger_DcMsg_isForwarded(JNIEnv *env, jobject obj)
|
||||
JNIEXPORT jstring Java_com_b44t_messenger_DcMsg_getWebxdcHref(JNIEnv *env, jobject obj)
|
||||
{
|
||||
return dc_msg_is_forwarded(get_dc_msg(env, obj))!=0;
|
||||
char* temp = dc_msg_get_webxdc_href(get_dc_msg(env, obj));
|
||||
jstring ret = JSTRING_NEW(temp);
|
||||
dc_str_unref(temp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jboolean Java_com_b44t_messenger_DcMsg_isIncreation(JNIEnv *env, jobject obj)
|
||||
JNIEXPORT jboolean Java_com_b44t_messenger_DcMsg_isForwarded(JNIEnv *env, jobject obj)
|
||||
{
|
||||
return dc_msg_is_increation(get_dc_msg(env, obj))!=0;
|
||||
return dc_msg_is_forwarded(get_dc_msg(env, obj))!=0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1663,6 +1652,21 @@ JNIEXPORT void Java_com_b44t_messenger_DcMsg_setFile(JNIEnv *env, jobject obj, j
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT void Java_com_b44t_messenger_DcMsg_forceSticker(JNIEnv *env, jobject obj)
|
||||
{
|
||||
dc_msg_force_sticker(get_dc_msg(env, obj));
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jstring Java_com_b44t_messenger_DcMsg_getPOILocation(JNIEnv *env, jobject obj)
|
||||
{
|
||||
char* temp = dc_msg_get_poi_location(get_dc_msg(env, obj));
|
||||
jstring ret = JSTRING_NEW(temp);
|
||||
dc_str_unref(temp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT void Java_com_b44t_messenger_DcMsg_setDimension(JNIEnv *env, jobject obj, int width, int height)
|
||||
{
|
||||
dc_msg_set_dimension(get_dc_msg(env, obj), width, height);
|
||||
|
||||
+1
-1
Submodule jni/deltachat-core-rust updated: 8f8178d5e0...2832d8ba7c
@@ -1 +1 @@
|
||||
../deltachat-pages/tools/create-local-help.py ../deltachat-pages/_site src/main/assets/help
|
||||
../deltachat-pages/tools/create-local-help.py ../deltachat-pages/result src/main/assets/help
|
||||
|
||||
+7
-6
@@ -38,8 +38,6 @@
|
||||
#
|
||||
# If anything doesn't work, please open an issue!!
|
||||
|
||||
"$(dirname "$0")/rebrand.sh"
|
||||
|
||||
set -e
|
||||
echo "starting time: `date`"
|
||||
|
||||
@@ -128,7 +126,7 @@ if test -z $1 || test $1 = armeabi-v7a; then
|
||||
TARGET_CC="$TOOLCHAIN/bin/armv7a-linux-androideabi21-clang" \
|
||||
TARGET_AR="$TOOLCHAIN/bin/llvm-ar" \
|
||||
TARGET_RANLIB="$TOOLCHAIN/bin/llvm-ranlib" \
|
||||
cargo build $RELEASEFLAG --target armv7-linux-androideabi -p deltachat_ffi --features jsonrpc
|
||||
cargo build $RELEASEFLAG --target armv7-linux-androideabi -p deltachat_ffi
|
||||
cp $CARGO_TARGET_DIR/armv7-linux-androideabi/$RELEASE/libdeltachat.a $jnidir/armeabi-v7a
|
||||
fi
|
||||
|
||||
@@ -137,7 +135,7 @@ if test -z $1 || test $1 = arm64-v8a; then
|
||||
TARGET_CC="$TOOLCHAIN/bin/aarch64-linux-android21-clang" \
|
||||
TARGET_AR="$TOOLCHAIN/bin/llvm-ar" \
|
||||
TARGET_RANLIB="$TOOLCHAIN/bin/llvm-ranlib" \
|
||||
cargo build $RELEASEFLAG --target aarch64-linux-android -p deltachat_ffi --features jsonrpc
|
||||
cargo build $RELEASEFLAG --target aarch64-linux-android -p deltachat_ffi
|
||||
cp $CARGO_TARGET_DIR/aarch64-linux-android/$RELEASE/libdeltachat.a $jnidir/arm64-v8a
|
||||
fi
|
||||
|
||||
@@ -146,7 +144,7 @@ if test -z $1 || test $1 = x86; then
|
||||
TARGET_CC="$TOOLCHAIN/bin/i686-linux-android21-clang" \
|
||||
TARGET_AR="$TOOLCHAIN/bin/llvm-ar" \
|
||||
TARGET_RANLIB="$TOOLCHAIN/bin/llvm-ranlib" \
|
||||
cargo build $RELEASEFLAG --target i686-linux-android -p deltachat_ffi --features jsonrpc
|
||||
cargo build $RELEASEFLAG --target i686-linux-android -p deltachat_ffi
|
||||
cp $CARGO_TARGET_DIR/i686-linux-android/$RELEASE/libdeltachat.a $jnidir/x86
|
||||
fi
|
||||
|
||||
@@ -155,7 +153,7 @@ fi
|
||||
TARGET_CC="$TOOLCHAIN/bin/x86_64-linux-android21-clang" \
|
||||
TARGET_AR="$TOOLCHAIN/bin/llvm-ar" \
|
||||
TARGET_RANLIB="$TOOLCHAIN/bin/llvm-ranlib" \
|
||||
cargo build $RELEASEFLAG --target x86_64-linux-android -p deltachat_ffi --features jsonrpc
|
||||
cargo build $RELEASEFLAG --target x86_64-linux-android -p deltachat_ffi
|
||||
cp $CARGO_TARGET_DIR/x86_64-linux-android/$RELEASE/libdeltachat.a $jnidir/x86_64
|
||||
fi
|
||||
|
||||
@@ -176,4 +174,7 @@ else
|
||||
rm -f ndkArch # Remove ndkArch, ignore if it doesn't exist
|
||||
fi
|
||||
|
||||
"$(dirname "$0")/rebrand.sh"
|
||||
|
||||
|
||||
echo "ending time: `date`"
|
||||
|
||||
@@ -1 +1 @@
|
||||
1.77.0
|
||||
1.83.0
|
||||
|
||||
@@ -4,3 +4,4 @@ find ./src/main/assets/help/ -type f -name '*.html' | xargs sed -i 's/github.com
|
||||
find ./src/main/assets/help/ -type f -name '*.html' | xargs sed -i 's/ArcaneChat/Delta Chat/g'
|
||||
find ./src/ -type f -name 'strings.xml' | xargs sed -i 's/github.com\/ArcaneChat/get.delta.chat/g'
|
||||
find ./src/ -type f -name 'strings.xml' | xargs sed -i 's/ArcaneChat/Delta Chat/g'
|
||||
sed -i 's/>Delta Chat</>ArcaneChat</g' ./src/main/res/values/strings.xml
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e # stop on all errors
|
||||
|
||||
git submodule update --init --recursive
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
VERSION=$1
|
||||
|
||||
@@ -29,7 +30,6 @@ echo ""
|
||||
echo "and now: here is Delta Chat $VERSION - choose your flavour and mind your backups:"
|
||||
echo "- 🍋 https://download.delta.chat/android/beta/deltachat-gplay-release-$VERSION.apk (google play candidate, overwrites existing installs, should keep data)"
|
||||
echo "- 🍉 https://download.delta.chat/android/beta/deltachat-foss-debug-$VERSION.apk (f-droid candidate, can be installed beside google play)"
|
||||
echo "- 🍏 https://testflight.apple.com/join/uEMc1NxS (ios, update to $VERSION may take a day or so)"
|
||||
echo ""
|
||||
echo "what to test: PLEASE_FILL_OUT"
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
VERSION=$1
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ public class SharingTest {
|
||||
}
|
||||
}
|
||||
Uri uri = Uri.parse("content://" + BuildConfig.APPLICATION_ID + ".attachments/" + Uri.encode(pngImage));
|
||||
DcHelper.sharedFiles.put("/" + pngImage, 1);
|
||||
DcHelper.sharedFiles.put(pngImage, 1);
|
||||
|
||||
Intent i = new Intent(Intent.ACTION_SEND);
|
||||
i.setType("image/png");
|
||||
|
||||
@@ -28,11 +28,6 @@ public class FcmReceiveService extends FirebaseMessagingService {
|
||||
private static volatile String prefixedToken;
|
||||
|
||||
public static void register(Context context) {
|
||||
if (Build.VERSION.SDK_INT < 19) {
|
||||
Log.w(TAG, "FCM not available on SDK < 19");
|
||||
triedRegistering = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (FcmReceiveService.prefixedToken != null) {
|
||||
Log.i(TAG, "FCM already registered");
|
||||
|
||||
@@ -389,6 +389,11 @@
|
||||
android:exported="true">
|
||||
</activity>
|
||||
|
||||
<activity android:name=".WebxdcStoreActivity"
|
||||
android:theme="@style/TextSecure.LightTheme"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode">
|
||||
</activity>
|
||||
|
||||
<activity android:name=".FullMsgActivity"
|
||||
android:theme="@style/TextSecure.LightTheme"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize">
|
||||
|
||||
@@ -99,6 +99,7 @@
|
||||
<li><a href="#lze-delta-chat-používat-s-protonmail--tutanota--criptext">Lze Delta Chat používat s Protonmail / Tutanota / Criptext?</a></li>
|
||||
<li><a href="#remove-account">How can I delete my account?</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>
|
||||
<li><a href="#where-can-my-friends-find-delta-chat">Where can my friends find Delta Chat?</a></li>
|
||||
<li><a href="#jak-je-financován-vývoj-delta-chatu">Jak je financován vývoj Delta Chatu?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
@@ -297,8 +298,7 @@ Archived chats remain accessible above the chat list or via search.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>To archive or pin a chat, long tap (Android), use the chat’s menu (Android/Desktop) or swipe to the left (iOS);
|
||||
to mute a chat, use the chat’s menu (Android/Desktop) or the chat’s profile (iOS).</p>
|
||||
<p>To use the functions, long tap or right click a chat in the chat list.</p>
|
||||
|
||||
<h3 id="what-does-the-green-dot-mean">
|
||||
|
||||
@@ -1309,6 +1309,12 @@ One device is not needed for the other to work.</p>
|
||||
and make sure, <strong>Private Network</strong> is selected as “Network profile type”
|
||||
(after transfer, you can change back to the original value)</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>On <strong>iOS</strong>, make sure “System Settings / Apps / Delta Chat / <strong>Local Network</strong>” access is granted</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>On <strong>macOS</strong>, enable “System Settings / Privacy & Security / <strong>Local Network</strong> / Delta Chat”</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Your system might have a “personal firewall”,
|
||||
which is known to cause problems (especially on Windows).
|
||||
@@ -1425,6 +1431,7 @@ you only open attachments from senders you trust, and not from spammers.</li>
|
||||
<ul>
|
||||
<li>In general, anyone can share webxdc apps with each
|
||||
other without restrictions.</li>
|
||||
<li>From <a href="https://webxdc.org/apps/">webxdc.org/apps</a>.</li>
|
||||
<li>You can <a href="https://delta.chat/en/2023-08-11-xstore">send ‘hi’ to xstore@testrun.org</a>
|
||||
to see an experimental webxdc appstore.
|
||||
All of the apps are open source and for free.</li>
|
||||
@@ -1874,6 +1881,35 @@ Otherwise you might receive undecryptable messages from those group chats.</p>
|
||||
<li>Dobrý začátek je <a href="https://github.com/deltachat/deltachat-core-rust/blob/master/standards.md#standards-used-in-delta-chat">Standards used in Delta Chat</a>.</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="where-can-my-friends-find-delta-chat">
|
||||
|
||||
|
||||
Where can my friends find Delta Chat? <a href="#where-can-my-friends-find-delta-chat" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Delta Chat is available for all major and some minor platforms:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>The <strong>official website</strong>, <a href="https://delta.chat/download">https://delta.chat/download</a> shows all options in detail</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>If unavailable, use the <strong>mirror</strong> at <a href="https://deltachat.github.io/deltachat-pages">https://deltachat.github.io/deltachat-pages</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Open one of the following <strong>app stores and search for “Delta Chat”:</strong>
|
||||
Google Play Store, F-Droid, Huawei App Gallery, Amazon App Store, iOS and macOS App Store, Microsoft Store</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Check the <strong>package manager</strong> of your Linux distributions</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Android APKs</strong> are also available on <a href="https://github.com/deltachat/deltachat-android/releases">https://github.com/deltachat/deltachat-android/releases</a></p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="jak-je-financován-vývoj-delta-chatu">
|
||||
|
||||
|
||||
|
||||
@@ -30,14 +30,14 @@
|
||||
<li><a href="#was-sind-push-benachrichtigungen-wie-kann-ich-nachrichten-sofort-erhalten">Was sind Push-Benachrichtigungen? Wie kann ich Nachrichten sofort erhalten?</a></li>
|
||||
<li><a href="#sind-push-benachrichtigungen-auf-ios-geräten-aktiviert-gibt-es-alternativen">Sind Push-Benachrichtigungen auf iOS-Geräten aktiviert? Gibt es Alternativen?</a></li>
|
||||
<li><a href="#android-push">Sind Push-Benachrichtigungen auf Android-Geräten aktiviert/erforderlich?</a></li>
|
||||
<li><a href="#privacy-notifications">Wie privat sind Delta Chat Push-Benachrichtigungen?</a></li>
|
||||
<li><a href="#privacy-notifications">Wie privat sind Delta-Chat-Push-Benachrichtigungen?</a></li>
|
||||
<li><a href="#warum-integriert-sich-delta-chat-in-zentralisierte-proprietäre-applegoogle-push-dienste">Warum integriert sich Delta Chat in zentralisierte, proprietäre Apple/Google-Push-Dienste?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#verschlüsselung-und-sicherheit">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="#whene2e">Wie kann ich wissen, ob Nachrichten Ende-zu-Ende-verschlüsselt sind?</a></li>
|
||||
<li><a href="#howtoe2ee">Wie kann ich garantierte Ende-zu-Ende-Verschlüsselung und grüne Häkchen erhalten?</a></li>
|
||||
<li><a href="#e2eeguarantee">Was bedeuten das “Grüne Häkchen” und die “garantierte Ende-zu-Ende-Verschlüsselung”?</a></li>
|
||||
<li><a href="#nocryptanymore">Ein Kontakt hat eine Nachricht von einem anderen Gerät gesendet”, was kann ich tun?</a></li>
|
||||
@@ -65,10 +65,10 @@
|
||||
<li><a href="#kann-ich-delta-chat-auf-mehreren-geräten-zur-selben-zeit-verwenden">Kann ich Delta Chat auf mehreren Geräten zur selben Zeit verwenden?</a></li>
|
||||
<li><a href="#fehlersuche">Fehlersuche</a></li>
|
||||
<li><a href="#backup">Manueller Transfer</a></li>
|
||||
<li><a href="#gibt-es-pläne-für-eine-delta-chat-web-anwendung">Gibt es Pläne für eine Delta Chat Web-Anwendung?</a></li>
|
||||
<li><a href="#gibt-es-pläne-für-eine-delta-chat-web-anwendung">Gibt es Pläne für eine Delta-Chat-Web-Anwendung?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#webxdc">Webxdc Apps</a>
|
||||
<li><a href="#webxdc">Webxdc-Apps</a>
|
||||
<ul>
|
||||
<li><a href="#wie-privat-sind-webxdc-apps">Wie privat sind Webxdc Apps?</a></li>
|
||||
<li><a href="#wo-bekomme-ich-webxdc-apps">Wo bekomme ich Webxdc Apps?</a></li>
|
||||
@@ -99,6 +99,7 @@
|
||||
<li><a href="#ist-delta-chat-kompatibel-mit-protonmail--tutanota--criptext">Ist Delta Chat kompatibel mit Protonmail / Tutanota / Criptext?</a></li>
|
||||
<li><a href="#remove-account">Wie kann ich mein Konto löschen?</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>
|
||||
<li><a href="#wo-können-meine-freunde-delta-chat-finden">Wo können meine Freunde Delta Chat finden?</a></li>
|
||||
<li><a href="#wie-wird-delta-chat-finanziert">Wie wird Delta Chat finanziert?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
@@ -152,7 +153,7 @@ auch wenn der Empfänger Delta Chat nicht benutzt.</p>
|
||||
die sofortige Push-Benachrichtigungen für iOS- und Android-Geräte bieten.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Durchgängige <a href="#multiple-accounts">Multi-Profil</a> und Multi-Geräte-Unterstützung auf allen Plattformen.</p>
|
||||
<p>Durchgängige <a href="#multiple-accounts">Multi-Profil-</a> und Multi-Geräte-Unterstützung auf allen Plattformen.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Interaktive <a href="https://webxdc.org/apps">Webanwendungen in Chats</a> für Spiele und für die Zusammenarbeit</p>
|
||||
@@ -286,7 +287,7 @@ unter dem Text Ihrer Nachrichten.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Zum Archivieren oder Anheften, tippen Sie lange auf den Chat (Android), verwenden Sie das Chatmenü (Android/Desktop) oder wischen Sie nach links (iOS); zum Stummschalten, verwenden Sie das Chatmenü (Android/Desktop) oder das Chatprofil (iOS).</p>
|
||||
<p>Um die Funktionen zu nutzen, lang auf einen Chat in der Chatliste tippen oder den Chat mit der rechten Maustaste anklicken.</p>
|
||||
|
||||
<h3 id="was-bedeutet-der-grüne-punkt">
|
||||
|
||||
@@ -303,7 +304,7 @@ unter dem Text Ihrer Nachrichten.</p>
|
||||
<li>entweder weil der Kontakt Ihnen direkt eine Nachricht gesendet hat,</li>
|
||||
<li>weil der Kontakt etwas an eine Gruppe geschrieben hat, in der sie beide Mitglied sind,</li>
|
||||
<li>weil der Kontakt Ihnen eine Lesebestätigung für eine von Ihnen geschriebene Nachricht gesendet hat</li>
|
||||
<li>oder weil der Kontakt Daten mithilfe einer <a href="#webxdc">Webxdc App</a> an Ihre Delta Chat-App gesendet hat.</li>
|
||||
<li>oder weil der Kontakt Daten mithilfe einer <a href="#webxdc">Webxdc-App</a> an Ihre Delta-Chat-App gesendet hat.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Dies ist also kein Echtzeit-Online-Status - und wenn jemand nicht sofort antwortet, obwohl er online zu sein scheint, machen Sie sich keine Sorgen und geben Sie ihm etwas Raum. ;-)</li>
|
||||
@@ -486,7 +487,7 @@ und Benachrichtigungen auf dem Telefon des Nutzers anzeigen kann.</p>
|
||||
<p>iOS-Geräten, durch die Integration mit den Apple-Push-Diensten.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Android-Geräten, durch die Integration des Google FCM Push-Dienste,
|
||||
<p>Android-Geräten, durch die Integration des Google-FCM-Push-Dienstes,
|
||||
auch auf Geräten, die <a href="https://microg.org">microG</a>
|
||||
anstelle von proprietärem Google-Code auf dem Telefon.</p>
|
||||
</li>
|
||||
@@ -517,7 +518,7 @@ keine Daten an Apple weitergibt, die Apple nicht bereits hat.</p>
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Wenn ein „Push-Service“ verfügbar ist, aktiviert Delta Chat Push-Benachrichtigungen
|
||||
<p>Wenn ein „Push-Service“ verfügbar ist, aktiviert Delta Chat Push-Benachrichtigungen,
|
||||
um eine sofortige Nachrichtenzustellung für alle Chatmail-Benutzer zu erreichen.
|
||||
Wenn Sie einen klassischen E-Mail-Anbieter anstelle von <a href="https://delta.chat/chatmail">chatmail</a> Servern verwenden,
|
||||
sind Push-Benachrichtigungen nicht verfügbar.</p>
|
||||
@@ -543,7 +544,7 @@ können sicher ausprobiert werden, wenn Sie feststellen, dass Nachrichten nur mi
|
||||
<h3 id="privacy-notifications">
|
||||
|
||||
|
||||
Wie privat sind Delta Chat Push-Benachrichtigungen? <a href="#privacy-notifications" class="anchor"></a>
|
||||
Wie privat sind Delta-Chat-Push-Benachrichtigungen? <a href="#privacy-notifications" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
@@ -560,7 +561,7 @@ an irgendein System, das an der Zustellung von Push-Benachrichtigungen beteiligt
|
||||
auf dem <a href="https://delta.chat/chatmail">Chatmail</a>-Server.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Wenn ein <a href="https://delta.chat/chatmail">Chatmail</a>-Server eine E-Mail für einen Delta Chat-Benutzer erhält
|
||||
<p>Wenn ein <a href="https://delta.chat/chatmail">Chatmail</a>-Server eine E-Mail für einen Delta-Chat-Benutzer erhält
|
||||
erhält, leitet er den „Geräte-Token“ an den zentralen Delta-Chat-Benachrichtigungs-Proxy weiter.</p>
|
||||
</li>
|
||||
<li>
|
||||
@@ -626,7 +627,7 @@ Willkommen bei der Macht des interoperablen und massiven Chatmail- und E-Mail-Sy
|
||||
<p><a href="https://autocrypt.org">Autocrypt</a> wird verwendet, um automatisch
|
||||
eine Ende-zu-Ende-Verschlüsselung mit Kontakten und Gruppenchats herzustellen.
|
||||
Autocrypt verwendet eine begrenzte und <a href="#openpgp-secure">sichere Untermenge des OpenPGP-Standards</a>.
|
||||
Ende-zu-Ende verschlüsselte Nachrichten sind mit einem Vorhängeschloss gekennzeichnet <img style="vertical-align:middle; width:1.2em; margin:1px" src="../lock-icon.png" alt="padlock" /></p>
|
||||
Ende-zu-Ende-verschlüsselte Nachrichten sind mit einem Vorhängeschloss gekennzeichnet <img style="vertical-align:middle; width:1.2em; margin:1px" src="../lock-icon.png" alt="padlock" /></p>
|
||||
|
||||
<p><a href="https://securejoin.delta.chat/en/latest/new.html">Secure-Join-Protokolle</a>
|
||||
werden für Chats mit garantierter Ende-zu-Ende-Verschlüsselung verwendet,
|
||||
@@ -638,7 +639,7 @@ garantieren Ende-zu-Ende-verschlüsselte Nachrichten.</p>
|
||||
<h3 id="whene2e">
|
||||
|
||||
|
||||
Wie kann ich wissen, ob Nachrichten Ende-zu-Ende verschlüsselt sind? <a href="#whene2e" class="anchor"></a>
|
||||
Wie kann ich wissen, ob Nachrichten Ende-zu-Ende-verschlüsselt sind? <a href="#whene2e" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
@@ -729,7 +730,7 @@ Das Einführen geschieht automatisch, wenn Sie Mitglieder zu Gruppen hinzufügen
|
||||
Wer einen Kontakt zu einer Gruppe mit grünem Häkchen hinzufügt, wird zum Einführenden
|
||||
für die Mitglieder, die noch nichts von dem hinzugefügten Kontakt wussten.
|
||||
In einem Kontaktprofil können Sie wiederholt auf den Text “Eingeführt von …” tippen
|
||||
bis du zu demjenigen gelangst, mit dem Sie einen direkten <a href="#howtoe2ee">QR-Scan</a> gemacht haben.</p>
|
||||
bis Sie zu demjenigen gelangen, mit dem Sie einen direkten <a href="#howtoe2ee">QR-Scan</a> gemacht haben.</p>
|
||||
|
||||
<p>Beachten Sie, dass Sie in einem Kontaktprofil unter Umständen Einführende sehen und antippen können, aber kein grünes Häkchen im Profiltitel vorhanden ist.
|
||||
Dies bedeutet normalerweise, dass der Kontakt <a href="#nocryptanymore">“eine Nachricht von einem anderen Gerät gesendet hat”</a>.</p>
|
||||
@@ -760,7 +761,7 @@ auch wenn der Kontakt dort Mitglied ist.</p>
|
||||
<p><strong>Ihr Kontakt verwendet Delta Chat auf einem zweiten Gerät (Smartphone oder Laptop)</strong></p>
|
||||
|
||||
<p>Wenn Ihr Kontakt ein weiteres Gerät mit Delta Chat eingerichtet hat,
|
||||
sollte das Konto von dem neuen Gerät entfernen werden und <a href="#multiclient">als zweites Gerät, wie hier beschrieben</a> erneut hinzugefügt werden.
|
||||
sollte das Konto von dem neuen Gerät entfernen werden und <a href="#multiclient">als zweites Gerät, wie hier beschrieben</a>, erneut hinzugefügt werden.
|
||||
Sobald sie sich danach schreiben, wird die Warnung verschwinden
|
||||
und die Verschlüsselung ist mit beiden Geräten Ihres Kontakts garantiert.</p>
|
||||
|
||||
@@ -882,7 +883,7 @@ wenn dieser falsch ist.</p>
|
||||
<p>Delta Chat war auch nie anfällig für den EFAIL-Angriff “Direct Exfiltration”,
|
||||
da nur <code class="language-plaintext highlighter-rouge">multipart/encrypted</code> Nachrichten entschlüsselt werden,
|
||||
die genau einen verschlüsselten und signierten Teil enthalten;
|
||||
so wie in der Autocrypt Level 1 Spezifikation definiert.</p>
|
||||
so wie in der Autocrypt-Level-1-Spezifikation definiert.</p>
|
||||
|
||||
<h3 id="tls">
|
||||
|
||||
@@ -948,7 +949,7 @@ Nachrichten an die Geräte der Empfänger weiterzuleiten und zuzustellen.</p>
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Sowohl zum Schutz vor E-Mail-Servern, die Metadaten sammeln
|
||||
<p>Sowohl zum Schutz vor E-Mail-Servern, die Metadaten sammeln,
|
||||
als auch gegen die Gefahr der Beschlagnahmung von Geräten
|
||||
empfehlen wir die Verwendung einer für Delta Chat optimierten <a href="https://delta.chat/serverguide">E-Mail-Server-Instanz</a>, um pseudonym-temporäre Konten durch Scannen von QR-Codes zu erstellen.
|
||||
Beachten Sie, dass Delta-Chat-Apps auf allen Plattformen mehrere Konten unterstützen.
|
||||
@@ -995,7 +996,7 @@ ohne Ende-zu-Ende-Unterstützung verwendet.</p>
|
||||
</h3>
|
||||
|
||||
<p>Wenn ein Kontakt keine Autocrypt-fähige App verwendet,
|
||||
werden alle Nachrichten, die diesen Kontakt betreffen (in Gruppen- oder Direkt-Chats)
|
||||
werden alle Nachrichten, die diesen Kontakt betreffen (in Gruppen- oder Direkt-Chats),
|
||||
nicht Ende-zu-Ende-verschlüsselt und zeigen daher kein “Vorhängeschloss”.
|
||||
Beachten Sie, auch Kontakte, die primär Delta Chat verwenden,
|
||||
können gleichzeitig auch nicht-Autocrypt-fähige Apps verwenden.
|
||||
@@ -1011,7 +1012,7 @@ um zu verhindern, dass unlesbare Nachrichten auf der Seite Ihrer Kontakte ankomm
|
||||
</h3>
|
||||
|
||||
<p>Wenn Sie einen sicheren Ende-zu-Ende-verschlüsselten Chat mit einem Kontakt benötigen,
|
||||
der sowohl Delta Chat als auch nicht-Autocrypt-Anwendungen nutzt,
|
||||
der sowohl Delta Chat als auch Nicht-Autocrypt-Anwendungen nutzt,
|
||||
können Sie eine <a href="#howtoe2ee">garantierte Ende-zu-Ende-Verschlüsselung</a> einrichten, mit einer Gruppe mit Ihnen beiden als Mitgliedern.
|
||||
In diesem Gruppenchat werden alle Nachrichten Ende-zu-Ende verschlüsselt werdejn,
|
||||
auch wenn im Direkt-Chat eine
|
||||
@@ -1025,10 +1026,10 @@ auch wenn im Direkt-Chat eine
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Der beste Weg, um sicherzustellen, dass alle Nachrichten Ende-zu-Ende verschlüsselt sind
|
||||
<p>Der beste Weg, um sicherzustellen, dass alle Nachrichten Ende-zu-Ende-verschlüsselt sind
|
||||
und Metadaten so schnell wie möglich gelöscht werden,
|
||||
ist <a href="#howtoe2ee">die Verwendung von Chats mit garantierter Ende-zu-Ende-Verschlüsselung</a>
|
||||
und die Aktivierung von <a href="#ephemeralmsgs">Verschwindende Nachrichten</a>.</p>
|
||||
und die Aktivierung von <a href="#ephemeralmsgs">verschwindenden Nachrichten</a>.</p>
|
||||
|
||||
<p>Garantierte Ende-zu-Ende-Verschlüsselung schützt vor <a href="https://en.wikipedia.org/wiki/Man-in-the-middle_attack">MITM-Angriffen</a>
|
||||
und das Aktivieren von “Verschwindende Nachrichten” löscht die Nachrichten
|
||||
@@ -1045,7 +1046,7 @@ auf dem Server und Lokal nach einer vom Benutzer eingestellten Zeit.</p>
|
||||
</h3>
|
||||
|
||||
<p>Nein, Delta Chat unterstützt kein “Perfect Forward Secrecy” (PFS).
|
||||
Das bedeutet, dass wenn Ihr privater Delta-Chat-Schlüssel durchgesickert ist,
|
||||
Das bedeutet, wenn Ihr privater Delta-Chat-Schlüssel durchgesickert ist
|
||||
und jemand Ihre vorherigen In-Transit-Nachrichten gesammelt hat,
|
||||
können diese mit dem veröffentlichtem Schlüssel entschlüsselt werden.</p>
|
||||
|
||||
@@ -1056,7 +1057,7 @@ Die typische, reale Situation für durchgesickerte private Schlüssel, ist die <
|
||||
OpenPGP ist nur ein Container für verschlüsselte Nachrichten mit dem
|
||||
die Verwaltung der Schlüssel (und damit die Schlüsselrotation oder das Schlüssel-“Ratcheting”)
|
||||
auf flexible Weise organisiert werden kann.
|
||||
Siehe <a href="https://gitlab.com/sequoia-pgp/openpgp-dr">Seqouia’s PFS-Prototyp</a>
|
||||
Siehe <a href="https://gitlab.com/sequoia-pgp/openpgp-dr">Seqouias PFS-Prototyp</a>
|
||||
für bestehende Experimente in der OpenPGP-Community.</p>
|
||||
|
||||
<h3 id="ist-die-ende-zu-ende-verschlüsselung-von-delta-chat-genauso-sicher-wie-die-von-signal">
|
||||
@@ -1145,7 +1146,7 @@ Für andere Programme können Sie online eine Lösung finden.</p>
|
||||
Weitere Informationen finden Sie in unserem Blogbeitrag über <a href="https://delta.chat/en/2024-03-25-crypto-analysis-securejoin">Hardening Guaranteed End-to-End encryption</a> und in der hinterher publizierten <a href="https://eprint.iacr.org/2024/918.pdf">Kryptografischen Analyse von Delta Chat</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Im April 2023 haben wir Sicherheits- und Datenschutzprobleme mit den “In Chats geteilten Apps”-Feature behoben, die mit Fehlern beim Sandboxing, insbesondere mit Chromium zusammenhängen. Wir haben daraufhin eine unabhängige Sicherheitsprüfung von Cure53 durchführen lassen, und alle gefundenen Probleme wurden mit den im April 2023 veröffentlichten 1.36 Releases behoben. Siehe <a href="https://delta.chat/en/2023-05-22-webxdc-security">hier für die vollständige Hintergrundgeschichte</a>.</p>
|
||||
<p>Im April 2023 haben wir Sicherheits- und Datenschutzprobleme mit dem “In Chats geteilten Apps”-Feature behoben, die mit Fehlern beim Sandboxing, insbesondere mit Chromium zusammenhängen. Wir haben daraufhin eine unabhängige Sicherheitsprüfung von Cure53 durchführen lassen, und alle gefundenen Probleme wurden mit den im April 2023 veröffentlichten 1.36 Releases behoben. Siehe <a href="https://delta.chat/en/2023-05-22-webxdc-security">hier für die vollständige Hintergrundgeschichte</a>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Im März 2023 analysierte <a href="https://cure53.de">Cure53</a> sowohl die Transportverschlüsselung von Delta Chats Netzwerkverbindungen als auch das reproduzierbare Mailserver-Setup wie <a href="https://delta.chat/de/serverguide">auf dieser Seite empfohlen</a>. Sie können mehr über das Audit <a href="https://delta.chat/en/2023-03-27-third-independent-security-audit">in unserem Blog</a> lesen oder Sie lesen den <a href="https://delta.chat/assets/blog/MER-01-report.pdf">vollständigen Bericht hier</a>.</p>
|
||||
@@ -1155,7 +1156,7 @@ Weitere Informationen finden Sie in unserem Blogbeitrag über <a href="https://d
|
||||
Es wurden keine kritischen oder hochgradig gefährlichen Probleme gefunden. Der Bericht wies auf einige Schwachstellen mittlerer Schwere hin - sie stellen für sich genommen keine Bedrohung für Delta-Chat-Benutzer dar, da sie von der Umgebung abhängen, in der Delta Chat verwendet wird. Aus Gründen der Benutzerfreundlichkeit und der Kompatibilität können wir nicht alle Schwachstellen beseitigen und haben beschlossen, Sicherheitsempfehlungen für bedrohte Benutzer zu geben. Sie können den <a href="https://delta.chat/assets/blog/2020-second-security-review.pdf">vollständigen Bericht hier</a> lesen.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Im Jahr 2019 analysierte <a href="https://includesecurity.com">Include Security</a> die von Delta Chat verwendeten <a href="https://github.com/rpgp/rpgp">PGP</a> und <a href="https://github.com/RustCrypto/RSA">RSA</a> Bibliotheken.
|
||||
<p>Im Jahr 2019 analysierte <a href="https://includesecurity.com">Include Security</a> die von Delta Chat verwendeten <a href="https://github.com/rpgp/rpgp">PGP-</a> und <a href="https://github.com/RustCrypto/RSA">RSA-</a> Bibliotheken.
|
||||
Es wurden keine kritischen Probleme gefunden, aber zwei Probleme mit hohem Schweregrad, die wir anschließend behoben haben. Außerdem wurden ein mittelschweres und einige weniger schwerwiegende Probleme gefunden, aber es gab keine Möglichkeit, diese Schwachstellen in der Delta-Chat-Implementierung auszunutzen. Einige dieser Schwachstellen haben wir dennoch nach Abschluss des Audits behoben. Sie können den [vollständigen Bericht hier] lesen (../assets/blog/2019-first-security-review.pdf).</p>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -1215,6 +1216,12 @@ Es wurden keine kritischen Probleme gefunden, aber zwei Probleme mit hohem Schwe
|
||||
und sicherstellen, dass <strong>Privates Netzwerk</strong> als “Netzwerkprofiltyp” ausgewählt ist.
|
||||
(nach der Übertragung kann wieder der ursprüngliche Wert verwendet werden)</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Auf <strong>iOS</strong>, sicherstellen, dass „Systemeinstellungen / Apps / Delta Chat / <strong>Lokales Netzwerk</strong>“ eingeschaltet ist</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Auf <strong>macOS,</strong> „Systemeinstellungen / Datenschutz & Sicherheit / <strong>Lokales Netzwerk</strong> / Delta Chat“ aktivieren</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Ihr System verfügt möglicherweise über eine “Personal Firewall”, diese sind dafür bekannt, Probleme zu verursachen (insbesondere bei Windows). <strong>Deaktivieren Sie die Personal Firewall</strong> für Delta Chat auf beiden Seiten und versuchen Sie es erneut</p>
|
||||
</li>
|
||||
@@ -1253,32 +1260,32 @@ Verwenden Sie nach Möglichkeit ein Nicht-Gast-Netzwerk. Wenn Sie Zugriff auf de
|
||||
<li><strong>Wenn Sie iOS verwenden</strong> und auf Schwierigkeiten stoßen, hilft Ihnen vielleicht <a href="https://support.delta.chat/t/import-backup-to-ios/1628">diese Anleitung</a>.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Sie sind nun synchronisiert und können beide Geräte zum Senden und Empfangen von Ende-zu-Ende verschlüsselten Nachrichten mit Ihren Kommunikationspartnern verwenden.</li>
|
||||
<li>Sie sind nun synchronisiert und können beide Geräte zum Senden und Empfangen von Ende-zu-Ende-verschlüsselten-Nachrichten mit Ihren Kommunikationspartnern verwenden.</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="gibt-es-pläne-für-eine-delta-chat-web-anwendung">
|
||||
|
||||
|
||||
Gibt es Pläne für eine Delta Chat Web-Anwendung? <a href="#gibt-es-pläne-für-eine-delta-chat-web-anwendung" class="anchor"></a>
|
||||
Gibt es Pläne für eine Delta-Chat-Web-Anwendung? <a href="#gibt-es-pläne-für-eine-delta-chat-web-anwendung" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>Es gibt keine direkten Pläne, aber einige vorläufige Gedanken.</li>
|
||||
<li>Es gibt 2-3 Möglichkeiten, einen Delta Chat Web-Client einzuführen, aber sie bedeuten alle immense Arbeit. Im Moment fokussieren wir uns darauf, stabile native Apps in den Appstores (Google Play/iOS/Windows/macOS/Linux repositories) anzubieten.</li>
|
||||
<li>Sollten Sie einen Web-Client benötigen, weil Sie auf Ihrem Arbeitsrechner keine Software installieren dürfen, können Sie den Windows Desktop-Client bzw. Applmage für Linux nutzen. Sie finden diese unter <a href="https://get.delta.chat">get.delta.chat</a>.</li>
|
||||
<li>Es gibt 2-3 Möglichkeiten, einen Delta-Chat-Web-Client einzuführen, aber sie bedeuten alle immense Arbeit. Im Moment fokussieren wir uns darauf, stabile native Apps in den Appstores (Google Play/iOS/Windows/macOS/Linux repositories) anzubieten.</li>
|
||||
<li>Sollten Sie einen Web-Client benötigen, weil Sie auf Ihrem Arbeitsrechner keine Software installieren dürfen, können Sie den Windows-Desktop-Client bzw. Applmage für Linux nutzen. Sie finden diese unter <a href="https://get.delta.chat">get.delta.chat</a>.</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="webxdc">
|
||||
|
||||
|
||||
Webxdc Apps <a href="#webxdc" class="anchor"></a>
|
||||
Webxdc-Apps <a href="#webxdc" class="anchor"></a>
|
||||
|
||||
|
||||
</h2>
|
||||
|
||||
<p>In Delta Chat können Sie <a href="https://webxdc.org">Webxdc Apps</a>, Anhänge mit der Dateierweiterung “.xdc” teilen. Sie können sehr unterschiedliche Dinge tun und machen Delta Chat zu einem wirklich erweiterbaren Messenger.</p>
|
||||
<p>In Delta Chat können Sie <a href="https://webxdc.org">Webxdc-Apps</a>, Anhänge mit der Dateierweiterung “.xdc” teilen. Sie können sehr unterschiedliche Dinge tun und machen Delta Chat zu einem wirklich erweiterbaren Messenger.</p>
|
||||
|
||||
<h3 id="wie-privat-sind-webxdc-apps">
|
||||
|
||||
@@ -1304,7 +1311,8 @@ Verwenden Sie nach Möglichkeit ein Nicht-Gast-Netzwerk. Wenn Sie Zugriff auf de
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>Grundsätzlich kann jeder Webxdc Apps mit anderen ohne Einschränkungen teilen.</li>
|
||||
<li>Grundsätzlich kann jeder Webxdc-Apps mit anderen ohne Einschränkungen teilen.</li>
|
||||
<li>Von <a href="https://webxdc.org/apps/">webxdc.org/apps</a>.</li>
|
||||
<li>Sie können <a href="https://delta.chat/en/2023-08-11-xstore">‘hallo’ an xstore@testrun.org senden</a>
|
||||
um einen experimentellen Webxdc Appstore zu sehen.
|
||||
Alle Apps dort sind Open Source und umsonst.</li>
|
||||
@@ -1322,7 +1330,7 @@ forum</a> veröffentlicht und diskutiert.</li>
|
||||
|
||||
<ul>
|
||||
<li>Webxdc Apps sind nur ZIP-Dateien, die HTML-, CSS- und JavaScript-Code enthalten.</li>
|
||||
<li>Sie können die <a href="https://github.com/webxdc/hello">Hello World-Beispiel-App</a> erweitern, um loszulegen.</li>
|
||||
<li>Sie können die <a href="https://github.com/webxdc/hello">Hello-World-Beispiel-App</a> erweitern, um loszulegen.</li>
|
||||
<li>Alles andere, was Sie wissen müssen, steht in der <a href="https://docs.webxdc.org/">Dokumentation</a>.</li>
|
||||
<li>Wenn Sie Fragen haben, können Sie andere mit Erfahrung im <a href="https://support.delta.chat/c/webxdc/20">Delta-Chat-Forum</a> fragen.</li>
|
||||
</ul>
|
||||
@@ -1635,7 +1643,7 @@ wenn Sie eine <a href="#signature">Signaturtext</a> einfügen.</p>
|
||||
<ul>
|
||||
<li>Ja und Nein.</li>
|
||||
<li>Nein, Sie können sich nicht mit Delta Chat in ein Protonmail-, Tutanota- oder Criptext-Konto einloggen, da diese keinen Standard-E-Mail-Empfang über IMAP anbieten.</li>
|
||||
<li>Ja, Sie können Delta Chat verwenden, um Nachrichten an Personen zu senden, die Protonmail, Tutanota oder Criptext verwenden. Diese Nachrichten werden jedoch nicht ende-zu-ende-verschlüsselt, da diese Anbieter keine mit dem <a href="https://autocrypt.org/">Autocrypt</a>-Standard kompatible Verschlüsselung verwenden.</li>
|
||||
<li>Ja, Sie können Delta Chat verwenden, um Nachrichten an Personen zu senden, die Protonmail, Tutanota oder Criptext verwenden. Diese Nachrichten werden jedoch nicht Ende-zu-Ende-verschlüsselt, da diese Anbieter keine mit dem <a href="https://autocrypt.org/">Autocrypt</a>-Standard kompatible Verschlüsselung verwenden.</li>
|
||||
<li>Delta Chat kann Ende-zu-Ende-Verschlüsselung über jeden E-Mail-Anbieter mit jeder
|
||||
<a href="https://autocrypt.org/dev-status.html">Autocrypt-fähige E-Mail-Anwendung</a> herstellen</li>
|
||||
</ul>
|
||||
@@ -1680,6 +1688,34 @@ Andernfalls könnten Sie unverschlüsselte Nachrichten aus diesen Gruppenchats e
|
||||
<li>Siehe hierzu <a href="https://github.com/deltachat/deltachat-core-rust/blob/master/standards.md#standards-used-in-delta-chat">in Delta Chat genutzte Standards</a>.</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="wo-können-meine-freunde-delta-chat-finden">
|
||||
|
||||
|
||||
Wo können meine Freunde Delta Chat finden? <a href="#wo-können-meine-freunde-delta-chat-finden" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Delta Chat ist für alle großen und einige kleinere Plattformen verfügbar:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>Die <strong>offizielle Website</strong>, <a href="https://delta.chat/download">https://delta.chat/download</a> zeigt alle Optionen im Detail</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Falls nicht verfügbar, verwenden Sie den <strong>Mirror</strong> auf <a href="https://deltachat.github.io/deltachat-pages">https://deltachat.github.io/deltachat-pages</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Öffnen Sie einen der folgenden <strong>App-Stores und suchen Sie nach „Delta Chat“:</strong> Google Play Store, F-Droid, Huawei App Gallery, Amazon App Store, iOS und macOS App Store, Microsoft Store</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Im <strong>Paketmanager</strong> Ihrer Linux-Distribution nachschauen</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Android-APKs</strong> sind auch auf <a href="https://github.com/deltachat/deltachat-android/releases">https://github.com/deltachat/deltachat-android/releases</a> verfügbar.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="wie-wird-delta-chat-finanziert">
|
||||
|
||||
|
||||
@@ -1705,10 +1741,10 @@ 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>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>
|
||||
</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>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>
|
||||
</li>
|
||||
<li>
|
||||
<p>2023-2024 schlossen wir erfolgreich das vom OTF finanzierte
|
||||
@@ -1718,11 +1754,11 @@ das <a href="https://delta.chat/chatmail">Chatmail-Server-Netzwerk</a>
|
||||
und „Instant Onboarding“ allen ab April 2024 veröffentlichten Anwendungen hinzu.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>2023 und 2024 wurden wir in das Next Generation Internet (NGI)
|
||||
Programm für unsere Arbeit an <a href="https://nlnet.nl/project/WebXDC-Push/">webxdc PUSH</a> aufgenommen,
|
||||
<p>2023 und 2024 wurden wir in das Next-Generation-Internet-Programm (NGI)
|
||||
für unsere Arbeit an <a href="https://nlnet.nl/project/WebXDC-Push/">Webxdc-PUSH</a> aufgenommen,
|
||||
zusammen mit Kooperationspartnern, die an
|
||||
<a href="https://nlnet.nl/project/Webxdc-Evolve/">webxdc evolve</a>,
|
||||
<a href="https://nlnet.nl/project/WebXDC-XMPP/">webxdc XMPP</a>,
|
||||
<a href="https://nlnet.nl/project/Webxdc-Evolve/">Webxdc-Evolve</a>,
|
||||
<a href="https://nlnet.nl/project/WebXDC-XMPP/">Webxdc-XMPP</a>,
|
||||
<a href="https://nlnet.nl/project/DeltaTouch/">DeltaTouch</a> und
|
||||
<a href="https://nlnet.nl/project/DeltaTauri/">DeltaTauri</a>.
|
||||
Alle diese Projekte sind teilweise abgeschlossen oder sollen Anfang 2025 abgeschlossen werden.</p>
|
||||
@@ -1740,7 +1776,7 @@ Der Erhalt von Spenden hilft uns auch, unabhängiger und langfristig lebensfähi
|
||||
|
||||
<p>Die oben aufgeführte finanzielle Förderung wird hauptsächlich von der merlinux GmbH in Freiburg (Deutschland) organisiert und an mehr als ein Dutzend Mitwirkende weltweit verteilt.</p>
|
||||
|
||||
<p>Möglichkeiten mitzuwirken finden Sie Auf der <a href="https://delta.chat/de/contribute">Delta Chat Seite “Mitwirken”</a>.</p>
|
||||
<p>Möglichkeiten mitzuwirken finden Sie Auf der <a href="https://delta.chat/de/contribute">Delta-Chat-Seite “Mitwirken”</a>.</p>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -99,6 +99,7 @@
|
||||
<li><a href="#is-delta-chat-compatible-with-protonmail--tutanota--criptext">Is Delta Chat compatible with Protonmail / Tutanota / Criptext?</a></li>
|
||||
<li><a href="#remove-account">How can I delete my account?</a></li>
|
||||
<li><a href="#im-interested-in-the-technical-details-can-you-tell-me-more">I’m interested in the technical details. Can you tell me more?</a></li>
|
||||
<li><a href="#where-can-my-friends-find-delta-chat">Where can my friends find Delta Chat?</a></li>
|
||||
<li><a href="#how-are-delta-chat-developments-funded">How are Delta Chat developments funded?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
@@ -301,8 +302,7 @@ Archived chats remain accessible above the chat list or via search.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>To archive or pin a chat, long tap (Android), use the chat’s menu (Android/Desktop) or swipe to the left (iOS);
|
||||
to mute a chat, use the chat’s menu (Android/Desktop) or the chat’s profile (iOS).</p>
|
||||
<p>To use the functions, long tap or right click a chat in the chat list.</p>
|
||||
|
||||
<h3 id="what-does-the-green-dot-mean">
|
||||
|
||||
@@ -1315,6 +1315,12 @@ One device is not needed for the other to work.</p>
|
||||
and make sure, <strong>Private Network</strong> is selected as “Network profile type”
|
||||
(after transfer, you can change back to the original value)</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>On <strong>iOS</strong>, make sure “System Settings / Apps / Delta Chat / <strong>Local Network</strong>” access is granted</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>On <strong>macOS</strong>, enable “System Settings / Privacy & Security / <strong>Local Network</strong> / Delta Chat”</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Your system might have a “personal firewall”,
|
||||
which is known to cause problems (especially on Windows).
|
||||
@@ -1432,6 +1438,7 @@ you only open attachments from senders you trust, and not from spammers.</li>
|
||||
<ul>
|
||||
<li>In general, anyone can share webxdc apps with each
|
||||
other without restrictions.</li>
|
||||
<li>From <a href="https://webxdc.org/apps/">webxdc.org/apps</a>.</li>
|
||||
<li>You can <a href="https://delta.chat/en/2023-08-11-xstore">send ‘hi’ to xstore@testrun.org</a>
|
||||
to see an experimental webxdc appstore.
|
||||
All of the apps are open source and for free.</li>
|
||||
@@ -1883,6 +1890,35 @@ Otherwise you might receive undecryptable messages from those group chats.</p>
|
||||
<li>See <a href="https://github.com/deltachat/deltachat-core-rust/blob/master/standards.md#standards-used-in-delta-chat">Standards used in Delta Chat</a>.</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="where-can-my-friends-find-delta-chat">
|
||||
|
||||
|
||||
Where can my friends find Delta Chat? <a href="#where-can-my-friends-find-delta-chat" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Delta Chat is available for all major and some minor platforms:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>The <strong>official website</strong>, <a href="https://delta.chat/download">https://delta.chat/download</a> shows all options in detail</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>If unavailable, use the <strong>mirror</strong> at <a href="https://deltachat.github.io/deltachat-pages">https://deltachat.github.io/deltachat-pages</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Open one of the following <strong>app stores and search for “Delta Chat”:</strong>
|
||||
Google Play Store, F-Droid, Huawei App Gallery, Amazon App Store, iOS and macOS App Store, Microsoft Store</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Check the <strong>package manager</strong> of your Linux distributions</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Android APKs</strong> are also available on <a href="https://github.com/deltachat/deltachat-android/releases">https://github.com/deltachat/deltachat-android/releases</a></p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="how-are-delta-chat-developments-funded">
|
||||
|
||||
|
||||
|
||||
@@ -99,6 +99,7 @@
|
||||
<li><a href="#delta-chat-es-compatible-con-protonmail--tutanota--criptext">¿Delta Chat es compatible con Protonmail / Tutanota / Criptext?</a></li>
|
||||
<li><a href="#remove-account">¿Cómo puedo eliminar mi cuenta?</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>
|
||||
<li><a href="#where-can-my-friends-find-delta-chat">Where can my friends find Delta Chat?</a></li>
|
||||
<li><a href="#cómo-se-financia-el-desarrollo-de-delta-chat">¿Cómo se financia el desarrollo de Delta Chat?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
@@ -1277,6 +1278,12 @@ No es necesario un dispositivo para que el otro funcione.</p>
|
||||
and make sure, <strong>Private Network</strong> is selected as “Network profile type”
|
||||
(after transfer, you can change back to the original value)</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>On <strong>iOS</strong>, make sure “System Settings / Apps / Delta Chat / <strong>Local Network</strong>” access is granted</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>On <strong>macOS</strong>, enable “System Settings / Privacy & Security / <strong>Local Network</strong> / Delta Chat”</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Your system might have a “personal firewall”,
|
||||
which is known to cause problems (especially on Windows).
|
||||
@@ -1394,6 +1401,7 @@ solo abre archivos adjuntos de remitentes en los que confía y no de spammers.</
|
||||
<ul>
|
||||
<li>In general, anyone can share webxdc apps with each
|
||||
other without restrictions.</li>
|
||||
<li>From <a href="https://webxdc.org/apps/">webxdc.org/apps</a>.</li>
|
||||
<li>You can <a href="https://delta.chat/en/2023-08-11-xstore">send ‘hi’ to xstore@testrun.org</a>
|
||||
to see an experimental webxdc appstore.
|
||||
All of the apps are open source and for free.</li>
|
||||
@@ -1827,6 +1835,35 @@ Otherwise you might receive undecryptable messages from those group chats.</p>
|
||||
<li>Visita la página <a href="https://github.com/deltachat/deltachat-core-rust/blob/master/standards.md#standards-used-in-delta-chat">Estándares usados en Delta Chat</a>.</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="where-can-my-friends-find-delta-chat">
|
||||
|
||||
|
||||
Where can my friends find Delta Chat? <a href="#where-can-my-friends-find-delta-chat" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Delta Chat is available for all major and some minor platforms:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>The <strong>official website</strong>, <a href="https://delta.chat/download">https://delta.chat/download</a> shows all options in detail</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>If unavailable, use the <strong>mirror</strong> at <a href="https://deltachat.github.io/deltachat-pages">https://deltachat.github.io/deltachat-pages</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Open one of the following <strong>app stores and search for “Delta Chat”:</strong>
|
||||
Google Play Store, F-Droid, Huawei App Gallery, Amazon App Store, iOS and macOS App Store, Microsoft Store</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Check the <strong>package manager</strong> of your Linux distributions</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Android APKs</strong> are also available on <a href="https://github.com/deltachat/deltachat-android/releases">https://github.com/deltachat/deltachat-android/releases</a></p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="cómo-se-financia-el-desarrollo-de-delta-chat">
|
||||
|
||||
|
||||
|
||||
@@ -99,6 +99,7 @@
|
||||
<li><a href="#delta-chat-est-il-compatible-avec-protonmail--tutanota--criptext-">Delta Chat est-il compatible avec Protonmail / Tutanota / Criptext ?</a></li>
|
||||
<li><a href="#remove-account">Comment supprimer mon compte ?</a></li>
|
||||
<li><a href="#les-détails-techniques-mintéressent-pouvez-vous-men-dire-plus-">Les détails techniques m’intéressent. Pouvez-vous m’en dire plus ?</a></li>
|
||||
<li><a href="#where-can-my-friends-find-delta-chat">Where can my friends find Delta Chat?</a></li>
|
||||
<li><a href="#comment-est-financé-le-développement-de-delta-chat-">Comment est financé le développement de Delta Chat ?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
@@ -1262,6 +1263,12 @@ L’un n’a pas besoin de l’autre pour pouvoir fonctionner.</p>
|
||||
and make sure, <strong>Private Network</strong> is selected as “Network profile type”
|
||||
(after transfer, you can change back to the original value)</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>On <strong>iOS</strong>, make sure “System Settings / Apps / Delta Chat / <strong>Local Network</strong>” access is granted</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>On <strong>macOS</strong>, enable “System Settings / Privacy & Security / <strong>Local Network</strong> / Delta Chat”</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Il se peut que votre système dispose d’un “pare-feu personnalisé”,
|
||||
source bien connue de dysfonctionnements (en particulier sur Windows).
|
||||
@@ -1375,6 +1382,7 @@ you only open attachments from senders you trust, and not from spammers.</li>
|
||||
<ul>
|
||||
<li>In general, anyone can share webxdc apps with each
|
||||
other without restrictions.</li>
|
||||
<li>From <a href="https://webxdc.org/apps/">webxdc.org/apps</a>.</li>
|
||||
<li>You can <a href="https://delta.chat/en/2023-08-11-xstore">send ‘hi’ to xstore@testrun.org</a>
|
||||
to see an experimental webxdc appstore.
|
||||
All of the apps are open source and for free.</li>
|
||||
@@ -1789,6 +1797,35 @@ Otherwise you might receive undecryptable messages from those group chats.</p>
|
||||
<li>Consultez les <a href="https://github.com/deltachat/deltachat-core-rust/blob/master/standards.md#standards-used-in-delta-chat">standards utilisés dans Delta Chat</a>.</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="where-can-my-friends-find-delta-chat">
|
||||
|
||||
|
||||
Where can my friends find Delta Chat? <a href="#where-can-my-friends-find-delta-chat" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Delta Chat is available for all major and some minor platforms:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>The <strong>official website</strong>, <a href="https://delta.chat/download">https://delta.chat/download</a> shows all options in detail</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>If unavailable, use the <strong>mirror</strong> at <a href="https://deltachat.github.io/deltachat-pages">https://deltachat.github.io/deltachat-pages</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Open one of the following <strong>app stores and search for “Delta Chat”:</strong>
|
||||
Google Play Store, F-Droid, Huawei App Gallery, Amazon App Store, iOS and macOS App Store, Microsoft Store</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Check the <strong>package manager</strong> of your Linux distributions</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Android APKs</strong> are also available on <a href="https://github.com/deltachat/deltachat-android/releases">https://github.com/deltachat/deltachat-android/releases</a></p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="comment-est-financé-le-développement-de-delta-chat-">
|
||||
|
||||
|
||||
|
||||
@@ -99,6 +99,7 @@
|
||||
<li><a href="#is-delta-chat-compatible-with-protonmail--tutanota--criptext">Is Delta Chat compatible with Protonmail / Tutanota / Criptext?</a></li>
|
||||
<li><a href="#remove-account">How can I delete my account?</a></li>
|
||||
<li><a href="#im-interested-in-the-technical-details-can-you-tell-me-more">I’m interested in the technical details. Can you tell me more?</a></li>
|
||||
<li><a href="#where-can-my-friends-find-delta-chat">Where can my friends find Delta Chat?</a></li>
|
||||
<li><a href="#how-are-delta-chat-developments-funded">How are Delta Chat developments funded?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
@@ -301,8 +302,7 @@ Archived chats remain accessible above the chat list or via search.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>To archive or pin a chat, long tap (Android), use the chat’s menu (Android/Desktop) or swipe to the left (iOS);
|
||||
to mute a chat, use the chat’s menu (Android/Desktop) or the chat’s profile (iOS).</p>
|
||||
<p>To use the functions, long tap or right click a chat in the chat list.</p>
|
||||
|
||||
<h3 id="what-does-the-green-dot-mean">
|
||||
|
||||
@@ -1315,6 +1315,12 @@ One device is not needed for the other to work.</p>
|
||||
and make sure, <strong>Private Network</strong> is selected as “Network profile type”
|
||||
(after transfer, you can change back to the original value)</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>On <strong>iOS</strong>, make sure “System Settings / Apps / Delta Chat / <strong>Local Network</strong>” access is granted</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>On <strong>macOS</strong>, enable “System Settings / Privacy & Security / <strong>Local Network</strong> / Delta Chat”</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Your system might have a “personal firewall”,
|
||||
which is known to cause problems (especially on Windows).
|
||||
@@ -1432,6 +1438,7 @@ you only open attachments from senders you trust, and not from spammers.</li>
|
||||
<ul>
|
||||
<li>In general, anyone can share webxdc apps with each
|
||||
other without restrictions.</li>
|
||||
<li>From <a href="https://webxdc.org/apps/">webxdc.org/apps</a>.</li>
|
||||
<li>You can <a href="https://delta.chat/en/2023-08-11-xstore">send ‘hi’ to xstore@testrun.org</a>
|
||||
to see an experimental webxdc appstore.
|
||||
All of the apps are open source and for free.</li>
|
||||
@@ -1883,6 +1890,35 @@ Otherwise you might receive undecryptable messages from those group chats.</p>
|
||||
<li>See <a href="https://github.com/deltachat/deltachat-core-rust/blob/master/standards.md#standards-used-in-delta-chat">Standards used in Delta Chat</a>.</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="where-can-my-friends-find-delta-chat">
|
||||
|
||||
|
||||
Where can my friends find Delta Chat? <a href="#where-can-my-friends-find-delta-chat" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Delta Chat is available for all major and some minor platforms:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>The <strong>official website</strong>, <a href="https://delta.chat/download">https://delta.chat/download</a> shows all options in detail</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>If unavailable, use the <strong>mirror</strong> at <a href="https://deltachat.github.io/deltachat-pages">https://deltachat.github.io/deltachat-pages</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Open one of the following <strong>app stores and search for “Delta Chat”:</strong>
|
||||
Google Play Store, F-Droid, Huawei App Gallery, Amazon App Store, iOS and macOS App Store, Microsoft Store</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Check the <strong>package manager</strong> of your Linux distributions</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Android APKs</strong> are also available on <a href="https://github.com/deltachat/deltachat-android/releases">https://github.com/deltachat/deltachat-android/releases</a></p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="how-are-delta-chat-developments-funded">
|
||||
|
||||
|
||||
|
||||
@@ -99,6 +99,7 @@
|
||||
<li><a href="#delta-chat-è-compatibile-con-protonmail--tutanota--criptext">Delta Chat è compatibile con Protonmail / Tutanota / Criptext?</a></li>
|
||||
<li><a href="#remove-account">Come posso eliminare il mio profilo?</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>
|
||||
<li><a href="#dove-possono-trovare-delta-chat-i-miei-amici">Dove possono trovare Delta Chat i miei amici?</a></li>
|
||||
<li><a href="#come-viene-finanziato-lo-sviluppo-di-delta-chat">Come viene finanziato lo sviluppo di Delta Chat?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
@@ -1302,6 +1303,12 @@ Un dispositivo non è necessario perché l’altro funzioni.</p>
|
||||
e assicurati che <strong>Rete Privata</strong> sia selezionata come “Tipo di profilo di rete”
|
||||
(dopo il trasferimento è possibile ripristinare il valore originale)</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Su <strong>iOS</strong>, assicurati che l’accesso a “Impostazioni di Sistema / App / Delta Chat / <strong>Rete locale</strong>” sia concesso</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Su <strong>macOS</strong>, abilita “Impostazioni di Sistema / Privacy & Sicurezza / <strong>Rete locale</strong> / Delta Chat”</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Il sistema potrebbe avere un “personal firewall”,
|
||||
che è noto per causare problemi (soprattutto su Windows).
|
||||
@@ -1845,6 +1852,35 @@ Altrimenti potresti ricevere messaggi non decifrabili da quelle chat di gruppo.<
|
||||
<li>Vedi <a href="https://github.com/deltachat/deltachat-core-rust/blob/master/standards.md#standards-used-in-delta-chat">Standard usati in Delta Chat</a>.</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="dove-possono-trovare-delta-chat-i-miei-amici">
|
||||
|
||||
|
||||
Dove possono trovare Delta Chat i miei amici? <a href="#dove-possono-trovare-delta-chat-i-miei-amici" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Delta Chat è disponibile per tutte le piattaforme principali e alcune minori:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>Il <strong>sito ufficiale</strong>, <a href="https://delta.chat/download">https://delta.chat/download</a> mostra tutte le opzioni in dettaglio</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Se non disponibile, utilizzare <strong>mirror</strong> su <a href="https://deltachat.github.io/deltachat-pages">https://deltachat.github.io/deltachat-pages</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Apri uno dei seguenti <strong>app store e cerca “Delta Chat”:</strong>
|
||||
Google Play Store, F-Droid, Huawei App Gallery, Amazon App Store, iOS e macOS App Store, Microsoft Store</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Controlla il <strong>gestore pacchetti</strong> delle tue distribuzioni Linux</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>APK Android</strong> sono disponibili anche su <a href="https://github.com/deltachat/deltachat-android/releases">https://github.com/deltachat/deltachat-android/releases</a></p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="come-viene-finanziato-lo-sviluppo-di-delta-chat">
|
||||
|
||||
|
||||
|
||||
@@ -99,6 +99,7 @@
|
||||
<li><a href="#is-delta-chat-compatibel-met-protonmailtutanotacriptext">Is Delta Chat compatibel met Protonmail/Tutanota/Criptext?</a></li>
|
||||
<li><a href="#remove-account">Hoe kan ik mijn account verwijderen?</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>
|
||||
<li><a href="#where-can-my-friends-find-delta-chat">Where can my friends find Delta Chat?</a></li>
|
||||
<li><a href="#hoe-wordt-de-ontwikkeling-van-delta-chat-gefinancierd">Hoe wordt de ontwikkeling van Delta Chat gefinancierd?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
@@ -1306,6 +1307,12 @@ op beide apparaten</strong>. Hierdoor hoef je niet het ene apparaat bij de hand
|
||||
and make sure, <strong>Private Network</strong> is selected as “Network profile type”
|
||||
(after transfer, you can change back to the original value)</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>On <strong>iOS</strong>, make sure “System Settings / Apps / Delta Chat / <strong>Local Network</strong>” access is granted</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>On <strong>macOS</strong>, enable “System Settings / Privacy & Security / <strong>Local Network</strong> / Delta Chat”</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Wellicht is een firewall actief op je apparaat,
|
||||
welke problemen kan veroorzaken (met name op Windows).
|
||||
@@ -1423,6 +1430,7 @@ you only open attachments from senders you trust, and not from spammers.</li>
|
||||
<ul>
|
||||
<li>In general, anyone can share webxdc apps with each
|
||||
other without restrictions.</li>
|
||||
<li>From <a href="https://webxdc.org/apps/">webxdc.org/apps</a>.</li>
|
||||
<li>You can <a href="https://delta.chat/en/2023-08-11-xstore">send ‘hi’ to xstore@testrun.org</a>
|
||||
to see an experimental webxdc appstore.
|
||||
All of the apps are open source and for free.</li>
|
||||
@@ -1868,6 +1876,35 @@ Otherwise you might receive undecryptable messages from those group chats.</p>
|
||||
<li>Bekijk de pagina <a href="https://github.com/deltachat/deltachat-core-rust/blob/master/standards.md#standards-used-in-delta-chat">Door Delta Chat gebruikte standaarden</a>.</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="where-can-my-friends-find-delta-chat">
|
||||
|
||||
|
||||
Where can my friends find Delta Chat? <a href="#where-can-my-friends-find-delta-chat" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Delta Chat is available for all major and some minor platforms:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>The <strong>official website</strong>, <a href="https://delta.chat/download">https://delta.chat/download</a> shows all options in detail</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>If unavailable, use the <strong>mirror</strong> at <a href="https://deltachat.github.io/deltachat-pages">https://deltachat.github.io/deltachat-pages</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Open one of the following <strong>app stores and search for “Delta Chat”:</strong>
|
||||
Google Play Store, F-Droid, Huawei App Gallery, Amazon App Store, iOS and macOS App Store, Microsoft Store</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Check the <strong>package manager</strong> of your Linux distributions</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Android APKs</strong> are also available on <a href="https://github.com/deltachat/deltachat-android/releases">https://github.com/deltachat/deltachat-android/releases</a></p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="hoe-wordt-de-ontwikkeling-van-delta-chat-gefinancierd">
|
||||
|
||||
|
||||
|
||||
@@ -99,6 +99,7 @@
|
||||
<li><a href="#czy-delta-chat-jest-kompatybilny-z-protonmail--tutanota--criptext">Czy Delta Chat jest kompatybilny z Protonmail / Tutanota / Criptext?</a></li>
|
||||
<li><a href="#remove-account">Jak mogę usunąć swoje konto?</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>
|
||||
<li><a href="#gdzie-moi-znajomi-mogą-znaleźć-delta-chat">Gdzie moi znajomi mogą znaleźć Delta Chat?</a></li>
|
||||
<li><a href="#w-jaki-sposób-finansowany-jest-rozwój-delta-chat">W jaki sposób finansowany jest rozwój Delta Chat?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
@@ -265,8 +266,7 @@
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Aby zarchiwizować lub przypiąć czat, dotknij i przytrzymaj (Android), użyj menu czatu (Android/Desktop) lub przesuń palcem w lewo (iOS);
|
||||
aby wyciszyć czat, użyj menu czatu (Android/Desktop) lub profilu czatu (iOS).</p>
|
||||
<p>Aby skorzystać z tych funkcji, przytrzymaj dłużej lub kliknij prawym przyciskiem myszy czat na liście czatów.</p>
|
||||
|
||||
<h3 id="co-oznacza-zielona-kropka">
|
||||
|
||||
@@ -941,6 +941,12 @@ W przypadku innych programów można znaleźć rozwiązanie online.</p>
|
||||
<p>Na <strong>Windowsie</strong>, przejdź do <strong>Panel sterowania / Sieć i internet</strong> i upewnij się, że <strong>Sieć prywatna</strong> jest wybrana jako “Typ profilu sieci”
|
||||
(po przeniesieniu możesz wrócić do pierwotnej wartości)</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>W systemie <strong>iOS</strong> upewnij się, że jest przydzielony dostęp do opcji „Ustawienia » Aplikacje » Delta Chat » <strong>Sieć lokalna</strong>”</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>W systemie <strong>macOS</strong> włącz „Ustawienia systemowe » Prywatność i bezpieczeństwo » <strong>Sieć lokalna</strong> » Delta Chat”</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Twój system może mieć „zaporę ogniową”, o której wiadomo, że powoduje problemy (szczególnie w systemie Windows).
|
||||
<strong>Wyłącz zaporę</strong> dla Delta Chat po obu stronach i spróbuj ponownie</p>
|
||||
@@ -1031,6 +1037,7 @@ W przypadku innych programów można znaleźć rozwiązanie online.</p>
|
||||
|
||||
<ul>
|
||||
<li>Ogólnie rzecz biorąc, każdy może udostępniać sobie aplikacje webxdc bez ograniczeń.</li>
|
||||
<li>Od <a href="https://webxdc.org/apps/">webxdc.org/apps</a>.</li>
|
||||
<li>Możesz <a href="https://delta.chat/en/2023-08-11-xstore">wysłać „hi” na adres xstore@testrun.org</a>, aby zobaczyć eksperymentalny sklep z aplikacjami webxdc. Wszystkie aplikacje są otwarto źródłowe i są bezpłatne.</li>
|
||||
<li>Wiele osób pisze własne, aplikacje webxdc i publikuje je na <a href="https://support.delta.chat/c/webxdc/20">forum Delta Chat</a>.</li>
|
||||
</ul>
|
||||
@@ -1356,6 +1363,34 @@ jeśli chcesz sprawdzić, czy Twoje poświadczenia są przetwarzane w bezpieczny
|
||||
<li>Zobacz <a href="https://github.com/deltachat/deltachat-core-rust/blob/master/standards.md#standards-used-in-delta-chat">Standardy używane w Delta Chat</a>.</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="gdzie-moi-znajomi-mogą-znaleźć-delta-chat">
|
||||
|
||||
|
||||
Gdzie moi znajomi mogą znaleźć Delta Chat? <a href="#gdzie-moi-znajomi-mogą-znaleźć-delta-chat" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Delta Chat jest dostępny na wszystkich głównych i niektórych mniejszych platformach:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>Oficjalna <strong>strona internetowa</strong> <a href="https://delta.chat/download">https://delta.chat/download</a> pokazuje wszystkie opcje szczegółowo</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Jeśli nie jest dostępna, użyj <strong>kopii strony</strong> pod adresem <a href="https://deltachat.github.io/deltachat-pages">https://deltachat.github.io/deltachat-pages</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Otwórz jeden z następujących <strong>sklepów z aplikacjami i wyszukaj „Delta Chat”</strong>: Google Play Store, F-Droid, Huawei App Gallery, Amazon App Store, iOS i macOS App Store, Microsoft Store</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Sprawdź <strong>menedżera pakietów</strong> swoich dystrybucji Linuksa</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Aplikacje na Androida</strong> są również dostępne na <a href="https://github.com/deltachat/deltachat-android/releases">https://github.com/deltachat/deltachat-android/releases</a></p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="w-jaki-sposób-finansowany-jest-rozwój-delta-chat">
|
||||
|
||||
|
||||
|
||||
@@ -99,6 +99,7 @@
|
||||
<li><a href="#o-delta-chat-é-compatível-com-protonmail--tutanota--criptext">O Delta Chat é compatível com Protonmail / Tutanota / Criptext?</a></li>
|
||||
<li><a href="#remove-account">How can I delete my account?</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>
|
||||
<li><a href="#where-can-my-friends-find-delta-chat">Where can my friends find Delta Chat?</a></li>
|
||||
<li><a href="#como-são-os-desenvolvimentos-do-delta-chat-financiados">Como são os desenvolvimentos do Delta Chat financiados?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
@@ -297,8 +298,7 @@ Archived chats remain accessible above the chat list or via search.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>To archive or pin a chat, long tap (Android), use the chat’s menu (Android/Desktop) or swipe to the left (iOS);
|
||||
to mute a chat, use the chat’s menu (Android/Desktop) or the chat’s profile (iOS).</p>
|
||||
<p>To use the functions, long tap or right click a chat in the chat list.</p>
|
||||
|
||||
<h3 id="what-does-the-green-dot-mean">
|
||||
|
||||
@@ -1309,6 +1309,12 @@ One device is not needed for the other to work.</p>
|
||||
and make sure, <strong>Private Network</strong> is selected as “Network profile type”
|
||||
(after transfer, you can change back to the original value)</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>On <strong>iOS</strong>, make sure “System Settings / Apps / Delta Chat / <strong>Local Network</strong>” access is granted</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>On <strong>macOS</strong>, enable “System Settings / Privacy & Security / <strong>Local Network</strong> / Delta Chat”</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Your system might have a “personal firewall”,
|
||||
which is known to cause problems (especially on Windows).
|
||||
@@ -1426,6 +1432,7 @@ you only open attachments from senders you trust, and not from spammers.</li>
|
||||
<ul>
|
||||
<li>In general, anyone can share webxdc apps with each
|
||||
other without restrictions.</li>
|
||||
<li>From <a href="https://webxdc.org/apps/">webxdc.org/apps</a>.</li>
|
||||
<li>You can <a href="https://delta.chat/en/2023-08-11-xstore">send ‘hi’ to xstore@testrun.org</a>
|
||||
to see an experimental webxdc appstore.
|
||||
All of the apps are open source and for free.</li>
|
||||
@@ -1869,6 +1876,35 @@ Otherwise you might receive undecryptable messages from those group chats.</p>
|
||||
<li>Veja <a href="https://github.com/deltachat/deltachat-core-rust/blob/master/standards.md#standards-used-in-delta-chat">As normas usadas no Delta Chat</a>.</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="where-can-my-friends-find-delta-chat">
|
||||
|
||||
|
||||
Where can my friends find Delta Chat? <a href="#where-can-my-friends-find-delta-chat" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Delta Chat is available for all major and some minor platforms:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>The <strong>official website</strong>, <a href="https://delta.chat/download">https://delta.chat/download</a> shows all options in detail</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>If unavailable, use the <strong>mirror</strong> at <a href="https://deltachat.github.io/deltachat-pages">https://deltachat.github.io/deltachat-pages</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Open one of the following <strong>app stores and search for “Delta Chat”:</strong>
|
||||
Google Play Store, F-Droid, Huawei App Gallery, Amazon App Store, iOS and macOS App Store, Microsoft Store</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Check the <strong>package manager</strong> of your Linux distributions</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Android APKs</strong> are also available on <a href="https://github.com/deltachat/deltachat-android/releases">https://github.com/deltachat/deltachat-android/releases</a></p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="como-são-os-desenvolvimentos-do-delta-chat-financiados">
|
||||
|
||||
|
||||
|
||||
@@ -99,6 +99,7 @@
|
||||
<li><a href="#совместим-ли-delta-chat-с-protonmail--tutanota--criptext">Совместим ли Delta Chat с Protonmail / Tutanota / Criptext?</a></li>
|
||||
<li><a href="#remove-account">Как я могу удалить свой аккаунт?</a></li>
|
||||
<li><a href="#меня-интересуют-технические-детали-можете-рассказать-больше">Меня интересуют технические детали. Можете рассказать больше?</a></li>
|
||||
<li><a href="#где-мои-друзья-могут-найти-delta-chat">Где мои друзья могут найти Delta Chat?</a></li>
|
||||
<li><a href="#как-финансируются-разработки-delta-chat">Как финансируются разработки Delta Chat?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
@@ -301,8 +302,7 @@
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Чтобы архивировать или закрепить чат, нажмите на него долгим нажатием (Android), воспользуйтесь меню чата (Android/Desktop) или проведите пальцем влево (iOS);
|
||||
чтобы отключить уведомления, воспользуйтесь меню чата (Android/Desktop) или профиль чата (iOS).</p>
|
||||
<p>Чтобы использовать функции, нажмите долгим нажатием или щелкните правой кнопкой мыши по чату в списке чатов.</p>
|
||||
|
||||
<h3 id="что-означает-зеленая-точка">
|
||||
|
||||
@@ -1312,6 +1312,12 @@ Chat <a href="https://github.com/rpgp/rpgp">PGP</a> и
|
||||
и убедитесь, что в качестве “Типа сетевого профиля” выбрана <strong>Частная сеть</strong>.
|
||||
(после передачи, вы можете изменить обратно на исходное значение)</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>На <strong>iOS</strong>, убедитесь, что предоставлен доступ “Настройки системы / Приложения / Delta Chat / <strong>Локальная сеть</strong>”</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>На <strong>macOS</strong>, включите “Системные настройки / Конфиденциальность и безопасность / <strong>Локальная сеть</strong> / Delta Chat”</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>В вашей системе может быть установлен “персональный брандмауэр”,
|
||||
который может вызвать проблемы (особенно на Windows).
|
||||
@@ -1430,11 +1436,11 @@ PIN-код разблокировки экрана, графический кл
|
||||
<ul>
|
||||
<li>В общем, каждый может поделиться приложениями webxdc
|
||||
друг с другом без ограничений.</li>
|
||||
<li>Из <a href="https://webxdc.org/apps/">webxdc.org/apps</a>.</li>
|
||||
<li>Вы можете <a href="https://delta.chat/en/2023-08-11-xstore">отправить ‘hi’ на xstore@testrun.org</a>
|
||||
чтобы увидеть экспериментальный магазин приложений webxdc.
|
||||
Все приложения с открытым исходным кодом и бесплатны.</li>
|
||||
<li>Многие люди пишут свои собственные приложения webxdc и публикуют их на <a href="https://support.delta.chat/c/webxdc/20">форуме
|
||||
Delta Chat</a>.</li>
|
||||
<li>Многие люди создают свои собственные приложения webxdc и публикуют их на <a href="https://support.delta.chat/c/webxdc/20">форуме Delta Chat</a>.</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="как-я-могу-создать-свои-собственные-приложения-webxdc">
|
||||
@@ -1879,6 +1885,35 @@ Chat.</li>
|
||||
<li>Смотрите <a href="https://github.com/deltachat/deltachat-core-rust/blob/master/standards.md#standards-used-in-delta-chat">Стандарты, используемые в Delta Chat</a>.</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="где-мои-друзья-могут-найти-delta-chat">
|
||||
|
||||
|
||||
Где мои друзья могут найти Delta Chat? <a href="#где-мои-друзья-могут-найти-delta-chat" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Delta Chat доступен на всех популярных и некоторых менее известных платформах:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>На <strong>официальной странице загрузки</strong>, <a href="https://delta.chat/download">https://delta.chat/download</a> можно найти подробную информацию о всех вариантах</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Если основной сайт недоступен, используйте <strong>зеркало</strong> <a href="https://deltachat.github.io/deltachat-pages">https://deltachat.github.io/deltachat-pages</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Откройте один из следующих <strong>онлайн-магазинов приложений и введите запрос “Delta Chat”:</strong>
|
||||
Google Play Store, F-Droid, Huawei App Gallery, Amazon App Store, App Store для iOS и macOS, Microsoft Store</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Проверьте <strong>менеджер пакетов</strong> вашего дистрибутива Linux</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Файлы <strong>APK для Android</strong> доступны на <a href="https://github.com/deltachat/deltachat-android/releases">https://github.com/deltachat/deltachat-android/releases</a></p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="как-финансируются-разработки-delta-chat">
|
||||
|
||||
|
||||
|
||||
@@ -99,6 +99,7 @@
|
||||
<li><a href="#je-delta-chat-kompatibilný-s-protonmail--tutanota--criptext">Je Delta Chat kompatibilný s Protonmail / Tutanota / Criptext?</a></li>
|
||||
<li><a href="#remove-account">How can I delete my account?</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>
|
||||
<li><a href="#where-can-my-friends-find-delta-chat">Where can my friends find Delta Chat?</a></li>
|
||||
<li><a href="#ako-sa-financuje-vývoj-delta-chat">Ako sa financuje vývoj Delta Chat?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
@@ -301,8 +302,7 @@ Archived chats remain accessible above the chat list or via search.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>To archive or pin a chat, long tap (Android), use the chat’s menu (Android/Desktop) or swipe to the left (iOS);
|
||||
to mute a chat, use the chat’s menu (Android/Desktop) or the chat’s profile (iOS).</p>
|
||||
<p>To use the functions, long tap or right click a chat in the chat list.</p>
|
||||
|
||||
<h3 id="what-does-the-green-dot-mean">
|
||||
|
||||
@@ -1315,6 +1315,12 @@ One device is not needed for the other to work.</p>
|
||||
and make sure, <strong>Private Network</strong> is selected as “Network profile type”
|
||||
(after transfer, you can change back to the original value)</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>On <strong>iOS</strong>, make sure “System Settings / Apps / Delta Chat / <strong>Local Network</strong>” access is granted</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>On <strong>macOS</strong>, enable “System Settings / Privacy & Security / <strong>Local Network</strong> / Delta Chat”</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Your system might have a “personal firewall”,
|
||||
which is known to cause problems (especially on Windows).
|
||||
@@ -1432,6 +1438,7 @@ you only open attachments from senders you trust, and not from spammers.</li>
|
||||
<ul>
|
||||
<li>In general, anyone can share webxdc apps with each
|
||||
other without restrictions.</li>
|
||||
<li>From <a href="https://webxdc.org/apps/">webxdc.org/apps</a>.</li>
|
||||
<li>You can <a href="https://delta.chat/en/2023-08-11-xstore">send ‘hi’ to xstore@testrun.org</a>
|
||||
to see an experimental webxdc appstore.
|
||||
All of the apps are open source and for free.</li>
|
||||
@@ -1879,6 +1886,35 @@ Otherwise you might receive undecryptable messages from those group chats.</p>
|
||||
<li>Pozrite si <a href="https://github.com/deltachat/deltachat-core-rust/blob/master/standards.md#standards-used-in-delta-chat">Štandardy používané v Delta Chate</a>.</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="where-can-my-friends-find-delta-chat">
|
||||
|
||||
|
||||
Where can my friends find Delta Chat? <a href="#where-can-my-friends-find-delta-chat" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Delta Chat is available for all major and some minor platforms:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>The <strong>official website</strong>, <a href="https://delta.chat/download">https://delta.chat/download</a> shows all options in detail</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>If unavailable, use the <strong>mirror</strong> at <a href="https://deltachat.github.io/deltachat-pages">https://deltachat.github.io/deltachat-pages</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Open one of the following <strong>app stores and search for “Delta Chat”:</strong>
|
||||
Google Play Store, F-Droid, Huawei App Gallery, Amazon App Store, iOS and macOS App Store, Microsoft Store</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Check the <strong>package manager</strong> of your Linux distributions</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Android APKs</strong> are also available on <a href="https://github.com/deltachat/deltachat-android/releases">https://github.com/deltachat/deltachat-android/releases</a></p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="ako-sa-financuje-vývoj-delta-chat">
|
||||
|
||||
|
||||
|
||||
@@ -99,6 +99,7 @@
|
||||
<li><a href="#a-është-i-përputhshëm-delta-chat-i-me-protonmail-in--tutanota-n--criptext-in">A është i përputhshëm Delta Chat-i me Protonmail-in / Tutanota-n / Criptext-in?</a></li>
|
||||
<li><a href="#remove-account">Si mund ta fshij llogarinë time?</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>
|
||||
<li><a href="#where-can-my-friends-find-delta-chat">Where can my friends find Delta Chat?</a></li>
|
||||
<li><a href="#si-financohet-zhvillimi-i-delta-chat-it">Si financohet zhvillimi i Delta Chat-it?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
@@ -1315,6 +1316,12 @@ Njëra pajisja s’ka nevojë për tjetrën që të funksionojë.</p>
|
||||
and make sure, <strong>Private Network</strong> is selected as “Network profile type”
|
||||
(after transfer, you can change back to the original value)</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>On <strong>iOS</strong>, make sure “System Settings / Apps / Delta Chat / <strong>Local Network</strong>” access is granted</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>On <strong>macOS</strong>, enable “System Settings / Privacy & Security / <strong>Local Network</strong> / Delta Chat”</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Sistemi juaj mund të ketë një “firewall personal”,
|
||||
që dihet se shkakton probleme (veçanërisht në Windows).
|
||||
@@ -1890,6 +1897,35 @@ Otherwise you might receive undecryptable messages from those group chats.</p>
|
||||
<li>Shihni <a href="https://github.com/deltachat/deltachat-core-rust/blob/master/standards.md#standards-used-in-delta-chat">Standarde të përdorur në Delta Chat</a>.</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="where-can-my-friends-find-delta-chat">
|
||||
|
||||
|
||||
Where can my friends find Delta Chat? <a href="#where-can-my-friends-find-delta-chat" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Delta Chat is available for all major and some minor platforms:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>The <strong>official website</strong>, <a href="https://delta.chat/download">https://delta.chat/download</a> shows all options in detail</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>If unavailable, use the <strong>mirror</strong> at <a href="https://deltachat.github.io/deltachat-pages">https://deltachat.github.io/deltachat-pages</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Open one of the following <strong>app stores and search for “Delta Chat”:</strong>
|
||||
Google Play Store, F-Droid, Huawei App Gallery, Amazon App Store, iOS and macOS App Store, Microsoft Store</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Check the <strong>package manager</strong> of your Linux distributions</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Android APKs</strong> are also available on <a href="https://github.com/deltachat/deltachat-android/releases">https://github.com/deltachat/deltachat-android/releases</a></p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="si-financohet-zhvillimi-i-delta-chat-it">
|
||||
|
||||
|
||||
|
||||
@@ -99,6 +99,7 @@
|
||||
<li><a href="#чи-сумісний-delta-chat-із-protonmail--tutanota--criptext">Чи сумісний Delta Chat із Protonmail / Tutanota / Criptext?</a></li>
|
||||
<li><a href="#remove-account">Як мені видалити свій обліковий запис?</a></li>
|
||||
<li><a href="#мене-цікавлять-технічні-деталі-можете-розповісти-більше">Мене цікавлять технічні деталі. Можете розповісти більше?</a></li>
|
||||
<li><a href="#де-мої-друзі-можуть-знайти-delta-chat">Де мої друзі можуть знайти Delta Chat?</a></li>
|
||||
<li><a href="#як-фінансується-розробка-delta-chat">Як фінансується розробка Delta Chat?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
@@ -267,7 +268,7 @@
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Щоб заархівувати або закріпити чат, довго торкніться (Android), скористайтеся меню чату (Android/комп’ютер) або проведіть пальцем ліворуч (iOS); щоб вимкнути звук чату, скористайтеся меню чату (Android/комп’ютер) або профілем чату (iOS).</p>
|
||||
<p>Щоб скористатися функціями, утримуйте натиснутою клавішу або клацніть правою кнопкою миші на чаті у списку чатів.</p>
|
||||
|
||||
<h3 id="що-означає-зелена-точка">
|
||||
|
||||
@@ -944,6 +945,12 @@ Look for something like <strong>Start Autocrypt Setup Transfer</strong> in the s
|
||||
<li>
|
||||
<p>У <strong>Windows</strong> перейдіть до <strong>Панель керування / Мережа та Інтернет</strong> і переконайтеся, що <strong>Приватна мережа</strong> вибрано як “Тип мережевого профілю” (після перенесення ви можете повернути початкове значення)</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>На <strong>iOS</strong> переконайтеся, що доступ до “Системні налаштування / Програми / Delta Chat / <strong>Локальна мережа</strong>” дозволено</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>У <strong>macOS</strong> увімкніть “Системні налаштування / Конфіденційність і безпека / <strong>Локальна мережа</strong> / Delta Chat”</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Ваша система може мати “персональний брандмауер”, який, як відомо, викликає проблеми (особливо у Windows). <strong>Вимкніть персональний брандмауер</strong> для Delta Chat на обох кінцях і повторіть спробу</p>
|
||||
</li>
|
||||
@@ -1032,9 +1039,11 @@ Look for something like <strong>Start Autocrypt Setup Transfer</strong> in the s
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>Загалом, будь-хто може ділитися додатками webxdc один з одним один з одним без обмежень.</li>
|
||||
<li>Ви можете <a href="https://delta.chat/en/2023-08-11-xstore">надіслати “hi” на xstore@testrun.org</a> щоб побачити експериментальний магазин додатків webxdc. Всі програми мають відкритий вихідний код і є безкоштовними.</li>
|
||||
<li>Багато людей пишуть власні програми для webxdc і публікують їх на <a href="https://support.delta.chat/c/webxdc/20">форумі Delta Chat</a>.</li>
|
||||
<li>Загалом, будь-хто може ділитися додатками webxdc один з одним без обмежень.</li>
|
||||
<li>З <a href="https://webxdc.org/apps/">webxdc.org/apps</a>.</li>
|
||||
<li>Ви можете <a href="https://delta.chat/en/2023-08-11-xstore">надіслати “привіт” на xstore@testrun.org</a> щоб побачити експериментальний магазин додатків webxdc.
|
||||
Всі програми мають відкритий вихідний код і є безкоштовними.</li>
|
||||
<li>Багато людей пишуть власні програми webxdc і публікують їх на <a href="https://support.delta.chat/c/webxdc/20">форумі Delta Chat</a>.</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="як-я-можу-створювати-власні-програми-webxdc">
|
||||
@@ -1374,6 +1383,34 @@ Look for something like <strong>Start Autocrypt Setup Transfer</strong> in the s
|
||||
<li>Дивіться <a href="https://github.com/deltachat/deltachat-core-rust/blob/master/standards.md#standards-used-in-delta-chat">Стандарти, що використовуються у Delta Chat</a>.</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="де-мої-друзі-можуть-знайти-delta-chat">
|
||||
|
||||
|
||||
Де мої друзі можуть знайти Delta Chat? <a href="#де-мої-друзі-можуть-знайти-delta-chat" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Delta Chat доступний для всіх основних і деяких другорядних платформ:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>На <strong>офіційному сайті</strong>, <a href="https://delta.chat/download">https://delta.chat/download</a> детально описані всі варіанти</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Якщо вона недоступна, скористайтеся <strong>дзеркалом</strong> за адресою <a href="https://deltachat.github.io/deltachat-pages">https://deltachat.github.io/deltachat-pages</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Відкрийте один з наступних <strong>магазинів додатків і введіть у пошук “Delta Chat”:</strong> Google Play Store, F-Droid, Huawei App Gallery, Amazon App Store, iOS та macOS App Store, Microsoft Store</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Перевірте <strong>менеджер пакунків</strong> вашого дистрибутива Linux</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>APK для Android</strong> також доступні на <a href="https://github.com/deltachat/deltachat-android/releases">https://github.com/deltachat/deltachat-android/releases</a></p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="як-фінансується-розробка-delta-chat">
|
||||
|
||||
|
||||
|
||||
@@ -27,9 +27,9 @@
|
||||
</li>
|
||||
<li><a href="#instant-delivery">Instant message delivery and Push Notifications</a>
|
||||
<ul>
|
||||
<li><a href="#what-are-push-notifications-how-can-i-get-instant-message-delivery">What are Push Notifications? How can I get instant message delivery?</a></li>
|
||||
<li><a href="#are-push-notifications-enabled-on-ios-devices-is-there-an-alternative">Are Push Notifications enabled on iOS devices? Is there an alternative?</a></li>
|
||||
<li><a href="#android-push">Are Push notifications enabled / needed on Android devices?</a></li>
|
||||
<li><a href="#什么是推送通知如何获得即时消息传递">什么是推送通知?如何获得即时消息传递?</a></li>
|
||||
<li><a href="#ios-设备上是否启用了推送通知我还有其他的选择吗">iOS 设备上是否启用了推送通知?我还有其他的选择吗?</a></li>
|
||||
<li><a href="#android-设备上是否启用需要推送通知android-push">Android 设备上是否启用/需要推送通知?{#android-push}</a></li>
|
||||
<li><a href="#privacy-notifications">How private are Delta Chat Push Notifications?</a></li>
|
||||
<li><a href="#why-does-delta-chat-integrate-with-centralized-proprietary-applegoogle-push-services">Why does Delta Chat integrate with centralized proprietary Apple/Google push services?</a></li>
|
||||
</ul>
|
||||
@@ -44,7 +44,7 @@
|
||||
<li><a href="#are-attachments-pictures-files-audio-etc-end-to-end-encrypted">Are attachments (pictures, files, audio etc.) end-to-end encrypted?</a></li>
|
||||
<li><a href="#openpgp-secure">Is OpenPGP secure?</a></li>
|
||||
<li><a href="#openpgp-alternatives">Did you consider using alternatives to OpenPGP for end-to-end -encryption?</a></li>
|
||||
<li><a href="#is-delta-chat-vulnerable-to-efail">Is Delta Chat vulnerable to EFAIL?</a></li>
|
||||
<li><a href="#delta-chat-是否容易受到-efail-攻击">Delta Chat 是否容易受到 EFAIL 攻击?</a></li>
|
||||
<li><a href="#tls">Is a message exposed in cleartext if end-to-end encryption is not available?</a></li>
|
||||
<li><a href="#message-metadata">How does Delta Chat protect metadata in messages?</a></li>
|
||||
<li><a href="#device-seizure">How to protect metadata and contacts when a device is seized?</a></li>
|
||||
@@ -53,7 +53,7 @@
|
||||
<li><a href="#why-do-i-see-unencrypted-messages">Why do I see unencrypted messages?</a></li>
|
||||
<li><a href="#how-can-i-get-an-end-to-end-encrypted-chat-with-a-delta-chat-contact-who-sometimes-uses-webmail-or-another-non-autocrypt-e-mail-app">How can i get an end-to-end encrypted chat with a Delta Chat contact who sometimes uses webmail or another non-Autocrypt e-mail app?</a></li>
|
||||
<li><a href="#how-can-i-ensure-message-end-to-end-encryption-and-deletion">How can I ensure message end-to-end encryption and deletion?</a></li>
|
||||
<li><a href="#pfs">Does Delta Chat support Perfect Forward Secrecy?</a></li>
|
||||
<li><a href="#pfs">Delta Chat 是否支持完美前向保密?</a></li>
|
||||
<li><a href="#is-end-to-end-encryption-of-delta-chat-as-safe-as-signal">Is end-to-end encryption of Delta Chat as safe as Signal?</a></li>
|
||||
<li><a href="#importkey">我可以重复使用现有的私钥吗?</a></li>
|
||||
<li><a href="#我无法将现有的-pgp-密钥导入-delta-chat">我无法将现有的 PGP 密钥导入 Delta Chat。</a></li>
|
||||
@@ -99,6 +99,7 @@
|
||||
<li><a href="#delta-chat-与-protonmail--tutanota--criptext-兼容吗">Delta Chat 与 Protonmail / Tutanota / Criptext 兼容吗?</a></li>
|
||||
<li><a href="#remove-account">如何删除我的账户?</a></li>
|
||||
<li><a href="#我对技术细节很感兴趣能告诉我更多吗">我对技术细节很感兴趣。能告诉我更多吗?</a></li>
|
||||
<li><a href="#where-can-my-friends-find-delta-chat">Where can my friends find Delta Chat?</a></li>
|
||||
<li><a href="#delta-chat-的开发是如何被资助的">Delta Chat 的开发是如何被资助的?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
@@ -337,10 +338,8 @@ The messages are deleted
|
||||
both in each email account on the server,
|
||||
and in the app itself.</p>
|
||||
|
||||
<p>Note that you can rely on disappearing messages
|
||||
only as long as you trust your chat partners;
|
||||
malicious chat partners can take photos,
|
||||
or otherwise save, copy or forward messages before deletion.</p>
|
||||
<p>请注意,只有当您信任您的聊天伙伴时,您才可以依赖“消息定时销毁”;
|
||||
不怀好意的人可能会拍照,或者在删除之前以其他方式保存、复制或转发消息。</p>
|
||||
|
||||
<p>Apart from that,
|
||||
if one chat partner uninstalls Delta Chat,
|
||||
@@ -473,64 +472,59 @@ Delta Chat 收到的所有电子邮件都将在此期限后从服务器中删除
|
||||
|
||||
</h2>
|
||||
|
||||
<h3 id="what-are-push-notifications-how-can-i-get-instant-message-delivery">
|
||||
<h3 id="什么是推送通知如何获得即时消息传递">
|
||||
|
||||
|
||||
What are Push Notifications? How can I get instant message delivery? <a href="#what-are-push-notifications-how-can-i-get-instant-message-delivery" class="anchor"></a>
|
||||
什么是推送通知?如何获得即时消息传递? <a href="#什么是推送通知如何获得即时消息传递" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Push Notifications are sent by Apple and Google “Push services” to a user’s device
|
||||
so that an inactive Delta Chat app can fetch messages in the background
|
||||
and show notifications on a user’s phone if needed.</p>
|
||||
<p>推送通知由 Apple 和 Google 的“推送服务”发送到用户的设备,以便非活动状态的 Delta Chat 应用可以在后台获取消息,并在需要时在用户的手机上显示通知。</p>
|
||||
|
||||
<p>Push Notifications work with all <a href="https://delta.chat/chatmail">chatmail</a> servers on</p>
|
||||
<p>推送通知适用于以下所有 <a href="https://delta.chat/chatmail">chatmail</a> 服务器:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>iOS devices, by integrating with Apple Push services.</p>
|
||||
<p>iOS 设备通过与 Apple Push 服务集成。</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Android devices, by integrating with the Google FCM Push service,
|
||||
including on devices that use <a href="https://microg.org">microG</a>
|
||||
instead of proprietary Google code on the phone.</p>
|
||||
<p>Android 设备,通过与 Google FCM Push 服务集成,
|
||||
包括使用 <a href="https://microg.org">microG</a>
|
||||
而不是手机上专有 Google 代码的设备。</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>As of May 2024, classic e-mail servers do not support Push Notifications
|
||||
for Delta Chat users.</p>
|
||||
<p>自 2024 年 5 月起,传统电子邮件服务器不再支持 Delta Chat 用户的推送通知。</p>
|
||||
|
||||
<h3 id="are-push-notifications-enabled-on-ios-devices-is-there-an-alternative">
|
||||
<h3 id="ios-设备上是否启用了推送通知我还有其他的选择吗">
|
||||
|
||||
|
||||
Are Push Notifications enabled on iOS devices? Is there an alternative? <a href="#are-push-notifications-enabled-on-ios-devices-is-there-an-alternative" class="anchor"></a>
|
||||
iOS 设备上是否启用了推送通知?我还有其他的选择吗? <a href="#ios-设备上是否启用了推送通知我还有其他的选择吗" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Yes, Delta Chat automatically uses Push Notifications for <a href="https://delta.chat/chatmail">chatmail</a> profiles.
|
||||
And no, there is no alternative on Apple’s phones to achieve instant message delivery
|
||||
because Apple devices do not allow Delta Chat to fetch data in the background.
|
||||
Push notifications are automatically activated for iOS users because
|
||||
<a href="#privacy-notifications">Delta Chat’s privacy-preserving Push Notification system</a>
|
||||
does not expose data to Apple that it doesn’t already have.</p>
|
||||
<p>是的,Delta Chat 会自动使用推送通知来接收 <a href="https://delta.chat/chatmail">chatmail</a> 个人资料。
|
||||
而且,Apple 手机上没有其他方式可以实现即时消息传递
|
||||
因为 Apple 设备不允许 Delta Chat 在后台获取数据。
|
||||
推送通知会自动为 iOS 用户激活,因为
|
||||
<a href="#privacy-notifications">Delta Chat 的隐私保护推送通知系统</a>
|
||||
不会向 Apple 泄露其尚未拥有的数据。</p>
|
||||
|
||||
<h3 id="android-push">
|
||||
<h3 id="android-设备上是否启用需要推送通知android-push">
|
||||
|
||||
|
||||
Are Push notifications enabled / needed on Android devices? <a href="#android-push" class="anchor"></a>
|
||||
Android 设备上是否启用/需要推送通知?{#android-push} <a href="#android-设备上是否启用需要推送通知android-push" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>If a “Push Service” is available, Delta Chat enables Push Notifications
|
||||
to achieve instant message delivery for all chatmail users.
|
||||
If you are using a classic e-mail provider instead of <a href="https://delta.chat/chatmail">chatmail</a> servers,
|
||||
Push Notifications are not available.</p>
|
||||
<p>如果有“推送服务”可用,Delta Chat 将启用推送通知,
|
||||
以实现所有聊天邮件用户的即时消息传递。
|
||||
如果您使用的是传统电子邮件提供商而不是 <a href="https://delta.chat/chatmail">chatmail</a> 服务器,则无法使用推送通知。</p>
|
||||
|
||||
<p>In the Delta Chat “Notifications” settings for “Instant delivery”
|
||||
you can change the following settings effecting all chat profiles:</p>
|
||||
<p>在 Delta Chat“通知”的“推送通知”设置中,您可以更改以下影响所有聊天配置文件的设置:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
@@ -710,17 +704,13 @@ both sides will eventually see a (group or direct) chat with a green checkmark
|
||||
next to the title.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>If one of the devices is offline, the green checkmarks will only
|
||||
appear later when the device is internet-connected again
|
||||
and the Secure-Join network protocol completed.</p>
|
||||
<p>如果其中一个设备处于离线状态,则只有当设备再次连接互联网且安全加入网络协议完成时,绿色复选标记才会出现。</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Congratulations!
|
||||
You now will automatically use guaranteed end-to-end encryption
|
||||
with this contact and both of you can add each other to green-checkmarked groups
|
||||
<img style="vertical-align:middle; width:1.5em; margin:1px" src="../green-checkmark.png" alt="green checkmark" />,
|
||||
thereby automatically spreading guaranteed end-to-end encryption among its members.</p>
|
||||
<p>恭喜!
|
||||
从现在开始您将会自动使用安全的端到端加密与此联系人联系,并且双方都可以将对方添加到绿色复选标记的群组
|
||||
<img style="vertical-align:middle; width:1.5em; margin:1px" src="../green-checkmark.png" alt="green checkmark" />,从而自动在其成员之间传播有保障的端到端加密。</p>
|
||||
|
||||
<h3 id="e2eeguarantee">
|
||||
|
||||
@@ -891,19 +881,18 @@ only one part of “user outcomes”,
|
||||
see also our answers to <a href="#device-seizure">device-seizure</a>
|
||||
and <a href="#message-metadata">message-metadata</a> questions.</p>
|
||||
|
||||
<h3 id="is-delta-chat-vulnerable-to-efail">
|
||||
<h3 id="delta-chat-是否容易受到-efail-攻击">
|
||||
|
||||
|
||||
Is Delta Chat vulnerable to EFAIL? <a href="#is-delta-chat-vulnerable-to-efail" class="anchor"></a>
|
||||
Delta Chat 是否容易受到 EFAIL 攻击? <a href="#delta-chat-是否容易受到-efail-攻击" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>No, <a href="https://delta.chat/en/2018-05-15-delta-chat-not-vulnerable-to-efail">Delta Chat never was vulnerable to EFAIL</a>
|
||||
because its OpenPGP implementation <a href="https://github.com/rpgp/rpgp">rPGP</a>
|
||||
uses Modification Detection Code when encrypting messages
|
||||
and returns <a href="https://docs.rs/pgp/latest/pgp/errors/enum.Error.html#variant.MdcError">an error</a>
|
||||
if the Modification Detection Code is incorrect.</p>
|
||||
<p>不,<a href="https://delta.chat/en/2018-05-15-delta-chat-not-vulnerable-to-efail">Delta Chat 从未受到任何 EFAIL 攻击</a>
|
||||
因为所使用的 OpenPGP 实现了 <a href="https://github.com/rpgp/rpgp">rPGP</a>
|
||||
在加密消息时“修改检测代码”
|
||||
并且如果“修改检测代码”不正确则返回 <a href="https://docs.rs/pgp/latest/pgp/errors/enum.Error.html#variant.MdcError">错误</a>。</p>
|
||||
|
||||
<p>Delta Chat also never was vulnerable to the “Direct Exfiltration” EFAIL attack
|
||||
because it only decrypts <code class="language-plaintext highlighter-rouge">multipart/encrypted</code> messages
|
||||
@@ -1072,21 +1061,21 @@ you can also turn on <a href="#delold">“delete messages from server automatica
|
||||
<h3 id="pfs">
|
||||
|
||||
|
||||
Does Delta Chat support Perfect Forward Secrecy? <a href="#pfs" class="anchor"></a>
|
||||
Delta Chat 是否支持完美前向保密? <a href="#pfs" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>No, Delta Chat doesn’t support Perfect Forward Secrecy (PFS).
|
||||
This means that if your Delta Chat private decryption key is leaked,
|
||||
and someone has collected your prior in-transit messages,
|
||||
they will be able to decrypt and read them using the leaked decryption key.</p>
|
||||
<p>不,Delta Chat 不支持完美前向保密 (PFS)。
|
||||
这意味着,如果您的 Delta Chat 私人解密密钥泄露,
|
||||
并且有人收集了您之前传输的消息,
|
||||
他们将能够使用泄露的解密密钥解密并阅读这些消息。</p>
|
||||
|
||||
<p>Note, however, that if anyone obtains to your decryption keys,
|
||||
they will typically also be able to obtain your messages,
|
||||
irrespective if Perfect Forward Secrecy is in place or not.
|
||||
The typical real-world situation for leaked decryption keys is device seizure
|
||||
which we discuss in our answer <a href="#device-seizure">on metadata and device seizure</a>.</p>
|
||||
<p>但请注意,如果有人获得您的解密密钥,
|
||||
他们通常也能够获得您的消息,
|
||||
无论是否实施了完全前向保密。
|
||||
泄露解密密钥的典型现实情况是设备扣押,
|
||||
我们在<a href="#device-seizure">关于元数据和设备扣押</a>的回答中讨论了这一点。</p>
|
||||
|
||||
<p>It is possible that Delta Chat evolves to support Perfect Forward Secrecy,
|
||||
because OpenPGP is just a container for encrypted messages
|
||||
@@ -1272,6 +1261,12 @@ One device is not needed for the other to work.</p>
|
||||
and make sure, <strong>Private Network</strong> is selected as “Network profile type”
|
||||
(after transfer, you can change back to the original value)</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>On <strong>iOS</strong>, make sure “System Settings / Apps / Delta Chat / <strong>Local Network</strong>” access is granted</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>On <strong>macOS</strong>, enable “System Settings / Privacy & Security / <strong>Local Network</strong> / Delta Chat”</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Your system might have a “personal firewall”,
|
||||
which is known to cause problems (especially on Windows).
|
||||
@@ -1384,6 +1379,7 @@ you only open attachments from senders you trust, and not from spammers.</li>
|
||||
<ul>
|
||||
<li>In general, anyone can share webxdc apps with each
|
||||
other without restrictions.</li>
|
||||
<li>From <a href="https://webxdc.org/apps/">webxdc.org/apps</a>.</li>
|
||||
<li>You can <a href="https://delta.chat/en/2023-08-11-xstore">send ‘hi’ to xstore@testrun.org</a>
|
||||
to see an experimental webxdc appstore.
|
||||
All of the apps are open source and for free.</li>
|
||||
@@ -1794,6 +1790,35 @@ Otherwise you might receive undecryptable messages from those group chats.</p>
|
||||
<li>请参阅 <a href="https://github.com/deltachat/deltachat-core-rust/blob/master/standards.md#standards-used-in-delta-chat">Delta Chat 中使用的标准</a>。</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="where-can-my-friends-find-delta-chat">
|
||||
|
||||
|
||||
Where can my friends find Delta Chat? <a href="#where-can-my-friends-find-delta-chat" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Delta Chat is available for all major and some minor platforms:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>The <strong>official website</strong>, <a href="https://delta.chat/download">https://delta.chat/download</a> shows all options in detail</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>If unavailable, use the <strong>mirror</strong> at <a href="https://deltachat.github.io/deltachat-pages">https://deltachat.github.io/deltachat-pages</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Open one of the following <strong>app stores and search for “Delta Chat”:</strong>
|
||||
Google Play Store, F-Droid, Huawei App Gallery, Amazon App Store, iOS and macOS App Store, Microsoft Store</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Check the <strong>package manager</strong> of your Linux distributions</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Android APKs</strong> are also available on <a href="https://github.com/deltachat/deltachat-android/releases">https://github.com/deltachat/deltachat-android/releases</a></p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="delta-chat-的开发是如何被资助的">
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
@@ -2,16 +2,14 @@ package com.b44t.messenger;
|
||||
|
||||
public class DcContext {
|
||||
|
||||
public final static int DC_PREF_DEFAULT_MDNS_ENABLED = 1;
|
||||
public final static int DC_PREF_DEFAULT_TRIM_ENABLED = 0;
|
||||
public final static int DC_PREF_DEFAULT_TRIM_LENGTH = 500;
|
||||
|
||||
public final static int DC_EVENT_INFO = 100;
|
||||
public final static int DC_EVENT_WARNING = 300;
|
||||
public final static int DC_EVENT_ERROR = 400;
|
||||
public final static int DC_EVENT_ERROR_SELF_NOT_IN_GROUP = 410;
|
||||
public final static int DC_EVENT_MSGS_CHANGED = 2000;
|
||||
public final static int DC_EVENT_REACTIONS_CHANGED = 2001;
|
||||
public final static int DC_EVENT_INCOMING_REACTION = 2002;
|
||||
public final static int DC_EVENT_INCOMING_WEBXDC_NOTIFY = 2003;
|
||||
public final static int DC_EVENT_INCOMING_MSG = 2005;
|
||||
public final static int DC_EVENT_MSGS_NOTICED = 2008;
|
||||
public final static int DC_EVENT_MSG_DELIVERED = 2010;
|
||||
@@ -82,16 +80,13 @@ public class DcContext {
|
||||
public final static int DC_MEDIA_QUALITY_BALANCED = 0;
|
||||
public final static int DC_MEDIA_QUALITY_WORSE = 1;
|
||||
|
||||
public final static int DC_DECISION_START_CHAT = 0;
|
||||
public final static int DC_DECISION_BLOCK = 1;
|
||||
public final static int DC_DECISION_NOT_NOW = 2;
|
||||
|
||||
public final static int DC_CONNECTIVITY_NOT_CONNECTED = 1000;
|
||||
public final static int DC_CONNECTIVITY_CONNECTING = 2000;
|
||||
public final static int DC_CONNECTIVITY_WORKING = 3000;
|
||||
public final static int DC_CONNECTIVITY_CONNECTED = 4000;
|
||||
|
||||
private static final String CONFIG_ACCOUNT_ENABLED = "ui.enabled";
|
||||
private static final String CONFIG_MUTE_MENTIONS_IF_MUTED = "ui.mute_mentions_if_muted";
|
||||
|
||||
// when using DcAccounts, use DcAccounts.addAccount() instead
|
||||
public DcContext(String osName, String dbfile) {
|
||||
@@ -200,11 +195,10 @@ public class DcContext {
|
||||
public native void deleteMsgs (int msg_ids[]);
|
||||
public native void forwardMsgs (int msg_ids[], int chat_id);
|
||||
public native boolean resendMsgs (int msg_ids[]);
|
||||
public native int prepareMsg (int chat_id, DcMsg msg);
|
||||
public native int sendMsg (int chat_id, DcMsg msg);
|
||||
public native int sendTextMsg (int chat_id, String text);
|
||||
public native int sendVideochatInvitation(int chat_id);
|
||||
public native boolean sendWebxdcStatusUpdate(int msg_id, String payload, String descr);
|
||||
public native boolean sendWebxdcStatusUpdate(int msg_id, String payload);
|
||||
public native String getWebxdcStatusUpdates(int msg_id, int last_known_serial);
|
||||
public native void setWebxdcIntegration (String file);
|
||||
public native int initWebxdcIntegration(int chat_id);
|
||||
@@ -232,22 +226,12 @@ public class DcContext {
|
||||
}
|
||||
}
|
||||
|
||||
public String getNameNAddr() {
|
||||
String displayname = getConfig("displayname");
|
||||
String addr = getConfig("addr");
|
||||
String ret = "";
|
||||
public boolean isMentionsEnabled() {
|
||||
return getConfigInt(CONFIG_MUTE_MENTIONS_IF_MUTED) != 1;
|
||||
}
|
||||
|
||||
if (!displayname.isEmpty() && !addr.isEmpty()) {
|
||||
ret = String.format("%s (%s)", displayname, addr);
|
||||
} else if (!addr.isEmpty()) {
|
||||
ret = addr;
|
||||
}
|
||||
|
||||
if (ret.isEmpty() || isConfigured() == 0) {
|
||||
ret += " (not configured)";
|
||||
}
|
||||
|
||||
return ret.trim();
|
||||
public void setMentionsEnabled(boolean enabled) {
|
||||
setConfigInt(CONFIG_MUTE_MENTIONS_IF_MUTED, enabled? 0 : 1);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
|
||||
@@ -148,6 +148,7 @@ public class DcMsg {
|
||||
return new JSONObject();
|
||||
}
|
||||
}
|
||||
public native String getWebxdcHref ();
|
||||
public native boolean isForwarded ();
|
||||
public native boolean isInfo ();
|
||||
public native boolean isSetupMessage ();
|
||||
@@ -155,25 +156,25 @@ public class DcMsg {
|
||||
public native String getSetupCodeBegin ();
|
||||
public native String getVideochatUrl ();
|
||||
public native int getVideochatType ();
|
||||
public native boolean isIncreation ();
|
||||
public native void setText (String text);
|
||||
public native void setSubject (String text);
|
||||
public native void setHtml (String text);
|
||||
public native void setFile (String file, String filemime);
|
||||
public native void forceSticker ();
|
||||
public native void setDimension (int width, int height);
|
||||
public native void setDuration (int duration);
|
||||
public native void setLocation (float latitude, float longitude);
|
||||
public native String getPOILocation ();
|
||||
public void setQuote (DcMsg quote) { setQuoteCPtr(quote.msgCPtr); }
|
||||
public native String getQuotedText ();
|
||||
public native String getError ();
|
||||
public native String getOverrideSenderName();
|
||||
public native boolean isOutgoing();
|
||||
public native int getSenderColor();
|
||||
|
||||
public String getSenderName(DcContact dcContact, boolean markOverride) {
|
||||
public String getSenderName(DcContact dcContact) {
|
||||
String overrideName = getOverrideSenderName();
|
||||
if (overrideName != null) {
|
||||
return (markOverride ? "~" : "") + overrideName;
|
||||
return "~" + overrideName;
|
||||
} else {
|
||||
return dcContact.getDisplayName();
|
||||
}
|
||||
@@ -208,6 +209,10 @@ public class DcMsg {
|
||||
return ids;
|
||||
}
|
||||
|
||||
public boolean isOutgoing() {
|
||||
return getFromId() == DcContact.DC_CONTACT_ID_SELF;
|
||||
}
|
||||
|
||||
public String getDisplayBody() {
|
||||
return getText();
|
||||
}
|
||||
|
||||
@@ -79,23 +79,6 @@ public class Rpc {
|
||||
}
|
||||
}
|
||||
|
||||
public int addAccount() throws RpcException {
|
||||
return gson.fromJson(getResult("add_account"), int.class);
|
||||
}
|
||||
|
||||
public void startIO() throws RpcException {
|
||||
getResult("start_io_for_all_accounts");
|
||||
}
|
||||
|
||||
public void stopIO() throws RpcException {
|
||||
getResult("stop_io_for_all_accounts");
|
||||
}
|
||||
|
||||
public Map<String, String> getSystemInfo() throws RpcException {
|
||||
TypeToken<Map<String, String>> mapType = new TypeToken<Map<String, String>>(){};
|
||||
return gson.fromJson(getResult("get_system_info"), mapType.getType());
|
||||
}
|
||||
|
||||
public List<VcardContact> parseVcard(String path) throws RpcException {
|
||||
TypeToken<List<VcardContact>> listType = new TypeToken<List<VcardContact>>(){};
|
||||
return gson.fromJson(getResult("parse_vcard", path), listType.getType());
|
||||
|
||||
@@ -36,7 +36,6 @@ import org.thoughtcrime.securesms.connect.KeepAliveService;
|
||||
import org.thoughtcrime.securesms.connect.NetworkStateReceiver;
|
||||
import org.thoughtcrime.securesms.crypto.DatabaseSecret;
|
||||
import org.thoughtcrime.securesms.crypto.DatabaseSecretProvider;
|
||||
import org.thoughtcrime.securesms.crypto.PRNGFixes;
|
||||
import org.thoughtcrime.securesms.geolocation.DcLocationManager;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobManager;
|
||||
import org.thoughtcrime.securesms.notifications.FcmReceiveService;
|
||||
@@ -125,9 +124,6 @@ public class ApplicationContext extends MultiDexApplication {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if ("deltafans@nine.testrun.org".equals(ac.getConfig("configured_addr")) && !ac.isCommunity()) {
|
||||
ac.setCommunityMode(true);
|
||||
}
|
||||
}
|
||||
if (allAccounts.length == 0) {
|
||||
dcAccounts.addAccount();
|
||||
@@ -203,7 +199,6 @@ public class ApplicationContext extends MultiDexApplication {
|
||||
|
||||
KeepAliveService.maybeStartSelf(this);
|
||||
|
||||
initializeRandomNumberFix();
|
||||
initializeLogging();
|
||||
initializeJobManager();
|
||||
InChatSounds.getInstance(this);
|
||||
@@ -234,11 +229,10 @@ public class ApplicationContext extends MultiDexApplication {
|
||||
TimeUnit.MILLISECONDS)
|
||||
.setConstraints(constraints)
|
||||
.build();
|
||||
try {
|
||||
// in Android 4 this throws exception due to R8/shrinking
|
||||
WorkManager.getInstance(this)
|
||||
.enqueueUniquePeriodicWork("FetchWorker", ExistingPeriodicWorkPolicy.KEEP, fetchWorkRequest);
|
||||
} catch (Throwable e) {}
|
||||
WorkManager.getInstance(this).enqueueUniquePeriodicWork(
|
||||
"FetchWorker",
|
||||
ExistingPeriodicWorkPolicy.KEEP,
|
||||
fetchWorkRequest);
|
||||
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
|
||||
|
||||
if (Prefs.isPushEnabled(this)) {
|
||||
@@ -252,10 +246,6 @@ public class ApplicationContext extends MultiDexApplication {
|
||||
return jobManager;
|
||||
}
|
||||
|
||||
private void initializeRandomNumberFix() {
|
||||
PRNGFixes.apply();
|
||||
}
|
||||
|
||||
private void initializeLogging() {
|
||||
SignalProtocolLoggerProvider.setProvider(new AndroidSignalProtocolLogger());
|
||||
}
|
||||
|
||||
@@ -156,10 +156,6 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
|
||||
this.findPreference(PREFERENCE_CATEGORY_HELP)
|
||||
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_HELP));
|
||||
|
||||
if (VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
tintIcons(getActivity());
|
||||
}
|
||||
|
||||
DcHelper.getEventCenter(getActivity()).addObserver(DcContext.DC_EVENT_CONNECTIVITY_CHANGED, this);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,9 +33,6 @@ public abstract class BaseActionBarActivity extends AppCompatActivity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
onPreCreate();
|
||||
if (BaseActivity.isMenuWorkaroundRequired()) {
|
||||
forceOverflowMenu();
|
||||
}
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@@ -46,20 +43,6 @@ public abstract class BaseActionBarActivity extends AppCompatActivity {
|
||||
dynamicTheme.onResume(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
return (keyCode == KeyEvent.KEYCODE_MENU && BaseActivity.isMenuWorkaroundRequired()) || super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) {
|
||||
if (keyCode == KeyEvent.KEYCODE_MENU && BaseActivity.isMenuWorkaroundRequired()) {
|
||||
openOptionsMenu();
|
||||
return true;
|
||||
}
|
||||
return super.onKeyUp(keyCode, event);
|
||||
}
|
||||
|
||||
private void initializeScreenshotSecurity() {
|
||||
if (Prefs.isScreenSecurityEnabled(this)) {
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.os.Build;
|
||||
import android.os.Build.VERSION;
|
||||
import android.os.Build.VERSION_CODES;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
public abstract class BaseActivity extends FragmentActivity {
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
return (keyCode == KeyEvent.KEYCODE_MENU && isMenuWorkaroundRequired()) || super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) {
|
||||
if (keyCode == KeyEvent.KEYCODE_MENU && isMenuWorkaroundRequired()) {
|
||||
openOptionsMenu();
|
||||
return true;
|
||||
}
|
||||
return super.onKeyUp(keyCode, event);
|
||||
}
|
||||
|
||||
public static boolean isMenuWorkaroundRequired() {
|
||||
return VERSION.SDK_INT < VERSION_CODES.KITKAT && ("LGE".equalsIgnoreCase(Build.MANUFACTURER) || "E6710".equalsIgnoreCase(Build.DEVICE));
|
||||
}
|
||||
}
|
||||
@@ -364,9 +364,7 @@ public abstract class BaseConversationListFragment extends Fragment implements A
|
||||
|
||||
mode.setTitle("1");
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
requireActivity().getWindow().setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
|
||||
}
|
||||
requireActivity().getWindow().setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -395,11 +393,9 @@ public abstract class BaseConversationListFragment extends Fragment implements A
|
||||
actionMode = null;
|
||||
getListAdapter().initializeBatchMode(false);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
TypedArray color = requireActivity().getTheme().obtainStyledAttributes(new int[] {android.R.attr.statusBarColor});
|
||||
requireActivity().getWindow().setStatusBarColor(color.getColor(0, Color.BLACK));
|
||||
color.recycle();
|
||||
}
|
||||
TypedArray color = requireActivity().getTheme().obtainStyledAttributes(new int[]{android.R.attr.statusBarColor});
|
||||
requireActivity().getWindow().setStatusBarColor(color.getColor(0, Color.BLACK));
|
||||
color.recycle();
|
||||
|
||||
Context context = getContext();
|
||||
if (context != null) {
|
||||
|
||||
@@ -136,9 +136,7 @@ public class ContactSelectionListFragment extends Fragment
|
||||
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
|
||||
MenuInflater inflater = getActivity().getMenuInflater();
|
||||
inflater.inflate(R.menu.contact_list, menu);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
getActivity().getWindow().setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
|
||||
}
|
||||
getActivity().getWindow().setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
|
||||
setCorrectMenuVisibility(menu);
|
||||
actionMode.setTitle("1");
|
||||
return true;
|
||||
@@ -170,11 +168,9 @@ public class ContactSelectionListFragment extends Fragment
|
||||
ContactSelectionListFragment.this.actionMode = null;
|
||||
getContactSelectionListAdapter().resetActionModeSelection();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
TypedArray color = getActivity().getTheme().obtainStyledAttributes(new int[] {android.R.attr.statusBarColor});
|
||||
getActivity().getWindow().setStatusBarColor(color.getColor(0, Color.BLACK));
|
||||
color.recycle();
|
||||
}
|
||||
TypedArray color = getActivity().getTheme().obtainStyledAttributes(new int[]{android.R.attr.statusBarColor});
|
||||
getActivity().getWindow().setStatusBarColor(color.getColor(0, Color.BLACK));
|
||||
color.recycle();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ import android.text.TextWatcher;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
@@ -53,6 +54,7 @@ import android.view.View.OnFocusChangeListener;
|
||||
import android.view.View.OnKeyListener;
|
||||
import android.view.WindowManager;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
@@ -117,7 +119,7 @@ import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
import org.thoughtcrime.securesms.util.concurrent.AssertedSuccessListener;
|
||||
import org.thoughtcrime.securesms.util.guava.Optional;
|
||||
import org.thoughtcrime.securesms.util.views.Stub;
|
||||
import org.thoughtcrime.securesms.util.views.ProgressDialog;
|
||||
import org.thoughtcrime.securesms.video.recode.VideoRecoder;
|
||||
import org.thoughtcrime.securesms.videochat.VideochatUtil;
|
||||
|
||||
@@ -160,8 +162,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
private static final int GROUP_EDIT = 6;
|
||||
private static final int TAKE_PHOTO = 7;
|
||||
private static final int RECORD_VIDEO = 8;
|
||||
private static final int PICK_LOCATION = 9; // TODO: i think, this can be deleted
|
||||
private static final int SMS_DEFAULT = 11; // TODO: i think, this can be deleted
|
||||
private static final int PICK_WEBXDC = 9;
|
||||
|
||||
private GlideRequests glideRequests;
|
||||
protected ComposeText composeText;
|
||||
@@ -174,11 +175,13 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
private View composePanel;
|
||||
private ScaleStableImageView backgroundView;
|
||||
private MessageRequestsBottomView messageRequestBottomView;
|
||||
private ProgressDialog progressDialog;
|
||||
|
||||
private AttachmentTypeSelector attachmentTypeSelector;
|
||||
private AttachmentManager attachmentManager;
|
||||
private AudioRecorder audioRecorder;
|
||||
private Stub<MediaKeyboard> emojiDrawerStub;
|
||||
private FrameLayout emojiPickerContainer;
|
||||
private MediaKeyboard emojiPicker;
|
||||
protected HidingLinearLayout quickAttachmentToggle;
|
||||
private InputPanel inputPanel;
|
||||
|
||||
@@ -318,10 +321,11 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
super.onConfigurationChanged(newConfig);
|
||||
composeText.setTransport(sendButton.getSelectedTransport());
|
||||
|
||||
if (emojiDrawerStub.resolved() && container.getCurrentInput() == emojiDrawerStub.get()) {
|
||||
if (emojiPicker != null && container.getCurrentInput() == emojiPicker) {
|
||||
container.hideAttachedInput(true);
|
||||
}
|
||||
|
||||
emojiPicker = null; // force reloading next time onEmojiToggle() is called
|
||||
initializeBackground();
|
||||
}
|
||||
|
||||
@@ -335,8 +339,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
public void onActivityResult(final int reqCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(reqCode, resultCode, data);
|
||||
|
||||
if ((data == null && reqCode != TAKE_PHOTO && reqCode != RECORD_VIDEO && reqCode != SMS_DEFAULT) ||
|
||||
(resultCode != RESULT_OK && reqCode != SMS_DEFAULT))
|
||||
if (resultCode != RESULT_OK || (data == null && reqCode != TAKE_PHOTO && reqCode != RECORD_VIDEO))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -360,7 +363,11 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
for (int i = 0; i < uriCount; i++) {
|
||||
uriList.add(multipleUris.getItemAt(i).getUri());
|
||||
}
|
||||
askSendingFiles(uriList, () -> SendRelayedMessageUtil.sendMultipleMsgs(this, chatId, uriList, null));
|
||||
askSendingFiles(uriList, () -> {
|
||||
Util.runOnAnyBackgroundThread(() -> {
|
||||
SendRelayedMessageUtil.sendMultipleMsgs(this, chatId, uriList, null);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -372,6 +379,10 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
setMedia(data.getData(), docMediaType);
|
||||
break;
|
||||
|
||||
case PICK_WEBXDC:
|
||||
setMedia(data.getData(), MediaType.DOCUMENT);
|
||||
break;
|
||||
|
||||
case PICK_CONTACT:
|
||||
addAttachmentContactInfo(data.getIntExtra(AttachContactActivity.CONTACT_ID_EXTRA, 0));
|
||||
break;
|
||||
@@ -399,16 +410,9 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
}
|
||||
break;
|
||||
|
||||
case PICK_LOCATION:
|
||||
break;
|
||||
|
||||
case ScribbleActivity.SCRIBBLE_REQUEST_CODE:
|
||||
setMedia(data.getData(), MediaType.IMAGE);
|
||||
break;
|
||||
|
||||
case SMS_DEFAULT:
|
||||
initializeSecurity(isSecureText, isDefaultSms);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -708,7 +712,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
DcMsg draft = dcContext.getDraft(chatId);
|
||||
final String sharedText = RelayUtil.getSharedText(this);
|
||||
|
||||
if (draft == null) {
|
||||
if (!draft.isOk()) {
|
||||
if (TextUtils.isEmpty(sharedText)) {
|
||||
composeText.setText("");
|
||||
future.set(false);
|
||||
@@ -735,8 +739,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
handleReplyMessage(quote);
|
||||
}
|
||||
|
||||
String filename = draft.getFile();
|
||||
if (filename.isEmpty() || !new File(filename).exists()) {
|
||||
String file = draft.getFile();
|
||||
if (file.isEmpty() || !new File(file).exists()) {
|
||||
future.set(!text.isEmpty());
|
||||
updateToggleButtonState();
|
||||
return future;
|
||||
@@ -756,26 +760,21 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
}
|
||||
};
|
||||
|
||||
File file = new File(filename);
|
||||
Uri uri = Uri.fromFile(file);
|
||||
switch (draft.getType()) {
|
||||
case DcMsg.DC_MSG_IMAGE:
|
||||
setMedia(uri, MediaType.IMAGE).addListener(listener);
|
||||
setMedia(draft, MediaType.IMAGE).addListener(listener);
|
||||
break;
|
||||
case DcMsg.DC_MSG_GIF:
|
||||
setMedia(uri, MediaType.GIF).addListener(listener);
|
||||
setMedia(draft, MediaType.GIF).addListener(listener);
|
||||
break;
|
||||
case DcMsg.DC_MSG_AUDIO:
|
||||
setMedia(uri, MediaType.AUDIO).addListener(listener);
|
||||
setMedia(draft, MediaType.AUDIO).addListener(listener);
|
||||
break;
|
||||
case DcMsg.DC_MSG_VIDEO:
|
||||
setMedia(uri, MediaType.VIDEO).addListener(listener);
|
||||
break;
|
||||
case DcMsg.DC_MSG_WEBXDC:
|
||||
setMedia(draft, MediaType.DOCUMENT).addListener(listener);
|
||||
setMedia(draft, MediaType.VIDEO).addListener(listener);
|
||||
break;
|
||||
default:
|
||||
setMedia(uri, MediaType.DOCUMENT).addListener(listener);
|
||||
setMedia(draft, MediaType.DOCUMENT).addListener(listener);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -809,7 +808,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
sendButton = ViewUtil.findById(this, R.id.send_button);
|
||||
attachButton = ViewUtil.findById(this, R.id.attach_button);
|
||||
composeText = ViewUtil.findById(this, R.id.embedded_text_editor);
|
||||
emojiDrawerStub = ViewUtil.findStubById(this, R.id.emoji_drawer_stub);
|
||||
emojiPickerContainer = ViewUtil.findById(this, R.id.emoji_picker_container);
|
||||
composePanel = ViewUtil.findById(this, R.id.bottom_panel);
|
||||
container = ViewUtil.findById(this, R.id.layout_container);
|
||||
quickAttachmentToggle = ViewUtil.findById(this, R.id.quick_attachment_toggle);
|
||||
@@ -929,13 +928,10 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
case AttachmentTypeSelector.TAKE_PHOTO:
|
||||
attachmentManager.capturePhoto(this, TAKE_PHOTO); break;
|
||||
case AttachmentTypeSelector.RECORD_VIDEO:
|
||||
if(VideoRecoder.canRecode()) {
|
||||
attachmentManager.captureVideo(this, RECORD_VIDEO);
|
||||
}
|
||||
else {
|
||||
Toast.makeText(this, "This device does not support video-compression (requires Android 4.4 KitKat)", Toast.LENGTH_LONG).show();
|
||||
}
|
||||
attachmentManager.captureVideo(this, RECORD_VIDEO);
|
||||
break;
|
||||
case AttachmentTypeSelector.ADD_WEBXDC:
|
||||
AttachmentManager.selectWebxdc(this, PICK_WEBXDC); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -984,14 +980,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
protected static final int ACTION_SEND_OUT = 1;
|
||||
protected static final int ACTION_SAVE_DRAFT = 2;
|
||||
|
||||
private String getSelfReaction(int msgId) {
|
||||
try {
|
||||
final String [] selfReactions = rpc.getMsgReactions(dcContext.getAccountId(), msgId).getReactionsByContact().get(DcContact.DC_CONTACT_ID_SELF);
|
||||
if (selfReactions != null && selfReactions.length > 0) return selfReactions[0];
|
||||
} catch(Exception e) { e.printStackTrace(); }
|
||||
return null;
|
||||
}
|
||||
|
||||
protected ListenableFuture<Integer> processComposeControls(int action) {
|
||||
return processComposeControls(action, composeText.getTextTrimmed(),
|
||||
attachmentManager.isAttachmentPresent() ?
|
||||
@@ -1077,7 +1065,23 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
{
|
||||
boolean doSend = true;
|
||||
if (recompress==DcMsg.DC_MSG_VIDEO) {
|
||||
Util.runOnMain(() -> {
|
||||
progressDialog = ProgressDialog.show(
|
||||
ConversationActivity.this,
|
||||
"",
|
||||
getString(R.string.one_moment),
|
||||
true,
|
||||
false
|
||||
);
|
||||
});
|
||||
doSend = VideoRecoder.prepareVideo(ConversationActivity.this, dcChat.getId(), msg);
|
||||
Util.runOnMain(() -> {
|
||||
try {
|
||||
progressDialog.dismiss();
|
||||
} catch (final IllegalArgumentException e) {
|
||||
// The activity is finishing/destroyed, do nothing.
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (doSend) {
|
||||
@@ -1233,16 +1237,23 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
});
|
||||
}
|
||||
|
||||
private void reloadEmojiPicker() {
|
||||
emojiPickerContainer.removeAllViews();
|
||||
emojiPicker = (MediaKeyboard) LayoutInflater.from(this).inflate(R.layout.conversation_activity_emojidrawer_stub, emojiPickerContainer, false);
|
||||
emojiPickerContainer.addView(emojiPicker);
|
||||
inputPanel.setMediaKeyboard(emojiPicker);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEmojiToggle() {
|
||||
if (!emojiDrawerStub.resolved()) {
|
||||
inputPanel.setMediaKeyboard(emojiDrawerStub.get());
|
||||
if (emojiPicker == null) {
|
||||
reloadEmojiPicker();
|
||||
}
|
||||
|
||||
if (container.getCurrentInput() == emojiDrawerStub.get()) {
|
||||
if (container.getCurrentInput() == emojiPicker) {
|
||||
container.showSoftkey(composeText);
|
||||
} else {
|
||||
container.show(composeText, emojiDrawerStub.get());
|
||||
container.show(composeText, emojiPicker);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1271,6 +1282,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
msg.setQuote(quote.get().getQuotedMsg());
|
||||
}
|
||||
msg.setFile(path, null);
|
||||
msg.forceSticker();
|
||||
dcContext.sendMsg(chatId, msg);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,9 +24,9 @@ import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.TextUtils;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -211,7 +211,7 @@ public class ConversationFragment extends MessageSelectorFragment
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
dcContext.marknoticedChat((int) chatId);
|
||||
Util.runOnBackground(() -> dcContext.marknoticedChat((int) chatId));
|
||||
if (list.getAdapter() != null) {
|
||||
list.getAdapter().notifyDataSetChanged();
|
||||
}
|
||||
@@ -442,7 +442,7 @@ public class ConversationFragment extends MessageSelectorFragment
|
||||
|
||||
if (msg.getFromId() != prevMsg.getFromId() && !singleMsg) {
|
||||
DcContact contact = dcContext.getContact(msg.getFromId());
|
||||
result.append(msg.getSenderName(contact, false)).append(":\n");
|
||||
result.append(msg.getSenderName(contact)).append(":\n");
|
||||
}
|
||||
if (msg.getType() == DcMsg.DC_MSG_TEXT || (singleMsg && !msg.getText().isEmpty())) {
|
||||
result.append(msg.getText());
|
||||
@@ -704,7 +704,7 @@ public class ConversationFragment extends MessageSelectorFragment
|
||||
index++;
|
||||
}
|
||||
}
|
||||
dcContext.markseenMsgs(ids);
|
||||
Util.runOnAnyBackgroundThread(() -> dcContext.markseenMsgs(ids));
|
||||
}
|
||||
|
||||
|
||||
@@ -810,7 +810,10 @@ public class ConversationFragment extends MessageSelectorFragment
|
||||
DozeReminder.dozeReminderTapped(getContext());
|
||||
}
|
||||
else if(messageRecord.getInfoType() == DcMsg.DC_INFO_WEBXDC_INFO_MESSAGE) {
|
||||
scrollMaybeSmoothToMsgId(messageRecord.getParent().getId());
|
||||
WebxdcActivity.openWebxdcActivity(getContext(), messageRecord.getParent(), messageRecord.getWebxdcHref());
|
||||
}
|
||||
else if (!TextUtils.isEmpty(messageRecord.getPOILocation()) && messageRecord.getType() == DcMsg.DC_MSG_TEXT && !messageRecord.hasHtml()) {
|
||||
WebxdcActivity.openMaps(getContext(), getListAdapter().getChat().getId(), "index.html#"+messageRecord.getPOILocation());
|
||||
}
|
||||
else {
|
||||
String self_mail = dcContext.getConfig("configured_mail_user");
|
||||
@@ -911,11 +914,9 @@ public class ConversationFragment extends MessageSelectorFragment
|
||||
|
||||
mode.setTitle("1");
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
Window window = getActivity().getWindow();
|
||||
statusBarColor = window.getStatusBarColor();
|
||||
window.setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
|
||||
}
|
||||
Window window = getActivity().getWindow();
|
||||
statusBarColor = window.getStatusBarColor();
|
||||
window.setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
|
||||
|
||||
setCorrectMenuVisibility(menu);
|
||||
ConversationAdaptiveActionsToolbar.adjustMenuActions(menu, 10, requireActivity().getWindow().getDecorView().getMeasuredWidth());
|
||||
@@ -932,9 +933,7 @@ public class ConversationFragment extends MessageSelectorFragment
|
||||
((ConversationAdapter)list.getAdapter()).clearSelection();
|
||||
list.getAdapter().notifyDataSetChanged();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
getActivity().getWindow().setStatusBarColor(statusBarColor);
|
||||
}
|
||||
getActivity().getWindow().setStatusBarColor(statusBarColor);
|
||||
|
||||
actionMode = null;
|
||||
hideAddReactionView();
|
||||
|
||||
@@ -22,12 +22,10 @@ import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.text.Spannable;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
@@ -496,9 +494,7 @@ public class ConversationItem extends BaseConversationItem
|
||||
audioViewStub.get().setAudio(new AudioSlide(context, messageRecord), duration);
|
||||
audioViewStub.get().setOnClickListener(passthroughClickListener);
|
||||
audioViewStub.get().setOnLongClickListener(passthroughClickListener);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
audioViewStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
|
||||
}
|
||||
audioViewStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
|
||||
|
||||
ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
@@ -516,9 +512,7 @@ public class ConversationItem extends BaseConversationItem
|
||||
documentViewStub.get().setDocument(new DocumentSlide(context, messageRecord));
|
||||
documentViewStub.get().setDocumentClickListener(new ThumbnailClickListener());
|
||||
documentViewStub.get().setOnLongClickListener(passthroughClickListener);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
documentViewStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
|
||||
}
|
||||
documentViewStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
|
||||
|
||||
ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
@@ -535,9 +529,7 @@ public class ConversationItem extends BaseConversationItem
|
||||
webxdcViewStub.get().setWebxdc(messageRecord, context.getString(R.string.webxdc_app));
|
||||
webxdcViewStub.get().setWebxdcClickListener(new ThumbnailClickListener());
|
||||
webxdcViewStub.get().setOnLongClickListener(passthroughClickListener);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
webxdcViewStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
|
||||
}
|
||||
webxdcViewStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
|
||||
|
||||
ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
@@ -555,9 +547,7 @@ public class ConversationItem extends BaseConversationItem
|
||||
vcardViewStub.get().setVcardClickListener(new ThumbnailClickListener());
|
||||
vcardViewStub.get().setOnLongClickListener(passthroughClickListener);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
vcardViewStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
|
||||
}
|
||||
vcardViewStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
|
||||
|
||||
ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
@@ -593,9 +583,7 @@ public class ConversationItem extends BaseConversationItem
|
||||
mediaThumbnailStub.get().setOnLongClickListener(passthroughClickListener);
|
||||
mediaThumbnailStub.get().setOnClickListener(passthroughClickListener);
|
||||
mediaThumbnailStub.get().showShade(TextUtils.isEmpty(messageRecord.getText()));
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
mediaThumbnailStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
|
||||
}
|
||||
mediaThumbnailStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
|
||||
|
||||
setThumbnailOutlineCorners(messageRecord, showSender);
|
||||
|
||||
@@ -618,9 +606,7 @@ public class ConversationItem extends BaseConversationItem
|
||||
stickerStub.get().setThumbnailClickListener(new StickerClickListener());
|
||||
stickerStub.get().setOnLongClickListener(passthroughClickListener);
|
||||
stickerStub.get().setOnClickListener(passthroughClickListener);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
stickerStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
|
||||
}
|
||||
stickerStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
|
||||
|
||||
ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
@@ -681,7 +667,7 @@ public class ConversationItem extends BaseConversationItem
|
||||
contactPhoto.setVisibility(View.GONE);
|
||||
} else {
|
||||
int color = messageRecord.getSenderColor();
|
||||
Recipient recipient = new Recipient(context, dcContact, messageRecord.getSenderName(dcContact, !dcContext.isCommunity()), color);
|
||||
Recipient recipient = new Recipient(context, dcContact, messageRecord.getSenderName(dcContact), color);
|
||||
contactPhoto.setAvatar(glideRequests, recipient, true);
|
||||
contactPhoto.setVisibility(View.VISIBLE);
|
||||
}
|
||||
@@ -806,14 +792,14 @@ public class ConversationItem extends BaseConversationItem
|
||||
|
||||
if (messageRecord.isForwarded()) {
|
||||
if (showSender && dcContact !=null) {
|
||||
this.groupSender.setText(context.getString(R.string.forwarded_by, messageRecord.getSenderName(dcContact, false)));
|
||||
this.groupSender.setText(context.getString(R.string.forwarded_by, messageRecord.getSenderName(dcContact)));
|
||||
} else {
|
||||
this.groupSender.setText(context.getString(R.string.forwarded_message));
|
||||
}
|
||||
this.groupSender.setTextColor(context.getResources().getColor(R.color.unknown_sender));
|
||||
}
|
||||
else if (showSender && dcContact !=null) {
|
||||
this.groupSender.setText(messageRecord.getSenderName(dcContact, true));
|
||||
this.groupSender.setText(messageRecord.getSenderName(dcContact));
|
||||
int color = messageRecord.getSenderColor();
|
||||
this.groupSender.setTextColor(Util.rgbToArgbColor(color!=0? color : dcContact.getColor()));
|
||||
}
|
||||
|
||||
@@ -174,9 +174,7 @@ class ConversationItemSwipeCallback extends ItemTouchHelper.SimpleCallback {
|
||||
vibrate(viewHolder.itemView.getContext());
|
||||
}
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
recyclerView.cancelPendingInputEvents();
|
||||
}
|
||||
recyclerView.cancelPendingInputEvents();
|
||||
}
|
||||
|
||||
private static void resetProgress(RecyclerView.ViewHolder viewHolder) {
|
||||
@@ -199,11 +197,7 @@ class ConversationItemSwipeCallback extends ItemTouchHelper.SimpleCallback {
|
||||
}
|
||||
|
||||
private static float getSignFromDirection(@NonNull View view) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
return view.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL ? -1f : 1f;
|
||||
} else {
|
||||
return 1f;
|
||||
}
|
||||
return view.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL ? -1f : 1f;
|
||||
}
|
||||
|
||||
private static boolean sameSign(float dX, float sign) {
|
||||
|
||||
@@ -89,7 +89,6 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
||||
public static final String CLEAR_NOTIFICATIONS = "clear_notifications";
|
||||
public static final String ACCOUNT_ID_EXTRA = "account_id";
|
||||
public static final String FROM_WELCOME = "from_welcome";
|
||||
public static final String WARN_CANNOT_ENCRYPT = "warn_cannot_encrypt";
|
||||
|
||||
private ConversationListFragment conversationListFragment;
|
||||
public TextView title;
|
||||
@@ -113,7 +112,7 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
||||
// it is not needed to keep all past update messages, however, when deleted, also the strings should be deleted.
|
||||
try {
|
||||
DcContext dcContext = DcHelper.getContext(this);
|
||||
final String deviceMsgLabel = "update_1_46_0l_android";
|
||||
final String deviceMsgLabel = "update_1_50_0_android";
|
||||
if (!dcContext.wasDeviceMsgEverAdded(deviceMsgLabel)) {
|
||||
DcMsg msg = null;
|
||||
if (!getIntent().getBooleanExtra(FROM_WELCOME, false)) {
|
||||
@@ -124,7 +123,7 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
||||
// Util.copy(inputStream, new FileOutputStream(outputFile));
|
||||
// msg.setFile(outputFile, "image/jpeg");
|
||||
|
||||
msg.setText(getString(R.string.update_1_46_android, "https://raw.githubusercontent.com/ArcaneChat/android/refs/heads/main/CHANGELOG.md"));
|
||||
msg.setText(getString(R.string.update_1_50_android, "https://raw.githubusercontent.com/ArcaneChat/android/refs/heads/main/CHANGELOG.md"));
|
||||
}
|
||||
dcContext.addDeviceMsg(deviceMsgLabel, msg);
|
||||
|
||||
@@ -257,6 +256,10 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
if (isFinishing()) {
|
||||
Log.w(TAG, "Activity is finishing, aborting onNewIntent()");
|
||||
return;
|
||||
}
|
||||
super.onNewIntent(intent);
|
||||
setIntent(intent);
|
||||
refresh();
|
||||
@@ -274,11 +277,6 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
||||
AccountManager.getInstance().switchAccountAndStartActivity(this, accountId);
|
||||
}
|
||||
|
||||
String warnAddr = getIntent().getStringExtra(WARN_CANNOT_ENCRYPT);
|
||||
if (!TextUtils.isEmpty(warnAddr)) {
|
||||
DcHelper.showEncryptionRequiredDialog(this, warnAddr);
|
||||
}
|
||||
|
||||
refreshAvatar();
|
||||
refreshUnreadIndicator();
|
||||
refreshTitle();
|
||||
@@ -458,11 +456,8 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
||||
case R.id.menu_all_media:
|
||||
startActivity(new Intent(this, ProfileActivity.class));
|
||||
return true;
|
||||
case R.id.menu_webxdc_apps_store:
|
||||
handleShowBot("juegos@buzon.uy", "OPENPGP4FPR:d3d403a734be71fe9293a00311fef80dbe5dbc89#a=juegos%40buzon.uy&n=&i=WQZY-8FODS3&s=ZQBkaclFzao");
|
||||
return true;
|
||||
case R.id.menu_public_bots:
|
||||
handleShowBot("puente@buzon.uy", "OPENPGP4FPR:4B41E5AFAF78A0C71DB56138D5BEFED00A45F97A#a=puente%40buzon.uy&n=Public%20Bots&i=ZC_oaJtuvJP&s=5SE96rRovsK");
|
||||
handleShowBot("botsindex@arcanechat.me", "https://i.delta.chat/#67889B0362BEDBFEE05ACD92C1D737FA632A9582&a=botsindex%40arcanechat.me&n=Public%20Bots&i=336MTEz38EH-RJxM9OKWygYK&s=TpVVGK6C4KrJmRG0bwHLalXt");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -564,7 +559,7 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
||||
private void shareInvite() {
|
||||
Intent intent = new Intent(Intent.ACTION_SEND);
|
||||
intent.setType("text/plain");
|
||||
String inviteURL = Util.QrDataToInviteURL(DcHelper.getContext(this).getSecurejoinQr(0));
|
||||
String inviteURL = DcHelper.getContext(this).getSecurejoinQr(0);
|
||||
intent.putExtra(Intent.EXTRA_TEXT, getString(R.string.invite_friends_text, inviteURL));
|
||||
startActivity(Intent.createChooser(intent, getString(R.string.chat_share_with_title)));
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ public class ConversationListItemInboxZero extends LinearLayout implements Binda
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
public ConversationListItemInboxZero(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.loader.app.LoaderManager;
|
||||
|
||||
import com.b44t.messenger.DcChat;
|
||||
@@ -221,22 +220,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
|
||||
updateGroup(groupName);
|
||||
} else {
|
||||
verified = !broadcast && allMembersVerified();
|
||||
if (verified && getAdapter().getContacts().size() == 1) {
|
||||
new AlertDialog.Builder(this)
|
||||
.setMessage(R.string.create_verified_group_ask)
|
||||
.setNeutralButton(R.string.learn_more, (d, w) -> DcHelper.openHelp(this, "#e2eeguarantee"))
|
||||
.setPositiveButton(R.string.yes, (d, w) -> {
|
||||
createGroup(groupName);
|
||||
})
|
||||
.setNegativeButton(R.string.no, (d, w) -> {
|
||||
verified = false;
|
||||
createGroup(groupName);
|
||||
})
|
||||
.setCancelable(true)
|
||||
.show();
|
||||
} else {
|
||||
createGroup(groupName);
|
||||
}
|
||||
createGroup(groupName);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -56,6 +56,7 @@ import org.thoughtcrime.securesms.profiles.ProfileMediaConstraints;
|
||||
import org.thoughtcrime.securesms.proxy.ProxySettingsActivity;
|
||||
import org.thoughtcrime.securesms.qr.RegistrationQrActivity;
|
||||
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.views.ProgressDialog;
|
||||
@@ -71,7 +72,7 @@ public class InstantOnboardingActivity extends BaseActionBarActivity implements
|
||||
private static final String DCACCOUNT = "dcaccount";
|
||||
private static final String DCLOGIN = "dclogin";
|
||||
private static final String INSTANCES_URL = "https://delta.chat/chatmail";
|
||||
private static final String DEFAULT_CHATMAIL_HOST = "nine.testrun.org";
|
||||
private static final String DEFAULT_CHATMAIL_HOST = "arcanechat.me";
|
||||
|
||||
public static final String QR_ACCOUNT_EXTRA = "qr_account_extra";
|
||||
public static final String FROM_WELCOME = "from_welcome";
|
||||
@@ -246,16 +247,22 @@ public class InstantOnboardingActivity extends BaseActionBarActivity implements
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
|
||||
final String displayName = name.getText().toString();
|
||||
DcHelper.set(this, DcHelper.CONFIG_DISPLAY_NAME, TextUtils.isEmpty(displayName)? null : displayName);
|
||||
// Save display name and avatar in the unconfigured profile.
|
||||
// If the currently selected profile is configured, then this means that rollbackAccountCreation()
|
||||
// was called (see handleOnBackPressed() above), i.e. the newly created profile was removed already
|
||||
// and we can't save the display name & avatar.
|
||||
if (DcHelper.getContext(this).isConfigured() == 0) {
|
||||
final String displayName = name.getText().toString();
|
||||
DcHelper.set(this, DcHelper.CONFIG_DISPLAY_NAME, TextUtils.isEmpty(displayName) ? null : displayName);
|
||||
|
||||
if (avatarChanged) {
|
||||
try {
|
||||
AvatarHelper.setSelfAvatar(InstantOnboardingActivity.this, avatarBmp);
|
||||
Prefs.setProfileAvatarId(InstantOnboardingActivity.this, new SecureRandom().nextInt());
|
||||
avatarChanged = false;
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Failed to save avatar", e);
|
||||
if (avatarChanged) {
|
||||
try {
|
||||
AvatarHelper.setSelfAvatar(InstantOnboardingActivity.this, avatarBmp);
|
||||
Prefs.setProfileAvatarId(InstantOnboardingActivity.this, new SecureRandom().nextInt());
|
||||
avatarChanged = false;
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Failed to save avatar", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -327,14 +334,14 @@ public class InstantOnboardingActivity extends BaseActionBarActivity implements
|
||||
|
||||
privacyPolicyBtn.setOnClickListener(view -> {
|
||||
if (!isDcLogin) {
|
||||
WebViewActivity.openUrlInBrowser(this, "https://" + providerHost + "/privacy.html");
|
||||
IntentUtils.showInBrowser(this, "https://" + providerHost + "/privacy.html");
|
||||
}
|
||||
});
|
||||
|
||||
signUpBtn.setOnClickListener(view -> createProfile());
|
||||
|
||||
findViewById(R.id.use_other_server).setOnClickListener((v) -> {
|
||||
WebViewActivity.openUrlInBrowser(this, INSTANCES_URL);
|
||||
IntentUtils.showInBrowser(this, INSTANCES_URL);
|
||||
});
|
||||
findViewById(R.id.login_button).setOnClickListener((v) -> {
|
||||
startRegistrationActivity();
|
||||
|
||||
@@ -62,16 +62,16 @@ public class LocalHelpActivity extends WebViewActivity
|
||||
webView.scrollTo(0, 0);
|
||||
return true;
|
||||
case R.id.learn_more:
|
||||
openOnlineUrl("https://delta.chat");
|
||||
openOnlineUrl("https://arcanechat.me");
|
||||
return true;
|
||||
case R.id.privacy_policy:
|
||||
openOnlineUrl("https://delta.chat/gdpr");
|
||||
openOnlineUrl("https://arcanechat.me/privacy.html");
|
||||
return true;
|
||||
case R.id.contribute:
|
||||
openOnlineUrl("https://github.com/deltachat/deltachat-android");
|
||||
openOnlineUrl("https://arcanechat.me/#contribute");
|
||||
return true;
|
||||
case R.id.report_issue:
|
||||
openOnlineUrl("https://github.com/deltachat/deltachat-android/issues");
|
||||
openOnlineUrl("https://github.com/ArcaneChat/android/issues");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -197,12 +197,11 @@ public class LogViewFragment extends Fragment {
|
||||
asMegs(info.maxMemory()));
|
||||
}
|
||||
|
||||
@TargetApi(VERSION_CODES.KITKAT)
|
||||
public static String getMemoryClass(Context context) {
|
||||
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
String lowMem = "";
|
||||
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.KITKAT && activityManager.isLowRamDevice()) {
|
||||
if (activityManager.isLowRamDevice()) {
|
||||
lowMem = ", low-mem device";
|
||||
}
|
||||
return activityManager.getMemoryClass() + lowMem;
|
||||
@@ -252,10 +251,8 @@ public class LogViewFragment extends Fragment {
|
||||
|
||||
Locale locale = Util.getLocale();
|
||||
builder.append("lang=").append(locale.toString()).append("\n");
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
boolean isRtl = Util.getLayoutDirection(context) == View.LAYOUT_DIRECTION_RTL;
|
||||
builder.append("rtl=").append(isRtl).append("\n");
|
||||
}
|
||||
boolean isRtl = Util.getLayoutDirection(context) == View.LAYOUT_DIRECTION_RTL;
|
||||
builder.append("rtl=").append(isRtl).append("\n");
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
boolean notifPermGranted = PermissionChecker.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) == PermissionChecker.PERMISSION_GRANTED;
|
||||
|
||||
@@ -207,7 +207,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
messageRecord = null;
|
||||
long date = getIntent().getLongExtra(DATE_EXTRA, 0);
|
||||
long size = getIntent().getLongExtra(SIZE_EXTRA, 0);
|
||||
initialMedia = new MediaItem(null, getIntent().getData(), getIntent().getType(),
|
||||
initialMedia = new MediaItem(null, getIntent().getData(), null, getIntent().getType(),
|
||||
DcMsg.DC_MSG_NO_ID, date, size, false);
|
||||
|
||||
if (address != null) {
|
||||
@@ -218,7 +218,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
} else {
|
||||
messageRecord = dcContext.getMsg(msgId);
|
||||
initialMedia = new MediaItem(Recipient.fromChat(context, msgId), Uri.fromFile(messageRecord.getFileAsFile()),
|
||||
messageRecord.getFilemime(), messageRecord.getId(), messageRecord.getDateReceived(),
|
||||
messageRecord.getFilename(), messageRecord.getFilemime(), messageRecord.getId(), messageRecord.getDateReceived(),
|
||||
messageRecord.getFilebytes(), messageRecord.isOutgoing());
|
||||
conversationRecipient = Recipient.fromChat(context, msgId);
|
||||
}
|
||||
@@ -232,12 +232,11 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
// if you search for the place where the media are loaded, go to 'onCreateLoader'.
|
||||
|
||||
Log.w(TAG, "Loading Part URI: " + initialMedia);
|
||||
|
||||
if (messageRecord != null) {
|
||||
getSupportLoaderManager().restartLoader(0, null, this);
|
||||
} else {
|
||||
mediaPager.setAdapter(new SingleItemPagerAdapter(this, GlideApp.with(this),
|
||||
getWindow(), initialMedia.uri, initialMedia.type, initialMedia.size));
|
||||
getWindow(), initialMedia.uri, initialMedia.name, initialMedia.type, initialMedia.size));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,7 +312,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
private void performSavetoDisk(@NonNull MediaItem mediaItem) {
|
||||
SaveAttachmentTask saveTask = new SaveAttachmentTask(MediaPreviewActivity.this);
|
||||
long saveDate = (mediaItem.date > 0) ? mediaItem.date : System.currentTimeMillis();
|
||||
saveTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, new Attachment(mediaItem.uri, mediaItem.type, saveDate, null));
|
||||
saveTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, new Attachment(mediaItem.uri, mediaItem.type, saveDate, mediaItem.name));
|
||||
}
|
||||
|
||||
private void showInChat() {
|
||||
@@ -473,9 +472,12 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
MediaItemAdapter adapter = (MediaItemAdapter)mediaPager.getAdapter();
|
||||
|
||||
if (adapter != null) {
|
||||
MediaItem item = adapter.getMediaItemFor(position);
|
||||
if (item.recipient != null) item.recipient.removeListener(MediaPreviewActivity.this);
|
||||
|
||||
try {
|
||||
MediaItem item = adapter.getMediaItemFor(position);
|
||||
if (item.recipient != null) item.recipient.removeListener(MediaPreviewActivity.this);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.w(TAG, "Ignoring invalid position index");
|
||||
}
|
||||
adapter.pause(position);
|
||||
}
|
||||
}
|
||||
@@ -486,18 +488,20 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
private final GlideRequests glideRequests;
|
||||
private final Window window;
|
||||
private final Uri uri;
|
||||
private final String name;
|
||||
private final String mediaType;
|
||||
private final long size;
|
||||
|
||||
private final LayoutInflater inflater;
|
||||
|
||||
SingleItemPagerAdapter(@NonNull Context context, @NonNull GlideRequests glideRequests,
|
||||
@NonNull Window window, @NonNull Uri uri, @NonNull String mediaType,
|
||||
@NonNull Window window, @NonNull Uri uri, @Nullable String name, @NonNull String mediaType,
|
||||
long size)
|
||||
{
|
||||
this.glideRequests = glideRequests;
|
||||
this.window = window;
|
||||
this.uri = uri;
|
||||
this.name = name;
|
||||
this.mediaType = mediaType;
|
||||
this.size = size;
|
||||
this.inflater = LayoutInflater.from(context);
|
||||
@@ -519,7 +523,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
MediaView mediaView = itemView.findViewById(R.id.media_view);
|
||||
|
||||
try {
|
||||
mediaView.set(glideRequests, window, uri, mediaType, size, true);
|
||||
mediaView.set(glideRequests, window, uri, name, mediaType, size, true);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
@@ -539,7 +543,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
|
||||
@Override
|
||||
public MediaItem getMediaItemFor(int position) {
|
||||
return new MediaItem(null, uri, mediaType, DcMsg.DC_MSG_NO_ID, -1, -1, true);
|
||||
return new MediaItem(null, uri, name, mediaType, DcMsg.DC_MSG_NO_ID, -1, -1, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -604,7 +608,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
|
||||
try {
|
||||
//noinspection ConstantConditions
|
||||
mediaView.set(glideRequests, window, Uri.fromFile(msg.getFileAsFile()),
|
||||
mediaView.set(glideRequests, window, Uri.fromFile(msg.getFileAsFile()), msg.getFilename(),
|
||||
msg.getFilemime(), msg.getFilebytes(), autoplay);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
@@ -633,6 +637,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
|
||||
return new MediaItem(Recipient.fromChat(context, msg.getId()),
|
||||
Uri.fromFile(msg.getFileAsFile()),
|
||||
msg.getFilename(),
|
||||
msg.getFilemime(),
|
||||
msg.getId(),
|
||||
msg.getDateReceived(),
|
||||
@@ -655,6 +660,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
private static class MediaItem {
|
||||
private final @Nullable Recipient recipient;
|
||||
private final @NonNull Uri uri;
|
||||
private final @Nullable String name;
|
||||
private final @NonNull String type;
|
||||
private final int msgId;
|
||||
private final long date;
|
||||
@@ -663,6 +669,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
|
||||
private MediaItem(@Nullable Recipient recipient,
|
||||
@NonNull Uri uri,
|
||||
@Nullable String name,
|
||||
@NonNull String type,
|
||||
int msgId,
|
||||
long date,
|
||||
@@ -671,6 +678,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
|
||||
{
|
||||
this.recipient = recipient;
|
||||
this.uri = uri;
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.msgId = msgId;
|
||||
this.date = date;
|
||||
|
||||
@@ -111,8 +111,6 @@ public class NewConversationActivity extends ContactSelectionActivity {
|
||||
int contactId = dcContext.lookupContactIdByAddr(addr);
|
||||
if (contactId!=0 && dcContext.getChatIdByContactId(contactId)!=0) {
|
||||
openConversation(dcContext.getChatIdByContactId(contactId));
|
||||
} else if (contactId == 0 && dcContext.isChatmail()) {
|
||||
DcHelper.showEncryptionRequiredDialog(this, addr);
|
||||
} else {
|
||||
String nameNAddr = contactId == 0 ? addr : dcContext.getContact(contactId).getNameNAddr();
|
||||
new AlertDialog.Builder(this)
|
||||
|
||||
@@ -229,11 +229,9 @@ public class ProfileDocumentsFragment
|
||||
mode.getMenuInflater().inflate(R.menu.profile_context, menu);
|
||||
mode.setTitle("1");
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
Window window = getActivity().getWindow();
|
||||
originalStatusBarColor = window.getStatusBarColor();
|
||||
window.setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
|
||||
}
|
||||
Window window = getActivity().getWindow();
|
||||
originalStatusBarColor = window.getStatusBarColor();
|
||||
window.setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
|
||||
setCorrectMenuVisibility(menu);
|
||||
return true;
|
||||
}
|
||||
@@ -283,9 +281,7 @@ public class ProfileDocumentsFragment
|
||||
actionMode = null;
|
||||
getListAdapter().clearSelection();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
getActivity().getWindow().setStatusBarColor(originalStatusBarColor);
|
||||
}
|
||||
getActivity().getWindow().setStatusBarColor(originalStatusBarColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,11 +219,9 @@ public class ProfileGalleryFragment
|
||||
mode.getMenuInflater().inflate(R.menu.profile_context, menu);
|
||||
mode.setTitle("1");
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
Window window = getActivity().getWindow();
|
||||
originalStatusBarColor = window.getStatusBarColor();
|
||||
window.setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
|
||||
}
|
||||
Window window = getActivity().getWindow();
|
||||
originalStatusBarColor = window.getStatusBarColor();
|
||||
window.setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
|
||||
setCorrectMenuVisibility(menu);
|
||||
return true;
|
||||
}
|
||||
@@ -269,9 +267,7 @@ public class ProfileGalleryFragment
|
||||
actionMode = null;
|
||||
getListAdapter().clearSelection();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
getActivity().getWindow().setStatusBarColor(originalStatusBarColor);
|
||||
}
|
||||
getActivity().getWindow().setStatusBarColor(originalStatusBarColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,11 +268,9 @@ public class ProfileSettingsFragment extends Fragment
|
||||
menu.findItem(R.id.menu_select_all).setVisible(false);
|
||||
mode.setTitle("1");
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
Window window = getActivity().getWindow();
|
||||
originalStatusBarColor = window.getStatusBarColor();
|
||||
window.setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
|
||||
}
|
||||
Window window = getActivity().getWindow();
|
||||
originalStatusBarColor = window.getStatusBarColor();
|
||||
window.setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -314,9 +312,7 @@ public class ProfileSettingsFragment extends Fragment
|
||||
public void onDestroyActionMode(ActionMode mode) {
|
||||
actionMode = null;
|
||||
adapter.clearSelection();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
getActivity().getWindow().setStatusBarColor(originalStatusBarColor);
|
||||
}
|
||||
getActivity().getWindow().setStatusBarColor(originalStatusBarColor);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_PROXY_ENABLED;
|
||||
import static org.thoughtcrime.securesms.connect.DcHelper.getContext;
|
||||
import static org.thoughtcrime.securesms.service.IPCAddAccountsService.ACCOUNT_DATA;
|
||||
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
@@ -438,7 +437,7 @@ public class RegistrationActivity extends BaseActionBarActivity implements DcEve
|
||||
.setPositiveButton(R.string.perm_continue, (dialog, which)-> {
|
||||
// pass control to browser, we'll be back in business at (**)
|
||||
activity.oauth2Requested = System.currentTimeMillis();
|
||||
IntentUtils.showBrowserIntent(activity, oauth2url);
|
||||
IntentUtils.showInBrowser(activity, oauth2url);
|
||||
oauth2started.set(true);
|
||||
})
|
||||
.setCancelable(false)
|
||||
@@ -493,11 +492,7 @@ public class RegistrationActivity extends BaseActionBarActivity implements DcEve
|
||||
if (provider!=null) {
|
||||
String url = provider.getOverviewPage();
|
||||
if(!url.isEmpty()) {
|
||||
try {
|
||||
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Toast.makeText(this, R.string.no_browser_installed, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
IntentUtils.showInBrowser(this, url);
|
||||
} else {
|
||||
// this should normally not happen
|
||||
Toast.makeText(this, "ErrProviderWithoutUrl", Toast.LENGTH_LONG).show();
|
||||
|
||||
@@ -58,6 +58,7 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity implement
|
||||
{
|
||||
private static final String TAG = ShareActivity.class.getSimpleName();
|
||||
|
||||
public static final String EXTRA_ACC_ID = "acc_id";
|
||||
public static final String EXTRA_CHAT_ID = "chat_id";
|
||||
public static final String EXTRA_MSG_TYPE = "msg_type";
|
||||
public static final String EXTRA_MSG_SUBJECT = "msg_subject";
|
||||
@@ -213,14 +214,10 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity implement
|
||||
}
|
||||
|
||||
private void handleResolvedMedia(Intent intent) {
|
||||
int accId = intent.getIntExtra(EXTRA_ACC_ID, -1);
|
||||
int chatId = intent.getIntExtra(EXTRA_CHAT_ID, -1);
|
||||
String msgType = intent.getStringExtra(EXTRA_MSG_TYPE);
|
||||
|
||||
String shortcutId = intent.getStringExtra(ShortcutManagerCompat.EXTRA_SHORTCUT_ID);
|
||||
if (chatId == -1 && shortcutId != null) {
|
||||
chatId = Integer.parseInt(shortcutId);
|
||||
}
|
||||
|
||||
String[] extraEmail = getIntent().getStringArrayExtra(Intent.EXTRA_EMAIL);
|
||||
/*
|
||||
usually, external app will try to start "e-mail sharing" intent, providing it:
|
||||
@@ -259,28 +256,21 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity implement
|
||||
}
|
||||
*/
|
||||
|
||||
String addr = null;
|
||||
if(chatId == -1 && extraEmail != null && extraEmail.length > 0) {
|
||||
addr = extraEmail[0];
|
||||
final String addr = extraEmail[0];
|
||||
int contactId = dcContext.lookupContactIdByAddr(addr);
|
||||
|
||||
if(contactId != 0 || !dcContext.isChatmail()) {
|
||||
if(contactId == 0) {
|
||||
contactId = dcContext.createContact(null, addr);
|
||||
}
|
||||
|
||||
chatId = dcContext.createChatByContactId(contactId);
|
||||
addr = null;
|
||||
if(contactId == 0) {
|
||||
contactId = dcContext.createContact(null, addr);
|
||||
}
|
||||
|
||||
chatId = dcContext.createChatByContactId(contactId);
|
||||
}
|
||||
Intent composeIntent;
|
||||
if (addr != null) {
|
||||
composeIntent = new Intent(this, ConversationListActivity.class);
|
||||
composeIntent.putExtra(ConversationListActivity.WARN_CANNOT_ENCRYPT, addr);
|
||||
startActivity(composeIntent);
|
||||
} else if (chatId != -1) {
|
||||
if (accId != -1 && chatId != -1) {
|
||||
composeIntent = getBaseShareIntent(ConversationActivity.class);
|
||||
composeIntent.putExtra(ConversationActivity.CHAT_ID_EXTRA, chatId);
|
||||
composeIntent.putExtra(ConversationActivity.ACCOUNT_ID_EXTRA, accId);
|
||||
RelayUtil.setSharedType(composeIntent, msgType);
|
||||
RelayUtil.setSharedUris(composeIntent, resolvedExtras);
|
||||
startActivity(composeIntent);
|
||||
|
||||
@@ -26,6 +26,7 @@ import androidx.webkit.ProxyController;
|
||||
import androidx.webkit.ProxyConfig;
|
||||
|
||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||
import org.thoughtcrime.securesms.util.IntentUtils;
|
||||
|
||||
public class WebViewActivity extends PassphraseRequiredActionBarActivity
|
||||
implements SearchView.OnQueryTextListener,
|
||||
@@ -278,16 +279,8 @@ public class WebViewActivity extends PassphraseRequiredActionBarActivity
|
||||
// onBackPressed() can be overwritten by derived classes as needed.
|
||||
// the default behavior (close the activity) is just fine eg. for Webxdc, Connectivity, HTML-mails
|
||||
|
||||
public static void openUrlInBrowser(Context context, String url) {
|
||||
try {
|
||||
context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Toast.makeText(context, R.string.no_browser_installed, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean openOnlineUrl(String url) {
|
||||
openUrlInBrowser(this, url);
|
||||
IntentUtils.showInBrowser(this, url);
|
||||
// returning `true` causes the WebView to abort loading
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Base64;
|
||||
@@ -40,11 +39,13 @@ import com.b44t.messenger.DcEvent;
|
||||
import com.b44t.messenger.DcMsg;
|
||||
import com.b44t.messenger.rpc.Rpc;
|
||||
import com.b44t.messenger.rpc.RpcException;
|
||||
import com.google.common.base.Charsets;
|
||||
|
||||
import org.json.JSONObject;
|
||||
import org.thoughtcrime.securesms.connect.AccountManager;
|
||||
import org.thoughtcrime.securesms.connect.DcEventCenter;
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
import org.thoughtcrime.securesms.util.IntentUtils;
|
||||
import org.thoughtcrime.securesms.util.JsonUtils;
|
||||
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||
import org.thoughtcrime.securesms.util.Prefs;
|
||||
@@ -54,6 +55,8 @@ import java.io.ByteArrayInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -63,7 +66,9 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE
|
||||
private static final String EXTRA_ACCOUNT_ID = "accountId";
|
||||
private static final String EXTRA_APP_MSG_ID = "appMessageId";
|
||||
private static final String EXTRA_HIDE_ACTION_BAR = "hideActionBar";
|
||||
private static final String EXTRA_HREF = "href";
|
||||
private static final int REQUEST_CODE_FILE_PICKER = 51426;
|
||||
private static long lastOpenTime = 0;
|
||||
|
||||
private ValueCallback<Uri[]> filePathCallback;
|
||||
private DcContext dcContext;
|
||||
@@ -71,12 +76,23 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE
|
||||
private DcMsg dcAppMsg;
|
||||
private String baseURL;
|
||||
private String sourceCodeUrl = "";
|
||||
private String selfAddr;
|
||||
private int sendUpdateMaxSize;
|
||||
private int sendUpdateInterval;
|
||||
private boolean internetAccess = false;
|
||||
private boolean hideActionBar = false;
|
||||
|
||||
public static void openMaps(Context context, int chatId) {
|
||||
openMaps(context, chatId, "");
|
||||
}
|
||||
|
||||
public static void openMaps(Context context, int chatId, String href) {
|
||||
DcContext dcContext = DcHelper.getContext(context);
|
||||
int msgId = dcContext.initWebxdcIntegration(chatId);
|
||||
int msgId = 0;
|
||||
final int mapsVersion = 2;
|
||||
if (dcContext.getConfigInt("ui.maps_version") >= mapsVersion) {
|
||||
msgId = dcContext.initWebxdcIntegration(chatId);
|
||||
}
|
||||
if (msgId == 0) {
|
||||
try {
|
||||
InputStream inputStream = context.getResources().getAssets().open("webxdc/maps.xdc");
|
||||
@@ -91,34 +107,36 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE
|
||||
Toast.makeText(context, "Cannot get maps.xdc, see log for details.", Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
dcContext.setConfigInt("ui.maps_version", mapsVersion);
|
||||
}
|
||||
openWebxdcActivity(context, msgId, true);
|
||||
openWebxdcActivity(context, msgId, true, href);
|
||||
}
|
||||
|
||||
public static void openWebxdcActivity(Context context, DcMsg instance) {
|
||||
openWebxdcActivity(context, instance.getId(), false);
|
||||
openWebxdcActivity(context, instance, "");
|
||||
}
|
||||
|
||||
public static void openWebxdcActivity(Context context, int msgId, boolean hideActionBar) {
|
||||
public static void openWebxdcActivity(Context context, DcMsg instance, String href) {
|
||||
openWebxdcActivity(context, instance.getId(), false, href);
|
||||
}
|
||||
|
||||
public static void openWebxdcActivity(Context context, int msgId, boolean hideActionBar, String href) {
|
||||
if (!Util.isClickedRecently()) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
if (Prefs.isDeveloperModeEnabled(context)) {
|
||||
WebView.setWebContentsDebuggingEnabled(true);
|
||||
}
|
||||
context.startActivity(getWebxdcIntent(context, msgId, hideActionBar));
|
||||
} else {
|
||||
Toast.makeText(context, "At least Android 5.0 (Lollipop) required for Webxdc.", Toast.LENGTH_LONG).show();
|
||||
if (Prefs.isDeveloperModeEnabled(context)) {
|
||||
WebView.setWebContentsDebuggingEnabled(true);
|
||||
}
|
||||
context.startActivity(getWebxdcIntent(context, msgId, hideActionBar, href));
|
||||
}
|
||||
}
|
||||
|
||||
private static Intent getWebxdcIntent(Context context, int msgId, boolean hideActionBar) {
|
||||
private static Intent getWebxdcIntent(Context context, int msgId, boolean hideActionBar, String href) {
|
||||
DcContext dcContext = DcHelper.getContext(context);
|
||||
Intent intent = new Intent(context, WebxdcActivity.class);
|
||||
intent.setAction(Intent.ACTION_VIEW);
|
||||
intent.putExtra(EXTRA_ACCOUNT_ID, dcContext.getAccountId());
|
||||
intent.putExtra(EXTRA_APP_MSG_ID, msgId);
|
||||
intent.putExtra(EXTRA_HIDE_ACTION_BAR, hideActionBar);
|
||||
intent.putExtra(EXTRA_HREF, href);
|
||||
return intent;
|
||||
}
|
||||
|
||||
@@ -129,7 +147,7 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE
|
||||
.putExtra(ConversationActivity.CHAT_ID_EXTRA, dcContext.getMsg(msgId).getChatId())
|
||||
.setAction(Intent.ACTION_VIEW);
|
||||
|
||||
final Intent webxdcIntent = getWebxdcIntent(context, msgId, false);
|
||||
final Intent webxdcIntent = getWebxdcIntent(context, msgId, false, "");
|
||||
|
||||
return TaskStackBuilder.create(context)
|
||||
.addNextIntentWithParentStack(chatIntent)
|
||||
@@ -197,6 +215,9 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE
|
||||
// this is needed here because if the app is opened while already in landscape mode, onConfigurationChanged() is not triggered
|
||||
setScreenMode(getResources().getConfiguration());
|
||||
}
|
||||
selfAddr = info.optString("self_addr");
|
||||
sendUpdateMaxSize = info.optInt("send_update_max_size");
|
||||
sendUpdateInterval = info.optInt("send_update_interval");
|
||||
|
||||
toggleFakeProxy(!internetAccess);
|
||||
|
||||
@@ -213,7 +234,20 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE
|
||||
webView.setNetworkAvailable(internetAccess); // this does not block network but sets `window.navigator.isOnline` in js land
|
||||
webView.addJavascriptInterface(new InternalJSApi(), "InternalJSApi");
|
||||
|
||||
webView.loadUrl(this.baseURL + "/index.html");
|
||||
String extraHref = b.getString(EXTRA_HREF, "");
|
||||
if (TextUtils.isEmpty(extraHref)) {
|
||||
extraHref = "index.html";
|
||||
}
|
||||
|
||||
String href = baseURL + "/" + extraHref;
|
||||
String encodedHref = "";
|
||||
try {
|
||||
encodedHref = URLEncoder.encode(href, Charsets.UTF_8.name());
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
webView.loadUrl(this.baseURL + "/webxdc_bootstrap324567869.html?i=1&href=" + encodedHref);
|
||||
|
||||
Util.runOnAnyBackgroundThread(() -> {
|
||||
final DcChat chat = dcContext.getChat(dcAppMsg.getChatId());
|
||||
@@ -223,8 +257,21 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
DcHelper.getNotificationCenter(this).updateVisibleWebxdc(dcContext.getAccountId(), dcAppMsg.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
DcHelper.getNotificationCenter(this).clearVisibleWebxdc();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
lastOpenTime = System.currentTimeMillis();
|
||||
DcHelper.getEventCenter(this.getApplicationContext()).removeObservers(this);
|
||||
leaveRealtimeChannel();
|
||||
super.onDestroy();
|
||||
@@ -247,7 +294,10 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE
|
||||
addToHomeScreen(this, dcAppMsg.getId());
|
||||
return true;
|
||||
case R.id.source_code:
|
||||
openUrlInBrowser(this, sourceCodeUrl);
|
||||
IntentUtils.showInBrowser(this, sourceCodeUrl);
|
||||
return true;
|
||||
case R.id.show_in_chat:
|
||||
showInChat();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -334,7 +384,7 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE
|
||||
res = new WebResourceResponse("text/plain", "UTF-8", targetStream);
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && !internetAccess) {
|
||||
if (!internetAccess) {
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("Content-Security-Policy",
|
||||
"default-src 'self'; "
|
||||
@@ -353,9 +403,7 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE
|
||||
}
|
||||
|
||||
private void callJavaScriptFunction(String func) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
webView.evaluateJavascript("window." + func + ";", null);
|
||||
}
|
||||
webView.evaluateJavascript("document.getElementById('frame').contentWindow." + func + ";", null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -394,6 +442,13 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE
|
||||
}
|
||||
}
|
||||
|
||||
private void showInChat() {
|
||||
Intent intent = new Intent(this, ConversationActivity.class);
|
||||
intent.putExtra(ConversationActivity.CHAT_ID_EXTRA, dcAppMsg.getChatId());
|
||||
intent.putExtra(ConversationActivity.STARTING_POSITION_EXTRA, DcMsg.getMessagePosition(dcAppMsg, dcContext));
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
public static void addToHomeScreen(Activity activity, int msgId) {
|
||||
Context context = activity.getApplicationContext();
|
||||
try {
|
||||
@@ -469,13 +524,23 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE
|
||||
return dcContext.isCommunity();
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
public int sendUpdateMaxSize() {
|
||||
return WebxdcActivity.this.sendUpdateMaxSize;
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
public int sendUpdateInterval() {
|
||||
return WebxdcActivity.this.sendUpdateInterval;
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
public String selfAddr() {
|
||||
if (dcContext.isCommunity() && !TextUtils.isEmpty(dcContext.getCommunityUser())) {
|
||||
int flags = Base64.NO_WRAP | Base64.NO_PADDING | Base64.URL_SAFE;
|
||||
return Base64.encodeToString(dcContext.getCommunityUser().getBytes(), flags);
|
||||
}
|
||||
return dcContext.getConfig("configured_addr");
|
||||
return WebxdcActivity.this.selfAddr;
|
||||
}
|
||||
|
||||
/** @noinspection unused*/
|
||||
@@ -493,9 +558,9 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE
|
||||
|
||||
/** @noinspection unused*/
|
||||
@JavascriptInterface
|
||||
public boolean sendStatusUpdate(String payload, String descr) {
|
||||
public boolean sendStatusUpdate(String payload) {
|
||||
Log.i(TAG, "sendStatusUpdate");
|
||||
if (!WebxdcActivity.this.dcContext.sendWebxdcStatusUpdate(WebxdcActivity.this.dcAppMsg.getId(), payload, descr)) {
|
||||
if (!WebxdcActivity.this.dcContext.sendWebxdcStatusUpdate(WebxdcActivity.this.dcAppMsg.getId(), payload)) {
|
||||
DcChat dcChat = WebxdcActivity.this.dcContext.getChat(WebxdcActivity.this.dcAppMsg.getChatId());
|
||||
Toast.makeText(WebxdcActivity.this,
|
||||
dcChat.isContactRequest() ?
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.view.MenuItem;
|
||||
import android.webkit.WebResourceRequest;
|
||||
import android.webkit.WebResourceResponse;
|
||||
import android.webkit.WebSettings;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
|
||||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.rpc.HttpResponse;
|
||||
import com.b44t.messenger.rpc.Rpc;
|
||||
import com.b44t.messenger.rpc.RpcException;
|
||||
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
import org.thoughtcrime.securesms.providers.PersistentBlobProvider;
|
||||
import org.thoughtcrime.securesms.util.IntentUtils;
|
||||
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||
import org.thoughtcrime.securesms.util.Prefs;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class WebxdcStoreActivity extends PassphraseRequiredActionBarActivity {
|
||||
private static final String TAG = WebxdcStoreActivity.class.getSimpleName();
|
||||
|
||||
private DcContext dcContext;
|
||||
private Rpc rpc;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle state, boolean ready) {
|
||||
setContentView(R.layout.web_view_activity);
|
||||
rpc = DcHelper.getRpc(this);
|
||||
dcContext = DcHelper.getContext(this);
|
||||
WebView webView = findViewById(R.id.webview);
|
||||
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
if (actionBar != null) {
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
actionBar.setTitle(R.string.webxdc_apps);
|
||||
}
|
||||
|
||||
webView.setWebViewClient(new WebViewClient() {
|
||||
@Override
|
||||
public boolean shouldOverrideUrlLoading(WebView view, String url) {
|
||||
String ext = MediaUtil.getFileExtensionFromUrl(Uri.parse(url).getPath());
|
||||
if ("xdc".equals(ext)) {
|
||||
Util.runOnAnyBackgroundThread(() -> {
|
||||
try {
|
||||
HttpResponse httpResponse = rpc.getHttpResponse(dcContext.getAccountId(), url);
|
||||
Uri uri = PersistentBlobProvider.getInstance().create(WebxdcStoreActivity.this, httpResponse.getBlob(), "application/octet-stream", "app.xdc");
|
||||
Intent intent = new Intent();
|
||||
intent.setData(uri);
|
||||
setResult(Activity.RESULT_OK, intent);
|
||||
finish();
|
||||
} catch (RpcException e) {
|
||||
e.printStackTrace();
|
||||
Util.runOnMain(() -> Toast.makeText(WebxdcStoreActivity.this, "Error: " + e.getMessage(), Toast.LENGTH_LONG).show());
|
||||
}
|
||||
});
|
||||
} else {
|
||||
IntentUtils.showInBrowser(WebxdcStoreActivity.this, url);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.N)
|
||||
@Override
|
||||
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
|
||||
return shouldOverrideUrlLoading(view, request.getUrl().toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
|
||||
return interceptRequest(request.getUrl().toString());
|
||||
}
|
||||
});
|
||||
|
||||
WebSettings webSettings = webView.getSettings();
|
||||
webSettings.setJavaScriptEnabled(true);
|
||||
webSettings.setAllowFileAccess(false);
|
||||
webSettings.setAllowContentAccess(false);
|
||||
webSettings.setGeolocationEnabled(false);
|
||||
webSettings.setAllowFileAccessFromFileURLs(false);
|
||||
webSettings.setAllowUniversalAccessFromFileURLs(false);
|
||||
webSettings.setDatabaseEnabled(true);
|
||||
webSettings.setDomStorageEnabled(true);
|
||||
webView.setNetworkAvailable(true); // this does not block network but sets `window.navigator.isOnline` in js land
|
||||
|
||||
webView.loadUrl(Prefs.getWebxdcStoreUrl(this));
|
||||
}
|
||||
|
||||
private WebResourceResponse interceptRequest(String url) {
|
||||
WebResourceResponse res = null;
|
||||
try {
|
||||
if (url == null) {
|
||||
throw new Exception("no url specified");
|
||||
}
|
||||
HttpResponse httpResponse = rpc.getHttpResponse(dcContext.getAccountId(), url);
|
||||
String mimeType = httpResponse.getMimetype();
|
||||
if (mimeType == null) {
|
||||
mimeType = "application/octet-stream";
|
||||
}
|
||||
|
||||
ByteArrayInputStream data = new ByteArrayInputStream(httpResponse.getBlob());
|
||||
res = new WebResourceResponse(mimeType, httpResponse.getEncoding(), data);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
ByteArrayInputStream data = new ByteArrayInputStream(("Could not load apps. Are you online?\n\n" + e.getMessage()).getBytes());
|
||||
res = new WebResourceResponse("text/plain", "UTF-8", data);
|
||||
}
|
||||
|
||||
HashMap<String, String> headers = new HashMap<>();
|
||||
headers.put("access-control-allow-origin", "*");
|
||||
res.setResponseHeaders(headers);
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
super.onOptionsItemSelected(item);
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -93,7 +93,7 @@ public class WelcomeActivity extends BaseActionBarActivity implements DcEventCen
|
||||
|
||||
boolean canGoBack = AccountManager.getInstance().canRollbackAccountCreation(this);
|
||||
supportActionBar.setDisplayHomeAsUpEnabled(canGoBack);
|
||||
getSupportActionBar().setTitle(canGoBack? R.string.add_account : R.string.welcome_desktop);
|
||||
getSupportActionBar().setTitle(canGoBack? R.string.add_account : R.string.app_name);
|
||||
}
|
||||
|
||||
private void registerForEvents() {
|
||||
@@ -166,7 +166,7 @@ public class WelcomeActivity extends BaseActionBarActivity implements DcEventCen
|
||||
.withPermanentDenialDialog(getString(R.string.perm_explain_access_to_storage_denied))
|
||||
.onAllGranted(() -> {
|
||||
File imexDir = DcHelper.getImexDir();
|
||||
if (Build.VERSION.SDK_INT >= 30) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
AttachmentManager.selectMediaType(this, "application/x-tar", null, PICK_BACKUP, StorageUtil.getDownloadUri());
|
||||
} else {
|
||||
final String backupFile = dcContext.imexHasBackup(imexDir.getAbsolutePath());
|
||||
|
||||
@@ -48,7 +48,7 @@ public class AudioRecorder {
|
||||
ParcelFileDescriptor fds[] = ParcelFileDescriptor.createPipe();
|
||||
|
||||
captureUri = blobProvider.create(context, new ParcelFileDescriptor.AutoCloseInputStream(fds[0]),
|
||||
MediaUtil.AUDIO_AAC, null, null);
|
||||
MediaUtil.AUDIO_AAC, "voice.aac", null);
|
||||
audioCodec = new AudioCodec(context);
|
||||
|
||||
audioCodec.start(new ParcelFileDescriptor.AutoCloseOutputStream(fds[1]));
|
||||
|
||||
@@ -87,11 +87,14 @@ public class AudioSlidePlayer {
|
||||
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
|
||||
if (playbackState == Player.STATE_READY) {
|
||||
Util.runOnMain(() -> {
|
||||
Log.d(TAG, "request duration " + durationCalculator.getDuration());
|
||||
getListener().onReceivedDuration(Long.valueOf(durationCalculator.getDuration()).intValue());
|
||||
durationCalculator.release();
|
||||
durationCalculator.removeListener(this);
|
||||
durationCalculator = null;
|
||||
synchronized (AudioSlidePlayer.this) {
|
||||
if (durationCalculator == null) return;
|
||||
Log.d(TAG, "request duration " + durationCalculator.getDuration());
|
||||
getListener().onReceivedDuration(Long.valueOf(durationCalculator.getDuration()).intValue());
|
||||
durationCalculator.release();
|
||||
durationCalculator.removeListener(this);
|
||||
durationCalculator = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ public class AttachmentTypeSelector extends PopupWindow {
|
||||
public static final int TAKE_PHOTO = 5;
|
||||
public static final int ADD_LOCATION = 6;
|
||||
public static final int RECORD_VIDEO = 7;
|
||||
public static final int ADD_WEBXDC = 8;
|
||||
|
||||
private static final int ANIMATION_DURATION = 300;
|
||||
|
||||
@@ -53,7 +54,7 @@ public class AttachmentTypeSelector extends PopupWindow {
|
||||
//private final @NonNull ImageView cameraButton;
|
||||
private final @NonNull ImageView videoButton;
|
||||
private final @NonNull ImageView locationButton;
|
||||
private final @NonNull ImageView closeButton;
|
||||
private final @NonNull ImageView webxdcButton;
|
||||
|
||||
private @Nullable View currentAnchor;
|
||||
private @Nullable AttachmentClickedListener listener;
|
||||
@@ -76,7 +77,7 @@ public class AttachmentTypeSelector extends PopupWindow {
|
||||
//this.cameraButton = ViewUtil.findById(layout, R.id.camera_button);
|
||||
this.videoButton = ViewUtil.findById(layout, R.id.record_video_button);
|
||||
this.locationButton = ViewUtil.findById(layout, R.id.location_button);
|
||||
this.closeButton = ViewUtil.findById(layout, R.id.close_button);
|
||||
this.webxdcButton = ViewUtil.findById(layout, R.id.webxdc_button);
|
||||
|
||||
this.imageButton.setOnClickListener(new PropagatingClickListener(ADD_GALLERY));
|
||||
this.videoChatButton.setOnClickListener(new PropagatingClickListener(INVITE_VIDEO_CHAT));
|
||||
@@ -85,7 +86,7 @@ public class AttachmentTypeSelector extends PopupWindow {
|
||||
//this.cameraButton.setOnClickListener(new PropagatingClickListener(TAKE_PHOTO));
|
||||
this.videoButton.setOnClickListener(new PropagatingClickListener(RECORD_VIDEO));
|
||||
this.locationButton.setOnClickListener(new PropagatingClickListener(ADD_LOCATION));
|
||||
this.closeButton.setOnClickListener(new CloseClickListener());
|
||||
this.webxdcButton.setOnClickListener(new PropagatingClickListener(ADD_WEBXDC));
|
||||
this.recentRail.setListener(new RecentPhotoSelectedListener());
|
||||
|
||||
if (!Prefs.isLocationStreamingEnabled(context)) {
|
||||
@@ -130,33 +131,23 @@ public class AttachmentTypeSelector extends PopupWindow {
|
||||
public void onGlobalLayout() {
|
||||
getContentView().getViewTreeObserver().removeGlobalOnLayoutListener(this);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
animateWindowInCircular(anchor, getContentView());
|
||||
} else {
|
||||
animateWindowInTranslate(getContentView());
|
||||
}
|
||||
animateWindowInCircular(anchor, getContentView());
|
||||
}
|
||||
});
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
//animateButtonIn(cameraButton, ANIMATION_DURATION / 2);
|
||||
animateButtonIn(videoButton, ANIMATION_DURATION / 2);
|
||||
animateButtonIn(imageButton, ANIMATION_DURATION / 3);
|
||||
animateButtonIn(contactButton, ANIMATION_DURATION / 3);
|
||||
animateButtonIn(locationButton, ANIMATION_DURATION / 4);
|
||||
animateButtonIn(documentButton, ANIMATION_DURATION / 4);
|
||||
animateButtonIn(videoChatButton, 0);
|
||||
animateButtonIn(closeButton, 0);
|
||||
}
|
||||
//animateButtonIn(cameraButton, ANIMATION_DURATION / 2);
|
||||
animateButtonIn(videoButton, ANIMATION_DURATION / 2);
|
||||
animateButtonIn(imageButton, ANIMATION_DURATION / 3);
|
||||
animateButtonIn(contactButton, ANIMATION_DURATION / 3);
|
||||
animateButtonIn(locationButton, ANIMATION_DURATION / 4);
|
||||
animateButtonIn(documentButton, ANIMATION_DURATION / 4);
|
||||
animateButtonIn(webxdcButton, 0);
|
||||
animateButtonIn(videoChatButton, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dismiss() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
animateWindowOutCircular(currentAnchor, getContentView());
|
||||
} else {
|
||||
animateWindowOutTranslate(getContentView());
|
||||
}
|
||||
animateWindowOutCircular(currentAnchor, getContentView());
|
||||
}
|
||||
|
||||
public void setListener(@Nullable AttachmentClickedListener listener) {
|
||||
@@ -186,7 +177,6 @@ public class AttachmentTypeSelector extends PopupWindow {
|
||||
button.startAnimation(animation);
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
private void animateWindowInCircular(@Nullable View anchor, @NonNull View contentView) {
|
||||
Pair<Integer, Integer> coordinates = getClickOrigin(anchor, contentView);
|
||||
Animator animator = ViewAnimationUtils.createCircularReveal(contentView,
|
||||
@@ -205,7 +195,6 @@ public class AttachmentTypeSelector extends PopupWindow {
|
||||
getContentView().startAnimation(animation);
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
private void animateWindowOutCircular(@Nullable View anchor, @NonNull View contentView) {
|
||||
Pair<Integer, Integer> coordinates = getClickOrigin(anchor, contentView);
|
||||
Animator animator = ViewAnimationUtils.createCircularReveal(getContentView(),
|
||||
@@ -301,13 +290,6 @@ public class AttachmentTypeSelector extends PopupWindow {
|
||||
|
||||
}
|
||||
|
||||
private class CloseClickListener implements View.OnClickListener {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
public interface AttachmentClickedListener {
|
||||
public void onClick(int type);
|
||||
public void onQuickAttachment(Uri uri);
|
||||
|
||||
@@ -71,12 +71,10 @@ public class AudioView extends FrameLayout implements AudioSlidePlayer.Listener
|
||||
this.pauseButton.setOnClickListener(new PauseClickedListener());
|
||||
this.seekBar.setOnSeekBarChangeListener(new SeekBarModifiedListener());
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
this.playButton.setImageDrawable(context.getDrawable(R.drawable.play_icon));
|
||||
this.pauseButton.setImageDrawable(context.getDrawable(R.drawable.pause_icon));
|
||||
this.playButton.setBackground(context.getDrawable(R.drawable.ic_circle_fill_white_48dp));
|
||||
this.pauseButton.setBackground(context.getDrawable(R.drawable.ic_circle_fill_white_48dp));
|
||||
}
|
||||
this.playButton.setImageDrawable(context.getDrawable(R.drawable.play_icon));
|
||||
this.pauseButton.setImageDrawable(context.getDrawable(R.drawable.pause_icon));
|
||||
this.playButton.setBackground(context.getDrawable(R.drawable.ic_circle_fill_white_48dp));
|
||||
this.pauseButton.setBackground(context.getDrawable(R.drawable.ic_circle_fill_white_48dp));
|
||||
|
||||
setTint(getContext().getResources().getColor(R.color.audio_icon));
|
||||
}
|
||||
@@ -192,13 +190,8 @@ public class AudioView extends FrameLayout implements AudioSlidePlayer.Listener
|
||||
}
|
||||
|
||||
public void setTint(int foregroundTint) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
this.playButton.setBackgroundTintList(ColorStateList.valueOf(foregroundTint));
|
||||
this.pauseButton.setBackgroundTintList(ColorStateList.valueOf(foregroundTint));
|
||||
} else {
|
||||
this.playButton.setColorFilter(foregroundTint, PorterDuff.Mode.SRC_IN);
|
||||
this.pauseButton.setColorFilter(foregroundTint, PorterDuff.Mode.SRC_IN);
|
||||
}
|
||||
this.playButton.setBackgroundTintList(ColorStateList.valueOf(foregroundTint));
|
||||
this.pauseButton.setBackgroundTintList(ColorStateList.valueOf(foregroundTint));
|
||||
|
||||
this.seekBar.getProgressDrawable().setColorFilter(foregroundTint, PorterDuff.Mode.SRC_IN);
|
||||
|
||||
@@ -220,25 +213,20 @@ public class AudioView extends FrameLayout implements AudioSlidePlayer.Listener
|
||||
private void togglePlayToPause() {
|
||||
controlToggle.displayQuick(pauseButton);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
AnimatedVectorDrawable playToPauseDrawable = (AnimatedVectorDrawable)getContext().getDrawable(R.drawable.play_to_pause_animation);
|
||||
pauseButton.setImageDrawable(playToPauseDrawable);
|
||||
playToPauseDrawable.start();
|
||||
}
|
||||
AnimatedVectorDrawable playToPauseDrawable = (AnimatedVectorDrawable) getContext().getDrawable(R.drawable.play_to_pause_animation);
|
||||
pauseButton.setImageDrawable(playToPauseDrawable);
|
||||
playToPauseDrawable.start();
|
||||
}
|
||||
|
||||
private void togglePauseToPlay() {
|
||||
controlToggle.displayQuick(playButton);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
AnimatedVectorDrawable pauseToPlayDrawable = (AnimatedVectorDrawable)getContext().getDrawable(R.drawable.pause_to_play_animation);
|
||||
playButton.setImageDrawable(pauseToPlayDrawable);
|
||||
pauseToPlayDrawable.start();
|
||||
}
|
||||
AnimatedVectorDrawable pauseToPlayDrawable = (AnimatedVectorDrawable) getContext().getDrawable(R.drawable.pause_to_play_animation);
|
||||
playButton.setImageDrawable(pauseToPlayDrawable);
|
||||
pauseToPlayDrawable.start();
|
||||
}
|
||||
|
||||
private class PlayClickedListener implements View.OnClickListener {
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
try {
|
||||
@@ -279,7 +267,6 @@ public class AudioView extends FrameLayout implements AudioSlidePlayer.Listener
|
||||
}
|
||||
|
||||
private class PauseClickedListener implements View.OnClickListener {
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Log.w(TAG, "pausebutton onClick");
|
||||
|
||||
@@ -122,7 +122,6 @@ public class ComposeText extends AppCompatEditText {
|
||||
editorInfo.imeOptions &= ~EditorInfo.IME_FLAG_NO_ENTER_ACTION;
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT < 21) return inputConnection;
|
||||
if (mediaListener == null) return inputConnection;
|
||||
if (inputConnection == null) return null;
|
||||
|
||||
|
||||
@@ -120,15 +120,10 @@ public class ConversationItemThumbnail extends FrameLayout {
|
||||
@SuppressWarnings("SuspiciousNameCombination")
|
||||
@Override
|
||||
protected void dispatchDraw(Canvas canvas) {
|
||||
if (cornerMask.isLegacy()) {
|
||||
cornerMask.mask(canvas);
|
||||
}
|
||||
|
||||
super.dispatchDraw(canvas);
|
||||
|
||||
if (!cornerMask.isLegacy()) {
|
||||
cornerMask.mask(canvas);
|
||||
}
|
||||
cornerMask.mask(canvas);
|
||||
|
||||
final float halfStrokeWidth = outlinePaint.getStrokeWidth() / 2;
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import android.graphics.Path;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffXfermode;
|
||||
import android.graphics.RectF;
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import android.view.View;
|
||||
|
||||
@@ -20,11 +20,7 @@ public class CornerMask {
|
||||
private final RectF bounds = new RectF();
|
||||
|
||||
public CornerMask(@NonNull View view) {
|
||||
if (isLegacy()) {
|
||||
view.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
|
||||
} else {
|
||||
view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
|
||||
}
|
||||
view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
|
||||
|
||||
clearPaint.setColor(Color.BLACK);
|
||||
clearPaint.setStyle(Paint.Style.FILL);
|
||||
@@ -44,19 +40,10 @@ public class CornerMask {
|
||||
// Note: There's a bug in the P beta where most PorterDuff modes aren't working. But CLEAR does.
|
||||
// So we find and inverse path and use Mode.CLEAR for versions that support Path.op().
|
||||
// See issue https://issuetracker.google.com/issues/111394085.
|
||||
if (!isLegacy()) {
|
||||
outline.reset();
|
||||
outline.addRect(bounds, Path.Direction.CW);
|
||||
outline.op(corners, Path.Op.DIFFERENCE);
|
||||
canvas.drawPath(outline, clearPaint);
|
||||
} else {
|
||||
corners.addRoundRect(bounds, radii, Path.Direction.CW);
|
||||
canvas.clipPath(corners);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isLegacy() {
|
||||
return Build.VERSION.SDK_INT < 19;
|
||||
outline.reset();
|
||||
outline.addRect(bounds, Path.Direction.CW);
|
||||
outline.op(corners, Path.Op.DIFFERENCE);
|
||||
canvas.drawPath(outline, clearPaint);
|
||||
}
|
||||
|
||||
public void setRadius(int radius) {
|
||||
|
||||
@@ -104,7 +104,7 @@ public class KeyboardAwareLinearLayout extends LinearLayoutCompat {
|
||||
}
|
||||
|
||||
private void updateKeyboardState() {
|
||||
if (viewInset == 0 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) viewInset = getViewInset();
|
||||
if (viewInset == 0) viewInset = getViewInset();
|
||||
|
||||
getWindowVisibleDisplayFrame(rect);
|
||||
|
||||
@@ -148,7 +148,6 @@ public class KeyboardAwareLinearLayout extends LinearLayoutCompat {
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
||||
private int getViewInset() {
|
||||
try {
|
||||
Field attachInfoField = View.class.getDeclaredField("mAttachInfo");
|
||||
@@ -219,11 +218,7 @@ public class KeyboardAwareLinearLayout extends LinearLayoutCompat {
|
||||
return Surface.ROTATION_0;
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
return ServiceUtil.getWindowManager(getContext()).getDefaultDisplay().getRotation();
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 30) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
getContext().getDisplay().getRealMetrics(displayMetrics);
|
||||
} else {
|
||||
ServiceUtil.getWindowManager(getContext()).getDefaultDisplay().getRealMetrics(displayMetrics);
|
||||
|
||||
@@ -3,10 +3,10 @@ package org.thoughtcrime.securesms.components;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
@@ -40,7 +40,6 @@ public class MediaView extends FrameLayout {
|
||||
initialize();
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
public MediaView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
initialize();
|
||||
@@ -56,6 +55,7 @@ public class MediaView extends FrameLayout {
|
||||
public void set(@NonNull GlideRequests glideRequests,
|
||||
@NonNull Window window,
|
||||
@NonNull Uri source,
|
||||
@Nullable String fileName,
|
||||
@NonNull String mediaType,
|
||||
long size,
|
||||
boolean autoplay)
|
||||
@@ -69,7 +69,7 @@ public class MediaView extends FrameLayout {
|
||||
imageView.setVisibility(View.GONE);
|
||||
videoView.get().setVisibility(View.VISIBLE);
|
||||
videoView.get().setWindow(window);
|
||||
videoView.get().setVideoSource(new VideoSlide(getContext(), source, size), autoplay);
|
||||
videoView.get().setVideoSource(new VideoSlide(getContext(), source, fileName, size), autoplay);
|
||||
} else {
|
||||
throw new IOException("Unsupported media type: " + mediaType);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ package org.thoughtcrime.securesms.components;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.text.Spannable;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
@@ -17,7 +16,6 @@ import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import com.annimon.stream.Stream;
|
||||
import com.b44t.messenger.DcContact;
|
||||
@@ -80,7 +78,6 @@ public class QuoteView extends FrameLayout implements RecipientForeverObserver {
|
||||
initialize(attrs);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
public QuoteView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
initialize(attrs);
|
||||
@@ -158,7 +155,7 @@ public class QuoteView extends FrameLayout implements RecipientForeverObserver {
|
||||
if (contact == null) {
|
||||
authorView.setText(getContext().getString(R.string.forwarded_message));
|
||||
} else {
|
||||
authorView.setText(getContext().getString(R.string.forwarded_by, quotedMsg.getSenderName(contact, false)));
|
||||
authorView.setText(getContext().getString(R.string.forwarded_by, quotedMsg.getSenderName(contact)));
|
||||
}
|
||||
authorView.setTextColor(getForwardedColor());
|
||||
quoteBarView.setBackgroundColor(getForwardedColor());
|
||||
@@ -169,7 +166,7 @@ public class QuoteView extends FrameLayout implements RecipientForeverObserver {
|
||||
quoteBarView.setBackgroundColor(getForwardedColor());
|
||||
} else {
|
||||
authorView.setVisibility(VISIBLE);
|
||||
authorView.setText(quotedMsg.getSenderName(contact, true));
|
||||
authorView.setText(quotedMsg.getSenderName(contact));
|
||||
if (hasSticker) {
|
||||
authorView.setTextColor(getResources().getColor(R.color.core_dark_05));
|
||||
quoteBarView.setBackgroundColor(getResources().getColor(R.color.core_dark_05));
|
||||
|
||||
@@ -29,7 +29,6 @@ public class RepeatableImageKey extends ImageButton {
|
||||
init();
|
||||
}
|
||||
|
||||
@TargetApi(VERSION_CODES.LOLLIPOP)
|
||||
public RepeatableImageKey(Context context, AttributeSet attrs, int defStyleAttr,
|
||||
int defStyleRes)
|
||||
{
|
||||
|
||||
@@ -130,15 +130,11 @@ public class SearchToolbar extends LinearLayout {
|
||||
|
||||
searchItem.expandActionView();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
Animator animator = ViewAnimationUtils.createCircularReveal(this, (int)x, (int)y, 0, getWidth());
|
||||
animator.setDuration(400);
|
||||
Animator animator = ViewAnimationUtils.createCircularReveal(this, (int) x, (int) y, 0, getWidth());
|
||||
animator.setDuration(400);
|
||||
|
||||
setVisibility(View.VISIBLE);
|
||||
animator.start();
|
||||
} else {
|
||||
setVisibility(View.VISIBLE);
|
||||
}
|
||||
setVisibility(View.VISIBLE);
|
||||
animator.start();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,19 +149,15 @@ public class SearchToolbar extends LinearLayout {
|
||||
|
||||
if (listener != null) listener.onSearchClosed();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
Animator animator = ViewAnimationUtils.createCircularReveal(this, (int)x, (int)y, getWidth(), 0);
|
||||
animator.setDuration(400);
|
||||
animator.addListener(new AnimationCompleteListener() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
setVisibility(View.INVISIBLE);
|
||||
}
|
||||
});
|
||||
animator.start();
|
||||
} else {
|
||||
setVisibility(View.INVISIBLE);
|
||||
}
|
||||
Animator animator = ViewAnimationUtils.createCircularReveal(this, (int) x, (int) y, getWidth(), 0);
|
||||
animator.setDuration(400);
|
||||
animator.addListener(new AnimationCompleteListener() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
setVisibility(View.INVISIBLE);
|
||||
}
|
||||
});
|
||||
animator.start();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ public class SwitchPreferenceCompat extends CheckBoxPreference {
|
||||
setLayoutRes();
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
public SwitchPreferenceCompat(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
setLayoutRes();
|
||||
|
||||
+16
-17
File diff suppressed because one or more lines are too long
@@ -29,7 +29,12 @@ public class AttachmentsContentProvider extends ContentProvider {
|
||||
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
|
||||
DcContext dcContext = DcHelper.getContext(getContext());
|
||||
|
||||
String path = uri.getPath();
|
||||
// `uri` originally comes from DcHelper.openForViewOrShare() and
|
||||
// looks like `content://chat.delta.attachments/ef39a39/text.txt`
|
||||
// where ef39a39 is the file in the blob directory
|
||||
// and text.txt is the original name of the file, as returned by `msg.getFilename()`.
|
||||
// `uri.getPathSegments()` returns ["ef39a39", "text.txt"] in this example.
|
||||
String path = uri.getPathSegments().get(0);
|
||||
if (!DcHelper.sharedFiles.containsKey(path)) {
|
||||
throw new FileNotFoundException("File was not shared before.");
|
||||
}
|
||||
|
||||
@@ -171,7 +171,15 @@ public class DcEventCenter {
|
||||
|
||||
switch (id) {
|
||||
case DcContext.DC_EVENT_INCOMING_MSG:
|
||||
DcHelper.getNotificationCenter(context).addNotification(accountId, event.getData1Int(), event.getData2Int());
|
||||
DcHelper.getNotificationCenter(context).notifyMessage(accountId, event.getData1Int(), event.getData2Int());
|
||||
break;
|
||||
|
||||
case DcContext.DC_EVENT_INCOMING_REACTION:
|
||||
DcHelper.getNotificationCenter(context).notifyReaction(accountId, event.getData1Int(), event.getData2Int(), event.getData2Str());
|
||||
break;
|
||||
|
||||
case DcContext.DC_EVENT_INCOMING_WEBXDC_NOTIFY:
|
||||
DcHelper.getNotificationCenter(context).notifyWebxdc(accountId, event.getData1Int(), event.getData2Int(), event.getData2Str());
|
||||
break;
|
||||
|
||||
case DcContext.DC_EVENT_MSGS_NOTICED:
|
||||
|
||||
@@ -263,9 +263,7 @@ public class DcHelper {
|
||||
}
|
||||
|
||||
public static File getImexDir() {
|
||||
// DIRECTORY_DOCUMENTS is only available since KitKat;
|
||||
// as we also support Ice Cream Sandwich and Jellybean (2017: 11% in total), this is no option.
|
||||
// Moreover, DIRECTORY_DOWNLOADS seems to be easier accessible by the user,
|
||||
// DIRECTORY_DOCUMENTS could be used but DIRECTORY_DOWNLOADS seems to be easier accessible by the user,
|
||||
// eg. "Download Managers" are nearly always installed.
|
||||
// CAVE: do not use DownloadManager to add the file as it is deleted on uninstall then ...
|
||||
return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
|
||||
@@ -286,6 +284,7 @@ public class DcHelper {
|
||||
|
||||
DcMsg msg = dcContext.getMsg(msg_id);
|
||||
String path = msg.getFile();
|
||||
String filename = msg.getFilename();
|
||||
String mimeType = msg.getFilemime();
|
||||
try {
|
||||
File file = new File(path);
|
||||
@@ -296,8 +295,11 @@ public class DcHelper {
|
||||
|
||||
Uri uri;
|
||||
if (path.startsWith(dcContext.getBlobdir())) {
|
||||
uri = Uri.parse("content://" + BuildConfig.APPLICATION_ID + ".attachments/" + Uri.encode(file.getName()));
|
||||
sharedFiles.put("/" + file.getName(), 1); // as different Android version handle uris in putExtra differently, we also check them on our own
|
||||
// Build a Uri that will later be passed to AttachmentsContentProvider.openFile().
|
||||
// The last part needs to be `filename`, i.e. the original, user-visible name of the file,
|
||||
// so that the external apps show the name of the file correctly.
|
||||
uri = Uri.parse("content://" + BuildConfig.APPLICATION_ID + ".attachments/" + Uri.encode(file.getName()) + "/" + Uri.encode(filename));
|
||||
sharedFiles.put(file.getName(), 1); // as different Android version handle uris in putExtra differently, we also check them on our own
|
||||
} else {
|
||||
if (Build.VERSION.SDK_INT >= 24) {
|
||||
uri = FileProvider.getUriForFile(activity, BuildConfig.APPLICATION_ID + ".fileprovider", file);
|
||||
@@ -307,7 +309,7 @@ public class DcHelper {
|
||||
}
|
||||
|
||||
if (cmd.equals(Intent.ACTION_VIEW)) {
|
||||
mimeType = checkMime(path, mimeType);
|
||||
mimeType = checkMime(filename, mimeType);
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setDataAndType(uri, mimeType);
|
||||
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
@@ -496,16 +498,6 @@ public class DcHelper {
|
||||
.show();
|
||||
}
|
||||
|
||||
public static void showEncryptionRequiredDialog(Context context, String addr) {
|
||||
new AlertDialog.Builder(context)
|
||||
.setMessage(context.getString(R.string.encryption_required_for_new_contact, addr))
|
||||
.setNeutralButton(R.string.learn_more, (d, w) -> openHelp(context, "#howtoe2ee"))
|
||||
.setNegativeButton(R.string.qrscan_title, (d, w) -> context.startActivity(new Intent(context, QrActivity.class)))
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.setCancelable(true)
|
||||
.show();
|
||||
}
|
||||
|
||||
public static void openWebxdc(Context context, DcMsg dcMsg) {
|
||||
JSONObject info = dcMsg.getWebxdcInfo();
|
||||
if (JsonUtils.optBoolean(info, "community")) {
|
||||
|
||||
@@ -125,6 +125,7 @@ public class DirectShareUtil {
|
||||
|
||||
Intent intent = new Intent(context, ShareActivity.class);
|
||||
intent.setAction(Intent.ACTION_SEND);
|
||||
intent.putExtra(ShareActivity.EXTRA_ACC_ID, dcContext.getAccountId());
|
||||
intent.putExtra(ShareActivity.EXTRA_CHAT_ID, chat.getId());
|
||||
|
||||
Recipient recipient = new Recipient(context, chat);
|
||||
|
||||
@@ -16,6 +16,7 @@ import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.components.AvatarView;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.ResourceContactPhoto;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.util.DateUtils;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
|
||||
import org.thoughtcrime.securesms.util.ThemeUtil;
|
||||
@@ -109,6 +110,19 @@ public class ContactSelectionListItem extends LinearLayout implements RecipientM
|
||||
this.nameView.setEnabled(true);
|
||||
this.nameView.setText(name==null? "#" : name);
|
||||
|
||||
if (contact != null) {
|
||||
if (contact.isBot()) {
|
||||
number = getContext().getString(R.string.bot);
|
||||
} else if (contact.wasSeenRecently()) {
|
||||
number = getContext().getString(R.string.online);
|
||||
} else {
|
||||
long timestamp = contact.getLastSeen();
|
||||
if (timestamp != 0) {
|
||||
number = getContext().getString(R.string.last_seen_at, DateUtils.getExtendedTimeSpanString(getContext(), timestamp));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(number!=null) {
|
||||
this.numberView.setText(number == null ? "" : number);
|
||||
this.labelView.setText(label==null? "" : label);
|
||||
|
||||
@@ -1,345 +0,0 @@
|
||||
/*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will Google be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, as long as the origin is not misrepresented.
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.crypto;
|
||||
|
||||
import android.os.Build;
|
||||
import android.os.Process;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.Provider;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.SecureRandomSpi;
|
||||
import java.security.Security;
|
||||
|
||||
/**
|
||||
* This class is taken directly from the Android blog post announcing this bug:
|
||||
* http://android-developers.blogspot.com/2013/08/some-securerandom-thoughts.html
|
||||
*
|
||||
* Since I still don't know exactly what the source of this bug was, I'm using
|
||||
* this class verbatim under the assumption that the Android team knows what
|
||||
* they're doing. Although, at this point, that is perhaps a foolish assumption.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Fixes for the output of the default PRNG having low entropy.
|
||||
*
|
||||
* The fixes need to be applied via {@link #apply()} before any use of Java
|
||||
* Cryptography Architecture primitives. A good place to invoke them is in the
|
||||
* application's {@code onCreate}.
|
||||
*/
|
||||
public final class PRNGFixes {
|
||||
|
||||
private static final int VERSION_CODE_JELLY_BEAN = 16;
|
||||
private static final int VERSION_CODE_JELLY_BEAN_MR2 = 18;
|
||||
private static final byte[] BUILD_FINGERPRINT_AND_DEVICE_SERIAL =
|
||||
getBuildFingerprintAndDeviceSerial();
|
||||
|
||||
/** Hidden constructor to prevent instantiation. */
|
||||
private PRNGFixes() {}
|
||||
|
||||
/**
|
||||
* Applies all fixes.
|
||||
*
|
||||
* @throws SecurityException if a fix is needed but could not be applied.
|
||||
*/
|
||||
public static void apply() {
|
||||
applyOpenSSLFix();
|
||||
installLinuxPRNGSecureRandom();
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the fix for OpenSSL PRNG having low entropy. Does nothing if the
|
||||
* fix is not needed.
|
||||
*
|
||||
* @throws SecurityException if the fix is needed but could not be applied.
|
||||
*/
|
||||
private static void applyOpenSSLFix() throws SecurityException {
|
||||
if ((Build.VERSION.SDK_INT < VERSION_CODE_JELLY_BEAN)
|
||||
|| (Build.VERSION.SDK_INT > VERSION_CODE_JELLY_BEAN_MR2)) {
|
||||
// No need to apply the fix
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Mix in the device- and invocation-specific seed.
|
||||
Class.forName("org.apache.harmony.xnet.provider.jsse.NativeCrypto")
|
||||
.getMethod("RAND_seed", byte[].class)
|
||||
.invoke(null, generateSeed());
|
||||
|
||||
// Mix output of Linux PRNG into OpenSSL's PRNG
|
||||
int bytesRead = (Integer) Class.forName(
|
||||
"org.apache.harmony.xnet.provider.jsse.NativeCrypto")
|
||||
.getMethod("RAND_load_file", String.class, long.class)
|
||||
.invoke(null, "/dev/urandom", 1024);
|
||||
if (bytesRead != 1024) {
|
||||
throw new IOException(
|
||||
"Unexpected number of bytes read from Linux PRNG: "
|
||||
+ bytesRead);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new SecurityException("Failed to seed OpenSSL PRNG", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs a Linux PRNG-backed {@code SecureRandom} implementation as the
|
||||
* default. Does nothing if the implementation is already the default or if
|
||||
* there is not need to install the implementation.
|
||||
*
|
||||
* @throws SecurityException if the fix is needed but could not be applied.
|
||||
*/
|
||||
private static void installLinuxPRNGSecureRandom()
|
||||
throws SecurityException {
|
||||
if (Build.VERSION.SDK_INT > VERSION_CODE_JELLY_BEAN_MR2) {
|
||||
// No need to apply the fix
|
||||
return;
|
||||
}
|
||||
|
||||
// Install a Linux PRNG-based SecureRandom implementation as the
|
||||
// default, if not yet installed.
|
||||
Provider[] secureRandomProviders =
|
||||
Security.getProviders("SecureRandom.SHA1PRNG");
|
||||
if ((secureRandomProviders == null)
|
||||
|| (secureRandomProviders.length < 1)
|
||||
|| (!LinuxPRNGSecureRandomProvider.class.equals(
|
||||
secureRandomProviders[0].getClass()))) {
|
||||
Security.insertProviderAt(new LinuxPRNGSecureRandomProvider(), 1);
|
||||
}
|
||||
|
||||
// Assert that new SecureRandom() and
|
||||
// SecureRandom.getInstance("SHA1PRNG") return a SecureRandom backed
|
||||
// by the Linux PRNG-based SecureRandom implementation.
|
||||
SecureRandom rng1 = new SecureRandom();
|
||||
if (!LinuxPRNGSecureRandomProvider.class.equals(
|
||||
rng1.getProvider().getClass())) {
|
||||
throw new SecurityException(
|
||||
"new SecureRandom() backed by wrong Provider: "
|
||||
+ rng1.getProvider().getClass());
|
||||
}
|
||||
|
||||
SecureRandom rng2;
|
||||
try {
|
||||
rng2 = SecureRandom.getInstance("SHA1PRNG");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new SecurityException("SHA1PRNG not available", e);
|
||||
}
|
||||
if (!LinuxPRNGSecureRandomProvider.class.equals(
|
||||
rng2.getProvider().getClass())) {
|
||||
throw new SecurityException(
|
||||
"SecureRandom.getInstance(\"SHA1PRNG\") backed by wrong"
|
||||
+ " Provider: " + rng2.getProvider().getClass());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code Provider} of {@code SecureRandom} engines which pass through
|
||||
* all requests to the Linux PRNG.
|
||||
*/
|
||||
private static class LinuxPRNGSecureRandomProvider extends Provider {
|
||||
|
||||
public LinuxPRNGSecureRandomProvider() {
|
||||
super("LinuxPRNG",
|
||||
1.0,
|
||||
"A Linux-specific random number provider that uses"
|
||||
+ " /dev/urandom");
|
||||
// Although /dev/urandom is not a SHA-1 PRNG, some apps
|
||||
// explicitly request a SHA1PRNG SecureRandom and we thus need to
|
||||
// prevent them from getting the default implementation whose output
|
||||
// may have low entropy.
|
||||
put("SecureRandom.SHA1PRNG", LinuxPRNGSecureRandom.class.getName());
|
||||
put("SecureRandom.SHA1PRNG ImplementedIn", "Software");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link SecureRandomSpi} which passes all requests to the Linux PRNG
|
||||
* ({@code /dev/urandom}).
|
||||
*/
|
||||
public static class LinuxPRNGSecureRandom extends SecureRandomSpi {
|
||||
|
||||
/*
|
||||
* IMPLEMENTATION NOTE: Requests to generate bytes and to mix in a seed
|
||||
* are passed through to the Linux PRNG (/dev/urandom). Instances of
|
||||
* this class seed themselves by mixing in the current time, PID, UID,
|
||||
* build fingerprint, and hardware serial number (where available) into
|
||||
* Linux PRNG.
|
||||
*
|
||||
* Concurrency: Read requests to the underlying Linux PRNG are
|
||||
* serialized (on sLock) to ensure that multiple threads do not get
|
||||
* duplicated PRNG output.
|
||||
*/
|
||||
|
||||
private static final File URANDOM_FILE = new File("/dev/urandom");
|
||||
|
||||
private static final Object sLock = new Object();
|
||||
|
||||
/**
|
||||
* Input stream for reading from Linux PRNG or {@code null} if not yet
|
||||
* opened.
|
||||
*
|
||||
* @GuardedBy("sLock")
|
||||
*/
|
||||
private static DataInputStream sUrandomIn;
|
||||
|
||||
/**
|
||||
* Output stream for writing to Linux PRNG or {@code null} if not yet
|
||||
* opened.
|
||||
*
|
||||
* @GuardedBy("sLock")
|
||||
*/
|
||||
private static OutputStream sUrandomOut;
|
||||
|
||||
/**
|
||||
* Whether this engine instance has been seeded. This is needed because
|
||||
* each instance needs to seed itself if the client does not explicitly
|
||||
* seed it.
|
||||
*/
|
||||
private boolean mSeeded;
|
||||
|
||||
@Override
|
||||
protected void engineSetSeed(byte[] bytes) {
|
||||
try {
|
||||
OutputStream out;
|
||||
synchronized (sLock) {
|
||||
out = getUrandomOutputStream();
|
||||
}
|
||||
out.write(bytes);
|
||||
out.flush();
|
||||
} catch (IOException e) {
|
||||
// On a small fraction of devices /dev/urandom is not writable.
|
||||
// Log and ignore.
|
||||
Log.w(PRNGFixes.class.getSimpleName(),
|
||||
"Failed to mix seed into " + URANDOM_FILE);
|
||||
} finally {
|
||||
mSeeded = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineNextBytes(byte[] bytes) {
|
||||
if (!mSeeded) {
|
||||
// Mix in the device- and invocation-specific seed.
|
||||
engineSetSeed(generateSeed());
|
||||
}
|
||||
|
||||
try {
|
||||
DataInputStream in;
|
||||
synchronized (sLock) {
|
||||
in = getUrandomInputStream();
|
||||
}
|
||||
synchronized (in) {
|
||||
in.readFully(bytes);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new SecurityException(
|
||||
"Failed to read from " + URANDOM_FILE, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] engineGenerateSeed(int size) {
|
||||
byte[] seed = new byte[size];
|
||||
engineNextBytes(seed);
|
||||
return seed;
|
||||
}
|
||||
|
||||
private DataInputStream getUrandomInputStream() {
|
||||
synchronized (sLock) {
|
||||
if (sUrandomIn == null) {
|
||||
// NOTE: Consider inserting a BufferedInputStream between
|
||||
// DataInputStream and FileInputStream if you need higher
|
||||
// PRNG output performance and can live with future PRNG
|
||||
// output being pulled into this process prematurely.
|
||||
try {
|
||||
sUrandomIn = new DataInputStream(
|
||||
new FileInputStream(URANDOM_FILE));
|
||||
} catch (IOException e) {
|
||||
throw new SecurityException("Failed to open "
|
||||
+ URANDOM_FILE + " for reading", e);
|
||||
}
|
||||
}
|
||||
return sUrandomIn;
|
||||
}
|
||||
}
|
||||
|
||||
private OutputStream getUrandomOutputStream() throws IOException {
|
||||
synchronized (sLock) {
|
||||
if (sUrandomOut == null) {
|
||||
sUrandomOut = new FileOutputStream(URANDOM_FILE);
|
||||
}
|
||||
return sUrandomOut;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a device- and invocation-specific seed to be mixed into the
|
||||
* Linux PRNG.
|
||||
*/
|
||||
private static byte[] generateSeed() {
|
||||
try {
|
||||
ByteArrayOutputStream seedBuffer = new ByteArrayOutputStream();
|
||||
DataOutputStream seedBufferOut =
|
||||
new DataOutputStream(seedBuffer);
|
||||
seedBufferOut.writeLong(System.currentTimeMillis());
|
||||
seedBufferOut.writeLong(System.nanoTime());
|
||||
seedBufferOut.writeInt(Process.myPid());
|
||||
seedBufferOut.writeInt(Process.myUid());
|
||||
seedBufferOut.write(BUILD_FINGERPRINT_AND_DEVICE_SERIAL);
|
||||
seedBufferOut.close();
|
||||
return seedBuffer.toByteArray();
|
||||
} catch (IOException e) {
|
||||
throw new SecurityException("Failed to generate seed", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the hardware serial number of this device.
|
||||
*
|
||||
* @return serial number or {@code null} if not available.
|
||||
*/
|
||||
private static String getDeviceSerialNumber() {
|
||||
// We're using the Reflection API because Build.SERIAL is only available
|
||||
// since API Level 9 (Gingerbread, Android 2.3).
|
||||
try {
|
||||
return (String) Build.class.getField("SERIAL").get(null);
|
||||
} catch (Exception ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] getBuildFingerprintAndDeviceSerial() {
|
||||
StringBuilder result = new StringBuilder();
|
||||
String fingerprint = Build.FINGERPRINT;
|
||||
if (fingerprint != null) {
|
||||
result.append(fingerprint);
|
||||
}
|
||||
String serial = getDeviceSerialNumber();
|
||||
if (serial != null) {
|
||||
result.append(serial);
|
||||
}
|
||||
try {
|
||||
return result.toString().getBytes("UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException("UTF-8 encoding not supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,6 +50,7 @@ import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.MediaPreviewActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.ShareLocationDialog;
|
||||
import org.thoughtcrime.securesms.WebxdcStoreActivity;
|
||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||
import org.thoughtcrime.securesms.attachments.UriAttachment;
|
||||
import org.thoughtcrime.securesms.audio.AudioSlidePlayer;
|
||||
@@ -124,11 +125,6 @@ public class AttachmentManager {
|
||||
removableMediaView.setRemoveClickListener(new RemoveButtonListener());
|
||||
removableMediaView.setEditClickListener(new EditButtonListener());
|
||||
thumbnail.setOnClickListener(new ThumbnailClickListener());
|
||||
int incomingBubbleColor = ThemeUtil.getThemedColor(context, R.attr.conversation_item_incoming_bubble_color);
|
||||
audioView.getBackground().setColorFilter(incomingBubbleColor, PorterDuff.Mode.MULTIPLY);
|
||||
documentView.getBackground().setColorFilter(incomingBubbleColor, PorterDuff.Mode.MULTIPLY);
|
||||
webxdcView.getBackground().setColorFilter(incomingBubbleColor, PorterDuff.Mode.MULTIPLY);
|
||||
vcardView.getBackground().setColorFilter(incomingBubbleColor, PorterDuff.Mode.MULTIPLY);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -260,11 +256,11 @@ public class AttachmentManager {
|
||||
return new DocumentSlide(context, msg);
|
||||
}
|
||||
else if (PartAuthority.isLocalUri(uri)) {
|
||||
return getManuallyCalculatedSlideInfo(uri, width, height);
|
||||
return getManuallyCalculatedSlideInfo(uri, width, height, msg);
|
||||
} else {
|
||||
Slide result = getContentResolverSlideInfo(uri, width, height, chatId);
|
||||
|
||||
if (result == null) return getManuallyCalculatedSlideInfo(uri, width, height);
|
||||
if (result == null) return getManuallyCalculatedSlideInfo(uri, width, height, msg);
|
||||
else return result;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
@@ -365,16 +361,21 @@ public class AttachmentManager {
|
||||
return null;
|
||||
}
|
||||
|
||||
private @NonNull Slide getManuallyCalculatedSlideInfo(Uri uri, int width, int height) throws IOException {
|
||||
private @NonNull Slide getManuallyCalculatedSlideInfo(Uri uri, int width, int height, @Nullable DcMsg msg) throws IOException {
|
||||
long start = System.currentTimeMillis();
|
||||
Long mediaSize = null;
|
||||
String fileName = null;
|
||||
String mimeType = null;
|
||||
|
||||
if (msg != null) {
|
||||
fileName = msg.getFilename();
|
||||
mimeType = msg.getFilemime();
|
||||
}
|
||||
|
||||
if (PartAuthority.isLocalUri(uri)) {
|
||||
mediaSize = PartAuthority.getAttachmentSize(context, uri);
|
||||
fileName = PartAuthority.getAttachmentFileName(context, uri);
|
||||
mimeType = PartAuthority.getAttachmentContentType(context, uri);
|
||||
if (fileName == null) fileName = PartAuthority.getAttachmentFileName(context, uri);
|
||||
if (mimeType == null) mimeType = PartAuthority.getAttachmentContentType(context, uri);
|
||||
}
|
||||
|
||||
if (mediaSize == null) {
|
||||
@@ -451,6 +452,11 @@ public class AttachmentManager {
|
||||
selectMediaType(activity, "*/*", null, requestCode);
|
||||
}
|
||||
|
||||
public static void selectWebxdc(Activity activity, int requestCode) {
|
||||
Intent intent = new Intent(activity, WebxdcStoreActivity.class);
|
||||
activity.startActivityForResult(intent, requestCode);
|
||||
}
|
||||
|
||||
public static void selectGallery(Activity activity, int requestCode) {
|
||||
// to enable camera roll,
|
||||
// we're asking for "gallery permissions" also on newer systems that do not strictly require that.
|
||||
@@ -584,7 +590,7 @@ public class AttachmentManager {
|
||||
final Intent intent = new Intent();
|
||||
intent.setType(type);
|
||||
|
||||
if (extraMimeType != null && Build.VERSION.SDK_INT >= 19) {
|
||||
if (extraMimeType != null) {
|
||||
intent.putExtra(Intent.EXTRA_MIME_TYPES, extraMimeType);
|
||||
}
|
||||
|
||||
@@ -596,14 +602,12 @@ public class AttachmentManager {
|
||||
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
|
||||
try {
|
||||
activity.startActivityForResult(intent, requestCode);
|
||||
return;
|
||||
} catch (ActivityNotFoundException anfe) {
|
||||
Log.w(TAG, "couldn't complete ACTION_OPEN_DOCUMENT, no activity found. falling back.");
|
||||
}
|
||||
intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
|
||||
try {
|
||||
activity.startActivityForResult(intent, requestCode);
|
||||
return;
|
||||
} catch (ActivityNotFoundException anfe) {
|
||||
Log.w(TAG, "couldn't complete ACTION_OPEN_DOCUMENT, no activity found. falling back.");
|
||||
}
|
||||
|
||||
intent.setAction(Intent.ACTION_GET_CONTENT);
|
||||
@@ -676,10 +680,10 @@ public class AttachmentManager {
|
||||
}
|
||||
|
||||
switch (this) {
|
||||
case IMAGE: return new ImageSlide(context, uri, dataSize, width, height);
|
||||
case GIF: return new GifSlide(context, uri, dataSize, width, height);
|
||||
case IMAGE: return new ImageSlide(context, uri, fileName, dataSize, width, height);
|
||||
case GIF: return new GifSlide(context, uri, fileName, dataSize, width, height);
|
||||
case AUDIO: return new AudioSlide(context, uri, dataSize, false, fileName);
|
||||
case VIDEO: return new VideoSlide(context, uri, dataSize);
|
||||
case VIDEO: return new VideoSlide(context, uri, fileName, dataSize);
|
||||
case DOCUMENT:
|
||||
// We have to special-case Webxdc slides: The user can interact with them as soon as a draft
|
||||
// is set. Therefore we need to create a DcMsg already now.
|
||||
|
||||
@@ -14,8 +14,8 @@ public class GifSlide extends ImageSlide {
|
||||
super(context, dcMsg);
|
||||
}
|
||||
|
||||
public GifSlide(Context context, Uri uri, long size, int width, int height) {
|
||||
super(context, constructAttachmentFromUri(context, uri, MediaUtil.IMAGE_GIF, size, width, height, uri, null, false));
|
||||
public GifSlide(Context context, Uri uri, String fileName, long size, int width, int height) {
|
||||
super(context, constructAttachmentFromUri(context, uri, MediaUtil.IMAGE_GIF, size, width, height, uri, fileName, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -39,8 +39,8 @@ public class ImageSlide extends Slide {
|
||||
super(context, attachment);
|
||||
}
|
||||
|
||||
public ImageSlide(Context context, Uri uri, long size, int width, int height) {
|
||||
super(context, constructAttachmentFromUri(context, uri, MediaUtil.IMAGE_JPEG, size, width, height, uri, null, false));
|
||||
public ImageSlide(Context context, Uri uri, String fileName, long size, int width, int height) {
|
||||
super(context, constructAttachmentFromUri(context, uri, MediaUtil.IMAGE_JPEG, size, width, height, uri, fileName, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -15,8 +15,6 @@ import com.bumptech.glide.Registry;
|
||||
import com.bumptech.glide.annotation.GlideModule;
|
||||
import com.bumptech.glide.load.model.UnitModelLoader;
|
||||
import com.bumptech.glide.module.AppGlideModule;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.github.penfeizhou.animation.glide.AnimationDecoderOption;
|
||||
|
||||
import com.caverock.androidsvg.SVG;
|
||||
|
||||
@@ -42,7 +40,6 @@ public class SignalGlideModule extends AppGlideModule {
|
||||
@Override
|
||||
public void applyOptions(Context context, GlideBuilder builder) {
|
||||
builder.setLogLevel(Log.ERROR);
|
||||
builder.setDefaultRequestOptions(new RequestOptions().set(AnimationDecoderOption.DISABLE_ANIMATION_APNG_DECODER, true));
|
||||
// builder.setDiskCache(new NoopDiskCacheFactory());
|
||||
}
|
||||
|
||||
|
||||
@@ -30,16 +30,16 @@ import java.io.File;
|
||||
|
||||
public class VideoSlide extends Slide {
|
||||
|
||||
private static Attachment constructVideoAttachment(Context context, Uri uri, long dataSize)
|
||||
private static Attachment constructVideoAttachment(Context context, Uri uri, String fileName, long dataSize)
|
||||
{
|
||||
Uri thumbnailUri = Uri.fromFile(new File(DcHelper.getBlobdirFile(DcHelper.getContext(context), "temp-preview.jpg")));
|
||||
MediaUtil.ThumbnailSize retWh = new MediaUtil.ThumbnailSize(0, 0);
|
||||
MediaUtil.createVideoThumbnailIfNeeded(context, uri, thumbnailUri, retWh);
|
||||
return constructAttachmentFromUri(context, uri, MediaUtil.VIDEO_UNSPECIFIED, dataSize, retWh.width, retWh.height, thumbnailUri, null, false);
|
||||
return constructAttachmentFromUri(context, uri, MediaUtil.VIDEO_UNSPECIFIED, dataSize, retWh.width, retWh.height, thumbnailUri, fileName, false);
|
||||
}
|
||||
|
||||
public VideoSlide(Context context, Uri uri, long dataSize) {
|
||||
super(context, constructVideoAttachment(context, uri, dataSize));
|
||||
public VideoSlide(Context context, Uri uri, String fileName, long dataSize) {
|
||||
super(context, constructVideoAttachment(context, uri, fileName, dataSize));
|
||||
}
|
||||
|
||||
public VideoSlide(Context context, DcMsg dcMsg) {
|
||||
|
||||
@@ -20,16 +20,19 @@ import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.WorkerThread;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.core.app.NotificationManagerCompat;
|
||||
import androidx.core.app.RemoteInput;
|
||||
import androidx.core.app.TaskStackBuilder;
|
||||
|
||||
import com.b44t.messenger.DcChat;
|
||||
import com.b44t.messenger.DcContact;
|
||||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.DcMsg;
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
|
||||
import org.json.JSONObject;
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.ConversationActivity;
|
||||
import org.thoughtcrime.securesms.ConversationListActivity;
|
||||
@@ -40,6 +43,8 @@ import org.thoughtcrime.securesms.preferences.widgets.NotificationPrivacyPrefere
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.BitmapUtil;
|
||||
import org.thoughtcrime.securesms.util.IntentUtils;
|
||||
import org.thoughtcrime.securesms.util.JsonUtils;
|
||||
import org.thoughtcrime.securesms.util.Pair;
|
||||
import org.thoughtcrime.securesms.util.Prefs;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
@@ -54,6 +59,7 @@ public class NotificationCenter {
|
||||
private static final String TAG = NotificationCenter.class.getSimpleName();
|
||||
@NonNull private final ApplicationContext context;
|
||||
private volatile ChatData visibleChat = null;
|
||||
private volatile Pair<Integer, Integer> visibleWebxdc = null;
|
||||
private volatile long lastAudibleNotification = 0;
|
||||
private static final long MIN_AUDIBLE_PERIOD_MILLIS = TimeUnit.SECONDS.toMillis(2);
|
||||
|
||||
@@ -331,17 +337,90 @@ public class NotificationCenter {
|
||||
// add notifications & co.
|
||||
// --------------------------------------------------------------------------------------------
|
||||
|
||||
public void addNotification(int accountId, int chatId, int msgId) {
|
||||
Util.runOnAnyBackgroundThread(() -> {
|
||||
public void notifyMessage(int accountId, int chatId, int msgId) {
|
||||
Util.runOnAnyBackgroundThread(() -> {
|
||||
DcContext dcContext = context.dcAccounts.getAccount(accountId);
|
||||
DcChat dcChat = dcContext.getChat(chatId);
|
||||
|
||||
DcMsg dcMsg = dcContext.getMsg(msgId);
|
||||
NotificationPrivacyPreference privacy = Prefs.getNotificationPrivacy(context);
|
||||
|
||||
String shortLine = privacy.isDisplayMessage()? dcMsg.getSummarytext(2000) : context.getString(R.string.notify_new_message);
|
||||
if (dcChat.isMultiUser() && privacy.isDisplayContact()) {
|
||||
shortLine = dcMsg.getSenderName(dcContext.getContact(dcMsg.getFromId())) + ": " + shortLine;
|
||||
}
|
||||
String tickerLine = shortLine;
|
||||
if (!dcChat.isMultiUser() && privacy.isDisplayContact()) {
|
||||
tickerLine = dcMsg.getSenderName(dcContext.getContact(dcMsg.getFromId())) + ": " + tickerLine;
|
||||
|
||||
if (dcMsg.getOverrideSenderName() != null) {
|
||||
// There is an "overridden" display name on the message, so, we need to prepend the display name to the message,
|
||||
// i.e. set the shortLine to be the same as the tickerLine.
|
||||
shortLine = tickerLine;
|
||||
}
|
||||
}
|
||||
|
||||
DcMsg quotedMsg = dcMsg.getQuotedMsg();
|
||||
boolean isMention = dcChat.isMultiUser() && quotedMsg != null && quotedMsg.isOutgoing();
|
||||
|
||||
maybeAddNotification(accountId, dcChat, msgId, shortLine, tickerLine, true, isMention);
|
||||
});
|
||||
}
|
||||
|
||||
public void notifyReaction(int accountId, int contactId, int msgId, String reaction) {
|
||||
Util.runOnAnyBackgroundThread(() -> {
|
||||
DcContext dcContext = context.dcAccounts.getAccount(accountId);
|
||||
DcMsg dcMsg = dcContext.getMsg(msgId);
|
||||
|
||||
NotificationPrivacyPreference privacy = Prefs.getNotificationPrivacy(context);
|
||||
if (!privacy.isDisplayContact() || !privacy.isDisplayMessage()) {
|
||||
return; // showing "New Message" is wrong and showing "New Reaction" is already content. just do nothing.
|
||||
}
|
||||
|
||||
DcContact sender = dcContext.getContact(contactId);
|
||||
String shortLine = context.getString(R.string.reaction_by_other, sender.getDisplayName(), reaction, dcMsg.getSummarytext(2000));
|
||||
DcChat dcChat = dcContext.getChat(dcMsg.getChatId());
|
||||
maybeAddNotification(accountId, dcChat, msgId, shortLine, shortLine, false, dcChat.isMultiUser());
|
||||
});
|
||||
}
|
||||
|
||||
public void notifyWebxdc(int accountId, int contactId, int msgId, String text) {
|
||||
Util.runOnAnyBackgroundThread(() -> {
|
||||
NotificationPrivacyPreference privacy = Prefs.getNotificationPrivacy(context);
|
||||
if (!privacy.isDisplayContact() || !privacy.isDisplayMessage()) {
|
||||
return; // showing "New Message" is wrong, just do nothing.
|
||||
}
|
||||
|
||||
DcContext dcContext = context.dcAccounts.getAccount(accountId);
|
||||
DcMsg dcMsg = dcContext.getMsg(msgId);
|
||||
DcMsg parentMsg;
|
||||
if(dcMsg.getType() == DcMsg.DC_MSG_WEBXDC) {
|
||||
parentMsg = dcMsg;
|
||||
} else { // info message, get parent xdc
|
||||
parentMsg = dcMsg.getParent() != null? dcMsg.getParent() : dcMsg;
|
||||
}
|
||||
|
||||
if (Util.equals(visibleWebxdc, new Pair<>(accountId, parentMsg.getId()))) {
|
||||
return; // do not notify if the app is already open
|
||||
}
|
||||
|
||||
JSONObject info = parentMsg.getWebxdcInfo();
|
||||
final String name = JsonUtils.optString(info, "name");
|
||||
String shortLine = name.isEmpty()? text : (name + ": " + text);
|
||||
DcChat dcChat = dcContext.getChat(dcMsg.getChatId());
|
||||
maybeAddNotification(accountId, dcChat, msgId, shortLine, shortLine, false, dcChat.isMultiUser());
|
||||
});
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private void maybeAddNotification(int accountId, DcChat dcChat, int msgId, String shortLine, String tickerLine, boolean playInChatSound, boolean isMention) {
|
||||
|
||||
DcContext dcContext = context.dcAccounts.getAccount(accountId);
|
||||
DcChat dcChat = dcContext.getChat(chatId);
|
||||
DcMsg dcMsg = dcContext.getMsg(msgId);
|
||||
DcMsg quotedMsg = dcMsg.getQuotedMsg();
|
||||
boolean isGroupMention = quotedMsg != null && dcChat.isMultiUser() && quotedMsg.isOutgoing();
|
||||
int chatId = dcChat.getId();
|
||||
ChatData chatData = new ChatData(accountId, chatId);
|
||||
isMention = isMention && dcContext.isMentionsEnabled();
|
||||
|
||||
if (dcContext.isMuted() || (!isGroupMention && dcChat.isMuted())) {
|
||||
if (dcContext.isMuted() || (!isMention && dcChat.isMuted())) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -351,21 +430,13 @@ public class NotificationCenter {
|
||||
}
|
||||
|
||||
if (Util.equals(visibleChat, chatData)) {
|
||||
if (Prefs.isInChatNotifications(context)) {
|
||||
if (playInChatSound && Prefs.isInChatNotifications(context)) {
|
||||
InChatSounds.getInstance(context).playIncomingSound();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// get notification text as a single line
|
||||
NotificationPrivacyPreference privacy = Prefs.getNotificationPrivacy(context);
|
||||
|
||||
String line = privacy.isDisplayMessage()? dcMsg.getSummarytext(2000) : context.getString(R.string.notify_new_message);
|
||||
if (dcChat.isMultiUser() && privacy.isDisplayContact()) {
|
||||
line = dcMsg.getSenderName(dcContext.getContact(dcMsg.getFromId()), false) + ": " + line;
|
||||
}
|
||||
|
||||
// play signal?
|
||||
long now = System.currentTimeMillis();
|
||||
boolean signal = (now - lastAudibleNotification) > MIN_AUDIBLE_PERIOD_MILLIS;
|
||||
if (signal) {
|
||||
@@ -383,7 +454,7 @@ public class NotificationCenter {
|
||||
.setPriority(Prefs.getNotificationPriority(context))
|
||||
.setCategory(NotificationCompat.CATEGORY_MESSAGE)
|
||||
.setOnlyAlertOnce(!signal)
|
||||
.setContentText(line)
|
||||
.setContentText(shortLine)
|
||||
.setDeleteIntent(getMarkAsReadIntent(chatData, msgId, false))
|
||||
.setContentIntent(getOpenChatIntent(chatData));
|
||||
|
||||
@@ -403,12 +474,6 @@ public class NotificationCenter {
|
||||
}
|
||||
}
|
||||
|
||||
// if privacy allows, for better accessibility,
|
||||
// prepend the sender in the ticker also for one-to-one chats (for group-chats, this is already done)
|
||||
String tickerLine = line;
|
||||
if (!dcChat.isMultiUser() && privacy.isDisplayContact()) {
|
||||
line = dcMsg.getSenderName(dcContext.getContact(dcMsg.getFromId()), false) + ": " + line;
|
||||
}
|
||||
builder.setTicker(tickerLine);
|
||||
|
||||
// set sound, vibrate, led for systems that do not have notification channels
|
||||
@@ -504,9 +569,9 @@ public class NotificationCenter {
|
||||
lines = new ArrayList<>();
|
||||
accountInbox.put(chatId, lines);
|
||||
}
|
||||
lines.add(line);
|
||||
lines.add(shortLine);
|
||||
|
||||
for (int l = lines.size() - 1; l >= 0; l--) {
|
||||
for (int l = 0; l < lines.size(); l++) {
|
||||
inboxStyle.addLine(lines.get(l));
|
||||
}
|
||||
}
|
||||
@@ -552,7 +617,6 @@ public class NotificationCenter {
|
||||
Log.e(TAG, "cannot add notification summary", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void removeNotifications(int accountId, int chatId) {
|
||||
@@ -610,6 +674,18 @@ public class NotificationCenter {
|
||||
visibleChat = null;
|
||||
}
|
||||
|
||||
public void updateVisibleWebxdc(int accountId, int msgId) {
|
||||
if (accountId != 0 && msgId != 0) {
|
||||
visibleWebxdc = new Pair<>(accountId, msgId);
|
||||
} else {
|
||||
visibleWebxdc = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void clearVisibleWebxdc() {
|
||||
visibleWebxdc = null;
|
||||
}
|
||||
|
||||
public void maybePlaySendSound(DcChat dcChat) {
|
||||
if (Prefs.isInChatNotifications(context) && !dcChat.isMuted()) {
|
||||
InChatSounds.getInstance(context).playSendSound();
|
||||
|
||||
@@ -69,7 +69,6 @@ public class RemoteReplyReceiver extends BroadcastReceiver {
|
||||
|
||||
DcMsg msg = new DcMsg(dcContext, DcMsg.DC_MSG_TEXT);
|
||||
msg.setText(responseText.toString());
|
||||
msg.setQuote(dcContext.getMsg(msgId));
|
||||
dcContext.sendMsg(chatId, msg);
|
||||
|
||||
DcHelper.getNotificationCenter(context).removeNotifications(accountId, chatId);
|
||||
|
||||
+36
-3
@@ -42,6 +42,7 @@ import org.thoughtcrime.securesms.connect.DcEventCenter;
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
import org.thoughtcrime.securesms.mms.AttachmentManager;
|
||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||
import org.thoughtcrime.securesms.util.Prefs;
|
||||
import org.thoughtcrime.securesms.util.ScreenLockUtil;
|
||||
import org.thoughtcrime.securesms.util.StorageUtil;
|
||||
import org.thoughtcrime.securesms.util.StreamUtil;
|
||||
@@ -134,11 +135,13 @@ public class AdvancedPreferenceFragment extends ListSummaryPreferenceFragment
|
||||
webrtcInstance.setOnPreferenceClickListener(new WebrtcInstanceListener());
|
||||
updateWebrtcSummary();
|
||||
|
||||
Preference webxdcStore = this.findPreference(Prefs.WEBXDC_STORE_URL_PREF);
|
||||
webxdcStore.setOnPreferenceClickListener(new WebxdcStoreUrlListener());
|
||||
updateWebxdcStoreSummary();
|
||||
|
||||
Preference developerModeEnabled = this.findPreference("pref_developer_mode_enabled");
|
||||
developerModeEnabled.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
WebView.setWebContentsDebuggingEnabled((Boolean) newValue);
|
||||
}
|
||||
WebView.setWebContentsDebuggingEnabled((Boolean) newValue);
|
||||
return true;
|
||||
});
|
||||
|
||||
@@ -282,6 +285,29 @@ public class AdvancedPreferenceFragment extends ListSummaryPreferenceFragment
|
||||
}
|
||||
}
|
||||
|
||||
private class WebxdcStoreUrlListener implements Preference.OnPreferenceClickListener {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
View gl = View.inflate(getActivity(), R.layout.single_line_input, null);
|
||||
EditText inputField = gl.findViewById(R.id.input_field);
|
||||
inputField.setHint(Prefs.DEFAULT_WEBXDC_STORE_URL);
|
||||
inputField.setText(Prefs.getWebxdcStoreUrl(getActivity()));
|
||||
inputField.setSelection(inputField.getText().length());
|
||||
inputField.setInputType(TYPE_TEXT_VARIATION_URI);
|
||||
new AlertDialog.Builder(getActivity())
|
||||
.setTitle(R.string.webxdc_store_url)
|
||||
.setMessage(R.string.webxdc_store_url_explain)
|
||||
.setView(gl)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setPositiveButton(android.R.string.ok, (dlg, btn) -> {
|
||||
Prefs.setWebxdcStoreUrl(getActivity(), inputField.getText().toString());
|
||||
updateWebxdcStoreSummary();
|
||||
})
|
||||
.show();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateWebrtcSummary() {
|
||||
Preference webrtcInstance = this.findPreference("pref_webrtc_instance");
|
||||
if (webrtcInstance != null) {
|
||||
@@ -290,6 +316,13 @@ public class AdvancedPreferenceFragment extends ListSummaryPreferenceFragment
|
||||
}
|
||||
}
|
||||
|
||||
private void updateWebxdcStoreSummary() {
|
||||
Preference preference = this.findPreference(Prefs.WEBXDC_STORE_URL_PREF);
|
||||
if (preference != null) {
|
||||
preference.setSummary(Prefs.getWebxdcStoreUrl(getActivity()));
|
||||
}
|
||||
}
|
||||
|
||||
private void openRegistrationActivity() {
|
||||
Intent intent = new Intent(getActivity(), RegistrationActivity.class);
|
||||
startActivity(intent);
|
||||
|
||||
+9
@@ -36,6 +36,7 @@ public class NotificationsPreferenceFragment extends ListSummaryPreferenceFragme
|
||||
|
||||
private CheckBoxPreference ignoreBattery;
|
||||
private CheckBoxPreference notificationsEnabled;
|
||||
private CheckBoxPreference mentionNotifEnabled;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle paramBundle) {
|
||||
@@ -99,6 +100,13 @@ public class NotificationsPreferenceFragment extends ListSummaryPreferenceFragme
|
||||
dcContext.setMuted(!enabled);
|
||||
return true;
|
||||
});
|
||||
|
||||
mentionNotifEnabled = this.findPreference("pref_enable_mention_notifications");
|
||||
mentionNotifEnabled.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
boolean enabled = (Boolean) newValue;
|
||||
dcContext.setMentionsEnabled(enabled);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -114,6 +122,7 @@ public class NotificationsPreferenceFragment extends ListSummaryPreferenceFragme
|
||||
// update ignoreBattery in onResume() to reflects changes done in the system settings
|
||||
ignoreBattery.setChecked(isIgnoringBatteryOptimizations());
|
||||
notificationsEnabled.setChecked(!dcContext.isMuted());
|
||||
mentionNotifEnabled.setChecked(dcContext.isMentionsEnabled());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -26,7 +26,6 @@ public class ProfilePreference extends Preference {
|
||||
private TextView profileNameView;
|
||||
private TextView profileAddressView;
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
public ProfilePreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
initialize();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user