From 916f705c50deabe69f9cb92771285fff7b53dd0f Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 31 Jul 2023 14:44:43 +0930 Subject: [PATCH 01/10] Prefix message with name in HomeActivity --- .../securesms/database/MmsSmsDatabase.java | 10 +++++++ .../securesms/database/ThreadDatabase.java | 10 ++++++- .../database/model/ThreadRecord.java | 4 ++- .../securesms/home/ConversationView.kt | 29 +++++++++++++------ 4 files changed, 42 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsDatabase.java index 0db4dd00e5..3d175fd8bd 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsDatabase.java @@ -209,6 +209,16 @@ public class MmsSmsDatabase extends Database { } } + public long getLastMessageTimestamp(long threadId) { + String order = MmsSmsColumns.NORMALIZED_DATE_SENT + " DESC"; + String selection = MmsSmsColumns.THREAD_ID + " = " + threadId; + + try (Cursor cursor = queryTables(PROJECTION, selection, order, "1")) { + cursor.moveToFirst(); + return cursor.getLong(cursor.getColumnIndexOrThrow(MmsSmsColumns.NORMALIZED_DATE_SENT)); + } + } + public Cursor getUnread() { String order = MmsSmsColumns.NORMALIZED_DATE_SENT + " ASC"; String selection = "(" + MmsSmsColumns.READ + " = 0 OR " + MmsSmsColumns.REACTIONS_UNREAD + " = 1) AND " + MmsSmsColumns.NOTIFIED + " = 0"; diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java index 5044529981..c525f05e7d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java @@ -951,7 +951,9 @@ public class ThreadDatabase extends Database { readReceiptCount = 0; } - return new ThreadRecord(body, snippetUri, recipient, date, count, + MessageRecord lastMessage = count > 0 ? getLastMessage(threadId) : null; + + return new ThreadRecord(body, snippetUri, lastMessage, recipient, date, count, unreadCount, unreadMentionCount, threadId, deliveryReceiptCount, status, type, distributionType, archived, expiresIn, lastSeen, readReceiptCount, pinned); } @@ -976,4 +978,10 @@ public class ThreadDatabase extends Database { } } } + + private MessageRecord getLastMessage(long threadId) { + MmsSmsDatabase mmsSmsDatabase = DatabaseComponent.get(context).mmsSmsDatabase(); + long messageTimestamp = mmsSmsDatabase.getLastMessageTimestamp(threadId); + return mmsSmsDatabase.getMessageForTimestamp(messageTimestamp); + } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/ThreadRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/ThreadRecord.java index f3e72a8747..0c023a8f29 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/ThreadRecord.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/ThreadRecord.java @@ -43,6 +43,7 @@ import network.loki.messenger.R; public class ThreadRecord extends DisplayRecord { private @Nullable final Uri snippetUri; + public @Nullable final MessageRecord lastMessage; private final long count; private final int unreadCount; private final int unreadMentionCount; @@ -54,13 +55,14 @@ public class ThreadRecord extends DisplayRecord { private final int initialRecipientHash; public ThreadRecord(@NonNull String body, @Nullable Uri snippetUri, - @NonNull Recipient recipient, long date, long count, int unreadCount, + @Nullable MessageRecord lastMessage, @NonNull Recipient recipient, long date, long count, int unreadCount, int unreadMentionCount, long threadId, int deliveryReceiptCount, int status, long snippetType, int distributionType, boolean archived, long expiresIn, long lastSeen, int readReceiptCount, boolean pinned) { super(body, recipient, date, date, threadId, status, deliveryReceiptCount, snippetType, readReceiptCount); this.snippetUri = snippetUri; + this.lastMessage = lastMessage; this.count = count; this.unreadCount = unreadCount; this.unreadMentionCount = unreadMentionCount; diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/ConversationView.kt b/app/src/main/java/org/thoughtcrime/securesms/home/ConversationView.kt index 31b281c6de..454bcef18d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/home/ConversationView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/home/ConversationView.kt @@ -4,6 +4,8 @@ import android.content.Context import android.content.res.Resources import android.graphics.Typeface import android.graphics.drawable.ColorDrawable +import android.text.SpannableString +import android.text.TextUtils import android.util.AttributeSet import android.util.TypedValue import android.view.View @@ -89,7 +91,7 @@ class ConversationView : LinearLayout { || (configFactory.convoVolatile?.getConversationUnread(thread) == true) binding.unreadMentionTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, textSize) binding.unreadMentionIndicator.isVisible = (thread.unreadMentionCount != 0 && thread.recipient.address.isGroup) - val senderDisplayName = getUserDisplayName(thread.recipient) + val senderDisplayName = getTitle(thread.recipient) ?: thread.recipient.address.toString() binding.conversationViewDisplayNameTextView.text = senderDisplayName binding.timestampTextView.text = DateUtils.getDisplayFormattedTimeSpanString(context, Locale.getDefault(), thread.date) @@ -101,9 +103,7 @@ class ConversationView : LinearLayout { R.drawable.ic_notifications_mentions } binding.muteIndicatorImageView.setImageResource(drawableRes) - val rawSnippet = thread.getDisplayBody(context) - val snippet = highlightMentions(rawSnippet, thread.threadId, context) - binding.snippetTextView.text = snippet + binding.snippetTextView.text = highlightMentions(getSnippet(thread), thread.threadId, context) binding.snippetTextView.typeface = if (unreadCount > 0 && !thread.isRead) Typeface.DEFAULT_BOLD else Typeface.DEFAULT binding.snippetTextView.visibility = if (isTyping) View.GONE else View.VISIBLE if (isTyping) { @@ -131,11 +131,22 @@ class ConversationView : LinearLayout { binding.profilePictureView.recycle() } - private fun getUserDisplayName(recipient: Recipient): String? { - return if (recipient.isLocalNumber) { - context.getString(R.string.note_to_self) - } else { - recipient.toShortString() // Internally uses the Contact API + private fun getTitle(recipient: Recipient): String? = when { + recipient.isLocalNumber -> context.getString(R.string.note_to_self) + else -> recipient.toShortString() // Internally uses the Contact API + } + + private fun getSnippet(thread: ThreadRecord): CharSequence { + thread.apply { + val body = getDisplayBody(context) + + val snippetAuthor = lastMessage?.individualRecipient + + return if (lastMessage?.isOutgoing == true) { + TextUtils.concat(resources.getString(R.string.MessageRecord_you), ": ", body) + } else { + return snippetAuthor?.toShortString()?.let { TextUtils.concat(it, ": ", body) } ?: body + } } } // endregion From dd345cbf074bb54e7e86d1f4e2a82f446f3dd2d3 Mon Sep 17 00:00:00 2001 From: Andrew Date: Mon, 31 Jul 2023 19:40:20 +0930 Subject: [PATCH 02/10] Hide sender prefix for note to self --- .../securesms/home/ConversationView.kt | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/ConversationView.kt b/app/src/main/java/org/thoughtcrime/securesms/home/ConversationView.kt index 454bcef18d..5191e05d77 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/home/ConversationView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/home/ConversationView.kt @@ -136,17 +136,19 @@ class ConversationView : LinearLayout { else -> recipient.toShortString() // Internally uses the Contact API } - private fun getSnippet(thread: ThreadRecord): CharSequence { - thread.apply { - val body = getDisplayBody(context) + private fun getSnippet(thread: ThreadRecord): CharSequence = thread.run { + val body = getDisplayBody(context) - val snippetAuthor = lastMessage?.individualRecipient - - return if (lastMessage?.isOutgoing == true) { + when { + recipient.isLocalNumber -> body // Note to self + lastMessage?.isOutgoing == true -> { TextUtils.concat(resources.getString(R.string.MessageRecord_you), ": ", body) - } else { - return snippetAuthor?.toShortString()?.let { TextUtils.concat(it, ": ", body) } ?: body } + else -> lastMessage + ?.individualRecipient + ?.toShortString() + ?.let { TextUtils.concat(it, ": ", body) } + ?: body } } // endregion From b487d5aa6407a1b91f48346ee4a7171401828814 Mon Sep 17 00:00:00 2001 From: Andrew Date: Mon, 31 Jul 2023 19:48:45 +0930 Subject: [PATCH 03/10] Hide sender prefix for control messages --- .../java/org/thoughtcrime/securesms/home/ConversationView.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/ConversationView.kt b/app/src/main/java/org/thoughtcrime/securesms/home/ConversationView.kt index 5191e05d77..b1bd55b20a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/home/ConversationView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/home/ConversationView.kt @@ -140,7 +140,7 @@ class ConversationView : LinearLayout { val body = getDisplayBody(context) when { - recipient.isLocalNumber -> body // Note to self + recipient.isLocalNumber || lastMessage?.isControlMessage == true -> body // Note to self lastMessage?.isOutgoing == true -> { TextUtils.concat(resources.getString(R.string.MessageRecord_you), ": ", body) } From f70aa9155b04b2980da1ce726826f483ceef6c49 Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 7 Aug 2023 10:26:20 +0930 Subject: [PATCH 04/10] Remove problematic getLastMessage() --- .../securesms/database/ThreadDatabase.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java index c525f05e7d..f4ab65f56c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java @@ -951,7 +951,13 @@ public class ThreadDatabase extends Database { readReceiptCount = 0; } - MessageRecord lastMessage = count > 0 ? getLastMessage(threadId) : null; + MessageRecord lastMessage = null; + + if (count > 0) { + MmsSmsDatabase mmsSmsDatabase = DatabaseComponent.get(context).mmsSmsDatabase(); + long messageTimestamp = mmsSmsDatabase.getLastMessageTimestamp(threadId); + lastMessage = mmsSmsDatabase.getMessageForTimestamp(messageTimestamp); + } return new ThreadRecord(body, snippetUri, lastMessage, recipient, date, count, unreadCount, unreadMentionCount, threadId, deliveryReceiptCount, status, type, @@ -978,10 +984,4 @@ public class ThreadDatabase extends Database { } } } - - private MessageRecord getLastMessage(long threadId) { - MmsSmsDatabase mmsSmsDatabase = DatabaseComponent.get(context).mmsSmsDatabase(); - long messageTimestamp = mmsSmsDatabase.getLastMessageTimestamp(threadId); - return mmsSmsDatabase.getMessageForTimestamp(messageTimestamp); - } } From 50fd3292c8b9cb45d6b7f8da212adcf2d15da2f7 Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 7 Aug 2023 10:46:38 +0930 Subject: [PATCH 05/10] Refactor snippet formatting --- .../securesms/home/ConversationView.kt | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/ConversationView.kt b/app/src/main/java/org/thoughtcrime/securesms/home/ConversationView.kt index b1bd55b20a..47a37a092a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/home/ConversationView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/home/ConversationView.kt @@ -103,7 +103,7 @@ class ConversationView : LinearLayout { R.drawable.ic_notifications_mentions } binding.muteIndicatorImageView.setImageResource(drawableRes) - binding.snippetTextView.text = highlightMentions(getSnippet(thread), thread.threadId, context) + binding.snippetTextView.text = highlightMentions(thread.getSnippet(), thread.threadId, context) binding.snippetTextView.typeface = if (unreadCount > 0 && !thread.isRead) Typeface.DEFAULT_BOLD else Typeface.DEFAULT binding.snippetTextView.visibility = if (isTyping) View.GONE else View.VISIBLE if (isTyping) { @@ -136,20 +136,16 @@ class ConversationView : LinearLayout { else -> recipient.toShortString() // Internally uses the Contact API } - private fun getSnippet(thread: ThreadRecord): CharSequence = thread.run { - val body = getDisplayBody(context) + private fun ThreadRecord.getSnippet(): CharSequence = + concatSnippet(getSnippetPrefix(), getDisplayBody(context)) - when { - recipient.isLocalNumber || lastMessage?.isControlMessage == true -> body // Note to self - lastMessage?.isOutgoing == true -> { - TextUtils.concat(resources.getString(R.string.MessageRecord_you), ": ", body) - } - else -> lastMessage - ?.individualRecipient - ?.toShortString() - ?.let { TextUtils.concat(it, ": ", body) } - ?: body - } + private fun concatSnippet(prefix: CharSequence?, body: CharSequence): CharSequence = + prefix?.let { TextUtils.concat(it, ": ", body) } ?: body + + private fun ThreadRecord.getSnippetPrefix(): CharSequence? = when { + recipient.isLocalNumber || lastMessage?.isControlMessage == true -> null + lastMessage?.isOutgoing == true -> resources.getString(R.string.MessageRecord_you) + else -> lastMessage?.individualRecipient?.toShortString() } // endregion } From 35d176c71e3ed6b0df3d98ca1369923e26b52773 Mon Sep 17 00:00:00 2001 From: Andrew Date: Tue, 9 Apr 2024 12:36:11 +0930 Subject: [PATCH 06/10] Handle case where there are no messages --- .../thoughtcrime/securesms/database/MmsSmsDatabase.java | 7 +++++-- .../thoughtcrime/securesms/database/ThreadDatabase.java | 4 +++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsDatabase.java index be66d84db2..da4f39f0c1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsDatabase.java @@ -325,9 +325,12 @@ public class MmsSmsDatabase extends Database { String selection = MmsSmsColumns.THREAD_ID + " = " + threadId; try (Cursor cursor = queryTables(PROJECTION, selection, order, "1")) { - cursor.moveToFirst(); - return cursor.getLong(cursor.getColumnIndexOrThrow(MmsSmsColumns.NORMALIZED_DATE_SENT)); + if (cursor.moveToFirst()) { + return cursor.getLong(cursor.getColumnIndexOrThrow(MmsSmsColumns.NORMALIZED_DATE_SENT)); + } } + + return -1; } public Cursor getUnread() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java index b7adab9320..ef3937d4d4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java @@ -939,7 +939,9 @@ public class ThreadDatabase extends Database { if (count > 0) { MmsSmsDatabase mmsSmsDatabase = DatabaseComponent.get(context).mmsSmsDatabase(); long messageTimestamp = mmsSmsDatabase.getLastMessageTimestamp(threadId); - lastMessage = mmsSmsDatabase.getMessageForTimestamp(messageTimestamp); + if (messageTimestamp > 0) { + lastMessage = mmsSmsDatabase.getMessageForTimestamp(messageTimestamp); + } } return new ThreadRecord(body, snippetUri, lastMessage, recipient, date, count, From 6960d0c7049147567a45e09f4c41ed44c792e003 Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 12 Apr 2024 11:37:45 +0930 Subject: [PATCH 07/10] Fix spacing when title is absent --- .../securesms/SessionDialogBuilder.kt | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/SessionDialogBuilder.kt b/app/src/main/java/org/thoughtcrime/securesms/SessionDialogBuilder.kt index a99b40f36f..52c9fe760a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/SessionDialogBuilder.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/SessionDialogBuilder.kt @@ -7,7 +7,9 @@ import android.view.ViewGroup.LayoutParams.MATCH_PARENT import android.view.ViewGroup.LayoutParams.WRAP_CONTENT import android.widget.Button import android.widget.LinearLayout +import android.widget.LinearLayout.LayoutParams import android.widget.LinearLayout.VERTICAL +import android.widget.Space import android.widget.TextView import androidx.annotation.AttrRes import androidx.annotation.LayoutRes @@ -15,13 +17,11 @@ import androidx.annotation.StringRes import androidx.annotation.StyleRes import androidx.appcompat.app.AlertDialog import androidx.core.view.setMargins -import androidx.core.view.setPadding import androidx.core.view.updateMargins import androidx.fragment.app.Fragment import network.loki.messenger.R import org.thoughtcrime.securesms.util.toPx - @DslMarker @Target(AnnotationTarget.CLASS, AnnotationTarget.TYPE) annotation class DialogDsl @@ -37,7 +37,9 @@ class SessionDialogBuilder(val context: Context) { private var dialog: AlertDialog? = null private fun dismiss() = dialog?.dismiss() - private val topView = LinearLayout(context).apply { orientation = VERTICAL } + private val topView = LinearLayout(context) + .apply { setPadding(0, dp20, 0, 0) } + .apply { orientation = VERTICAL } .also(dialogBuilder::setCustomTitle) private val contentView = LinearLayout(context).apply { orientation = VERTICAL } private val buttonLayout = LinearLayout(context) @@ -53,18 +55,17 @@ class SessionDialogBuilder(val context: Context) { fun title(text: CharSequence?) = title(text?.toString()) fun title(text: String?) { - text(text, R.style.TextAppearance_AppCompat_Title) { setPadding(dp20) } + text(text, R.style.TextAppearance_AppCompat_Title) { setPadding(dp20, 0, dp20, 0) } } fun text(@StringRes id: Int, style: Int = 0) = text(context.getString(id), style) fun text(text: CharSequence?, @StyleRes style: Int = 0) { text(text, style) { layoutParams = LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT) - .apply { updateMargins(dp40, 0, dp40, dp20) } + .apply { updateMargins(dp40, 0, dp40, 0) } } } - private fun text(text: CharSequence?, @StyleRes style: Int, modify: TextView.() -> Unit) { text ?: return TextView(context, null, 0, style) @@ -73,6 +74,10 @@ class SessionDialogBuilder(val context: Context) { textAlignment = View.TEXT_ALIGNMENT_CENTER modify() }.let(topView::addView) + + Space(context).apply { + layoutParams = LayoutParams(0, dp20) + }.let(topView::addView) } fun view(view: View) = contentView.addView(view) @@ -126,7 +131,7 @@ class SessionDialogBuilder(val context: Context) { setText(text) contentDescription = resources.getString(contentDescriptionRes) layoutParams = LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT, 1f) - .apply { setMargins(toPx(20, resources)) } + .apply { setMargins(dp20) } setOnClickListener { listener.invoke() if (dismiss) dismiss() From 8f69d5737404cd321fc554deddc2af4e1bc43158 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sat, 13 Apr 2024 00:04:33 +0930 Subject: [PATCH 08/10] Fix multiple quote previews --- .../securesms/conversation/v2/input_bar/InputBar.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBar.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBar.kt index 5959c41d16..f9cbea2b1f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBar.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBar.kt @@ -140,6 +140,8 @@ class InputBar : RelativeLayout, InputBarEditTextDelegate, QuoteViewDelegate, Li } fun draftQuote(thread: Recipient, message: MessageRecord, glide: GlideRequests) { + quoteView?.let(binding.inputBarAdditionalContentContainer::removeView) + quote = message // If we already have a link preview View then clear the 'additional content' layout so that From 9d1762eab0374901a73bce68145ab12d6c2a092a Mon Sep 17 00:00:00 2001 From: Andrew Date: Sat, 13 Apr 2024 00:27:45 +0930 Subject: [PATCH 09/10] Fix message menu icons not visible in light theme --- .../thoughtcrime/securesms/components/menu/ContextMenuList.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/menu/ContextMenuList.kt b/app/src/main/java/org/thoughtcrime/securesms/components/menu/ContextMenuList.kt index 31870e9b7a..69dec0cdd6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/menu/ContextMenuList.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/menu/ContextMenuList.kt @@ -17,6 +17,7 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.launch import network.loki.messenger.R +import org.session.libsession.utilities.getColorFromAttr import org.thoughtcrime.securesms.util.adapter.mapping.LayoutFactory import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter import org.thoughtcrime.securesms.util.adapter.mapping.MappingModel @@ -84,7 +85,7 @@ class ContextMenuList(recyclerView: RecyclerView, onItemClick: () -> Unit) { context.theme.resolveAttribute(item.iconRes, typedValue, true) icon.setImageDrawable(ContextCompat.getDrawable(context, typedValue.resourceId)) - icon.imageTintList = color?.let(ColorStateList::valueOf) + icon.imageTintList = ColorStateList.valueOf(color ?: context.getColorFromAttr(android.R.attr.textColor)) } item.contentDescription?.let(context.resources::getString)?.let { itemView.contentDescription = it } title.setText(item.title) From 96510946c6f4adf58c5643916b175a274da12ba6 Mon Sep 17 00:00:00 2001 From: AL-Session <160798022+AL-Session@users.noreply.github.com> Date: Tue, 16 Apr 2024 13:37:13 +1000 Subject: [PATCH 10/10] SES-1727 Mentions text is the wrong colour (#1454) * Fixes #1453 * Cleanup * Code review adjustments * Adjusted mentions to use the accent colour as their background colour when using light themes --------- Co-authored-by: alansley --- .../securesms/BaseActionBarActivity.java | 9 ++++- .../v2/utilities/MentionUtilities.kt | 40 ++++++++++++++++--- .../securesms/util/ViewUtilities.kt | 18 ++++++++- .../messaging/mentions/MentionsManager.kt | 2 +- .../libsession/utilities/ThemeUtil.java | 4 ++ 5 files changed, 63 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/BaseActionBarActivity.java b/app/src/main/java/org/thoughtcrime/securesms/BaseActionBarActivity.java index 51f66ec323..c43d406575 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/BaseActionBarActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/BaseActionBarActivity.java @@ -39,15 +39,20 @@ public abstract class BaseActionBarActivity extends AppCompatActivity { public int getDesiredTheme() { ThemeState themeState = ActivityUtilitiesKt.themeState(getPreferences()); int userSelectedTheme = themeState.getTheme(); + + // If the user has configured Session to follow the system light/dark theme mode then do so.. if (themeState.getFollowSystem()) { - // do light or dark based on the selected theme + + // Use light or dark versions of the user's theme based on light-mode / dark-mode settings boolean isDayUi = UiModeUtilities.isDayUiMode(this); if (userSelectedTheme == R.style.Ocean_Dark || userSelectedTheme == R.style.Ocean_Light) { return isDayUi ? R.style.Ocean_Light : R.style.Ocean_Dark; } else { return isDayUi ? R.style.Classic_Light : R.style.Classic_Dark; } - } else { + } + else // ..otherwise just return their selected theme. + { return userSelectedTheme; } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/MentionUtilities.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/MentionUtilities.kt index 1ba4a0c3e5..a52d8458f1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/MentionUtilities.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/MentionUtilities.kt @@ -4,18 +4,24 @@ import android.content.Context import android.graphics.Typeface import android.text.Spannable import android.text.SpannableString +import android.text.style.BackgroundColorSpan import android.text.style.ForegroundColorSpan import android.text.style.StyleSpan import android.util.Range +import androidx.appcompat.widget.ThemeUtils import androidx.core.content.res.ResourcesCompat import network.loki.messenger.R import nl.komponents.kovenant.combine.Tuple2 import org.session.libsession.messaging.contacts.Contact import org.session.libsession.messaging.utilities.SodiumUtilities import org.session.libsession.utilities.TextSecurePreferences +import org.session.libsession.utilities.ThemeUtil +import org.session.libsignal.utilities.Log import org.thoughtcrime.securesms.dependencies.DatabaseComponent import org.thoughtcrime.securesms.util.UiModeUtilities import org.thoughtcrime.securesms.util.getAccentColor +import org.thoughtcrime.securesms.util.getColorResourceIdFromAttr +import org.thoughtcrime.securesms.util.getMessageTextColourAttr import java.util.regex.Pattern object MentionUtilities { @@ -58,15 +64,37 @@ object MentionUtilities { } } val result = SpannableString(text) - val isLightMode = UiModeUtilities.isDayUiMode(context) - val color = if (isOutgoingMessage) { - ResourcesCompat.getColor(context.resources, if (isLightMode) R.color.white else R.color.black, context.theme) - } else { - context.getAccentColor() + + var mentionTextColour: Int? = null + // In dark themes.. + if (ThemeUtil.isDarkTheme(context)) { + // ..we use the standard outgoing message colour for outgoing messages.. + if (isOutgoingMessage) { + val mentionTextColourAttributeId = getMessageTextColourAttr(true) + val mentionTextColourResourceId = getColorResourceIdFromAttr(context, mentionTextColourAttributeId) + mentionTextColour = ResourcesCompat.getColor(context.resources, mentionTextColourResourceId, context.theme) + } + else // ..but we use the accent colour for incoming messages (i.e., someone mentioning us).. + { + mentionTextColour = context.getAccentColor() + } } + else // ..while in light themes we always just use the incoming or outgoing message text colour for mentions. + { + val mentionTextColourAttributeId = getMessageTextColourAttr(isOutgoingMessage) + val mentionTextColourResourceId = getColorResourceIdFromAttr(context, mentionTextColourAttributeId) + mentionTextColour = ResourcesCompat.getColor(context.resources, mentionTextColourResourceId, context.theme) + } + for (mention in mentions) { - result.setSpan(ForegroundColorSpan(color), mention.first.lower, mention.first.upper, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) + result.setSpan(ForegroundColorSpan(mentionTextColour), mention.first.lower, mention.first.upper, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) result.setSpan(StyleSpan(Typeface.BOLD), mention.first.lower, mention.first.upper, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) + + // If we're using a light theme then we change the background colour of the mention to be the accent colour + if (ThemeUtil.isLightTheme(context)) { + val backgroundColour = context.getAccentColor(); + result.setSpan(BackgroundColorSpan(backgroundColour), mention.first.lower, mention.first.upper, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) + } } return result } diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/ViewUtilities.kt b/app/src/main/java/org/thoughtcrime/securesms/util/ViewUtilities.kt index dfd4ffe419..9c427e1f86 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/ViewUtilities.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/util/ViewUtilities.kt @@ -9,12 +9,15 @@ import android.graphics.Bitmap import android.graphics.PointF import android.graphics.Rect import android.util.Size +import android.util.TypedValue import android.view.View import androidx.annotation.ColorInt import androidx.annotation.DimenRes import network.loki.messenger.R import org.session.libsession.utilities.getColorFromAttr import android.view.inputmethod.InputMethodManager +import androidx.annotation.AttrRes +import androidx.annotation.ColorRes import androidx.core.graphics.applyCanvas import kotlin.math.roundToInt @@ -32,6 +35,20 @@ val View.hitRect: Rect @ColorInt fun Context.getAccentColor() = getColorFromAttr(R.attr.colorAccent) +// Method to grab the appropriate attribute for a message colour. +// Note: This is an attribute, NOT a resource Id - see `getColorResourceIdFromAttr` for that. +@AttrRes +fun getMessageTextColourAttr(messageIsOutgoing: Boolean): Int = + if (messageIsOutgoing) R.attr.message_sent_text_color else R.attr.message_received_text_color + +// Method to get an actual R.id. resource Id from an attribute such as R.attr.message_sent_text_color etc. +@ColorRes +fun getColorResourceIdFromAttr(context: Context, attr: Int): Int { + val typedValue = TypedValue() + context.theme.resolveAttribute(attr, typedValue, true) + return typedValue.resourceId +} + fun View.animateSizeChange(@DimenRes startSizeID: Int, @DimenRes endSizeID: Int, animationDuration: Long = 250) { val startSize = resources.getDimension(startSizeID) val endSize = resources.getDimension(endSizeID) @@ -70,7 +87,6 @@ fun View.hideKeyboard() { imm.hideSoftInputFromWindow(this.windowToken, 0) } - fun View.drawToBitmap(config: Bitmap.Config = Bitmap.Config.ARGB_8888, longestWidth: Int = 2000): Bitmap { val size = Size(measuredWidth, measuredHeight).coerceAtMost(longestWidth) val scale = size.width / measuredWidth.toFloat() diff --git a/libsession/src/main/java/org/session/libsession/messaging/mentions/MentionsManager.kt b/libsession/src/main/java/org/session/libsession/messaging/mentions/MentionsManager.kt index fd16061e67..c3537a334a 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/mentions/MentionsManager.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/mentions/MentionsManager.kt @@ -2,7 +2,7 @@ package org.session.libsession.messaging.mentions import org.session.libsession.messaging.MessagingModuleConfiguration import org.session.libsession.messaging.contacts.Contact -import java.util.* +import java.util.Locale object MentionsManager { var userPublicKeyCache = mutableMapOf>() // Thread ID to set of user hex encoded public keys diff --git a/libsession/src/main/java/org/session/libsession/utilities/ThemeUtil.java b/libsession/src/main/java/org/session/libsession/utilities/ThemeUtil.java index dc77aae5ac..22375b1da7 100644 --- a/libsession/src/main/java/org/session/libsession/utilities/ThemeUtil.java +++ b/libsession/src/main/java/org/session/libsession/utilities/ThemeUtil.java @@ -27,6 +27,10 @@ public class ThemeUtil { return getAttributeText(context, R.attr.theme_type, "light").equals("dark"); } + public static boolean isLightTheme(@NonNull Context context) { + return getAttributeText(context, R.attr.theme_type, "light").equals("light"); + } + public static boolean getThemedBoolean(@NonNull Context context, @AttrRes int attr) { TypedValue typedValue = new TypedValue(); Resources.Theme theme = context.getTheme();