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