aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/eu/siacs
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/eu/siacs')
-rw-r--r--src/main/java/eu/siacs/conversations/Config.java2
-rw-r--r--src/main/java/eu/siacs/conversations/crypto/PgpEngine.java9
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Account.java5
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Bookmark.java7
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Contact.java8
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Conversation.java10
-rw-r--r--src/main/java/eu/siacs/conversations/entities/ListItem.java2
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Message.java62
-rw-r--r--src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java5
-rw-r--r--src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java31
-rw-r--r--src/main/java/eu/siacs/conversations/parser/AbstractParser.java39
-rw-r--r--src/main/java/eu/siacs/conversations/parser/MessageParser.java3
-rw-r--r--src/main/java/eu/siacs/conversations/services/NotificationService.java5
-rw-r--r--src/main/java/eu/siacs/conversations/services/XmppConnectionService.java39
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ChangePasswordActivity.java9
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ConversationActivity.java4
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ConversationFragment.java156
-rw-r--r--src/main/java/eu/siacs/conversations/ui/EditMessage.java3
-rw-r--r--src/main/java/eu/siacs/conversations/ui/SettingsActivity.java87
-rw-r--r--src/main/java/eu/siacs/conversations/ui/XmppActivity.java4
-rw-r--r--src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java1
-rw-r--r--src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java42
-rw-r--r--src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java27
-rw-r--r--src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java15
-rw-r--r--src/main/java/eu/siacs/conversations/ui/listeners/ConversationMoreMessagesLoadedListener.java118
-rw-r--r--src/main/java/eu/siacs/conversations/ui/listeners/ConversationSwipeRefreshListener.java48
-rw-r--r--src/main/java/eu/siacs/conversations/utils/UIHelper.java26
-rw-r--r--src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java6
-rw-r--r--src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java1
29 files changed, 633 insertions, 141 deletions
diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java
index f3cbffe6..f2303626 100644
--- a/src/main/java/eu/siacs/conversations/Config.java
+++ b/src/main/java/eu/siacs/conversations/Config.java
@@ -30,6 +30,8 @@ public final class Config {
public static final int MESSAGE_MERGE_WINDOW = 20;
+ public static final boolean UTF8_EMOTICONS = false;
+
public static final int PAGE_SIZE = 50;
public static final int MAX_NUM_PAGES = 3;
diff --git a/src/main/java/eu/siacs/conversations/crypto/PgpEngine.java b/src/main/java/eu/siacs/conversations/crypto/PgpEngine.java
index 8f8122f0..33089a8c 100644
--- a/src/main/java/eu/siacs/conversations/crypto/PgpEngine.java
+++ b/src/main/java/eu/siacs/conversations/crypto/PgpEngine.java
@@ -17,6 +17,7 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
+import de.tzur.conversations.Settings;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
@@ -61,6 +62,8 @@ public class PgpEngine {
final HttpConnectionManager manager = mXmppConnectionService.getHttpConnectionManager();
if (message.trusted()
&& message.treatAsDownloadable() != Message.Decision.NEVER
+ && Settings.DOWNLOAD_IMAGE_LINKS
+ && mXmppConnectionService.isDownloadAllowedInConnection()
&& manager.getAutoAcceptFileSize() > 0) {
manager.createNewDownloadConnection(message);
}
@@ -167,7 +170,7 @@ public class PgpEngine {
String[] lines = os.toString().split("\n");
for (int i = 2; i < lines.length - 1; ++i) {
if (!lines[i].contains("Version")) {
- encryptedMessageBody.append(lines[i].trim());
+ encryptedMessageBody.append(lines[i]);
}
}
message.setEncryptedBody(encryptedMessageBody
@@ -242,7 +245,7 @@ public class PgpEngine {
pgpSig.append("-----BEGIN PGP SIGNATURE-----");
pgpSig.append('\n');
pgpSig.append('\n');
- pgpSig.append(signature.replace("\n", "").trim());
+ pgpSig.append(signature.replace("\n", ""));
pgpSig.append('\n');
pgpSig.append("-----END PGP SIGNATURE-----");
Intent params = new Intent();
@@ -295,7 +298,7 @@ public class PgpEngine {
sig = false;
} else {
if (!line.contains("Version")) {
- signatureBuilder.append(line.trim());
+ signatureBuilder.append(line);
}
}
}
diff --git a/src/main/java/eu/siacs/conversations/entities/Account.java b/src/main/java/eu/siacs/conversations/entities/Account.java
index 7a2dc3f7..a8b9252f 100644
--- a/src/main/java/eu/siacs/conversations/entities/Account.java
+++ b/src/main/java/eu/siacs/conversations/entities/Account.java
@@ -130,6 +130,7 @@ public class Account extends AbstractEntity {
private final Roster roster = new Roster(this);
private List<Bookmark> bookmarks = new CopyOnWriteArrayList<>();
private final Collection<Jid> blocklist = new CopyOnWriteArraySet<>();
+ private XmppConnectionService mXmppConnectionService;
public Account() {
this.uuid = "0";
@@ -429,4 +430,8 @@ public class Account extends AbstractEntity {
public boolean isOnlineAndConnected() {
return this.getStatus() == State.ONLINE && this.getXmppConnection() != null;
}
+
+ public XmppConnectionService getXmppConnectionService() {
+ return mXmppConnectionService;
+ }
}
diff --git a/src/main/java/eu/siacs/conversations/entities/Bookmark.java b/src/main/java/eu/siacs/conversations/entities/Bookmark.java
index cc6f146b..06c46c1c 100644
--- a/src/main/java/eu/siacs/conversations/entities/Bookmark.java
+++ b/src/main/java/eu/siacs/conversations/entities/Bookmark.java
@@ -1,5 +1,7 @@
package eu.siacs.conversations.entities;
+import android.graphics.Color;
+
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
@@ -74,6 +76,11 @@ public class Bookmark extends Element implements ListItem {
return tags;
}
+ @Override
+ public int getStatusColor() {
+ return Color.parseColor("#259B23");
+ }
+
public String getNick() {
return this.findChildContent("nick");
}
diff --git a/src/main/java/eu/siacs/conversations/entities/Contact.java b/src/main/java/eu/siacs/conversations/entities/Contact.java
index f924c05a..2d103faf 100644
--- a/src/main/java/eu/siacs/conversations/entities/Contact.java
+++ b/src/main/java/eu/siacs/conversations/entities/Contact.java
@@ -2,6 +2,7 @@ package eu.siacs.conversations.entities;
import android.content.ContentValues;
import android.database.Cursor;
+import android.graphics.Color;
import org.json.JSONArray;
import org.json.JSONException;
@@ -152,11 +153,16 @@ public class Contact implements ListItem, Blockable {
return tags;
}
+ @Override
+ public int getStatusColor() {
+ return Color.parseColor(UIHelper.getStatusColor(getMostAvailableStatus()));
+ }
+
public boolean match(String needle) {
if (needle == null || needle.isEmpty()) {
return true;
}
- needle = needle.toLowerCase(Locale.US).trim();
+ needle = needle.toLowerCase(Locale.US);
String[] parts = needle.split("\\s+");
if (parts.length > 1) {
for(int i = 0; i < parts.length; ++i) {
diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java
index 36d6b43b..1c985e2f 100644
--- a/src/main/java/eu/siacs/conversations/entities/Conversation.java
+++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java
@@ -775,10 +775,16 @@ public class Conversation extends AbstractEntity implements Blockable {
synchronized (this.messages) {
int count = 0;
for(int i = this.messages.size() - 1; i >= 0; --i) {
- if (this.messages.get(i).isRead()) {
+ Message message = this.messages.get(i);
+ if (message.isRead()) {
return count;
}
- ++count;
+ if (getMode() == Conversation.MODE_SINGLE
+ || account.getXmppConnectionService().getNotificationService().conferenceNotificationsEnabled()
+ || account.getXmppConnectionService().getNotificationService().wasHighlightedOrPrivate(message)
+ ) {
+ ++count;
+ }
}
return count;
}
diff --git a/src/main/java/eu/siacs/conversations/entities/ListItem.java b/src/main/java/eu/siacs/conversations/entities/ListItem.java
index efc1c2b9..aba2aef2 100644
--- a/src/main/java/eu/siacs/conversations/entities/ListItem.java
+++ b/src/main/java/eu/siacs/conversations/entities/ListItem.java
@@ -11,6 +11,8 @@ public interface ListItem extends Comparable<ListItem> {
public List<Tag> getTags();
+ public int getStatusColor();
+
public final class Tag {
private final String name;
private final int color;
diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java
index 0eff99cf..6a878e90 100644
--- a/src/main/java/eu/siacs/conversations/entities/Message.java
+++ b/src/main/java/eu/siacs/conversations/entities/Message.java
@@ -63,7 +63,7 @@ public class Message extends AbstractEntity {
protected String conversationUuid;
protected Jid counterpart;
protected Jid trueCounterpart;
- protected String body;
+ private String body;
protected String encryptedBody;
protected long timeSent;
protected int encryption;
@@ -345,16 +345,16 @@ public class Message extends AbstractEntity {
public boolean equals(Message message) {
if (this.serverMsgId != null && message.getServerMsgId() != null) {
return this.serverMsgId.equals(message.getServerMsgId());
- } else if (this.body == null || this.counterpart == null) {
+ } else if (this.getBody() == null || this.counterpart == null) {
return false;
} else {
String body, otherBody;
if (this.hasFileOnRemoteHost()) {
body = getFileParams().url.toString();
- otherBody = message.body == null ? null : message.body.trim();
+ otherBody = message.getBody() == null ? null : message.getBody();
} else {
- body = this.body;
- otherBody = message.body;
+ body = this.getBody();
+ otherBody = message.getBody();
}
if (message.getRemoteMsgId() != null) {
return (message.getRemoteMsgId().equals(this.remoteMsgId) || message.getRemoteMsgId().equals(this.uuid))
@@ -411,13 +411,11 @@ public class Message extends AbstractEntity {
this.getCounterpart().equals(message.getCounterpart()) &&
(message.getTimeSent() - this.getTimeSent()) <= (Config.MESSAGE_MERGE_WINDOW * 1000) &&
!GeoHelper.isGeoUri(message.getBody()) &&
- !GeoHelper.isGeoUri(this.body) &&
+ !GeoHelper.isGeoUri(this.getBody()) &&
message.treatAsDownloadable() == Decision.NEVER &&
this.treatAsDownloadable() == Decision.NEVER &&
!message.getBody().startsWith(ME_COMMAND) &&
!this.getBody().startsWith(ME_COMMAND) &&
- !this.bodyIsHeart() &&
- !message.bodyIsHeart() &&
this.isTrusted() == message.isTrusted()
);
}
@@ -439,7 +437,7 @@ public class Message extends AbstractEntity {
while(current.mergeable(current.next())) {
current = current.next();
body.append(MERGE_SEPARATOR);
- body.append(current.getBody().trim());
+ body.append(current.getBody());
}
return body.toString();
}
@@ -506,17 +504,28 @@ public class Message extends AbstractEntity {
private static String extractRelevantExtension(URL url) {
String path = url.getPath();
+ return extractRelevantExtension(path);
+ }
+
+ private static String extractRelevantExtension(String path) {
if (path == null || path.isEmpty()) {
return null;
}
+
String filename = path.substring(path.lastIndexOf('/') + 1).toLowerCase();
- String[] extensionParts = filename.split("\\.");
- if (extensionParts.length == 2) {
- return extensionParts[extensionParts.length - 1];
- } else if (extensionParts.length == 3 && Arrays
- .asList(Transferable.VALID_CRYPTO_EXTENSIONS)
- .contains(extensionParts[extensionParts.length - 1])) {
- return extensionParts[extensionParts.length -2];
+
+ int dotPosition = filename.lastIndexOf(".");
+
+ if (dotPosition != -1)
+ {
+ String extension = filename.substring(dotPosition + 1);
+
+ // we want the real file extension, not the crypto one
+ if (Arrays.asList(Transferable.VALID_CRYPTO_EXTENSIONS).contains(extension)) {
+ return extractRelevantExtension(path.substring(0,dotPosition));
+ } else {
+ return extension;
+ }
}
return null;
}
@@ -531,7 +540,7 @@ public class Message extends AbstractEntity {
}
} else {
try {
- return MimeUtils.guessMimeTypeFromExtension(extractRelevantExtension(new URL(body.trim())));
+ return MimeUtils.guessMimeTypeFromExtension(extractRelevantExtension(new URL(this.getBody())));
} catch (MalformedURLException e) {
return null;
}
@@ -539,7 +548,12 @@ public class Message extends AbstractEntity {
}
public Decision treatAsDownloadable() {
- if (body.trim().contains(" ")) {
+ /**
+ * there are a few cases where spaces result in an unwanted behavior, e.g.
+ * "http://example.com/image.jpg" text that will not be shown /abc.png"
+ * or more than one image link in one message.
+ */
+ if (getBody().contains(" ")) {
return Decision.NEVER;
}
try {
@@ -572,10 +586,6 @@ public class Message extends AbstractEntity {
}
}
- public boolean bodyIsHeart() {
- return body != null && UIHelper.HEARTS.contains(body.trim());
- }
-
public FileParams getFileParams() {
FileParams params = getLegacyFileParams();
if (params != null) {
@@ -585,10 +595,10 @@ public class Message extends AbstractEntity {
if (this.transferable != null) {
params.size = this.transferable.getFileSize();
}
- if (body == null) {
+ if (this.getBody() == null) {
return params;
}
- String parts[] = body.split("\\|");
+ String parts[] = this.getBody().split("\\|");
switch (parts.length) {
case 1:
try {
@@ -647,10 +657,10 @@ public class Message extends AbstractEntity {
public FileParams getLegacyFileParams() {
FileParams params = new FileParams();
- if (body == null) {
+ if (this.getBody() == null) {
return params;
}
- String parts[] = body.split(",");
+ String parts[] = this.getBody().split(",");
if (parts.length == 3) {
try {
params.size = Long.parseLong(parts[0]);
diff --git a/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java b/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java
index 69bb1803..3a256219 100644
--- a/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java
+++ b/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java
@@ -12,6 +12,7 @@ import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
+import de.tzur.conversations.Settings;
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.utils.PhoneHelper;
@@ -72,7 +73,7 @@ public abstract class AbstractGenerator {
s.append(feature + "<");
}
byte[] sha1 = md.digest(s.toString().getBytes());
- return new String(Base64.encode(sha1, Base64.DEFAULT)).trim();
+ return new String(Base64.encode(sha1, Base64.DEFAULT));
}
public static String getTimestamp(long time) {
@@ -83,7 +84,7 @@ public abstract class AbstractGenerator {
public List<String> getFeatures() {
ArrayList<String> features = new ArrayList<>();
features.addAll(Arrays.asList(FEATURES));
- if (mXmppConnectionService.confirmMessages()) {
+ if (Settings.CONFIRM_MESSAGE_RECEIVED) {
features.addAll(Arrays.asList(MESSAGE_CONFIRMATION_FEATURES));
}
Collections.sort(features);
diff --git a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java
index 0d202bb9..356f9417 100644
--- a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java
+++ b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java
@@ -165,7 +165,7 @@ public class HttpDownloadConnection implements Transferable {
return;
}
file.setExpectedSize(size);
- if (size <= mHttpConnectionManager.getAutoAcceptFileSize()) {
+ if (size != -1 && size <= mHttpConnectionManager.getAutoAcceptFileSize()) {
HttpDownloadConnection.this.acceptedAutomatically = true;
new Thread(new FileDownloader(interactive)).start();
} else {
@@ -176,25 +176,22 @@ public class HttpDownloadConnection implements Transferable {
}
private long retrieveFileSize() throws IOException {
+ Log.d(Config.LOGTAG,"retrieve file size. interactive:"+String.valueOf(interactive));
+ changeStatus(STATUS_CHECKING);
+ HttpURLConnection connection = (HttpURLConnection) mUrl.openConnection();
+ connection.setRequestMethod("HEAD");
+ if (connection instanceof HttpsURLConnection) {
+ mHttpConnectionManager.setupTrustManager((HttpsURLConnection) connection, interactive);
+ }
+ connection.connect();
+ String contentLength = connection.getHeaderField("Content-Length");
+ if (contentLength == null) {
+ return -1;
+ }
try {
- Log.d(Config.LOGTAG, "retrieve file size. interactive:" + String.valueOf(interactive));
- changeStatus(STATUS_CHECKING);
- HttpURLConnection connection = (HttpURLConnection) mUrl.openConnection();
- connection.setRequestMethod("HEAD");
- if (connection instanceof HttpsURLConnection) {
- mHttpConnectionManager.setupTrustManager((HttpsURLConnection) connection, interactive);
- }
- connection.connect();
- String contentLength = connection.getHeaderField("Content-Length");
- connection.disconnect();
- if (contentLength == null) {
- throw new IOException();
- }
return Long.parseLong(contentLength, 10);
- } catch (IOException e) {
- throw e;
} catch (NumberFormatException e) {
- throw new IOException();
+ return -1;
}
}
diff --git a/src/main/java/eu/siacs/conversations/parser/AbstractParser.java b/src/main/java/eu/siacs/conversations/parser/AbstractParser.java
index 18331796..3f11f756 100644
--- a/src/main/java/eu/siacs/conversations/parser/AbstractParser.java
+++ b/src/main/java/eu/siacs/conversations/parser/AbstractParser.java
@@ -1,16 +1,21 @@
package eu.siacs.conversations.parser;
+import android.util.Log;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
+import javax.xml.datatype.DatatypeConfigurationException;
+import javax.xml.datatype.DatatypeFactory;
+
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xmpp.jid.Jid;
+import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
public abstract class AbstractParser {
@@ -20,6 +25,15 @@ public abstract class AbstractParser {
this.mXmppConnectionService = service;
}
+ /**
+ * Gets the timestamp from the 'delay' element.
+ * Refer to XEP-0203: Delayed Delivery for details. @link{http://xmpp.org/extensions/xep-0203.html}
+ * @param packet the element to find the child element 'delay' in.
+ * @return the time in milli seconds of the attribute 'stamp' of the
+ * element 'delay'. In case there is no 'delay' element or no 'stamp'
+ * attribute or the current time is less than the value of the 'stamp'
+ * attribute the current time is returned.
+ */
public static Long getTimestamp(Element element, Long defaultValue) {
Element delay = element.findChild("delay","urn:xmpp:delay");
if (delay != null) {
@@ -39,12 +53,27 @@ public abstract class AbstractParser {
return getTimestamp(packet,System.currentTimeMillis());
}
+ /**
+ * Parses the timestamp according to XEP-0082: XMPP Date and Time Profiles.
+ * @link{http://xmpp.org/extensions/xep-0082.html}
+ *
+ * @param timestamp the timestamp to parse
+ * @return Date
+ * @throws ParseException
+ */
public static Date parseTimestamp(String timestamp) throws ParseException {
- timestamp = timestamp.replace("Z", "+0000");
- SimpleDateFormat dateFormat;
- timestamp = timestamp.substring(0,19)+timestamp.substring(timestamp.length() -5,timestamp.length());
- dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ",Locale.US);
- return dateFormat.parse(timestamp);
+ /*try {
+ Log.d("TIMESTAMP", timestamp);
+ return DatatypeFactory.newInstance().newXMLGregorianCalendar(timestamp).toGregorianCalendar().getTime();
+ } catch (DatatypeConfigurationException e) {
+ Log.d("TIMESTAMP", e.getMessage());
+ return new Date();
+ }*/
+ timestamp = timestamp.replace("Z", "+0000");
+ SimpleDateFormat dateFormat;
+ timestamp = timestamp.substring(0,19)+timestamp.substring(timestamp.length() -5,timestamp.length());
+ dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ",Locale.US);
+ return dateFormat.parse(timestamp);
}
protected void updateLastseen(final Element packet, final Account account, final boolean presenceOverwrite) {
diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java
index 025ed1e7..e2f13bd3 100644
--- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java
+++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java
@@ -8,6 +8,7 @@ import net.java.otr4j.session.SessionStatus;
import java.util.Set;
+import de.tzur.conversations.Settings;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
import eu.siacs.conversations.crypto.axolotl.XmppAxolotlMessage;
@@ -117,6 +118,8 @@ public class MessageParser extends AbstractParser implements
this.jid = jid;
this.password = password;
}
+ return false;
+ }
public boolean execute(Account account) {
if (jid != null) {
diff --git a/src/main/java/eu/siacs/conversations/services/NotificationService.java b/src/main/java/eu/siacs/conversations/services/NotificationService.java
index 90e4d216..d03dcb84 100644
--- a/src/main/java/eu/siacs/conversations/services/NotificationService.java
+++ b/src/main/java/eu/siacs/conversations/services/NotificationService.java
@@ -31,6 +31,7 @@ import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import de.tzur.conversations.Settings;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
@@ -218,7 +219,7 @@ public class NotificationService {
mBuilder.setDefaults(0);
mBuilder.setSmallIcon(R.drawable.ic_notification);
mBuilder.setDeleteIntent(createDeleteIntent());
- mBuilder.setLights(0xff00FF00, 2000, 3000);
+ mBuilder.setLights(Settings.LED_COLOR, 2000, 4000);
final Notification notification = mBuilder.build();
notificationManager.notify(NOTIFICATION_ID, notification);
}
@@ -442,7 +443,7 @@ public class NotificationService {
return PendingIntent.getService(mXmppConnectionService,0,intent,PendingIntent.FLAG_UPDATE_CURRENT);
}
- private boolean wasHighlightedOrPrivate(final Message message) {
+ public boolean wasHighlightedOrPrivate(final Message message) {
final String nick = message.getConversation().getMucOptions().getActualNick();
final Pattern highlight = generateNickHighlightPattern(nick);
if (message.getBody() == null || nick == null) {
diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
index 36d6cd49..b165ede4 100644
--- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
+++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
@@ -49,6 +49,7 @@ import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import de.duenndns.ssl.MemorizingTrustManager;
+import de.tzur.conversations.Settings;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.PgpEngine;
@@ -579,6 +580,25 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
return activeNetwork != null && activeNetwork.isConnected();
}
+ /**
+ * check whether we are allowed to download at the moment
+ */
+ public boolean isDownloadAllowedInConnection() {
+ if (Settings.DOWNLOAD_ONLY_WLAN) {
+ return isWifiConnected();
+ }
+ return true;
+ }
+
+ /**
+ * check whether wifi is connected
+ */
+ public boolean isWifiConnected() {
+ ConnectivityManager cm = (ConnectivityManager) getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
+ NetworkInfo niWifi = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ return niWifi.isConnected();
+ }
+
@SuppressLint("TrulyRandom")
@Override
public void onCreate() {
@@ -1069,6 +1089,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
public void loadMoreMessages(final Conversation conversation, final long timestamp, final OnMoreMessagesLoaded callback) {
Log.d(Config.LOGTAG, "load more messages for " + conversation.getName() + " prior to " + MessageGenerator.getTimestamp(timestamp));
if (XmppConnectionService.this.getMessageArchiveService().queryInProgress(conversation,callback)) {
+ Log.d("mam", "Query in progress");
return;
}
Runnable runnable = new Runnable() {
@@ -1076,19 +1097,26 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
public void run() {
final Account account = conversation.getAccount();
List<Message> messages = databaseBackend.getMessages(conversation, 50,timestamp);
+ Log.d("mam", "runnable load more messages");
if (messages.size() > 0) {
+ Log.d("mam", "At least one message");
conversation.addAll(0, messages);
checkDeletedFiles(conversation);
callback.onMoreMessagesLoaded(messages.size(), conversation);
} else if (conversation.hasMessagesLeftOnServer()
&& account.isOnlineAndConnected()
&& account.getXmppConnection().getFeatures().mam()) {
+ Log.d("mam", "mam activate, account online and connected and messages left on server");
MessageArchiveService.Query query = getMessageArchiveService().query(conversation,0,timestamp - 1);
if (query != null) {
query.setCallback(callback);
}
callback.informUser(R.string.fetching_history_from_server);
- }
+ } else {
+ Log.d("mam", ((!conversation.hasMessagesLeftOnServer()) ? "no" : "") + " more messages left on server, mam " + ((account.getXmppConnection().getFeatures().mam()) ? "" : "not") + " activated, account is " + ((account.isOnlineAndConnected()) ? "" : "not") + " online or connected)");
+ callback.onMoreMessagesLoaded(0, conversation);
+ callback.informUser(R.string.no_more_history_on_server);
+ }
}
};
mDatabaseExecutor.execute(runnable);
@@ -2371,7 +2399,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
public void sendReadMarker(final Conversation conversation) {
final Message markable = conversation.getLatestMarkableMessage();
this.markRead(conversation);
- if (confirmMessages() && markable != null && markable.getRemoteMsgId() != null) {
+ if (Settings.CONFIRM_MESSAGE_READ && markable != null && markable.getRemoteMsgId() != null) {
Log.d(Config.LOGTAG, conversation.getAccount().getJid().toBareJid() + ": sending read marker to " + markable.getCounterpart().toString());
Account account = conversation.getAccount();
final Jid to = markable.getCounterpart();
@@ -2549,7 +2577,12 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
public void clearConversationHistory(final Conversation conversation) {
conversation.clearMessages();
- conversation.setHasMessagesLeftOnServer(false); //avoid messages getting loaded through mam
+ /*
+ * In case the history was loaded completely before.
+ * The flag "hasMessagesLeftOnServer" is set to false and no messages will be loaded anymore
+ * Therefore set this flag to true and try to get messages from server
+ */
+ conversation.setHasMessagesLeftOnServer(true);
new Thread(new Runnable() {
@Override
public void run() {
diff --git a/src/main/java/eu/siacs/conversations/ui/ChangePasswordActivity.java b/src/main/java/eu/siacs/conversations/ui/ChangePasswordActivity.java
index aa986bd1..09988b7c 100644
--- a/src/main/java/eu/siacs/conversations/ui/ChangePasswordActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ChangePasswordActivity.java
@@ -26,11 +26,14 @@ public class ChangePasswordActivity extends XmppActivity implements XmppConnecti
mCurrentPassword.requestFocus();
mCurrentPassword.setError(getString(R.string.account_status_unauthorized));
} else if (!newPassword.equals(newPasswordConfirm)) {
- mNewPasswordConfirm.requestFocus();
- mNewPasswordConfirm.setError(getString(R.string.passwords_do_not_match));
+ mNewPasswordConfirm.requestFocus();
+ mNewPasswordConfirm.setError(getString(R.string.passwords_do_not_match));
+ } else if (newPassword.isEmpty()) {
+ mNewPassword.requestFocus();
+ mNewPassword.setError(getString(R.string.password_should_not_be_empty));
} else if (newPassword.trim().isEmpty()) {
mNewPassword.requestFocus();
- mNewPassword.setError(getString(R.string.password_should_not_be_empty));
+ mNewPassword.setError(getString(R.string.password_should_not_contain_only_spaces));
} else {
mCurrentPassword.setError(null);
mNewPassword.setError(null);
diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java
index 219a4fca..7fec827b 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java
@@ -53,6 +53,7 @@ import eu.siacs.conversations.utils.ExceptionHelper;
import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
import eu.siacs.conversations.xmpp.jid.Jid;
+import github.ankushsachdeva.emojicon.EmojiconEditText;
public class ConversationActivity extends XmppActivity
implements OnAccountUpdate, OnConversationUpdate, OnRosterUpdate, OnUpdateBlocklist, XmppConnectionService.OnShowErrorToast {
@@ -257,6 +258,7 @@ public class ConversationActivity extends XmppActivity
}
});
listView.enableSwipeToDismiss();
+ listView.setSwipeDirection(EnhancedListView.SwipeDirection.START);
listView.setSwipingLayout(R.id.swipeable_item);
listView.setUndoStyle(EnhancedListView.UndoStyle.SINGLE_POPUP);
listView.setUndoHideDelay(5000);
@@ -1144,7 +1146,7 @@ public class ConversationActivity extends XmppActivity
}
prepareFileToast = Toast.makeText(getApplicationContext(),getText(R.string.preparing_file), Toast.LENGTH_LONG);
prepareFileToast.show();
- xmppConnectionService.attachFileToConversation(conversation,uri, new UiCallback<Message>() {
+ xmppConnectionService.attachFileToConversation(conversation, uri, new UiCallback<Message>() {
@Override
public void success(Message message) {
hidePrepareFileToast();
diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
index de758efc..f645b241 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
@@ -11,7 +11,9 @@ import android.content.Intent;
import android.content.IntentSender;
import android.content.IntentSender.SendIntentException;
import android.os.Bundle;
+import android.support.v4.widget.SwipeRefreshLayout;
import android.text.InputType;
+import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Gravity;
@@ -23,12 +25,12 @@ import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
-import android.widget.AbsListView;
-import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.ImageButton;
+import android.widget.ImageView;
import android.widget.ListView;
+import android.widget.PopupWindow;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
@@ -47,7 +49,13 @@ import eu.siacs.conversations.crypto.PgpEngine;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
+<<<<<<< HEAD
+import eu.siacs.conversations.entities.Transferable;
+import eu.siacs.conversations.entities.DownloadableFile;
+import eu.siacs.conversations.entities.TransferablePlaceholder;
+=======
import eu.siacs.conversations.entities.DownloadableFile;
+>>>>>>> 1.6.3
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.MucOptions;
import eu.siacs.conversations.entities.Presences;
@@ -59,10 +67,14 @@ import eu.siacs.conversations.ui.XmppActivity.OnValueEdited;
import eu.siacs.conversations.ui.adapter.MessageAdapter;
import eu.siacs.conversations.ui.adapter.MessageAdapter.OnContactPictureClicked;
import eu.siacs.conversations.ui.adapter.MessageAdapter.OnContactPictureLongClicked;
+import eu.siacs.conversations.ui.listeners.ConversationSwipeRefreshListener;
import eu.siacs.conversations.utils.GeoHelper;
import eu.siacs.conversations.utils.UIHelper;
import eu.siacs.conversations.xmpp.chatstate.ChatState;
import eu.siacs.conversations.xmpp.jid.Jid;
+import github.ankushsachdeva.emojicon.EmojiconGridView;
+import github.ankushsachdeva.emojicon.EmojiconsPopup;
+import github.ankushsachdeva.emojicon.emoji.Emojicon;
public class ConversationFragment extends Fragment implements EditMessage.KeyboardListener {
@@ -101,10 +113,14 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
}
};
protected ListView messagesView;
- final protected List<Message> messageList = new ArrayList<>();
+ protected SwipeRefreshLayout swipeLayout;
+ final protected List<Message> messageList = new ArrayList<>();
protected MessageAdapter messageListAdapter;
private EditMessage mEditMessage;
private ImageButton mSendButton;
+ private ImageView mEmojButton;
+ private View mRootView;
+ private EmojiconsPopup mEmojPopup;
private RelativeLayout snackbar;
private TextView snackbarMessage;
private TextView snackbarAction;
@@ -371,6 +387,107 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
});
mEditMessage.setOnEditorActionListener(mEditorActionListener);
+ // Start of emojicon
+ mEmojButton = (ImageView) view.findViewById(R.id.emoji_btn);
+ mRootView = view.findViewById(R.id.textsend);
+
+ // Give the topmost view of your activity layout hierarchy. This will be used to measure soft keyboard height
+ mEmojPopup = new EmojiconsPopup(mRootView, this.getActivity());
+
+ //Will automatically set size according to the soft keyboard size
+ mEmojPopup.setSizeForSoftKeyboard();
+
+ //If the emoji popup is dismissed, change emojiButton to smiley icon
+ mEmojPopup.setOnDismissListener(new PopupWindow.OnDismissListener() {
+
+ @Override
+ public void onDismiss() {
+ changeEmojiKeyboardIcon(mEmojButton, R.drawable.smiley);
+ }
+ });
+
+ //If the text keyboard closes, also dismiss the emoji popup
+ mEmojPopup.setOnSoftKeyboardOpenCloseListener(new EmojiconsPopup.OnSoftKeyboardOpenCloseListener() {
+
+ @Override
+ public void onKeyboardOpen(int keyBoardHeight) {
+
+ }
+
+ @Override
+ public void onKeyboardClose() {
+ if (mEmojPopup.isShowing())
+ mEmojPopup.dismiss();
+ }
+ });
+
+ //On emoji clicked, add it to edittext
+ mEmojPopup.setOnEmojiconClickedListener(new EmojiconGridView.OnEmojiconClickedListener() {
+
+ @Override
+ public void onEmojiconClicked(Emojicon emojicon) {
+ if (mEditMessage == null || emojicon == null) {
+ return;
+ }
+
+ int start = mEditMessage.getSelectionStart();
+ int end = mEditMessage.getSelectionEnd();
+ if (start < 0) {
+ mEditMessage.append(emojicon.getEmoji());
+ } else {
+ mEditMessage.getText().replace(Math.min(start, end),
+ Math.max(start, end), emojicon.getEmoji(), 0,
+ emojicon.getEmoji().length());
+ }
+ }
+ });
+
+ //On backspace clicked, emulate the KEYCODE_DEL key event
+ mEmojPopup.setOnEmojiconBackspaceClickedListener(new EmojiconsPopup.OnEmojiconBackspaceClickedListener() {
+
+ @Override
+ public void onEmojiconBackspaceClicked(View v) {
+ KeyEvent event = new KeyEvent(
+ 0, 0, 0, KeyEvent.KEYCODE_DEL, 0, 0, 0, 0, KeyEvent.KEYCODE_ENDCALL);
+ mEditMessage.dispatchKeyEvent(event);
+ }
+ });
+
+ // To toggle between text keyboard and emoji keyboard keyboard(Popup)
+ mEmojButton.setOnClickListener(new OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+
+ //If popup is not showing => emoji keyboard is not visible, we need to show it
+ if(!mEmojPopup.isShowing()){
+
+ //If keyboard is visible, simply show the emoji popup
+ if(mEmojPopup.isKeyBoardOpen()){
+ mEmojPopup.showAtBottom();
+ changeEmojiKeyboardIcon(mEmojButton, R.drawable.ic_action_keyboard);
+ }
+
+ //else, open the text keyboard first and immediately after that show the emoji popup
+ else{
+ mEditMessage.setFocusableInTouchMode(true);
+ mEditMessage.requestFocus();
+ mEmojPopup.showAtBottomPending();
+ final InputMethodManager inputMethodManager = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
+ inputMethodManager.showSoftInput(mEditMessage, InputMethodManager.SHOW_IMPLICIT);
+ changeEmojiKeyboardIcon(mEmojButton, R.drawable.ic_action_keyboard);
+ }
+ }
+
+ //If popup is showing, simply dismiss it to show the undelying text keyboard
+ else{
+ mEmojPopup.dismiss();
+ }
+ }
+ });
+
+ // End of emojicon
+
mSendButton = (ImageButton) view.findViewById(R.id.textSendButton);
mSendButton.setOnClickListener(this.mSendButtonListener);
@@ -434,6 +551,12 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
registerForContextMenu(messagesView);
+ // Start of swipe refresh
+ // New Swipe refresh
+ swipeLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipe_refresh_container);
+ swipeLayout.setOnRefreshListener(new ConversationSwipeRefreshListener(messageList, swipeLayout, this, messagesView, messageListAdapter));
+ // End of swipe refresh
+
return view;
}
@@ -572,7 +695,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
resId = R.string.file_url;
url = message.getFileParams().url.toString();
} else {
- url = message.getBody().trim();
+ url = message.getBody();
resId = R.string.file_url;
}
if (activity.copyTextToClipboard(url, resId)) {
@@ -603,7 +726,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
}
protected void highlightInConference(String nick) {
- String oldString = mEditMessage.getText().toString().trim();
+ String oldString = mEditMessage.getText().toString();
if (oldString.isEmpty() || mEditMessage.getSelectionStart() == 0) {
mEditMessage.getText().insert(0, nick + ": ");
} else {
@@ -669,6 +792,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
if (size > 0) {
messagesView.setSelection(size - 1);
}
+ swipeLayout.setRefreshing(false);
}
private OnClickListener mUnblockClickListener = new OnClickListener() {
@@ -1151,15 +1275,15 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
final ConversationActivity activity = (ConversationActivity) getActivity();
final XmppConnectionService xmppService = activity.xmppConnectionService;
activity.selectPresence(message.getConversation(),
- new OnPresenceSelected() {
-
- @Override
- public void onPresenceSelected() {
- message.setCounterpart(conversation.getNextCounterpart());
- xmppService.sendMessage(message);
- messageSent();
- }
- });
+ new OnPresenceSelected() {
+
+ @Override
+ public void onPresenceSelected() {
+ message.setCounterpart(conversation.getNextCounterpart());
+ xmppService.sendMessage(message);
+ messageSent();
+ }
+ });
}
public void appendText(String text) {
@@ -1224,4 +1348,8 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
}
}
+ private void changeEmojiKeyboardIcon(ImageView iconToBeChanged, int drawableResourceId){
+ iconToBeChanged.setImageResource(drawableResourceId);
+ }
+
}
diff --git a/src/main/java/eu/siacs/conversations/ui/EditMessage.java b/src/main/java/eu/siacs/conversations/ui/EditMessage.java
index a58cf2b8..a7aa2024 100644
--- a/src/main/java/eu/siacs/conversations/ui/EditMessage.java
+++ b/src/main/java/eu/siacs/conversations/ui/EditMessage.java
@@ -7,8 +7,9 @@ import android.view.KeyEvent;
import android.widget.EditText;
import eu.siacs.conversations.Config;
+import github.ankushsachdeva.emojicon.EmojiconEditText;
-public class EditMessage extends EditText {
+public class EditMessage extends EmojiconEditText {
public EditMessage(Context context, AttributeSet attrs) {
super(context, attrs);
diff --git a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java
index 6e5fe610..f9238f13 100644
--- a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java
@@ -1,6 +1,21 @@
package eu.siacs.conversations.ui;
+import java.security.KeyStoreException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Locale;
+
+import de.tzur.conversations.Settings;
+import de.duenndns.ssl.MemorizingTrustManager;
+
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.xmpp.XmppConnection;
+import github.ankushsachdeva.emojicon.EmojiconHandler;
+
import android.app.AlertDialog;
+import android.app.Fragment;
import android.app.FragmentManager;
import android.content.DialogInterface;
import android.content.SharedPreferences;
@@ -12,17 +27,6 @@ import android.preference.Preference;
import android.preference.PreferenceManager;
import android.widget.Toast;
-import java.security.KeyStoreException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Locale;
-
-import de.duenndns.ssl.MemorizingTrustManager;
-import eu.siacs.conversations.R;
-import eu.siacs.conversations.entities.Account;
-import eu.siacs.conversations.xmpp.XmppConnection;
-
public class SettingsActivity extends XmppActivity implements
OnSharedPreferenceChangeListener {
private SettingsFragment mSettingsFragment;
@@ -130,37 +134,46 @@ public class SettingsActivity extends XmppActivity implements
@Override
public void onSharedPreferenceChanged(SharedPreferences preferences,
String name) {
- if (name.equals("resource")) {
- String resource = preferences.getString("resource", "mobile")
- .toLowerCase(Locale.US);
- if (xmppConnectionServiceBound) {
- for (Account account : xmppConnectionService.getAccounts()) {
- if (account.setResource(resource)) {
+ // need to synchronize the settings class first
+ Settings.synchronizeSettingsClassWithPreferences(getPreferences(), name);
+ switch (name) {
+ case "resource":
+ String resource = preferences.getString("resource", "mobile")
+ .toLowerCase(Locale.US);
+ if (xmppConnectionServiceBound) {
+ for (Account account : xmppConnectionService.getAccounts()) {
+ if (account.setResource(resource)) {
+ if (!account.isOptionSet(Account.OPTION_DISABLED)) {
+ XmppConnection connection = account.getXmppConnection();
+ if (connection != null) {
+ connection.resetStreamId();
+ }
+ xmppConnectionService.reconnectAccountInBackground(account);
+ }
+ }
+ }
+ }
+ break;
+ case "keep_foreground_service":
+ xmppConnectionService.toggleForegroundService();
+ break;
+ case "confirm_messages":
+ if (xmppConnectionServiceBound) {
+ for (Account account : xmppConnectionService.getAccounts()) {
if (!account.isOptionSet(Account.OPTION_DISABLED)) {
- XmppConnection connection = account.getXmppConnection();
- if (connection != null) {
- connection.resetStreamId();
- }
- xmppConnectionService.reconnectAccountInBackground(account);
+ xmppConnectionService.sendPresence(account);
}
}
}
- }
- } else if (name.equals("keep_foreground_service")) {
- xmppConnectionService.toggleForegroundService();
- } else if (name.equals("confirm_messages")) {
- if (xmppConnectionServiceBound) {
- for (Account account : xmppConnectionService.getAccounts()) {
- if (!account.isOptionSet(Account.OPTION_DISABLED)) {
- xmppConnectionService.sendPresence(account);
- }
- }
- }
- } else if (name.equals("dont_trust_system_cas")) {
- xmppConnectionService.updateMemorizingTrustmanager();
- reconnectAccounts();
+ break;
+ case "dont_trust_system_cas":
+ xmppConnectionService.updateMemorizingTrustmanager();
+ reconnectAccounts();
+ break;
+ case "parse_emoticons":
+ EmojiconHandler.setParseEmoticons(Settings.PARSE_EMOTICONS);
+ break;
}
-
}
private void displayToast(final String msg) {
diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
index 7734dc11..2d780eda 100644
--- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
@@ -68,6 +68,7 @@ import java.util.Hashtable;
import java.util.List;
import java.util.concurrent.RejectedExecutionException;
+import de.tzur.conversations.Settings;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession;
@@ -361,6 +362,9 @@ public abstract class XmppActivity extends Activity {
setTheme(this.mTheme);
this.mUsingEnterKey = usingEnterKey();
mUseSubject = getPreferences().getBoolean("use_subject", true);
+
+ Settings.initSettingsClassWithPreferences(getPreferences());
+
final ActionBar ab = getActionBar();
if (ab!=null) {
ab.setDisplayHomeAsUpEnabled(true);
diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java
index 98250af9..141dbc3a 100644
--- a/src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java
+++ b/src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java
@@ -8,6 +8,7 @@ import android.widget.ArrayAdapter;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.TextView;
+import android.widget.Switch;
import java.util.List;
diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java
index 6918713e..b89dd01a 100644
--- a/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java
+++ b/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java
@@ -19,13 +19,29 @@ import java.lang.ref.WeakReference;
import java.util.List;
import java.util.concurrent.RejectedExecutionException;
+import de.tzur.conversations.Settings;
+import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
+import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.Transferable;
import eu.siacs.conversations.ui.ConversationActivity;
import eu.siacs.conversations.ui.XmppActivity;
import eu.siacs.conversations.utils.UIHelper;
+import github.ankushsachdeva.emojicon.EmojiconTextView;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.Typeface;
+import android.preference.PreferenceManager;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
public class ConversationAdapter extends ArrayAdapter<Conversation> {
@@ -56,10 +72,34 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
} else {
convName.setText(conversation.getJid().toBareJid().toString());
}
- TextView mLastMessage = (TextView) view.findViewById(R.id.conversation_lastmsg);
+ EmojiconTextView mLastMessage = (EmojiconTextView) view.findViewById(R.id.conversation_lastmsg);
TextView mTimestamp = (TextView) view.findViewById(R.id.conversation_lastupdate);
ImageView imagePreview = (ImageView) view.findViewById(R.id.conversation_lastimage);
+ if (Settings.SHOW_ONLINE_STATUS && conversation != null && conversation.getAccount().getStatus() == Account.State.ONLINE) {
+ TextView status = (TextView) view.findViewById(R.id.status);
+
+ String color = "#000000";
+ if (conversation.getMode() == Conversation.MODE_SINGLE) {
+ switch (conversation.getContact().getMostAvailableStatus()) {
+ case Presences.ONLINE:
+ case Presences.CHAT:
+ color = "#259B23";
+ break;
+ case Presences.AWAY:
+ case Presences.XA:
+ color = "#FF9800";
+ break;
+ case Presences.DND:
+ color = "#E51C23";
+ break;
+ }
+ } else if (conversation.getMode() == Conversation.MODE_MULTI && conversation.getMucOptions().online()) {
+ color = "#259B23";
+ }
+ status.setBackgroundColor(Color.parseColor(color));
+ }
+
Message message = conversation.getLatestMessage();
if (!conversation.isRead()) {
diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java
index ad7d7622..4187ec60 100644
--- a/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java
+++ b/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java
@@ -1,5 +1,16 @@
package eu.siacs.conversations.ui.adapter;
+import java.lang.ref.WeakReference;
+import java.util.List;
+import java.util.concurrent.RejectedExecutionException;
+
+import de.tzur.conversations.Settings;
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.entities.ListItem;
+import eu.siacs.conversations.ui.XmppActivity;
+import eu.siacs.conversations.utils.UIHelper;
+import eu.siacs.conversations.xmpp.jid.Jid;
+
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
@@ -16,16 +27,6 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
-import java.lang.ref.WeakReference;
-import java.util.List;
-import java.util.concurrent.RejectedExecutionException;
-
-import eu.siacs.conversations.R;
-import eu.siacs.conversations.entities.ListItem;
-import eu.siacs.conversations.ui.XmppActivity;
-import eu.siacs.conversations.utils.UIHelper;
-import eu.siacs.conversations.xmpp.jid.Jid;
-
public class ListItemAdapter extends ArrayAdapter<ListItem> {
protected XmppActivity activity;
@@ -57,6 +58,12 @@ public class ListItemAdapter extends ArrayAdapter<ListItem> {
if (view == null) {
view = inflater.inflate(R.layout.contact, parent, false);
}
+
+ if (Settings.SHOW_ONLINE_STATUS) {
+ TextView tvStatus = (TextView) view.findViewById(R.id.contact_status);
+ tvStatus.setBackgroundColor(item.getStatusColor());
+ }
+
TextView tvName = (TextView) view.findViewById(R.id.contact_display_name);
TextView tvJid = (TextView) view.findViewById(R.id.contact_jid);
ImageView picture = (ImageView) view.findViewById(R.id.contact_photo);
diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java
index 1ddd6c44..a5b25967 100644
--- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java
+++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java
@@ -6,6 +6,7 @@ import android.content.pm.ResolveInfo;
import android.graphics.Color;
import android.graphics.Typeface;
import android.net.Uri;
+import android.preference.PreferenceManager;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.Spanned;
@@ -26,6 +27,8 @@ import android.widget.Toast;
import java.util.List;
+import de.tzur.conversations.Settings;
+import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession;
import eu.siacs.conversations.entities.Account;
@@ -38,6 +41,7 @@ import eu.siacs.conversations.entities.Transferable;
import eu.siacs.conversations.ui.ConversationActivity;
import eu.siacs.conversations.utils.GeoHelper;
import eu.siacs.conversations.utils.UIHelper;
+import github.ankushsachdeva.emojicon.EmojiconTextView;
public class MessageAdapter extends ArrayAdapter<Message> {
@@ -279,13 +283,14 @@ public class MessageAdapter extends ArrayAdapter<Message> {
i = body.indexOf(Message.MERGE_SEPARATOR,end);
}
if (message.getType() != Message.TYPE_PRIVATE) {
+
if (message.hasMeCommand()) {
final Spannable span = new SpannableString(formattedBody);
span.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), 0, nick.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
viewHolder.messageBody.setText(span);
} else {
- viewHolder.messageBody.setText(formattedBody);
+ viewHolder.messageBody.setText(formattedBody);
}
} else {
String privateMarker;
@@ -424,7 +429,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
.findViewById(R.id.security_indicator);
viewHolder.image = (ImageView) view
.findViewById(R.id.message_image);
- viewHolder.messageBody = (TextView) view
+ viewHolder.messageBody = (EmojiconTextView) view
.findViewById(R.id.message_body);
viewHolder.time = (TextView) view
.findViewById(R.id.message_time);
@@ -444,7 +449,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
.findViewById(R.id.security_indicator);
viewHolder.image = (ImageView) view
.findViewById(R.id.message_image);
- viewHolder.messageBody = (TextView) view
+ viewHolder.messageBody = (EmojiconTextView) view
.findViewById(R.id.message_body);
viewHolder.time = (TextView) view
.findViewById(R.id.message_time);
@@ -555,8 +560,6 @@ public class MessageAdapter extends ArrayAdapter<Message> {
} else {
if (GeoHelper.isGeoUri(message.getBody())) {
displayLocationMessage(viewHolder,message);
- } else if (message.bodyIsHeart()) {
- displayHeartMessage(viewHolder, message.getBody().trim());
} else if (message.treatAsDownloadable() == Message.Decision.MUST) {
displayDownloadableMessage(viewHolder, message, activity.getString(R.string.check_x_filesize, UIHelper.getFileDescriptionString(activity, message)));
} else {
@@ -632,7 +635,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
protected ImageView indicator;
protected ImageView indicatorReceived;
protected TextView time;
- protected TextView messageBody;
+ protected EmojiconTextView messageBody;
protected ImageView contact_picture;
protected TextView status_message;
}
diff --git a/src/main/java/eu/siacs/conversations/ui/listeners/ConversationMoreMessagesLoadedListener.java b/src/main/java/eu/siacs/conversations/ui/listeners/ConversationMoreMessagesLoadedListener.java
new file mode 100644
index 00000000..2154f8d8
--- /dev/null
+++ b/src/main/java/eu/siacs/conversations/ui/listeners/ConversationMoreMessagesLoadedListener.java
@@ -0,0 +1,118 @@
+package eu.siacs.conversations.ui.listeners;
+
+import android.support.v4.widget.SwipeRefreshLayout;
+import android.view.View;
+import android.widget.ListView;
+import android.widget.Toast;
+
+import java.util.List;
+
+import eu.siacs.conversations.entities.Conversation;
+import eu.siacs.conversations.entities.Message;
+import eu.siacs.conversations.services.XmppConnectionService;
+import eu.siacs.conversations.ui.ConversationActivity;
+import eu.siacs.conversations.ui.ConversationFragment;
+import eu.siacs.conversations.ui.adapter.MessageAdapter;
+
+/**
+ * This listener updates the UI when messages are loaded from the server.
+ */
+public class ConversationMoreMessagesLoadedListener implements XmppConnectionService.OnMoreMessagesLoaded {
+ private SwipeRefreshLayout swipeLayout;
+ private List<Message> messageList;
+ private ConversationFragment fragment;
+ private ListView messagesView;
+ private MessageAdapter messageListAdapter;
+ private Toast messageLoaderToast;
+
+ public ConversationMoreMessagesLoadedListener(SwipeRefreshLayout swipeLayout, List<Message> messageList, ConversationFragment fragment, ListView messagesView, MessageAdapter messageListAdapter) {
+ this.swipeLayout = swipeLayout;
+ this.messageList = messageList;
+ this.fragment = fragment;
+ this.messagesView = messagesView;
+ this.messageListAdapter = messageListAdapter;
+ }
+
+ @Override
+ public void onMoreMessagesLoaded(final int c, final Conversation conversation) {
+ ConversationActivity activity = (ConversationActivity) fragment.getActivity();
+ if (activity.getSelectedConversation() != conversation) {
+ activity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ swipeLayout.setRefreshing(false);
+ }
+ });
+ return;
+ }
+ if (0 == c) {
+ activity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ swipeLayout.setRefreshing(false);
+ }
+ });
+ }
+ activity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ final int oldPosition = messagesView.getFirstVisiblePosition();
+ int pos = 0;
+ View v = messagesView.getChildAt(0);
+ final int pxOffset = (v == null) ? 0 : v.getTop();
+ if (-1 < oldPosition && messageList.size() > oldPosition) {
+ Message message = messageList.get(oldPosition);
+ String uuid = message != null ? message.getUuid() : null;
+ pos = getIndexOf(uuid, messageList);
+ }
+ conversation.populateWithMessages(messageList);
+ fragment.updateStatusMessages();
+ messageListAdapter.notifyDataSetChanged();
+ messagesView.setSelectionFromTop(pos, pxOffset);
+
+ if (messageLoaderToast != null) {
+ messageLoaderToast.cancel();
+ }
+ swipeLayout.setRefreshing(false);
+ }
+ });
+ }
+
+ @Override
+ public void informUser(final int resId) {
+ final ConversationActivity activity = (ConversationActivity) fragment.getActivity();
+
+ activity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ if (messageLoaderToast != null) {
+ messageLoaderToast.cancel();
+ }
+ messageLoaderToast = Toast.makeText(activity, resId, Toast.LENGTH_LONG);
+ messageLoaderToast.show();
+ }
+ });
+
+ }
+
+ private int getIndexOf(String uuid, List<Message> messages) {
+ if (uuid == null) {
+ return 0;
+ }
+ for(int i = 0; i < messages.size(); ++i) {
+ if (uuid.equals(messages.get(i).getUuid())) {
+ return i;
+ } else {
+ Message next = messages.get(i);
+ while(next != null && next.wasMergedIntoPrevious()) {
+ if (uuid.equals(next.getUuid())) {
+ return i;
+ }
+ next = next.next();
+ }
+
+ }
+ }
+ return 0;
+ }
+}
diff --git a/src/main/java/eu/siacs/conversations/ui/listeners/ConversationSwipeRefreshListener.java b/src/main/java/eu/siacs/conversations/ui/listeners/ConversationSwipeRefreshListener.java
new file mode 100644
index 00000000..09a8d730
--- /dev/null
+++ b/src/main/java/eu/siacs/conversations/ui/listeners/ConversationSwipeRefreshListener.java
@@ -0,0 +1,48 @@
+package eu.siacs.conversations.ui.listeners;
+
+import android.support.v4.widget.SwipeRefreshLayout;
+import android.util.Log;
+import android.view.View;
+import android.widget.ListView;
+import android.widget.Toast;
+
+import java.util.List;
+
+import eu.siacs.conversations.Config;
+import eu.siacs.conversations.entities.Conversation;
+import eu.siacs.conversations.entities.Message;
+import eu.siacs.conversations.services.XmppConnectionService;
+import eu.siacs.conversations.ui.ConversationActivity;
+import eu.siacs.conversations.ui.ConversationFragment;
+import eu.siacs.conversations.ui.adapter.MessageAdapter;
+
+/**
+ * This listener starts loading messages from the server.
+ */
+public class ConversationSwipeRefreshListener implements SwipeRefreshLayout.OnRefreshListener {
+ private List<Message> messageList;
+ private ConversationFragment fragment;
+ private ConversationMoreMessagesLoadedListener listener;
+
+ public ConversationSwipeRefreshListener(List<Message> messageList, SwipeRefreshLayout swipeLayout, ConversationFragment fragment, ListView messagesView, MessageAdapter messageListAdapter) {
+ this.messageList = messageList;
+ this.fragment = fragment;
+ this.listener = new ConversationMoreMessagesLoadedListener(swipeLayout, messageList, fragment, messagesView, messageListAdapter);
+ }
+
+ @Override
+ public void onRefresh() {
+ Log.d(Config.LOGTAG, "Refresh swipe container");
+ synchronized (this.messageList) {
+ long timestamp;
+ if (messageList.isEmpty()) {
+ timestamp = System.currentTimeMillis();
+ } else {
+ timestamp = this.messageList.get(0).getTimeSent();
+ }
+ ConversationActivity activity = (ConversationActivity) fragment.getActivity();
+ activity.xmppConnectionService.loadMoreMessages(activity.getSelectedConversation(), timestamp, this.listener);
+ }
+ Log.d(Config.LOGTAG, "End Refresh swipe container");
+ }
+}
diff --git a/src/main/java/eu/siacs/conversations/utils/UIHelper.java b/src/main/java/eu/siacs/conversations/utils/UIHelper.java
index cac23f07..44a38728 100644
--- a/src/main/java/eu/siacs/conversations/utils/UIHelper.java
+++ b/src/main/java/eu/siacs/conversations/utils/UIHelper.java
@@ -11,11 +11,13 @@ import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
+import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
-import eu.siacs.conversations.entities.Message;
+import eu.siacs.conversations.entities.Presences;
import eu.siacs.conversations.entities.Transferable;
+import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.xmpp.jid.Jid;
public class UIHelper {
@@ -190,7 +192,7 @@ public class UIHelper {
return new Pair<>(context.getString(R.string.location), true);
}
} else{
- return new Pair<>(message.getBody().trim(), false);
+ return new Pair<>(message.getBody(), false);
}
}
}
@@ -241,13 +243,27 @@ public class UIHelper {
}
}
+ public static String getStatusColor(int status) {
+ switch (status) {
+ case Presences.ONLINE:
+ case Presences.CHAT:
+ return "#259B23";
+ case Presences.AWAY:
+ case Presences.XA:
+ return "#FF9800";
+ case Presences.DND:
+ return "#E51C23";
+ }
+ return "#CCCCCC";
+ }
+
private static String getDisplayedMucCounterpart(final Jid counterpart) {
if (counterpart==null) {
return "";
} else if (!counterpart.isBareJid()) {
- return counterpart.getResourcepart().trim();
+ return counterpart.getResourcepart();
} else {
- return counterpart.toString().trim();
+ return counterpart.toString();
}
}
@@ -257,7 +273,7 @@ public class UIHelper {
|| message.getType() != Message.TYPE_TEXT) {
return false;
}
- String body = message.getBody() == null ? null : message.getBody().trim().toLowerCase(Locale.getDefault());
+ String body = message.getBody() == null ? null : message.getBody().toLowerCase(Locale.getDefault());
body = body.replace("?","").replace("¿","");
return LOCATION_QUESTIONS.contains(body);
}
diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java
index 4f733b10..42b14330 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java
@@ -355,8 +355,10 @@ public class JingleConnection implements Transferable {
message.setBody(Long.toString(size));
conversation.add(message);
mXmppConnectionService.updateConversationUi();
- if (size < this.mJingleConnectionManager.getAutoAcceptFileSize()) {
- Log.d(Config.LOGTAG, "auto accepting file from "+ packet.getFrom());
+ if (size <= this.mJingleConnectionManager.getAutoAcceptFileSize()
+ && mXmppConnectionService.isDownloadAllowedInConnection()) {
+ Log.d(Config.LOGTAG, "auto accepting file from "
+ + packet.getFrom());
this.acceptedAutomatically = true;
this.sendAccept();
} else {
diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java
index ab564480..2c888d0f 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java
@@ -11,6 +11,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.entities.Transferable;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.Transferable;
import eu.siacs.conversations.services.AbstractConnectionManager;