improve replies on file or image messages
This commit is contained in:
parent
350b36a2d6
commit
8c78febaa8
|
@ -1,10 +1,13 @@
|
|||
package eu.siacs.conversations.entities;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.TextUtils;
|
||||
import android.text.style.ImageSpan;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
@ -16,6 +19,7 @@ import com.google.common.primitives.Longs;
|
|||
|
||||
import org.json.JSONException;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
|
@ -27,10 +31,12 @@ import java.util.Set;
|
|||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
import eu.siacs.conversations.Config;
|
||||
import eu.siacs.conversations.R;
|
||||
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
|
||||
import eu.siacs.conversations.crypto.axolotl.FingerprintStatus;
|
||||
import eu.siacs.conversations.http.URL;
|
||||
import eu.siacs.conversations.services.AvatarService;
|
||||
import eu.siacs.conversations.services.XmppConnectionService;
|
||||
import eu.siacs.conversations.ui.util.PresenceSelector;
|
||||
import eu.siacs.conversations.ui.util.QuoteHelper;
|
||||
import eu.siacs.conversations.utils.CryptoHelper;
|
||||
|
@ -38,6 +44,7 @@ import eu.siacs.conversations.utils.Emoticons;
|
|||
import eu.siacs.conversations.utils.GeoHelper;
|
||||
import eu.siacs.conversations.utils.MessageUtils;
|
||||
import eu.siacs.conversations.utils.MimeUtils;
|
||||
import eu.siacs.conversations.utils.StringUtils;
|
||||
import eu.siacs.conversations.utils.UIHelper;
|
||||
import eu.siacs.conversations.xml.Element;
|
||||
import eu.siacs.conversations.xml.Tag;
|
||||
|
@ -839,9 +846,17 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable
|
|||
}
|
||||
|
||||
public SpannableStringBuilder getBodyForDisplaying() {
|
||||
return getBodyForDisplaying(false);
|
||||
}
|
||||
|
||||
public SpannableStringBuilder getBodyForDisplaying(boolean omitReplyText) {
|
||||
if (replyMessage != null) {
|
||||
if (omitReplyText) {
|
||||
return new SpannableStringBuilder(MessageUtils.filterLtrRtl(removeReplyFallback(this).toString()).trim());
|
||||
}
|
||||
|
||||
try {
|
||||
return new SpannableStringBuilder(MessageUtils.filterLtrRtl(getReplyText(replyMessage) + "\n" + removeReplyFallback(this, replyMessage)).trim());
|
||||
return new SpannableStringBuilder(MessageUtils.filterLtrRtl(getReplyText(replyMessage) + "\n" + removeReplyFallback(this)).trim());
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
return new SpannableStringBuilder(MessageUtils.filterLtrRtl(this.body).trim());
|
||||
}
|
||||
|
@ -850,16 +865,20 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable
|
|||
}
|
||||
}
|
||||
|
||||
public SpannableStringBuilder getBodyForReplyPreview() {
|
||||
try {
|
||||
return new SpannableStringBuilder(MessageUtils.filterLtrRtl(getReplyText(this).toString()).trim());
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
return new SpannableStringBuilder(MessageUtils.filterLtrRtl(this.body).trim());
|
||||
public SpannableStringBuilder getBodyForReplyPreview(XmppConnectionService xmppConnectionService) {
|
||||
if (isFileOrImage()) {
|
||||
return SpannableStringBuilder.valueOf(StringUtils.capitalize(UIHelper.getFileDescriptionString(xmppConnectionService, this)));
|
||||
} else {
|
||||
try {
|
||||
return new SpannableStringBuilder(MessageUtils.filterLtrRtl(getReplyText(this).toString()).trim());
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
return new SpannableStringBuilder(MessageUtils.filterLtrRtl(this.body).trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private StringBuilder getReplyText(Message message) {
|
||||
StringBuilder reply = removeReplyFallback(message, message.replyMessage);
|
||||
StringBuilder reply = removeReplyFallback(message);
|
||||
reply.insert(0, '>');
|
||||
for (int i=0;i<reply.length();i++) {
|
||||
char c = reply.charAt(i);
|
||||
|
@ -872,7 +891,7 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable
|
|||
return reply;
|
||||
}
|
||||
|
||||
private StringBuilder removeReplyFallback(Message message, Message replyMessage) {
|
||||
private StringBuilder removeReplyFallback(Message message) {
|
||||
StringBuilder sb = new StringBuilder(message.body);
|
||||
|
||||
List<Element> replyFallback = message.getFallbacks("urn:xmpp:reply:0");
|
||||
|
|
|
@ -38,6 +38,7 @@ import android.os.Vibrator;
|
|||
import android.preference.PreferenceManager;
|
||||
import android.provider.MediaStore;
|
||||
import android.text.Editable;
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.TextUtils;
|
||||
import android.text.format.DateUtils;
|
||||
|
@ -62,6 +63,7 @@ import android.widget.AbsListView.OnScrollListener;
|
|||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.AdapterContextMenuInfo;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ListView;
|
||||
import android.widget.PopupMenu;
|
||||
import android.widget.TextView.OnEditorActionListener;
|
||||
|
@ -73,6 +75,7 @@ import androidx.annotation.NonNull;
|
|||
import androidx.annotation.StringRes;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.content.res.AppCompatResources;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.view.inputmethod.InputConnectionCompat;
|
||||
import androidx.core.view.inputmethod.InputContentInfoCompat;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
|
@ -126,6 +129,7 @@ import eu.siacs.conversations.services.XmppConnectionService;
|
|||
import eu.siacs.conversations.ui.adapter.CommandAdapter;
|
||||
import eu.siacs.conversations.ui.adapter.MediaPreviewAdapter;
|
||||
import eu.siacs.conversations.ui.adapter.MessageAdapter;
|
||||
import eu.siacs.conversations.ui.text.QuoteSpan;
|
||||
import eu.siacs.conversations.ui.util.ActivityResult;
|
||||
import eu.siacs.conversations.ui.util.Attachment;
|
||||
import eu.siacs.conversations.ui.util.ConversationMenuConfigurator;
|
||||
|
@ -1572,9 +1576,33 @@ public class ConversationFragment extends XmppFragment
|
|||
return;
|
||||
}
|
||||
|
||||
SpannableStringBuilder body = message.getBodyForReplyPreview();
|
||||
if (message.isFileOrImage() || message.isOOb()) body.append(" 🖼️");
|
||||
messageListAdapter.handleTextQuotes(body, activity.isDarkTheme(), true, message);
|
||||
SpannableStringBuilder body = message.getBodyForReplyPreview(activity.xmppConnectionService);
|
||||
|
||||
if (message.isFileOrImage() && message.getEncryption() != Message.ENCRYPTION_PGP && message.getEncryption() != Message.ENCRYPTION_DECRYPTION_FAILED) {
|
||||
if (message.getFileParams().width > 0 && message.getFileParams().height > 0) {
|
||||
binding.contextPreviewImage.setVisibility(View.VISIBLE);
|
||||
binding.contextPreviewDoc.setVisibility(View.GONE);
|
||||
binding.contextPreviewAudio.setVisibility(View.GONE);
|
||||
activity.loadBitmap(message, binding.contextPreviewImage);
|
||||
} else if (message.getFileParams().runtime > 0) {
|
||||
binding.contextPreviewImage.setVisibility(View.GONE);
|
||||
binding.contextPreviewDoc.setVisibility(View.GONE);
|
||||
binding.contextPreviewAudio.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
binding.contextPreviewImage.setVisibility(View.GONE);
|
||||
binding.contextPreviewDoc.setVisibility(View.VISIBLE);
|
||||
binding.contextPreviewAudio.setVisibility(View.GONE);
|
||||
}
|
||||
} else if (message.isOOb()) {
|
||||
messageListAdapter.handleTextQuotes(body, activity.isDarkTheme(), true, message);
|
||||
binding.contextPreviewImage.setVisibility(View.GONE);
|
||||
binding.contextPreviewDoc.setVisibility(View.GONE);
|
||||
body.append(" 🖼️");
|
||||
} else {
|
||||
messageListAdapter.handleTextQuotes(body, activity.isDarkTheme(), true, message);
|
||||
binding.contextPreviewImage.setVisibility(View.GONE);
|
||||
binding.contextPreviewDoc.setVisibility(View.GONE);
|
||||
}
|
||||
binding.contextPreviewText.setText(body);
|
||||
binding.contextPreviewAuthor.setText(message.getAvatarName());
|
||||
binding.contextPreview.setVisibility(View.VISIBLE);
|
||||
|
|
|
@ -314,7 +314,7 @@ public class MessageAdapter extends ArrayAdapter<Message> implements DraggableLi
|
|||
return this.getItemViewType(getItem(position));
|
||||
}
|
||||
|
||||
private int getMessageTextColor(boolean onDark, boolean primary) {
|
||||
public int getMessageTextColor(boolean onDark, boolean primary) {
|
||||
if (onDark) {
|
||||
return ContextCompat.getColor(activity, primary ? R.color.white : R.color.white70);
|
||||
} else {
|
||||
|
@ -520,8 +520,8 @@ public class MessageAdapter extends ArrayAdapter<Message> implements DraggableLi
|
|||
int color = this.getMessageTextColor(darkBackground, false);
|
||||
|
||||
DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
|
||||
body.setSpan(new QuoteSpan(color, highlightReply ? ContextCompat.getColor(activity, R.color.blue_a100) : -1, metrics), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
if (highlightReply) {
|
||||
body.setSpan(new QuoteSpan(color, highlightReply && start == 0 ? ContextCompat.getColor(activity, R.color.blue_a100) : -1, metrics), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
if (highlightReply && start == 0) {
|
||||
body.setSpan(new ReplyClickableSpan(new WeakReference(replyClickListener), new WeakReference(message)), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
}
|
||||
|
@ -633,15 +633,22 @@ public class MessageAdapter extends ArrayAdapter<Message> implements DraggableLi
|
|||
|
||||
if (message.getBody() != null) {
|
||||
final String nick = UIHelper.getMessageDisplayName(message);
|
||||
SpannableStringBuilder body = message.getBodyForDisplaying();
|
||||
|
||||
Message replyMessage = message.getReplyMessage();
|
||||
Boolean fileOrImageReply = replyMessage != null && replyMessage.isFileOrImage();
|
||||
|
||||
SpannableStringBuilder body = message.getBodyForDisplaying(fileOrImageReply);
|
||||
|
||||
boolean hasMeCommand = message.hasMeCommand();
|
||||
if (hasMeCommand) {
|
||||
body = body.replace(0, Message.ME_COMMAND.length(), nick + " ");
|
||||
}
|
||||
|
||||
if (body.length() > Config.MAX_DISPLAY_MESSAGE_CHARS) {
|
||||
body = new SpannableStringBuilder(body, 0, Config.MAX_DISPLAY_MESSAGE_CHARS);
|
||||
body.append("\u2026");
|
||||
}
|
||||
|
||||
Message.MergeSeparator[] mergeSeparators = body.getSpans(0, body.length(), Message.MergeSeparator.class);
|
||||
for (Message.MergeSeparator mergeSeparator : mergeSeparators) {
|
||||
int start = body.getSpanStart(mergeSeparator);
|
||||
|
@ -656,7 +663,46 @@ public class MessageAdapter extends ArrayAdapter<Message> implements DraggableLi
|
|||
applyQuoteSpan(body, start, end, darkBackground, message.getReplyMessage() != null, message);
|
||||
}
|
||||
|
||||
handleTextQuotes(body, darkBackground, message.getReplyMessage() != null, message);
|
||||
if (fileOrImageReply) {
|
||||
viewHolder.nonTextReplyContent.setVisibility(View.VISIBLE);
|
||||
WeakReference<ReplyClickListener> listener = new WeakReference<>(replyClickListener);
|
||||
viewHolder.nonTextReplyContent.setOnClickListener(v -> {
|
||||
ReplyClickListener l = listener.get();
|
||||
if (l != null) {
|
||||
l.onReplyClick(message);
|
||||
}
|
||||
});
|
||||
|
||||
TextView text = viewHolder.nonTextReplyContent.findViewById(R.id.reply_body);
|
||||
|
||||
TextView author = viewHolder.nonTextReplyContent.findViewById(R.id.context_preview_author);
|
||||
ImageView contextPreviewImage = viewHolder.nonTextReplyContent.findViewById(R.id.context_preview_image);
|
||||
View contextPreviewDoc = viewHolder.nonTextReplyContent.findViewById(R.id.context_preview_doc);
|
||||
View contextPreviewAudio = viewHolder.nonTextReplyContent.findViewById(R.id.context_preview_audio);
|
||||
|
||||
text.setText(replyMessage.getBodyForReplyPreview(activity.xmppConnectionService));
|
||||
author.setText(replyMessage.getAvatarName());
|
||||
|
||||
if (replyMessage.getFileParams().width > 0 && replyMessage.getFileParams().height > 0) {
|
||||
contextPreviewImage.setVisibility(View.VISIBLE);
|
||||
contextPreviewDoc.setVisibility(View.GONE);
|
||||
contextPreviewAudio.setVisibility(View.GONE);
|
||||
activity.loadBitmap(replyMessage, contextPreviewImage);
|
||||
} else if (replyMessage.getFileParams().runtime > 0) {
|
||||
contextPreviewImage.setVisibility(View.GONE);
|
||||
contextPreviewDoc.setVisibility(View.GONE);
|
||||
contextPreviewAudio.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
contextPreviewImage.setVisibility(View.GONE);
|
||||
contextPreviewDoc.setVisibility(View.VISIBLE);
|
||||
contextPreviewAudio.setVisibility(View.GONE);
|
||||
}
|
||||
} else {
|
||||
viewHolder.nonTextReplyContent.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
handleTextQuotes(body, darkBackground, message.getReplyMessage() != null && !fileOrImageReply, message);
|
||||
|
||||
if (!message.isPrivateMessage()) {
|
||||
if (hasMeCommand) {
|
||||
body.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), 0, nick.length(),
|
||||
|
@ -859,6 +905,7 @@ public class MessageAdapter extends ArrayAdapter<Message> implements DraggableLi
|
|||
viewHolder.edit_indicator = view.findViewById(R.id.edit_indicator);
|
||||
viewHolder.image = view.findViewById(R.id.message_image);
|
||||
viewHolder.messageBody = view.findViewById(R.id.message_body);
|
||||
viewHolder.nonTextReplyContent = view.findViewById(R.id.non_text_reply_content);
|
||||
viewHolder.time = view.findViewById(R.id.message_time);
|
||||
viewHolder.indicatorReceived = view.findViewById(R.id.indicator_received);
|
||||
viewHolder.audioPlayer = view.findViewById(R.id.audio_player);
|
||||
|
@ -875,6 +922,7 @@ public class MessageAdapter extends ArrayAdapter<Message> implements DraggableLi
|
|||
viewHolder.edit_indicator = view.findViewById(R.id.edit_indicator);
|
||||
viewHolder.image = view.findViewById(R.id.message_image);
|
||||
viewHolder.messageBody = view.findViewById(R.id.message_body);
|
||||
viewHolder.nonTextReplyContent = view.findViewById(R.id.non_text_reply_content);
|
||||
viewHolder.time = view.findViewById(R.id.message_time);
|
||||
viewHolder.indicatorReceived = view.findViewById(R.id.indicator_received);
|
||||
viewHolder.encryption = view.findViewById(R.id.message_encryption);
|
||||
|
@ -1302,6 +1350,8 @@ public class MessageAdapter extends ArrayAdapter<Message> implements DraggableLi
|
|||
protected TextView status_message;
|
||||
protected TextView encryption;
|
||||
|
||||
protected View nonTextReplyContent;
|
||||
|
||||
protected View clicksInterceptor;
|
||||
|
||||
int position;
|
||||
|
|
|
@ -47,4 +47,8 @@ public class StringUtils {
|
|||
return input == null || input.trim().isEmpty() ? null : input;
|
||||
}
|
||||
|
||||
public static String capitalize(String str) {
|
||||
if(str == null || str.length()<=1) return str;
|
||||
return str.substring(0, 1).toUpperCase() + str.substring(1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,6 +70,34 @@
|
|||
android:layout_marginRight="8dp"
|
||||
android:contentDescription="Reply to" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/context_preview_image"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:scaleType="centerCrop"
|
||||
android:layout_marginEnd="16dp"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/context_preview_doc"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:src="?attr/ic_attach_document" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/context_preview_audio"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:src="?attr/ic_attach_record" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_weight="1"
|
||||
android:layout_width="0dp"
|
||||
|
@ -87,7 +115,6 @@
|
|||
android:id="@+id/context_preview_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="5"
|
||||
android:ellipsize="end" />
|
||||
|
||||
</LinearLayout>
|
||||
|
|
|
@ -1,6 +1,74 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/non_text_reply_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:visibility="gone">
|
||||
|
||||
<View
|
||||
android:id="@+id/divider"
|
||||
android:layout_width="2sp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginStart="1dp"
|
||||
android:layout_centerVertical="true"
|
||||
android:background="@color/blue_a100" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/icons_container"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_toEndOf="@id/divider"
|
||||
android:layout_centerVertical="true">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/context_preview_image"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:scaleType="centerCrop"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/context_preview_doc"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:src="?attr/ic_attach_document"
|
||||
android:layout_toEndOf="@id/divider"
|
||||
android:layout_below="@id/reply_body"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/context_preview_audio"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:src="?attr/ic_attach_record"
|
||||
android:layout_toEndOf="@id/divider"
|
||||
android:layout_below="@id/reply_body"
|
||||
android:visibility="gone"/>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/context_preview_author"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toEndOf="@id/icons_container"
|
||||
android:fontFamily="sans-serif-medium" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/reply_body"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="-2dp"
|
||||
android:longClickable="false"
|
||||
android:layout_toEndOf="@id/icons_container"
|
||||
android:layout_below="@id/context_preview_author"/>
|
||||
</RelativeLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/message_body"
|
||||
android:layout_width="wrap_content"
|
||||
|
|
Loading…
Reference in a new issue