@@ -3,6 +3,8 @@ package eu.siacs.conversations.entities;
import android.content.ContentValues;
import android.database.Cursor;
import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
import org.json.JSONArray;
import org.json.JSONException;
@@ -46,13 +48,14 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
public static final String ATTRIBUTE_MUTED_TILL = "muted_till";
public static final String ATTRIBUTE_ALWAYS_NOTIFY = "always_notify";
public static final String ATTRIBUTE_LAST_CLEAR_HISTORY = "last_clear_history";
- public static final String ATTRIBUTE_NEXT_MESSAGE = "next_message";
-
+ static final String ATTRIBUTE_MUC_PASSWORD = "muc_password";
+ private static final String ATTRIBUTE_NEXT_MESSAGE = "next_message";
+ private static final String ATTRIBUTE_NEXT_MESSAGE_TIMESTAMP = "next_message_timestamp";
private static final String ATTRIBUTE_CRYPTO_TARGETS = "crypto_targets";
-
private static final String ATTRIBUTE_NEXT_ENCRYPTION = "next_encryption";
- static final String ATTRIBUTE_MUC_PASSWORD = "muc_password";
-
+ protected final ArrayList<Message> messages = new ArrayList<>();
+ public AtomicBoolean messagesLoaded = new AtomicBoolean(true);
+ protected Account account = null;
private String draftMessage;
private String name;
private String contactUuid;
@@ -61,22 +64,59 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
private int status;
private long created;
private int mode;
-
private JSONObject attributes = new JSONObject();
-
private Jid nextCounterpart;
-
- protected final ArrayList<Message> messages = new ArrayList<>();
- protected Account account = null;
-
private transient MucOptions mucOptions = null;
-
private boolean messagesLeftOnServer = true;
private ChatState mOutgoingChatState = Config.DEFAULT_CHATSTATE;
private ChatState mIncomingChatState = Config.DEFAULT_CHATSTATE;
private String mFirstMamReference = null;
private Message correctingMessage;
- public AtomicBoolean messagesLoaded = new AtomicBoolean(true);
+
+ public Conversation(final String name, final Account account, final Jid contactJid,
+ final int mode) {
+ this(java.util.UUID.randomUUID().toString(), name, null, account
+ .getUuid(), contactJid, System.currentTimeMillis(),
+ STATUS_AVAILABLE, mode, "");
+ this.account = account;
+ }
+
+ public Conversation(final String uuid, final String name, final String contactUuid,
+ final String accountUuid, final Jid contactJid, final long created, final int status,
+ final int mode, final String attributes) {
+ this.uuid = uuid;
+ this.name = name;
+ this.contactUuid = contactUuid;
+ this.accountUuid = accountUuid;
+ this.contactJid = contactJid;
+ this.created = created;
+ this.status = status;
+ this.mode = mode;
+ try {
+ this.attributes = new JSONObject(attributes == null ? "" : attributes);
+ } catch (JSONException e) {
+ this.attributes = new JSONObject();
+ }
+ }
+
+ public static Conversation fromCursor(Cursor cursor) {
+ Jid jid;
+ try {
+ jid = Jid.of(cursor.getString(cursor.getColumnIndex(CONTACTJID)));
+ } catch (final IllegalArgumentException e) {
+ // Borked DB..
+ jid = null;
+ }
+ return new Conversation(cursor.getString(cursor.getColumnIndex(UUID)),
+ cursor.getString(cursor.getColumnIndex(NAME)),
+ cursor.getString(cursor.getColumnIndex(CONTACT)),
+ cursor.getString(cursor.getColumnIndex(ACCOUNT)),
+ jid,
+ cursor.getLong(cursor.getColumnIndex(CREATED)),
+ cursor.getInt(cursor.getColumnIndex(STATUS)),
+ cursor.getInt(cursor.getColumnIndex(MODE)),
+ cursor.getString(cursor.getColumnIndex(ATTRIBUTES)));
+ }
public boolean hasMessagesLeftOnServer() {
return messagesLeftOnServer;
@@ -86,7 +126,6 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
this.messagesLeftOnServer = value;
}
-
public Message getFirstUnreadMessage() {
Message first = null;
synchronized (this.messages) {
@@ -102,7 +141,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
}
public Message findUnsentMessageWithUuid(String uuid) {
- synchronized(this.messages) {
+ synchronized (this.messages) {
for (final Message message : this.messages) {
final int s = message.getStatus();
if ((s == Message.STATUS_UNSEND || s == Message.STATUS_WAITING) && message.getUuid().equals(uuid)) {
@@ -115,7 +154,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
public void findWaitingMessages(OnMessageFound onMessageFound) {
synchronized (this.messages) {
- for(Message message : this.messages) {
+ for (Message message : this.messages) {
if (message.getStatus() == Message.STATUS_WAITING) {
onMessageFound.onMessageFound(message);
}
@@ -125,7 +164,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
public void findUnreadMessages(OnMessageFound onMessageFound) {
synchronized (this.messages) {
- for(Message message : this.messages) {
+ for (Message message : this.messages) {
if (!message.isRead()) {
onMessageFound.onMessageFound(message);
}
@@ -139,7 +178,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
if ((message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE)
&& message.getEncryption() != Message.ENCRYPTION_PGP) {
onMessageFound.onMessageFound(message);
- }
+ }
}
}
}
@@ -222,7 +261,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
if (message.getType() != Message.TYPE_IMAGE
&& message.getStatus() == Message.STATUS_UNSEND) {
onMessageFound.onMessageFound(message);
- }
+ }
}
}
}
@@ -242,11 +281,11 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
public Message findMessageWithRemoteIdAndCounterpart(String id, Jid counterpart, boolean received, boolean carbon) {
synchronized (this.messages) {
- for(int i = this.messages.size() - 1; i >= 0; --i) {
+ for (int i = this.messages.size() - 1; i >= 0; --i) {
Message message = messages.get(i);
if (counterpart.equals(message.getCounterpart())
&& ((message.getStatus() == Message.STATUS_RECEIVED) == received)
- && (carbon == message.isCarbon() || received) ) {
+ && (carbon == message.isCarbon() || received)) {
if (id.equals(message.getRemoteMsgId()) && !message.isFileOrImage() && !message.treatAsDownloadable()) {
return message;
} else {
@@ -271,7 +310,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
public Message findMessageWithRemoteId(String id, Jid counterpart) {
synchronized (this.messages) {
- for(Message message : this.messages) {
+ for (Message message : this.messages) {
if (counterpart.equals(message.getCounterpart())
&& (id.equals(message.getRemoteMsgId()) || id.equals(message.getUuid()))) {
return message;
@@ -283,7 +322,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
public boolean hasMessageWithCounterpart(Jid counterpart) {
synchronized (this.messages) {
- for(Message message : this.messages) {
+ for (Message message : this.messages) {
if (counterpart.equals(message.getCounterpart())) {
return true;
}
@@ -297,7 +336,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
messages.clear();
messages.addAll(this.messages);
}
- for(Iterator<Message> iterator = messages.iterator(); iterator.hasNext();) {
+ for (Iterator<Message> iterator = messages.iterator(); iterator.hasNext(); ) {
if (iterator.next().wasMergedIntoPrevious()) {
iterator.remove();
}
@@ -325,19 +364,19 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
}
}
- public void setFirstMamReference(String reference) {
- this.mFirstMamReference = reference;
- }
-
public String getFirstMamReference() {
return this.mFirstMamReference;
}
- public void setLastClearHistory(long time,String reference) {
+ public void setFirstMamReference(String reference) {
+ this.mFirstMamReference = reference;
+ }
+
+ public void setLastClearHistory(long time, String reference) {
if (reference != null) {
setAttribute(ATTRIBUTE_LAST_CLEAR_HISTORY, String.valueOf(time) + ":" + reference);
} else {
- setAttribute(ATTRIBUTE_LAST_CLEAR_HISTORY, String.valueOf(time));
+ setAttribute(ATTRIBUTE_LAST_CLEAR_HISTORY, time);
}
}
@@ -372,53 +411,25 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
@Override
public int compareTo(@NonNull Conversation another) {
- final Message left = getLatestMessage();
- final Message right = another.getLatestMessage();
- if (left.getTimeSent() > right.getTimeSent()) {
- return -1;
- } else if (left.getTimeSent() < right.getTimeSent()) {
- return 1;
- } else {
- return 0;
- }
+ return Long.compare(another.getSortableTime(), getSortableTime());
}
- public void setDraftMessage(String draftMessage) {
- this.draftMessage = draftMessage;
+ private long getSortableTime() {
+ Draft draft = getDraft();
+ long messageTime = getLatestMessage().getTimeSent();
+ if (draft == null) {
+ return messageTime;
+ } else {
+ return Math.max(messageTime, draft.getTimestamp());
+ }
}
public String getDraftMessage() {
return draftMessage;
}
- public interface OnMessageFound {
- void onMessageFound(final Message message);
- }
-
- public Conversation(final String name, final Account account, final Jid contactJid,
- final int mode) {
- this(java.util.UUID.randomUUID().toString(), name, null, account
- .getUuid(), contactJid, System.currentTimeMillis(),
- STATUS_AVAILABLE, mode, "");
- this.account = account;
- }
-
- public Conversation(final String uuid, final String name, final String contactUuid,
- final String accountUuid, final Jid contactJid, final long created, final int status,
- final int mode, final String attributes) {
- this.uuid = uuid;
- this.name = name;
- this.contactUuid = contactUuid;
- this.accountUuid = accountUuid;
- this.contactJid = contactJid;
- this.created = created;
- this.status = status;
- this.mode = mode;
- try {
- this.attributes = new JSONObject(attributes == null ? "" : attributes);
- } catch (JSONException e) {
- this.attributes = new JSONObject();
- }
+ public void setDraftMessage(String draftMessage) {
+ this.draftMessage = draftMessage;
}
public boolean isRead() {
@@ -428,7 +439,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
public List<Message> markRead() {
final List<Message> unread = new ArrayList<>();
synchronized (this.messages) {
- for(Message message : this.messages) {
+ for (Message message : this.messages) {
if (!message.isRead()) {
message.markRead();
unread.add(message);
@@ -497,14 +508,14 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
return this.account;
}
- public Contact getContact() {
- return this.account.getRoster().getContact(this.contactJid);
- }
-
public void setAccount(final Account account) {
this.account = account;
}
+ public Contact getContact() {
+ return this.account.getRoster().getContact(this.contactJid);
+ }
+
@Override
public Jid getJid() {
return this.contactJid;
@@ -514,6 +525,10 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
return this.status;
}
+ public void setStatus(int status) {
+ this.status = status;
+ }
+
public long getCreated() {
return this.created;
}
@@ -532,29 +547,6 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
return values;
}
- public static Conversation fromCursor(Cursor cursor) {
- Jid jid;
- try {
- jid = Jid.of(cursor.getString(cursor.getColumnIndex(CONTACTJID)));
- } catch (final IllegalArgumentException e) {
- // Borked DB..
- jid = null;
- }
- return new Conversation(cursor.getString(cursor.getColumnIndex(UUID)),
- cursor.getString(cursor.getColumnIndex(NAME)),
- cursor.getString(cursor.getColumnIndex(CONTACT)),
- cursor.getString(cursor.getColumnIndex(ACCOUNT)),
- jid,
- cursor.getLong(cursor.getColumnIndex(CREATED)),
- cursor.getInt(cursor.getColumnIndex(STATUS)),
- cursor.getInt(cursor.getColumnIndex(MODE)),
- cursor.getString(cursor.getColumnIndex(ATTRIBUTES)));
- }
-
- public void setStatus(int status) {
- this.status = status;
- }
-
public int getMode() {
return this.mode;
}
@@ -589,14 +581,14 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
this.contactJid = jid;
}
- public void setNextCounterpart(Jid jid) {
- this.nextCounterpart = jid;
- }
-
public Jid getNextCounterpart() {
return this.nextCounterpart;
}
+ public void setNextCounterpart(Jid jid) {
+ this.nextCounterpart = jid;
+ }
+
public int getNextEncryption() {
final int defaultEncryption;
AxolotlService axolotlService = account.getAxolotlService();
@@ -605,7 +597,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
} else if (axolotlService != null && axolotlService.isConversationAxolotlCapable(this)) {
defaultEncryption = Message.ENCRYPTION_AXOLOTL;
} else {
- defaultEncryption = Message.ENCRYPTION_NONE;
+ defaultEncryption = Message.ENCRYPTION_NONE;
}
int encryption = this.getIntAttribute(ATTRIBUTE_NEXT_ENCRYPTION, defaultEncryption);
if (encryption == Message.ENCRYPTION_OTR) {
@@ -624,9 +616,24 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
return nextMessage == null ? "" : nextMessage;
}
+ public @Nullable
+ Draft getDraft() {
+ long timestamp = getLongAttribute(ATTRIBUTE_NEXT_MESSAGE_TIMESTAMP, 0);
+ if (timestamp > getLatestMessage().getTimeSent()) {
+ String message = getAttribute(ATTRIBUTE_NEXT_MESSAGE);
+ if (!TextUtils.isEmpty(message) && timestamp != 0) {
+ return new Draft(message, timestamp);
+ }
+ }
+ return null;
+ }
+
public boolean setNextMessage(String message) {
boolean changed = !getNextMessage().equals(message);
this.setAttribute(ATTRIBUTE_NEXT_MESSAGE, message);
+ if (changed) {
+ this.setAttribute(ATTRIBUTE_NEXT_MESSAGE_TIMESTAMP, TextUtils.isEmpty(message) ? 0 : System.currentTimeMillis());
+ }
return changed;
}
@@ -673,18 +680,18 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
final MamReference lastClear = getLastClearHistory();
MamReference lastReceived = new MamReference(0);
synchronized (this.messages) {
- for(int i = this.messages.size() - 1; i >= 0; --i) {
+ for (int i = this.messages.size() - 1; i >= 0; --i) {
final Message message = this.messages.get(i);
if (message.getType() == Message.TYPE_PRIVATE) {
continue; //it's unsafe to use private messages as anchor. They could be coming from user archive
}
if (message.getStatus() == Message.STATUS_RECEIVED || message.isCarbon() || message.getServerMsgId() != null) {
- lastReceived = new MamReference(message.getTimeSent(),message.getServerMsgId());
+ lastReceived = new MamReference(message.getTimeSent(), message.getServerMsgId());
break;
}
}
}
- return MamReference.max(lastClear,lastReceived);
+ return MamReference.max(lastClear, lastReceived);
}
public void setMutedTill(long value) {
@@ -699,6 +706,10 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
return mode == MODE_SINGLE || getBooleanAttribute(ATTRIBUTE_ALWAYS_NOTIFY, Config.ALWAYS_NOTIFY_BY_DEFAULT || isPrivateAndNonAnonymous());
}
+ private boolean setAttribute(String key, long value) {
+ return setAttribute(key, Long.toString(value));
+ }
+
public boolean setAttribute(String key, String value) {
synchronized (this.attributes) {
try {
@@ -712,7 +723,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
public boolean setAttribute(String key, List<Jid> jids) {
JSONArray array = new JSONArray();
- for(Jid jid : jids) {
+ for (Jid jid : jids) {
array.put(jid.asBareJid().toString());
}
synchronized (this.attributes) {
@@ -798,7 +809,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
public void prepend(int offset, Message message) {
synchronized (this.messages) {
- this.messages.add(Math.min(offset,this.messages.size()),message);
+ this.messages.add(Math.min(offset, this.messages.size()), message);
}
}
@@ -811,7 +822,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
public void expireOldMessages(long timestamp) {
synchronized (this.messages) {
- for(ListIterator<Message> iterator = this.messages.listIterator(); iterator.hasNext();) {
+ for (ListIterator<Message> iterator = this.messages.listIterator(); iterator.hasNext(); ) {
if (iterator.next().getTimeSent() < timestamp) {
iterator.remove();
}
@@ -836,7 +847,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
}
private void untieMessages() {
- for(Message message : this.messages) {
+ for (Message message : this.messages) {
message.untie();
}
}
@@ -844,7 +855,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
public int unreadCount() {
synchronized (this.messages) {
int count = 0;
- for(int i = this.messages.size() - 1; i >= 0; --i) {
+ for (int i = this.messages.size() - 1; i >= 0; --i) {
if (this.messages.get(i).isRead()) {
return count;
}
@@ -857,7 +868,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
public int receivedMessagesCount() {
int count = 0;
synchronized (this.messages) {
- for(Message message : messages) {
+ for (Message message : messages) {
if (message.getStatus() == Message.STATUS_RECEIVED) {
++count;
}
@@ -869,7 +880,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
private int sentMessagesCount() {
int count = 0;
synchronized (this.messages) {
- for(Message message : messages) {
+ for (Message message : messages) {
if (message.getStatus() != Message.STATUS_RECEIVED) {
++count;
}
@@ -884,4 +895,26 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
&& !getContact().showInRoster()
&& sentMessagesCount() == 0;
}
+
+ public interface OnMessageFound {
+ void onMessageFound(final Message message);
+ }
+
+ public static class Draft {
+ private final String message;
+ private final long timestamp;
+
+ private Draft(String message, long timestamp) {
+ this.message = message;
+ this.timestamp = timestamp;
+ }
+
+ public long getTimestamp() {
+ return timestamp;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+ }
}
@@ -45,18 +45,45 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
this.activity = activity;
}
+ private static boolean cancelPotentialWork(Conversation conversation, ImageView imageView) {
+ final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
+
+ if (bitmapWorkerTask != null) {
+ final Conversation oldConversation = bitmapWorkerTask.conversation;
+ if (oldConversation == null || conversation != oldConversation) {
+ bitmapWorkerTask.cancel(true);
+ } else {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
+ if (imageView != null) {
+ final Drawable drawable = imageView.getDrawable();
+ if (drawable instanceof AsyncDrawable) {
+ final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
+ return asyncDrawable.getBitmapWorkerTask();
+ }
+ }
+ return null;
+ }
+
@Override
- public View getView(int position, View view, @NonNull ViewGroup parent) {
+ public @NonNull
+ View getView(int position, View view, @NonNull ViewGroup parent) {
if (view == null) {
LayoutInflater inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- view = inflater.inflate(R.layout.conversation_list_row,parent, false);
+ view = inflater.inflate(R.layout.conversation_list_row, parent, false);
}
ViewHolder viewHolder = ViewHolder.get(view);
Conversation conversation = getItem(position);
- if (this.activity instanceof XmppActivity) {
- int c = Color.get(activity, conversation == selectedConversation ? R.attr.color_background_secondary: R.attr.color_background_primary);
- viewHolder.swipeableItem.setBackgroundColor(c);
+ if (conversation == null) {
+ return view;
}
+ int c = Color.get(activity, conversation == selectedConversation ? R.attr.color_background_secondary : R.attr.color_background_primary);
+ viewHolder.swipeableItem.setBackgroundColor(c);
if (conversation.getMode() == Conversation.MODE_SINGLE || activity.useSubjectToIdentifyConference()) {
CharSequence name = conversation.getName();
if (name instanceof Jid) {
@@ -69,7 +96,9 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
}
Message message = conversation.getLatestMessage();
- int unreadCount = conversation.unreadCount();
+ final int unreadCount = conversation.unreadCount();
+ final boolean isRead = conversation.isRead();
+ final Conversation.Draft draft = isRead ? conversation.getDraft() : null;
if (unreadCount > 0) {
viewHolder.unreadCount.setVisibility(View.VISIBLE);
viewHolder.unreadCount.setUnreadCount(unreadCount);
@@ -77,88 +106,97 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
viewHolder.unreadCount.setVisibility(View.GONE);
}
- if (!conversation.isRead()) {
- viewHolder.name.setTypeface(null, Typeface.BOLD);
- } else {
+ if (isRead) {
viewHolder.name.setTypeface(null, Typeface.NORMAL);
+ } else {
+ viewHolder.name.setTypeface(null, Typeface.BOLD);
}
- final boolean fileAvailable = message.getTransferable() == null || message.getTransferable().getStatus() != Transferable.STATUS_DELETED;
- final boolean showPreviewText;
- if (fileAvailable && (message.isFileOrImage() || message.treatAsDownloadable() || message.isGeoUri())) {
- final int imageResource;
- if (message.isGeoUri()) {
- imageResource = activity.getThemeResource(R.attr.ic_attach_location, R.drawable.ic_attach_location);
- showPreviewText = false;
- } else {
- final String mime = message.getMimeType();
- switch (mime == null ? "" : mime.split("/")[0]) {
- case "image":
- imageResource = activity.getThemeResource(R.attr.ic_attach_photo, R.drawable.ic_attach_photo);
- showPreviewText = false;
- break;
- case "video":
- imageResource = activity.getThemeResource(R.attr.ic_attach_videocam, R.drawable.ic_attach_videocam);
- showPreviewText = false;
- break;
- case "audio":
- imageResource = activity.getThemeResource(R.attr.ic_attach_record, R.drawable.ic_attach_record);
- showPreviewText = false;
- break;
- default:
- imageResource = activity.getThemeResource(R.attr.ic_attach_document, R.drawable.ic_attach_document);
- showPreviewText = true;
- break;
- }
- }
- viewHolder.lastMessageIcon.setImageResource(imageResource);
- viewHolder.lastMessageIcon.setVisibility(View.VISIBLE);
- } else {
+ if (draft != null) {
viewHolder.lastMessageIcon.setVisibility(View.GONE);
- showPreviewText = true;
- }
- final Pair<String,Boolean> preview = UIHelper.getMessagePreview(activity,message);
- if (showPreviewText) {
- viewHolder.lastMessage.setText(EmojiWrapper.transform(preview.first));
+ viewHolder.lastMessage.setText(EmojiWrapper.transform(draft.getMessage()));
+ viewHolder.sender.setText(R.string.draft);
+ viewHolder.sender.setVisibility(View.VISIBLE);
+ viewHolder.lastMessage.setTypeface(null, Typeface.NORMAL);
+ viewHolder.sender.setTypeface(null, Typeface.ITALIC);
} else {
- viewHolder.lastMessageIcon.setContentDescription(preview.first);
- }
- viewHolder.lastMessage.setVisibility(showPreviewText ? View.VISIBLE : View.GONE);
- if (preview.second) {
- if (conversation.isRead()) {
- viewHolder.lastMessage.setTypeface(null, Typeface.ITALIC);
- viewHolder.sender.setTypeface(null, Typeface.NORMAL);
+ final boolean fileAvailable = message.getTransferable() == null || message.getTransferable().getStatus() != Transferable.STATUS_DELETED;
+ final boolean showPreviewText;
+ if (fileAvailable && (message.isFileOrImage() || message.treatAsDownloadable() || message.isGeoUri())) {
+ final int imageResource;
+ if (message.isGeoUri()) {
+ imageResource = activity.getThemeResource(R.attr.ic_attach_location, R.drawable.ic_attach_location);
+ showPreviewText = false;
+ } else {
+ final String mime = message.getMimeType();
+ switch (mime == null ? "" : mime.split("/")[0]) {
+ case "image":
+ imageResource = activity.getThemeResource(R.attr.ic_attach_photo, R.drawable.ic_attach_photo);
+ showPreviewText = false;
+ break;
+ case "video":
+ imageResource = activity.getThemeResource(R.attr.ic_attach_videocam, R.drawable.ic_attach_videocam);
+ showPreviewText = false;
+ break;
+ case "audio":
+ imageResource = activity.getThemeResource(R.attr.ic_attach_record, R.drawable.ic_attach_record);
+ showPreviewText = false;
+ break;
+ default:
+ imageResource = activity.getThemeResource(R.attr.ic_attach_document, R.drawable.ic_attach_document);
+ showPreviewText = true;
+ break;
+ }
+ }
+ viewHolder.lastMessageIcon.setImageResource(imageResource);
+ viewHolder.lastMessageIcon.setVisibility(View.VISIBLE);
} else {
- viewHolder.lastMessage.setTypeface(null,Typeface.BOLD_ITALIC);
- viewHolder.sender.setTypeface(null,Typeface.BOLD);
+ viewHolder.lastMessageIcon.setVisibility(View.GONE);
+ showPreviewText = true;
}
- } else {
- if (conversation.isRead()) {
- viewHolder.lastMessage.setTypeface(null,Typeface.NORMAL);
- viewHolder.sender.setTypeface(null,Typeface.NORMAL);
+ final Pair<String, Boolean> preview = UIHelper.getMessagePreview(activity, message);
+ if (showPreviewText) {
+ viewHolder.lastMessage.setText(EmojiWrapper.transform(preview.first));
} else {
- viewHolder.lastMessage.setTypeface(null,Typeface.BOLD);
- viewHolder.sender.setTypeface(null,Typeface.BOLD);
+ viewHolder.lastMessageIcon.setContentDescription(preview.first);
}
- }
- if (message.getStatus() == Message.STATUS_RECEIVED) {
- if (conversation.getMode() == Conversation.MODE_MULTI) {
+ viewHolder.lastMessage.setVisibility(showPreviewText ? View.VISIBLE : View.GONE);
+ if (preview.second) {
+ if (isRead) {
+ viewHolder.lastMessage.setTypeface(null, Typeface.ITALIC);
+ viewHolder.sender.setTypeface(null, Typeface.NORMAL);
+ } else {
+ viewHolder.lastMessage.setTypeface(null, Typeface.BOLD_ITALIC);
+ viewHolder.sender.setTypeface(null, Typeface.BOLD);
+ }
+ } else {
+ if (isRead) {
+ viewHolder.lastMessage.setTypeface(null, Typeface.NORMAL);
+ viewHolder.sender.setTypeface(null, Typeface.NORMAL);
+ } else {
+ viewHolder.lastMessage.setTypeface(null, Typeface.BOLD);
+ viewHolder.sender.setTypeface(null, Typeface.BOLD);
+ }
+ }
+ if (message.getStatus() == Message.STATUS_RECEIVED) {
+ if (conversation.getMode() == Conversation.MODE_MULTI) {
+ viewHolder.sender.setVisibility(View.VISIBLE);
+ viewHolder.sender.setText(UIHelper.getMessageDisplayName(message).split("\\s+")[0] + ':');
+ } else {
+ viewHolder.sender.setVisibility(View.GONE);
+ }
+ } else if (message.getType() != Message.TYPE_STATUS) {
viewHolder.sender.setVisibility(View.VISIBLE);
- viewHolder.sender.setText(UIHelper.getMessageDisplayName(message).split("\\s+")[0]+':');
+ viewHolder.sender.setText(activity.getString(R.string.me) + ':');
} else {
viewHolder.sender.setVisibility(View.GONE);
}
- } else if (message.getType() != Message.TYPE_STATUS) {
- viewHolder.sender.setVisibility(View.VISIBLE);
- viewHolder.sender.setText(activity.getString(R.string.me)+':');
- } else {
- viewHolder.sender.setVisibility(View.GONE);
}
- long muted_till = conversation.getLongAttribute(Conversation.ATTRIBUTE_MUTED_TILL,0);
+ long muted_till = conversation.getLongAttribute(Conversation.ATTRIBUTE_MUTED_TILL, 0);
if (muted_till == Long.MAX_VALUE) {
viewHolder.notificationIcon.setVisibility(View.VISIBLE);
- int ic_notifications_off = activity.getThemeResource(R.attr.icon_notifications_off, R.drawable.ic_notifications_off_black_24dp);
+ int ic_notifications_off = activity.getThemeResource(R.attr.icon_notifications_off, R.drawable.ic_notifications_off_black_24dp);
viewHolder.notificationIcon.setImageResource(ic_notifications_off);
} else if (muted_till >= System.currentTimeMillis()) {
viewHolder.notificationIcon.setVisibility(View.VISIBLE);
@@ -168,11 +206,17 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
viewHolder.notificationIcon.setVisibility(View.GONE);
} else {
viewHolder.notificationIcon.setVisibility(View.VISIBLE);
- int ic_notifications_none = activity.getThemeResource(R.attr.icon_notifications_none, R.drawable.ic_notifications_none_black_24dp);
+ int ic_notifications_none = activity.getThemeResource(R.attr.icon_notifications_none, R.drawable.ic_notifications_none_black_24dp);
viewHolder.notificationIcon.setImageResource(ic_notifications_none);
}
- viewHolder.timestamp.setText(UIHelper.readableTimeDifference(activity,conversation.getLatestMessage().getTimeSent()));
+ long timestamp;
+ if (draft != null) {
+ timestamp = draft.getTimestamp();
+ } else {
+ timestamp = conversation.getLatestMessage().getTimeSent();
+ }
+ viewHolder.timestamp.setText(UIHelper.readableTimeDifference(activity, timestamp));
loadAvatar(conversation, viewHolder.avatar);
return view;
@@ -184,6 +228,27 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
super.notifyDataSetChanged();
}
+ private void loadAvatar(Conversation conversation, ImageView imageView) {
+ if (cancelPotentialWork(conversation, imageView)) {
+ final Bitmap bm = activity.avatarService().get(conversation, activity.getPixel(56), true);
+ if (bm != null) {
+ cancelPotentialWork(conversation, imageView);
+ imageView.setImageBitmap(bm);
+ imageView.setBackgroundColor(0x00000000);
+ } else {
+ imageView.setBackgroundColor(UIHelper.getColorForName(conversation.getName().toString()));
+ imageView.setImageDrawable(null);
+ final BitmapWorkerTask task = new BitmapWorkerTask(imageView);
+ final AsyncDrawable asyncDrawable = new AsyncDrawable(activity.getResources(), null, task);
+ imageView.setImageDrawable(asyncDrawable);
+ try {
+ task.execute(conversation);
+ } catch (final RejectedExecutionException ignored) {
+ }
+ }
+ }
+ }
+
public static class ViewHolder {
private View swipeableItem;
private TextView name;
@@ -218,6 +283,19 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
}
}
+ static class AsyncDrawable extends BitmapDrawable {
+ private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;
+
+ public AsyncDrawable(Resources res, Bitmap bitmap, BitmapWorkerTask bitmapWorkerTask) {
+ super(res, bitmap);
+ bitmapWorkerTaskReference = new WeakReference<>(bitmapWorkerTask);
+ }
+
+ public BitmapWorkerTask getBitmapWorkerTask() {
+ return bitmapWorkerTaskReference.get();
+ }
+ }
+
class BitmapWorkerTask extends AsyncTask<Conversation, Void, Bitmap> {
private final WeakReference<ImageView> imageViewReference;
private Conversation conversation = null;
@@ -243,63 +321,4 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
}
}
}
-
- private void loadAvatar(Conversation conversation, ImageView imageView) {
- if (cancelPotentialWork(conversation, imageView)) {
- final Bitmap bm = activity.avatarService().get(conversation, activity.getPixel(56), true);
- if (bm != null) {
- cancelPotentialWork(conversation, imageView);
- imageView.setImageBitmap(bm);
- imageView.setBackgroundColor(0x00000000);
- } else {
- imageView.setBackgroundColor(UIHelper.getColorForName(conversation.getName().toString()));
- imageView.setImageDrawable(null);
- final BitmapWorkerTask task = new BitmapWorkerTask(imageView);
- final AsyncDrawable asyncDrawable = new AsyncDrawable(activity.getResources(), null, task);
- imageView.setImageDrawable(asyncDrawable);
- try {
- task.execute(conversation);
- } catch (final RejectedExecutionException ignored) {
- }
- }
- }
- }
-
- private static boolean cancelPotentialWork(Conversation conversation, ImageView imageView) {
- final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
-
- if (bitmapWorkerTask != null) {
- final Conversation oldConversation = bitmapWorkerTask.conversation;
- if (oldConversation == null || conversation != oldConversation) {
- bitmapWorkerTask.cancel(true);
- } else {
- return false;
- }
- }
- return true;
- }
-
- private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
- if (imageView != null) {
- final Drawable drawable = imageView.getDrawable();
- if (drawable instanceof AsyncDrawable) {
- final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
- return asyncDrawable.getBitmapWorkerTask();
- }
- }
- return null;
- }
-
- static class AsyncDrawable extends BitmapDrawable {
- private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;
-
- public AsyncDrawable(Resources res, Bitmap bitmap, BitmapWorkerTask bitmapWorkerTask) {
- super(res, bitmap);
- bitmapWorkerTaskReference = new WeakReference<>(bitmapWorkerTask);
- }
-
- public BitmapWorkerTask getBitmapWorkerTask() {
- return bitmapWorkerTaskReference.get();
- }
- }
}