From c131fb500d035bc41101f8d7aaeb046513418b49 Mon Sep 17 00:00:00 2001 From: Veniamin Vynohradov Date: Mon, 19 Sep 2022 21:32:21 +0300 Subject: [PATCH] Add 'detailed' conversation style to show full file names. Fixes #12442 Closes #12463 --- .../securesms/BindableConversationItem.java | 3 +- .../securesms/components/DocumentView.java | 14 ++++++- .../conversation/ConversationAdapter.java | 4 +- .../conversation/ConversationItem.java | 38 ++++++++++--------- .../ConversationItemDisplayMode.kt | 10 +++++ .../conversation/ConversationUpdateItem.java | 6 +-- .../MessageHeaderViewHolder.java | 3 +- app/src/main/res/layout/document_view.xml | 2 - 8 files changed, 52 insertions(+), 28 deletions(-) create mode 100644 app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItemDisplayMode.kt diff --git a/app/src/main/java/org/thoughtcrime/securesms/BindableConversationItem.java b/app/src/main/java/org/thoughtcrime/securesms/BindableConversationItem.java index 502fff0630..348c914dee 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/BindableConversationItem.java +++ b/app/src/main/java/org/thoughtcrime/securesms/BindableConversationItem.java @@ -13,6 +13,7 @@ import org.thoughtcrime.securesms.contactshare.Contact; import org.thoughtcrime.securesms.conversation.ConversationMessage; import org.thoughtcrime.securesms.conversation.colors.Colorizable; import org.thoughtcrime.securesms.conversation.colors.Colorizer; +import org.thoughtcrime.securesms.conversation.ConversationItemDisplayMode; import org.thoughtcrime.securesms.conversation.mutiselect.MultiselectPart; import org.thoughtcrime.securesms.conversation.mutiselect.Multiselectable; import org.thoughtcrime.securesms.database.model.InMemoryMessageRecord; @@ -47,7 +48,7 @@ public interface BindableConversationItem extends Unbindable, GiphyMp4Playable, boolean isMessageRequestAccepted, boolean canPlayInline, @NonNull Colorizer colorizer, - boolean isCondensedMode); + @NonNull ConversationItemDisplayMode displayMode); @NonNull ConversationMessage getConversationMessage(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/DocumentView.java b/app/src/main/java/org/thoughtcrime/securesms/components/DocumentView.java index ff66b08a42..44fc289681 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/DocumentView.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/DocumentView.java @@ -90,7 +90,8 @@ public class DocumentView extends FrameLayout { } public void setDocument(final @NonNull Slide documentSlide, - final boolean showControls) + final boolean showControls, + final boolean showSingleLineFilename) { if (showControls && documentSlide.isPendingDownload()) { controlToggle.displayQuick(downloadButton); @@ -106,6 +107,11 @@ public class DocumentView extends FrameLayout { this.documentSlide = documentSlide; + // Android OS filenames are limited to 256 characters, so + // we don't need an additional max characters/lines constraint when + // [showSingleLineFilename] is false. + this.fileName.setSingleLine(showSingleLineFilename); + this.fileName.setText(OptionalUtil.or(documentSlide.getFileName(), documentSlide.getCaption()) .orElse(getContext().getString(R.string.DocumentView_unnamed_file))); @@ -114,6 +120,12 @@ public class DocumentView extends FrameLayout { this.setOnClickListener(new OpenClickedListener(documentSlide)); } + public void setDocument(final @NonNull Slide documentSlide, + final boolean showControls) + { + setDocument(documentSlide, showControls, true); + } + @Override public void setFocusable(boolean focusable) { super.setFocusable(focusable); 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 f793085ccd..272168337c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationAdapter.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationAdapter.java @@ -280,6 +280,8 @@ public class ConversationAdapter ConversationMessage previousMessage = adapterPosition < getItemCount() - 1 && !isFooterPosition(adapterPosition + 1) ? getItem(adapterPosition + 1) : null; ConversationMessage nextMessage = adapterPosition > 0 && !isHeaderPosition(adapterPosition - 1) ? getItem(adapterPosition - 1) : null; + ConversationItemDisplayMode displayMode = condensedMode ? ConversationItemDisplayMode.CONDENSED : ConversationItemDisplayMode.STANDARD; + conversationViewHolder.getBindable().bind(lifecycleOwner, conversationMessage, Optional.ofNullable(previousMessage != null ? previousMessage.getMessageRecord() : null), @@ -294,7 +296,7 @@ public class ConversationAdapter isMessageRequestAccepted, conversationMessage == inlineContent, colorizer, - condensedMode); + displayMode); if (conversationMessage == recordToPulse) { recordToPulse = null; 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 7272b35f65..f8dc9f066d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java @@ -18,7 +18,6 @@ package org.thoughtcrime.securesms.conversation; import android.animation.ValueAnimator; import android.annotation.SuppressLint; -import android.app.Activity; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; @@ -114,7 +113,6 @@ import org.thoughtcrime.securesms.jobs.SmsSendJob; import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.linkpreview.LinkPreview; import org.thoughtcrime.securesms.mediapreview.MediaIntentFactory; -import org.thoughtcrime.securesms.mediapreview.MediaPreviewV2Activity; import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.mms.ImageSlide; import org.thoughtcrime.securesms.mms.PartAuthority; @@ -130,7 +128,6 @@ import org.thoughtcrime.securesms.recipients.RecipientForeverObserver; import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.revealable.ViewOnceMessageView; import org.thoughtcrime.securesms.util.DateUtils; -import org.thoughtcrime.securesms.util.FeatureFlags; import org.thoughtcrime.securesms.util.InterceptableLongClickCopyLinkSpan; import org.thoughtcrime.securesms.util.LinkUtil; import org.thoughtcrime.securesms.util.LongClickMovementMethod; @@ -191,13 +188,8 @@ public final class ConversationItem extends RelativeLayout implements BindableCo private LiveRecipient recipient; private GlideRequests glideRequests; private ValueAnimator pulseOutlinerAlphaAnimator; - private Optional previousMessage; - - /** - * Whether or not we're rendering this item in a constrained space. - * Today this is only {@link org.thoughtcrime.securesms.conversation.quotes.MessageQuotesBottomSheet}. - */ - private boolean isCondensedMode; + private Optional previousMessage; + private ConversationItemDisplayMode displayMode; protected ConversationItemBodyBubble bodyBubble; protected View reply; @@ -355,7 +347,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo boolean isMessageRequestAccepted, boolean allowedToPlayInline, @NonNull Colorizer colorizer, - boolean isCondensedMode) + @NonNull ConversationItemDisplayMode displayMode) { if (this.recipient != null) this.recipient.removeForeverObserver(this); if (this.conversationRecipient != null) this.conversationRecipient.removeForeverObserver(this); @@ -376,7 +368,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo this.canPlayContent = false; this.mediaItem = null; this.colorizer = colorizer; - this.isCondensedMode = isCondensedMode; + this.displayMode = displayMode; this.previousMessage = previousMessageRecord; this.recipient.observeForever(this); @@ -422,7 +414,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo @Override public boolean dispatchTouchEvent(MotionEvent ev) { - if (isCondensedMode) return super.dispatchTouchEvent(ev); + if (isCondensedMode()) return super.dispatchTouchEvent(ev); switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: @@ -906,12 +898,20 @@ public final class ConversationItem extends RelativeLayout implements BindableCo } } + /** + * Whether or not we're rendering this item in a constrained space. + * Today this is only {@link org.thoughtcrime.securesms.conversation.quotes.MessageQuotesBottomSheet}. + */ + private boolean isCondensedMode() { + return displayMode == ConversationItemDisplayMode.CONDENSED; + } + /** * Whether or not we want to condense the actual content of the bubble. e.g. shorten image height, text content, etc. * Today, we only want to do this for the first message when we're in condensed mode. */ private boolean isContentCondensed() { - return isCondensedMode && !previousMessage.isPresent(); + return isCondensedMode() && !previousMessage.isPresent(); } private boolean isStoryReaction(MessageRecord messageRecord) { @@ -1187,7 +1187,11 @@ public final class ConversationItem extends RelativeLayout implements BindableCo if (giftViewStub.resolved()) giftViewStub.get().setVisibility(View.GONE); //noinspection ConstantConditions - documentViewStub.get().setDocument(((MediaMmsMessageRecord) messageRecord).getSlideDeck().getDocumentSlide(), showControls); + documentViewStub.get().setDocument( + ((MediaMmsMessageRecord) messageRecord).getSlideDeck().getDocumentSlide(), + showControls, + displayMode != ConversationItemDisplayMode.DETAILED + ); documentViewStub.get().setDocumentClickListener(new ThumbnailClickListener()); documentViewStub.get().setDownloadClickListener(singleDownloadClickListener); documentViewStub.get().setOnLongClickListener(passthroughClickListener); @@ -1690,7 +1694,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo } private void setHasBeenQuoted(@NonNull ConversationMessage message) { - if (message.hasBeenQuoted() && !isCondensedMode && quotedIndicator != null && batchSelected.isEmpty()) { + if (message.hasBeenQuoted() && !isCondensedMode() && quotedIndicator != null && batchSelected.isEmpty()) { quotedIndicator.setVisibility(VISIBLE); quotedIndicator.setOnClickListener(quotedIndicatorClickListener); } else if (quotedIndicator != null) { @@ -2312,7 +2316,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo private class ThumbnailClickListener implements SlideClickListener { public void onClick(final View v, final Slide slide) { - if (shouldInterceptClicks(messageRecord) || !batchSelected.isEmpty() || isCondensedMode) { + if (shouldInterceptClicks(messageRecord) || !batchSelected.isEmpty() || isCondensedMode()) { performClick(); } else if (!canPlayContent && mediaItem != null && eventListener != null) { eventListener.onPlayInlineContent(conversationMessage); diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItemDisplayMode.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItemDisplayMode.kt new file mode 100644 index 0000000000..f72e1f46dd --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItemDisplayMode.kt @@ -0,0 +1,10 @@ +package org.thoughtcrime.securesms.conversation + +enum class ConversationItemDisplayMode { + /** Normal rendering, used for normal bubbles in the conversation view */ + STANDARD, + /** Smaller bubbles, often trimming text and shrinking images. Used for quote threads. */ + CONDENSED, + /** Less length restrictions. Used to show more info in message details. */ + DETAILED, +} 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 5c03949732..bc1e9c5e7b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationUpdateItem.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationUpdateItem.java @@ -14,9 +14,7 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.content.res.AppCompatResources; -import androidx.cardview.widget.CardView; import androidx.core.content.ContextCompat; -import androidx.core.content.res.ColorStateListInflaterCompat; import androidx.lifecycle.LifecycleOwner; import androidx.lifecycle.LiveData; import androidx.lifecycle.Observer; @@ -51,8 +49,6 @@ import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.concurrent.ListenableFuture; import org.thoughtcrime.securesms.util.livedata.LiveDataUtil; -import org.thoughtcrime.securesms.util.views.AutoRounder; -import org.thoughtcrime.securesms.util.views.Stub; import org.thoughtcrime.securesms.verify.VerifyIdentityActivity; import org.whispersystems.signalservice.api.push.ServiceId; @@ -129,7 +125,7 @@ public final class ConversationUpdateItem extends FrameLayout boolean isMessageRequestAccepted, boolean allowedToPlayInline, @NonNull Colorizer colorizer, - boolean isCondensedMode) + @NonNull ConversationItemDisplayMode displayMode) { this.batchSelected = batchSelected; 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 419326f432..b3ebd8f0fa 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageHeaderViewHolder.java +++ b/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageHeaderViewHolder.java @@ -26,6 +26,7 @@ import org.thoughtcrime.securesms.conversation.ConversationItem; import org.thoughtcrime.securesms.conversation.ConversationMessage; import org.thoughtcrime.securesms.conversation.colors.Colorizable; import org.thoughtcrime.securesms.conversation.colors.Colorizer; +import org.thoughtcrime.securesms.conversation.ConversationItemDisplayMode; import org.thoughtcrime.securesms.database.model.MessageRecord; import org.thoughtcrime.securesms.giph.mp4.GiphyMp4Playable; import org.thoughtcrime.securesms.giph.mp4.GiphyMp4PlaybackPolicyEnforcer; @@ -110,7 +111,7 @@ final class MessageHeaderViewHolder extends RecyclerView.ViewHolder implements G false, true, colorizer, - false); + ConversationItemDisplayMode.DETAILED); } private void bindErrorState(MessageRecord messageRecord) { diff --git a/app/src/main/res/layout/document_view.xml b/app/src/main/res/layout/document_view.xml index 35ff360e31..d1ac9f7994 100644 --- a/app/src/main/res/layout/document_view.xml +++ b/app/src/main/res/layout/document_view.xml @@ -91,8 +91,6 @@ android:layout_width="match_parent" android:layout_height="wrap_content" style="@style/Signal.Text.Body" - android:singleLine="true" - android:maxLines="1" android:clickable="false" android:ellipsize="end" tools:text="The-Anarchist-Tension-by-Alfredo-Bonanno.pdf"/>