for 2.5.1 Merge branch 'master' into develop

This commit is contained in:
Martin/Geno 2019-05-04 14:41:34 +02:00
commit 69b92f264a
No known key found for this signature in database
GPG Key ID: 9D7D3C6BFF600C6A
16 changed files with 152 additions and 91 deletions

View File

@ -1,5 +1,9 @@
# Changelog
### Version 2.5.1
* minor bug fixes
* Set own OMEMO devices to inactive after not seeing them for 14 days. (was 7 days)
### Version 2.5.0
* Added channel search via search.jabbercat.org
* Reworked onboarding screens

View File

@ -81,8 +81,8 @@ android {
defaultConfig {
minSdkVersion 16
targetSdkVersion 28
versionCode 326
versionName "2.5.0"
versionCode 327
versionName "2.5.1"
archivesBaseName += "-$versionName"
applicationId "eu.sum7.conversations"
resValue "string", "applicationId", applicationId

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="pick_a_server">Hautatu zure XMPP hornitzailea</string>
<string name="use_conversations.im">Erabili conversations.im</string>
<string name="create_new_account">Kontu berria sortu</string>
<string name="do_you_have_an_account">XMPP kontu bat badaukazu dagoeneko? Horrela izan daiteke beste XMPP aplikazio bat erabiltzen baduzu edo Conversations lehenago erabili baduzu. Bestela XMPP kontu berri bat sortu dezakezu oraintxe bertan.\nIradokizuna: email hornitzaile batzuek XMPP kontuak hornitzen dituzte ere.</string>
<string name="server_select_text">XMPP hornitzailez independientea den bat-bateko mezularitza sare bat da. Aplikazio hau nahi duzun XMPP zerbitzariarekin erabili dezakezu.\nHala ere zure erosotasunerako conversations.im¹-en, Conversationsekin bereziki erabiltzeko egokia den hornitzaile batean, kontu bat sortzea erraz egin dugu.</string>
</resources>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="pick_a_server">Escolla o seu provedor XMPP</string>
<string name="use_conversations.im">Utilizar conversations.im</string>
<string name="create_new_account">Crear nova conta</string>
<string name="do_you_have_an_account">Xa posúe unha conta XMPP? Este pode ser o caso se xa está a utilizar outro cliente XMPP ou utilizou Conversations previamente. Se non é así pode crear unha nova conta agora mesmo.\nTruco: Algúns provedores de correo tamén proporcionan contas XMPP.</string>
<string name="server_select_text">XMPP é unha rede de mensaxería independente do provedor. Pode utilizar este cliente con calquer provedor XMPP da súa elección.\nMais para a súa conveniencia fixemos que fose doado crear unha conta en conversations.im¹; un provedor especialmente axeitado para utilizar con Conversations.</string>
</resources>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="pick_a_server">Wybierz dostawcę XMPP</string>
<string name="use_conversations.im">Użyj conversations.im</string>
<string name="create_new_account">Stwórz nowe konto</string>
<string name="do_you_have_an_account">Czy masz już konto XMPP? Tak może być jeśli używasz już innego klienta XMPP lub używałeś już Conversations. Jeśli nie możesz stworzyć nowe konto XMPP teraz.\nPodpowiedź: Niektórzy dostawcy poczty oferują również konta XMPP.</string>
<string name="server_select_text">XMPP to niezależna od dostawcy sieć komunikacji błyskawicznej. Możesz użyć tego klienta z dowolnym serwerem XMPP.\nDla twojej wygody jednak ułatwiliśmy stworzenie konta na conversations.im¹; dostawcy specjalnie dostosowanego do pracy z Conversations.</string>
</resources>

View File

@ -1,4 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="pick_a_server">Selecione o seu provedor XMPP</string>
</resources>
<string name="use_conversations.im">Usar o conversations.im</string>
<string name="create_new_account">Criar uma nova conta</string>
<string name="do_you_have_an_account">Você já possui uma conta XMPP? Esse pode ser o seu caso caso já esteja usando um outro cliente XMPP ou tenha usado o Conversations antes. Caso contrário, você pode criar uma nova conta XMPP agora.\nDica: alguns provedores de e-mail também fornecem contas XMPP.</string>
<string name="server_select_text">O XMPP é uma rede de mensageria instantânea independente de provedor. Você pode usar esse cliente com qualquer servidor XMPP que você escolher.\nEntretanto, para sua conveniência, nós simplificamos o processo de criação de uma conta em conversations.im¹, um provedor especialmente configurado para se usar com o Conversations.</string>
</resources>

View File

@ -94,7 +94,7 @@ public final class Config {
public static final long MILLISECONDS_IN_DAY = 24 * 60 * 60 * 1000;
public static final long OMEMO_AUTO_EXPIRY = 7 * MILLISECONDS_IN_DAY;
public static final long OMEMO_AUTO_EXPIRY = 14 * MILLISECONDS_IN_DAY;
public static final boolean REMOVE_BROKEN_DEVICES = false;
public static final boolean OMEMO_PADDING = false;
public static final boolean PUT_AUTH_TAG_INTO_KEY = true;
@ -122,7 +122,7 @@ public final class Config {
public static final int EXPIRY_INTERVAL = 30 * 60 * 1000; // 30 minutes
public static final String ENABLED_CIPHERS[] = {
public static final String[] ENABLED_CIPHERS = {
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA256",

View File

@ -3,7 +3,6 @@ package eu.siacs.conversations.entities;
import android.content.ContentValues;
import android.database.Cursor;
import android.graphics.Color;
import android.support.annotation.ColorInt;
import android.text.SpannableStringBuilder;
import android.util.Log;
@ -181,35 +180,11 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable
}
public static Message fromCursor(Cursor cursor, Conversation conversation) {
Jid jid;
try {
String value = cursor.getString(cursor.getColumnIndex(COUNTERPART));
if (value != null) {
jid = Jid.of(value);
} else {
jid = null;
}
} catch (IllegalArgumentException e) {
jid = null;
} catch (IllegalStateException e) {
return null; // message too long?
}
Jid trueCounterpart;
try {
String value = cursor.getString(cursor.getColumnIndex(TRUE_COUNTERPART));
if (value != null) {
trueCounterpart = Jid.of(value);
} else {
trueCounterpart = null;
}
} catch (IllegalArgumentException e) {
trueCounterpart = null;
}
return new Message(conversation,
cursor.getString(cursor.getColumnIndex(UUID)),
cursor.getString(cursor.getColumnIndex(CONVERSATION)),
jid,
trueCounterpart,
fromString(cursor.getString(cursor.getColumnIndex(COUNTERPART))),
fromString(cursor.getString(cursor.getColumnIndex(TRUE_COUNTERPART))),
cursor.getString(cursor.getColumnIndex(BODY)),
cursor.getLong(cursor.getColumnIndex(TIME_SENT)),
cursor.getInt(cursor.getColumnIndex(ENCRYPTION)),
@ -229,6 +204,17 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable
cursor.getInt(cursor.getColumnIndex(DELETED)) > 0);
}
private static Jid fromString(String value) {
try {
if (value != null) {
return Jid.of(value);
}
} catch (IllegalArgumentException e) {
return null;
}
return null;
}
public static Message createStatusMessage(Conversation conversation, String body) {
final Message message = new Message(conversation);
message.setType(Message.TYPE_STATUS);

View File

@ -4,9 +4,11 @@ import com.google.common.base.Objects;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import eu.siacs.conversations.services.AvatarService;
import eu.siacs.conversations.utils.LanguageUtils;
import eu.siacs.conversations.utils.UIHelper;
import retrofit2.Call;
import retrofit2.http.Body;
@ -35,6 +37,7 @@ public interface MuclumbusService {
public String address;
public String name;
public String description;
public String language;
public String getName() {
return name;
@ -52,6 +55,10 @@ public interface MuclumbusService {
}
}
public String getLanguage() {
return LanguageUtils.convert(language);
}
@Override
public int getAvatarBackgroundColor() {
Jid room = getRoom();

View File

@ -28,10 +28,8 @@ import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -750,14 +748,15 @@ public class DatabaseBackend extends SQLiteOpenHelper {
null, null, Message.TIME_SENT + " DESC",
String.valueOf(limit));
}
if (cursor.getCount() > 0) {
cursor.moveToLast();
do {
Message message = Message.fromCursor(cursor, conversation);
while (cursor.moveToNext()) {
try {
final Message message = Message.fromCursor(cursor, conversation);
if (message != null) {
list.add(message);
list.add(0, message);
}
} catch (Exception e) {
Log.e(Config.LOGTAG,"unable to restore message");
}
} while (cursor.moveToPrevious());
}
cursor.close();
return list;
@ -770,40 +769,6 @@ public class DatabaseBackend extends SQLiteOpenHelper {
return db.rawQuery(SQL, new String[]{FtsUtils.toMatchString(term)});
}
public Iterable<Message> getMessagesIterable(final Conversation conversation) {
return () -> {
class MessageIterator implements Iterator<Message> {
private SQLiteDatabase db = getReadableDatabase();
private String[] selectionArgs = {conversation.getUuid()};
private Cursor cursor = db.query(Message.TABLENAME, null, Message.CONVERSATION
+ "=?", selectionArgs, null, null, Message.TIME_SENT
+ " ASC", null);
private MessageIterator() {
cursor.moveToFirst();
}
@Override
public boolean hasNext() {
return !cursor.isAfterLast();
}
@Override
public Message next() {
Message message = Message.fromCursor(cursor, conversation);
cursor.moveToNext();
return message;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
return new MessageIterator();
};
}
public List<String> markFileAsDeleted(final File file, final boolean internal) {
SQLiteDatabase db = this.getReadableDatabase();
String selection;

View File

@ -10,6 +10,8 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.util.Locale;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.SearchResultItemBinding;
import eu.siacs.conversations.http.services.MuclumbusService;
@ -38,7 +40,7 @@ public class ChannelSearchResultAdapter extends ListAdapter<MuclumbusService.Roo
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
return new ViewHolder(DataBindingUtil.inflate(LayoutInflater.from(viewGroup.getContext()), R.layout.search_result_item,viewGroup,false));
return new ViewHolder(DataBindingUtil.inflate(LayoutInflater.from(viewGroup.getContext()), R.layout.search_result_item, viewGroup, false));
}
@Override
@ -46,12 +48,19 @@ public class ChannelSearchResultAdapter extends ListAdapter<MuclumbusService.Roo
final MuclumbusService.Room searchResult = getItem(position);
viewHolder.binding.name.setText(searchResult.getName());
final String description = searchResult.getDescription();
final String language = searchResult.getLanguage();
if (TextUtils.isEmpty(description)) {
viewHolder.binding.description.setVisibility(View.GONE);
} else {
viewHolder.binding.description.setText(description);
viewHolder.binding.description.setVisibility(View.VISIBLE);
}
if (language == null || language.length() != 2) {
viewHolder.binding.language.setVisibility(View.GONE);
} else {
viewHolder.binding.language.setText(language.toUpperCase(Locale.ENGLISH));
viewHolder.binding.language.setVisibility(View.VISIBLE);
}
viewHolder.binding.room.setText(searchResult.getRoom().asBareJid().toString());
AvatarWorkerTask.loadAvatar(searchResult, viewHolder.binding.avatar, R.dimen.avatar);
viewHolder.binding.getRoot().setOnClickListener(v -> listener.onChannelSearchResult(searchResult));

View File

@ -87,16 +87,20 @@ public class EditMessage extends EmojiWrapperEditText {
}
private void triggerKeyboardEvents(final int length) {
final KeyboardListener listener = this.keyboardListener;
if (listener == null) {
return;
}
this.mTypingHandler.removeCallbacks(mTypingTimeout);
this.mTypingHandler.postDelayed(mTypingTimeout, Config.TYPING_TIMEOUT * 1000);
if (!isUserTyping && length > 0) {
this.isUserTyping = true;
this.keyboardListener.onTypingStarted();
listener.onTypingStarted();
} else if (length == 0) {
this.isUserTyping = false;
this.keyboardListener.onTextDeleted();
listener.onTextDeleted();
}
this.keyboardListener.onTextChanged();
listener.onTextChanged();
}
public void setKeyboardListener(KeyboardListener listener) {

View File

@ -0,0 +1,28 @@
package eu.siacs.conversations.utils;
import com.google.common.collect.ImmutableMap;
import java.util.Locale;
import java.util.Map;
public class LanguageUtils {
private static final Map<String,String> LANGUAGE_MAP;
static {
ImmutableMap.Builder<String, String> builder = new ImmutableMap.Builder<>();
builder.put("german","de");
builder.put("deutsch","de");
builder.put("english","en");
builder.put("russian","ru");
LANGUAGE_MAP = builder.build();
}
public static String convert(final String in) {
if (in == null) {
return null;
}
final String out = LANGUAGE_MAP.get(in.toLowerCase(Locale.US));
return out == null ? in : out;
}
}

View File

@ -1003,16 +1003,17 @@ public class JingleConnection implements Transferable {
}
private void sendCandidateError() {
Log.d(Config.LOGTAG,"sending canditate error");
JinglePacket packet = bootstrapPacket("transport-info");
Content content = new Content(this.contentCreator, this.contentName);
content.setTransportId(this.transportId);
content.socks5transport().addChild("candidate-error");
packet.setContent(content);
this.sentCandidate = true;
this.sendJinglePacket(packet);
if (receivedCandidate && mJingleStatus == JINGLE_STATUS_ACCEPTED) {
connect();
}
this.sendJinglePacket(packet);
}
public int getJingleStatus() {

View File

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<layout 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"
xmlns:tools="http://schemas.android.com/tools">
<RelativeLayout
android:layout_width="match_parent"
@ -14,35 +15,49 @@
android:layout_height="48dp"
android:layout_alignParentLeft="true"
android:scaleType="centerCrop"
app:riv_corner_radius="2dp"/>
app:riv_corner_radius="2dp" />
<LinearLayout
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/avatar"
android:orientation="vertical"
android:layout_marginLeft="@dimen/avatar_item_distance">
android:layout_marginLeft="@dimen/avatar_item_distance"
android:layout_toRightOf="@+id/avatar">
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.Conversations.Subhead"/>
android:textAppearance="@style/TextAppearance.Conversations.Subhead"
tools:text="Proosdy IM Chat trantu" />
<TextView
android:id="@+id/language"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@id/name"
android:layout_marginLeft="8sp"
android:layout_toRightOf="@id/name"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.Conversations.Caption"
tools:text="EN" />
<TextView
android:id="@+id/description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/name"
android:maxLines="2"
android:textAppearance="@style/TextAppearance.Conversations.Body1"/>
android:textAppearance="@style/TextAppearance.Conversations.Body1" />
<TextView
android:id="@+id/room"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/description"
android:maxLines="2"
android:textAppearance="@style/TextAppearance.Conversations.Body1.Secondary"/>
</LinearLayout>
android:textAppearance="@style/TextAppearance.Conversations.Body1.Secondary" />
</RelativeLayout>
</RelativeLayout>
</layout>

View File

@ -422,8 +422,8 @@
<string name="no_application_found_to_display_location">Kokapena erakutsi dezakeen aplikaziorik ez da aurkitu</string>
<string name="location">Kokapena</string>
<string name="title_undo_swipe_out_conversation">Elkarrizketa itxi egin da</string>
<string name="title_undo_swipe_out_group_chat">Talde pribatua utzi</string>
<string name="title_undo_swipe_out_channel">Kanal publikoa utzi</string>
<string name="title_undo_swipe_out_group_chat">Talde pribatua utzi da</string>
<string name="title_undo_swipe_out_channel">Kanal publikoa utzi da</string>
<string name="pref_dont_trust_system_cas_title">Sistemaren CAtaz ez fidatu</string>
<string name="pref_dont_trust_system_cas_summary">Ziurtagiri guztiak eskuz onartu behar dira</string>
<string name="pref_remove_trusted_certificates_title">Ziurtagiriak kendu</string>
@ -850,4 +850,14 @@
<string name="search_participants">Parte-hartzaileak bilatu</string>
<string name="file_too_large">Fitxategia handiegia da</string>
<string name="attach">Erantsi</string>
<string name="discover_channels">Kanalak aurkitu</string>
<string name="search_channels">Kanalak bilatu</string>
<string name="channel_discovery_opt_in_title">Balizko pribatutasun urraketa!</string>
<string name="channel_discover_opt_in_message"><![CDATA[Kanalak aurkitzeko ezaugarriak <a href="https://search.jabbercat.org">search.jabbercat.org</a> izeneko hirugarren zerbitzu bat erabiltzen du.<br><br>Ezaugarri hau erabiltzeak zure IP helbidea eta bilatutako testua zerbitzu horretara bidaltzea dakar. Ikusi beren <a href="https://search.jabbercat.org/privacy">pribatutasun politika</a> informazio gehiago lortzeko.]]></string>
<string name="i_already_have_an_account">Badaukat kontu bat dagoeneko</string>
<string name="add_existing_account">Gehitu existitzen den kontu bat</string>
<string name="register_new_account">Kontu berria erregistratu</string>
<string name="this_looks_like_a_domain">Honek domeinu helbide baten itxura dauka</string>
<string name="add_anway">Gehitu hala ere</string>
<string name="this_looks_like_channel">Honek kanal helbide baten itxura dauka</string>
</resources>