diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/InputPanel.java b/app/src/main/java/org/thoughtcrime/securesms/components/InputPanel.java index c8dc12d63..dfcd561c6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/InputPanel.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/InputPanel.java @@ -164,10 +164,9 @@ public class InputPanel extends LinearLayout long id, @NonNull Recipient author, @NonNull CharSequence body, - @NonNull SlideDeck attachments, - @NonNull Colorizer colorizer) + @NonNull SlideDeck attachments) { - this.quoteView.setQuote(glideRequests, id, author, body, false, attachments, colorizer); + this.quoteView.setQuote(glideRequests, id, author, body, false, attachments, null); int originalHeight = this.quoteView.getVisibility() == VISIBLE ? this.quoteView.getMeasuredHeight() : 0; diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/QuoteView.java b/app/src/main/java/org/thoughtcrime/securesms/components/QuoteView.java index b0cbab614..a0e9f726f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/QuoteView.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/QuoteView.java @@ -26,7 +26,7 @@ import org.signal.core.util.logging.Log; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.attachments.Attachment; import org.thoughtcrime.securesms.components.mention.MentionAnnotation; -import org.thoughtcrime.securesms.conversation.colors.Colorizer; +import org.thoughtcrime.securesms.conversation.colors.ChatColors; import org.thoughtcrime.securesms.database.model.Mention; import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri; import org.thoughtcrime.securesms.mms.GlideRequests; @@ -69,7 +69,6 @@ public class QuoteView extends FrameLayout implements RecipientForeverObserver { private int largeCornerRadius; private int smallCornerRadius; private CornerMask cornerMask; - private Colorizer colorizer; public QuoteView(Context context) { @@ -157,7 +156,7 @@ public class QuoteView extends FrameLayout implements RecipientForeverObserver { @Nullable CharSequence body, boolean originalMissing, @NonNull SlideDeck attachments, - @NonNull Colorizer colorizer) + @Nullable ChatColors chatColors) { if (this.author != null) this.author.removeForeverObserver(this); @@ -165,13 +164,18 @@ public class QuoteView extends FrameLayout implements RecipientForeverObserver { this.author = author.live(); this.body = body; this.attachments = attachments; - this.colorizer = colorizer; this.author.observeForever(this); setQuoteAuthor(author); setQuoteText(body, attachments); setQuoteAttachment(glideRequests, attachments); setQuoteMissingFooter(originalMissing); + + if (Build.VERSION.SDK_INT < 21 && messageType == MESSAGE_TYPE_INCOMING && chatColors != null) { + this.setBackgroundColor(chatColors.asSingleColor()); + } else { + this.setBackground(null); + } } public void setTopCornerSizes(boolean topLeftLarge, boolean topRightLarge) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java index 5733e937c..0b43c8035 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java @@ -3506,8 +3506,7 @@ public class ConversationActivity extends PassphraseRequiredActivity messageRecord.getDateSent(), author, body, - slideDeck, - fragment.getColorizer()); + slideDeck); } else if (messageRecord.isMms() && !((MmsMessageRecord) messageRecord).getLinkPreviews().isEmpty()) { LinkPreview linkPreview = ((MmsMessageRecord) messageRecord).getLinkPreviews().get(0); @@ -3521,8 +3520,7 @@ public class ConversationActivity extends PassphraseRequiredActivity messageRecord.getDateSent(), author, conversationMessage.getDisplayBody(this), - slideDeck, - fragment.getColorizer()); + slideDeck); } else { SlideDeck slideDeck = messageRecord.isMms() ? ((MmsMessageRecord) messageRecord).getSlideDeck() : new SlideDeck(); @@ -3536,8 +3534,7 @@ public class ConversationActivity extends PassphraseRequiredActivity messageRecord.getDateSent(), author, conversationMessage.getDisplayBody(this), - slideDeck, - fragment.getColorizer()); + slideDeck); } inputPanel.clickOnComposeInput(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java index b81af5cb2..3c34e2885 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java @@ -80,6 +80,7 @@ import org.thoughtcrime.securesms.components.SharedContactView; import org.thoughtcrime.securesms.components.emoji.EmojiTextView; import org.thoughtcrime.securesms.components.mention.MentionAnnotation; import org.thoughtcrime.securesms.contactshare.Contact; +import org.thoughtcrime.securesms.conversation.colors.ChatColors; import org.thoughtcrime.securesms.conversation.colors.Colorizer; import org.thoughtcrime.securesms.database.AttachmentDatabase; import org.thoughtcrime.securesms.database.DatabaseFactory; @@ -316,7 +317,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo setGroupMessageStatus(messageRecord, recipient.get()); setGroupAuthorColor(messageRecord, hasWallpaper, colorizer); setAuthor(messageRecord, previousMessageRecord, nextMessageRecord, groupThread, hasWallpaper); - setQuote(messageRecord, previousMessageRecord, nextMessageRecord, groupThread, colorizer); + setQuote(messageRecord, previousMessageRecord, nextMessageRecord, groupThread, messageRecord.getRecipient().getChatColors()); setMessageSpacing(context, messageRecord, previousMessageRecord, nextMessageRecord, groupThread); setReactions(messageRecord); setFooter(messageRecord, nextMessageRecord, locale, groupThread, hasWallpaper); @@ -1095,14 +1096,14 @@ public final class ConversationItem extends RelativeLayout implements BindableCo } } - private void setQuote(@NonNull MessageRecord current, @NonNull Optional previous, @NonNull Optional next, boolean isGroupThread, @NonNull Colorizer colorizer) { + private void setQuote(@NonNull MessageRecord current, @NonNull Optional previous, @NonNull Optional next, boolean isGroupThread, @NonNull ChatColors chatColors) { if (current.isMms() && !current.isMmsNotification() && ((MediaMmsMessageRecord)current).getQuote() != null) { if (quoteView == null) { throw new AssertionError(); } Quote quote = ((MediaMmsMessageRecord)current).getQuote(); //noinspection ConstantConditions - quoteView.setQuote(glideRequests, quote.getId(), Recipient.live(quote.getAuthor()).get(), quote.getDisplayText(), quote.isOriginalMissing(), quote.getAttachment(), colorizer); + quoteView.setQuote(glideRequests, quote.getId(), Recipient.live(quote.getAuthor()).get(), quote.getDisplayText(), quote.isOriginalMissing(), quote.getAttachment(), chatColors); quoteView.setVisibility(View.VISIBLE); quoteView.getLayoutParams().width = ViewGroup.LayoutParams.WRAP_CONTENT; diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/colors/ChatColors.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/colors/ChatColors.kt index 8cd6ac7d1..4bcb2d689 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/colors/ChatColors.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/colors/ChatColors.kt @@ -7,6 +7,9 @@ import android.graphics.PorterDuff import android.graphics.PorterDuffColorFilter import android.graphics.drawable.ColorDrawable import android.graphics.drawable.Drawable +import android.graphics.drawable.ShapeDrawable +import android.graphics.drawable.shapes.OvalShape +import android.os.Build import androidx.annotation.ColorInt import com.google.common.base.Objects import org.signal.core.util.ColorUtil @@ -32,18 +35,32 @@ class ChatColors private constructor( * Returns the Drawable to render the linear gradient, or null if this ChatColors is a single color. */ val chatBubbleMask: Drawable - get() = linearGradient?.let { - RotatableGradientDrawable( - it.degrees, - it.colors, - it.positions - ) - } ?: ColorDrawable(asSingleColor()) + get() { + return when { + Build.VERSION.SDK_INT < 21 -> { + ColorDrawable(Color.TRANSPARENT) + } + linearGradient != null -> { + RotatableGradientDrawable( + linearGradient.degrees, + linearGradient.colors, + linearGradient.positions + ) + } + else -> { + ColorDrawable(asSingleColor()) + } + } + } /** * Returns the ColorFilter to apply to a conversation bubble or other relevant piece of UI. */ - val chatBubbleColorFilter: ColorFilter = PorterDuffColorFilter(Color.TRANSPARENT, PorterDuff.Mode.SRC_IN) + val chatBubbleColorFilter: ColorFilter = if (Build.VERSION.SDK_INT >= 21) { + PorterDuffColorFilter(Color.TRANSPARENT, PorterDuff.Mode.SRC_IN) + } else { + PorterDuffColorFilter(asSingleColor(), PorterDuff.Mode.SRC_IN) + } @ColorInt fun asSingleColor(): Int { @@ -94,6 +111,12 @@ class ChatColors private constructor( } fun asCircle(): Drawable { + if (Build.VERSION.SDK_INT < 21) { + return ShapeDrawable(OvalShape()).apply { + paint.color = asSingleColor() + } + } + val toWrap: Drawable = chatBubbleMask val path = Path() diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/colors/Colorizer.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/colors/Colorizer.kt index d1ceeae6f..c3d531292 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/colors/Colorizer.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/colors/Colorizer.kt @@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.conversation.colors import android.content.Context import android.graphics.Color +import android.os.Build import android.view.View import androidx.annotation.ColorInt import androidx.core.content.ContextCompat @@ -64,6 +65,10 @@ class Colorizer(private val colorizerView: ColorizerView) : RecyclerView.OnScrol } fun applyClipPathsToMaskedGradient(recyclerView: RecyclerView) { + if (Build.VERSION.SDK_INT < 21) { + return + } + val layoutManager = recyclerView.layoutManager as LinearLayoutManager val firstVisibleItemPosition: Int = layoutManager.findFirstVisibleItemPosition() diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/colors/ui/ChatColorSelectionAdapter.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/colors/ui/ChatColorSelectionAdapter.kt index 5db8bdeeb..92f5366f2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/colors/ui/ChatColorSelectionAdapter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/colors/ui/ChatColorSelectionAdapter.kt @@ -1,7 +1,6 @@ package org.thoughtcrime.securesms.conversation.colors.ui import android.content.Context -import android.graphics.Path import android.view.View import android.widget.ImageView import android.widget.TextView @@ -9,7 +8,8 @@ import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.conversation.colors.ChatColors import org.thoughtcrime.securesms.util.MappingAdapter import org.thoughtcrime.securesms.util.MappingViewHolder -import org.thoughtcrime.securesms.util.customizeOnDraw +import org.thoughtcrime.securesms.util.ViewUtil +import org.thoughtcrime.securesms.util.withFixedSize class ChatColorSelectionAdapter( context: Context, @@ -81,24 +81,8 @@ class ChatColorSelectionAdapter( preview.isLongClickable = false } - val mask = model.chatColors.chatBubbleMask - preview.setImageDrawable( - mask.customizeOnDraw { wrapped, canvas -> - val circlePath = Path() - val bounds = canvas.clipBounds - circlePath.addCircle( - bounds.width() / 2f, - bounds.height() / 2f, - bounds.width() / 2f, - Path.Direction.CW - ) - - canvas.save() - canvas.clipPath(circlePath) - wrapped.draw(canvas) - canvas.restore() - } - ) + val mask = model.chatColors.asCircle() + preview.setImageDrawable(mask.withFixedSize(ViewUtil.dpToPx(56))) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/colors/ui/custom/CustomChatColorCreatorFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/colors/ui/custom/CustomChatColorCreatorFragment.kt index f31bf254b..6d6d02d4e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/colors/ui/custom/CustomChatColorCreatorFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/colors/ui/custom/CustomChatColorCreatorFragment.kt @@ -1,5 +1,6 @@ package org.thoughtcrime.securesms.conversation.colors.ui.custom +import android.os.Build import android.os.Bundle import android.view.View import androidx.appcompat.widget.Toolbar @@ -33,7 +34,12 @@ class CustomChatColorCreatorFragment : Fragment(R.layout.custom_chat_color_creat pager.isUserInputEnabled = false pager.adapter = adapter - tabLayoutMediator.attach() + + if (Build.VERSION.SDK_INT < 21) { + tabLayout.visibility = View.GONE + } else { + tabLayoutMediator.attach() + } val startPage = CustomChatColorCreatorFragmentArgs.fromBundle(requireArguments()).startPage pager.setCurrentItem(startPage, false) diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/FixedSizeDrawable.kt b/app/src/main/java/org/thoughtcrime/securesms/util/FixedSizeDrawable.kt new file mode 100644 index 000000000..d313bc73c --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/util/FixedSizeDrawable.kt @@ -0,0 +1,20 @@ +package org.thoughtcrime.securesms.util + +import android.graphics.drawable.Drawable +import android.graphics.drawable.LayerDrawable +import androidx.annotation.Px + +/** + * Drawable that wraps another drawable but explicitly sets its intrinsic width and height as specified. + */ +class FixedSizeDrawable( + drawable: Drawable, + @Px private val width: Int, + @Px private val height: Int +) : LayerDrawable(arrayOf(drawable)) { + override fun getIntrinsicHeight(): Int = width + override fun getIntrinsicWidth(): Int = height +} + +fun Drawable.withFixedSize(@Px width: Int, @Px height: Int) = FixedSizeDrawable(this, width, height) +fun Drawable.withFixedSize(@Px size: Int) = withFixedSize(size, size) diff --git a/app/src/main/java/org/thoughtcrime/securesms/wallpaper/ChatWallpaperFragment.java b/app/src/main/java/org/thoughtcrime/securesms/wallpaper/ChatWallpaperFragment.java index f22cb55c9..1c75c0426 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/wallpaper/ChatWallpaperFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/wallpaper/ChatWallpaperFragment.java @@ -5,6 +5,7 @@ import android.graphics.Color; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.drawable.Drawable; +import android.os.Build; import android.os.Bundle; import android.util.DisplayMetrics; import android.view.LayoutInflater;