Update style for conversation header view.

This commit is contained in:
Alex Hart 2023-12-21 12:08:35 -04:00 committed by Clark Chen
parent 2b606a2dec
commit d70ebc2398
8 changed files with 174 additions and 86 deletions

View file

@ -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 {

View file

@ -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()
}
}

View file

@ -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));

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
<stroke android:width="1.5dp" android:color="@color/signal_colorOutline_38"/>
<corners android:radius="18dp"/>
</shape>

View file

@ -0,0 +1,18 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M13.13 7.15c0-2.09 1.4-3.9 3.37-3.9 1.98 0 3.38 1.81 3.38 3.9 0 1.05-0.35 2.06-0.93 2.8-0.58 0.76-1.44 1.3-2.45 1.3-1.01 0-1.87-0.54-2.45-1.3-0.58-0.74-0.93-1.75-0.93-2.8Zm3.37-2.4c-0.92 0-1.88 0.9-1.88 2.4 0 0.74 0.25 1.41 0.62 1.89 0.37 0.47 0.82 0.71 1.26 0.71 0.44 0 0.9-0.24 1.26-0.71 0.37-0.48 0.61-1.15 0.61-1.9 0-1.5-0.95-2.39-1.87-2.39Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M7.5 12.75c1.22 0 2.4 0.3 3.4 0.82-0.4 0.34-0.75 0.73-1.06 1.15-0.7-0.3-1.49-0.47-2.34-0.47-2.79 0-4.93 1.82-5.22 4h6.24l-0.02 0.5c0 0.34 0.02 0.68 0.07 1H1.76c-0.53 0-1.01-0.42-1.01-1 0-3.4 3.12-6 6.75-6Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M16.5 12.75c-3.63 0-6.75 2.6-6.75 6 0 0.58 0.48 1 1 1h11.5c0.52 0 1-0.42 1-1 0-3.4-3.12-6-6.75-6Zm0 1.5c2.79 0 4.93 1.82 5.22 4H11.28c0.29-2.18 2.43-4 5.22-4Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M7.5 3.25c-1.98 0-3.38 1.81-3.38 3.9 0 1.05 0.35 2.06 0.93 2.8 0.58 0.76 1.44 1.3 2.45 1.3 1.01 0 1.87-0.54 2.45-1.3 0.58-0.74 0.93-1.75 0.93-2.8 0-2.09-1.4-3.9-3.38-3.9Zm-1.88 3.9c0-1.5 0.96-2.4 1.88-2.4 0.92 0 1.88 0.9 1.88 2.4 0 0.74-0.25 1.41-0.62 1.89C8.4 9.5 7.94 9.75 7.5 9.75c-0.44 0-0.9-0.24-1.26-0.71-0.37-0.48-0.62-1.15-0.62-1.9Z"/>
</vector>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M4.34 2.81C5.54 1.62 7.5 1.76 8.52 3.1l2.17 2.85c0.84 1.1 0.73 2.66-0.25 3.65l-1.1 1.1c0.03 0.11 0.1 0.27 0.21 0.49 0.29 0.5 0.78 1.16 1.44 1.82 0.66 0.66 1.31 1.15 1.82 1.44 0.22 0.12 0.38 0.18 0.49 0.21l1.1-1.1c0.99-0.98 2.54-1.09 3.65-0.25l2.85 2.17c1.34 1.02 1.48 2.99 0.29 4.18l-0.44 0.43c-1.54 1.55-3.84 2.38-6.03 1.63-2.8-0.96-5.43-2.55-7.66-4.78-2.23-2.23-3.82-4.86-4.78-7.66-0.75-2.2 0.08-4.49 1.63-6.03l0.43-0.44Zm2.99 1.2C6.86 3.39 5.95 3.33 5.4 3.87L4.97 4.31C3.73 5.55 3.17 7.27 3.7 8.8c0.88 2.58 2.36 5.01 4.42 7.08 2.07 2.06 4.5 3.54 7.08 4.42 1.53 0.53 3.25-0.03 4.49-1.27l0.44-0.43c0.54-0.55 0.48-1.46-0.14-1.93l-2.85-2.17c-0.5-0.38-1.22-0.33-1.68 0.12l-1.24 1.24c-0.37 0.37-0.86 0.35-1.15 0.29-0.32-0.06-0.66-0.21-0.99-0.4-0.66-0.36-1.42-0.95-2.15-1.68s-1.32-1.5-1.69-2.15c-0.18-0.33-0.33-0.67-0.39-1-0.06-0.28-0.08-0.77 0.29-1.14l1.24-1.24c0.45-0.46 0.5-1.17 0.11-1.68L7.33 4Z"/>
</vector>

View file

@ -1,17 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:viewBindingIgnore="true"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="24dp"
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
<org.thoughtcrime.securesms.components.AvatarImageView
android:id="@+id/message_request_avatar"
android:layout_width="80dp"
android:layout_height="80dp"
app:layout_constraintBottom_toTopOf="@id/message_request_title"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
@ -67,7 +66,8 @@
android:gravity="center"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:textAppearance="@style/Signal.Text.MessageRequest.Title"
android:textAppearance="@style/Signal.Text.HeadlineMedium"
app:layout_constraintBottom_toTopOf="@id/message_request_about"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/message_request_avatar"
@ -82,32 +82,72 @@
android:paddingEnd="16dp"
android:textAppearance="@style/Signal.Text.MessageRequest.Subtitle"
app:emoji_forceCustom="true"
app:layout_constraintBottom_toTopOf="@id/message_request_divider"
app:layout_constraintTop_toBottomOf="@id/message_request_title"
tools:text="Hangin' on the web" />
<TextView
android:id="@+id/message_request_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:gravity="center"
android:textAppearance="@style/Signal.Text.MessageRequest.Subtitle"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/message_request_about"
tools:text="\@caycepollard" />
<View
android:id="@+id/message_request_divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:background="@color/signal_dark_colorTransparentInverse2"
app:layout_constraintBottom_toTopOf="@id/message_request_info"
app:layout_constraintTop_toBottomOf="@id/message_request_about" />
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/message_request_description"
<View
android:id="@+id/message_request_info_outline"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@drawable/message_request_info_outline"
app:layout_constraintBottom_toBottomOf="@id/message_request_info"
app:layout_constraintEnd_toEndOf="@id/message_request_info"
app:layout_constraintStart_toStartOf="@id/message_request_info"
app:layout_constraintTop_toTopOf="@id/message_request_info" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/message_request_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:gravity="center"
android:textAppearance="@style/Signal.Text.MessageRequest.Description"
android:layout_marginHorizontal="@dimen/core_ui__gutter"
android:padding="20dp"
app:layout_constrainedWidth="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/message_request_subtitle"
tools:text="Member of NYC Rock Climbers, Dinner Party and Friends" />
app:layout_constraintTop_toBottomOf="@id/message_request_divider"
app:layout_constraintWidth_max="308dp"
app:layout_constraintWidth_min="256dp">
<TextView
android:id="@+id/message_request_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:textAppearance="@style/Signal.Text.MessageRequest.Subtitle"
app:layout_constrainedWidth="true"
app:layout_constraintBottom_toTopOf="@id/message_request_description"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="\@caycepollard" />
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/message_request_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:gravity="center"
android:textAppearance="@style/Signal.Text.MessageRequest.Description"
android:visibility="gone"
app:layout_constrainedWidth="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/message_request_subtitle"
tools:text="Member of NYC Rock Climbers, Dinner Party and Friends" />
</androidx.constraintlayout.widget.ConstraintLayout>
</merge>

View file

@ -1,18 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2023 Signal Messenger, LLC
~ SPDX-License-Identifier: AGPL-3.0-only
-->
<org.thoughtcrime.securesms.conversation.ConversationHeaderView
xmlns:tools="http://schemas.android.com/tools"
tools:viewBindingIgnore="true"
xmlns:android="http://schemas.android.com/apk/res/android"
<org.thoughtcrime.securesms.conversation.ConversationHeaderView 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:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="32dp"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:paddingTop="24dp"
android:paddingBottom="24dp"
app:layout_constraintTop_toTopOf="parent"/>
android:layout_marginHorizontal="52dp"
android:paddingTop="22dp"
android:paddingBottom="4dp"
app:layout_constraintTop_toTopOf="parent"
tools:viewBindingIgnore="true" />