mirror of
https://github.com/ArcaneChat/android.git
synced 2026-07-03 14:05:24 +02:00
Compare commits
112 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7589b5ac37 | |||
| 8a9ce2ddd1 | |||
| be449f5afc | |||
| ac832a617e | |||
| 4fd2832370 | |||
| 52b072a7f3 | |||
| 55862757d6 | |||
| cbdf495c5f | |||
| a9d0d2e179 | |||
| d0cbf169dd | |||
| 833bc14405 | |||
| fb3620d0e3 | |||
| 02466e09fe | |||
| e39134faad | |||
| fa90b167ef | |||
| f5f20399ac | |||
| 659152dfcf | |||
| f34e87a593 | |||
| a172441155 | |||
| 90ca85ae9c | |||
| 40c0612412 | |||
| 5de79e3b0b | |||
| 39369aadd7 | |||
| b1e709d5bc | |||
| f760573fe4 | |||
| 4263ece65b | |||
| 217c45c102 | |||
| 3b2145ec79 | |||
| 566d1a1c13 | |||
| 09dab94807 | |||
| 6e3ddb8d96 | |||
| 8d7bb437eb | |||
| 392b43e8f7 | |||
| 32201a60c4 | |||
| bb114c570f | |||
| 42c52c10c7 | |||
| ade21a2cb8 | |||
| aced181d92 | |||
| 92cd1fc31c | |||
| 743138a100 | |||
| bebda06160 | |||
| f581930a40 | |||
| 70d4844dc6 | |||
| d3dd50dcac | |||
| ab8fdbad78 | |||
| 174bd9e986 | |||
| ab6f7ec97f | |||
| 6288463ddb | |||
| d700353ed8 | |||
| e979873bb3 | |||
| 331c77d317 | |||
| f9792615b7 | |||
| a94dc9336e | |||
| 6f1e11e860 | |||
| e720b4cef8 | |||
| 10f4534ee8 | |||
| 28c02a767d | |||
| 98f2ae5430 | |||
| 00c61133d5 | |||
| e457ab431d | |||
| b854fb6689 | |||
| 7c3a80296a | |||
| 4328bdd698 | |||
| e5f45df59a | |||
| 9dd270172b | |||
| 310f1fb921 | |||
| 5f14f0792f | |||
| fb3b43426a | |||
| 62b66d93ee | |||
| 6b12ff335d | |||
| ea522be8f4 | |||
| 44441f1ff9 | |||
| 3fca807356 | |||
| 4dc377233a | |||
| aabc60d36f | |||
| a653ac6382 | |||
| df7cc90da9 | |||
| eeb56a4630 | |||
| 713a87993e | |||
| 8ff55f3cf3 | |||
| 0fd72d2415 | |||
| 3c7f12c7b8 | |||
| 56abaa7c20 | |||
| 9335eedd04 | |||
| c13536031e | |||
| 57581634c4 | |||
| 4fa2535118 | |||
| 0ac0276dea | |||
| ed72a60f24 | |||
| 656aca7d1f | |||
| 3594847d8e | |||
| c17ac1d090 | |||
| 93ba86a779 | |||
| 738f5b2cc8 | |||
| 71a473d3e3 | |||
| d64d094de3 | |||
| 41df4eb03d | |||
| dde82ccb2f | |||
| c89f9ce875 | |||
| 87ac24124a | |||
| 138dcd7bdf | |||
| 0d51e097d5 | |||
| abff1c0c55 | |||
| 08643d3389 | |||
| 36249777e0 | |||
| b878ed4df3 | |||
| 16a02a5e4f | |||
| c614c5f004 | |||
| c7a542aac7 | |||
| e76f445985 | |||
| 69e18a009b | |||
| 64ef656544 |
@@ -0,0 +1,50 @@
|
||||
name: Core Cache
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'jni/deltachat-core-rust'
|
||||
- 'jni/Android.mk'
|
||||
- 'jni/Application.mk'
|
||||
- 'jni/dc_wrapper.c'
|
||||
- 'scripts/ndk-make.sh'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- uses: android-actions/setup-android@v3
|
||||
- uses: nttld/setup-ndk@v1
|
||||
id: setup-ndk
|
||||
with:
|
||||
ndk-version: r27
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
workspaces: jni/deltachat-core-rust
|
||||
|
||||
- name: Get deltachat-core-rust submodule hash
|
||||
id: core-hash
|
||||
run: echo "hash=$(git rev-parse HEAD:jni/deltachat-core-rust)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache compiled core
|
||||
id: cache-core
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
jni/arm64-v8a
|
||||
libs/arm64-v8a
|
||||
key: core-arm64-v8a-${{ steps.core-hash.outputs.hash }}-${{ hashFiles('jni/Android.mk', 'jni/Application.mk', 'jni/dc_wrapper.c', 'scripts/ndk-make.sh') }}-ndk-r27
|
||||
|
||||
- name: Compile core
|
||||
if: steps.cache-core.outputs.cache-hit != 'true'
|
||||
env:
|
||||
ANDROID_NDK_ROOT: ${{ steps.setup-ndk.outputs.ndk-path }}
|
||||
run: |
|
||||
export PATH="${PATH}:${ANDROID_NDK_ROOT}/toolchains/llvm/prebuilt/linux-x86_64/bin/"
|
||||
scripts/install-toolchains.sh && scripts/ndk-make.sh arm64-v8a
|
||||
@@ -0,0 +1,35 @@
|
||||
name: Code Format
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
||||
|
||||
jobs:
|
||||
spotless:
|
||||
name: Check code format (Spotless)
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/setup-java@v5
|
||||
with:
|
||||
java-version: 17
|
||||
distribution: temurin
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
- name: Validate Gradle Wrapper
|
||||
uses: gradle/actions/wrapper-validation@v4
|
||||
- name: Check formatting
|
||||
run: ./gradlew spotlessCheck
|
||||
@@ -14,16 +14,15 @@ jobs:
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Validate Fastlane Metadata
|
||||
uses: ashutoshgngwr/validate-fastlane-supply-metadata@v2
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
working-directory: jni/deltachat-core-rust
|
||||
|
||||
- uses: actions/setup-java@v5
|
||||
with:
|
||||
java-version: 17
|
||||
distribution: 'temurin'
|
||||
- uses: android-actions/setup-android@v3
|
||||
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
@@ -32,15 +31,35 @@ jobs:
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
|
||||
- name: Validate Gradle Wrapper
|
||||
uses: gradle/actions/wrapper-validation@v4
|
||||
|
||||
- uses: android-actions/setup-android@v3
|
||||
- uses: nttld/setup-ndk@v1
|
||||
id: setup-ndk
|
||||
with:
|
||||
ndk-version: r27
|
||||
|
||||
- name: Validate Gradle Wrapper
|
||||
uses: gradle/actions/wrapper-validation@v4
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
workspaces: jni/deltachat-core-rust
|
||||
|
||||
- name: Get deltachat-core-rust submodule hash
|
||||
id: core-hash
|
||||
run: echo "hash=$(git rev-parse HEAD:jni/deltachat-core-rust)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Restore compiled core
|
||||
id: core-cache
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: |
|
||||
jni/arm64-v8a
|
||||
libs/arm64-v8a
|
||||
key: core-arm64-v8a-${{ steps.core-hash.outputs.hash }}-${{ hashFiles('jni/Android.mk', 'jni/Application.mk', 'jni/dc_wrapper.c', 'scripts/ndk-make.sh') }}-ndk-r27
|
||||
|
||||
- name: Compile core
|
||||
if: steps.core-cache.outputs.cache-hit != 'true'
|
||||
env:
|
||||
ANDROID_NDK_ROOT: ${{ steps.setup-ndk.outputs.ndk-path }}
|
||||
run: |
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ install Rust tooling (read sections below) and the [dcrpcgen tool](https://githu
|
||||
then generate the code running the script:
|
||||
|
||||
```
|
||||
./scripts/generate-rpc-bindings.sh
|
||||
./scripts/update-rpc-bindings.sh
|
||||
```
|
||||
|
||||
## Build Using Nix
|
||||
|
||||
+11
-2
@@ -1,16 +1,25 @@
|
||||
# Delta Chat Android Changelog
|
||||
|
||||
## Unreleased
|
||||
## v2.46.0
|
||||
2026-03
|
||||
|
||||
* Allow to set chat description
|
||||
* Unified date display in call bubbles
|
||||
* Explain at "Settings / Chats / Outgoing Media Quality" how to send original quality
|
||||
* Add a basic sticker picker
|
||||
* Leave groups and channels before deletion
|
||||
* Further minimize metadata in messages and while getting in contact.
|
||||
* Increase resilience of multi-relay usage: if on relay goes down, messages are still received in the others.
|
||||
* Allow to hide a relay from contacts instead of removing, allowing smoother relay changes
|
||||
* HTML emails: allow to review and copy links before opening them
|
||||
* Mark call message as seen when accepting/declining a call
|
||||
* Fix: keep original sent timestamp for resent messages
|
||||
* Fix: make clicking on broadcast member-added messages work always
|
||||
* Fix: remove notification when a message is deleted by sender
|
||||
* Update to core 2.44.0
|
||||
* Fix: avoid "reply privately" not quoting the selected message sometimes
|
||||
* Fix: properly hide the calls button
|
||||
* Some more bug fixes and updated translations
|
||||
* Update to core 2.46.0
|
||||
|
||||
## v2.43.0
|
||||
2026-02
|
||||
|
||||
+7
-10
@@ -73,18 +73,15 @@ esp. before/after screenshots.
|
||||
|
||||
### Coding Conventions
|
||||
|
||||
Source files are partly derived from different other open source projects
|
||||
and may follow different coding styles and conventions.
|
||||
|
||||
If you do a PR fixing a bug or adding a feature,
|
||||
please embrace the coding convention you see in the corresponding files,
|
||||
so that the result fits well together.
|
||||
|
||||
Do not refactor or rename things in the same PR
|
||||
to make the diff small and the PR easy to review.
|
||||
|
||||
Project language is Java.
|
||||
|
||||
Code formatting is enforced via [Spotless](https://github.com/diffplug/spotless) Gradle plugin.
|
||||
Auto-format all files by running `./gradlew spotlessApply` before opening a PR.
|
||||
CI will fail if files are not formatted correctly so make sure to run the formatter before pushing.
|
||||
|
||||
If you do a PR fixing a bug or adding a feature, do not refactor or rename things in the same PR
|
||||
to make the diff small and the PR easy to review.
|
||||
|
||||
By using [Delta Chat Core](https://github.com/deltachat/deltachat-core-rust)
|
||||
there is already a strong separation between "UI" and "Model".
|
||||
Further separations and abstraction layers are often not helpful
|
||||
|
||||
+63
-21
@@ -1,6 +1,7 @@
|
||||
plugins {
|
||||
id 'com.android.application' version '8.11.1'
|
||||
id 'com.google.gms.google-services' version '4.4.1'
|
||||
id 'com.diffplug.spotless' version '8.3.0'
|
||||
}
|
||||
|
||||
repositories {
|
||||
@@ -33,8 +34,8 @@ android {
|
||||
useLibrary 'org.apache.http.legacy'
|
||||
|
||||
defaultConfig {
|
||||
versionCode 30000737
|
||||
versionName "2.43.0"
|
||||
versionCode 30000738
|
||||
versionName "2.46.0"
|
||||
|
||||
applicationId "chat.delta.lite"
|
||||
multiDexEnabled true
|
||||
@@ -72,10 +73,20 @@ android {
|
||||
packagingOptions {
|
||||
jniLibs {
|
||||
doNotStrip '**/*.so'
|
||||
keepDebugSymbols += ['*/mips/*.so', '*/mips64/*.so']
|
||||
keepDebugSymbols += [
|
||||
'*/mips/*.so',
|
||||
'*/mips64/*.so'
|
||||
]
|
||||
}
|
||||
resources {
|
||||
excludes += ['LICENSE.txt', 'LICENSE', 'NOTICE', 'asm-license.txt', 'META-INF/LICENSE', 'META-INF/NOTICE']
|
||||
excludes += [
|
||||
'LICENSE.txt',
|
||||
'LICENSE',
|
||||
'NOTICE',
|
||||
'asm-license.txt',
|
||||
'META-INF/LICENSE',
|
||||
'META-INF/NOTICE'
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,14 +165,14 @@ android {
|
||||
}
|
||||
|
||||
if(!project.hasProperty("ABI_FILTER")) {
|
||||
splits {
|
||||
abi {
|
||||
enable true
|
||||
reset()
|
||||
include "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
|
||||
universalApk true
|
||||
splits {
|
||||
abi {
|
||||
enable true
|
||||
reset()
|
||||
include "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
|
||||
universalApk true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
project.ext.versionCodes = ['armeabi-v7a': 1, 'arm64-v8a': 2, 'x86': 3, 'x86_64': 4]
|
||||
@@ -169,16 +180,16 @@ android {
|
||||
android.applicationVariants.all { variant ->
|
||||
variant.outputs.all { output ->
|
||||
output.outputFileName = output.outputFileName
|
||||
.replace("android", "ArcaneChat")
|
||||
.replace("-release", "")
|
||||
.replace(".apk", "-${variant.versionName}.apk")
|
||||
.replace("android", "ArcaneChat")
|
||||
.replace("-release", "")
|
||||
.replace(".apk", "-${variant.versionName}.apk")
|
||||
if(project.hasProperty("ABI_FILTER")) {
|
||||
output.versionCodeOverride =
|
||||
variant.versionCode * 10 + project.ext.versionCodes.get(ABI_FILTER)
|
||||
output.versionCodeOverride =
|
||||
variant.versionCode * 10 + project.ext.versionCodes.get(ABI_FILTER)
|
||||
} else {
|
||||
output.versionCodeOverride =
|
||||
variant.versionCode * 10 + project.ext.versionCodes.get(output.getFilter(com.android.build.OutputFile.ABI), 4)
|
||||
}
|
||||
output.versionCodeOverride =
|
||||
variant.versionCode * 10 + project.ext.versionCodes.get(output.getFilter(com.android.build.OutputFile.ABI), 4)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,7 +210,31 @@ android {
|
||||
renderScript true
|
||||
aidl true
|
||||
}
|
||||
}
|
||||
|
||||
spotless {
|
||||
java {
|
||||
target 'src/*/java/**/*.java'
|
||||
targetExclude 'src/main/java/chat/delta/**' // ignore auto-generated code
|
||||
googleJavaFormat() // Google style = 2-space indent, matches Android Studio defaults
|
||||
removeUnusedImports()
|
||||
trimTrailingWhitespace()
|
||||
endWithNewline()
|
||||
}
|
||||
format 'xml', {
|
||||
target 'src/*/res/**/*.xml', 'src/*/AndroidManifest.xml'
|
||||
targetExclude 'src/*/res/values*/strings.xml' // line-break changes invalidate translations
|
||||
eclipseWtp('xml').configFile('spotless/eclipse-wtp-xml.prefs')
|
||||
trimTrailingWhitespace()
|
||||
endWithNewline()
|
||||
}
|
||||
groovyGradle {
|
||||
target '*.gradle'
|
||||
greclipse()
|
||||
leadingTabsToSpaces(4)
|
||||
trimTrailingWhitespace()
|
||||
endWithNewline()
|
||||
}
|
||||
}
|
||||
|
||||
final def markwon_version = '4.6.2'
|
||||
@@ -214,6 +249,11 @@ dependencies {
|
||||
def media3_version = "1.8.0" // 1.9.0 need minSdkVersion 23
|
||||
|
||||
implementation 'androidx.concurrent:concurrent-futures:1.3.0'
|
||||
implementation 'androidx.core:core:1.17.0'
|
||||
implementation 'androidx.core:core-telecom:1.0.1'
|
||||
implementation 'im.conversations.webrtc:webrtc-android:129.0.0'
|
||||
// For Kotlin->Java interpolation
|
||||
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.9.4'
|
||||
implementation 'androidx.sharetarget:sharetarget:1.2.0'
|
||||
implementation 'androidx.webkit:webkit:1.14.0'
|
||||
implementation 'androidx.multidex:multidex:2.0.1'
|
||||
@@ -251,7 +291,8 @@ dependencies {
|
||||
implementation 'com.github.amulyakhare:TextDrawable:558677ea31' // number of unread messages,
|
||||
// the one-letter circle for the contacts (when there is not avatar) and a white background.
|
||||
implementation 'com.googlecode.mp4parser:isoparser:1.0.6' // MP4 recoding; upgrading eg. to 1.1.22 breaks recoding, however, i have not investigated further, just reset to 1.0.6
|
||||
implementation ('com.davemorrissey.labs:subsampling-scale-image-view:3.10.0') { // for the zooming on photos / media
|
||||
implementation ('com.davemorrissey.labs:subsampling-scale-image-view:3.10.0') {
|
||||
// for the zooming on photos / media
|
||||
exclude group: 'com.android.support', module: 'support-annotations'
|
||||
}
|
||||
|
||||
@@ -260,7 +301,8 @@ dependencies {
|
||||
// <https://github.com/cketti/SafeContentResolver>
|
||||
implementation 'de.cketti.safecontentresolver:safe-content-resolver-v21:1.0.0'
|
||||
|
||||
gplayImplementation('com.google.firebase:firebase-messaging:24.1.2') { // for PUSH notifications, don't upgrade: v25.0.0 requires minSdk>=23
|
||||
gplayImplementation('com.google.firebase:firebase-messaging:24.1.2') {
|
||||
// for PUSH notifications, don't upgrade: v25.0.0 requires minSdk>=23
|
||||
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'
|
||||
|
||||
@@ -946,18 +946,6 @@ JNIEXPORT jstring Java_com_b44t_messenger_DcContext_getContactEncrInfo(JNIEnv *e
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jstring Java_com_b44t_messenger_DcContext_initiateKeyTransfer(JNIEnv *env, jobject obj)
|
||||
{
|
||||
jstring setup_code = NULL;
|
||||
char* temp = dc_initiate_key_transfer(get_dc_context(env, obj));
|
||||
if (temp) {
|
||||
setup_code = JSTRING_NEW(temp);
|
||||
dc_str_unref(temp);
|
||||
}
|
||||
return setup_code;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT void Java_com_b44t_messenger_DcContext_imex(JNIEnv *env, jobject obj, jint what, jstring dir)
|
||||
{
|
||||
CHAR_REF(dir);
|
||||
@@ -1630,15 +1618,6 @@ JNIEXPORT jboolean Java_com_b44t_messenger_DcMsg_hasHtml(JNIEnv *env, jobject ob
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jstring Java_com_b44t_messenger_DcMsg_getSetupCodeBegin(JNIEnv *env, jobject obj)
|
||||
{
|
||||
char* temp = dc_msg_get_setupcodebegin(get_dc_msg(env, obj));
|
||||
jstring ret = JSTRING_NEW(temp);
|
||||
dc_str_unref(temp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT void Java_com_b44t_messenger_DcMsg_setSubject(JNIEnv *env, jobject obj, jstring text)
|
||||
{
|
||||
CHAR_REF(text);
|
||||
|
||||
+1
-1
Submodule jni/deltachat-core-rust updated: 27dbe0bb6c...0d8e13c1e0
Vendored
+5
@@ -13,3 +13,8 @@
|
||||
-keep class org.thoughtcrime.securesms.crypto.KeyStoreHelper* { *; }
|
||||
|
||||
-dontwarn com.google.firebase.analytics.connector.AnalyticsConnector
|
||||
|
||||
# Keep WebRTC classes
|
||||
-keep class org.webrtc.** { *; }
|
||||
-keepclassmembers class org.webrtc.** { *; }
|
||||
-keepattributes InnerClasses
|
||||
|
||||
@@ -9,3 +9,4 @@ cd "$ROOT_DIR"
|
||||
|
||||
# generate code
|
||||
dcrpcgen java --schema schema.json -o ./src/main/java/
|
||||
rm schema.json
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
pluginManagement {
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
eclipse.preferences.version=1
|
||||
lineWidth=100
|
||||
splitMultiAttrs=true
|
||||
indentMultipleAttributes=true
|
||||
indentationChar=space
|
||||
indentationSize=4
|
||||
spaceBeforeEmptyCloseTag=true
|
||||
@@ -3,10 +3,6 @@
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<!-- force compiling emojipicker on sdk<21 and firebase on sdk<19; runtime checks are required then -->
|
||||
<uses-sdk
|
||||
tools:overrideLibrary="androidx.emoji2.emojipicker, com.google.firebase.messaging, com.google.android.gms.cloudmessaging" />
|
||||
|
||||
<meta-data
|
||||
android:name="firebase_analytics_collection_deactivated"
|
||||
android:value="true" />
|
||||
|
||||
+548
-455
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,6 @@
|
||||
<li><a href="#howtoe2ee">How can I find people to chat with?</a></li>
|
||||
<li><a href="#why-is-a-chat-marked-as-request">Why is a chat marked as “Request”?</a></li>
|
||||
<li><a href="#how-can-i-put-two-of-my-friends-in-contact-with-each-other">How can I put two of my friends in contact with each other?</a></li>
|
||||
<li><a href="#podporuje-delta-chat-obrázky-videa-a-jiné-přílohy">Podporuje Delta Chat obrázky, videa a jiné přílohy?</a></li>
|
||||
<li><a href="#multiple-accounts">What are profiles? How can I switch between them?</a></li>
|
||||
<li><a href="#kdo-uvidí-můj-profilový-obrázek">Kdo uvidí můj profilový obrázek?</a></li>
|
||||
<li><a href="#signature">Can I set a Bio/Status with Delta Chat?</a></li>
|
||||
@@ -14,6 +13,7 @@
|
||||
<li><a href="#what-does-the-green-dot-mean">What does the green dot mean?</a></li>
|
||||
<li><a href="#what-do-the-ticks-shown-beside-outgoing-messages-mean">What do the ticks shown beside outgoing messages mean?</a></li>
|
||||
<li><a href="#edit">Correct typos and delete messages after sending</a></li>
|
||||
<li><a href="#mediaquality">How is media quality handled?</a></li>
|
||||
<li><a href="#ephemeralmsgs">How do disappearing messages work?</a></li>
|
||||
<li><a href="#delold">What happens if I turn on “Delete Messages from Device”?</a></li>
|
||||
<li><a href="#remove-account">How can I delete my chat profile?</a></li>
|
||||
@@ -218,19 +218,6 @@ You can also add a little introduction message.</p>
|
||||
<p>The second contact will receive a <strong>card</strong> then
|
||||
and can tap it to start chatting with the first contact.</p>
|
||||
|
||||
<h3 id="podporuje-delta-chat-obrázky-videa-a-jiné-přílohy">
|
||||
|
||||
|
||||
Podporuje Delta Chat obrázky, videa a jiné přílohy? <a href="#podporuje-delta-chat-obrázky-videa-a-jiné-přílohy" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Yes. Images, videos, files, voice messages etc. can be sent using the <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Attachment-</strong>
|
||||
or <img style="vertical-align:middle; width:0.8em; margin:1px" src="../mic.png" alt="Microphone" /> <strong>Voice Message</strong> buttons</p>
|
||||
|
||||
<p>For performance, images are optimized and sent at a smaller size by default, but you can send it as a “file” to preserve the original.</p>
|
||||
|
||||
<h3 id="multiple-accounts">
|
||||
|
||||
|
||||
@@ -412,6 +399,32 @@ Notifications are not sent and there is no time limit.</p>
|
||||
<p>Note, that the original message may still be received by chat members
|
||||
who could have already replied, forwarded, saved, screenshotted or otherwise copied the message.</p>
|
||||
|
||||
<h3 id="mediaquality">
|
||||
|
||||
|
||||
How is media quality handled? <a href="#mediaquality" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Images, videos, files, voice messages etc. can be sent using the <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Attach-</strong>
|
||||
or <img style="vertical-align:middle; width:0.8em; margin:1px" src="../mic.png" alt="Microphone" /> <strong>Voice Message</strong> buttons.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>By default, compression ensures <strong>fast, efficient delivery</strong> that respects everyone’s data limits and storage.
|
||||
This is ideal for everyday communication.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>In regions with worse connectivity,
|
||||
you can choose higher compression at <strong>Settings → Chats → Outgoing Media Quality</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>If you specifically need to send media in its <strong>original quality</strong>, use <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Attach → File</strong> in the chat.
|
||||
Please use this method sparingly, as sending original files will significantly increase data usage for you and all recipients in the chat.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="ephemeralmsgs">
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
<li><a href="#howtoe2ee">Wie finde ich Leute, mit denen ich chatten kann?</a></li>
|
||||
<li><a href="#warum-ist-ein-chat-als-anfrage-markiert">Warum ist ein Chat als “Anfrage” markiert?</a></li>
|
||||
<li><a href="#wie-kann-ich-zwei-meiner-freunde-miteinander-in-kontakt-bringen">Wie kann ich zwei meiner Freunde miteinander in Kontakt bringen?</a></li>
|
||||
<li><a href="#unterstützt-delta-chat-bilder-videos-und-dateianhänge">Unterstützt Delta Chat Bilder, Videos und Dateianhänge?</a></li>
|
||||
<li><a href="#multiple-accounts">Was sind Profile? Wie kann ich zwischen ihnen wechseln?</a></li>
|
||||
<li><a href="#wer-sieht-mein-profilbild">Wer sieht mein Profilbild?</a></li>
|
||||
<li><a href="#signature">Kann ich einen Status festlegen?</a></li>
|
||||
@@ -14,6 +13,7 @@
|
||||
<li><a href="#was-bedeutet-der-grüne-punkt">Was bedeutet der grüne Punkt?</a></li>
|
||||
<li><a href="#was-bedeuten-die-häkchen-neben-den-ausgehenden-nachrichten">Was bedeuten die Häkchen neben den ausgehenden Nachrichten?</a></li>
|
||||
<li><a href="#edit">Schreibfehler korrigieren und Nachrichten nach dem Senden löschen</a></li>
|
||||
<li><a href="#mediaquality">Medienqualität und Datenverbrauch</a></li>
|
||||
<li><a href="#ephemeralmsgs">Wie funktionieren “Verschwindende Nachrichten”?</a></li>
|
||||
<li><a href="#delold">Was passiert, wenn ich “Nachrichten vom Gerät löschen” aktiviere?</a></li>
|
||||
<li><a href="#remove-account">Wie kann ich mein Chat-Profil löschen?</a></li>
|
||||
@@ -109,7 +109,7 @@
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>Einfache Erstellung von <strong>privaten Chat-Profile</strong> mit sicheren, schnellen und interoperablen <a href="https://chatmail.at/relays">Chatmail-Servern</a>,
|
||||
<p>Einfache Erstellung von <strong>privaten Chat-Profilen</strong> mit sicheren, schnellen und interoperablen <a href="https://chatmail.at/relays">Chatmail-Servern</a>,
|
||||
die sofortige Push-Benachrichtigungen für iOS- und Android-Geräte bieten.</p>
|
||||
</li>
|
||||
<li>
|
||||
@@ -137,17 +137,17 @@ basierend auf <a href="https://github.com/chatmail/core/blob/main/standards.md#s
|
||||
</h3>
|
||||
|
||||
<p>Beachte zunächst, dass Delta Chat ein privater Messenger ist.
|
||||
Es gibt keine öffentliches Verzeichnis, du entscheiden selbst über deine Kontakte.</p>
|
||||
Es gibt kein öffentliches Verzeichnis, du entscheidest selbst über deine Kontakte.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>Wenn du <strong>persönlich</strong> mit deinen Freunden oder Familie zusammen bist,
|
||||
tippe auf das <strong>QR-Code</strong>-Symbol <img style="vertical-align:middle; height:1.3em; margin:1px" src="../qr-icon.png" />
|
||||
auf dem Hauptbildschirm.<br />
|
||||
Bitte deinen Chatpartner den QR-Code mit Delta Chat zu <strong>scannen</strong>.</p>
|
||||
Bitte dann deinen Chatpartner den QR-Code mit Delta Chat zu <strong>scannen</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Für eine Kontaktaufnahme <strong>aus der Ferne</strong>, klicke im selben Bildschirm auf “Kopieren” oder “Teilen” und sende den <strong>Einladungslink</strong> über einen anderen privaten Chat.</p>
|
||||
<p>Für eine Kontaktaufnahme <strong>aus der Ferne</strong> klicke im selben Bildschirm auf “Kopieren” oder “Teilen” und sende den <strong>Einladungslink</strong> über einen anderen privaten Chat.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -177,7 +177,7 @@ wird eine Ende-zu-Ende-Verschlüsselung zwischen allen Mitgliedern eingerichtet.
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Da Delta Chat ein privater Messenger ist, können dir zunächst nur Freunde und Familienmitglieder, denen du deinen <a href="#howtoe2ee">QR-Code oder Einladungslink</a> schickst, schreiben.</p>
|
||||
<p>Da Delta Chat ein privater Messenger ist, können dir zunächst nur Freunde und Familienmitglieder schreiben, denen du deinen <a href="#howtoe2ee">QR-Code oder Einladungslink</a> schickst.</p>
|
||||
|
||||
<p>Deine Freunde können deine Kontaktdaten dann mit anderen Freunden teilen. Dies wird als <b style="border: 1px solid currentColor; padding: 0 3px; font-size:90%">Anfrage</b> angezeigt.</p>
|
||||
|
||||
@@ -186,12 +186,12 @@ wird eine Ende-zu-Ende-Verschlüsselung zwischen allen Mitgliedern eingerichtet.
|
||||
<p>Du musst die Anfrage <strong>akzeptieren</strong>, bevor du antworten kannst.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Du kannst sie auch “löschen”, wenn du vorerst nicht mit ihm chatten möchten.</p>
|
||||
<p>Du kannst sie auch “löschen”, wenn du vorerst nicht mit dieser Person chatten möchtest.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>If you delete a request, future messages from that contact will still appear
|
||||
as message request, so you can change your mind. If you really don’t want to
|
||||
receive messages from this person, consider <strong>blocking</strong> them.</p>
|
||||
<p>Wenn du eine Anfrage löschst, werden zukünftige Nachrichten von diesem Kontakt weiterhin
|
||||
als Nachrichtenanfrage angezeigt, sodass du deine Meinung ändern kannst. Wenn du wirklich keine
|
||||
Nachrichten von dieser Person erhalten möchtest, solltest du sie <strong>blockieren</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -209,19 +209,6 @@ Du kannst auch eine kurze Nachricht hinzufügen.</p>
|
||||
<p>Der zweite Kontakt erhält dann die <strong>Kontaktdaten</strong> und
|
||||
kann darauf tippen, um mit dem ersten Kontakt zu chatten.</p>
|
||||
|
||||
<h3 id="unterstützt-delta-chat-bilder-videos-und-dateianhänge">
|
||||
|
||||
|
||||
Unterstützt Delta Chat Bilder, Videos und Dateianhänge? <a href="#unterstützt-delta-chat-bilder-videos-und-dateianhänge" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Ja. Bilder, Videos, Dateien, Sprachnachrichten und mehr können über die <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Anhang-</strong>
|
||||
bzw. <img style="vertical-align:middle; width:0.8em; margin:1px" src="../mic.png" alt="Microphone" /> <strong>Sprachnachricht</strong>-Buttons hinzugefügt werden</p>
|
||||
|
||||
<p>Um die Leistung zu verbessern, werden die Bilder standardmäßig optimiert und in einer kleineren Größe gesendet, aber du kannst sie auch als “Datei” senden, um das Original zu erhalten.</p>
|
||||
|
||||
<h3 id="multiple-accounts">
|
||||
|
||||
|
||||
@@ -241,7 +228,7 @@ oder <strong>Profile zu wechseln</strong>.</p>
|
||||
|
||||
<p>Du kannst separate Profile für politische, familiäre oder berufliche Aktivitäten verwenden.</p>
|
||||
|
||||
<p>Vielleicht möchtest due auch erfahren, wie du <a href="#multiclient">Profile auf mehreren Geräten verwenden kannst</a>.</p>
|
||||
<p>Vielleicht möchtest du auch erfahren, wie du <a href="#multiclient">Profile auf mehreren Geräten verwenden kannst</a>.</p>
|
||||
|
||||
<h3 id="wer-sieht-mein-profilbild">
|
||||
|
||||
@@ -279,7 +266,7 @@ Sobald du eine Nachricht an einen Kontakt sendest, kann dieser deine Signatur in
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p><strong>Angeheftete Chats</strong> bleiben immer ganz oben in der Chatliste. So kannst du schnell auf deine Lieblingschats zugreifen oder du verwendest vorübergehend angeheftete Chats um Dinge nicht zu vergessen.</p>
|
||||
<p><strong>Angeheftete Chats</strong> bleiben immer ganz oben in der Chatliste. So kannst du schnell auf deine Lieblingschats zugreifen oder du verwendest vorübergehend angeheftete Chats, um Dinge nicht zu vergessen.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Stummgeschaltete Chats</strong> erhalten keine Benachrichtigungen, bleiben ansonsten aber an ihrem Platz. Du kannst auch stummgeschaltete Chats anheften.</p>
|
||||
@@ -292,7 +279,7 @@ Sobald du eine Nachricht an einen Kontakt sendest, kann dieser deine Signatur in
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Um die Funktionen zu nutzen, lang auf einen Chat in der Chatliste tippen oder den Chat mit der rechten Maustaste anklicken.</p>
|
||||
<p>Um die Funktionen zu nutzen, tippe lang auf einen Chat in der Chatliste oder klicke den Chat mit der rechten Maustaste an.</p>
|
||||
|
||||
<h3 id="save">
|
||||
|
||||
@@ -302,11 +289,11 @@ Sobald du eine Nachricht an einen Kontakt sendest, kann dieser deine Signatur in
|
||||
|
||||
</h3>
|
||||
|
||||
<p><strong>Gespeicherte Nachrichten</strong> ist ein Chat, den du verwenden kannst, um dir Nachrichten zu merken und wiederzufinden.</p>
|
||||
<p><strong>Gespeicherte Nachrichten</strong> ist ein Chat, den du verwenden kannst, um dir Nachrichten zu merken und sie wiederzufinden.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>Tippen in einem beliebigen Chat lange auf eine Nachricht oder klicken mit der rechten Maustaste darauf und wähle <strong>Speichern</strong>.</p>
|
||||
<p>Tippe im Chat lange auf eine Nachricht oder klicke mit der rechten Maustaste darauf und wähle <strong>Speichern</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Gespeicherte Nachrichten werden mit dem Symbol
|
||||
@@ -319,7 +306,7 @@ Durch Tippen auf <img style="vertical-align:middle; width:1.2em; margin:1px" src
|
||||
kannst du zu der ursprünglichen Nachricht im ursprünglichen Chat zurückkehren</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Schließlich kannst du auch „Gespeicherte Nachrichten“ verwenden, um <strong>persönliche Notizen</strong> zu machen - öffnen den Chat, gib etwas ein, fügen ein Foto oder eine Sprachnachricht hinzu usw.</p>
|
||||
<p>Schließlich kannst du auch „Gespeicherte Nachrichten“ verwenden, um <strong>persönliche Notizen</strong> zu machen. Öffne den Chat, gib etwas ein, fügen ein Foto oder eine Sprachnachricht hinzu usw.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Da „Gespeicherte Nachrichten“ synchronisiert werden, können sie sehr praktisch für die Übertragung von Daten zwischen Geräten sein</p>
|
||||
@@ -360,7 +347,7 @@ sei es durch den <a href="#edit">Absender</a>, durch <a href="#delold">Automatis
|
||||
|
||||
<p>In <a href="#groups">Gruppen</a> bedeutet das zweite Häkchen, dass die Nachricht von mindestens einem Mitglied gelesen wurde.</p>
|
||||
|
||||
<p>Du erhälst nur dann das zweite Häkchen, wenn sowohl du als auch einer der Empfänger, die die Nachricht gelesen haben, <strong>Einstellungen → Chats → Lesebestätigungen</strong> aktiviert haben.</p>
|
||||
<p>Du erhältst nur dann das zweite Häkchen, wenn sowohl du als auch einer der Empfänger, die die Nachricht gelesen haben, <strong>Einstellungen → Chats → Lesebestätigungen</strong> aktiviert haben.</p>
|
||||
|
||||
<h3 id="edit">
|
||||
|
||||
@@ -388,6 +375,31 @@ Es werden keine Benachrichtigungen verschickt und es gibt kein Zeitlimit.</p>
|
||||
<p>Beachten, dass die ursprüngliche Nachricht dennoch von Chatteilnehmern empfangen worden sein könnte,
|
||||
die die Nachricht bereits beantwortet, weitergeleitet, gespeichert, mit einem Screenshot versehen oder anderweitig kopiert haben könnten.</p>
|
||||
|
||||
<h3 id="mediaquality">
|
||||
|
||||
|
||||
Medienqualität und Datenverbrauch <a href="#mediaquality" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Bilder, Videos, Dateien, Sprachnachrichten und mehr können über die <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Anhang-</strong>
|
||||
bzw. <img style="vertical-align:middle; width:0.8em; margin:1px" src="../mic.png" alt="Microphone" /> <strong>Sprachnachricht</strong>-Buttons hinzugefügt werden.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>Standardmäßig sorgt Komprimierung für eine <strong>schnelle, effiziente Übertragung</strong>, die die Datenlimits und Speicherplatzkapazitäten aller Beteiligten berücksichtigt.
|
||||
Dies ist ideal für die tägliche Kommunikation.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>In Regionen mit schlechter Verbindung können Sie unter <strong>Einstellungen → Chats → Medienqualität beim Senden</strong> eine höhere Komprimierung wählen.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Wenn Sie Medien ausdrücklich in ihrer <strong>Originalqualität</strong> senden müssen, verwende im Chat die Option <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Anhängen → Datei</strong>.
|
||||
Verwende diese Methode nur sparsam, da das Senden von Originaldateien den Datenverbrauch für dich und alle Empfänger im Chat erheblich erhöht.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="ephemeralmsgs">
|
||||
|
||||
|
||||
@@ -503,7 +515,7 @@ und seine <a href="#edit">eigenen Nachrichten von Geräten der Mitglieder lösch
|
||||
<p>Wenn das Mitglied noch nicht in deiner Kontaktliste ist, sie sich aber <strong>persönlich</strong> treffen, wählen Sie dort <strong>QR-Einladungscode</strong> an. Dein Chat-Partner kann nun den QR-Code mit seiner Delta Chat-App <strong>scannen</strong> indem er auf <img style="vertical-align:middle; height:1.3em; margin:1px" src="../qr-icon.png" /> auf dem Hauptbildschirm tippt.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Für eine Kontaktaufnahme <strong>aus der Ferne</strong>, tippe dort “Kopieren” oder “Teilen” und sende den Einladungslink über einen anderen privaten Chat zum neuen Mitglied.</p>
|
||||
<p>Für eine Kontaktaufnahme <strong>aus der Ferne</strong> tippe dort “Kopieren” oder “Teilen” und sende den Einladungslink über einen anderen privaten Chat zum neuen Mitglied.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -533,7 +545,7 @@ Kein Problem, bitte einfach ein anderes Gruppenmitglied in einem normalen Chat,
|
||||
Wenn du der Gruppe später erneut beitreten möchtest, bitten ein anderes Gruppenmitglied, dich hinzuzufügen.</li>
|
||||
</ul>
|
||||
|
||||
<p>Alternativ kannst du eine Gruppe auch “stummschalten” - dies bedeutet, dass du weiterhin alle Nachrichten erhälst und neue schreiben kannst, aber nicht mehr über neue Nachrichten informiert wirst.</p>
|
||||
<p>Alternativ kannst du eine Gruppe auch “stummschalten” - dies bedeutet, dass du weiterhin alle Nachrichten erhältst und neue schreiben kannst, aber nicht mehr über neue Nachrichten informiert wirst.</p>
|
||||
|
||||
<h3 id="eine-gruppe-klonen">
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
<li><a href="#howtoe2ee">How can I find people to chat with?</a></li>
|
||||
<li><a href="#why-is-a-chat-marked-as-request">Why is a chat marked as “Request”?</a></li>
|
||||
<li><a href="#how-can-i-put-two-of-my-friends-in-contact-with-each-other">How can I put two of my friends in contact with each other?</a></li>
|
||||
<li><a href="#does-delta-chat-support-images-videos-and-other-attachments">Does Delta Chat support images, videos and other attachments?</a></li>
|
||||
<li><a href="#multiple-accounts">What are profiles? How can I switch between them?</a></li>
|
||||
<li><a href="#who-sees-my-profile-picture">Who sees my profile picture?</a></li>
|
||||
<li><a href="#signature">Can I set a Bio/Status with Delta Chat?</a></li>
|
||||
@@ -14,6 +13,7 @@
|
||||
<li><a href="#what-does-the-green-dot-mean">What does the green dot mean?</a></li>
|
||||
<li><a href="#what-do-the-ticks-shown-beside-outgoing-messages-mean">What do the ticks shown beside outgoing messages mean?</a></li>
|
||||
<li><a href="#edit">Correct typos and delete messages after sending</a></li>
|
||||
<li><a href="#mediaquality">How is media quality handled?</a></li>
|
||||
<li><a href="#ephemeralmsgs">How do disappearing messages work?</a></li>
|
||||
<li><a href="#delold">What happens if I turn on “Delete Messages from Device”?</a></li>
|
||||
<li><a href="#remove-account">How can I delete my chat profile?</a></li>
|
||||
@@ -218,19 +218,6 @@ You can also add a little introduction message.</p>
|
||||
<p>The second contact will receive a <strong>card</strong> then
|
||||
and can tap it to start chatting with the first contact.</p>
|
||||
|
||||
<h3 id="does-delta-chat-support-images-videos-and-other-attachments">
|
||||
|
||||
|
||||
Does Delta Chat support images, videos and other attachments? <a href="#does-delta-chat-support-images-videos-and-other-attachments" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Yes. Images, videos, files, voice messages etc. can be sent using the <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Attachment-</strong>
|
||||
or <img style="vertical-align:middle; width:0.8em; margin:1px" src="../mic.png" alt="Microphone" /> <strong>Voice Message</strong> buttons</p>
|
||||
|
||||
<p>For performance, images are optimized and sent at a smaller size by default, but you can send it as a “file” to preserve the original.</p>
|
||||
|
||||
<h3 id="multiple-accounts">
|
||||
|
||||
|
||||
@@ -411,6 +398,32 @@ Notifications are not sent and there is no time limit.</p>
|
||||
<p>Note, that the original message may still be received by chat members
|
||||
who could have already replied, forwarded, saved, screenshotted or otherwise copied the message.</p>
|
||||
|
||||
<h3 id="mediaquality">
|
||||
|
||||
|
||||
How is media quality handled? <a href="#mediaquality" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Images, videos, files, voice messages etc. can be sent using the <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Attach-</strong>
|
||||
or <img style="vertical-align:middle; width:0.8em; margin:1px" src="../mic.png" alt="Microphone" /> <strong>Voice Message</strong> buttons.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>By default, compression ensures <strong>fast, efficient delivery</strong> that respects everyone’s data limits and storage.
|
||||
This is ideal for everyday communication.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>In regions with worse connectivity,
|
||||
you can choose higher compression at <strong>Settings → Chats → Outgoing Media Quality</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>If you specifically need to send media in its <strong>original quality</strong>, use <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Attach → File</strong> in the chat.
|
||||
Please use this method sparingly, as sending original files will significantly increase data usage for you and all recipients in the chat.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="ephemeralmsgs">
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
<li><a href="#howtoe2ee">How can I find people to chat with?</a></li>
|
||||
<li><a href="#why-is-a-chat-marked-as-request">Why is a chat marked as “Request”?</a></li>
|
||||
<li><a href="#how-can-i-put-two-of-my-friends-in-contact-with-each-other">How can I put two of my friends in contact with each other?</a></li>
|
||||
<li><a href="#delta-chat-soporta-envío-de-imágenes-videos-documentos-y-otros-archivos">¿Delta Chat soporta envío de imágenes, videos, documentos y otros archivos?</a></li>
|
||||
<li><a href="#multiple-accounts">¿Qué son los perfiles? ¿Cómo puedo cambiar entre ellos?</a></li>
|
||||
<li><a href="#quién-ve-mi-foto-de-perfil">¿Quién ve mi foto de perfil?</a></li>
|
||||
<li><a href="#signature">Can I set a Bio/Status with Delta Chat?</a></li>
|
||||
@@ -14,6 +13,7 @@
|
||||
<li><a href="#qué-significa-el-punto-verde">¿Qué significa el punto verde?</a></li>
|
||||
<li><a href="#qué-significan-las-marcas-que-se-muestran-junto-a-los-mensajes-salientes">¿Qué significan las marcas que se muestran junto a los mensajes salientes?</a></li>
|
||||
<li><a href="#edit">Corregir errores y borrar mensajes después de enviar</a></li>
|
||||
<li><a href="#mediaquality">How is media quality handled?</a></li>
|
||||
<li><a href="#ephemeralmsgs">¿Cómo funciona la desaparición de mensajes?</a></li>
|
||||
<li><a href="#delold">¿Qué pasa si activo “Borrar mensajes del dispositivo”?</a></li>
|
||||
<li><a href="#remove-account">How can I delete my chat profile?</a></li>
|
||||
@@ -216,19 +216,6 @@ You can also add a little introduction message.</p>
|
||||
<p>The second contact will receive a <strong>card</strong> then
|
||||
and can tap it to start chatting with the first contact.</p>
|
||||
|
||||
<h3 id="delta-chat-soporta-envío-de-imágenes-videos-documentos-y-otros-archivos">
|
||||
|
||||
|
||||
¿Delta Chat soporta envío de imágenes, videos, documentos y otros archivos? <a href="#delta-chat-soporta-envío-de-imágenes-videos-documentos-y-otros-archivos" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Yes. Images, videos, files, voice messages etc. can be sent using the <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Attachment-</strong>
|
||||
or <img style="vertical-align:middle; width:0.8em; margin:1px" src="../mic.png" alt="Microphone" /> <strong>Voice Message</strong> buttons</p>
|
||||
|
||||
<p>Para mejorar el rendimiento, las imágenes se optimizan y se envían en un tamaño más pequeño de forma predeterminada, pero puedes enviarla como un “archivo” para conservar la original.</p>
|
||||
|
||||
<h3 id="multiple-accounts">
|
||||
|
||||
|
||||
@@ -407,6 +394,32 @@ No se envían notificaciones y no hay límite de tiempo.</p>
|
||||
<p>Note, that the original message may still be received by chat members
|
||||
who could have already replied, forwarded, saved, screenshotted or otherwise copied the message.</p>
|
||||
|
||||
<h3 id="mediaquality">
|
||||
|
||||
|
||||
How is media quality handled? <a href="#mediaquality" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Images, videos, files, voice messages etc. can be sent using the <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Attach-</strong>
|
||||
or <img style="vertical-align:middle; width:0.8em; margin:1px" src="../mic.png" alt="Microphone" /> <strong>Voice Message</strong> buttons.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>By default, compression ensures <strong>fast, efficient delivery</strong> that respects everyone’s data limits and storage.
|
||||
This is ideal for everyday communication.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>In regions with worse connectivity,
|
||||
you can choose higher compression at <strong>Settings → Chats → Outgoing Media Quality</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>If you specifically need to send media in its <strong>original quality</strong>, use <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Attach → File</strong> in the chat.
|
||||
Please use this method sparingly, as sending original files will significantly increase data usage for you and all recipients in the chat.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="ephemeralmsgs">
|
||||
|
||||
|
||||
|
||||
+104
-163
@@ -2,27 +2,27 @@
|
||||
<html lang="fr"><head><meta charset="UTF-8" /><meta name="viewport" content="initial-scale=1.0" /><link rel="stylesheet" href="../help.css" /></head><body><ul id="top">
|
||||
<li><a href="#quest-ce-que-delta-chat-">Qu’est-ce que Delta Chat ?</a>
|
||||
<ul>
|
||||
<li><a href="#howtoe2ee">How can I find people to chat with?</a></li>
|
||||
<li><a href="#why-is-a-chat-marked-as-request">Why is a chat marked as “Request”?</a></li>
|
||||
<li><a href="#how-can-i-put-two-of-my-friends-in-contact-with-each-other">How can I put two of my friends in contact with each other?</a></li>
|
||||
<li><a href="#delta-chat-prend-il-en-charge-les-images-vidéos-et-autres-pièces-jointes-">Delta Chat prend-il en charge les images, vidéos et autres pièces jointes ?</a></li>
|
||||
<li><a href="#multiple-accounts">What are profiles? How can I switch between them?</a></li>
|
||||
<li><a href="#howtoe2ee">Comment trouver des personnes avec qui discuter ?</a></li>
|
||||
<li><a href="#pourquoi-une-discussion-est-marquée-comme-invitation-">Pourquoi une discussion est marquée comme “invitation” ?</a></li>
|
||||
<li><a href="#comment-mettre-deux-personnes-en-relation-entre-elles-">Comment mettre deux personnes en relation entre elles ?</a></li>
|
||||
<li><a href="#multiple-accounts">À quoi correspondent les profils ? Comment est-ce que je peux passer de l’un à l’autre ?</a></li>
|
||||
<li><a href="#qui-peut-voir-ma-photo-de-profil-">Qui peut voir ma photo de profil ?</a></li>
|
||||
<li><a href="#signature">Can I set a Bio/Status with Delta Chat?</a></li>
|
||||
<li><a href="#signature">Est-il possible de définir une Bio/un Statut avec Delta Chat ?</a></li>
|
||||
<li><a href="#que-signifient-épingler-sourdine-et-archiver-">Que signifient “épingler”, “sourdine” et “archiver” ?</a></li>
|
||||
<li><a href="#save">How do “Saved Messages” work?</a></li>
|
||||
<li><a href="#save">Comment fonctionnent les “Messages enregistrés” ?</a></li>
|
||||
<li><a href="#que-signifie-le-point-vert-">Que signifie le point vert ?</a></li>
|
||||
<li><a href="#que-signifient-les-coches-affichées-à-côté-des-messages-sortants-">Que signifient les coches affichées à côté des messages sortants ?</a></li>
|
||||
<li><a href="#edit">Correct typos and delete messages after sending</a></li>
|
||||
<li><a href="#ephemeralmsgs">How do disappearing messages work?</a></li>
|
||||
<li><a href="#edit">Corriger des fautes et supprimer des messages après les avoir envoyés</a></li>
|
||||
<li><a href="#mediaquality">Comment est gérée la qualité des médias envoyés ?</a></li>
|
||||
<li><a href="#ephemeralmsgs">Comment fonctionnent les messages éphémères ?</a></li>
|
||||
<li><a href="#delold">Que se passe-t-il si j’active l’option “Supprimer les anciens messages de l’appareil” ?</a></li>
|
||||
<li><a href="#remove-account">How can I delete my chat profile?</a></li>
|
||||
<li><a href="#remove-account">Comment puis-je supprimer un profil de discussion ?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#groups">Groups</a>
|
||||
<li><a href="#groups">Groupes</a>
|
||||
<ul>
|
||||
<li><a href="#création-dun-groupe">Création d’un groupe</a></li>
|
||||
<li><a href="#addmembers">Add and remove members</a></li>
|
||||
<li><a href="#addmembers">Ajouter et supprimer des membres</a></li>
|
||||
<li><a href="#jai-quitté-un-groupe-par-accident">J’ai quitté un groupe par accident.</a></li>
|
||||
<li><a href="#je-ne-souhaite-plus-recevoir-les-messages-dun-groupe">Je ne souhaite plus recevoir les messages d’un groupe.</a></li>
|
||||
<li><a href="#cloning-a-group">Cloning a group</a></li>
|
||||
@@ -105,90 +105,71 @@
|
||||
|
||||
</h2>
|
||||
|
||||
<p>Delta Chat is a reliable, decentralized and secure instant messaging app,
|
||||
available for mobile and desktop platforms.</p>
|
||||
<p>Delta Chat est une application de messagerie fiable, décentralisée et sécurisée, disponible pour smartphones et ordinateurs de bureau.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>Instant creation of <strong>private chat profiles</strong>
|
||||
with secure and interoperable <a href="https://chatmail.at/relays">chatmail relays</a>
|
||||
that offer instant message delivery, and Push Notifications for iOS and Android devices.</p>
|
||||
<p>Création à la volée de <strong>profils de discussion privés</strong> grâce à des <a href="https://chatmail.at/relays">relais chatmail</a> sécurisés et interopérables qui permettent des échanges instantanés et des notifications Push pour les appareils iOS et Android.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Pervasive <a href="#multiple-accounts">multi-profile</a> and
|
||||
<a href="#multiclient">multi-device</a> support on all platforms
|
||||
and between different <a href="https://chatmail.at/clients">chatmail apps</a>.</p>
|
||||
<p>Fonctionne en <a href="#multiple-accounts">multi-profils</a> et <a href="#multiclient">multi-appareils</a> sur toutes les plateformes et quelque soit <a href="https://chatmail.at/clients">l’application chatmail</a> utilisée.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Interactive <a href="#webxdc">in-chat apps</a> for gaming and collaboration</p>
|
||||
<p><a href="#webxdc">Applications</a> interactives permettant de jouer et collaborer au sein des discussions.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="#security-audits">Audited end-to-end encryption</a>
|
||||
safe against network and server attacks.</p>
|
||||
<p><a href="#security-audits">Chiffrement de bout-en-bout audité</a> protégé contre les attaques réseaux et de serveurs.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Free and Open Source software, both app and server side,
|
||||
built on <a href="https://github.com/chatmail/core/blob/main/standards.md#standards-used-in-delta-chat">Internet Standards</a>.</p>
|
||||
<p>Logiciel libre et gratuit, autant côté serveur que côté application, développé autour des <a href="https://github.com/chatmail/core/blob/main/standards.md#standards-used-in-delta-chat">standards d’internet</a>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="howtoe2ee">
|
||||
|
||||
|
||||
How can I find people to chat with? <a href="#howtoe2ee" class="anchor"></a>
|
||||
Comment trouver des personnes avec qui discuter ? <a href="#howtoe2ee" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>First, note that Delta Chat is a private messenger.
|
||||
There is no public discovery, <em>you</em> decide about your contacts.</p>
|
||||
<p>Delta Chat est une application de messagerie privée. Il n’y a pas de mécanisme de découverte publique des utilisateurs et utilisatrices. <em>Vous</em> décidez avec qui vous échangez dans Delta Chat.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>If you are <strong>face to face</strong> with your friend or family,
|
||||
tap the <strong>QR Code</strong> icon <img style="vertical-align:middle; height:1.3em; margin:1px" src="../qr-icon.png" />
|
||||
on the main screen.<br />
|
||||
Ask your chat partner to <strong>scan</strong> the QR image
|
||||
with their Delta Chat app.</p>
|
||||
<p>En <strong>présence physique</strong> de vos amis ou de membres de votre famille, appuyez sur l’icône <strong>QR code</strong> <img style="vertical-align:middle; height:1.3em; margin:1px" src="../qr-icon.png" /> sur l’écran principal. Demandez à votre contact de <strong>scanner</strong> le QR code avec leur application Delta Chat.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>For a <strong>remote</strong> contact setup,
|
||||
from the same screen,
|
||||
click “Copy” or “Share” and send the <strong>invite link</strong>
|
||||
through another private chat.</p>
|
||||
<p>Pour la mise en place d’un échange <strong>à distance</strong>, cliquez sur l’icône <strong>QR code</strong> sur l’écran principal, puis sur le bouton “Lien”, puis sur “Copier” ou “Partager” et envoyez le lien d’invitation via une autre messagerie privée.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Now wait while connection gets established.</p>
|
||||
<p>Il suffit ensuite d’attendre que la connexion soit établie.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>If both sides are online, they will soon see a chat
|
||||
and can start messaging securely.</p>
|
||||
<p>Si les deux contacts sont en ligne, ils verront rapidement apparaître une nouvelle discussion et pourront tout de suite commencer une discussion sécurisée.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>If one side is offline or in bad network,
|
||||
the ability to chat is delayed until connectivity is restored.</p>
|
||||
<p>Si l’un des contacts n’est pas en ligne ou a des problèmes de réseau, la possibilité de démarrer la discussion aura lieu dès que la connectivité sera rétablie.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Congratulations!
|
||||
You now will automatically use <a href="#e2ee">end-to-end encryption</a> with this contact.
|
||||
If you add each other to <a href="#groups">groups</a>, end-to-end encryption will be established among all members.</p>
|
||||
<p>Félicitations !
|
||||
Vous utiliserez désormais le <a href="#e2ee">chiffrement de bout-en-bout</a> avec ce contact.
|
||||
Si vous vous ajoutez à des discussions de <a href="#groups">groupe</a> le chiffrement de bout-en-bout sera établi entre tous les membres de la discussion.</p>
|
||||
|
||||
<h3 id="why-is-a-chat-marked-as-request">
|
||||
<h3 id="pourquoi-une-discussion-est-marquée-comme-invitation-">
|
||||
|
||||
|
||||
Why is a chat marked as “Request”? <a href="#why-is-a-chat-marked-as-request" class="anchor"></a>
|
||||
Pourquoi une discussion est marquée comme “invitation” ? <a href="#pourquoi-une-discussion-est-marquée-comme-invitation-" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>As being a private messenger,
|
||||
only friends and family you <a href="#howtoe2ee">share your QR code or invite link with</a> can write to you.</p>
|
||||
<p>Delta Chat étant une messagerie privée, seules les personnes avec qui vous <a href="#howtoe2ee">partagez votre QR code ou lien d’invitation</a> peuvent vous écrire.</p>
|
||||
|
||||
<p>Your friends may share your contact with other friends,
|
||||
this appears as <b style="border: 1px solid currentColor; padding: 0 3px; font-size:90%">Request</b></p>
|
||||
<p>Vos contacts peuvent cependant partager votre profil avec d’autres personnes, ce qui apparaît alors comme une <b style="border: 1px solid currentColor; padding: 0 3px; font-size:90%">invitation</b>.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
@@ -204,53 +185,37 @@ recevoir de messages de cette personne, nous vous conseillons de la <strong>bloq
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="how-can-i-put-two-of-my-friends-in-contact-with-each-other">
|
||||
<h3 id="comment-mettre-deux-personnes-en-relation-entre-elles-">
|
||||
|
||||
|
||||
How can I put two of my friends in contact with each other? <a href="#how-can-i-put-two-of-my-friends-in-contact-with-each-other" class="anchor"></a>
|
||||
Comment mettre deux personnes en relation entre elles ? <a href="#comment-mettre-deux-personnes-en-relation-entre-elles-" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Attach the first contact to the chat of the second using <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Attachment Button → Contact</strong>.
|
||||
You can also add a little introduction message.</p>
|
||||
<p>Joignez le premier contact à votre discussion avec le second en utilisant <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Bouton pièce jointe → Contact</strong>.
|
||||
Profitez-en pour ajouter un message de présentation.</p>
|
||||
|
||||
<p>The second contact will receive a <strong>card</strong> then
|
||||
and can tap it to start chatting with the first contact.</p>
|
||||
|
||||
<h3 id="delta-chat-prend-il-en-charge-les-images-vidéos-et-autres-pièces-jointes-">
|
||||
|
||||
|
||||
Delta Chat prend-il en charge les images, vidéos et autres pièces jointes ? <a href="#delta-chat-prend-il-en-charge-les-images-vidéos-et-autres-pièces-jointes-" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Oui. Images, videos, files, voice messages etc. can be sent using the <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Attachment-</strong>
|
||||
or <img style="vertical-align:middle; width:0.8em; margin:1px" src="../mic.png" alt="Microphone" /> <strong>Voice Message</strong> buttons</p>
|
||||
|
||||
<p>Pour améliorer les performances, les images sont redimensionnées et envoyées en taille réduite par défaut ; mais vous pouvez les envoyer en tant que “fichier” pour en conserver la taille originale.</p>
|
||||
<p>Le deuxième contact recevra une <strong>carte</strong> qu’il pourra cliquer pour commencer une discussion avec le premier.</p>
|
||||
|
||||
<h3 id="multiple-accounts">
|
||||
|
||||
|
||||
What are profiles? How can I switch between them? <a href="#multiple-accounts" class="anchor"></a>
|
||||
À quoi correspondent les profils ? Comment est-ce que je peux passer de l’un à l’autre ? <a href="#multiple-accounts" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>A profile is <strong>a name, a picture</strong> and some additional information for encrypting messages.
|
||||
A profile lives on your device(s) only
|
||||
and uses the server only to relay messages.</p>
|
||||
<p>Un profil est <strong>un nom, une photo</strong> et quelques informations supplémentaires pour chiffrer des messages.
|
||||
Un profil n’est présent que sur votre appareil/vos appareils et utilise le serveur seulement pour relayer les messages vers vos contacts.</p>
|
||||
|
||||
<p>On first installation of Delta Chat a first profile is created.</p>
|
||||
<p>Lors de la première installation de Delta Chat un premier profil est créé.</p>
|
||||
|
||||
<p>Later, you can tap your profile image in the upper left corner to <strong>Add Profiles</strong>
|
||||
or to <strong>Switch Profiles</strong>.</p>
|
||||
<p>Par la suite vous pourrez cliquer sur votre image de profil en haut à gauche de l’écran principal pour <strong>Ajouter un profil</strong> ou <strong>Changer de profil</strong>.</p>
|
||||
|
||||
<p>You may want to use separate profiles for political, family or work related activities.</p>
|
||||
<p>Vous souhaiterez peut être utiliser des profils différents pour vos activités familiales, professionnelles ou politiques.</p>
|
||||
|
||||
<p>You may also wish to learn <a href="#multiclient">how to use the same profile on multiple devices</a>.</p>
|
||||
<p>Vous souhaiterez peut être aussi apprendre <a href="#multiclient">comment utiliser le même profil sur plusieurs appareils</a>.</p>
|
||||
|
||||
<h3 id="qui-peut-voir-ma-photo-de-profil-">
|
||||
|
||||
@@ -267,15 +232,13 @@ or to <strong>Switch Profiles</strong>.</p>
|
||||
<h3 id="signature">
|
||||
|
||||
|
||||
Can I set a Bio/Status with Delta Chat? <a href="#signature" class="anchor"></a>
|
||||
Est-il possible de définir une Bio/un Statut avec Delta Chat ? <a href="#signature" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Yes,
|
||||
you can do so under <strong>Settings → Profile → Bio</strong>.
|
||||
Once you sent a message to a contact,
|
||||
they will see it when they view your contact details.</p>
|
||||
<p>Oui, vous pouvez le faire dans <strong>Paramètres → Profil → Signature</strong>.
|
||||
À partir du moment ou vous échangez avec quelqu’un, cette personne pourra voir votre Signature en regardant les détails de votre profil.</p>
|
||||
|
||||
<h3 id="que-signifient-épingler-sourdine-et-archiver-">
|
||||
|
||||
@@ -309,37 +272,33 @@ pour mettre une discussion en sourdine, ouvrez le menu de la conversation (Andro
|
||||
<h3 id="save">
|
||||
|
||||
|
||||
How do “Saved Messages” work? <a href="#save" class="anchor"></a>
|
||||
Comment fonctionnent les “Messages enregistrés” ? <a href="#save" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p><strong>Saved Messages</strong> is a chat that you can use to easily remember and find messages.</p>
|
||||
<p><strong>Messages enregistrés</strong> est une discussion que vous pouvez utiliser pour sauvegarder et retrouver facilement des messages.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>In any chat, long tap or right click a message and select <strong>Save</strong></p>
|
||||
<p>Dans n’importe quelle discussion, touchez <img style="vertical-align:middle; width:1.2em; margin:1px;" src="../saved-icon.png" alt="Saved icon" /> ou faites un clic droit sur un message et sélectionnez <strong>Enregistrer</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Saved messages are marked by the symbol
|
||||
<img style="vertical-align:middle; width:1.2em; margin:1px" src="../saved-icon.png" alt="Saved icon" />
|
||||
next to the timestamp</p>
|
||||
<p>Les messages enregistrés sont identifiés par le symbole <img style="vertical-align:middle; width:1.2em; margin:1px" src="../saved-icon.png" alt="Saved icon" /> à côté de l’horodatage du message.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Later, open the “Saved Messages” chat - and you will see the saved messages there.
|
||||
By tapping <img style="vertical-align:middle; width:1.2em; margin:1px" src="../go-to-original.png" alt="Arrow-right icon" />,
|
||||
you can go back to the original message in the original chat</p>
|
||||
<p>Par la suite vous pourrez retrouver tous ces messages dans la discussion “Messages enregistrés”.
|
||||
En touchant <img style="vertical-align:middle; width:1.2em; margin:1px" src="../go-to-original.png" alt="Arrow-right icon" /> vous retrouverez le message dans sa discussion d’origine.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Finally, you can also use “Saved Messages” to take <strong>personal notes</strong> - open the chat, type something, add a photo or a voice message etc.</p>
|
||||
<p>Enfin vous pouvez aussi utiliser la discussion “Messages enregistrés” pour prendre des <strong>notes privées</strong> - ouvrez la discussion, écrivez votre message, ajoutez une photo, un message vocal, etc.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>As “Saved Message” are synced, they can become very handy for transferring data between devices</p>
|
||||
<p>La discussion “Messages enregistrés” étant synchronisée elle peut être très pratique pour transférer des informations d’un appareil à un autre.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Messages stay saved even if they are edited or deleted -
|
||||
may it be by <a href="#edit">sender</a>, by <a href="#delold">device cleanup</a> or by <a href="#ephemeralmsgs">disappearing messages of other chats</a>.</p>
|
||||
<p>Les messages restent enregistrés même lorsqu’ils sont édités ou supprimés, que ça soit par <a href="#edit">l’expéditeur⋅rice</a>, par <a href="#delold">suppression des anciens messages de l’appareil</a> ou par <a href="#ephemeralmsgs">disparition des messages éphémères au sein d’une discussion</a>.</p>
|
||||
|
||||
<h3 id="que-signifie-le-point-vert-">
|
||||
|
||||
@@ -349,13 +308,10 @@ may it be by <a href="#edit">sender</a>, by <a href="#delold">device cleanup</a>
|
||||
|
||||
</h3>
|
||||
|
||||
<p>You can sometimes see a <strong>green dot</strong> <img style="vertical-align:middle; width:1.2em; margin:1px" src="../green-dot.png" alt="" />
|
||||
next to the avatar of a contact.
|
||||
It means they were <strong>recently seen by you</strong> in the last 10 minutes,
|
||||
e.g. because they messaged you or sent a read receipt.</p>
|
||||
<p>Vous pourrez parfois voir un <strong>point vert</strong> <img style="vertical-align:middle; width:1.2em; margin:1px" src="../green-dot.png" alt="" /> sur le profil d’un contact.
|
||||
Cela veut dire que vous avez <strong>récemment vu</strong> le contact dans les 10 dernières minutes, par exemple parce que vous avez échangé avec ce contact, ou que vous avez reçu un accusé de lecture.</p>
|
||||
|
||||
<p>So this is not a real time online status
|
||||
and others will as well not always see that you are “online”.</p>
|
||||
<p>Ceci n’est donc pas un indicateur temps réel de présence en ligne et vos contacts ne pourront donc pas toujours voir si vous êtes en ligne ou non.</p>
|
||||
|
||||
<h3 id="que-signifient-les-coches-affichées-à-côté-des-messages-sortants-">
|
||||
|
||||
@@ -367,79 +323,75 @@ and others will as well not always see that you are “online”.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p><strong>One tick</strong> <img style="vertical-align:middle; width:1.5em; margin:1px" src="../tick1.png" alt="" />
|
||||
means that the message was sent successfully to the <a href="#relays">relay</a>.</p>
|
||||
<p><strong>Une marque</strong> <img style="vertical-align:middle; width:1.5em; margin:1px" src="../tick1.png" alt="" /> veut dire que le message a été envoyé correctement au <a href="#relays">relai</a>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Two ticks</strong> <img style="vertical-align:middle; width:1.5em; margin:1px" src="../tick2.png" alt="" />
|
||||
indicate your contact has read the message.</p>
|
||||
<p><strong>Deux marques</strong> <img style="vertical-align:middle; width:1.5em; margin:1px" src="../tick2.png" alt="" /> indiquent que votre contact a lu le message.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>In <a href="#groups">groups</a> the second tick means that at least one member has reported back having read the message.</p>
|
||||
<p>Au sein des <a href="#groups">groupes</a> la seconde marque veut dire qu’au moins un membre du groupe a pu lire le message.</p>
|
||||
|
||||
<p>You will only get the second tick if both you and one of the recipients who read the message
|
||||
has <strong>Settings → Chats → Read Receipts</strong> enabled.</p>
|
||||
<p>La seconde marque ne peut s’afficher que si vous et l’un de vos destinataires du message avez activé <strong>Paramètres → Discussions → Accusés de lecture</strong>.</p>
|
||||
|
||||
<h3 id="edit">
|
||||
|
||||
|
||||
Correct typos and delete messages after sending <a href="#edit" class="anchor"></a>
|
||||
Corriger des fautes et supprimer des messages après les avoir envoyés <a href="#edit" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>You can edit the text of your messages after sending.
|
||||
For that, long tap or right click the message and select <strong>Edit</strong>
|
||||
or <img style="vertical-align:middle; width:1.2em; margin:1px" src="../edit-icon.png" alt="Edit icon" />.</p>
|
||||
<p>Vous pouvez éditer le texte de votre message après l’avoir envoyé. Pour cela, appuyer longtemps ou faire clic droit sur le message et choisir <strong>Modifier</strong> ou <img style="vertical-align:middle; width:1.2em; margin:1px" src="../edit-icon.png" alt="Edit icon" />.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>If you have sent a message accidentally,
|
||||
from the same menu, select <strong>Delete</strong> and then <strong>Delete for Everyone</strong>.</p>
|
||||
<p>Si vous avez envoyé un message par erreur vous pouvez le supprimer depuis le même menu en choisissant <strong>Supprimer le message</strong> puis <strong>Supprimer pour moi</strong> ou <strong>Supprimer pour tout le monde</strong>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>While edited messages will have the word “Edited” next to the timestamp,
|
||||
deleted messages will be removed without a marker in the chat.
|
||||
Notifications are not sent and there is no time limit.</p>
|
||||
<p>Les messages modifiés seront indiqués par le mot “Modifié” à côté de l’horodatage du message, tandis que les messages supprimés le sont sans notification, ni dans la discussion, ni sur l’appareil, et peuvent l’être sans limite dans le temps.</p>
|
||||
|
||||
<p>Note, that the original message may still be received by chat members
|
||||
who could have already replied, forwarded, saved, screenshotted or otherwise copied the message.</p>
|
||||
<p>Remarque : le message original peut toutefois encore exister s’il a déjà été transféré, enregistré, ou si l’un des membres de la discussion en a fait une copie ou une capture d’écran.</p>
|
||||
|
||||
<h3 id="ephemeralmsgs">
|
||||
<h3 id="mediaquality">
|
||||
|
||||
|
||||
How do disappearing messages work? <a href="#ephemeralmsgs" class="anchor"></a>
|
||||
Comment est gérée la qualité des médias envoyés ? <a href="#mediaquality" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>You can turn on “disappearing messages”
|
||||
in the settings of a chat,
|
||||
at the top right of the chat window,
|
||||
by selecting a time span
|
||||
between 5 minutes and 1 year.</p>
|
||||
<p>Images, vidéos, fichiers, messages vocaux etc. peuvent être envoyé avec les boutons <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Pièce jointe</strong> ou <img style="vertical-align:middle; width:0.8em; margin:1px" src="../mic.png" alt="Microphone" /> <strong>Message vocal</strong>.</p>
|
||||
|
||||
<p>Until the setting is turned off again,
|
||||
each chat member’s Delta Chat app takes care
|
||||
of deleting the messages
|
||||
after the selected time span.
|
||||
The time span begins
|
||||
when the receiver first sees the message in Delta Chat.
|
||||
The messages are deleted both,
|
||||
on the servers,
|
||||
and in the apps itself.</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p>Par défaut le niveau de compression choisi permet un <strong>envoi rapide et efficace</strong> des messages en respectant les limites de données et de stockage de tout le monde. C’est un réglage idéal pour des échanges standards.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Dans les régions avec une connectivité limitée il est possible de choisir une compression plus forte dans <strong>Paramètres → Discussions → Qualité du média en sortie</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Si vous souhaitez absolument transmettre un fichier en <strong>qualité originale</strong>, utilisez <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Pièce jointe → Fichier</strong> dans la discussion. Pensez à utiliser cette fonctionnalité avec parcimonie pour limiter l’utilisation des données par toutes les personnes dans la discussion.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="ephemeralmsgs">
|
||||
|
||||
|
||||
Comment fonctionnent les messages éphémères ? <a href="#ephemeralmsgs" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<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>Vous pouvez activer les “Messages éphémères” dans les paramètres d’une discussion, dans le menu en haut à droite, en choisissant une durée prédéfinie entre 5 min et 1 an.</p>
|
||||
|
||||
<p>Apart from that,
|
||||
if one chat partner uninstalls Delta Chat,
|
||||
the (anyway encrypted) messages may take longer to get deleted from their server.</p>
|
||||
<p>Tant que le paramètre reste activé, les applications de chacun des membres se chargent de supprimer les messages qui dépassent la durée définie. La durée est comptabilisée à partir du moment où le message est vu pour la première fois, et le message est supprimé au sein de l’application et sur le serveur.</p>
|
||||
|
||||
<p>Remarque : ne faites confiance au réglage “Messages éphémères” que si vous faites confiance aux membres de la discussion. Des membres mal intentionné⋅es peuvent très bien prendre des photos, copier, sauvegarder, transférer un message avant qu’il ne soit supprimé.</p>
|
||||
|
||||
<p>Enfin, si l’un⋅e des membres d’une discussion désinstalle l’application Delta Chat, les messages (chiffrés, pour rappel) peuvent rester plus longtemps sur le serveur avant d’être supprimés.</p>
|
||||
|
||||
<h3 id="delold">
|
||||
|
||||
@@ -456,39 +408,28 @@ the (anyway encrypted) messages may take longer to get deleted from their server
|
||||
<h3 id="remove-account">
|
||||
|
||||
|
||||
How can I delete my chat profile? <a href="#remove-account" class="anchor"></a>
|
||||
Comment puis-je supprimer un profil de discussion ? <a href="#remove-account" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>If you are using more than one chat profile,
|
||||
you can remove single ones in the top profile switcher menu (on Android and iOS),
|
||||
or in the sidebar with a right click (in the Desktop app).
|
||||
Chat profiles are only removed on the device where deletion was triggered.
|
||||
Chat profiles on other devices will continue to fully function.</p>
|
||||
<p>Si vous utilisez plus d’un profil dans l’application, vous pouvez supprimer un profil spécifique via le menu (en haut sur Android et iOS), ou dans la barre latérale (sur l’application de bureau) permettant de passer d’un profil à un autre. Les profils ne sont toujours supprimés que sur l’appareil en question. Les profils continueront donc d’exister sur les autres appareils le cas échéant.</p>
|
||||
|
||||
<p>If you use a single default chat profile you can simply uninstall the app.
|
||||
This will still automatically trigger deletion of all associated address data on the chatmail server.
|
||||
For more info, please refer to <a href="https://nine.testrun.org/info.html#account-deletion">nine.testrun.org address-deletion</a>
|
||||
or the respective page from your chosen <a href="https://chatmail.at/relays">3rd party chatmail server</a>.</p>
|
||||
<p>Si vous n’utilisez qu’un seul profil vous pouvez tout simplement désinstaller l’application. Cela déclenchera la suppression des données liées au profil en question sur le serveur chatmail. Pour plus d’informations voir <a href="https://nine.testrun.org/info.html#account-deletion">Account deletion sur nine.testrun.org</a> ou la page respective du <a href="https://chatmail.at/relays">serveur chatmail</a> que vous utilisez.</p>
|
||||
|
||||
<h2 id="groups">
|
||||
|
||||
|
||||
Groups <a href="#groups" class="anchor"></a>
|
||||
Groupes <a href="#groups" class="anchor"></a>
|
||||
|
||||
|
||||
</h2>
|
||||
|
||||
<p>Groups let several people chat together privately with <strong>equal rights</strong>.</p>
|
||||
<p>Les groupes permettent à plusieurs personnes d’avoir une discussion. Chaque membre du groupe à les <strong>même droits</strong>.</p>
|
||||
|
||||
<p>Anyone can
|
||||
change the group name or avatar,
|
||||
<a href="#addmembers">add or remove members</a>,
|
||||
set <a href="#ephemeralmsgs">disappearing messages</a>,
|
||||
and <a href="#edit">delete their own messages</a> from all member’s devices.</p>
|
||||
<p>Chaque membre du groupe peut changer le nom du groupe ou l’avatar, <a href="#addmembers">ajouter ou supprimer des membres</a>, activer/désactiver <a href="#ephemeralmsgs">les messages éphémères</a>, et <a href="#edit">supprimer leurs propres messages</a> sur tous les appareils des membres de la discussion.</p>
|
||||
|
||||
<p>Because all members have the same rights, groups work best among <strong>trusted friends and family</strong>.</p>
|
||||
<p>Puisque tous les membres d’une discussion ont les mêmes droits, les groupes fonctionnent mieux avec des <strong>personnes de confiance et la famille</strong>.</p>
|
||||
|
||||
<h3 id="création-dun-groupe">
|
||||
|
||||
@@ -513,7 +454,7 @@ and <a href="#edit">delete their own messages</a> from all member’s devices.</
|
||||
<h3 id="addmembers">
|
||||
|
||||
|
||||
Add and remove members <a href="#addmembers" class="anchor"></a>
|
||||
Ajouter et supprimer des membres <a href="#addmembers" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
<li><a href="#howtoe2ee">How can I find people to chat with?</a></li>
|
||||
<li><a href="#why-is-a-chat-marked-as-request">Why is a chat marked as “Request”?</a></li>
|
||||
<li><a href="#how-can-i-put-two-of-my-friends-in-contact-with-each-other">How can I put two of my friends in contact with each other?</a></li>
|
||||
<li><a href="#apakah-delta-chat-mendukung-gambar-vidio-dan-lampiran-lainnya">Apakah Delta Chat mendukung gambar, vidio dan lampiran lainnya?</a></li>
|
||||
<li><a href="#multiple-accounts">What are profiles? How can I switch between them?</a></li>
|
||||
<li><a href="#siapa-yang-dapat-melihat-foto-profil-saya">Siapa yang dapat melihat Foto Profil saya?</a></li>
|
||||
<li><a href="#signature">Can I set a Bio/Status with Delta Chat?</a></li>
|
||||
@@ -14,6 +13,7 @@
|
||||
<li><a href="#what-does-the-green-dot-mean">What does the green dot mean?</a></li>
|
||||
<li><a href="#what-do-the-ticks-shown-beside-outgoing-messages-mean">What do the ticks shown beside outgoing messages mean?</a></li>
|
||||
<li><a href="#edit">Correct typos and delete messages after sending</a></li>
|
||||
<li><a href="#mediaquality">How is media quality handled?</a></li>
|
||||
<li><a href="#ephemeralmsgs">How do disappearing messages work?</a></li>
|
||||
<li><a href="#delold">What happens if I turn on “Delete Messages from Device”?</a></li>
|
||||
<li><a href="#remove-account">How can I delete my chat profile?</a></li>
|
||||
@@ -218,19 +218,6 @@ You can also add a little introduction message.</p>
|
||||
<p>The second contact will receive a <strong>card</strong> then
|
||||
and can tap it to start chatting with the first contact.</p>
|
||||
|
||||
<h3 id="apakah-delta-chat-mendukung-gambar-vidio-dan-lampiran-lainnya">
|
||||
|
||||
|
||||
Apakah Delta Chat mendukung gambar, vidio dan lampiran lainnya? <a href="#apakah-delta-chat-mendukung-gambar-vidio-dan-lampiran-lainnya" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Yes. Images, videos, files, voice messages etc. can be sent using the <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Attachment-</strong>
|
||||
or <img style="vertical-align:middle; width:0.8em; margin:1px" src="../mic.png" alt="Microphone" /> <strong>Voice Message</strong> buttons</p>
|
||||
|
||||
<p>For performance, images are optimized and sent at a smaller size by default, but you can send it as a “file” to preserve the original.</p>
|
||||
|
||||
<h3 id="multiple-accounts">
|
||||
|
||||
|
||||
@@ -411,6 +398,32 @@ Notifications are not sent and there is no time limit.</p>
|
||||
<p>Note, that the original message may still be received by chat members
|
||||
who could have already replied, forwarded, saved, screenshotted or otherwise copied the message.</p>
|
||||
|
||||
<h3 id="mediaquality">
|
||||
|
||||
|
||||
How is media quality handled? <a href="#mediaquality" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Images, videos, files, voice messages etc. can be sent using the <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Attach-</strong>
|
||||
or <img style="vertical-align:middle; width:0.8em; margin:1px" src="../mic.png" alt="Microphone" /> <strong>Voice Message</strong> buttons.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>By default, compression ensures <strong>fast, efficient delivery</strong> that respects everyone’s data limits and storage.
|
||||
This is ideal for everyday communication.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>In regions with worse connectivity,
|
||||
you can choose higher compression at <strong>Settings → Chats → Outgoing Media Quality</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>If you specifically need to send media in its <strong>original quality</strong>, use <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Attach → File</strong> in the chat.
|
||||
Please use this method sparingly, as sending original files will significantly increase data usage for you and all recipients in the chat.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="ephemeralmsgs">
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
<li><a href="#howtoe2ee">Come posso trovare persone con cui chattare?</a></li>
|
||||
<li><a href="#perché-una-chat-è-contrassegnata-come-richiesta">Perché una chat è contrassegnata come “Richiesta”?</a></li>
|
||||
<li><a href="#come-posso-mettere-in-contatto-due-miei-amici">Come posso mettere in contatto due miei amici?</a></li>
|
||||
<li><a href="#delta-chat-supporta-immagini-video-e-altri-allegati">Delta Chat supporta immagini, video e altri allegati?</a></li>
|
||||
<li><a href="#multiple-accounts">Cosa sono i profili? Come posso passare dall’uno all’altro?</a></li>
|
||||
<li><a href="#chi-vede-la-mia-immagine-del-profilo">Chi vede la mia immagine del profilo?</a></li>
|
||||
<li><a href="#signature">Posso impostare una Biografia/Stato con Delta Chat?</a></li>
|
||||
@@ -14,6 +13,7 @@
|
||||
<li><a href="#cosa-significa-il-punto-verde">Cosa significa il punto verde?</a></li>
|
||||
<li><a href="#cosa-significano-i-segni-di-spunta-visualizzati-accanto-ai-messaggi-in-uscita">Cosa significano i segni di spunta visualizzati accanto ai messaggi in uscita?</a></li>
|
||||
<li><a href="#edit">Correggi gli errori e cancella i messaggi dopo averli inviati</a></li>
|
||||
<li><a href="#mediaquality">How is media quality handled?</a></li>
|
||||
<li><a href="#ephemeralmsgs">Come funzionano i messaggi a scomparsa?</a></li>
|
||||
<li><a href="#delold">Cosa succede se attivo “Elimina Messaggi dal Dispositivo”?</a></li>
|
||||
<li><a href="#remove-account">Come posso eliminare il mio profilo chat?</a></li>
|
||||
@@ -217,19 +217,6 @@ Puoi anche aggiungere un breve messaggio di presentazione.</p>
|
||||
<p>Il secondo contatto riceverà una <strong>scheda</strong>
|
||||
e potrà toccarla per iniziare a chattare con il primo contatto.</p>
|
||||
|
||||
<h3 id="delta-chat-supporta-immagini-video-e-altri-allegati">
|
||||
|
||||
|
||||
Delta Chat supporta immagini, video e altri allegati? <a href="#delta-chat-supporta-immagini-video-e-altri-allegati" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Sì. Immagini, video, files, messaggi vocali ecc. possono essere inviati utilizzando <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Allegato-</strong>
|
||||
o <img style="vertical-align:middle; width:0.8em; margin:1px" src="../mic.png" alt="Microphone" /> pulsanti <strong>Messaggio Vocale</strong></p>
|
||||
|
||||
<p>Per le prestazioni, le immagini sono ottimizzate e inviate in dimensioni inferiori per impostazione predefinita, ma è possibile inviarle come “file” per preservare l’originale.</p>
|
||||
|
||||
<h3 id="multiple-accounts">
|
||||
|
||||
|
||||
@@ -409,6 +396,32 @@ Non vengono inviate notifiche e non c’è limite di tempo.</p>
|
||||
<p>Nota che il messaggio originale potrebbe essere ancora sui dispositivi dei membri della chat
|
||||
che avrebbero già potuto rispondere, inoltrare, salvare, scattare una schermata o copiare il messaggio in altri modi.</p>
|
||||
|
||||
<h3 id="mediaquality">
|
||||
|
||||
|
||||
How is media quality handled? <a href="#mediaquality" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Immagini, video, files, messaggi vocali ecc. possono essere inviati utilizzando <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Allegato-</strong>
|
||||
o <img style="vertical-align:middle; width:0.8em; margin:1px" src="../mic.png" alt="Microphone" /> pulsanti <strong>Messaggio Vocale</strong></p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>By default, compression ensures <strong>fast, efficient delivery</strong> that respects everyone’s data limits and storage.
|
||||
This is ideal for everyday communication.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>In regions with worse connectivity,
|
||||
you can choose higher compression at <strong>Settings → Chats → Outgoing Media Quality</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>If you specifically need to send media in its <strong>original quality</strong>, use <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Attach → File</strong> in the chat.
|
||||
Please use this method sparingly, as sending original files will significantly increase data usage for you and all recipients in the chat.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="ephemeralmsgs">
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
<li><a href="#howtoe2ee">How can I find people to chat with?</a></li>
|
||||
<li><a href="#why-is-a-chat-marked-as-request">Why is a chat marked as “Request”?</a></li>
|
||||
<li><a href="#how-can-i-put-two-of-my-friends-in-contact-with-each-other">How can I put two of my friends in contact with each other?</a></li>
|
||||
<li><a href="#ondersteunt-delta-chat-afbeeldingen-videos-en-ander-soort-bijlagen">Ondersteunt Delta Chat afbeeldingen, video’s en ander soort bijlagen?</a></li>
|
||||
<li><a href="#multiple-accounts">What are profiles? How can I switch between them?</a></li>
|
||||
<li><a href="#wie-kan-mijn-profielfoto-zien">Wie kan mijn profielfoto zien?</a></li>
|
||||
<li><a href="#signature">Can I set a Bio/Status with Delta Chat?</a></li>
|
||||
@@ -14,6 +13,7 @@
|
||||
<li><a href="#wat-betekent-die-groene-stip">Wat betekent die groene stip?</a></li>
|
||||
<li><a href="#wat-betekenen-de-vinkjes-naast-verzonden-berichten">Wat betekenen de vinkjes naast verzonden berichten?</a></li>
|
||||
<li><a href="#edit">Correct typos and delete messages after sending</a></li>
|
||||
<li><a href="#mediaquality">How is media quality handled?</a></li>
|
||||
<li><a href="#ephemeralmsgs">How do disappearing messages work?</a></li>
|
||||
<li><a href="#delold">Wat gebeurt er als ik ‘Oude berichten van server verwijderen’ inschakel?</a></li>
|
||||
<li><a href="#remove-account">How can I delete my chat profile?</a></li>
|
||||
@@ -218,19 +218,6 @@ You can also add a little introduction message.</p>
|
||||
<p>The second contact will receive a <strong>card</strong> then
|
||||
and can tap it to start chatting with the first contact.</p>
|
||||
|
||||
<h3 id="ondersteunt-delta-chat-afbeeldingen-videos-en-ander-soort-bijlagen">
|
||||
|
||||
|
||||
Ondersteunt Delta Chat afbeeldingen, video’s en ander soort bijlagen? <a href="#ondersteunt-delta-chat-afbeeldingen-videos-en-ander-soort-bijlagen" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Yes. Images, videos, files, voice messages etc. can be sent using the <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Attachment-</strong>
|
||||
or <img style="vertical-align:middle; width:0.8em; margin:1px" src="../mic.png" alt="Microphone" /> <strong>Voice Message</strong> buttons</p>
|
||||
|
||||
<p>Om de prestaties te verhogen, worden afbeeldingen standaard geoptimaliseerd en verkleind verstuurd, maar je kunt ze als een bestand verzenden om het origineel te sturen.</p>
|
||||
|
||||
<h3 id="multiple-accounts">
|
||||
|
||||
|
||||
@@ -410,6 +397,32 @@ Notifications are not sent and there is no time limit.</p>
|
||||
<p>Note, that the original message may still be received by chat members
|
||||
who could have already replied, forwarded, saved, screenshotted or otherwise copied the message.</p>
|
||||
|
||||
<h3 id="mediaquality">
|
||||
|
||||
|
||||
How is media quality handled? <a href="#mediaquality" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Images, videos, files, voice messages etc. can be sent using the <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Attach-</strong>
|
||||
or <img style="vertical-align:middle; width:0.8em; margin:1px" src="../mic.png" alt="Microphone" /> <strong>Voice Message</strong> buttons.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>By default, compression ensures <strong>fast, efficient delivery</strong> that respects everyone’s data limits and storage.
|
||||
This is ideal for everyday communication.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>In regions with worse connectivity,
|
||||
you can choose higher compression at <strong>Settings → Chats → Outgoing Media Quality</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>If you specifically need to send media in its <strong>original quality</strong>, use <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Attach → File</strong> in the chat.
|
||||
Please use this method sparingly, as sending original files will significantly increase data usage for you and all recipients in the chat.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="ephemeralmsgs">
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
<li><a href="#howtoe2ee">How can I find people to chat with?</a></li>
|
||||
<li><a href="#why-is-a-chat-marked-as-request">Why is a chat marked as “Request”?</a></li>
|
||||
<li><a href="#how-can-i-put-two-of-my-friends-in-contact-with-each-other">How can I put two of my friends in contact with each other?</a></li>
|
||||
<li><a href="#czy-delta-chat-obsługuje-obrazy-filmy-i-inne-załączniki">Czy Delta Chat obsługuje obrazy, filmy i inne załączniki?</a></li>
|
||||
<li><a href="#multiple-accounts">Czym są profile? Jak mogę przełączać się między nimi?</a></li>
|
||||
<li><a href="#kto-widzi-moje-zdjęcie-profilowe">Kto widzi moje zdjęcie profilowe?</a></li>
|
||||
<li><a href="#signature">Can I set a Bio/Status with Delta Chat?</a></li>
|
||||
@@ -14,6 +13,7 @@
|
||||
<li><a href="#co-oznacza-zielona-kropka">Co oznacza zielona kropka?</a></li>
|
||||
<li><a href="#co-oznaczają-znaczniki-wyświetlane-obok-wiadomości-wychodzących">Co oznaczają znaczniki wyświetlane obok wiadomości wychodzących?</a></li>
|
||||
<li><a href="#edit">Poprawianie literówek i usuwanie wiadomości po wysłaniu</a></li>
|
||||
<li><a href="#mediaquality">How is media quality handled?</a></li>
|
||||
<li><a href="#ephemeralmsgs">Jak działają znikające wiadomości?</a></li>
|
||||
<li><a href="#delold">Co się stanie, jeśli włączę opcję „Usuń wiadomości z urządzenia”?</a></li>
|
||||
<li><a href="#remove-account">How can I delete my chat profile?</a></li>
|
||||
@@ -215,19 +215,6 @@ You can also add a little introduction message.</p>
|
||||
<p>The second contact will receive a <strong>card</strong> then
|
||||
and can tap it to start chatting with the first contact.</p>
|
||||
|
||||
<h3 id="czy-delta-chat-obsługuje-obrazy-filmy-i-inne-załączniki">
|
||||
|
||||
|
||||
Czy Delta Chat obsługuje obrazy, filmy i inne załączniki? <a href="#czy-delta-chat-obsługuje-obrazy-filmy-i-inne-załączniki" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Tak. Images, videos, files, voice messages etc. can be sent using the <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Attachment-</strong>
|
||||
or <img style="vertical-align:middle; width:0.8em; margin:1px" src="../mic.png" alt="Microphone" /> <strong>Voice Message</strong> buttons</p>
|
||||
|
||||
<p>Ze względu na wydajność obrazy są domyślnie optymalizowane i wysyłane w mniejszym rozmiarze, ale można je wysłać jako „plik”, aby zachować oryginał.</p>
|
||||
|
||||
<h3 id="multiple-accounts">
|
||||
|
||||
|
||||
@@ -392,6 +379,32 @@ has <strong>Settings → Chats → Read Receipts</strong> enabled.</p>
|
||||
|
||||
<p>Pamiętaj, że oryginalną wiadomość nadal mogą otrzymać członkowie czatu, którzy mogli już odpowiedzieć, przesłać dalej, zapisać, wykonać zrzut ekranu lub w inny sposób skopiować wiadomość.</p>
|
||||
|
||||
<h3 id="mediaquality">
|
||||
|
||||
|
||||
How is media quality handled? <a href="#mediaquality" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Images, videos, files, voice messages etc. can be sent using the <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Attach-</strong>
|
||||
or <img style="vertical-align:middle; width:0.8em; margin:1px" src="../mic.png" alt="Microphone" /> <strong>Voice Message</strong> buttons.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>By default, compression ensures <strong>fast, efficient delivery</strong> that respects everyone’s data limits and storage.
|
||||
This is ideal for everyday communication.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>In regions with worse connectivity,
|
||||
you can choose higher compression at <strong>Settings → Chats → Outgoing Media Quality</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>If you specifically need to send media in its <strong>original quality</strong>, use <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Attach → File</strong> in the chat.
|
||||
Please use this method sparingly, as sending original files will significantly increase data usage for you and all recipients in the chat.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="ephemeralmsgs">
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
<li><a href="#howtoe2ee">Como posso encontrar pessoas para conversar?</a></li>
|
||||
<li><a href="#por-que-um-chat-está-marcado-como-solicitação">Por que um chat está marcado como “Solicitação”?</a></li>
|
||||
<li><a href="#como-posso-colocar-dois-dos-meus-amigos-em-contato-um-com-o-outro">Como posso colocar dois dos meus amigos em contato um com o outro?</a></li>
|
||||
<li><a href="#dá-para-mandar-imagens-vídeos-e-outros-anexos-pelo-delta-chat">Dá para mandar imagens, vídeos e outros anexos pelo Delta Chat?</a></li>
|
||||
<li><a href="#multiple-accounts">O que são perfis? Como posso alternar entre eles?</a></li>
|
||||
<li><a href="#quem-consegue-ver-a-imagem-do-meu-perfil">Quem consegue ver a imagem do meu perfil?</a></li>
|
||||
<li><a href="#signature">Posso definir uma Bio/Assinatura com o Delta Chat?</a></li>
|
||||
@@ -14,6 +13,7 @@
|
||||
<li><a href="#o-que-significa-o-ponto-verde">O que significa o ponto verde?</a></li>
|
||||
<li><a href="#o-que-significam-os-carrapatos-mostrados-ao-lado-das-mensagens-de-saída">O que significam os carrapatos mostrados ao lado das mensagens de saída?</a></li>
|
||||
<li><a href="#edit">Corrigir erros de digitação e excluir mensagens após o envio</a></li>
|
||||
<li><a href="#mediaquality">How is media quality handled?</a></li>
|
||||
<li><a href="#ephemeralmsgs">Como funcionam as mensagens efêmeras?</a></li>
|
||||
<li><a href="#delold">O que acontece se eu ativar a opção “Apagar mensagens do dispositivo”?</a></li>
|
||||
<li><a href="#remove-account">Como posso excluir minha conta?</a></li>
|
||||
@@ -218,19 +218,6 @@ Você também pode adicionar uma pequena mensagem de apresentação.</p>
|
||||
<p>O segundo contato receberá um <strong>cartão</strong>
|
||||
e poderá tocar nele para começar a conversar com o primeiro contato.</p>
|
||||
|
||||
<h3 id="dá-para-mandar-imagens-vídeos-e-outros-anexos-pelo-delta-chat">
|
||||
|
||||
|
||||
Dá para mandar imagens, vídeos e outros anexos pelo Delta Chat? <a href="#dá-para-mandar-imagens-vídeos-e-outros-anexos-pelo-delta-chat" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Sim. Imagens, vídeos, arquivos, mensagens de voz etc. podem ser enviados usando os botões de<img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Anexo-</strong>
|
||||
ou <img style="vertical-align:middle; width:0.8em; margin:1px" src="../mic.png" alt="Microphone" /> <strong>Mensagem de Voz</strong></p>
|
||||
|
||||
<p>Para fins de desempenho, as imagens são otimizadas e enviadas em um tamanho menor por padrão, mas você pode enviá-las como um “arquivo” para preservar o original.</p>
|
||||
|
||||
<h3 id="multiple-accounts">
|
||||
|
||||
|
||||
@@ -409,6 +396,32 @@ Não são enviadas notificações e não há limite de tempo.</p>
|
||||
<p>Observe que a mensagem original ainda pode ser recebida pelos membros do conversa
|
||||
que podem ter respondido, encaminhado, salvo, capturado a tela ou copiado a mensagem.</p>
|
||||
|
||||
<h3 id="mediaquality">
|
||||
|
||||
|
||||
How is media quality handled? <a href="#mediaquality" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Imagens, vídeos, arquivos, mensagens de voz etc. podem ser enviados usando os botões de<img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Anexo-</strong>
|
||||
ou <img style="vertical-align:middle; width:0.8em; margin:1px" src="../mic.png" alt="Microphone" /> <strong>Mensagem de Voz</strong></p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>By default, compression ensures <strong>fast, efficient delivery</strong> that respects everyone’s data limits and storage.
|
||||
This is ideal for everyday communication.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>In regions with worse connectivity,
|
||||
you can choose higher compression at <strong>Settings → Chats → Outgoing Media Quality</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>If you specifically need to send media in its <strong>original quality</strong>, use <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Attach → File</strong> in the chat.
|
||||
Please use this method sparingly, as sending original files will significantly increase data usage for you and all recipients in the chat.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="ephemeralmsgs">
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
<li><a href="#howtoe2ee">Как найти людей для общения?</a></li>
|
||||
<li><a href="#почему-чат-помечен-как-запрос">Почему чат помечен как “Запрос”?</a></li>
|
||||
<li><a href="#как-я-могу-связать-двух-своих-друзей-друг-с-другом">Как я могу связать двух своих друзей друг с другом?</a></li>
|
||||
<li><a href="#поддерживает-ли-delta-chat-изображения-видео-и-другие-вложения">Поддерживает ли Delta Chat изображения, видео и другие вложения?</a></li>
|
||||
<li><a href="#multiple-accounts">Что такое профили? Как я могу переключатся между ними?</a></li>
|
||||
<li><a href="#кто-видит-изображение-моего-профиля">Кто видит изображение моего профиля?</a></li>
|
||||
<li><a href="#signature">Могу ли я установить статус/подпись в Delta Chat?</a></li>
|
||||
@@ -14,6 +13,7 @@
|
||||
<li><a href="#что-означает-зеленая-точка">Что означает зеленая точка?</a></li>
|
||||
<li><a href="#что-означают-галочки-рядом-с-исходящими-сообщениями">Что означают галочки рядом с исходящими сообщениями?</a></li>
|
||||
<li><a href="#edit">Исправление опечаток и удаление сообщений после отправки</a></li>
|
||||
<li><a href="#mediaquality">Как обеспечивается качество мультимедиа?</a></li>
|
||||
<li><a href="#ephemeralmsgs">Как работают исчезающие сообщения?</a></li>
|
||||
<li><a href="#delold">Что произойдет, если я включу функцию “Удалять сообщения с устройства”?</a></li>
|
||||
<li><a href="#remove-account">Как удалить свой профиль в чате?</a></li>
|
||||
@@ -214,19 +214,6 @@
|
||||
<p>Второй контакт получит <strong>карточку</strong>
|
||||
на которую можно нажать, чтобы начать общение с первым контактом.</p>
|
||||
|
||||
<h3 id="поддерживает-ли-delta-chat-изображения-видео-и-другие-вложения">
|
||||
|
||||
|
||||
Поддерживает ли Delta Chat изображения, видео и другие вложения? <a href="#поддерживает-ли-delta-chat-изображения-видео-и-другие-вложения" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Да. Изображения, видео, файлы, голосовые сообщения и т.д. можно отправлять с помощью кнопок <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Вложение</strong>
|
||||
или <img style="vertical-align:middle; width:0.8em; margin:1px" src="../mic.png" alt="Microphone" /> <strong>Голосовое сообщение</strong>.</p>
|
||||
|
||||
<p>Для повышения производительности, изображения оптимизируются и отправляются по умолчанию в уменьшенном размере, но вы можете отправить их как “файл”, чтобы сохранить оригинал.</p>
|
||||
|
||||
<h3 id="multiple-accounts">
|
||||
|
||||
|
||||
@@ -406,6 +393,32 @@
|
||||
<p>Обратите внимание, что исходное сообщение все еще может быть получено участниками чата
|
||||
которые могли уже ответить, переслать, сохранить, сделать скриншот или иным образом скопировать сообщение.</p>
|
||||
|
||||
<h3 id="mediaquality">
|
||||
|
||||
|
||||
Как обеспечивается качество мультимедиа? <a href="#mediaquality" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Изображения, видео, файлы, голосовые сообщения и т.д. можно отправлять с помощью кнопок <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Вложение</strong>
|
||||
или <img style="vertical-align:middle; width:0.8em; margin:1px" src="../mic.png" alt="Microphone" /> <strong>Голосовое сообщение</strong>.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>По умолчанию сжатие обеспечивает <strong>быструю и эффективную доставку</strong> сообщений, учитывая ограничения по объему данных и хранилищу у всех пользователей.
|
||||
Это идеально подходит для повседневного общения.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>В регионах с плохим качеством связи,
|
||||
вы можете выбрать более высокую степень сжатия в меню <strong>Настройки → Чаты → Качество отправляемых медиафайлов</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Если вам необходимо отправить мультимедийный файл в <strong>исходном качестве</strong>, используйте значок <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Прикрепить → Файл</strong> в чате.
|
||||
Используйте этот метод с осторожностью, так как отправка файлов в исходном качестве значительно увеличит объем трафика как для вас, так и для всех участников чата.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="ephemeralmsgs">
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
<li><a href="#howtoe2ee">How can I find people to chat with?</a></li>
|
||||
<li><a href="#why-is-a-chat-marked-as-request">Why is a chat marked as “Request”?</a></li>
|
||||
<li><a href="#how-can-i-put-two-of-my-friends-in-contact-with-each-other">How can I put two of my friends in contact with each other?</a></li>
|
||||
<li><a href="#podporuje-delta-chat-obrázky-videá-a-iné-prílohy">Podporuje Delta Chat obrázky, videá a iné prílohy?</a></li>
|
||||
<li><a href="#multiple-accounts">What are profiles? How can I switch between them?</a></li>
|
||||
<li><a href="#kto-vidí-moju-profilovú-fotku">Kto vidí moju profilovú fotku?</a></li>
|
||||
<li><a href="#signature">Can I set a Bio/Status with Delta Chat?</a></li>
|
||||
@@ -14,6 +13,7 @@
|
||||
<li><a href="#what-does-the-green-dot-mean">What does the green dot mean?</a></li>
|
||||
<li><a href="#čo-znamenajú-zaškrtnutia-zobrazené-vedľa-odchádzajúcich-správ">Čo znamenajú zaškrtnutia zobrazené vedľa odchádzajúcich správ?</a></li>
|
||||
<li><a href="#edit">Correct typos and delete messages after sending</a></li>
|
||||
<li><a href="#mediaquality">How is media quality handled?</a></li>
|
||||
<li><a href="#ephemeralmsgs">How do disappearing messages work?</a></li>
|
||||
<li><a href="#delold">What happens if I turn on “Delete Messages from Device”?</a></li>
|
||||
<li><a href="#remove-account">How can I delete my chat profile?</a></li>
|
||||
@@ -218,19 +218,6 @@ You can also add a little introduction message.</p>
|
||||
<p>The second contact will receive a <strong>card</strong> then
|
||||
and can tap it to start chatting with the first contact.</p>
|
||||
|
||||
<h3 id="podporuje-delta-chat-obrázky-videá-a-iné-prílohy">
|
||||
|
||||
|
||||
Podporuje Delta Chat obrázky, videá a iné prílohy? <a href="#podporuje-delta-chat-obrázky-videá-a-iné-prílohy" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Yes. Images, videos, files, voice messages etc. can be sent using the <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Attachment-</strong>
|
||||
or <img style="vertical-align:middle; width:0.8em; margin:1px" src="../mic.png" alt="Microphone" /> <strong>Voice Message</strong> buttons</p>
|
||||
|
||||
<p>For performance, images are optimized and sent at a smaller size by default, but you can send it as a “file” to preserve the original.</p>
|
||||
|
||||
<h3 id="multiple-accounts">
|
||||
|
||||
|
||||
@@ -411,6 +398,32 @@ Notifications are not sent and there is no time limit.</p>
|
||||
<p>Note, that the original message may still be received by chat members
|
||||
who could have already replied, forwarded, saved, screenshotted or otherwise copied the message.</p>
|
||||
|
||||
<h3 id="mediaquality">
|
||||
|
||||
|
||||
How is media quality handled? <a href="#mediaquality" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Images, videos, files, voice messages etc. can be sent using the <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Attach-</strong>
|
||||
or <img style="vertical-align:middle; width:0.8em; margin:1px" src="../mic.png" alt="Microphone" /> <strong>Voice Message</strong> buttons.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>By default, compression ensures <strong>fast, efficient delivery</strong> that respects everyone’s data limits and storage.
|
||||
This is ideal for everyday communication.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>In regions with worse connectivity,
|
||||
you can choose higher compression at <strong>Settings → Chats → Outgoing Media Quality</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>If you specifically need to send media in its <strong>original quality</strong>, use <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Attach → File</strong> in the chat.
|
||||
Please use this method sparingly, as sending original files will significantly increase data usage for you and all recipients in the chat.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="ephemeralmsgs">
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
<li><a href="#howtoe2ee">How can I find people to chat with?</a></li>
|
||||
<li><a href="#why-is-a-chat-marked-as-request">Why is a chat marked as “Request”?</a></li>
|
||||
<li><a href="#how-can-i-put-two-of-my-friends-in-contact-with-each-other">How can I put two of my friends in contact with each other?</a></li>
|
||||
<li><a href="#a-mbulon-delta-chat-i-figura-video-dhe-bashkëngjitje-të-tjera">A mbulon Delta Chat-i figura, video dhe bashkëngjitje të tjera?</a></li>
|
||||
<li><a href="#multiple-accounts">What are profiles? How can I switch between them?</a></li>
|
||||
<li><a href="#kush-e-sheh-profilin-tim">Kush e sheh profilin tim?</a></li>
|
||||
<li><a href="#signature">Can I set a Bio/Status with Delta Chat?</a></li>
|
||||
@@ -14,6 +13,7 @@
|
||||
<li><a href="#çdo-të-thotë-pika-e-gjelbër">Ç’do të thotë pika e gjelbër?</a></li>
|
||||
<li><a href="#çduan-të-thonë-shenjat-e-shfaqura-pas-mesazheve-që-dërgohen">Ç’duan të thonë shenjat e shfaqura pas mesazheve që dërgohen?</a></li>
|
||||
<li><a href="#edit">Correct typos and delete messages after sending</a></li>
|
||||
<li><a href="#mediaquality">How is media quality handled?</a></li>
|
||||
<li><a href="#ephemeralmsgs">How do disappearing messages work?</a></li>
|
||||
<li><a href="#delold">Ç’ndodh, nëse aktivizoj “Fshi prej pajisjes mesazhe të vjetër”?</a></li>
|
||||
<li><a href="#remove-account">How can I delete my chat profile?</a></li>
|
||||
@@ -218,19 +218,6 @@ You can also add a little introduction message.</p>
|
||||
<p>The second contact will receive a <strong>card</strong> then
|
||||
and can tap it to start chatting with the first contact.</p>
|
||||
|
||||
<h3 id="a-mbulon-delta-chat-i-figura-video-dhe-bashkëngjitje-të-tjera">
|
||||
|
||||
|
||||
A mbulon Delta Chat-i figura, video dhe bashkëngjitje të tjera? <a href="#a-mbulon-delta-chat-i-figura-video-dhe-bashkëngjitje-të-tjera" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Po Images, videos, files, voice messages etc. can be sent using the <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Attachment-</strong>
|
||||
or <img style="vertical-align:middle; width:0.8em; margin:1px" src="../mic.png" alt="Microphone" /> <strong>Voice Message</strong> buttons</p>
|
||||
|
||||
<p>Si parazgjedhje, për funksionim më të mirë, figurat optimizohen dhe dërgohen në madhësi më të vogël, por mund ta dërgoni si një “kartelë”, që të ruhet origjinali.</p>
|
||||
|
||||
<h3 id="multiple-accounts">
|
||||
|
||||
|
||||
@@ -410,6 +397,32 @@ Notifications are not sent and there is no time limit.</p>
|
||||
<p>Note, that the original message may still be received by chat members
|
||||
who could have already replied, forwarded, saved, screenshotted or otherwise copied the message.</p>
|
||||
|
||||
<h3 id="mediaquality">
|
||||
|
||||
|
||||
How is media quality handled? <a href="#mediaquality" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Images, videos, files, voice messages etc. can be sent using the <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Attach-</strong>
|
||||
or <img style="vertical-align:middle; width:0.8em; margin:1px" src="../mic.png" alt="Microphone" /> <strong>Voice Message</strong> buttons.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>By default, compression ensures <strong>fast, efficient delivery</strong> that respects everyone’s data limits and storage.
|
||||
This is ideal for everyday communication.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>In regions with worse connectivity,
|
||||
you can choose higher compression at <strong>Settings → Chats → Outgoing Media Quality</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>If you specifically need to send media in its <strong>original quality</strong>, use <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Attach → File</strong> in the chat.
|
||||
Please use this method sparingly, as sending original files will significantly increase data usage for you and all recipients in the chat.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="ephemeralmsgs">
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
<li><a href="#howtoe2ee">Як мені знайти людей для спілкування?</a></li>
|
||||
<li><a href="#why-is-a-chat-marked-as-request">Why is a chat marked as “Request”?</a></li>
|
||||
<li><a href="#how-can-i-put-two-of-my-friends-in-contact-with-each-other">How can I put two of my friends in contact with each other?</a></li>
|
||||
<li><a href="#чи-підтримує-delta-chat-вкладення-у-вигляді-фото-відео-тощо">Чи підтримує Delta Chat вкладення у вигляді фото, відео тощо?</a></li>
|
||||
<li><a href="#multiple-accounts">Що таке профілі? Як я можу перемикатися між ними?</a></li>
|
||||
<li><a href="#хто-бачить-моє-зображення-профілю">Хто бачить моє зображення профілю?</a></li>
|
||||
<li><a href="#signature">Чи можу я встановити біографію/статус у Delta Chat?</a></li>
|
||||
@@ -14,6 +13,7 @@
|
||||
<li><a href="#що-означає-зелена-точка">Що означає зелена точка?</a></li>
|
||||
<li><a href="#що-означають-галочки-біля-вихідних-повідомлень">Що означають галочки біля вихідних повідомлень?</a></li>
|
||||
<li><a href="#edit">Виправлення помилок та видалення повідомлень після надсилання</a></li>
|
||||
<li><a href="#mediaquality">How is media quality handled?</a></li>
|
||||
<li><a href="#ephemeralmsgs">Як працюють повідомлення, що зникають?</a></li>
|
||||
<li><a href="#delold">Що станеться, якщо я ввімкну «Видаляти старі повідомлення з пристрою»?</a></li>
|
||||
</ul>
|
||||
@@ -204,19 +204,6 @@ You can also add a little introduction message.</p>
|
||||
<p>The second contact will receive a <strong>card</strong> then
|
||||
and can tap it to start chatting with the first contact.</p>
|
||||
|
||||
<h3 id="чи-підтримує-delta-chat-вкладення-у-вигляді-фото-відео-тощо">
|
||||
|
||||
|
||||
Чи підтримує Delta Chat вкладення у вигляді фото, відео тощо? <a href="#чи-підтримує-delta-chat-вкладення-у-вигляді-фото-відео-тощо" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Так. Images, videos, files, voice messages etc. can be sent using the <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Attachment-</strong>
|
||||
or <img style="vertical-align:middle; width:0.8em; margin:1px" src="../mic.png" alt="Microphone" /> <strong>Voice Message</strong> buttons</p>
|
||||
|
||||
<p>З міркувань продуктивності, зображення оптимізовані та надсилаються в меншому розмірі за замовчуванням, але ви можете надіслати їх як «файл», щоб зберегти оригінал.</p>
|
||||
|
||||
<h3 id="multiple-accounts">
|
||||
|
||||
|
||||
@@ -381,6 +368,32 @@ has <strong>Settings → Chats → Read Receipts</strong> enabled.</p>
|
||||
|
||||
<p>Зауважте, що початкове повідомлення все ще може бути отримане учасниками чату які могли вже відповісти, переслати, зберегти, зробити знімок екрану або іншим чином скопіювати повідомлення.</p>
|
||||
|
||||
<h3 id="mediaquality">
|
||||
|
||||
|
||||
How is media quality handled? <a href="#mediaquality" class="anchor"></a>
|
||||
|
||||
|
||||
</h3>
|
||||
|
||||
<p>Images, videos, files, voice messages etc. can be sent using the <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Attach-</strong>
|
||||
or <img style="vertical-align:middle; width:0.8em; margin:1px" src="../mic.png" alt="Microphone" /> <strong>Voice Message</strong> buttons.</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>By default, compression ensures <strong>fast, efficient delivery</strong> that respects everyone’s data limits and storage.
|
||||
This is ideal for everyday communication.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>In regions with worse connectivity,
|
||||
you can choose higher compression at <strong>Settings → Chats → Outgoing Media Quality</strong>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>If you specifically need to send media in its <strong>original quality</strong>, use <img style="vertical-align:middle; width:1.0em; margin:1px" src="../paperclip.png" alt="Paperclip" /> <strong>Attach → File</strong> in the chat.
|
||||
Please use this method sparingly, as sending original files will significantly increase data usage for you and all recipients in the chat.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="ephemeralmsgs">
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -14,7 +14,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
/* Basic RPC Transport implementation */
|
||||
public abstract class BaseTransport implements Rpc.Transport {
|
||||
public abstract class BaseRpcTransport implements Rpc.RpcTransport {
|
||||
private final Map<Integer, SettableFuture<JsonNode>> requestFutures = new ConcurrentHashMap<>();
|
||||
private int requestId = 0;
|
||||
private final ObjectMapper mapper = new ObjectMapper();
|
||||
@@ -9,16 +9,16 @@ import chat.delta.rpc.types.*;
|
||||
|
||||
public class Rpc {
|
||||
|
||||
public interface Transport {
|
||||
public interface RpcTransport {
|
||||
void call(String method, JsonNode... params) throws RpcException;
|
||||
<T> T callForResult(TypeReference<T> resultType, String method, JsonNode... params) throws RpcException;
|
||||
ObjectMapper getObjectMapper();
|
||||
}
|
||||
|
||||
public final Transport transport;
|
||||
public final RpcTransport transport;
|
||||
private final ObjectMapper mapper;
|
||||
|
||||
public Rpc(Transport transport) {
|
||||
public Rpc(RpcTransport transport) {
|
||||
this.transport = transport;
|
||||
this.mapper = transport.getObjectMapper();
|
||||
}
|
||||
@@ -289,6 +289,7 @@ public class Rpc {
|
||||
* from a server encoded in a QR code.
|
||||
* - [Self::list_transports()] to get a list of all configured transports.
|
||||
* - [Self::delete_transport()] to remove a transport.
|
||||
* - [Self::set_transport_unpublished()] to set whether contacts see this transport.
|
||||
*/
|
||||
public void addOrUpdateTransport(Integer accountId, EnteredLoginParam param) throws RpcException {
|
||||
transport.call("add_or_update_transport", mapper.valueToTree(accountId), mapper.valueToTree(param));
|
||||
@@ -312,11 +313,22 @@ public class Rpc {
|
||||
* Returns the list of all email accounts that are used as a transport in the current profile.
|
||||
* Use [Self::add_or_update_transport()] to add or change a transport
|
||||
* and [Self::delete_transport()] to delete a transport.
|
||||
* Use [Self::list_transports_ex()] to additionally query
|
||||
* whether the transports are marked as 'unpublished'.
|
||||
*/
|
||||
public java.util.List<EnteredLoginParam> listTransports(Integer accountId) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<java.util.List<EnteredLoginParam>>(){}, "list_transports", mapper.valueToTree(accountId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of all email accounts that are used as a transport in the current profile.
|
||||
* Use [Self::add_or_update_transport()] to add or change a transport
|
||||
* and [Self::delete_transport()] to delete a transport.
|
||||
*/
|
||||
public java.util.List<TransportListEntry> listTransportsEx(Integer accountId) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<java.util.List<TransportListEntry>>(){}, "list_transports_ex", mapper.valueToTree(accountId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the transport with the specified email address
|
||||
* (i.e. [EnteredLoginParam::addr]).
|
||||
@@ -325,6 +337,22 @@ public class Rpc {
|
||||
transport.call("delete_transport", mapper.valueToTree(accountId), mapper.valueToTree(addr));
|
||||
}
|
||||
|
||||
/**
|
||||
* Change whether the transport is unpublished.
|
||||
* <p>
|
||||
* Unpublished transports are not advertised to contacts,
|
||||
* and self-sent messages are not sent there,
|
||||
* so that we don't cause extra messages to the corresponding inbox,
|
||||
* but can still receive messages from contacts who don't know our new transport addresses yet.
|
||||
* <p>
|
||||
* The default is false, but when the user updates from a version that didn't have this flag,
|
||||
* existing secondary transports are set to unpublished,
|
||||
* so that an existing transport address doesn't suddenly get spammed with a lot of messages.
|
||||
*/
|
||||
public void setTransportUnpublished(Integer accountId, String addr, Boolean unpublished) throws RpcException {
|
||||
transport.call("set_transport_unpublished", mapper.valueToTree(accountId), mapper.valueToTree(addr), mapper.valueToTree(unpublished));
|
||||
}
|
||||
|
||||
/** Signal an ongoing process to stop. */
|
||||
public void stopOngoingProcess(Integer accountId) throws RpcException {
|
||||
transport.call("stop_ongoing_process", mapper.valueToTree(accountId));
|
||||
@@ -410,14 +438,6 @@ public class Rpc {
|
||||
return transport.callForResult(new TypeReference<Integer>(){}, "estimate_auto_deletion_count", mapper.valueToTree(accountId), mapper.valueToTree(fromServer), mapper.valueToTree(seconds));
|
||||
}
|
||||
|
||||
public String initiateAutocryptKeyTransfer(Integer accountId) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<String>(){}, "initiate_autocrypt_key_transfer", mapper.valueToTree(accountId));
|
||||
}
|
||||
|
||||
public void continueAutocryptKeyTransfer(Integer accountId, Integer messageId, String setupCode) throws RpcException {
|
||||
transport.call("continue_autocrypt_key_transfer", mapper.valueToTree(accountId), mapper.valueToTree(messageId), mapper.valueToTree(setupCode));
|
||||
}
|
||||
|
||||
public java.util.List<Integer> getChatlistEntries(Integer accountId, Integer listFlags, String queryString, Integer queryContactId) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<java.util.List<Integer>>(){}, "get_chatlist_entries", mapper.valueToTree(accountId), mapper.valueToTree(listFlags), mapper.valueToTree(queryString), mapper.valueToTree(queryContactId));
|
||||
}
|
||||
@@ -509,6 +529,8 @@ public class Rpc {
|
||||
* if `checkQr()` returns `askVerifyContact` or `askVerifyGroup`
|
||||
* an out-of-band-verification can be joined using `secure_join()`
|
||||
* <p>
|
||||
* @deprecated as of 2026-03; use create_qr_svg(get_chat_securejoin_qr_code()) instead.
|
||||
* <p>
|
||||
* chat_id: If set to a group-chat-id,
|
||||
* the Verified-Group-Invite protocol is offered in the QR code;
|
||||
* works for protected groups as well as for normal groups.
|
||||
@@ -1211,12 +1233,19 @@ public class Rpc {
|
||||
* even if there is no concurrent call to [`CommandApi::provide_backup`],
|
||||
* but will fail after 60 seconds to avoid deadlocks.
|
||||
* <p>
|
||||
* @deprecated as of 2026-03; use `create_qr_svg(get_backup_qr())` instead.
|
||||
* <p>
|
||||
* Returns the QR code rendered as an SVG image.
|
||||
*/
|
||||
public String getBackupQrSvg(Integer accountId) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<String>(){}, "get_backup_qr_svg", mapper.valueToTree(accountId));
|
||||
}
|
||||
|
||||
/** Renders the given text as a QR code SVG image. */
|
||||
public String createQrSvg(String text) throws RpcException {
|
||||
return transport.callForResult(new TypeReference<String>(){}, "create_qr_svg", mapper.valueToTree(text));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a backup from a remote provider.
|
||||
* <p>
|
||||
|
||||
@@ -387,6 +387,8 @@ public abstract class EventType {
|
||||
public static class IncomingCallAccepted extends EventType {
|
||||
/** ID of the chat which the message belongs to. */
|
||||
public Integer chat_id;
|
||||
/** The call was accepted from this device (process). */
|
||||
public Boolean from_this_device;
|
||||
/** ID of the info message referring to the call. */
|
||||
public Integer msg_id;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ public class Message {
|
||||
public Boolean isEdited;
|
||||
public Boolean isForwarded;
|
||||
public Boolean isInfo;
|
||||
public Boolean isSetupmessage;
|
||||
@com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
|
||||
public Integer originalMsgId;
|
||||
@com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
|
||||
@@ -47,8 +46,6 @@ public class Message {
|
||||
@com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
|
||||
public Integer savedMessageId;
|
||||
public Contact sender;
|
||||
@com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
|
||||
public String setupCodeBegin;
|
||||
/**
|
||||
* True if the message was correctly encrypted&signed, false otherwise. Historically, UIs showed a small padlock on the message then.
|
||||
* <p>
|
||||
|
||||
@@ -42,7 +42,6 @@ public abstract class MessageLoadResult {
|
||||
public Boolean isEdited;
|
||||
public Boolean isForwarded;
|
||||
public Boolean isInfo;
|
||||
public Boolean isSetupmessage;
|
||||
@com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
|
||||
public Integer originalMsgId;
|
||||
@com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
|
||||
@@ -57,8 +56,6 @@ public abstract class MessageLoadResult {
|
||||
@com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
|
||||
public Integer savedMessageId;
|
||||
public Contact sender;
|
||||
@com.fasterxml.jackson.annotation.JsonSetter(nulls = com.fasterxml.jackson.annotation.Nulls.SET)
|
||||
public String setupCodeBegin;
|
||||
/**
|
||||
* True if the message was correctly encrypted&signed, false otherwise. Historically, UIs showed a small padlock on the message then.
|
||||
* <p>
|
||||
|
||||
@@ -25,6 +25,8 @@ public abstract class Qr {
|
||||
public String fingerprint;
|
||||
/** Invite number. */
|
||||
public String invitenumber;
|
||||
/** Whether the inviter supports the new Securejoin v3 protocol */
|
||||
public Boolean is_v3;
|
||||
}
|
||||
|
||||
/** Ask the user whether to join the group. */
|
||||
@@ -41,6 +43,8 @@ public abstract class Qr {
|
||||
public String grpname;
|
||||
/** Invite number. */
|
||||
public String invitenumber;
|
||||
/** Whether the inviter supports the new Securejoin v3 protocol */
|
||||
public Boolean is_v3;
|
||||
}
|
||||
|
||||
/** Ask the user whether to join the broadcast channel. */
|
||||
@@ -55,6 +59,8 @@ public abstract class Qr {
|
||||
public String grpid;
|
||||
/** Invite number. */
|
||||
public String invitenumber;
|
||||
/** Whether the inviter supports the new Securejoin v3 protocol */
|
||||
public Boolean is_v3;
|
||||
/** The user-visible name of this broadcast channel */
|
||||
public String name;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
/* Autogenerated file, do not edit manually */
|
||||
package chat.delta.rpc.types;
|
||||
|
||||
public class TransportListEntry {
|
||||
/** Whether this transport is set to 'unpublished'. See `set_transport_unpublished` / `setTransportUnpublished` for details. */
|
||||
public Boolean isUnpublished;
|
||||
/** The login data entered by the user. */
|
||||
public EnteredLoginParam param;
|
||||
}
|
||||
@@ -176,8 +176,6 @@ public class DcContext {
|
||||
|
||||
public native String getConnectivityHtml();
|
||||
|
||||
public native String initiateKeyTransfer();
|
||||
|
||||
public native void imex(int what, String dir);
|
||||
|
||||
public native String imexHasBackup(String dir);
|
||||
|
||||
@@ -25,7 +25,6 @@ public class DcMsg {
|
||||
public static final int DC_INFO_GROUP_IMAGE_CHANGED = 3;
|
||||
public static final int DC_INFO_MEMBER_ADDED_TO_GROUP = 4;
|
||||
public static final int DC_INFO_MEMBER_REMOVED_FROM_GROUP = 5;
|
||||
public static final int DC_INFO_AUTOCRYPT_SETUP_MESSAGE = 6;
|
||||
public static final int DC_INFO_SECURE_JOIN_MESSAGE = 7;
|
||||
public static final int DC_INFO_LOCATIONSTREAMING_ENABLED = 8;
|
||||
public static final int DC_INFO_LOCATION_ONLY = 9;
|
||||
@@ -191,8 +190,6 @@ public class DcMsg {
|
||||
|
||||
public native boolean hasHtml();
|
||||
|
||||
public native String getSetupCodeBegin();
|
||||
|
||||
public native void setText(String text);
|
||||
|
||||
public native void setSubject(String text);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package com.b44t.messenger;
|
||||
|
||||
import chat.delta.rpc.BaseTransport;
|
||||
import chat.delta.rpc.BaseRpcTransport;
|
||||
|
||||
/* RPC transport over C FFI */
|
||||
public class FFITransport extends BaseTransport {
|
||||
public class FFITransport extends BaseRpcTransport {
|
||||
private final DcJsonrpcInstance dcJsonrpcInstance;
|
||||
|
||||
public FFITransport(DcJsonrpcInstance dcJsonrpcInstance) {
|
||||
|
||||
@@ -9,7 +9,6 @@ import android.net.LinkProperties;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.core.app.NotificationManagerCompat;
|
||||
@@ -19,14 +18,19 @@ import androidx.work.ExistingPeriodicWorkPolicy;
|
||||
import androidx.work.NetworkType;
|
||||
import androidx.work.PeriodicWorkRequest;
|
||||
import androidx.work.WorkManager;
|
||||
|
||||
import chat.delta.rpc.Rpc;
|
||||
import chat.delta.rpc.RpcException;
|
||||
import com.b44t.messenger.DcAccounts;
|
||||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.DcEvent;
|
||||
import com.b44t.messenger.DcEventChannel;
|
||||
import com.b44t.messenger.DcEventEmitter;
|
||||
import com.b44t.messenger.FFITransport;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.thoughtcrime.securesms.calls.CallCoordinator;
|
||||
import org.thoughtcrime.securesms.connect.AccountManager;
|
||||
import org.thoughtcrime.securesms.connect.DcEventCenter;
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
@@ -48,35 +52,27 @@ import org.thoughtcrime.securesms.util.SignalProtocolLoggerProvider;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.webxdc.WebxdcGarbageCollectionWorker;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import chat.delta.rpc.Rpc;
|
||||
import chat.delta.rpc.RpcException;
|
||||
|
||||
public class ApplicationContext extends MultiDexApplication {
|
||||
private static final String TAG = ApplicationContext.class.getSimpleName();
|
||||
private static final Object initLock = new Object();
|
||||
private static volatile boolean isInitialized = false;
|
||||
|
||||
private static DcAccounts dcAccounts;
|
||||
private Rpc rpc;
|
||||
private DcContext dcContext;
|
||||
private static DcAccounts dcAccounts;
|
||||
private Rpc rpc;
|
||||
private DcContext dcContext;
|
||||
|
||||
private DcLocationManager dcLocationManager;
|
||||
private DcEventCenter eventCenter;
|
||||
private NotificationCenter notificationCenter;
|
||||
private JobManager jobManager;
|
||||
private DcLocationManager dcLocationManager;
|
||||
private DcEventCenter eventCenter;
|
||||
private NotificationCenter notificationCenter;
|
||||
private JobManager jobManager;
|
||||
|
||||
private int debugOnAvailableCount;
|
||||
private int debugOnBlockedStatusChangedCount;
|
||||
private int debugOnCapabilitiesChangedCount;
|
||||
private int debugOnLinkPropertiesChangedCount;
|
||||
private int debugOnAvailableCount;
|
||||
private int debugOnBlockedStatusChangedCount;
|
||||
private int debugOnCapabilitiesChangedCount;
|
||||
private int debugOnLinkPropertiesChangedCount;
|
||||
|
||||
public static ApplicationContext getInstance(@NonNull Context context) {
|
||||
return (ApplicationContext)context.getApplicationContext();
|
||||
return (ApplicationContext) context.getApplicationContext();
|
||||
}
|
||||
|
||||
private static void ensureInitialized() {
|
||||
@@ -93,8 +89,8 @@ public class ApplicationContext extends MultiDexApplication {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get DcAccounts instance, waiting for initialization if necessary.
|
||||
* This method is thread-safe and will block until initialization is complete.
|
||||
* Get DcAccounts instance, waiting for initialization if necessary. This method is thread-safe
|
||||
* and will block until initialization is complete.
|
||||
*/
|
||||
public static DcAccounts getDcAccounts() {
|
||||
ensureInitialized();
|
||||
@@ -102,8 +98,8 @@ public class ApplicationContext extends MultiDexApplication {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Rpc instance, waiting for initialization if necessary.
|
||||
* This method is thread-safe and will block until initialization is complete.
|
||||
* Get Rpc instance, waiting for initialization if necessary. This method is thread-safe and will
|
||||
* block until initialization is complete.
|
||||
*/
|
||||
public Rpc getRpc() {
|
||||
ensureInitialized();
|
||||
@@ -111,8 +107,8 @@ public class ApplicationContext extends MultiDexApplication {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get DcContext instance, waiting for initialization if necessary.
|
||||
* This method is thread-safe and will block until initialization is complete.
|
||||
* Get DcContext instance, waiting for initialization if necessary. This method is thread-safe and
|
||||
* will block until initialization is complete.
|
||||
*/
|
||||
public DcContext getDcContext() {
|
||||
ensureInitialized();
|
||||
@@ -121,8 +117,8 @@ public class ApplicationContext extends MultiDexApplication {
|
||||
|
||||
/**
|
||||
* Set DcContext instance. This should only be called by AccountManager when switching accounts,
|
||||
* which only happens after initial initialization is complete.
|
||||
* This method is thread-safe but does NOT trigger initialization or notify waiting threads.
|
||||
* which only happens after initial initialization is complete. This method is thread-safe but
|
||||
* does NOT trigger initialization or notify waiting threads.
|
||||
*/
|
||||
public void setDcContext(DcContext dcContext) {
|
||||
synchronized (initLock) {
|
||||
@@ -131,8 +127,8 @@ public class ApplicationContext extends MultiDexApplication {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get DcLocationManager instance, waiting for initialization if necessary.
|
||||
* This method is thread-safe and will block until initialization is complete.
|
||||
* Get DcLocationManager instance, waiting for initialization if necessary. This method is
|
||||
* thread-safe and will block until initialization is complete.
|
||||
*/
|
||||
public DcLocationManager getLocationManager() {
|
||||
ensureInitialized();
|
||||
@@ -140,8 +136,8 @@ public class ApplicationContext extends MultiDexApplication {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get DcEventCenter instance, waiting for initialization if necessary.
|
||||
* This method is thread-safe and will block until initialization is complete.
|
||||
* Get DcEventCenter instance, waiting for initialization if necessary. This method is thread-safe
|
||||
* and will block until initialization is complete.
|
||||
*/
|
||||
public DcEventCenter getEventCenter() {
|
||||
ensureInitialized();
|
||||
@@ -149,8 +145,8 @@ public class ApplicationContext extends MultiDexApplication {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get NotificationCenter instance, waiting for initialization if necessary.
|
||||
* This method is thread-safe and will block until initialization is complete.
|
||||
* Get NotificationCenter instance, waiting for initialization if necessary. This method is
|
||||
* thread-safe and will block until initialization is complete.
|
||||
*/
|
||||
public NotificationCenter getNotificationCenter() {
|
||||
ensureInitialized();
|
||||
@@ -161,26 +157,30 @@ public class ApplicationContext extends MultiDexApplication {
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
throwable.printStackTrace(new PrintWriter(stringWriter, true));
|
||||
String errorMsg = "Android " + Build.VERSION.RELEASE +":\n" + stringWriter.getBuffer().toString();
|
||||
errorMsg += "\n" + LogViewFragment.grabLogcat();
|
||||
String subject = "ArcaneChat " + BuildConfig.VERSION_NAME + "-" + BuildConfig.FLAVOR + " Crash Report";
|
||||
Intent intent = new Intent(android.content.Intent.ACTION_SEND);
|
||||
intent.setType("text/plain");
|
||||
intent.putExtra(android.content.Intent.EXTRA_SUBJECT, subject);
|
||||
intent.putExtra(android.content.Intent.EXTRA_TEXT, subject + "\n\n" + errorMsg);
|
||||
intent.putExtra(Intent.EXTRA_EMAIL, "adb@merlinux.eu");
|
||||
Intent chooser = Intent.createChooser(intent, subject);
|
||||
chooser.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
chooser.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
|
||||
startActivity(chooser);
|
||||
Thread.setDefaultUncaughtExceptionHandler(
|
||||
(thread, throwable) -> {
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
throwable.printStackTrace(new PrintWriter(stringWriter, true));
|
||||
String errorMsg =
|
||||
"Android " + Build.VERSION.RELEASE + ":\n" + stringWriter.getBuffer().toString();
|
||||
errorMsg += "\n" + LogViewFragment.grabLogcat();
|
||||
String subject =
|
||||
"ArcaneChat " + BuildConfig.VERSION_NAME + "-" + BuildConfig.FLAVOR + " Crash Report";
|
||||
Intent intent = new Intent(android.content.Intent.ACTION_SEND);
|
||||
intent.setType("text/plain");
|
||||
intent.putExtra(android.content.Intent.EXTRA_SUBJECT, subject);
|
||||
intent.putExtra(android.content.Intent.EXTRA_TEXT, subject + "\n\n" + errorMsg);
|
||||
intent.putExtra(Intent.EXTRA_EMAIL, "adb@merlinux.eu");
|
||||
Intent chooser = Intent.createChooser(intent, subject);
|
||||
chooser.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
chooser.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
|
||||
startActivity(chooser);
|
||||
|
||||
try {
|
||||
ApplicationContext.this.finalize();
|
||||
} catch (Throwable e) {}
|
||||
});
|
||||
try {
|
||||
ApplicationContext.this.finalize();
|
||||
} catch (Throwable e) {
|
||||
}
|
||||
});
|
||||
|
||||
// if (LeakCanary.isInAnalyzerProcess(this)) {
|
||||
// // This process is dedicated to LeakCanary for heap analysis.
|
||||
@@ -194,90 +194,114 @@ public class ApplicationContext extends MultiDexApplication {
|
||||
System.loadLibrary("native-utils");
|
||||
|
||||
// Initialize DcAccounts in background to avoid ANR during SQL migrations
|
||||
Util.runOnBackground(() -> {
|
||||
synchronized (initLock) {
|
||||
try {
|
||||
DcEventChannel eventChannel = new DcEventChannel();
|
||||
DcEventEmitter emitter = eventChannel.getEventEmitter();
|
||||
eventCenter = new DcEventCenter(this);
|
||||
|
||||
new Thread(() -> {
|
||||
Log.i(TAG, "Starting event loop");
|
||||
while (true) {
|
||||
DcEvent event = emitter.getNextEvent();
|
||||
if (event == null) {
|
||||
break;
|
||||
}
|
||||
if (isInitialized) {
|
||||
eventCenter.handleEvent(event);
|
||||
} else {
|
||||
// not fully initialized, only handle logging events,
|
||||
// ex. account migrations during DcAccounts initialization
|
||||
eventCenter.handleLogging(event);
|
||||
}
|
||||
}
|
||||
Log.i("DeltaChat", "shutting down event handler");
|
||||
}, "eventThread").start();
|
||||
|
||||
dcAccounts = new DcAccounts(new File(getFilesDir(), "accounts").getAbsolutePath(), eventChannel);
|
||||
Log.i(TAG, "DcAccounts created");
|
||||
rpc = new Rpc(new FFITransport(dcAccounts.getJsonrpcInstance()));
|
||||
Log.i(TAG, "Rpc created");
|
||||
AccountManager.getInstance().migrateToDcAccounts(this);
|
||||
|
||||
int[] allAccounts = dcAccounts.getAll();
|
||||
Log.i(TAG, "Number of profiles: " + allAccounts.length);
|
||||
for (int accountId : allAccounts) {
|
||||
DcContext ac = dcAccounts.getAccount(accountId);
|
||||
if (!ac.isOpen()) {
|
||||
try {
|
||||
DatabaseSecret secret = DatabaseSecretProvider.getOrCreateDatabaseSecret(this, accountId);
|
||||
boolean res = ac.open(secret.asString());
|
||||
if (res) Log.i(TAG, "Successfully opened account " + accountId + ", path: " + ac.getBlobdir());
|
||||
else Log.e(TAG, "Error opening account " + accountId + ", path: " + ac.getBlobdir());
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Failed to open account " + accountId + ", path: " + ac.getBlobdir() + ": " + e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// 2025-12-16: The setting was removed.
|
||||
// Revert it to the default if it was changed in the past.
|
||||
ac.setConfigInt("webxdc_realtime_enabled", 1);
|
||||
|
||||
// 2025-11-12: this is needed until core starts ignoring "delete_server_after" for chatmail
|
||||
if (ac.isChatmail()) {
|
||||
ac.setConfig("delete_server_after", null); // reset
|
||||
}
|
||||
}
|
||||
if (allAccounts.length == 0) {
|
||||
Util.runOnBackground(
|
||||
() -> {
|
||||
synchronized (initLock) {
|
||||
try {
|
||||
rpc.addAccount();
|
||||
} catch (RpcException e) {
|
||||
e.printStackTrace();
|
||||
DcEventChannel eventChannel = new DcEventChannel();
|
||||
DcEventEmitter emitter = eventChannel.getEventEmitter();
|
||||
eventCenter = new DcEventCenter(this);
|
||||
|
||||
new Thread(
|
||||
() -> {
|
||||
Log.i(TAG, "Starting event loop");
|
||||
while (true) {
|
||||
DcEvent event = emitter.getNextEvent();
|
||||
if (event == null) {
|
||||
break;
|
||||
}
|
||||
if (isInitialized) {
|
||||
eventCenter.handleEvent(event);
|
||||
} else {
|
||||
// not fully initialized, only handle logging events,
|
||||
// ex. account migrations during DcAccounts initialization
|
||||
eventCenter.handleLogging(event);
|
||||
}
|
||||
}
|
||||
Log.i("DeltaChat", "shutting down event handler");
|
||||
},
|
||||
"eventThread")
|
||||
.start();
|
||||
|
||||
dcAccounts =
|
||||
new DcAccounts(
|
||||
new File(getFilesDir(), "accounts").getAbsolutePath(), eventChannel);
|
||||
Log.i(TAG, "DcAccounts created");
|
||||
rpc = new Rpc(new FFITransport(dcAccounts.getJsonrpcInstance()));
|
||||
Log.i(TAG, "Rpc created");
|
||||
AccountManager.getInstance().migrateToDcAccounts(this);
|
||||
|
||||
int[] allAccounts = dcAccounts.getAll();
|
||||
Log.i(TAG, "Number of profiles: " + allAccounts.length);
|
||||
for (int accountId : allAccounts) {
|
||||
DcContext ac = dcAccounts.getAccount(accountId);
|
||||
if (!ac.isOpen()) {
|
||||
try {
|
||||
DatabaseSecret secret =
|
||||
DatabaseSecretProvider.getOrCreateDatabaseSecret(this, accountId);
|
||||
boolean res = ac.open(secret.asString());
|
||||
if (res)
|
||||
Log.i(
|
||||
TAG,
|
||||
"Successfully opened account "
|
||||
+ accountId
|
||||
+ ", path: "
|
||||
+ ac.getBlobdir());
|
||||
else
|
||||
Log.e(
|
||||
TAG, "Error opening account " + accountId + ", path: " + ac.getBlobdir());
|
||||
} catch (Exception e) {
|
||||
Log.e(
|
||||
TAG,
|
||||
"Failed to open account "
|
||||
+ accountId
|
||||
+ ", path: "
|
||||
+ ac.getBlobdir()
|
||||
+ ": "
|
||||
+ e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// 2025-12-16: The setting was removed.
|
||||
// Revert it to the default if it was changed in the past.
|
||||
ac.setConfigInt("webxdc_realtime_enabled", 1);
|
||||
|
||||
// 2025-11-12: this is needed until core starts ignoring "delete_server_after" for
|
||||
// chatmail
|
||||
if (ac.isChatmail()) {
|
||||
ac.setConfig("delete_server_after", null); // reset
|
||||
}
|
||||
}
|
||||
if (allAccounts.length == 0) {
|
||||
try {
|
||||
rpc.addAccount();
|
||||
} catch (RpcException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
dcContext = dcAccounts.getSelectedAccount();
|
||||
notificationCenter = new NotificationCenter(this);
|
||||
dcLocationManager = new DcLocationManager(this, dcContext);
|
||||
|
||||
isInitialized = true;
|
||||
initLock.notifyAll();
|
||||
Log.i(TAG, "DcAccounts initialization complete");
|
||||
|
||||
// set translations before starting I/O to avoid sending untranslated MDNs (issue
|
||||
// #2288)
|
||||
DcHelper.setStockTranslations(this);
|
||||
|
||||
dcAccounts.startIo();
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Fatal error during DcAccounts initialization", e);
|
||||
// Mark as initialized even on error to avoid deadlock
|
||||
isInitialized = true;
|
||||
initLock.notifyAll();
|
||||
throw new RuntimeException("Failed to initialize DcAccounts", e);
|
||||
}
|
||||
}
|
||||
dcContext = dcAccounts.getSelectedAccount();
|
||||
notificationCenter = new NotificationCenter(this);
|
||||
dcLocationManager = new DcLocationManager(this, dcContext);
|
||||
|
||||
isInitialized = true;
|
||||
initLock.notifyAll();
|
||||
Log.i(TAG, "DcAccounts initialization complete");
|
||||
|
||||
// set translations before starting I/O to avoid sending untranslated MDNs (issue #2288)
|
||||
DcHelper.setStockTranslations(this);
|
||||
|
||||
dcAccounts.startIo();
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Fatal error during DcAccounts initialization", e);
|
||||
// Mark as initialized even on error to avoid deadlock
|
||||
isInitialized = true;
|
||||
initLock.notifyAll();
|
||||
throw new RuntimeException("Failed to initialize DcAccounts", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// October-2025 migration: delete deprecated "permanent channel" id
|
||||
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
|
||||
@@ -288,33 +312,50 @@ public class ApplicationContext extends MultiDexApplication {
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
ConnectivityManager connectivityManager =
|
||||
(ConnectivityManager) this.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
connectivityManager.registerDefaultNetworkCallback(new ConnectivityManager.NetworkCallback() {
|
||||
@Override
|
||||
public void onAvailable(@NonNull android.net.Network network) {
|
||||
Log.i("DeltaChat", "++++++++++++++++++ NetworkCallback.onAvailable() #" + debugOnAvailableCount++);
|
||||
getDcAccounts().maybeNetwork();
|
||||
}
|
||||
(ConnectivityManager) this.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
connectivityManager.registerDefaultNetworkCallback(
|
||||
new ConnectivityManager.NetworkCallback() {
|
||||
@Override
|
||||
public void onAvailable(@NonNull android.net.Network network) {
|
||||
Log.i(
|
||||
"DeltaChat",
|
||||
"++++++++++++++++++ NetworkCallback.onAvailable() #" + debugOnAvailableCount++);
|
||||
getDcAccounts().maybeNetwork();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockedStatusChanged(@NonNull android.net.Network network, boolean blocked) {
|
||||
Log.i("DeltaChat", "++++++++++++++++++ NetworkCallback.onBlockedStatusChanged() #" + debugOnBlockedStatusChangedCount++);
|
||||
}
|
||||
@Override
|
||||
public void onBlockedStatusChanged(
|
||||
@NonNull android.net.Network network, boolean blocked) {
|
||||
Log.i(
|
||||
"DeltaChat",
|
||||
"++++++++++++++++++ NetworkCallback.onBlockedStatusChanged() #"
|
||||
+ debugOnBlockedStatusChangedCount++);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCapabilitiesChanged(@NonNull android.net.Network network, NetworkCapabilities networkCapabilities) {
|
||||
// usually called after onAvailable(), so a maybeNetwork seems contraproductive
|
||||
Log.i("DeltaChat", "++++++++++++++++++ NetworkCallback.onCapabilitiesChanged() #" + debugOnCapabilitiesChangedCount++);
|
||||
}
|
||||
@Override
|
||||
public void onCapabilitiesChanged(
|
||||
@NonNull android.net.Network network, NetworkCapabilities networkCapabilities) {
|
||||
// usually called after onAvailable(), so a maybeNetwork seems contraproductive
|
||||
Log.i(
|
||||
"DeltaChat",
|
||||
"++++++++++++++++++ NetworkCallback.onCapabilitiesChanged() #"
|
||||
+ debugOnCapabilitiesChangedCount++);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLinkPropertiesChanged(@NonNull android.net.Network network, LinkProperties linkProperties) {
|
||||
Log.i("DeltaChat", "++++++++++++++++++ NetworkCallback.onLinkPropertiesChanged() #" + debugOnLinkPropertiesChangedCount++);
|
||||
}
|
||||
});
|
||||
@Override
|
||||
public void onLinkPropertiesChanged(
|
||||
@NonNull android.net.Network network, LinkProperties linkProperties) {
|
||||
Log.i(
|
||||
"DeltaChat",
|
||||
"++++++++++++++++++ NetworkCallback.onLinkPropertiesChanged() #"
|
||||
+ debugOnLinkPropertiesChangedCount++);
|
||||
}
|
||||
});
|
||||
} // no else: use old method for debugging
|
||||
BroadcastReceiver networkStateReceiver = new NetworkStateReceiver();
|
||||
registerReceiver(networkStateReceiver, new IntentFilter(android.net.ConnectivityManager.CONNECTIVITY_ACTION));
|
||||
registerReceiver(
|
||||
networkStateReceiver,
|
||||
new IntentFilter(android.net.ConnectivityManager.CONNECTIVITY_ACTION));
|
||||
|
||||
KeepAliveService.maybeStartSelf(this);
|
||||
|
||||
@@ -322,16 +363,23 @@ public class ApplicationContext extends MultiDexApplication {
|
||||
initializeJobManager();
|
||||
InChatSounds.getInstance(this);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
EglUtils.getEglBase();
|
||||
CallCoordinator.getInstance(this);
|
||||
}
|
||||
|
||||
DynamicTheme.setDefaultDayNightMode(this);
|
||||
|
||||
IntentFilter filter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
|
||||
registerReceiver(new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
registerReceiver(
|
||||
new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
Util.localeChanged();
|
||||
DcHelper.setStockTranslations(context);
|
||||
}
|
||||
}, filter);
|
||||
}
|
||||
},
|
||||
filter);
|
||||
|
||||
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
|
||||
|
||||
@@ -342,31 +390,34 @@ public class ApplicationContext extends MultiDexApplication {
|
||||
// MAYBE TODO: i think the ApplicationContext is also created
|
||||
// when the app is stated by FetchWorker timeouts.
|
||||
// in this case, the normal threads shall not be started.
|
||||
Constraints constraints = new Constraints.Builder()
|
||||
.setRequiredNetworkType(NetworkType.CONNECTED)
|
||||
.build();
|
||||
PeriodicWorkRequest fetchWorkRequest = new PeriodicWorkRequest.Builder(
|
||||
FetchWorker.class,
|
||||
PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS, // usually 15 minutes
|
||||
TimeUnit.MILLISECONDS,
|
||||
PeriodicWorkRequest.MIN_PERIODIC_FLEX_MILLIS, // the start may be preferred by up to 5 minutes, so we run every 10-15 minutes
|
||||
TimeUnit.MILLISECONDS)
|
||||
Constraints constraints =
|
||||
new Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build();
|
||||
PeriodicWorkRequest fetchWorkRequest =
|
||||
new PeriodicWorkRequest.Builder(
|
||||
FetchWorker.class,
|
||||
PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS, // usually 15 minutes
|
||||
TimeUnit.MILLISECONDS,
|
||||
PeriodicWorkRequest
|
||||
.MIN_PERIODIC_FLEX_MILLIS, // the start may be preferred by up to 5 minutes,
|
||||
// so we run every 10-15 minutes
|
||||
TimeUnit.MILLISECONDS)
|
||||
.setConstraints(constraints)
|
||||
.build();
|
||||
WorkManager.getInstance(this).enqueueUniquePeriodicWork(
|
||||
"FetchWorker",
|
||||
ExistingPeriodicWorkPolicy.KEEP,
|
||||
fetchWorkRequest);
|
||||
WorkManager.getInstance(this)
|
||||
.enqueueUniquePeriodicWork(
|
||||
"FetchWorker", ExistingPeriodicWorkPolicy.KEEP, fetchWorkRequest);
|
||||
}
|
||||
|
||||
PeriodicWorkRequest webxdcGarbageCollectionRequest = new PeriodicWorkRequest.Builder(
|
||||
WebxdcGarbageCollectionWorker.class,
|
||||
PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS,
|
||||
TimeUnit.MILLISECONDS,
|
||||
PeriodicWorkRequest.MIN_PERIODIC_FLEX_MILLIS,
|
||||
TimeUnit.MILLISECONDS)
|
||||
PeriodicWorkRequest webxdcGarbageCollectionRequest =
|
||||
new PeriodicWorkRequest.Builder(
|
||||
WebxdcGarbageCollectionWorker.class,
|
||||
PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS,
|
||||
TimeUnit.MILLISECONDS,
|
||||
PeriodicWorkRequest.MIN_PERIODIC_FLEX_MILLIS,
|
||||
TimeUnit.MILLISECONDS)
|
||||
.build();
|
||||
WorkManager.getInstance(this).enqueueUniquePeriodicWork(
|
||||
WorkManager.getInstance(this)
|
||||
.enqueueUniquePeriodicWork(
|
||||
"WebxdcGarbageCollectionWorker",
|
||||
ExistingPeriodicWorkPolicy.KEEP,
|
||||
webxdcGarbageCollectionRequest);
|
||||
@@ -374,6 +425,14 @@ public class ApplicationContext extends MultiDexApplication {
|
||||
Log.i("DeltaChat", "+++++++++++ ApplicationContext.onCreate() finished ++++++++++");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTerminate() {
|
||||
super.onTerminate();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
EglUtils.release();
|
||||
}
|
||||
}
|
||||
|
||||
public JobManager getJobManager() {
|
||||
return jobManager;
|
||||
}
|
||||
|
||||
@@ -81,19 +81,14 @@ public abstract class BaseActionBarActivity extends AppCompatActivity {
|
||||
}
|
||||
}
|
||||
|
||||
public void makeSearchMenuVisible(final Menu menu, final MenuItem searchItem, boolean visible) {
|
||||
public void makeSearchMenuVisible(final Menu menu, final MenuItem searchItem) {
|
||||
for (int i = 0; i < menu.size(); ++i) {
|
||||
MenuItem item = menu.getItem(i);
|
||||
int id = item.getItemId();
|
||||
if (id == R.id.menu_search_up || id == R.id.menu_search_down) {
|
||||
item.setVisible(visible);
|
||||
} else if (id == R.id.menu_search_counter) {
|
||||
item.setVisible(false); // always hide menu_search_counter initially
|
||||
} else if (item == searchItem) {
|
||||
; // searchItem is just always visible
|
||||
} else {
|
||||
item.setVisible(
|
||||
!visible); // if search is shown, other items are hidden - and the other way round
|
||||
item.setVisible(true);
|
||||
} else if (item != searchItem) {
|
||||
item.setVisible(false); // hide all other items
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -676,7 +676,7 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
||||
// should be deleted.
|
||||
try {
|
||||
DcContext dcContext = DcHelper.getContext(this);
|
||||
final String deviceMsgLabel = "update_2_33_1_android";
|
||||
final String deviceMsgLabel = "update_2_46_0a_android";
|
||||
if (!dcContext.wasDeviceMsgEverAdded(deviceMsgLabel)) {
|
||||
DcMsg msg = null;
|
||||
if (!getIntent().getBooleanExtra(FROM_WELCOME, false)) {
|
||||
@@ -688,7 +688,7 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
||||
// Util.copy(inputStream, new FileOutputStream(outputFile));
|
||||
// msg.setFile(outputFile, "image/jpeg");
|
||||
|
||||
msg.setText(getString(R.string.update_2_33, "https://arcanechat.me/#contribute"));
|
||||
msg.setText(getString(R.string.update_2_46ac, "https://arcanechat.me/#contribute", "https://i.delta.chat/#0A45953086F0C166D3BAF1D4BB2025496E4C2704&x=MVPi07rQBEmHO4FRb3brpwDe&j=n8mkKqu42WAKKUCx1bQOVh23&s=AM1YCd_2hKuiSiTEb-2177On&a=arcanechat%40arcanechat.me&n=ArcaneChat&b=ArcaneChat+Channel"));
|
||||
}
|
||||
dcContext.addDeviceMsg(deviceMsgLabel, msg);
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.os.Build;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import org.webrtc.EglBase;
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.M)
|
||||
public class EglUtils {
|
||||
private static EglBase eglBase;
|
||||
|
||||
public static synchronized EglBase getEglBase() {
|
||||
if (eglBase == null) {
|
||||
eglBase = EglBase.create();
|
||||
}
|
||||
return eglBase;
|
||||
}
|
||||
|
||||
public static synchronized void release() {
|
||||
if (eglBase != null) {
|
||||
eglBase.release();
|
||||
eglBase = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -257,4 +257,9 @@ public class FullMsgActivity extends WebViewActivity {
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldAskToOpenLink() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ import java.util.Set;
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
import org.thoughtcrime.securesms.contacts.ContactSelectionListItem;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.util.DateUtils;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
public class ProfileAdapter extends RecyclerView.Adapter {
|
||||
|
||||
@@ -268,7 +268,7 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity
|
||||
accId = dcContext.getAccountId();
|
||||
}
|
||||
Intent composeIntent;
|
||||
if (accId != -1 && chatId != -1) {
|
||||
if (accId != -1 && chatId > 0) {
|
||||
composeIntent = getBaseShareIntent(ConversationActivity.class);
|
||||
composeIntent.putExtra(ConversationActivity.CHAT_ID_EXTRA, chatId);
|
||||
composeIntent.putExtra(ConversationActivity.ACCOUNT_ID_EXTRA, accId);
|
||||
|
||||
@@ -194,13 +194,13 @@ public class WebViewActivity extends PassphraseRequiredActionBarActivity
|
||||
public boolean onMenuItemActionExpand(final MenuItem item) {
|
||||
searchMenu = menu;
|
||||
WebViewActivity.this.lastQuery = "";
|
||||
WebViewActivity.this.makeSearchMenuVisible(menu, searchItem, true);
|
||||
WebViewActivity.this.makeSearchMenuVisible(menu, searchItem);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemActionCollapse(final MenuItem item) {
|
||||
WebViewActivity.this.makeSearchMenuVisible(menu, searchItem, false);
|
||||
WebViewActivity.this.invalidateOptionsMenu();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -6,24 +6,21 @@ import android.media.AudioRecord;
|
||||
import android.media.MediaCodec;
|
||||
import android.media.MediaCodecInfo;
|
||||
import android.media.MediaFormat;
|
||||
import android.media.MediaMuxer;
|
||||
import android.media.MediaRecorder;
|
||||
import android.util.Log;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import org.thoughtcrime.securesms.util.Prefs;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
public class AudioCodec {
|
||||
|
||||
private static final String TAG = AudioCodec.class.getSimpleName();
|
||||
|
||||
private static final int SAMPLE_RATE_BALANCED = 44100;
|
||||
private static final int SAMPLE_RATE_INDEX_BALANCED = 4;
|
||||
private static final int BIT_RATE_BALANCED = 32000;
|
||||
|
||||
private static final int SAMPLE_RATE_WORSE = 24000;
|
||||
private static final int SAMPLE_RATE_INDEX_WORSE = 6;
|
||||
private static final int BIT_RATE_WORSE = 16000;
|
||||
|
||||
private static final int CHANNELS = 1;
|
||||
@@ -32,12 +29,15 @@ public class AudioCodec {
|
||||
private final MediaCodec mediaCodec;
|
||||
private final AudioRecord audioRecord;
|
||||
private final Context context;
|
||||
private final String outputPath;
|
||||
|
||||
private boolean running = true;
|
||||
private boolean finished = false;
|
||||
private volatile boolean running = true;
|
||||
private volatile boolean finished = false;
|
||||
private long startTime = 0;
|
||||
|
||||
public AudioCodec(Context context) throws IOException {
|
||||
public AudioCodec(Context context, String outputPath) throws IOException {
|
||||
this.context = context;
|
||||
this.outputPath = outputPath;
|
||||
this.bufferSize =
|
||||
AudioRecord.getMinBufferSize(
|
||||
getSampleRate(), AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
|
||||
@@ -49,7 +49,7 @@ public class AudioCodec {
|
||||
try {
|
||||
audioRecord.startRecording();
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, e);
|
||||
Log.w(TAG, "Failed to start recording", e);
|
||||
mediaCodec.release();
|
||||
throw new IOException(e);
|
||||
}
|
||||
@@ -57,41 +57,143 @@ public class AudioCodec {
|
||||
|
||||
public synchronized void stop() {
|
||||
running = false;
|
||||
while (!finished) Util.wait(this, 0);
|
||||
while (!finished) {
|
||||
try {
|
||||
wait(5000);
|
||||
if (!finished) {
|
||||
Log.w(TAG, "Timeout waiting for recording to finish");
|
||||
break;
|
||||
}
|
||||
} catch (InterruptedException ie) {
|
||||
Log.w(TAG, "Interrupted while waiting for recording to finish", ie);
|
||||
Thread.currentThread().interrupt();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void start(final OutputStream outputStream) {
|
||||
public void start() {
|
||||
new Thread(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
|
||||
byte[] audioRecordData = new byte[bufferSize];
|
||||
ByteBuffer[] codecInputBuffers = mediaCodec.getInputBuffers();
|
||||
ByteBuffer[] codecOutputBuffers = mediaCodec.getOutputBuffers();
|
||||
() -> {
|
||||
this.startTime = System.nanoTime();
|
||||
|
||||
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
|
||||
byte[] audioRecordData = new byte[bufferSize];
|
||||
MediaMuxer muxer = null;
|
||||
int audioTrackIndex = -1;
|
||||
boolean muxerStarted = false;
|
||||
|
||||
try {
|
||||
muxer = new MediaMuxer(outputPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
|
||||
|
||||
while (true) {
|
||||
boolean running = isRunning();
|
||||
|
||||
handleCodecInput(audioRecord, audioRecordData, mediaCodec, running);
|
||||
int codecOutputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 2000);
|
||||
|
||||
while (codecOutputBufferIndex != MediaCodec.INFO_TRY_AGAIN_LATER) {
|
||||
if (codecOutputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
|
||||
// Get the format to add track to muxer
|
||||
if (muxerStarted) {
|
||||
Log.w(TAG, "Output format changed after muxer started, ignoring");
|
||||
codecOutputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
|
||||
continue;
|
||||
}
|
||||
MediaFormat newFormat = mediaCodec.getOutputFormat();
|
||||
Log.d(TAG, "Output format changed: " + newFormat);
|
||||
audioTrackIndex = muxer.addTrack(newFormat);
|
||||
muxer.start();
|
||||
muxerStarted = true;
|
||||
Log.d(TAG, "Muxer started");
|
||||
} else if (codecOutputBufferIndex >= 0) {
|
||||
ByteBuffer encodedData = mediaCodec.getOutputBuffer(codecOutputBufferIndex);
|
||||
|
||||
if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
|
||||
// Codec config info, not actual data, skip it
|
||||
Log.d(TAG, "Ignoring CODEC_CONFIG buffer");
|
||||
bufferInfo.size = 0;
|
||||
}
|
||||
|
||||
if (bufferInfo.size != 0 && encodedData != null) {
|
||||
if (!muxerStarted) {
|
||||
Log.w(TAG, "Muxer not started, dropping encoded data");
|
||||
} else {
|
||||
// Adjust ByteBuffer to match BufferInfo
|
||||
encodedData.position(bufferInfo.offset);
|
||||
encodedData.limit(bufferInfo.offset + bufferInfo.size);
|
||||
|
||||
// Write sample data to muxer
|
||||
muxer.writeSampleData(audioTrackIndex, encodedData, bufferInfo);
|
||||
}
|
||||
}
|
||||
|
||||
mediaCodec.releaseOutputBuffer(codecOutputBufferIndex, false);
|
||||
|
||||
// Check for end of stream
|
||||
if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
|
||||
Log.d(TAG, "End of stream reached");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
codecOutputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
|
||||
}
|
||||
|
||||
if (!running && (bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, "Error during encoding", e);
|
||||
} finally {
|
||||
try {
|
||||
if (muxerStarted && muxer != null) {
|
||||
try {
|
||||
muxer.stop();
|
||||
Log.d(TAG, "Muxer stopped");
|
||||
} catch (IllegalStateException e) {
|
||||
Log.w(TAG, "Muxer already stopped", e);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, "Error stopping muxer", e);
|
||||
}
|
||||
|
||||
if (muxer != null) {
|
||||
try {
|
||||
muxer.release();
|
||||
Log.d(TAG, "Muxer released");
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, "Error releasing muxer", e);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
while (true) {
|
||||
boolean running = isRunning();
|
||||
|
||||
handleCodecInput(
|
||||
audioRecord, audioRecordData, mediaCodec, codecInputBuffers, running);
|
||||
handleCodecOutput(mediaCodec, codecOutputBuffers, bufferInfo, outputStream);
|
||||
|
||||
if (!running) break;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
} finally {
|
||||
mediaCodec.stop();
|
||||
audioRecord.stop();
|
||||
|
||||
mediaCodec.release();
|
||||
audioRecord.release();
|
||||
|
||||
Util.close(outputStream);
|
||||
setFinished();
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, "Error stopping codec", e);
|
||||
}
|
||||
|
||||
try {
|
||||
audioRecord.stop();
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, "Error stopping audio record", e);
|
||||
}
|
||||
|
||||
try {
|
||||
mediaCodec.release();
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, "Error releasing codec", e);
|
||||
}
|
||||
|
||||
try {
|
||||
audioRecord.release();
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, "Error releasing audio record", e);
|
||||
}
|
||||
|
||||
setFinished();
|
||||
}
|
||||
},
|
||||
AudioCodec.class.getSimpleName())
|
||||
@@ -108,75 +210,35 @@ public class AudioCodec {
|
||||
}
|
||||
|
||||
private void handleCodecInput(
|
||||
AudioRecord audioRecord,
|
||||
byte[] audioRecordData,
|
||||
MediaCodec mediaCodec,
|
||||
ByteBuffer[] codecInputBuffers,
|
||||
boolean running) {
|
||||
AudioRecord audioRecord, byte[] audioRecordData, MediaCodec mediaCodec, boolean running) {
|
||||
int length = audioRecord.read(audioRecordData, 0, audioRecordData.length);
|
||||
|
||||
if (length < 0) {
|
||||
Log.w(TAG, "Error reading from AudioRecord: " + length);
|
||||
return;
|
||||
}
|
||||
|
||||
int codecInputBufferIndex = mediaCodec.dequeueInputBuffer(10 * 1000);
|
||||
|
||||
if (codecInputBufferIndex >= 0) {
|
||||
ByteBuffer codecBuffer = codecInputBuffers[codecInputBufferIndex];
|
||||
codecBuffer.clear();
|
||||
codecBuffer.put(audioRecordData);
|
||||
mediaCodec.queueInputBuffer(
|
||||
codecInputBufferIndex, 0, length, 0, running ? 0 : MediaCodec.BUFFER_FLAG_END_OF_STREAM);
|
||||
}
|
||||
}
|
||||
ByteBuffer codecBuffer = mediaCodec.getInputBuffer(codecInputBufferIndex);
|
||||
|
||||
private void handleCodecOutput(
|
||||
MediaCodec mediaCodec,
|
||||
ByteBuffer[] codecOutputBuffers,
|
||||
MediaCodec.BufferInfo bufferInfo,
|
||||
OutputStream outputStream)
|
||||
throws IOException {
|
||||
int codecOutputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
|
||||
|
||||
while (codecOutputBufferIndex != MediaCodec.INFO_TRY_AGAIN_LATER) {
|
||||
if (codecOutputBufferIndex >= 0) {
|
||||
ByteBuffer encoderOutputBuffer = codecOutputBuffers[codecOutputBufferIndex];
|
||||
|
||||
encoderOutputBuffer.position(bufferInfo.offset);
|
||||
encoderOutputBuffer.limit(bufferInfo.offset + bufferInfo.size);
|
||||
|
||||
if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG)
|
||||
!= MediaCodec.BUFFER_FLAG_CODEC_CONFIG) {
|
||||
byte[] header = createAdtsHeader(bufferInfo.size - bufferInfo.offset);
|
||||
|
||||
outputStream.write(header);
|
||||
|
||||
byte[] data = new byte[encoderOutputBuffer.remaining()];
|
||||
encoderOutputBuffer.get(data);
|
||||
outputStream.write(data);
|
||||
}
|
||||
|
||||
encoderOutputBuffer.clear();
|
||||
|
||||
mediaCodec.releaseOutputBuffer(codecOutputBufferIndex, false);
|
||||
} else if (codecOutputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
|
||||
codecOutputBuffers = mediaCodec.getOutputBuffers();
|
||||
if (codecBuffer != null) {
|
||||
codecBuffer.clear();
|
||||
codecBuffer.put(audioRecordData, 0, length);
|
||||
long presentationTimeUs = getPresentationTimeUs();
|
||||
mediaCodec.queueInputBuffer(
|
||||
codecInputBufferIndex,
|
||||
0,
|
||||
length,
|
||||
presentationTimeUs,
|
||||
running ? 0 : MediaCodec.BUFFER_FLAG_END_OF_STREAM);
|
||||
}
|
||||
|
||||
codecOutputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] createAdtsHeader(int length) {
|
||||
int frameLength = length + 7;
|
||||
byte[] adtsHeader = new byte[7];
|
||||
|
||||
adtsHeader[0] = (byte) 0xFF; // Sync Word
|
||||
adtsHeader[1] = (byte) 0xF1; // MPEG-4, Layer (0), No CRC
|
||||
adtsHeader[2] = (byte) ((MediaCodecInfo.CodecProfileLevel.AACObjectLC - 1) << 6);
|
||||
adtsHeader[2] |= (((byte) getSampleRateIndex()) << 2);
|
||||
adtsHeader[2] |= (((byte) CHANNELS) >> 2);
|
||||
adtsHeader[3] = (byte) (((CHANNELS & 3) << 6) | ((frameLength >> 11) & 0x03));
|
||||
adtsHeader[4] = (byte) ((frameLength >> 3) & 0xFF);
|
||||
adtsHeader[5] = (byte) (((frameLength & 0x07) << 5) | 0x1f);
|
||||
adtsHeader[6] = (byte) 0xFC;
|
||||
|
||||
return adtsHeader;
|
||||
private long getPresentationTimeUs() {
|
||||
return (System.nanoTime() - startTime) / 1000;
|
||||
}
|
||||
|
||||
private AudioRecord createAudioRecord(int bufferSize) {
|
||||
@@ -190,11 +252,9 @@ public class AudioCodec {
|
||||
|
||||
private MediaCodec createMediaCodec(int bufferSize) throws IOException {
|
||||
MediaCodec mediaCodec = MediaCodec.createEncoderByType("audio/mp4a-latm");
|
||||
MediaFormat mediaFormat = new MediaFormat();
|
||||
|
||||
mediaFormat.setString(MediaFormat.KEY_MIME, "audio/mp4a-latm");
|
||||
mediaFormat.setInteger(MediaFormat.KEY_SAMPLE_RATE, getSampleRate());
|
||||
mediaFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, CHANNELS);
|
||||
MediaFormat mediaFormat =
|
||||
MediaFormat.createAudioFormat("audio/mp4a-latm", getSampleRate(), CHANNELS);
|
||||
mediaFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, bufferSize);
|
||||
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, getBitRate());
|
||||
mediaFormat.setInteger(
|
||||
@@ -215,12 +275,6 @@ public class AudioCodec {
|
||||
return Prefs.isHardCompressionEnabled(context) ? SAMPLE_RATE_WORSE : SAMPLE_RATE_BALANCED;
|
||||
}
|
||||
|
||||
private int getSampleRateIndex() {
|
||||
return Prefs.isHardCompressionEnabled(context)
|
||||
? SAMPLE_RATE_INDEX_WORSE
|
||||
: SAMPLE_RATE_INDEX_BALANCED;
|
||||
}
|
||||
|
||||
private int getBitRate() {
|
||||
return Prefs.isHardCompressionEnabled(context) ? BIT_RATE_WORSE : BIT_RATE_BALANCED;
|
||||
}
|
||||
|
||||
@@ -2,14 +2,15 @@ package org.thoughtcrime.securesms.audio;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import androidx.annotation.NonNull;
|
||||
import chat.delta.util.ListenableFuture;
|
||||
import chat.delta.util.SettableFuture;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import org.thoughtcrime.securesms.providers.PersistentBlobProvider;
|
||||
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||
import org.thoughtcrime.securesms.util.ThreadUtil;
|
||||
@@ -24,8 +25,17 @@ public class AudioRecorder {
|
||||
private final Context context;
|
||||
private final PersistentBlobProvider blobProvider;
|
||||
|
||||
private AudioCodec audioCodec;
|
||||
private Uri captureUri;
|
||||
private final AtomicReference<RecordingState> recordingState = new AtomicReference<>(null);
|
||||
|
||||
private static class RecordingState {
|
||||
final AudioCodec audioCodec;
|
||||
final String outputFilePath;
|
||||
|
||||
RecordingState(AudioCodec audioCodec, String outputFilePath) {
|
||||
this.audioCodec = audioCodec;
|
||||
this.outputFilePath = outputFilePath;
|
||||
}
|
||||
}
|
||||
|
||||
public AudioRecorder(@NonNull Context context) {
|
||||
this.context = context;
|
||||
@@ -39,24 +49,22 @@ public class AudioRecorder {
|
||||
() -> {
|
||||
Log.w(TAG, "Running startRecording() + " + Thread.currentThread().getId());
|
||||
try {
|
||||
if (audioCodec != null) {
|
||||
RecordingState currentState = recordingState.get();
|
||||
if (currentState != null) {
|
||||
throw new AssertionError("We can only record once at a time.");
|
||||
}
|
||||
|
||||
ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe();
|
||||
// Create temporary file for M4A output
|
||||
File outputFile = File.createTempFile("voice", ".m4a", context.getCacheDir());
|
||||
String outputFilePath = outputFile.getAbsolutePath();
|
||||
|
||||
captureUri =
|
||||
blobProvider.create(
|
||||
context,
|
||||
new ParcelFileDescriptor.AutoCloseInputStream(fds[0]),
|
||||
MediaUtil.AUDIO_AAC,
|
||||
"voice.aac",
|
||||
null);
|
||||
audioCodec = new AudioCodec(context);
|
||||
AudioCodec audioCodec = new AudioCodec(context, outputFilePath);
|
||||
recordingState.set(new RecordingState(audioCodec, outputFilePath));
|
||||
|
||||
audioCodec.start(new ParcelFileDescriptor.AutoCloseOutputStream(fds[1]));
|
||||
audioCodec.start();
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
recordingState.set(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -68,24 +76,39 @@ public class AudioRecorder {
|
||||
|
||||
executor.execute(
|
||||
() -> {
|
||||
if (audioCodec == null) {
|
||||
RecordingState state = recordingState.getAndSet(null);
|
||||
|
||||
if (state == null || state.audioCodec == null) {
|
||||
sendToFuture(
|
||||
future, new IOException("MediaRecorder was never initialized successfully!"));
|
||||
return;
|
||||
}
|
||||
|
||||
audioCodec.stop();
|
||||
state.audioCodec.stop();
|
||||
|
||||
try {
|
||||
long size = MediaUtil.getMediaSize(context, captureUri);
|
||||
File outputFile = new File(state.outputFilePath);
|
||||
|
||||
if (!outputFile.exists()) {
|
||||
sendToFuture(future, new IOException("Output file does not exist"));
|
||||
return;
|
||||
}
|
||||
|
||||
long size = outputFile.length();
|
||||
|
||||
// Create blob using synchronous file-based method
|
||||
Uri captureUri =
|
||||
blobProvider.create(context, outputFile, MediaUtil.AUDIO_M4A, "voice.m4a", size);
|
||||
|
||||
if (!outputFile.delete()) {
|
||||
Log.d(TAG, "Temp file already moved or couldn't be deleted");
|
||||
}
|
||||
|
||||
sendToFuture(future, new Pair<>(captureUri, size));
|
||||
} catch (IOException ioe) {
|
||||
Log.w(TAG, ioe);
|
||||
Log.w(TAG, "Failed to create blob from recording", ioe);
|
||||
sendToFuture(future, ioe);
|
||||
}
|
||||
|
||||
audioCodec = null;
|
||||
captureUri = null;
|
||||
});
|
||||
|
||||
return future;
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
package org.thoughtcrime.securesms.calls;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.core.telecom.CallEndpointCompat;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog;
|
||||
import java.util.List;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
|
||||
/** Bottom sheet dialog for selecting audio output device */
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
public class AudioDevicePickerDialog extends BottomSheetDialog {
|
||||
private static final String TAG = AudioDevicePickerDialog.class.getSimpleName();
|
||||
|
||||
public interface OnDeviceSelectedListener {
|
||||
void onDeviceSelected(CallEndpointCompat endpoint);
|
||||
}
|
||||
|
||||
public AudioDevicePickerDialog(
|
||||
@NonNull Context context,
|
||||
@NonNull List<CallEndpointCompat> endpoints,
|
||||
CallEndpointCompat currentEndpoint,
|
||||
@NonNull OnDeviceSelectedListener listener) {
|
||||
super(context);
|
||||
|
||||
setContentView(R.layout.dialog_audio_device_picker);
|
||||
|
||||
RecyclerView recyclerView = findViewById(R.id.audio_device_list);
|
||||
if (recyclerView == null) {
|
||||
Log.e(TAG, "RecyclerView not found in layout");
|
||||
return;
|
||||
}
|
||||
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(context));
|
||||
|
||||
AudioDeviceAdapter adapter =
|
||||
new AudioDeviceAdapter(
|
||||
endpoints,
|
||||
currentEndpoint,
|
||||
endpoint -> {
|
||||
listener.onDeviceSelected(endpoint);
|
||||
dismiss();
|
||||
});
|
||||
|
||||
recyclerView.setAdapter(adapter);
|
||||
}
|
||||
|
||||
/** RecyclerView adapter for audio devices */
|
||||
private static class AudioDeviceAdapter
|
||||
extends RecyclerView.Adapter<AudioDeviceAdapter.ViewHolder> {
|
||||
|
||||
private final List<CallEndpointCompat> endpoints;
|
||||
private final CallEndpointCompat currentEndpoint;
|
||||
private final OnDeviceSelectedListener listener;
|
||||
|
||||
AudioDeviceAdapter(
|
||||
List<CallEndpointCompat> endpoints,
|
||||
CallEndpointCompat currentEndpoint,
|
||||
OnDeviceSelectedListener listener) {
|
||||
this.endpoints = endpoints;
|
||||
this.currentEndpoint = currentEndpoint;
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view =
|
||||
LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.item_audio_device, parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
CallEndpointCompat endpoint = endpoints.get(position);
|
||||
boolean isCurrent =
|
||||
currentEndpoint != null
|
||||
&& endpoint.getIdentifier().equals(currentEndpoint.getIdentifier());
|
||||
|
||||
holder.bind(endpoint, isCurrent, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return endpoints.size();
|
||||
}
|
||||
|
||||
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
private final ImageView iconView;
|
||||
private final TextView nameView;
|
||||
private final ImageView checkView;
|
||||
|
||||
ViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
iconView = itemView.findViewById(R.id.device_icon);
|
||||
nameView = itemView.findViewById(R.id.device_name);
|
||||
checkView = itemView.findViewById(R.id.device_check);
|
||||
}
|
||||
|
||||
void bind(CallEndpointCompat endpoint, boolean isCurrent, OnDeviceSelectedListener listener) {
|
||||
nameView.setText(endpoint.getName());
|
||||
|
||||
int iconRes = CallUtil.getIconResByCallEndpoint(endpoint);
|
||||
iconView.setImageResource(iconRes);
|
||||
|
||||
checkView.setVisibility(isCurrent ? View.VISIBLE : View.GONE);
|
||||
|
||||
itemView.setOnClickListener(v -> listener.onDeviceSelected(endpoint));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,525 @@
|
||||
package org.thoughtcrime.securesms.calls;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.media.AudioAttributes;
|
||||
import android.media.AudioFocusRequest;
|
||||
import android.media.AudioManager;
|
||||
import android.media.Ringtone;
|
||||
import android.media.RingtoneManager;
|
||||
import android.media.ToneGenerator;
|
||||
import android.net.Uri;
|
||||
import android.os.Binder;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
import android.util.Log;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import chat.delta.rpc.RpcException;
|
||||
import org.thoughtcrime.securesms.webrtc.WebRTCClient;
|
||||
import org.webrtc.AudioTrack;
|
||||
import org.webrtc.MediaStream;
|
||||
import org.webrtc.PeerConnection;
|
||||
import org.webrtc.VideoTrack;
|
||||
|
||||
/**
|
||||
* Foreground service for VoIP calls
|
||||
*
|
||||
* <p>Required to post CallStyle notifications on Android 12+. Owns WebRTC resources and keeps call
|
||||
* alive.
|
||||
*/
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
public class CallService extends Service implements WebRTCClient.Callbacks {
|
||||
|
||||
private static final String TAG = CallService.class.getSimpleName();
|
||||
|
||||
private final IBinder binder = new LocalBinder();
|
||||
|
||||
// WebRTC Resources
|
||||
private WebRTCClient webRTCClient;
|
||||
private MediaStreamManager mediaStreamManager;
|
||||
|
||||
// Ringtone Resources
|
||||
private Ringtone ringtone;
|
||||
private AudioManager audioManager;
|
||||
private AudioFocusRequest audioFocusRequest;
|
||||
private ToneGenerator toneGenerator;
|
||||
private Runnable toneLoopRunnable;
|
||||
|
||||
private CallCoordinator callCoordinator;
|
||||
|
||||
public class LocalBinder extends Binder {
|
||||
CallService getService() {
|
||||
return CallService.this;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return binder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
Log.d(TAG, "CallService onCreate");
|
||||
|
||||
callCoordinator = CallCoordinator.getInstance(getApplicationContext());
|
||||
|
||||
audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
|
||||
|
||||
Log.d(TAG, "CallService created");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
Log.d(TAG, "CallService started");
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
// Initialization
|
||||
|
||||
/** Initialize call infrastructure Does NOT start camera/microphone */
|
||||
public void initializeCall() {
|
||||
Log.d(TAG, "initializeCall (Infrastructure only)");
|
||||
|
||||
if (webRTCClient != null) {
|
||||
Log.w(TAG, "Infrastructure already initialized, ignoring");
|
||||
return;
|
||||
}
|
||||
|
||||
webRTCClient = new WebRTCClient(getApplicationContext(), this);
|
||||
|
||||
mediaStreamManager =
|
||||
new MediaStreamManager(getApplicationContext(), webRTCClient.getPeerConnectionFactory());
|
||||
|
||||
fetchIceServersAndSetup();
|
||||
}
|
||||
|
||||
private void fetchIceServersAndSetup() {
|
||||
new Thread(
|
||||
() -> {
|
||||
if (!callCoordinator.hasActiveCall()) {
|
||||
Log.d(TAG, "Call ended before ICE fetch, aborting");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
String iceServersJson = callCoordinator.fetchIceServers();
|
||||
Log.d(TAG, "ICE servers fetched: " + iceServersJson);
|
||||
|
||||
webRTCClient.configure(iceServersJson);
|
||||
|
||||
Log.d(TAG, "Infrastructure initialized, waiting for media capture");
|
||||
|
||||
} catch (RpcException e) {
|
||||
Log.e(TAG, "Failed to fetch ICE servers", e);
|
||||
callCoordinator.reportError("Failed to connect: " + e.getMessage());
|
||||
}
|
||||
})
|
||||
.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start camera/microphone capture
|
||||
*
|
||||
* <p>Must be called when app is in foreground. Called by coordinator when ViewModel/Activity is
|
||||
* ready.
|
||||
*/
|
||||
public void startMediaCapture() {
|
||||
Log.d(TAG, "startMediaCapture (Camera/Microphone)");
|
||||
|
||||
if (webRTCClient != null && webRTCClient.hasLocalMediaStream()) {
|
||||
Log.w(TAG, "Media already initialized, skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mediaStreamManager == null) {
|
||||
Log.e(TAG, "MediaStreamManager not initialized");
|
||||
callCoordinator.reportError("MediaStreamManager not initialized");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check permissions
|
||||
boolean hasMicrophone = callCoordinator.hasMicrophonePermission();
|
||||
boolean hasCamera = callCoordinator.hasCameraPermission();
|
||||
|
||||
if (!hasMicrophone) {
|
||||
Log.e(TAG, "Microphone permission not granted, cannot start call");
|
||||
callCoordinator.reportError("Microphone permission is required for calls");
|
||||
return;
|
||||
}
|
||||
|
||||
boolean startsWithVideo = callCoordinator.isStartsWithVideo() && hasCamera;
|
||||
|
||||
Log.d(TAG, "Creating media stream with video: " + startsWithVideo);
|
||||
|
||||
mediaStreamManager.createMediaStream(
|
||||
new MediaStreamManager.Callback() {
|
||||
@Override
|
||||
public void onMediaStreamReady(MediaStream stream) {
|
||||
Log.d(TAG, "Media stream ready");
|
||||
|
||||
webRTCClient.setLocalMediaStream(stream);
|
||||
|
||||
callCoordinator.setVideoEnabled(startsWithVideo);
|
||||
|
||||
if (!stream.videoTracks.isEmpty()) {
|
||||
VideoTrack localTrack = stream.videoTracks.get(0);
|
||||
callCoordinator.updateLocalVideoTrack(localTrack);
|
||||
} else {
|
||||
Log.w(TAG, "Camera unavailable, call will be audio-only");
|
||||
callCoordinator.reportError("Camera unavailable, using audio only");
|
||||
callCoordinator.setVideoEnabled(false);
|
||||
}
|
||||
|
||||
Log.d(TAG, "Media capture complete, ready for call");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String error) {
|
||||
Log.e(TAG, "Failed to setup media: " + error);
|
||||
callCoordinator.reportError("Camera/microphone error: " + error);
|
||||
callCoordinator.setVideoEnabled(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Ringtone Management
|
||||
|
||||
public void startIncomingRingtone() {
|
||||
Log.d(TAG, "startIncomingRingtone");
|
||||
|
||||
if (ringtone != null && ringtone.isPlaying()) {
|
||||
Log.d(TAG, "Ringtone already playing");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Get system default ringtone URI
|
||||
Uri ringtoneUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);
|
||||
|
||||
if (ringtoneUri == null) {
|
||||
Log.w(TAG, "No default ringtone available");
|
||||
return;
|
||||
}
|
||||
|
||||
ringtone = RingtoneManager.getRingtone(getApplicationContext(), ringtoneUri);
|
||||
|
||||
if (ringtone == null) {
|
||||
Log.e(TAG, "Failed to create Ringtone from URI: " + ringtoneUri);
|
||||
return;
|
||||
}
|
||||
|
||||
AudioAttributes audioAttributes =
|
||||
new AudioAttributes.Builder()
|
||||
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
|
||||
.setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
|
||||
.setLegacyStreamType(AudioManager.STREAM_RING)
|
||||
.build();
|
||||
|
||||
ringtone.setAudioAttributes(audioAttributes);
|
||||
|
||||
// Request audio focus
|
||||
audioFocusRequest =
|
||||
new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT)
|
||||
.setAudioAttributes(audioAttributes)
|
||||
.setWillPauseWhenDucked(false)
|
||||
.build();
|
||||
|
||||
int result = audioManager.requestAudioFocus(audioFocusRequest);
|
||||
if (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
|
||||
Log.w(TAG, "Audio focus not granted");
|
||||
}
|
||||
|
||||
ringtone.play();
|
||||
Log.d(TAG, "Ringtone started playing");
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Failed to start ringtone", e);
|
||||
// Clean up on error
|
||||
stopRingtone();
|
||||
}
|
||||
}
|
||||
|
||||
public void startOutgoingRingtone() {
|
||||
Log.d(TAG, "startOutgoingRingtone");
|
||||
|
||||
if (toneGenerator != null) {
|
||||
Log.d(TAG, "Tone already playing");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
AudioAttributes audioAttributes =
|
||||
new AudioAttributes.Builder()
|
||||
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
|
||||
.setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
|
||||
.setLegacyStreamType(AudioManager.STREAM_VOICE_CALL)
|
||||
.build();
|
||||
|
||||
audioFocusRequest =
|
||||
new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK)
|
||||
.setAudioAttributes(audioAttributes)
|
||||
.setWillPauseWhenDucked(false)
|
||||
.build();
|
||||
|
||||
int result = audioManager.requestAudioFocus(audioFocusRequest);
|
||||
if (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
|
||||
Log.w(TAG, "Audio focus not granted");
|
||||
}
|
||||
|
||||
// Create ToneGenerator
|
||||
toneGenerator = new ToneGenerator(AudioManager.STREAM_VOICE_CALL, 80);
|
||||
|
||||
boolean started = toneGenerator.startTone(ToneGenerator.TONE_SUP_RINGTONE, -1);
|
||||
|
||||
if (started) {
|
||||
Log.d(TAG, "Outgoing ringback tone started playing");
|
||||
} else {
|
||||
Log.e(TAG, "Failed to start tone");
|
||||
stopRingtone();
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Failed to start outgoing ringtone", e);
|
||||
stopRingtone();
|
||||
}
|
||||
}
|
||||
|
||||
/** Stop playing ringtone */
|
||||
public void stopRingtone() {
|
||||
Log.d(TAG, "stopRingtone");
|
||||
|
||||
if (toneGenerator != null) {
|
||||
try {
|
||||
toneGenerator.stopTone();
|
||||
toneGenerator.release();
|
||||
Log.d(TAG, "ToneGenerator stopped and released");
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error stopping ToneGenerator", e);
|
||||
}
|
||||
toneGenerator = null;
|
||||
}
|
||||
|
||||
if (ringtone != null) {
|
||||
try {
|
||||
if (ringtone.isPlaying()) {
|
||||
ringtone.stop();
|
||||
Log.d(TAG, "Ringtone stopped");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error stopping ringtone", e);
|
||||
}
|
||||
ringtone = null;
|
||||
}
|
||||
|
||||
if (audioFocusRequest != null && audioManager != null) {
|
||||
audioManager.abandonAudioFocusRequest(audioFocusRequest);
|
||||
audioFocusRequest = null;
|
||||
Log.d(TAG, "Audio focus abandoned");
|
||||
}
|
||||
}
|
||||
|
||||
// Call Control
|
||||
|
||||
public void startOutgoingCall() {
|
||||
Log.d(TAG, "startOutgoingCall");
|
||||
|
||||
if (webRTCClient == null) {
|
||||
Log.e(TAG, "Cannot start call, not initialized");
|
||||
callCoordinator.reportError("Service not ready");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!webRTCClient.hasLocalMediaStream()) {
|
||||
Log.e(TAG, "Cannot start call, media not ready");
|
||||
callCoordinator.reportError("Media not ready");
|
||||
return;
|
||||
}
|
||||
|
||||
webRTCClient.startOutgoingCall();
|
||||
}
|
||||
|
||||
public void answerIncomingCall() {
|
||||
Log.d(TAG, "answerIncomingCall");
|
||||
|
||||
String offerSdp = callCoordinator.getPendingOfferSdp();
|
||||
|
||||
if (offerSdp == null) {
|
||||
Log.e(TAG, "No offer SDP available");
|
||||
callCoordinator.reportError("Call data missing");
|
||||
return;
|
||||
}
|
||||
|
||||
if (webRTCClient == null) {
|
||||
Log.e(TAG, "Cannot answer call, not initialized");
|
||||
callCoordinator.reportError("Service not ready");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!webRTCClient.hasLocalMediaStream()) {
|
||||
Log.e(TAG, "Cannot answer, media not ready");
|
||||
callCoordinator.reportError("Media not ready");
|
||||
return;
|
||||
}
|
||||
|
||||
callCoordinator.clearPendingOfferSdp();
|
||||
|
||||
webRTCClient.acceptIncomingCall(offerSdp);
|
||||
}
|
||||
|
||||
public void handleAnswerSdp(String answerSdp) {
|
||||
Log.d(TAG, "handleAnswerSdp");
|
||||
|
||||
if (webRTCClient == null) {
|
||||
Log.e(TAG, "Cannot handle answer, not initialized");
|
||||
return;
|
||||
}
|
||||
|
||||
webRTCClient.handleAnswerSdp(answerSdp);
|
||||
}
|
||||
|
||||
public void setAudioEnabled(boolean enabled) {
|
||||
Log.d(TAG, "setAudioEnabled: " + enabled);
|
||||
|
||||
if (webRTCClient != null) {
|
||||
webRTCClient.setAudioEnabled(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
public void setVideoEnabled(boolean enabled) {
|
||||
Log.d(TAG, "setVideoEnabled: " + enabled);
|
||||
|
||||
if (webRTCClient != null) {
|
||||
webRTCClient.setVideoEnabled(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendMutedState(boolean audioEnabled, boolean videoEnabled) {
|
||||
Log.d(TAG, "sendMutedState: audio=" + audioEnabled + ", video=" + videoEnabled);
|
||||
|
||||
if (webRTCClient != null) {
|
||||
webRTCClient.sendMutedState(audioEnabled, videoEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
public void switchCamera() {
|
||||
Log.d(TAG, "switchCamera");
|
||||
|
||||
if (mediaStreamManager != null) {
|
||||
mediaStreamManager.switchCamera();
|
||||
}
|
||||
}
|
||||
|
||||
public void endCall() {
|
||||
Log.d(TAG, "endCall");
|
||||
|
||||
disposeWebRTC();
|
||||
|
||||
stopService();
|
||||
}
|
||||
|
||||
// WebRTCClient.Callbacks
|
||||
|
||||
@Override
|
||||
public void onOfferReady(String offerSdp) {
|
||||
Log.d(TAG, "onOfferReady callback");
|
||||
|
||||
callCoordinator.handleOfferReady(offerSdp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnswerReady(String answerSdp) {
|
||||
Log.d(TAG, "onAnswerReady callback");
|
||||
|
||||
callCoordinator.handleAnswerReady(answerSdp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemoteVideoTrack(VideoTrack videoTrack) {
|
||||
Log.d(TAG, "onRemoteVideoTrack callback");
|
||||
|
||||
callCoordinator.updateRemoteVideoTrack(videoTrack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemoteAudioTrack(AudioTrack audioTrack) {
|
||||
Log.d(TAG, "onRemoteAudioTrack callback");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectionStateChanged(PeerConnection.PeerConnectionState state) {
|
||||
Log.d(TAG, "onConnectionStateChanged: " + state);
|
||||
|
||||
callCoordinator.updateConnectionState(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemoteMutedStateChanged(boolean audioEnabled, boolean videoEnabled) {
|
||||
Log.d(TAG, "onRemoteMutedStateChanged: audio=" + audioEnabled + ", video=" + videoEnabled);
|
||||
|
||||
callCoordinator.updateRemoteMutedState(audioEnabled, videoEnabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRelayUsageChanged(Boolean isRelayUsed) {
|
||||
Log.d(TAG, "onRelayUsageChanged: " + isRelayUsed);
|
||||
|
||||
callCoordinator.updateRelayUsage(isRelayUsed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String error) {
|
||||
Log.e(TAG, "onError: " + error);
|
||||
|
||||
callCoordinator.reportError(error);
|
||||
}
|
||||
|
||||
// Foreground Notification
|
||||
|
||||
public void startForegroundWithNotification(int id, Notification notification) {
|
||||
Log.d(TAG, "Starting foreground with notification id: " + id);
|
||||
startForeground(id, notification);
|
||||
}
|
||||
|
||||
public void stopForegroundAndDismiss() {
|
||||
Log.d(TAG, "Stopping foreground and dismissing notification");
|
||||
stopForeground(STOP_FOREGROUND_REMOVE);
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
|
||||
private void disposeWebRTC() {
|
||||
Log.d(TAG, "Disposing WebRTC resources");
|
||||
|
||||
if (mediaStreamManager != null) {
|
||||
mediaStreamManager.dispose();
|
||||
mediaStreamManager = null;
|
||||
}
|
||||
|
||||
if (webRTCClient != null) {
|
||||
webRTCClient.dispose();
|
||||
webRTCClient = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void stopService() {
|
||||
Log.d(TAG, "Stopping CallService");
|
||||
stopSelf();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
Log.d(TAG, "CallService onDestroy");
|
||||
|
||||
stopRingtone();
|
||||
|
||||
disposeWebRTC();
|
||||
|
||||
Log.d(TAG, "CallService destroyed");
|
||||
}
|
||||
}
|
||||
@@ -1,62 +1,141 @@
|
||||
package org.thoughtcrime.securesms.calls;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.Base64;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
|
||||
import android.widget.Toast;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.core.telecom.CallEndpointCompat;
|
||||
import com.b44t.messenger.DcChat;
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
|
||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.BitmapUtil;
|
||||
|
||||
public class CallUtil {
|
||||
private static final String TAG = CallUtil.class.getSimpleName();
|
||||
|
||||
public static void startCall(Activity activity, int chatId, boolean hasVideo) {
|
||||
Permissions.with(activity)
|
||||
.request(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO)
|
||||
.ifNecessary()
|
||||
.withPermanentDenialDialog(activity.getString(R.string.perm_explain_access_to_camera_denied))
|
||||
.onAllGranted(() -> {
|
||||
int accId = DcHelper.getContext(activity).getAccountId();
|
||||
startCall(activity, accId, chatId, hasVideo);
|
||||
})
|
||||
.execute();
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
public static void startAudioCall(Context context, int chatId) {
|
||||
Log.d(TAG, "Starting audio call to " + chatId);
|
||||
startCall(context, chatId, false);
|
||||
}
|
||||
|
||||
public static void startCall(Context context, int accId, int chatId, boolean hasVideo) {
|
||||
Intent intent = new Intent(context, CallActivity.class);
|
||||
intent.setAction(Intent.ACTION_VIEW);
|
||||
intent.putExtra(CallActivity.EXTRA_ACCOUNT_ID, accId);
|
||||
intent.putExtra(CallActivity.EXTRA_CHAT_ID, chatId);
|
||||
intent.putExtra(CallActivity.EXTRA_HAS_VIDEO, hasVideo);
|
||||
intent.putExtra(CallActivity.EXTRA_HASH, "#startCall");
|
||||
context.startActivity(intent);
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
public static void startVideoCall(Context context, int chatId) {
|
||||
Log.d(TAG, "Starting video call to " + chatId);
|
||||
startCall(context, chatId, true);
|
||||
}
|
||||
|
||||
public static void openCall(Context context, int accId, int chatId, int callId, String payload, boolean hasVideo) {
|
||||
String base64 = Base64.encodeToString(payload.getBytes(StandardCharsets.UTF_8), Base64.NO_WRAP);
|
||||
String hash = "";
|
||||
try {
|
||||
hash = "#offerIncomingCall=" + URLEncoder.encode(base64, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
Log.e(TAG, "Error", e);
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
private static void startCall(Context context, int chatId, boolean startsWithVideo) {
|
||||
if (chatId < 0) {
|
||||
Log.e(TAG, "Cannot start call: wrong chatId");
|
||||
return;
|
||||
}
|
||||
|
||||
Intent intent = new Intent(context, CallActivity.class);
|
||||
intent.setAction(Intent.ACTION_VIEW);
|
||||
intent.putExtra(CallActivity.EXTRA_ACCOUNT_ID, accId);
|
||||
intent.putExtra(CallActivity.EXTRA_CHAT_ID, chatId);
|
||||
intent.putExtra(CallActivity.EXTRA_CALL_ID, callId);
|
||||
intent.putExtra(CallActivity.EXTRA_HAS_VIDEO, hasVideo);
|
||||
intent.putExtra(CallActivity.EXTRA_HASH, hash);
|
||||
context.startActivity(intent);
|
||||
CallCoordinator coordinator = CallCoordinator.getInstance(context);
|
||||
|
||||
if (coordinator.hasActiveCall()) {
|
||||
Toast.makeText(context, R.string.already_in_call, Toast.LENGTH_SHORT).show();
|
||||
Intent intent = new Intent(context, CallActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
context.startActivity(intent);
|
||||
return;
|
||||
}
|
||||
|
||||
int accId = DcHelper.getContext(context).getAccountId();
|
||||
coordinator.initiateOutgoingCall(accId, chatId, startsWithVideo);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
protected static Icon getIconFromChat(Context context, DcChat dcChat) {
|
||||
Log.d(TAG, "getIconFromChat: thread=" + Thread.currentThread().getName());
|
||||
|
||||
try {
|
||||
Recipient recipient = new Recipient(context, dcChat);
|
||||
ContactPhoto contactPhoto = recipient.getContactPhoto(context);
|
||||
|
||||
int wh = context.getResources().getDimensionPixelSize(R.dimen.contact_photo_target_size);
|
||||
Bitmap bitmap;
|
||||
|
||||
if (contactPhoto != null) {
|
||||
bitmap =
|
||||
GlideApp.with(context)
|
||||
.asBitmap()
|
||||
.load(contactPhoto)
|
||||
.diskCacheStrategy(DiskCacheStrategy.ALL)
|
||||
.circleCrop()
|
||||
.submit(wh, wh)
|
||||
.get();
|
||||
} else {
|
||||
Drawable drawable =
|
||||
recipient
|
||||
.getFallbackContactPhoto()
|
||||
.asDrawable(context, recipient.getFallbackAvatarColor());
|
||||
bitmap = BitmapUtil.createFromDrawable(drawable, wh, wh);
|
||||
}
|
||||
|
||||
if (bitmap != null) {
|
||||
Log.d(
|
||||
TAG,
|
||||
"Bitmap loaded: "
|
||||
+ bitmap.getWidth()
|
||||
+ "x"
|
||||
+ bitmap.getHeight()
|
||||
+ ", config="
|
||||
+ bitmap.getConfig()
|
||||
+ ", recycled="
|
||||
+ bitmap.isRecycled());
|
||||
Icon icon = Icon.createWithBitmap(bitmap);
|
||||
Log.d(TAG, "Icon created successfully");
|
||||
return icon;
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Failed to load caller icon", e);
|
||||
}
|
||||
|
||||
Log.w(TAG, "Returning null icon");
|
||||
return null;
|
||||
}
|
||||
|
||||
protected static String getNameFromChat(DcChat dcChat) {
|
||||
return dcChat.getName();
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
public static int getIconResByCallEndpoint(CallEndpointCompat endpoint) {
|
||||
int iconRes;
|
||||
switch (endpoint.getType()) {
|
||||
case CallEndpointCompat.TYPE_EARPIECE:
|
||||
iconRes = R.drawable.ic_phone_in_talk;
|
||||
break;
|
||||
case CallEndpointCompat.TYPE_SPEAKER:
|
||||
iconRes = R.drawable.ic_volume_up;
|
||||
break;
|
||||
case CallEndpointCompat.TYPE_BLUETOOTH:
|
||||
iconRes = R.drawable.ic_bluetooth_audio;
|
||||
break;
|
||||
case CallEndpointCompat.TYPE_WIRED_HEADSET:
|
||||
iconRes = R.drawable.ic_headset;
|
||||
break;
|
||||
case CallEndpointCompat.TYPE_STREAMING:
|
||||
iconRes = R.drawable.ic_cast;
|
||||
break;
|
||||
default:
|
||||
iconRes = R.drawable.ic_volume_up;
|
||||
break;
|
||||
}
|
||||
return iconRes;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,456 @@
|
||||
package org.thoughtcrime.securesms.calls;
|
||||
|
||||
import android.app.Application;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.os.Build;
|
||||
import android.telecom.DisconnectCause;
|
||||
import android.util.Log;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.core.telecom.CallEndpointCompat;
|
||||
import androidx.lifecycle.AndroidViewModel;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MediatorLiveData;
|
||||
import androidx.lifecycle.Observer;
|
||||
import java.util.List;
|
||||
import org.webrtc.PeerConnection;
|
||||
import org.webrtc.VideoTrack;
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
public class CallViewModel extends AndroidViewModel {
|
||||
|
||||
private static final String TAG = CallViewModel.class.getSimpleName();
|
||||
|
||||
private final CallCoordinator callCoordinator;
|
||||
|
||||
// UI State LiveData (from Coordinator)
|
||||
|
||||
private final LiveData<VideoTrack> localVideoTrack;
|
||||
private final LiveData<VideoTrack> remoteVideoTrack;
|
||||
private final LiveData<Boolean> localAudioEnabled;
|
||||
private final LiveData<Boolean> localVideoEnabled;
|
||||
private final LiveData<Boolean> remoteAudioEnabled;
|
||||
private final LiveData<Boolean> remoteVideoEnabled;
|
||||
private final LiveData<Boolean> isRelayUsed;
|
||||
private final LiveData<String> errorMessage;
|
||||
private final LiveData<String> displayName;
|
||||
private final LiveData<Icon> displayIcon;
|
||||
private final LiveData<Boolean> outgoingCallPlaced;
|
||||
private final LiveData<CallEndpointCompat> currentAudioEndpoint;
|
||||
private final LiveData<List<CallEndpointCompat>> availableAudioEndpoints;
|
||||
|
||||
// Translated from coordinator's connectionState
|
||||
private final MediatorLiveData<CallState> callState;
|
||||
|
||||
// Observer References for one-time observe
|
||||
private Observer<VideoTrack> answerCallObserver;
|
||||
private Observer<VideoTrack> startOutgoingCallObserver;
|
||||
|
||||
private boolean hasCallEnded = false;
|
||||
|
||||
// User-facing call states
|
||||
public enum CallState {
|
||||
INITIALIZING,
|
||||
PROMPTING_USER_ACCEPT,
|
||||
RINGING,
|
||||
CONNECTING,
|
||||
CONNECTED,
|
||||
RECONNECTING,
|
||||
ENDED,
|
||||
ERROR
|
||||
}
|
||||
|
||||
public CallViewModel(@NonNull Application application) {
|
||||
super(application);
|
||||
|
||||
this.callCoordinator = CallCoordinator.getInstance(application);
|
||||
|
||||
// Setup LiveData observations
|
||||
this.localVideoTrack = callCoordinator.getLocalVideoTrack();
|
||||
this.remoteVideoTrack = callCoordinator.getRemoteVideoTrack();
|
||||
this.localAudioEnabled = callCoordinator.getLocalAudioEnabled();
|
||||
this.localVideoEnabled = callCoordinator.getLocalVideoEnabled();
|
||||
this.remoteAudioEnabled = callCoordinator.getRemoteAudioEnabled();
|
||||
this.remoteVideoEnabled = callCoordinator.getRemoteVideoEnabled();
|
||||
this.isRelayUsed = callCoordinator.getIsRelayUsed();
|
||||
this.errorMessage = callCoordinator.getErrorMessage();
|
||||
this.displayName = callCoordinator.getDisplayName();
|
||||
this.displayIcon = callCoordinator.getDisplayIcon();
|
||||
this.outgoingCallPlaced = callCoordinator.getOutgoingCallPlaced();
|
||||
this.currentAudioEndpoint = callCoordinator.getCurrentAudioEndpoint();
|
||||
this.availableAudioEndpoints = callCoordinator.getAvailableAudioEndpoints();
|
||||
|
||||
this.callState = new MediatorLiveData<>(CallState.INITIALIZING);
|
||||
|
||||
setupConnectionStateObserver();
|
||||
|
||||
Log.d(TAG, "CallViewModel created");
|
||||
}
|
||||
|
||||
public void initialize() {
|
||||
Log.d(TAG, "Initializing CallViewModel");
|
||||
|
||||
callCoordinator.setActiveCallViewModel(this);
|
||||
|
||||
if (callCoordinator.isIncomingCall()) {
|
||||
callState.setValue(CallState.PROMPTING_USER_ACCEPT);
|
||||
} else {
|
||||
callState.setValue(CallState.CONNECTING);
|
||||
}
|
||||
|
||||
Log.d(TAG, "CallViewModel initialized");
|
||||
}
|
||||
|
||||
private void setupConnectionStateObserver() {
|
||||
callState.addSource(
|
||||
callCoordinator.getConnectionState(),
|
||||
state -> {
|
||||
CallState newState = translateConnectionState(state);
|
||||
|
||||
if (callState.getValue() != newState) {
|
||||
callState.setValue(newState);
|
||||
}
|
||||
|
||||
if (state == PeerConnection.PeerConnectionState.FAILED
|
||||
|| state == PeerConnection.PeerConnectionState.CLOSED) {
|
||||
if (!hasCallEnded) {
|
||||
hasCallEnded = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
callState.addSource(
|
||||
outgoingCallPlaced,
|
||||
placed -> {
|
||||
if (Boolean.TRUE.equals(placed) && !callCoordinator.isIncomingCall()) {
|
||||
if (callState.getValue() == CallState.CONNECTING) {
|
||||
callState.setValue(CallState.RINGING);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private CallState translateConnectionState(PeerConnection.PeerConnectionState state) {
|
||||
switch (state) {
|
||||
case NEW:
|
||||
if (callCoordinator.isIncomingCall()) {
|
||||
return CallState.PROMPTING_USER_ACCEPT;
|
||||
} else {
|
||||
return CallState.RINGING;
|
||||
}
|
||||
|
||||
case CONNECTING:
|
||||
if (callCoordinator.isIncomingCall()) {
|
||||
return CallState.CONNECTING;
|
||||
} else {
|
||||
return Boolean.TRUE.equals(outgoingCallPlaced.getValue())
|
||||
? CallState.RINGING
|
||||
: CallState.CONNECTING;
|
||||
}
|
||||
|
||||
case CONNECTED:
|
||||
return CallState.CONNECTED;
|
||||
|
||||
case DISCONNECTED:
|
||||
return CallState.RECONNECTING;
|
||||
|
||||
case FAILED:
|
||||
return CallState.ERROR;
|
||||
|
||||
case CLOSED:
|
||||
return CallState.ENDED;
|
||||
|
||||
default:
|
||||
return CallState.INITIALIZING;
|
||||
}
|
||||
}
|
||||
|
||||
// Call Control
|
||||
|
||||
public void answerCall() {
|
||||
Log.d(TAG, "answerCall");
|
||||
|
||||
if (!callCoordinator.isIncomingCall()) {
|
||||
Log.w(TAG, "answerCall() called but this is not an incoming call");
|
||||
return;
|
||||
}
|
||||
|
||||
// System integration
|
||||
callCoordinator.handleCallControlScopeAnswer();
|
||||
|
||||
answerCallWhenReady();
|
||||
}
|
||||
|
||||
/** Answer incoming call (WebRTC only) Used when system answer already happened */
|
||||
public void answerCallWhenReady() {
|
||||
Log.d(TAG, "answerCallWhenReady");
|
||||
|
||||
if (callCoordinator.hasOngoingCall()) {
|
||||
Log.w(TAG, "Call already ongoing, not starting duplicate");
|
||||
return;
|
||||
}
|
||||
|
||||
// Start media capture
|
||||
callCoordinator.startMediaCapture();
|
||||
|
||||
// Create one-time observer
|
||||
LiveData<VideoTrack> localTrack = callCoordinator.getLocalVideoTrack();
|
||||
|
||||
answerCallObserver =
|
||||
new Observer<VideoTrack>() {
|
||||
@Override
|
||||
public void onChanged(VideoTrack videoTrack) {
|
||||
if (videoTrack != null) {
|
||||
// Media is ready, remove observer
|
||||
localTrack.removeObserver(this);
|
||||
answerCallObserver = null;
|
||||
|
||||
Log.d(TAG, "Local video ready, answering call (WebRTC)");
|
||||
|
||||
callCoordinator.answerWebRTC();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
localTrack.observeForever(answerCallObserver);
|
||||
}
|
||||
|
||||
/** Start outgoing call with media capture Called by Activity for outgoing calls */
|
||||
public void startOutgoingCallWhenReady() {
|
||||
Log.d(TAG, "startOutgoingCallWhenReady");
|
||||
|
||||
if (callCoordinator.hasOngoingCall()) {
|
||||
Log.w(TAG, "Call already ongoing, not starting duplicate");
|
||||
return;
|
||||
}
|
||||
|
||||
callCoordinator.startMediaCapture();
|
||||
|
||||
// Create one-time observer
|
||||
LiveData<VideoTrack> localTrack = callCoordinator.getLocalVideoTrack();
|
||||
VideoTrack currentValue = localTrack.getValue();
|
||||
|
||||
if (currentValue != null) {
|
||||
Log.d(TAG, "Media already ready, starting call immediately");
|
||||
callCoordinator.startOutgoingCall();
|
||||
} else {
|
||||
startOutgoingCallObserver =
|
||||
new Observer<VideoTrack>() {
|
||||
@Override
|
||||
public void onChanged(VideoTrack videoTrack) {
|
||||
if (videoTrack != null) {
|
||||
// Media is ready, remove observer
|
||||
localTrack.removeObserver(this);
|
||||
startOutgoingCallObserver = null;
|
||||
|
||||
Log.d(TAG, "Local video ready, starting outgoing call");
|
||||
|
||||
callCoordinator.startOutgoingCall();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
localTrack.observeForever(startOutgoingCallObserver);
|
||||
}
|
||||
}
|
||||
|
||||
public void declineCall() {
|
||||
Log.d(TAG, "declineCall");
|
||||
|
||||
if (hasCallEnded) {
|
||||
Log.w(TAG, "Call already ended");
|
||||
return;
|
||||
}
|
||||
hasCallEnded = true;
|
||||
|
||||
callCoordinator.declineCall();
|
||||
}
|
||||
|
||||
public void hangUp() {
|
||||
Log.d(TAG, "hangUp");
|
||||
|
||||
if (hasCallEnded) {
|
||||
Log.w(TAG, "Call already ended");
|
||||
return;
|
||||
}
|
||||
hasCallEnded = true;
|
||||
|
||||
callCoordinator.hangUp();
|
||||
}
|
||||
|
||||
public void toggleAudio() {
|
||||
Boolean current = localAudioEnabled.getValue();
|
||||
boolean newState = current == null || !current;
|
||||
|
||||
Log.d(TAG, "toggleAudio: " + newState);
|
||||
|
||||
callCoordinator.setAudioEnabled(newState);
|
||||
}
|
||||
|
||||
public void toggleVideo() {
|
||||
Boolean current = localVideoEnabled.getValue();
|
||||
boolean newState = current == null || !current;
|
||||
|
||||
Log.d(TAG, "toggleVideo: " + newState);
|
||||
|
||||
callCoordinator.setVideoEnabled(newState);
|
||||
}
|
||||
|
||||
public void switchCamera() {
|
||||
Log.d(TAG, "switchCamera");
|
||||
|
||||
callCoordinator.switchCamera();
|
||||
}
|
||||
|
||||
public void selectAudioDevice(CallEndpointCompat endpoint) {
|
||||
Log.d(TAG, "selectAudioDevice: " + endpoint.getName());
|
||||
|
||||
callCoordinator.requestAudioEndpointChange(endpoint);
|
||||
}
|
||||
|
||||
public void switchToEarpiece(boolean shallUseEarpiece) {
|
||||
Log.d(TAG, "switchToEarpiece: shallUseEarpiece: " + shallUseEarpiece);
|
||||
|
||||
List<CallEndpointCompat> endpoints = availableAudioEndpoints.getValue();
|
||||
|
||||
if (endpoints == null) {
|
||||
Log.w(TAG, "No available audio endpoint");
|
||||
return;
|
||||
}
|
||||
|
||||
CallEndpointCompat targetEndpoint = null;
|
||||
for (CallEndpointCompat endpoint : endpoints) {
|
||||
boolean isEarpiece = endpoint.getType() == CallEndpointCompat.TYPE_EARPIECE;
|
||||
if (isEarpiece == shallUseEarpiece) {
|
||||
targetEndpoint = endpoint;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (targetEndpoint != null) {
|
||||
selectAudioDevice(targetEndpoint);
|
||||
}
|
||||
}
|
||||
|
||||
public void setStartsWithVideo(boolean startsWithVideo) {
|
||||
Log.d(TAG, "setStartsWithVideo: " + startsWithVideo);
|
||||
callCoordinator.setStartsWithVideo(startsWithVideo);
|
||||
}
|
||||
|
||||
// CallControlScope Callbacks
|
||||
|
||||
public void onCallAnswered() {
|
||||
Log.d(TAG, "onCallAnswered callback from CallControlScope");
|
||||
}
|
||||
|
||||
public void onCallActive() {
|
||||
Log.d(TAG, "onCallActive callback from CallControlScope");
|
||||
}
|
||||
|
||||
public void onCallInactive() {
|
||||
Log.d(TAG, "onCallInactive callback from CallControlScope");
|
||||
}
|
||||
|
||||
public void onCallDisconnected(DisconnectCause disconnectCause) {
|
||||
Log.d(TAG, "onCallDisconnected callback from CallControlScope, cause: " + disconnectCause);
|
||||
|
||||
if (!hasCallEnded) {
|
||||
hasCallEnded = true;
|
||||
callState.postValue(CallState.ENDED);
|
||||
}
|
||||
}
|
||||
|
||||
// LiveData Getters
|
||||
|
||||
public LiveData<CallState> getCallState() {
|
||||
return callState;
|
||||
}
|
||||
|
||||
public LiveData<Boolean> getAudioEnabled() {
|
||||
return localAudioEnabled;
|
||||
}
|
||||
|
||||
public LiveData<Boolean> getVideoEnabled() {
|
||||
return localVideoEnabled;
|
||||
}
|
||||
|
||||
public LiveData<Boolean> getRemoteAudioEnabled() {
|
||||
return remoteAudioEnabled;
|
||||
}
|
||||
|
||||
public LiveData<Boolean> getRemoteVideoEnabled() {
|
||||
return remoteVideoEnabled;
|
||||
}
|
||||
|
||||
public LiveData<VideoTrack> getLocalVideoTrack() {
|
||||
return localVideoTrack;
|
||||
}
|
||||
|
||||
public LiveData<VideoTrack> getRemoteVideoTrack() {
|
||||
return remoteVideoTrack;
|
||||
}
|
||||
|
||||
public LiveData<String> getErrorMessage() {
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
public LiveData<Boolean> getIsRelayUsed() {
|
||||
return isRelayUsed;
|
||||
}
|
||||
|
||||
public LiveData<String> getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public LiveData<Icon> getDisplayIcon() {
|
||||
return displayIcon;
|
||||
}
|
||||
|
||||
public LiveData<CallEndpointCompat> getCurrentAudioEndpoint() {
|
||||
return currentAudioEndpoint;
|
||||
}
|
||||
|
||||
public LiveData<List<CallEndpointCompat>> getAvailableAudioEndpoints() {
|
||||
return availableAudioEndpoints;
|
||||
}
|
||||
|
||||
// Notification Action Handlers
|
||||
|
||||
public void handleNotificationAnswer() {
|
||||
Log.d(TAG, "handleNotificationAnswer");
|
||||
|
||||
answerCall();
|
||||
}
|
||||
|
||||
public void handleNotificationDecline() {
|
||||
Log.d(TAG, "handleNotificationDecline");
|
||||
|
||||
declineCall();
|
||||
}
|
||||
|
||||
public void handleNotificationHangup() {
|
||||
Log.d(TAG, "handleNotificationHangup");
|
||||
|
||||
hangUp();
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
|
||||
@Override
|
||||
protected void onCleared() {
|
||||
super.onCleared();
|
||||
Log.d(TAG, "CallViewModel cleared");
|
||||
|
||||
if (answerCallObserver != null) {
|
||||
callCoordinator.getLocalVideoTrack().removeObserver(answerCallObserver);
|
||||
answerCallObserver = null;
|
||||
}
|
||||
|
||||
if (startOutgoingCallObserver != null) {
|
||||
callCoordinator.getLocalVideoTrack().removeObserver(startOutgoingCallObserver);
|
||||
startOutgoingCallObserver = null;
|
||||
}
|
||||
|
||||
callCoordinator.clearActiveCallViewModel();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
package org.thoughtcrime.securesms.calls;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import org.thoughtcrime.securesms.EglUtils;
|
||||
import org.webrtc.AudioSource;
|
||||
import org.webrtc.AudioTrack;
|
||||
import org.webrtc.Camera2Enumerator;
|
||||
import org.webrtc.CameraVideoCapturer;
|
||||
import org.webrtc.MediaConstraints;
|
||||
import org.webrtc.MediaStream;
|
||||
import org.webrtc.PeerConnectionFactory;
|
||||
import org.webrtc.SurfaceTextureHelper;
|
||||
import org.webrtc.VideoCapturer;
|
||||
import org.webrtc.VideoSource;
|
||||
import org.webrtc.VideoTrack;
|
||||
|
||||
public class MediaStreamManager {
|
||||
|
||||
private static final String TAG = MediaStreamManager.class.getSimpleName();
|
||||
private static final String STREAM_ID = "local_stream";
|
||||
private static final String AUDIO_TRACK_ID = "audio_track";
|
||||
private static final String VIDEO_TRACK_ID = "video_track";
|
||||
|
||||
private final Context context;
|
||||
private final PeerConnectionFactory peerConnectionFactory;
|
||||
|
||||
private VideoCapturer videoCapturer;
|
||||
private VideoSource videoSource;
|
||||
private AudioSource audioSource;
|
||||
private SurfaceTextureHelper surfaceTextureHelper;
|
||||
|
||||
public interface Callback {
|
||||
void onMediaStreamReady(MediaStream stream);
|
||||
|
||||
void onError(String error);
|
||||
}
|
||||
|
||||
public MediaStreamManager(@NonNull Context context, PeerConnectionFactory peerConnectionFactory) {
|
||||
this.context = context.getApplicationContext();
|
||||
|
||||
this.peerConnectionFactory = peerConnectionFactory;
|
||||
}
|
||||
|
||||
/** Create media stream with audio and optionally video */
|
||||
public void createMediaStream(Callback callback) {
|
||||
try {
|
||||
MediaStream mediaStream = peerConnectionFactory.createLocalMediaStream(STREAM_ID);
|
||||
|
||||
// Create audio track
|
||||
MediaConstraints audioConstraints = new MediaConstraints();
|
||||
audioSource = peerConnectionFactory.createAudioSource(audioConstraints);
|
||||
AudioTrack audioTrack = peerConnectionFactory.createAudioTrack(AUDIO_TRACK_ID, audioSource);
|
||||
mediaStream.addTrack(audioTrack);
|
||||
|
||||
// Create video track
|
||||
videoCapturer = createVideoCapturer();
|
||||
if (videoCapturer == null) {
|
||||
callback.onError("No camera available");
|
||||
callback.onMediaStreamReady(mediaStream);
|
||||
return;
|
||||
}
|
||||
|
||||
videoSource = peerConnectionFactory.createVideoSource(videoCapturer.isScreencast());
|
||||
VideoTrack videoTrack = peerConnectionFactory.createVideoTrack(VIDEO_TRACK_ID, videoSource);
|
||||
mediaStream.addTrack(videoTrack);
|
||||
|
||||
// Start capturing
|
||||
surfaceTextureHelper =
|
||||
SurfaceTextureHelper.create("CaptureThread", EglUtils.getEglBase().getEglBaseContext());
|
||||
videoCapturer.initialize(surfaceTextureHelper, context, videoSource.getCapturerObserver());
|
||||
videoCapturer.startCapture(1280, 720, 30);
|
||||
|
||||
callback.onMediaStreamReady(mediaStream);
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Failed to create media stream", e);
|
||||
callback.onError("Failed to access camera/microphone: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private VideoCapturer createVideoCapturer() {
|
||||
Camera2Enumerator enumerator = new Camera2Enumerator(context);
|
||||
|
||||
// Try front camera first
|
||||
String[] deviceNames = enumerator.getDeviceNames();
|
||||
for (String deviceName : deviceNames) {
|
||||
if (enumerator.isFrontFacing(deviceName)) {
|
||||
VideoCapturer capturer = enumerator.createCapturer(deviceName, null);
|
||||
if (capturer != null) {
|
||||
return capturer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fall back to any camera
|
||||
for (String deviceName : deviceNames) {
|
||||
VideoCapturer capturer = enumerator.createCapturer(deviceName, null);
|
||||
if (capturer != null) {
|
||||
return capturer;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void switchCamera() {
|
||||
if (videoCapturer instanceof CameraVideoCapturer) {
|
||||
CameraVideoCapturer cameraVideoCapturer = (CameraVideoCapturer) videoCapturer;
|
||||
cameraVideoCapturer.switchCamera(null);
|
||||
Log.d(TAG, "Camera switched");
|
||||
}
|
||||
}
|
||||
|
||||
/** Cleanup resources */
|
||||
public void dispose() {
|
||||
if (videoCapturer != null) {
|
||||
try {
|
||||
videoCapturer.stopCapture();
|
||||
} catch (InterruptedException e) {
|
||||
Log.e(TAG, "Error stopping capture", e);
|
||||
}
|
||||
videoCapturer.dispose();
|
||||
videoCapturer = null;
|
||||
}
|
||||
|
||||
if (surfaceTextureHelper != null) {
|
||||
surfaceTextureHelper.dispose();
|
||||
surfaceTextureHelper = null;
|
||||
}
|
||||
|
||||
if (videoSource != null) {
|
||||
videoSource.dispose();
|
||||
videoSource = null;
|
||||
}
|
||||
|
||||
if (audioSource != null) {
|
||||
audioSource.dispose();
|
||||
audioSource = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,125 +3,128 @@ package org.thoughtcrime.securesms.connect;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.DcEvent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Hashtable;
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.service.FetchForegroundService;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Hashtable;
|
||||
|
||||
public class DcEventCenter {
|
||||
private static final String TAG = DcEventCenter.class.getSimpleName();
|
||||
private @NonNull final Hashtable<Integer, ArrayList<DcEventDelegate>> currentAccountObservers = new Hashtable<>();
|
||||
private @NonNull final Hashtable<Integer, ArrayList<DcEventDelegate>> multiAccountObservers = new Hashtable<>();
|
||||
private final Object LOCK = new Object();
|
||||
private final @NonNull ApplicationContext context;
|
||||
private static final String TAG = DcEventCenter.class.getSimpleName();
|
||||
private @NonNull final Hashtable<Integer, ArrayList<DcEventDelegate>> currentAccountObservers =
|
||||
new Hashtable<>();
|
||||
private @NonNull final Hashtable<Integer, ArrayList<DcEventDelegate>> multiAccountObservers =
|
||||
new Hashtable<>();
|
||||
private final Object LOCK = new Object();
|
||||
private final @NonNull ApplicationContext context;
|
||||
|
||||
public interface DcEventDelegate {
|
||||
void handleEvent(@NonNull DcEvent event);
|
||||
default boolean runOnMain() {
|
||||
return true;
|
||||
public interface DcEventDelegate {
|
||||
void handleEvent(@NonNull DcEvent event);
|
||||
|
||||
default boolean runOnMain() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public DcEventCenter(@NonNull Context context) {
|
||||
this.context = ApplicationContext.getInstance(context);
|
||||
}
|
||||
|
||||
public void addObserver(int eventId, @NonNull DcEventDelegate observer) {
|
||||
addObserver(currentAccountObservers, eventId, observer);
|
||||
}
|
||||
|
||||
public void addMultiAccountObserver(int eventId, @NonNull DcEventDelegate observer) {
|
||||
addObserver(multiAccountObservers, eventId, observer);
|
||||
}
|
||||
|
||||
private void addObserver(
|
||||
Hashtable<Integer, ArrayList<DcEventDelegate>> observers,
|
||||
int eventId,
|
||||
@NonNull DcEventDelegate observer) {
|
||||
synchronized (LOCK) {
|
||||
ArrayList<DcEventDelegate> idObservers = observers.get(eventId);
|
||||
if (idObservers == null) {
|
||||
observers.put(eventId, (idObservers = new ArrayList<>()));
|
||||
}
|
||||
idObservers.add(observer);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeObserver(int eventId, DcEventDelegate observer) {
|
||||
synchronized (LOCK) {
|
||||
ArrayList<DcEventDelegate> idObservers = currentAccountObservers.get(eventId);
|
||||
if (idObservers != null) {
|
||||
idObservers.remove(observer);
|
||||
}
|
||||
idObservers = multiAccountObservers.get(eventId);
|
||||
if (idObservers != null) {
|
||||
idObservers.remove(observer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeObservers(DcEventDelegate observer) {
|
||||
synchronized (LOCK) {
|
||||
for (Integer eventId : currentAccountObservers.keySet()) {
|
||||
ArrayList<DcEventDelegate> idObservers = currentAccountObservers.get(eventId);
|
||||
if (idObservers != null) {
|
||||
idObservers.remove(observer);
|
||||
}
|
||||
}
|
||||
|
||||
public DcEventCenter(@NonNull Context context) {
|
||||
this.context = ApplicationContext.getInstance(context);
|
||||
}
|
||||
|
||||
public void addObserver(int eventId, @NonNull DcEventDelegate observer) {
|
||||
addObserver(currentAccountObservers, eventId, observer);
|
||||
}
|
||||
|
||||
public void addMultiAccountObserver(int eventId, @NonNull DcEventDelegate observer) {
|
||||
addObserver(multiAccountObservers, eventId, observer);
|
||||
}
|
||||
|
||||
private void addObserver(Hashtable<Integer, ArrayList<DcEventDelegate>> observers, int eventId, @NonNull DcEventDelegate observer) {
|
||||
synchronized (LOCK) {
|
||||
ArrayList<DcEventDelegate> idObservers = observers.get(eventId);
|
||||
if (idObservers == null) {
|
||||
observers.put(eventId, (idObservers = new ArrayList<>()));
|
||||
}
|
||||
idObservers.add(observer);
|
||||
}
|
||||
for (Integer eventId : multiAccountObservers.keySet()) {
|
||||
ArrayList<DcEventDelegate> idObservers = multiAccountObservers.get(eventId);
|
||||
if (idObservers != null) {
|
||||
idObservers.remove(observer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeObserver(int eventId, DcEventDelegate observer) {
|
||||
synchronized (LOCK) {
|
||||
ArrayList<DcEventDelegate> idObservers = currentAccountObservers.get(eventId);
|
||||
if (idObservers != null) {
|
||||
idObservers.remove(observer);
|
||||
}
|
||||
idObservers = multiAccountObservers.get(eventId);
|
||||
if (idObservers != null) {
|
||||
idObservers.remove(observer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeObservers(DcEventDelegate observer) {
|
||||
synchronized (LOCK) {
|
||||
for(Integer eventId : currentAccountObservers.keySet()) {
|
||||
ArrayList<DcEventDelegate> idObservers = currentAccountObservers.get(eventId);
|
||||
if (idObservers != null) {
|
||||
idObservers.remove(observer);
|
||||
}
|
||||
}
|
||||
for(Integer eventId : multiAccountObservers.keySet()) {
|
||||
ArrayList<DcEventDelegate> idObservers = multiAccountObservers.get(eventId);
|
||||
if (idObservers != null) {
|
||||
idObservers.remove(observer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void sendToMultiAccountObservers(@NonNull DcEvent event) {
|
||||
sendToObservers(multiAccountObservers, event);
|
||||
}
|
||||
|
||||
private void sendToCurrentAccountObservers(@NonNull DcEvent event) {
|
||||
sendToObservers(currentAccountObservers, event);
|
||||
}
|
||||
|
||||
private void sendToObservers(Hashtable<Integer, ArrayList<DcEventDelegate>> observers, @NonNull DcEvent event) {
|
||||
synchronized (LOCK) {
|
||||
ArrayList<DcEventDelegate> idObservers = observers.get(event.getId());
|
||||
if (idObservers != null) {
|
||||
for (DcEventDelegate observer : idObservers) {
|
||||
// using try/catch blocks as under some circumstances eg. getContext() may return NULL -
|
||||
// and as this function is used virtually everywhere, also in libs,
|
||||
// it's not feasible to check all single occurrences.
|
||||
if(observer.runOnMain()) {
|
||||
Util.runOnMain(() -> {
|
||||
try {
|
||||
observer.handleEvent(event);
|
||||
}
|
||||
catch(Exception e) {
|
||||
Log.e(TAG, "Error calling observer.handleEvent()", e);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Util.runOnBackground(() -> {
|
||||
try {
|
||||
observer.handleEvent(event);
|
||||
}
|
||||
catch (Exception e) {
|
||||
Log.e(TAG, "Error calling observer.handleEvent()", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
private void sendToMultiAccountObservers(@NonNull DcEvent event) {
|
||||
sendToObservers(multiAccountObservers, event);
|
||||
}
|
||||
|
||||
private void sendToCurrentAccountObservers(@NonNull DcEvent event) {
|
||||
sendToObservers(currentAccountObservers, event);
|
||||
}
|
||||
|
||||
private void sendToObservers(
|
||||
Hashtable<Integer, ArrayList<DcEventDelegate>> observers, @NonNull DcEvent event) {
|
||||
synchronized (LOCK) {
|
||||
ArrayList<DcEventDelegate> idObservers = observers.get(event.getId());
|
||||
if (idObservers != null) {
|
||||
for (DcEventDelegate observer : idObservers) {
|
||||
// using try/catch blocks as under some circumstances eg. getContext() may return NULL -
|
||||
// and as this function is used virtually everywhere, also in libs,
|
||||
// it's not feasible to check all single occurrences.
|
||||
if (observer.runOnMain()) {
|
||||
Util.runOnMain(
|
||||
() -> {
|
||||
try {
|
||||
observer.handleEvent(event);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error calling observer.handleEvent()", e);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Util.runOnBackground(
|
||||
() -> {
|
||||
try {
|
||||
observer.handleEvent(event);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error calling observer.handleEvent()", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final Object lastErrorLock = new Object();
|
||||
private boolean showNextErrorAsToast = true;
|
||||
@@ -148,24 +151,26 @@ public class DcEventCenter {
|
||||
}
|
||||
|
||||
// show error to user
|
||||
Util.runOnMain(() -> {
|
||||
if (showAsToast) {
|
||||
String toastString = null;
|
||||
Util.runOnMain(
|
||||
() -> {
|
||||
if (showAsToast) {
|
||||
String toastString = null;
|
||||
|
||||
if (event == DcContext.DC_EVENT_ERROR_SELF_NOT_IN_GROUP) {
|
||||
toastString = context.getString(R.string.group_self_not_in_group);
|
||||
}
|
||||
if (event == DcContext.DC_EVENT_ERROR_SELF_NOT_IN_GROUP) {
|
||||
toastString = context.getString(R.string.group_self_not_in_group);
|
||||
}
|
||||
|
||||
ForegroundDetector foregroundDetector = ForegroundDetector.getInstance();
|
||||
if (toastString != null && (foregroundDetector == null || foregroundDetector.isForeground())) {
|
||||
Toast.makeText(context, toastString, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
});
|
||||
ForegroundDetector foregroundDetector = ForegroundDetector.getInstance();
|
||||
if (toastString != null
|
||||
&& (foregroundDetector == null || foregroundDetector.isForeground())) {
|
||||
Toast.makeText(context, toastString, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void handleLogging(@NonNull DcEvent event) {
|
||||
final String logPrefix = "[accId="+event.getAccountId()+ "] ";
|
||||
final String logPrefix = "[accId=" + event.getAccountId() + "] ";
|
||||
switch (event.getId()) {
|
||||
case DcContext.DC_EVENT_INFO:
|
||||
Log.i("DeltaChat", logPrefix + event.getData2Str());
|
||||
@@ -189,24 +194,19 @@ public class DcEventCenter {
|
||||
|
||||
switch (id) {
|
||||
case DcContext.DC_EVENT_INCOMING_MSG:
|
||||
DcHelper.getNotificationCenter(context).notifyMessage(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());
|
||||
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_INCOMING_CALL:
|
||||
DcHelper.getNotificationCenter(context).notifyCall(accountId, event.getData1Int(), event.getData2Str());
|
||||
break;
|
||||
|
||||
case DcContext.DC_EVENT_INCOMING_CALL_ACCEPTED:
|
||||
case DcContext.DC_EVENT_CALL_ENDED:
|
||||
DcHelper.getNotificationCenter(context).removeCallNotification(accountId, event.getData1Int());
|
||||
DcHelper.getNotificationCenter(context)
|
||||
.notifyWebxdc(accountId, event.getData1Int(), event.getData2Int(), event.getData2Str());
|
||||
break;
|
||||
|
||||
case DcContext.DC_EVENT_MSGS_NOTICED:
|
||||
@@ -214,7 +214,8 @@ public class DcEventCenter {
|
||||
break;
|
||||
|
||||
case DcContext.DC_EVENT_MSG_DELETED:
|
||||
DcHelper.getNotificationCenter(context).removeNotification(accountId, event.getData1Int(), event.getData2Int());
|
||||
DcHelper.getNotificationCenter(context)
|
||||
.removeNotification(accountId, event.getData1Int(), event.getData2Int());
|
||||
break;
|
||||
|
||||
case DcContext.DC_EVENT_ACCOUNTS_BACKGROUND_FETCH_DONE:
|
||||
|
||||
@@ -12,17 +12,19 @@ import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
import android.webkit.MimeTypeMap;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.core.content.FileProvider;
|
||||
|
||||
import chat.delta.rpc.Rpc;
|
||||
import chat.delta.rpc.RpcException;
|
||||
import com.b44t.messenger.DcAccounts;
|
||||
import com.b44t.messenger.DcChat;
|
||||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.DcLot;
|
||||
import com.b44t.messenger.DcMsg;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.BuildConfig;
|
||||
import org.thoughtcrime.securesms.LocalHelpActivity;
|
||||
@@ -38,83 +40,79 @@ import org.thoughtcrime.securesms.util.MediaUtil;
|
||||
import org.thoughtcrime.securesms.util.ShareUtil;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
|
||||
import chat.delta.rpc.Rpc;
|
||||
import chat.delta.rpc.RpcException;
|
||||
|
||||
public class DcHelper {
|
||||
|
||||
private static final String TAG = DcHelper.class.getSimpleName();
|
||||
private static final String TAG = DcHelper.class.getSimpleName();
|
||||
|
||||
public static final String CONFIG_CONFIGURED_ADDRESS = "configured_addr";
|
||||
public static final String CONFIG_DISPLAY_NAME = "displayname";
|
||||
public static final String CONFIG_SELF_STATUS = "selfstatus";
|
||||
public static final String CONFIG_SELF_AVATAR = "selfavatar";
|
||||
public static final String CONFIG_MVBOX_MOVE = "mvbox_move";
|
||||
public static final String CONFIG_ONLY_FETCH_MVBOX = "only_fetch_mvbox";
|
||||
public static final String CONFIG_BCC_SELF = "bcc_self";
|
||||
public static final String CONFIG_SHOW_EMAILS = "show_emails";
|
||||
public static final String CONFIG_MEDIA_QUALITY = "media_quality";
|
||||
public static final String CONFIG_PROXY_ENABLED = "proxy_enabled";
|
||||
public static final String CONFIG_PROXY_URL = "proxy_url";
|
||||
public static final String CONFIG_PRIVATE_TAG = "private_tag";
|
||||
public static final String CONFIG_STATS_SENDING = "stats_sending";
|
||||
public static final String CONFIG_STATS_ID = "stats_id";
|
||||
public static final String CONFIG_CONFIGURED_ADDRESS = "configured_addr";
|
||||
public static final String CONFIG_DISPLAY_NAME = "displayname";
|
||||
public static final String CONFIG_SELF_STATUS = "selfstatus";
|
||||
public static final String CONFIG_SELF_AVATAR = "selfavatar";
|
||||
public static final String CONFIG_MVBOX_MOVE = "mvbox_move";
|
||||
public static final String CONFIG_ONLY_FETCH_MVBOX = "only_fetch_mvbox";
|
||||
public static final String CONFIG_BCC_SELF = "bcc_self";
|
||||
public static final String CONFIG_SHOW_EMAILS = "show_emails";
|
||||
public static final String CONFIG_MEDIA_QUALITY = "media_quality";
|
||||
public static final String CONFIG_PROXY_ENABLED = "proxy_enabled";
|
||||
public static final String CONFIG_PROXY_URL = "proxy_url";
|
||||
public static final String CONFIG_PRIVATE_TAG = "private_tag";
|
||||
public static final String CONFIG_STATS_SENDING = "stats_sending";
|
||||
public static final String CONFIG_STATS_ID = "stats_id";
|
||||
|
||||
public static DcContext getContext(@NonNull Context context) {
|
||||
return ApplicationContext.getInstance(context).getDcContext();
|
||||
}
|
||||
public static DcContext getContext(@NonNull Context context) {
|
||||
return ApplicationContext.getInstance(context).getDcContext();
|
||||
}
|
||||
|
||||
public static Rpc getRpc(@NonNull Context context) {
|
||||
return ApplicationContext.getInstance(context).getRpc();
|
||||
}
|
||||
public static Rpc getRpc(@NonNull Context context) {
|
||||
return ApplicationContext.getInstance(context).getRpc();
|
||||
}
|
||||
|
||||
public static DcAccounts getAccounts(@NonNull Context context) {
|
||||
return ApplicationContext.getInstance(context).getDcAccounts();
|
||||
}
|
||||
public static DcAccounts getAccounts(@NonNull Context context) {
|
||||
return ApplicationContext.getInstance(context).getDcAccounts();
|
||||
}
|
||||
|
||||
public static DcEventCenter getEventCenter(@NonNull Context context) {
|
||||
return ApplicationContext.getInstance(context).getEventCenter();
|
||||
}
|
||||
public static DcEventCenter getEventCenter(@NonNull Context context) {
|
||||
return ApplicationContext.getInstance(context).getEventCenter();
|
||||
}
|
||||
|
||||
public static NotificationCenter getNotificationCenter(@NonNull Context context) {
|
||||
return ApplicationContext.getInstance(context).getNotificationCenter();
|
||||
}
|
||||
public static NotificationCenter getNotificationCenter(@NonNull Context context) {
|
||||
return ApplicationContext.getInstance(context).getNotificationCenter();
|
||||
}
|
||||
|
||||
public static boolean isConfigured(Context context) {
|
||||
DcContext dcContext = getContext(context);
|
||||
return dcContext.isConfigured() == 1;
|
||||
}
|
||||
public static boolean isConfigured(Context context) {
|
||||
DcContext dcContext = getContext(context);
|
||||
return dcContext.isConfigured() == 1;
|
||||
}
|
||||
|
||||
public static int getInt(Context context, String key) {
|
||||
DcContext dcContext = getContext(context);
|
||||
return dcContext.getConfigInt(key);
|
||||
}
|
||||
public static int getInt(Context context, String key) {
|
||||
DcContext dcContext = getContext(context);
|
||||
return dcContext.getConfigInt(key);
|
||||
}
|
||||
|
||||
public static String get(Context context, String key) {
|
||||
DcContext dcContext = getContext(context);
|
||||
return dcContext.getConfig(key);
|
||||
}
|
||||
public static String get(Context context, String key) {
|
||||
DcContext dcContext = getContext(context);
|
||||
return dcContext.getConfig(key);
|
||||
}
|
||||
|
||||
@Deprecated public static int getInt(Context context, String key, int defaultValue) {
|
||||
return getInt(context, key);
|
||||
}
|
||||
@Deprecated
|
||||
public static int getInt(Context context, String key, int defaultValue) {
|
||||
return getInt(context, key);
|
||||
}
|
||||
|
||||
@Deprecated public static String get(Context context, String key, String defaultValue) {
|
||||
return get(context, key);
|
||||
}
|
||||
@Deprecated
|
||||
public static String get(Context context, String key, String defaultValue) {
|
||||
return get(context, key);
|
||||
}
|
||||
|
||||
public static void set(Context context, String key, String value) {
|
||||
DcContext dcContext = getContext(context);
|
||||
dcContext.setConfig(key, value);
|
||||
}
|
||||
public static void set(Context context, String key, String value) {
|
||||
DcContext dcContext = getContext(context);
|
||||
dcContext.setConfig(key, value);
|
||||
}
|
||||
|
||||
public static void setStockTranslations(Context context) {
|
||||
DcContext dcContext = getContext(context);
|
||||
// the integers are defined in the core and used only here, an enum or sth. like that won't have a big benefit
|
||||
// the integers are defined in the core and used only here, an enum or sth. like that won't have
|
||||
// a big benefit
|
||||
dcContext.setStockTranslation(1, context.getString(R.string.chat_no_messages));
|
||||
dcContext.setStockTranslation(2, context.getString(R.string.self));
|
||||
dcContext.setStockTranslation(3, context.getString(R.string.draft));
|
||||
@@ -132,8 +130,13 @@ public class DcHelper {
|
||||
dcContext.setStockTranslation(68, context.getString(R.string.device_talk));
|
||||
dcContext.setStockTranslation(69, context.getString(R.string.saved_messages));
|
||||
dcContext.setStockTranslation(70, context.getString(R.string.device_talk_explain));
|
||||
dcContext.setStockTranslation(71, context.getString(R.string.device_welcome_message, "https://i.delta.chat/#0A45953086F0C166D3BAF1D4BB2025496E4C2704&x=3KvvQZfzU4t-9u5s0PF3USGp&i=X-QDZ681F6Plz_uBu47CKdg4&s=IwE4LraLDcdPBW597wB7DBnI&a=arcanechat%40arcanechat.me&n=ArcaneChat&g=ArcaneChat+Community"));
|
||||
dcContext.setStockTranslation(73, context.getString(R.string.systemmsg_subject_for_new_contact));
|
||||
dcContext.setStockTranslation(
|
||||
71,
|
||||
context.getString(
|
||||
R.string.device_welcome_message,
|
||||
"https://i.delta.chat/#0A45953086F0C166D3BAF1D4BB2025496E4C2704&x=MVPi07rQBEmHO4FRb3brpwDe&j=n8mkKqu42WAKKUCx1bQOVh23&s=AM1YCd_2hKuiSiTEb-2177On&a=arcanechat%40arcanechat.me&n=ArcaneChat&b=ArcaneChat+Channel"));
|
||||
dcContext.setStockTranslation(
|
||||
73, context.getString(R.string.systemmsg_subject_for_new_contact));
|
||||
dcContext.setStockTranslation(74, context.getString(R.string.systemmsg_failed_sending_to));
|
||||
dcContext.setStockTranslation(84, context.getString(R.string.configuration_failed_with_error));
|
||||
dcContext.setStockTranslation(85, context.getString(R.string.devicemsg_bad_time));
|
||||
@@ -160,9 +163,11 @@ public class DcHelper {
|
||||
dcContext.setStockTranslation(119, context.getString(R.string.qrshow_join_contact_hint));
|
||||
|
||||
// HACK: svg does not handle entities correctly and shows `"` as the text `quot;`.
|
||||
// until that is fixed, we fix the most obvious errors (core uses encode_minimal, so this does not affect so many characters)
|
||||
// until that is fixed, we fix the most obvious errors (core uses encode_minimal, so this does
|
||||
// not affect so many characters)
|
||||
// cmp. https://github.com/deltachat/deltachat-android/issues/2187
|
||||
dcContext.setStockTranslation(120, context.getString(R.string.qrshow_join_group_hint).replace("\"", ""));
|
||||
dcContext.setStockTranslation(
|
||||
120, context.getString(R.string.qrshow_join_group_hint).replace("\"", ""));
|
||||
dcContext.setStockTranslation(121, context.getString(R.string.connectivity_not_connected));
|
||||
dcContext.setStockTranslation(124, context.getString(R.string.group_name_changed_by_you));
|
||||
dcContext.setStockTranslation(125, context.getString(R.string.group_name_changed_by_other));
|
||||
@@ -179,9 +184,11 @@ public class DcHelper {
|
||||
dcContext.setStockTranslation(136, context.getString(R.string.location_enabled_by_you));
|
||||
dcContext.setStockTranslation(137, context.getString(R.string.location_enabled_by_other));
|
||||
dcContext.setStockTranslation(138, context.getString(R.string.ephemeral_timer_disabled_by_you));
|
||||
dcContext.setStockTranslation(139, context.getString(R.string.ephemeral_timer_disabled_by_other));
|
||||
dcContext.setStockTranslation(
|
||||
139, context.getString(R.string.ephemeral_timer_disabled_by_other));
|
||||
dcContext.setStockTranslation(140, context.getString(R.string.ephemeral_timer_seconds_by_you));
|
||||
dcContext.setStockTranslation(141, context.getString(R.string.ephemeral_timer_seconds_by_other));
|
||||
dcContext.setStockTranslation(
|
||||
141, context.getString(R.string.ephemeral_timer_seconds_by_other));
|
||||
dcContext.setStockTranslation(144, context.getString(R.string.ephemeral_timer_1_hour_by_you));
|
||||
dcContext.setStockTranslation(145, context.getString(R.string.ephemeral_timer_1_hour_by_other));
|
||||
dcContext.setStockTranslation(146, context.getString(R.string.ephemeral_timer_1_day_by_you));
|
||||
@@ -189,7 +196,8 @@ public class DcHelper {
|
||||
dcContext.setStockTranslation(148, context.getString(R.string.ephemeral_timer_1_week_by_you));
|
||||
dcContext.setStockTranslation(149, context.getString(R.string.ephemeral_timer_1_week_by_other));
|
||||
dcContext.setStockTranslation(150, context.getString(R.string.ephemeral_timer_minutes_by_you));
|
||||
dcContext.setStockTranslation(151, context.getString(R.string.ephemeral_timer_minutes_by_other));
|
||||
dcContext.setStockTranslation(
|
||||
151, context.getString(R.string.ephemeral_timer_minutes_by_other));
|
||||
dcContext.setStockTranslation(152, context.getString(R.string.ephemeral_timer_hours_by_you));
|
||||
dcContext.setStockTranslation(153, context.getString(R.string.ephemeral_timer_hours_by_other));
|
||||
dcContext.setStockTranslation(154, context.getString(R.string.ephemeral_timer_days_by_you));
|
||||
@@ -199,11 +207,14 @@ public class DcHelper {
|
||||
dcContext.setStockTranslation(158, context.getString(R.string.ephemeral_timer_1_year_by_you));
|
||||
dcContext.setStockTranslation(159, context.getString(R.string.ephemeral_timer_1_year_by_other));
|
||||
dcContext.setStockTranslation(162, context.getString(R.string.multidevice_qr_subtitle));
|
||||
dcContext.setStockTranslation(163, context.getString(R.string.multidevice_transfer_done_devicemsg));
|
||||
dcContext.setStockTranslation(170, context.getString(R.string.chat_protection_enabled_tap_to_learn_more));
|
||||
dcContext.setStockTranslation(
|
||||
163, context.getString(R.string.multidevice_transfer_done_devicemsg));
|
||||
dcContext.setStockTranslation(
|
||||
170, context.getString(R.string.chat_protection_enabled_tap_to_learn_more));
|
||||
dcContext.setStockTranslation(172, context.getString(R.string.chat_new_group_hint));
|
||||
dcContext.setStockTranslation(173, context.getString(R.string.member_x_added));
|
||||
dcContext.setStockTranslation(174, context.getString(R.string.invalid_unencrypted_tap_to_learn_more));
|
||||
dcContext.setStockTranslation(
|
||||
174, context.getString(R.string.invalid_unencrypted_tap_to_learn_more));
|
||||
dcContext.setStockTranslation(176, context.getString(R.string.reaction_by_you));
|
||||
dcContext.setStockTranslation(177, context.getString(R.string.reaction_by_other));
|
||||
dcContext.setStockTranslation(178, context.getString(R.string.member_x_removed));
|
||||
@@ -225,28 +236,35 @@ public class DcHelper {
|
||||
dcContext.setStockTranslation(234, context.getString(R.string.audio_call));
|
||||
dcContext.setStockTranslation(235, context.getString(R.string.video_call));
|
||||
dcContext.setStockTranslation(240, context.getString(R.string.chat_description_changed_by_you));
|
||||
dcContext.setStockTranslation(241, context.getString(R.string.chat_description_changed_by_other));
|
||||
dcContext.setStockTranslation(
|
||||
241, context.getString(R.string.chat_description_changed_by_other));
|
||||
dcContext.setStockTranslation(242, context.getString(R.string.messages_are_e2ee));
|
||||
}
|
||||
|
||||
public static File getImexDir() {
|
||||
// DIRECTORY_DOCUMENTS could be used but 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);
|
||||
}
|
||||
|
||||
// When the user shares a file to another app or opens a file in another app, it is added here.
|
||||
// `HashMap<file, mimetype>` where `file` is the name of the file in the blobdir (not the user-visible filename).
|
||||
// `HashMap<file, mimetype>` where `file` is the name of the file in the blobdir (not the
|
||||
// user-visible filename).
|
||||
public static final HashMap<String, String> sharedFiles = new HashMap<>();
|
||||
|
||||
public static void openForViewOrShare(Context activity, int msg_id, String cmd) {
|
||||
DcContext dcContext = getContext(activity);
|
||||
|
||||
if(!(activity instanceof Activity)) {
|
||||
if (!(activity instanceof Activity)) {
|
||||
// would be nicer to accepting only Activity objects,
|
||||
// however, typically in Android just Context objects are passed around (as this normally does not make a difference).
|
||||
// Accepting only Activity here would force callers to cast, which would easily result in even more ugliness.
|
||||
Toast.makeText(activity, "openForViewOrShare() expects an Activity object", Toast.LENGTH_LONG).show();
|
||||
// however, typically in Android just Context objects are passed around (as this normally does
|
||||
// not make a difference).
|
||||
// Accepting only Activity here would force callers to cast, which would easily result in even
|
||||
// more ugliness.
|
||||
Toast.makeText(activity, "openForViewOrShare() expects an Activity object", Toast.LENGTH_LONG)
|
||||
.show();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -257,7 +275,9 @@ public class DcHelper {
|
||||
try {
|
||||
File file = new File(path);
|
||||
if (!file.exists()) {
|
||||
Toast.makeText(activity, activity.getString(R.string.file_not_found, path), Toast.LENGTH_LONG).show();
|
||||
Toast.makeText(
|
||||
activity, activity.getString(R.string.file_not_found, path), Toast.LENGTH_LONG)
|
||||
.show();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -267,7 +287,14 @@ public class DcHelper {
|
||||
// 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));
|
||||
uri =
|
||||
Uri.parse(
|
||||
"content://"
|
||||
+ BuildConfig.APPLICATION_ID
|
||||
+ ".attachments/"
|
||||
+ Uri.encode(file.getName())
|
||||
+ "/"
|
||||
+ Uri.encode(filename));
|
||||
|
||||
// As different Android version handle uris in putExtra differently,
|
||||
// we also check on our own that the file was actually shared.
|
||||
@@ -275,7 +302,9 @@ public class DcHelper {
|
||||
sharedFiles.put(file.getName(), mimeType);
|
||||
} else {
|
||||
if (Build.VERSION.SDK_INT >= 24) {
|
||||
uri = FileProvider.getUriForFile(activity, BuildConfig.APPLICATION_ID + ".fileprovider", file);
|
||||
uri =
|
||||
FileProvider.getUriForFile(
|
||||
activity, BuildConfig.APPLICATION_ID + ".fileprovider", file);
|
||||
} else {
|
||||
uri = Uri.fromFile(file);
|
||||
}
|
||||
@@ -292,87 +321,108 @@ public class DcHelper {
|
||||
intent.putExtra(Intent.EXTRA_STREAM, uri);
|
||||
intent.putExtra(Intent.EXTRA_TEXT, msg.getText());
|
||||
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
activity.startActivity(Intent.createChooser(intent, activity.getString(R.string.chat_share_with_title)));
|
||||
activity.startActivity(
|
||||
Intent.createChooser(intent, activity.getString(R.string.chat_share_with_title)));
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
Toast.makeText(activity, String.format("%s (%s)", activity.getString(R.string.no_app_to_handle_data), mimeType), Toast.LENGTH_LONG).show();
|
||||
Toast.makeText(
|
||||
activity,
|
||||
String.format(
|
||||
"%s (%s)", activity.getString(R.string.no_app_to_handle_data), mimeType),
|
||||
Toast.LENGTH_LONG)
|
||||
.show();
|
||||
Log.i(TAG, "opening of external activity failed.", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendToChat(Context activity, byte[] data, String type, String fileName, String html, String subject, String text) {
|
||||
Intent intent = new Intent(activity, ShareActivity.class);
|
||||
intent.setAction(Intent.ACTION_SEND);
|
||||
ShareUtil.setIsFromWebxdc(intent, true);
|
||||
public static void sendToChat(
|
||||
Context activity,
|
||||
byte[] data,
|
||||
String type,
|
||||
String fileName,
|
||||
String html,
|
||||
String subject,
|
||||
String text) {
|
||||
Intent intent = new Intent(activity, ShareActivity.class);
|
||||
intent.setAction(Intent.ACTION_SEND);
|
||||
ShareUtil.setIsFromWebxdc(intent, true);
|
||||
|
||||
if (data != null) {
|
||||
String mimeType = "application/octet-stream";
|
||||
Uri uri = PersistentBlobProvider.getInstance().create(activity, data, mimeType, fileName);
|
||||
intent.setType(mimeType);
|
||||
intent.putExtra(Intent.EXTRA_STREAM, uri);
|
||||
ShareUtil.setSharedType(intent, type);
|
||||
ShareUtil.setSharedTitle(intent, activity.getString(R.string.send_file_to, fileName));
|
||||
} else {
|
||||
ShareUtil.setSharedTitle(intent, activity.getString(R.string.send_message_to));
|
||||
}
|
||||
if (data != null) {
|
||||
String mimeType = "application/octet-stream";
|
||||
Uri uri = PersistentBlobProvider.getInstance().create(activity, data, mimeType, fileName);
|
||||
intent.setType(mimeType);
|
||||
intent.putExtra(Intent.EXTRA_STREAM, uri);
|
||||
ShareUtil.setSharedType(intent, type);
|
||||
ShareUtil.setSharedTitle(intent, activity.getString(R.string.send_file_to, fileName));
|
||||
} else {
|
||||
ShareUtil.setSharedTitle(intent, activity.getString(R.string.send_message_to));
|
||||
}
|
||||
|
||||
if (text != null) {
|
||||
intent.putExtra(Intent.EXTRA_TEXT, text);
|
||||
}
|
||||
if (text != null) {
|
||||
intent.putExtra(Intent.EXTRA_TEXT, text);
|
||||
}
|
||||
|
||||
if (subject != null) {
|
||||
ShareUtil.setSharedSubject(intent, subject);
|
||||
}
|
||||
if (subject != null) {
|
||||
ShareUtil.setSharedSubject(intent, subject);
|
||||
}
|
||||
|
||||
if (html != null) {
|
||||
String mimeType = "application/octet-stream";
|
||||
Uri uri = PersistentBlobProvider.getInstance().create(activity, html.getBytes(), mimeType, "index.html");
|
||||
ShareUtil.setSharedHtml(intent, uri);
|
||||
}
|
||||
if (html != null) {
|
||||
String mimeType = "application/octet-stream";
|
||||
Uri uri =
|
||||
PersistentBlobProvider.getInstance()
|
||||
.create(activity, html.getBytes(), mimeType, "index.html");
|
||||
ShareUtil.setSharedHtml(intent, uri);
|
||||
}
|
||||
|
||||
activity.startActivity(intent);
|
||||
activity.startActivity(intent);
|
||||
}
|
||||
|
||||
private static void startActivity(Activity activity, Intent intent) {
|
||||
// request for permission to install apks on API 26+ if intent mimetype is an apk
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
|
||||
"application/vnd.android.package-archive".equals(intent.getType()) &&
|
||||
!activity.getPackageManager().canRequestPackageInstalls()) {
|
||||
activity.startActivity(new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES).setData(Uri.parse(String.format("package:%s", activity.getPackageName()))));
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
|
||||
&& "application/vnd.android.package-archive".equals(intent.getType())
|
||||
&& !activity.getPackageManager().canRequestPackageInstalls()) {
|
||||
activity.startActivity(
|
||||
new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES)
|
||||
.setData(Uri.parse(String.format("package:%s", activity.getPackageName()))));
|
||||
return;
|
||||
}
|
||||
activity.startActivity(intent);
|
||||
}
|
||||
|
||||
public static String checkMime(String path, String mimeType) {
|
||||
if(mimeType == null || mimeType.equals("application/octet-stream")) {
|
||||
if (mimeType == null || mimeType.equals("application/octet-stream")) {
|
||||
path = path.replaceAll(" ", "");
|
||||
String extension = MediaUtil.getFileExtensionFromUrl(path);
|
||||
String newType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
|
||||
if(newType != null) return newType;
|
||||
if (newType != null) return newType;
|
||||
}
|
||||
return mimeType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path of a not-yet-existing file in the blobdir with roughly the given filename
|
||||
* and the given extension.
|
||||
* In many cases, since we're using setFileAndDeduplicate now, this wouldn't be necessary anymore
|
||||
* and we could just create a file with a random filename,
|
||||
* but there are a few usages that still need the current behavior (like `openMaps()`).
|
||||
* Return the path of a not-yet-existing file in the blobdir with roughly the given filename and
|
||||
* the given extension. In many cases, since we're using setFileAndDeduplicate now, this wouldn't
|
||||
* be necessary anymore and we could just create a file with a random filename, but there are a
|
||||
* few usages that still need the current behavior (like `openMaps()`).
|
||||
*/
|
||||
public static String getBlobdirFile(DcContext dcContext, String filename, String ext) {
|
||||
filename = FileUtils.sanitizeFilename(filename);
|
||||
ext = FileUtils.sanitizeFilename(ext);
|
||||
String outPath = null;
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
String test = dcContext.getBlobdir() + "/" + filename + (i == 0 ? "" : i < 100 ? "-" + i : "-" + (new Date().getTime() + i)) + ext;
|
||||
String test =
|
||||
dcContext.getBlobdir()
|
||||
+ "/"
|
||||
+ filename
|
||||
+ (i == 0 ? "" : i < 100 ? "-" + i : "-" + (new Date().getTime() + i))
|
||||
+ ext;
|
||||
if (!new File(test).exists()) {
|
||||
outPath = test;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(outPath==null) {
|
||||
if (outPath == null) {
|
||||
// should not happen
|
||||
outPath = dcContext.getBlobdir() + "/" + Math.random();
|
||||
}
|
||||
@@ -380,19 +430,22 @@ public class DcHelper {
|
||||
}
|
||||
|
||||
public static String getBlobdirFile(DcContext dcContext, String path) {
|
||||
String filename = path.substring(path.lastIndexOf('/')+1); // is the whole path if '/' is not found (lastIndexOf() returns -1 then)
|
||||
String filename =
|
||||
path.substring(
|
||||
path.lastIndexOf('/')
|
||||
+ 1); // is the whole path if '/' is not found (lastIndexOf() returns -1 then)
|
||||
String ext = "";
|
||||
int point = filename.indexOf('.');
|
||||
if(point!=-1) {
|
||||
if (point != -1) {
|
||||
ext = filename.substring(point);
|
||||
filename = filename.substring(0, point);
|
||||
}
|
||||
return getBlobdirFile(dcContext, filename, ext);
|
||||
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static ThreadRecord getThreadRecord(Context context, DcLot summary, DcChat chat) { // adapted from ThreadDatabase.getCurrent()
|
||||
public static ThreadRecord getThreadRecord(
|
||||
Context context, DcLot summary, DcChat chat) { // adapted from ThreadDatabase.getCurrent()
|
||||
int chatId = chat.getId();
|
||||
|
||||
String body = summary.getText1();
|
||||
@@ -405,14 +458,23 @@ public class DcHelper {
|
||||
long date = summary.getTimestamp();
|
||||
int unreadCount = getContext(context).getFreshMsgCount(chatId);
|
||||
|
||||
return new ThreadRecord(body, recipient, date,
|
||||
unreadCount, chatId,
|
||||
chat.getVisibility(), chat.isSendingLocations(), chat.isMuted(), chat.isContactRequest(), summary);
|
||||
return new ThreadRecord(
|
||||
body,
|
||||
recipient,
|
||||
date,
|
||||
unreadCount,
|
||||
chatId,
|
||||
chat.getVisibility(),
|
||||
chat.isSendingLocations(),
|
||||
chat.isMuted(),
|
||||
chat.isContactRequest(),
|
||||
summary);
|
||||
}
|
||||
|
||||
public static boolean isNetworkConnected(Context context) {
|
||||
try {
|
||||
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
ConnectivityManager cm =
|
||||
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
NetworkInfo netInfo = cm.getActiveNetworkInfo();
|
||||
if (netInfo != null && netInfo.isConnected()) {
|
||||
return true;
|
||||
@@ -425,105 +487,110 @@ public class DcHelper {
|
||||
|
||||
/**
|
||||
* Gets a string you can show to the user with basic information about connectivity.
|
||||
*
|
||||
* @param context
|
||||
* @param connectedString Usually "Connected", but when using this as the title in
|
||||
* ConversationListActivity, we want to write "ArcaneChat"
|
||||
* or the user's display name there instead.
|
||||
* ConversationListActivity, we want to write "Delta Chat" or the user's display name there
|
||||
* instead.
|
||||
* @return
|
||||
*/
|
||||
public static String getConnectivitySummary(Context context, String connectedString) {
|
||||
int connectivity = getContext(context).getConnectivity();
|
||||
if (connectivity >= DcContext.DC_CONNECTIVITY_CONNECTED) {
|
||||
return connectedString;
|
||||
} else if (connectivity >= DcContext.DC_CONNECTIVITY_WORKING) {
|
||||
return context.getString(R.string.connectivity_updating);
|
||||
} else if (connectivity >= DcContext.DC_CONNECTIVITY_CONNECTING) {
|
||||
return context.getString(R.string.connectivity_connecting);
|
||||
} else {
|
||||
return context.getString(R.string.connectivity_not_connected);
|
||||
}
|
||||
int connectivity = getContext(context).getConnectivity();
|
||||
if (connectivity >= DcContext.DC_CONNECTIVITY_CONNECTED) {
|
||||
return connectedString;
|
||||
} else if (connectivity >= DcContext.DC_CONNECTIVITY_WORKING) {
|
||||
return context.getString(R.string.connectivity_updating);
|
||||
} else if (connectivity >= DcContext.DC_CONNECTIVITY_CONNECTING) {
|
||||
return context.getString(R.string.connectivity_connecting);
|
||||
} else {
|
||||
return context.getString(R.string.connectivity_not_connected);
|
||||
}
|
||||
}
|
||||
|
||||
public static void showProtectionEnabledDialog(Context context) {
|
||||
new AlertDialog.Builder(context)
|
||||
.setMessage(context.getString(R.string.chat_protection_enabled_explanation))
|
||||
.setNeutralButton(R.string.learn_more, (d, w) -> openHelp(context, "#e2ee"))
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.setCancelable(true)
|
||||
.show();
|
||||
.setMessage(context.getString(R.string.chat_protection_enabled_explanation))
|
||||
.setNeutralButton(R.string.learn_more, (d, w) -> openHelp(context, "#e2ee"))
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.setCancelable(true)
|
||||
.show();
|
||||
}
|
||||
|
||||
public static void showInvalidUnencryptedDialog(Context context) {
|
||||
new AlertDialog.Builder(context)
|
||||
.setMessage(context.getString(R.string.invalid_unencrypted_explanation))
|
||||
.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();
|
||||
.setMessage(context.getString(R.string.invalid_unencrypted_explanation))
|
||||
.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 openHelp(Context context, String section) {
|
||||
Intent intent = new Intent(context, LocalHelpActivity.class);
|
||||
if (section != null) { intent.putExtra(LocalHelpActivity.SECTION_EXTRA, section); }
|
||||
if (section != null) {
|
||||
intent.putExtra(LocalHelpActivity.SECTION_EXTRA, section);
|
||||
}
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
/**
|
||||
* For the PGP-Contacts migration, things can go wrong.
|
||||
* The migration happens when the account is setup, at which point no events can be sent yet.
|
||||
* So, instead, if something goes wrong, it's returned by getLastError().
|
||||
* This function shows the error message to the user.
|
||||
* <p>
|
||||
* A few releases after the PGP-contacts migration (which happened in 2025-05),
|
||||
* we can remove this function again.
|
||||
*/
|
||||
public static void maybeShowMigrationError(Context context) {
|
||||
try {
|
||||
String lastError = DcHelper.getRpc(context).getMigrationError(DcHelper.getContext(context).getAccountId());
|
||||
/**
|
||||
* For the PGP-Contacts migration, things can go wrong. The migration happens when the account is
|
||||
* setup, at which point no events can be sent yet. So, instead, if something goes wrong, it's
|
||||
* returned by getLastError(). This function shows the error message to the user.
|
||||
*
|
||||
* <p>A few releases after the PGP-contacts migration (which happened in 2025-05), we can remove
|
||||
* this function again.
|
||||
*/
|
||||
public static void maybeShowMigrationError(Context context) {
|
||||
try {
|
||||
String lastError =
|
||||
DcHelper.getRpc(context).getMigrationError(DcHelper.getContext(context).getAccountId());
|
||||
|
||||
if (lastError != null && !lastError.isEmpty()) {
|
||||
Log.w(TAG, "Opening account failed, trying to share error: " + lastError);
|
||||
if (lastError != null && !lastError.isEmpty()) {
|
||||
Log.w(TAG, "Opening account failed, trying to share error: " + lastError);
|
||||
|
||||
String subject = "Delta Chat failed to update";
|
||||
String email = "delta@merlinux.eu";
|
||||
String subject = "Delta Chat failed to update";
|
||||
String email = "delta@merlinux.eu";
|
||||
|
||||
new AlertDialog.Builder(context)
|
||||
.setMessage(context.getString(R.string.error_x, lastError))
|
||||
.setNeutralButton(R.string.global_menu_edit_copy_desktop, (d, which) -> {
|
||||
Util.writeTextToClipboard(context, lastError);
|
||||
})
|
||||
.setPositiveButton(R.string.menu_send, (d, which) -> {
|
||||
Intent sharingIntent = new Intent(
|
||||
Intent.ACTION_SENDTO, Uri.fromParts(
|
||||
"mailto", email, null
|
||||
)
|
||||
);
|
||||
sharingIntent.putExtra(Intent.EXTRA_EMAIL, new String[]{email});
|
||||
sharingIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
|
||||
sharingIntent.putExtra(Intent.EXTRA_TEXT, lastError);
|
||||
new AlertDialog.Builder(context)
|
||||
.setMessage(context.getString(R.string.error_x, lastError))
|
||||
.setNeutralButton(
|
||||
R.string.global_menu_edit_copy_desktop,
|
||||
(d, which) -> {
|
||||
Util.writeTextToClipboard(context, lastError);
|
||||
})
|
||||
.setPositiveButton(
|
||||
R.string.menu_send,
|
||||
(d, which) -> {
|
||||
Intent sharingIntent =
|
||||
new Intent(Intent.ACTION_SENDTO, Uri.fromParts("mailto", email, null));
|
||||
sharingIntent.putExtra(Intent.EXTRA_EMAIL, new String[] {email});
|
||||
sharingIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
|
||||
sharingIntent.putExtra(Intent.EXTRA_TEXT, lastError);
|
||||
|
||||
if (sharingIntent.resolveActivity(context.getPackageManager()) == null) {
|
||||
Log.w(TAG, "No email client found to send crash report");
|
||||
sharingIntent = new Intent(Intent.ACTION_SEND);
|
||||
sharingIntent.setType("text/plain");
|
||||
sharingIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
|
||||
sharingIntent.putExtra(Intent.EXTRA_TEXT, lastError);
|
||||
sharingIntent.putExtra(Intent.EXTRA_EMAIL, email);
|
||||
}
|
||||
if (sharingIntent.resolveActivity(context.getPackageManager()) == null) {
|
||||
Log.w(TAG, "No email client found to send crash report");
|
||||
sharingIntent = new Intent(Intent.ACTION_SEND);
|
||||
sharingIntent.setType("text/plain");
|
||||
sharingIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
|
||||
sharingIntent.putExtra(Intent.EXTRA_TEXT, lastError);
|
||||
sharingIntent.putExtra(Intent.EXTRA_EMAIL, email);
|
||||
}
|
||||
|
||||
Intent chooser =
|
||||
Intent.createChooser(sharingIntent, "Send using...");
|
||||
chooser.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
chooser.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
|
||||
Intent chooser = Intent.createChooser(sharingIntent, "Send using...");
|
||||
chooser.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
chooser.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
|
||||
|
||||
context.startActivity(chooser);
|
||||
})
|
||||
.setCancelable(false)
|
||||
.show();
|
||||
}
|
||||
} catch (RpcException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
context.startActivity(chooser);
|
||||
})
|
||||
.setCancelable(false)
|
||||
.show();
|
||||
}
|
||||
} catch (RpcException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
package org.thoughtcrime.securesms.notifications;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
import chat.delta.rpc.RpcException;
|
||||
|
||||
public class DeclineCallReceiver extends BroadcastReceiver {
|
||||
private static final String TAG = DeclineCallReceiver.class.getSimpleName();
|
||||
|
||||
public static final String DECLINE_ACTION = "org.thoughtcrime.securesms.notifications.DECLINE_CALL";
|
||||
public static final String ACCOUNT_ID_EXTRA = "account_id";
|
||||
public static final String CALL_ID_EXTRA = "call_id";
|
||||
|
||||
@Override
|
||||
public void onReceive(final Context context, Intent intent) {
|
||||
if (!DECLINE_ACTION.equals(intent.getAction())) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int accountId = intent.getIntExtra(ACCOUNT_ID_EXTRA, 0);
|
||||
final int callId = intent.getIntExtra(CALL_ID_EXTRA, 0);
|
||||
if (accountId == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Util.runOnAnyBackgroundThread(() -> {
|
||||
DcHelper.getNotificationCenter(context).removeCallNotification(accountId, callId);
|
||||
try {
|
||||
DcHelper.getRpc(context).endCall(accountId, callId);
|
||||
} catch (RpcException e) {
|
||||
Log.e(TAG, "Error", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -66,6 +66,71 @@ public class PersistentBlobProvider {
|
||||
|
||||
private PersistentBlobProvider() {}
|
||||
|
||||
public Uri create(
|
||||
@NonNull Context context,
|
||||
@NonNull File inputFile,
|
||||
@NonNull String mimeType,
|
||||
@Nullable String fileName,
|
||||
@Nullable Long fileSize)
|
||||
throws IOException {
|
||||
|
||||
if (!inputFile.exists()) {
|
||||
throw new IOException("Input file does not exist: " + inputFile.getAbsolutePath());
|
||||
}
|
||||
|
||||
final long id = System.currentTimeMillis();
|
||||
|
||||
if (fileName == null) {
|
||||
fileName = "file." + getExtensionFromMimeType(mimeType);
|
||||
}
|
||||
|
||||
if (fileSize == null) {
|
||||
fileSize = inputFile.length();
|
||||
}
|
||||
|
||||
File destFile = getModernCacheFile(context, id);
|
||||
|
||||
// Try move first
|
||||
boolean moved = inputFile.renameTo(destFile);
|
||||
|
||||
if (!moved) {
|
||||
// Move failed, copy instead
|
||||
InputStream input = null;
|
||||
OutputStream output = null;
|
||||
try {
|
||||
input = new FileInputStream(inputFile);
|
||||
output = new FileOutputStream(destFile);
|
||||
Util.copy(input, output);
|
||||
} finally {
|
||||
if (output != null) {
|
||||
try {
|
||||
output.close();
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
if (input != null) {
|
||||
try {
|
||||
input.close();
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final Uri uniqueUri =
|
||||
CONTENT_URI
|
||||
.buildUpon()
|
||||
.appendPath(mimeType)
|
||||
.appendPath(fileName)
|
||||
.appendEncodedPath(String.valueOf(fileSize))
|
||||
.appendEncodedPath(String.valueOf(System.currentTimeMillis()))
|
||||
.build();
|
||||
|
||||
return ContentUris.withAppendedId(uniqueUri, id);
|
||||
}
|
||||
|
||||
public Uri create(
|
||||
@NonNull Context context,
|
||||
@NonNull byte[] blobBytes,
|
||||
|
||||
@@ -16,7 +16,7 @@ import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import chat.delta.rpc.Rpc;
|
||||
import chat.delta.rpc.RpcException;
|
||||
import chat.delta.rpc.types.EnteredLoginParam;
|
||||
import chat.delta.rpc.types.TransportListEntry;
|
||||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.DcEvent;
|
||||
import com.google.zxing.integration.android.IntentIntegrator;
|
||||
@@ -53,7 +53,7 @@ public class RelayListActivity extends BaseActionBarActivity
|
||||
private ActivityResultLauncher<Intent> qrScannerLauncher;
|
||||
|
||||
/** Relay selected for context menu via onRelayLongClick() */
|
||||
private EnteredLoginParam contextMenuRelay = null;
|
||||
private TransportListEntry contextMenuRelay = null;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
@@ -162,7 +162,7 @@ public class RelayListActivity extends BaseActionBarActivity
|
||||
String finalMainRelayAddr = mainRelayAddr;
|
||||
|
||||
try {
|
||||
List<EnteredLoginParam> relays = rpc.listTransports(accId);
|
||||
List<TransportListEntry> relays = rpc.listTransportsEx(accId);
|
||||
|
||||
Util.runOnMain(() -> adapter.setRelays(relays, finalMainRelayAddr));
|
||||
} catch (RpcException e) {
|
||||
@@ -173,12 +173,12 @@ public class RelayListActivity extends BaseActionBarActivity
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRelayClick(EnteredLoginParam relay) {
|
||||
if (relay.addr != null && !relay.addr.equals(adapter.getMainRelay())) {
|
||||
public void onRelayClick(TransportListEntry relay) {
|
||||
if (relay.param.addr != null && !relay.param.addr.equals(adapter.getMainRelay())) {
|
||||
Util.runOnAnyBackgroundThread(
|
||||
() -> {
|
||||
try {
|
||||
rpc.setConfig(accId, DcHelper.CONFIG_CONFIGURED_ADDRESS, relay.addr);
|
||||
rpc.setConfig(accId, DcHelper.CONFIG_CONFIGURED_ADDRESS, relay.param.addr);
|
||||
} catch (RpcException e) {
|
||||
Log.e(TAG, "RPC.setConfig() failed", e);
|
||||
}
|
||||
@@ -189,7 +189,7 @@ public class RelayListActivity extends BaseActionBarActivity
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRelayLongClick(View view, EnteredLoginParam relay) {
|
||||
public void onRelayLongClick(View view, TransportListEntry relay) {
|
||||
contextMenuRelay = relay;
|
||||
registerForContextMenu(view);
|
||||
openContextMenu(view);
|
||||
@@ -201,8 +201,10 @@ public class RelayListActivity extends BaseActionBarActivity
|
||||
super.onCreateContextMenu(menu, v, menuInfo);
|
||||
getMenuInflater().inflate(R.menu.relay_item_context, menu);
|
||||
|
||||
boolean nonNullAddr = contextMenuRelay != null && contextMenuRelay.addr != null;
|
||||
boolean isMain = nonNullAddr && contextMenuRelay.addr.equals(adapter.getMainRelay());
|
||||
boolean nonNullAddr = contextMenuRelay != null && contextMenuRelay.param.addr != null;
|
||||
boolean isMain = nonNullAddr && contextMenuRelay.param.addr.equals(adapter.getMainRelay());
|
||||
|
||||
Util.redMenuItem(menu, R.id.menu_delete_relay);
|
||||
menu.findItem(R.id.menu_delete_relay).setVisible(!isMain);
|
||||
}
|
||||
|
||||
@@ -230,28 +232,40 @@ public class RelayListActivity extends BaseActionBarActivity
|
||||
return super.onContextItemSelected(item);
|
||||
}
|
||||
|
||||
private void onRelayEdit(EnteredLoginParam relay) {
|
||||
private void onRelayEdit(TransportListEntry relay) {
|
||||
Intent intent = new Intent(this, EditRelayActivity.class);
|
||||
intent.putExtra(EditRelayActivity.EXTRA_ADDR, relay.addr);
|
||||
intent.putExtra(EditRelayActivity.EXTRA_ADDR, relay.param.addr);
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
private void onRelayDelete(EnteredLoginParam relay) {
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle(R.string.remove_transport)
|
||||
.setMessage(getString(R.string.confirm_remove_transport, relay.addr))
|
||||
.setPositiveButton(
|
||||
R.string.ok,
|
||||
(dialog, which) -> {
|
||||
try {
|
||||
rpc.deleteTransport(accId, relay.addr);
|
||||
loadRelays();
|
||||
} catch (RpcException e) {
|
||||
Log.e(TAG, "RPC.deleteTransport() failed", e);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show();
|
||||
private void onRelayDelete(TransportListEntry relay) {
|
||||
AlertDialog dialog =
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle(R.string.remove_transport)
|
||||
.setMessage(getString(R.string.confirm_remove_or_hide_transport_x, relay.param.addr))
|
||||
.setPositiveButton(
|
||||
R.string.remove_transport,
|
||||
(d, which) -> {
|
||||
try {
|
||||
rpc.deleteTransport(accId, relay.param.addr);
|
||||
loadRelays();
|
||||
} catch (RpcException e) {
|
||||
Log.e(TAG, "RPC.deleteTransport() failed", e);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.setNeutralButton(
|
||||
R.string.hide_from_contacts,
|
||||
(d, which) -> {
|
||||
try {
|
||||
rpc.setTransportUnpublished(accId, relay.param.addr, true);
|
||||
loadRelays();
|
||||
} catch (RpcException e) {
|
||||
Log.e(TAG, "cannot unpublish relay: ", e);
|
||||
}
|
||||
})
|
||||
.show();
|
||||
Util.redPositiveButton(dialog);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.thoughtcrime.securesms.relay;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@@ -8,21 +9,21 @@ import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import chat.delta.rpc.types.EnteredLoginParam;
|
||||
import chat.delta.rpc.types.TransportListEntry;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
|
||||
public class RelayListAdapter extends RecyclerView.Adapter<RelayListAdapter.RelayViewHolder> {
|
||||
|
||||
private List<EnteredLoginParam> relays = new ArrayList<>();
|
||||
private List<TransportListEntry> relays = new ArrayList<>();
|
||||
private final OnRelayClickListener listener;
|
||||
private String mainRelayAddr;
|
||||
|
||||
public interface OnRelayClickListener {
|
||||
void onRelayClick(EnteredLoginParam relay);
|
||||
void onRelayClick(TransportListEntry relay);
|
||||
|
||||
void onRelayLongClick(View view, EnteredLoginParam relay);
|
||||
void onRelayLongClick(View view, TransportListEntry relay);
|
||||
}
|
||||
|
||||
public RelayListAdapter(OnRelayClickListener listener) {
|
||||
@@ -33,7 +34,7 @@ public class RelayListAdapter extends RecyclerView.Adapter<RelayListAdapter.Rela
|
||||
return mainRelayAddr;
|
||||
}
|
||||
|
||||
public void setRelays(@Nullable List<EnteredLoginParam> relays, String mainRelayAddr) {
|
||||
public void setRelays(@Nullable List<TransportListEntry> relays, String mainRelayAddr) {
|
||||
this.relays = relays != null ? relays : new ArrayList<>();
|
||||
this.mainRelayAddr = mainRelayAddr;
|
||||
notifyDataSetChanged();
|
||||
@@ -49,8 +50,8 @@ public class RelayListAdapter extends RecyclerView.Adapter<RelayListAdapter.Rela
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull RelayViewHolder holder, int position) {
|
||||
EnteredLoginParam relay = relays.get(position);
|
||||
boolean isMain = relay.addr != null && relay.addr.equals(mainRelayAddr);
|
||||
TransportListEntry relay = relays.get(position);
|
||||
boolean isMain = relay.param.addr != null && relay.param.addr.equals(mainRelayAddr);
|
||||
holder.bind(relay, isMain, listener);
|
||||
}
|
||||
|
||||
@@ -71,10 +72,20 @@ public class RelayListAdapter extends RecyclerView.Adapter<RelayListAdapter.Rela
|
||||
mainIndicator = itemView.findViewById(R.id.main_indicator);
|
||||
}
|
||||
|
||||
public void bind(EnteredLoginParam relay, boolean isMain, OnRelayClickListener listener) {
|
||||
String[] parts = relay.addr.split("@");
|
||||
public void bind(TransportListEntry relay, boolean isMain, OnRelayClickListener listener) {
|
||||
Context context = itemView.getContext();
|
||||
String[] parts = relay.param.addr.split("@");
|
||||
titleText.setText(parts.length == 2 ? parts[1] : parts[0]);
|
||||
subtitleText.setText(parts.length == 2 ? parts[0] : "");
|
||||
|
||||
String subtitle = parts.length == 2 ? parts[0] : "";
|
||||
if (isMain) {
|
||||
subtitle += " · " + context.getString(R.string.used_for_sending);
|
||||
}
|
||||
if (relay.isUnpublished) {
|
||||
subtitle += " · " + context.getString(R.string.hidden_from_contacts);
|
||||
}
|
||||
subtitleText.setText(subtitle);
|
||||
|
||||
mainIndicator.setVisibility(isMain ? View.VISIBLE : View.INVISIBLE);
|
||||
|
||||
itemView.setOnClickListener(
|
||||
|
||||
@@ -2,45 +2,46 @@ package org.thoughtcrime.securesms.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.Spannable;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.commonmark.node.FencedCodeBlock;
|
||||
import org.commonmark.parser.Parser;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
|
||||
import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.SoftBreakAddsNewLinePlugin;
|
||||
import io.noties.markwon.ext.strikethrough.StrikethroughPlugin;
|
||||
import io.noties.markwon.inlineparser.HtmlInlineProcessor;
|
||||
import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import org.commonmark.node.FencedCodeBlock;
|
||||
import org.commonmark.parser.Parser;
|
||||
|
||||
public class MarkdownUtil {
|
||||
private static MarkdownUtil instance;
|
||||
private final Markwon markwon;
|
||||
|
||||
private MarkdownUtil(final Context context) {
|
||||
markwon = Markwon.builder(context)
|
||||
.usePlugin(StrikethroughPlugin.create())
|
||||
.usePlugin(SoftBreakAddsNewLinePlugin.create())
|
||||
.usePlugin(MarkwonInlineParserPlugin.create())
|
||||
.usePlugin(new AbstractMarkwonPlugin() {
|
||||
@Override
|
||||
public void configure(@NonNull Registry registry) {
|
||||
registry.require(MarkwonInlineParserPlugin.class, plugin -> {
|
||||
plugin.factoryBuilder().excludeInlineProcessor(HtmlInlineProcessor.class);
|
||||
});
|
||||
}
|
||||
@Override
|
||||
public void configureParser(@NonNull Parser.Builder builder) {
|
||||
builder.enabledBlockTypes(new HashSet<>(Collections.singletonList(FencedCodeBlock.class)));
|
||||
}
|
||||
})
|
||||
.build();
|
||||
markwon =
|
||||
Markwon.builder(context)
|
||||
.usePlugin(StrikethroughPlugin.create())
|
||||
.usePlugin(SoftBreakAddsNewLinePlugin.create())
|
||||
.usePlugin(MarkwonInlineParserPlugin.create())
|
||||
.usePlugin(
|
||||
new AbstractMarkwonPlugin() {
|
||||
@Override
|
||||
public void configure(@NonNull Registry registry) {
|
||||
registry.require(
|
||||
MarkwonInlineParserPlugin.class,
|
||||
plugin -> {
|
||||
plugin.factoryBuilder().excludeInlineProcessor(HtmlInlineProcessor.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureParser(@NonNull Parser.Builder builder) {
|
||||
builder.enabledBlockTypes(
|
||||
new HashSet<>(Collections.singletonList(FencedCodeBlock.class)));
|
||||
}
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
private static MarkdownUtil getInstance(Context context) {
|
||||
|
||||
@@ -41,6 +41,7 @@ public class MediaUtil {
|
||||
public static final String IMAGE_JPEG = "image/jpeg";
|
||||
public static final String IMAGE_GIF = "image/gif";
|
||||
public static final String AUDIO_AAC = "audio/aac";
|
||||
public static final String AUDIO_M4A = "audio/mp4";
|
||||
public static final String AUDIO_UNSPECIFIED = "audio/*";
|
||||
public static final String VIDEO_UNSPECIFIED = "video/*";
|
||||
public static final String OCTET = "application/octet-stream";
|
||||
@@ -294,6 +295,8 @@ public class MediaUtil {
|
||||
switch (contentType) {
|
||||
case AUDIO_AAC:
|
||||
return "aac";
|
||||
case AUDIO_M4A:
|
||||
return "m4a";
|
||||
case IMAGE_WEBP:
|
||||
return "webp";
|
||||
case WEBXDC:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M680,480L680,328L588,420L560,392L672,280L560,168L588,140L680,232L680,80L700,80L814,196L728,280L814,366L700,480L680,480ZM720,404L758,366L720,328L720,404ZM720,232L758,196L720,158L720,232ZM798,840Q673,840 551,785.5Q429,731 329,631Q229,531 174.5,409Q120,287 120,162Q120,144 132,132Q144,120 162,120L324,120Q338,120 349,129.5Q360,139 362,152L388,292Q390,308 387,319Q384,330 376,338L279,436Q299,473 326.5,507.5Q354,542 387,574Q418,605 452,631.5Q486,658 524,680L618,586Q627,577 641.5,572.5Q656,568 670,570L808,598Q822,602 831,612.5Q840,623 840,636L840,798Q840,816 828,828Q816,840 798,840ZM241,360L307,294Q307,294 307,294Q307,294 307,294L290,200Q290,200 290,200Q290,200 290,200L201,200Q201,200 201,200Q201,200 201,200Q206,241 215,281Q224,321 241,360ZM599,718Q638,735 678.5,745Q719,755 760,758Q760,758 760,758Q760,758 760,758L760,670Q760,670 760,670Q760,670 760,670L666,651Q666,651 666,651Q666,651 666,651L599,718ZM241,360Q241,360 241,360Q241,360 241,360Q241,360 241,360Q241,360 241,360L241,360Q241,360 241,360Q241,360 241,360L241,360Q241,360 241,360Q241,360 241,360ZM599,718L599,718Q599,718 599,718Q599,718 599,718L599,718Q599,718 599,718Q599,718 599,718L599,718Q599,718 599,718Q599,718 599,718Q599,718 599,718Q599,718 599,718Z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,11 @@
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M798,840Q673,840 551,785.5Q429,731 329,631Q229,531 174.5,409Q120,287 120,162Q120,144 132,132Q144,120 162,120L324,120Q338,120 349,129.5Q360,139 362,152L388,292Q390,308 387,319Q384,330 376,338L279,436Q299,473 326.5,507.5Q354,542 387,574Q418,605 452,631.5Q486,658 524,680L618,586Q627,577 641.5,572.5Q656,568 670,570L808,598Q822,602 831,612.5Q840,623 840,636L840,798Q840,816 828,828Q816,840 798,840ZM241,360L307,294Q307,294 307,294Q307,294 307,294L290,200Q290,200 290,200Q290,200 290,200L201,200Q201,200 201,200Q201,200 201,200Q206,241 215,281Q224,321 241,360ZM599,718Q638,735 678.5,745Q719,755 760,758Q760,758 760,758Q760,758 760,758L760,670Q760,670 760,670Q760,670 760,670L666,651Q666,651 666,651Q666,651 666,651L599,718ZM241,360Q241,360 241,360Q241,360 241,360Q241,360 241,360Q241,360 241,360L241,360Q241,360 241,360Q241,360 241,360L241,360Q241,360 241,360Q241,360 241,360ZM599,718L599,718Q599,718 599,718Q599,718 599,718L599,718Q599,718 599,718Q599,718 599,718L599,718Q599,718 599,718Q599,718 599,718Q599,718 599,718Q599,718 599,718Z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,11 @@
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M136,656L44,566Q32,554 32,538Q32,522 44,510Q132,415 247,367.5Q362,320 480,320Q598,320 712.5,367.5Q827,415 916,510Q928,522 928,538Q928,554 916,566L824,656Q813,667 798.5,668Q784,669 772,660L656,572Q648,566 644,558Q640,550 640,540L640,426Q602,414 562,407Q522,400 480,400Q438,400 398,407Q358,414 320,426L320,540Q320,550 316,558Q312,566 304,572L188,660Q176,669 161.5,668Q147,667 136,656ZM240,458Q211,473 184,492.5Q157,512 128,536Q128,536 128,536Q128,536 128,536L168,576Q168,576 168,576Q168,576 168,576L240,520Q240,520 240,520Q240,520 240,520L240,458ZM720,460L720,520Q720,520 720,520Q720,520 720,520L792,576Q792,576 792,576Q792,576 792,576L832,538Q832,538 832,538Q832,538 832,538Q803,512 776,493Q749,474 720,460ZM240,458L240,458Q240,458 240,458Q240,458 240,458L240,458Q240,458 240,458Q240,458 240,458L240,458Q240,458 240,458Q240,458 240,458Q240,458 240,458Q240,458 240,458ZM720,460Q720,460 720,460Q720,460 720,460Q720,460 720,460Q720,460 720,460L720,460Q720,460 720,460Q720,460 720,460L720,460Q720,460 720,460Q720,460 720,460Z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,11 @@
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M480,480Q480,480 480,480Q480,480 480,480L480,480Q480,480 480,480Q480,480 480,480L480,480Q480,480 480,480Q480,480 480,480L480,480Q480,480 480,480Q480,480 480,480ZM800,800L600,800Q600,780 598.5,760Q597,740 594,720L800,720Q800,720 800,720Q800,720 800,720L800,240Q800,240 800,240Q800,240 800,240L160,240Q160,240 160,240Q160,240 160,240L160,286Q140,283 120,281.5Q100,280 80,280L80,240Q80,207 103.5,183.5Q127,160 160,160L800,160Q833,160 856.5,183.5Q880,207 880,240L880,720Q880,753 856.5,776.5Q833,800 800,800ZM80,800L80,680Q130,680 165,715Q200,750 200,800L80,800ZM280,800Q280,717 221.5,658.5Q163,600 80,600L80,520Q197,520 278.5,601.5Q360,683 360,800L280,800ZM440,800Q440,725 411.5,659.5Q383,594 334.5,545.5Q286,497 220.5,468.5Q155,440 80,440L80,360Q171,360 251,394.5Q331,429 391,489Q451,549 485.5,629Q520,709 520,800L440,800Z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,11 @@
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M400,656L240,496L296,440L400,544L664,280L720,336L400,656Z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,11 @@
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M480,920L480,840L760,840Q760,840 760,840Q760,840 760,840L760,800L600,800L600,480L760,480L760,440Q760,324 678,242Q596,160 480,160Q364,160 282,242Q200,324 200,440L200,480L360,480L360,800L200,800Q167,800 143.5,776.5Q120,753 120,720L120,440Q120,366 148.5,300.5Q177,235 226,186Q275,137 340.5,108.5Q406,80 480,80Q554,80 619.5,108.5Q685,137 734,186Q783,235 811.5,300.5Q840,366 840,440L840,840Q840,873 816.5,896.5Q793,920 760,920L480,920ZM200,720L280,720L280,560L200,560L200,720Q200,720 200,720Q200,720 200,720ZM680,720L760,720L760,560L680,560L680,720ZM200,560Q200,560 200,560Q200,560 200,560L200,560L280,560L280,560L200,560ZM680,560L680,560L760,560L760,560L680,560Z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,11 @@
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M710,598L652,540Q666,517 673,492Q680,467 680,440L760,440Q760,484 747,523.5Q734,563 710,598ZM480,366Q480,366 480,366L480,366L480,366L480,366Q480,366 480,366Q480,366 480,366Q480,366 480,366ZM592,478L520,406L520,200Q520,183 508.5,171.5Q497,160 480,160Q463,160 451.5,171.5Q440,183 440,200L440,326L360,246L360,200Q360,150 395,115Q430,80 480,80Q530,80 565,115Q600,150 600,200L600,440Q600,451 597.5,460Q595,469 592,478ZM440,840L440,717Q336,703 268,624Q200,545 200,440L280,440Q280,523 337.5,581.5Q395,640 480,640Q514,640 544.5,629.5Q575,619 600,600L657,657Q628,680 593.5,696Q559,712 520,717L520,840L440,840ZM792,904L56,168L112,112L848,848L792,904Z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,11 @@
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M395,525Q360,490 360,440L360,200Q360,150 395,115Q430,80 480,80Q530,80 565,115Q600,150 600,200L600,440Q600,490 565,525Q530,560 480,560Q430,560 395,525ZM480,320Q480,320 480,320L480,320Q480,320 480,320Q480,320 480,320Q480,320 480,320Q480,320 480,320L480,320Q480,320 480,320Q480,320 480,320Q480,320 480,320ZM440,840L440,717Q336,703 268,624Q200,545 200,440L280,440Q280,523 338.5,581.5Q397,640 480,640Q563,640 621.5,581.5Q680,523 680,440L760,440Q760,545 692,624Q624,703 520,717L520,840L440,840ZM508.5,468.5Q520,457 520,440L520,200Q520,183 508.5,171.5Q497,160 480,160Q463,160 451.5,171.5Q440,183 440,200L440,440Q440,457 451.5,468.5Q463,480 480,480Q497,480 508.5,468.5Z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,11 @@
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M367,433Q320,386 320,320Q320,254 367,207Q414,160 480,160Q546,160 593,207Q640,254 640,320Q640,386 593,433Q546,480 480,480Q414,480 367,433ZM160,800L160,688Q160,654 177.5,625.5Q195,597 224,582Q286,551 350,535.5Q414,520 480,520Q546,520 610,535.5Q674,551 736,582Q765,597 782.5,625.5Q800,654 800,688L800,800L160,800ZM240,720L720,720L720,688Q720,677 714.5,668Q709,659 700,654Q646,627 591,613.5Q536,600 480,600Q424,600 369,613.5Q314,627 260,654Q251,659 245.5,668Q240,677 240,688L240,720ZM536.5,376.5Q560,353 560,320Q560,287 536.5,263.5Q513,240 480,240Q447,240 423.5,263.5Q400,287 400,320Q400,353 423.5,376.5Q447,400 480,400Q513,400 536.5,376.5ZM480,320Q480,320 480,320Q480,320 480,320Q480,320 480,320Q480,320 480,320Q480,320 480,320Q480,320 480,320Q480,320 480,320Q480,320 480,320ZM480,720L480,720Q480,720 480,720Q480,720 480,720Q480,720 480,720Q480,720 480,720Q480,720 480,720Q480,720 480,720Q480,720 480,720Q480,720 480,720L480,720Z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,11 @@
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M760,480Q760,363 678.5,281.5Q597,200 480,200L480,120Q555,120 620.5,148.5Q686,177 734.5,225.5Q783,274 811.5,339.5Q840,405 840,480L760,480ZM600,480Q600,430 565,395Q530,360 480,360L480,280Q563,280 621.5,338.5Q680,397 680,480L600,480ZM798,840Q673,840 551,785.5Q429,731 329,631Q229,531 174.5,409Q120,287 120,162Q120,144 132,132Q144,120 162,120L324,120Q338,120 349,129.5Q360,139 362,152L388,292Q390,308 387,319Q384,330 376,338L279,436Q299,473 326.5,507.5Q354,542 387,574Q418,605 452,631.5Q486,658 524,680L618,586Q627,577 641.5,572.5Q656,568 670,570L808,598Q822,602 831,612.5Q840,623 840,636L840,798Q840,816 828,828Q816,840 798,840ZM241,360L307,294Q307,294 307,294Q307,294 307,294L290,200Q290,200 290,200Q290,200 290,200L201,200Q201,200 201,200Q201,200 201,200Q206,241 215,281Q224,321 241,360ZM599,718Q638,735 678.5,745Q719,755 760,758Q760,758 760,758Q760,758 760,758L760,670Q760,670 760,670Q760,670 760,670L666,651Q666,651 666,651Q666,651 666,651L599,718ZM241,360Q241,360 241,360Q241,360 241,360Q241,360 241,360Q241,360 241,360L241,360Q241,360 241,360Q241,360 241,360L241,360Q241,360 241,360Q241,360 241,360ZM599,718L599,718Q599,718 599,718Q599,718 599,718L599,718Q599,718 599,718Q599,718 599,718L599,718Q599,718 599,718Q599,718 599,718Q599,718 599,718Q599,718 599,718Z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,11 @@
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M320,680Q287,680 263.5,656.5Q240,633 240,600L240,360Q240,327 263.5,303.5Q287,280 320,280L360,280L400,240L560,240L600,280L640,280Q673,280 696.5,303.5Q720,327 720,360L720,600Q720,633 696.5,656.5Q673,680 640,680L320,680ZM320,600L640,600Q640,600 640,600Q640,600 640,600L640,360Q640,360 640,360Q640,360 640,360L320,360Q320,360 320,360Q320,360 320,360L320,600Q320,600 320,600Q320,600 320,600ZM480,560Q513,560 536.5,536.5Q560,513 560,480Q560,447 536.5,423.5Q513,400 480,400Q447,400 423.5,423.5Q400,447 400,480Q400,513 423.5,536.5Q447,560 480,560ZM342,20Q376,9 410.5,4.5Q445,0 480,0Q574,0 657.5,33.5Q741,67 805.5,126.5Q870,186 911,266.5Q952,347 960,440L880,440Q873,368 842,305.5Q811,243 762.5,195.5Q714,148 651,118Q588,88 516,82L578,144L522,200L342,20ZM618,940Q584,951 549.5,955.5Q515,960 480,960Q386,960 302.5,926.5Q219,893 154.5,833.5Q90,774 49,693.5Q8,613 0,520L80,520Q88,592 118.5,654.5Q149,717 197.5,764.5Q246,812 309,842Q372,872 444,878L382,816L438,760L618,940ZM480,480Q480,480 480,480Q480,480 480,480L480,480Q480,480 480,480Q480,480 480,480L480,480Q480,480 480,480Q480,480 480,480L480,480Q480,480 480,480Q480,480 480,480Z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,11 @@
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M880,700L720,540L720,607L640,527L640,240Q640,240 640,240Q640,240 640,240L353,240L273,160L640,160Q673,160 696.5,183.5Q720,207 720,240L720,420L880,260L880,700ZM822,934L26,138L82,82L878,878L822,934ZM498,385L498,385Q498,385 498,385Q498,385 498,385L498,385ZM382,496Q382,496 382,496Q382,496 382,496L382,496Q382,496 382,496Q382,496 382,496L382,496Q382,496 382,496Q382,496 382,496ZM160,160L240,240L160,240Q160,240 160,240Q160,240 160,240L160,720Q160,720 160,720Q160,720 160,720L640,720Q640,720 640,720Q640,720 640,720L640,640L720,720L720,720Q720,753 696.5,776.5Q673,800 640,800L160,800Q127,800 103.5,776.5Q80,753 80,720L80,240Q80,207 103.5,183.5Q127,160 160,160Z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,11 @@
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M160,800Q127,800 103.5,776.5Q80,753 80,720L80,240Q80,207 103.5,183.5Q127,160 160,160L640,160Q673,160 696.5,183.5Q720,207 720,240L720,420L880,260L880,700L720,540L720,720Q720,753 696.5,776.5Q673,800 640,800L160,800ZM160,720L640,720Q640,720 640,720Q640,720 640,720L640,240Q640,240 640,240Q640,240 640,240L160,240Q160,240 160,240Q160,240 160,240L160,720Q160,720 160,720Q160,720 160,720ZM160,720Q160,720 160,720Q160,720 160,720L160,240Q160,240 160,240Q160,240 160,240L160,240Q160,240 160,240Q160,240 160,240L160,720Q160,720 160,720Q160,720 160,720Z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,12 @@
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:autoMirrored="true">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M560,829L560,747Q650,721 705,647Q760,573 760,479Q760,385 705,311Q650,237 560,211L560,129Q684,157 762,254.5Q840,352 840,479Q840,606 762,703.5Q684,801 560,829ZM120,600L120,360L280,360L480,160L480,800L280,600L120,600ZM560,640L560,318Q607,340 633.5,384Q660,428 660,480Q660,531 633.5,574.5Q607,618 560,640ZM400,354L314,440L200,440L200,520L314,520L400,606L400,354ZM300,480L300,480L300,480L300,480L300,480L300,480Z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,343 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/call_root_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@android:color/black"
|
||||
android:fitsSystemWindows="false">
|
||||
|
||||
<!-- Remote Video (Full Screen, Black background) -->
|
||||
<org.webrtc.SurfaceViewRenderer
|
||||
android:id="@+id/remote_video_view"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<com.google.android.material.imageview.ShapeableImageView
|
||||
android:id="@+id/remote_avatar_view"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:scaleType="centerCrop"
|
||||
android:contentDescription="Contact photo"
|
||||
app:shapeAppearanceOverlay="@style/ShapeAppearance.Material3.Corner.Full"
|
||||
app:layout_constraintWidth_percent="0.4"
|
||||
app:layout_constraintDimensionRatio="1:1"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
tools:visibility="visible"
|
||||
tools:src="@drawable/ic_person" />
|
||||
|
||||
<!-- Top Bar -->
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/top_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingBottom="12dp"
|
||||
android:background="@color/calls_dark_surface"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_marginStart="8dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/display_name_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/calls_dark_on_surface"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
tools:text="John Doe" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/status_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/calls_dark_on_surface_variant"
|
||||
android:textSize="14sp"
|
||||
tools:text="Connecting..." />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<!-- Local Video (Top Right) -->
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/local_video_container"
|
||||
android:layout_width="90dp"
|
||||
android:layout_height="120dp"
|
||||
android:layout_margin="16dp"
|
||||
app:cardElevation="4dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/top_bar"
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
|
||||
<org.webrtc.SurfaceViewRenderer
|
||||
android:id="@+id/local_video_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<!-- Caller Icon (during incoming call prompt) -->
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/caller_icon_container"
|
||||
android:layout_width="140dp"
|
||||
android:layout_height="140dp"
|
||||
android:visibility="gone"
|
||||
app:cardCornerRadius="70dp"
|
||||
app:cardElevation="8dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/top_bar"
|
||||
app:layout_constraintBottom_toTopOf="@id/incoming_call_prompt"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintVertical_bias="0.35"
|
||||
tools:visibility="visible">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/caller_icon"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scaleType="centerCrop"
|
||||
android:contentDescription="Caller photo"
|
||||
tools:src="@drawable/ic_person" />
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<!-- Answer Mode Selector -->
|
||||
<com.google.android.material.button.MaterialButtonToggleGroup
|
||||
android:id="@+id/answer_mode_selector"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
app:singleSelection="true"
|
||||
app:selectionRequired="true"
|
||||
app:layout_constraintTop_toBottomOf="@id/caller_icon_container"
|
||||
app:layout_constraintBottom_toTopOf="@id/incoming_call_prompt"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="24dp"
|
||||
tools:visibility="visible">
|
||||
|
||||
<Button
|
||||
android:id="@+id/answer_audio_only_button"
|
||||
style="?attr/materialButtonOutlinedStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Audio"
|
||||
android:textSize="14sp"
|
||||
android:minWidth="100dp"
|
||||
app:icon="@drawable/ic_call"
|
||||
app:iconGravity="textStart"
|
||||
app:iconSize="20dp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/answer_video_button"
|
||||
style="?attr/materialButtonOutlinedStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Video"
|
||||
android:textSize="14sp"
|
||||
android:minWidth="100dp"
|
||||
app:icon="@drawable/ic_videocam_on"
|
||||
app:iconGravity="textStart"
|
||||
app:iconSize="20dp" />
|
||||
|
||||
</com.google.android.material.button.MaterialButtonToggleGroup>
|
||||
|
||||
<!-- Incoming Call Buttons -->
|
||||
<LinearLayout
|
||||
android:id="@+id/incoming_call_prompt"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center"
|
||||
android:padding="24dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:layout_marginBottom="48dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
tools:visibility="visible">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/decline_button"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="56dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:text="Decline"
|
||||
android:textSize="15sp"
|
||||
app:icon="@drawable/ic_call_end"
|
||||
app:iconGravity="textStart"
|
||||
app:cornerRadius="28dp"
|
||||
style="@style/Widget.Material3.Button.TonalButton"
|
||||
app:backgroundTint="@color/calls_red" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/answer_button"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="56dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginStart="8dp"
|
||||
android:text="Answer"
|
||||
android:textSize="15sp"
|
||||
app:icon="@drawable/ic_call"
|
||||
app:iconGravity="textStart"
|
||||
app:cornerRadius="28dp"
|
||||
style="@style/Widget.Material3.Button"
|
||||
app:backgroundTint="@color/calls_green" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Call Controls -->
|
||||
<LinearLayout
|
||||
android:id="@+id/call_controls_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:baselineAligned="false"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingBottom="24dp"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintWidth_max="600dp">
|
||||
|
||||
<!-- Mute Button -->
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center">
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/mute_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_mic_on"
|
||||
android:contentDescription="Toggle microphone"
|
||||
app:tint="@color/calls_dark_on_surface"
|
||||
app:backgroundTint="@color/calls_dark_surface_3"
|
||||
app:fabSize="normal"
|
||||
app:shapeAppearance="@style/ShapeAppearance.Material3.Corner.Full"
|
||||
app:borderWidth="0dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Video Button -->
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center">
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/video_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_videocam_on"
|
||||
android:contentDescription="Toggle camera"
|
||||
app:tint="@color/calls_dark_on_surface"
|
||||
app:backgroundTint="@color/calls_dark_surface_3"
|
||||
app:fabSize="normal"
|
||||
app:shapeAppearance="@style/ShapeAppearance.Material3.Corner.Full"
|
||||
app:borderWidth="0dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- End Call Button -->
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center">
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/end_call_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_call_end"
|
||||
android:contentDescription="End call"
|
||||
app:tint="@android:color/white"
|
||||
app:backgroundTint="@color/calls_red"
|
||||
app:fabSize="normal"
|
||||
app:shapeAppearance="@style/ShapeAppearance.Material3.Corner.Full"
|
||||
app:borderWidth="0dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Speaker Button -->
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center">
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/speaker_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_volume_up"
|
||||
android:contentDescription="Audio output"
|
||||
app:tint="@color/calls_dark_on_surface"
|
||||
app:backgroundTint="@color/calls_dark_surface_3"
|
||||
app:fabSize="normal"
|
||||
app:shapeAppearance="@style/ShapeAppearance.Material3.Corner.Full"
|
||||
app:borderWidth="0dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Switch Camera Button -->
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center">
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/switch_camera_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_switch_camera"
|
||||
android:contentDescription="Switch camera"
|
||||
app:tint="@color/calls_dark_on_surface"
|
||||
app:backgroundTint="@color/calls_dark_surface_3"
|
||||
app:fabSize="normal"
|
||||
app:shapeAppearance="@style/ShapeAppearance.Material3.Corner.Full"
|
||||
app:borderWidth="0dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Audio Output"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
android:paddingBottom="16dp" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/audio_device_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:nestedScrollingEnabled="false" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:orientation="horizontal"
|
||||
android:padding="16dp"
|
||||
android:gravity="center_vertical"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/device_icon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:importantForAccessibility="no"
|
||||
tools:src="@drawable/ic_volume_up" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/device_name"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:textSize="16sp"
|
||||
tools:text="Speaker" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/device_check"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:src="@drawable/ic_check"
|
||||
android:visibility="gone"
|
||||
android:contentDescription="@string/selected" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -157,8 +157,6 @@
|
||||
<string name="import_backup_title">استيراد نسخة احتياطية</string>
|
||||
<string name="delete_account">حذف الحساب</string>
|
||||
<!-- preferences -->
|
||||
<string name="pref_using_custom">استخدام التخصيص: %s</string>
|
||||
<string name="pref_using_default">مستخدم كافتراضي: %s</string>
|
||||
<string name="pref_profile_info_headline">معلومات ملفك التعريفي</string>
|
||||
<string name="pref_profile_photo">صورة الملف التعريفي</string>
|
||||
<string name="pref_blocked_contacts">المراسلون المحبوسون</string>
|
||||
@@ -174,8 +172,6 @@
|
||||
<string name="pref_led_color">لون ضوء التنبيه LED</string>
|
||||
<string name="pref_sound">الصوت</string>
|
||||
<string name="pref_privacy">الخصوصية</string>
|
||||
<!-- deprecated, use pref_chats -->
|
||||
<string name="pref_chats_and_media">الدردشة والوسائط</string>
|
||||
<string name="pref_system_default">افتراضيات النظام</string>
|
||||
<!-- Translators: as in "opposite of dark" -->
|
||||
<string name="pref_light_theme">فاتح</string>
|
||||
@@ -190,7 +186,7 @@
|
||||
<string name="pref_background">الخلفية</string>
|
||||
<string name="pref_show_emails_all">كلها</string>
|
||||
<string name="qrscan_fingerprint_label">البصمة</string>
|
||||
<!-- notifications -->
|
||||
<!-- notifications -->
|
||||
<string name="notify_reply_button">رد</string>
|
||||
<string name="notify_new_message">رسالة جديدة</string>
|
||||
<string name="notify_priority_high">عالي</string>
|
||||
|
||||
@@ -183,7 +183,6 @@
|
||||
<string name="contacts_title">Kontaktlar</string>
|
||||
<string name="contacts_type_email_above">E-poçt ünvanını yazın</string>
|
||||
|
||||
|
||||
<!-- chatlist and chat view -->
|
||||
<plurals name="chat_archived">
|
||||
<item quantity="one">%d çat arxiv olundu</item>
|
||||
@@ -215,12 +214,6 @@
|
||||
<string name="save_message">Saxla</string>
|
||||
<string name="saved_messages">Saxlanılmış mesajlar</string>
|
||||
<string name="retry_send">Mesaji yenidən göndərməyə cəht et</string>
|
||||
<!-- map -->
|
||||
<string name="filter_map_on_time">Vaxt məhdudiyyəti ilə yerləşmə yerləri göstərin</string>
|
||||
<string name="show_location_traces">İzləri göstərmək</string>
|
||||
<string name="add_poi">Maraq nöqtəsini göndərin</string>
|
||||
|
||||
|
||||
<!-- search -->
|
||||
<string name="search">Axtarış</string>
|
||||
<string name="search_explain">Çatlar, kontaktlar və mesajlar axtar</string>
|
||||
@@ -269,10 +262,7 @@
|
||||
<string name="forward_to">İrəli ...</string>
|
||||
<string name="share_abort">İcazə olmadığına görə göndərmə kəsildi</string>
|
||||
|
||||
|
||||
<!-- preferences -->
|
||||
<string name="pref_using_custom">:Xüsusi istifadə %s</string>
|
||||
<string name="pref_using_default">Varsayılan istifadə: %s</string>
|
||||
<string name="pref_profile_info_headline">Profil məlumatınız</string>
|
||||
<string name="pref_profile_photo">Profil şəkili</string>
|
||||
<string name="pref_blocked_contacts">Bloklanmış kontaktlar</string>
|
||||
@@ -298,8 +288,6 @@
|
||||
<string name="pref_sound">Səs</string>
|
||||
<string name="pref_silent">Səssiz</string>
|
||||
<string name="pref_privacy">Gizlilik</string>
|
||||
<!-- deprecated, use pref_chats -->
|
||||
<string name="pref_chats_and_media">Çatlar və faillar</string>
|
||||
<!-- Translators: as in "opposite of dark" -->
|
||||
<string name="pref_light_theme">Açıq</string>
|
||||
<string name="pref_dark_theme">Tünd</string>
|
||||
@@ -376,7 +364,7 @@
|
||||
<string name="qrshow_join_contact_hint">%1$silə əlaqə qurmaq üçün bunu skan edin</string>
|
||||
<string name="qrshow_join_contact_no_connection_toast">İnternet bağlantısı yoxdur, QR kodunu qura bilmir.</string>
|
||||
<string name="contact_verified">%1$s yoxlanıldı.</string>
|
||||
<!-- notifications -->
|
||||
<!-- notifications -->
|
||||
<string name="notify_reply_button">Cavab ver</string>
|
||||
<string name="notify_new_message">Yeni mesaj</string>
|
||||
<string name="notify_background_connection_enabled">Arxa fon əlaqəsi aktivdir</string>
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
<string name="off">Изключено</string>
|
||||
<string name="def">По подразбиране</string>
|
||||
<string name="default_value">По подразбиране (%1$s)</string>
|
||||
<string name="default_value_as_above">По подразбиране (същото като по-горе)</string>
|
||||
<string name="custom">Дефиниран от потребителя</string>
|
||||
<string name="none">Без</string>
|
||||
<string name="automatic">Автоматично</string>
|
||||
@@ -96,7 +95,7 @@
|
||||
<string name="last_month">Миналия месец</string>
|
||||
<!-- Refers to the time a contact was last seen. Shown below contact name in the profile. The placeholder will be replaced by date or time, resulting in "Last seen at 12:13 AM" or "Last seen Nov 12" -->
|
||||
<string name="last_seen_at">Последно видян на %1$s</string>
|
||||
<!-- Refers to the time a contact was last seen. Shown below contact name in the profile. The placeholder will be replaced by a relative point in time as "3 minutes ago" (see https://momentjs.com for more examples and languages)-->
|
||||
<!-- Refers to the time a contact was last seen. Shown below contact name in the profile. The placeholder will be replaced by a relative point in time as "3 minutes ago" (see https://momentjs.com for more examples and languages) -->
|
||||
<string name="last_seen_relative">Последно видян %1$s</string>
|
||||
<string name="last_seen_unknown">Последно видян: Не е известно</string>
|
||||
<!-- Shown beside messages that are "N minutes old". Prefer short strings, or well-known abbreviations. -->
|
||||
@@ -200,8 +199,6 @@
|
||||
<string name="menu_new_chat">Нов чат</string>
|
||||
<string name="menu_new_group">Нова група</string>
|
||||
<string name="clone_chat">Клониране на чат</string>
|
||||
<!-- deprecated -->
|
||||
<string name="add_recipients">Добавяне на получатели</string>
|
||||
<string name="menu_send">Изпращане</string>
|
||||
<string name="menu_toggle_keyboard">Включване/изключване на Emoji клавиатура</string>
|
||||
<string name="menu_edit_group">Редактиране на група</string>
|
||||
@@ -262,13 +259,12 @@
|
||||
<string name="menu_more_options">Още опции</string>
|
||||
<string name="menu_learn_spelling">Запомняне на правописа</string>
|
||||
<string name="jump_to_message">Към съобщение</string>
|
||||
<string name="copy_json">Копиране на JSON</string>
|
||||
<string name="replace_draft">Замяна на чернова</string>
|
||||
<string name="title_share_location">Местоположението да се споделя с всички членове на групата</string>
|
||||
<string name="device_talk">Съобщения в устройството</string>
|
||||
<string name="device_talk_subtitle">Локално генерирани съобщения</string>
|
||||
<string name="device_talk_explain">Съобщенията в този чат се генерират на Вашето устройство, за да информират относно актуализации на приложението и проблеми по време на ползване.</string>
|
||||
<string name="device_talk_welcome_message2">Свържете се!\n\n🙌 Натиснете \"QR код\" в главния екран и на двете устройства. Изберете \"Сканиране на QR код\" на едно от устройствата и го насочете към другото\n\n🌍 Ако двете устройства не се намират в една и съща стая, сканирайте посредством видео обаждане или споделете връзка с покана от \"Сканиране на QR код\"\n\nСлед това: Насладете се на изживяването да обменяте съобщения през най-голямата децентрализирана мрежа, която някога е съществувала: електронната поща. And in contrast to other popular apps, without central control or tracking or selling you, friends, colleagues or family out to large organizations.</string>
|
||||
<string name="device_talk_welcome_message2">Свържете се!\n\n🙌 Натиснете \"QR код\" в главния екран и на двете устройства. Изберете \"Сканиране на QR код\" на едно от устройствата и го насочете към другото\n\n🌍 Ако двете устройства не се намират в една и съща стая, сканирайте посредством видео обаждане или споделете връзка с покана от \"Сканиране на QR код\"\n\nСлед това: Насладете се на изживяването да обменяте съобщения през най-голямата децентрализирана мрежа, която някога е съществувала: електронната поща. And in contrast to other popular apps, without central control or tracking or selling you, friends, colleagues or family out to large organizations.</string>
|
||||
<string name="edit_contact">Редактиране на контакт</string>
|
||||
<!-- Verb "to pin", making something sticky, not a noun or abbreviation for "pin number". -->
|
||||
<string name="pin_chat">Забождане на чата</string>
|
||||
@@ -314,12 +310,10 @@
|
||||
<string name="ask_remove_members">Премахване на %1$s от групата?</string>
|
||||
<string name="open_url_confirmation">Искате ли да отворите тази връзка?</string>
|
||||
|
||||
|
||||
<!-- contact list -->
|
||||
<string name="contacts_title">Контакти</string>
|
||||
<string name="contacts_type_email_above">Въведете адрес за електронна поща по-горе</string>
|
||||
|
||||
|
||||
<!-- chatlist and chat view -->
|
||||
<plurals name="chat_archived">
|
||||
<item quantity="one">%d чат е архивиран</item>
|
||||
@@ -376,22 +370,14 @@
|
||||
<string name="send_file_to">Изпращане на \"%1$s\" до</string>
|
||||
<!-- title shown above a list contacts where one should be selected (eg. when a webxdc attempts to send a message to a chat) -->
|
||||
<string name="send_message_to">Изпращане на съобщение до…</string>
|
||||
<!-- map -->
|
||||
<string name="filter_map_on_time">Показване на местоположенията във времева рамка</string>
|
||||
<string name="show_location_traces">Показване на съобщенията за проследяване</string>
|
||||
<string name="add_poi">Изпращане на място, представляващо интерес</string>
|
||||
|
||||
|
||||
<!-- punycode warning / labeled links -->
|
||||
<!-- placeholder is domain/hostname that should be trusted -->
|
||||
<string name="open_external_url_trust_domain">Да не се пита повече за %1$s</string>
|
||||
<string name="puny_code_warning_header">Открита е подозрителна връзка</string>
|
||||
<!-- placeholder contains the hostname converted to ascii -->
|
||||
<string name="puny_code_warning_question">Сигурни ли сте, че искате да посетите %1$s?</string>
|
||||
<!-- this message is shown whenever a link with non-latin characters is clicked. first placeholder is original hostname with special chars, second placeholder is hostname encoded in ascii -->
|
||||
<string name="puny_code_warning_description">Има вероятност тази връзка лъжливо да представя някои знаци чрез подобно изглеждащи такива от различни от текущата азбуки. Следването на връзката с етикет %1$s ще доведе до %2$s, което е обичайно за знаци, които не са от Latin набора. Ако не сте очаквали такива знаци, тази връзка може да причини вреда</string>
|
||||
|
||||
|
||||
<!-- search -->
|
||||
<string name="search">Търсене</string>
|
||||
<string name="search_in_chat">Търсене в чата</string>
|
||||
@@ -457,8 +443,6 @@
|
||||
<string name="incoming_messages">Входящи съобщения</string>
|
||||
<!-- Headline for the "Outbox" eg. in the "Connectivity" view -->
|
||||
<string name="outgoing_messages">Изходящи съобщения</string>
|
||||
<!-- deprecated -->
|
||||
<string name="storage_on_domain">Съхранение върху %1$s</string>
|
||||
<string name="connectivity">Свързаност</string>
|
||||
<!-- Shown in the title bar if the app is "Not connected"; prefer short strings. -->
|
||||
<string name="connectivity_not_connected">Не сте свързани</string>
|
||||
@@ -476,11 +460,10 @@
|
||||
<!-- Used for describing resource usage, resulting string will be eg. "1.2 GiB of 3 GiB used" -->
|
||||
<string name="part_of_total_used">Използвани са %1$s от %2$s</string>
|
||||
|
||||
|
||||
<!-- welcome and login -->
|
||||
<!-- Primary button on the welcome screen, allows to create an instant profile -->
|
||||
<string name="onboarding_create_instant_account">Създаване на нов профил</string>
|
||||
<!-- Secondary button on the welcome screen, allows to "Add as Second Device", "Restore from Backup" -->
|
||||
<!-- Secondary button on the welcome screen, allows to "Add as Second Device", "Restore from Backup" -->
|
||||
<string name="onboarding_alternative_logins">Вече имам профил</string>
|
||||
<!-- This is a button and a title, allowing to use existing, classic email, setting ports, passwords and so on -->
|
||||
<string name="manual_account_setup_option">Вход в класическа електронна поща</string>
|
||||
@@ -549,10 +532,7 @@
|
||||
<string name="share_text_multiple_chats">Да бъде ли изпратен този текст към %1$d чата?\n\n\"%2$s\"</string>
|
||||
<string name="share_abort">Споделянето е прекъснато поради липсващи позволения.</string>
|
||||
|
||||
|
||||
<!-- preferences -->
|
||||
<string name="pref_using_custom">Използва се дефинирано от Вас: %s</string>
|
||||
<string name="pref_using_default">Използва се подразбиращо се: %s</string>
|
||||
<string name="pref_profile_info_headline">Информация от Вашия профил</string>
|
||||
<string name="pref_profile_photo">Изображение на профила</string>
|
||||
<string name="pref_blocked_contacts">Блокирани контакти</string>
|
||||
@@ -582,8 +562,6 @@
|
||||
<string name="pref_sound">Звук</string>
|
||||
<string name="pref_silent">Без звук</string>
|
||||
<string name="pref_privacy">Поверителност</string>
|
||||
<!-- deprecated, use pref_chats -->
|
||||
<string name="pref_chats_and_media">Чатове и медийни файлове</string>
|
||||
<string name="pref_system_default">Подразбиращото се за системата</string>
|
||||
<!-- Translators: as in "opposite of dark" -->
|
||||
<string name="pref_light_theme">Светъл</string>
|
||||
@@ -646,8 +624,6 @@
|
||||
<string name="profile_image_delete">Изтриване на изображението на профила</string>
|
||||
<string name="pref_show_tray_icon">Показване на иконата в System Tray</string>
|
||||
<string name="pref_edit_profile">Редактиране на профил</string>
|
||||
<string name="disable_imap_idle">Деактивиране на IMAP IDLE</string>
|
||||
<string name="disable_imap_idle_explain">Да не се използва разширението IMAP IDLE дори ако сървърът го поддържа. Ако тази опция бъде разрешена, извличането на съобщенията ще бъде забавено. Разрешете я само за тестване.</string>
|
||||
<string name="send_stats_to_devs">Да се изпраща статистика към разработчиците на Delta Chat</string>
|
||||
<!-- Emoji picker and categories -->
|
||||
<string name="emoji_search_results">Резултати от търсенето</string>
|
||||
@@ -726,10 +702,6 @@
|
||||
<string name="ephemeral_timer_seconds_by_you">Установихте таймера на изчезващите съобщения на %1$s</string>
|
||||
<!-- %1$s will be replaced by the number of seconds (always >1) the timer is set to, %2$s will be replaced by name of the contact -->
|
||||
<string name="ephemeral_timer_seconds_by_other">Таймерът на изчезващите съобщение е установен на %1$sсек. от %2$s.</string>
|
||||
<!-- deprecated, usage needs to be removed in core -->
|
||||
<string name="ephemeral_timer_1_minute_by_you">Установихте таймера на изчезващите съобщения на 1 минута.</string>
|
||||
<!-- deprecated, usage needs to be removed in core -->
|
||||
<string name="ephemeral_timer_1_minute_by_other">Таймерът на изчезващите съобщения е установен на 1 минута от %1$s.</string>
|
||||
<string name="ephemeral_timer_1_hour_by_you">Установихте таймера на изчезващите съобщения на 1 час.</string>
|
||||
<!-- %1$s will be replaced by name of the contact -->
|
||||
<string name="ephemeral_timer_1_hour_by_other">Таймерът на изчезващите съобщения е установен на 1 час от %1$s.</string>
|
||||
@@ -801,7 +773,7 @@
|
||||
<string name="qrshow_join_contact_hint">Сканирайте, за да чатите с %1$s</string>
|
||||
<string name="qrshow_join_contact_no_connection_toast">Няма връзка към Интернет, не може да бъде извършена настройка чрез QR код.</string>
|
||||
<string name="qraccount_ask_create_and_login">Да бъде ли създаден нов адрес за електронна поща на \"%1$s\" и да бъде ли осъществено влизане там?</string>
|
||||
<string name="set_name_and_avatar_explain">Задайте име, което Вашите контакти ще разпознават. Можете също да установите изображение за профил.</string>
|
||||
<string name="set_name_and_avatar_explain">Задайте име, което Вашите контакти ще разпознават. Можете също да установите изображение за профил.</string>
|
||||
<string name="please_enter_name">Моля, въведете име.</string>
|
||||
<string name="qraccount_qr_code_cannot_be_used">Не може да бъде създаден нов акаунт със сканирания QR код.</string>
|
||||
<!-- the placeholder will be replaced by the address of the profile -->
|
||||
@@ -815,14 +787,12 @@
|
||||
<!-- Shown in contact profile. The placeholder will be replaced by the name of the contact that introduced the contact. -->
|
||||
<string name="verified_by">Проверен от%1$s</string>
|
||||
<string name="verified_by_you">Представен от мен</string>
|
||||
<!-- deprecated -->
|
||||
<string name="verified_contact_required_explain">За да се гарантира криптирането от край до край, можете да добавяте в тази група само контакти, отбелязани със зелена отметка.\n\nБихте могли да се срещнете с лицата, с които желаете да контактувате, лично и да сканирате техните QR кодове, за да ги въведете.</string>
|
||||
<string name="mailto_dialog_header_select_chat">Изберете чат, към който да бъде пратено съобщението</string>
|
||||
<!-- first placeholder is the name of the chat -->
|
||||
<string name="confirm_replace_draft">%1$s вече има съобщение чернова, искате ли да го замените?</string>
|
||||
<string name="mailto_link_could_not_be_decoded">Неуспешно декодиране на mailto връзка: %1$s</string>
|
||||
|
||||
<!-- notifications -->
|
||||
<!-- notifications -->
|
||||
<string name="notify_reply_button">Отговор</string>
|
||||
<string name="notify_new_message">Ново съобщение</string>
|
||||
<string name="notify_background_connection_enabled">Връзката във фонов режим е разрешена</string>
|
||||
@@ -837,7 +807,6 @@
|
||||
<string name="new_messages_body">Имате нови съобщения</string>
|
||||
<string name="n_messages_in_m_chats">%1$d съобщения в %2$d чата</string>
|
||||
|
||||
|
||||
<!-- permissions -->
|
||||
<string name="perm_required_title">Изисква се позволение</string>
|
||||
<string name="perm_continue">Продължаване</string>
|
||||
@@ -858,9 +827,6 @@
|
||||
<string name="ImageEditorHud_flip">Обръщане</string>
|
||||
<string name="ImageEditorHud_rotate">Завъртане</string>
|
||||
|
||||
<!-- strings introduced on desktop. we want to share strings between the os, in general, please do not add generic strings here -->
|
||||
<string name="about_offical_app_desktop">Това е официалното настолно приложение Delta Chat.</string>
|
||||
<string name="about_licensed_under_desktop">Този софтуер е лицензиран под GNU GPL версия 3. Изходният код е наличен в GitHub.</string>
|
||||
<string name="welcome_desktop">Добре дошли в Delta Chat</string>
|
||||
<string name="global_menu_preferences_language_desktop">Език</string>
|
||||
<string name="global_menu_file_desktop">Файл</string>
|
||||
@@ -896,6 +862,7 @@
|
||||
<string name="menu.view.developer.open.log.folder">Отваряне на папката \"Дневник\"</string>
|
||||
<string name="menu.view.developer.open.current.log.file">Отваряне на текущия файл на дневника</string>
|
||||
<string name="explain_desktop_minimized_disabled_tray_pref" tools:ignore="TypographyDashes">Показването на икона в системната лента не може да бъде забранено, тъй като Delta Chat е стартиран с опцията --minimized.</string>
|
||||
<!-- deprecated, used on desktop although there is not spell checker -->
|
||||
<string name="no_spellcheck_suggestions_found">Няма открити предложения за правопис.</string>
|
||||
<string name="show_window">Показване на прозореца</string>
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
<string name="off">کۊر</string>
|
||||
<string name="def">پؽش فرز</string>
|
||||
<string name="default_value">پؽش فرز (%1$s)</string>
|
||||
<string name="default_value_as_above">پؽش فرز (جۊر روء)</string>
|
||||
<string name="custom">سفارشی</string>
|
||||
<string name="none">هیچکویکی</string>
|
||||
<string name="automatic">خوتکار</string>
|
||||
@@ -34,8 +33,6 @@
|
||||
<string name="update">ورۊ کردن</string>
|
||||
<string name="emoji">ایموجی</string>
|
||||
<string name="attachment">پیوست</string>
|
||||
<!-- the placeholder will be replaced by the name of the image or file to attach -->
|
||||
<string name="ask_attach">«%1$s» پیوست بۊ؟</string>
|
||||
<string name="back">وورگشتن</string>
|
||||
<string name="close">بستن</string>
|
||||
<string name="close_window">بستن نیمدری</string>
|
||||
@@ -113,7 +110,7 @@
|
||||
<string name="last_month">ما زیتری</string>
|
||||
<!-- Refers to the time a contact was last seen. Shown below contact name in the profile. The placeholder will be replaced by date or time, resulting in "Last seen at 12:13 AM" or "Last seen Nov 12" -->
|
||||
<string name="last_seen_at">ریتور دیندایی من %1$s</string>
|
||||
<!-- Refers to the time a contact was last seen. Shown below contact name in the profile. The placeholder will be replaced by a relative point in time as "3 minutes ago" (see https://momentjs.com for more examples and languages)-->
|
||||
<!-- Refers to the time a contact was last seen. Shown below contact name in the profile. The placeholder will be replaced by a relative point in time as "3 minutes ago" (see https://momentjs.com for more examples and languages) -->
|
||||
<string name="last_seen_relative">ریتور دیندایی %1$s</string>
|
||||
<string name="last_seen_unknown">ریتور دیندایی: دیار نؽ</string>
|
||||
<!-- Shown beside messages that are "N minutes old". Prefer short strings, or well-known abbreviations. -->
|
||||
@@ -331,7 +328,6 @@
|
||||
<string name="ask_remove_members">پاک کردن %1$s ز جرگه؟</string>
|
||||
<string name="open_url_confirmation">اخۊی ای لینگن بۊگۊشی؟</string>
|
||||
|
||||
|
||||
<!-- contact list -->
|
||||
<string name="contacts_title">هومدنگووݩ</string>
|
||||
<string name="chat_please_enter_message">ی پیوم بزݩ.</string>
|
||||
@@ -359,7 +355,7 @@
|
||||
<string name="send_file_to">فشناڌن \"%1$s\" و...</string>
|
||||
<!-- title shown above a list contacts where one should be selected (eg. when a webxdc attempts to send a message to a chat) -->
|
||||
<string name="send_message_to">فشناڌن پیوم و...</string>
|
||||
<string name="show_location_traces">نشووݩ داڌن جا پا</string>
|
||||
|
||||
<!-- search -->
|
||||
<string name="search">پیتینیڌن</string>
|
||||
<!-- create/edit groups, contact/group profile -->
|
||||
@@ -378,8 +374,6 @@
|
||||
<string name="media_preview">نشووݩ داڌن وارسگر</string>
|
||||
<string name="send_message">فشناڌن پیوم</string>
|
||||
|
||||
<!-- deprecated -->
|
||||
<string name="storage_on_domain">زفت کردن من %1$s</string>
|
||||
<!-- Shown in the title bar if the app is "Connecting"; prefer short strings. The ellipsis is a single character (…), not three (...) -->
|
||||
<string name="connectivity_connecting">هونی منپیز ابۊ...</string>
|
||||
<!-- Shown in the title bar if the app is "Updating" (eg. getting new/old message, sync things); prefer short strings. The ellipsis is a single character (…), not three (...) -->
|
||||
@@ -433,7 +427,7 @@
|
||||
<string name="contact_verified">%1$s تاییڌ وابی.</string>
|
||||
<!-- Shown in contact profile. The placeholder will be replaced by the name of the contact that introduced the contact. -->
|
||||
<string name="verified_by">تاییڌ وابیڌه و دس %1$s</string>
|
||||
<!-- notifications -->
|
||||
<!-- notifications -->
|
||||
<string name="notify_reply_button">ولوم</string>
|
||||
<string name="notify_new_message">پیوم نۊ</string>
|
||||
<string name="notify_name_and_message">نوم وو پیوم</string>
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
<string name="off">Desactivat</string>
|
||||
<string name="def">Per defecte</string>
|
||||
<string name="default_value">Per defecte (%1$s)</string>
|
||||
<string name="default_value_as_above">Per defecte (igual que a dalt)</string>
|
||||
<string name="custom">Personalitzat</string>
|
||||
<string name="none">Cap</string>
|
||||
<string name="automatic">Automàtic</string>
|
||||
@@ -28,14 +27,12 @@
|
||||
<string name="join">Uneix-te</string>
|
||||
<string name="rejoin">Torna a unir-te</string>
|
||||
<string name="delete">Esborra</string>
|
||||
<string name="delete_for_me">Elimina per a mi</string>
|
||||
<string name="delete_for_me">Esborra per a mi</string>
|
||||
<string name="delete_for_everyone">Esborra per a tothom</string>
|
||||
<string name="info">Info</string>
|
||||
<string name="update">Actualitza</string>
|
||||
<string name="emoji">Emojis</string>
|
||||
<string name="attachment">Adjunt</string>
|
||||
<!-- the placeholder will be replaced by the name of the image or file to attach -->
|
||||
<string name="ask_attach">Voleu adjuntar \"%1$s\"?</string>
|
||||
<string name="back">Enrere</string>
|
||||
<string name="close">Tanca</string>
|
||||
<string name="close_window">Tanca la finestra</string>
|
||||
@@ -115,19 +112,16 @@
|
||||
<string name="last_month">El mes passat</string>
|
||||
<!-- Refers to the time a contact was last seen. Shown below contact name in the profile. The placeholder will be replaced by date or time, resulting in "Last seen at 12:13 AM" or "Last seen Nov 12" -->
|
||||
<string name="last_seen_at">Vist per darrer cop: %1$s</string>
|
||||
<!-- Refers to the time a contact was last seen. Shown below contact name in the profile. The placeholder will be replaced by a relative point in time as "3 minutes ago" (see https://momentjs.com for more examples and languages)-->
|
||||
<!-- Refers to the time a contact was last seen. Shown below contact name in the profile. The placeholder will be replaced by a relative point in time as "3 minutes ago" (see https://momentjs.com for more examples and languages) -->
|
||||
<string name="last_seen_relative">Vist per darrer cop: %1$s</string>
|
||||
<string name="last_seen_unknown">Vist per darrer cop: desconegut</string>
|
||||
<!-- Shown in call duration. Avoid abbreviations, prefer full words ex. "N seconds". -->
|
||||
<plurals name="n_seconds_ext">
|
||||
<item quantity="one">%d segon</item>
|
||||
<item quantity="other">%d segons</item>
|
||||
</plurals>
|
||||
<!-- Shown in call duration. Avoid abbreviations, prefer full words ex. "N minutes". -->
|
||||
<plurals name="n_minutes_ext">
|
||||
<item quantity="one">%d minut</item>
|
||||
<item quantity="other">%d minuts</item>
|
||||
<!-- Call duration as shown in the call bubbles. There is some risk to mix with the sending time, so the word "Duration" may be helpful. Might also be "Duration: %d minutes", "%d-minute duration", "%d-minute length" or "%d-minute call" -->
|
||||
<plurals name="call_duration_minutes">
|
||||
<item quantity="one">%d durada d\'un minut</item>
|
||||
<item quantity="other">%d minuts de durada</item>
|
||||
</plurals>
|
||||
<!-- Call duration as shown in the call bubbles in case the call is less than one minute. If the context is not clear enough, one may want to add the word "Duration". -->
|
||||
<string name="call_duration_less_than_a_minute">Menys d\'1 minut</string>
|
||||
<!-- Shown beside messages that are "N minutes old". Prefer short strings, or well-known abbreviations. -->
|
||||
<plurals name="n_minutes">
|
||||
<item quantity="one">%d min</item>
|
||||
@@ -169,6 +163,7 @@
|
||||
<item quantity="other">%d seleccionats</item>
|
||||
</plurals>
|
||||
<string name="selected_colon">Seleccionat:</string>
|
||||
<string name="selected">Seleccionat</string>
|
||||
<string name="self">Jo</string>
|
||||
<string name="draft">Esborrany</string>
|
||||
<string name="image">Imatge</string>
|
||||
@@ -180,6 +175,9 @@
|
||||
<string name="add_to_sticker_collection">Afegeix a la col·lecció d\'adhesius</string>
|
||||
<string name="add_stickers_instructions">Per a afegir adhesius: premeu \"Obre la carpeta d\'adhesius\", creeu una subcarpeta per a la vostra col·lecció d\'adhesius i arrossegueu-hi la imatge i els fitxers d\'adhesius.</string>
|
||||
<string name="open_sticker_folder">Obre la carpeta d\'adhesius</string>
|
||||
<string name="ask_add_sticker_to_collection">Afegir l\'adhesiu a la col·lecció?</string>
|
||||
<string name="ask_delete_sticker">Esborrar l\'adhesiu?</string>
|
||||
<string name="sticker_picker_empty_hint">Prem un adhesiu per afegir-lo aquí.</string>
|
||||
<string name="images">Imatges</string>
|
||||
<!-- a noun, used for "Music" and other "Audio" files -->
|
||||
<string name="audio">Àudio</string>
|
||||
@@ -259,10 +257,13 @@
|
||||
<string name="channels">Canals</string>
|
||||
<!-- consider keeping the term "channel" as in WhatsApp or Telegram -->
|
||||
<string name="new_channel">Nou Canal</string>
|
||||
<!-- deprecated -->
|
||||
<string name="add_recipients">Afegeix destinataris</string>
|
||||
<!-- consider keeping the term "channel" as in WhatsApp or Telegram -->
|
||||
<string name="channel_name">Nom del Canal</string>
|
||||
<!-- The number of times a message is shown in channels. Use what other messengers are using here, smth. as "N-times seen" or "1 Aufruf" (german) work as well, where "1 impression" or "1 hit" may sound too formal and may be more marketing slang. -->
|
||||
<plurals name="n_views">
|
||||
<item quantity="one">%d vista</item>
|
||||
<item quantity="other">%d visualitzacions</item>
|
||||
</plurals>
|
||||
<string name="email">Correu electrònic</string>
|
||||
<!-- "New" as in "Create New Email"; shown together with "New Group" and "New Channel" -->
|
||||
<string name="new_email">Nou correu electrònic</string>
|
||||
@@ -278,6 +279,7 @@
|
||||
<string name="menu_add_attachment">Afegeix un adjunt</string>
|
||||
<string name="menu_leave_group">Deixa el grup</string>
|
||||
<string name="menu_leave_channel">Sortir del Canal</string>
|
||||
<string name="menu_leave_and_delete">Sortir i esborrar per a mi</string>
|
||||
<string name="menu_delete_chat">Esborra el xat</string>
|
||||
<!-- Command to delete all messages in a chat. The chat itself will not be deleted but will be empty afterwards, so make sure to be different from "Delete Chat" here. "Clear" is a verb here, "Empty Chat" would also be fine (eg. in German "Chat leeren") -->
|
||||
<string name="clear_chat">Buida el xat</string>
|
||||
@@ -329,7 +331,7 @@
|
||||
<!-- The placeholder will be replaced by the name the contact gave themself -->
|
||||
<string name="edit_name_explain">Indiqueu un sobrenom que se us mostrarà en comptes de «%1$s». Deixeu-ho buit per a usar el nom triat pel contacte.</string>
|
||||
<!-- The placeholder will be replaced by the name the contact gave themself -->
|
||||
<string name="edit_name_placeholder">Sobrenom per a «%1$s»</string>
|
||||
<string name="edit_name_placeholder">Sobrenom per a «%1$s»</string>
|
||||
<string name="menu_settings">Preferències</string>
|
||||
<string name="menu_advanced">Avançat</string>
|
||||
<string name="menu_view_profile">Veure el perfil</string>
|
||||
@@ -339,14 +341,12 @@
|
||||
<string name="menu_more_options">Més opcions</string>
|
||||
<string name="menu_learn_spelling">Aprèn l\'ortografia</string>
|
||||
<string name="jump_to_message">Ves al missatge</string>
|
||||
<string name="jump_to_original_message">Vés al Missatge Original</string>
|
||||
<string name="copy_json">Copia el JSON</string>
|
||||
<string name="replace_draft">Substitueix l\'esborrany</string>
|
||||
<string name="title_share_location">Comparteix la ubicació amb tots els membres del grup</string>
|
||||
<string name="device_talk">Missatges del dispositiu</string>
|
||||
<string name="device_talk_subtitle">Missatges generats localment</string>
|
||||
<string name="device_talk_explain">Els missatges d\'aquest xat són generats en el vostre dispositiu per a informar-vos sobre actualitzacions de l\'aplicació o de problemes durant el seu ús.</string>
|
||||
<string name="device_talk_welcome_message2">Esteu en contacte!\n\n🙌 Toqueu «Codi QR» en la finestra principal d\'ambdós dispositius. Trieu «Escaneja codi QR» en un dispositiu, i apunteu cap a l\'altre\n\n🌍 Si no esteu en la mateixa sala, podeu escanejar o compartir un enllaç d\'invitació des de «Escaneja codi QR»\n\nDesprés: gaudiu de l\'experiència de missatgeria sobre la xarxa descentralitzada més gran que ha existit mai: el correu electrònic. I, en contrast amb altres aplicacions populars, sense control central, seguiment ni comercialització de vós, amics, col·legues o familiars amb grans organitzacions.</string>
|
||||
<string name="device_talk_welcome_message2">Esteu en contacte!\n\n🙌 Prem «Codi QR» a la finestra principal d\'ambdós dispositius. Tria «Escaneja codi QR» en un dispositiu, i apunta cap a l\'altre\n\n🌍 Si no esteu a la mateixa sala, podeu escanejar o compartir un enllaç d\'invitació des de \"Escaneja codi QR\"\n\nLlavors: gaudiu de l\'experiència de missatgeria sobre la xarxa descentralitzada més gran que ha existit mai: el correu electrònic. I, en comparació amb altres aplicacions populars, sense control central, sense seguiment ni tampóc comercialització per part de grans companyies de tu i els teus amics, col·legues o familiars.</string>
|
||||
<string name="edit_contact">Edita el contacte</string>
|
||||
<!-- Verb "to pin", making something sticky, not a noun or abbreviation for "pin number". -->
|
||||
<string name="pin_chat">Fixa el xat</string>
|
||||
@@ -384,26 +384,35 @@
|
||||
|
||||
<!-- the action "to call someone", used as a tooltip for the "phone" icon. not: "the call" -->
|
||||
<string name="start_call">Truca</string>
|
||||
<!-- Menu item to start an audio call; verbs as "start" are probably superfluous in many translations -->
|
||||
<string name="start_audio_call">Trucada de veu</string>
|
||||
<!-- Menu item to start a video call; verbs as "start" are probably superfluous in many translations -->
|
||||
<string name="start_video_call">Videotrucada</string>
|
||||
<!-- the action "to answer" or to "accept" or to "pick up" a call. not: "the answer" -->
|
||||
<string name="answer_call">Respon</string>
|
||||
<!-- the action "to decline" a call, not: "the decline" -->
|
||||
<string name="end_call">Rebutja</string>
|
||||
<!-- deprecated, use outgoing_audio_call or outgoing_video_call instead -->
|
||||
<string name="outgoing_call">Trucada sortint</string>
|
||||
<!-- Used in call bubbles, summaries, notifications -->
|
||||
<string name="audio_call">Trucada de veu</string>
|
||||
<!-- Used in call bubbles, summaries, notifications -->
|
||||
<string name="video_call">Video trucada</string>
|
||||
<string name="call_initializing">Inicialitzant...</string>
|
||||
<string name="call_incoming">Et truquen</string>
|
||||
<string name="call_ringing">Trucant...</string>
|
||||
<string name="call_reconnecting">Reconnectant...</string>
|
||||
<string name="call_ended">Trucada finalitzada</string>
|
||||
<string name="call_failed">Trucada fallida</string>
|
||||
<!-- deprecated, use "Audio call" instead -->
|
||||
<string name="outgoing_audio_call">Trucada de veu sortint</string>
|
||||
<!-- deprecated, use "Video call" instead -->
|
||||
<string name="outgoing_video_call">Videotrucada sortint</string>
|
||||
<!-- deprecated, use incoming_audio_call or incoming_video_call instead -->
|
||||
<string name="incoming_call">Trucada entrant</string>
|
||||
<!-- deprecated, use "Audio call" instead -->
|
||||
<string name="incoming_audio_call">Trucada de veu entrant</string>
|
||||
<!-- deprecated, use "Video call" instead -->
|
||||
<string name="incoming_video_call">Videotrucada entrant</string>
|
||||
<string name="declined_call">Trucada rebutjada</string>
|
||||
<string name="canceled_call">Trucada cancel·lada</string>
|
||||
<string name="missed_call">Trucada perduda</string>
|
||||
<!-- the first placeholder will be replaced by a date, the second placeholder by duration, example: "Thu, 08:12 pm, 2 minutes" -->
|
||||
<string name="call_date_and_duration">%1$s, %2$s</string>
|
||||
|
||||
<!-- get confirmations -->
|
||||
<!-- confirmation for leaving groups or channels. If a subject is needed, "Are you sure you want to leave the chat?" would work as well -->
|
||||
<string name="ask_leave_group">Segur que vols sortir?</string>
|
||||
@@ -431,12 +440,10 @@
|
||||
<string name="ask_remove_from_channel">Eliminar %1$s del canal?</string>
|
||||
<string name="open_url_confirmation">Voleu obrir aquest enllaç?</string>
|
||||
|
||||
|
||||
<!-- contact list -->
|
||||
<string name="contacts_title">Llista de contactes</string>
|
||||
<string name="contacts_type_email_above">Escriviu l\'adreça d\'email superior</string>
|
||||
|
||||
|
||||
<!-- chatlist and chat view -->
|
||||
<plurals name="chat_archived">
|
||||
<item quantity="one">%d xat arxivat</item>
|
||||
@@ -491,30 +498,19 @@
|
||||
<!-- "Start..." button for an app -->
|
||||
<string name="start_app">Comença...</string>
|
||||
<!-- this is a warning that is shown when one tries to send something to a chat that is not yet accepted. -->
|
||||
<string name="accept_request_first">Si us plau accepteu primer el requeriment del xat.</string>
|
||||
<string name="accept_request_first">Si us plau accepteu primer la sol·licitud del xat.</string>
|
||||
<!-- title shown above a list of chats where one should be selected (eg. when sharing files from a webxdc). the placeholder will be replaced by a file name -->
|
||||
<string name="send_file_to">Envia \"%1$s\" a…</string>
|
||||
<!-- title shown above a list contacts where one should be selected (eg. when a webxdc attempts to send a message to a chat) -->
|
||||
<string name="send_message_to">Envia el missatge a...</string>
|
||||
<string name="enable_realtime">Aplicacions en temps real</string>
|
||||
<string name="enable_realtime_explain">Activa connexions en temps real per a aplicacions compartides als xats. Si està activada, els companys de xat poden descobrir la vostra IP en iniciar una aplicació.</string>
|
||||
|
||||
<!-- map -->
|
||||
<string name="filter_map_on_time">Mostra les ubicacions al llarg del temps</string>
|
||||
<string name="show_location_traces">Mostra el rastre</string>
|
||||
<string name="add_poi">Envia el punt d\'interès</string>
|
||||
|
||||
|
||||
<!-- punycode warning / labeled links -->
|
||||
<!-- placeholder is domain/hostname that should be trusted -->
|
||||
<string name="open_external_url_trust_domain">No em tornis a demanar per %1$s</string>
|
||||
<string name="puny_code_warning_header">S\'ha detectat un enllaç sospitós</string>
|
||||
<!-- placeholder contains the hostname converted to ascii -->
|
||||
<string name="puny_code_warning_question">Esteu segur de voler visitar %1$s?</string>
|
||||
<!-- this message is shown whenever a link with non-latin characters is clicked. first placeholder is original hostname with special chars, second placeholder is hostname encoded in ascii -->
|
||||
<string name="puny_code_warning_description">Aquest enllaç usa caràcters amb un aspecte similar però de diferents alfabets. Si seguiu l\'enllaç %1$sus enviarà a %2$s, que és normal per a caràcters no llatins. Si no espereu aquests caràcters, l\'enllaç podria ser maliciós. </string>
|
||||
|
||||
|
||||
<!-- search -->
|
||||
<string name="search">Busca</string>
|
||||
<string name="search_in_chat">Busca al xat</string>
|
||||
@@ -524,7 +520,6 @@
|
||||
<!-- Adjective, as in "Show Unread Messages" -->
|
||||
<string name="search_unread">Sense llegir</string>
|
||||
|
||||
|
||||
<!-- create/edit groups, contact/group profile -->
|
||||
<string name="group_name">Nom del grup</string>
|
||||
<string name="group_avatar">Imatge del grup</string>
|
||||
@@ -567,7 +562,7 @@
|
||||
<string name="multidevice_this_creates_a_qr_code">Això crea un codi QR que es pot escanejar en un segon dispositiu per a copiar el perfil.</string>
|
||||
<string name="multidevice_install_dc_on_other_device">Instal·leu Delta Chat en el vostre altre dispositiu (https://get.delta.chat)</string>
|
||||
<!-- "I Already Have a Profile / Add as Second Device” should be the same text as defined by the keys onboarding_alternative_logins and multidevice_receiver_title -->
|
||||
<string name="multidevice_tap_scan_on_other_device">Inicieu Delta Chat, toqueu «Ja tinc un perfil / Afegeix un segon dispositiu» i escanegeu el codi que es mostra aquí.</string>
|
||||
<string name="multidevice_tap_scan_on_other_device">Inicieu Delta Chat, toqueu «Ja tinc un perfil / Afegeix un segon dispositiu» i escanegeu el codi que es mostra aquí.</string>
|
||||
<!-- Shown inside a "QR code card" with very limited space; please formulate the text as short as possible therefore. The placeholder will be replaced by the profile name eg. "Scan to set up second device for Alice" -->
|
||||
<string name="multidevice_qr_subtitle">Escanegeu-lo per configurar un segon dispositiu per a %1$s</string>
|
||||
<string name="multidevice_receiver_title">Afegeix com a segon dispositiu</string>
|
||||
@@ -588,8 +583,6 @@
|
||||
<string name="incoming_messages">Missatges entrants</string>
|
||||
<!-- Headline for the "Outbox" eg. in the "Connectivity" view -->
|
||||
<string name="outgoing_messages">Missatges sortints</string>
|
||||
<!-- deprecated -->
|
||||
<string name="storage_on_domain">Emmagatzematge a %1$s.</string>
|
||||
<string name="connectivity">Connectivitat</string>
|
||||
<!-- Shown in the title bar if the app is "Not connected"; prefer short strings. -->
|
||||
<string name="connectivity_not_connected">Desconnectat</string>
|
||||
@@ -607,11 +600,10 @@
|
||||
<!-- Used for describing resource usage, resulting string will be eg. "1.2 GiB of 3 GiB used" -->
|
||||
<string name="part_of_total_used">%1$s de %2$s usats</string>
|
||||
|
||||
|
||||
<!-- welcome and login -->
|
||||
<!-- Primary button on the welcome screen, allows to create an instant profile -->
|
||||
<string name="onboarding_create_instant_account">Crea un perfil nou</string>
|
||||
<!-- Secondary button on the welcome screen, allows to "Add as Second Device", "Restore from Backup" -->
|
||||
<!-- Secondary button on the welcome screen, allows to "Add as Second Device", "Restore from Backup" -->
|
||||
<string name="onboarding_alternative_logins">Ja tinc un perfil</string>
|
||||
<!-- This is a button and a title, allowing to use existing, classic email, setting ports, passwords and so on -->
|
||||
<string name="manual_account_setup_option">Inici de sessió correu-e clàssic</string>
|
||||
@@ -638,7 +630,7 @@
|
||||
<string name="welcome_chat_over_email">Xat segur i descentralitzat</string>
|
||||
<string name="scan_invitation_code">Escaneja el Codi d\'Invitació</string>
|
||||
<string name="login_title">Identifiqueu-vos</string>
|
||||
<string name="login_advanced_hint">Aquest inici de sessió és per a usuaris avançats:\n\n• No feu servir una adreça que utilitzeu a una altra app.\n\n• Les adreces de correu tradicional admeten xats sense xifratge d\'extrem a extrem, indicades amb una icona de correu.</string>
|
||||
<string name="login_advanced_hint">Aquest inici de sessió és per a usuaris avançats:\n\n• No feu servir una adreça que utilitzeu a una altra app.\n\n• Les adreces de correu tradicional admeten xats sense xifrar d\'extrem a extrem, indicades amb una icona de correu.</string>
|
||||
<string name="login_inbox">Safata d\'entrada</string>
|
||||
<string name="login_imap_login">Nom d\'identificació IMAP</string>
|
||||
<string name="login_imap_server">Servidor IMAP</string>
|
||||
@@ -665,10 +657,25 @@
|
||||
<string name="proxy_share_link">Comparteix l\'enllaç</string>
|
||||
<string name="proxy_enabled">Servidor intermediari activat</string>
|
||||
<string name="proxy_enabled_hint">Esteu fent servir un servidor intermediari. Si teniu problemes per a connectar-vos, proveu un servidor intermediari diferent.</string>
|
||||
<!-- "Relay" refers to the relay servers used; please chose a common term in your language, no need to be literal. If in doubt, stay with "Relay" -->
|
||||
<string name="transports">Relés</string>
|
||||
<string name="add_transport">Afegir Relé</string>
|
||||
<string name="remove_transport">Elimina Relé</string>
|
||||
<string name="edit_transport">Edita Relé</string>
|
||||
<string name="used_for_sending">Utilitzat per enviar</string>
|
||||
<string name="hide_from_contacts">Amagar als contactes</string>
|
||||
<string name="hidden_from_contacts">Amagat als contactes</string>
|
||||
<!-- Hint for the list of relays -->
|
||||
<string name="transport_list_hint">Missatges rebuts en tots els relés</string>
|
||||
<!-- shown if a QR code was scanned that can be used as a relay -->
|
||||
<string name="confirm_add_transport">Afegeix aquest relé?</string>
|
||||
<string name="invalid_transport_qr">El codi QR escanejat no conté un relé vàlid.</string>
|
||||
<!-- placeholder will be replaced by a relay server name -->
|
||||
<string name="confirm_remove_or_hide_transport_x">Esborrar el relé \"%1$s\"?\n\nEls contactes que només coneixen aquest relé no et podran contactar fins que els escriguis de nou.\n\nSi no ho tens clar, amaga\'l enlloc d\'esborrar-lo.</string>
|
||||
<string name="login_certificate_checks">El certificat coincideix</string>
|
||||
<string name="login_error_mail">Si us plau poseu una adreça d\'email vàlida</string>
|
||||
<string name="login_error_server">Si us plau poseu un servidor / adreça IP vàlida</string>
|
||||
<string name="login_error_port">Si us plau poseu un port vàlid (1-65535)</string>
|
||||
<string name="login_error_port">Si us plau poseu un port vàlid (1-65535)</string>
|
||||
<string name="login_error_required_fields">Si us plau poseu una adreça i contrasenya vàlids</string>
|
||||
<string name="import_backup_title">Importa una còpia de seguretat</string>
|
||||
<string name="import_backup_ask">S\'ha trobat una còpia de seguretat a \"%1$s\".\n\nVoleu importar-la i fer-ne servir les dades i els paràmetres de configuració?</string>
|
||||
@@ -677,17 +684,17 @@
|
||||
<string name="login_error_cannot_login">No es pot iniciar la sessió com a \"%1$s\". Comproveu que l\'adreça electrònica i la contrasenya són correctes.</string>
|
||||
<!-- TLS certificate checks -->
|
||||
<string name="accept_invalid_certificates">Accepta certificats no vàlids</string>
|
||||
<string name="switch_account">Canvia el perfil</string>
|
||||
<string name="add_account">Afegeix un compte</string>
|
||||
<string name="switch_account">Canvia de perfil</string>
|
||||
<string name="add_account">Afegeix un perfil</string>
|
||||
<!-- for translations, you can also think of "Profile Tag" or "Profile Description" as the source string -->
|
||||
<string name="profile_tag">Etiqueta de Perfil</string>
|
||||
<string name="profile_tag">Etiqueta del Perfil</string>
|
||||
<string name="profile_tag_hint">p.ex. treball, família</string>
|
||||
<string name="profile_tag_explain">Configureu una etiqueta visible només per a vosaltres; ajudant-vos a diferir entre els vostres perfils.</string>
|
||||
<string name="profile_tag_explain">Configureu una etiqueta visible només per a vosaltres; ajudant-vos a diferenciar entre els vostres perfils.</string>
|
||||
<!-- Menu entry to sort an item to the beginning of a list. Only "To Top" may do as well in some translations, if that helps to stay shorter. -->
|
||||
<string name="move_to_top">Desplaçat a l\'inici</string>
|
||||
<string name="delete_account">Esborra el perfil</string>
|
||||
<string name="delete_account_ask">Esteu segur de voler esborrar les dades del vostre perfil?</string>
|
||||
<string name="delete_account_explain_with_name">S\'esborraran totes les dades del perfil «%s» en aquest dispositiu, incloent-hi la configuració de xifratge d\'extrem a extrem, contactes, xats, missatges i contingut multimèdia. Aquesta acció no es pot desfer.</string>
|
||||
<string name="delete_account_explain_with_name">S\'esborraran totes les dades del perfil «%s» en aquest dispositiu, incloent-hi la configuració de xifrat d\'extrem a extrem, contactes, xats, missatges i contingut multimèdia. Aquesta acció no es pot desfer.</string>
|
||||
<string name="unconfigured_account">Perfil sense configurar</string>
|
||||
<string name="unconfigured_account_hint">Obriu el per perfil per a configurar-lo.</string>
|
||||
<string name="try_connect_now">Prova de connectar-hi ara</string>
|
||||
@@ -705,22 +712,21 @@
|
||||
<string name="share_text_multiple_chats">Voleu enviar aquest text a %1$d xats?\n\n«%2$s»</string>
|
||||
<string name="share_abort">S\'ha avortat la compartició per falta de permisos.</string>
|
||||
|
||||
|
||||
<!-- preferences -->
|
||||
<string name="pref_using_custom">Ús personalitzat: %s</string>
|
||||
<string name="pref_using_default">Ús per defecte: %s</string>
|
||||
<string name="pref_profile_info_headline">El vostre perfil</string>
|
||||
<string name="pref_profile_photo">Fotografia de perfil</string>
|
||||
<string name="pref_blocked_contacts">Contactes bloquejats</string>
|
||||
<string name="blocked_empty_hint">Els contactes blocats apareixeran aquí.</string>
|
||||
<string name="pref_who_can_see_profile_explain">La vostra imatge de perfil, nom i biografia s\'enviaran amb juntament els missatges que escriviu quant us comuniqueu amb altres usuaris.</string>
|
||||
<string name="pref_who_can_see_profile_explain">La vostra imatge de perfil, nom i signatura s\'enviaran juntament amb els missatges que escriviu quant us comuniqueu amb altres usuaris.</string>
|
||||
<string name="pref_your_name">El vostre nom</string>
|
||||
<!-- Label of the Bio/Signature/Status/Motto field -->
|
||||
<string name="pref_default_status_label">Signatura</string>
|
||||
<string name="chat_description">Descripció</string>
|
||||
<!-- Option name for changing behaviour of the "Enter key" to sending out a message directly (instead of adding new line). If in doubt, please refer to a similar option in other messengers. -->
|
||||
<string name="pref_enter_sends">La tecla «Retorn» envia</string>
|
||||
<string name="pref_enter_sends_explain">Els missatges s\'enviaran prement la tecla «Retorn»</string>
|
||||
<string name="pref_outgoing_media_quality">Qualitat del contingut multimèdia sortint</string>
|
||||
<string name="pref_outgoing_media_quality_hint">Per enviar sense comprimir, adjunta-ho com a \"Fitxer\". Això consumeix més dades, tant les teves, com les dels destinataris.</string>
|
||||
<string name="pref_outgoing_balanced">Balancejat</string>
|
||||
<string name="pref_outgoing_worse">Pitjor qualitat, mida petita</string>
|
||||
<string name="pref_vibrate">Vibració</string>
|
||||
@@ -731,6 +737,10 @@
|
||||
<string name="pref_notifications">Notificacions</string>
|
||||
<string name="pref_mention_notifications">Mencions</string>
|
||||
<string name="pref_mention_notifications_explain">En els grups silenciats, notifica els missatges dirigits a vós, com ara respostes i reaccions</string>
|
||||
<!-- Title for the "Calls" notification setting. This is a plural noun, not a verb. -->
|
||||
<string name="pref_calls">Trucades</string>
|
||||
<!-- Details about what the "Calls" notification setting does -->
|
||||
<string name="pref_calls_explain">Mostrar la pantalla de trucada quan reps una trucada</string>
|
||||
<string name="pref_notifications_show">Mostra</string>
|
||||
<string name="pref_notifications_priority">Prioritat</string>
|
||||
<string name="pref_notifications_explain">Habilita les notificacions del sistema per als missatges nous</string>
|
||||
@@ -740,8 +750,6 @@
|
||||
<string name="pref_sound">So</string>
|
||||
<string name="pref_silent">Silenci</string>
|
||||
<string name="pref_privacy">Privacitat</string>
|
||||
<!-- deprecated, use pref_chats -->
|
||||
<string name="pref_chats_and_media">Xats i multimèdia</string>
|
||||
<string name="pref_system_default">Per defecte del sistema</string>
|
||||
<!-- Translators: as in "opposite of dark" -->
|
||||
<string name="pref_light_theme">Clar</string>
|
||||
@@ -778,10 +786,10 @@
|
||||
<string name="pref_background_btn_default">Usa la imatge per defecte</string>
|
||||
<string name="pref_background_btn_gallery">Trieu de la galeria</string>
|
||||
<string name="pref_imap_folder_warn_disable_defaults">Si desactiveu aquesta opció, assegureu-vos que el vostre servidor i els altres programes estiguin configurats de la mateixa manera.\n\nAltrament podeu tenir problemes de funcionament.</string>
|
||||
<!-- No need to be literal here, you can also use "Use Multiple Devices", "Support Multiple Devices" or other fitting terms. However, it should fit to the wording or your language at https://delta.chat/help -->
|
||||
<!-- No need to be literal here, you can also use "Use Multiple Devices", "Support Multiple Devices" or other fitting terms. However, it should fit to the wording or your language at https://delta.chat/help -->
|
||||
<string name="pref_multidevice">Mode multidispositiu</string>
|
||||
<string name="pref_multidevice_explain">Sincronitza els vostres missatges amb els vostres altres dispositius. Activat automàticament quan s\'afegeix un segon dispositiu.</string>
|
||||
<string name="pref_multidevice_change_warn">El mode multidispositiu ha d\'estar habilitat quan feu servir el mateix compte des de diferents perfils. Només desactiveu aquesta opció si heu suprimit aquest perfil de tots els vostres altres dispositius.\n\nDesactivar aquesta opció mentre es fa servir en el mateix perfil en múltiples dispositius farà que es perdin missatges i hi hagi altres problemes.</string>
|
||||
<string name="pref_multidevice_change_warn">El mode multidispositiu ha d\'estar habilitat quan feu servir el mateix perfil des de diferents dispositius. Desactiva aquesta opció només si has esborrat aquest perfil de tots els altres dispositius.\n\nDesactivar aquesta opció mentre es fa servir el mateix perfil en múltiples dispositius farà que es perdin missatges i hi hagi altres problemes.</string>
|
||||
<string name="pref_auto_folder_moves">Moure automàticament a la carpeta de Delta Chat</string>
|
||||
<string name="pref_only_fetch_mvbox_title">Agafa només de la carpeta de DeltaChat</string>
|
||||
<string name="pref_show_emails">Mostra els correus clàssics</string>
|
||||
@@ -806,15 +814,11 @@
|
||||
<string name="n_bytes_message">%1$s missatge</string>
|
||||
<!-- %1$s will be replaced by human-readable date and time -->
|
||||
<string name="download_max_available_until">Baixa el màxim disponible fins a %1$s</string>
|
||||
<!-- deprecated -->
|
||||
<string name="select_profile">Trieu Perfil</string>
|
||||
<string name="profile_image_select">Trieu la imatge de perfil</string>
|
||||
<string name="select_your_new_profile_image">Trieu la imatge nova de perfil</string>
|
||||
<string name="profile_image_delete">Esborra la imatge del perfil</string>
|
||||
<string name="pref_show_tray_icon">Mostra la icona de la safata</string>
|
||||
<string name="pref_edit_profile">Edita el perfil</string>
|
||||
<string name="disable_imap_idle">Desactiva IMAP IDLE</string>
|
||||
<string name="disable_imap_idle_explain">No usis l\'extensió IMAP IDLE encara que el servidor la permeti. Activar aquesta opció endarreria l\'obtenció de missatges, activeu-ho només per a proves.</string>
|
||||
<string name="send_stats_to_devs">Envia estadístiques als desenvolupadors del Delta Chat</string>
|
||||
<string name="stats_device_message">Voleu ajudar a millorar Delta Chat i donar suport a la recerca enviant estadístiques d\'ús anònimes setmanalment?\n\n👉 Feu clic aquí… 👈</string>
|
||||
<string name="stats_confirmation_dialog">Voleu ajudar a millorar Delta Chat i donar suport a la recerca enviant estadístiques d\'ús anònimes setmanalment?</string>
|
||||
@@ -872,12 +876,15 @@
|
||||
<string name="systemmsg_subject_for_new_contact">Missatge de %1$s</string>
|
||||
<string name="systemmsg_failed_sending_to">No s\'ha pogut enviar el missatge a %1$s.</string>
|
||||
<!-- %1$s will be replaced by the old group name, %2$s will be replaced by the new group name -->
|
||||
<string name="group_name_changed_by_you">Heu canviat el nom del grup de «%1$s» a «%2$s».</string>
|
||||
<string name="group_name_changed_by_you">Heu canviat el nom del grup de «%1$s» a «%2$s».</string>
|
||||
<!-- %1$s will be replaced by the old group name, %2$s will be replaced by the new group name, %3$s will be replaced by name and address of the contact who did the action. -->
|
||||
<string name="group_name_changed_by_other">Nom del grup \"%1$s\" canviat a \"%2$s\" per %3$s.</string>
|
||||
<string name="group_image_changed_by_you">Heu canviat la imatge de grup.</string>
|
||||
<!-- %1$s will be replaced by name of the contact who did the action -->
|
||||
<string name="group_image_changed_by_other">Imatge de grup canviada per %1$s.</string>
|
||||
<string name="chat_description_changed_by_you">Has modificat la descripció del xat.</string>
|
||||
<!-- %1$s will be replaced by name of the contact who did the action -->
|
||||
<string name="chat_description_changed_by_other">Descripció del xat modificada per %1$s.</string>
|
||||
<!-- %1$s will be replaced by name of the contact added to the group -->
|
||||
<string name="member_x_added">S\'ha afegit el membre %1$s.</string>
|
||||
<!-- %1$s will be replaced by name of the contact added to the group -->
|
||||
@@ -910,10 +917,6 @@
|
||||
<string name="ephemeral_timer_seconds_by_you">Heu definit el temporitzador dels missatges efímers a %1$s segons.</string>
|
||||
<!-- %1$s will be replaced by the number of seconds (always >1) the timer is set to, %2$s will be replaced by name of the contact -->
|
||||
<string name="ephemeral_timer_seconds_by_other">%2$s ha definit el temporitzador dels missatges efímers a %1$s segons.</string>
|
||||
<!-- deprecated, usage needs to be removed in core -->
|
||||
<string name="ephemeral_timer_1_minute_by_you">Heu definit el temporitzador dels missatges fonedissos a 1 segon.</string>
|
||||
<!-- deprecated, usage needs to be removed in core -->
|
||||
<string name="ephemeral_timer_1_minute_by_other">%1$s ha definit el temporitzador dels missatges efímers a 1 minut.</string>
|
||||
<string name="ephemeral_timer_1_hour_by_you">Heu definit el temporitzador dels missatges fonedissos a 1 hora.</string>
|
||||
<!-- %1$s will be replaced by name of the contact -->
|
||||
<string name="ephemeral_timer_1_hour_by_other">%1$s ha definit el temporitzador dels missatges efímers a 1 hora.</string>
|
||||
@@ -973,7 +976,7 @@
|
||||
<string name="qrscan_contains_text">Text del codi QR escanejat:\n\n%1$s</string>
|
||||
<string name="qrscan_contains_url">URL del codi QR escanejat:\n\n%1$s</string>
|
||||
<string name="qrscan_fingerprint_label">Empremta</string>
|
||||
<string name="withdraw_verifycontact_explain">Altres persones que vulguin contactar amb vós poden escanejar aquest codi QR.\n\nPodeu reinicialitzar-lo, de manera que el codi QR o enllaç actual existent ja no servirà.</string>
|
||||
<string name="withdraw_verifycontact_explain">Altres persones que vulguin contactar amb vós poden escanejar aquest codi QR.\n\nPodeu reinicialitzar-lo, de manera que el codi QR o enllaç d\'invitació existent ja no servirà.</string>
|
||||
<string name="withdraw_verifygroup_explain">Altres poden escanejar aquest codi QR per a unir-se al grup «%1$s».\n\nPodeu reinicialitzar-lo, de manera que el codi QR existent, o l\'enllaç d\'invitació, deixarà de funcionar.</string>
|
||||
<string name="withdraw_joinbroadcast_explain">Altres poden escanejar aquest codi QR per a unir-se al canal «%1$s».\n\nPodeu reinicialitzar-lo, de manera que el codi QR existent, o l\'enllaç d\'invitació, deixarà de funcionar.</string>
|
||||
<string name="withdraw_qr_code">Reinicialitza el codi QR</string>
|
||||
@@ -981,7 +984,7 @@
|
||||
<string name="revive_qr_code">Activa el codi QR</string>
|
||||
<string name="qrshow_title">Codi QR d\'invitació</string>
|
||||
<string name="qrshow_x_joining">%1$s s\'uneix.</string>
|
||||
<string name="qrshow_x_verified">%1$s verificat.</string>
|
||||
<string name="qrshow_x_verified">%1$s afegit.</string>
|
||||
<string name="qrshow_x_has_joined_group">%1$s s\'ha unit al grup.</string>
|
||||
<string name="qrshow_join_group_title">Codi QR d\'invitació</string>
|
||||
<!-- This text is shown inside the "QR code card" with very limited space; please formulate the text as short as possible therefore. The placeholder will be replaced by the group name, eg. "Scan to join group \"Testing group\"" -->
|
||||
@@ -1004,20 +1007,18 @@
|
||||
<!-- placeholder will be replaced by the name of the inviter. -->
|
||||
<string name="secure_join_replies">%1$s ha respost, espereu per a ser afegit al grup...</string>
|
||||
<string name="secure_join_wait">S\'està establint el xifratge d\'extrem a extrem garantit, espereu...</string>
|
||||
<string name="contact_verified">%1$s verificat.</string>
|
||||
<string name="contact_verified">%1$s afegit.</string>
|
||||
<string name="contact_blocked">Heu blocat el contacte</string>
|
||||
<!-- Shown in contact profile. The placeholder will be replaced by the name of the contact that introduced the contact. -->
|
||||
<string name="verified_by">Afegit per %1$s</string>
|
||||
<string name="verified_by_you">Afegit per mi</string>
|
||||
<string name="verified_by_unknown">Afegit</string>
|
||||
<!-- deprecated -->
|
||||
<string name="verified_contact_required_explain">Per a garantir el xifrat extrem a extrem, només podeu afegir a aquest grup contactes que tinguin la marca verda.\n\nPodeu trobar-vos en persona amb els contactes per a escanejar els seus codis QR i poder-los afegir. </string>
|
||||
<string name="mailto_dialog_header_select_chat">Trieu el xat on enviar el missatge</string>
|
||||
<!-- first placeholder is the name of the chat -->
|
||||
<string name="confirm_replace_draft">%1$s ja té un missatge d\'esborrany, voleu substituir-lo?</string>
|
||||
<string name="mailto_link_could_not_be_decoded">No s\'ha pogut desxifrar l\'enllaç mailto: %1$s</string>
|
||||
|
||||
<!-- notifications -->
|
||||
<!-- notifications -->
|
||||
<string name="notify_reply_button">Respondre</string>
|
||||
<string name="notify_new_message">Missatge nou</string>
|
||||
<string name="notify_background_connection_enabled">Connexió habilitada en segon pla</string>
|
||||
@@ -1033,7 +1034,6 @@
|
||||
<string name="new_messages_body">Teniu missatges nous</string>
|
||||
<string name="n_messages_in_m_chats">%1$d missatges en %2$d xats</string>
|
||||
|
||||
|
||||
<!-- permissions -->
|
||||
<string name="perm_required_title">Es requereix permís</string>
|
||||
<string name="perm_continue">Continua</string>
|
||||
@@ -1054,9 +1054,6 @@
|
||||
<string name="ImageEditorHud_flip">Capgira</string>
|
||||
<string name="ImageEditorHud_rotate">Gira</string>
|
||||
|
||||
<!-- strings introduced on desktop. we want to share strings between the os, in general, please do not add generic strings here -->
|
||||
<string name="about_offical_app_desktop">Aquesta és l\'aplicació d\'escriptori oficial de Delta Chat.</string>
|
||||
<string name="about_licensed_under_desktop">Aquest programari és llicenciat amb la llicència GNU GPL versió 3 i el codi font és disponible a GitHub</string>
|
||||
<string name="welcome_desktop">Us donem la benvinguda al Delta Chat</string>
|
||||
<string name="global_menu_preferences_language_desktop">Trieu l\'idioma...</string>
|
||||
<string name="global_menu_file_desktop">Arxiva</string>
|
||||
@@ -1096,6 +1093,7 @@
|
||||
<string name="menu.view.developer.open.log.folder">Obre la carpeta de registre</string>
|
||||
<string name="menu.view.developer.open.current.log.file">Obre el fitxer de registre actual</string>
|
||||
<string name="explain_desktop_minimized_disabled_tray_pref" tools:ignore="TypographyDashes">La icona de la safata no es pot desactivar perquè Delta Chat s\'ha iniciat amb l\'opció --minimized</string>
|
||||
<!-- deprecated, used on desktop although there is not spell checker -->
|
||||
<string name="no_spellcheck_suggestions_found">No s\'ha trobat cap suggeriment ortogràfic.</string>
|
||||
<string name="show_window">Mostra la finestra</string>
|
||||
|
||||
@@ -1175,5 +1173,5 @@
|
||||
<string name="perm_enable_bg_already_done">Ja heu autoritzat Delta Chat a rebre missatges en segon pla.\n\nSi encara no us arriben els missatge, reviseu els paràmetres de sistema.</string>
|
||||
|
||||
<!-- device messages for updates -->
|
||||
<string name="update_2_0">Què hi ha de nou?\n\n💯 L’encriptació de punta a punta és fiable i permanent. Els candaus 🔒 han desaparegut!\n\n✉️ El correu electrònic clàssic sense encriptació de punta a punta es mostra amb el símbol d\'un sobre.\n\n😻 Nova pantalla de perfil millorada per a tots els teus contactes.\n\n🔲 Nou botó per accedir ràpidament a les aplicacions utilitzades als xats.\n\n❤️ Si us plau, fes una donació per ajudar-nos a continuar independents i seguir aportant millores: %1$s</string>
|
||||
<string name="update_2_0">Què hi ha de nou?\n\n💯 El xifrat d\'extrem a extrem és fiable i permanent. Els candaus 🔒 han desaparegut!\n\n✉️ El correu electrònic clàssic sense xifrar d\'extrem a extrem es mostra amb el símbol d\'un sobre.\n\n😻 Nova pantalla de perfil millorada per a tots els teus contactes.\n\n🔲 Nou botó per accedir ràpidament a les aplicacions utilitzades als xats.\n\n❤️ Si us plau, fes una donació per ajudar-nos a continuar independents i seguir aportant millores: %1$s</string>
|
||||
</resources>
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
<string name="off">ناچالاک</string>
|
||||
<string name="def">بنەڕەتی</string>
|
||||
<string name="default_value">بنەڕەتی (%1$s)</string>
|
||||
<string name="default_value_as_above">بنەڕەتی (وەکوو سەرەوە)</string>
|
||||
<string name="custom">دڵخواز</string>
|
||||
<string name="none">هیچیان</string>
|
||||
<string name="automatic">خۆکار</string>
|
||||
@@ -233,12 +232,10 @@
|
||||
<string name="ask_remove_members">%1$sلە کۆڕ دەخەیتەدەر؟</string>
|
||||
<string name="open_url_confirmation">دەتەوێت ئەم بەستەرە بکەیتەوە؟</string>
|
||||
|
||||
|
||||
<!-- contact list -->
|
||||
<string name="contacts_title">بەردەنگەکان</string>
|
||||
<string name="contacts_type_email_above">ئیمەیلەکە لە سەرەوە بنووسە</string>
|
||||
|
||||
|
||||
<!-- chatlist and chat view -->
|
||||
<plurals name="chat_archived">
|
||||
<item quantity="one">%dوتووێژ ئەرشیڤ کرا</item>
|
||||
@@ -278,9 +275,6 @@
|
||||
<!-- mailing lists -->
|
||||
<string name="mailing_list">لیستەی ئیمەیلەکان</string>
|
||||
|
||||
<!-- map -->
|
||||
<string name="filter_map_on_time">شوێنەکان لە نێو چوارچێوەی کاتدا پیشان بدرێت؟</string>
|
||||
<string name="show_location_traces">پیشاندانی شوێنپێ</string>
|
||||
<!-- search -->
|
||||
<string name="search">گەڕان</string>
|
||||
<string name="search_explain">بگەڕە بۆ وتووێژەکان و بەردەنگەکان و پەیامەکان</string>
|
||||
@@ -339,8 +333,6 @@
|
||||
<string name="forward_to">هەناردن بۆ...</string>
|
||||
<string name="share_text_multiple_chats">ئەم دەقە دەنێریت بۆ %1$d وتووێژ؟n\n\"%2$s\"</string>
|
||||
<!-- preferences -->
|
||||
<string name="pref_using_custom">بەکارهێنانی دڵخواز: %s</string>
|
||||
<string name="pref_using_default">بەکارهێنانی بنەڕەتی: %s</string>
|
||||
<string name="pref_profile_info_headline">زانیارییەکانی پرۆفایلەکەت</string>
|
||||
<string name="pref_profile_photo">وێنەی لادیمەن</string>
|
||||
<string name="pref_blocked_contacts">هەژمارە ئاستەنگکراوەکان</string>
|
||||
@@ -366,8 +358,6 @@
|
||||
<string name="pref_sound">دەنگ</string>
|
||||
<string name="pref_silent">بێدەنگ</string>
|
||||
<string name="pref_privacy">پاراستنی تاکەکەسی</string>
|
||||
<!-- deprecated, use pref_chats -->
|
||||
<string name="pref_chats_and_media">وتووێژ و ڕەنگاڵەکان</string>
|
||||
<string name="pref_system_default">بنەڕەتی سیستەم</string>
|
||||
<!-- Translators: as in "opposite of dark" -->
|
||||
<string name="pref_light_theme">ڕووناک</string>
|
||||
@@ -388,7 +378,7 @@
|
||||
<string name="pref_backup_explain">یەدەک گرتن لە وتووێژەکان و دانانی لەسەر بیرگەی دەرەکی</string>
|
||||
<string name="pref_backup_export_explain">یەدەک یارمەتیت دەدات تاکوو نەرمامێرەکە لەسەر ئەم ئامێرە یان ئامێرێکی دیکە دەبمەزرێنیتەوە.\n\n یەدەکەکە بریتی دەبێت لە هەموو پەیامەکان و بەردەنگەکان و وتووێژەکان و ڕێکخستنی ئۆتۆکریپتی ئەمسەر-ئەوسەر. پەڕگەی یەدەکەکە لە شوێنێکی قایمدا بپارێزە یان بە زووترین کات بیسڕەوە.</string>
|
||||
<string name="pref_backup_export_start_button">دەستپێبکە</string>
|
||||
<string name="pref_backup_written_to_x">یەدەک بە سەرکەوتوویی لە \"%1$s\"دا پاشەکەوت کرا.</string>
|
||||
<string name="pref_backup_written_to_x">یەدەک بە سەرکەوتوویی لە \"%1$s\"دا پاشەکەوت کرا.</string>
|
||||
<!-- No need to translate "Wallpaper" literally. Chose what is common in your language for a "Wallpaper" or a "Background". Avoid adding the term "image" here, as the "Wallpaper" may also be just a single color. -->
|
||||
<string name="pref_background">پشتخان</string>
|
||||
<string name="pref_background_btn_default">بەکارهێنانی وێنەی بنەڕەتی</string>
|
||||
@@ -463,7 +453,7 @@
|
||||
<string name="qraccount_ask_create_and_login">دەتەوێت ناونیشانی ئیمەیلێکی نوێ لەسەر \"%1$s\" درووست بکەیت و لەوێ بچیتە ژوورەوە؟</string>
|
||||
<string name="qraccount_qr_code_cannot_be_used">ناتوانی لە کۆدی QRە سکان کراوەکە کەڵک بگریت بۆ پێکهێنانی هەژمارێکی نوێ.</string>
|
||||
<string name="contact_verified">%1$s پشتڕاست کرایەوە</string>
|
||||
<!-- notifications -->
|
||||
<!-- notifications -->
|
||||
<string name="notify_reply_button">وەڵام دانەوە</string>
|
||||
<string name="notify_new_message">پەیامی نوێ</string>
|
||||
<string name="notify_background_connection_enabled">پەیوەندی پشتخان چالاک کرا</string>
|
||||
@@ -480,8 +470,6 @@
|
||||
<string name="perm_explain_access_to_mic_denied">بۆ هەناردنی پەیامی دەنگی، بچۆ بەشی ڕێکخستنەکانی نەرمامێرەکە، لە بەشی \"ڕێگەپێدان\"دا، \"مایک\" چالاک بکەوە.</string>
|
||||
<string name="perm_explain_access_to_storage_denied">بۆ هەناردن و وەرگرتنی پەڕگەکان، بچۆ بەشی ڕێکخستنەکانی نەرمامێرەکە، لە بەشی \"ڕێگەپێدان\"دا، \"بیرگە\" چالاک بکەوە.</string>
|
||||
<string name="perm_explain_access_to_location_denied">بۆ لکاندنی شوێنێک، بچۆ بەشی ڕێکخستنەکانی نەرمامێرەکە، لە بەشی \"ڕێگەپێدان\"دا، \"شوێن\" چالاک بکەوە.</string>
|
||||
<!-- strings introduced on desktop. we want to share strings between the os, in general, please do not add generic strings here -->
|
||||
<string name="about_offical_app_desktop">ئەمە نەرمامێری فەرمی دێڵتا چاتە بۆ کۆمپووتەری ڕوومێز.</string>
|
||||
<string name="welcome_desktop">بەخێر بێن بۆ دێڵتا چات</string>
|
||||
<string name="global_menu_preferences_language_desktop">زمان</string>
|
||||
<string name="global_menu_file_desktop">پەڕگە</string>
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
<string name="off">Vypnuto</string>
|
||||
<string name="def">Výchozí</string>
|
||||
<string name="default_value">Výchozí (%1$s)</string>
|
||||
<string name="default_value_as_above">Výchozí (jako výše)</string>
|
||||
<string name="custom">Vlastní</string>
|
||||
<string name="none">Žádný</string>
|
||||
<string name="automatic">Automaticky</string>
|
||||
@@ -34,8 +33,6 @@
|
||||
<string name="update">Aktualizovat</string>
|
||||
<string name="emoji">Emoji</string>
|
||||
<string name="attachment">Příloha</string>
|
||||
<!-- the placeholder will be replaced by the name of the image or file to attach -->
|
||||
<string name="ask_attach">Připojit \"%1$s\"?</string>
|
||||
<string name="back">Zpět</string>
|
||||
<string name="close">Zavřít</string>
|
||||
<string name="close_window">Zavřít okno</string>
|
||||
@@ -115,23 +112,9 @@
|
||||
<string name="last_month">Minulý měsíc</string>
|
||||
<!-- Refers to the time a contact was last seen. Shown below contact name in the profile. The placeholder will be replaced by date or time, resulting in "Last seen at 12:13 AM" or "Last seen Nov 12" -->
|
||||
<string name="last_seen_at">Naposledy viděni v %1$s</string>
|
||||
<!-- Refers to the time a contact was last seen. Shown below contact name in the profile. The placeholder will be replaced by a relative point in time as "3 minutes ago" (see https://momentjs.com for more examples and languages)-->
|
||||
<!-- Refers to the time a contact was last seen. Shown below contact name in the profile. The placeholder will be replaced by a relative point in time as "3 minutes ago" (see https://momentjs.com for more examples and languages) -->
|
||||
<string name="last_seen_relative">Naposledy viděni %1$s</string>
|
||||
<string name="last_seen_unknown">Naposledy viděno: Neznámý</string>
|
||||
<!-- Shown in call duration. Avoid abbreviations, prefer full words ex. "N seconds". -->
|
||||
<plurals name="n_seconds_ext">
|
||||
<item quantity="one">%d druhý</item>
|
||||
<item quantity="few">%d sekundy</item>
|
||||
<item quantity="many">%d sekundy</item>
|
||||
<item quantity="other">%d vteřny</item>
|
||||
</plurals>
|
||||
<!-- Shown in call duration. Avoid abbreviations, prefer full words ex. "N minutes". -->
|
||||
<plurals name="n_minutes_ext">
|
||||
<item quantity="one">%d minuta</item>
|
||||
<item quantity="few">%d minuty</item>
|
||||
<item quantity="many">%d minuty</item>
|
||||
<item quantity="other">%d minuty</item>
|
||||
</plurals>
|
||||
<!-- Shown beside messages that are "N minutes old". Prefer short strings, or well-known abbreviations. -->
|
||||
<plurals name="n_minutes">
|
||||
<item quantity="one">%d min.</item>
|
||||
@@ -281,8 +264,6 @@
|
||||
<string name="channels">Kanály</string>
|
||||
<!-- consider keeping the term "channel" as in WhatsApp or Telegram -->
|
||||
<string name="new_channel">Nový kanál</string>
|
||||
<!-- deprecated -->
|
||||
<string name="add_recipients">Přidat příjemce</string>
|
||||
<!-- consider keeping the term "channel" as in WhatsApp or Telegram -->
|
||||
<string name="channel_name">Název kanálu</string>
|
||||
<string name="email">E-mail</string>
|
||||
@@ -361,8 +342,6 @@
|
||||
<string name="menu_more_options">Další možnosti</string>
|
||||
<string name="menu_learn_spelling">Naučte se pravopis</string>
|
||||
<string name="jump_to_message">Přejít na zprávu</string>
|
||||
<string name="jump_to_original_message">Přejít na původní zprávu</string>
|
||||
<string name="copy_json">Kopírovat JSON</string>
|
||||
<string name="replace_draft">Nahradit rozepsanou zprávu</string>
|
||||
<string name="title_share_location">Sdílet polohu se všemi členy skupiny</string>
|
||||
<string name="device_talk">Zprávy v zařízení</string>
|
||||
@@ -412,16 +391,9 @@
|
||||
<string name="answer_call">Zvedni</string>
|
||||
<!-- the action "to decline" a call, not: "the decline" -->
|
||||
<string name="end_call">Pokles</string>
|
||||
<!-- deprecated, use outgoing_audio_call or outgoing_video_call instead -->
|
||||
<string name="outgoing_call">Odchozí hovor</string>
|
||||
<!-- deprecated, use incoming_audio_call or incoming_video_call instead -->
|
||||
<string name="incoming_call">Příchozí hovor</string>
|
||||
<string name="declined_call">Odmítnutý hovor</string>
|
||||
<string name="canceled_call">Zrušený hovor</string>
|
||||
<string name="missed_call">Zmeškaný hovor</string>
|
||||
<!-- the first placeholder will be replaced by a date, the second placeholder by duration, example: "Thu, 08:12 pm, 2 minutes" -->
|
||||
<string name="call_date_and_duration">%1$s, %2$s</string>
|
||||
|
||||
<!-- get confirmations -->
|
||||
<!-- confirmation for leaving groups or channels. If a subject is needed, "Are you sure you want to leave the chat?" would work as well -->
|
||||
<string name="ask_leave_group">Jste si jistý, že chcete odejít?</string>
|
||||
@@ -453,12 +425,10 @@
|
||||
<string name="ask_remove_from_channel">Odstranit %1$s z kanálu?</string>
|
||||
<string name="open_url_confirmation">Přejete si otevřít tento odkaz?</string>
|
||||
|
||||
|
||||
<!-- contact list -->
|
||||
<string name="contacts_title">Kontakty</string>
|
||||
<string name="contacts_type_email_above">Zadejte e-mail výše</string>
|
||||
|
||||
|
||||
<!-- chatlist and chat view -->
|
||||
<plurals name="chat_archived">
|
||||
<item quantity="one">%d chat archivován</item>
|
||||
@@ -524,25 +494,14 @@
|
||||
<string name="send_file_to">Odeslat \"%1$s\"...</string>
|
||||
<!-- title shown above a list contacts where one should be selected (eg. when a webxdc attempts to send a message to a chat) -->
|
||||
<string name="send_message_to">Odeslat zprávu...</string>
|
||||
<string name="enable_realtime">Real-time aplikace</string>
|
||||
<string name="enable_realtime_explain">Umožnit aplikacím sdíleným v chatech, aby navazovaly spojení v reálném čase. Tato volba umožní vašim kontaktům zjistit vaši IP adresu, když nějakou aplikaci spustíte.</string>
|
||||
|
||||
<!-- map -->
|
||||
<string name="filter_map_on_time">Zobrazit polohy v časovém úseku</string>
|
||||
<string name="show_location_traces">Zobrazit trasy</string>
|
||||
<string name="add_poi">Odeslat bod zájmu</string>
|
||||
|
||||
|
||||
<!-- punycode warning / labeled links -->
|
||||
<!-- placeholder is domain/hostname that should be trusted -->
|
||||
<string name="open_external_url_trust_domain">U %1$s se již znovu neptat</string>
|
||||
<string name="puny_code_warning_header">Byl nalezen podezřelý odkaz</string>
|
||||
<!-- placeholder contains the hostname converted to ascii -->
|
||||
<string name="puny_code_warning_question">Opravdu si přejete navštívit stránku %1$s?</string>
|
||||
<!-- this message is shown whenever a link with non-latin characters is clicked. first placeholder is original hostname with special chars, second placeholder is hostname encoded in ascii -->
|
||||
<string name="puny_code_warning_description">Tento odkaz může obsahovat znaky zaměněné za podobně vypadající znaky z cizích abeced. Odkaz označený jako %1$s vás navede na stránku %2$s, což je normální pro znaky mimo anglickou latinku. Pokud neočekáváte adresu s takovýmito znaky, odkaz může být škodlivý.</string>
|
||||
|
||||
|
||||
<!-- search -->
|
||||
<string name="search">Hledat</string>
|
||||
<string name="search_in_chat">Hledat v chatu</string>
|
||||
@@ -552,7 +511,6 @@
|
||||
<!-- Adjective, as in "Show Unread Messages" -->
|
||||
<string name="search_unread">Nepřečtené</string>
|
||||
|
||||
|
||||
<!-- create/edit groups, contact/group profile -->
|
||||
<string name="group_name">Název skupiny</string>
|
||||
<string name="group_avatar">Obrázek skupiny</string>
|
||||
@@ -616,8 +574,6 @@
|
||||
<string name="incoming_messages">Příchozí zprávy</string>
|
||||
<!-- Headline for the "Outbox" eg. in the "Connectivity" view -->
|
||||
<string name="outgoing_messages">Odchozí zprávy</string>
|
||||
<!-- deprecated -->
|
||||
<string name="storage_on_domain">Úložiště na %1$s</string>
|
||||
<string name="connectivity">Připojení</string>
|
||||
<!-- Shown in the title bar if the app is "Not connected"; prefer short strings. -->
|
||||
<string name="connectivity_not_connected">Nepřipojeno</string>
|
||||
@@ -635,11 +591,10 @@
|
||||
<!-- Used for describing resource usage, resulting string will be eg. "1.2 GiB of 3 GiB used" -->
|
||||
<string name="part_of_total_used">Zaplněno %1$s z %2$s</string>
|
||||
|
||||
|
||||
<!-- welcome and login -->
|
||||
<!-- Primary button on the welcome screen, allows to create an instant profile -->
|
||||
<string name="onboarding_create_instant_account">Vytvořit nový profil</string>
|
||||
<!-- Secondary button on the welcome screen, allows to "Add as Second Device", "Restore from Backup" -->
|
||||
<!-- Secondary button on the welcome screen, allows to "Add as Second Device", "Restore from Backup" -->
|
||||
<string name="onboarding_alternative_logins">Již mám svůj profil</string>
|
||||
<!-- This is a button and a title, allowing to use existing, classic email, setting ports, passwords and so on -->
|
||||
<string name="manual_account_setup_option">Přihlášení ke klasickému e-mailu</string>
|
||||
@@ -701,9 +656,6 @@
|
||||
<!-- shown if a QR code was scanned that can be used as a relay -->
|
||||
<string name="confirm_add_transport">Přidat toto vysílání?</string>
|
||||
<string name="invalid_transport_qr">Naskenovaný kód QR neobsahuje platné vysílání.</string>
|
||||
<!-- placeholder will be replaced by a relay server name -->
|
||||
<string name="confirm_remove_transport">Odstranit vysílání \"%1$s\"? \n\n Vaše kontakty se s vámi spojí pouze tehdy, pokud jste je předtím kontaktovali prostřednictvím jiného vysílání. \n\n Pokud máte pochybnosti, odstraňte spojení později.</string>
|
||||
|
||||
<string name="login_certificate_checks">Kontroly certifikátu</string>
|
||||
<string name="login_error_mail">Prosím, zadejte platnou e-mailovou adresu</string>
|
||||
<string name="login_error_server">Prosím, zadejte platný server / IP adresu</string>
|
||||
@@ -744,10 +696,7 @@
|
||||
<string name="share_text_multiple_chats">Poslat tento text do %1$d chatů?\n\n\"%2$s\"</string>
|
||||
<string name="share_abort">Sdílení přerušeno kvůli chybějícím oprávnění.</string>
|
||||
|
||||
|
||||
<!-- preferences -->
|
||||
<string name="pref_using_custom">Nastaven vlastní: %s</string>
|
||||
<string name="pref_using_default">Nastaven výchozí: %s</string>
|
||||
<string name="pref_profile_info_headline">Přehled účtu</string>
|
||||
<string name="pref_profile_photo">Profilový obrázek</string>
|
||||
<string name="pref_blocked_contacts">Blokované kontakty</string>
|
||||
@@ -779,8 +728,6 @@
|
||||
<string name="pref_sound">Zvuk</string>
|
||||
<string name="pref_silent">Ticho</string>
|
||||
<string name="pref_privacy">Soukromí</string>
|
||||
<!-- deprecated, use pref_chats -->
|
||||
<string name="pref_chats_and_media">Chaty a multimédia</string>
|
||||
<string name="pref_system_default">Podle systému</string>
|
||||
<!-- Translators: as in "opposite of dark" -->
|
||||
<string name="pref_light_theme">Světlý</string>
|
||||
@@ -817,7 +764,7 @@
|
||||
<string name="pref_background_btn_default">Použít výchozí obrázek</string>
|
||||
<string name="pref_background_btn_gallery">Vybrat z galerie</string>
|
||||
<string name="pref_imap_folder_warn_disable_defaults">Při změně této volby se ujistěte, že váš server a ostatní klientské aplikace mají odpovídající nastavení.\n\nJinak může vše přestat fungovat.</string>
|
||||
<!-- No need to be literal here, you can also use "Use Multiple Devices", "Support Multiple Devices" or other fitting terms. However, it should fit to the wording or your language at https://delta.chat/help -->
|
||||
<!-- No need to be literal here, you can also use "Use Multiple Devices", "Support Multiple Devices" or other fitting terms. However, it should fit to the wording or your language at https://delta.chat/help -->
|
||||
<string name="pref_multidevice">Režim pro více zařízení</string>
|
||||
<string name="pref_multidevice_explain">Synchronizujte zprávy s ostatními zařízeními. Automaticky povoleno při přidání druhého zařízení</string>
|
||||
<string name="pref_multidevice_change_warn">Při použití stejného profilu na více zařízeních musí být povolen \"režim více zařízení\". Toto nastavení zakažte pouze v případě, že jste tento profil odstranili ze všech ostatních zařízení. \n\n Zakázání režimu \"režim více zařízení\" při používání profilu na více zařízeních bude mít za následek zmeškané zprávy a další problémy.</string>
|
||||
@@ -845,15 +792,11 @@
|
||||
<string name="n_bytes_message">%1$s zpráva</string>
|
||||
<!-- %1$s will be replaced by human-readable date and time -->
|
||||
<string name="download_max_available_until">Stahovat dostupné maximum do %1$s</string>
|
||||
<!-- deprecated -->
|
||||
<string name="select_profile">Vyberte profil</string>
|
||||
<string name="profile_image_select">Vybrat profilový obrázek</string>
|
||||
<string name="select_your_new_profile_image">Vyberte si svůj nový profilový obrázek</string>
|
||||
<string name="profile_image_delete">Smazat profilový obrázek</string>
|
||||
<string name="pref_show_tray_icon">Zobrazit ikonu v oznamovací oblasti</string>
|
||||
<string name="pref_edit_profile">Upravit profil</string>
|
||||
<string name="disable_imap_idle">Zakázat IMAP IDLE</string>
|
||||
<string name="disable_imap_idle_explain">Nepoužívat rozšíření IMAP IDLE ani když jej server podporuje. Zapnutí této volby zvýší prodlevu při získávání zpráv, použijte ji jen pro testování.</string>
|
||||
<string name="send_stats_to_devs">Odeslat statistiky vývojářům Delta Chatu</string>
|
||||
<string name="stats_msg_body">Příloha obsahuje anonymní statistiky používání, které nám pomáhají zlepšovat službu Delta Chat. Děkujeme vám!</string>
|
||||
|
||||
@@ -943,10 +886,6 @@
|
||||
<string name="ephemeral_timer_seconds_by_you">Nastavili jste časovač mizejících zpráv na %1$s sekund.</string>
|
||||
<!-- %1$s will be replaced by the number of seconds (always >1) the timer is set to, %2$s will be replaced by name of the contact -->
|
||||
<string name="ephemeral_timer_seconds_by_other">Uživatel %2$s nastavil časovač mizejících zpráv na %1$s sekund.</string>
|
||||
<!-- deprecated, usage needs to be removed in core -->
|
||||
<string name="ephemeral_timer_1_minute_by_you">Nastavili jste časovač mizejících zpráv na 1 minutu.</string>
|
||||
<!-- deprecated, usage needs to be removed in core -->
|
||||
<string name="ephemeral_timer_1_minute_by_other">Uživatel %1$s změnil časovač mizejících zpráv na 1 minutu.</string>
|
||||
<string name="ephemeral_timer_1_hour_by_you">Nastavili jste časovač mizejících zpráv na 1 hodinu.</string>
|
||||
<!-- %1$s will be replaced by name of the contact -->
|
||||
<string name="ephemeral_timer_1_hour_by_other">Uživatel %1$s změnil časovač mizejících zpráv na 1 hodinu.</string>
|
||||
@@ -1042,14 +981,12 @@
|
||||
<string name="verified_by">Ověřeni uživatelem %1$s.</string>
|
||||
<string name="verified_by_you">Ověřeni mnou</string>
|
||||
<string name="verified_by_unknown">Představeno</string>
|
||||
<!-- deprecated -->
|
||||
<string name="verified_contact_required_explain">Aby mohlo být garantováno koncové šifrování, můžete do této skupiny přidávat pouze uživatele se zeleným zaškrtávátkem.\n\nSe svými kontakty se můžete setkat osobně a naskenovat jejich QR kód, abyste je ověřili.</string>
|
||||
<string name="mailto_dialog_header_select_chat">Vyberte chat, do kterého chcete zprávu poslat</string>
|
||||
<!-- first placeholder is the name of the chat -->
|
||||
<string name="confirm_replace_draft">%1$s již obsahuje rozepsanou zprávu, přejete si ji přepsat?</string>
|
||||
<string name="mailto_link_could_not_be_decoded">Odkaz typu mailto nebyl rozpoznán: %1$s</string>
|
||||
|
||||
<!-- notifications -->
|
||||
<!-- notifications -->
|
||||
<string name="notify_reply_button">Odpovědět</string>
|
||||
<string name="notify_new_message">Nová zpráva</string>
|
||||
<string name="notify_background_connection_enabled">Spojení na pozadí je zapnuto</string>
|
||||
@@ -1065,7 +1002,6 @@
|
||||
<string name="new_messages_body">Máte nové zprávy</string>
|
||||
<string name="n_messages_in_m_chats">%1$d zprávy v %2$d chatech </string>
|
||||
|
||||
|
||||
<!-- permissions -->
|
||||
<string name="perm_required_title">Oprávnění vyžadováno</string>
|
||||
<string name="perm_continue">Pokračovat</string>
|
||||
@@ -1086,9 +1022,6 @@
|
||||
<string name="ImageEditorHud_flip">Zrcadlení</string>
|
||||
<string name="ImageEditorHud_rotate">Otočení</string>
|
||||
|
||||
<!-- strings introduced on desktop. we want to share strings between the os, in general, please do not add generic strings here -->
|
||||
<string name="about_offical_app_desktop">Toto je oficiální aplikace Delta Chat Desktop.</string>
|
||||
<string name="about_licensed_under_desktop">Tento software je distribuován pod licencí GNU GPL verze 3 a jeho zdrojový kód je k dispozici na GitHubu.</string>
|
||||
<string name="welcome_desktop">Vítejte v aplikaci Delta Chat</string>
|
||||
<string name="global_menu_preferences_language_desktop">Jazyk</string>
|
||||
<string name="global_menu_file_desktop">Soubor</string>
|
||||
@@ -1128,6 +1061,7 @@
|
||||
<string name="menu.view.developer.open.log.folder">Otevřít složku protokolu</string>
|
||||
<string name="menu.view.developer.open.current.log.file">Otevřít stávající soubor s protokolem</string>
|
||||
<string name="explain_desktop_minimized_disabled_tray_pref" tools:ignore="TypographyDashes">Ikonu na panelu nelze deaktivovat, protože Delta Chat byl spuštěn s volbou --minimized.</string>
|
||||
<!-- deprecated, used on desktop although there is not spell checker -->
|
||||
<string name="no_spellcheck_suggestions_found">Žádné pravopisné návrhy.</string>
|
||||
<string name="show_window">Zobrazit okno</string>
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
<string name="off">Fra</string>
|
||||
<string name="def">Standard</string>
|
||||
<string name="default_value">Standardindstilling (%1$s)</string>
|
||||
<string name="default_value_as_above">Standardindstilling ()</string>
|
||||
<string name="custom">Tilpasset</string>
|
||||
<string name="none">Ingen</string>
|
||||
<string name="automatic">Automatisk</string>
|
||||
@@ -206,7 +205,6 @@
|
||||
<string name="menu_zoom_in">Forstør</string>
|
||||
<string name="menu_zoom_out">Formindsk</string>
|
||||
<string name="menu_save_log">Gem log</string>
|
||||
<string name="copy_json">Kopier JSON</string>
|
||||
<string name="title_share_location">Del placering med alle gruppemedlemmer</string>
|
||||
<string name="device_talk">Enhedsbeskeder</string>
|
||||
<string name="device_talk_subtitle">Lokalt genererede beskeder</string>
|
||||
@@ -256,12 +254,10 @@
|
||||
<string name="ask_remove_members">Fjern %1$s fra gruppe?</string>
|
||||
<string name="open_url_confirmation">Vil du åbne dette link?</string>
|
||||
|
||||
|
||||
<!-- contact list -->
|
||||
<string name="contacts_title">Kontakter</string>
|
||||
<string name="contacts_type_email_above">Indtast e-mailadresse ovenover</string>
|
||||
|
||||
|
||||
<!-- chatlist and chat view -->
|
||||
<plurals name="chat_archived">
|
||||
<item quantity="one">%d samtale arkiveret</item>
|
||||
@@ -298,16 +294,10 @@
|
||||
<string name="retry_send">Forsøg igen at sende besked</string>
|
||||
<string name="cannot_display_unsuported_file_type">Kan ikke vise denne filtype: 1%s</string>
|
||||
<string name="attachment_failed_to_load">Visning af vedhæftede fil mislykkedes</string>
|
||||
<!-- map -->
|
||||
<string name="filter_map_on_time">Vis placeringer i tidsramme</string>
|
||||
<string name="show_location_traces">Vis spor</string>
|
||||
<string name="add_poi">Send interessepunkt</string>
|
||||
|
||||
|
||||
<!-- search -->
|
||||
<string name="search">Søg</string>
|
||||
<string name="search_explain">Søg efter samtaler, kontakter og beskeder</string>
|
||||
<string name="search_no_result_for_x">Ingen resultater fundet for \"%s\"</string>
|
||||
<string name="search_no_result_for_x">Ingen resultater fundet for \"%s\"</string>
|
||||
<!-- create/edit groups, contact/group profile -->
|
||||
<string name="group_name">Gruppenavn</string>
|
||||
<string name="group_avatar">Gruppeikon</string>
|
||||
@@ -349,7 +339,6 @@
|
||||
<!-- Used for describing resource usage, resulting string will be eg. "1.2 GiB of 3 GiB used" -->
|
||||
<string name="part_of_total_used">%1$s af %2$s brugt</string>
|
||||
|
||||
|
||||
<string name="login_title">Login</string>
|
||||
<string name="login_inbox">Indbakke</string>
|
||||
<string name="login_imap_login">IMAP logind navn</string>
|
||||
@@ -371,7 +360,7 @@
|
||||
<string name="import_backup_ask">Sikkerhedskopi fundet hos \"%1$s\".\n\nVil du Importere og bruge al data og opsætning fra den?</string>
|
||||
<string name="import_backup_no_backup_found">Ingen sikkerhedskopi fundet.\n\nKopier sikkerhedskopi til \"%1$s\" og prøv igen.</string>
|
||||
<!-- %1$s will be replaced by the failing address -->
|
||||
<string name="login_error_cannot_login">Kan ikke logge ind som \"%1$s\". Kontroller om e-mailadresse og adgangskode er korrekt.</string>
|
||||
<string name="login_error_cannot_login">Kan ikke logge ind som \"%1$s\". Kontroller om e-mailadresse og adgangskode er korrekt.</string>
|
||||
<!-- TLS certificate checks -->
|
||||
<string name="accept_invalid_certificates">Acceptér ugyldige certifikater</string>
|
||||
<string name="switch_account">Skift konto</string>
|
||||
@@ -391,10 +380,7 @@
|
||||
<string name="share_text_multiple_chats">Send denne tekst til %1$d samtaler?\n\n\"%2$s\"</string>
|
||||
<string name="share_abort">Deling afbrudt på grund af manglende tilladelser.</string>
|
||||
|
||||
|
||||
<!-- preferences -->
|
||||
<string name="pref_using_custom">Bruger tilpasset: %s</string>
|
||||
<string name="pref_using_default">Bruger standard: %s</string>
|
||||
<string name="pref_profile_info_headline">Profil information</string>
|
||||
<string name="pref_profile_photo">Profilbillede</string>
|
||||
<string name="pref_blocked_contacts">Blokerede kontakter</string>
|
||||
@@ -424,8 +410,6 @@
|
||||
<string name="pref_sound">Lyd</string>
|
||||
<string name="pref_silent">Stille</string>
|
||||
<string name="pref_privacy">Privatliv</string>
|
||||
<!-- deprecated, use pref_chats -->
|
||||
<string name="pref_chats_and_media">Samtaler og medie</string>
|
||||
<string name="pref_system_default">Systemstandard</string>
|
||||
<!-- Translators: as in "opposite of dark" -->
|
||||
<string name="pref_light_theme">Lys</string>
|
||||
@@ -534,10 +518,6 @@
|
||||
<string name="ephemeral_timer_seconds_by_you">Tidsudløb for beskeder sat til %1$s s af mig.</string>
|
||||
<!-- %1$s will be replaced by the number of seconds (always >1) the timer is set to, %2$s will be replaced by name of the contact -->
|
||||
<string name="ephemeral_timer_seconds_by_other">Tidsudløb for beskeder sat til %1$s s af %2$s.</string>
|
||||
<!-- deprecated, usage needs to be removed in core -->
|
||||
<string name="ephemeral_timer_1_minute_by_you">Tidsudløb for beskeder sat til 1 minut af mig.</string>
|
||||
<!-- deprecated, usage needs to be removed in core -->
|
||||
<string name="ephemeral_timer_1_minute_by_other">Tidsudløb for beskeder sat til 1 minut af %1$s.</string>
|
||||
<string name="ephemeral_timer_1_hour_by_you">Tidsudløb for beskeder sat til 1 time af mig.</string>
|
||||
<!-- %1$s will be replaced by name of the contact -->
|
||||
<string name="ephemeral_timer_1_hour_by_other">Tidsudløb for beskeder sat til 1 time af %1$s.</string>
|
||||
@@ -591,7 +571,7 @@
|
||||
<string name="qraccount_ask_create_and_login">Opret ny e-mail adresse på \"%1$s\" og log ind der?</string>
|
||||
<string name="qraccount_qr_code_cannot_be_used">Den skannede QR-kode kan ikke bruges til at opsætte en ny konto.</string>
|
||||
<string name="contact_verified">%1$s bekræftet.</string>
|
||||
<!-- notifications -->
|
||||
<!-- notifications -->
|
||||
<string name="notify_reply_button">Svar</string>
|
||||
<string name="notify_new_message">Ny besked</string>
|
||||
<string name="notify_background_connection_enabled">Baggrundsforbindelse aktiveret</string>
|
||||
@@ -612,9 +592,6 @@
|
||||
<string name="ImageEditorHud_draw_anywhere_to_blur">Tegn hvor som helst for at sløre</string>
|
||||
<string name="ImageEditorHud_rotate">Roter</string>
|
||||
|
||||
<!-- strings introduced on desktop. we want to share strings between the os, in general, please do not add generic strings here -->
|
||||
<string name="about_offical_app_desktop">Dette er den officielle Delta Chat Desktop app.</string>
|
||||
<string name="about_licensed_under_desktop">Denne software er licenseret under GNU GPL version 3 og kildekoden er tilgængelig på GitHub</string>
|
||||
<string name="welcome_desktop">Velkommen til Delta Chat</string>
|
||||
<string name="global_menu_preferences_language_desktop">Vælge sprog...</string>
|
||||
<string name="global_menu_file_desktop">Fil</string>
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
<string name="off">Aus</string>
|
||||
<string name="def">Standard</string>
|
||||
<string name="default_value">Standard (%1$s)</string>
|
||||
<string name="default_value_as_above">Standard (siehe oben)</string>
|
||||
<string name="custom">Benutzerdefiniert</string>
|
||||
<string name="none">Keine</string>
|
||||
<string name="automatic">Automatisch</string>
|
||||
@@ -34,8 +33,6 @@
|
||||
<string name="update">Aktualisieren</string>
|
||||
<string name="emoji">Emoji</string>
|
||||
<string name="attachment">Anhang</string>
|
||||
<!-- the placeholder will be replaced by the name of the image or file to attach -->
|
||||
<string name="ask_attach">\"%1$s\" anhängen?</string>
|
||||
<string name="back">Zurück</string>
|
||||
<string name="close">Schließen</string>
|
||||
<string name="close_window">Fenster schließen</string>
|
||||
@@ -72,6 +69,8 @@
|
||||
<string name="mark_as_read">Gelesen</string>
|
||||
<!-- Shortest text for "Mark as being read". In english, this could be "Read" (past tense of "to read"), in german, this could be "Gelesen". -->
|
||||
<string name="mark_as_read_short">Gelesen</string>
|
||||
<!-- Shortest text for "Mark as being unread". In english, this could be "Unread" (past tense of "to unread"), in german, this could be "Ungelesen". -->
|
||||
<string name="mark_as_unread_short">Ungelesen</string>
|
||||
<!-- Placeholder text when something is loading -->
|
||||
<string name="loading">Wird geladen…</string>
|
||||
<string name="hide">Verstecken</string>
|
||||
@@ -115,19 +114,16 @@
|
||||
<string name="last_month">Letzter Monat</string>
|
||||
<!-- Refers to the time a contact was last seen. Shown below contact name in the profile. The placeholder will be replaced by date or time, resulting in "Last seen at 12:13 AM" or "Last seen Nov 12" -->
|
||||
<string name="last_seen_at">Zuletzt gesehen %1$s</string>
|
||||
<!-- Refers to the time a contact was last seen. Shown below contact name in the profile. The placeholder will be replaced by a relative point in time as "3 minutes ago" (see https://momentjs.com for more examples and languages)-->
|
||||
<!-- Refers to the time a contact was last seen. Shown below contact name in the profile. The placeholder will be replaced by a relative point in time as "3 minutes ago" (see https://momentjs.com for more examples and languages) -->
|
||||
<string name="last_seen_relative">Zuletzt gesehen %1$s</string>
|
||||
<string name="last_seen_unknown">Zuletzt gesehen: Unbekannt</string>
|
||||
<!-- Shown in call duration. Avoid abbreviations, prefer full words ex. "N seconds". -->
|
||||
<plurals name="n_seconds_ext">
|
||||
<item quantity="one">%d Sekunde</item>
|
||||
<item quantity="other">%d Sekunden</item>
|
||||
</plurals>
|
||||
<!-- Shown in call duration. Avoid abbreviations, prefer full words ex. "N minutes". -->
|
||||
<plurals name="n_minutes_ext">
|
||||
<item quantity="one">%d Minute</item>
|
||||
<item quantity="other">%d Minuten</item>
|
||||
<!-- Call duration as shown in the call bubbles. There is some risk to mix with the sending time, so the word "Duration" may be helpful. Might also be "Duration: %d minutes", "%d-minute duration", "%d-minute length" or "%d-minute call" -->
|
||||
<plurals name="call_duration_minutes">
|
||||
<item quantity="one">Dauer: %d Minute</item>
|
||||
<item quantity="other">Dauer: %d Minuten</item>
|
||||
</plurals>
|
||||
<!-- Call duration as shown in the call bubbles in case the call is less than one minute. If the context is not clear enough, one may want to add the word "Duration". -->
|
||||
<string name="call_duration_less_than_a_minute">Weniger als 1 Minute</string>
|
||||
<!-- Shown beside messages that are "N minutes old". Prefer short strings, or well-known abbreviations. -->
|
||||
<plurals name="n_minutes">
|
||||
<item quantity="one">%d Min</item>
|
||||
@@ -169,6 +165,7 @@
|
||||
<item quantity="other">%d ausgewählt</item>
|
||||
</plurals>
|
||||
<string name="selected_colon">Ausgewählt:</string>
|
||||
<string name="selected">Ausgewählt</string>
|
||||
<string name="self">Ich</string>
|
||||
<string name="draft">Entwurf</string>
|
||||
<string name="image">Bild</string>
|
||||
@@ -180,6 +177,9 @@
|
||||
<string name="add_to_sticker_collection">Zu Sticker-Sammlung hinzufügen</string>
|
||||
<string name="add_stickers_instructions">Um Sticker hinzuzufügen, tippe auf \"Sticker-Ordner öffnen\", erstelle einen Unterordner für dein Sticker-Paket und ziehe Bild- und Sticker-Dateien dorthin.</string>
|
||||
<string name="open_sticker_folder">Sticker-Ordner öffnen</string>
|
||||
<string name="ask_add_sticker_to_collection">Sticker zur Sammlung hinzufügen?</string>
|
||||
<string name="ask_delete_sticker">Sticker löschen?</string>
|
||||
<string name="sticker_picker_empty_hint">Sticker zum Hinzufügen antippen</string>
|
||||
<string name="images">Bilder</string>
|
||||
<!-- a noun, used for "Music" and other "Audio" files -->
|
||||
<string name="audio">Audio</string>
|
||||
@@ -213,7 +213,7 @@
|
||||
<string name="webxdc_apps">Apps</string>
|
||||
<string name="webxdc_store_url">App-Picker-URL</string>
|
||||
<string name="webxdc_store_url_explain">Wenn gesetzt, wird diese URL als App-Picker anstelle der Voreinstellung verwendet.</string>
|
||||
<string name="webxdc_draft_hint">Zum Teilen auf \"Senden\" klicken</string>
|
||||
<string name="webxdc_draft_hint">Zum Teilen auf \"Senden\" tippen</string>
|
||||
<string name="home">Start</string>
|
||||
<string name="games">Spiele</string>
|
||||
<string name="tools">Tools</string>
|
||||
@@ -259,10 +259,13 @@
|
||||
<string name="channels">Kanäle</string>
|
||||
<!-- consider keeping the term "channel" as in WhatsApp or Telegram -->
|
||||
<string name="new_channel">Neuer Kanal</string>
|
||||
<!-- deprecated -->
|
||||
<string name="add_recipients">Empfänger hinzufügen</string>
|
||||
<!-- consider keeping the term "channel" as in WhatsApp or Telegram -->
|
||||
<string name="channel_name">Name des Kanals</string>
|
||||
<!-- The number of times a message is shown in channels. Use what other messengers are using here, smth. as "N-times seen" or "1 Aufruf" (german) work as well, where "1 impression" or "1 hit" may sound too formal and may be more marketing slang. -->
|
||||
<plurals name="n_views">
|
||||
<item quantity="one">%d Aufruf</item>
|
||||
<item quantity="other">%d Aufrufe</item>
|
||||
</plurals>
|
||||
<string name="email">E-Mail</string>
|
||||
<!-- "New" as in "Create New Email"; shown together with "New Group" and "New Channel" -->
|
||||
<string name="new_email">Neue E-Mail</string>
|
||||
@@ -278,6 +281,7 @@
|
||||
<string name="menu_add_attachment">Dateien anhängen</string>
|
||||
<string name="menu_leave_group">Gruppe verlassen</string>
|
||||
<string name="menu_leave_channel">Kanal verlassen</string>
|
||||
<string name="menu_leave_and_delete">Verlassen & für mich löschen</string>
|
||||
<string name="menu_delete_chat">Chat löschen</string>
|
||||
<!-- Command to delete all messages in a chat. The chat itself will not be deleted but will be empty afterwards, so make sure to be different from "Delete Chat" here. "Clear" is a verb here, "Empty Chat" would also be fine (eg. in German "Chat leeren") -->
|
||||
<string name="clear_chat">Chat leeren</string>
|
||||
@@ -339,8 +343,6 @@
|
||||
<string name="menu_more_options">Mehr Optionen</string>
|
||||
<string name="menu_learn_spelling">Schreibweise lernen</string>
|
||||
<string name="jump_to_message">Zur Nachricht springen</string>
|
||||
<string name="jump_to_original_message">Zur Originalnachricht springen</string>
|
||||
<string name="copy_json">JSON kopieren</string>
|
||||
<string name="replace_draft">Entwurf ersetzen</string>
|
||||
<string name="title_share_location">Standort mit allen Gruppenmitgliedern teilen</string>
|
||||
<string name="device_talk">Systemnachrichten</string>
|
||||
@@ -385,25 +387,36 @@
|
||||
|
||||
<!-- the action "to call someone", used as a tooltip for the "phone" icon. not: "the call" -->
|
||||
<string name="start_call">Anrufen</string>
|
||||
<!-- Menu item to start an audio call; verbs as "start" are probably superfluous in many translations -->
|
||||
<string name="start_audio_call">Sprachanruf</string>
|
||||
<!-- Menu item to start a video call; verbs as "start" are probably superfluous in many translations -->
|
||||
<string name="start_video_call">Videoanruf</string>
|
||||
<!-- the action "to answer" or to "accept" or to "pick up" a call. not: "the answer" -->
|
||||
<string name="answer_call">Annehmen</string>
|
||||
<!-- the action "to decline" a call, not: "the decline" -->
|
||||
<string name="end_call">Ablehnen</string>
|
||||
<!-- deprecated, use outgoing_audio_call or outgoing_video_call instead -->
|
||||
<string name="outgoing_call">Ausgehender Anruf</string>
|
||||
<!-- Used in call bubbles, summaries, notifications -->
|
||||
<string name="audio_call">Sprachanruf</string>
|
||||
<!-- Used in call bubbles, summaries, notifications -->
|
||||
<string name="video_call">Videoanruf</string>
|
||||
<string name="call_initializing">Initialisieren…</string>
|
||||
<string name="call_incoming">Eingehender Anruf</string>
|
||||
<string name="call_ringing">Klingeln…</string>
|
||||
<string name="call_reconnecting">Wiederverbinden…</string>
|
||||
<string name="call_ended">Anruf beendet</string>
|
||||
<string name="call_failed">Anruf fehlgeschlagen</string>
|
||||
<!-- deprecated, use "Audio call" instead -->
|
||||
<string name="outgoing_audio_call">Ausgehender Sprachanruf</string>
|
||||
<!-- deprecated, use "Video call" instead -->
|
||||
<string name="outgoing_video_call">Ausgehender Videoanruf</string>
|
||||
<!-- deprecated, use incoming_audio_call or incoming_video_call instead -->
|
||||
<string name="incoming_call">Eingehender Anruf</string>
|
||||
<!-- deprecated, use "Audio call" instead -->
|
||||
<string name="incoming_audio_call">Eingehender Sprachanruf</string>
|
||||
<!-- deprecated, use "Video call" instead -->
|
||||
<string name="incoming_video_call">Eingehender Videoanruf</string>
|
||||
<string name="declined_call">Abgelehnter Anruf</string>
|
||||
<string name="canceled_call">Abgebrochener Anruf</string>
|
||||
<string name="missed_call">Verpasster Anruf</string>
|
||||
<!-- the first placeholder will be replaced by a date, the second placeholder by duration, example: "Thu, 08:12 pm, 2 minutes" -->
|
||||
<string name="call_date_and_duration">%1$s, %2$s</string>
|
||||
<string name="already_in_call">Bereits im Anruf</string>
|
||||
|
||||
<!-- get confirmations -->
|
||||
<!-- confirmation for leaving groups or channels. If a subject is needed, "Are you sure you want to leave the chat?" would work as well -->
|
||||
@@ -432,12 +445,10 @@
|
||||
<string name="ask_remove_from_channel">%1$s vom Kanal entfernen?</string>
|
||||
<string name="open_url_confirmation">Diesen Link öffnen?</string>
|
||||
|
||||
|
||||
<!-- contact list -->
|
||||
<string name="contacts_title">Kontakte</string>
|
||||
<string name="contacts_type_email_above">Oben eine E-Mail-Adresse eingeben</string>
|
||||
|
||||
|
||||
<!-- chatlist and chat view -->
|
||||
<plurals name="chat_archived">
|
||||
<item quantity="one">%d Chat archiviert</item>
|
||||
@@ -497,25 +508,14 @@
|
||||
<string name="send_file_to">Sende \"%1$s\" an…</string>
|
||||
<!-- title shown above a list contacts where one should be selected (eg. when a webxdc attempts to send a message to a chat) -->
|
||||
<string name="send_message_to">Nachricht senden an…</string>
|
||||
<string name="enable_realtime">Echtzeit-Apps</string>
|
||||
<string name="enable_realtime_explain">Aktiviert Echtzeitverbindungen für an Chats angehängte Apps. Wenn aktiviert, können Chat-Partner möglicherweise deine IP-Adresse ermitteln, wenn du eine App startest.</string>
|
||||
|
||||
<!-- map -->
|
||||
<string name="filter_map_on_time">Standorte im Zeitrahmen anzeigen</string>
|
||||
<string name="show_location_traces">Spuren anzeigen</string>
|
||||
<string name="add_poi">Sende eine Ortsmarkierung. </string>
|
||||
|
||||
|
||||
<!-- punycode warning / labeled links -->
|
||||
<!-- placeholder is domain/hostname that should be trusted -->
|
||||
<string name="open_external_url_trust_domain">Nicht noch einmal nach %1$s fragen</string>
|
||||
<string name="puny_code_warning_header">Verdächtiger Link erkannt</string>
|
||||
<!-- placeholder contains the hostname converted to ascii -->
|
||||
<string name="puny_code_warning_question">Bist du sicher, dass du %1$s besuchen möchten?</string>
|
||||
<!-- this message is shown whenever a link with non-latin characters is clicked. first placeholder is original hostname with special chars, second placeholder is hostname encoded in ascii -->
|
||||
<string name="puny_code_warning_description">Du bist einem Link gefolgt, der durch die Verwendung ähnlich aussehender Zeichen aus verschiedenen Alphabeten zu einer falschen Darstellung führen könnte. Wenn du dem Link mit der Bezeichnung %1$s folgst, gelangst du zu %2$s, was für nicht-lateinische Zeichen normal ist. Wenn du solche Zeichen nicht erwartet hast, könnte dieser Link schädlich sein.</string>
|
||||
|
||||
|
||||
<!-- search -->
|
||||
<string name="search">Suchen</string>
|
||||
<string name="search_in_chat">Im Chat suchen</string>
|
||||
@@ -525,7 +525,6 @@
|
||||
<!-- Adjective, as in "Show Unread Messages" -->
|
||||
<string name="search_unread">Ungelesen</string>
|
||||
|
||||
|
||||
<!-- create/edit groups, contact/group profile -->
|
||||
<string name="group_name">Gruppenname</string>
|
||||
<string name="group_avatar">Gruppenbild</string>
|
||||
@@ -589,8 +588,6 @@
|
||||
<string name="incoming_messages">Eingehende Nachrichten</string>
|
||||
<!-- Headline for the "Outbox" eg. in the "Connectivity" view -->
|
||||
<string name="outgoing_messages">Ausgehende Nachrichten</string>
|
||||
<!-- deprecated -->
|
||||
<string name="storage_on_domain">Speicher auf %1$s</string>
|
||||
<string name="connectivity">Verbindungsstatus</string>
|
||||
<!-- Shown in the title bar if the app is "Not connected"; prefer short strings. -->
|
||||
<string name="connectivity_not_connected">Nicht verbunden</string>
|
||||
@@ -608,11 +605,10 @@
|
||||
<!-- Used for describing resource usage, resulting string will be eg. "1.2 GiB of 3 GiB used" -->
|
||||
<string name="part_of_total_used">%1$s von %2$s verwendet</string>
|
||||
|
||||
|
||||
<!-- welcome and login -->
|
||||
<!-- Primary button on the welcome screen, allows to create an instant profile -->
|
||||
<string name="onboarding_create_instant_account">Neues Profil erstellen</string>
|
||||
<!-- Secondary button on the welcome screen, allows to "Add as Second Device", "Restore from Backup" -->
|
||||
<!-- Secondary button on the welcome screen, allows to "Add as Second Device", "Restore from Backup" -->
|
||||
<string name="onboarding_alternative_logins">Ich habe bereits ein Profil</string>
|
||||
<!-- This is a button and a title, allowing to use existing, classic email, setting ports, passwords and so on -->
|
||||
<string name="manual_account_setup_option">Klassische E-Mail als Relay</string>
|
||||
@@ -671,12 +667,16 @@
|
||||
<string name="add_transport">Relay hinzufügen</string>
|
||||
<string name="remove_transport">Relay entfernen</string>
|
||||
<string name="edit_transport">Relay bearbeiten</string>
|
||||
<string name="used_for_sending">Zum Senden verwendet</string>
|
||||
<string name="hide_from_contacts">Vor Kontakten verstecken</string>
|
||||
<string name="hidden_from_contacts">Vor Kontakten versteckt</string>
|
||||
<!-- Hint for the list of relays -->
|
||||
<string name="transport_list_hint">Nachrichten werden auf allen Relays empfangen</string>
|
||||
<!-- shown if a QR code was scanned that can be used as a relay -->
|
||||
<string name="confirm_add_transport">Relay hinzufügen?</string>
|
||||
<string name="invalid_transport_qr">Der gescannte QR-Code enthält keine gültiges Relay.</string>
|
||||
<!-- placeholder will be replaced by a relay server name -->
|
||||
<string name="confirm_remove_transport">Relay \"%1$s\" entfernen?\n\nDeine Kontakte können dich nur erreichen, wenn du sie zuvor über einen anderes Relay erreicht hast.\n\nIm Zweifel, entferne den Relay später.</string>
|
||||
|
||||
<string name="confirm_remove_or_hide_transport_x">Relay \"%1$s\" entfernen?\n\nKontakte, die nur dieses Relay kennen, erreichen dich möglicherweise erst wieder, wenn du ihnen erneut eine Nachricht schickst.\n\nIm Zweifelsfall, verstecke das Relay anstelle es zu löschen.</string>
|
||||
<string name="login_certificate_checks">Zertifikatsüberprüfung</string>
|
||||
<string name="login_error_mail">Bitte eine gültige E-Mail-Adresse eingeben</string>
|
||||
<string name="login_error_server">Bitte eine gültige Server/IP-Adresse eingeben</string>
|
||||
@@ -717,10 +717,7 @@
|
||||
<string name="share_text_multiple_chats">Den folgenden Text an %1$d Chats senden?\n\n\"%2$s\"</string>
|
||||
<string name="share_abort">Teilen aufgrund fehlender Berechtigungen abgebrochen.</string>
|
||||
|
||||
|
||||
<!-- preferences -->
|
||||
<string name="pref_using_custom">Benutzerdefiniert verwenden: %s</string>
|
||||
<string name="pref_using_default">Standard verwenden: %s</string>
|
||||
<string name="pref_profile_info_headline">Mein Profil</string>
|
||||
<string name="pref_profile_photo">Profilbild</string>
|
||||
<string name="pref_blocked_contacts">Blockierte Kontakte</string>
|
||||
@@ -734,6 +731,7 @@
|
||||
<string name="pref_enter_sends">Enter-Taste sendet</string>
|
||||
<string name="pref_enter_sends_explain">Durch Drücken der Eingabetaste werden Textnachrichten gesendet.</string>
|
||||
<string name="pref_outgoing_media_quality">Medienqualität beim Senden</string>
|
||||
<string name="pref_outgoing_media_quality_hint">Um Originalqualität zu senden, hänge Medien als „Datei“ an. Dies verbraucht deutlich mehr Datenvolumen für dich und die Empfänger.</string>
|
||||
<string name="pref_outgoing_balanced">Ausgewogen</string>
|
||||
<string name="pref_outgoing_worse">Schlechte Qualität, kleine Dateien</string>
|
||||
<string name="pref_vibrate">Vibrieren</string>
|
||||
@@ -744,6 +742,10 @@
|
||||
<string name="pref_notifications">Benachrichtigungen</string>
|
||||
<string name="pref_mention_notifications">Erwähnungen</string>
|
||||
<string name="pref_mention_notifications_explain">In stummgeschalteten Gruppen, über an dich gerichtete Nachrichten, wie Antworten oder Reaktionen, benachrichtigen</string>
|
||||
<!-- Title for the "Calls" notification setting. This is a plural noun, not a verb. -->
|
||||
<string name="pref_calls">Anrufe</string>
|
||||
<!-- Details about what the "Calls" notification setting does -->
|
||||
<string name="pref_calls_explain">Anrufbildschirm bei eingehenden Anrufen</string>
|
||||
<string name="pref_notifications_show">Anzeigen</string>
|
||||
<string name="pref_notifications_priority">Priorität</string>
|
||||
<string name="pref_notifications_explain">System-Benachrichtigungen bei neuen Nachrichten aktivieren</string>
|
||||
@@ -753,8 +755,6 @@
|
||||
<string name="pref_sound">Ton</string>
|
||||
<string name="pref_silent">Leise</string>
|
||||
<string name="pref_privacy">Datenschutz</string>
|
||||
<!-- deprecated, use pref_chats -->
|
||||
<string name="pref_chats_and_media">Chats und Medien</string>
|
||||
<string name="pref_system_default">Systemstandard</string>
|
||||
<!-- Translators: as in "opposite of dark" -->
|
||||
<string name="pref_light_theme">Hell</string>
|
||||
@@ -791,7 +791,7 @@
|
||||
<string name="pref_background_btn_default">Standard-Bild verwenden</string>
|
||||
<string name="pref_background_btn_gallery">Aus Galerie auswählen</string>
|
||||
<string name="pref_imap_folder_warn_disable_defaults">Wenn du diese Option änderst, stelle sicher, dass der Server und die anderen Geräte entsprechend konfiguriert sind\n\nAndernfalls funktionieren Dinge möglicherweise nicht wie erwartet.</string>
|
||||
<!-- No need to be literal here, you can also use "Use Multiple Devices", "Support Multiple Devices" or other fitting terms. However, it should fit to the wording or your language at https://delta.chat/help -->
|
||||
<!-- No need to be literal here, you can also use "Use Multiple Devices", "Support Multiple Devices" or other fitting terms. However, it should fit to the wording or your language at https://delta.chat/help -->
|
||||
<string name="pref_multidevice">Mehrgerätemodus</string>
|
||||
<string name="pref_multidevice_explain">Synchronisiere deine Nachrichten mit deinen anderen Geräten. Wird beim Hinzufügen eines zweiten Geräts automatisch aktiviert.</string>
|
||||
<string name="pref_multidevice_change_warn">Der Mehrgerätemodus muss aktiviert sein, wenn dasselbe Profil auf mehreren Geräten verwendet wird. Deaktiviere diese Einstellung nur, wenn du dieses Profil von allen anderen Geräten entfernt hast.\n\nDie Deaktivierung des Mehrgerätemodus bei Verwendung des Profils auf mehreren Geräten führt zu verlorenen Nachrichten und anderen Problemen.</string>
|
||||
@@ -819,15 +819,11 @@
|
||||
<string name="n_bytes_message">%1$s Nachricht</string>
|
||||
<!-- %1$s will be replaced by human-readable date and time -->
|
||||
<string name="download_max_available_until">Download max. verfügbar bis %1$s</string>
|
||||
<!-- deprecated -->
|
||||
<string name="select_profile">Profil auswählen</string>
|
||||
<string name="profile_image_select">Profilbild auswählen</string>
|
||||
<string name="select_your_new_profile_image">Wählen dein Profilbild aus</string>
|
||||
<string name="profile_image_delete">Profilbild löschen</string>
|
||||
<string name="pref_show_tray_icon">Benachrichtigungssymbol anzeigen</string>
|
||||
<string name="pref_edit_profile">Profil bearbeiten</string>
|
||||
<string name="disable_imap_idle">IMAP IDLE deaktivieren</string>
|
||||
<string name="disable_imap_idle_explain">IMAP IDLE ausschalten, selbst wenn vom Server unterstützt. Die Aktivierung dieser Option verzögert den Abruf von Nachrichten; nur zu Testzwecken aktivieren</string>
|
||||
<string name="send_stats_to_devs">Statistik an Delta Chat Entwickler senden</string>
|
||||
<string name="stats_device_message">Möchtest du helfen, Delta Chat zu verbessern, indem du wöchentlich anonyme Nutzungsstatistiken sendest?\n\n👉 Hier tippen … 👈</string>
|
||||
<string name="stats_confirmation_dialog">Möchtest du helfen, Delta Chat zu verbessern, indem du wöchentlich anonyme Nutzungsstatistiken sendest?</string>
|
||||
@@ -835,7 +831,7 @@
|
||||
<string name="stats_disable_dialog">Das Senden von Statistiken ist bereits eingeschaltet.\n\nMöchtest du es ausschalten?</string>
|
||||
<string name="disable">Ausschalten</string>
|
||||
<string name="stats_keep_sending">Weiter senden</string>
|
||||
<string name="stats_msg_body">Der Anhang enthält anonyme Statistiken, die uns helfen, Delta Chat zu verbessern. Vielen Dank!</string>
|
||||
<string name="stats_msg_body">Der Anhang enthält anonyme Statistiken, die uns helfen, Delta Chat zu verbessern. Vielen Dank! Für weitere Infos, siehe https://delta.chat/help#statssending </string>
|
||||
|
||||
<!-- Emoji picker and categories -->
|
||||
<string name="emoji_search_results">Suchergebnisse</string>
|
||||
@@ -926,10 +922,6 @@
|
||||
<string name="ephemeral_timer_seconds_by_you">Du hast die Ablaufzeit verschwindender Nachrichten auf %1$s Sekunden gesetzt.</string>
|
||||
<!-- %1$s will be replaced by the number of seconds (always >1) the timer is set to, %2$s will be replaced by name of the contact -->
|
||||
<string name="ephemeral_timer_seconds_by_other">Ablaufzeit verschwindender Nachrichten auf %1$s Sekunden gesetzt von %2$s.</string>
|
||||
<!-- deprecated, usage needs to be removed in core -->
|
||||
<string name="ephemeral_timer_1_minute_by_you">Du hast die Ablaufzeit verschwindender Nachrichten auf 1 Minute gesetzt.</string>
|
||||
<!-- deprecated, usage needs to be removed in core -->
|
||||
<string name="ephemeral_timer_1_minute_by_other">Ablaufzeit verschwindender Nachrichten auf 1 MInute gesetzt von %1$s.</string>
|
||||
<string name="ephemeral_timer_1_hour_by_you">Du hast die Ablaufzeit verschwindender Nachrichten auf 1 Stunde gesetzt.</string>
|
||||
<!-- %1$s will be replaced by name of the contact -->
|
||||
<string name="ephemeral_timer_1_hour_by_other">Ablaufzeit verschwindender Nachrichten auf 1 Stunde gesetzt von %1$s.</string>
|
||||
@@ -1026,14 +1018,12 @@
|
||||
<string name="verified_by">Eingeführt von %1$s</string>
|
||||
<string name="verified_by_you">Durch mich eingeführt</string>
|
||||
<string name="verified_by_unknown">Eingeführt</string>
|
||||
<!-- deprecated -->
|
||||
<string name="verified_contact_required_explain">Um Ende-zu-Ende-Verschlüsselung zu gewährleisten, können nur Kontakte mit grünem Häkchen zu dieser Gruppe hinzugefügt werden.\n\nDu kannst Kontakte persönlich treffen und ihren QR-Code scannen, um sie einzuführen.</string>
|
||||
<string name="mailto_dialog_header_select_chat">Wähle den Chat, an den die Nachricht gesendet werden soll</string>
|
||||
<!-- first placeholder is the name of the chat -->
|
||||
<string name="confirm_replace_draft">%1$s hat bereits einen Entwurf. Möchtest du diesen ersetzen?</string>
|
||||
<string name="mailto_link_could_not_be_decoded">Mailto-Link konnte nicht dekodiert werden: %1$s</string>
|
||||
|
||||
<!-- notifications -->
|
||||
<!-- notifications -->
|
||||
<string name="notify_reply_button">Antworten</string>
|
||||
<string name="notify_new_message">Neue Nachricht</string>
|
||||
<string name="notify_background_connection_enabled">Hintergrundverbindung aktiviert</string>
|
||||
@@ -1049,7 +1039,6 @@
|
||||
<string name="new_messages_body">Du hast neue Nachrichten</string>
|
||||
<string name="n_messages_in_m_chats">%1$d Nachrichten in %2$d Chats</string>
|
||||
|
||||
|
||||
<!-- permissions -->
|
||||
<string name="perm_required_title">Berechtigung erforderlich</string>
|
||||
<string name="perm_continue">Weiter</string>
|
||||
@@ -1070,9 +1059,6 @@
|
||||
<string name="ImageEditorHud_flip">Spiegeln</string>
|
||||
<string name="ImageEditorHud_rotate">Drehen</string>
|
||||
|
||||
<!-- strings introduced on desktop. we want to share strings between the os, in general, please do not add generic strings here -->
|
||||
<string name="about_offical_app_desktop">Dies ist die offizielle Delta Chat Desktop App.</string>
|
||||
<string name="about_licensed_under_desktop">Dieses Programm ist lizenziert unter der GNU GPL version 3 und der Quellcode ist auf Github verfügbar.</string>
|
||||
<string name="welcome_desktop">Willkommen bei Delta Chat</string>
|
||||
<string name="global_menu_preferences_language_desktop">Sprache</string>
|
||||
<string name="global_menu_file_desktop">Datei</string>
|
||||
@@ -1112,6 +1098,7 @@
|
||||
<string name="menu.view.developer.open.log.folder">Log-Ordner öffnen</string>
|
||||
<string name="menu.view.developer.open.current.log.file">Aktuelle Logdatei öffnen</string>
|
||||
<string name="explain_desktop_minimized_disabled_tray_pref" tools:ignore="TypographyDashes">Benachrichtigungssymbol kann nicht deaktiviert werden, da Delta Chat mit der Option --minimized gestartet wurde.</string>
|
||||
<!-- deprecated, used on desktop although there is not spell checker -->
|
||||
<string name="no_spellcheck_suggestions_found">Keine Rechtschreibvorschläge gefunden.</string>
|
||||
<string name="show_window">Fenster anzeigen</string>
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
<string name="off">Απενεργοποιημένο</string>
|
||||
<string name="def">Προεπιλογή</string>
|
||||
<string name="default_value">Προεπιλογή(%1$s)</string>
|
||||
<string name="default_value_as_above">Προκαθορισμένο (Ίδιο με το παραπάνω)</string>
|
||||
<string name="custom">Προσαρμογή</string>
|
||||
<string name="none">Κανένα</string>
|
||||
<string name="automatic">Αυτόματα</string>
|
||||
@@ -40,7 +39,7 @@
|
||||
<!-- Verb "to mute". used to mute a chat, so that it is silenced e.g. does not make noise or cause notifications -->
|
||||
<string name="mute">Σίγαση</string>
|
||||
<string name="ephemeral_messages">Μηνύματα που εξαφανίζονται</string>
|
||||
<string name="ephemeral_messages_hint">Ισχύει για όλα τα μέλη της συνομιλίας αν χρησιμοποιούν Delta Chat: έχουν την δυνατότητα αντιγραφής, αποθήκευσης, και κοινοποίησης μηνυμάτων ή χρήση άλλων e-mail πελατών.</string>
|
||||
<string name="ephemeral_messages_hint">Ισχύει για όλα τα μέλη της συνομιλίας αν χρησιμοποιούν Delta Chat: έχουν την δυνατότητα αντιγραφής, αποθήκευσης, και κοινοποίησης μηνυμάτων ή χρήση άλλων e-mail πελατών.</string>
|
||||
<string name="save">Αποθήκευση</string>
|
||||
<string name="chat">Συνομιλία</string>
|
||||
<string name="media">Πολυμέσα</string>
|
||||
@@ -182,8 +181,6 @@
|
||||
<string name="menu_new_contact">Νέα Επαφή</string>
|
||||
<string name="menu_new_chat">Νέα Συνομιλία</string>
|
||||
<string name="menu_new_group">Νέα ομάδα</string>
|
||||
<!-- deprecated -->
|
||||
<string name="add_recipients">Προσθήκη Παραλήπτη</string>
|
||||
<string name="menu_send">Αποστολή</string>
|
||||
<string name="menu_toggle_keyboard">Εναλλαγή πληκτρολογίου emoji</string>
|
||||
<string name="menu_edit_group">Επεξεργασία ομάδας</string>
|
||||
@@ -237,7 +234,6 @@
|
||||
<string name="menu_more_options">Περισσότερες Επιλογές</string>
|
||||
<string name="menu_learn_spelling">Μάθε Ορθογραφία</string>
|
||||
<string name="jump_to_message">Μετακίνηση στη Συνομιλία</string>
|
||||
<string name="copy_json">Αντιγραφή JSON</string>
|
||||
<string name="replace_draft">Αντικατάσταση Σχεδίου</string>
|
||||
<string name="title_share_location">Διαμοιρασμός τοποθεσίας με όλα τα μέλη της ομάδας</string>
|
||||
<string name="device_talk">Μηνύματα Συσκευής</string>
|
||||
@@ -291,12 +287,10 @@
|
||||
<string name="ask_remove_members">Αφαίρεση του/της %1$s από την ομάδα;</string>
|
||||
<string name="open_url_confirmation">Θέλετε να ανοίξετε αυτό τον σύνδεσμό;</string>
|
||||
|
||||
|
||||
<!-- contact list -->
|
||||
<string name="contacts_title">Επαφές</string>
|
||||
<string name="contacts_type_email_above">Εισάγετε την διεύθυνση e-mail παραπάνω</string>
|
||||
|
||||
|
||||
<!-- chatlist and chat view -->
|
||||
<plurals name="chat_archived">
|
||||
<item quantity="one">%d συνομιλία αρχειοθετήθηκε</item>
|
||||
@@ -349,22 +343,13 @@
|
||||
<string name="start_app">Εκκίνηση…</string>
|
||||
<!-- this is a warning that is shown when one tries to send something to a chat that is not yet accepted. -->
|
||||
<string name="accept_request_first">Αποδεχτείτε πρώτα το αίτημα συνομιλίας.</string>
|
||||
<!-- map -->
|
||||
<string name="filter_map_on_time">Εμφάνιση τοποθεσιών σε χρονικό πλαίσιο</string>
|
||||
<string name="show_location_traces">Εμφάνιση ιχνών</string>
|
||||
<string name="add_poi">Αποστολή σημείου ενδιαφέροντος</string>
|
||||
|
||||
|
||||
<!-- punycode warning / labeled links -->
|
||||
<!-- placeholder is domain/hostname that should be trusted -->
|
||||
<string name="open_external_url_trust_domain">Μην ξαναρωτήθω για %1$s</string>
|
||||
<string name="puny_code_warning_header">Εντοπίστηκε ύποπτος σύνδεσμος</string>
|
||||
<!-- placeholder contains the hostname converted to ascii -->
|
||||
<string name="puny_code_warning_question">Είστε σίγουροι ότι θέλετε να επισκεφθείτε %1$s;</string>
|
||||
<!-- this message is shown whenever a link with non-latin characters is clicked. first placeholder is original hostname with special chars, second placeholder is hostname encoded in ascii -->
|
||||
<string name="puny_code_warning_description">Αυτός ο σύνδεσμος μπορεί να παραποιεί χαρακτήρες με παρόμοια εμφάνιση από διαφορετικά αλφάβητα. Ακολουθώντας τον σύνδεσμο με την ετικέτα %1$s θα οδηγήσει σε %2$s κάτι που είναι φυσιολογικό για μη λατινικούς χαρακτήρες. Αν δεν περιμένατε τέτοιους χαρακτήρες, αυτός ο σύνδεσμος θα μπορούσε να είναι επιβλαβής.</string>
|
||||
|
||||
|
||||
<!-- search -->
|
||||
<string name="search">Αναζήτηση</string>
|
||||
<string name="search_explain">Αναζήτηση για συνομιλίες, επαφές, και μηνύματα</string>
|
||||
@@ -401,8 +386,6 @@
|
||||
<string name="incoming_messages">Εισερχόμενα Μηνύματα</string>
|
||||
<!-- Headline for the "Outbox" eg. in the "Connectivity" view -->
|
||||
<string name="outgoing_messages">Εξερχόμενα Μηνύματα</string>
|
||||
<!-- deprecated -->
|
||||
<string name="storage_on_domain">Αποθήκευση στο %1$s</string>
|
||||
<string name="connectivity">Συνδεσιμότητα</string>
|
||||
<!-- Shown in the title bar if the app is "Not connected"; prefer short strings. -->
|
||||
<string name="connectivity_not_connected">Μη συνδεδεμένο</string>
|
||||
@@ -420,7 +403,6 @@
|
||||
<!-- Used for describing resource usage, resulting string will be eg. "1.2 GiB of 3 GiB used" -->
|
||||
<string name="part_of_total_used">%1$s από %2$s χρησιμοποιείται</string>
|
||||
|
||||
|
||||
<string name="scan_invitation_code">Σάρωση Κωδικού Πρόσκλησης</string>
|
||||
<string name="login_title">Σύνδεση</string>
|
||||
<string name="login_inbox">Εισερχόμενα</string>
|
||||
@@ -465,10 +447,7 @@
|
||||
<string name="share_text_multiple_chats">Αποστολή αυτού του κειμένου σε %1$d συνομιλίες;\n\n\"%2$s\"</string>
|
||||
<string name="share_abort">Η κοινή χρήση ματαιώθηκε λόγω έλλειψης αδειών.</string>
|
||||
|
||||
|
||||
<!-- preferences -->
|
||||
<string name="pref_using_custom">Χρήση προσαρμοσμένου: %s</string>
|
||||
<string name="pref_using_default">Χρήση προεπιλογής: %s</string>
|
||||
<string name="pref_profile_info_headline">Πληροφορίες Προφίλ</string>
|
||||
<string name="pref_profile_photo">Εικόνα Προφίλ</string>
|
||||
<string name="pref_blocked_contacts">Αποκλεισμένες Επαφές</string>
|
||||
@@ -498,8 +477,6 @@
|
||||
<string name="pref_sound">Ήχος</string>
|
||||
<string name="pref_silent">Σε σίγαση</string>
|
||||
<string name="pref_privacy">Ιδιωτικότητα</string>
|
||||
<!-- deprecated, use pref_chats -->
|
||||
<string name="pref_chats_and_media">Συνομιλίες και Πολυμέσα</string>
|
||||
<string name="pref_system_default">Προκαθορισμένο του συστήματος</string>
|
||||
<!-- Translators: as in "opposite of dark" -->
|
||||
<string name="pref_light_theme">Φωτεινό</string>
|
||||
@@ -624,10 +601,6 @@
|
||||
<string name="ephemeral_timer_seconds_by_you">Όρισες το χρόνο εξαφάνισης των μηνυμάτων σε %1$s δευτερόλεπτα.</string>
|
||||
<!-- %1$s will be replaced by the number of seconds (always >1) the timer is set to, %2$s will be replaced by name of the contact -->
|
||||
<string name="ephemeral_timer_seconds_by_other">Ο/Η %2$s όρισε το χρόνο εξαφάνισης των μηνυμάτων σε %1$s δευτερόλεπτα.</string>
|
||||
<!-- deprecated, usage needs to be removed in core -->
|
||||
<string name="ephemeral_timer_1_minute_by_you">Όρισες το χρόνο εξαφάνισης των μηνυμάτων σε 1 λεπτό.</string>
|
||||
<!-- deprecated, usage needs to be removed in core -->
|
||||
<string name="ephemeral_timer_1_minute_by_other">Ο/Η %1$s όρισε το χρόνο εξαφάνισης των μηνυμάτων σε 1 λεπτό.</string>
|
||||
<string name="ephemeral_timer_1_hour_by_you">Όρισες το χρόνο εξαφάνισης των μηνυμάτων σε 1 ώρα.</string>
|
||||
<!-- %1$s will be replaced by name of the contact -->
|
||||
<string name="ephemeral_timer_1_hour_by_other">Ο/Η %1$s όρισε το χρόνο εξαφάνισης των μηνυμάτων σε 1 ώρα.</string>
|
||||
@@ -638,7 +611,7 @@
|
||||
<!-- %1$s will be replaced by name of the contact -->
|
||||
<string name="ephemeral_timer_1_week_by_other">Ο/Η %1$s όρισε το χρόνο εξαφάνισης των μηνυμάτων σε 1 εβδομάδα.</string>
|
||||
<!-- %1$s will be replaced by the number of minutes (always >1) the timer is set to -->
|
||||
<string name="ephemeral_timer_minutes_by_you">Όρισες το χρόνο εξαφάνισης των μηνυμάτων σε %1$s λεπτά.</string>
|
||||
<string name="ephemeral_timer_minutes_by_you">Όρισες το χρόνο εξαφάνισης των μηνυμάτων σε %1$s λεπτά.</string>
|
||||
<!-- %1$s will be replaced by the number of minutes (always >1) the timer is set to, %2$s will be replaced by name of the contact -->
|
||||
<string name="ephemeral_timer_minutes_by_other">Ο/Η %2$s όρισε το χρόνο εξαφάνισης των μηνυμάτων σε %1$s λεπτά.</string>
|
||||
<!-- %1$s will be replaced by the number of hours (always >1) the timer is set to -->
|
||||
@@ -705,7 +678,7 @@
|
||||
<string name="confirm_replace_draft">%1$s έχει ήδη ένα πρόχειρο μήνυμα, θέλετε να το αντικαταστήσετε;</string>
|
||||
<string name="mailto_link_could_not_be_decoded">Αδυναμία αποκωδικοποίησης του συνδέσμου mailto: %1$s</string>
|
||||
|
||||
<!-- notifications -->
|
||||
<!-- notifications -->
|
||||
<string name="notify_reply_button">Απάντηση</string>
|
||||
<string name="notify_new_message">Νέο μήνυμα</string>
|
||||
<string name="notify_background_connection_enabled">Η σύνδεση στο παρασκήνιο ενεργοποιήθηκε</string>
|
||||
@@ -732,9 +705,6 @@
|
||||
<string name="ImageEditorHud_flip">Εναλλαγή</string>
|
||||
<string name="ImageEditorHud_rotate">Περιστροφή</string>
|
||||
|
||||
<!-- strings introduced on desktop. we want to share strings between the os, in general, please do not add generic strings here -->
|
||||
<string name="about_offical_app_desktop">Αυτή είναι η επίσημη εφαρμογή Delta Chat Desktop.</string>
|
||||
<string name="about_licensed_under_desktop">Αυτό το λογισμικό έχει άδεια χρήσης σύμφωνα με την GNU GPL έκδοση 3 και ο πηγαίος κώδικας είναι διαθέσιμος στο GitHub.</string>
|
||||
<string name="welcome_desktop">Καλώς ήρθατε στο Delta Chat</string>
|
||||
<string name="global_menu_preferences_language_desktop">Γλώσσα</string>
|
||||
<string name="global_menu_file_desktop">Αρχείο</string>
|
||||
@@ -770,6 +740,7 @@
|
||||
<string name="menu.view.developer.open.log.folder">Άνοιγμα του φακέλου καταγραφής</string>
|
||||
<string name="menu.view.developer.open.current.log.file">Άνοιγμα του τρέχον αρχείου καταγραφής</string>
|
||||
<string name="explain_desktop_minimized_disabled_tray_pref" tools:ignore="TypographyDashes">Το εικονίδιο του δίσκου δεν μπορεί να απενεργοποιηθεί καθώς το Delta Chat ξεκίνησε με την επιλογή --ελαχιστοποιημένη.</string>
|
||||
<!-- deprecated, used on desktop although there is not spell checker -->
|
||||
<string name="no_spellcheck_suggestions_found">Δεν βρέθηκαν προτάσεις ορθογραφίας.</string>
|
||||
<string name="show_window">Εμφάνιση παραθύρου</string>
|
||||
|
||||
|
||||
@@ -28,8 +28,6 @@
|
||||
<string name="update">Ĝisdatigi</string>
|
||||
<string name="emoji">Emoji</string>
|
||||
<string name="attachment">Aldonaĵo</string>
|
||||
<!-- the placeholder will be replaced by the name of the image or file to attach -->
|
||||
<string name="ask_attach">Ĉu alkroĉi \"%1$s\"?</string>
|
||||
<string name="back">Reen</string>
|
||||
<string name="close">Fermi</string>
|
||||
<string name="close_window">Fermi fenestron</string>
|
||||
@@ -109,19 +107,9 @@
|
||||
<string name="last_month">Pasint-monate</string>
|
||||
<!-- Refers to the time a contact was last seen. Shown below contact name in the profile. The placeholder will be replaced by date or time, resulting in "Last seen at 12:13 AM" or "Last seen Nov 12" -->
|
||||
<string name="last_seen_at">Laste vidita je%1$s</string>
|
||||
<!-- Refers to the time a contact was last seen. Shown below contact name in the profile. The placeholder will be replaced by a relative point in time as "3 minutes ago" (see https://momentjs.com for more examples and languages)-->
|
||||
<!-- Refers to the time a contact was last seen. Shown below contact name in the profile. The placeholder will be replaced by a relative point in time as "3 minutes ago" (see https://momentjs.com for more examples and languages) -->
|
||||
<string name="last_seen_relative">Laste vidita %1$s</string>
|
||||
<string name="last_seen_unknown">Laste vidita: nedisponebla informo</string>
|
||||
<!-- Shown in call duration. Avoid abbreviations, prefer full words ex. "N seconds". -->
|
||||
<plurals name="n_seconds_ext">
|
||||
<item quantity="one">%d sekundo</item>
|
||||
<item quantity="other">%d sekundoj</item>
|
||||
</plurals>
|
||||
<!-- Shown in call duration. Avoid abbreviations, prefer full words ex. "N minutes". -->
|
||||
<plurals name="n_minutes_ext">
|
||||
<item quantity="one">%d minuto</item>
|
||||
<item quantity="other">%d minutoj</item>
|
||||
</plurals>
|
||||
<!-- Shown beside messages that are "N minutes old". Prefer short strings, or well-known abbreviations. -->
|
||||
<plurals name="n_minutes">
|
||||
<item quantity="one">%d min</item>
|
||||
@@ -221,8 +209,6 @@
|
||||
<string name="menu_new_contact">Nova kontakto</string>
|
||||
<string name="menu_new_chat">Nova babilo</string>
|
||||
<string name="menu_new_group">Nova grupo</string>
|
||||
<!-- deprecated -->
|
||||
<string name="add_recipients">Aldoni Ricevantojn</string>
|
||||
<string name="menu_send">Sendi</string>
|
||||
<string name="menu_toggle_keyboard">Baskuligi emoĝian klavaron</string>
|
||||
<string name="menu_edit_group">Redakti grupon</string>
|
||||
@@ -279,7 +265,6 @@
|
||||
<string name="menu_more_options">Pli da ebloj</string>
|
||||
<string name="menu_learn_spelling">Lernu la ortografion</string>
|
||||
<string name="jump_to_message">Iru al mesaĝo</string>
|
||||
<string name="copy_json">Kopiu JSON</string>
|
||||
<string name="title_share_location">Konigi lokon al ĉiuj grupanoj</string>
|
||||
<string name="device_talk">Aparataj mesaĝoj</string>
|
||||
<string name="device_talk_subtitle">Loke generitaj mesaĝoj</string>
|
||||
@@ -315,7 +300,6 @@
|
||||
<string name="contacts_title">Kontaktoj</string>
|
||||
<string name="contacts_type_email_above">Enigu retadreson supren</string>
|
||||
|
||||
|
||||
<!-- chatlist and chat view -->
|
||||
<plurals name="chat_archived">
|
||||
<item quantity="one">%d babilo enarĥivigita</item>
|
||||
@@ -345,10 +329,6 @@
|
||||
<string name="save_message">Konservi</string>
|
||||
<string name="saved_messages">Konservitaj mesaĝoj</string>
|
||||
<string name="retry_send">Reprovi sendi mesaĝon</string>
|
||||
<string name="show_location_traces">Montri spurojn</string>
|
||||
<string name="add_poi">Sendi punkton de intereso</string>
|
||||
|
||||
|
||||
<!-- search -->
|
||||
<string name="search">Serĉi</string>
|
||||
<string name="search_explain">Serĉi babilojn, kontaktojn, kaj mesaĝojn</string>
|
||||
@@ -398,7 +378,6 @@
|
||||
<string name="forward_to">Plusendi al…</string>
|
||||
<string name="share_abort">Kunhavigado ĉesis pro manko de permesoj.</string>
|
||||
|
||||
|
||||
<string name="pref_profile_photo">Profilbildo</string>
|
||||
<string name="pref_blocked_contacts">Blokitaj kontaktoj</string>
|
||||
<string name="pref_your_name">Via nomo</string>
|
||||
@@ -416,8 +395,6 @@
|
||||
<string name="pref_sound">Sono</string>
|
||||
<string name="pref_silent">Silenta</string>
|
||||
<string name="pref_privacy">Privateco</string>
|
||||
<!-- deprecated, use pref_chats -->
|
||||
<string name="pref_chats_and_media">Interparoloj kaj aŭdvidaĵoj</string>
|
||||
<string name="pref_system_default">Sistema defaŭlto</string>
|
||||
<!-- Translators: as in "opposite of dark" -->
|
||||
<string name="pref_light_theme">Hela</string>
|
||||
@@ -447,7 +424,7 @@
|
||||
<string name="pref_background_btn_default">Uzi defaŭltan bildon</string>
|
||||
<string name="pref_background_btn_gallery">Elekti el galerio</string>
|
||||
<string name="pref_show_emails_all">Ĉiuj</string>
|
||||
<!-- notifications -->
|
||||
<!-- notifications -->
|
||||
<string name="notify_reply_button">Respondi</string>
|
||||
<string name="notify_new_message">Nova mesaĝo</string>
|
||||
<string name="notify_priority_high">Alta</string>
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
<string name="off">Desactivado</string>
|
||||
<string name="def">Por defecto</string>
|
||||
<string name="default_value">Por defecto (%1$s)</string>
|
||||
<string name="default_value_as_above">Por defecto (igual que el superior)</string>
|
||||
<string name="custom">Personalizado</string>
|
||||
<string name="none">Ninguno</string>
|
||||
<string name="automatic">Automático</string>
|
||||
@@ -34,8 +33,6 @@
|
||||
<string name="update">Actualización</string>
|
||||
<string name="emoji">Emoji</string>
|
||||
<string name="attachment">Adjunto</string>
|
||||
<!-- the placeholder will be replaced by the name of the image or file to attach -->
|
||||
<string name="ask_attach">¿Adjunta \"%1$s\"?</string>
|
||||
<string name="back">Atrás</string>
|
||||
<string name="close">Cerrar</string>
|
||||
<string name="close_window">Cerrar ventana</string>
|
||||
@@ -72,6 +69,8 @@
|
||||
<string name="mark_as_read">Marcar como leído</string>
|
||||
<!-- Shortest text for "Mark as being read". In english, this could be "Read" (past tense of "to read"), in german, this could be "Gelesen". -->
|
||||
<string name="mark_as_read_short">Leído</string>
|
||||
<!-- Shortest text for "Mark as being unread". In english, this could be "Unread" (past tense of "to unread"), in german, this could be "Ungelesen". -->
|
||||
<string name="mark_as_unread_short">No leído</string>
|
||||
<!-- Placeholder text when something is loading -->
|
||||
<string name="loading">Cargando…</string>
|
||||
<string name="hide">Ocultar</string>
|
||||
@@ -115,21 +114,17 @@
|
||||
<string name="last_month">El mes pasado</string>
|
||||
<!-- Refers to the time a contact was last seen. Shown below contact name in the profile. The placeholder will be replaced by date or time, resulting in "Last seen at 12:13 AM" or "Last seen Nov 12" -->
|
||||
<string name="last_seen_at">últ. vez: %1$s</string>
|
||||
<!-- Refers to the time a contact was last seen. Shown below contact name in the profile. The placeholder will be replaced by a relative point in time as "3 minutes ago" (see https://momentjs.com for more examples and languages)-->
|
||||
<!-- Refers to the time a contact was last seen. Shown below contact name in the profile. The placeholder will be replaced by a relative point in time as "3 minutes ago" (see https://momentjs.com for more examples and languages) -->
|
||||
<string name="last_seen_relative">últ. vez: %1$s</string>
|
||||
<string name="last_seen_unknown">últ. vez: Desconocido</string>
|
||||
<!-- Shown in call duration. Avoid abbreviations, prefer full words ex. "N seconds". -->
|
||||
<plurals name="n_seconds_ext">
|
||||
<item quantity="one">%d segundo</item>
|
||||
<item quantity="many">%d segundos</item>
|
||||
<item quantity="other">%d segundos</item>
|
||||
</plurals>
|
||||
<!-- Shown in call duration. Avoid abbreviations, prefer full words ex. "N minutes". -->
|
||||
<plurals name="n_minutes_ext">
|
||||
<!-- Call duration as shown in the call bubbles. There is some risk to mix with the sending time, so the word "Duration" may be helpful. Might also be "Duration: %d minutes", "%d-minute duration", "%d-minute length" or "%d-minute call" -->
|
||||
<plurals name="call_duration_minutes">
|
||||
<item quantity="one">%d minuto</item>
|
||||
<item quantity="many">%d minutos</item>
|
||||
<item quantity="other">%d minutos</item>
|
||||
</plurals>
|
||||
<!-- Call duration as shown in the call bubbles in case the call is less than one minute. If the context is not clear enough, one may want to add the word "Duration". -->
|
||||
<string name="call_duration_less_than_a_minute">Menos de 1 minuto</string>
|
||||
<!-- Shown beside messages that are "N minutes old". Prefer short strings, or well-known abbreviations. -->
|
||||
<plurals name="n_minutes">
|
||||
<item quantity="one">%d min</item>
|
||||
@@ -180,6 +175,7 @@
|
||||
<item quantity="other">%d seleccionados</item>
|
||||
</plurals>
|
||||
<string name="selected_colon">Seleccionado:</string>
|
||||
<string name="selected">Seleccionado</string>
|
||||
<string name="self">Yo</string>
|
||||
<string name="draft">Borrador</string>
|
||||
<string name="image">Imagen</string>
|
||||
@@ -191,6 +187,9 @@
|
||||
<string name="add_to_sticker_collection">Añadir a la colección de stickers</string>
|
||||
<string name="add_stickers_instructions">Para añadir stickers, toca en \"Abrir carpeta de stickers\", crea una subcarpeta para tu colección de stickers y copia imágenes y stickers allí</string>
|
||||
<string name="open_sticker_folder">Abrir la carpeta de stickers</string>
|
||||
<string name="ask_add_sticker_to_collection">¿Añadir este sticker a tu colección?</string>
|
||||
<string name="ask_delete_sticker">¿Eliminar este sticker?</string>
|
||||
<string name="sticker_picker_empty_hint">Toca un sticker para añadirlo aquí.</string>
|
||||
<string name="images">Imágenes</string>
|
||||
<!-- a noun, used for "Music" and other "Audio" files -->
|
||||
<string name="audio">Audio</string>
|
||||
@@ -258,7 +257,7 @@
|
||||
<!-- menu labels (or icon, buttons...) -->
|
||||
<string name="menu_new_contact">Nuevo contacto</string>
|
||||
<string name="menu_new_classic_contact">Añadir contacto manualmente</string>
|
||||
<string name="new_classic_contact_explain">Los contactos añadidos manualmente se pueden utilizar para enviar mensajes a contactos que usan clientes de correo electrónico clásico y no se garantiza que estén cifrados de extremo a extremo.</string>
|
||||
<string name="new_classic_contact_explain">Los contactos añadidos manualmente se pueden utilizar para enviar mensajes a contactos que usan clientes de correo electrónico clásico y no se garantiza que estén cifrados de extremo a extremo.</string>
|
||||
<string name="menu_new_chat">Nuevo chat</string>
|
||||
<string name="menu_new_group">Nuevo grupo</string>
|
||||
<!-- "Chat" is a verb here, "Message to" would also fit. the string might be used in the "New Chat" screen above the contact list -->
|
||||
@@ -270,10 +269,14 @@
|
||||
<string name="channels">Canales</string>
|
||||
<!-- consider keeping the term "channel" as in WhatsApp or Telegram -->
|
||||
<string name="new_channel">Nuevo canal</string>
|
||||
<!-- deprecated -->
|
||||
<string name="add_recipients">Agregar destinatarios</string>
|
||||
<!-- consider keeping the term "channel" as in WhatsApp or Telegram -->
|
||||
<string name="channel_name">Nombre del canal</string>
|
||||
<!-- The number of times a message is shown in channels. Use what other messengers are using here, smth. as "N-times seen" or "1 Aufruf" (german) work as well, where "1 impression" or "1 hit" may sound too formal and may be more marketing slang. -->
|
||||
<plurals name="n_views">
|
||||
<item quantity="one">%d visualización</item>
|
||||
<item quantity="many">%d visualizaciones</item>
|
||||
<item quantity="other">%d visualizaciones</item>
|
||||
</plurals>
|
||||
<string name="email">Correo electrónico</string>
|
||||
<!-- "New" as in "Create New Email"; shown together with "New Group" and "New Channel" -->
|
||||
<string name="new_email">Nuevo correo electrónico</string>
|
||||
@@ -289,6 +292,7 @@
|
||||
<string name="menu_add_attachment">Añadir adjunto</string>
|
||||
<string name="menu_leave_group">Abandonar grupo</string>
|
||||
<string name="menu_leave_channel">Abandonar canal</string>
|
||||
<string name="menu_leave_and_delete">Abandonar y eliminar</string>
|
||||
<string name="menu_delete_chat">Eliminar chat</string>
|
||||
<!-- Command to delete all messages in a chat. The chat itself will not be deleted but will be empty afterwards, so make sure to be different from "Delete Chat" here. "Clear" is a verb here, "Empty Chat" would also be fine (eg. in German "Chat leeren") -->
|
||||
<string name="clear_chat">Vaciar chat</string>
|
||||
@@ -350,8 +354,6 @@
|
||||
<string name="menu_more_options">Más opciones</string>
|
||||
<string name="menu_learn_spelling">Aprender ortografía</string>
|
||||
<string name="jump_to_message">Saltar al mensaje</string>
|
||||
<string name="jump_to_original_message">Saltar al mensaje original</string>
|
||||
<string name="copy_json">Copiar JSON</string>
|
||||
<string name="replace_draft">Reemplazar borrador</string>
|
||||
<string name="title_share_location">Compartir ubicación con todos los miembros del grupo</string>
|
||||
<string name="device_talk">Mensajes del dispositivo</string>
|
||||
@@ -388,7 +390,7 @@
|
||||
<string name="share_location_for_six_hours">Por 6 horas</string>
|
||||
|
||||
<plurals name="ask_send_following_n_files_to">
|
||||
<item quantity="one">¿Enviar el archivo a %s?</item>
|
||||
<item quantity="one">¿Enviar el archivo a %s?</item>
|
||||
<item quantity="many">¿Enviar los siguientes %d archivos a %s?</item>
|
||||
<item quantity="other">¿Enviar los siguientes %d archivos a %s?</item>
|
||||
</plurals>
|
||||
@@ -396,25 +398,36 @@
|
||||
|
||||
<!-- the action "to call someone", used as a tooltip for the "phone" icon. not: "the call" -->
|
||||
<string name="start_call">Llamar</string>
|
||||
<!-- Menu item to start an audio call; verbs as "start" are probably superfluous in many translations -->
|
||||
<string name="start_audio_call">Llamada</string>
|
||||
<!-- Menu item to start a video call; verbs as "start" are probably superfluous in many translations -->
|
||||
<string name="start_video_call">Videollamada</string>
|
||||
<!-- the action "to answer" or to "accept" or to "pick up" a call. not: "the answer" -->
|
||||
<string name="answer_call">Contestar</string>
|
||||
<!-- the action "to decline" a call, not: "the decline" -->
|
||||
<string name="end_call">Rechazar</string>
|
||||
<!-- deprecated, use outgoing_audio_call or outgoing_video_call instead -->
|
||||
<string name="outgoing_call">Llamada saliente</string>
|
||||
<!-- Used in call bubbles, summaries, notifications -->
|
||||
<string name="audio_call">Llamada</string>
|
||||
<!-- Used in call bubbles, summaries, notifications -->
|
||||
<string name="video_call">Videollamada</string>
|
||||
<string name="call_initializing">Inicializando…</string>
|
||||
<string name="call_incoming">Llamada entrante</string>
|
||||
<string name="call_ringing">Sonando…</string>
|
||||
<string name="call_reconnecting">Reconectando…</string>
|
||||
<string name="call_ended">Finalizó la llamada</string>
|
||||
<string name="call_failed">La llamada falló</string>
|
||||
<!-- deprecated, use "Audio call" instead -->
|
||||
<string name="outgoing_audio_call">Llamada saliente</string>
|
||||
<!-- deprecated, use "Video call" instead -->
|
||||
<string name="outgoing_video_call">Videollamada saliente</string>
|
||||
<!-- deprecated, use incoming_audio_call or incoming_video_call instead -->
|
||||
<string name="incoming_call">Llamada entrante</string>
|
||||
<!-- deprecated, use "Audio call" instead -->
|
||||
<string name="incoming_audio_call">Llamada entrante</string>
|
||||
<!-- deprecated, use "Video call" instead -->
|
||||
<string name="incoming_video_call">Videollamada entrante</string>
|
||||
<string name="declined_call">Llamada rechazada</string>
|
||||
<string name="canceled_call">Llamada cancelada</string>
|
||||
<string name="missed_call">Llamada perdida</string>
|
||||
<!-- the first placeholder will be replaced by a date, the second placeholder by duration, example: "Thu, 08:12 pm, 2 minutes" -->
|
||||
<string name="call_date_and_duration">%1$s, %2$s</string>
|
||||
<string name="already_in_call">Ya estás en una llamada</string>
|
||||
|
||||
<!-- get confirmations -->
|
||||
<!-- confirmation for leaving groups or channels. If a subject is needed, "Are you sure you want to leave the chat?" would work as well -->
|
||||
@@ -445,12 +458,10 @@
|
||||
<string name="ask_remove_from_channel">¿Quita %1$s del canal?</string>
|
||||
<string name="open_url_confirmation">¿Quieres abrir este enlace?</string>
|
||||
|
||||
|
||||
<!-- contact list -->
|
||||
<string name="contacts_title">Contactos</string>
|
||||
<string name="contacts_type_email_above">Escriba la dirección de correo arriba</string>
|
||||
|
||||
|
||||
<!-- chatlist and chat view -->
|
||||
<plurals name="chat_archived">
|
||||
<item quantity="one">%d chat archivado</item>
|
||||
@@ -513,25 +524,14 @@
|
||||
<string name="send_file_to">Enviar \"%1$s\" a…</string>
|
||||
<!-- title shown above a list contacts where one should be selected (eg. when a webxdc attempts to send a message to a chat) -->
|
||||
<string name="send_message_to">Enviar mensaje a…</string>
|
||||
<string name="enable_realtime">Aplicaciones en tiempo real</string>
|
||||
<string name="enable_realtime_explain">Habilite las conexiones en tiempo real para las aplicaciones compartidas en los chats. Si esta opción está habilitada, los participantes del chat podrán descubrir su dirección IP cuando inicie una aplicación.</string>
|
||||
|
||||
<!-- map -->
|
||||
<string name="filter_map_on_time">Mostrar ubicaciones en el marco de tiempo</string>
|
||||
<string name="show_location_traces">Mostrar trazas</string>
|
||||
<string name="add_poi">Enviar punto de interés</string>
|
||||
|
||||
|
||||
<!-- punycode warning / labeled links -->
|
||||
<!-- placeholder is domain/hostname that should be trusted -->
|
||||
<string name="open_external_url_trust_domain">No preguntar nuevamente para %1$s</string>
|
||||
<string name="puny_code_warning_header">Enlace sospechoso detectado</string>
|
||||
<!-- placeholder contains the hostname converted to ascii -->
|
||||
<string name="puny_code_warning_question">¿Estás seguro de que quieres visitar %1$s?</string>
|
||||
<!-- this message is shown whenever a link with non-latin characters is clicked. first placeholder is original hostname with special chars, second placeholder is hostname encoded in ascii -->
|
||||
<string name="puny_code_warning_description">Siguió un enlace que podría estar tergiversando caracteres al usar caracteres de diferentes alfabetos con un aspecto similar. Seguir el enlace etiquetado %1$s conducirá a %2$s, que es normal para caracteres no latinos. Si no esperaba tales caracteres, este enlace podría ser dañino.</string>
|
||||
|
||||
|
||||
<!-- search -->
|
||||
<string name="search">Buscar</string>
|
||||
<string name="search_in_chat">Buscar en el chat</string>
|
||||
@@ -541,7 +541,6 @@
|
||||
<!-- Adjective, as in "Show Unread Messages" -->
|
||||
<string name="search_unread">No leído</string>
|
||||
|
||||
|
||||
<!-- create/edit groups, contact/group profile -->
|
||||
<string name="group_name">Nombre del grupo</string>
|
||||
<string name="group_avatar">Imagen del grupo</string>
|
||||
@@ -605,8 +604,6 @@
|
||||
<string name="incoming_messages">Mensajes entrantes</string>
|
||||
<!-- Headline for the "Outbox" eg. in the "Connectivity" view -->
|
||||
<string name="outgoing_messages">Mensajes salientes</string>
|
||||
<!-- deprecated -->
|
||||
<string name="storage_on_domain">Almacenamiento en %1$s</string>
|
||||
<string name="connectivity">Conectividad</string>
|
||||
<!-- Shown in the title bar if the app is "Not connected"; prefer short strings. -->
|
||||
<string name="connectivity_not_connected">Desconectado</string>
|
||||
@@ -624,11 +621,10 @@
|
||||
<!-- Used for describing resource usage, resulting string will be eg. "1.2 GiB of 3 GiB used" -->
|
||||
<string name="part_of_total_used">%1$s de %2$s usado</string>
|
||||
|
||||
|
||||
<!-- welcome and login -->
|
||||
<!-- Primary button on the welcome screen, allows to create an instant profile -->
|
||||
<string name="onboarding_create_instant_account">Crear perfil nuevo</string>
|
||||
<!-- Secondary button on the welcome screen, allows to "Add as Second Device", "Restore from Backup" -->
|
||||
<!-- Secondary button on the welcome screen, allows to "Add as Second Device", "Restore from Backup" -->
|
||||
<string name="onboarding_alternative_logins">Ya tengo un perfil</string>
|
||||
<!-- This is a button and a title, allowing to use existing, classic email, setting ports, passwords and so on -->
|
||||
<string name="manual_account_setup_option">Iniciar sesión con correo electrónico</string>
|
||||
@@ -655,7 +651,7 @@
|
||||
<string name="welcome_chat_over_email">Chat seguro y descentralizado</string>
|
||||
<string name="scan_invitation_code">Escanear código de invitación</string>
|
||||
<string name="login_title">Iniciar sesión</string>
|
||||
<string name="login_advanced_hint">Este inicio de sesión es para usuarios avanzados:\n\n• No utilice una cuenta que esté usando en otra app.\n\n• El servidor de correo electrónico clásico permite chats sin cifrado de extremo a extremo, los cuales están marcados por un icono de correo.</string>
|
||||
<string name="login_advanced_hint">Este inicio de sesión es para usuarios avanzados:\n\n• No utilice una cuenta que esté usando en otra app.\n\n• El servidor de correo electrónico clásico permite chats sin cifrado de extremo a extremo, los cuales están marcados por un icono de correo.</string>
|
||||
<string name="login_inbox">Bandeja de entrada</string>
|
||||
<string name="login_imap_login">Nombre de usuario IMAP</string>
|
||||
<string name="login_imap_server">Servidor IMAP</string>
|
||||
@@ -687,12 +683,16 @@
|
||||
<string name="add_transport">Añadir transporte</string>
|
||||
<string name="remove_transport">Eliminar transporte</string>
|
||||
<string name="edit_transport">Editar transporte</string>
|
||||
<string name="used_for_sending">Usado para enviar</string>
|
||||
<string name="hide_from_contacts">Ocultar de los contactos</string>
|
||||
<string name="hidden_from_contacts">Ocultado de los contactos</string>
|
||||
<!-- Hint for the list of relays -->
|
||||
<string name="transport_list_hint">Los mensajes se reciben en todos los relays.</string>
|
||||
<!-- shown if a QR code was scanned that can be used as a relay -->
|
||||
<string name="confirm_add_transport">¿Añadir este transporte?</string>
|
||||
<string name="invalid_transport_qr">El código QR escaneado no contiene un transporte válido.</string>
|
||||
<!-- placeholder will be replaced by a relay server name -->
|
||||
<string name="confirm_remove_transport">¿Eliminar el transporte \"%1$s\"?\nTus contactos solo podrán localizarte si previamente has contactado con ellos mediante otro transporte.\nEn caso de duda, quita el transporte más tarde.</string>
|
||||
|
||||
<string name="confirm_remove_or_hide_transport_x">¿Eliminar el relay \"%1$s\"?\n\nLos contactos que solo conocen este relay podrían no comunicarse contigo hasta que les envíes otro mensaje.\n\nEn caso de duda, es mejor ocultarlo que eliminarlo.</string>
|
||||
<string name="login_certificate_checks">Comprobaciones de certificados</string>
|
||||
<string name="login_error_mail">Por favor, introduzca una dirección de correo válida</string>
|
||||
<string name="login_error_server">Por favor, introduzca un servidor / dirección IP válido</string>
|
||||
@@ -730,13 +730,10 @@
|
||||
<string name="ask_send_files_to_chat">¿Enviar %1$d archivos a \"%2$s\"?</string>
|
||||
<string name="ask_send_files_to_selected_chats">¿Enviar %1$d archivo(s) a %2$d chats?</string>
|
||||
<string name="videos_sent_without_recoding">(Los videos se enviarán en su tamaño original. Para enviar videos como archivos más pequeños, adjúntelos por separado)</string>
|
||||
<string name="share_text_multiple_chats">¿Enviar este texto a %1$d chats?\n\n\"%2$s\"</string>
|
||||
<string name="share_text_multiple_chats">¿Enviar este texto a %1$d chats?\n\n\"%2$s\"</string>
|
||||
<string name="share_abort">Intercambio abortado debido a la falta de permisos.</string>
|
||||
|
||||
|
||||
<!-- preferences -->
|
||||
<string name="pref_using_custom">Usando valor personalizado: %s</string>
|
||||
<string name="pref_using_default">Usando valor por defecto: %s</string>
|
||||
<string name="pref_profile_info_headline">Información de perfil</string>
|
||||
<string name="pref_profile_photo">Foto de perfil</string>
|
||||
<string name="pref_blocked_contacts">Contactos bloqueados</string>
|
||||
@@ -745,10 +742,12 @@
|
||||
<string name="pref_your_name">Tu nombre</string>
|
||||
<!-- Label of the Bio/Signature/Status/Motto field -->
|
||||
<string name="pref_default_status_label">Texto de firma</string>
|
||||
<string name="chat_description">Descripción</string>
|
||||
<!-- Option name for changing behaviour of the "Enter key" to sending out a message directly (instead of adding new line). If in doubt, please refer to a similar option in other messengers. -->
|
||||
<string name="pref_enter_sends">Tecla Intro envía</string>
|
||||
<string name="pref_enter_sends_explain">La tecla Intro enviará tu mensaje</string>
|
||||
<string name="pref_outgoing_media_quality">Calidad de multimedia saliente</string>
|
||||
<string name="pref_outgoing_media_quality_hint">Para enviar imágenes con calidad original, adjúntalas como \"Archivo\". Esto consume muchos más datos tanto para ti como para los destinatarios.</string>
|
||||
<string name="pref_outgoing_balanced">Balanceada</string>
|
||||
<string name="pref_outgoing_worse">Peor calidad, tamaño pequeño</string>
|
||||
<string name="pref_vibrate">Vibrar</string>
|
||||
@@ -759,6 +758,10 @@
|
||||
<string name="pref_notifications">Notificaciones </string>
|
||||
<string name="pref_mention_notifications">Menciones</string>
|
||||
<string name="pref_mention_notifications_explain">En los grupos silenciados, notifica los mensajes dirigidos a ti, como respuestas o reacciones</string>
|
||||
<!-- Title for the "Calls" notification setting. This is a plural noun, not a verb. -->
|
||||
<string name="pref_calls">Llamadas</string>
|
||||
<!-- Details about what the "Calls" notification setting does -->
|
||||
<string name="pref_calls_explain">Mostrar la pantalla de llamada para las llamadas entrantes</string>
|
||||
<string name="pref_notifications_show">Mostrar</string>
|
||||
<string name="pref_notifications_priority">Prioridad</string>
|
||||
<string name="pref_notifications_explain">Habilitar las notificaciones del sistema para nuevos mensajes</string>
|
||||
@@ -768,8 +771,6 @@
|
||||
<string name="pref_sound">Sonido</string>
|
||||
<string name="pref_silent">Silencio</string>
|
||||
<string name="pref_privacy">Privacidad</string>
|
||||
<!-- deprecated, use pref_chats -->
|
||||
<string name="pref_chats_and_media">Chats y multimedia</string>
|
||||
<string name="pref_system_default">Predeterminado del sistema</string>
|
||||
<!-- Translators: as in "opposite of dark" -->
|
||||
<string name="pref_light_theme">Claro</string>
|
||||
@@ -806,11 +807,10 @@
|
||||
<string name="pref_background_btn_default">Usar imagen por defecto</string>
|
||||
<string name="pref_background_btn_gallery">Seleccionar de la galería</string>
|
||||
<string name="pref_imap_folder_warn_disable_defaults">Si deshabilita esta opción, asegúrese de que su servidor y sus otros clientes estén configurados en consecuencia.\n\nDe lo contrario, las cosas pueden no funcionar en absoluto.</string>
|
||||
<!-- No need to be literal here, you can also use "Use Multiple Devices", "Support Multiple Devices" or other fitting terms. However, it should fit to the wording or your language at https://delta.chat/help -->
|
||||
<!-- No need to be literal here, you can also use "Use Multiple Devices", "Support Multiple Devices" or other fitting terms. However, it should fit to the wording or your language at https://delta.chat/help -->
|
||||
<string name="pref_multidevice">Modo multidispositivo</string>
|
||||
<string name="pref_multidevice_explain">Sincroniza tus mensajes con tus otros dispositivos. Se activa automáticamente al añadir un segundo dispositivo</string>
|
||||
<string name="pref_multidevice_change_warn">El modo multidispositivo debe estar activado cuando usas el mismo perfil en varios dispositivos.
|
||||
Desactiva este ajuste solo si has eliminado este perfil de todos tus demás dispositivos.\n\nSi desactivas el modo multidispositivo mientras usas el perfil en varios dispositivos, se perderán mensajes y se producirán otros problemas.</string>
|
||||
<string name="pref_multidevice_change_warn">El modo multidispositivo debe estar activado cuando usas el mismo perfil en varios dispositivos. Desactiva este ajuste solo si has eliminado este perfil de todos tus demás dispositivos.\n\nSi desactivas el modo multidispositivo mientras usas el perfil en varios dispositivos, se perderán mensajes y se producirán otros problemas.</string>
|
||||
<string name="pref_auto_folder_moves">Mover automáticamente a la carpeta DeltaChat</string>
|
||||
<string name="pref_only_fetch_mvbox_title">Solo obtener de la carpeta DeltaChat</string>
|
||||
<string name="pref_show_emails">Mostrar correos clásicos</string>
|
||||
@@ -835,16 +835,12 @@ Desactiva este ajuste solo si has eliminado este perfil de todos tus demás disp
|
||||
<string name="n_bytes_message">Mensaje de %1$s</string>
|
||||
<!-- %1$s will be replaced by human-readable date and time -->
|
||||
<string name="download_max_available_until">Descarga disponible hasta %1$s</string>
|
||||
<!-- deprecated -->
|
||||
<string name="select_profile">Seleccionar perfil</string>
|
||||
<string name="profile_image_select">Seleccionar imagen de perfil</string>
|
||||
<string name="select_your_new_profile_image">Seleccionar tu nueva imagen de perfil</string>
|
||||
<string name="profile_image_delete">Borrar imagen de perfil</string>
|
||||
<string name="pref_show_tray_icon">Mostrar icono de bandeja</string>
|
||||
<string name="pref_edit_profile">Editar perfil</string>
|
||||
<string name="disable_imap_idle">Deshabilitar IMAP IDLE</string>
|
||||
<string name="disable_imap_idle_explain">No utilizar la extensión IMAP IDLE aunque el servidor la admita. Habilitar esta opción retrasará el recibo de mensajes, actívala solo para pruebas.</string>
|
||||
<string name="send_stats_to_devs">Enviar estadísticas a los desarrolladores de Delta Chat</string>
|
||||
<string name="send_stats_to_devs">Enviar estadísticas a los desarrolladores de Delta Chat</string>
|
||||
<string name="stats_device_message">¿Quieres ayudar a mejorar Delta Chat y apoyar la investigación enviando estadísticas de uso anónimas semanales?\n\n👉 Pulsa aquí… 👈</string>
|
||||
<string name="stats_confirmation_dialog">¿Quieres ayudar a mejorar Delta Chat y apoyar la investigación enviando estadísticas de uso anónimas semanales?</string>
|
||||
<string name="stats_thanks">¡Gracias! Siempre puedes desactivar el envío en \"Configuración -> Avanzado\".\n\n¿Tienes 5 minutos adicionales para participar en un estudio científico sobre la seguridad de Delta Chat?</string>
|
||||
@@ -882,9 +878,9 @@ Desactiva este ajuste solo si has eliminado este perfil de todos tus demás disp
|
||||
<!-- %1$d will be replaced by the number of messages, you can assume plural/lots here. %2$s will be replaced by a timespan option. -->
|
||||
<string name="autodel_device_ask">¿Desea borrar %1$d mensajes ahora y todos los mensajes recientemente alcanzados \"%2$s\" en el futuro?\n\n• Esto incluye toda la multimedia\n\n• Los mensajes serán eliminados siendo vistos o no\n\n• \"Mensajes guardados\" serán saltados de este proceso local</string>
|
||||
<!-- %1$d will be replaced by the number of messages, you can assume plural/lots here. %2$s will be replaced by a timespan option. -->
|
||||
<string name="autodel_server_ask">¿Deseas borrar %1$d mensajes ahora y todos los mensajes recibidos en \"%2$s\" al futuro?\n\n⚠️ Esto incluye correos, multimedia y \"Mensajes guardados\" en todas las carpetas del servidor. No uses esta función si quieres mantener tus datos en el servidor o si estas usando otros clientes de correo más allá de Delta Chat\n\n⚠️ No uses esta función si deseas mantener tus datos en el servidor\n\n⚠️ No uses esta función si estás usando otros clientes de correo más allá de Delta Chat</string>
|
||||
<string name="autodel_server_ask">¿Deseas borrar %1$d mensajes ahora y todos los mensajes recibidos en \"%2$s\" al futuro?\n\n⚠️ Esto incluye correos, multimedia y \"Mensajes guardados\" en todas las carpetas del servidor. No uses esta función si quieres mantener tus datos en el servidor o si estas usando otros clientes de correo más allá de Delta Chat\n\n⚠️ No uses esta función si deseas mantener tus datos en el servidor\n\n⚠️ No uses esta función si estás usando otros clientes de correo más allá de Delta Chat</string>
|
||||
<!-- shown below enabled autodel_server-option, should be a summary of autodel_server_ask and remind about the impact -->
|
||||
<string name="autodel_server_enabled_hint">Esto incluye correos, multimedia y \"Mensajes guardados\" en todas las carpetas del servidor. No uses esta función si quieres mantener tus datos en el servidor o si estas usando otros clientes de correo además de Delta Chat</string>
|
||||
<string name="autodel_server_enabled_hint">Esto incluye correos, multimedia y \"Mensajes guardados\" en todas las carpetas del servidor. No uses esta función si quieres mantener tus datos en el servidor o si estas usando otros clientes de correo además de Delta Chat</string>
|
||||
<string name="autodel_server_warn_multi_device_title">Activar la eliminación inmediata</string>
|
||||
<string name="autodel_server_warn_multi_device">Si habilita la eliminación inmediata, no podrá utilizar varios dispositivos en este perfil.</string>
|
||||
<string name="autodel_confirm">Comprendo, borrar todos estos mensajes</string>
|
||||
@@ -907,6 +903,9 @@ Desactiva este ajuste solo si has eliminado este perfil de todos tus demás disp
|
||||
<string name="group_image_changed_by_you">Cambiaste la imagen del grupo.</string>
|
||||
<!-- %1$s will be replaced by name of the contact who did the action -->
|
||||
<string name="group_image_changed_by_other">Imagen del grupo cambiada por %1$s.</string>
|
||||
<string name="chat_description_changed_by_you">Cambiaste la descripción del chat.</string>
|
||||
<!-- %1$s will be replaced by name of the contact who did the action -->
|
||||
<string name="chat_description_changed_by_other">Descripción del chat modificada por %1$s.</string>
|
||||
<!-- %1$s will be replaced by name of the contact added to the group -->
|
||||
<string name="member_x_added">Miembro %1$s añadido.</string>
|
||||
<!-- %1$s will be replaced by name of the contact added to the group -->
|
||||
@@ -939,10 +938,6 @@ Desactiva este ajuste solo si has eliminado este perfil de todos tus demás disp
|
||||
<string name="ephemeral_timer_seconds_by_you">Estableciste el temporizador de la desaparición de mensajes en %1$s segundos</string>
|
||||
<!-- %1$s will be replaced by the number of seconds (always >1) the timer is set to, %2$s will be replaced by name of the contact -->
|
||||
<string name="ephemeral_timer_seconds_by_other">Temporizador de la desaparición de mensajes establecido en %1$s segundos por %2$s.</string>
|
||||
<!-- deprecated, usage needs to be removed in core -->
|
||||
<string name="ephemeral_timer_1_minute_by_you">Estableciste el temporizador de la desaparición de mensajes en 1 minuto.</string>
|
||||
<!-- deprecated, usage needs to be removed in core -->
|
||||
<string name="ephemeral_timer_1_minute_by_other">Temporizador de la desaparición de mensajes establecido en 1 minuto por %1$s.</string>
|
||||
<string name="ephemeral_timer_1_hour_by_you">Estableciste el temporizador de la desaparición de mensajes en 1 hora.</string>
|
||||
<!-- %1$s will be replaced by name of the contact -->
|
||||
<string name="ephemeral_timer_1_hour_by_other">Temporizador de la desaparición de mensajes establecido en 1 hora por %1$s.</string>
|
||||
@@ -1039,14 +1034,12 @@ Desactiva este ajuste solo si has eliminado este perfil de todos tus demás disp
|
||||
<string name="verified_by">Verificado por %1$s</string>
|
||||
<string name="verified_by_you">Verificado por ti</string>
|
||||
<string name="verified_by_unknown">Introducido</string>
|
||||
<!-- deprecated -->
|
||||
<string name="verified_contact_required_explain">Para garantizar el cifrado de extremo a extremo, solo puedes añadir contactos con una marca de verificación verde</string>
|
||||
<string name="mailto_dialog_header_select_chat">Seleccione el chat para enviar el mensaje</string>
|
||||
<!-- first placeholder is the name of the chat -->
|
||||
<string name="confirm_replace_draft">%1$s ya tiene un mensaje borrador, ¿quieres reemplazarlo?</string>
|
||||
<string name="mailto_link_could_not_be_decoded">El enlace mailto no se pudo decodificar: %1$s</string>
|
||||
|
||||
<!-- notifications -->
|
||||
<!-- notifications -->
|
||||
<string name="notify_reply_button">Responder</string>
|
||||
<string name="notify_new_message">Nuevo mensaje</string>
|
||||
<string name="notify_background_connection_enabled">Conexión en segundo plano habilitada</string>
|
||||
@@ -1062,7 +1055,6 @@ Desactiva este ajuste solo si has eliminado este perfil de todos tus demás disp
|
||||
<string name="new_messages_body">Tienes mensajes nuevos</string>
|
||||
<string name="n_messages_in_m_chats">%1$d mensajes en %2$d chats</string>
|
||||
|
||||
|
||||
<!-- permissions -->
|
||||
<string name="perm_required_title">Permiso requerido</string>
|
||||
<string name="perm_continue">Continuar</string>
|
||||
@@ -1083,9 +1075,6 @@ Desactiva este ajuste solo si has eliminado este perfil de todos tus demás disp
|
||||
<string name="ImageEditorHud_flip">Voltear</string>
|
||||
<string name="ImageEditorHud_rotate">Rotar</string>
|
||||
|
||||
<!-- strings introduced on desktop. we want to share strings between the os, in general, please do not add generic strings here -->
|
||||
<string name="about_offical_app_desktop">Esta es la aplicación oficial de Delta Chat para escritorio.</string>
|
||||
<string name="about_licensed_under_desktop">Este programa está licenciado bajo GNU GPL versión 3 y el código está disponible en GitHub.</string>
|
||||
<string name="welcome_desktop">Bienvenido a Delta Chat</string>
|
||||
<string name="global_menu_preferences_language_desktop">Idioma</string>
|
||||
<string name="global_menu_file_desktop">Archivo</string>
|
||||
@@ -1125,6 +1114,7 @@ Desactiva este ajuste solo si has eliminado este perfil de todos tus demás disp
|
||||
<string name="menu.view.developer.open.log.folder">Abrir Carpeta de Logs</string>
|
||||
<string name="menu.view.developer.open.current.log.file">Abrir Archivo de Logs Actual</string>
|
||||
<string name="explain_desktop_minimized_disabled_tray_pref" tools:ignore="TypographyDashes">El icono de la bandeja no se puede desactivar ya que Delta Chat se inició con la opción --minimized.</string>
|
||||
<!-- deprecated, used on desktop although there is not spell checker -->
|
||||
<string name="no_spellcheck_suggestions_found">No se encontraron sugerencias ortográficas.</string>
|
||||
<string name="show_window">Mostrar ventana</string>
|
||||
|
||||
|
||||
@@ -17,10 +17,5 @@
|
||||
Únete al [Canal Oficial de ArcaneChat](%1$s) (en inglés) para noticias sobre el desarrollo
|
||||
de la aplicación.</string>
|
||||
|
||||
<string name="update_2_33">🔮 ¿Qué hay de nuevo?\n\n★ Soporte para Android 16\n\n★ Mejorado el diseño
|
||||
para hacer mejor uso del espacio en pantalla\n\n★ Añadido color a los enlaces en las
|
||||
burbujas del chat\n\n★ Más protección de metadatos de los mensajes\n\n★ Arreglado problema
|
||||
con fallos inesperados de la aplicación\n\n★ Varios otros arreglos y pequeñas
|
||||
mejoras\n\n\n💜 Dona para ayudarnos a mantener nuestra independencia y seguir mejorando:
|
||||
%1$s</string>
|
||||
<string name="update_2_46ac">🔮 ¿Qué hay de nuevo?\n\n✦ Llamadas de audio/video experimentales mejoradas con una mejor integración con el sistema\n\n✦ Se agregó un selector de stickers básico\n\n✦ Se mejoró el selector de archivos adjuntos\n\n✦ Se minimizó aún más los metadatos en los mensajes\n\n✦ Mayor resiliencia con el uso de múltiples relays: si un relay falla, los mensajes se siguen recibiendo en los demás\n\n✦ Mejor sincronización del estado de las notificaciones en varios dispositivos\n\n✦ Enlace de invitación corregido para unirse al 📢 [Canal oficial de ArcaneChat](%2$s) (en inglés)\n\n✦ Varias correcciones de errores y traducciones actualizadas\n\n\n💜 Por favor, dona para ayudarnos a mantenernos independientes y continuar brindando mejoras: %1$s</string>
|
||||
</resources>
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
<string name="off">Väljas</string>
|
||||
<string name="def">Vaikimisi</string>
|
||||
<string name="default_value">Vaikimisi (%1$s)</string>
|
||||
<string name="default_value_as_above">Vaikimisi (sama, kui ülal)</string>
|
||||
<string name="custom">Kohandatud</string>
|
||||
<string name="none">Puudub</string>
|
||||
<string name="automatic">Automaatne</string>
|
||||
@@ -34,8 +33,6 @@
|
||||
<string name="update">Uuenda</string>
|
||||
<string name="emoji">Emoji</string>
|
||||
<string name="attachment">Manus</string>
|
||||
<!-- the placeholder will be replaced by the name of the image or file to attach -->
|
||||
<string name="ask_attach">Kas lisame manusena: „%1$s“?</string>
|
||||
<string name="back">Tagasi</string>
|
||||
<string name="close">Sulge</string>
|
||||
<string name="close_window">Sulge aken</string>
|
||||
@@ -115,19 +112,16 @@
|
||||
<string name="last_month">Eelmisel kuul</string>
|
||||
<!-- Refers to the time a contact was last seen. Shown below contact name in the profile. The placeholder will be replaced by date or time, resulting in "Last seen at 12:13 AM" or "Last seen Nov 12" -->
|
||||
<string name="last_seen_at">Viimati nähtud: %1$s</string>
|
||||
<!-- Refers to the time a contact was last seen. Shown below contact name in the profile. The placeholder will be replaced by a relative point in time as "3 minutes ago" (see https://momentjs.com for more examples and languages)-->
|
||||
<!-- Refers to the time a contact was last seen. Shown below contact name in the profile. The placeholder will be replaced by a relative point in time as "3 minutes ago" (see https://momentjs.com for more examples and languages) -->
|
||||
<string name="last_seen_relative">Viimati nähtud: %1$s</string>
|
||||
<string name="last_seen_unknown">Viimati nähtud: pole teada</string>
|
||||
<!-- Shown in call duration. Avoid abbreviations, prefer full words ex. "N seconds". -->
|
||||
<plurals name="n_seconds_ext">
|
||||
<item quantity="one">%d sekund</item>
|
||||
<item quantity="other">%d sekundit</item>
|
||||
</plurals>
|
||||
<!-- Shown in call duration. Avoid abbreviations, prefer full words ex. "N minutes". -->
|
||||
<plurals name="n_minutes_ext">
|
||||
<item quantity="one">%d minut</item>
|
||||
<item quantity="other">%d minutit</item>
|
||||
<!-- Call duration as shown in the call bubbles. There is some risk to mix with the sending time, so the word "Duration" may be helpful. Might also be "Duration: %d minutes", "%d-minute duration", "%d-minute length" or "%d-minute call" -->
|
||||
<plurals name="call_duration_minutes">
|
||||
<item quantity="one">kestusega %d minut</item>
|
||||
<item quantity="other">kestusega %d minutit</item>
|
||||
</plurals>
|
||||
<!-- Call duration as shown in the call bubbles in case the call is less than one minute. If the context is not clear enough, one may want to add the word "Duration". -->
|
||||
<string name="call_duration_less_than_a_minute">alla ühe minuti</string>
|
||||
<!-- Shown beside messages that are "N minutes old". Prefer short strings, or well-known abbreviations. -->
|
||||
<plurals name="n_minutes">
|
||||
<item quantity="one">%d min</item>
|
||||
@@ -180,6 +174,9 @@
|
||||
<string name="add_to_sticker_collection">Lisa kleepsude kogumikku</string>
|
||||
<string name="add_stickers_instructions">Kleepsude lisamiseks klõpsi valikut „Ava kleepsude kaust“, loo oma kleepsupaki jaoks sinna alamkaust ning lohista pildi- ja kleepsufailid sinna</string>
|
||||
<string name="open_sticker_folder">Ava kleepsude kaust</string>
|
||||
<string name="ask_add_sticker_to_collection">Kas lisad selle kleepsu oma kogumikku?</string>
|
||||
<string name="ask_delete_sticker">Kas kustutad selle kleepsu?</string>
|
||||
<string name="sticker_picker_empty_hint">Klõpsa kleepsu lisamiseks siia.</string>
|
||||
<string name="images">Pildid</string>
|
||||
<!-- a noun, used for "Music" and other "Audio" files -->
|
||||
<string name="audio">Heli</string>
|
||||
@@ -259,10 +256,13 @@
|
||||
<string name="channels">Kanalid</string>
|
||||
<!-- consider keeping the term "channel" as in WhatsApp or Telegram -->
|
||||
<string name="new_channel">Uus kanal</string>
|
||||
<!-- deprecated -->
|
||||
<string name="add_recipients">Lisa saajaid</string>
|
||||
<!-- consider keeping the term "channel" as in WhatsApp or Telegram -->
|
||||
<string name="channel_name">Kanali nimi</string>
|
||||
<!-- The number of times a message is shown in channels. Use what other messengers are using here, smth. as "N-times seen" or "1 Aufruf" (german) work as well, where "1 impression" or "1 hit" may sound too formal and may be more marketing slang. -->
|
||||
<plurals name="n_views">
|
||||
<item quantity="one">Nähtud %d kord</item>
|
||||
<item quantity="other">Nähtud %d korda</item>
|
||||
</plurals>
|
||||
<string name="email">E-post</string>
|
||||
<!-- "New" as in "Create New Email"; shown together with "New Group" and "New Channel" -->
|
||||
<string name="new_email">Uus e-kiri</string>
|
||||
@@ -278,6 +278,7 @@
|
||||
<string name="menu_add_attachment">Lisa manus</string>
|
||||
<string name="menu_leave_group">Lahku grupist</string>
|
||||
<string name="menu_leave_channel">Lahku kanalist</string>
|
||||
<string name="menu_leave_and_delete">Lahku ja kustuta minu jaoks</string>
|
||||
<string name="menu_delete_chat">Kustuta vestlus</string>
|
||||
<!-- Command to delete all messages in a chat. The chat itself will not be deleted but will be empty afterwards, so make sure to be different from "Delete Chat" here. "Clear" is a verb here, "Empty Chat" would also be fine (eg. in German "Chat leeren") -->
|
||||
<string name="clear_chat">Eemalda vestluse sisu</string>
|
||||
@@ -339,8 +340,6 @@
|
||||
<string name="menu_more_options">Täiendavad valikud</string>
|
||||
<string name="menu_learn_spelling">Õpi õigekirja</string>
|
||||
<string name="jump_to_message">Mine sõnumi juurde</string>
|
||||
<string name="jump_to_original_message">Mine algse sõnumi juurde</string>
|
||||
<string name="copy_json">Kopeeri JSON-vormingus</string>
|
||||
<string name="replace_draft">Asenda kavand</string>
|
||||
<string name="title_share_location">Jaga asukohta kõikide grupi liikmetega</string>
|
||||
<string name="device_talk">Seadme sõnumid</string>
|
||||
@@ -384,26 +383,29 @@
|
||||
|
||||
<!-- the action "to call someone", used as a tooltip for the "phone" icon. not: "the call" -->
|
||||
<string name="start_call">Helista</string>
|
||||
<!-- Menu item to start an audio call; verbs as "start" are probably superfluous in many translations -->
|
||||
<string name="start_audio_call">Häälkõne</string>
|
||||
<!-- Menu item to start a video call; verbs as "start" are probably superfluous in many translations -->
|
||||
<string name="start_video_call">Videokõne</string>
|
||||
<!-- the action "to answer" or to "accept" or to "pick up" a call. not: "the answer" -->
|
||||
<string name="answer_call">Vasta</string>
|
||||
<!-- the action "to decline" a call, not: "the decline" -->
|
||||
<string name="end_call">Keeldu</string>
|
||||
<!-- deprecated, use outgoing_audio_call or outgoing_video_call instead -->
|
||||
<string name="outgoing_call">Väljuv kõne</string>
|
||||
<!-- Used in call bubbles, summaries, notifications -->
|
||||
<string name="audio_call">Häälkõne</string>
|
||||
<!-- Used in call bubbles, summaries, notifications -->
|
||||
<string name="video_call">Videokõne</string>
|
||||
<!-- deprecated, use "Audio call" instead -->
|
||||
<string name="outgoing_audio_call">Väljuv häälkõne</string>
|
||||
<!-- deprecated, use "Video call" instead -->
|
||||
<string name="outgoing_video_call">Väljuv videokõne</string>
|
||||
<!-- deprecated, use incoming_audio_call or incoming_video_call instead -->
|
||||
<string name="incoming_call">Saabuv kõne</string>
|
||||
<!-- deprecated, use "Audio call" instead -->
|
||||
<string name="incoming_audio_call">Saabuv häälkõne</string>
|
||||
<!-- deprecated, use "Video call" instead -->
|
||||
<string name="incoming_video_call">Saabuv videokõne</string>
|
||||
<string name="declined_call">Keeldutud kõne</string>
|
||||
<string name="canceled_call">katkestatud kõne</string>
|
||||
<string name="missed_call">Märkamata kõne</string>
|
||||
<!-- the first placeholder will be replaced by a date, the second placeholder by duration, example: "Thu, 08:12 pm, 2 minutes" -->
|
||||
<string name="call_date_and_duration">%1$s, %2$s</string>
|
||||
|
||||
<!-- get confirmations -->
|
||||
<!-- confirmation for leaving groups or channels. If a subject is needed, "Are you sure you want to leave the chat?" would work as well -->
|
||||
<string name="ask_leave_group">Kas oled kindel, et soovid lahkuda?</string>
|
||||
@@ -431,12 +433,10 @@
|
||||
<string name="ask_remove_from_channel">Kas eemaldad järgnevad kasutajad kanalilt: %1$s?</string>
|
||||
<string name="open_url_confirmation">Kas sa soovid selle lingi avada?</string>
|
||||
|
||||
|
||||
<!-- contact list -->
|
||||
<string name="contacts_title">Kontaktid</string>
|
||||
<string name="contacts_type_email_above">Palun sisesta ülale e-posti aadress</string>
|
||||
|
||||
|
||||
<!-- chatlist and chat view -->
|
||||
<plurals name="chat_archived">
|
||||
<item quantity="one">%d vestlus on arhiveeritud</item>
|
||||
@@ -496,25 +496,14 @@
|
||||
<string name="send_file_to">Saada „%1$s“ fail kasutajale…</string>
|
||||
<!-- title shown above a list contacts where one should be selected (eg. when a webxdc attempts to send a message to a chat) -->
|
||||
<string name="send_message_to">Saada sõnum…</string>
|
||||
<string name="enable_realtime">Reaalajas toimivad rakendused</string>
|
||||
<string name="enable_realtime_explain">Vestlustega seotud rakendused võivad kasutada reaalajas ühendusi. Kui valik on kasutusel, siis vestluste osapooltel on võimalik peale rakenduse käivitamist tuvastada sinu IP-aadress.</string>
|
||||
|
||||
<!-- map -->
|
||||
<string name="filter_map_on_time">Näita asukohti ajavahemike kaupa</string>
|
||||
<string name="show_location_traces">Näita asukohti kaardil</string>
|
||||
<string name="add_poi">Saada huvipunkti teave</string>
|
||||
|
||||
|
||||
<!-- punycode warning / labeled links -->
|
||||
<!-- placeholder is domain/hostname that should be trusted -->
|
||||
<string name="open_external_url_trust_domain">Ära enam %1$s puhul küsi</string>
|
||||
<string name="puny_code_warning_header">Tuvastasin kahtlase lingi</string>
|
||||
<!-- placeholder contains the hostname converted to ascii -->
|
||||
<string name="puny_code_warning_question">Kas oled kindel, et soovid avada „%1$s“?</string>
|
||||
<!-- this message is shown whenever a link with non-latin characters is clicked. first placeholder is original hostname with special chars, second placeholder is hostname encoded in ascii -->
|
||||
<string name="puny_code_warning_description">Selles lingis võivad olla petlikult sarnased tähed teistest tähestikest. Kui klõpsad linki „%1$s“, siis tegelikult avaneb „%2$s“. Kui sa midagi sellist ei eeldanud, siis võib olla tegemist ohtliku lingiga.</string>
|
||||
|
||||
|
||||
<!-- search -->
|
||||
<string name="search">Otsi</string>
|
||||
<string name="search_in_chat">Otsi vestlusest</string>
|
||||
@@ -524,7 +513,6 @@
|
||||
<!-- Adjective, as in "Show Unread Messages" -->
|
||||
<string name="search_unread">Lugemata</string>
|
||||
|
||||
|
||||
<!-- create/edit groups, contact/group profile -->
|
||||
<string name="group_name">Grupi nimi</string>
|
||||
<string name="group_avatar">Grupi tunnuspilt</string>
|
||||
@@ -588,8 +576,6 @@
|
||||
<string name="incoming_messages">Saabuvad sõnumid</string>
|
||||
<!-- Headline for the "Outbox" eg. in the "Connectivity" view -->
|
||||
<string name="outgoing_messages">Väljuvad sõnumid</string>
|
||||
<!-- deprecated -->
|
||||
<string name="storage_on_domain">Andmeruum domeenis %1$s</string>
|
||||
<string name="connectivity">Ühenduvus</string>
|
||||
<!-- Shown in the title bar if the app is "Not connected"; prefer short strings. -->
|
||||
<string name="connectivity_not_connected">Pole ühendatud</string>
|
||||
@@ -607,11 +593,10 @@
|
||||
<!-- Used for describing resource usage, resulting string will be eg. "1.2 GiB of 3 GiB used" -->
|
||||
<string name="part_of_total_used">Kasutusel %1$s / %2$s</string>
|
||||
|
||||
|
||||
<!-- welcome and login -->
|
||||
<!-- Primary button on the welcome screen, allows to create an instant profile -->
|
||||
<string name="onboarding_create_instant_account">Loo uus profiil</string>
|
||||
<!-- Secondary button on the welcome screen, allows to "Add as Second Device", "Restore from Backup" -->
|
||||
<!-- Secondary button on the welcome screen, allows to "Add as Second Device", "Restore from Backup" -->
|
||||
<string name="onboarding_alternative_logins">Mul juba on profiil olemas</string>
|
||||
<!-- This is a button and a title, allowing to use existing, classic email, setting ports, passwords and so on -->
|
||||
<string name="manual_account_setup_option">Klassikaline e-post alusühendusena</string>
|
||||
@@ -638,7 +623,7 @@
|
||||
<string name="welcome_chat_over_email">Turvaline hajutatud vestluslahendus</string>
|
||||
<string name="scan_invitation_code">Skaneeri kutsekoodi</string>
|
||||
<string name="login_title">Logi sisse</string>
|
||||
<string name="login_advanced_hint">See sisselogimine sobib oskuskasutajatele:\n\n• Ära kasuta kontot, mis juba on kasutusel mõnes muus rakenduses.\n\n• Klassikaline e-posti server võimaldab vestlemist vaid ilma läbiva krüptimiseta ja seda märgistab kirja ikoon.</string>
|
||||
<string name="login_advanced_hint">See sisselogimine sobib oskuskasutajatele:\n\n• Ära kasuta kontot, mis juba on kasutusel mõnes muus rakenduses.\n\n• Klassikaline e-posti server võimaldab vestlemist vaid ilma läbiva krüptimiseta ja seda märgistab kirja ikoon.</string>
|
||||
<string name="login_inbox">Saabuvad kirjad</string>
|
||||
<string name="login_imap_login">IMAP-i kasutajanimi</string>
|
||||
<string name="login_imap_server">IMAP-i server</string>
|
||||
@@ -673,9 +658,6 @@
|
||||
<!-- shown if a QR code was scanned that can be used as a relay -->
|
||||
<string name="confirm_add_transport">Kas lisad selle alusühenduse?</string>
|
||||
<string name="invalid_transport_qr">Skaneeritud QR-koodis pole korrektset alusühendust</string>
|
||||
<!-- placeholder will be replaced by a relay server name -->
|
||||
<string name="confirm_remove_transport">Kas eemaldad „%1$s“ alusühenduse?\n\nSinu kontaktid saavad sind kätte vaid siis, kui oled selleks kasutanud mõnda muud alusühendust.\n\nKui kahtled, siis eemalda alusühendus hiljem.</string>
|
||||
|
||||
<string name="login_certificate_checks">Sertifikaadikontrollid</string>
|
||||
<string name="login_error_mail">Palun sisesta korrektne e-posti aadress</string>
|
||||
<string name="login_error_server">Palun sisesta korrektne serveri täisnimi või ip-aadress</string>
|
||||
@@ -716,10 +698,7 @@
|
||||
<string name="share_text_multiple_chats">Kas saadad selle teksti %1$d vestlusesse?\n\n„%2$s“</string>
|
||||
<string name="share_abort">Puuduvate õiguste tõttu on jagamine katkestatud.</string>
|
||||
|
||||
|
||||
<!-- preferences -->
|
||||
<string name="pref_using_custom">Kasutan kohandatud väärtust: %s</string>
|
||||
<string name="pref_using_default">Kasutan vaikimisi väärtust: %s</string>
|
||||
<string name="pref_profile_info_headline">Sinu profiil</string>
|
||||
<string name="pref_profile_photo">Profiilipilt</string>
|
||||
<string name="pref_blocked_contacts">Blokeeritud kontaktid</string>
|
||||
@@ -733,6 +712,7 @@
|
||||
<string name="pref_enter_sends">Sisestusklahv saadab sõnumi</string>
|
||||
<string name="pref_enter_sends_explain">Sisestusklahvi vajutamisega saadad sõnumi ära</string>
|
||||
<string name="pref_outgoing_media_quality">Saadetava meediumi kvaliteet</string>
|
||||
<string name="pref_outgoing_media_quality_hint">Saatmaks algse kvaliteediga, palun vali manuse tüübiks „Fail“ ning arvesta, et nii sinu kui saaja puhul kasutatakse suuremat andmemahtu.</string>
|
||||
<string name="pref_outgoing_balanced">Tasakaalustatud</string>
|
||||
<string name="pref_outgoing_worse">Kõige kehvem kvaliteet, aga väikseim maht</string>
|
||||
<string name="pref_vibrate">Väristamine</string>
|
||||
@@ -743,6 +723,10 @@
|
||||
<string name="pref_notifications">Teavitused</string>
|
||||
<string name="pref_mention_notifications">Mainimised</string>
|
||||
<string name="pref_mention_notifications_explain">Summutatud gruppides teavita sinule suunatud sõnumitest, milleks võivad olla vastused või reageerimised</string>
|
||||
<!-- Title for the "Calls" notification setting. This is a plural noun, not a verb. -->
|
||||
<string name="pref_calls">Kõned</string>
|
||||
<!-- Details about what the "Calls" notification setting does -->
|
||||
<string name="pref_calls_explain">Saabuvate kõnede puhul näita kõvaadet</string>
|
||||
<string name="pref_notifications_show">Näita</string>
|
||||
<string name="pref_notifications_priority">Prioriteet</string>
|
||||
<string name="pref_notifications_explain">Kasuta uute sõnumite puhul süsteemi teavitusi</string>
|
||||
@@ -752,8 +736,6 @@
|
||||
<string name="pref_sound">Heli</string>
|
||||
<string name="pref_silent">Vaikne</string>
|
||||
<string name="pref_privacy">Privaatsus</string>
|
||||
<!-- deprecated, use pref_chats -->
|
||||
<string name="pref_chats_and_media">Vestlused ja meediumid</string>
|
||||
<string name="pref_system_default">Süsteemi vaikimisi valik</string>
|
||||
<!-- Translators: as in "opposite of dark" -->
|
||||
<string name="pref_light_theme">Hele kujundus</string>
|
||||
@@ -790,7 +772,7 @@
|
||||
<string name="pref_background_btn_default">Kasuta vaikimisi pilti</string>
|
||||
<string name="pref_background_btn_gallery">Vali galeriist</string>
|
||||
<string name="pref_imap_folder_warn_disable_defaults">Kui sa seda eelistust muudad, siis palun kontrolli, et server ja muud kliendid on vastavalt seadistatud.\n\nVastasel juhul võib minna nii, et mitte miski ei toimi.</string>
|
||||
<!-- No need to be literal here, you can also use "Use Multiple Devices", "Support Multiple Devices" or other fitting terms. However, it should fit to the wording or your language at https://delta.chat/help -->
|
||||
<!-- No need to be literal here, you can also use "Use Multiple Devices", "Support Multiple Devices" or other fitting terms. However, it should fit to the wording or your language at https://delta.chat/help -->
|
||||
<string name="pref_multidevice">Mitme seadme tugi</string>
|
||||
<string name="pref_multidevice_explain">Sünkrooni oma sõnumid oma muude seadmetega. Teise seadme lisamisel lülitatakse automaatselt sisse.</string>
|
||||
<string name="pref_multidevice_change_warn">Kui kasutad sama profiili mitmes seadmes, siis peab mitme seadme režiimi sisse lülitama. Lülita see seadistus välja vaid siis, kui oled selle profiili eemaldanud kõikidest muudest oma seadmetest.\n\nKui aga lülitad välja siis, kui profiil on kasutusel mitmes seadmes, on tulemuseks kadunud sõnumid ja muud imelikud juhtumised.</string>
|
||||
@@ -818,15 +800,11 @@
|
||||
<string name="n_bytes_message">Sõnum suurusega %1$s</string>
|
||||
<!-- %1$s will be replaced by human-readable date and time -->
|
||||
<string name="download_max_available_until">Allalaadimise ülempiir on saadaval kuni %1$s</string>
|
||||
<!-- deprecated -->
|
||||
<string name="select_profile">Vali profiil</string>
|
||||
<string name="profile_image_select">Vali profiilipilt</string>
|
||||
<string name="select_your_new_profile_image">Vali oma uus profiilipilt</string>
|
||||
<string name="profile_image_delete">Kustuta profiilipilt</string>
|
||||
<string name="pref_show_tray_icon">Näita süsteemisalve ikooni</string>
|
||||
<string name="pref_edit_profile">Muuda profiili</string>
|
||||
<string name="disable_imap_idle">Lülita IMAP IDLE välja</string>
|
||||
<string name="disable_imap_idle_explain">Ära kasuta IMAP IDLE meetodit, seda isegi siis, kui server seda toetab. Sisselülitamisel tekib sõnumite laadimisel viivitusi. Kasuta seda vaid testimiseks.</string>
|
||||
<string name="send_stats_to_devs">Saada statistikat Delta Chati kasutajatele</string>
|
||||
<string name="stats_device_message">Kas sa tahad aidata Delta Chati paremaks muuta? Siis luba rakendusel kord nädalas saata anonüümset statistikat kasutuse kohta.\n\n👉 Klõpsa siia… 👈</string>
|
||||
<string name="stats_confirmation_dialog">Kas sa tahad aidata Delta Chati paremaks muuta? Siis luba rakendusel kord nädalas saata anonüümset statistikat kasutuse kohta.</string>
|
||||
@@ -925,10 +903,6 @@
|
||||
<string name="ephemeral_timer_seconds_by_you">Sa määrasid isekustuvate sõnumite kehtivuseks %1$s sekundit.</string>
|
||||
<!-- %1$s will be replaced by the number of seconds (always >1) the timer is set to, %2$s will be replaced by name of the contact -->
|
||||
<string name="ephemeral_timer_seconds_by_other">%2$s määras isekustuvate sõnumite kehtivuseks %1$s sekundit.</string>
|
||||
<!-- deprecated, usage needs to be removed in core -->
|
||||
<string name="ephemeral_timer_1_minute_by_you">Sa määrasid isekustuvate sõnumite kehtivuseks 1 minuti.</string>
|
||||
<!-- deprecated, usage needs to be removed in core -->
|
||||
<string name="ephemeral_timer_1_minute_by_other">%1$s määras isekustuvate sõnumite kehtivuseks 1 minuti.</string>
|
||||
<string name="ephemeral_timer_1_hour_by_you">Sa määrasid isekustuvate sõnumite kehtivuseks 1 tunni.</string>
|
||||
<!-- %1$s will be replaced by name of the contact -->
|
||||
<string name="ephemeral_timer_1_hour_by_other">%1$s määras isekustuvate sõnumite kehtivuseks 1 tunni.</string>
|
||||
@@ -1025,14 +999,12 @@
|
||||
<string name="verified_by">%1$s lisas kontakti vestlusesse</string>
|
||||
<string name="verified_by_you">Mina lisasin kontakti vestlusesse</string>
|
||||
<string name="verified_by_unknown">Vestlusesse lisatud</string>
|
||||
<!-- deprecated -->
|
||||
<string name="verified_contact_required_explain">Selleks, et läbiv krüptimine toimiks garanteeritult, sa võid sellesse vestlusesse lisada vaid rohelise linnukesega kontakte.\n\nParim viis on omavahel kohtuda ning teise osapoole QR-koodi skaneerimisega lisada ta vestlusesse.</string>
|
||||
<string name="mailto_dialog_header_select_chat">Vali vestlus, kuhu soovid sõnumi saata</string>
|
||||
<!-- first placeholder is the name of the chat -->
|
||||
<string name="confirm_replace_draft">Vestluses „%1$s“ juba on üks sõnumi kavand, kas sa soovid selle asendada?</string>
|
||||
<string name="mailto_link_could_not_be_decoded">mailto lingi dekodeerimine ei õnnestunud: %1$s</string>
|
||||
|
||||
<!-- notifications -->
|
||||
<!-- notifications -->
|
||||
<string name="notify_reply_button">Vasta</string>
|
||||
<string name="notify_new_message">Uus sõnum</string>
|
||||
<string name="notify_background_connection_enabled">Taustal toimiv ühendus on kasutusel</string>
|
||||
@@ -1048,7 +1020,6 @@
|
||||
<string name="new_messages_body">Sulle on uusi sõnumeid</string>
|
||||
<string name="n_messages_in_m_chats">%1$d sõnumit %2$d-s vestluses</string>
|
||||
|
||||
|
||||
<!-- permissions -->
|
||||
<string name="perm_required_title">Õigused on vajalikud</string>
|
||||
<string name="perm_continue">Jätka</string>
|
||||
@@ -1069,9 +1040,6 @@
|
||||
<string name="ImageEditorHud_flip">Pööra teistpidi</string>
|
||||
<string name="ImageEditorHud_rotate">Pööra</string>
|
||||
|
||||
<!-- strings introduced on desktop. we want to share strings between the os, in general, please do not add generic strings here -->
|
||||
<string name="about_offical_app_desktop">See on Delta Chati ametlik töölauarakendus.</string>
|
||||
<string name="about_licensed_under_desktop">See tarkvara on litsentseeritud GNU GPL versiooni 3 alusel ning rakenduse lähtekood on saadaval GitHubis.</string>
|
||||
<string name="welcome_desktop">Tere tulemast, see on Delta Chat</string>
|
||||
<string name="global_menu_preferences_language_desktop">Keel</string>
|
||||
<string name="global_menu_file_desktop">Fail</string>
|
||||
@@ -1111,6 +1079,7 @@
|
||||
<string name="menu.view.developer.open.log.folder">Ava logifailide kaust</string>
|
||||
<string name="menu.view.developer.open.current.log.file">Ava praegune logifail</string>
|
||||
<string name="explain_desktop_minimized_disabled_tray_pref" tools:ignore="TypographyDashes">Kuna Delta Chat juba käivitati --minimized argumendiga, siis süsteemisalve ikooni ei saa välja lülitada.</string>
|
||||
<!-- deprecated, used on desktop although there is not spell checker -->
|
||||
<string name="no_spellcheck_suggestions_found">Õigekirjasoovitusi ei leidu.</string>
|
||||
<string name="show_window">Näita akent</string>
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user