Polish about sheet UX.

This commit is contained in:
Alex Hart
2024-01-17 11:24:25 -04:00
committed by Greyson Parrelli
parent 99f936ff97
commit 73d98da32b
9 changed files with 76 additions and 66 deletions

View File

@@ -323,9 +323,14 @@ class ConversationSettingsFragment : DSLSettingsFragment(
state.withRecipientSettingsState { state.withRecipientSettingsState {
customPref( customPref(
BioTextPreference.RecipientModel(recipient = state.recipient, onHeadlineClickListener = { BioTextPreference.RecipientModel(
AboutSheet.create(state.recipient).show(parentFragmentManager, null) recipient = state.recipient,
}) onHeadlineClickListener = if (state.recipient.isSelf || !state.recipient.isIndividual) {
null
} else {
{ AboutSheet.create(state.recipient).show(parentFragmentManager, null) }
}
)
) )
} }

View File

@@ -2,13 +2,14 @@ package org.thoughtcrime.securesms.components.settings.conversation.preferences
import android.content.ClipData import android.content.ClipData
import android.content.Context import android.content.Context
import android.graphics.drawable.InsetDrawable
import android.text.SpannableStringBuilder import android.text.SpannableStringBuilder
import android.view.View import android.view.View
import android.widget.TextView import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import org.signal.core.util.dp
import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.PreferenceModel import org.thoughtcrime.securesms.components.settings.PreferenceModel
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter
import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.util.ContextUtil import org.thoughtcrime.securesms.util.ContextUtil
import org.thoughtcrime.securesms.util.ServiceUtil import org.thoughtcrime.securesms.util.ServiceUtil
@@ -32,12 +33,12 @@ object BioTextPreference {
abstract fun getSubhead1Text(context: Context): String? abstract fun getSubhead1Text(context: Context): String?
abstract fun getSubhead2Text(): String? abstract fun getSubhead2Text(): String?
open val onHeadlineClickListener: () -> Unit = {} open val onHeadlineClickListener: (() -> Unit)? = null
} }
class RecipientModel( class RecipientModel(
private val recipient: Recipient, private val recipient: Recipient,
override val onHeadlineClickListener: () -> Unit override val onHeadlineClickListener: (() -> Unit)?
) : BioTextPreferenceModel<RecipientModel>() { ) : BioTextPreferenceModel<RecipientModel>() {
override fun getHeadlineText(context: Context): CharSequence { override fun getHeadlineText(context: Context): CharSequence {
@@ -56,8 +57,13 @@ object BioTextPreference {
SpanUtil.appendCenteredImageSpan(this, ContextUtil.requireDrawable(context, R.drawable.ic_official_28), 28, 28) SpanUtil.appendCenteredImageSpan(this, ContextUtil.requireDrawable(context, R.drawable.ic_official_28), 28, 28)
} }
if (recipient.isIndividual) { if (recipient.isIndividual && !recipient.isSelf) {
SpanUtil.appendCenteredImageSpan(this, ContextUtil.requireDrawable(context, R.drawable.symbol_chevron_right_24_color_on_secondary_container), 24, 24) val drawable = ContextUtil.requireDrawable(context, R.drawable.symbol_chevron_right_24_color_on_secondary_container)
drawable.setBounds(0, 0, 24.dp, 24.dp)
val insetDrawable = InsetDrawable(drawable, 0, 0, 0, 4.dp)
SpanUtil.appendBottomImageSpan(this, insetDrawable, 24, 28)
} }
} }
} }
@@ -70,11 +76,7 @@ object BioTextPreference {
} }
} }
override fun getSubhead2Text(): String? = if (recipient.shouldShowE164()) { override fun getSubhead2Text(): String? = null
recipient.e164.map(PhoneNumberFormatter::prettyPrint).orElse(null)
} else {
null
}
override fun areContentsTheSame(newItem: RecipientModel): Boolean { override fun areContentsTheSame(newItem: RecipientModel): Boolean {
return super.areContentsTheSame(newItem) && newItem.recipient.hasSameContent(recipient) return super.areContentsTheSame(newItem) && newItem.recipient.hasSameContent(recipient)
@@ -114,7 +116,11 @@ object BioTextPreference {
override fun bind(model: T) { override fun bind(model: T) {
headline.text = model.getHeadlineText(context) headline.text = model.getHeadlineText(context)
headline.setOnClickListener { model.onHeadlineClickListener() }
val clickListener = model.onHeadlineClickListener
if (clickListener != null) {
headline.setOnClickListener { clickListener() }
}
model.getSubhead1Text(context).let { model.getSubhead1Text(context).let {
subhead1.text = it subhead1.text = it

View File

@@ -584,7 +584,7 @@ class ConversationAdapterV2(
conversationBanner.hideSubtitle() conversationBanner.hideSubtitle()
} }
} else if (isSelf) { } else if (isSelf) {
conversationBanner.setSubtitle(context.getString(R.string.ConversationFragment__you_can_add_notes_for_yourself_in_this_conversation), R.drawable.symbol_person_light_24) conversationBanner.setSubtitle(context.getString(R.string.ConversationFragment__you_can_add_notes_for_yourself_in_this_conversation), R.drawable.symbol_note_light_24)
} else { } else {
val subtitle: String? = recipient.takeIf { it.shouldShowE164() }?.e164?.map { e164: String? -> PhoneNumberFormatter.prettyPrint(e164!!) }?.orElse(null) val subtitle: String? = recipient.takeIf { it.shouldShowE164() }?.e164?.map { e164: String? -> PhoneNumberFormatter.prettyPrint(e164!!) }?.orElse(null)
if (subtitle == null || subtitle == title) { if (subtitle == null || subtitle == title) {

View File

@@ -5,6 +5,7 @@ import android.content.ActivityNotFoundException;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.graphics.drawable.InsetDrawable;
import android.os.Bundle; import android.os.Bundle;
import android.text.SpannableStringBuilder; import android.text.SpannableStringBuilder;
import android.text.TextUtils; import android.text.TextUtils;
@@ -17,13 +18,13 @@ import android.widget.Toast;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.DialogFragment; import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment; import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
import org.signal.core.util.DimensionUnit;
import org.signal.core.util.logging.Log; import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.avatar.view.AvatarView; import org.thoughtcrime.securesms.avatar.view.AvatarView;
@@ -35,7 +36,6 @@ import org.thoughtcrime.securesms.contacts.avatars.FallbackContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.FallbackPhoto80dp; import org.thoughtcrime.securesms.contacts.avatars.FallbackPhoto80dp;
import org.thoughtcrime.securesms.groups.GroupId; import org.thoughtcrime.securesms.groups.GroupId;
import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientExporter; import org.thoughtcrime.securesms.recipients.RecipientExporter;
import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.recipients.RecipientId;
@@ -43,8 +43,6 @@ import org.thoughtcrime.securesms.recipients.RecipientUtil;
import org.thoughtcrime.securesms.recipients.ui.about.AboutSheet; import org.thoughtcrime.securesms.recipients.ui.about.AboutSheet;
import org.thoughtcrime.securesms.util.BottomSheetUtil; import org.thoughtcrime.securesms.util.BottomSheetUtil;
import org.thoughtcrime.securesms.util.ContextUtil; import org.thoughtcrime.securesms.util.ContextUtil;
import org.thoughtcrime.securesms.util.DrawableUtil;
import org.thoughtcrime.securesms.util.ServiceUtil;
import org.thoughtcrime.securesms.util.SpanUtil; import org.thoughtcrime.securesms.util.SpanUtil;
import org.thoughtcrime.securesms.util.ThemeUtil; import org.thoughtcrime.securesms.util.ThemeUtil;
import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.Util;
@@ -73,7 +71,6 @@ public final class RecipientBottomSheetDialogFragment extends BottomSheetDialogF
private AvatarView avatar; private AvatarView avatar;
private TextView fullName; private TextView fullName;
private TextView about; private TextView about;
private TextView usernameNumber;
private TextView blockButton; private TextView blockButton;
private TextView unblockButton; private TextView unblockButton;
private TextView addContactButton; private TextView addContactButton;
@@ -124,7 +121,6 @@ public final class RecipientBottomSheetDialogFragment extends BottomSheetDialogF
avatar = view.findViewById(R.id.rbs_recipient_avatar); avatar = view.findViewById(R.id.rbs_recipient_avatar);
fullName = view.findViewById(R.id.rbs_full_name); fullName = view.findViewById(R.id.rbs_full_name);
about = view.findViewById(R.id.rbs_about); about = view.findViewById(R.id.rbs_about);
usernameNumber = view.findViewById(R.id.rbs_username_number);
blockButton = view.findViewById(R.id.rbs_block_button); blockButton = view.findViewById(R.id.rbs_block_button);
unblockButton = view.findViewById(R.id.rbs_unblock_button); unblockButton = view.findViewById(R.id.rbs_unblock_button);
addContactButton = view.findViewById(R.id.rbs_add_contact_button); addContactButton = view.findViewById(R.id.rbs_add_contact_button);
@@ -186,20 +182,24 @@ public final class RecipientBottomSheetDialogFragment extends BottomSheetDialogF
: recipient.getDisplayName(requireContext()); : recipient.getDisplayName(requireContext());
fullName.setVisibility(TextUtils.isEmpty(name) ? View.GONE : View.VISIBLE); fullName.setVisibility(TextUtils.isEmpty(name) ? View.GONE : View.VISIBLE);
SpannableStringBuilder nameBuilder = new SpannableStringBuilder(name); SpannableStringBuilder nameBuilder = new SpannableStringBuilder(name);
if (recipient.isSystemContact() && !recipient.isSelf()) { if (recipient.showVerified()) {
Drawable systemContact = DrawableUtil.tint(ContextUtil.requireDrawable(requireContext(), R.drawable.ic_profile_circle_outline_16),
ContextCompat.getColor(requireContext(), R.color.signal_text_primary));
SpanUtil.appendCenteredImageSpan(nameBuilder, systemContact, 16, 16);
} else if (recipient.showVerified()) {
SpanUtil.appendCenteredImageSpan(nameBuilder, ContextUtil.requireDrawable(requireContext(), R.drawable.ic_official_28), 28, 28); SpanUtil.appendCenteredImageSpan(nameBuilder, ContextUtil.requireDrawable(requireContext(), R.drawable.ic_official_28), 28, 28);
} }
SpanUtil.appendCenteredImageSpan(nameBuilder, ContextUtil.requireDrawable(requireContext(), R.drawable.symbol_chevron_right_24_color_on_secondary_container), 24, 24); if (!recipient.isSelf() && recipient.isIndividual()) {
fullName.setText(nameBuilder); Drawable drawable = ContextUtil.requireDrawable(requireContext(), R.drawable.symbol_chevron_right_24_color_on_secondary_container);
fullName.setOnClickListener(v -> { drawable.setBounds(0, 0, (int) DimensionUnit.DP.toPixels(24), (int) DimensionUnit.DP.toPixels(24));
dismiss();
AboutSheet.create(recipient).show(getParentFragmentManager(), null); Drawable insetDrawable = new InsetDrawable(drawable, 0, 0, 0, (int) DimensionUnit.DP.toPixels(4));
});
SpanUtil.appendBottomImageSpan(nameBuilder, insetDrawable, 24, 28);
fullName.setText(nameBuilder);
fullName.setOnClickListener(v -> {
dismiss();
AboutSheet.create(recipient).show(getParentFragmentManager(), null);
});
}
String aboutText = recipient.getCombinedAboutAndEmoji(); String aboutText = recipient.getCombinedAboutAndEmoji();
if (recipient.isReleaseNotes()) { if (recipient.isReleaseNotes()) {
@@ -213,18 +213,6 @@ public final class RecipientBottomSheetDialogFragment extends BottomSheetDialogF
about.setVisibility(View.GONE); about.setVisibility(View.GONE);
} }
String usernameNumberString = recipient.hasAUserSetDisplayName(requireContext()) && !recipient.isSelf() && recipient.shouldShowE164()
? recipient.getSmsAddress().map(PhoneNumberFormatter::prettyPrint).orElse("").trim()
: "";
usernameNumber.setText(usernameNumberString);
usernameNumber.setVisibility(TextUtils.isEmpty(usernameNumberString) ? View.GONE : View.VISIBLE);
usernameNumber.setOnLongClickListener(v -> {
Util.copyToClipboard(v.getContext(), usernameNumber.getText().toString());
ServiceUtil.getVibrator(v.getContext()).vibrate(250);
Toast.makeText(v.getContext(), R.string.RecipientBottomSheet_copied_to_clipboard, Toast.LENGTH_SHORT).show();
return true;
});
noteToSelfDescription.setVisibility(recipient.isSelf() ? View.VISIBLE : View.GONE); noteToSelfDescription.setVisibility(recipient.isSelf() ? View.VISIBLE : View.GONE);
if (RecipientUtil.isBlockable(recipient)) { if (RecipientUtil.isBlockable(recipient)) {

View File

@@ -116,10 +116,14 @@ public final class SpanUtil {
} }
public static CharSequence buildImageSpan(@NonNull Drawable drawable) { public static CharSequence buildImageSpan(@NonNull Drawable drawable) {
SpannableString imageSpan = new SpannableString(" ");
int flag = Build.VERSION.SDK_INT >= 29 ? DynamicDrawableSpan.ALIGN_CENTER : DynamicDrawableSpan.ALIGN_BASELINE; int flag = Build.VERSION.SDK_INT >= 29 ? DynamicDrawableSpan.ALIGN_CENTER : DynamicDrawableSpan.ALIGN_BASELINE;
return buildImageSpan(drawable, flag);
}
private static CharSequence buildImageSpan(@NonNull Drawable drawable, int flag) {
SpannableString imageSpan = new SpannableString(" ");
imageSpan.setSpan(new ImageSpan(drawable, flag), 0, imageSpan.length(), 0); imageSpan.setSpan(new ImageSpan(drawable, flag), 0, imageSpan.length(), 0);
return imageSpan; return imageSpan;
@@ -143,6 +147,11 @@ public final class SpanUtil {
builder.append(" ").append(SpanUtil.buildCenteredImageSpan(drawable)); builder.append(" ").append(SpanUtil.buildCenteredImageSpan(drawable));
} }
public static void appendBottomImageSpan(@NonNull SpannableStringBuilder builder, @NonNull Drawable drawable, int width, int height) {
drawable.setBounds(0, 0, ViewUtil.dpToPx(width), ViewUtil.dpToPx(height));
builder.append(" ").append(SpanUtil.buildImageSpan(drawable, DynamicDrawableSpan.ALIGN_BOTTOM));
}
public static CharSequence learnMore(@NonNull Context context, public static CharSequence learnMore(@NonNull Context context,
@ColorInt int color, @ColorInt int color,
@NonNull View.OnClickListener onLearnMoreClicked) @NonNull View.OnClickListener onLearnMoreClicked)

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="M8 10c-0.41 0-0.75 0.34-0.75 0.75S7.59 11.5 8 11.5h8c0.41 0 0.75-0.34 0.75-0.75S16.41 10 16 10H8Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M7.25 14.25c0-0.41 0.34-0.75 0.75-0.75h8c0.41 0 0.75 0.34 0.75 0.75S16.41 15 16 15H8c-0.41 0-0.75-0.34-0.75-0.75Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M8 17c-0.41 0-0.75 0.34-0.75 0.75S7.59 18.5 8 18.5h5c0.41 0 0.75-0.34 0.75-0.75S13.41 17 13 17H8Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M9.27 1.75h5.46c0.81 0 1.47 0 2 0.04 0.55 0.05 1.03 0.14 1.47 0.37 0.7 0.36 1.28 0.93 1.64 1.64 0.23 0.44 0.32 0.92 0.37 1.47 0.04 0.53 0.04 1.19 0.04 2v9.46c0 0.82 0 1.47-0.04 2-0.05 0.55-0.14 1.03-0.37 1.47-0.36 0.7-0.93 1.28-1.64 1.64-0.44 0.23-0.92 0.32-1.47 0.37-0.53 0.04-1.19 0.04-2 0.04H9.27c-0.81 0-1.47 0-2-0.04-0.55-0.05-1.03-0.14-1.47-0.37-0.7-0.36-1.28-0.93-1.64-1.64-0.23-0.44-0.32-0.92-0.37-1.47-0.04-0.53-0.04-1.19-0.04-2V7.27c0-0.81 0-1.47 0.04-2C3.84 4.72 3.93 4.24 4.16 3.8 4.52 3.1 5.09 2.52 5.8 2.16c0.44-0.23 0.92-0.32 1.47-0.37 0.53-0.04 1.19-0.04 2-0.04ZM7.39 3.29c-0.45 0.04-0.71 0.1-0.91 0.2C6.06 3.72 5.7 4.07 5.5 4.49c-0.1 0.2-0.17 0.46-0.21 0.91L5.25 6.25h13.5c0-0.34-0.02-0.62-0.04-0.86-0.04-0.45-0.1-0.71-0.2-0.91-0.22-0.42-0.57-0.77-0.99-0.98-0.2-0.1-0.46-0.17-0.91-0.21-0.46-0.04-1.06-0.04-1.91-0.04H9.3c-0.85 0-1.45 0-1.9 0.04ZM5.25 16.7c0 0.85 0 1.45 0.04 1.9 0.04 0.46 0.1 0.72 0.2 0.92 0.22 0.42 0.57 0.77 0.99 0.98 0.2 0.1 0.46 0.17 0.91 0.21 0.46 0.04 1.06 0.04 1.91 0.04h5.4c0.85 0 1.45 0 1.9-0.04 0.46-0.04 0.72-0.1 0.92-0.2 0.42-0.22 0.77-0.57 0.98-0.99 0.1-0.2 0.17-0.46 0.21-0.91 0.04-0.46 0.04-1.06 0.04-1.91V7.75H5.25v8.95Z"/>
</vector>

View File

@@ -124,7 +124,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center" android:gravity="center"
android:textAppearance="@style/Signal.Text.MessageRequest.Subtitle" android:textAppearance="@style/Signal.Text.BodyMedium"
app:layout_constrainedWidth="true" app:layout_constrainedWidth="true"
app:layout_constraintBottom_toTopOf="@id/message_request_description" app:layout_constraintBottom_toTopOf="@id/message_request_description"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
@@ -139,7 +139,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="15dp" android:layout_marginTop="15dp"
android:gravity="center" android:gravity="center"
android:textAppearance="@style/Signal.Text.MessageRequest.Description" android:textAppearance="@style/Signal.Text.BodyMedium"
android:visibility="gone" android:visibility="gone"
app:layout_constrainedWidth="true" app:layout_constrainedWidth="true"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"

View File

@@ -74,22 +74,6 @@
app:layout_constraintTop_toBottomOf="@id/rbs_full_name" app:layout_constraintTop_toBottomOf="@id/rbs_full_name"
tools:text="🕷🕷🕷Hangin' on the web🕷🕷" /> tools:text="🕷🕷🕷Hangin' on the web🕷🕷" />
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/rbs_username_number"
style="@style/Signal.Text.BodyLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dsl_settings_gutter"
android:layout_marginTop="4dp"
android:layout_marginEnd="@dimen/dsl_settings_gutter"
android:textColor="@color/signal_text_secondary"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/rbs_about"
app:layout_goneMarginTop="8dp"
tools:text="\@spidergwen +1 555-654-6657" />
<TextView <TextView
android:id="@+id/rbs_note_to_self_description" android:id="@+id/rbs_note_to_self_description"
android:layout_width="0dp" android:layout_width="0dp"
@@ -106,7 +90,7 @@
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5" app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/rbs_username_number" app:layout_constraintTop_toBottomOf="@+id/rbs_about"
tools:visibility="visible" /> tools:visibility="visible" />
<LinearLayout <LinearLayout

View File

@@ -480,7 +480,7 @@
<string name="ConversationFragment_you_can_swipe_to_the_left_reply">You can swipe to the left on any message to quickly reply</string> <string name="ConversationFragment_you_can_swipe_to_the_left_reply">You can swipe to the left on any message to quickly reply</string>
<string name="ConversationFragment_view_once_media_is_deleted_after_sending">View-once media is deleted after sending</string> <string name="ConversationFragment_view_once_media_is_deleted_after_sending">View-once media is deleted after sending</string>
<string name="ConversationFragment_you_already_viewed_this_message">You already viewed this message</string> <string name="ConversationFragment_you_already_viewed_this_message">You already viewed this message</string>
<string name="ConversationFragment__you_can_add_notes_for_yourself_in_this_conversation">You can add notes for yourself in this chat.\nIf your account has any linked devices, new notes will be synced.</string> <string name="ConversationFragment__you_can_add_notes_for_yourself_in_this_conversation">You can add notes for yourself in this chat. If your account has any linked devices, new notes will be synced.</string>
<string name="ConversationFragment__d_group_members_have_the_same_name">%1$d group members have the same name.</string> <string name="ConversationFragment__d_group_members_have_the_same_name">%1$d group members have the same name.</string>
<string name="ConversationFragment__tap_to_review">Tap to review</string> <string name="ConversationFragment__tap_to_review">Tap to review</string>
<string name="ConversationFragment__review_requests_carefully">Review requests carefully</string> <string name="ConversationFragment__review_requests_carefully">Review requests carefully</string>