Skip to content

Commit

Permalink
Added ability to receive long messages.
Browse files Browse the repository at this point in the history
Send support is in here too. We'll enable it in a future release after
enough people have updated.
  • Loading branch information
greyson-signal committed Mar 1, 2019
1 parent bf28e10 commit 55699e2
Show file tree
Hide file tree
Showing 31 changed files with 766 additions and 75 deletions.
2 changes: 2 additions & 0 deletions AndroidManifest.xml
Expand Up @@ -218,6 +218,8 @@
android:value="org.thoughtcrime.securesms.ConversationListActivity" />
</activity>

<activity android:name=".longmessage.LongMessageActivity" />

<activity android:name=".conversation.ConversationPopupActivity"
android:windowSoftInputMode="stateVisible"
android:launchMode="singleTask"
Expand Down
2 changes: 2 additions & 0 deletions res/layout/conversation_item_received.xml
Expand Up @@ -165,7 +165,9 @@
style="@style/Signal.Text.Body"
android:textColor="?conversation_item_received_text_primary_color"
android:textColorLink="?conversation_item_received_text_primary_color"
android:ellipsize="end"
app:scaleEmojis="true"
app:emoji_maxLength="1000"
tools:text="Mango pickle lorem ipsum"/>

<org.thoughtcrime.securesms.components.ConversationItemFooter
Expand Down
2 changes: 2 additions & 0 deletions res/layout/conversation_item_sent.xml
Expand Up @@ -102,7 +102,9 @@
style="@style/Signal.Text.Body"
android:textColor="?conversation_item_sent_text_primary_color"
android:textColorLink="?conversation_item_sent_text_primary_color"
android:ellipsize="end"
app:scaleEmojis="true"
app:emoji_maxLength="1000"
tools:text="Mango pickle lorem ipsum"/>

<View
Expand Down
26 changes: 26 additions & 0 deletions res/layout/longmessage_activity.xml
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp">

<ViewStub
android:id="@+id/longmessage_sent_stub"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout="@layout/longmessage_bubble_sent"/>

<ViewStub
android:id="@+id/longmessage_received_stub"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout="@layout/longmessage_bubble_received"/>

</FrameLayout>

</ScrollView>
42 changes: 42 additions & 0 deletions res/layout/longmessage_bubble_received.xml
@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@drawable/message_bubble_background_received_alone"
android:visibility="gone"
tools:visibility="visible">

<org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/longmessage_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/message_bubble_top_padding"
android:layout_marginLeft="@dimen/message_bubble_horizontal_padding"
android:layout_marginRight="@dimen/message_bubble_horizontal_padding"
android:layout_marginBottom="@dimen/message_bubble_collapsed_footer_padding"
style="@style/Signal.Text.Body"
android:textColor="?conversation_item_received_text_primary_color"
android:textColorLink="?conversation_item_received_text_primary_color"
android:textIsSelectable="true"
app:scaleEmojis="true"
tools:text="With great power comes great responsibility."/>

<org.thoughtcrime.securesms.components.ConversationItemFooter
android:id="@+id/longmessage_footer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="-4dp"
android:layout_marginLeft="@dimen/message_bubble_horizontal_padding"
android:layout_marginRight="@dimen/message_bubble_horizontal_padding"
android:layout_marginBottom="@dimen/message_bubble_bottom_padding"
android:clipChildren="false"
android:clipToPadding="false"
android:alpha="0.7"
app:footer_text_color="?attr/conversation_item_received_text_secondary_color"
app:footer_icon_color="?attr/conversation_item_received_text_secondary_color"/>

</LinearLayout>
41 changes: 41 additions & 0 deletions res/layout/longmessage_bubble_sent.xml
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@drawable/message_bubble_background_sent_alone"
android:visibility="gone"
tools:visibility="visible">

<org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/longmessage_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/message_bubble_top_padding"
android:layout_marginLeft="@dimen/message_bubble_horizontal_padding"
android:layout_marginRight="@dimen/message_bubble_horizontal_padding"
android:layout_marginBottom="@dimen/message_bubble_collapsed_footer_padding"
style="@style/Signal.Text.Body"
android:textColor="?conversation_item_sent_text_primary_color"
android:textColorLink="?conversation_item_sent_text_primary_color"
android:textIsSelectable="true"
app:scaleEmojis="true"
tools:text="With great power comes great responsibility."/>

<org.thoughtcrime.securesms.components.ConversationItemFooter
android:id="@+id/longmessage_footer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="-4dp"
android:layout_marginLeft="@dimen/message_bubble_horizontal_padding"
android:layout_marginRight="@dimen/message_bubble_horizontal_padding"
android:layout_marginBottom="@dimen/message_bubble_bottom_padding"
android:clipChildren="false"
android:clipToPadding="false"
app:footer_text_color="?attr/conversation_item_sent_text_secondary_color"
app:footer_icon_color="?attr/conversation_item_sent_icon_color"/>

</LinearLayout>
1 change: 1 addition & 0 deletions res/values/attrs.xml
Expand Up @@ -236,6 +236,7 @@

<declare-styleable name="EmojiTextView">
<attr name="scaleEmojis" format="boolean" />
<attr name="emoji_maxLength" format="integer" />
</declare-styleable>

<declare-styleable name="RingtonePreference">
Expand Down
8 changes: 8 additions & 0 deletions res/values/strings.xml
Expand Up @@ -133,6 +133,9 @@
<string name="ConversationItem_copied_text">Copied %s</string>
<string name="ConversationItem_from_s">from %s</string>
<string name="ConversationItem_to_s">to %s</string>
<string name="ConversationItem_read_more">&#160; Read More</string>
<string name="ConversationItem_download_more">&#160; Download More</string>
<string name="ConversationItem_pending">&#160; Pending</string>

<!-- ConversationActivity -->
<string name="ConversationActivity_reset_secure_session_question">Reset secure session?</string>
Expand Down Expand Up @@ -409,6 +412,11 @@
<string name="MessageDetailsRecipient_failed_to_send">Failed to send</string>
<string name="MessageDetailsRecipient_new_safety_number">New safety number</string>

<!-- LongMessageActivity -->
<string name="LongMessageActivity_unable_to_find_message">Unable to find message</string>
<string name="LongMessageActivity_message_from_s">Message from %1$s</string>
<string name="LongMessageActivity_your_message">Your message</string>

<!-- MessageRetrievalService -->
<string name="MessageRetrievalService_signal">Signal</string>
<string name="MessageRetrievalService_background_connection_enabled">Background connection enabled</string>
Expand Down
2 changes: 2 additions & 0 deletions res/values/styles.xml
Expand Up @@ -173,6 +173,8 @@
<item name="android:padding">2dp</item>
<item name="android:background">@null</item>
<item name="android:maxLines">4</item>
<!-- TODO: Switch to 64kb to enable long message sending. -->
<!--<item name="android:maxLength">65536</item>-->
<item name="android:maxLength">2000</item>
<item name="android:textColor">?conversation_item_sent_text_primary_color</item>
<item name="android:capitalize">sentences</item>
Expand Down
2 changes: 2 additions & 0 deletions src/org/thoughtcrime/securesms/BindableConversationItem.java
Expand Up @@ -5,6 +5,7 @@
import android.view.View;

import org.thoughtcrime.securesms.contactshare.Contact;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
Expand Down Expand Up @@ -34,6 +35,7 @@ void bind(@NonNull MessageRecord messageRecord,
interface EventListener {
void onQuoteClicked(MmsMessageRecord messageRecord);
void onLinkPreviewClicked(@NonNull LinkPreview linkPreview);
void onMoreTextClicked(@NonNull Address conversationAddress, long messageId, boolean isMms);
void onSharedContactDetailsClicked(@NonNull Contact contact, @NonNull View avatarTransitionView);
void onAddToContactsClicked(@NonNull Contact contact);
void onMessageSharedContactClicked(@NonNull List<Recipient> choices);
Expand Down
54 changes: 40 additions & 14 deletions src/org/thoughtcrime/securesms/components/emoji/EmojiTextView.java
Expand Up @@ -17,17 +17,23 @@
import org.thoughtcrime.securesms.components.emoji.parsing.EmojiParser;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.libsignal.util.guava.Optional;


public class EmojiTextView extends AppCompatTextView {

private final boolean scaleEmojis;

private static final char ELLIPSIS = '…';

private CharSequence previousText;
private BufferType previousBufferType;
private float originalFontSize;
private boolean useSystemEmoji;
private boolean sizeChangeInProgress;
private int maxLength;
private CharSequence overflowText;
private CharSequence previousOverflowText;

public EmojiTextView(Context context) {
this(context, null);
Expand All @@ -42,6 +48,7 @@ public EmojiTextView(Context context, AttributeSet attrs, int defStyleAttr) {

TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.EmojiTextView, 0, 0);
scaleEmojis = a.getBoolean(R.styleable.EmojiTextView_scaleEmojis, false);
maxLength = a.getInteger(R.styleable.EmojiTextView_emoji_maxLength, -1);
a.recycle();

a = context.obtainStyledAttributes(attrs, new int[]{android.R.attr.textSize});
Expand All @@ -67,21 +74,22 @@ public EmojiTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super.setTextSize(TypedValue.COMPLEX_UNIT_PX, originalFontSize);
}

if (unchanged(text, type)) {
if (unchanged(text, overflowText, type)) {
return;
}

previousText = text;
previousBufferType = type;
useSystemEmoji = useSystemEmoji();
previousText = text;
previousOverflowText = overflowText;
previousBufferType = type;
useSystemEmoji = useSystemEmoji();

if (useSystemEmoji || candidates == null || candidates.size() == 0) {
super.setText(text, BufferType.NORMAL);
if (maxLength <= 0 && (useSystemEmoji || candidates == null || candidates.size() == 0)) {
super.setText(new SpannableStringBuilder(Optional.fromNullable(text).or("")).append(Optional.fromNullable(overflowText).or("")), BufferType.NORMAL);
return;
}

CharSequence emojified = provider.emojify(candidates, text, this);
super.setText(emojified, BufferType.SPANNABLE);
super.setText(new SpannableStringBuilder(emojified).append(Optional.fromNullable(overflowText).or("")), BufferType.SPANNABLE);

// Android fails to ellipsize spannable strings. (https://issuetracker.google.com/issues/36991688)
// We ellipsize them ourselves by manually truncating the appropriate section.
Expand All @@ -90,18 +98,34 @@ public EmojiTextView(Context context, AttributeSet attrs, int defStyleAttr) {
}
}

public void setOverflowText(@Nullable CharSequence overflowText) {
this.overflowText = overflowText;
setText(previousText, BufferType.SPANNABLE);
}

private void ellipsize() {
if (maxLength > 0 && getText().length() > maxLength + 1) {
SpannableStringBuilder newContent = new SpannableStringBuilder();
newContent.append(getText().subSequence(0, maxLength)).append(ELLIPSIS).append(Optional.fromNullable(overflowText).or(""));

EmojiParser.CandidateList newCandidates = EmojiProvider.getInstance(getContext()).getCandidates(newContent);
CharSequence emojified = EmojiProvider.getInstance(getContext()).emojify(newCandidates, newContent, this);

super.setText(emojified, BufferType.SPANNABLE);
return;
}

post(() -> {
if (getLayout() == null) {
ellipsize();
return;
}

int maxLines = TextViewCompat.getMaxLines(EmojiTextView.this);
if (maxLines <= 0) {
if (maxLines <= 0 && maxLength < 0) {
return;
}

int lineCount = getLineCount();
if (lineCount > maxLines) {
int overflowStart = getLayout().getLineStart(maxLines - 1);
Expand All @@ -110,7 +134,8 @@ private void ellipsize() {

SpannableStringBuilder newContent = new SpannableStringBuilder();
newContent.append(getText().subSequence(0, overflowStart))
.append(ellipsized.subSequence(0, ellipsized.length()));
.append(ellipsized.subSequence(0, ellipsized.length()))
.append(Optional.fromNullable(overflowText).or(""));

EmojiParser.CandidateList newCandidates = EmojiProvider.getInstance(getContext()).getCandidates(newContent);
CharSequence emojified = EmojiProvider.getInstance(getContext()).emojify(newCandidates, newContent, this);
Expand All @@ -120,10 +145,11 @@ private void ellipsize() {
});
}

private boolean unchanged(CharSequence text, BufferType bufferType) {
return Util.equals(previousText, text) &&
Util.equals(previousBufferType, bufferType) &&
useSystemEmoji == useSystemEmoji() &&
private boolean unchanged(CharSequence text, CharSequence overflowText, BufferType bufferType) {
return Util.equals(previousText, text) &&
Util.equals(previousOverflowText, overflowText) &&
Util.equals(previousBufferType, bufferType) &&
useSystemEmoji == useSystemEmoji() &&
!sizeChangeInProgress;
}

Expand Down

0 comments on commit 55699e2

Please sign in to comment.