From 11dfd8767224ad8f5010c31fb63729d7bb1c3a88 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sat, 17 Mar 2018 19:18:22 +0100 Subject: [PATCH] show message draft in conversation overview --- .../conversations/entities/Conversation.java | 259 +++++++++------- .../ui/adapter/ConversationAdapter.java | 289 ++++++++++-------- src/main/res/values/strings.xml | 1 + 3 files changed, 301 insertions(+), 248 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index af1c8c41f..4340978a6 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -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"; - - 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"; - + 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"; + protected final ArrayList 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 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 iterator = messages.iterator(); iterator.hasNext();) { + for (Iterator 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 markRead() { final List 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 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 iterator = this.messages.listIterator(); iterator.hasNext();) { + for (ListIterator 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; + } + } } 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 79a483a49..e0b6595e9 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java @@ -45,18 +45,45 @@ public class ConversationAdapter extends ArrayAdapter { 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 { } 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 { 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; + if (draft != null) { + viewHolder.lastMessageIcon.setVisibility(View.GONE); + 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 { + 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 { - 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.setVisibility(View.GONE); + showPreviewText = true; + } + final Pair preview = UIHelper.getMessagePreview(activity, message); + if (showPreviewText) { + viewHolder.lastMessage.setText(EmojiWrapper.transform(preview.first)); + } else { + viewHolder.lastMessageIcon.setContentDescription(preview.first); + } + 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); } } - viewHolder.lastMessageIcon.setImageResource(imageResource); - viewHolder.lastMessageIcon.setVisibility(View.VISIBLE); - } else { - viewHolder.lastMessageIcon.setVisibility(View.GONE); - showPreviewText = true; - } - final Pair preview = UIHelper.getMessagePreview(activity,message); - if (showPreviewText) { - viewHolder.lastMessage.setText(EmojiWrapper.transform(preview.first)); - } 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); - } else { - viewHolder.lastMessage.setTypeface(null,Typeface.BOLD_ITALIC); - viewHolder.sender.setTypeface(null,Typeface.BOLD); - } - } else { - if (conversation.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) { + 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 { 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 { 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 { } } + static class AsyncDrawable extends BitmapDrawable { + private final WeakReference 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 { private final WeakReference imageViewReference; private Conversation conversation = null; @@ -243,63 +321,4 @@ public class ConversationAdapter extends ArrayAdapter { } } } - - 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 bitmapWorkerTaskReference; - - public AsyncDrawable(Resources res, Bitmap bitmap, BitmapWorkerTask bitmapWorkerTask) { - super(res, bitmap); - bitmapWorkerTaskReference = new WeakReference<>(bitmapWorkerTask); - } - - public BitmapWorkerTask getBitmapWorkerTask() { - return bitmapWorkerTaskReference.get(); - } - } } diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 4cceeef33..c5ccc844e 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -734,4 +734,5 @@ Hint: In some cases this can be fixed by adding each other your contact lists. Are you sure you want to disable OMEMO encryption for this conversation?\nThis will allow your server administrator to read your messages, but it might be the only way to communicate with people using outdated clients. Disable now + Draft: