diff --git a/src/org/thoughtcrime/securesms/ConversationAdapter.java b/src/org/thoughtcrime/securesms/ConversationAdapter.java index 12bd79bcc..5b9b8a113 100644 --- a/src/org/thoughtcrime/securesms/ConversationAdapter.java +++ b/src/org/thoughtcrime/securesms/ConversationAdapter.java @@ -20,7 +20,6 @@ import android.content.Context; import android.support.annotation.LayoutRes; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.support.annotation.VisibleForTesting; import android.support.v7.widget.RecyclerView; import android.util.Log; import android.view.LayoutInflater; @@ -39,14 +38,14 @@ import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.util.DateUtils; import org.thoughtcrime.securesms.util.LRUCache; import org.thoughtcrime.securesms.util.StickyHeaderDecoration; +import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.ViewUtil; import org.whispersystems.libsignal.util.guava.Optional; import java.lang.ref.SoftReference; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; import java.util.Calendar; import java.util.Collections; +import java.util.Date; import java.util.HashSet; import java.util.Locale; import java.util.Map; @@ -89,7 +88,6 @@ public class ConversationAdapter private final @NonNull LayoutInflater inflater; private final @NonNull Context context; private final @NonNull Calendar calendar; - private final @NonNull MessageDigest digest; private ApplicationDcContext dcContext; private @NonNull int[] dcMsgList = new int[0]; @@ -110,6 +108,11 @@ public class ConversationAdapter } } + + public boolean isActive() { + return dcMsgList.length > 0; + } + @Override public int getItemCount() { return dcMsgList.length; @@ -122,6 +125,7 @@ public class ConversationAdapter return new DcMsg(0); } + static class HeaderViewHolder extends RecyclerView.ViewHolder { TextView textView; @@ -146,44 +150,21 @@ public class ConversationAdapter void onItemLongClick(DcMsg item); } - @SuppressWarnings("ConstantConditions") - @VisibleForTesting - ConversationAdapter(Context context) { - try { - this.glideRequests = null; - this.locale = null; - this.clickListener = null; - this.recipient = null; - this.inflater = null; - this.calendar = null; - this.context = context; - this.digest = MessageDigest.getInstance("SHA1"); - this.dcContext = DcHelper.getContext(context); - } catch (NoSuchAlgorithmException nsae) { - throw new AssertionError("SHA1 isn't supported!"); - } - } - public ConversationAdapter(@NonNull Context context, @NonNull GlideRequests glideRequests, @NonNull Locale locale, @Nullable ItemClickListener clickListener, @NonNull Recipient recipient) { - try { - this.glideRequests = glideRequests; - this.locale = locale; - this.clickListener = clickListener; - this.recipient = recipient; - this.context = context; - this.inflater = LayoutInflater.from(context); - this.calendar = Calendar.getInstance(); - this.digest = MessageDigest.getInstance("SHA1"); - this.dcContext = DcHelper.getContext(context); + this.glideRequests = glideRequests; + this.locale = locale; + this.clickListener = clickListener; + this.recipient = recipient; + this.context = context; + this.inflater = LayoutInflater.from(context); + this.calendar = Calendar.getInstance(); + this.dcContext = DcHelper.getContext(context); - setHasStableIds(true); - } catch (NoSuchAlgorithmException nsae) { - throw new AssertionError("SHA1 isn't supported!"); - } + setHasStableIds(true); } @Override @@ -255,7 +236,7 @@ public class ConversationAdapter public int findLastSeenPosition(long lastSeen) { /* TODO -- we shoud do this without loading all messages in the chat if (lastSeen <= 0) return -1; - if (isActive()) return -1; + if (!isActive()) return -1; int count = getItemCount(); @@ -291,39 +272,8 @@ public class ConversationAdapter } } - protected boolean isFooterPosition(int position) { -// return hasFooterView() && position == getItemCount() - 1; - return false; - } - - protected boolean isHeaderPosition(int position) { -// return hasHeaderView() && position == 0; - return false; - } - - @Override - public long getHeaderId(int position) { - return -1; // no header Id. -// if (isActive()) return -1; -// if (isHeaderPosition(position)) return -1; -// if (isFooterPosition(position)) return -1; -// if (position >= getItemCount()) return -1; -// if (position < 0) return -1; -// -// MessageRecord record = getRecordForPositionOrThrow(position); -// -// calendar.setTime(new Date(record.getDateSent())); -// return Util.hashCode(calendar.get(Calendar.YEAR), calendar.get(Calendar.DAY_OF_YEAR)); - } - - public boolean isActive() { - return dcMsgList.length > 0; - } - public long getReceivedTimestamp(int position) { - if (isActive()) return 0; - if (isHeaderPosition(position)) return 0; - if (isFooterPosition(position)) return 0; + if (!isActive()) return 0; if (position >= getItemCount()) return 0; if (position < 0) return 0; @@ -336,21 +286,10 @@ public class ConversationAdapter return context; } - @Override - public HeaderViewHolder onCreateHeaderViewHolder(ViewGroup parent) { - return new HeaderViewHolder(LayoutInflater.from(getContext()).inflate(R.layout.conversation_item_header, parent, false)); - } - public HeaderViewHolder onCreateLastSeenViewHolder(ViewGroup parent) { return new HeaderViewHolder(LayoutInflater.from(getContext()).inflate(R.layout.conversation_item_last_seen, parent, false)); } - @Override - public void onBindHeaderViewHolder(HeaderViewHolder viewHolder, int position) { - DcMsg msg = getMsg(position); - viewHolder.setText(DateUtils.getRelativeDate(getContext(), locale, msg.getTimestamp())); - } - public void onBindLastSeenViewHolder(HeaderViewHolder viewHolder, int position) { viewHolder.setText(getContext().getResources().getQuantityString(R.plurals.ConversationAdapter_n_unread_messages, (position + 1), (position + 1))); } @@ -405,14 +344,40 @@ public class ConversationAdapter } } - public void changeData(@Nullable int[] dcMsgList) { - this.dcMsgList = dcMsgList==null? new int[0] : dcMsgList; - messageRecordCache.clear(); - notifyDataSetChanged(); + + @Override + public long getHeaderId(int position) { + if (position >= getItemCount()) return -1; + if (position < 0) return -1; + + DcMsg dcMsg = getMsg(position); + + calendar.setTime(new Date(dcMsg.getTimestamp())); + return Util.hashCode(calendar.get(Calendar.YEAR), calendar.get(Calendar.DAY_OF_YEAR)); } - public void setHeaderView(@Nullable View headerView) { - // TODO: must not be implemented, remove calls to this function + @Override + public HeaderViewHolder onCreateHeaderViewHolder(ViewGroup parent) { + return new HeaderViewHolder(LayoutInflater.from(getContext()).inflate(R.layout.conversation_item_header, parent, false)); + } + + @Override + public void onBindHeaderViewHolder(HeaderViewHolder viewHolder, int position) { + DcMsg msg = getMsg(position); + viewHolder.setText(DateUtils.getRelativeDate(getContext(), locale, msg.getTimestamp())); + } + + + public void changeData(@Nullable int[] dcMsgList) { + // should be called when there are new messages + this.dcMsgList = dcMsgList==null? new int[0] : dcMsgList; + reloadData(); + } + + public void reloadData() { + // should be called when some items in a message are changed, eg. seen-state + messageRecordCache.clear(); + notifyDataSetChanged(); } public void addFastRecord(@NonNull MessageRecord record) { diff --git a/src/org/thoughtcrime/securesms/ConversationFragment.java b/src/org/thoughtcrime/securesms/ConversationFragment.java index 6c20bd78c..022c4b9ca 100644 --- a/src/org/thoughtcrime/securesms/ConversationFragment.java +++ b/src/org/thoughtcrime/securesms/ConversationFragment.java @@ -549,7 +549,7 @@ public class ConversationFragment extends Fragment MessageRecord messageRecord = DatabaseFactory.getMmsDatabase(getContext()).readerFor(message, threadId).getCurrent(); if (getListAdapter() != null) { - getListAdapter().setHeaderView(null); + //getListAdapter().setHeaderView(null); setLastSeen(0); getListAdapter().addFastRecord(messageRecord); } @@ -561,7 +561,7 @@ public class ConversationFragment extends Fragment MessageRecord messageRecord = DatabaseFactory.getSmsDatabase(getContext()).readerFor(message, threadId).getCurrent(); if (getListAdapter() != null) { - getListAdapter().setHeaderView(null); + //getListAdapter().setHeaderView(null); setLastSeen(0); getListAdapter().addFastRecord(messageRecord); } diff --git a/src/org/thoughtcrime/securesms/components/ConversationItemFooter.java b/src/org/thoughtcrime/securesms/components/ConversationItemFooter.java index b46814382..f307b535d 100644 --- a/src/org/thoughtcrime/securesms/components/ConversationItemFooter.java +++ b/src/org/thoughtcrime/securesms/components/ConversationItemFooter.java @@ -99,7 +99,7 @@ public class ConversationItemFooter extends LinearLayout { if (messageRecord.isFailed()) { dateView.setText(R.string.ConversationItem_error_not_delivered); } else { - dateView.setText(DateUtils.getExtendedRelativeTimeSpanString(getContext(), locale, messageRecord.getTimestamp())); + dateView.setText(DateUtils.getTimeOfDayTimeSpanString(getContext(), locale, messageRecord.getTimestamp())); } } diff --git a/src/org/thoughtcrime/securesms/util/DateUtils.java b/src/org/thoughtcrime/securesms/util/DateUtils.java index 0b9f66e6d..9b3dbd82d 100644 --- a/src/org/thoughtcrime/securesms/util/DateUtils.java +++ b/src/org/thoughtcrime/securesms/util/DateUtils.java @@ -91,6 +91,21 @@ public class DateUtils extends android.text.format.DateUtils { } } + public static String getTimeOfDayTimeSpanString(final Context c, final Locale locale, final long timestamp) { + if (isWithin(timestamp, 1, TimeUnit.MINUTES)) { + return c.getString(R.string.DateUtils_just_now); + } else if (isWithin(timestamp, 1, TimeUnit.HOURS)) { + int mins = (int)TimeUnit.MINUTES.convert(System.currentTimeMillis() - timestamp, TimeUnit.MILLISECONDS); + return c.getResources().getString(R.string.DateUtils_minutes_ago, mins); + } else { + StringBuilder format = new StringBuilder(); + if (DateFormat.is24HourFormat(c)) format.append("HH:mm"); + else format.append("hh:mm a"); + + return getFormattedDateTime(timestamp, format.toString(), locale); + } + } + public static String getDayPrecisionTimeSpanString(Context context, Locale locale, long timestamp) { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");