diff --git a/app/src/main/java/com/duckduckgo/app/browser/BrowserTabFragment.kt b/app/src/main/java/com/duckduckgo/app/browser/BrowserTabFragment.kt
index 9870cfb000fe..c37c50d0b494 100644
--- a/app/src/main/java/com/duckduckgo/app/browser/BrowserTabFragment.kt
+++ b/app/src/main/java/com/duckduckgo/app/browser/BrowserTabFragment.kt
@@ -3483,6 +3483,18 @@ class BrowserTabFragment :
return message.data.getString(URL_BUNDLE_KEY)
}
+ /**
+ * Use requestFocusNodeHref to get the a tag title for the touched link.
+ */
+ private fun getTargetTitleForLinkSource(): String? {
+ val handler = Handler()
+ val message = handler.obtainMessage()
+
+ webView?.requestFocusNodeHref(message)
+
+ return message.data.getString(TITLE_BUNDLE_KEY)?.trim()
+ }
+
private fun getLongPressTarget(hitTestResult: HitTestResult): LongPressTarget? {
return when {
hitTestResult.extra == null -> null
@@ -3502,6 +3514,7 @@ class BrowserTabFragment :
else -> LongPressTarget(
url = hitTestResult.extra,
type = hitTestResult.type,
+ text = getTargetTitleForLinkSource(),
)
}
}
@@ -4100,6 +4113,7 @@ class BrowserTabFragment :
private const val PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE = 200
private const val URL_BUNDLE_KEY = "url"
+ private const val TITLE_BUNDLE_KEY = "title"
private const val DOWNLOAD_CONFIRMATION_TAG = "DOWNLOAD_CONFIRMATION_TAG"
private const val DAX_DIALOG_DIALOG_TAG = "DAX_DIALOG_TAG"
diff --git a/app/src/main/java/com/duckduckgo/app/browser/BrowserTabViewModel.kt b/app/src/main/java/com/duckduckgo/app/browser/BrowserTabViewModel.kt
index 35283be9a955..3327ee70e213 100644
--- a/app/src/main/java/com/duckduckgo/app/browser/BrowserTabViewModel.kt
+++ b/app/src/main/java/com/duckduckgo/app/browser/BrowserTabViewModel.kt
@@ -2579,7 +2579,7 @@ class BrowserTabViewModel @Inject constructor(
menu: ContextMenu,
) {
logcat(INFO) { "Long pressed on ${target.type}, (url=${target.url}), (image url = ${target.imageUrl})" }
- longPressHandler.handleLongPress(target.type, target.url, menu)
+ longPressHandler.handleLongPress(target.type, target.url, target.text, menu)
}
fun userSelectedItemFromLongPressMenu(
@@ -2625,6 +2625,11 @@ class BrowserTabViewModel @Inject constructor(
true
}
+ is RequiredAction.CopyLinkText -> {
+ command.value = CopyLink(requiredAction.text)
+ true
+ }
+
RequiredAction.None -> {
false
}
diff --git a/app/src/main/java/com/duckduckgo/app/browser/WebViewLongPressHandler.kt b/app/src/main/java/com/duckduckgo/app/browser/WebViewLongPressHandler.kt
index f01b830ddb17..987873efe14d 100644
--- a/app/src/main/java/com/duckduckgo/app/browser/WebViewLongPressHandler.kt
+++ b/app/src/main/java/com/duckduckgo/app/browser/WebViewLongPressHandler.kt
@@ -35,6 +35,7 @@ interface LongPressHandler {
fun handleLongPress(
longPressTargetType: Int,
longPressTargetUrl: String?,
+ longPressTargetTitle: String?,
menu: ContextMenu,
)
@@ -50,6 +51,7 @@ interface LongPressHandler {
class DownloadFile(val url: String) : RequiredAction()
class ShareLink(val url: String) : RequiredAction()
class CopyLink(val url: String) : RequiredAction()
+ class CopyLinkText(val text: String) : RequiredAction()
}
}
@@ -62,6 +64,7 @@ class WebViewLongPressHandler @Inject constructor(
override fun handleLongPress(
longPressTargetType: Int,
longPressTargetUrl: String?,
+ longPressTargetTitle: String?,
menu: ContextMenu,
) {
menu.setHeaderTitle(longPressTargetUrl?.take(MAX_TITLE_LENGTH) ?: context.getString(R.string.options))
@@ -93,6 +96,10 @@ class WebViewLongPressHandler @Inject constructor(
if (!customTabDetector.isCustomTab()) {
addLinkMenuOpenInTabOptions(menu)
}
+ if (!longPressTargetTitle.isNullOrEmpty()) {
+ addLinkMenuCopyLinkTextOptions(menu)
+ }
+
addLinkMenuOtherOptions(menu)
}
}
@@ -125,6 +132,10 @@ class WebViewLongPressHandler @Inject constructor(
menu.add(0, CONTEXT_MENU_ID_SHARE_LINK, CONTEXT_MENU_ID_SHARE_LINK, R.string.shareLink)
}
+ private fun addLinkMenuCopyLinkTextOptions(menu: ContextMenu) {
+ menu.add(0, CONTEXT_MENU_ID_COPY_TEXT, CONTEXT_MENU_ID_COPY_TEXT, R.string.copyText)
+ }
+
private fun isLinkSupported(longPressTargetUrl: String?) = URLUtil.isNetworkUrl(longPressTargetUrl) || URLUtil.isDataUrl(longPressTargetUrl)
override fun userSelectedMenuItem(
@@ -162,6 +173,11 @@ class WebViewLongPressHandler @Inject constructor(
val url = longPressTarget.url ?: return None
return CopyLink(url)
}
+ CONTEXT_MENU_ID_COPY_TEXT -> {
+ // pixel.fire(LONG_PRESS_COPY_TEXT)
+ val text = longPressTarget.text ?: return None
+ return CopyLinkText(text)
+ }
else -> None
}
}
@@ -173,6 +189,7 @@ class WebViewLongPressHandler @Inject constructor(
const val CONTEXT_MENU_ID_SHARE_LINK = 4
const val CONTEXT_MENU_ID_DOWNLOAD_IMAGE = 5
const val CONTEXT_MENU_ID_OPEN_IMAGE_IN_NEW_BACKGROUND_TAB = 6
+ const val CONTEXT_MENU_ID_COPY_TEXT = 7
private const val MAX_TITLE_LENGTH = 100
}
diff --git a/app/src/main/java/com/duckduckgo/app/browser/model/LongPressTarget.kt b/app/src/main/java/com/duckduckgo/app/browser/model/LongPressTarget.kt
index 351d3cbd5585..943f5c30d41f 100644
--- a/app/src/main/java/com/duckduckgo/app/browser/model/LongPressTarget.kt
+++ b/app/src/main/java/com/duckduckgo/app/browser/model/LongPressTarget.kt
@@ -20,4 +20,5 @@ data class LongPressTarget(
val url: String?,
val type: Int,
val imageUrl: String? = null,
+ val text: String? = null,
)
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index bab0b64c1a81..88b46a5d45df 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -77,6 +77,7 @@
Share Link
Share
Copy Link Address
+ Copy Link Text
Find in Page