From 9eba978da6677930db9fbc368ff00e0c2fb4bad7 Mon Sep 17 00:00:00 2001 From: Michelle Tang Date: Fri, 7 Mar 2025 15:15:22 -0500 Subject: [PATCH] Update various message request UI. --- .../conversation/ConversationHeaderView.java | 46 ++++++++++++------- .../conversation/v2/ConversationAdapterV2.kt | 22 +++++---- .../securesms/fonts/SignalSymbols.kt | 11 ++++- .../RecipientBottomSheetDialogFragment.kt | 2 + .../thoughtcrime/securesms/util/SpanUtil.java | 12 +++++ .../drawable/message_request_info_outline.xml | 2 +- .../drawable/release_header_background.xml | 15 ++---- .../res/drawable/symbol_group_question_16.xml | 30 ++++++++++++ .../res/layout/conversation_header_view.xml | 26 ++++------- .../conversation_item_thread_header.xml | 1 - app/src/main/res/values/dimens.xml | 4 ++ 11 files changed, 113 insertions(+), 58 deletions(-) create mode 100644 app/src/main/res/drawable/symbol_group_question_16.xml 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 b28da8ca8d..ae4321d3c4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationHeaderView.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationHeaderView.java @@ -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() 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 38097bbd0b..a256aae947 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 @@ -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 { diff --git a/app/src/main/java/org/thoughtcrime/securesms/fonts/SignalSymbols.kt b/app/src/main/java/org/thoughtcrime/securesms/fonts/SignalSymbols.kt index 9ba4dcee3c..43df9c171c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/fonts/SignalSymbols.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/fonts/SignalSymbols.kt @@ -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 diff --git a/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/bottomsheet/RecipientBottomSheetDialogFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/bottomsheet/RecipientBottomSheetDialogFragment.kt index 268db1dc62..8125cf3c96 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/bottomsheet/RecipientBottomSheetDialogFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/bottomsheet/RecipientBottomSheetDialogFragment.kt @@ -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 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 b915df0e66..b74c83f588 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/SpanUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/SpanUtil.java @@ -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); diff --git a/app/src/main/res/drawable/message_request_info_outline.xml b/app/src/main/res/drawable/message_request_info_outline.xml index 8ca7527dc0..96c7727fd4 100644 --- a/app/src/main/res/drawable/message_request_info_outline.xml +++ b/app/src/main/res/drawable/message_request_info_outline.xml @@ -1,5 +1,5 @@ - + \ No newline at end of file diff --git a/app/src/main/res/drawable/release_header_background.xml b/app/src/main/res/drawable/release_header_background.xml index bcd3166348..cff466b321 100644 --- a/app/src/main/res/drawable/release_header_background.xml +++ b/app/src/main/res/drawable/release_header_background.xml @@ -1,10 +1,5 @@ - - - + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/symbol_group_question_16.xml b/app/src/main/res/drawable/symbol_group_question_16.xml new file mode 100644 index 0000000000..5c593e40ac --- /dev/null +++ b/app/src/main/res/drawable/symbol_group_question_16.xml @@ -0,0 +1,30 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/conversation_header_view.xml b/app/src/main/res/layout/conversation_header_view.xml index 4cef223e82..7246d322f0 100644 --- a/app/src/main/res/layout/conversation_header_view.xml +++ b/app/src/main/res/layout/conversation_header_view.xml @@ -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" /> - - @@ -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" > 64dp + 24dp + 32dp + 308dp +