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
This commit is contained in:
Naveen Singh 2025-12-23 18:28:34 +05:30 committed by GitHub
parent 195e35d8c0
commit 74e49cf939
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 45 additions and 26 deletions

View file

@ -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). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased] ## [Unreleased]
### Added
- Added "Copy number to clipboard" option inside chat overflow menu ([#651])
### Fixed ### Fixed
- Fixed missing notifications in some cases ([#159]) - Fixed missing notifications in some cases ([#159])
- Fixed incorrect blocking of MMS messages in some rare cases ([#644]) - 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 [#600]: https://github.com/FossifyOrg/Messages/issues/600
[#610]: https://github.com/FossifyOrg/Messages/issues/610 [#610]: https://github.com/FossifyOrg/Messages/issues/610
[#644]: https://github.com/FossifyOrg/Messages/issues/644 [#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 [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 [1.7.0]: https://github.com/FossifyOrg/Messages/compare/1.6.0...1.7.0

View file

@ -28,6 +28,7 @@ import android.text.format.DateUtils.FORMAT_SHOW_TIME
import android.util.TypedValue import android.util.TypedValue
import android.view.Gravity import android.view.Gravity
import android.view.KeyEvent import android.view.KeyEvent
import android.view.MenuItem
import android.view.View import android.view.View
import android.view.WindowManager import android.view.WindowManager
import android.view.animation.OvershootInterpolator import android.view.animation.OvershootInterpolator
@ -42,12 +43,8 @@ import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.res.ResourcesCompat import androidx.core.content.res.ResourcesCompat
import androidx.core.net.toUri import androidx.core.net.toUri
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsAnimationCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import androidx.core.view.doOnLayout
import androidx.core.view.updateLayoutParams import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
import androidx.documentfile.provider.DocumentFile import androidx.documentfile.provider.DocumentFile
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView 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.beGone
import org.fossify.commons.extensions.beVisible import org.fossify.commons.extensions.beVisible
import org.fossify.commons.extensions.beVisibleIf import org.fossify.commons.extensions.beVisibleIf
import org.fossify.commons.extensions.copyToClipboard
import org.fossify.commons.extensions.darkenColor import org.fossify.commons.extensions.darkenColor
import org.fossify.commons.extensions.formatDate import org.fossify.commons.extensions.formatDate
import org.fossify.commons.extensions.getBottomNavigationBackgroundColor 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 // 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 = findItem(R.id.add_number_to_contact).isVisible =
participants.size == 1 && participants.first().name == firstPhoneNumber && firstPhoneNumber.any { participants.size == 1
it.isDigit() && participants.first().name == firstPhoneNumber
} && !isRecycleBin && firstPhoneNumber.any { it.isDigit() }
&& !isRecycleBin
findItem(R.id.copy_number).isVisible =
participants.size == 1 && !firstPhoneNumber.isNullOrEmpty() && !isRecycleBin
} }
} }
private fun setupOptionsMenu() { private fun setupOptionsMenu() {
binding.threadToolbar.setOnMenuItemClickListener { menuItem -> binding.threadToolbar.setOnMenuItemClickListener { menuItem ->
if (participants.isEmpty()) { if (participants.isEmpty()) return@setOnMenuItemClickListener true
return@setOnMenuItemClickListener true return@setOnMenuItemClickListener handleMenuItemAction(menuItem)
}
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
} }
} }
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?) { override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
super.onActivityResult(requestCode, resultCode, resultData) super.onActivityResult(requestCode, resultCode, resultData)
if (resultCode != Activity.RESULT_OK) return if (resultCode != Activity.RESULT_OK) return
@ -1175,6 +1179,13 @@ class ThreadActivity : SimpleActivity() {
dialNumber(phoneNumber) dialNumber(phoneNumber)
} }
private fun copyNumberToClipboard() {
val phoneNumber = conversation?.phoneNumber
?.ifEmpty { participants.firstOrNull()?.phoneNumbers?.firstOrNull()?.value }
?: return
copyToClipboard(phoneNumber)
}
private fun managePeople() { private fun managePeople() {
if (binding.threadAddContacts.isVisible()) { if (binding.threadAddContacts.isVisible()) {
hideKeyboard() hideKeyboard()

View file

@ -30,6 +30,10 @@
android:id="@+id/add_number_to_contact" android:id="@+id/add_number_to_contact"
android:title="@string/add_number_to_contact" android:title="@string/add_number_to_contact"
app:showAsAction="never" /> app:showAsAction="never" />
<item
android:id="@+id/copy_number"
android:title="@string/copy_number_to_clipboard"
app:showAsAction="never" />
<item <item
android:id="@+id/rename_conversation" android:id="@+id/rename_conversation"
android:showAsAction="never" android:showAsAction="never"