From 74e49cf939af2b0fcf0565b8b913f79d136ca8e3 Mon Sep 17 00:00:00 2001
From: Naveen Singh <36371707+naveensingh@users.noreply.github.com>
Date: Tue, 23 Dec 2025 18:28:34 +0530
Subject: [PATCH] feat: allow copying numbers from inside threads (#652)
* feat: allow copying numbers from inside threads
* fix: no such item exception!
* fix: reduce cyclomatic complexity for `setupOptionsMenu()`
* fix: prefer `conversation.phoneNumber` for clipboard
Refs: https://github.com/FossifyOrg/Messages/issues/651
---
CHANGELOG.md | 4 ++
.../messages/activities/ThreadActivity.kt | 63 +++++++++++--------
app/src/main/res/menu/menu_thread.xml | 4 ++
3 files changed, 45 insertions(+), 26 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 00b904a6..b18acda3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
+### Added
+- Added "Copy number to clipboard" option inside chat overflow menu ([#651])
+
### Fixed
- Fixed missing notifications in some cases ([#159])
- Fixed incorrect blocking of MMS messages in some rare cases ([#644])
@@ -223,6 +226,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[#600]: https://github.com/FossifyOrg/Messages/issues/600
[#610]: https://github.com/FossifyOrg/Messages/issues/610
[#644]: https://github.com/FossifyOrg/Messages/issues/644
+[#651]: https://github.com/FossifyOrg/Messages/issues/651
[Unreleased]: https://github.com/FossifyOrg/Messages/compare/1.7.0...HEAD
[1.7.0]: https://github.com/FossifyOrg/Messages/compare/1.6.0...1.7.0
diff --git a/app/src/main/kotlin/org/fossify/messages/activities/ThreadActivity.kt b/app/src/main/kotlin/org/fossify/messages/activities/ThreadActivity.kt
index d7f62265..0c7c47b6 100644
--- a/app/src/main/kotlin/org/fossify/messages/activities/ThreadActivity.kt
+++ b/app/src/main/kotlin/org/fossify/messages/activities/ThreadActivity.kt
@@ -28,6 +28,7 @@ import android.text.format.DateUtils.FORMAT_SHOW_TIME
import android.util.TypedValue
import android.view.Gravity
import android.view.KeyEvent
+import android.view.MenuItem
import android.view.View
import android.view.WindowManager
import android.view.animation.OvershootInterpolator
@@ -42,12 +43,8 @@ import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.res.ResourcesCompat
import androidx.core.net.toUri
import androidx.core.view.ViewCompat
-import androidx.core.view.WindowCompat
-import androidx.core.view.WindowInsetsAnimationCompat
import androidx.core.view.WindowInsetsCompat
-import androidx.core.view.doOnLayout
import androidx.core.view.updateLayoutParams
-import androidx.core.view.updatePadding
import androidx.documentfile.provider.DocumentFile
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
@@ -63,6 +60,7 @@ import org.fossify.commons.extensions.applyColorFilter
import org.fossify.commons.extensions.beGone
import org.fossify.commons.extensions.beVisible
import org.fossify.commons.extensions.beVisibleIf
+import org.fossify.commons.extensions.copyToClipboard
import org.fossify.commons.extensions.darkenColor
import org.fossify.commons.extensions.formatDate
import org.fossify.commons.extensions.getBottomNavigationBackgroundColor
@@ -374,36 +372,42 @@ class ThreadActivity : SimpleActivity() {
// allow saving number in cases when we don't have it stored yet and it is a casual readable number
findItem(R.id.add_number_to_contact).isVisible =
- participants.size == 1 && participants.first().name == firstPhoneNumber && firstPhoneNumber.any {
- it.isDigit()
- } && !isRecycleBin
+ participants.size == 1
+ && participants.first().name == firstPhoneNumber
+ && firstPhoneNumber.any { it.isDigit() }
+ && !isRecycleBin
+ findItem(R.id.copy_number).isVisible =
+ participants.size == 1 && !firstPhoneNumber.isNullOrEmpty() && !isRecycleBin
}
}
private fun setupOptionsMenu() {
binding.threadToolbar.setOnMenuItemClickListener { menuItem ->
- if (participants.isEmpty()) {
- return@setOnMenuItemClickListener true
- }
-
- when (menuItem.itemId) {
- R.id.block_number -> tryBlocking()
- R.id.delete -> askConfirmDelete()
- R.id.restore -> askConfirmRestoreAll()
- R.id.archive -> archiveConversation()
- R.id.unarchive -> unarchiveConversation()
- R.id.rename_conversation -> renameConversation()
- R.id.conversation_details -> launchConversationDetails(threadId)
- R.id.add_number_to_contact -> addNumberToContact()
- R.id.dial_number -> dialNumber()
- R.id.manage_people -> managePeople()
- R.id.mark_as_unread -> markAsUnread()
- else -> return@setOnMenuItemClickListener false
- }
- return@setOnMenuItemClickListener true
+ if (participants.isEmpty()) return@setOnMenuItemClickListener true
+ return@setOnMenuItemClickListener handleMenuItemAction(menuItem)
}
}
+ private fun handleMenuItemAction(menuItem: MenuItem): Boolean {
+ when (menuItem.itemId) {
+ R.id.block_number -> tryBlocking()
+ R.id.delete -> askConfirmDelete()
+ R.id.restore -> askConfirmRestoreAll()
+ R.id.archive -> archiveConversation()
+ R.id.unarchive -> unarchiveConversation()
+ R.id.rename_conversation -> renameConversation()
+ R.id.conversation_details -> launchConversationDetails(threadId)
+ R.id.add_number_to_contact -> addNumberToContact()
+ R.id.copy_number -> copyNumberToClipboard()
+ R.id.dial_number -> dialNumber()
+ R.id.manage_people -> managePeople()
+ R.id.mark_as_unread -> markAsUnread()
+ else -> return false
+ }
+
+ return true
+ }
+
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
super.onActivityResult(requestCode, resultCode, resultData)
if (resultCode != Activity.RESULT_OK) return
@@ -1175,6 +1179,13 @@ class ThreadActivity : SimpleActivity() {
dialNumber(phoneNumber)
}
+ private fun copyNumberToClipboard() {
+ val phoneNumber = conversation?.phoneNumber
+ ?.ifEmpty { participants.firstOrNull()?.phoneNumbers?.firstOrNull()?.value }
+ ?: return
+ copyToClipboard(phoneNumber)
+ }
+
private fun managePeople() {
if (binding.threadAddContacts.isVisible()) {
hideKeyboard()
diff --git a/app/src/main/res/menu/menu_thread.xml b/app/src/main/res/menu/menu_thread.xml
index bfd88b05..4ae064ea 100644
--- a/app/src/main/res/menu/menu_thread.xml
+++ b/app/src/main/res/menu/menu_thread.xml
@@ -30,6 +30,10 @@
android:id="@+id/add_number_to_contact"
android:title="@string/add_number_to_contact"
app:showAsAction="never" />
+