Add go to indicator for pinned messages.

This commit is contained in:
Michelle Tang
2025-11-26 11:06:07 -05:00
committed by jeffrey-signal
parent 8e2f2b8d1a
commit 864867f60e
13 changed files with 113 additions and 15 deletions

View File

@@ -326,7 +326,7 @@ public class ConversationAdapter
if (conversationMessage == null) return -1;
if (displayMode.getScheduleMessageMode()) {
if (displayMode.getMessageMode() == ConversationItemDisplayMode.MessageMode.SCHEDULED) {
calendar.setTimeInMillis(((MmsMessageRecord) conversationMessage.getMessageRecord()).getScheduledDate());
} else if (displayMode == ConversationItemDisplayMode.EditHistory.INSTANCE) {
calendar.setTimeInMillis(conversationMessage.getMessageRecord().getDateSent());
@@ -346,7 +346,7 @@ public class ConversationAdapter
Context context = viewHolder.itemView.getContext();
ConversationMessage conversationMessage = Objects.requireNonNull(getItem(position));
if (displayMode.getScheduleMessageMode()) {
if (displayMode.getMessageMode() == ConversationItemDisplayMode.MessageMode.SCHEDULED) {
viewHolder.setText(DateUtils.getScheduledMessagesDateHeaderString(viewHolder.itemView.getContext(), locale, ((MmsMessageRecord) conversationMessage.getMessageRecord()).getScheduledDate()));
} else if (displayMode == ConversationItemDisplayMode.EditHistory.INSTANCE) {
viewHolder.setText(DateUtils.getConversationDateHeaderString(viewHolder.itemView.getContext(), locale, conversationMessage.getMessageRecord().getDateSent()));

View File

@@ -221,6 +221,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
private TextView storyReactionLabel;
private View quotedIndicator;
private View scheduledIndicator;
private View goToPinnedIndicator;
private @NonNull Set<MultiselectPart> batchSelected = new HashSet<>();
private final @NonNull Outliner outliner = new Outliner();
@@ -359,6 +360,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
this.paymentViewStub = new Stub<>(findViewById(R.id.payment_view_stub));
this.scheduledIndicator = findViewById(R.id.scheduled_indicator);
this.pollView = new Stub<>(findViewById(R.id.poll));
this.goToPinnedIndicator = findViewById(R.id.go_to_pinned_indicator);
setOnClickListener(new ClickListener(null));
@@ -424,6 +426,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
setStoryReactionLabel(messageRecord);
setHasBeenQuoted(conversationMessage);
setHasBeenScheduled(conversationMessage);
setHasBeenPinned(conversationMessage);
setPoll(messageRecord, messageRecord.getToRecipient().getChatColors().asSingleColor());
if (audioViewStub.resolved()) {
@@ -1260,7 +1263,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
ViewUtil.updateLayoutParamsIfNonNull(groupSenderHolder, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
ViewUtil.setTopMargin(linkPreviewStub.get(), 0);
} else {
linkPreviewStub.get().setLinkPreview(requestManager, linkPreview, true, !isContentCondensed(), displayMode.getScheduleMessageMode());
linkPreviewStub.get().setLinkPreview(requestManager, linkPreview, true, !isContentCondensed(), displayMode.getMessageMode() == ConversationItemDisplayMode.MessageMode.SCHEDULED);
linkPreviewStub.get().setDownloadClickedListener(downloadClickListener);
setLinkPreviewCorners(messageRecord, previousRecord, nextRecord, isGroupThread, false);
ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
@@ -1920,6 +1923,17 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
}
}
private void setHasBeenPinned(@NonNull ConversationMessage message) {
if (goToPinnedIndicator == null) {
return;
}
if (message.getMessageRecord().getPinnedUntil() > 0 && displayMode.getMessageMode() == ConversationItemDisplayMode.MessageMode.PINNED) {
goToPinnedIndicator.setVisibility(View.VISIBLE);
} else {
goToPinnedIndicator.setVisibility(View.GONE);
}
}
private boolean forceFooter(@NonNull MessageRecord messageRecord) {
return hasAudio(messageRecord) || MessageRecordUtil.isEditMessage(messageRecord) || displayMode == ConversationItemDisplayMode.EditHistory.INSTANCE || messageRecord.getPinnedUntil() > 0;
}

View File

@@ -1,11 +1,11 @@
package org.thoughtcrime.securesms.conversation
sealed class ConversationItemDisplayMode(val scheduleMessageMode: Boolean = false) {
sealed class ConversationItemDisplayMode(val messageMode: MessageMode = MessageMode.STANDARD) {
/** Normal rendering, used for normal bubbles in the conversation view */
object Standard : ConversationItemDisplayMode()
/** Smaller bubbles, often trimming text and shrinking images. Used for quote threads. */
class Condensed(scheduleMessageMode: Boolean) : ConversationItemDisplayMode(scheduleMessageMode)
class Condensed(messageMode: MessageMode) : ConversationItemDisplayMode(messageMode)
/** Smaller bubbles, always singular bubbles, with a footer. Used for edit message history. */
object EditHistory : ConversationItemDisplayMode()
@@ -16,4 +16,10 @@ sealed class ConversationItemDisplayMode(val scheduleMessageMode: Boolean = fals
fun displayWallpaper(): Boolean {
return this == Standard || this == Detailed
}
enum class MessageMode {
SCHEDULED,
PINNED,
STANDARD
}
}

View File

@@ -76,7 +76,7 @@ class PinnedMessagesBottomSheet : FixedRoundedCornerBottomSheetDialogFragment()
val colorizer = Colorizer()
messageAdapter = ConversationAdapter(requireContext(), viewLifecycleOwner, Glide.with(this), Locale.getDefault(), ConversationAdapterListener(), conversationRecipient.hasWallpaper, colorizer).apply {
setCondensedMode(ConversationItemDisplayMode.Condensed(scheduleMessageMode = false))
setCondensedMode(ConversationItemDisplayMode.Condensed(ConversationItemDisplayMode.MessageMode.PINNED))
}
val list: RecyclerView = view.findViewById<RecyclerView>(R.id.pinned_list).apply {

View File

@@ -92,7 +92,7 @@ class ScheduledMessagesBottomSheet : FixedRoundedCornerBottomSheetDialogFragment
val colorizer = Colorizer()
messageAdapter = ConversationAdapter(requireContext(), viewLifecycleOwner, Glide.with(this), Locale.getDefault(), ConversationAdapterListener(), conversationRecipient.hasWallpaper, colorizer).apply {
setCondensedMode(ConversationItemDisplayMode.Condensed(scheduleMessageMode = true))
setCondensedMode(ConversationItemDisplayMode.Condensed(ConversationItemDisplayMode.MessageMode.SCHEDULED))
}
val list: RecyclerView = view.findViewById<RecyclerView>(R.id.scheduled_list).apply {

View File

@@ -77,7 +77,7 @@ class MessageQuotesBottomSheet : FixedRoundedCornerBottomSheetDialogFragment() {
val colorizer = Colorizer()
messageAdapter = ConversationAdapter(requireContext(), viewLifecycleOwner, Glide.with(this), Locale.getDefault(), ConversationAdapterListener(), conversationRecipient.hasWallpaper, colorizer).apply {
setCondensedMode(ConversationItemDisplayMode.Condensed(scheduleMessageMode = false))
setCondensedMode(ConversationItemDisplayMode.Condensed(ConversationItemDisplayMode.MessageMode.STANDARD))
}
val list: RecyclerView = view.findViewById<RecyclerView>(R.id.quotes_list).apply {

View File

@@ -75,7 +75,7 @@ fun PinnedMessagesBanner(
val (glyph, body, showThumbnail) = getMessageMetadata(conversationMessage)
Column {
HorizontalDivider()
HorizontalDivider(thickness = 1.dp)
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
@@ -154,7 +154,7 @@ fun PinnedMessagesBanner(
if (canUnpin) {
DropdownMenus.ItemWithIcon(menuController, R.drawable.symbol_pin_slash_24, R.string.PinnedMessage__unpin_message) { onUnpinMessage(message.id) }
}
DropdownMenus.ItemWithIcon(menuController, R.drawable.symbol_chat_24, R.string.PinnedMessage__go_to_message) { onGoToMessage(message.id) }
DropdownMenus.ItemWithIcon(menuController, R.drawable.symbol_chat_arrow_24, R.string.PinnedMessage__go_to_message) { onGoToMessage(message.id) }
DropdownMenus.ItemWithIcon(menuController, R.drawable.symbol_list_bullet_24, R.string.PinnedMessage__view_all_messages) { onViewAllMessages() }
}
}

View File

@@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M1.875,12C1.875,6.408 6.408,1.875 12,1.875C17.592,1.875 22.125,6.408 22.125,12C22.125,17.592 17.592,22.125 12,22.125C10.329,22.125 8.75,21.719 7.359,21.001L3.296,22.463C2.202,22.858 1.143,21.799 1.537,20.704L2.999,16.641C2.281,15.25 1.875,13.671 1.875,12ZM12,3.625C7.375,3.625 3.625,7.375 3.625,12C3.625,13.432 3.984,14.777 4.615,15.954C4.796,16.291 4.838,16.7 4.701,17.082L3.453,20.547L6.918,19.299C7.3,19.162 7.71,19.204 8.047,19.385C9.223,20.017 10.568,20.375 12,20.375C16.625,20.375 20.375,16.625 20.375,12C20.375,7.375 16.625,3.625 12,3.625Z"
android:fillColor="#000000"/>
<path
android:pathData="M11.756,7.631C12.098,7.29 12.652,7.29 12.994,7.631L16.744,11.381C16.908,11.545 17,11.768 17,12C17,12.232 16.908,12.455 16.744,12.619L12.994,16.369C12.652,16.71 12.098,16.71 11.756,16.369C11.415,16.027 11.415,15.473 11.756,15.131L12.375,14.51C13.008,13.877 13.659,13.346 14.421,12.847L14.389,12.776C13.774,12.848 13.17,12.875 12.375,12.875H7.625C7.142,12.875 6.75,12.483 6.75,12C6.75,11.517 7.142,11.125 7.625,11.125H12.375C13.17,11.125 13.774,11.151 14.389,11.224L14.421,11.152C13.659,10.654 13.008,10.123 12.375,9.49L11.756,8.869C11.415,8.527 11.415,7.973 11.756,7.631Z"
android:fillColor="#1B1B1D"/>
</vector>

View File

@@ -320,6 +320,18 @@
android:tint="@color/signal_colorOnSurfaceVariant"
app:srcCompat="@drawable/ic_replies_outline_20" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/go_to_pinned_indicator"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_gravity="center_vertical"
android:background="@drawable/circle_tintable"
android:backgroundTint="@color/signal_colorSurfaceVariant"
android:padding="6dp"
android:tint="@color/signal_colorOnSurfaceVariant"
android:visibility="gone"
app:srcCompat="@drawable/symbol_chat_arrow_24" />
</FrameLayout>
<org.thoughtcrime.securesms.reactions.ReactionsConversationView

View File

@@ -35,6 +35,28 @@
</FrameLayout>
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignEnd="@id/body_bubble"
android:layout_alignTop="@id/body_bubble"
android:layout_alignBottom="@id/body_bubble"
android:layout_marginEnd="-42dp" >
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/go_to_pinned_indicator"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_gravity="center_vertical"
android:background="@drawable/circle_tintable"
android:backgroundTint="@color/signal_colorSurfaceVariant"
android:padding="6dp"
android:tint="@color/signal_colorOnSurfaceVariant"
android:visibility="gone"
app:srcCompat="@drawable/symbol_chat_arrow_24" />
</FrameLayout>
<FrameLayout
android:id="@+id/contact_photo_container"
android:layout_width="@dimen/conversation_item_avatar_size"

View File

@@ -264,6 +264,18 @@
android:tint="@color/signal_colorOnSurfaceVariant"
app:srcCompat="@drawable/symbol_calendar_24" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/go_to_pinned_indicator"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_gravity="center_vertical"
android:background="@drawable/circle_tintable"
android:backgroundTint="@color/signal_colorSurfaceVariant"
android:padding="6dp"
android:tint="@color/signal_colorOnSurfaceVariant"
android:visibility="gone"
app:srcCompat="@drawable/symbol_chat_arrow_24" />
</FrameLayout>
<org.thoughtcrime.securesms.reactions.ReactionsConversationView

View File

@@ -127,6 +127,18 @@
android:tint="@color/signal_colorOnSurfaceVariant"
app:srcCompat="@drawable/symbol_calendar_24" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/go_to_pinned_indicator"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_gravity="center_vertical"
android:background="@drawable/circle_tintable"
android:backgroundTint="@color/signal_colorSurfaceVariant"
android:padding="6dp"
android:tint="@color/signal_colorOnSurfaceVariant"
android:visibility="gone"
app:srcCompat="@drawable/symbol_chat_arrow_24" />
</FrameLayout>
<org.thoughtcrime.securesms.reactions.ReactionsConversationView

View File

@@ -43,23 +43,31 @@
android:id="@+id/pinned_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="40dp"
android:clipToPadding="false"
app:layout_constrainedHeight="true"
app:layout_constraintTop_toBottomOf="@id/pinned_message_header"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toTopOf="@+id/unpin_all" />
app:layout_constraintBottom_toTopOf="@+id/unpin_all_container" />
<FrameLayout
android:id="@+id/unpin_all_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/signal_colorSurface"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent">
<com.google.android.material.button.MaterialButton
android:id="@+id/unpin_all"
style="@style/Signal.Widget.Button.Large.Tonal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginVertical="8dp"
android:layout_marginHorizontal="32dp"
android:text="@string/PinnedMessage__unpin_all_messages" />
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>