diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationHeaderView.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationHeaderView.java
index 328be627b5..6f7b0a5f56 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationHeaderView.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationHeaderView.java
@@ -1,39 +1,36 @@
package org.thoughtcrime.securesms.conversation;
import android.content.Context;
+import android.graphics.drawable.Drawable;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
-import android.widget.TextView;
+import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;
+import androidx.core.content.ContextCompat;
+import org.signal.core.util.DimensionUnit;
import org.signal.core.util.concurrent.SignalExecutors;
import org.thoughtcrime.securesms.R;
-import org.thoughtcrime.securesms.badges.BadgeImageView;
-import org.thoughtcrime.securesms.components.AvatarImageView;
import org.thoughtcrime.securesms.components.emoji.EmojiTextView;
import org.thoughtcrime.securesms.contacts.avatars.FallbackContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.ResourceContactPhoto;
import org.thoughtcrime.securesms.database.SignalDatabase;
+import org.thoughtcrime.securesms.databinding.ConversationHeaderViewBinding;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.ContextUtil;
import org.thoughtcrime.securesms.util.LongClickMovementMethod;
import org.thoughtcrime.securesms.util.SpanUtil;
+import org.whispersystems.signalservice.api.util.Preconditions;
public class ConversationHeaderView extends ConstraintLayout {
- private AvatarImageView contactAvatar;
- private TextView contactTitle;
- private TextView contactAbout;
- private TextView contactSubtitle;
- private EmojiTextView contactDescription;
- private View tapToView;
- private BadgeImageView contactBadge;
+ private final ConversationHeaderViewBinding binding;
public ConversationHeaderView(Context context) {
this(context, null);
@@ -46,38 +43,32 @@ public class ConversationHeaderView extends ConstraintLayout {
public ConversationHeaderView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- inflate(getContext(), R.layout.conversation_banner_view, this);
+ inflate(getContext(), R.layout.conversation_header_view, this);
- contactAvatar = findViewById(R.id.message_request_avatar);
- contactBadge = findViewById(R.id.message_request_badge);
- contactTitle = findViewById(R.id.message_request_title);
- contactAbout = findViewById(R.id.message_request_about);
- contactSubtitle = findViewById(R.id.message_request_subtitle);
- contactDescription = findViewById(R.id.message_request_description);
- tapToView = findViewById(R.id.message_request_avatar_tap_to_view);
+ binding = ConversationHeaderViewBinding.bind(this);
- contactAvatar.setFallbackPhotoProvider(new FallbackPhotoProvider());
+ binding.messageRequestAvatar.setFallbackPhotoProvider(new FallbackPhotoProvider());
}
public void setBadge(@Nullable Recipient recipient) {
if (recipient == null || recipient.isSelf()) {
- contactBadge.setBadge(null);
+ binding.messageRequestBadge.setBadge(null);
} else {
- contactBadge.setBadgeFromRecipient(recipient);
+ binding.messageRequestBadge.setBadgeFromRecipient(recipient);
}
}
public void setAvatar(@NonNull GlideRequests requests, @Nullable Recipient recipient) {
- contactAvatar.setAvatar(requests, recipient, false);
+ binding.messageRequestAvatar.setAvatar(requests, recipient, false);
if (recipient != null && recipient.shouldBlurAvatar() && recipient.getContactPhoto() != null) {
- tapToView.setVisibility(VISIBLE);
- tapToView.setOnClickListener(v -> {
+ binding.messageRequestAvatarTapToView.setVisibility(VISIBLE);
+ binding.messageRequestAvatarTapToView.setOnClickListener(v -> {
SignalExecutors.BOUNDED.execute(() -> SignalDatabase.recipients().manuallyShowAvatar(recipient.getId()));
});
} else {
- tapToView.setVisibility(GONE);
- tapToView.setOnClickListener(null);
+ binding.messageRequestAvatarTapToView.setVisibility(GONE);
+ binding.messageRequestAvatarTapToView.setOnClickListener(null);
}
}
@@ -86,7 +77,7 @@ public class ConversationHeaderView extends ConstraintLayout {
if (recipient.showVerified()) {
SpanUtil.appendCenteredImageSpan(title, ContextUtil.requireDrawable(getContext(), R.drawable.ic_official_28), 28, 28);
}
- contactTitle.setText(title);
+ binding.messageRequestTitle.setText(title);
return title.toString();
}
@@ -98,46 +89,66 @@ public class ConversationHeaderView extends ConstraintLayout {
about = recipient.getCombinedAboutAndEmoji();
}
- contactAbout.setText(about);
- contactAbout.setVisibility(TextUtils.isEmpty(about) ? GONE : VISIBLE);
+ binding.messageRequestAbout.setText(about);
+ binding.messageRequestAbout.setVisibility(TextUtils.isEmpty(about) ? GONE : VISIBLE);
}
- public void setSubtitle(@Nullable CharSequence subtitle) {
- contactSubtitle.setText(subtitle);
- contactSubtitle.setVisibility(TextUtils.isEmpty(subtitle) ? GONE : VISIBLE);
+ public void setSubtitle(@NonNull CharSequence subtitle, @DrawableRes int iconRes) {
+ binding.messageRequestSubtitle.setText(prependIcon(subtitle, iconRes));
+ binding.messageRequestSubtitle.setVisibility(View.VISIBLE);
}
- public void setDescription(@Nullable CharSequence description) {
- contactDescription.setText(description);
- contactDescription.setVisibility(TextUtils.isEmpty(description) ? GONE : VISIBLE);
+ public void setDescription(@Nullable CharSequence description, @DrawableRes int iconRes) {
+ if (description == null) {
+ hideDescription();
+ return;
+ }
+
+ binding.messageRequestSubtitle.setText(prependIcon(description, iconRes));
+ binding.messageRequestDescription.setVisibility(View.VISIBLE);
}
public @NonNull EmojiTextView getDescription() {
- return contactDescription;
+ return binding.messageRequestDescription;
}
public void showBackgroundBubble(boolean enabled) {
if (enabled) {
- setBackgroundResource(R.drawable.wallpaper_bubble_background_12);
+ setBackgroundResource(R.drawable.wallpaper_bubble_background_18);
+ binding.messageRequestInfoOutline.setVisibility(View.INVISIBLE);
+ binding.messageRequestDivider.setVisibility(View.VISIBLE);
} else {
setBackground(null);
+ binding.messageRequestInfoOutline.setVisibility(View.VISIBLE);
+ binding.messageRequestDivider.setVisibility(View.INVISIBLE);
}
}
public void hideSubtitle() {
- contactSubtitle.setVisibility(View.GONE);
+ binding.messageRequestSubtitle.setVisibility(View.GONE);
}
public void showDescription() {
- contactDescription.setVisibility(View.VISIBLE);
+ binding.messageRequestDescription.setVisibility(View.VISIBLE);
}
public void hideDescription() {
- contactDescription.setVisibility(View.GONE);
+ binding.messageRequestDescription.setVisibility(View.GONE);
}
public void setLinkifyDescription(boolean enable) {
- contactDescription.setMovementMethod(enable ? LongClickMovementMethod.getInstance(getContext()) : null);
+ binding.messageRequestDescription.setMovementMethod(enable ? LongClickMovementMethod.getInstance(getContext()) : null);
+ }
+
+ private @NonNull CharSequence prependIcon(@NonNull CharSequence input, @DrawableRes int iconRes) {
+ Drawable drawable = ContextCompat.getDrawable(getContext(), iconRes);
+ Preconditions.checkNotNull(drawable);
+ drawable.setBounds(0, 0, (int) DimensionUnit.DP.toPixels(20), (int) DimensionUnit.DP.toPixels(20));
+
+ return new SpannableStringBuilder()
+ .append(SpanUtil.buildCenteredImageSpan(drawable))
+ .append(SpanUtil.space(8, DimensionUnit.DP))
+ .append(input);
}
private static final class FallbackPhotoProvider extends Recipient.FallbackPhotoProvider {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2.kt
index 07e1e14b35..34f07c2199 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapterV2.kt
@@ -53,7 +53,6 @@ import org.thoughtcrime.securesms.mms.GlideRequests
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.util.CachedInflater
-import org.thoughtcrime.securesms.util.HtmlUtil
import org.thoughtcrime.securesms.util.Projection
import org.thoughtcrime.securesms.util.ProjectionList
import org.thoughtcrime.securesms.util.adapter.mapping.MappingViewHolder
@@ -572,20 +571,20 @@ class ConversationAdapterV2(
if (recipient.isGroup) {
if (groupInfo.pendingMemberCount > 0) {
val invited = context.resources.getQuantityString(R.plurals.MessageRequestProfileView_invited, groupInfo.pendingMemberCount, groupInfo.pendingMemberCount)
- conversationBanner.setSubtitle(context.resources.getQuantityString(R.plurals.MessageRequestProfileView_members_and_invited, groupInfo.fullMemberCount, groupInfo.fullMemberCount, invited))
+ conversationBanner.setSubtitle(context.resources.getQuantityString(R.plurals.MessageRequestProfileView_members_and_invited, groupInfo.fullMemberCount, groupInfo.fullMemberCount, invited), R.drawable.symbol_group_light_20)
} else if (groupInfo.fullMemberCount > 0) {
- conversationBanner.setSubtitle(context.resources.getQuantityString(R.plurals.MessageRequestProfileView_members, groupInfo.fullMemberCount, groupInfo.fullMemberCount))
+ conversationBanner.setSubtitle(context.resources.getQuantityString(R.plurals.MessageRequestProfileView_members, groupInfo.fullMemberCount, groupInfo.fullMemberCount), R.drawable.symbol_group_light_20)
} else {
- conversationBanner.setSubtitle(null)
+ conversationBanner.hideSubtitle()
}
} else if (isSelf) {
- conversationBanner.setSubtitle(context.getString(R.string.ConversationFragment__you_can_add_notes_for_yourself_in_this_conversation))
+ conversationBanner.setSubtitle(context.getString(R.string.ConversationFragment__you_can_add_notes_for_yourself_in_this_conversation), R.drawable.symbol_person_light_24)
} else {
val subtitle: String? = recipient.takeIf { it.shouldShowE164() }?.e164?.map { e164: String? -> PhoneNumberFormatter.prettyPrint(e164!!) }?.orElse(null)
if (subtitle == null || subtitle == title) {
conversationBanner.hideSubtitle()
} else {
- conversationBanner.setSubtitle(subtitle)
+ conversationBanner.setSubtitle(subtitle, R.drawable.symbol_phone_light_20)
}
}
@@ -609,20 +608,20 @@ class ConversationAdapterV2(
}
} else {
val description: String = when (sharedGroups.size) {
- 1 -> context.getString(R.string.MessageRequestProfileView_member_of_one_group, HtmlUtil.bold(sharedGroups[0]))
- 2 -> context.getString(R.string.MessageRequestProfileView_member_of_two_groups, HtmlUtil.bold(sharedGroups[0]), HtmlUtil.bold(sharedGroups[1]))
- 3 -> context.getString(R.string.MessageRequestProfileView_member_of_many_groups, HtmlUtil.bold(sharedGroups[0]), HtmlUtil.bold(sharedGroups[1]), HtmlUtil.bold(sharedGroups[2]))
+ 1 -> context.getString(R.string.MessageRequestProfileView_member_of_one_group, sharedGroups[0])
+ 2 -> context.getString(R.string.MessageRequestProfileView_member_of_two_groups, sharedGroups[0], sharedGroups[1])
+ 3 -> context.getString(R.string.MessageRequestProfileView_member_of_many_groups, sharedGroups[0], sharedGroups[1], sharedGroups[2])
else -> {
val others: Int = sharedGroups.size - 2
context.getString(
R.string.MessageRequestProfileView_member_of_many_groups,
- HtmlUtil.bold(sharedGroups[0]),
- HtmlUtil.bold(sharedGroups[1]),
+ sharedGroups[0],
+ sharedGroups[1],
context.resources.getQuantityString(R.plurals.MessageRequestProfileView_member_of_d_additional_groups, others, others)
)
}
}
- conversationBanner.setDescription(HtmlCompat.fromHtml(description, 0))
+ conversationBanner.setDescription(HtmlCompat.fromHtml(description, 0), R.drawable.symbol_group_light_20)
conversationBanner.showDescription()
}
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/SpanUtil.java b/app/src/main/java/org/thoughtcrime/securesms/util/SpanUtil.java
index 37873dc22d..44dd314459 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/util/SpanUtil.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/util/SpanUtil.java
@@ -2,7 +2,9 @@ package org.thoughtcrime.securesms.util;
import android.content.Context;
import android.content.res.Resources;
+import android.graphics.Color;
import android.graphics.Typeface;
+import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.Layout;
@@ -33,6 +35,7 @@ import androidx.annotation.StringRes;
import androidx.annotation.StyleRes;
import androidx.core.content.ContextCompat;
+import org.signal.core.util.DimensionUnit;
import org.thoughtcrime.securesms.R;
public final class SpanUtil {
@@ -128,6 +131,13 @@ public final class SpanUtil {
return imageSpan;
}
+ public static CharSequence space(int width, @NonNull DimensionUnit widthUnit) {
+ Drawable drawable = new ColorDrawable(Color.TRANSPARENT);
+ drawable.setBounds(0, 0, (int) widthUnit.toPixels(width), 1);
+
+ return buildCenteredImageSpan(drawable);
+ }
+
public static void appendCenteredImageSpan(@NonNull SpannableStringBuilder builder, @NonNull Drawable drawable, int width, int height) {
drawable.setBounds(0, 0, ViewUtil.dpToPx(width), ViewUtil.dpToPx(height));
builder.append(" ").append(SpanUtil.buildCenteredImageSpan(drawable));
diff --git a/app/src/main/res/drawable/message_request_info_outline.xml b/app/src/main/res/drawable/message_request_info_outline.xml
new file mode 100644
index 0000000000..8ca7527dc0
--- /dev/null
+++ b/app/src/main/res/drawable/message_request_info_outline.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/symbol_group_light_20.xml b/app/src/main/res/drawable/symbol_group_light_20.xml
new file mode 100644
index 0000000000..5a45ae198e
--- /dev/null
+++ b/app/src/main/res/drawable/symbol_group_light_20.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/symbol_phone_light_20.xml b/app/src/main/res/drawable/symbol_phone_light_20.xml
new file mode 100644
index 0000000000..05f8214962
--- /dev/null
+++ b/app/src/main/res/drawable/symbol_phone_light_20.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/layout/conversation_banner_view.xml b/app/src/main/res/layout/conversation_header_view.xml
similarity index 57%
rename from app/src/main/res/layout/conversation_banner_view.xml
rename to app/src/main/res/layout/conversation_header_view.xml
index 416e8c8176..a049d3e0b1 100644
--- a/app/src/main/res/layout/conversation_banner_view.xml
+++ b/app/src/main/res/layout/conversation_header_view.xml
@@ -1,17 +1,16 @@
-
+
-
+
+
+ app:layout_constraintTop_toBottomOf="@id/message_request_divider"
+ app:layout_constraintWidth_max="308dp"
+ app:layout_constraintWidth_min="256dp">
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/conversation_item_thread_header.xml b/app/src/main/res/layout/conversation_item_thread_header.xml
index b60b16cb05..2630d18ab1 100644
--- a/app/src/main/res/layout/conversation_item_thread_header.xml
+++ b/app/src/main/res/layout/conversation_item_thread_header.xml
@@ -1,18 +1,14 @@
-
-
-
+ android:layout_marginHorizontal="52dp"
+ android:paddingTop="22dp"
+ android:paddingBottom="4dp"
+ app:layout_constraintTop_toTopOf="parent"
+ tools:viewBindingIgnore="true" />