Merge tag '2.8.9' into develop

This commit is contained in:
genofire 2020-07-18 13:38:12 +02:00
commit 1b28ea9dda
75 changed files with 643 additions and 409 deletions

View File

@ -11,7 +11,7 @@ android:
- '.+' - '.+'
before_script: before_script:
- mkdir libs - mkdir libs
- wget -O libs/libwebrtc-m83.aar http://gultsch.de/files/libwebrtc-m83.aar - wget -O libs/libwebrtc-m84.aar http://gultsch.de/files/libwebrtc-m84.aar
script: script:
- ./gradlew assembleConversationsFreeSystemRelease - ./gradlew assembleConversationsFreeSystemRelease
- ./gradlew assembleQuicksyFreeCompatRelease - ./gradlew assembleQuicksyFreeCompatRelease

View File

@ -1,6 +1,13 @@
# Changelog # Changelog
### Version 2.8.9
* add 'Return to chat' to audio call screen
* Improve keyboard shortcuts
* bug fixes
### Version 2.8.8 ### Version 2.8.8
* Fixed notifications not showing up under certain conditions * Fixed notifications not showing up under certain conditions
* Fixed compatibility issues and crashes related to A/V calls * Fixed compatibility issues and crashes related to A/V calls
@ -33,7 +40,7 @@
### Version 2.8.2 ### Version 2.8.2
* Add button to switch camea during video call * Add button to switch camera during video call
* Fixed voice calls on tablets * Fixed voice calls on tablets
### Version 2.8.1 ### Version 2.8.1

View File

@ -96,8 +96,8 @@ android {
defaultConfig { defaultConfig {
minSdkVersion 16 minSdkVersion 16
targetSdkVersion 25 targetSdkVersion 25
versionCode 394 versionCode 395
versionName "2.8.8" versionName "2.8.9"
archivesBaseName += "-$versionName" archivesBaseName += "-$versionName"
applicationId "eu.sum7.conversations" applicationId "eu.sum7.conversations"
resValue "string", "applicationId", applicationId resValue "string", "applicationId", applicationId
@ -232,7 +232,7 @@ android {
} }
lintOptions { lintOptions {
disable 'ExtraTranslation', 'MissingTranslation', 'InvalidPackage', 'MissingQuantity', 'AppCompatResource' disable 'MissingTranslation', 'InvalidPackage', 'AppCompatResource'
abortOnError false abortOnError false
} }

View File

@ -1,3 +1,3 @@
* Show help button if A/V call fails Show help button if A/V call fails
* Fixed some annoying crashes Fixed some annoying crashes
* Fixed Jingle connections (file transfer + calls) with bare JIDs Fixed Jingle connections (file transfer + calls) with bare JIDs

View File

@ -0,0 +1,3 @@
• add 'Return to chat' to audio call screen
• Improve keyboard shortcuts
• bug fixes

View File

@ -1,5 +1,6 @@
package eu.siacs.conversations.services; package eu.siacs.conversations.services;
import android.app.Notification;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.app.Service; import android.app.Service;
@ -10,9 +11,21 @@ import android.database.sqlite.SQLiteDatabase;
import android.net.Uri; import android.net.Uri;
import android.os.Binder; import android.os.Binder;
import android.os.IBinder; import android.os.IBinder;
import android.provider.OpenableColumns;
import android.support.v4.app.NotificationCompat; import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationManagerCompat;
import android.util.Log; import android.util.Log;
import com.google.common.base.Charsets;
import com.google.common.io.CountingInputStream;
import org.bouncycastle.crypto.engines.AESEngine;
import org.bouncycastle.crypto.io.CipherInputStream;
import org.bouncycastle.crypto.modes.AEADBlockCipher;
import org.bouncycastle.crypto.modes.GCMBlockCipher;
import org.bouncycastle.crypto.params.AEADParameters;
import org.bouncycastle.crypto.params.KeyParameter;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.File; import java.io.File;
@ -33,10 +46,6 @@ import java.util.zip.GZIPInputStream;
import java.util.zip.ZipException; import java.util.zip.ZipException;
import javax.crypto.BadPaddingException; import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import eu.siacs.conversations.Config; import eu.siacs.conversations.Config;
import eu.siacs.conversations.R; import eu.siacs.conversations.R;
@ -44,14 +53,9 @@ import eu.siacs.conversations.persistance.DatabaseBackend;
import eu.siacs.conversations.persistance.FileBackend; import eu.siacs.conversations.persistance.FileBackend;
import eu.siacs.conversations.ui.ManageAccountActivity; import eu.siacs.conversations.ui.ManageAccountActivity;
import eu.siacs.conversations.utils.BackupFileHeader; import eu.siacs.conversations.utils.BackupFileHeader;
import eu.siacs.conversations.utils.Compatibility;
import eu.siacs.conversations.utils.SerialSingleThreadExecutor; import eu.siacs.conversations.utils.SerialSingleThreadExecutor;
import eu.siacs.conversations.xmpp.Jid; import eu.siacs.conversations.xmpp.Jid;
import static eu.siacs.conversations.services.ExportBackupService.CIPHERMODE;
import static eu.siacs.conversations.services.ExportBackupService.KEYTYPE;
import static eu.siacs.conversations.services.ExportBackupService.PROVIDER;
public class ImportBackupService extends Service { public class ImportBackupService extends Service {
private static final int NOTIFICATION_ID = 21; private static final int NOTIFICATION_ID = 21;
@ -117,9 +121,9 @@ public class ImportBackupService extends Service {
return running.get(); return running.get();
} }
public void loadBackupFiles(OnBackupFilesLoaded onBackupFilesLoaded) { public void loadBackupFiles(final OnBackupFilesLoaded onBackupFilesLoaded) {
executor.execute(() -> { executor.execute(() -> {
List<Jid> accounts = mDatabaseBackend.getAccountJids(false); final List<Jid> accounts = mDatabaseBackend.getAccountJids(false);
final ArrayList<BackupFile> backupFiles = new ArrayList<>(); final ArrayList<BackupFile> backupFiles = new ArrayList<>();
final Set<String> apps = new HashSet<>(Arrays.asList("Conversations", "Quicksy", getString(R.string.app_name))); final Set<String> apps = new HashSet<>(Arrays.asList("Conversations", "Quicksy", getString(R.string.app_name)));
for (String app : apps) { for (String app : apps) {
@ -128,7 +132,12 @@ public class ImportBackupService extends Service {
Log.d(Config.LOGTAG, "directory not found: " + directory.getAbsolutePath()); Log.d(Config.LOGTAG, "directory not found: " + directory.getAbsolutePath());
continue; continue;
} }
for (File file : directory.listFiles()) { final File[] files = directory.listFiles();
if (files == null) {
onBackupFilesLoaded.onBackupFilesLoaded(backupFiles);
return;
}
for (final File file : files) {
if (file.isFile() && file.getName().endsWith(".ceb")) { if (file.isFile() && file.getName().endsWith(".ceb")) {
try { try {
final BackupFile backupFile = BackupFile.read(file); final BackupFile backupFile = BackupFile.read(file);
@ -149,24 +158,67 @@ public class ImportBackupService extends Service {
} }
private void startForegroundService() { private void startForegroundService() {
startForeground(NOTIFICATION_ID, createImportBackupNotification(1, 0));
}
private void updateImportBackupNotification(final long total, final long current) {
final int max;
final int progress;
if (total == 0) {
max = 1;
progress = 0;
} else {
max = 100;
progress = (int) (current * 100 / total);
}
final NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
try {
notificationManager.notify(NOTIFICATION_ID, createImportBackupNotification(max, progress));
} catch (final RuntimeException e) {
Log.d(Config.LOGTAG, "unable to make notification", e);
}
}
private Notification createImportBackupNotification(final int max, final int progress) {
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(getBaseContext(), "backup"); NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(getBaseContext(), "backup");
mBuilder.setContentTitle(getString(R.string.restoring_backup)) mBuilder.setContentTitle(getString(R.string.restoring_backup))
.setSmallIcon(R.drawable.ic_unarchive_white_24dp) .setSmallIcon(R.drawable.ic_unarchive_white_24dp)
.setProgress(1, 0, true); .setProgress(max, progress, max == 1 && progress == 0);
startForeground(NOTIFICATION_ID, mBuilder.build()); return mBuilder.build();
} }
private boolean importBackup(Uri uri, String password) { private boolean importBackup(final Uri uri, final String password) {
Log.d(Config.LOGTAG, "importing backup from " + uri); Log.d(Config.LOGTAG, "importing backup from " + uri);
try { try {
SQLiteDatabase db = mDatabaseBackend.getWritableDatabase(); final SQLiteDatabase db = mDatabaseBackend.getWritableDatabase();
final InputStream inputStream; final InputStream inputStream;
if ("file".equals(uri.getScheme())) { final String path = uri.getPath();
inputStream = new FileInputStream(new File(uri.getPath())); final long fileSize;
if ("file".equals(uri.getScheme()) && path != null) {
final File file = new File(path);
inputStream = new FileInputStream(file);
fileSize = file.length();
} else { } else {
final Cursor returnCursor = getContentResolver().query(uri, null, null, null, null);
if (returnCursor == null) {
fileSize = 0;
} else {
returnCursor.moveToFirst();
fileSize = returnCursor.getLong(returnCursor.getColumnIndex(OpenableColumns.SIZE));
returnCursor.close();
}
inputStream = getContentResolver().openInputStream(uri); inputStream = getContentResolver().openInputStream(uri);
} }
final DataInputStream dataInputStream = new DataInputStream(inputStream); if (inputStream == null) {
synchronized (mOnBackupProcessedListeners) {
for (final OnBackupProcessed l : mOnBackupProcessedListeners) {
l.onBackupRestoreFailed();
}
}
return false;
}
final CountingInputStream countingInputStream = new CountingInputStream(inputStream);
final DataInputStream dataInputStream = new DataInputStream(countingInputStream);
final BackupFileHeader backupFileHeader = BackupFileHeader.read(dataInputStream); final BackupFileHeader backupFileHeader = BackupFileHeader.read(dataInputStream);
Log.d(Config.LOGTAG, backupFileHeader.toString()); Log.d(Config.LOGTAG, backupFileHeader.toString());
@ -179,15 +231,14 @@ public class ImportBackupService extends Service {
return false; return false;
} }
final Cipher cipher = Compatibility.twentyEight() ? Cipher.getInstance(CIPHERMODE) : Cipher.getInstance(CIPHERMODE, PROVIDER); final byte[] key = ExportBackupService.getKey(password, backupFileHeader.getSalt());
byte[] key = ExportBackupService.getKey(password, backupFileHeader.getSalt());
SecretKeySpec keySpec = new SecretKeySpec(key, KEYTYPE);
IvParameterSpec ivSpec = new IvParameterSpec(backupFileHeader.getIv());
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
CipherInputStream cipherInputStream = new CipherInputStream(inputStream, cipher);
GZIPInputStream gzipInputStream = new GZIPInputStream(cipherInputStream); AEADBlockCipher cipher = new GCMBlockCipher(new AESEngine());
BufferedReader reader = new BufferedReader(new InputStreamReader(gzipInputStream, "UTF-8")); cipher.init(false, new AEADParameters(new KeyParameter(key), 128, backupFileHeader.getIv()));
final CipherInputStream cipherInputStream = new CipherInputStream(countingInputStream, cipher);
final GZIPInputStream gzipInputStream = new GZIPInputStream(cipherInputStream);
BufferedReader reader = new BufferedReader(new InputStreamReader(gzipInputStream, Charsets.UTF_8));
String line; String line;
StringBuilder multiLineQuery = null; StringBuilder multiLineQuery = null;
while ((line = reader.readLine()) != null) { while ((line = reader.readLine()) != null) {
@ -198,10 +249,12 @@ public class ImportBackupService extends Service {
if (count % 2 == 1) { if (count % 2 == 1) {
db.execSQL(multiLineQuery.toString()); db.execSQL(multiLineQuery.toString());
multiLineQuery = null; multiLineQuery = null;
updateImportBackupNotification(fileSize, countingInputStream.getCount());
} }
} else { } else {
if (count % 2 == 0) { if (count % 2 == 0) {
db.execSQL(line); db.execSQL(line);
updateImportBackupNotification(fileSize, countingInputStream.getCount());
} else { } else {
multiLineQuery = new StringBuilder(line); multiLineQuery = new StringBuilder(line);
} }
@ -220,7 +273,7 @@ public class ImportBackupService extends Service {
} }
} }
return true; return true;
} catch (Exception e) { } catch (final Exception e) {
Throwable throwable = e.getCause(); Throwable throwable = e.getCause();
final boolean reasonWasCrypto = throwable instanceof BadPaddingException || e instanceof ZipException; final boolean reasonWasCrypto = throwable instanceof BadPaddingException || e instanceof ZipException;
synchronized (mOnBackupProcessedListeners) { synchronized (mOnBackupProcessedListeners) {

View File

@ -8,4 +8,5 @@
<string name="magic_create_text_on_x">Du wurdest zu %1$s eingeladen. Wir führen dich durch den Prozess der Kontoerstellung.\nWenn du %1$s als Provider wählst, kannst du mit Nutzern anderer Anbieter kommunizieren, indem du ihnen deine vollständige XMPP-Adresse gibst.</string> <string name="magic_create_text_on_x">Du wurdest zu %1$s eingeladen. Wir führen dich durch den Prozess der Kontoerstellung.\nWenn du %1$s als Provider wählst, kannst du mit Nutzern anderer Anbieter kommunizieren, indem du ihnen deine vollständige XMPP-Adresse gibst.</string>
<string name="magic_create_text_fixed">Du wurdest zu %1$seingeladen. Ein Benutzername ist bereits für dich ausgewählt worden. Wir führen dich durch den Prozess der Kontoerstellung.\nDu kannst mit Nutzern anderer Anbieter kommunizieren, indem du ihnen deine vollständige XMPP-Adresse gibst.</string> <string name="magic_create_text_fixed">Du wurdest zu %1$seingeladen. Ein Benutzername ist bereits für dich ausgewählt worden. Wir führen dich durch den Prozess der Kontoerstellung.\nDu kannst mit Nutzern anderer Anbieter kommunizieren, indem du ihnen deine vollständige XMPP-Adresse gibst.</string>
<string name="your_server_invitation">Deine Einladung für den Server</string> <string name="your_server_invitation">Deine Einladung für den Server</string>
<string name="improperly_formatted_provisioning">Falsch formatierter Provisionierungscode</string>
</resources> </resources>

View File

@ -8,4 +8,4 @@
<string name="magic_create_text_on_x">Έχετε προσκληθεί στο %1$s. Ένα όνομα χρήστη έχει ήδη επιλεγεί για εσάς. Θα σας καθοδηγήσουμε στη διαδικασία δημιουργίας λογαριασμού.\nΕπιλέγοντας τον %1$s ως πάροχο θα μπορείτε να επικοινωνείτε με χρήστες άλλων παρόχων δίνοντάς τους την πλήρη διεύθυνση XMPP σας.</string> <string name="magic_create_text_on_x">Έχετε προσκληθεί στο %1$s. Ένα όνομα χρήστη έχει ήδη επιλεγεί για εσάς. Θα σας καθοδηγήσουμε στη διαδικασία δημιουργίας λογαριασμού.\nΕπιλέγοντας τον %1$s ως πάροχο θα μπορείτε να επικοινωνείτε με χρήστες άλλων παρόχων δίνοντάς τους την πλήρη διεύθυνση XMPP σας.</string>
<string name="magic_create_text_fixed">Έχετε προσκληθεί στο %1$s. Ένα όνομα χρήστη έχει ήδη επιλεγεί για εσάς. Θα σας καθοδηγήσουμε στη διαδικασία δημιουργίας λογαριασμού.\nΘα μπορείτε να επικοινωνείτε με χρήστες άλλων παρόχων δίνοντάς τους την πλήρη διεύθυνση XMPP σας.</string> <string name="magic_create_text_fixed">Έχετε προσκληθεί στο %1$s. Ένα όνομα χρήστη έχει ήδη επιλεγεί για εσάς. Θα σας καθοδηγήσουμε στη διαδικασία δημιουργίας λογαριασμού.\nΘα μπορείτε να επικοινωνείτε με χρήστες άλλων παρόχων δίνοντάς τους την πλήρη διεύθυνση XMPP σας.</string>
<string name="your_server_invitation">Η πρόσκλησή σας στον διακομιστή</string> <string name="your_server_invitation">Η πρόσκλησή σας στον διακομιστή</string>
</resources> </resources>

View File

@ -8,4 +8,5 @@
<string name="magic_create_text_on_x">Has sido invitado a %1$s. Te guiaremos durante el proceso de creación de la cuenta.\nCuando selecciones %1$s como proveedor podrás comunicarte con usuarios de otros servidores proporcionándoles tu dirección XMPP completa. </string> <string name="magic_create_text_on_x">Has sido invitado a %1$s. Te guiaremos durante el proceso de creación de la cuenta.\nCuando selecciones %1$s como proveedor podrás comunicarte con usuarios de otros servidores proporcionándoles tu dirección XMPP completa. </string>
<string name="magic_create_text_fixed">Has sido invitado a %1$s. Un nombre de usuario ya ha sido escogido para ti. Te guiaremos durante el proceso de creación de la cuenta.\nPodrás comunicarte con otros usuarios de otros servidores proporcionándoles tu dirección XMPP completa. </string> <string name="magic_create_text_fixed">Has sido invitado a %1$s. Un nombre de usuario ya ha sido escogido para ti. Te guiaremos durante el proceso de creación de la cuenta.\nPodrás comunicarte con otros usuarios de otros servidores proporcionándoles tu dirección XMPP completa. </string>
<string name="your_server_invitation">Tu invitación al servidor</string> <string name="your_server_invitation">Tu invitación al servidor</string>
<string name="improperly_formatted_provisioning">Código de abastecimiento formateado incorrectamente</string>
</resources> </resources>

View File

@ -8,4 +8,5 @@
<string name="magic_create_text_on_x">Vous avez été invité à %1$s. Nous allons vous guider à travers le processus de création dun compte.\nEn choisissant %1$s comme fournisseur, vous pourrez communiquer avec les utilisateurs des autres fournisseurs en leur donnant votre adresse XMPP complète.</string> <string name="magic_create_text_on_x">Vous avez été invité à %1$s. Nous allons vous guider à travers le processus de création dun compte.\nEn choisissant %1$s comme fournisseur, vous pourrez communiquer avec les utilisateurs des autres fournisseurs en leur donnant votre adresse XMPP complète.</string>
<string name="magic_create_text_fixed">Vous avez été invité à %1$s. Un nom dutilisateur a déjà été choisi pour vous. Nous allons vous guider à travers le processus de création dun compte.\nVous pourrez communiquer avec les utilisateurs des autres fournisseurs en leur donnant votre adresse XMPP complète.</string> <string name="magic_create_text_fixed">Vous avez été invité à %1$s. Un nom dutilisateur a déjà été choisi pour vous. Nous allons vous guider à travers le processus de création dun compte.\nVous pourrez communiquer avec les utilisateurs des autres fournisseurs en leur donnant votre adresse XMPP complète.</string>
<string name="your_server_invitation">Votre invitation au serveur</string> <string name="your_server_invitation">Votre invitation au serveur</string>
<string name="improperly_formatted_provisioning">Code de provisionnement mal formaté</string>
</resources> </resources>

View File

@ -8,4 +8,5 @@
<string name="magic_create_text_on_x">Convidáronte a %1$s. Guiarémoste no proceso para crear unha conta.\nAo escoller %1$s como provedor poderás comunicarte con usuarias de outros provedores cando lles deas o teu enderezo XMPP completo.</string> <string name="magic_create_text_on_x">Convidáronte a %1$s. Guiarémoste no proceso para crear unha conta.\nAo escoller %1$s como provedor poderás comunicarte con usuarias de outros provedores cando lles deas o teu enderezo XMPP completo.</string>
<string name="magic_create_text_fixed">Convidáronte a %1$s. Escollemos un nome de usuaria por ti. Guiarémoste no proceso de crear unha conta.\nPoderás comunicarte con usuarias de outros provedores cando lles digas o teu enderezo XMPP completo.</string> <string name="magic_create_text_fixed">Convidáronte a %1$s. Escollemos un nome de usuaria por ti. Guiarémoste no proceso de crear unha conta.\nPoderás comunicarte con usuarias de outros provedores cando lles digas o teu enderezo XMPP completo.</string>
<string name="your_server_invitation">O convite do teu servidor</string> <string name="your_server_invitation">O convite do teu servidor</string>
<string name="improperly_formatted_provisioning">Código de aprovisionamento con formato non válido</string>
</resources> </resources>

View File

@ -8,4 +8,4 @@
<string name="magic_create_text_on_x">Meghívást kapott a(z) %1$s kiszolgálóra. Végig fogjuk vezetni egy fiók létrehozásának folyamatán.\nHa a(z) %1$s kiszolgálót választja szolgáltatóként, akkor képes lesz más szolgáltatók felhasználóival is kommunikálni, ha megadja nekik a teljes XMPP-címét.</string> <string name="magic_create_text_on_x">Meghívást kapott a(z) %1$s kiszolgálóra. Végig fogjuk vezetni egy fiók létrehozásának folyamatán.\nHa a(z) %1$s kiszolgálót választja szolgáltatóként, akkor képes lesz más szolgáltatók felhasználóival is kommunikálni, ha megadja nekik a teljes XMPP-címét.</string>
<string name="magic_create_text_fixed">Meghívást kapott a(z) %1$s kiszolgálóra. Már kiválasztottak Önnek egy felhasználónevet. Végig fogjuk vezetni egy fiók létrehozásának folyamatán.\nKépes lesz más szolgáltatók felhasználóival is kommunikálni, ha megadja nekik a teljes XMPP-címét.</string> <string name="magic_create_text_fixed">Meghívást kapott a(z) %1$s kiszolgálóra. Már kiválasztottak Önnek egy felhasználónevet. Végig fogjuk vezetni egy fiók létrehozásának folyamatán.\nKépes lesz más szolgáltatók felhasználóival is kommunikálni, ha megadja nekik a teljes XMPP-címét.</string>
<string name="your_server_invitation">Az Ön kiszolgálómeghívása</string> <string name="your_server_invitation">Az Ön kiszolgálómeghívása</string>
</resources> </resources>

View File

@ -10,4 +10,4 @@ In ogni caso per facilitare puoi creare facilmente un account su chat.sum7.eu, u
<string name="magic_create_text_on_x">Sei stato invitato su %1$s. Ti guideremo nel procedimento per creare un account.\nQuando scegli %1$s come fornitore sarai in grado di comunicare con utenti di altri fornitori dando loro l\'indirizzo XMPP completo.</string> <string name="magic_create_text_on_x">Sei stato invitato su %1$s. Ti guideremo nel procedimento per creare un account.\nQuando scegli %1$s come fornitore sarai in grado di comunicare con utenti di altri fornitori dando loro l\'indirizzo XMPP completo.</string>
<string name="magic_create_text_fixed">Sei stato invitato su %1$s. È già stato scelto un nome utente per te. Ti guideremo nel procedimento per creare un account.\nSarai in grado di comunicare con utenti di altri fornitori dando loro l\'indirizzo XMPP completo.</string> <string name="magic_create_text_fixed">Sei stato invitato su %1$s. È già stato scelto un nome utente per te. Ti guideremo nel procedimento per creare un account.\nSarai in grado di comunicare con utenti di altri fornitori dando loro l\'indirizzo XMPP completo.</string>
<string name="your_server_invitation">Il tuo invito al server</string> <string name="your_server_invitation">Il tuo invito al server</string>
</resources> </resources>

View File

@ -8,4 +8,4 @@
<string name="magic_create_text_on_x">Je ontving een uitnodiging voor %1$s. We zullen je helpen een account aan te maken.\nWanneer je %1$s als je provider kiest kan je met gebruikers van andere providers communiceren door hen je volledige XMPP-adres te geven.</string> <string name="magic_create_text_on_x">Je ontving een uitnodiging voor %1$s. We zullen je helpen een account aan te maken.\nWanneer je %1$s als je provider kiest kan je met gebruikers van andere providers communiceren door hen je volledige XMPP-adres te geven.</string>
<string name="magic_create_text_fixed">Je ontving een uitnodiging voor %1$s. Er werd reeds een gebruikersnaam voor jou gekozen. We zullen je helpen een account aan te maken.\nJe zal met gebruikers van andere providers communiceren door hen je volledige XMPP-adres te geven.</string> <string name="magic_create_text_fixed">Je ontving een uitnodiging voor %1$s. Er werd reeds een gebruikersnaam voor jou gekozen. We zullen je helpen een account aan te maken.\nJe zal met gebruikers van andere providers communiceren door hen je volledige XMPP-adres te geven.</string>
<string name="your_server_invitation">Je server uitnodiging</string> <string name="your_server_invitation">Je server uitnodiging</string>
</resources> </resources>

View File

@ -8,4 +8,4 @@
<string name="magic_create_text_on_x">Zostałeś zaproszony do %1$s. Poprowadzimy ciebie przez proces tworzenia konta.\nWybierając %1$s jako dostawcę będziesz mógł komunikować się z innymi użytkownikami podając swój pełny adres XMPP.</string> <string name="magic_create_text_on_x">Zostałeś zaproszony do %1$s. Poprowadzimy ciebie przez proces tworzenia konta.\nWybierając %1$s jako dostawcę będziesz mógł komunikować się z innymi użytkownikami podając swój pełny adres XMPP.</string>
<string name="magic_create_text_fixed">Zostałeś zaproszony do %1$s. Nazwa użytkownika została już dla ciebie wybrana. Poprowadzimy ciebie przez proces tworzenia konta.\nBęziesz mógł komunikować się z innymi użytkownikami podając swój adres XMPP.</string> <string name="magic_create_text_fixed">Zostałeś zaproszony do %1$s. Nazwa użytkownika została już dla ciebie wybrana. Poprowadzimy ciebie przez proces tworzenia konta.\nBęziesz mógł komunikować się z innymi użytkownikami podając swój adres XMPP.</string>
<string name="your_server_invitation">Zaproszenie twojego serwera</string> <string name="your_server_invitation">Zaproszenie twojego serwera</string>
</resources> </resources>

View File

@ -8,4 +8,4 @@
<string name="magic_create_text_on_x">Você foi convidado para %1$s. Nós iremos guiá-lo ao longo do processo de criação de uma conta.\nAo escolher %1$s como um provedor você conseguirá se comunicar com usuários de outros provedores dando a eles seu endereço XMPP completo.</string> <string name="magic_create_text_on_x">Você foi convidado para %1$s. Nós iremos guiá-lo ao longo do processo de criação de uma conta.\nAo escolher %1$s como um provedor você conseguirá se comunicar com usuários de outros provedores dando a eles seu endereço XMPP completo.</string>
<string name="magic_create_text_fixed">Você foi convidado para %1$s. Um nome de usuário já foi escolhido para você. Nós iremos guiá-lo ao longo do processo de criação de uma conta.\nVocê conseguirá se comunicar com usuários de outros provedores dando a eles seu endereço XMPP completo.</string> <string name="magic_create_text_fixed">Você foi convidado para %1$s. Um nome de usuário já foi escolhido para você. Nós iremos guiá-lo ao longo do processo de criação de uma conta.\nVocê conseguirá se comunicar com usuários de outros provedores dando a eles seu endereço XMPP completo.</string>
<string name="your_server_invitation">Seu convite do servidor</string> <string name="your_server_invitation">Seu convite do servidor</string>
</resources> </resources>

View File

@ -8,4 +8,5 @@
<string name="magic_create_text_on_x">Ați fost invitați la %1$s. Vă vom ghida prin procesul de creare al unui cont.\nCând alegeți %1$s ca furnizor veți putea comunica cu utilizatorii altor furnizori oferindu-le adresa dumneavoastră completă XMPP.</string> <string name="magic_create_text_on_x">Ați fost invitați la %1$s. Vă vom ghida prin procesul de creare al unui cont.\nCând alegeți %1$s ca furnizor veți putea comunica cu utilizatorii altor furnizori oferindu-le adresa dumneavoastră completă XMPP.</string>
<string name="magic_create_text_fixed">Ați fost invitați la %1$s. Un nume de utilizator a fost deja ales pentru dumneavoastră. Vă vom ghida prin procesul de creare al unui cont.\nVeți putea comunica cu utilizatorii altor furnizori oferindu-le adresa dumneavoastră completă XMPP.</string> <string name="magic_create_text_fixed">Ați fost invitați la %1$s. Un nume de utilizator a fost deja ales pentru dumneavoastră. Vă vom ghida prin procesul de creare al unui cont.\nVeți putea comunica cu utilizatorii altor furnizori oferindu-le adresa dumneavoastră completă XMPP.</string>
<string name="your_server_invitation">Invitația serverului dumneavoastră</string> <string name="your_server_invitation">Invitația serverului dumneavoastră</string>
<string name="improperly_formatted_provisioning">Cod de acces formatat necorespunzător</string>
</resources> </resources>

View File

@ -4,5 +4,8 @@
<string name="use_chat.sum7.eu">Использовать chat.sum7.eu</string> <string name="use_chat.sum7.eu">Использовать chat.sum7.eu</string>
<string name="create_new_account">Создать новый аккаунт</string> <string name="create_new_account">Создать новый аккаунт</string>
<string name="do_you_have_an_account">У вас есть аккаунт XMPP? Если вы использовали Conversations или другой XMPP-клиент в прошлом, то скорее всего, он у вас есть. Если у вас нет аккаунта, вы можете создать его прямо сейчас.\nНекоторые провайдеры электронной почты также регистрируют аккаунты XMPP. </string> <string name="do_you_have_an_account">У вас есть аккаунт XMPP? Если вы использовали Conversations или другой XMPP-клиент в прошлом, то скорее всего, он у вас есть. Если у вас нет аккаунта, вы можете создать его прямо сейчас.\nНекоторые провайдеры электронной почты также регистрируют аккаунты XMPP. </string>
<string name="server_select_text">XMPP - это независимая сеть обмена сообщениями. Conversations позволяет вам подключиться к любому XMPP-серверу на ваш выбор.\nЕсли у вас нет сервера, предлагаем вам зарегистрировать аккаунт на chat.sum7.eu, сервер, специально предназначеный для работы с приложением Conv6sations.</string> <string name="server_select_text">XMPP - это независимая сеть обмена сообщениями. Conversations позволяет вам подключиться к любому XMPP-серверу на ваш выбор.\nЕсли у вас нет сервера, предлагаем вам зарегистрировать аккаунт на chat.sum7.eu, сервере, специально предназначенном для работы с Conversations.</string>
</resources> <string name="magic_create_text_on_x">Вас пригласили на %1$s. Мы проведём вас через процесс создания аккаунта. Аккаунт на %1$s позволит вам общаться с пользователями и на этом, и на других серверах, используя ваш полный XMPP-адрес.</string>
<string name="magic_create_text_fixed">Вас пригласили на %1$s. Вам уже назначили имя пользователя. Мы проведём вас через процесс создания аккаунта. Этот аккаунт позволит вам общаться с пользователями и на этом, и на других серверах, используя ваш полный XMPP-адрес.</string>
<string name="your_server_invitation">Ваше приглашение</string>
</resources>

View File

@ -8,4 +8,5 @@
<string name="magic_create_text_on_x">Вас запросили до %1$s. Ми проведемо вас крок за кроком, щоб створити обліковий запис.\nОбираючи %1$s в якості свого постачальника, ви зможете спілкуватися з користувачами інших постачальників, для цього повідомте їм свою повну адресу XMPP.</string> <string name="magic_create_text_on_x">Вас запросили до %1$s. Ми проведемо вас крок за кроком, щоб створити обліковий запис.\nОбираючи %1$s в якості свого постачальника, ви зможете спілкуватися з користувачами інших постачальників, для цього повідомте їм свою повну адресу XMPP.</string>
<string name="magic_create_text_fixed">Вас запросили до %1$s. Для вас створено ім\'я користувача. Ми проведемо вас крок за кроком, щоб створити обліковий запис.\nВи зможете спілкуватися з користувачами інших постачальників, для цього повідомите їм свою повну адресу XMPP.</string> <string name="magic_create_text_fixed">Вас запросили до %1$s. Для вас створено ім\'я користувача. Ми проведемо вас крок за кроком, щоб створити обліковий запис.\nВи зможете спілкуватися з користувачами інших постачальників, для цього повідомите їм свою повну адресу XMPP.</string>
<string name="your_server_invitation">Ваше запрошення до сервера</string> <string name="your_server_invitation">Ваше запрошення до сервера</string>
<string name="improperly_formatted_provisioning">Неправильно відформатований код забезпечення</string>
</resources> </resources>

View File

@ -8,4 +8,4 @@
<string name="magic_create_text_on_x">您已受邀参加%1$s。 我们将指导您完成创建帐户的过程。\n选择%1$s作为提供者后您可以通过提供其他人的完整XMPP地址与其他提供者的用户进行交流。</string> <string name="magic_create_text_on_x">您已受邀参加%1$s。 我们将指导您完成创建帐户的过程。\n选择%1$s作为提供者后您可以通过提供其他人的完整XMPP地址与其他提供者的用户进行交流。</string>
<string name="magic_create_text_fixed">您已受邀参加%1$s。 已经为您选择了一个用户名。 我们将指导您完成创建帐户的过程。\n您可以通过向其他提供商的用户提供完整的XMPP地址来与他们进行交流。</string> <string name="magic_create_text_fixed">您已受邀参加%1$s。 已经为您选择了一个用户名。 我们将指导您完成创建帐户的过程。\n您可以通过向其他提供商的用户提供完整的XMPP地址来与他们进行交流。</string>
<string name="your_server_invitation">你的服务器邀请</string> <string name="your_server_invitation">你的服务器邀请</string>
</resources> </resources>

View File

@ -173,7 +173,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
public String findMostRecentRemoteDisplayableId() { public String findMostRecentRemoteDisplayableId() {
final boolean multi = mode == Conversation.MODE_MULTI; final boolean multi = mode == Conversation.MODE_MULTI;
synchronized (this.messages) { synchronized (this.messages) {
for(final Message message : Lists.reverse(this.messages)) { for (final Message message : Lists.reverse(this.messages)) {
if (message.getStatus() == Message.STATUS_RECEIVED) { if (message.getStatus() == Message.STATUS_RECEIVED) {
final String serverMsgId = message.getServerMsgId(); final String serverMsgId = message.getServerMsgId();
if (serverMsgId != null && multi) { if (serverMsgId != null && multi) {
@ -186,6 +186,21 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
return null; return null;
} }
public Message getLastEditableMessage() {
synchronized (this.messages) {
for (final Message message : Lists.reverse(this.messages)) {
if (message.isEditable()) {
if (message.isGeoUri() || message.getType() != Message.TYPE_TEXT) {
return null;
}
return message;
}
}
}
return null;
}
public Message findUnsentMessageWithUuid(String uuid) { public Message findUnsentMessageWithUuid(String uuid) {
synchronized (this.messages) { synchronized (this.messages) {
for (final Message message : this.messages) { for (final Message message : this.messages) {
@ -499,7 +514,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
@Override @Override
public int compareTo(@NonNull Conversation another) { public int compareTo(@NonNull Conversation another) {
return ComparisonChain.start() return ComparisonChain.start()
.compareFalseFirst(another.getBooleanAttribute(ATTRIBUTE_PINNED_ON_TOP, false), getBooleanAttribute(ATTRIBUTE_PINNED_ON_TOP,false)) .compareFalseFirst(another.getBooleanAttribute(ATTRIBUTE_PINNED_ON_TOP, false), getBooleanAttribute(ATTRIBUTE_PINNED_ON_TOP, false))
.compare(another.getSortableTime(), getSortableTime()) .compare(another.getSortableTime(), getSortableTime())
.result(); .result();
} }

View File

@ -15,7 +15,6 @@ import java.lang.ref.WeakReference;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@ -613,15 +612,15 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable
public boolean isLastCorrectableMessage() { public boolean isLastCorrectableMessage() {
Message next = next(); Message next = next();
while (next != null) { while (next != null) {
if (next.isCorrectable()) { if (next.isEditable()) {
return false; return false;
} }
next = next.next(); next = next.next();
} }
return isCorrectable(); return isEditable();
} }
private boolean isCorrectable() { public boolean isEditable() {
return getStatus() != STATUS_RECEIVED && !isCarbon(); return getStatus() != STATUS_RECEIVED && !isCarbon();
} }

View File

@ -1,16 +1,20 @@
package eu.siacs.conversations.ui; package eu.siacs.conversations.ui;
import android.Manifest;
import android.content.ActivityNotFoundException; import android.content.ActivityNotFoundException;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.databinding.DataBindingUtil; import android.databinding.DataBindingUtil;
import android.net.Uri; import android.net.Uri;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.provider.ContactsContract.CommonDataKinds; import android.provider.ContactsContract.CommonDataKinds;
import android.provider.ContactsContract.Contacts; import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Intents; import android.provider.ContactsContract.Intents;
import android.support.annotation.NonNull;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar;
import android.text.Spannable; import android.text.Spannable;
@ -57,15 +61,15 @@ import eu.siacs.conversations.utils.IrregularUnicodeDetector;
import eu.siacs.conversations.utils.UIHelper; import eu.siacs.conversations.utils.UIHelper;
import eu.siacs.conversations.utils.XmppUri; import eu.siacs.conversations.utils.XmppUri;
import eu.siacs.conversations.xml.Namespace; import eu.siacs.conversations.xml.Namespace;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.OnKeyStatusUpdated; import eu.siacs.conversations.xmpp.OnKeyStatusUpdated;
import eu.siacs.conversations.xmpp.OnUpdateBlocklist; import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
import eu.siacs.conversations.xmpp.XmppConnection; import eu.siacs.conversations.xmpp.XmppConnection;
import eu.siacs.conversations.xmpp.Jid;
public class ContactDetailsActivity extends OmemoActivity implements OnAccountUpdate, OnRosterUpdate, OnUpdateBlocklist, OnKeyStatusUpdated, OnMediaLoaded { public class ContactDetailsActivity extends OmemoActivity implements OnAccountUpdate, OnRosterUpdate, OnUpdateBlocklist, OnKeyStatusUpdated, OnMediaLoaded {
public static final String ACTION_VIEW_CONTACT = "view_contact"; public static final String ACTION_VIEW_CONTACT = "view_contact";
private final int REQUEST_SYNC_CONTACTS = 0x28cf;
ActivityContactDetailsBinding binding; ActivityContactDetailsBinding binding;
private MediaAdapter mMediaAdapter; private MediaAdapter mMediaAdapter;
private Contact contact; private Contact contact;
@ -110,47 +114,41 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
private boolean showInactiveOmemo = false; private boolean showInactiveOmemo = false;
private String messageFingerprint; private String messageFingerprint;
private DialogInterface.OnClickListener addToPhonebook = new DialogInterface.OnClickListener() { private void checkContactPermissionAndShowAddDialog() {
if (hasContactsPermission()) {
showAddToPhoneBookDialog();
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, REQUEST_SYNC_CONTACTS);
}
}
@Override private boolean hasContactsPermission() {
public void onClick(DialogInterface dialog, int which) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT); return checkSelfPermission(Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED;
} else {
return true;
}
}
private void showAddToPhoneBookDialog() {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(getString(R.string.action_add_phone_book));
builder.setMessage(getString(R.string.add_phone_book_text, contact.getJid().toEscapedString()));
builder.setNegativeButton(getString(R.string.cancel), null);
builder.setPositiveButton(getString(R.string.add), (dialog, which) -> {
final Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
intent.setType(Contacts.CONTENT_ITEM_TYPE); intent.setType(Contacts.CONTENT_ITEM_TYPE);
intent.putExtra(Intents.Insert.IM_HANDLE, contact.getJid().toEscapedString()); intent.putExtra(Intents.Insert.IM_HANDLE, contact.getJid().toEscapedString());
intent.putExtra(Intents.Insert.IM_PROTOCOL, CommonDataKinds.Im.PROTOCOL_JABBER); intent.putExtra(Intents.Insert.IM_PROTOCOL, CommonDataKinds.Im.PROTOCOL_JABBER);
intent.putExtra("finishActivityOnSaveCompleted", true); intent.putExtra("finishActivityOnSaveCompleted", true);
try { try {
ContactDetailsActivity.this.startActivityForResult(intent, 0); startActivityForResult(intent, 0);
} catch (ActivityNotFoundException e) { } catch (ActivityNotFoundException e) {
Toast.makeText(ContactDetailsActivity.this, R.string.no_application_found_to_view_contact, Toast.LENGTH_SHORT).show(); Toast.makeText(ContactDetailsActivity.this, R.string.no_application_found_to_view_contact, Toast.LENGTH_SHORT).show();
} }
} });
}; builder.create().show();
}
private OnClickListener onBadgeClick = new OnClickListener() {
@Override
public void onClick(View v) {
Uri systemAccount = contact.getSystemAccount();
if (systemAccount == null) {
AlertDialog.Builder builder = new AlertDialog.Builder(
ContactDetailsActivity.this);
builder.setTitle(getString(R.string.action_add_phone_book));
builder.setMessage(getString(R.string.add_phone_book_text, contact.getJid().toEscapedString()));
builder.setNegativeButton(getString(R.string.cancel), null);
builder.setPositiveButton(getString(R.string.add), addToPhonebook);
builder.create().show();
} else {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(systemAccount);
try {
startActivity(intent);
} catch (ActivityNotFoundException e) {
Toast.makeText(ContactDetailsActivity.this, R.string.no_application_found_to_view_contact, Toast.LENGTH_SHORT).show();
}
}
}
};
@Override @Override
public void onRosterUpdate() { public void onRosterUpdate() {
@ -233,6 +231,18 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
mMediaAdapter.setAttachments(Collections.emptyList()); mMediaAdapter.setAttachments(Collections.emptyList());
} }
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
if (grantResults.length > 0)
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (requestCode == REQUEST_SYNC_CONTACTS && xmppConnectionServiceBound) {
showAddToPhoneBookDialog();
xmppConnectionService.loadPhoneContacts();
xmppConnectionService.startContactObserver();
}
}
}
@Override @Override
public boolean onOptionsItemSelected(final MenuItem menuItem) { public boolean onOptionsItemSelected(final MenuItem menuItem) {
if (MenuDoubleTabUtil.shouldIgnoreTap()) { if (MenuDoubleTabUtil.shouldIgnoreTap()) {
@ -417,7 +427,7 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
} }
binding.detailsAccount.setText(getString(R.string.using_account, account)); binding.detailsAccount.setText(getString(R.string.using_account, account));
AvatarWorkerTask.loadAvatar(contact, binding.detailsContactBadge, R.dimen.avatar_on_details_screen_size); AvatarWorkerTask.loadAvatar(contact, binding.detailsContactBadge, R.dimen.avatar_on_details_screen_size);
binding.detailsContactBadge.setOnClickListener(this.onBadgeClick); binding.detailsContactBadge.setOnClickListener(this::onBadgeClick);
binding.detailsContactKeys.removeAllViews(); binding.detailsContactKeys.removeAllViews();
boolean hasKeys = false; boolean hasKeys = false;
@ -496,6 +506,21 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
} }
} }
private void onBadgeClick(View view) {
final Uri systemAccount = contact.getSystemAccount();
if (systemAccount == null) {
checkContactPermissionAndShowAddDialog();
} else {
final Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(systemAccount);
try {
startActivity(intent);
} catch (final ActivityNotFoundException e) {
Toast.makeText(this, R.string.no_application_found_to_view_contact, Toast.LENGTH_SHORT).show();
}
}
}
public void onBackendConnected() { public void onBackendConnected() {
if (accountJid != null && contactJid != null) { if (accountJid != null && contactJid != null) {
Account account = xmppConnectionService.findAccountByJid(accountJid); Account account = xmppConnectionService.findAccountByJid(accountJid);

View File

@ -32,6 +32,7 @@ import android.util.Log;
import android.view.ContextMenu; import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo; import android.view.ContextMenu.ContextMenuInfo;
import android.view.Gravity; import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
@ -2733,15 +2734,26 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
} }
@Override @Override
public boolean onEnterPressed() { public boolean onEnterPressed(final boolean isCtrlPressed) {
SharedPreferences p = PreferenceManager.getDefaultSharedPreferences(getActivity()); if (isCtrlPressed || enterIsSend()) {
final boolean enterIsSend = p.getBoolean("enter_is_send", getResources().getBoolean(R.bool.enter_is_send));
if (enterIsSend) {
sendMessage(); sendMessage();
return true; return true;
} else {
return false;
} }
return false;
}
private boolean enterIsSend() {
final SharedPreferences p = PreferenceManager.getDefaultSharedPreferences(getActivity());
return p.getBoolean("enter_is_send", getResources().getBoolean(R.bool.enter_is_send));
}
public boolean onArrowUpCtrlPressed() {
final Message lastEditableMessage = conversation == null ? null : conversation.getLastEditableMessage();
if (lastEditableMessage != null) {
correctMessage(lastEditableMessage);
return true;
}
return false;
} }
@Override @Override

View File

@ -49,6 +49,7 @@ import android.support.v7.app.ActionBar;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar;
import android.util.Log; import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.widget.Toast; import android.widget.Toast;
@ -493,8 +494,19 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
} }
@Override @Override
public void onSaveInstanceState(Bundle savedInstanceState) { public boolean onKeyDown(final int keyCode, final KeyEvent keyEvent) {
Intent pendingIntent = pendingViewIntent.peek(); if (keyCode == KeyEvent.KEYCODE_DPAD_UP && keyEvent.isCtrlPressed()) {
final ConversationFragment conversationFragment = ConversationFragment.get(this);
if (conversationFragment != null && conversationFragment.onArrowUpCtrlPressed()) {
return true;
}
}
return super.onKeyDown(keyCode, keyEvent);
}
@Override
public void onSaveInstanceState(final Bundle savedInstanceState) {
final Intent pendingIntent = pendingViewIntent.peek();
savedInstanceState.putParcelable("intent", pendingIntent != null ? pendingIntent : getIntent()); savedInstanceState.putParcelable("intent", pendingIntent != null ? pendingIntent : getIntent());
super.onSaveInstanceState(savedInstanceState); super.onSaveInstanceState(savedInstanceState);
} }

View File

@ -88,6 +88,10 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
RtpEndUserState.APPLICATION_ERROR, RtpEndUserState.APPLICATION_ERROR,
RtpEndUserState.CONNECTIVITY_ERROR RtpEndUserState.CONNECTIVITY_ERROR
); );
private static final List<RtpEndUserState> STATES_SHOWING_SWITCH_TO_CHAT = Arrays.asList(
RtpEndUserState.CONNECTING,
RtpEndUserState.CONNECTED
);
private static final String PROXIMITY_WAKE_LOCK_TAG = "conversations:in-rtp-session"; private static final String PROXIMITY_WAKE_LOCK_TAG = "conversations:in-rtp-session";
private static final int REQUEST_ACCEPT_CALL = 0x1111; private static final int REQUEST_ACCEPT_CALL = 0x1111;
private WeakReference<JingleRtpConnection> rtpConnectionReference; private WeakReference<JingleRtpConnection> rtpConnectionReference;
@ -135,7 +139,9 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
public boolean onCreateOptionsMenu(final Menu menu) { public boolean onCreateOptionsMenu(final Menu menu) {
getMenuInflater().inflate(R.menu.activity_rtp_session, menu); getMenuInflater().inflate(R.menu.activity_rtp_session, menu);
final MenuItem help = menu.findItem(R.id.action_help); final MenuItem help = menu.findItem(R.id.action_help);
final MenuItem gotoChat = menu.findItem(R.id.action_goto_chat);
help.setVisible(isHelpButtonVisible()); help.setVisible(isHelpButtonVisible());
gotoChat.setVisible(isSwitchToConversationVisible());
return super.onCreateOptionsMenu(menu); return super.onCreateOptionsMenu(menu);
} }
@ -153,10 +159,25 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
} }
} }
private boolean isSwitchToConversationVisible() {
final JingleRtpConnection connection = this.rtpConnectionReference != null ? this.rtpConnectionReference.get() : null;
return connection != null && STATES_SHOWING_SWITCH_TO_CHAT.contains(connection.getEndUserState());
}
private void switchToConversation() {
final Contact contact = getWith();
final Conversation conversation = xmppConnectionService.findOrCreateConversation(contact.getAccount(), contact.getJid(), false, true);
switchToConversation(conversation);
}
public boolean onOptionsItemSelected(final MenuItem item) { public boolean onOptionsItemSelected(final MenuItem item) {
if (item.getItemId() == R.id.action_help) { switch (item.getItemId()) {
launchHelpInBrowser(); case R.id.action_help:
return true; launchHelpInBrowser();
break;
case R.id.action_goto_chat:
switchToConversation();
break;
} }
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
@ -308,6 +329,7 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
return; return;
} }
final Account account = extractAccount(intent); final Account account = extractAccount(intent);
final String action = intent.getAction();
final Jid with = Jid.ofEscaped(intent.getStringExtra(EXTRA_WITH)); final Jid with = Jid.ofEscaped(intent.getStringExtra(EXTRA_WITH));
final String sessionId = intent.getStringExtra(EXTRA_SESSION_ID); final String sessionId = intent.getStringExtra(EXTRA_SESSION_ID);
if (sessionId != null) { if (sessionId != null) {
@ -320,6 +342,9 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
requestPermissionsAndAcceptCall(); requestPermissionsAndAcceptCall();
resetIntent(intent.getExtras()); resetIntent(intent.getExtras());
} }
} else if (asList(ACTION_MAKE_VIDEO_CALL, ACTION_MAKE_VOICE_CALL).contains(action)) {
proposeJingleRtpSession(account, with, actionToMedia(action));
binding.with.setText(account.getRoster().getContact(with).getDisplayName());
} else { } else {
throw new IllegalStateException("received onNewIntent without sessionId"); throw new IllegalStateException("received onNewIntent without sessionId");
} }
@ -437,7 +462,11 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
return; return;
} }
} }
retractSessionProposal(); //TODO apparently this method is not getting called on Android 10 when using the task switcher
final boolean emptyReference = rtpConnectionReference == null || rtpConnectionReference.get() == null;
if (emptyReference && xmppConnectionService != null) {
retractSessionProposal();
}
} }
@RequiresApi(api = Build.VERSION_CODES.O) @RequiresApi(api = Build.VERSION_CODES.O)
@ -910,15 +939,17 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
} }
private void disableMicrophone(View view) { private void disableMicrophone(View view) {
JingleRtpConnection rtpConnection = requireRtpConnection(); final JingleRtpConnection rtpConnection = requireRtpConnection();
rtpConnection.setMicrophoneEnabled(false); if (rtpConnection.setMicrophoneEnabled(false)) {
updateInCallButtonConfiguration(); updateInCallButtonConfiguration();
}
} }
private void enableMicrophone(View view) { private void enableMicrophone(View view) {
JingleRtpConnection rtpConnection = requireRtpConnection(); final JingleRtpConnection rtpConnection = requireRtpConnection();
rtpConnection.setMicrophoneEnabled(true); if (rtpConnection.setMicrophoneEnabled(true)) {
updateInCallButtonConfiguration(); updateInCallButtonConfiguration();
}
} }
private void switchToEarpiece(View view) { private void switchToEarpiece(View view) {

View File

@ -553,7 +553,7 @@ public class MessageAdapter extends ArrayAdapter<Message> implements CopyTextVie
viewHolder.audioPlayer.setVisibility(View.GONE); viewHolder.audioPlayer.setVisibility(View.GONE);
viewHolder.image.setVisibility(View.VISIBLE); viewHolder.image.setVisibility(View.VISIBLE);
final FileParams params = message.getFileParams(); final FileParams params = message.getFileParams();
final double target = metrics.density * 288; final float target = activity.getResources().getDimension(R.dimen.image_preview_width);
final int scaledW; final int scaledW;
final int scaledH; final int scaledH;
if (Math.max(params.height, params.width) * metrics.density <= target) { if (Math.max(params.height, params.width) * metrics.density <= target) {
@ -569,7 +569,7 @@ public class MessageAdapter extends ArrayAdapter<Message> implements CopyTextVie
scaledW = (int) target; scaledW = (int) target;
scaledH = (int) (params.height / ((double) params.width / target)); scaledH = (int) (params.height / ((double) params.width / target));
} }
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(scaledW, scaledH); final LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(scaledW, scaledH);
layoutParams.setMargins(0, (int) (metrics.density * 4), 0, (int) (metrics.density * 4)); layoutParams.setMargins(0, (int) (metrics.density * 4), 0, (int) (metrics.density * 4));
viewHolder.image.setLayoutParams(layoutParams); viewHolder.image.setLayoutParams(layoutParams);
activity.loadBitmap(message, viewHolder.image); activity.loadBitmap(message, viewHolder.image);

View File

@ -54,13 +54,14 @@ public class EditMessage extends EmojiWrapperEditText {
} }
@Override @Override
public boolean onKeyDown(int keyCode, KeyEvent e) { public boolean onKeyDown(final int keyCode, final KeyEvent e) {
final boolean isCtrlPressed = e.isCtrlPressed();
if (keyCode == KeyEvent.KEYCODE_ENTER && !e.isShiftPressed()) { if (keyCode == KeyEvent.KEYCODE_ENTER && !e.isShiftPressed()) {
lastInputWasTab = false; lastInputWasTab = false;
if (keyboardListener != null && keyboardListener.onEnterPressed()) { if (keyboardListener != null && keyboardListener.onEnterPressed(isCtrlPressed)) {
return true; return true;
} }
} else if (keyCode == KeyEvent.KEYCODE_TAB && !e.isAltPressed() && !e.isCtrlPressed()) { } else if (keyCode == KeyEvent.KEYCODE_TAB && !e.isAltPressed() && !isCtrlPressed) {
if (keyboardListener != null && keyboardListener.onTabPressed(this.lastInputWasTab)) { if (keyboardListener != null && keyboardListener.onTabPressed(this.lastInputWasTab)) {
lastInputWasTab = true; lastInputWasTab = true;
return true; return true;
@ -191,7 +192,7 @@ public class EditMessage extends EmojiWrapperEditText {
} }
public interface KeyboardListener { public interface KeyboardListener {
boolean onEnterPressed(); boolean onEnterPressed(boolean isCtrlPressed);
void onTypingStarted(); void onTypingStarted();

View File

@ -29,280 +29,281 @@
package eu.siacs.conversations.utils; package eu.siacs.conversations.utils;
import android.support.annotation.NonNull;
import android.util.LruCache; import android.util.LruCache;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.regex.Pattern; import java.util.regex.Pattern;
public class Emoticons { public class Emoticons {
private static final UnicodeRange MISC_SYMBOLS_AND_PICTOGRAPHS = new UnicodeRange(0x1F300,0x1F5FF); private static final UnicodeRange MISC_SYMBOLS_AND_PICTOGRAPHS = new UnicodeRange(0x1F300, 0x1F5FF);
private static final UnicodeRange SUPPLEMENTAL_SYMBOLS = new UnicodeRange(0x1F900,0x1F9FF); private static final UnicodeRange SUPPLEMENTAL_SYMBOLS = new UnicodeRange(0x1F900, 0x1F9FF);
private static final UnicodeRange EMOTICONS = new UnicodeRange(0x1F600,0x1F64F); private static final UnicodeRange EMOTICONS = new UnicodeRange(0x1F600, 0x1F64F);
private static final UnicodeRange TRANSPORT_SYMBOLS = new UnicodeRange(0x1F680,0x1F6FF); private static final UnicodeRange TRANSPORT_SYMBOLS = new UnicodeRange(0x1F680, 0x1F6FF);
private static final UnicodeRange MISC_SYMBOLS = new UnicodeRange(0x2600,0x26FF); private static final UnicodeRange MISC_SYMBOLS = new UnicodeRange(0x2600, 0x26FF);
private static final UnicodeRange DINGBATS = new UnicodeRange(0x2700,0x27BF); private static final UnicodeRange DINGBATS = new UnicodeRange(0x2700, 0x27BF);
private static final UnicodeRange ENCLOSED_ALPHANUMERIC_SUPPLEMENT = new UnicodeRange(0x1F100,0x1F1FF); private static final UnicodeRange ENCLOSED_ALPHANUMERIC_SUPPLEMENT = new UnicodeRange(0x1F100, 0x1F1FF);
private static final UnicodeRange ENCLOSED_IDEOGRAPHIC_SUPPLEMENT = new UnicodeRange(0x1F200,0x1F2FF); private static final UnicodeRange ENCLOSED_IDEOGRAPHIC_SUPPLEMENT = new UnicodeRange(0x1F200, 0x1F2FF);
private static final UnicodeRange REGIONAL_INDICATORS = new UnicodeRange(0x1F1E6,0x1F1FF); private static final UnicodeRange REGIONAL_INDICATORS = new UnicodeRange(0x1F1E6, 0x1F1FF);
private static final UnicodeRange GEOMETRIC_SHAPES = new UnicodeRange(0x25A0,0x25FF); private static final UnicodeRange GEOMETRIC_SHAPES = new UnicodeRange(0x25A0, 0x25FF);
private static final UnicodeRange LATIN_SUPPLEMENT = new UnicodeRange(0x80,0xFF); private static final UnicodeRange LATIN_SUPPLEMENT = new UnicodeRange(0x80, 0xFF);
private static final UnicodeRange MISC_TECHNICAL = new UnicodeRange(0x2300,0x23FF); private static final UnicodeRange MISC_TECHNICAL = new UnicodeRange(0x2300, 0x23FF);
private static final UnicodeRange TAGS = new UnicodeRange(0xE0020,0xE007F); private static final UnicodeRange TAGS = new UnicodeRange(0xE0020, 0xE007F);
private static final UnicodeList CYK_SYMBOLS_AND_PUNCTUATION = new UnicodeList(0x3030,0x303D); private static final UnicodeList CYK_SYMBOLS_AND_PUNCTUATION = new UnicodeList(0x3030, 0x303D);
private static final UnicodeList LETTERLIKE_SYMBOLS = new UnicodeList(0x2122,0x2139); private static final UnicodeList LETTERLIKE_SYMBOLS = new UnicodeList(0x2122, 0x2139);
private static final UnicodeBlocks KEYCAP_COMBINEABLE = new UnicodeBlocks(new UnicodeList(0x23),new UnicodeList(0x2A),new UnicodeRange(0x30,0x39)); private static final UnicodeBlocks KEYCAP_COMBINEABLE = new UnicodeBlocks(new UnicodeList(0x23), new UnicodeList(0x2A), new UnicodeRange(0x30, 0x39));
private static final UnicodeBlocks SYMBOLIZE = new UnicodeBlocks( private static final UnicodeBlocks SYMBOLIZE = new UnicodeBlocks(
GEOMETRIC_SHAPES, GEOMETRIC_SHAPES,
LATIN_SUPPLEMENT, LATIN_SUPPLEMENT,
CYK_SYMBOLS_AND_PUNCTUATION, CYK_SYMBOLS_AND_PUNCTUATION,
LETTERLIKE_SYMBOLS, LETTERLIKE_SYMBOLS,
KEYCAP_COMBINEABLE); KEYCAP_COMBINEABLE);
private static final UnicodeBlocks EMOJIS = new UnicodeBlocks( private static final UnicodeBlocks EMOJIS = new UnicodeBlocks(
MISC_SYMBOLS_AND_PICTOGRAPHS, MISC_SYMBOLS_AND_PICTOGRAPHS,
SUPPLEMENTAL_SYMBOLS, SUPPLEMENTAL_SYMBOLS,
EMOTICONS, EMOTICONS,
TRANSPORT_SYMBOLS, TRANSPORT_SYMBOLS,
MISC_SYMBOLS, MISC_SYMBOLS,
DINGBATS, DINGBATS,
ENCLOSED_ALPHANUMERIC_SUPPLEMENT, ENCLOSED_ALPHANUMERIC_SUPPLEMENT,
ENCLOSED_IDEOGRAPHIC_SUPPLEMENT, ENCLOSED_IDEOGRAPHIC_SUPPLEMENT,
MISC_TECHNICAL); MISC_TECHNICAL);
private static final int MAX_EMOIJS = 42; private static final int MAX_EMOIJS = 42;
private static final int ZWJ = 0x200D; private static final int ZWJ = 0x200D;
private static final int VARIATION_16 = 0xFE0F; private static final int VARIATION_16 = 0xFE0F;
private static final int COMBINING_ENCLOSING_KEYCAP = 0x20E3; private static final int COMBINING_ENCLOSING_KEYCAP = 0x20E3;
private static final int BLACK_FLAG = 0x1F3F4; private static final int BLACK_FLAG = 0x1F3F4;
private static final UnicodeRange FITZPATRICK = new UnicodeRange(0x1F3FB,0x1F3FF); private static final UnicodeRange FITZPATRICK = new UnicodeRange(0x1F3FB, 0x1F3FF);
private static final LruCache<CharSequence,Pattern> CACHE = new LruCache<>(256); private static final LruCache<CharSequence, Pattern> CACHE = new LruCache<>(256);
private static List<Symbol> parse(String input) { private static List<Symbol> parse(String input) {
List<Symbol> symbols = new ArrayList<>(); List<Symbol> symbols = new ArrayList<>();
Builder builder = new Builder(); Builder builder = new Builder();
boolean needsFinalBuild = false; boolean needsFinalBuild = false;
for (int cp, i = 0; i < input.length(); i += Character.charCount(cp)) { for (int cp, i = 0; i < input.length(); i += Character.charCount(cp)) {
cp = input.codePointAt(i); cp = input.codePointAt(i);
if (builder.offer(cp)) { if (builder.offer(cp)) {
needsFinalBuild = true; needsFinalBuild = true;
} else { } else {
symbols.add(builder.build()); symbols.add(builder.build());
builder = new Builder(); builder = new Builder();
if (builder.offer(cp)) { if (builder.offer(cp)) {
needsFinalBuild = true; needsFinalBuild = true;
} }
} }
} }
if (needsFinalBuild) { if (needsFinalBuild) {
symbols.add(builder.build()); symbols.add(builder.build());
} }
return symbols; return symbols;
} }
public static Pattern getEmojiPattern(CharSequence input) { public static Pattern getEmojiPattern(final CharSequence input) {
Pattern pattern = CACHE.get(input); Pattern pattern = CACHE.get(input);
if (pattern == null) { if (pattern == null) {
pattern = generatePattern(input); pattern = generatePattern(input);
CACHE.put(input, pattern); CACHE.put(input, pattern);
} }
return pattern; return pattern;
} }
private static Pattern generatePattern(CharSequence input) { private static Pattern generatePattern(CharSequence input) {
final HashSet<String> emojis = new HashSet<>(); final HashSet<String> emojis = new HashSet<>();
int i = 0; int i = 0;
for(Symbol symbol : parse(input.toString())) { for (final Symbol symbol : parse(input.toString())) {
if (symbol instanceof Emoji) { if (symbol instanceof Emoji) {
emojis.add(symbol.toString()); emojis.add(symbol.toString());
if (++i >= MAX_EMOIJS) { if (++i >= MAX_EMOIJS) {
return Pattern.compile(""); return Pattern.compile("");
} }
} }
} }
final StringBuilder pattern = new StringBuilder(); final StringBuilder pattern = new StringBuilder();
for(String emoji : emojis) { for (String emoji : emojis) {
if (pattern.length() != 0) { if (pattern.length() != 0) {
pattern.append('|'); pattern.append('|');
} }
pattern.append(Pattern.quote(emoji)); pattern.append(Pattern.quote(emoji));
} }
return Pattern.compile(pattern.toString()); return Pattern.compile(pattern.toString());
} }
public static boolean isEmoji(String input) { public static boolean isEmoji(String input) {
List<Symbol> symbols = parse(input); List<Symbol> symbols = parse(input);
return symbols.size() == 1 && symbols.get(0).isEmoji(); return symbols.size() == 1 && symbols.get(0).isEmoji();
} }
public static boolean isOnlyEmoji(String input) { public static boolean isOnlyEmoji(String input) {
List<Symbol> symbols = parse(input); List<Symbol> symbols = parse(input);
for(Symbol symbol : symbols) { for (Symbol symbol : symbols) {
if (!symbol.isEmoji()) { if (!symbol.isEmoji()) {
return false; return false;
} }
} }
return symbols.size() > 0; return symbols.size() > 0;
} }
private static abstract class Symbol { private static abstract class Symbol {
private final String value; private final String value;
public Symbol(List<Integer> codepoints) { Symbol(List<Integer> codepoints) {
StringBuilder builder = new StringBuilder(); final StringBuilder builder = new StringBuilder();
for(Integer codepoint : codepoints) { for (final Integer codepoint : codepoints) {
builder.appendCodePoint(codepoint); builder.appendCodePoint(codepoint);
} }
this.value = builder.toString(); this.value = builder.toString();
} }
abstract boolean isEmoji(); abstract boolean isEmoji();
@Override @NonNull
public String toString() { @Override
return value; public String toString() {
} return value;
} }
}
public static class Emoji extends Symbol { public static class Emoji extends Symbol {
public Emoji(List<Integer> codepoints) { Emoji(List<Integer> codepoints) {
super(codepoints); super(codepoints);
} }
@Override @Override
boolean isEmoji() { boolean isEmoji() {
return true; return true;
} }
} }
public static class Other extends Symbol { public static class Other extends Symbol {
public Other(List<Integer> codepoints) { public Other(List<Integer> codepoints) {
super(codepoints); super(codepoints);
} }
@Override @Override
boolean isEmoji() { boolean isEmoji() {
return false; return false;
} }
} }
private static class Builder { private static class Builder {
private final List<Integer> codepoints = new ArrayList<>(); private final List<Integer> codepoints = new ArrayList<>();
public boolean offer(int codepoint) { public boolean offer(int codepoint) {
boolean add = false; boolean add = false;
if (this.codepoints.size() == 0) { if (this.codepoints.size() == 0) {
if (SYMBOLIZE.contains(codepoint)) { if (SYMBOLIZE.contains(codepoint)) {
add = true; add = true;
} else if (REGIONAL_INDICATORS.contains(codepoint)) { } else if (REGIONAL_INDICATORS.contains(codepoint)) {
add = true; add = true;
} else if (EMOJIS.contains(codepoint) && !FITZPATRICK.contains(codepoint) && codepoint != ZWJ) { } else if (EMOJIS.contains(codepoint) && !FITZPATRICK.contains(codepoint) && codepoint != ZWJ) {
add = true; add = true;
} }
} else { } else {
int previous = codepoints.get(codepoints.size() -1); int previous = codepoints.get(codepoints.size() - 1);
if (codepoints.get(0) == BLACK_FLAG) { if (codepoints.get(0) == BLACK_FLAG) {
add = TAGS.contains(codepoint); add = TAGS.contains(codepoint);
} else if (COMBINING_ENCLOSING_KEYCAP == codepoint) { } else if (COMBINING_ENCLOSING_KEYCAP == codepoint) {
add = KEYCAP_COMBINEABLE.contains(previous) || previous == VARIATION_16; add = KEYCAP_COMBINEABLE.contains(previous) || previous == VARIATION_16;
} else if (SYMBOLIZE.contains(previous)) { } else if (SYMBOLIZE.contains(previous)) {
add = codepoint == VARIATION_16; add = codepoint == VARIATION_16;
} else if (REGIONAL_INDICATORS.contains(previous) && REGIONAL_INDICATORS.contains(codepoint)) { } else if (REGIONAL_INDICATORS.contains(previous) && REGIONAL_INDICATORS.contains(codepoint)) {
add = codepoints.size() == 1; add = codepoints.size() == 1;
} else if (previous == VARIATION_16) { } else if (previous == VARIATION_16) {
add = isMerger(codepoint); add = isMerger(codepoint) || codepoint == VARIATION_16;
} else if (FITZPATRICK.contains(previous)) { } else if (FITZPATRICK.contains(previous)) {
add = codepoint == ZWJ; add = codepoint == ZWJ;
} else if (ZWJ == previous) { } else if (ZWJ == previous) {
add = EMOJIS.contains(codepoint); add = EMOJIS.contains(codepoint);
} else if (isMerger(codepoint)) { } else if (isMerger(codepoint)) {
add = true; add = true;
} else if (codepoint == VARIATION_16 && EMOJIS.contains(previous)) { } else if (codepoint == VARIATION_16 && EMOJIS.contains(previous)) {
add = true; add = true;
} }
} }
if (add) { if (add) {
codepoints.add(codepoint); codepoints.add(codepoint);
return true; return true;
} else { } else {
return false; return false;
} }
} }
private static boolean isMerger(int codepoint) { private static boolean isMerger(int codepoint) {
return codepoint == ZWJ || FITZPATRICK.contains(codepoint); return codepoint == ZWJ || FITZPATRICK.contains(codepoint);
} }
public Symbol build() { public Symbol build() {
if (codepoints.size() > 0 && SYMBOLIZE.contains(codepoints.get(codepoints.size() - 1))) { if (codepoints.size() > 0 && SYMBOLIZE.contains(codepoints.get(codepoints.size() - 1))) {
return new Other(codepoints); return new Other(codepoints);
} else if (codepoints.size() > 1 && KEYCAP_COMBINEABLE.contains(codepoints.get(0)) && codepoints.get(codepoints.size() - 1) != COMBINING_ENCLOSING_KEYCAP) { } else if (codepoints.size() > 1 && KEYCAP_COMBINEABLE.contains(codepoints.get(0)) && codepoints.get(codepoints.size() - 1) != COMBINING_ENCLOSING_KEYCAP) {
return new Other(codepoints); return new Other(codepoints);
} }
return codepoints.size() == 0 ? new Other(codepoints): new Emoji(codepoints); return codepoints.size() == 0 ? new Other(codepoints) : new Emoji(codepoints);
} }
} }
public static class UnicodeBlocks implements UnicodeSet { public static class UnicodeBlocks implements UnicodeSet {
final UnicodeSet[] unicodeSets; final UnicodeSet[] unicodeSets;
public UnicodeBlocks(UnicodeSet... sets) { UnicodeBlocks(final UnicodeSet... sets) {
this.unicodeSets = sets; this.unicodeSets = sets;
} }
@Override @Override
public boolean contains(int codepoint) { public boolean contains(int codepoint) {
for(UnicodeSet unicodeSet : unicodeSets) { for (UnicodeSet unicodeSet : unicodeSets) {
if (unicodeSet.contains(codepoint)) { if (unicodeSet.contains(codepoint)) {
return true; return true;
} }
} }
return false; return false;
} }
} }
public interface UnicodeSet { public interface UnicodeSet {
boolean contains(int codepoint); boolean contains(int codepoint);
} }
public static class UnicodeList implements UnicodeSet { public static class UnicodeList implements UnicodeSet {
private final List<Integer> list; private final List<Integer> list;
public UnicodeList(Integer... codes) { UnicodeList(final Integer... codes) {
this.list = Arrays.asList(codes); this.list = Arrays.asList(codes);
} }
@Override @Override
public boolean contains(int codepoint) { public boolean contains(int codepoint) {
return this.list.contains(codepoint); return this.list.contains(codepoint);
} }
} }
public static class UnicodeRange implements UnicodeSet { public static class UnicodeRange implements UnicodeSet {
private final int lower; private final int lower;
private final int upper; private final int upper;
UnicodeRange(int lower, int upper) { UnicodeRange(int lower, int upper) {
this.lower = lower; this.lower = lower;
this.upper = upper; this.upper = upper;
} }
public boolean contains(int codePoint) { public boolean contains(int codePoint) {
return codePoint >= lower && codePoint <= upper; return codePoint >= lower && codePoint <= upper;
} }
} }
} }

View File

@ -1085,8 +1085,8 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
return webRTCWrapper.isMicrophoneEnabled(); return webRTCWrapper.isMicrophoneEnabled();
} }
public void setMicrophoneEnabled(final boolean enabled) { public boolean setMicrophoneEnabled(final boolean enabled) {
webRTCWrapper.setMicrophoneEnabled(enabled); return webRTCWrapper.setMicrophoneEnabled(enabled);
} }
public boolean isVideoEnabled() { public boolean isVideoEnabled() {

View File

@ -370,12 +370,19 @@ public class WebRTCWrapper {
} }
} }
void setMicrophoneEnabled(final boolean enabled) { boolean setMicrophoneEnabled(final boolean enabled) {
final AudioTrack audioTrack = this.localAudioTrack; final AudioTrack audioTrack = this.localAudioTrack;
if (audioTrack == null) { if (audioTrack == null) {
throw new IllegalStateException("Local audio track does not exist (yet)"); throw new IllegalStateException("Local audio track does not exist (yet)");
} }
audioTrack.setEnabled(enabled); try {
audioTrack.setEnabled(enabled);
return true;
} catch (final IllegalStateException e) {
Log.d(Config.LOGTAG, "unable to toggle microphone", e);
//ignoring race condition in case MediaStreamTrack has been disposed
return false;
}
} }
boolean isVideoEnabled() { boolean isVideoEnabled() {
@ -502,7 +509,7 @@ public class WebRTCWrapper {
final CameraEnumerator enumerator = getCameraEnumerator(); final CameraEnumerator enumerator = getCameraEnumerator();
final Set<String> deviceNames = ImmutableSet.copyOf(enumerator.getDeviceNames()); final Set<String> deviceNames = ImmutableSet.copyOf(enumerator.getDeviceNames());
for (final String deviceName : deviceNames) { for (final String deviceName : deviceNames) {
if (enumerator.isFrontFacing(deviceName)) { if (isFrontFacing(enumerator, deviceName)) {
final CapturerChoice capturerChoice = of(enumerator, deviceName, deviceNames); final CapturerChoice capturerChoice = of(enumerator, deviceName, deviceNames);
if (capturerChoice == null) { if (capturerChoice == null) {
return Optional.absent(); return Optional.absent();
@ -518,6 +525,14 @@ public class WebRTCWrapper {
} }
} }
private static boolean isFrontFacing(final CameraEnumerator cameraEnumerator, final String deviceName) {
try {
return cameraEnumerator.isFrontFacing(deviceName);
} catch (final NullPointerException e) {
return false;
}
}
public PeerConnection.PeerConnectionState getState() { public PeerConnection.PeerConnectionState getState() {
return requirePeerConnection().connectionState(); return requirePeerConnection().connectionState();
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 320 B

View File

@ -1,11 +1,16 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" <menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"> xmlns:app="http://schemas.android.com/apk/res-auto">
<item <item
android:id="@+id/action_help" android:id="@+id/action_help"
android:icon="?attr/icon_help" android:icon="?attr/icon_help"
android:title="@string/help" android:title="@string/help"
app:showAsAction="always"/> app:showAsAction="always" />
<item
android:id="@+id/action_goto_chat"
android:icon="?attr/icon_goto_chat"
android:title="@string/switch_to_conversation"
app:showAsAction="always" />
</menu> </menu>

View File

@ -316,7 +316,6 @@
<string name="reply">الرد</string> <string name="reply">الرد</string>
<string name="mark_as_read">إعتباره كمقروء</string> <string name="mark_as_read">إعتباره كمقروء</string>
<string name="pref_enter_is_send">أدخل للإرسال</string> <string name="pref_enter_is_send">أدخل للإرسال</string>
<string name="pref_enter_is_send_summary">استخدام مفتاح الدخول لإرسال رسالة</string>
<string name="pref_display_enter_key">عرض مفتاح الادخال</string> <string name="pref_display_enter_key">عرض مفتاح الادخال</string>
<string name="pref_display_enter_key_summary">تغيير مفتاح الرموز إلى مفتاح الدخول</string> <string name="pref_display_enter_key_summary">تغيير مفتاح الرموز إلى مفتاح الدخول</string>
<string name="audio">صوت</string> <string name="audio">صوت</string>

View File

@ -316,7 +316,6 @@
<string name="mark_as_read">Отбелязване като прочетено</string> <string name="mark_as_read">Отбелязване като прочетено</string>
<string name="pref_input_options">Въвеждане</string> <string name="pref_input_options">Въвеждане</string>
<string name="pref_enter_is_send">Enter изпраща</string> <string name="pref_enter_is_send">Enter изпраща</string>
<string name="pref_enter_is_send_summary">Натискането на клавиша Enter изпраща съобщението</string>
<string name="pref_display_enter_key">Показване на клавиша Enter</string> <string name="pref_display_enter_key">Показване на клавиша Enter</string>
<string name="pref_display_enter_key_summary">Смяна на клавиша за емотикони с клавиша Enter</string> <string name="pref_display_enter_key_summary">Смяна на клавиша за емотикони с клавиша Enter</string>
<string name="audio">аудио</string> <string name="audio">аудио</string>

View File

@ -314,7 +314,6 @@
<string name="mark_as_read">Marcar com llegit</string> <string name="mark_as_read">Marcar com llegit</string>
<string name="pref_input_options">Entrada</string> <string name="pref_input_options">Entrada</string>
<string name="pref_enter_is_send">Entra per enviar</string> <string name="pref_enter_is_send">Entra per enviar</string>
<string name="pref_enter_is_send_summary">Utilitza el botó enter per enviar el missatge</string>
<string name="pref_display_enter_key">Mostra el botó enter</string> <string name="pref_display_enter_key">Mostra el botó enter</string>
<string name="pref_display_enter_key_summary">Canviar la clau dels emoticones per un botó d\'entrada </string> <string name="pref_display_enter_key_summary">Canviar la clau dels emoticones per un botó d\'entrada </string>
<string name="audio">audio</string> <string name="audio">audio</string>

View File

@ -264,7 +264,6 @@
<string name="until_further_notice">Než opět změním</string> <string name="until_further_notice">Než opět změním</string>
<string name="pref_input_options">Vstup</string> <string name="pref_input_options">Vstup</string>
<string name="pref_enter_is_send">Enter odesílá</string> <string name="pref_enter_is_send">Enter odesílá</string>
<string name="pref_enter_is_send_summary">Použít klávesu enter pro odesílání zpráv</string>
<string name="pref_display_enter_key">Zobrazit klávesu enter</string> <string name="pref_display_enter_key">Zobrazit klávesu enter</string>
<string name="pref_display_enter_key_summary">Změnit klávesu emotikon na klávesu enter</string> <string name="pref_display_enter_key_summary">Změnit klávesu emotikon na klávesu enter</string>
<string name="audio">audio</string> <string name="audio">audio</string>

View File

@ -400,10 +400,10 @@
<string name="reply">Antworten</string> <string name="reply">Antworten</string>
<string name="mark_as_read">Als gelesen markieren</string> <string name="mark_as_read">Als gelesen markieren</string>
<string name="pref_input_options">Eingabe</string> <string name="pref_input_options">Eingabe</string>
<string name="pref_enter_is_send">Eingabe-Taste (Enter) sendet Nachricht</string> <string name="pref_enter_is_send">Eingabetaste sendet Nachricht</string>
<string name="pref_enter_is_send_summary">Eingabe-Taste (Enter) zum Versenden einer Nachricht verwenden</string> <string name="pref_enter_is_send_summary">Nutze die Eingabetaste zum Versenden einer Nachricht. Strg+Eingabetaste sendet die Nachricht unabhängig von dieser Einstellung.</string>
<string name="pref_display_enter_key">Zeige Eingabe-Taste (Enter)</string> <string name="pref_display_enter_key">Zeige Eingabetaste</string>
<string name="pref_display_enter_key_summary">Emoji-Taste durch Eingabe-Taste ersetzen</string> <string name="pref_display_enter_key_summary">Emoji-Taste durch Eingabetaste ersetzen</string>
<string name="audio">Audio</string> <string name="audio">Audio</string>
<string name="video">Video</string> <string name="video">Video</string>
<string name="image">Bild</string> <string name="image">Bild</string>
@ -916,6 +916,7 @@
<string name="audio_call">Audioanruf</string> <string name="audio_call">Audioanruf</string>
<string name="video_call">Videoanruf</string> <string name="video_call">Videoanruf</string>
<string name="help">Hilfe</string> <string name="help">Hilfe</string>
<string name="switch_to_conversation">Zur Unterhaltung wechseln</string>
<string name="microphone_unavailable">Dein Mikrofon ist nicht verfügbar</string> <string name="microphone_unavailable">Dein Mikrofon ist nicht verfügbar</string>
<string name="only_one_call_at_a_time">Du kannst immer nur einen Anruf zur gleichen Zeit machen.</string> <string name="only_one_call_at_a_time">Du kannst immer nur einen Anruf zur gleichen Zeit machen.</string>
<string name="return_to_ongoing_call">Zurück zum laufenden Aufruf</string> <string name="return_to_ongoing_call">Zurück zum laufenden Aufruf</string>

View File

@ -347,7 +347,6 @@
<string name="mark_as_read">Σημείωμα ως αναγνωσμένο</string> <string name="mark_as_read">Σημείωμα ως αναγνωσμένο</string>
<string name="pref_input_options">Είσοδος</string> <string name="pref_input_options">Είσοδος</string>
<string name="pref_enter_is_send">Αποστολή με το πλήκτρο Enter</string> <string name="pref_enter_is_send">Αποστολή με το πλήκτρο Enter</string>
<string name="pref_enter_is_send_summary">Χρήση του πλήκτρου Enter για την αποστολή μηνύματος</string>
<string name="pref_display_enter_key">Εμφάνιση του πλήκτρου Enter</string> <string name="pref_display_enter_key">Εμφάνιση του πλήκτρου Enter</string>
<string name="pref_display_enter_key_summary">Αλλαγή του πλήκτρου emoticons σε πλήκτρο Enter</string> <string name="pref_display_enter_key_summary">Αλλαγή του πλήκτρου emoticons σε πλήκτρο Enter</string>
<string name="audio">ήχος</string> <string name="audio">ήχος</string>

View File

@ -401,7 +401,7 @@
<string name="mark_as_read">Marcar como leído</string> <string name="mark_as_read">Marcar como leído</string>
<string name="pref_input_options">Entrada</string> <string name="pref_input_options">Entrada</string>
<string name="pref_enter_is_send">Intro para enviar</string> <string name="pref_enter_is_send">Intro para enviar</string>
<string name="pref_enter_is_send_summary">Usar la tecla intro para enviar el mensaje</string> <string name="pref_enter_is_send_summary">Utilizar la tecla Enter para enviar un mensaje. Siempre puedes usar Ctrl+Enter para enviar un mensaje, incluso si esta opción está deshabilitada.</string>
<string name="pref_display_enter_key">Mostrar tecla Intro</string> <string name="pref_display_enter_key">Mostrar tecla Intro</string>
<string name="pref_display_enter_key_summary">Cambiar la tecla de emoticonos por la tecla Intro</string> <string name="pref_display_enter_key_summary">Cambiar la tecla de emoticonos por la tecla Intro</string>
<string name="audio">audio</string> <string name="audio">audio</string>
@ -916,6 +916,7 @@
<string name="audio_call">Audio llamada</string> <string name="audio_call">Audio llamada</string>
<string name="video_call">Video llamada</string> <string name="video_call">Video llamada</string>
<string name="help">Ayuda</string> <string name="help">Ayuda</string>
<string name="switch_to_conversation">Cambiar a conversación</string>
<string name="microphone_unavailable">Tu micrófono no está disponible</string> <string name="microphone_unavailable">Tu micrófono no está disponible</string>
<string name="only_one_call_at_a_time">Solo puedes hacer una llamada a la vez</string> <string name="only_one_call_at_a_time">Solo puedes hacer una llamada a la vez</string>
<string name="return_to_ongoing_call">Volver a la llamada en curso</string> <string name="return_to_ongoing_call">Volver a la llamada en curso</string>

View File

@ -344,7 +344,6 @@
<string name="mark_as_read">Irakurrita bezala markatu</string> <string name="mark_as_read">Irakurrita bezala markatu</string>
<string name="pref_input_options">Sarrera</string> <string name="pref_input_options">Sarrera</string>
<string name="pref_enter_is_send">Sartu teklak bidaltzen du</string> <string name="pref_enter_is_send">Sartu teklak bidaltzen du</string>
<string name="pref_enter_is_send_summary">Sartu tekla erabili mezua bidaltzeko</string>
<string name="pref_display_enter_key">Sartu tekla erakutsi</string> <string name="pref_display_enter_key">Sartu tekla erakutsi</string>
<string name="pref_display_enter_key_summary">Aurpegieren tekla sartu teklarekin aldatu</string> <string name="pref_display_enter_key_summary">Aurpegieren tekla sartu teklarekin aldatu</string>
<string name="audio">audioa</string> <string name="audio">audioa</string>

View File

@ -401,7 +401,6 @@
<string name="mark_as_read">Marquer comme lu</string> <string name="mark_as_read">Marquer comme lu</string>
<string name="pref_input_options">Saisie</string> <string name="pref_input_options">Saisie</string>
<string name="pref_enter_is_send">Touche Entrée pour envoyer</string> <string name="pref_enter_is_send">Touche Entrée pour envoyer</string>
<string name="pref_enter_is_send_summary">Utiliser la touche Entrée pour envoyer un message.</string>
<string name="pref_display_enter_key">Afficher la touche Entrée</string> <string name="pref_display_enter_key">Afficher la touche Entrée</string>
<string name="pref_display_enter_key_summary">Remplacer la touche Émoticônes par une touche Entrée.</string> <string name="pref_display_enter_key_summary">Remplacer la touche Émoticônes par une touche Entrée.</string>
<string name="audio">audio</string> <string name="audio">audio</string>

View File

@ -401,7 +401,7 @@
<string name="mark_as_read">Marcar como lido</string> <string name="mark_as_read">Marcar como lido</string>
<string name="pref_input_options">Entrada</string> <string name="pref_input_options">Entrada</string>
<string name="pref_enter_is_send">Enter envía</string> <string name="pref_enter_is_send">Enter envía</string>
<string name="pref_enter_is_send_summary">Utilizar a tecla Enter para enviar mensaxe</string> <string name="pref_enter_is_send_summary">Usa a tecla Enter para enviar a mensaxe. Igualmente poderás usar Ctrl+Enter para enviar, incluso se esta opción está desactivada.</string>
<string name="pref_display_enter_key">Mostrar a tecla Enter</string> <string name="pref_display_enter_key">Mostrar a tecla Enter</string>
<string name="pref_display_enter_key_summary">Cambiar a chave de emoticonas pola tecla Enter</string> <string name="pref_display_enter_key_summary">Cambiar a chave de emoticonas pola tecla Enter</string>
<string name="audio">son</string> <string name="audio">son</string>
@ -916,6 +916,7 @@
<string name="audio_call">Chamada de audio</string> <string name="audio_call">Chamada de audio</string>
<string name="video_call">Chamada de vídeo</string> <string name="video_call">Chamada de vídeo</string>
<string name="help">Axuda</string> <string name="help">Axuda</string>
<string name="switch_to_conversation">Ir á conversa</string>
<string name="microphone_unavailable">O micrófono non está dispoñible</string> <string name="microphone_unavailable">O micrófono non está dispoñible</string>
<string name="only_one_call_at_a_time">Só podes manter unha chamada en cada momento.</string> <string name="only_one_call_at_a_time">Só podes manter unha chamada en cada momento.</string>
<string name="return_to_ongoing_call">Voltar á chamada activa</string> <string name="return_to_ongoing_call">Voltar á chamada activa</string>

View File

@ -384,7 +384,6 @@
<string name="mark_as_read">Megjelölés olvasottként</string> <string name="mark_as_read">Megjelölés olvasottként</string>
<string name="pref_input_options">Bevitel</string> <string name="pref_input_options">Bevitel</string>
<string name="pref_enter_is_send">Küldés enterrel</string> <string name="pref_enter_is_send">Küldés enterrel</string>
<string name="pref_enter_is_send_summary">Az enter billentyű használata az üzenet küldéséhez</string>
<string name="pref_display_enter_key">Enter billentyű megjelenítése</string> <string name="pref_display_enter_key">Enter billentyű megjelenítése</string>
<string name="pref_display_enter_key_summary">Hangulatjelek billentyű megváltoztatása az enter billentyűre</string> <string name="pref_display_enter_key_summary">Hangulatjelek billentyű megváltoztatása az enter billentyűre</string>
<string name="audio">hang</string> <string name="audio">hang</string>

View File

@ -226,7 +226,6 @@
<string name="until_further_notice">Sampai pemberitahuan selanjutnya</string> <string name="until_further_notice">Sampai pemberitahuan selanjutnya</string>
<string name="pref_input_options">Masukan</string> <string name="pref_input_options">Masukan</string>
<string name="pref_enter_is_send">Enter untuk mengirim</string> <string name="pref_enter_is_send">Enter untuk mengirim</string>
<string name="pref_enter_is_send_summary">Gunakan enter untuk mengrim pesan</string>
<string name="pref_display_enter_key">Tampilkan masukan kunci</string> <string name="pref_display_enter_key">Tampilkan masukan kunci</string>
<string name="pref_display_enter_key_summary">Mengubah kunci emoji untuk memasukan kunci</string> <string name="pref_display_enter_key_summary">Mengubah kunci emoji untuk memasukan kunci</string>
<string name="audio">audio</string> <string name="audio">audio</string>

View File

@ -401,7 +401,6 @@
<string name="mark_as_read">Segna come già letto</string> <string name="mark_as_read">Segna come già letto</string>
<string name="pref_input_options">Input</string> <string name="pref_input_options">Input</string>
<string name="pref_enter_is_send">Invio spedisce</string> <string name="pref_enter_is_send">Invio spedisce</string>
<string name="pref_enter_is_send_summary">Il tasto invio spedisce il messaggio</string>
<string name="pref_display_enter_key">Mostra il tasto invio</string> <string name="pref_display_enter_key">Mostra il tasto invio</string>
<string name="pref_display_enter_key_summary">Cambia il tasto delle faccine nel tasto di invio</string> <string name="pref_display_enter_key_summary">Cambia il tasto delle faccine nel tasto di invio</string>
<string name="audio">audio</string> <string name="audio">audio</string>

View File

@ -220,7 +220,6 @@
<string name="never">לעולם לא</string> <string name="never">לעולם לא</string>
<string name="until_further_notice">עד אחרית הימים</string> <string name="until_further_notice">עד אחרית הימים</string>
<string name="pref_enter_is_send">לחצן Enter שולח את ההודעה</string> <string name="pref_enter_is_send">לחצן Enter שולח את ההודעה</string>
<string name="pref_enter_is_send_summary">השתמש בלחצן ה-Enter כלחצן השליחה</string>
<string name="pref_display_enter_key">הראה את לחצן ה Enter</string> <string name="pref_display_enter_key">הראה את לחצן ה Enter</string>
<string name="pref_display_enter_key_summary">שנה את לחצן האימוג\'י ללחצן Enter</string> <string name="pref_display_enter_key_summary">שנה את לחצן האימוג\'י ללחצן Enter</string>
<string name="audio">קול</string> <string name="audio">קול</string>

View File

@ -316,7 +316,6 @@
<string name="mark_as_read">既読にする</string> <string name="mark_as_read">既読にする</string>
<string name="pref_input_options">入力</string> <string name="pref_input_options">入力</string>
<string name="pref_enter_is_send">Enter は送信</string> <string name="pref_enter_is_send">Enter は送信</string>
<string name="pref_enter_is_send_summary">Enter キーをメッセージの送信に使用します</string>
<string name="pref_display_enter_key">Enter キーを表示</string> <string name="pref_display_enter_key">Enter キーを表示</string>
<string name="pref_display_enter_key_summary">絵文字キーを Enter キーに変更</string> <string name="pref_display_enter_key_summary">絵文字キーを Enter キーに変更</string>
<string name="audio">オーディオ</string> <string name="audio">オーディオ</string>

View File

@ -257,7 +257,6 @@
<string name="until_further_notice">나중에 알릴때까지 </string> <string name="until_further_notice">나중에 알릴때까지 </string>
<string name="pref_input_options">입력</string> <string name="pref_input_options">입력</string>
<string name="pref_enter_is_send">엔터 키로 전송 </string> <string name="pref_enter_is_send">엔터 키로 전송 </string>
<string name="pref_enter_is_send_summary">엔터 키로 메세지를 보냅니다 </string>
<string name="pref_display_enter_key">엔터 키 표시 </string> <string name="pref_display_enter_key">엔터 키 표시 </string>
<string name="pref_display_enter_key_summary">이모티콘 키를 엔터 키로 바꿉니다 </string> <string name="pref_display_enter_key_summary">이모티콘 키를 엔터 키로 바꿉니다 </string>
<string name="audio">오디오 </string> <string name="audio">오디오 </string>

View File

@ -285,7 +285,6 @@
<string name="mark_as_read">Merk som lest</string> <string name="mark_as_read">Merk som lest</string>
<string name="pref_input_options">Inndata</string> <string name="pref_input_options">Inndata</string>
<string name="pref_enter_is_send">Enter-forsendelsesknapp</string> <string name="pref_enter_is_send">Enter-forsendelsesknapp</string>
<string name="pref_enter_is_send_summary">Bruk enter for å sende en melding</string>
<string name="pref_display_enter_key">Vis enter-tast</string> <string name="pref_display_enter_key">Vis enter-tast</string>
<string name="pref_display_enter_key_summary">Endre smilefjas-tast til en enter-tast</string> <string name="pref_display_enter_key_summary">Endre smilefjas-tast til en enter-tast</string>
<string name="audio">lyd</string> <string name="audio">lyd</string>

View File

@ -356,7 +356,6 @@
<string name="mark_as_read">Markeren als gelezen</string> <string name="mark_as_read">Markeren als gelezen</string>
<string name="pref_input_options">Invoer</string> <string name="pref_input_options">Invoer</string>
<string name="pref_enter_is_send">Enter is versturen</string> <string name="pref_enter_is_send">Enter is versturen</string>
<string name="pref_enter_is_send_summary">Gebruik de enter-toets om berichten te versturen</string>
<string name="pref_display_enter_key">Toon enter-toets</string> <string name="pref_display_enter_key">Toon enter-toets</string>
<string name="pref_display_enter_key_summary">Verander de emoticon-toets in een enter-toets</string> <string name="pref_display_enter_key_summary">Verander de emoticon-toets in een enter-toets</string>
<string name="audio">audio</string> <string name="audio">audio</string>

View File

@ -401,7 +401,6 @@
<string name="mark_as_read">Oznacz jako przeczytane</string> <string name="mark_as_read">Oznacz jako przeczytane</string>
<string name="pref_input_options">Ustawienia wprowadzania</string> <string name="pref_input_options">Ustawienia wprowadzania</string>
<string name="pref_enter_is_send">Enter wysyła</string> <string name="pref_enter_is_send">Enter wysyła</string>
<string name="pref_enter_is_send_summary">Używaj klawisza Enter do wysyłania wiadomości</string>
<string name="pref_display_enter_key">Pokaż klawisz Enter</string> <string name="pref_display_enter_key">Pokaż klawisz Enter</string>
<string name="pref_display_enter_key_summary">Zamień klawisz emotikon na klawisz Enter</string> <string name="pref_display_enter_key_summary">Zamień klawisz emotikon na klawisz Enter</string>
<string name="audio">plik audio</string> <string name="audio">plik audio</string>

View File

@ -401,7 +401,6 @@
<string name="mark_as_read">Marcar como lida</string> <string name="mark_as_read">Marcar como lida</string>
<string name="pref_input_options">Entrada</string> <string name="pref_input_options">Entrada</string>
<string name="pref_enter_is_send">Enter envia</string> <string name="pref_enter_is_send">Enter envia</string>
<string name="pref_enter_is_send_summary">Usa o botão Enter para enviar a mensagem.</string>
<string name="pref_display_enter_key">Exibir o botão Enter</string> <string name="pref_display_enter_key">Exibir o botão Enter</string>
<string name="pref_display_enter_key_summary">Altera o botão de emoticons para um botão Enter.</string> <string name="pref_display_enter_key_summary">Altera o botão de emoticons para um botão Enter.</string>
<string name="audio">áudio</string> <string name="audio">áudio</string>

View File

@ -279,7 +279,6 @@
<string name="mark_as_read">Marcar como lida</string> <string name="mark_as_read">Marcar como lida</string>
<string name="pref_input_options">Introdução</string> <string name="pref_input_options">Introdução</string>
<string name="pref_enter_is_send">O enter envia</string> <string name="pref_enter_is_send">O enter envia</string>
<string name="pref_enter_is_send_summary">Use o enter para enviar a mensagem</string>
<string name="pref_display_enter_key">Exibir tecla enter</string> <string name="pref_display_enter_key">Exibir tecla enter</string>
<string name="pref_display_enter_key_summary">Alterar a tecla dos emoticons para uma tecla enter</string> <string name="pref_display_enter_key_summary">Alterar a tecla dos emoticons para uma tecla enter</string>
<string name="audio">áudio</string> <string name="audio">áudio</string>

View File

@ -401,7 +401,7 @@
<string name="mark_as_read">Marchează ca citit</string> <string name="mark_as_read">Marchează ca citit</string>
<string name="pref_input_options">Opțiuni introducere text</string> <string name="pref_input_options">Opțiuni introducere text</string>
<string name="pref_enter_is_send">ENTER trimite</string> <string name="pref_enter_is_send">ENTER trimite</string>
<string name="pref_enter_is_send_summary">Apasă tasta ENTER pentru a trimite mesajul</string> <string name="pref_enter_is_send_summary">Apasă tasta Enter pentru a trimite mesajul. Puteți mereu apăsa Ctrl-Enter pentru a trimite mesajul, chiar dacă această opțiune nu este activată.</string>
<string name="pref_display_enter_key">Arată tasta ENTER</string> <string name="pref_display_enter_key">Arată tasta ENTER</string>
<string name="pref_display_enter_key_summary">Preschimbă tasta emoticon în ENTER</string> <string name="pref_display_enter_key_summary">Preschimbă tasta emoticon în ENTER</string>
<string name="audio">audio</string> <string name="audio">audio</string>
@ -924,6 +924,7 @@
<string name="audio_call">Apel audio</string> <string name="audio_call">Apel audio</string>
<string name="video_call">Apel video</string> <string name="video_call">Apel video</string>
<string name="help">Ajutor</string> <string name="help">Ajutor</string>
<string name="switch_to_conversation">Comutare la discuție</string>
<string name="microphone_unavailable">Microfonul nu este disponibil</string> <string name="microphone_unavailable">Microfonul nu este disponibil</string>
<string name="only_one_call_at_a_time">Puteți avea un singur apel simultan.</string> <string name="only_one_call_at_a_time">Puteți avea un singur apel simultan.</string>
<string name="return_to_ongoing_call">Reveniți la apelul în curs</string> <string name="return_to_ongoing_call">Reveniți la apelul în curs</string>

View File

@ -121,11 +121,15 @@
<string name="pref_notification_sound_summary">Звук уведомления о новых сообщениях</string> <string name="pref_notification_sound_summary">Звук уведомления о новых сообщениях</string>
<string name="pref_call_ringtone_summary">Мелодия входящего звонка</string> <string name="pref_call_ringtone_summary">Мелодия входящего звонка</string>
<string name="pref_notification_grace_period">Грейс-период</string> <string name="pref_notification_grace_period">Грейс-период</string>
<string name="pref_notification_grace_period_summary">Время, на которое уведомления будут отключены, когда вы пользуетесь аккаунтом на другом устройстве.</string>
<string name="pref_advanced_options">Дополнительно</string> <string name="pref_advanced_options">Дополнительно</string>
<string name="pref_never_send_crash">Не отправлять отчёты об ошибках</string> <string name="pref_never_send_crash">Не отправлять отчёты об ошибках</string>
<string name="pref_never_send_crash_summary">Отправляя отчеты об ошибках, вы помогаете разработке этого приложения</string>
<string name="pref_confirm_messages">Отчёты о получении</string> <string name="pref_confirm_messages">Отчёты о получении</string>
<string name="pref_confirm_messages_summary">Позволяет вашим контактам видеть, когда вы получили и прочитали их сообщения</string> <string name="pref_confirm_messages_summary">Позволяет вашим контактам видеть, когда вы получили и прочитали их сообщения</string>
<string name="pref_ui_options">Интерфейс</string> <string name="pref_ui_options">Интерфейс</string>
<string name="openpgp_error">OpenKeychain вызвал ошибку.</string>
<string name="bad_key_for_encryption">Неподходящий ключ для шифрования.</string>
<string name="accept">Принять</string> <string name="accept">Принять</string>
<string name="error">Произошла ошибка</string> <string name="error">Произошла ошибка</string>
<string name="recording_error">Ошибка</string> <string name="recording_error">Ошибка</string>
@ -137,8 +141,10 @@
<string name="attach_take_picture">Сделать снимок</string> <string name="attach_take_picture">Сделать снимок</string>
<string name="preemptively_grant">Удовлетворять запросы на подписки</string> <string name="preemptively_grant">Удовлетворять запросы на подписки</string>
<string name="error_not_an_image_file">Выбранный файл не является изображением</string> <string name="error_not_an_image_file">Выбранный файл не является изображением</string>
<string name="error_compressing_image">Не удалось конвертировать изображение</string>
<string name="error_file_not_found">Файл не найден</string> <string name="error_file_not_found">Файл не найден</string>
<string name="error_io_exception">Общая ошибка ввода/вывода. Возможно, на устройстве недостаточно свободного места?</string> <string name="error_io_exception">Общая ошибка ввода/вывода. Возможно, на устройстве недостаточно свободного места?</string>
<string name="error_security_exception_during_image_copy">У приложения, которым вы выбрали это изображение, недостаточно прав, чтобы прочитать этот файл.\n\n<small>Пожалуйста, используйте другой файловый менеджер, чтобы выбрать это изображение</small>.</string>
<string name="account_status_unknown">Неизвестен</string> <string name="account_status_unknown">Неизвестен</string>
<string name="account_status_disabled">Временно отключён</string> <string name="account_status_disabled">Временно отключён</string>
<string name="account_status_online">В сети</string> <string name="account_status_online">В сети</string>
@ -150,6 +156,8 @@
<string name="account_status_regis_fail">Регистрация не удалась</string> <string name="account_status_regis_fail">Регистрация не удалась</string>
<string name="account_status_regis_conflict">Имя пользователя уже используется</string> <string name="account_status_regis_conflict">Имя пользователя уже используется</string>
<string name="account_status_regis_success">Регистрация завершена</string> <string name="account_status_regis_success">Регистрация завершена</string>
<string name="account_status_regis_not_sup">Сервер не поддерживает возможность регистрации</string>
<string name="account_status_regis_invalid_token">Неправильный токен регистрации</string>
<string name="account_status_tls_error">Не удалось согласовать TLS</string> <string name="account_status_tls_error">Не удалось согласовать TLS</string>
<string name="account_status_policy_violation">Нарушение правил</string> <string name="account_status_policy_violation">Нарушение правил</string>
<string name="account_status_incompatible_server">Несовместимый сервер</string> <string name="account_status_incompatible_server">Несовместимый сервер</string>
@ -165,14 +173,17 @@
<string name="mgmt_account_publish_pgp">Анонсировать OpenPGP ключ</string> <string name="mgmt_account_publish_pgp">Анонсировать OpenPGP ключ</string>
<string name="unpublish_pgp">Удалить открытый ключ OpenPGP</string> <string name="unpublish_pgp">Удалить открытый ключ OpenPGP</string>
<string name="unpublish_pgp_message">Вы действительно хотите удалить ваш OpenPGP публичный ключ из опубликованных?\nВаши собеседники не смогут больше отправлять вам зашифрованные OpenPGP сообщения.</string> <string name="unpublish_pgp_message">Вы действительно хотите удалить ваш OpenPGP публичный ключ из опубликованных?\nВаши собеседники не смогут больше отправлять вам зашифрованные OpenPGP сообщения.</string>
<string name="openpgp_has_been_published">Публичный ключ OpenPGP опубликован.</string>
<string name="mgmt_account_enable">Включить аккаунт</string> <string name="mgmt_account_enable">Включить аккаунт</string>
<string name="mgmt_account_are_you_sure">Вы уверены?</string> <string name="mgmt_account_are_you_sure">Вы уверены?</string>
<string name="mgmt_account_delete_confirm_text">Удаление аккаунта также удалит всю историю вашей переписки</string>
<string name="attach_record_voice">Запись голоса</string> <string name="attach_record_voice">Запись голоса</string>
<string name="account_settings_jabber_id">XMPP-адрес</string> <string name="account_settings_jabber_id">XMPP-адрес</string>
<string name="block_jabber_id">Заблокировать XMPP-адрес</string> <string name="block_jabber_id">Заблокировать XMPP-адрес</string>
<string name="account_settings_example_jabber_id">username@example.com</string> <string name="account_settings_example_jabber_id">username@example.com</string>
<string name="password">Пароль</string> <string name="password">Пароль</string>
<string name="invalid_jid">Недопустимый XMPP-адрес</string> <string name="invalid_jid">Недопустимый XMPP-адрес</string>
<string name="error_out_of_memory">Нехватка памяти. Изображение слишком большое</string>
<string name="add_phone_book_text">Вы хотите добавить %s в вашу адресную книгу?</string> <string name="add_phone_book_text">Вы хотите добавить %s в вашу адресную книгу?</string>
<string name="server_info_show_more">Информация о сервере</string> <string name="server_info_show_more">Информация о сервере</string>
<string name="server_info_mam">XEP-0313: Архив сообщений</string> <string name="server_info_mam">XEP-0313: Архив сообщений</string>
@ -181,6 +192,7 @@
<string name="server_info_blocking">XEP-0191: Команда блокирования</string> <string name="server_info_blocking">XEP-0191: Команда блокирования</string>
<string name="server_info_roster_version">XEP-0237: Версии списков</string> <string name="server_info_roster_version">XEP-0237: Версии списков</string>
<string name="server_info_stream_management">XEP-0198: Управление потоками</string> <string name="server_info_stream_management">XEP-0198: Управление потоками</string>
<string name="server_info_external_service_discovery">XEP-0215: Обнаружение внешних служб</string>
<string name="server_info_pep">XEP-0163: PEP (Аватары / OMEMO)</string> <string name="server_info_pep">XEP-0163: PEP (Аватары / OMEMO)</string>
<string name="server_info_http_upload">XEP-0363: Загрузка по HTTP</string> <string name="server_info_http_upload">XEP-0363: Загрузка по HTTP</string>
<string name="server_info_push">XEP-0357: Push-уведомления</string> <string name="server_info_push">XEP-0357: Push-уведомления</string>
@ -188,9 +200,14 @@
<string name="server_info_unavailable">недоступно</string> <string name="server_info_unavailable">недоступно</string>
<string name="missing_public_keys">Отсутствие анонсирования открытых ключей</string> <string name="missing_public_keys">Отсутствие анонсирования открытых ключей</string>
<string name="last_seen_now">Присутствие: только что</string> <string name="last_seen_now">Присутствие: только что</string>
<string name="last_seen_min">Присутствие: одну минуту назад</string>
<string name="last_seen_mins">Присутствие: %d мин. назад</string> <string name="last_seen_mins">Присутствие: %d мин. назад</string>
<string name="last_seen_hour">Присутствие: один час назад</string>
<string name="last_seen_hours">Присутствие: %d час. назад</string> <string name="last_seen_hours">Присутствие: %d час. назад</string>
<string name="last_seen_day">Присутствие: один день назад</string>
<string name="last_seen_days">Присутствие: %d дн. назад</string> <string name="last_seen_days">Присутствие: %d дн. назад</string>
<string name="install_openkeychain">Зашифрованное сообщение. Пожалуйста, установите OpenKeychain для дешифрования.</string>
<string name="openpgp_messages_found">Найдены новые OpenPGP зашифрованые сообщения</string>
<string name="openpgp_key_id">ID OpenPGP ключа</string> <string name="openpgp_key_id">ID OpenPGP ключа</string>
<string name="omemo_fingerprint">OMEMO отпечаток</string> <string name="omemo_fingerprint">OMEMO отпечаток</string>
<string name="omemo_fingerprint_x509">v\\OMEMO отпечаток</string> <string name="omemo_fingerprint_x509">v\\OMEMO отпечаток</string>
@ -212,10 +229,14 @@
<string name="select">Выбрать</string> <string name="select">Выбрать</string>
<string name="contact_already_exists">Контакт уже существует</string> <string name="contact_already_exists">Контакт уже существует</string>
<string name="join">Присоединиться</string> <string name="join">Присоединиться</string>
<string name="channel_full_jid_example">канал@конференция.пример.com/никнейм</string>
<string name="channel_bare_jid_example">канал@конференция.пример.com</string>
<string name="save_as_bookmark">Сохранить закладку</string> <string name="save_as_bookmark">Сохранить закладку</string>
<string name="delete_bookmark">Удалить закладку</string> <string name="delete_bookmark">Удалить закладку</string>
<string name="destroy_room">Уничтожить конференцию</string> <string name="destroy_room">Уничтожить конференцию</string>
<string name="destroy_channel">Уничтожить канал</string> <string name="destroy_channel">Уничтожить канал</string>
<string name="destroy_room_dialog">Вы уверены, что хотите распустить эту конференцию?\n\n<b>Предупреждение:</b>Конференция будет полностью удалена с сервера.</string>
<string name="destroy_channel_dialog">Вы уверены, что хотите закрыть этот публичный канал?\n\n<b>Предупреждение:</b> Канал будет полностью удален с сервера.</string>
<string name="could_not_destroy_room">Не удалось уничтожить конференцию</string> <string name="could_not_destroy_room">Не удалось уничтожить конференцию</string>
<string name="could_not_destroy_channel">Не удалось уничтожить канал</string> <string name="could_not_destroy_channel">Не удалось уничтожить канал</string>
<string name="action_edit_subject">Редактировать тему конференции</string> <string name="action_edit_subject">Редактировать тему конференции</string>
@ -378,7 +399,6 @@
<string name="mark_as_read">Прочитано</string> <string name="mark_as_read">Прочитано</string>
<string name="pref_input_options">Ввод</string> <string name="pref_input_options">Ввод</string>
<string name="pref_enter_is_send">Отправить на \"Enter\"</string> <string name="pref_enter_is_send">Отправить на \"Enter\"</string>
<string name="pref_enter_is_send_summary">Клавиша \"Enter\" отправляет сообщение</string>
<string name="pref_display_enter_key">Показывать клавишу ввода</string> <string name="pref_display_enter_key">Показывать клавишу ввода</string>
<string name="pref_display_enter_key_summary">Поменять кнопку смайликов на кнопку ввода</string> <string name="pref_display_enter_key_summary">Поменять кнопку смайликов на кнопку ввода</string>
<string name="audio">аудио</string> <string name="audio">аудио</string>
@ -393,7 +413,7 @@
<string name="hide_offline">Скрыть пользователей вне сети</string> <string name="hide_offline">Скрыть пользователей вне сети</string>
<string name="contact_is_typing">%s печатает…</string> <string name="contact_is_typing">%s печатает…</string>
<string name="contact_has_stopped_typing">%s прекратил набор</string> <string name="contact_has_stopped_typing">%s прекратил набор</string>
<string name="contacts_are_typing">%s печатают...</string> <string name="contacts_are_typing">%s печатают</string>
<string name="contacts_have_stopped_typing">%s перестали печатать</string> <string name="contacts_have_stopped_typing">%s перестали печатать</string>
<string name="pref_chat_states">Оповещения о наборе</string> <string name="pref_chat_states">Оповещения о наборе</string>
<string name="pref_chat_states_summary">Позволяет вашим контактам видеть, когда вы пишете им новое сообщение</string> <string name="pref_chat_states_summary">Позволяет вашим контактам видеть, когда вы пишете им новое сообщение</string>
@ -440,11 +460,11 @@
<string name="server_info_broken">Повреждено</string> <string name="server_info_broken">Повреждено</string>
<string name="pref_presence_settings">Доступность</string> <string name="pref_presence_settings">Доступность</string>
<string name="pref_away_when_screen_off">\"Отошёл\" когда экран выключен</string> <string name="pref_away_when_screen_off">\"Отошёл\" когда экран выключен</string>
<string name="pref_away_when_screen_off_summary">Отмечает ваш ресурс как «отошёл» когда экран выключен</string> <string name="pref_away_when_screen_off_summary">Устанавливает статус \"Отошёл\", когда экран выключен</string>
<string name="pref_dnd_on_silent_mode">\"Не беспокоить\" в беззвучном режиме</string> <string name="pref_dnd_on_silent_mode">\"Не беспокоить\" в беззвучном режиме</string>
<string name="pref_dnd_on_silent_mode_summary">Помечать ресурс как \"Не беспокоить\", когда устройство в беззвучном режиме</string> <string name="pref_dnd_on_silent_mode_summary">Устанавливает статус \"Не беспокоить\", когда устройство в беззвучном режиме</string>
<string name="pref_treat_vibrate_as_silent">Не доступен в режиме вибрации</string> <string name="pref_treat_vibrate_as_silent">Не доступен в режиме вибрации</string>
<string name="pref_treat_vibrate_as_dnd_summary">Помечать ресурс как \"Не беспокоить\", когда устройство на вибрации</string> <string name="pref_treat_vibrate_as_dnd_summary">Устанавливает статус \"Не беспокоить\", когда устройство на вибрации</string>
<string name="pref_show_connection_options">Расширенные настройки подключения</string> <string name="pref_show_connection_options">Расширенные настройки подключения</string>
<string name="pref_show_connection_options_summary">Показывать имя сервера и порт в настройках аккаунтов</string> <string name="pref_show_connection_options_summary">Показывать имя сервера и порт в настройках аккаунтов</string>
<string name="hostname_example">xmpp.example.com</string> <string name="hostname_example">xmpp.example.com</string>
@ -674,6 +694,7 @@
<string name="mtm_hostname_mismatch">Серверу не удалось аутентифицироваться в качестве \"%s\". Сертификат подходит только для:</string> <string name="mtm_hostname_mismatch">Серверу не удалось аутентифицироваться в качестве \"%s\". Сертификат подходит только для:</string>
<string name="mtm_connect_anyway">Вы все равно хотите подключиться?</string> <string name="mtm_connect_anyway">Вы все равно хотите подключиться?</string>
<string name="mtm_cert_details">Детали сертификата:</string> <string name="mtm_cert_details">Детали сертификата:</string>
<string name="once">Один раз</string>
<string name="qr_code_scanner_needs_access_to_camera">Сканеру QR-кода необходим доступ к камере</string> <string name="qr_code_scanner_needs_access_to_camera">Сканеру QR-кода необходим доступ к камере</string>
<string name="pref_scroll_to_bottom">Прокручивать вниз</string> <string name="pref_scroll_to_bottom">Прокручивать вниз</string>
<string name="pref_scroll_to_bottom_summary">Прокручивать вниз после отправки сообщения</string> <string name="pref_scroll_to_bottom_summary">Прокручивать вниз после отправки сообщения</string>
@ -707,6 +728,7 @@
<string name="action_unfix_from_location">Открепить позицию</string> <string name="action_unfix_from_location">Открепить позицию</string>
<string name="action_copy_location">Копировать местоположение</string> <string name="action_copy_location">Копировать местоположение</string>
<string name="action_share_location">Поделиться местоположением</string> <string name="action_share_location">Поделиться местоположением</string>
<string name="action_directions">Направления</string>
<string name="title_activity_share_location">Поделиться местоположением</string> <string name="title_activity_share_location">Поделиться местоположением</string>
<string name="title_activity_show_location">Показать местоположение</string> <string name="title_activity_show_location">Показать местоположение</string>
<string name="share">Поделиться</string> <string name="share">Поделиться</string>
@ -782,8 +804,8 @@
<string name="abort_registration_procedure">Вы уверены, что хотите прервать процедуру регистрации?</string> <string name="abort_registration_procedure">Вы уверены, что хотите прервать процедуру регистрации?</string>
<string name="yes">Да</string> <string name="yes">Да</string>
<string name="no">Нет</string> <string name="no">Нет</string>
<string name="verifying">Подтверждение...</string> <string name="verifying">Подтверждение</string>
<string name="requesting_sms">Запрос SMS...</string> <string name="requesting_sms">Запрос SMS</string>
<string name="incorrect_pin">Введенный вами код некорректен.</string> <string name="incorrect_pin">Введенный вами код некорректен.</string>
<string name="pin_expired">Отправленный вам код просрочен.</string> <string name="pin_expired">Отправленный вам код просрочен.</string>
<string name="unknown_api_error_network">Неизвестная ошибка сети.</string> <string name="unknown_api_error_network">Неизвестная ошибка сети.</string>
@ -799,6 +821,7 @@
<string name="rate_limited">У вас есть ограничение скорости</string> <string name="rate_limited">У вас есть ограничение скорости</string>
<string name="too_many_attempts">Слишком много попыток</string> <string name="too_many_attempts">Слишком много попыток</string>
<string name="the_app_is_out_of_date">Вы используете устаревшую версию приложения</string> <string name="the_app_is_out_of_date">Вы используете устаревшую версию приложения</string>
<string name="update">Обновить</string>
<string name="logged_in_with_another_device">Этот номер телефона в данный момент авторизирован на другом устройстве.</string> <string name="logged_in_with_another_device">Этот номер телефона в данный момент авторизирован на другом устройстве.</string>
<string name="enter_your_name_instructions">Пожалуйста, введите ваше имя, чтобы другие люди, у которых нет вас в списке контактов, знали кто вы.</string> <string name="enter_your_name_instructions">Пожалуйста, введите ваше имя, чтобы другие люди, у которых нет вас в списке контактов, знали кто вы.</string>
<string name="your_name">Ваше имя</string> <string name="your_name">Ваше имя</string>
@ -811,7 +834,7 @@
<string name="group_chat_will_make_your_jabber_id_public">Этот канал сделает ваш XMPP-адрес публичным</string> <string name="group_chat_will_make_your_jabber_id_public">Этот канал сделает ваш XMPP-адрес публичным</string>
<string name="ebook">Электронная книга</string> <string name="ebook">Электронная книга</string>
<string name="video_original">Оригинал (без сжатия)</string> <string name="video_original">Оригинал (без сжатия)</string>
<string name="open_with">Открыть с помощью...</string> <string name="open_with">Открыть с помощью</string>
<string name="set_profile_picture">Картинка профиля Conversations</string> <string name="set_profile_picture">Картинка профиля Conversations</string>
<string name="choose_account">Выбрать аккаунт</string> <string name="choose_account">Выбрать аккаунт</string>
<string name="restore_backup">Восстановить из резервной копии</string> <string name="restore_backup">Восстановить из резервной копии</string>
@ -831,7 +854,7 @@
<string name="please_enter_name">Пожалуйста, предоставьте имя для канала</string> <string name="please_enter_name">Пожалуйста, предоставьте имя для канала</string>
<string name="please_enter_xmpp_address">Пожалуйста, предоставьте XMPP-адрес</string> <string name="please_enter_xmpp_address">Пожалуйста, предоставьте XMPP-адрес</string>
<string name="this_is_an_xmpp_address">Это XMPP-адрес. Пожалуйста, предоставьте имя.</string> <string name="this_is_an_xmpp_address">Это XMPP-адрес. Пожалуйста, предоставьте имя.</string>
<string name="creating_channel">Создание публичного канала...</string> <string name="creating_channel">Создание публичного канала</string>
<string name="channel_already_exists">Этот канал уже существует</string> <string name="channel_already_exists">Этот канал уже существует</string>
<string name="joined_an_existing_channel">Вы присоединились к существующему каналу</string> <string name="joined_an_existing_channel">Вы присоединились к существующему каналу</string>
<string name="unable_to_set_channel_configuration">Не удалось сохранить настройки канала</string> <string name="unable_to_set_channel_configuration">Не удалось сохранить настройки канала</string>
@ -868,11 +891,12 @@
<string name="account_already_setup">Эта учетная запись уже настроена</string> <string name="account_already_setup">Эта учетная запись уже настроена</string>
<string name="please_enter_password">Пожалуйста, введите пароль этой учетной записи</string> <string name="please_enter_password">Пожалуйста, введите пароль этой учетной записи</string>
<string name="unable_to_perform_this_action">Не удалось совершить это действие</string> <string name="unable_to_perform_this_action">Не удалось совершить это действие</string>
<string name="open_join_dialog">Присоединиться к публичному каналу...</string> <string name="open_join_dialog">Присоединиться к публичному каналу…</string>
<string name="sharing_application_not_grant_permission">Приложение для обмена не предоставило право доступа к этому файлу.</string>
<string name="group_chats_and_channels"><![CDATA[Группы и каналы]]></string> <string name="group_chats_and_channels"><![CDATA[Группы и каналы]]></string>
<string name="jabber_network">jabber.network</string> <string name="jabber_network">jabber.network</string>
<string name="local_server">Локальный сервер</string> <string name="local_server">Локальный сервер</string>
<string name="pref_channel_discovery_summary">Большиству пользователей следует выбрать jabber.network для лучших предложений от всей публичной экосистемы XMPP.</string> <string name="pref_channel_discovery_summary">Большиству пользователей следует выбрать jabber.network для получения наиболее подходящих предложений от всей публичной экосистемы XMPP.</string>
<string name="pref_channel_discovery">Способ поиска каналов</string> <string name="pref_channel_discovery">Способ поиска каналов</string>
<string name="backup">Резервное копирование</string> <string name="backup">Резервное копирование</string>
<string name="category_about">О</string> <string name="category_about">О</string>
@ -890,6 +914,8 @@
<string name="rtp_state_ringing">Вызов</string> <string name="rtp_state_ringing">Вызов</string>
<string name="rtp_state_declined_or_busy">Занято</string> <string name="rtp_state_declined_or_busy">Занято</string>
<string name="rtp_state_connectivity_error">Не удалось установить соединение</string> <string name="rtp_state_connectivity_error">Не удалось установить соединение</string>
<string name="rtp_state_connectivity_lost_error">Соединение потеряно</string>
<string name="rtp_state_retracted">Вызов отклонен</string>
<string name="rtp_state_application_failure">Ошибка приложения</string> <string name="rtp_state_application_failure">Ошибка приложения</string>
<string name="hang_up">Завершить</string> <string name="hang_up">Завершить</string>
<string name="ongoing_call">Активный звонок</string> <string name="ongoing_call">Активный звонок</string>
@ -902,9 +928,18 @@
<string name="missed_call">Пропущен вызов</string> <string name="missed_call">Пропущен вызов</string>
<string name="audio_call">Аудиозвонок</string> <string name="audio_call">Аудиозвонок</string>
<string name="video_call">Видеозвонок</string> <string name="video_call">Видеозвонок</string>
<string name="help">Помощь</string>
<string name="switch_to_conversation">Переключиться на беседу</string>
<string name="microphone_unavailable">Микрофон недоступен</string> <string name="microphone_unavailable">Микрофон недоступен</string>
<string name="only_one_call_at_a_time">Нельзя одновременно совершать больше одного звонка.</string>
<string name="return_to_ongoing_call">Вернуться к текущему звонку</string> <string name="return_to_ongoing_call">Вернуться к текущему звонку</string>
<string name="could_not_switch_camera">Не удалось переключить камеру</string> <string name="could_not_switch_camera">Не удалось переключить камеру</string>
<string name="add_to_favorites">Добавить в избранные</string> <string name="add_to_favorites">Добавить в избранные</string>
<string name="remove_from_favorites">Убрать из избранных</string> <string name="remove_from_favorites">Убрать из избранных</string>
<plurals name="view_users">
<item quantity="one">Просмотр %1$d участника</item>
<item quantity="few">Просмотр %1$d участников</item>
<item quantity="many">Просмотр %1$d участников</item>
<item quantity="other">Просмотр %1$d участников</item>
</plurals>
</resources> </resources>

View File

@ -216,7 +216,6 @@
<string name="never">Nikdy</string> <string name="never">Nikdy</string>
<string name="until_further_notice">Až do odvolania</string> <string name="until_further_notice">Až do odvolania</string>
<string name="pref_enter_is_send">Enter odosiela</string> <string name="pref_enter_is_send">Enter odosiela</string>
<string name="pref_enter_is_send_summary">Použiť klávesu enter na odoslanie správy</string>
<string name="pref_display_enter_key">Zobraziť klávesu enter</string> <string name="pref_display_enter_key">Zobraziť klávesu enter</string>
<string name="pref_display_enter_key_summary">Zmeniť klávesu s emotikonmi na klávesu enter</string> <string name="pref_display_enter_key_summary">Zmeniť klávesu s emotikonmi na klávesu enter</string>
<string name="audio">audio</string> <string name="audio">audio</string>

View File

@ -296,7 +296,6 @@
<string name="mark_as_read">Означи прочитаним</string> <string name="mark_as_read">Означи прочитаним</string>
<string name="pref_input_options">Унос</string> <string name="pref_input_options">Унос</string>
<string name="pref_enter_is_send">Ентер шаље</string> <string name="pref_enter_is_send">Ентер шаље</string>
<string name="pref_enter_is_send_summary">Користи Ентер тастер за слање порука</string>
<string name="pref_display_enter_key">Прикажи Ентер тастер</string> <string name="pref_display_enter_key">Прикажи Ентер тастер</string>
<string name="pref_display_enter_key_summary">Промени тастер за емотиконе у ентер тастер</string> <string name="pref_display_enter_key_summary">Промени тастер за емотиконе у ентер тастер</string>
<string name="audio">звук</string> <string name="audio">звук</string>

View File

@ -319,7 +319,6 @@
<string name="mark_as_read">Läsmarkera</string> <string name="mark_as_read">Läsmarkera</string>
<string name="pref_input_options">Input</string> <string name="pref_input_options">Input</string>
<string name="pref_enter_is_send">Skicka med enter</string> <string name="pref_enter_is_send">Skicka med enter</string>
<string name="pref_enter_is_send_summary">Använd enter-knappen för att skicka meddelande</string>
<string name="pref_display_enter_key">Visa enter-knappen</string> <string name="pref_display_enter_key">Visa enter-knappen</string>
<string name="pref_display_enter_key_summary">Byt ut emoticons-tangenten mot en enter-tangent</string> <string name="pref_display_enter_key_summary">Byt ut emoticons-tangenten mot en enter-tangent</string>
<string name="audio">ljud</string> <string name="audio">ljud</string>

View File

@ -271,7 +271,6 @@
<string name="until_further_notice">İkinci bildirime kadar</string> <string name="until_further_notice">İkinci bildirime kadar</string>
<string name="pref_input_options">Girdi</string> <string name="pref_input_options">Girdi</string>
<string name="pref_enter_is_send">Enter=gönder</string> <string name="pref_enter_is_send">Enter=gönder</string>
<string name="pref_enter_is_send_summary">İleti göndermek için \"enter\" tuşunu kullan</string>
<string name="pref_display_enter_key">\"Enter\" tuşunu göster</string> <string name="pref_display_enter_key">\"Enter\" tuşunu göster</string>
<string name="pref_display_enter_key_summary">İfade simgesi tuşunu \"enter\" tuşu olarak değiştir</string> <string name="pref_display_enter_key_summary">İfade simgesi tuşunu \"enter\" tuşu olarak değiştir</string>
<string name="audio">ses</string> <string name="audio">ses</string>

View File

@ -401,7 +401,6 @@
<string name="mark_as_read">Позначити як прочитане</string> <string name="mark_as_read">Позначити як прочитане</string>
<string name="pref_input_options">Введення</string> <string name="pref_input_options">Введення</string>
<string name="pref_enter_is_send">Enter для надсилання</string> <string name="pref_enter_is_send">Enter для надсилання</string>
<string name="pref_enter_is_send_summary">Використовувати Enter для надсилання повідомлення</string>
<string name="pref_display_enter_key">Показувати кнопку Enter</string> <string name="pref_display_enter_key">Показувати кнопку Enter</string>
<string name="pref_display_enter_key_summary">Змінити клавішу емоційок на кнопку Enter</string> <string name="pref_display_enter_key_summary">Змінити клавішу емоційок на кнопку Enter</string>
<string name="audio">аудіо</string> <string name="audio">аудіо</string>
@ -932,6 +931,7 @@
<string name="audio_call">Голосовий виклик</string> <string name="audio_call">Голосовий виклик</string>
<string name="video_call">Відеовиклик</string> <string name="video_call">Відеовиклик</string>
<string name="help">Допомога</string> <string name="help">Допомога</string>
<string name="switch_to_conversation">Перейти до розмови</string>
<string name="microphone_unavailable">Недоступний мікрофон</string> <string name="microphone_unavailable">Недоступний мікрофон</string>
<string name="only_one_call_at_a_time">Водночас можливо здійснювати лише один виклик.</string> <string name="only_one_call_at_a_time">Водночас можливо здійснювати лише один виклик.</string>
<string name="return_to_ongoing_call">Назад до активного виклику</string> <string name="return_to_ongoing_call">Назад до активного виклику</string>

View File

@ -246,7 +246,6 @@
<string name="never">Chưa từng</string> <string name="never">Chưa từng</string>
<string name="until_further_notice">Cho đến thông báo tiếp theo</string> <string name="until_further_notice">Cho đến thông báo tiếp theo</string>
<string name="pref_enter_is_send">Bấm Enter để gửi</string> <string name="pref_enter_is_send">Bấm Enter để gửi</string>
<string name="pref_enter_is_send_summary">Bấm nút Enter để gửi tin nhắn</string>
<string name="pref_display_enter_key">Hiện nút Enter</string> <string name="pref_display_enter_key">Hiện nút Enter</string>
<string name="pref_display_enter_key_summary">Đổi nút biểu tượng cảm xúc thành nút Enter</string> <string name="pref_display_enter_key_summary">Đổi nút biểu tượng cảm xúc thành nút Enter</string>
<string name="audio">âm thanh</string> <string name="audio">âm thanh</string>

View File

@ -1,9 +1,10 @@
<resources> <resources>
<!-- 384dp is the screen width of the Nexus 4. Something like a Moto G is smaller but a Nexus 5X is larger --> <!-- 384dp is the screen width of the Nexus 4. Something like a Moto G is smaller but a Nexus 5X is larger -->
<!-- https://material.io/devices/ --> <!-- https://material.io/devices/ -->
<dimen name="fineprint_size">12sp</dimen> <dimen name="fineprint_size">12sp</dimen>
<dimen name="audio_player_width">288dp</dimen> <dimen name="audio_player_width">288dp</dimen>
<dimen name="avatar_on_details_screen_size">72dp</dimen> <dimen name="image_preview_width">288dp</dimen>
<dimen name="media_size">64dp</dimen> <!-- ideally not larger than avatar_on_details_screen --> <dimen name="avatar_on_details_screen_size">72dp</dimen>
<dimen name="sd_label_max_width">288dp</dimen> <dimen name="media_size">64dp</dimen> <!-- ideally not larger than avatar_on_details_screen -->
<dimen name="sd_label_max_width">288dp</dimen>
</resources> </resources>

View File

@ -401,7 +401,6 @@
<string name="mark_as_read">标记为已读</string> <string name="mark_as_read">标记为已读</string>
<string name="pref_input_options">输入</string> <string name="pref_input_options">输入</string>
<string name="pref_enter_is_send">点击回车发送</string> <string name="pref_enter_is_send">点击回车发送</string>
<string name="pref_enter_is_send_summary">回车键发送消息</string>
<string name="pref_display_enter_key">显示回车键</string> <string name="pref_display_enter_key">显示回车键</string>
<string name="pref_display_enter_key_summary">将表情键改为回车键</string> <string name="pref_display_enter_key_summary">将表情键改为回车键</string>
<string name="audio">音频</string> <string name="audio">音频</string>

View File

@ -260,7 +260,6 @@
<string name="until_further_notice">直到新的通知</string> <string name="until_further_notice">直到新的通知</string>
<string name="pref_input_options">輸入</string> <string name="pref_input_options">輸入</string>
<string name="pref_enter_is_send">回車是發送</string> <string name="pref_enter_is_send">回車是發送</string>
<string name="pref_enter_is_send_summary">用 Enter 鍵來發送訊息</string>
<string name="pref_display_enter_key">顯示回車鍵</string> <string name="pref_display_enter_key">顯示回車鍵</string>
<string name="pref_display_enter_key_summary">改變表情鍵為回車鍵</string> <string name="pref_display_enter_key_summary">改變表情鍵為回車鍵</string>
<string name="audio">音訊</string> <string name="audio">音訊</string>

View File

@ -97,6 +97,7 @@
<attr name="icon_remove" format="reference" /> <attr name="icon_remove" format="reference" />
<attr name="icon_search" format="reference" /> <attr name="icon_search" format="reference" />
<attr name="icon_help" format="reference" /> <attr name="icon_help" format="reference" />
<attr name="icon_goto_chat" format="reference" />
<attr name="icon_secure" format="reference" /> <attr name="icon_secure" format="reference" />
<attr name="icon_settings" format="reference" /> <attr name="icon_settings" format="reference" />
<attr name="icon_share" format="reference" /> <attr name="icon_share" format="reference" />

View File

@ -10,6 +10,7 @@
</dimen> <!-- icon width (24dp) + 2 * image button padding --> </dimen> <!-- icon width (24dp) + 2 * image button padding -->
<dimen name="fineprint_size">11sp</dimen> <dimen name="fineprint_size">11sp</dimen>
<dimen name="audio_player_width">224dp</dimen> <dimen name="audio_player_width">224dp</dimen>
<dimen name="image_preview_width">224dp</dimen>
<dimen name="avatar_item_distance">16dp</dimen> <dimen name="avatar_item_distance">16dp</dimen>
<dimen name="media_preview_size">80dp</dimen> <dimen name="media_preview_size">80dp</dimen>

View File

@ -401,7 +401,7 @@
<string name="mark_as_read">Mark as read</string> <string name="mark_as_read">Mark as read</string>
<string name="pref_input_options">Input</string> <string name="pref_input_options">Input</string>
<string name="pref_enter_is_send">Enter is send</string> <string name="pref_enter_is_send">Enter is send</string>
<string name="pref_enter_is_send_summary">Use enter key to send message</string> <string name="pref_enter_is_send_summary">Use Enter key to send message. You can always use Ctrl+Enter to send message, even if this option is disabled.</string>
<string name="pref_display_enter_key">Show enter key</string> <string name="pref_display_enter_key">Show enter key</string>
<string name="pref_display_enter_key_summary">Change the emoticons key to an enter key</string> <string name="pref_display_enter_key_summary">Change the emoticons key to an enter key</string>
<string name="audio">audio</string> <string name="audio">audio</string>
@ -918,6 +918,7 @@
<string name="audio_call">Audio call</string> <string name="audio_call">Audio call</string>
<string name="video_call">Video call</string> <string name="video_call">Video call</string>
<string name="help">Help</string> <string name="help">Help</string>
<string name="switch_to_conversation">Switch to conversation</string>
<string name="microphone_unavailable">Your microphone is unavailable</string> <string name="microphone_unavailable">Your microphone is unavailable</string>
<string name="only_one_call_at_a_time">You can only have one call at a time.</string> <string name="only_one_call_at_a_time">You can only have one call at a time.</string>
<string name="return_to_ongoing_call">Return to ongoing call</string> <string name="return_to_ongoing_call">Return to ongoing call</string>

View File

@ -115,6 +115,7 @@
<item name="icon_remove" type="reference">@drawable/ic_delete_black_24dp</item> <item name="icon_remove" type="reference">@drawable/ic_delete_black_24dp</item>
<item name="icon_search" type="reference">@drawable/ic_search_white_24dp</item> <item name="icon_search" type="reference">@drawable/ic_search_white_24dp</item>
<item name="icon_help" type="reference">@drawable/ic_help_white_24dp</item> <item name="icon_help" type="reference">@drawable/ic_help_white_24dp</item>
<item name="icon_goto_chat" type="reference">@drawable/ic_question_answer_white_24dp</item>
<item name="icon_secure" type="reference">@drawable/ic_lock_open_white_24dp</item> <item name="icon_secure" type="reference">@drawable/ic_lock_open_white_24dp</item>
<item name="icon_settings" type="reference">@drawable/ic_settings_black_24dp</item> <item name="icon_settings" type="reference">@drawable/ic_settings_black_24dp</item>
<item name="icon_share" type="reference">@drawable/ic_share_white_24dp</item> <item name="icon_share" type="reference">@drawable/ic_share_white_24dp</item>
@ -269,6 +270,7 @@
<item name="icon_remove" type="reference">@drawable/ic_delete_white_24dp</item> <item name="icon_remove" type="reference">@drawable/ic_delete_white_24dp</item>
<item name="icon_search" type="reference">@drawable/ic_search_white_24dp</item> <item name="icon_search" type="reference">@drawable/ic_search_white_24dp</item>
<item name="icon_help" type="reference">@drawable/ic_help_white_24dp</item> <item name="icon_help" type="reference">@drawable/ic_help_white_24dp</item>
<item name="icon_goto_chat" type="reference">@drawable/ic_question_answer_white_24dp</item>
<item name="icon_secure" type="reference">@drawable/ic_lock_open_white_24dp</item> <item name="icon_secure" type="reference">@drawable/ic_lock_open_white_24dp</item>
<item name="icon_settings" type="reference">@drawable/ic_settings_white_24dp</item> <item name="icon_settings" type="reference">@drawable/ic_settings_white_24dp</item>
<item name="icon_share" type="reference">@drawable/ic_share_white_24dp</item> <item name="icon_share" type="reference">@drawable/ic_share_white_24dp</item>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="crash_report_title">В Quicksy произошёл сбой</string>
<string name="crash_report_message">Отправляя отчёты об ошибках, вы помогаете исправить и улучшить Quicksy\n<b>Предупреждение:</b> Отчёт будет отправлен разработчику с вашего XMPP аккаунта. </string>
<string name="openkeychain_required_long">Conversations использует стороннее приложение под названием <b>OpenKeychain</b> для шифровки и расшифровки сообщений и управления открытыми ключами.\nПрограмма OpenKeychain распространяется под лицензией GPLv3 и доступна через F-Droid или Google Play.\n\n<small>(Пожалуйста, перезапустите Quicksy после установки.)</small></string>
<string name="contact_has_no_pgp_key">Quicksy не может зашифровать сообщение, потому что ваш собеседник не анонсирует свой открытый ключ.\n\n<small>Пожалуйста, попросите вашего собеседника настроить OpenPGP.</small></string>
<string name="contacts_have_no_pgp_keys">Quicksy не может зашифровать сообщение, потому что ваши собеседники не анонсируют их открытые ключи.\n\n<small>Пожалуйста, попросите ваших собеседников настроить OpenPGP.</small></string>
<string name="pref_notification_grace_period_summary">Время, на которое уведомления от Quicksy будут отключены, когда вы пользуетесь аккаунтом на другом устройстве.</string>
<string name="pref_never_send_crash_summary">Отправляя отчёты об ошибках, вы помогаете в разработке Quicksy</string>
<string name="no_storage_permission">Quicksy требуется доступ к основной файловой системе</string>
<string name="no_camera_permission">Quicksy требуется доступ к камере</string>
<string name="battery_optimizations_enabled_explained">Ваше устройство использует агрессивную оптимизацию энергопотребления Quicksy, что может привести к задержке уведомлений и даже потере сообщений.\nРекомендуем ее отключить.</string>
<string name="battery_optimizations_enabled_dialog">Ваше устройство использует агрессивную оптимизацию энергопотребления Quicksy, что может привести к задержке уведомлений и даже потере сообщений.\nСейчас появится предложение ее отключить.</string>
<string name="pref_broadcast_last_activity_summary">Извещать собеседников, когда вы пользуетесь Quicksy</string>
<string name="data_saver_enabled_explained">Ваша операционная система не позволяет Quicksy доступ в Интернет в фоновом режиме. Для получения уведомлений вы должны разрешить Quicksy неограниченный доступ в Интернет в режиме экономии трафика.\nQuicksy будет использовать настолько мало трафика, насколько это возможно.</string>
<string name="device_does_not_support_data_saver">Ваше устройство не позволяет отключить режим экономии трафика для Quicksy.</string>
<string name="huawei_protected_apps_summary">Чтобы продолжать получать уведомления, даже если экран выключен, вам необходимо добавить Quicksy в список защищенных приложений.</string>
<string name="error_trustkey_general">Quicksy не удалось отправить зашифрованные сообщения для %1$s. Причиной этому может быть использование получателем устаревшего сервера или приложения, которые не поддерживают OMEMO.</string>
<string name="no_microphone_permission">Quicksy требуется доступ к микрофону</string>
<string name="foreground_service_channel_description">Эта категория уведомлений используется для отображения постоянного уведомления о том что Quicksy работает.</string>
<string name="set_profile_picture">Аватар для Quicksy</string>
<string name="not_available_in_your_country">Quicksy не доступно в вашем регионе</string>
<string name="unable_to_verify_server_identity">Не удалось подтвердить сервер.</string>
<string name="unknown_security_error">Неизвестная ошибка безопасности.</string>
<string name="timeout_while_connecting_to_server">Время ожидания подключения к серверу вышло.</string>
</resources>

View File

@ -1,26 +1,26 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="crash_report_title">Програма дала збій</string> <string name="crash_report_title">Відмова застосунку</string>
<string name="crash_report_message">Надсилаючи траси стеків виклику Ви допомагаєте розробці цієї програми\n<b>Увага:</b> Це використовуватиме ваш обліковий запис XMPP, щоб надсилати траси стеків виклику розробнику.</string> <string name="crash_report_message">Надсилаючи траси стеків виклику, ви допомагаєте у розробці цього застосунку.\n<b>Увага:</b> Це використовуватиме ваш обліковий запис XMPP, щоб надсилати траси стеків виклику розробнику.</string>
<string name="openkeychain_required_long">Ця програма використовує сторонній додаток, який називається <b>OpenKeychain</b>, для шифрування повідомлень і впорядкування ваших публічних ключів.\n\nOpenKeychain поширюється на умова ліцензії GPLv3 й доступна в F-Droid та Google Play.\n\n<small>(Будь ласка, перезапустіть цю програму після цього.)</small></string> <string name="openkeychain_required_long">Цей застосунок використовує сторонній застосунок, який називається <b>OpenKeychain</b>, для шифрування повідомлень і впорядкування ваших публічних ключів.\n\nOpenKeychain поширюється на умова ліцензії GPLv3 й доступна в F-Droid та Google Play.\n\n<small>(Будь ласка, перезапустіть цю програму після цього.)</small></string>
<string name="contact_has_no_pgp_key">Ця програма не змогла зашифрувати повідомлення, оскільки публічний ключ адресата не опубліковано.\n\n<small>Будь ласка, попросіть адресата налаштувати OpenPGP.</small></string> <string name="contact_has_no_pgp_key">Застосунок не зміг зашифрувати повідомлення, оскільки публічний ключ адресата не опубліковано.\n\n<small>Будь ласка, попросіть адресата налаштувати OpenPGP.</small></string>
<string name="contacts_have_no_pgp_keys">Ця програма не змогла зашифрувати повідомлення, оскільки публічні ключі адресатів не опубліковано.\n\n<small>Будь ласка, попросіть їх налаштувати OpenPGP.</small></string> <string name="contacts_have_no_pgp_keys">Застосунок не зміг зашифрувати повідомлення, оскільки публічні ключі адресатів не опубліковано.\n\n<small>Будь ласка, попросіть їх налаштувати OpenPGP.</small></string>
<string name="pref_notification_grace_period_summary">Час, протягом якого ця програма дотримується тиші після активності на іншому пристрої.</string> <string name="pref_notification_grace_period_summary">Час, протягом якого застосунок дотримується тиші після активності на іншому пристрої.</string>
<string name="pref_never_send_crash_summary">Надсилаючи траси стеків виклику, ви допомагаєте розробці цієї програми.</string> <string name="pref_never_send_crash_summary">Надсилаючи траси стеків виклику, ви допомагаєте розробці цього застосунку.</string>
<string name="no_storage_permission">Ця програма потребує доступу до зовнішнього сховища</string> <string name="no_storage_permission">Цей застосунок потребує доступу до зовнішнього сховища</string>
<string name="no_camera_permission">Ця програма потребує доступу до камери</string> <string name="no_camera_permission">Цей застосунок потребує доступу до камери</string>
<string name="battery_optimizations_enabled_explained">Ваш пристрій використовує посилену оптимізацію батареї для Quicksy, що може призвести до затримок у отриманні сповіщень або навіть втраті повідомлень.\nlt Рекомендується вимкнути цю функцію.</string> <string name="battery_optimizations_enabled_explained">Ваш пристрій використовує посилену оптимізацію батареї для Quicksy, що може призвести до затримок у отриманні сповіщень або навіть втраті повідомлень.\nlt Рекомендується вимкнути цю функцію.</string>
<string name="battery_optimizations_enabled_dialog">Ваш пристрій використовує посилену оптимізацію батареї для Quicksy, що може призвести до затримок у отриманні сповіщень або навіть втраті повідомлень.\n\n Ми вас попросимо вимкнути цю функцію.</string> <string name="battery_optimizations_enabled_dialog">Ваш пристрій використовує посилену оптимізацію батареї для Quicksy, що може призвести до затримок у отриманні сповіщень або навіть втраті повідомлень.\n\n Ми вас попросимо вимкнути цю функцію.</string>
<string name="pref_broadcast_last_activity_summary">Дозволити всім вашим контактам знати, коли ви використовуєте цю програму.</string> <string name="pref_broadcast_last_activity_summary">Дозволити всім вашим контактам знати, коли ви використовуєте цю програму.</string>
<string name="data_saver_enabled_explained">Операційна система обмежує цю програму в доступі до Інтернету, коли вона не на екрані. Щоб отримувати сповіщення про нові повідомлення, слід дозволити цій програмі доступ, коли ввімкнено заощадження трафіку.\nЦя програма все одно намагатиметься заощадити трафік, коли можливо.</string> <string name="data_saver_enabled_explained">Операційна система обмежує цю програму в доступі до Інтернету, коли вона не на екрані. Щоб отримувати сповіщення про нові повідомлення, слід дозволити цій програмі доступ, коли ввімкнено заощадження трафіку.\nЦя програма все одно намагатиметься заощадити трафік, коли можливо.</string>
<string name="device_does_not_support_data_saver">Цей пристрій не надає можливості зробити виняток щодо заощадження трафіку для цієї програми.</string> <string name="device_does_not_support_data_saver">Цей пристрій не надає можливості зробити виняток щодо заощадження трафіку для цієї програми.</string>
<string name="huawei_protected_apps_summary">Щоб продовжувати отримувати сповіщення, навіть коли екран вимкнуто, потрібно додати цю програму до списку захищених.</string> <string name="huawei_protected_apps_summary">Щоб продовжувати отримувати сповіщення, навіть коли екран вимкнуто, потрібно додати цю програму до списку захищених.</string>
<string name="error_trustkey_general">Програма не може надіслати зашифроване повідомлення до %1$s. Можливо, це обумовлено тим, що адресат користується застарілим сервером або програмою, яка не підтримує OMEMO.</string> <string name="error_trustkey_general">Застосунок не може надіслати зашифроване повідомлення до %1$s. Можливо, це обумовлено тим, що адресат користується застарілим сервером або програмою, яка не підтримує OMEMO.</string>
<string name="no_microphone_permission">Програма потребує доступу до мікрофона</string> <string name="no_microphone_permission">Цей застосунок потребує доступу до мікрофона</string>
<string name="foreground_service_channel_description">Цей вид сповіщень показує постійне сповіщення про те, що ця програма працює.</string> <string name="foreground_service_channel_description">Цей вид сповіщень показує постійне сповіщення про те, що ця програма працює.</string>
<string name="set_profile_picture">Зображення профілю для Quicksy</string> <string name="set_profile_picture">Зображення профілю для Quicksy</string>
<string name="not_available_in_your_country">Ця програма не доступна у Вашій країні.</string> <string name="not_available_in_your_country">Цей застосунок не доступний у вашій країні.</string>
<string name="unable_to_verify_server_identity">Автентичність сервера не підтверджено</string> <string name="unable_to_verify_server_identity">Автентичність сервера не підтверджено.</string>
<string name="unknown_security_error">Невідома помилка безпеки.</string> <string name="unknown_security_error">Невідома помилка безпеки.</string>
<string name="timeout_while_connecting_to_server">Вичерпано час для встановлення з\'єднання із сервером.</string> <string name="timeout_while_connecting_to_server">Вичерпано час для встановлення з\'єднання із сервером.</string>
</resources> </resources>