mirror of
https://github.com/oxen-io/session-android.git
synced 2025-12-03 13:43:28 +00:00
Added ability to receive long messages.
Send support is in here too. We'll enable it in a future release after enough people have updated.
This commit is contained in:
@@ -170,12 +170,14 @@ import org.thoughtcrime.securesms.mms.QuoteId;
|
||||
import org.thoughtcrime.securesms.mms.QuoteModel;
|
||||
import org.thoughtcrime.securesms.mms.Slide;
|
||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||
import org.thoughtcrime.securesms.mms.TextSlide;
|
||||
import org.thoughtcrime.securesms.mms.VideoSlide;
|
||||
import org.thoughtcrime.securesms.notifications.MarkReadReceiver;
|
||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||
import org.thoughtcrime.securesms.profiles.GroupShareProfileView;
|
||||
import org.thoughtcrime.securesms.providers.MemoryBlobProvider;
|
||||
import org.thoughtcrime.securesms.providers.PersistentBlobProvider;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
|
||||
@@ -212,9 +214,12 @@ import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import java.io.IOException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
@@ -1905,7 +1910,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
charactersLeft.setText(String.format(dynamicLanguage.getCurrentLocale(),
|
||||
"%d/%d (%d)",
|
||||
characterState.charactersRemaining,
|
||||
characterState.maxMessageSize,
|
||||
characterState.maxTotalMessageSize,
|
||||
characterState.messagesSpent));
|
||||
charactersLeft.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
@@ -1961,6 +1966,24 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
return rawText;
|
||||
}
|
||||
|
||||
private Pair<String, Optional<Slide>> getSplitMessage(String rawText, int maxPrimaryMessageSize) {
|
||||
String bodyText = rawText;
|
||||
Optional<Slide> extraText = Optional.absent();
|
||||
|
||||
if (bodyText.length() > maxPrimaryMessageSize) {
|
||||
bodyText = rawText.substring(0, maxPrimaryMessageSize);
|
||||
|
||||
byte[] extraData = rawText.substring(maxPrimaryMessageSize).getBytes();
|
||||
Uri textUri = MemoryBlobProvider.getInstance().createUri(extraData);
|
||||
String timestamp = new SimpleDateFormat("yyyy-MM-dd-HHmmss", Locale.US).format(new Date());
|
||||
String filename = String.format("signal-%s.txt", timestamp);
|
||||
|
||||
extraText = Optional.of(new TextSlide(this, textUri, filename, extraData.length));
|
||||
}
|
||||
|
||||
return new Pair<>(bodyText, extraText);
|
||||
}
|
||||
|
||||
private MediaConstraints getCurrentMediaConstraints() {
|
||||
return sendButton.getSelectedTransport().getType() == Type.TEXTSECURE
|
||||
? MediaConstraints.getPushMediaConstraints()
|
||||
@@ -2021,6 +2044,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
throw new RecipientFormattingException("Badly formatted");
|
||||
}
|
||||
|
||||
String message = getMessage();
|
||||
boolean forceSms = sendButton.isManualSelection() && sendButton.getSelectedTransport().isSms();
|
||||
int subscriptionId = sendButton.getSelectedTransport().getSimSubscriptionId().or(-1);
|
||||
long expiresIn = recipient.getExpireMessages() * 1000L;
|
||||
@@ -2029,7 +2053,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
recipient.isGroupRecipient() ||
|
||||
recipient.getAddress().isEmail() ||
|
||||
inputPanel.getQuote().isPresent() ||
|
||||
linkPreviewViewModel.hasLinkPreview();
|
||||
linkPreviewViewModel.hasLinkPreview() ||
|
||||
message.length() > sendButton.getSelectedTransport().calculateCharacters(message).maxPrimaryMessageSize;
|
||||
|
||||
Log.i(TAG, "isManual Selection: " + sendButton.isManualSelection());
|
||||
Log.i(TAG, "forceSms: " + forceSms);
|
||||
@@ -2078,6 +2103,15 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
return new SettableFuture<>(null);
|
||||
}
|
||||
|
||||
if (isSecureText && !forceSms) {
|
||||
Pair<String, Optional<Slide>> splitMessage = getSplitMessage(body, sendButton.getSelectedTransport().calculateCharacters(body).maxPrimaryMessageSize);
|
||||
body = splitMessage.first;
|
||||
|
||||
if (splitMessage.second.isPresent()) {
|
||||
slideDeck.addSlide(splitMessage.second.get());
|
||||
}
|
||||
}
|
||||
|
||||
OutgoingMediaMessage outgoingMessageCandidate = new OutgoingMediaMessage(recipient, slideDeck, body, System.currentTimeMillis(), subscriptionId, expiresIn, distributionType, inputPanel.getQuote().orNull(), contacts, previews);
|
||||
|
||||
final SettableFuture<Void> future = new SettableFuture<>();
|
||||
|
||||
@@ -82,9 +82,11 @@ import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
|
||||
import org.thoughtcrime.securesms.jobs.DirectoryRefreshJob;
|
||||
import org.thoughtcrime.securesms.longmessage.LongMessageActivity;
|
||||
import org.thoughtcrime.securesms.mediasend.Media;
|
||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
||||
import org.thoughtcrime.securesms.mms.PartAuthority;
|
||||
import org.thoughtcrime.securesms.mms.Slide;
|
||||
import org.thoughtcrime.securesms.profiles.UnknownSenderView;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
@@ -100,6 +102,8 @@ import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
||||
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
@@ -516,43 +520,60 @@ public class ConversationFragment extends Fragment
|
||||
}
|
||||
|
||||
private void handleForwardMessage(MessageRecord message) {
|
||||
Intent composeIntent = new Intent(getActivity(), ShareActivity.class);
|
||||
composeIntent.putExtra(Intent.EXTRA_TEXT, message.getDisplayBody().toString());
|
||||
if (message.isMms()) {
|
||||
MmsMessageRecord mediaMessage = (MmsMessageRecord) message;
|
||||
boolean isAlbum = mediaMessage.containsMediaSlide() &&
|
||||
mediaMessage.getSlideDeck().getSlides().size() > 1 &&
|
||||
mediaMessage.getSlideDeck().getAudioSlide() == null &&
|
||||
mediaMessage.getSlideDeck().getDocumentSlide() == null;
|
||||
SimpleTask.run(getLifecycle(), () -> {
|
||||
Intent composeIntent = new Intent(getActivity(), ShareActivity.class);
|
||||
composeIntent.putExtra(Intent.EXTRA_TEXT, message.getDisplayBody().toString());
|
||||
|
||||
if (isAlbum) {
|
||||
ArrayList<Media> mediaList = new ArrayList<>(mediaMessage.getSlideDeck().getSlides().size());
|
||||
if (message.isMms()) {
|
||||
MmsMessageRecord mediaMessage = (MmsMessageRecord) message;
|
||||
boolean isAlbum = mediaMessage.containsMediaSlide() &&
|
||||
mediaMessage.getSlideDeck().getSlides().size() > 1 &&
|
||||
mediaMessage.getSlideDeck().getAudioSlide() == null &&
|
||||
mediaMessage.getSlideDeck().getDocumentSlide() == null;
|
||||
|
||||
for (Attachment attachment : mediaMessage.getSlideDeck().asAttachments()) {
|
||||
Uri uri = attachment.getDataUri() != null ? attachment.getDataUri() : attachment.getThumbnailUri();
|
||||
if (isAlbum) {
|
||||
ArrayList<Media> mediaList = new ArrayList<>(mediaMessage.getSlideDeck().getSlides().size());
|
||||
List<Attachment> attachments = Stream.of(mediaMessage.getSlideDeck().getSlides())
|
||||
.filter(s -> s.hasImage() || s.hasVideo())
|
||||
.map(Slide::asAttachment)
|
||||
.toList();
|
||||
|
||||
if (uri != null) {
|
||||
mediaList.add(new Media(uri,
|
||||
attachment.getContentType(),
|
||||
System.currentTimeMillis(),
|
||||
attachment.getWidth(),
|
||||
attachment.getHeight(),
|
||||
attachment.getSize(),
|
||||
Optional.absent(),
|
||||
Optional.fromNullable(attachment.getCaption())));
|
||||
for (Attachment attachment : attachments) {
|
||||
Uri uri = attachment.getDataUri() != null ? attachment.getDataUri() : attachment.getThumbnailUri();
|
||||
|
||||
if (uri != null) {
|
||||
mediaList.add(new Media(uri,
|
||||
attachment.getContentType(),
|
||||
System.currentTimeMillis(),
|
||||
attachment.getWidth(),
|
||||
attachment.getHeight(),
|
||||
attachment.getSize(),
|
||||
Optional.absent(),
|
||||
Optional.fromNullable(attachment.getCaption())));
|
||||
}
|
||||
};
|
||||
|
||||
if (!mediaList.isEmpty()) {
|
||||
composeIntent.putExtra(ConversationActivity.MEDIA_EXTRA, mediaList);
|
||||
}
|
||||
} else if (mediaMessage.containsMediaSlide()) {
|
||||
Slide slide = mediaMessage.getSlideDeck().getSlides().get(0);
|
||||
composeIntent.putExtra(Intent.EXTRA_STREAM, slide.getUri());
|
||||
composeIntent.setType(slide.getContentType());
|
||||
}
|
||||
|
||||
if (mediaMessage.getSlideDeck().getTextSlide() != null && mediaMessage.getSlideDeck().getTextSlide().getUri() != null) {
|
||||
try (InputStream stream = PartAuthority.getAttachmentStream(requireContext(), mediaMessage.getSlideDeck().getTextSlide().getUri())) {
|
||||
String extraText = Util.readFullyAsString(stream);
|
||||
composeIntent.putExtra(Intent.EXTRA_TEXT, message.getDisplayBody().toString() + extraText);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, "Failed to read long message text when forwarding.");
|
||||
}
|
||||
}
|
||||
|
||||
if (!mediaList.isEmpty()) {
|
||||
composeIntent.putExtra(ConversationActivity.MEDIA_EXTRA, mediaList);
|
||||
}
|
||||
} else if (mediaMessage.containsMediaSlide()) {
|
||||
Slide slide = mediaMessage.getSlideDeck().getSlides().get(0);
|
||||
composeIntent.putExtra(Intent.EXTRA_STREAM, slide.getUri());
|
||||
composeIntent.setType(slide.getContentType());
|
||||
}
|
||||
}
|
||||
startActivity(composeIntent);
|
||||
|
||||
return composeIntent;
|
||||
}, this::startActivity);
|
||||
}
|
||||
|
||||
private void handleResendMessage(final MessageRecord message) {
|
||||
@@ -910,6 +931,13 @@ public class ConversationFragment extends Fragment
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMoreTextClicked(@NonNull Address conversationAddress, long messageId, boolean isMms) {
|
||||
if (getContext() != null && getActivity() != null) {
|
||||
startActivity(LongMessageActivity.getIntent(getContext(), conversationAddress, messageId, isMms));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedContactDetailsClicked(@NonNull Contact contact, @NonNull View avatarTransitionView) {
|
||||
if (getContext() != null && getActivity() != null) {
|
||||
|
||||
@@ -23,6 +23,7 @@ import android.content.Intent;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.Typeface;
|
||||
import android.net.Uri;
|
||||
import android.support.annotation.DimenRes;
|
||||
import android.support.annotation.NonNull;
|
||||
@@ -30,9 +31,13 @@ import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableString;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.Spanned;
|
||||
import android.text.TextPaint;
|
||||
import android.text.TextUtils;
|
||||
import android.text.style.BackgroundColorSpan;
|
||||
import android.text.style.CharacterStyle;
|
||||
import android.text.style.ClickableSpan;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
import android.text.style.URLSpan;
|
||||
import android.text.util.Linkify;
|
||||
@@ -46,6 +51,8 @@ import org.thoughtcrime.securesms.MessageDetailsActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||
import org.thoughtcrime.securesms.components.LinkPreviewView;
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiTextView;
|
||||
import org.thoughtcrime.securesms.database.AttachmentDatabase;
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
@@ -87,6 +94,7 @@ import org.thoughtcrime.securesms.mms.PartAuthority;
|
||||
import org.thoughtcrime.securesms.mms.Slide;
|
||||
import org.thoughtcrime.securesms.mms.SlideClickListener;
|
||||
import org.thoughtcrime.securesms.mms.SlidesClickedListener;
|
||||
import org.thoughtcrime.securesms.mms.TextSlide;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
|
||||
import org.thoughtcrime.securesms.util.DateUtils;
|
||||
@@ -119,7 +127,8 @@ public class ConversationItem extends LinearLayout
|
||||
{
|
||||
private static final String TAG = ConversationItem.class.getSimpleName();
|
||||
|
||||
private static final int MAX_MEASURE_CALLS = 3;
|
||||
private static final int MAX_MEASURE_CALLS = 3;
|
||||
private static final int MAX_BODY_DISPLAY_LENGTH = 1000;
|
||||
|
||||
private MessageRecord messageRecord;
|
||||
private Locale locale;
|
||||
@@ -129,7 +138,7 @@ public class ConversationItem extends LinearLayout
|
||||
|
||||
protected ViewGroup bodyBubble;
|
||||
private QuoteView quoteView;
|
||||
private TextView bodyText;
|
||||
private EmojiTextView bodyText;
|
||||
private ConversationItemFooter footer;
|
||||
private TextView groupSender;
|
||||
private TextView groupSenderProfileName;
|
||||
@@ -378,7 +387,7 @@ public class ConversationItem extends LinearLayout
|
||||
}
|
||||
|
||||
private boolean isCaptionlessMms(MessageRecord messageRecord) {
|
||||
return TextUtils.isEmpty(messageRecord.getDisplayBody()) && messageRecord.isMms();
|
||||
return TextUtils.isEmpty(messageRecord.getDisplayBody()) && messageRecord.isMms() && ((MmsMessageRecord) messageRecord).getSlideDeck().getTextSlide() == null;
|
||||
}
|
||||
|
||||
private boolean hasAudio(MessageRecord messageRecord) {
|
||||
@@ -397,6 +406,13 @@ public class ConversationItem extends LinearLayout
|
||||
return messageRecord.isMms() && ((MmsMessageRecord)messageRecord).getSlideDeck().getDocumentSlide() != null;
|
||||
}
|
||||
|
||||
private boolean hasExtraText(MessageRecord messageRecord) {
|
||||
boolean hasTextSlide = messageRecord.isMms() && ((MmsMessageRecord)messageRecord).getSlideDeck().getTextSlide() != null;
|
||||
boolean hasOverflowText = messageRecord.getBody().length() > MAX_BODY_DISPLAY_LENGTH;
|
||||
|
||||
return hasTextSlide || hasOverflowText;
|
||||
}
|
||||
|
||||
private boolean hasQuote(MessageRecord messageRecord) {
|
||||
return messageRecord.isMms() && ((MmsMessageRecord)messageRecord).getQuote() != null;
|
||||
}
|
||||
@@ -421,6 +437,12 @@ public class ConversationItem extends LinearLayout
|
||||
styledText = SearchUtil.getHighlightedSpan(locale, () -> new BackgroundColorSpan(Color.YELLOW), styledText, searchQuery);
|
||||
styledText = SearchUtil.getHighlightedSpan(locale, () -> new ForegroundColorSpan(Color.BLACK), styledText, searchQuery);
|
||||
|
||||
if (hasExtraText(messageRecord)) {
|
||||
bodyText.setOverflowText(getLongMessageSpan(messageRecord));
|
||||
} else {
|
||||
bodyText.setOverflowText(null);
|
||||
}
|
||||
|
||||
bodyText.setText(styledText);
|
||||
bodyText.setVisibility(View.VISIBLE);
|
||||
}
|
||||
@@ -536,7 +558,7 @@ public class ConversationItem extends LinearLayout
|
||||
mediaThumbnailStub.get().setDownloadClickListener(downloadClickListener);
|
||||
mediaThumbnailStub.get().setOnLongClickListener(passthroughClickListener);
|
||||
mediaThumbnailStub.get().setOnClickListener(passthroughClickListener);
|
||||
mediaThumbnailStub.get().showShade(TextUtils.isEmpty(messageRecord.getDisplayBody()));
|
||||
mediaThumbnailStub.get().showShade(TextUtils.isEmpty(messageRecord.getDisplayBody()) && !hasExtraText(messageRecord));
|
||||
mediaThumbnailStub.get().setConversationColor(messageRecord.isOutgoing() ? defaultBubbleColor
|
||||
: messageRecord.getRecipient().getColor().toConversationColor(context));
|
||||
|
||||
@@ -613,7 +635,7 @@ public class ConversationItem extends LinearLayout
|
||||
topRight = 0;
|
||||
}
|
||||
|
||||
if (hasLinkPreview(messageRecord)) {
|
||||
if (hasLinkPreview(messageRecord) || hasExtraText(messageRecord)) {
|
||||
bottomLeft = 0;
|
||||
bottomRight = 0;
|
||||
}
|
||||
@@ -748,7 +770,7 @@ public class ConversationItem extends LinearLayout
|
||||
ViewUtil.updateLayoutParams(footer, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
|
||||
|
||||
footer.setVisibility(GONE);
|
||||
if (sharedContactStub.resolved()) sharedContactStub.get().getFooter().setVisibility(GONE);
|
||||
if (sharedContactStub.resolved()) sharedContactStub.get().getFooter().setVisibility(GONE);
|
||||
if (mediaThumbnailStub.resolved()) mediaThumbnailStub.get().getFooter().setVisibility(GONE);
|
||||
|
||||
boolean differentTimestamps = next.isPresent() && !DateUtils.isSameExtendedRelativeTimestamp(context, locale, next.get().getTimestamp(), current.getTimestamp());
|
||||
@@ -899,6 +921,49 @@ public class ConversationItem extends LinearLayout
|
||||
new ConfirmIdentityDialog(context, messageRecord, mismatches.get(0)).show();
|
||||
}
|
||||
|
||||
private Spannable getLongMessageSpan(@NonNull MessageRecord messageRecord) {
|
||||
String message;
|
||||
Runnable action;
|
||||
|
||||
if (messageRecord.isMms()) {
|
||||
TextSlide slide = ((MmsMessageRecord) messageRecord).getSlideDeck().getTextSlide();
|
||||
|
||||
if (slide != null && slide.asAttachment().getTransferState() == AttachmentDatabase.TRANSFER_PROGRESS_DONE) {
|
||||
message = getResources().getString(R.string.ConversationItem_read_more);
|
||||
action = () -> eventListener.onMoreTextClicked(conversationRecipient.getAddress(), messageRecord.getId(), messageRecord.isMms());
|
||||
} else if (slide != null && slide.asAttachment().getTransferState() == AttachmentDatabase.TRANSFER_PROGRESS_STARTED) {
|
||||
message = getResources().getString(R.string.ConversationItem_pending);
|
||||
action = () -> {};
|
||||
} else if (slide != null) {
|
||||
message = getResources().getString(R.string.ConversationItem_download_more);
|
||||
action = () -> singleDownloadClickListener.onClick(bodyText, slide);
|
||||
} else {
|
||||
message = getResources().getString(R.string.ConversationItem_read_more);
|
||||
action = () -> eventListener.onMoreTextClicked(conversationRecipient.getAddress(), messageRecord.getId(), messageRecord.isMms());
|
||||
}
|
||||
} else {
|
||||
message = getResources().getString(R.string.ConversationItem_read_more);
|
||||
action = () -> eventListener.onMoreTextClicked(conversationRecipient.getAddress(), messageRecord.getId(), messageRecord.isMms());
|
||||
}
|
||||
|
||||
SpannableStringBuilder span = new SpannableStringBuilder(message);
|
||||
CharacterStyle style = new ClickableSpan() {
|
||||
@Override
|
||||
public void onClick(@NonNull View widget) {
|
||||
if (eventListener != null && batchSelected.isEmpty()) {
|
||||
action.run();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDrawState(@NonNull TextPaint ds) {
|
||||
ds.setTypeface(Typeface.DEFAULT_BOLD);
|
||||
}
|
||||
};
|
||||
span.setSpan(style, 0, span.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
return span;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onModified(final Recipient modified) {
|
||||
Util.runOnMain(() -> {
|
||||
|
||||
Reference in New Issue
Block a user