diff --git a/app/src/main/java/im/conversations/android/database/model/MessageWithContentReactions.java b/app/src/main/java/im/conversations/android/database/model/MessageWithContentReactions.java index f366c254e..9eec214e5 100644 --- a/app/src/main/java/im/conversations/android/database/model/MessageWithContentReactions.java +++ b/app/src/main/java/im/conversations/android/database/model/MessageWithContentReactions.java @@ -96,15 +96,34 @@ public final class MessageWithContentReactions public String textContent() { final var content = Iterables.getFirst(this.contents, null); - final var text = Strings.nullToEmpty(content == null ? null : content.body); - return text; - // return text.substring(0,Math.min(text.length(),20)); + return Strings.nullToEmpty(content == null ? null : content.body); } public boolean hasPreview() { return Iterables.tryFind(this.contents, c -> c.type == PartType.FILE).isPresent(); } + public boolean hasInReplyTo() { + return this.inReplyTo != null; + } + + public Instant inReplyToSentAt() { + return this.inReplyTo == null ? null : this.inReplyTo.sentAt; + } + + public String inReplyToSender() { + return this.inReplyTo == null ? null : this.inReplyTo.fromResource; + } + + public String inReplyToTextContent() { + final var inReplyTo = this.inReplyTo; + if (inReplyTo == null) { + return null; + } + final var content = Iterables.getFirst(inReplyTo.contents, null); + return Strings.nullToEmpty(content == null ? null : content.body); + } + public AddressWithName getAddressWithName() { if (isKnownSender()) { return new AddressWithName(individualAddress(), individualName()); diff --git a/app/src/main/java/im/conversations/android/ui/adapter/MessageAdapter.java b/app/src/main/java/im/conversations/android/ui/adapter/MessageAdapter.java index 71e3a1d77..dbfe3f920 100644 --- a/app/src/main/java/im/conversations/android/ui/adapter/MessageAdapter.java +++ b/app/src/main/java/im/conversations/android/ui/adapter/MessageAdapter.java @@ -15,6 +15,7 @@ import im.conversations.android.databinding.ItemMessageReceivedBinding; import im.conversations.android.databinding.ItemMessageSentBinding; import im.conversations.android.databinding.ItemMessageSeparatorBinding; import im.conversations.android.ui.AvatarFetcher; +import java.util.function.Consumer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -27,6 +28,8 @@ public class MessageAdapter private static final Logger LOGGER = LoggerFactory.getLogger(MessageAdapter.class); + private Consumer onNavigateToInReplyTo; + public MessageAdapter(@NonNull DiffUtil.ItemCallback diffCallback) { super(diffCallback); } @@ -90,7 +93,12 @@ public class MessageAdapter @NonNull AbstractMessageViewHolder holder, @NonNull final MessageWithContentReactions message) { holder.setItem(message); + final var inReplyTo = message.inReplyTo; if (holder instanceof MessageReceivedViewHolder messageReceivedViewHolder) { + if (inReplyTo != null) { + messageReceivedViewHolder.binding.embeddedMessage.setOnClickListener( + view -> onNavigateToInReplyTo.accept(inReplyTo.id)); + } final var addressWithName = message.getAddressWithName(); final var avatar = message.getAvatar(); if (avatar != null) { @@ -98,9 +106,18 @@ public class MessageAdapter } else { AvatarFetcher.setDefault(messageReceivedViewHolder.binding.avatar, addressWithName); } + } else if (holder instanceof MessageSentViewHolder messageSentViewHolder) { + if (inReplyTo != null) { + messageSentViewHolder.binding.embeddedMessage.setOnClickListener( + view -> onNavigateToInReplyTo.accept(inReplyTo.id)); + } } } + public void setOnNavigateToInReplyTo(final Consumer consumer) { + this.onNavigateToInReplyTo = consumer; + } + protected abstract static class AbstractMessageViewHolder extends RecyclerView.ViewHolder { private AbstractMessageViewHolder(@NonNull View itemView) { diff --git a/app/src/main/java/im/conversations/android/ui/fragment/main/ChatFragment.java b/app/src/main/java/im/conversations/android/ui/fragment/main/ChatFragment.java index 8940ccbe1..45f707040 100644 --- a/app/src/main/java/im/conversations/android/ui/fragment/main/ChatFragment.java +++ b/app/src/main/java/im/conversations/android/ui/fragment/main/ChatFragment.java @@ -53,6 +53,7 @@ public class ChatFragment extends Fragment { this.binding.messages.setLayoutManager(linearLayoutManager); this.recyclerViewScroller = new RecyclerViewScroller(this.binding.messages); this.messageAdapter = new MessageAdapter(new MessageComparator()); + this.messageAdapter.setOnNavigateToInReplyTo(this::onNavigateToInReplyTo); this.binding.messages.setAdapter(this.messageAdapter); this.chatViewModel.getMessages().observe(getViewLifecycleOwner(), this::submitPagingData); @@ -64,10 +65,6 @@ public class ChatFragment extends Fragment { NavControllers.findNavController(requireActivity(), R.id.nav_host_fragment) .popBackStack(); }); - this.binding.addContent.setOnClickListener( - v -> { - scrollToMessageId(1039); - }); this.binding.messageLayout.setEndIconOnClickListener( v -> { this.scrollToPositionToEnd(); @@ -76,6 +73,10 @@ public class ChatFragment extends Fragment { return this.binding.getRoot(); } + private void onNavigateToInReplyTo(long messageId) { + this.scrollToMessageId(messageId); + } + private void submitPagingData(final Boolean isShowDateSeparators) { final var pagingData = this.chatViewModel.getMessages().getValue(); if (pagingData == null) { diff --git a/app/src/main/res/layout/item_message_received.xml b/app/src/main/res/layout/item_message_received.xml index 6bb995f04..f4e1c7ce1 100644 --- a/app/src/main/res/layout/item_message_received.xml +++ b/app/src/main/res/layout/item_message_received.xml @@ -34,6 +34,53 @@ app:layout_constraintTop_toTopOf="parent" app:layout_constraintWidth_max="@dimen/message_bubble_max_width"> + + + + + + + + + + + + + + + + + + -