From 8f551c8b3256db8b4f3fc7bac2974653ae3ce7ea Mon Sep 17 00:00:00 2001 From: Greyson Parrelli Date: Wed, 18 Jul 2018 13:53:50 -0700 Subject: [PATCH] Fix various redesign issues with Android 4.x. In particular, there were many issues with drawing corners. Unfortunately, there's no pretty way to get masking working on every Android version, so we have to switch back to using custom backgrounds and then using multiple masking methods depending on Android version. Also, I had to remove attr references in drawables. They crash on 4.x. --- ...ground.xml => compose_background_dark.xml} | 4 +- res/drawable/compose_background_light.xml | 16 ++ ...ssage_bubble_background_received_alone.xml | 13 + ...message_bubble_background_received_end.xml | 17 ++ ...sage_bubble_background_received_middle.xml | 17 ++ ...ssage_bubble_background_received_start.xml | 17 ++ .../message_bubble_background_sent_alone.xml | 13 + .../message_bubble_background_sent_end.xml | 17 ++ .../message_bubble_background_sent_middle.xml | 17 ++ .../message_bubble_background_sent_start.xml | 17 ++ ...=> sticky_date_header_background_dark.xml} | 2 +- .../sticky_date_header_background_light.xml | 8 + res/layout/conversation_fragment.xml | 2 +- res/layout/conversation_input_panel.xml | 2 +- res/layout/conversation_item_received.xml | 27 +- res/layout/conversation_item_sent.xml | 190 +++++++------- res/layout/quote_view.xml | 239 +++++++++--------- res/values/attrs.xml | 5 +- res/values/themes.xml | 10 +- .../securesms/ConversationItem.java | 105 ++++---- .../components/ConversationItemThumbnail.java | 12 + .../securesms/components/CornerMask.java | 88 +++++++ .../securesms/components/QuoteView.java | 72 ++++-- .../components/SharedContactView.java | 43 ++++ .../thoughtcrime/securesms/util/ViewUtil.java | 1 + 25 files changed, 614 insertions(+), 340 deletions(-) rename res/drawable/{compose_background.xml => compose_background_dark.xml} (64%) create mode 100644 res/drawable/compose_background_light.xml create mode 100644 res/drawable/message_bubble_background_received_alone.xml create mode 100644 res/drawable/message_bubble_background_received_end.xml create mode 100644 res/drawable/message_bubble_background_received_middle.xml create mode 100644 res/drawable/message_bubble_background_received_start.xml create mode 100644 res/drawable/message_bubble_background_sent_alone.xml create mode 100644 res/drawable/message_bubble_background_sent_end.xml create mode 100644 res/drawable/message_bubble_background_sent_middle.xml create mode 100644 res/drawable/message_bubble_background_sent_start.xml rename res/drawable/{sticky_date_header_background.xml => sticky_date_header_background_dark.xml} (69%) create mode 100644 res/drawable/sticky_date_header_background_light.xml create mode 100644 src/org/thoughtcrime/securesms/components/CornerMask.java diff --git a/res/drawable/compose_background.xml b/res/drawable/compose_background_dark.xml similarity index 64% rename from res/drawable/compose_background.xml rename to res/drawable/compose_background_dark.xml index 18b651b7f8..c04badbf74 100644 --- a/res/drawable/compose_background.xml +++ b/res/drawable/compose_background_dark.xml @@ -5,10 +5,10 @@ + android:color="@color/core_dark_70" /> + android:color="@color/core_dark_85" /> diff --git a/res/drawable/compose_background_light.xml b/res/drawable/compose_background_light.xml new file mode 100644 index 0000000000..b93c9edb7b --- /dev/null +++ b/res/drawable/compose_background_light.xml @@ -0,0 +1,16 @@ + + + + + + + + + + \ No newline at end of file diff --git a/res/drawable/message_bubble_background_received_alone.xml b/res/drawable/message_bubble_background_received_alone.xml new file mode 100644 index 0000000000..cda641b1da --- /dev/null +++ b/res/drawable/message_bubble_background_received_alone.xml @@ -0,0 +1,13 @@ + + + + + + + + + + diff --git a/res/drawable/message_bubble_background_received_end.xml b/res/drawable/message_bubble_background_received_end.xml new file mode 100644 index 0000000000..3e4e2c0562 --- /dev/null +++ b/res/drawable/message_bubble_background_received_end.xml @@ -0,0 +1,17 @@ + + + + + + + + + + diff --git a/res/drawable/message_bubble_background_received_middle.xml b/res/drawable/message_bubble_background_received_middle.xml new file mode 100644 index 0000000000..e3888978ab --- /dev/null +++ b/res/drawable/message_bubble_background_received_middle.xml @@ -0,0 +1,17 @@ + + + + + + + + + + diff --git a/res/drawable/message_bubble_background_received_start.xml b/res/drawable/message_bubble_background_received_start.xml new file mode 100644 index 0000000000..4c30cc7565 --- /dev/null +++ b/res/drawable/message_bubble_background_received_start.xml @@ -0,0 +1,17 @@ + + + + + + + + + + diff --git a/res/drawable/message_bubble_background_sent_alone.xml b/res/drawable/message_bubble_background_sent_alone.xml new file mode 100644 index 0000000000..6f19f4f16f --- /dev/null +++ b/res/drawable/message_bubble_background_sent_alone.xml @@ -0,0 +1,13 @@ + + + + + + + + + + \ No newline at end of file diff --git a/res/drawable/message_bubble_background_sent_end.xml b/res/drawable/message_bubble_background_sent_end.xml new file mode 100644 index 0000000000..5bc4597c03 --- /dev/null +++ b/res/drawable/message_bubble_background_sent_end.xml @@ -0,0 +1,17 @@ + + + + + + + + + + \ No newline at end of file diff --git a/res/drawable/message_bubble_background_sent_middle.xml b/res/drawable/message_bubble_background_sent_middle.xml new file mode 100644 index 0000000000..aea4264539 --- /dev/null +++ b/res/drawable/message_bubble_background_sent_middle.xml @@ -0,0 +1,17 @@ + + + + + + + + + + diff --git a/res/drawable/message_bubble_background_sent_start.xml b/res/drawable/message_bubble_background_sent_start.xml new file mode 100644 index 0000000000..4719d235f4 --- /dev/null +++ b/res/drawable/message_bubble_background_sent_start.xml @@ -0,0 +1,17 @@ + + + + + + + + + + diff --git a/res/drawable/sticky_date_header_background.xml b/res/drawable/sticky_date_header_background_dark.xml similarity index 69% rename from res/drawable/sticky_date_header_background.xml rename to res/drawable/sticky_date_header_background_dark.xml index e4fa232676..d5be2c288c 100644 --- a/res/drawable/sticky_date_header_background.xml +++ b/res/drawable/sticky_date_header_background_dark.xml @@ -4,5 +4,5 @@ android:shape="rectangle"> - + \ No newline at end of file diff --git a/res/drawable/sticky_date_header_background_light.xml b/res/drawable/sticky_date_header_background_light.xml new file mode 100644 index 0000000000..b015b381ba --- /dev/null +++ b/res/drawable/sticky_date_header_background_light.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/res/layout/conversation_fragment.xml b/res/layout/conversation_fragment.xml index 41eac4b702..ab905ae024 100644 --- a/res/layout/conversation_fragment.xml +++ b/res/layout/conversation_fragment.xml @@ -28,7 +28,7 @@ style="@style/Signal.Text.Caption" android:textColor="?attr/conversation_item_sticky_date_text_color" android:textAllCaps="true" - android:background="@drawable/sticky_date_header_background" + android:background="?attr/conversation_item_sticky_date_background" android:elevation="9dp" android:visibility="gone" tools:text="March 1, 2015" /> diff --git a/res/layout/conversation_input_panel.xml b/res/layout/conversation_input_panel.xml index 70e43f2207..c06879dc34 100644 --- a/res/layout/conversation_input_panel.xml +++ b/res/layout/conversation_input_panel.xml @@ -27,7 +27,7 @@ android:id="@+id/compose_bubble" android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="@drawable/compose_background" + android:background="?attr/conversation_input_background" android:clipChildren="false" android:clipToPadding="false" android:orientation="vertical"> diff --git a/res/layout/conversation_item_received.xml b/res/layout/conversation_item_received.xml index 91870ed9aa..d5eee08bb9 100644 --- a/res/layout/conversation_item_received.xml +++ b/res/layout/conversation_item_received.xml @@ -20,6 +20,8 @@ android:layout_height="wrap_content" android:layout_marginRight="@dimen/conversation_individual_right_gutter" android:layout_marginEnd="@dimen/conversation_individual_right_gutter" + android:paddingLeft="8dp" + android:paddingStart="8dp" android:clipToPadding="false" android:clipChildren="false"> @@ -28,31 +30,28 @@ android:foreground="@drawable/contact_photo_background" android:layout_width="36dp" android:layout_height="36dp" - android:layout_marginLeft="8dp" - android:layout_marginRight="8dp" android:layout_marginBottom="6dp" android:layout_alignParentLeft="true" + android:layout_alignParentStart="true" android:layout_alignParentBottom="true" android:cropToPadding="true" android:contentDescription="@string/conversation_item_received__contact_photo_description" /> - - - + android:clipChildren="false" + android:background="@color/white" + tools:backgroundTint="@color/conversation_blue"> - - - + - - + + + + + + + + + + + + + + + + + + + app:footer_color="?conversation_item_sent_text_secondary_color"/> - - - - - - - - - - - - - - - - - - - - - - - + - + android:layout_height="wrap_content" + android:orientation="horizontal"> + + + android:layout_marginLeft="8dp" + android:layout_marginStart="8dp" + android:layout_marginRight="8dp" + android:layout_marginEnd="8dp" + android:layout_marginTop="8dp" + android:layout_marginBottom="8dp" + android:orientation="vertical" + android:layout_weight="1"> - + + android:layout_marginBottom="2dp" + android:orientation="horizontal" + android:gravity="center_vertical" + android:visibility="gone" + tools:visibility="visible"> - - - - - - - - - + - - - + tools:text="The-Amazing-Spider-Man.cba" /> - - - + android:layout_height="wrap_content" + android:layout_marginRight="8dp" + style="@style/Signal.Text.Caption" + android:textColor="@color/core_light_90" + android:paddingTop="4dp" + android:textStyle="italic" + android:visibility="gone" + tools:text="Photo" + tools:visibility="visible" /> - + - - - - - - + android:layout_height="match_parent"> - + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/values/attrs.xml b/res/values/attrs.xml index 0b6db57e42..0390480837 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -28,8 +28,7 @@ - - + @@ -77,7 +76,7 @@ - + diff --git a/res/values/themes.xml b/res/values/themes.xml index 95936da31d..c35309cc06 100644 --- a/res/values/themes.xml +++ b/res/values/themes.xml @@ -146,8 +146,7 @@ @color/core_white #22000000 #ff111111 - @color/core_light_02 - @color/core_light_10 + @drawable/compose_background_light @drawable/ic_send_sms_insecure @drawable/ic_send_push @color/white @@ -195,7 +194,7 @@ @color/core_light_60 @color/core_light_45 @color/core_light_90 - @color/core_light_02 + @drawable/sticky_date_header_background_light @color/core_light_60 @color/core_light_45 @@ -295,7 +294,7 @@ @color/core_dark_30 @color/core_dark_55 @color/core_dark_05 - @color/core_dark_85 + @drawable/sticky_date_header_background_dark @color/core_dark_30 @color/core_dark_60 @@ -319,8 +318,7 @@ @color/black #22ffffff #ffeeeeee - @color/core_dark_85 - @color/core_dark_70 + @drawable/compose_background_dark @drawable/ic_send_sms_insecure_dark @drawable/ic_send_push @color/black diff --git a/src/org/thoughtcrime/securesms/ConversationItem.java b/src/org/thoughtcrime/securesms/ConversationItem.java index 5cad022cfa..b6797811a8 100644 --- a/src/org/thoughtcrime/securesms/ConversationItem.java +++ b/src/org/thoughtcrime/securesms/ConversationItem.java @@ -110,16 +110,16 @@ public class ConversationItem extends LinearLayout private Recipient recipient; private GlideRequests glideRequests; - protected CornerMaskingView bodyBubble; - private QuoteView quoteView; - private TextView bodyText; - private ConversationItemFooter footer; - private TextView groupSender; - private TextView groupSenderProfileName; - private View groupSenderHolder; - private AvatarImageView contactPhoto; - private AlertView alertView; - private ViewGroup container; + protected ViewGroup bodyBubble; + private QuoteView quoteView; + private TextView bodyText; + private ConversationItemFooter footer; + private TextView groupSender; + private TextView groupSenderProfileName; + private View groupSenderHolder; + private AvatarImageView contactPhoto; + private AlertView alertView; + private ViewGroup container; private @NonNull Set batchSelected = new HashSet<>(); private @NonNull Recipient conversationRecipient; @@ -203,7 +203,9 @@ public class ConversationItem extends LinearLayout this.recipient.addListener(this); this.conversationRecipient.addListener(this); - setMediaAttributes(messageRecord, nextMessageRecord, previousMessageRecord, conversationRecipient, groupThread); + setGutterSizes(messageRecord, groupThread); + setMessageShape(messageRecord, previousMessageRecord, nextMessageRecord, groupThread); + setMediaAttributes(messageRecord, previousMessageRecord, nextMessageRecord, conversationRecipient, groupThread); setInteractionState(messageRecord, pulseHighlight); setBodyText(messageRecord); setBubbleState(messageRecord); @@ -213,9 +215,7 @@ public class ConversationItem extends LinearLayout setAuthor(messageRecord, previousMessageRecord, nextMessageRecord, groupThread); setQuote(messageRecord, previousMessageRecord, nextMessageRecord, groupThread); setMessageSpacing(context, messageRecord, nextMessageRecord); - setGutterSizes(messageRecord, groupThread); setFooter(messageRecord, nextMessageRecord, locale, groupThread); - setMessageShape(messageRecord, previousMessageRecord, nextMessageRecord, groupThread); } @Override @@ -414,6 +414,8 @@ public class ConversationItem extends LinearLayout sharedContactStub.get().setOnClickListener(sharedContactClickListener); sharedContactStub.get().setOnLongClickListener(passthroughClickListener); + setSharedContactCorners(messageRecord, previousRecord, nextRecord, isGroupThread); + ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); footer.setVisibility(GONE); } else if (hasAudio(messageRecord)) { @@ -464,7 +466,7 @@ public class ConversationItem extends LinearLayout mediaThumbnailStub.get().setOnClickListener(passthroughClickListener); mediaThumbnailStub.get().showShade(TextUtils.isEmpty(messageRecord.getDisplayBody())); - setThumbnailOutlineCorners(messageRecord, nextRecord, previousRecord, isGroupThread); + setThumbnailOutlineCorners(messageRecord, previousRecord, nextRecord, isGroupThread); ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); footer.setVisibility(VISIBLE); @@ -537,6 +539,18 @@ public class ConversationItem extends LinearLayout mediaThumbnailStub.get().setOutlineCorners(topLeft, topRight, bottomRight, bottomLeft); } + private void setSharedContactCorners(@NonNull MessageRecord current, @NonNull Optional previous, @NonNull Optional next, boolean isGroupThread) { + if (isSingularMessage(current, previous, next, isGroupThread) || isEndOfMessageCluster(current, next, isGroupThread)) { + sharedContactStub.get().setSingularStyle(); + } else { + if (current.isOutgoing()) { + sharedContactStub.get().setClusteredOutgoingStyle(); + } else { + sharedContactStub.get().setClusteredIncomingStyle(); + } + } + } + private void setContactPhoto(@NonNull Recipient recipient) { if (contactPhoto == null) return; @@ -621,18 +635,10 @@ public class ConversationItem extends LinearLayout } private void setGutterSizes(@NonNull MessageRecord current, boolean isGroupThread) { - if (isGroupThread) { - if (current.isOutgoing()) { - ViewUtil.setLeftMargin(container, readDimen(R.dimen.conversation_group_left_gutter)); - } else { - ViewUtil.setLeftMargin(bodyBubble, readDimen(R.dimen.conversation_group_left_gutter)); - } - } else { - if (current.isOutgoing()) { - ViewUtil.setLeftMargin(container, readDimen(R.dimen.conversation_individual_left_gutter)); - } else { - ViewUtil.setLeftMargin(bodyBubble, readDimen(R.dimen.conversation_individual_left_gutter)); - } + if (isGroupThread && current.isOutgoing()) { + ViewUtil.setLeftMargin(container, readDimen(R.dimen.conversation_group_left_gutter)); + } else if (current.isOutgoing()) { + ViewUtil.setLeftMargin(container, readDimen(R.dimen.conversation_individual_left_gutter)); } } @@ -698,7 +704,7 @@ public class ConversationItem extends LinearLayout if (!next.isPresent() || next.get().isUpdate() || !current.getRecipient().getAddress().equals(next.get().getRecipient().getAddress())) { contactPhoto.setVisibility(VISIBLE); } else { - contactPhoto.setVisibility(GONE); + contactPhoto.setVisibility(INVISIBLE); } } else { groupSenderHolder.setVisibility(GONE); @@ -710,45 +716,22 @@ public class ConversationItem extends LinearLayout } private void setMessageShape(@NonNull MessageRecord current, @NonNull Optional previous, @NonNull Optional next, boolean isGroupThread) { + int background; if (isSingularMessage(current, previous, next, isGroupThread)) { - bodyBubble.setRadius(readDimen(R.dimen.message_corner_radius)); + background = current.isOutgoing() ? R.drawable.message_bubble_background_sent_alone + : R.drawable.message_bubble_background_received_alone; } else if (isStartOfMessageCluster(current, previous, isGroupThread)) { - if (current.isOutgoing()) { - bodyBubble.setRadii(readDimen(R.dimen.message_corner_radius), - readDimen(R.dimen.message_corner_radius), - readDimen(R.dimen.message_corner_collapse_radius), - readDimen(R.dimen.message_corner_radius)); - } else { - bodyBubble.setRadii(readDimen(R.dimen.message_corner_radius), - readDimen(R.dimen.message_corner_radius), - readDimen(R.dimen.message_corner_radius), - readDimen(R.dimen.message_corner_collapse_radius)); - } + background = current.isOutgoing() ? R.drawable.message_bubble_background_sent_start + : R.drawable.message_bubble_background_received_start; } else if (isEndOfMessageCluster(current, next, isGroupThread)) { - if (current.isOutgoing()) { - bodyBubble.setRadii(readDimen(R.dimen.message_corner_radius), - readDimen(R.dimen.message_corner_collapse_radius), - readDimen(R.dimen.message_corner_radius), - readDimen(R.dimen.message_corner_radius)); - } else { - bodyBubble.setRadii(readDimen(R.dimen.message_corner_collapse_radius), - readDimen(R.dimen.message_corner_radius), - readDimen(R.dimen.message_corner_radius), - readDimen(R.dimen.message_corner_radius)); - } + background = current.isOutgoing() ? R.drawable.message_bubble_background_sent_end + : R.drawable.message_bubble_background_received_end; } else { - if (current.isOutgoing()) { - bodyBubble.setRadii(readDimen(R.dimen.message_corner_radius), - readDimen(R.dimen.message_corner_collapse_radius), - readDimen(R.dimen.message_corner_collapse_radius), - readDimen(R.dimen.message_corner_radius)); - } else { - bodyBubble.setRadii(readDimen(R.dimen.message_corner_collapse_radius), - readDimen(R.dimen.message_corner_radius), - readDimen(R.dimen.message_corner_radius), - readDimen(R.dimen.message_corner_collapse_radius)); - } + background = current.isOutgoing() ? R.drawable.message_bubble_background_sent_middle + : R.drawable.message_bubble_background_received_middle; } + + bodyBubble.setBackgroundResource(background); } private boolean isStartOfMessageCluster(@NonNull MessageRecord current, @NonNull Optional previous, boolean isGroupThread) { diff --git a/src/org/thoughtcrime/securesms/components/ConversationItemThumbnail.java b/src/org/thoughtcrime/securesms/components/ConversationItemThumbnail.java index 83148e460f..4d4356f908 100644 --- a/src/org/thoughtcrime/securesms/components/ConversationItemThumbnail.java +++ b/src/org/thoughtcrime/securesms/components/ConversationItemThumbnail.java @@ -48,6 +48,7 @@ public class ConversationItemThumbnail extends FrameLayout { private ImageView shade; private ConversationItemFooter footer; private Paint outlinePaint; + private CornerMask cornerMask; public ConversationItemThumbnail(Context context) { super(context); @@ -71,6 +72,7 @@ public class ConversationItemThumbnail extends FrameLayout { this.shade = findViewById(R.id.conversation_thumbnail_shade); this.footer = findViewById(R.id.conversation_thumbnail_footer); this.outlinePaint = ThemeUtil.isDarkTheme(getContext()) ? DARK_THEME_OUTLINE_PAINT : LIGHT_THEME_OUTLINE_PAINT; + this.cornerMask = new CornerMask(this); setTouchDelegate(thumbnail.getTouchDelegate()); @@ -87,8 +89,16 @@ public class ConversationItemThumbnail extends FrameLayout { @SuppressWarnings("SuspiciousNameCombination") @Override protected void dispatchDraw(Canvas canvas) { + if (cornerMask.isLegacy()) { + cornerMask.mask(canvas); + } + super.dispatchDraw(canvas); + if (!cornerMask.isLegacy()) { + cornerMask.mask(canvas); + } + final float halfStrokeWidth = outlinePaint.getStrokeWidth() / 2; bounds.left = halfStrokeWidth; @@ -137,6 +147,8 @@ public class ConversationItemThumbnail extends FrameLayout { radii[2] = radii[3] = topRight; radii[4] = radii[5] = bottomRight; radii[6] = radii[7] = bottomLeft; + + cornerMask.setRadii(topLeft, topRight, bottomRight, bottomLeft); } public ConversationItemFooter getFooter() { diff --git a/src/org/thoughtcrime/securesms/components/CornerMask.java b/src/org/thoughtcrime/securesms/components/CornerMask.java new file mode 100644 index 0000000000..085df25574 --- /dev/null +++ b/src/org/thoughtcrime/securesms/components/CornerMask.java @@ -0,0 +1,88 @@ +package org.thoughtcrime.securesms.components; + +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.RectF; +import android.os.Build; +import android.support.annotation.NonNull; +import android.view.View; + +public class CornerMask { + + private final float[] radii = new float[8]; + private final Paint clearPaint = new Paint(); + private final Path outline = new Path(); + private final Path corners = new Path(); + private final RectF bounds = new RectF(); + + public CornerMask(@NonNull View view) { + if (isLegacy()) { + view.setLayerType(View.LAYER_TYPE_SOFTWARE, null); + } else { + view.setLayerType(View.LAYER_TYPE_HARDWARE, null); + } + + clearPaint.setColor(Color.BLACK); + clearPaint.setStyle(Paint.Style.FILL); + clearPaint.setAntiAlias(true); + clearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); + } + + public void mask(Canvas canvas) { + bounds.left = 0; + bounds.top = 0; + bounds.right = canvas.getWidth(); + bounds.bottom = canvas.getHeight(); + + corners.reset(); + corners.addRoundRect(bounds, radii, Path.Direction.CW); + + // Note: There's a bug in the P beta where most PorterDuff modes aren't working. But CLEAR does. + // So we find and inverse path and use Mode.CLEAR for versions that support Path.op(). + // See issue https://issuetracker.google.com/issues/111394085. + if (!isLegacy()) { + outline.reset(); + outline.addRect(bounds, Path.Direction.CW); + outline.op(corners, Path.Op.DIFFERENCE); + canvas.drawPath(outline, clearPaint); + } else { + corners.addRoundRect(bounds, radii, Path.Direction.CW); + canvas.clipPath(corners); + } + } + + public boolean isLegacy() { + return Build.VERSION.SDK_INT < 19; + } + + public void setRadius(int radius) { + setRadii(radius, radius, radius, radius); + } + + public void setRadii(int topLeft, int topRight, int bottomRight, int bottomLeft) { + radii[0] = radii[1] = topLeft; + radii[2] = radii[3] = topRight; + radii[4] = radii[5] = bottomRight; + radii[6] = radii[7] = bottomLeft; + } + + public void setTopLeftRadius(int radius) { + radii[0] = radii[1] = radius; + } + + public void setTopRightRadius(int radius) { + radii[2] = radii[3] = radius; + } + + public void setBottomRightRadius(int radius) { + radii[4] = radii[5] = radius; + } + + public void setBottomLeftRadius(int radius) { + radii[6] = radii[7] = radius; + } +} diff --git a/src/org/thoughtcrime/securesms/components/QuoteView.java b/src/org/thoughtcrime/securesms/components/QuoteView.java index c2dbcbc995..8222c1062a 100644 --- a/src/org/thoughtcrime/securesms/components/QuoteView.java +++ b/src/org/thoughtcrime/securesms/components/QuoteView.java @@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.components; import android.content.Context; import android.content.res.TypedArray; +import android.graphics.Canvas; import android.graphics.Color; import android.os.Build; import android.support.annotation.NonNull; @@ -40,25 +41,25 @@ public class QuoteView extends LinearLayout implements RecipientModifiedListener private static final int MESSAGE_TYPE_OUTGOING = 1; private static final int MESSAGE_TYPE_INCOMING = 2; - private CornerMaskingView rootView; - private View backgroundView; - private TextView authorView; - private TextView bodyView; - private ImageView quoteBarView; - private ImageView thumbnailView; - private View attachmentVideoOverlayView; - private ViewGroup attachmentContainerView; - private TextView attachmentNameView; - private ImageView dismissView; + private ViewGroup rootView; + private TextView authorView; + private TextView bodyView; + private ImageView quoteBarView; + private ImageView thumbnailView; + private View attachmentVideoOverlayView; + private ViewGroup attachmentContainerView; + private TextView attachmentNameView; + private ImageView dismissView; - private long id; - private Recipient author; - private String body; - private TextView mediaDescriptionText; - private SlideDeck attachments; - private int messageType; - private int largeCornerRadius; - private int smallCornerRadius; + private long id; + private Recipient author; + private String body; + private TextView mediaDescriptionText; + private SlideDeck attachments; + private int messageType; + private int largeCornerRadius; + private int smallCornerRadius; + private CornerMask cornerMask; public QuoteView(Context context) { @@ -86,7 +87,6 @@ public class QuoteView extends LinearLayout implements RecipientModifiedListener inflate(getContext(), R.layout.quote_view, this); this.rootView = findViewById(R.id.quote_root); - this.backgroundView = findViewById(R.id.quote_background); this.authorView = findViewById(R.id.quote_author); this.bodyView = findViewById(R.id.quote_text); this.quoteBarView = findViewById(R.id.quote_bar); @@ -99,7 +99,8 @@ public class QuoteView extends LinearLayout implements RecipientModifiedListener this.largeCornerRadius = getResources().getDimensionPixelSize(R.dimen.quote_corner_radius_large); this.smallCornerRadius = getResources().getDimensionPixelSize(R.dimen.quote_corner_radius_bottom); - rootView.setRadii(largeCornerRadius, largeCornerRadius, smallCornerRadius, smallCornerRadius); + cornerMask = new CornerMask(this); + cornerMask.setRadii(largeCornerRadius, largeCornerRadius, smallCornerRadius, smallCornerRadius); if (attrs != null) { TypedArray typedArray = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.QuoteView, 0, 0); @@ -117,16 +118,31 @@ public class QuoteView extends LinearLayout implements RecipientModifiedListener if (messageType == MESSAGE_TYPE_PREVIEW) { int radius = getResources().getDimensionPixelOffset(R.dimen.quote_corner_radius_preview); - rootView.setTopLeftRadius(radius); - rootView.setTopRightRadius(radius); + cornerMask.setTopLeftRadius(radius); + cornerMask.setTopRightRadius(radius); } } dismissView.setOnClickListener(view -> setVisibility(GONE)); - setWillNotDraw(false); - if (Build.VERSION.SDK_INT < 18) { - setLayerType(View.LAYER_TYPE_SOFTWARE, null); + if (cornerMask.isLegacy()) { + setWillNotDraw(false); + } + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + if (cornerMask.isLegacy()) { + cornerMask.mask(canvas); + } + } + + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + if (!cornerMask.isLegacy()) { + cornerMask.mask(canvas); } } @@ -145,8 +161,8 @@ public class QuoteView extends LinearLayout implements RecipientModifiedListener } public void setTopCornerSizes(boolean topLeftLarge, boolean topRightLarge) { - rootView.setTopLeftRadius(topLeftLarge ? largeCornerRadius : smallCornerRadius); - rootView.setTopRightRadius(topRightLarge ? largeCornerRadius : smallCornerRadius); + cornerMask.setTopLeftRadius(topLeftLarge ? largeCornerRadius : smallCornerRadius); + cornerMask.setTopRightRadius(topRightLarge ? largeCornerRadius : smallCornerRadius); } public void dismiss() { @@ -177,7 +193,7 @@ public class QuoteView extends LinearLayout implements RecipientModifiedListener // We use the raw color resource because Android 4.x was struggling with tints here quoteBarView.setImageResource(author.getColor().toQuoteBarColorResource(getContext(), outgoing)); - backgroundView.setBackgroundColor(author.getColor().toQuoteBackgroundColor(getContext(), outgoing)); + rootView.setBackgroundColor(author.getColor().toQuoteBackgroundColor(getContext(), outgoing)); } private void setQuoteText(@Nullable String body, @NonNull SlideDeck attachments) { diff --git a/src/org/thoughtcrime/securesms/components/SharedContactView.java b/src/org/thoughtcrime/securesms/components/SharedContactView.java index 30af4c725c..94435e2405 100644 --- a/src/org/thoughtcrime/securesms/components/SharedContactView.java +++ b/src/org/thoughtcrime/securesms/components/SharedContactView.java @@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.components; import android.content.Context; import android.content.res.TypedArray; +import android.graphics.Canvas; import android.graphics.Color; import android.net.Uri; import android.os.Build; @@ -46,6 +47,9 @@ public class SharedContactView extends LinearLayout implements RecipientModified private Locale locale; private GlideRequests glideRequests; private EventListener eventListener; + private CornerMask cornerMask; + private int bigCornerRadius; + private int smallCornerRadius; private final Map activeRecipients = new HashMap<>(); @@ -79,6 +83,10 @@ public class SharedContactView extends LinearLayout implements RecipientModified actionButtonView = findViewById(R.id.contact_action_button); footer = findViewById(R.id.contact_footer); + cornerMask = new CornerMask(this); + bigCornerRadius = getResources().getDimensionPixelOffset(R.dimen.message_corner_radius); + smallCornerRadius = getResources().getDimensionPixelOffset(R.dimen.message_corner_collapse_radius); + if (attrs != null) { TypedArray typedArray = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.SharedContactView, 0, 0); int titleColor = typedArray.getInt(R.styleable.SharedContactView_contact_titleColor, Color.BLACK); @@ -89,6 +97,26 @@ public class SharedContactView extends LinearLayout implements RecipientModified numberView.setTextColor(captionColor); footer.setColor(captionColor); } + + if (cornerMask.isLegacy()) { + setWillNotDraw(false); + } + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + if (cornerMask.isLegacy()) { + cornerMask.mask(canvas); + } + } + + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + if (!cornerMask.isLegacy()) { + cornerMask.mask(canvas); + } } public void setContact(@NonNull Contact contact, @NonNull GlideRequests glideRequests, @NonNull Locale locale) { @@ -104,6 +132,21 @@ public class SharedContactView extends LinearLayout implements RecipientModified presentActionButtons(ContactUtil.getRecipients(getContext(), contact)); } + public void setSingularStyle() { + cornerMask.setBottomLeftRadius(bigCornerRadius); + cornerMask.setBottomRightRadius(bigCornerRadius); + } + + public void setClusteredIncomingStyle() { + cornerMask.setBottomLeftRadius(smallCornerRadius); + cornerMask.setBottomRightRadius(bigCornerRadius); + } + + public void setClusteredOutgoingStyle() { + cornerMask.setBottomLeftRadius(bigCornerRadius); + cornerMask.setBottomRightRadius(smallCornerRadius); + } + public void setEventListener(@NonNull EventListener eventListener) { this.eventListener = eventListener; } diff --git a/src/org/thoughtcrime/securesms/util/ViewUtil.java b/src/org/thoughtcrime/securesms/util/ViewUtil.java index b52cd6b192..8f606103c3 100644 --- a/src/org/thoughtcrime/securesms/util/ViewUtil.java +++ b/src/org/thoughtcrime/securesms/util/ViewUtil.java @@ -224,6 +224,7 @@ public class ViewUtil { } else { ((ViewGroup.MarginLayoutParams) view.getLayoutParams()).rightMargin = margin; } + view.forceLayout(); view.requestLayout(); }