diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationAdapter.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationAdapter.java index 9f7e396496..49d8330cf4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationAdapter.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationAdapter.java @@ -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())); diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java index ff41271ae4..5cd14a6426 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java @@ -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 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; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItemDisplayMode.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItemDisplayMode.kt index ad03ab892b..feae8da7ce 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItemDisplayMode.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItemDisplayMode.kt @@ -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 + } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/PinnedMessagesBottomSheet.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/PinnedMessagesBottomSheet.kt index b8622c7d29..9141b83776 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/PinnedMessagesBottomSheet.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/PinnedMessagesBottomSheet.kt @@ -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(R.id.pinned_list).apply { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ScheduledMessagesBottomSheet.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/ScheduledMessagesBottomSheet.kt index 42870c9b5e..01888fdc70 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ScheduledMessagesBottomSheet.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ScheduledMessagesBottomSheet.kt @@ -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(R.id.scheduled_list).apply { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/quotes/MessageQuotesBottomSheet.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/quotes/MessageQuotesBottomSheet.kt index 82134a17d1..9bfe49788e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/quotes/MessageQuotesBottomSheet.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/quotes/MessageQuotesBottomSheet.kt @@ -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(R.id.quotes_list).apply { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/PinnedMessagesComponent.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/PinnedMessagesComponent.kt index 178f1ecfbb..1fb1e4c6a3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/PinnedMessagesComponent.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/PinnedMessagesComponent.kt @@ -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() } } } diff --git a/app/src/main/res/drawable/symbol_chat_arrow_24.xml b/app/src/main/res/drawable/symbol_chat_arrow_24.xml new file mode 100644 index 0000000000..2a03300044 --- /dev/null +++ b/app/src/main/res/drawable/symbol_chat_arrow_24.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/layout/conversation_item_received_multimedia.xml b/app/src/main/res/layout/conversation_item_received_multimedia.xml index 71c707915b..289243e6bf 100644 --- a/app/src/main/res/layout/conversation_item_received_multimedia.xml +++ b/app/src/main/res/layout/conversation_item_received_multimedia.xml @@ -320,6 +320,18 @@ android:tint="@color/signal_colorOnSurfaceVariant" app:srcCompat="@drawable/ic_replies_outline_20" /> + + + + + + + + + + + + + app:layout_constraintBottom_toTopOf="@+id/unpin_all_container" /> + + + +