Update various message request UI.

This commit is contained in:
Michelle Tang
2025-03-07 15:15:22 -05:00
committed by Greyson Parrelli
parent caa1d0a2b3
commit 9eba978da6
11 changed files with 113 additions and 58 deletions

View File

@@ -40,6 +40,7 @@ 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.thoughtcrime.securesms.util.ViewUtil;
import org.whispersystems.signalservice.api.util.Preconditions;
public class ConversationHeaderView extends ConstraintLayout {
@@ -135,7 +136,7 @@ public class ConversationHeaderView extends ConstraintLayout {
}
if (recipient.isIndividual() && !recipient.isSelf()) {
CharSequence chevronRight = SignalSymbols.getSpannedString(getContext(), SignalSymbols.Weight.BOLD, SignalSymbols.Glyph.CHEVRON_RIGHT);
CharSequence chevronRight = SignalSymbols.getSpannedString(getContext(), SignalSymbols.Weight.BOLD, SignalSymbols.Glyph.CHEVRON_RIGHT, R.color.signal_colorOutline);
title.append(" ");
title.append(SpanUtil.ofSize(chevronRight, 24));
@@ -192,6 +193,7 @@ public class ConversationHeaderView extends ConstraintLayout {
binding.messageRequestDescription.setText(prependIcon(description, iconRes));
binding.messageRequestDescription.setVisibility(View.VISIBLE);
updateOutlineVisibility();
}
public @NonNull EmojiTextView getDescription() {
@@ -212,17 +214,17 @@ public class ConversationHeaderView extends ConstraintLayout {
binding.messageRequestReviewCarefully.setVisibility(View.GONE);
}
public void setUnverifiedNameSubtitle(@DrawableRes int iconRes, @StringRes int clickableRes, boolean forGroup, @Nullable Runnable onClick) {
public void setUnverifiedNameSubtitle(@DrawableRes int iconRes, boolean forGroup, @NonNull Runnable onClick) {
binding.messageRequestProfileNameUnverified.setVisibility(View.VISIBLE);
binding.messageRequestProfileNameUnverified.setMovementMethod(LinkMovementMethod.getInstance());
CharSequence builder = SpanUtil.clickSubstring(
getContext(),
forGroup ? R.string.ConversationFragment_group_names_not_verified : R.string.ConversationFragment_profile_names_not_verified,
clickableRes,
listener -> onClick.run(),
true,
R.color.signal_colorOnSurface
);
binding.messageRequestProfileNameUnverified.setOnClickListener(view -> onClick.run());
String substring = forGroup ? getContext().getString(R.string.ConversationFragment_group_names)
: getContext().getString(R.string.ConversationFragment_profile_names);
String fullString = forGroup ? getContext().getString(R.string.ConversationFragment_group_names_not_verified, substring)
: getContext().getString(R.string.ConversationFragment_profile_names_not_verified, substring);
CharSequence builder = SpanUtil.underlineSubstring(fullString, substring);
binding.messageRequestProfileNameUnverified.setText(prependIcon(builder, iconRes, forGroup));
}
@@ -286,17 +288,27 @@ public class ConversationHeaderView extends ConstraintLayout {
binding.messageRequestDivider.setVisibility(View.VISIBLE);
} else {
binding.messageRequestInfoOutline.setVisibility(View.VISIBLE);
binding.messageRequestDivider.setVisibility(View.INVISIBLE);
binding.messageRequestDivider.setVisibility(View.GONE);
}
} else if (ViewKt.isVisible(binding.releaseHeaderContainer)) {
binding.messageRequestInfoOutline.setVisibility(View.GONE);
binding.messageRequestDivider.setVisibility(View.INVISIBLE);
} else {
binding.messageRequestInfoOutline.setVisibility(View.GONE);
binding.messageRequestDivider.setVisibility(View.GONE);
}
}
public void updateOutlineBoxSize() {
int visibleCount = 0;
for (int i = 0; i < binding.messageRequestInfo.getChildCount(); i++) {
if (ViewKt.isVisible(binding.messageRequestInfo.getChildAt(i))) {
visibleCount++;
}
}
int padding = visibleCount == 1 ? getContext().getResources().getDimensionPixelOffset(R.dimen.conversation_header_padding) : getContext().getResources().getDimensionPixelOffset(R.dimen.conversation_header_padding_expanded);
ViewUtil.setPaddingStart(binding.messageRequestInfo, padding);
ViewUtil.setPaddingEnd(binding.messageRequestInfo, padding);
}
private @NonNull CharSequence prependIcon(@NonNull CharSequence input, @DrawableRes int iconRes) {
return prependIcon(input, iconRes, false);
}
@@ -305,8 +317,8 @@ public class ConversationHeaderView extends ConstraintLayout {
private @NonNull CharSequence prependIcon(@NonNull CharSequence input, @DrawableRes int iconRes, boolean useIntrinsicWidth) {
Drawable drawable = ContextCompat.getDrawable(getContext(), iconRes);
Preconditions.checkNotNull(drawable);
int width = useIntrinsicWidth ? drawable.getIntrinsicWidth() : (int) DimensionUnit.SP.toPixels(20);
drawable.setBounds(0, 0, width, (int) DimensionUnit.SP.toPixels(20));
int width = useIntrinsicWidth ? drawable.getIntrinsicWidth() : (int) DimensionUnit.SP.toPixels(16);
drawable.setBounds(0, 0, width, (int) DimensionUnit.SP.toPixels(16));
drawable.setColorFilter(ContextCompat.getColor(getContext(), R.color.signal_colorOnSurface), PorterDuff.Mode.SRC_ATOP);
return new SpannableStringBuilder()

View File

@@ -563,7 +563,7 @@ class ConversationAdapterV2(
if (recipient.isGroup) {
if (!groupInfo.hasExistingContacts) {
conversationBanner.setUnverifiedNameSubtitle(R.drawable.symbol_group_question_20, R.string.ConversationFragment_group_names, true) {
conversationBanner.setUnverifiedNameSubtitle(R.drawable.symbol_group_question_16, true) {
clickListener.onShowUnverifiedProfileSheet(true)
}
} else {
@@ -572,17 +572,20 @@ class ConversationAdapterV2(
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), R.drawable.symbol_group_light_20) { goToGroupSettings(recipient) }
conversationBanner.setSubtitle(context.resources.getQuantityString(R.plurals.MessageRequestProfileView_members_and_invited, groupInfo.fullMemberCount, groupInfo.fullMemberCount, invited), R.drawable.symbol_group_compact_16) { goToGroupSettings(recipient) }
} else if (groupInfo.fullMemberCount > 0) {
conversationBanner.setSubtitle(context.resources.getQuantityString(R.plurals.MessageRequestProfileView_members, groupInfo.fullMemberCount, groupInfo.fullMemberCount), R.drawable.symbol_group_light_20) { goToGroupSettings(recipient) }
if (groupInfo.fullMemberCount == 1 && recipient.isActiveGroup) {
conversationBanner.hideUnverifiedNameSubtitle()
}
conversationBanner.setSubtitle(context.resources.getQuantityString(R.plurals.MessageRequestProfileView_members, groupInfo.fullMemberCount, groupInfo.fullMemberCount), R.drawable.symbol_group_compact_16) { goToGroupSettings(recipient) }
} else {
conversationBanner.hideSubtitle()
}
} else if (isSelf) {
conversationBanner.setSubtitle(context.getString(R.string.ConversationFragment__you_can_add_notes_for_yourself_in_this_conversation), R.drawable.symbol_note_light_24, null)
conversationBanner.setSubtitle(context.getString(R.string.ConversationFragment__you_can_add_notes_for_yourself_in_this_conversation), R.drawable.symbol_note_compact_16, null)
} else {
if (recipient.nickname.isEmpty && !recipient.isSystemContact) {
conversationBanner.setUnverifiedNameSubtitle(R.drawable.symbol_person_question_16, R.string.ConversationFragment_profile_names, false) {
if ((recipient.profileName.toString() == recipient.getDisplayName(context)) && recipient.nickname.isEmpty && !recipient.isSystemContact) {
conversationBanner.setUnverifiedNameSubtitle(R.drawable.symbol_person_question_16, false) {
clickListener.onShowUnverifiedProfileSheet(false)
}
} else {
@@ -593,7 +596,7 @@ class ConversationAdapterV2(
if (subtitle == null || subtitle == title) {
conversationBanner.hideSubtitle()
} else {
conversationBanner.setSubtitle(subtitle, R.drawable.symbol_phone_light_20, null)
conversationBanner.setSubtitle(subtitle, R.drawable.symbol_phone_compact_16, null)
}
}
@@ -606,7 +609,7 @@ class ConversationAdapterV2(
conversationBanner.setButton(context.getString(R.string.ConversationFragment_safety_tips)) {
clickListener.onShowSafetyTips(false)
}
conversationBanner.setDescription(getDescription(context, sharedGroups), R.drawable.symbol_group_light_20)
conversationBanner.setDescription(getDescription(context, sharedGroups), R.drawable.symbol_group_compact_16)
} else if (messageRequestState?.isAccepted == false && recipient.isGroup) {
conversationBanner.showWarningSubtitle()
conversationBanner.setButton(context.getString(R.string.ConversationFragment_safety_tips)) {
@@ -633,8 +636,9 @@ class ConversationAdapterV2(
}
} else {
conversationBanner.hideWarningSubtitle()
conversationBanner.setDescription(getDescription(context, sharedGroups), R.drawable.symbol_group_light_20)
conversationBanner.setDescription(getDescription(context, sharedGroups), R.drawable.symbol_group_compact_16)
}
conversationBanner.updateOutlineBoxSize()
}
private fun getDescription(context: Context, sharedGroups: List<String>): String {

View File

@@ -10,12 +10,14 @@ import android.graphics.Typeface
import android.text.SpannableStringBuilder
import android.text.TextPaint
import android.text.style.MetricAffectingSpan
import androidx.annotation.ColorRes
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.withStyle
import org.thoughtcrime.securesms.util.SpanUtil
/**
* Helper object for working with the SignalSymbols font
@@ -40,7 +42,8 @@ object SignalSymbols {
fun getSpannedString(
context: Context,
weight: Weight,
glyph: Glyph
glyph: Glyph,
@ColorRes colorRes: Int = -1
): CharSequence {
val typeface = getTypeface(context, weight)
val span = CustomTypefaceSpan(typeface)
@@ -48,7 +51,11 @@ object SignalSymbols {
val text = SpannableStringBuilder(glyph.unicode.toString())
text.setSpan(span, 0, text.length, 0)
return text
return if (colorRes != -1) {
SpanUtil.color(colorRes, text)
} else {
text
}
}
@Composable

View File

@@ -255,6 +255,8 @@ class RecipientBottomSheetDialogFragment : BottomSheetDialogFragment() {
nickname.setOnClickListener {
nicknameLauncher.launch(NicknameActivity.Args(recipientId, false))
}
} else if (recipient.isReleaseNotes) {
fullName.text = name
}
var aboutText = recipient.combinedAboutAndEmoji

View File

@@ -27,6 +27,7 @@ import android.text.style.StyleSpan;
import android.text.style.TextAppearanceSpan;
import android.text.style.TypefaceSpan;
import android.text.style.URLSpan;
import android.text.style.UnderlineSpan;
import android.view.View;
import androidx.annotation.ColorInt;
@@ -99,6 +100,17 @@ public final class SpanUtil {
return spannable;
}
public static CharSequence underlineSubstring(CharSequence fullString, CharSequence substring) {
SpannableString spannable = new SpannableString(fullString);
int start = TextUtils.indexOf(fullString, substring);
int end = start + substring.length();
if (start >= 0 && end <= fullString.length()) {
spannable.setSpan(new UnderlineSpan(), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
return spannable;
}
public static CharSequence color(int color, CharSequence sequence) {
SpannableString spannable = new SpannableString(sequence);
spannable.setSpan(new ForegroundColorSpan(color), 0, sequence.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

View File

@@ -1,5 +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"/>
<stroke android:width="2dp" android:color="@color/signal_colorOutline_38"/>
<corners android:radius="18dp"/>
</shape>

View File

@@ -1,10 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="188dp"
android:height="123dp"
android:viewportWidth="288"
android:viewportHeight="123">
<path
android:pathData="M18,0L270,0A18,18 0,0 1,288 18L288,105A18,18 0,0 1,270 123L18,123A18,18 0,0 1,0 105L0,18A18,18 0,0 1,18 0z"
android:fillColor="#2934FD"
android:fillAlpha="0.08"/>
</vector>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
<solid android:color="#142934FD" />
<corners android:radius="18dp"/>
</shape>

View File

@@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="22dp"
android:height="16dp"
android:viewportWidth="22"
android:viewportHeight="16">
<path
android:fillColor="#FF000000"
android:fillType="evenOdd"
android:pathData="M6.98 9C6.37 8.73 5.7 8.6 5 8.6c-2.48 0-4.65 1.78-4.65 4.15 0 0.53 0.44 0.9 0.91 0.9h4.07c-0.05-0.29-0.08-0.59-0.08-0.9 0-0.14 0-0.27 0.02-0.4H1.68C1.91 11.02 3.24 9.9 5 9.9c0.38 0 0.73 0.05 1.06 0.14C6.32 9.66 6.63 9.3 6.98 9Z"/>
<path
android:fillColor="#FF000000"
android:fillType="evenOdd"
android:pathData="M7.68 12.35h6.64C14.09 11.02 12.76 9.9 11 9.9c-1.76 0-3.1 1.12-3.32 2.45Zm-1.33 0.4c0-2.37 2.17-4.15 4.65-4.15 2.48 0 4.65 1.78 4.65 4.15 0 0.53-0.44 0.9-0.91 0.9H7.26c-0.47 0-0.91-0.37-0.91-0.9Z"/>
<path
android:fillColor="#FF000000"
android:fillType="evenOdd"
android:pathData="M11 3.65c-0.52 0-1.1 0.5-1.1 1.4 0 0.46 0.15 0.86 0.37 1.14C10.5 6.47 10.76 6.6 11 6.6s0.5-0.13 0.73-0.4c0.22-0.29 0.37-0.7 0.37-1.14 0-0.91-0.58-1.41-1.1-1.41Zm-2.4 1.4c0-1.43 0.99-2.7 2.4-2.7s2.4 1.27 2.4 2.7c0 0.74-0.24 1.43-0.65 1.95-0.41 0.52-1.03 0.9-1.75 0.9S9.66 7.52 9.25 7C8.85 6.48 8.6 5.79 8.6 5.06Z"/>
<path
android:fillColor="#FF000000"
android:fillType="evenOdd"
android:pathData="M5 3.65c-0.52 0-1.1 0.5-1.1 1.4 0 0.46 0.15 0.86 0.37 1.14C4.5 6.47 4.76 6.6 5 6.6s0.5-0.13 0.73-0.4C5.95 5.9 6.1 5.5 6.1 5.05c0-0.91-0.58-1.41-1.1-1.41Zm-2.4 1.4c0-1.43 0.99-2.7 2.4-2.7s2.4 1.27 2.4 2.7C7.4 5.8 7.16 6.49 6.75 7 6.34 7.52 5.72 7.9 5 7.9S3.66 7.52 3.25 7C2.85 6.48 2.6 5.79 2.6 5.06Z"/>
<path
android:fillColor="#FF000000"
android:fillType="evenOdd"
android:pathData="M17 3.99c0.4-0.27 0.92-0.39 1.5-0.39 0.69 0 1.28 0.18 1.72 0.53C20.66 4.48 20.9 5 20.9 5.58c0 0.47-0.14 0.83-0.35 1.13-0.18 0.26-0.43 0.46-0.62 0.62l-0.04 0.03c-0.22 0.19-0.4 0.34-0.52 0.53-0.12 0.18-0.2 0.4-0.2 0.76v0.09c0 0.36-0.3 0.66-0.67 0.66-0.36 0-0.66-0.3-0.66-0.66v-0.1c0-0.52 0.13-0.92 0.33-1.26 0.2-0.32 0.46-0.56 0.68-0.74l0.1-0.09c0.43-0.35 0.63-0.52 0.63-0.88 0-0.33-0.12-0.55-0.28-0.68-0.17-0.14-0.44-0.24-0.8-0.24-0.35 0-0.58 0.08-0.74 0.19-0.14 0.1-0.25 0.26-0.31 0.5-0.07 0.28-0.31 0.54-0.66 0.54-0.38 0-0.73-0.35-0.62-0.78 0.13-0.53 0.4-0.94 0.83-1.21Z"/>
<path
android:fillColor="#FF000000"
android:fillType="evenOdd"
android:pathData="M17.75 11c0-0.41 0.34-0.75 0.75-0.75s0.75 0.34 0.75 0.75-0.34 0.75-0.75 0.75-0.75-0.34-0.75-0.75Z"/>
</vector>

View File

@@ -10,7 +10,6 @@
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"
@@ -80,7 +79,6 @@
android:paddingStart="16dp"
android:paddingEnd="16dp"
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"
@@ -94,7 +92,6 @@
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:textAppearance="@style/Signal.Text.MessageRequest.Subtitle"
app:layout_constraintBottom_toTopOf="@id/message_request_divider"
app:layout_constraintTop_toBottomOf="@id/message_request_title"
tools:text="Hangin' on the web" />
@@ -103,18 +100,9 @@
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_barrier"
app:layout_constraintTop_toBottomOf="@id/message_request_about" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/message_request_barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="top"
app:constraint_referenced_ids="message_request_info,release_header_container" />
<LinearLayout
android:id="@+id/release_header_container"
android:layout_width="wrap_content"
@@ -123,10 +111,11 @@
android:orientation="vertical"
android:background="@drawable/release_header_background"
android:minWidth="288dp"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginTop="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/message_request_divider"
app:layout_constraintWidth_max="@dimen/conversation_header_max_size"
android:visibility="gone"
tools:visibility="visible">
@@ -163,14 +152,14 @@
android:id="@+id/message_request_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="16dp"
android:paddingVertical="16dp"
android:paddingHorizontal="32dp"
android:layout_marginTop="16dp"
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_divider"
app:layout_constraintWidth_max="308dp"
app:layout_constraintWidth_min="256dp">
app:layout_constraintWidth_max="@dimen/conversation_header_max_size" >
<TextView
android:id="@+id/message_request_review_carefully"
@@ -179,7 +168,7 @@
android:text="@string/ConversationFragment_review_carefully"
android:textColor="#A88746"
android:textAppearance="@style/Signal.Text.BodyMedium"
android:textStyle="bold"
android:fontFamily="sans-serif-medium"
android:visibility="gone"
app:drawableStartCompat="@drawable/symbol_error_triangle_filled_16"
android:drawablePadding="6dp"
@@ -197,6 +186,7 @@
android:textAppearance="@style/Signal.Text.BodyMedium"
android:text="@string/ConversationFragment_profile_names_not_verified"
android:visibility="gone"
android:textAlignment="center"
android:layout_marginBottom="8dp"
app:layout_constrainedWidth="true"
app:layout_constraintEnd_toEndOf="parent"

View File

@@ -7,7 +7,6 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="52dp"
android:paddingTop="22dp"
android:paddingBottom="4dp"
app:layout_constraintTop_toTopOf="parent"

View File

@@ -246,4 +246,8 @@
<dimen name="chat_folder_row_height">64dp</dimen>
<dimen name="conversation_header_padding">24dp</dimen>
<dimen name="conversation_header_padding_expanded">32dp</dimen>
<dimen name="conversation_header_max_size">308dp</dimen>
</resources>