From f345c723483c5d8af092acd5d59fd2a2e095052b Mon Sep 17 00:00:00 2001 From: jbsession Date: Fri, 26 Sep 2025 12:13:44 +0800 Subject: [PATCH 1/3] added extension function to defer scrolling --- .../conversation/v2/ConversationActivityV2.kt | 13 +++++++++++-- .../securesms/util/adapter/RecyclerViewUtils.kt | 9 +++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index e9bdbd0541..ed9d0aefe4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -205,6 +205,7 @@ import org.thoughtcrime.securesms.util.PaddedImageSpan import org.thoughtcrime.securesms.util.SaveAttachmentTask import org.thoughtcrime.securesms.util.adapter.applyImeBottomPadding import org.thoughtcrime.securesms.util.adapter.handleScrollToBottom +import org.thoughtcrime.securesms.util.adapter.runWhenLaidOut import org.thoughtcrime.securesms.util.drawToBitmap import org.thoughtcrime.securesms.util.fadeIn import org.thoughtcrime.securesms.util.fadeOut @@ -1162,14 +1163,22 @@ class ConversationActivityV2 : ScreenLockActionBarActivity(), InputBarDelegate, private fun scrollToFirstUnreadMessageOrBottom() { // if there are no unread messages, go straight to the very bottom of the list if (unreadCount == 0) { - layoutManager?.scrollToPositionWithOffset(adapter.itemCount - 1, Int.MIN_VALUE) + binding.conversationRecyclerView.runWhenLaidOut { + layoutManager?.scrollToPositionWithOffset(adapter.itemCount - 1, Int.MIN_VALUE) + } return } val lastSeenTimestamp = threadDb.getLastSeenAndHasSent(viewModel.threadId).first() val lastSeenItemPosition = adapter.findLastSeenItemPosition(lastSeenTimestamp) ?: return - layoutManager?.scrollToPositionWithOffset(lastSeenItemPosition, ((layoutManager?.height ?: 0) / 2)) + binding.conversationRecyclerView.runWhenLaidOut { + layoutManager?.scrollToPositionWithOffset( + lastSeenItemPosition, + ((layoutManager?.height ?: 0) / 2) + ) + } + } private fun highlightViewAtPosition(position: Int) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/adapter/RecyclerViewUtils.kt b/app/src/main/java/org/thoughtcrime/securesms/util/adapter/RecyclerViewUtils.kt index aa1d43cb5c..d749d023a1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/adapter/RecyclerViewUtils.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/util/adapter/RecyclerViewUtils.kt @@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.util.adapter import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat +import androidx.core.view.doOnPreDraw import androidx.core.view.updatePadding import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearSmoothScroller @@ -43,4 +44,12 @@ fun RecyclerView.handleScrollToBottom() { } scroller.targetPosition = last layoutManager.startSmoothScroll(scroller) +} + +fun RecyclerView.runWhenLaidOut(block: () -> Unit) { + if (isLaidOut && !isLayoutRequested) { + post(block) + } else { + doOnPreDraw { post(block) } + } } \ No newline at end of file From 38b65f1a310415b471a7e3f38335fa407be6eb41 Mon Sep 17 00:00:00 2001 From: jbsession Date: Fri, 3 Oct 2025 13:25:13 +0800 Subject: [PATCH 2/3] Added fallback address when extras get stripped --- .../conversation/v2/ConversationActivityV2.kt | 17 +++++++++++++++-- .../notifications/NotificationItem.java | 14 ++++++++------ 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index 9fa6a86079..f8d946cc74 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -283,9 +283,22 @@ class ConversationActivityV2 : ScreenLockActionBarActivity(), InputBarDelegate, } private val address: Address.Conversable by lazy { - requireNotNull(IntentCompat.getParcelableExtra(intent, ADDRESS, Address.Conversable::class.java)) { - "Address must be provided in the intent extras" + val fromExtras = + IntentCompat.getParcelableExtra(intent, ADDRESS, Address.Conversable::class.java) + if (fromExtras != null) { + return@lazy fromExtras } + + // Fallback: parse from URI + val serialized = intent.data?.getQueryParameter(ADDRESS) + if (!serialized.isNullOrEmpty()) { + val parsed = fromSerialized(serialized) + if (parsed is Address.Conversable) { + return@lazy parsed + } + } + + throw IllegalArgumentException("Address must be provided in the intent extras or URI") } private val viewModel: ConversationViewModel by viewModels(extrasProducer = { diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationItem.java b/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationItem.java index 0454cb8599..abaaa419c5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationItem.java +++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationItem.java @@ -72,19 +72,21 @@ public long getThreadId() { } public PendingIntent getPendingIntent(Context context) { - - Recipient notifyRecipients = threadRecipient != null ? threadRecipient : conversationRecipient; + Recipient notifyRecipients = getRecipient(); final Intent intent = ConversationActivityV2.Companion.createIntent(context, (Address.Conversable) notifyRecipients.getAddress()); - intent.setData((Uri.parse("custom://"+System.currentTimeMillis()))); + intent.setData(Uri.parse("custom://" + System.currentTimeMillis()) + .buildUpon() + .appendQueryParameter("address", notifyRecipients.getAddress().toString()) + .build()); - int intentFlags = PendingIntent.FLAG_UPDATE_CURRENT; + int intentFlags = PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_CANCEL_CURRENT; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { intentFlags |= PendingIntent.FLAG_MUTABLE; } return TaskStackBuilder.create(context) - .addNextIntentWithParentStack(intent) - .getPendingIntent(0, intentFlags); + .addNextIntentWithParentStack(intent) + .getPendingIntent(0, intentFlags); } public long getId() { From 91ba165c24665d55b6b3c2de62d7c54bcc3dfe82 Mon Sep 17 00:00:00 2001 From: jbsession Date: Fri, 3 Oct 2025 13:36:15 +0800 Subject: [PATCH 3/3] update intent flags --- .../thoughtcrime/securesms/notifications/NotificationItem.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationItem.java b/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationItem.java index abaaa419c5..c0042fb271 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationItem.java +++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationItem.java @@ -79,7 +79,7 @@ public PendingIntent getPendingIntent(Context context) { .appendQueryParameter("address", notifyRecipients.getAddress().toString()) .build()); - int intentFlags = PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_CANCEL_CURRENT; + int intentFlags = PendingIntent.FLAG_UPDATE_CURRENT; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { intentFlags |= PendingIntent.FLAG_MUTABLE; }