diff --git a/app/src/main/java/org/thoughtcrime/securesms/BindableConversationItem.java b/app/src/main/java/org/thoughtcrime/securesms/BindableConversationItem.java index 618c19d3c..17b2e8355 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/BindableConversationItem.java +++ b/app/src/main/java/org/thoughtcrime/securesms/BindableConversationItem.java @@ -37,7 +37,8 @@ public interface BindableConversationItem extends Unbindable { @NonNull Recipient recipients, @Nullable String searchQuery, boolean pulseMention, - boolean hasWallpaper); + boolean hasWallpaper, + boolean isMessageRequestAccepted); ConversationMessage getConversationMessage(); 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 d88baf1da..9b51a52e4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationAdapter.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationAdapter.java @@ -17,7 +17,6 @@ package org.thoughtcrime.securesms.conversation; import android.content.Context; -import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -44,6 +43,7 @@ import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.database.model.MessageRecord; import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.recipients.Recipient; +import org.thoughtcrime.securesms.recipients.RecipientUtil; import org.thoughtcrime.securesms.util.CachedInflater; import org.thoughtcrime.securesms.util.DateUtils; import org.thoughtcrime.securesms.util.StickyHeaderDecoration; @@ -112,6 +112,7 @@ public class ConversationAdapter private View footerView; private PagingController pagingController; private boolean hasWallpaper; + private boolean isMessageRequestAccepted; ConversationAdapter(@NonNull LifecycleOwner lifecycleOwner, @NonNull GlideRequests glideRequests, @@ -133,16 +134,17 @@ public class ConversationAdapter this.lifecycleOwner = lifecycleOwner; - this.glideRequests = glideRequests; - this.locale = locale; - this.clickListener = clickListener; - this.recipient = recipient; - this.selected = new HashSet<>(); - this.fastRecords = new ArrayList<>(); - this.releasedFastRecords = new HashSet<>(); - this.calendar = Calendar.getInstance(); - this.digest = getMessageDigestOrThrow(); - this.hasWallpaper = recipient.hasWallpaper(); + this.glideRequests = glideRequests; + this.locale = locale; + this.clickListener = clickListener; + this.recipient = recipient; + this.selected = new HashSet<>(); + this.fastRecords = new ArrayList<>(); + this.releasedFastRecords = new HashSet<>(); + this.calendar = Calendar.getInstance(); + this.digest = getMessageDigestOrThrow(); + this.hasWallpaper = recipient.hasWallpaper(); + this.isMessageRequestAccepted = true; setHasStableIds(true); } @@ -254,7 +256,8 @@ public class ConversationAdapter recipient, searchQuery, conversationMessage == recordToPulse, - hasWallpaper); + hasWallpaper, + isMessageRequestAccepted); if (conversationMessage == recordToPulse) { recordToPulse = null; @@ -595,6 +598,13 @@ public class ConversationAdapter return getItem(position - ((hasFooter() && position == getItemCount() - 1) ? 1 : 0)); } + public void setMessageRequestAccepted(boolean messageRequestAccepted) { + if (this.isMessageRequestAccepted != messageRequestAccepted) { + this.isMessageRequestAccepted = messageRequestAccepted; + notifyDataSetChanged(); + } + } + static class ConversationViewHolder extends RecyclerView.ViewHolder { public ConversationViewHolder(final @NonNull View itemView) { super(itemView); diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java index 328b606b3..1dc854ec0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java @@ -23,7 +23,6 @@ import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; import android.content.Intent; -import android.graphics.Rect; import android.net.Uri; import android.os.AsyncTask; import android.os.Build; @@ -105,6 +104,7 @@ import org.thoughtcrime.securesms.linkpreview.LinkPreview; import org.thoughtcrime.securesms.longmessage.LongMessageActivity; import org.thoughtcrime.securesms.mediasend.Media; import org.thoughtcrime.securesms.messagedetails.MessageDetailsActivity; +import org.thoughtcrime.securesms.messagerequests.MessageRequestState; import org.thoughtcrime.securesms.messagerequests.MessageRequestViewModel; import org.thoughtcrime.securesms.mms.GlideApp; import org.thoughtcrime.securesms.mms.OutgoingMediaMessage; @@ -426,6 +426,13 @@ public class ConversationFragment extends LoggingFragment { presentMessageRequestProfileView(requireContext(), recipientInfo, conversationBanner); presentMessageRequestProfileView(requireContext(), recipientInfo, emptyConversationBanner); }); + + messageRequestViewModel.getMessageData().observe(getViewLifecycleOwner(), data -> { + ConversationAdapter adapter = getListAdapter(); + if (adapter != null) { + adapter.setMessageRequestAccepted(data.getMessageState() == MessageRequestState.NONE); + } + }); } private static void presentMessageRequestProfileView(@NonNull Context context, @NonNull MessageRequestViewModel.RecipientInfo recipientInfo, @Nullable ConversationBannerView conversationBanner) { 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 45f31435a..1c5a3478f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java @@ -259,7 +259,8 @@ public final class ConversationItem extends RelativeLayout implements BindableCo @NonNull Recipient conversationRecipient, @Nullable String searchQuery, boolean pulse, - boolean hasWallpaper) + boolean hasWallpaper, + boolean isMessageRequestAccepted) { if (this.recipient != null) this.recipient.removeForeverObserver(this); if (this.conversationRecipient != null) this.conversationRecipient.removeForeverObserver(this); @@ -280,8 +281,8 @@ public final class ConversationItem extends RelativeLayout implements BindableCo setGutterSizes(messageRecord, groupThread); setMessageShape(messageRecord, previousMessageRecord, nextMessageRecord, groupThread); - setMediaAttributes(messageRecord, previousMessageRecord, nextMessageRecord, conversationRecipient, groupThread, hasWallpaper); - setBodyText(messageRecord, searchQuery); + setMediaAttributes(messageRecord, previousMessageRecord, nextMessageRecord, groupThread, hasWallpaper, isMessageRequestAccepted); + setBodyText(messageRecord, searchQuery, isMessageRequestAccepted); setBubbleState(messageRecord, hasWallpaper); setInteractionState(conversationMessage, pulse); setStatusIcons(messageRecord, hasWallpaper); @@ -627,7 +628,8 @@ public final class ConversationItem extends RelativeLayout implements BindableCo } private void setBodyText(@NonNull MessageRecord messageRecord, - @Nullable String searchQuery) + @Nullable String searchQuery, + boolean messageRequestAccepted) { bodyText.setClickable(false); bodyText.setFocusable(false); @@ -649,7 +651,10 @@ public final class ConversationItem extends RelativeLayout implements BindableCo } else if (isCaptionlessMms(messageRecord)) { bodyText.setVisibility(View.GONE); } else { - Spannable styledText = linkifyMessageBody(conversationMessage.getDisplayBody(getContext()), batchSelected.isEmpty()); + Spannable styledText = conversationMessage.getDisplayBody(getContext()); + if (messageRequestAccepted) { + linkifyMessageBody(styledText, batchSelected.isEmpty()); + } styledText = SearchUtil.getHighlightedSpan(locale, () -> new BackgroundColorSpan(Color.YELLOW), styledText, searchQuery); styledText = SearchUtil.getHighlightedSpan(locale, () -> new ForegroundColorSpan(Color.BLACK), styledText, searchQuery); @@ -673,9 +678,9 @@ public final class ConversationItem extends RelativeLayout implements BindableCo private void setMediaAttributes(@NonNull MessageRecord messageRecord, @NonNull Optional previousRecord, @NonNull Optional nextRecord, - @NonNull Recipient conversationRecipient, boolean isGroupThread, - boolean hasWallpaper) + boolean hasWallpaper, + boolean messageRequestAccepted) { boolean showControls = !messageRecord.isFailed(); @@ -717,7 +722,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); ViewUtil.updateLayoutParamsIfNonNull(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); footer.setVisibility(GONE); - } else if (hasLinkPreview(messageRecord)) { + } else if (hasLinkPreview(messageRecord) && messageRequestAccepted) { linkPreviewStub.get().setVisibility(View.VISIBLE); if (audioViewStub.resolved()) audioViewStub.get().setVisibility(View.GONE); if (mediaThumbnailStub.resolved()) mediaThumbnailStub.get().setVisibility(View.GONE); @@ -982,8 +987,8 @@ public final class ConversationItem extends RelativeLayout implements BindableCo contactPhoto.setAvatar(glideRequests, recipient, false); } - private SpannableString linkifyMessageBody(@NonNull SpannableString messageBody, - boolean shouldLinkifyAllLinks) + private void linkifyMessageBody(@NonNull Spannable messageBody, + boolean shouldLinkifyAllLinks) { int linkPattern = Linkify.WEB_URLS | Linkify.EMAIL_ADDRESSES | Linkify.PHONE_NUMBERS; boolean hasLinks = Linkify.addLinks(messageBody, shouldLinkifyAllLinks ? linkPattern : 0); @@ -1007,8 +1012,6 @@ public final class ConversationItem extends RelativeLayout implements BindableCo for (Annotation annotation : mentionAnnotations) { messageBody.setSpan(new MentionClickableSpan(RecipientId.from(annotation.getValue())), messageBody.getSpanStart(annotation), messageBody.getSpanEnd(annotation), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } - - return messageBody; } private void setStatusIcons(MessageRecord messageRecord, boolean hasWallpaper) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationUpdateItem.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationUpdateItem.java index e478eab91..183bdc86d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationUpdateItem.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationUpdateItem.java @@ -100,7 +100,8 @@ public final class ConversationUpdateItem extends FrameLayout @NonNull Recipient conversationRecipient, @Nullable String searchQuery, boolean pulseMention, - boolean hasWallpaper) + boolean hasWallpaper, + boolean isMessageRequestAccepted) { this.batchSelected = batchSelected; diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationViewModel.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationViewModel.java index b8e565b82..37b4bd69a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationViewModel.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationViewModel.java @@ -19,9 +19,9 @@ import org.thoughtcrime.securesms.database.DatabaseObserver; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; import org.thoughtcrime.securesms.mediasend.Media; import org.thoughtcrime.securesms.mediasend.MediaRepository; -import org.thoughtcrime.securesms.recipients.LiveRecipient; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientId; +import org.thoughtcrime.securesms.recipients.RecipientUtil; import org.thoughtcrime.securesms.util.livedata.LiveDataUtil; import org.thoughtcrime.securesms.wallpaper.ChatWallpaper; import org.whispersystems.libsignal.util.Pair; diff --git a/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageHeaderViewHolder.java b/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageHeaderViewHolder.java index 267403a77..4f63908f6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageHeaderViewHolder.java +++ b/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageHeaderViewHolder.java @@ -88,7 +88,7 @@ final class MessageHeaderViewHolder extends RecyclerView.ViewHolder { conversationItem = (ConversationItem) receivedStub.inflate(); } } - conversationItem.bind(lifecycleOwner, conversationMessage, Optional.absent(), Optional.absent(), glideRequests, Locale.getDefault(), new HashSet<>(), conversationMessage.getMessageRecord().getRecipient(), null, false, false); + conversationItem.bind(lifecycleOwner, conversationMessage, Optional.absent(), Optional.absent(), glideRequests, Locale.getDefault(), new HashSet<>(), conversationMessage.getMessageRecord().getRecipient(), null, false, false, false); } private void bindErrorState(MessageRecord messageRecord) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/livedata/LiveDataUtil.java b/app/src/main/java/org/thoughtcrime/securesms/util/livedata/LiveDataUtil.java index f7ac85ab5..d19453ce0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/livedata/LiveDataUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/livedata/LiveDataUtil.java @@ -198,6 +198,22 @@ public final class LiveDataUtil { return outputLiveData; } + /** + * Observes a source until the predicate is met. The final value matching the predicate is emitted. + */ + public static @NonNull LiveData until(@NonNull LiveData source, @NonNull Predicate predicate) { + MediatorLiveData mediator = new MediatorLiveData<>(); + + mediator.addSource(source, newValue -> { + mediator.setValue(newValue); + if (predicate.test(newValue)) { + mediator.removeSource(source); + } + }); + + return mediator; + } + public interface Combine { @NonNull R apply(@NonNull A a, @NonNull B b); }