diff --git a/ring-android/app/src/main/java/cx/ring/adapters/ConversationAdapter.java b/ring-android/app/src/main/java/cx/ring/adapters/ConversationAdapter.java index 3b09b84199b240c6b62e51b23c14e365d6fcdf02..079be396da5bd929449d05cb83e9ee43fc3e93a1 100644 --- a/ring-android/app/src/main/java/cx/ring/adapters/ConversationAdapter.java +++ b/ring-android/app/src/main/java/cx/ring/adapters/ConversationAdapter.java @@ -20,6 +20,9 @@ */ package cx.ring.adapters; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; import android.content.Context; import android.content.Intent; import android.content.res.Resources; @@ -61,6 +64,7 @@ import java.text.DateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; +import java.util.Locale; import cx.ring.R; import cx.ring.client.MediaViewerActivity; @@ -90,21 +94,33 @@ import static androidx.core.content.FileProvider.getUriForFile; public class ConversationAdapter extends RecyclerView.Adapter<ConversationViewHolder> { private final static String TAG = ConversationAdapter.class.getSimpleName(); - private static final double MINUTE = 60L * 1000L; - private static final double HOUR = 3600L * 1000L; - private final ArrayList<Interaction> mInteractions = new ArrayList<>(); + private final long TIMESTAMP_UPDATE_INTERVAL = 10 * DateUtils.SECOND_IN_MILLIS; + private final ConversationPresenter presenter; private final ConversationFragment conversationFragment; private final int hPadding; private final int vPadding; - private final int vPaddingEmoticon; private final int mPictureMaxSize; private final GlideOptions PICTURE_OPTIONS; private RecyclerViewContextMenuInfo mCurrentLongItem = null; private int convColor = 0; + private int expandedItemPosition = -1; + private int lastDeliveredPosition = -1; + + private static int[] msgBGLayouts = new int[] { + R.drawable.textmsg_bg_out_first, + R.drawable.textmsg_bg_out_middle, + R.drawable.textmsg_bg_out_last, + R.drawable.textmsg_bg_out, + R.drawable.textmsg_bg_in_first, + R.drawable.textmsg_bg_in_middle, + R.drawable.textmsg_bg_in_last, + R.drawable.textmsg_bg_in + }; + public ConversationAdapter(ConversationFragment conversationFragment, ConversationPresenter presenter) { this.conversationFragment = conversationFragment; this.presenter = presenter; @@ -112,7 +128,6 @@ public class ConversationAdapter extends RecyclerView.Adapter<ConversationViewHo Resources res = context.getResources(); hPadding = res.getDimensionPixelSize(R.dimen.padding_medium); vPadding = res.getDimensionPixelSize(R.dimen.padding_small); - vPaddingEmoticon = res.getDimensionPixelSize(R.dimen.padding_xsmall); mPictureMaxSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 200, res.getDisplayMetrics()); int corner = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8, res.getDisplayMetrics()); PICTURE_OPTIONS = new GlideOptions() @@ -148,6 +163,9 @@ public class ConversationAdapter extends RecyclerView.Adapter<ConversationViewHo } public void update(Interaction e) { + if (!e.isIncoming() && e.getStatus() == InteractionStatus.SUCCESS) { + notifyItemChanged(lastDeliveredPosition); + } for (int i = mInteractions.size() - 1; i >= 0; i--) { Interaction element = mInteractions.get(i); if (e == element) { @@ -163,6 +181,12 @@ public class ConversationAdapter extends RecyclerView.Adapter<ConversationViewHo if (e.getId().equals(element.getId())) { mInteractions.remove(i); notifyItemRemoved(i); + if (i > 0) { + notifyItemChanged(i - 1); + } + if (i != mInteractions.size()) { + notifyItemChanged(i); + } break; } } @@ -269,6 +293,14 @@ public class ConversationAdapter extends RecyclerView.Adapter<ConversationViewHo holder.player.release(); holder.player = null; } + if (holder.mMsgTxt != null) { + holder.mMsgTxt.setOnClickListener(null); + holder.mMsgTxt.setOnLongClickListener(null); + } + if (expandedItemPosition == holder.getLayoutPosition()) { + holder.mMsgDetailTxt.setVisibility(View.GONE); + expandedItemPosition = -1; + } super.onViewRecycled(holder); } @@ -576,7 +608,6 @@ public class ConversationAdapter extends RecyclerView.Adapter<ConversationViewHo } } - /** * Configures the viewholder to display a classic text message, ie. not a call info text message * @@ -587,6 +618,7 @@ public class ConversationAdapter extends RecyclerView.Adapter<ConversationViewHo private void configureForTextMessage(@NonNull final ConversationViewHolder convViewHolder, @NonNull final Interaction interaction, int position) { + final Context context = convViewHolder.itemView.getContext(); TextMessage textMessage = (TextMessage)interaction; CallContact contact = textMessage.getContact(); if (contact == null) { @@ -594,12 +626,14 @@ public class ConversationAdapter extends RecyclerView.Adapter<ConversationViewHo return; } + convViewHolder.mCid = textMessage.getConversation().getParticipant(); + String message = textMessage.getBody().trim(); + View longPressView = convViewHolder.mMsgTxt; longPressView.getBackground().setTintList(null); longPressView.setOnCreateContextMenuListener((menu, v, menuInfo) -> { Date date = new Date(interaction.getTimestamp()); - //DateFormat dateFormat = android.text.format.DateFormat..getDateFormat(v.getContext()); DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT); menu.setHeaderTitle(dateFormat.format(date)); conversationFragment.onCreateContextMenu(menu, v, menuInfo); @@ -615,6 +649,9 @@ public class ConversationAdapter extends RecyclerView.Adapter<ConversationViewHo }); longPressView.setOnLongClickListener((View v) -> { + if (expandedItemPosition == position) { + expandedItemPosition = -1; + } conversationFragment.updatePosition(convViewHolder.getAdapterPosition()); if (textMessage.isIncoming()) { longPressView.getBackground().setTint(conversationFragment.getResources().getColor(R.color.grey_500)); @@ -625,14 +662,15 @@ public class ConversationAdapter extends RecyclerView.Adapter<ConversationViewHo return false; }); - - convViewHolder.mCid = textMessage.getConversation().getParticipant(); - String message = textMessage.getBody().trim(); + final boolean isTimeShown = hasPermanentTimeString(textMessage, position); + final SequenceType msgSequenceType = getMsgSequencing(position, isTimeShown); if (StringUtils.isOnlyEmoji(message)) { convViewHolder.mMsgTxt.getBackground().setAlpha(0); - convViewHolder.mMsgTxt.setTextSize(24.f); - convViewHolder.mMsgTxt.setPadding(hPadding, vPaddingEmoticon, hPadding, vPaddingEmoticon); + convViewHolder.mMsgTxt.setTextSize(32.0f); + convViewHolder.mMsgTxt.setPadding(0, 0, 0, 0); } else { + int resIndex = msgSequenceType.ordinal() + (textMessage.isIncoming() ? 1 : 0) * 4; + convViewHolder.mMsgTxt.setBackground(ContextCompat.getDrawable(context, msgBGLayouts[resIndex])); if (convColor != 0 && !textMessage.isIncoming()) { convViewHolder.mMsgTxt.getBackground().setTint(convColor); } @@ -646,51 +684,67 @@ public class ConversationAdapter extends RecyclerView.Adapter<ConversationViewHo convViewHolder.mPhoto.setImageBitmap(null); } - boolean separateByDetails = shouldSeparateByDetails(textMessage, position); - boolean isLast = position == mInteractions.size() - 1; - boolean sameAsPreviousMsg = isMessageConfigSameAsPrevious(textMessage, position); - final Context context = convViewHolder.itemView.getContext(); - - if (textMessage.isIncoming() && !sameAsPreviousMsg) { - convViewHolder.mPhoto.setImageDrawable( - conversationFragment.getConversationAvatar(contact.getPrimaryNumber()) - ); + if (msgSequenceType == SequenceType.LAST || msgSequenceType == SequenceType.SINGLE) { + setBottomMargin(convViewHolder.mMsgTxt, 8); + if (textMessage.isIncoming()) { + convViewHolder.mPhoto.setImageDrawable( + conversationFragment.getConversationAvatar(contact.getPrimaryNumber()) + ); + } + } else { + setBottomMargin(convViewHolder.mMsgTxt, 0); } - switch (textMessage.getStatus()) { - case SENDING: - if (!textMessage.isIncoming()) { + if (!textMessage.isIncoming()) { + switch (textMessage.getStatus()) { + case SENDING: convViewHolder.mPhoto.setVisibility(View.VISIBLE); convViewHolder.mPhoto.setImageResource(R.drawable.baseline_circle_24); - convViewHolder.mMsgDetailTxt.setVisibility(View.GONE); - } - break; - case FAILURE: - if (!textMessage.isIncoming()) { + break; + case FAILURE: convViewHolder.mPhoto.setVisibility(View.VISIBLE); convViewHolder.mPhoto.setImageResource(R.drawable.round_highlight_off_24); - convViewHolder.mMsgDetailTxt.setVisibility(View.GONE); - } - break; - default: - if (separateByDetails) { - if (!textMessage.isIncoming()) { + break; + default: + if (shouldSeparateByDetails(textMessage, position) && position == lastOutgoingIndex()) { convViewHolder.mPhoto.setVisibility(View.VISIBLE); convViewHolder.mPhoto.setImageResource(R.drawable.baseline_check_circle_24); - } - if (!isLast) { - convViewHolder.updater = new UiUpdater(() -> convViewHolder.mMsgDetailTxt.setText(timestampToDetailString(context, textMessage.getTimestamp())), 10000); - convViewHolder.updater.start(); - convViewHolder.mMsgDetailTxt.setVisibility(View.VISIBLE); + lastDeliveredPosition = position; } else { - convViewHolder.mMsgDetailTxt.setVisibility(View.GONE); - } - } else { - if (!textMessage.isIncoming()) { convViewHolder.mPhoto.setVisibility(View.GONE); } - convViewHolder.mMsgDetailTxt.setVisibility(View.GONE); + } + } + + if (isTimeShown) { + convViewHolder.updater = new UiUpdater(() -> { + String timeSeparationString = timestampToDetailString(context, textMessage.getTimestamp()); + convViewHolder.mMsgDetailTxtPerm.setText(timeSeparationString); + }, TIMESTAMP_UPDATE_INTERVAL); + convViewHolder.updater.start(); + convViewHolder.mMsgDetailTxtPerm.setVisibility(View.VISIBLE); + } else { + convViewHolder.mMsgDetailTxtPerm.setVisibility(View.GONE); + final boolean isExpanded = position == expandedItemPosition; + if (isExpanded) { + convViewHolder.updater = new UiUpdater(() -> { + String timeSeparationString = timestampToDetailString(context, textMessage.getTimestamp()); + convViewHolder.mMsgDetailTxt.setText(timeSeparationString); + }, TIMESTAMP_UPDATE_INTERVAL); + convViewHolder.updater.start(); + } + setItemViewExpansionState(convViewHolder, isExpanded); + convViewHolder.mMsgTxt.setOnClickListener((View v) -> { + if (convViewHolder.animator != null && convViewHolder.animator.isRunning()) { + return; } + if (expandedItemPosition >= 0) { + int prev = expandedItemPosition; + notifyItemChanged(prev); + } + expandedItemPosition = isExpanded ? -1 : position; + notifyItemChanged(expandedItemPosition); + }); } } @@ -704,7 +758,7 @@ public class ConversationAdapter extends RecyclerView.Adapter<ConversationViewHo viewHolder.updater = new UiUpdater(() -> { String timeSeparationString = timestampToDetailString(viewHolder.itemView.getContext(), event.getTimestamp()); viewHolder.mMsgDetailTxt.setText(timeSeparationString); - }, 10000); + }, TIMESTAMP_UPDATE_INTERVAL); viewHolder.updater.start(); } @@ -782,15 +836,27 @@ public class ConversationAdapter extends RecyclerView.Adapter<ConversationViewHo * @return The string to display in the text details between messages. */ private String timestampToDetailString(Context context, long timestamp) { - long now = new Date().getTime(); - if (now - timestamp < MINUTE) { - return context.getString(R.string.time_just_now); - } else if (now - timestamp < HOUR) { - return DateUtils.getRelativeTimeSpanString(timestamp, now, 0, 0).toString(); + long diff = new Date().getTime() - timestamp; + String timeStr; + if (diff < DateUtils.WEEK_IN_MILLIS) { + if (diff < DateUtils.DAY_IN_MILLIS && DateUtils.isToday(timestamp)) { // 11:32 A.M. + timeStr = DateUtils.formatDateTime(context, timestamp, DateUtils.FORMAT_SHOW_TIME); + } else { + timeStr = DateUtils.formatDateTime(context, timestamp, + DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_NO_YEAR | + DateUtils.FORMAT_ABBREV_ALL | DateUtils.FORMAT_SHOW_TIME); + } + } else if (diff < DateUtils.YEAR_IN_MILLIS) { // JAN. 7, 11:02 A.M. + timeStr = DateUtils.formatDateTime(context, timestamp, + DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NO_YEAR | + DateUtils.FORMAT_ABBREV_ALL | DateUtils.FORMAT_SHOW_TIME); } else { - return DateUtils.formatSameDayTime(timestamp, now, DateFormat.SHORT, DateFormat.SHORT) - .toString(); + timeStr = DateUtils.formatDateTime(context, timestamp, + DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE | + DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_SHOW_WEEKDAY | + DateUtils.FORMAT_ABBREV_ALL); } + return timeStr.toUpperCase(Locale.getDefault()); } /** @@ -822,15 +888,15 @@ public class ConversationAdapter extends RecyclerView.Adapter<ConversationViewHo } /** - * Helper used to determine if a text details string should be displayed under a message at a + * Helper used to determine if a text details string should be displayed for a message at a * certain position. * - * @param ht The conversationElement at the given position + * @param msg The Interaction at the given position * @param position The position of the current message * @return true if a text details string should be displayed under the message */ - private boolean shouldSeparateByDetails(final Interaction ht, int position) { - if (ht == null) { + private boolean shouldSeparateByDetails(final Interaction msg, int position) { + if (msg == null) { return false; } boolean shouldSeparateMsg = false; @@ -839,8 +905,8 @@ public class ConversationAdapter extends RecyclerView.Adapter<ConversationViewHo shouldSeparateMsg = true; Interaction nextTextMessage = getNextMessageFromPosition(position); if (nextTextMessage != null) { - long diff = nextTextMessage.getTimestamp() - ht.getTimestamp(); - if (diff < MINUTE) { + long diff = nextTextMessage.getTimestamp() - msg.getTimestamp(); + if (diff < DateUtils.MINUTE_IN_MILLIS) { shouldSeparateMsg = false; } } @@ -848,32 +914,131 @@ public class ConversationAdapter extends RecyclerView.Adapter<ConversationViewHo return shouldSeparateMsg; } - /** - * Helper method determining if a given conversationElement should be distinguished from the - * previous ie. if their configuration is not the same. - * - * @param textMessage The conversationElement at the given position - * @param position The position of the current message - * @return true if the configuration is the same as the previous message, false otherwise. - */ - private boolean isMessageConfigSameAsPrevious(final Interaction textMessage, - int position) { - if (textMessage == null) { + private boolean isSeqBreak(@NonNull Interaction first, @NonNull Interaction second) { + return StringUtils.isOnlyEmoji(first.getBody()) != StringUtils.isOnlyEmoji(second.getBody()) + || first.isIncoming() != second.isIncoming() + || first.getType() == InteractionType.CONTACT + || first.getType() == InteractionType.CALL + || second.getType() == InteractionType.CONTACT + || second.getType() == InteractionType.CALL; + } + + private boolean isAlwaysSingleMsg(@NonNull Interaction msg) { + return msg.getType() == InteractionType.CONTACT + || msg.getType() == InteractionType.CALL + || StringUtils.isOnlyEmoji(msg.getBody()); + } + + private SequenceType getMsgSequencing(final int i, final boolean isTimeShown) { + Interaction msg = mInteractions.get(i); + if (isAlwaysSingleMsg(msg)) { + return SequenceType.SINGLE; + } + if (mInteractions.size() == 1 || i == 0) { + if (mInteractions.size() == i + 1) { + return SequenceType.SINGLE; + } + Interaction nextMsg = getNextMessageFromPosition(i); + if (nextMsg != null) { + if (isSeqBreak(msg, nextMsg)) { + return SequenceType.SINGLE; + } else { + return SequenceType.FIRST; + } + } + } else if (mInteractions.size() == i + 1) { + Interaction prevMsg = getPreviousMessageFromPosition(i); + if (prevMsg != null) { + if (isSeqBreak(msg, prevMsg) || isTimeShown) { + return SequenceType.SINGLE; + } else { + return SequenceType.LAST; + } + } + } + Interaction prevMsg = getPreviousMessageFromPosition(i); + Interaction nextMsg = getNextMessageFromPosition(i); + if (prevMsg != null && nextMsg != null) { + if (((isSeqBreak(msg, prevMsg) || isTimeShown) && !isSeqBreak(msg, nextMsg))) { + return SequenceType.FIRST; + } else if (!isSeqBreak(msg, prevMsg) && !isTimeShown && isSeqBreak(msg, nextMsg)) { + return SequenceType.LAST; + } else if (!isSeqBreak(msg, prevMsg) && !isTimeShown && !isSeqBreak(msg, nextMsg)) { + return SequenceType.MIDDLE; + } + } + return SequenceType.SINGLE; + } + + private void setItemViewExpansionState(ConversationViewHolder viewHolder, boolean expanded) { + View view = viewHolder.mMsgDetailTxt; + if (viewHolder.animator == null) { + if (view.getHeight() == 0 && !expanded) { + return; + } + viewHolder.animator = new ValueAnimator(); + } + if (viewHolder.animator.isRunning()) { + viewHolder.animator.reverse(); + return; + } + view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); + viewHolder.animator.setIntValues(0, view.getMeasuredHeight()); + if (expanded) { + view.setVisibility(View.VISIBLE); + } + viewHolder.animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + ValueAnimator va = (ValueAnimator) animation; + if ((Integer) va.getAnimatedValue() == 0) { + view.setVisibility(View.GONE); + } + viewHolder.animator = null; + } + }); + viewHolder.animator.setDuration(200); + viewHolder.animator.addUpdateListener(animation -> { + view.getLayoutParams().height = (Integer) animation.getAnimatedValue(); + view.requestLayout(); + }); + if (!expanded) { + viewHolder.animator.reverse(); + } else { + viewHolder.animator.start(); + } + } + + private static void setBottomMargin(View view, int value) { + int targetSize = (int) (value * view.getContext().getResources().getDisplayMetrics().density); + ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) view.getLayoutParams(); + params.bottomMargin = targetSize; + } + + private boolean hasPermanentTimeString(final Interaction msg, int position) { + if (msg == null) { return false; } + Interaction prevMsg = getPreviousMessageFromPosition(position); + return (prevMsg != null && + (msg.getTimestamp() - prevMsg.getTimestamp()) > 10 * DateUtils.MINUTE_IN_MILLIS); + } - boolean sameConfig = false; - Interaction previousMessage = getPreviousMessageFromPosition(position); - if (previousMessage != null && - textMessage.getAuthor() != null && - previousMessage.getAuthor() != null && - textMessage.getAuthor().equals(previousMessage.getAuthor()) && - textMessage.getType() == (previousMessage.getType()) && - textMessage.isIncoming() && - previousMessage.getConversation().getParticipant().equals(textMessage.getConversation().getParticipant())) { - sameConfig = true; + private int lastOutgoingIndex() { + int i; + for (i = mInteractions.size() - 1; i >= 0; i--) { + if (!mInteractions.get(i).isIncoming()) { + break; + } } - return sameConfig; + return i; + } + + private enum SequenceType { + FIRST, + MIDDLE, + LAST, + SINGLE; } public enum MessageType { diff --git a/ring-android/app/src/main/java/cx/ring/utils/UiUpdater.java b/ring-android/app/src/main/java/cx/ring/utils/UiUpdater.java index 648107eff9532d4664537b0f1237cf2e2bcfedf8..fe3514796cd7f813864eee0ccf5551242185408f 100644 --- a/ring-android/app/src/main/java/cx/ring/utils/UiUpdater.java +++ b/ring-android/app/src/main/java/cx/ring/utils/UiUpdater.java @@ -9,9 +9,9 @@ public class UiUpdater { // Create a Handler that uses the Main Looper to run in private final Handler mHandler = new Handler(Looper.getMainLooper()); private final Runnable mStatusChecker; - private final int UPDATE_INTERVAL; + private final long UPDATE_INTERVAL; - public UiUpdater(final Runnable uiUpdater, int interval) { + public UiUpdater(final Runnable uiUpdater, long interval) { UPDATE_INTERVAL = interval; mStatusChecker = new Runnable() { @Override @@ -29,7 +29,7 @@ public class UiUpdater { } public UiUpdater(Runnable uiUpdater){ - this(uiUpdater, 1000); + this(uiUpdater, 1000L); } /** diff --git a/ring-android/app/src/main/java/cx/ring/views/ConversationViewHolder.java b/ring-android/app/src/main/java/cx/ring/views/ConversationViewHolder.java index 38c89edb08f6efdcceb2b3e2674cbc9255cdba57..97552de2508409f65a07e3905ba384ef2ec8d7b7 100644 --- a/ring-android/app/src/main/java/cx/ring/views/ConversationViewHolder.java +++ b/ring-android/app/src/main/java/cx/ring/views/ConversationViewHolder.java @@ -22,6 +22,7 @@ package cx.ring.views; import androidx.recyclerview.widget.RecyclerView; +import android.animation.ValueAnimator; import android.media.MediaPlayer; import android.view.Surface; import android.view.TextureView; @@ -35,11 +36,11 @@ import android.widget.TextView; import cx.ring.R; import cx.ring.adapters.ConversationAdapter; import cx.ring.utils.UiUpdater; -import io.reactivex.disposables.Disposable; public class ConversationViewHolder extends RecyclerView.ViewHolder { public TextView mMsgTxt; public TextView mMsgDetailTxt; + public TextView mMsgDetailTxtPerm; public ImageView mPhoto; public TextView mHistTxt; public TextView mHistDetailTxt; @@ -55,17 +56,19 @@ public class ConversationViewHolder extends RecyclerView.ViewHolder { public String mCid; public UiUpdater updater; public LinearLayout mCallInfoLayout, mFileInfoLayout, mAudioInfoLayout; - public Disposable disposable = null; + public ValueAnimator animator; public ConversationViewHolder(ViewGroup v, ConversationAdapter.MessageType type) { super(v); if (type == ConversationAdapter.MessageType.INCOMING_TEXT_MESSAGE) { mMsgTxt = v.findViewById(R.id.msg_txt); mMsgDetailTxt = v.findViewById(R.id.msg_details_txt); + mMsgDetailTxtPerm = v.findViewById(R.id.msg_details_txt_perm); mPhoto = v.findViewById(R.id.photo); } else if (type == ConversationAdapter.MessageType.OUTGOING_TEXT_MESSAGE) { mMsgTxt = v.findViewById(R.id.msg_txt); mMsgDetailTxt = v.findViewById(R.id.msg_details_txt); + mMsgDetailTxtPerm = v.findViewById(R.id.msg_details_txt_perm); mPhoto = v.findViewById(R.id.status_icon); } else if (type == ConversationAdapter.MessageType.CALL_INFORMATION) { mHistTxt = v.findViewById(R.id.call_hist_txt); diff --git a/ring-android/app/src/main/res/drawable/textmsg_background.xml b/ring-android/app/src/main/res/drawable/textmsg_bg_in.xml similarity index 61% rename from ring-android/app/src/main/res/drawable/textmsg_background.xml rename to ring-android/app/src/main/res/drawable/textmsg_bg_in.xml index 79259216a54630fe04935d07ed9464c5bd5e74ec..2cf39fa539ef5ed1c06a5d0e49d20fa61f3ebc0e 100644 --- a/ring-android/app/src/main/res/drawable/textmsg_background.xml +++ b/ring-android/app/src/main/res/drawable/textmsg_bg_in.xml @@ -8,9 +8,11 @@ <solid android:color="@color/conversation_secondary_background" /> <padding - android:left="1dp" - android:right="1dp" - android:top="1dp" /> + android:left="@dimen/padding_medium" + android:right="@dimen/padding_medium" + android:top="@dimen/conversation_message_padding_top" + android:bottom="@dimen/conversation_message_padding_bottom" + /> <corners android:radius="@dimen/conversation_message_radius" /> diff --git a/ring-android/app/src/main/res/drawable/textmsg_bg_in_first.xml b/ring-android/app/src/main/res/drawable/textmsg_bg_in_first.xml new file mode 100644 index 0000000000000000000000000000000000000000..9bc837bc061906fd6f5ce20c0f0c8b1d78d84e02 --- /dev/null +++ b/ring-android/app/src/main/res/drawable/textmsg_bg_in_first.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + + <stroke + android:width="0dp" + android:color="@android:color/transparent" /> + + <solid android:color="@color/conversation_secondary_background" /> + + <padding + android:left="@dimen/padding_medium" + android:right="@dimen/padding_medium" + android:top="@dimen/conversation_message_padding_top" + android:bottom="@dimen/conversation_message_padding_bottom" + /> + + <corners + android:topLeftRadius="@dimen/conversation_message_radius" + android:topRightRadius="@dimen/conversation_message_radius" + android:bottomRightRadius="@dimen/conversation_message_radius" + android:bottomLeftRadius="@dimen/conversation_message_minor_radius" + /> + +</shape> \ No newline at end of file diff --git a/ring-android/app/src/main/res/drawable/textmsg_bg_in_last.xml b/ring-android/app/src/main/res/drawable/textmsg_bg_in_last.xml new file mode 100644 index 0000000000000000000000000000000000000000..9ad0866765fe32572ba1dfe797d9b34167708c62 --- /dev/null +++ b/ring-android/app/src/main/res/drawable/textmsg_bg_in_last.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + + <stroke + android:width="0dp" + android:color="@android:color/transparent" /> + + <solid android:color="@color/conversation_secondary_background" /> + + <padding + android:left="@dimen/padding_medium" + android:right="@dimen/padding_medium" + android:top="@dimen/conversation_message_padding_top" + android:bottom="@dimen/conversation_message_padding_bottom" + /> + + <corners + android:topLeftRadius="@dimen/conversation_message_minor_radius" + android:topRightRadius="@dimen/conversation_message_radius" + android:bottomRightRadius="@dimen/conversation_message_radius" + android:bottomLeftRadius="@dimen/conversation_message_radius" + /> + +</shape> \ No newline at end of file diff --git a/ring-android/app/src/main/res/drawable/textmsg_bg_in_middle.xml b/ring-android/app/src/main/res/drawable/textmsg_bg_in_middle.xml new file mode 100644 index 0000000000000000000000000000000000000000..af93951eb23a4923c47d77a3350f1f23a87695af --- /dev/null +++ b/ring-android/app/src/main/res/drawable/textmsg_bg_in_middle.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + + <stroke + android:width="0dp" + android:color="@android:color/transparent" /> + + <solid android:color="@color/conversation_secondary_background" /> + + <padding + android:left="@dimen/padding_medium" + android:right="@dimen/padding_medium" + android:top="@dimen/conversation_message_padding_top" + android:bottom="@dimen/conversation_message_padding_bottom" + /> + + <corners + android:topLeftRadius="@dimen/conversation_message_minor_radius" + android:topRightRadius="@dimen/conversation_message_radius" + android:bottomRightRadius="@dimen/conversation_message_radius" + android:bottomLeftRadius="@dimen/conversation_message_minor_radius" + /> + +</shape> \ No newline at end of file diff --git a/ring-android/app/src/main/res/drawable/textmsg_me_background.xml b/ring-android/app/src/main/res/drawable/textmsg_bg_out.xml similarity index 61% rename from ring-android/app/src/main/res/drawable/textmsg_me_background.xml rename to ring-android/app/src/main/res/drawable/textmsg_bg_out.xml index aefa345edb308bc6aed429dee325898ce0c41ee1..20681a6d9cb011dfa597cc18266478d923b6d35b 100644 --- a/ring-android/app/src/main/res/drawable/textmsg_me_background.xml +++ b/ring-android/app/src/main/res/drawable/textmsg_bg_out.xml @@ -8,9 +8,11 @@ <solid android:color="@color/conversation_primary_background" /> <padding - android:left="1dp" - android:right="1dp" - android:top="1dp" /> + android:left="@dimen/padding_medium" + android:right="@dimen/padding_medium" + android:top="@dimen/conversation_message_padding_top" + android:bottom="@dimen/conversation_message_padding_bottom" + /> <corners android:radius="@dimen/conversation_message_radius" /> diff --git a/ring-android/app/src/main/res/drawable/textmsg_bg_out_first.xml b/ring-android/app/src/main/res/drawable/textmsg_bg_out_first.xml new file mode 100644 index 0000000000000000000000000000000000000000..f05e24596582c747d3a0634f6e7119d8c60cd5fb --- /dev/null +++ b/ring-android/app/src/main/res/drawable/textmsg_bg_out_first.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + + <stroke + android:width="0dp" + android:color="@android:color/transparent" /> + + <solid android:color="@color/conversation_primary_background" /> + + <padding + android:left="@dimen/padding_medium" + android:right="@dimen/padding_medium" + android:top="@dimen/conversation_message_padding_top" + android:bottom="@dimen/conversation_message_padding_bottom" + /> + + <corners + android:bottomRightRadius="@dimen/conversation_message_minor_radius" + android:bottomLeftRadius="@dimen/conversation_message_radius" + android:topLeftRadius="@dimen/conversation_message_radius" + android:topRightRadius="@dimen/conversation_message_radius" + /> + +</shape> \ No newline at end of file diff --git a/ring-android/app/src/main/res/drawable/textmsg_bg_out_last.xml b/ring-android/app/src/main/res/drawable/textmsg_bg_out_last.xml new file mode 100644 index 0000000000000000000000000000000000000000..bcbaac39ef22bb1e95fcafc6533cdb6223c603a8 --- /dev/null +++ b/ring-android/app/src/main/res/drawable/textmsg_bg_out_last.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + + <stroke + android:width="0dp" + android:color="@android:color/transparent" /> + + <solid android:color="@color/conversation_primary_background" /> + + <padding + android:left="@dimen/padding_medium" + android:right="@dimen/padding_medium" + android:top="@dimen/conversation_message_padding_top" + android:bottom="@dimen/conversation_message_padding_bottom" + /> + + <corners + android:topLeftRadius="@dimen/conversation_message_radius" + android:topRightRadius="@dimen/conversation_message_minor_radius" + android:bottomRightRadius="@dimen/conversation_message_radius" + android:bottomLeftRadius="@dimen/conversation_message_radius" + /> + +</shape> \ No newline at end of file diff --git a/ring-android/app/src/main/res/drawable/textmsg_bg_out_middle.xml b/ring-android/app/src/main/res/drawable/textmsg_bg_out_middle.xml new file mode 100644 index 0000000000000000000000000000000000000000..d02da3e82617e17d3d058a56ffbd0fb622eb48f8 --- /dev/null +++ b/ring-android/app/src/main/res/drawable/textmsg_bg_out_middle.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + + <stroke + android:width="0dp" + android:color="@android:color/transparent" /> + + <solid android:color="@color/conversation_primary_background" /> + + <padding + android:left="@dimen/padding_medium" + android:right="@dimen/padding_medium" + android:top="@dimen/conversation_message_padding_top" + android:bottom="@dimen/conversation_message_padding_bottom" + /> + + <corners + android:topLeftRadius="@dimen/conversation_message_radius" + android:topRightRadius="@dimen/conversation_message_minor_radius" + android:bottomRightRadius="@dimen/conversation_message_minor_radius" + android:bottomLeftRadius="@dimen/conversation_message_radius" + /> + +</shape> \ No newline at end of file diff --git a/ring-android/app/src/main/res/layout/item_conv_image.xml b/ring-android/app/src/main/res/layout/item_conv_image.xml index d02b1e24af0970dc2b6d223e2cf32ec0c2e1a563..55e5bfb321706d5de90b01ba6b96469bdf6ee7c3 100644 --- a/ring-android/app/src/main/res/layout/item_conv_image.xml +++ b/ring-android/app/src/main/res/layout/item_conv_image.xml @@ -47,7 +47,7 @@ android:adjustViewBounds="true" android:maxHeight="200dp" android:transitionName="picture" - tools:src="@drawable/banner" /> + tools:src="@drawable/logo_sfl_coul_rgb" /> <TextView android:id="@+id/msg_details_txt" diff --git a/ring-android/app/src/main/res/layout/item_conv_msg_me.xml b/ring-android/app/src/main/res/layout/item_conv_msg_me.xml index 5e300c5a33e18de438e16e81e41a7f6d362905db..f7aa80612a350c2d8326efe73d171fe4b87a4094 100644 --- a/ring-android/app/src/main/res/layout/item_conv_msg_me.xml +++ b/ring-android/app/src/main/res/layout/item_conv_msg_me.xml @@ -18,67 +18,81 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. --> -<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/txt_entry" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_gravity="end" + android:paddingBottom="2dp" android:background="@android:color/transparent" - android:focusable="false" - android:paddingStart="@dimen/padding_large" - android:paddingTop="4dp" - android:paddingEnd="0dp" - android:paddingBottom="4dp"> + android:orientation="vertical" + android:gravity="center"> <TextView - android:id="@+id/msg_txt" + android:id="@+id/msg_details_txt_perm" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_alignParentTop="true" - android:layout_alignParentEnd="true" - android:layout_marginStart="72dp" - android:layout_marginEnd="20dp" - android:autoLink="all" - android:background="@drawable/textmsg_me_background" - android:ellipsize="marquee" - android:focusable="true" - android:marqueeRepeatLimit="marquee_forever" - android:paddingStart="@dimen/padding_medium" - android:paddingTop="5dp" - android:paddingEnd="@dimen/padding_medium" - android:paddingBottom="@dimen/padding_small" - android:scrollHorizontally="true" - android:singleLine="false" - android:textColor="@color/text_color_primary_dark" - android:textColorLink="@color/text_color_primary_dark" - android:textIsSelectable="true" - android:textSize="16sp" - tools:text="yo this is the test of a long long text can not be_found_message" /> + android:visibility="gone" + android:textColor="@color/textColorSecondary" + android:textSize="14sp" + android:paddingTop="4dp" + android:paddingBottom="8dp" + tools:text="@string/time_just_now" /> <TextView android:id="@+id/msg_details_txt" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_below="@+id/msg_txt" - android:layout_alignEnd="@id/msg_txt" - android:layout_marginEnd="4dp" - android:layout_marginBottom="4dp" + android:visibility="gone" android:textColor="@color/textColorSecondary" android:textSize="14sp" - tools:text="@string/message_sending" /> + android:paddingTop="4dp" + android:paddingBottom="2dp" + tools:text="@string/time_just_now" /> + + + <RelativeLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingStart="@dimen/padding_large" + android:paddingEnd="2dp"> + + <TextView + android:id="@+id/msg_txt" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentTop="true" + android:layout_alignParentEnd="true" + android:minWidth="@dimen/conversation_avatar_size" + android:minHeight="@dimen/conversation_avatar_size" + android:layout_marginStart="72dp" + android:layout_marginEnd="24dp" + android:autoLink="all" + android:background="@drawable/textmsg_bg_out" + android:ellipsize="marquee" + android:focusable="false" + android:marqueeRepeatLimit="marquee_forever" + android:padding="@dimen/padding_medium" + android:scrollHorizontally="true" + android:singleLine="false" + android:textColor="@color/text_color_primary_dark" + android:textColorLink="@color/text_color_primary_dark" + android:textIsSelectable="true" + android:textSize="16sp" + tools:text="yo this is the test of a long long text can not be_found_message" /> - <ImageView - android:id="@+id/status_icon" - android:layout_width="14dp" - android:layout_height="14dp" - android:layout_alignBottom="@id/msg_txt" - android:layout_alignParentEnd="true" - android:layout_marginTop="3dp" - android:layout_marginEnd="4dp" - android:tint="@color/grey_500" - app:srcCompat="@drawable/round_check_circle_24" /> + <ImageView + android:id="@+id/status_icon" + android:layout_width="14dp" + android:layout_height="14dp" + android:layout_alignBottom="@id/msg_txt" + android:layout_alignParentEnd="true" + android:layout_marginEnd="5dp" + android:tint="@color/grey_500" + app:srcCompat="@drawable/round_check_circle_24" /> -</RelativeLayout> + </RelativeLayout> +</LinearLayout> \ No newline at end of file diff --git a/ring-android/app/src/main/res/layout/item_conv_msg_peer.xml b/ring-android/app/src/main/res/layout/item_conv_msg_peer.xml index 8e79cfc43ab01f5bd93cc4ccdbcc1dcef97c262d..ee3b4ecbe0e30843319eaf2b25c36d54513e0443 100644 --- a/ring-android/app/src/main/res/layout/item_conv_msg_peer.xml +++ b/ring-android/app/src/main/res/layout/item_conv_msg_peer.xml @@ -18,62 +18,74 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. --> -<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/txt_entry" android:layout_width="match_parent" android:layout_height="wrap_content" + android:paddingBottom="2dp" android:background="@android:color/transparent" - android:focusable="false" - android:paddingStart="@dimen/padding_large" - android:paddingLeft="@dimen/padding_large" - android:paddingTop="4dp" - android:paddingEnd="@dimen/padding_large" - android:paddingRight="@dimen/padding_large" - android:paddingBottom="4dp"> - - <ImageView - android:id="@+id/photo" - android:layout_width="40dp" - android:layout_height="40dp" - android:layout_alignParentStart="true" - android:layout_alignParentTop="true" - android:layout_marginEnd="16dp" - android:background="@null" - android:scaleType="centerCrop" /> + android:orientation="vertical" + android:gravity="center"> <TextView - android:id="@+id/msg_txt" + android:id="@+id/msg_details_txt_perm" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_alignParentTop="true" - android:layout_marginEnd="48dp" - android:layout_toEndOf="@+id/photo" - android:autoLink="all" - android:background="@drawable/textmsg_background" - android:ellipsize="marquee" - android:focusable="true" - android:marqueeRepeatLimit="marquee_forever" - android:paddingLeft="@dimen/padding_medium" - android:paddingTop="5dp" - android:paddingRight="@dimen/padding_medium" - android:paddingBottom="@dimen/padding_small" - android:scrollHorizontally="true" - android:singleLine="false" - android:textColor="@color/textColorPrimary" - android:textIsSelectable="true" - android:textSize="16sp" - tools:text="yo" /> + android:visibility="gone" + android:textColor="@color/textColorSecondary" + android:textSize="14sp" + android:paddingTop="4dp" + android:paddingBottom="8dp" + tools:text="@string/time_just_now" /> <TextView android:id="@+id/msg_details_txt" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_below="@+id/msg_txt" - android:layout_marginBottom="4dp" - android:layout_toEndOf="@id/photo" + android:visibility="gone" android:textColor="@color/textColorSecondary" android:textSize="14sp" + android:paddingTop="4dp" + android:paddingBottom="2dp" tools:text="@string/time_just_now" /> -</RelativeLayout> + <RelativeLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingStart="@dimen/padding_medium" + android:paddingEnd="@dimen/padding_large"> + + <ImageView + android:id="@+id/photo" + android:layout_width="@dimen/conversation_avatar_size" + android:layout_height="@dimen/conversation_avatar_size" + android:background="@null" + android:layout_alignBottom="@id/msg_txt" + android:scaleType="centerCrop"/> + + <TextView + android:id="@+id/msg_txt" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_toRightOf="@+id/photo" + android:layout_marginStart="@dimen/padding_medium" + android:layout_marginEnd="20dp" + android:minWidth="@dimen/conversation_avatar_size" + android:minHeight="@dimen/conversation_avatar_size" + android:autoLink="all" + android:background="@drawable/textmsg_bg_in" + android:ellipsize="marquee" + android:focusable="false" + android:marqueeRepeatLimit="marquee_forever" + android:scrollHorizontally="true" + android:singleLine="false" + android:textColor="@color/textColorPrimary" + android:textIsSelectable="true" + android:textSize="16sp" + tools:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod" /> + + </RelativeLayout> + +</LinearLayout> \ No newline at end of file diff --git a/ring-android/app/src/main/res/values/dimens.xml b/ring-android/app/src/main/res/values/dimens.xml index 7a451727f4e5481dbfa69b17ae37c139c1ba41bf..f66f8566169ea211ac6cff27e22812e6c52d8583 100644 --- a/ring-android/app/src/main/res/values/dimens.xml +++ b/ring-android/app/src/main/res/values/dimens.xml @@ -24,9 +24,14 @@ along with this program; if not, write to the Free Software <dimen name="padding_medium">12dp</dimen> <dimen name="padding_large">16dp</dimen> + <dimen name="conversation_message_padding_top">7dp</dimen> + <dimen name="conversation_message_padding_bottom">7dp</dimen> + <dimen name="conversation_message_input_radius">24dp</dimen> <dimen name="conversation_message_input_margin">16dp</dimen> - <dimen name="conversation_message_radius">24dp</dimen> + <dimen name="conversation_avatar_size">36dp</dimen> + <dimen name="conversation_message_radius">18dp</dimen> + <dimen name="conversation_message_minor_radius">3dp</dimen> <dimen name="activity_horizontal_margin">32dp</dimen> <dimen name="activity_vertical_margin">16dp</dimen> diff --git a/ring-android/libringclient/src/main/java/cx/ring/conversation/ConversationPresenter.java b/ring-android/libringclient/src/main/java/cx/ring/conversation/ConversationPresenter.java index fd4079abc2d80a01ad3ef18c624ac70cc20c19fc..7611dfb72ca08cdde74d005ac72a181fb5962fd2 100644 --- a/ring-android/libringclient/src/main/java/cx/ring/conversation/ConversationPresenter.java +++ b/ring-android/libringclient/src/main/java/cx/ring/conversation/ConversationPresenter.java @@ -138,7 +138,6 @@ public class ConversationPresenter extends RootPresenter<ConversationView> { .subscribe(conversation -> { conversation.setVisible(true); updateOngoingCallView(conversation); - getView().displayContact(conversation.getContact()); mConversationFacade.readMessages(mAccountService.getAccount(mAccountId), conversation); }, e -> Log.e(TAG, "Error loading conversation", e))); } diff --git a/ring-android/libringclient/src/main/java/cx/ring/model/Interaction.java b/ring-android/libringclient/src/main/java/cx/ring/model/Interaction.java index 198a556d323ac9512009ab0bb67bde5fcf7d949b..560f279d157b809723b0753d40992df6ad0f886e 100644 --- a/ring-android/libringclient/src/main/java/cx/ring/model/Interaction.java +++ b/ring-android/libringclient/src/main/java/cx/ring/model/Interaction.java @@ -288,6 +288,4 @@ public class Interaction { } } - - }