From b2ea91909b9f201ab86de67f3358e9ee00e362a1 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sat, 27 Apr 2019 11:46:43 +0200 Subject: [PATCH] introduced type private_file_message to handle attachments in PMs. fixes #3372 --- .../crypto/axolotl/AxolotlService.java | 2 +- .../conversations/entities/Conversation.java | 4 +- .../siacs/conversations/entities/Message.java | 36 +++++++++- .../generator/MessageGenerator.java | 7 +- .../http/HttpDownloadConnection.java | 3 +- .../http/HttpUploadConnection.java | 4 +- .../conversations/parser/MessageParser.java | 6 +- .../persistance/DatabaseBackend.java | 10 +-- .../persistance/FileBackend.java | 3 +- .../services/NotificationService.java | 2 +- .../services/XmppConnectionService.java | 22 +++--- .../ui/ConversationFragment.java | 9 +-- .../ui/adapter/MessageAdapter.java | 70 ++++++++++++------- src/main/res/layout/message_content.xml | 16 ++--- 14 files changed, 123 insertions(+), 71 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java index 9e983a595..bbc96811b 100644 --- a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java +++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java @@ -1326,7 +1326,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { } final boolean success; - if (message.getType() == Message.TYPE_PRIVATE) { + if (message.isPrivateMessage()) { success = buildHeader(axolotlMessage, message.getTrueCounterpart()); } else { success = buildHeader(axolotlMessage, (Conversation) message.getConversation()); diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index b8dbbf70f..8b02d8be5 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -486,7 +486,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl final Message message = messages.get(i); if (message.getStatus() <= Message.STATUS_RECEIVED && (message.markable || isPrivateAndNonAnonymousMuc) - && message.getType() != Message.TYPE_PRIVATE) { + && !message.isPrivateMessage()) { return message; } } @@ -748,7 +748,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl synchronized (this.messages) { for (int i = this.messages.size() - 1; i >= 0; --i) { final Message message = this.messages.get(i); - if (message.getType() == Message.TYPE_PRIVATE) { + if (message.isPrivateMessage()) { continue; //it's unsafe to use private messages as anchor. They could be coming from user archive } if (message.getStatus() == Message.STATUS_RECEIVED || message.isCarbon() || message.getServerMsgId() != null) { diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java index 83eecc155..e960d62d3 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/src/main/java/eu/siacs/conversations/entities/Message.java @@ -57,6 +57,7 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable public static final int TYPE_FILE = 2; public static final int TYPE_STATUS = 3; public static final int TYPE_PRIVATE = 4; + public static final int TYPE_PRIVATE_FILE = 5; public static final String CONVERSATION = "conversationUuid"; public static final String COUNTERPART = "counterpart"; @@ -495,7 +496,7 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable } boolean similar(Message message) { - if (type != TYPE_PRIVATE && this.serverMsgId != null && message.getServerMsgId() != null) { + if (!isPrivateMessage() && this.serverMsgId != null && message.getServerMsgId() != null) { return this.serverMsgId.equals(message.getServerMsgId()) || Edited.wasPreviouslyEditedServerMsgId(edits, message.getServerMsgId()); } else if (Edited.wasPreviouslyEditedServerMsgId(edits, message.getServerMsgId())) { return true; @@ -837,8 +838,12 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable this.mPreviousMessage = null; } + public boolean isPrivateMessage() { + return type == TYPE_PRIVATE || type == TYPE_PRIVATE_FILE; + } + public boolean isFileOrImage() { - return type == TYPE_FILE || type == TYPE_IMAGE; + return type == TYPE_FILE || type == TYPE_IMAGE || type == TYPE_PRIVATE_FILE; } public boolean hasFileOnRemoteHost() { @@ -915,4 +920,31 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable } return encryption; } + + public static boolean configurePrivateMessage(final Message message) { + return configurePrivateMessage(message, false); + } + + public static boolean configurePrivateFileMessage(final Message message) { + return configurePrivateMessage(message, true); + } + + private static boolean configurePrivateMessage(final Message message, final boolean isFile) { + final Conversation conversation; + if (message.conversation instanceof Conversation) { + conversation = (Conversation) message.conversation; + } else { + return false; + } + if (conversation.getMode() == Conversation.MODE_MULTI) { + final Jid nextCounterpart = conversation.getNextCounterpart(); + if (nextCounterpart != null) { + message.setCounterpart(nextCounterpart); + message.setTrueCounterpart(conversation.getMucOptions().getTrueCounterpart(nextCounterpart)); + message.setType(isFile ? Message.TYPE_PRIVATE_FILE : Message.TYPE_PRIVATE); + return true; + } + } + return false; + } } diff --git a/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java b/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java index b82f081e5..771ebccdc 100644 --- a/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java @@ -1,7 +1,5 @@ package eu.siacs.conversations.generator; -import android.util.Log; - import java.net.URL; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -13,7 +11,6 @@ import eu.siacs.conversations.Config; import eu.siacs.conversations.crypto.axolotl.AxolotlService; import eu.siacs.conversations.crypto.axolotl.XmppAxolotlMessage; import eu.siacs.conversations.entities.Account; -import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.http.P1S3UrlStreamHandler; @@ -43,7 +40,7 @@ public class MessageGenerator extends AbstractGenerator { if (this.mXmppConnectionService.indicateReceived() && !isWithSelf) { packet.addChild("request", "urn:xmpp:receipts"); } - } else if (message.getType() == Message.TYPE_PRIVATE) { //TODO files and images might be private as well + } else if (message.isPrivateMessage()) { packet.setTo(message.getCounterpart()); packet.setType(MessagePacket.TYPE_CHAT); packet.addChild("x", "http://jabber.org/protocol/muc#user"); @@ -54,7 +51,7 @@ public class MessageGenerator extends AbstractGenerator { packet.setTo(message.getCounterpart().asBareJid()); packet.setType(MessagePacket.TYPE_GROUPCHAT); } - if (conversation.isSingleOrPrivateAndNonAnonymous() && message.getType() != Message.TYPE_PRIVATE) { + if (conversation.isSingleOrPrivateAndNonAnonymous() && !message.isPrivateMessage()) { packet.addChild("markable", "urn:xmpp:chat-markers:0"); } packet.setFrom(account.getJid()); diff --git a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java index 74f8edebb..e67ac2db5 100644 --- a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java +++ b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java @@ -442,7 +442,8 @@ public class HttpDownloadConnection implements Transferable { } private void updateImageBounds() { - message.setType(Message.TYPE_FILE); + final boolean privateMessage = message.isPrivateMessage(); + message.setType(privateMessage ? Message.TYPE_PRIVATE_FILE : Message.TYPE_FILE); final URL url; final String ref = mUrl.getRef(); if (method == Method.P1_S3) { diff --git a/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java b/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java index eba40054a..b3f5f021b 100644 --- a/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java +++ b/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java @@ -216,7 +216,9 @@ public class HttpUploadConnection implements Transferable { mXmppConnectionService.getFileBackend().updateFileParams(message, get); mXmppConnectionService.getFileBackend().updateMediaScanner(file); finish(); - message.setCounterpart(message.getConversation().getJid().asBareJid()); + if (!message.isPrivateMessage()) { + message.setCounterpart(message.getConversation().getJid().asBareJid()); + } mXmppConnectionService.resendMessage(message, delayed); } else { Log.d(Config.LOGTAG,"http upload failed because response code was "+code); diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index 77cf2e3a6..10c9e9764 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -551,7 +551,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece mXmppConnectionService.updateMessage(replacedMessage, uuid); if (mXmppConnectionService.confirmMessages() && replacedMessage.getStatus() == Message.STATUS_RECEIVED - && (replacedMessage.trusted() || replacedMessage.getType() == Message.TYPE_PRIVATE) + && (replacedMessage.trusted() || replacedMessage.isPrivateMessage()) //TODO do we really want to send receipts for all PMs? && remoteMsgId != null && !selfAddressed && !isTypeGroupChat) { @@ -577,7 +577,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece } boolean checkForDuplicates = (isTypeGroupChat && packet.hasChild("delay", "urn:xmpp:delay")) - || message.getType() == Message.TYPE_PRIVATE + || message.isPrivateMessage() || message.getServerMsgId() != null || (query == null && mXmppConnectionService.getMessageArchiveService().isCatchupInProgress(conversation)); if (checkForDuplicates) { @@ -637,7 +637,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece if (mXmppConnectionService.confirmMessages() && message.getStatus() == Message.STATUS_RECEIVED - && (message.trusted() || message.getType() == Message.TYPE_PRIVATE) + && (message.trusted() || message.isPrivateMessage()) && remoteMsgId != null && !selfAddressed && !isTypeGroupChat) { diff --git a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java index 34758fe3e..c893d80c9 100644 --- a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java @@ -812,14 +812,14 @@ public class DatabaseBackend extends SQLiteOpenHelper { if (internal) { final String name = file.getName(); if (name.endsWith(".pgp")) { - selection = "(" + Message.RELATIVE_FILE_PATH + " IN(?,?) OR (" + Message.RELATIVE_FILE_PATH + "=? and encryption in(1,4))) and type in (1,2)"; + selection = "(" + Message.RELATIVE_FILE_PATH + " IN(?,?) OR (" + Message.RELATIVE_FILE_PATH + "=? and encryption in(1,4))) and type in (1,2,5)"; selectionArgs = new String[]{file.getAbsolutePath(), name, name.substring(0, name.length() - 4)}; } else { - selection = Message.RELATIVE_FILE_PATH + " IN(?,?) and type in (1,2)"; + selection = Message.RELATIVE_FILE_PATH + " IN(?,?) and type in (1,2,5)"; selectionArgs = new String[]{file.getAbsolutePath(), name}; } } else { - selection = Message.RELATIVE_FILE_PATH + "=? and type in (1,2)"; + selection = Message.RELATIVE_FILE_PATH + "=? and type in (1,2,5)"; selectionArgs = new String[]{file.getAbsolutePath()}; } final List uuids = new ArrayList<>(); @@ -862,7 +862,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { public List getFilePathInfo() { final SQLiteDatabase db = this.getReadableDatabase(); - final Cursor cursor = db.query(Message.TABLENAME, new String[]{Message.UUID, Message.RELATIVE_FILE_PATH, Message.DELETED}, "type in (1,2) and "+Message.RELATIVE_FILE_PATH+" is not null", null, null, null, null); + final Cursor cursor = db.query(Message.TABLENAME, new String[]{Message.UUID, Message.RELATIVE_FILE_PATH, Message.DELETED}, "type in (1,2,5) and "+Message.RELATIVE_FILE_PATH+" is not null", null, null, null, null); final List list = new ArrayList<>(); while (cursor != null && cursor.moveToNext()) { list.add(new FilePathInfo(cursor.getString(0), cursor.getString(1), cursor.getInt(2) > 0)); @@ -875,7 +875,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { public List getRelativeFilePaths(String account, Jid jid, int limit) { SQLiteDatabase db = this.getReadableDatabase(); - final String SQL = "select uuid,relativeFilePath from messages where type in (1,2) and deleted=0 and "+Message.RELATIVE_FILE_PATH+" is not null and conversationUuid=(select uuid from conversations where accountUuid=? and (contactJid=? or contactJid like ?)) order by timeSent desc"; + final String SQL = "select uuid,relativeFilePath from messages where type in (1,2,5) and deleted=0 and "+Message.RELATIVE_FILE_PATH+" is not null and conversationUuid=(select uuid from conversations where accountUuid=? and (contactJid=? or contactJid like ?)) order by timeSent desc"; final String[] args = {account, jid.toEscapedString(), jid.toEscapedString() + "/%"}; Cursor cursor = db.rawQuery(SQL + (limit > 0 ? " limit " + String.valueOf(limit) : ""), args); List filesPaths = new ArrayList<>(); diff --git a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java index 746854a28..b6f5dc518 100644 --- a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java @@ -1178,6 +1178,7 @@ public class FileBackend { public void updateFileParams(Message message, URL url) { DownloadableFile file = getFile(message); final String mime = file.getMimeType(); + final boolean privateMessage = message.isPrivateMessage(); final boolean image = message.getType() == Message.TYPE_IMAGE || (mime != null && mime.startsWith("image/")); final boolean video = mime != null && mime.startsWith("video/"); final boolean audio = mime != null && mime.startsWith("audio/"); @@ -1201,7 +1202,7 @@ public class FileBackend { } message.setBody(body.toString()); message.setDeleted(false); - message.setType(image ? Message.TYPE_IMAGE : Message.TYPE_FILE); + message.setType(privateMessage ? Message.TYPE_PRIVATE_FILE : (image ? Message.TYPE_IMAGE : Message.TYPE_FILE)); } diff --git a/src/main/java/eu/siacs/conversations/services/NotificationService.java b/src/main/java/eu/siacs/conversations/services/NotificationService.java index 06ed560f3..6aa816229 100644 --- a/src/main/java/eu/siacs/conversations/services/NotificationService.java +++ b/src/main/java/eu/siacs/conversations/services/NotificationService.java @@ -868,7 +868,7 @@ public class NotificationService { return false; } final Matcher m = highlight.matcher(message.getBody()); - return (m.find() || message.getType() == Message.TYPE_PRIVATE); + return (m.find() || message.isPrivateMessage()); } else { return false; } diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 370748b5c..4a88f3660 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -487,9 +487,7 @@ public class XmppConnectionService extends Service { encryption = Message.ENCRYPTION_DECRYPTED; } Message message = new Message(conversation, uri.toString(), encryption); - if (conversation.getNextCounterpart() != null) { - message.setCounterpart(conversation.getNextCounterpart()); - } + Message.configurePrivateMessage(message); if (encryption == Message.ENCRYPTION_DECRYPTED) { getPgpEngine().encrypt(message, callback); } else { @@ -505,8 +503,12 @@ public class XmppConnectionService extends Service { } else { message = new Message(conversation, "", conversation.getNextEncryption()); } - message.setCounterpart(conversation.getNextCounterpart()); - message.setType(Message.TYPE_FILE); + if (!Message.configurePrivateFileMessage(message)) { + message.setCounterpart(conversation.getNextCounterpart()); + message.setType(Message.TYPE_FILE); + } + Log.d(Config.LOGTAG,"attachFile: type="+message.getType()); + Log.d(Config.LOGTAG,"counterpart="+message.getCounterpart()); final AttachFileToConversationRunnable runnable = new AttachFileToConversationRunnable(this, uri, type, message, callback); if (runnable.isVideoMessage()) { mVideoCompressionExecutor.execute(runnable); @@ -533,8 +535,11 @@ public class XmppConnectionService extends Service { } else { message = new Message(conversation, "", conversation.getNextEncryption()); } - message.setCounterpart(conversation.getNextCounterpart()); - message.setType(Message.TYPE_IMAGE); + if (!Message.configurePrivateFileMessage(message)) { + message.setCounterpart(conversation.getNextCounterpart()); + message.setType(Message.TYPE_IMAGE); + } + Log.d(Config.LOGTAG,"attachImage: type="+message.getType()); mFileAddingExecutor.execute(() -> { try { getFileBackend().copyImageToPrivateStorage(message, uri); @@ -1431,7 +1436,7 @@ public class XmppConnectionService extends Service { } - boolean mucMessage = conversation.getMode() == Conversation.MODE_MULTI && message.getType() != Message.TYPE_PRIVATE; + boolean mucMessage = conversation.getMode() == Conversation.MODE_MULTI && !message.isPrivateMessage(); if (mucMessage) { message.setCounterpart(conversation.getMucOptions().getSelf().getFullJid()); } @@ -1466,6 +1471,7 @@ public class XmppConnectionService extends Service { packet.addChild(ChatState.toElement(conversation.getOutgoingChatState())); } } + Log.d(Config.LOGTAG,packet.toString()); sendMessagePacket(account, packet); } } diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index 49b92c3ca..b6f33204e 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -728,14 +728,7 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke final Message message; if (conversation.getCorrectingMessage() == null) { message = new Message(conversation, body, conversation.getNextEncryption()); - if (conversation.getMode() == Conversation.MODE_MULTI) { - final Jid nextCounterpart = conversation.getNextCounterpart(); - if (nextCounterpart != null) { - message.setCounterpart(nextCounterpart); - message.setTrueCounterpart(conversation.getMucOptions().getTrueCounterpart(nextCounterpart)); - message.setType(Message.TYPE_PRIVATE); - } - } + Message.configurePrivateMessage(message); } else { message = conversation.getCorrectingMessage(); message.setBody(body); diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java index 077e1b8bc..6c4ffd9fd 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -32,6 +32,8 @@ import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; +import com.google.common.base.Strings; + import java.net.URL; import java.util.List; import java.util.regex.Matcher; @@ -70,6 +72,7 @@ import eu.siacs.conversations.utils.GeoHelper; import eu.siacs.conversations.utils.StylingHelper; import eu.siacs.conversations.utils.UIHelper; import eu.siacs.conversations.xmpp.mam.MamReference; +import rocks.xmpp.addr.Jid; public class MessageAdapter extends ArrayAdapter implements CopyTextView.CopyHandler { @@ -439,7 +442,7 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie body.setSpan(new DividerSpan(true), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } boolean startsWithQuote = handleTextQuotes(body, darkBackground); - if (message.getType() != Message.TYPE_PRIVATE) { + if (!message.isPrivateMessage()) { if (hasMeCommand) { body.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), 0, nick.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); @@ -449,13 +452,8 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie if (message.getStatus() <= Message.STATUS_RECEIVED) { privateMarker = activity.getString(R.string.private_message); } else { - final String to; - if (message.getCounterpart() != null) { - to = message.getCounterpart().getResource(); - } else { - to = ""; - } - privateMarker = activity.getString(R.string.private_message_to, to); + Jid cp = message.getCounterpart(); + privateMarker = activity.getString(R.string.private_message_to, Strings.nullToEmpty(cp == null ? null : cp.getResource())); } body.insert(0, privateMarker); int privateMarkerIndex = privateMarker.length(); @@ -506,27 +504,27 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie } } - private void displayDownloadableMessage(ViewHolder viewHolder, final Message message, String text) { + private void displayDownloadableMessage(ViewHolder viewHolder, final Message message, String text, final boolean darkBackground) { + toggleWhisperInfo(viewHolder, message, darkBackground); viewHolder.image.setVisibility(View.GONE); - viewHolder.messageBody.setVisibility(View.GONE); viewHolder.audioPlayer.setVisibility(View.GONE); viewHolder.download_button.setVisibility(View.VISIBLE); viewHolder.download_button.setText(text); viewHolder.download_button.setOnClickListener(v -> ConversationFragment.downloadFile(activity, message)); } - private void displayOpenableMessage(ViewHolder viewHolder, final Message message) { + private void displayOpenableMessage(ViewHolder viewHolder, final Message message, final boolean darkBackground) { + toggleWhisperInfo(viewHolder, message, darkBackground); viewHolder.image.setVisibility(View.GONE); - viewHolder.messageBody.setVisibility(View.GONE); viewHolder.audioPlayer.setVisibility(View.GONE); viewHolder.download_button.setVisibility(View.VISIBLE); viewHolder.download_button.setText(activity.getString(R.string.open_x_file, UIHelper.getFileDescriptionString(activity, message))); viewHolder.download_button.setOnClickListener(v -> openDownloadable(message)); } - private void displayLocationMessage(ViewHolder viewHolder, final Message message) { + private void displayLocationMessage(ViewHolder viewHolder, final Message message, final boolean darkBackground) { + toggleWhisperInfo(viewHolder, message, darkBackground); viewHolder.image.setVisibility(View.GONE); - viewHolder.messageBody.setVisibility(View.GONE); viewHolder.audioPlayer.setVisibility(View.GONE); viewHolder.download_button.setVisibility(View.VISIBLE); viewHolder.download_button.setText(R.string.show_location); @@ -534,8 +532,8 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie } private void displayAudioMessage(ViewHolder viewHolder, Message message, boolean darkBackground) { + toggleWhisperInfo(viewHolder, message, darkBackground); viewHolder.image.setVisibility(View.GONE); - viewHolder.messageBody.setVisibility(View.GONE); viewHolder.download_button.setVisibility(View.GONE); final RelativeLayout audioPlayer = viewHolder.audioPlayer; audioPlayer.setVisibility(View.VISIBLE); @@ -543,9 +541,9 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie this.audioPlayer.init(audioPlayer, message); } - private void displayImageMessage(ViewHolder viewHolder, final Message message) { + private void displayImageMessage(ViewHolder viewHolder, final Message message, final boolean darkBackground) { + toggleWhisperInfo(viewHolder, message, darkBackground); viewHolder.download_button.setVisibility(View.GONE); - viewHolder.messageBody.setVisibility(View.GONE); viewHolder.audioPlayer.setVisibility(View.GONE); viewHolder.image.setVisibility(View.VISIBLE); FileParams params = message.getFileParams(); @@ -572,6 +570,25 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie viewHolder.image.setOnClickListener(v -> openDownloadable(message)); } + private void toggleWhisperInfo(ViewHolder viewHolder, final Message message, final boolean darkBackground) { + if (message.isPrivateMessage()) { + final String privateMarker; + if (message.getStatus() <= Message.STATUS_RECEIVED) { + privateMarker = activity.getString(R.string.private_message); + } else { + Jid cp = message.getCounterpart(); + privateMarker = activity.getString(R.string.private_message_to, Strings.nullToEmpty(cp == null ? null : cp.getResource())); + } + final SpannableString body = new SpannableString(privateMarker); + body.setSpan(new ForegroundColorSpan(getMessageTextColor(darkBackground, false)), 0, privateMarker.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + body.setSpan(new StyleSpan(Typeface.BOLD), 0, privateMarker.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + viewHolder.messageBody.setText(body); + viewHolder.messageBody.setVisibility(View.VISIBLE); + } else { + viewHolder.messageBody.setVisibility(View.GONE); + } + } + private void loadMoreMessages(Conversation conversation) { conversation.setLastClearHistory(0, null); activity.xmppConnectionService.updateConversation(conversation); @@ -722,19 +739,19 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie final Transferable transferable = message.getTransferable(); if (message.isDeleted() || (transferable != null && transferable.getStatus() != Transferable.STATUS_UPLOADING)) { if (transferable != null && transferable.getStatus() == Transferable.STATUS_OFFER) { - displayDownloadableMessage(viewHolder, message, activity.getString(R.string.download_x_file, UIHelper.getFileDescriptionString(activity, message))); + displayDownloadableMessage(viewHolder, message, activity.getString(R.string.download_x_file, UIHelper.getFileDescriptionString(activity, message)), darkBackground); } else if (transferable != null && transferable.getStatus() == Transferable.STATUS_OFFER_CHECK_FILESIZE) { - displayDownloadableMessage(viewHolder, message, activity.getString(R.string.check_x_filesize, UIHelper.getFileDescriptionString(activity, message))); + displayDownloadableMessage(viewHolder, message, activity.getString(R.string.check_x_filesize, UIHelper.getFileDescriptionString(activity, message)), darkBackground); } else { displayInfoMessage(viewHolder, UIHelper.getMessagePreview(activity, message).first, darkBackground); } } else if (message.isFileOrImage() && message.getEncryption() != Message.ENCRYPTION_PGP && message.getEncryption() != Message.ENCRYPTION_DECRYPTION_FAILED) { if (message.getFileParams().width > 0 && message.getFileParams().height > 0) { - displayImageMessage(viewHolder, message); + displayImageMessage(viewHolder, message, darkBackground); } else if (message.getFileParams().runtime > 0) { displayAudioMessage(viewHolder, message, darkBackground); } else { - displayOpenableMessage(viewHolder, message); + displayOpenableMessage(viewHolder, message, darkBackground); } } else if (message.getEncryption() == Message.ENCRYPTION_PGP) { if (account.isPgpDecryptionServiceConnected()) { @@ -756,7 +773,7 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie displayInfoMessage(viewHolder, activity.getString(R.string.omemo_decryption_failed), darkBackground); } else { if (message.isGeoUri()) { - displayLocationMessage(viewHolder, message); + displayLocationMessage(viewHolder, message, darkBackground); } else if (message.bodyIsOnlyEmojis() && message.getType() != Message.TYPE_PRIVATE) { displayEmojiMessage(viewHolder, message.getBody().trim(), darkBackground); } else if (message.treatAsDownloadable()) { @@ -766,19 +783,22 @@ public class MessageAdapter extends ArrayAdapter implements CopyTextVie displayDownloadableMessage(viewHolder, message, activity.getString(R.string.check_x_filesize, - UIHelper.getFileDescriptionString(activity, message))); + UIHelper.getFileDescriptionString(activity, message)), + darkBackground); } else { displayDownloadableMessage(viewHolder, message, activity.getString(R.string.check_x_filesize_on_host, UIHelper.getFileDescriptionString(activity, message), - url.getHost())); + url.getHost()), + darkBackground); } } catch (Exception e) { displayDownloadableMessage(viewHolder, message, activity.getString(R.string.check_x_filesize, - UIHelper.getFileDescriptionString(activity, message))); + UIHelper.getFileDescriptionString(activity, message)), + darkBackground); } } else { displayTextMessage(viewHolder, message, darkBackground, type); diff --git a/src/main/res/layout/message_content.xml b/src/main/res/layout/message_content.xml index 7a2492187..f1f584f0c 100644 --- a/src/main/res/layout/message_content.xml +++ b/src/main/res/layout/message_content.xml @@ -1,6 +1,14 @@ + + - -