diff --git a/art/date_bubble_grey.svg b/art/date_bubble_grey.svg new file mode 100644 index 00000000..38db49f9 --- /dev/null +++ b/art/date_bubble_grey.svg @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/art/date_bubble_white.svg b/art/date_bubble_white.svg new file mode 100644 index 00000000..452ae927 --- /dev/null +++ b/art/date_bubble_white.svg @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/art/render.rb b/art/render.rb index 01ab3903..e20b951c 100755 --- a/art/render.rb +++ b/art/render.rb @@ -64,6 +64,8 @@ images = { 'message_bubble_received_white.svg' => ['message_bubble_received_white.9', 0], 'message_bubble_sent.svg' => ['message_bubble_sent.9', 0], 'message_bubble_sent_grey.svg' => ['message_bubble_sent_grey.9', 0], + 'date_bubble_white.svg' => ['date_bubble_white.9', 0], + 'date_bubble_grey.svg' => ['date_bubble_grey.9', 0], } # Executable paths for Mac OSX diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java index f360122d..77b54d32 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/src/main/java/eu/siacs/conversations/entities/Message.java @@ -10,6 +10,7 @@ import java.net.URL; import eu.siacs.conversations.Config; import eu.siacs.conversations.crypto.axolotl.FingerprintStatus; import eu.siacs.conversations.http.AesGcmURLStreamHandler; +import eu.siacs.conversations.ui.adapter.MessageAdapter; import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.utils.GeoHelper; import eu.siacs.conversations.utils.MimeUtils; @@ -203,6 +204,14 @@ public class Message extends AbstractEntity { return message; } + public static Message createDateSeparator(Message message) { + final Message separator = new Message(message.getConversation()); + separator.setType(Message.TYPE_STATUS); + separator.setBody(MessageAdapter.DATE_SEPARATOR_BODY); + separator.setTime(message.getTimeSent()); + return separator; + } + @Override public ContentValues getContentValues() { ContentValues values = new ContentValues(); @@ -493,7 +502,8 @@ public class Message extends AbstractEntity { !this.getBody().startsWith(ME_COMMAND) && !this.bodyIsHeart() && !message.bodyIsHeart() && - ((this.axolotlFingerprint == null && message.axolotlFingerprint == null) || this.axolotlFingerprint.equals(message.getFingerprint())) + ((this.axolotlFingerprint == null && message.axolotlFingerprint == null) || this.axolotlFingerprint.equals(message.getFingerprint())) && + UIHelper.sameDay(message.getTimeSent(),this.getTimeSent()) ); } diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index 84151930..afdabcfe 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -46,6 +46,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.ListIterator; import java.util.UUID; import java.util.concurrent.atomic.AtomicBoolean; @@ -154,14 +155,16 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa @Override public void run() { final int oldPosition = messagesView.getFirstVisiblePosition(); - final Message message; - if (oldPosition < messageList.size()) { - message = messageList.get(oldPosition); - } else { - message = null; + Message message = null; + int childPos; + for(childPos = 0; childPos + oldPosition < messageList.size(); ++childPos) { + message = messageList.get(oldPosition + childPos); + if (message.getType() != Message.TYPE_STATUS) { + break; + } } - String uuid = message != null ? message.getUuid() : null; - View v = messagesView.getChildAt(0); + final String uuid = message != null ? message.getUuid() : null; + View v = messagesView.getChildAt(childPos); final int pxOffset = (v == null) ? 0 : v.getTop(); ConversationFragment.this.conversation.populateWithMessages(ConversationFragment.this.messageList); try { @@ -1300,7 +1303,20 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa this.mSendButton.setImageResource(getSendButtonImageResource(action, status)); } + protected void updateDateSeparators() { + synchronized (this.messageList) { + for(int i = 0; i < this.messageList.size(); ++i) { + final Message current = this.messageList.get(i); + if (i == 0 || !UIHelper.sameDay(this.messageList.get(i-1).getTimeSent(),current.getTimeSent())) { + this.messageList.add(i,Message.createDateSeparator(current)); + i++; + } + } + } + } + protected void updateStatusMessages() { + updateDateSeparators(); synchronized (this.messageList) { if (showLoadMoreMessages(conversation)) { this.messageList.add(0, Message.createLoadMoreMessage(conversation)); diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java index 9c2e9bae..a4b7c5ca 100644 --- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java @@ -391,6 +391,7 @@ public abstract class XmppActivity extends Activity { mPrimaryBackgroundColor = ContextCompat.getColor(this, R.color.grey50); mSecondaryBackgroundColor = ContextCompat.getColor(this, R.color.grey200); + this.mTheme = findTheme(); if(isDarkTheme()) { mPrimaryTextColor = ContextCompat.getColor(this, R.color.white); mSecondaryTextColor = ContextCompat.getColor(this, R.color.white70); @@ -398,8 +399,6 @@ public abstract class XmppActivity extends Activity { mPrimaryBackgroundColor = ContextCompat.getColor(this, R.color.grey800); mSecondaryBackgroundColor = ContextCompat.getColor(this, R.color.grey900); } - - this.mTheme = findTheme(); setTheme(this.mTheme); this.mUsingEnterKey = usingEnterKey(); @@ -411,7 +410,7 @@ public abstract class XmppActivity extends Activity { } public boolean isDarkTheme() { - return getPreferences().getString("theme", getResources().getString(R.string.theme)).equals("dark"); + return this.mTheme == R.style.ConversationsTheme_Dark || this.mTheme == R.style.ConversationsTheme_Dark_LargerText; } public int getThemeResource(int r_attr_name, int r_drawable_def) { 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 1a203e9e..adaa3117 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -16,6 +16,7 @@ import android.text.Spannable; import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.Spanned; +import android.text.format.DateUtils; import android.text.style.ForegroundColorSpan; import android.text.style.RelativeSizeSpan; import android.text.style.StyleSpan; @@ -72,6 +73,10 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie private static final int SENT = 0; private static final int RECEIVED = 1; private static final int STATUS = 2; + private static final int DATE_SEPARATOR = 3; + + public static final String DATE_SEPARATOR_BODY = "DATE_SEPARATOR"; + private static final Pattern XMPP_PATTERN = Pattern .compile("xmpp\\:(?:(?:[" + Patterns.GOOD_IRI_CHAR @@ -135,12 +140,16 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie @Override public int getViewTypeCount() { - return 3; + return 4; } public int getItemViewType(Message message) { if (message.getType() == Message.TYPE_STATUS) { - return STATUS; + if (DATE_SEPARATOR_BODY.equals(message.getBody())) { + return DATE_SEPARATOR; + } else { + return STATUS; + } } else if (message.getStatus() <= Message.STATUS_RECEIVED) { return RECEIVED; } @@ -591,6 +600,11 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie if (view == null) { viewHolder = new ViewHolder(); switch (type) { + case DATE_SEPARATOR: + view = activity.getLayoutInflater().inflate(R.layout.message_date_bubble, parent, false); + viewHolder.status_message = (TextView) view.findViewById(R.id.message_body); + viewHolder.message_box = (LinearLayout) view.findViewById(R.id.message_box); + break; case SENT: view = activity.getLayoutInflater().inflate( R.layout.message_sent, parent, false); @@ -659,7 +673,18 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie boolean darkBackground = type == RECEIVED && (!isInValidSession || mUseGreenBackground) || activity.isDarkTheme(); - if (type == STATUS) { + if (type == DATE_SEPARATOR) { + if (UIHelper.today(message.getTimeSent())) { + viewHolder.status_message.setText(R.string.today); + } else if (UIHelper.yesterday(message.getTimeSent())) { + viewHolder.status_message.setText(R.string.yesterday); + } else { + viewHolder.status_message.setText(DateUtils.formatDateTime(activity,message.getTimeSent(),DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR)); + } + viewHolder.message_box.setBackgroundResource(activity.isDarkTheme() ? R.drawable.date_bubble_grey : R.drawable.date_bubble_white); + viewHolder.status_message.setTextColor(activity.getSecondaryTextColor()); + return view; + } else if (type == STATUS) { if ("LOAD_MORE".equals(message.getBody())) { viewHolder.status_message.setVisibility(View.GONE); viewHolder.contact_picture.setVisibility(View.GONE); diff --git a/src/main/java/eu/siacs/conversations/utils/UIHelper.java b/src/main/java/eu/siacs/conversations/utils/UIHelper.java index 658fdc1e..af0f5b6c 100644 --- a/src/main/java/eu/siacs/conversations/utils/UIHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/UIHelper.java @@ -100,6 +100,24 @@ public class UIHelper { return sameDay(date,new Date(System.currentTimeMillis())); } + public static boolean today(long date) { + return sameDay(date,System.currentTimeMillis()); + } + + public static boolean yesterday(long date) { + Calendar cal1 = Calendar.getInstance(); + Calendar cal2 = Calendar.getInstance(); + cal1.add(Calendar.DAY_OF_YEAR,-1); + cal2.setTime(new Date(date)); + return cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) + && cal1.get(Calendar.DAY_OF_YEAR) == cal2 + .get(Calendar.DAY_OF_YEAR); + } + + public static boolean sameDay(long a, long b) { + return sameDay(new Date(a),new Date(b)); + } + private static boolean sameDay(Date a, Date b) { Calendar cal1 = Calendar.getInstance(); Calendar cal2 = Calendar.getInstance(); diff --git a/src/main/res/drawable-hdpi/date_bubble_grey.9.png b/src/main/res/drawable-hdpi/date_bubble_grey.9.png new file mode 100644 index 00000000..d12d22f4 Binary files /dev/null and b/src/main/res/drawable-hdpi/date_bubble_grey.9.png differ diff --git a/src/main/res/drawable-hdpi/date_bubble_white.9.png b/src/main/res/drawable-hdpi/date_bubble_white.9.png new file mode 100644 index 00000000..df74d811 Binary files /dev/null and b/src/main/res/drawable-hdpi/date_bubble_white.9.png differ diff --git a/src/main/res/drawable-mdpi/date_bubble_grey.9.png b/src/main/res/drawable-mdpi/date_bubble_grey.9.png new file mode 100644 index 00000000..864f6910 Binary files /dev/null and b/src/main/res/drawable-mdpi/date_bubble_grey.9.png differ diff --git a/src/main/res/drawable-mdpi/date_bubble_white.9.png b/src/main/res/drawable-mdpi/date_bubble_white.9.png new file mode 100644 index 00000000..cdfa3109 Binary files /dev/null and b/src/main/res/drawable-mdpi/date_bubble_white.9.png differ diff --git a/src/main/res/drawable-xhdpi/date_bubble_grey.9.png b/src/main/res/drawable-xhdpi/date_bubble_grey.9.png new file mode 100644 index 00000000..c83fd613 Binary files /dev/null and b/src/main/res/drawable-xhdpi/date_bubble_grey.9.png differ diff --git a/src/main/res/drawable-xhdpi/date_bubble_white.9.png b/src/main/res/drawable-xhdpi/date_bubble_white.9.png new file mode 100644 index 00000000..ba59e1c5 Binary files /dev/null and b/src/main/res/drawable-xhdpi/date_bubble_white.9.png differ diff --git a/src/main/res/drawable-xxhdpi/date_bubble_grey.9.png b/src/main/res/drawable-xxhdpi/date_bubble_grey.9.png new file mode 100644 index 00000000..4b4dc4d5 Binary files /dev/null and b/src/main/res/drawable-xxhdpi/date_bubble_grey.9.png differ diff --git a/src/main/res/drawable-xxhdpi/date_bubble_white.9.png b/src/main/res/drawable-xxhdpi/date_bubble_white.9.png new file mode 100644 index 00000000..80885df7 Binary files /dev/null and b/src/main/res/drawable-xxhdpi/date_bubble_white.9.png differ diff --git a/src/main/res/drawable-xxxhdpi/date_bubble_grey.9.png b/src/main/res/drawable-xxxhdpi/date_bubble_grey.9.png new file mode 100644 index 00000000..d3db7bf2 Binary files /dev/null and b/src/main/res/drawable-xxxhdpi/date_bubble_grey.9.png differ diff --git a/src/main/res/drawable-xxxhdpi/date_bubble_white.9.png b/src/main/res/drawable-xxxhdpi/date_bubble_white.9.png new file mode 100644 index 00000000..37c12f38 Binary files /dev/null and b/src/main/res/drawable-xxxhdpi/date_bubble_white.9.png differ diff --git a/src/main/res/layout/message_date_bubble.xml b/src/main/res/layout/message_date_bubble.xml new file mode 100644 index 00000000..2d3cae7f --- /dev/null +++ b/src/main/res/layout/message_date_bubble.xml @@ -0,0 +1,26 @@ + + + + + + + + \ No newline at end of file diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index a372a297..53a8c036 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -754,4 +754,6 @@ No application found to open website Heads-up Notifications Show Heads-up Notifications + Today + Yesterday