Fixed #2670 : Timestamp click behaviour in the description.

This commit is contained in:
faisalcodes 2023-01-17 00:20:33 +05:30
parent 0ee5753e91
commit 6d322bf9f7
3 changed files with 90 additions and 37 deletions

View File

@ -76,7 +76,6 @@ import com.github.libretube.ui.dialogs.AddToPlaylistDialog
import com.github.libretube.ui.dialogs.DownloadDialog import com.github.libretube.ui.dialogs.DownloadDialog
import com.github.libretube.ui.dialogs.ShareDialog import com.github.libretube.ui.dialogs.ShareDialog
import com.github.libretube.ui.extensions.setAspectRatio import com.github.libretube.ui.extensions.setAspectRatio
import com.github.libretube.ui.extensions.setFormattedHtml
import com.github.libretube.ui.extensions.setupSubscriptionButton import com.github.libretube.ui.extensions.setupSubscriptionButton
import com.github.libretube.ui.interfaces.OnlinePlayerOptions import com.github.libretube.ui.interfaces.OnlinePlayerOptions
import com.github.libretube.ui.models.CommentsViewModel import com.github.libretube.ui.models.CommentsViewModel
@ -84,7 +83,19 @@ import com.github.libretube.ui.models.PlayerViewModel
import com.github.libretube.ui.sheets.BaseBottomSheet import com.github.libretube.ui.sheets.BaseBottomSheet
import com.github.libretube.ui.sheets.CommentsSheet import com.github.libretube.ui.sheets.CommentsSheet
import com.github.libretube.ui.sheets.PlayingQueueSheet import com.github.libretube.ui.sheets.PlayingQueueSheet
import com.github.libretube.util.* import com.github.libretube.util.BackgroundHelper
import com.github.libretube.util.DashHelper
import com.github.libretube.util.DataSaverMode
import com.github.libretube.util.HtmlParser
import com.github.libretube.util.ImageHelper
import com.github.libretube.util.LinkHandler
import com.github.libretube.util.NavigationHelper
import com.github.libretube.util.NowPlayingNotification
import com.github.libretube.util.PlayerHelper
import com.github.libretube.util.PlayingQueue
import com.github.libretube.util.PreferenceHelper
import com.github.libretube.util.SeekbarPreviewListener
import com.github.libretube.util.TextUtils
import com.google.android.exoplayer2.C import com.google.android.exoplayer2.C
import com.google.android.exoplayer2.DefaultLoadControl import com.google.android.exoplayer2.DefaultLoadControl
import com.google.android.exoplayer2.ExoPlayer import com.google.android.exoplayer2.ExoPlayer
@ -1026,7 +1037,11 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
} }
} }
private fun setupDescription(descTextView: TextView, description: String, exoPlayer: ExoPlayer) { private fun setupDescription(
descTextView: TextView,
description: String,
exoPlayer: ExoPlayer
) {
// detect whether the description is html formatted // detect whether the description is html formatted
if (description.contains("<") && description.contains(">")) { if (description.contains("<") && description.contains(">")) {
descTextView.movementMethod = LinkMovementMethod.getInstance() descTextView.movementMethod = LinkMovementMethod.getInstance()
@ -1065,7 +1080,6 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(link)) val intent = Intent(Intent.ACTION_VIEW, Uri.parse(link))
startActivity(intent) startActivity(intent)
} }
} else { } else {
// not a youtube link // not a youtube link
// handle normally // handle normally

View File

@ -4,10 +4,15 @@ import android.text.Editable
import android.text.Html import android.text.Html
import android.text.Spanned import android.text.Spanned
import androidx.core.text.HtmlCompat import androidx.core.text.HtmlCompat
import org.xml.sax.* import org.xml.sax.Attributes
import java.util.* import org.xml.sax.ContentHandler
import org.xml.sax.Locator
import org.xml.sax.SAXException
import org.xml.sax.XMLReader
class HtmlParser private constructor(private val handler: TagHandler) : Html.TagHandler, ContentHandler { class HtmlParser private constructor(private val handler: TagHandler) :
Html.TagHandler,
ContentHandler {
private val tagStatus = ArrayDeque<Boolean>() private val tagStatus = ArrayDeque<Boolean>()
private var wrapped: ContentHandler? = null private var wrapped: ContentHandler? = null
private var text: Editable? = null private var text: Editable? = null
@ -27,7 +32,13 @@ class HtmlParser private constructor(private val handler: TagHandler) : Html.Tag
} }
} }
@Throws(SAXException::class) override fun startElement(uri: String, localName: String, qName: String, attributes: Attributes) { @Throws(SAXException::class)
override fun startElement(
uri: String,
localName: String,
qName: String,
attributes: Attributes
) {
val isHandled = handler.handleTag(true, localName, text, attributes) val isHandled = handler.handleTag(true, localName, text, attributes)
tagStatus.addLast(isHandled) tagStatus.addLast(isHandled)
if (!isHandled) { if (!isHandled) {
@ -35,7 +46,8 @@ class HtmlParser private constructor(private val handler: TagHandler) : Html.Tag
} }
} }
@Throws(SAXException::class) override fun endElement(uri: String, localName: String, qName: String) { @Throws(SAXException::class)
override fun endElement(uri: String, localName: String, qName: String) {
if (!tagStatus.removeLast()) { if (!tagStatus.removeLast()) {
wrapped?.endElement(uri, localName, qName) wrapped?.endElement(uri, localName, qName)
} }
@ -46,47 +58,65 @@ class HtmlParser private constructor(private val handler: TagHandler) : Html.Tag
wrapped?.setDocumentLocator(locator) wrapped?.setDocumentLocator(locator)
} }
@Throws(SAXException::class) override fun startDocument() { @Throws(SAXException::class)
override fun startDocument() {
wrapped?.startDocument() wrapped?.startDocument()
} }
@Throws(SAXException::class) override fun endDocument() { @Throws(SAXException::class)
override fun endDocument() {
wrapped?.endDocument() wrapped?.endDocument()
} }
@Throws(SAXException::class) override fun startPrefixMapping(prefix: String, uri: String) { @Throws(SAXException::class)
override fun startPrefixMapping(prefix: String, uri: String) {
wrapped?.startPrefixMapping(prefix, uri) wrapped?.startPrefixMapping(prefix, uri)
} }
@Throws(SAXException::class) override fun endPrefixMapping(prefix: String) { @Throws(SAXException::class)
override fun endPrefixMapping(prefix: String) {
wrapped?.endPrefixMapping(prefix) wrapped?.endPrefixMapping(prefix)
} }
@Throws(SAXException::class) override fun characters(ch: CharArray, start: Int, length: Int) { @Throws(SAXException::class)
override fun characters(ch: CharArray, start: Int, length: Int) {
wrapped?.characters(ch, start, length) wrapped?.characters(ch, start, length)
} }
@Throws(SAXException::class) override fun ignorableWhitespace(ch: CharArray, start: Int, length: Int) { @Throws(SAXException::class)
override fun ignorableWhitespace(ch: CharArray, start: Int, length: Int) {
wrapped?.ignorableWhitespace(ch, start, length) wrapped?.ignorableWhitespace(ch, start, length)
} }
@Throws(SAXException::class) override fun processingInstruction(target: String, data: String) { @Throws(SAXException::class)
override fun processingInstruction(target: String, data: String) {
wrapped?.processingInstruction(target, data) wrapped?.processingInstruction(target, data)
} }
@Throws(SAXException::class) override fun skippedEntity(name: String) { @Throws(SAXException::class)
override fun skippedEntity(name: String) {
wrapped?.skippedEntity(name) wrapped?.skippedEntity(name)
} }
interface TagHandler { interface TagHandler {
fun handleTag(opening: Boolean, tag: String?, output: Editable?, attributes: Attributes?): Boolean fun handleTag(
opening: Boolean,
tag: String?,
output: Editable?,
attributes: Attributes?
): Boolean
} }
companion object { companion object {
fun createSpannedText(html: String, handler: TagHandler): Spanned { fun createSpannedText(html: String, handler: TagHandler): Spanned {
// add a tag at the start that is not handled by default, // add a tag at the start that is not handled by default,
// allowing custom tag handler to replace xmlReader contentHandler // allowing custom tag handler to replace xmlReader contentHandler
return HtmlCompat.fromHtml(html, HtmlCompat.FROM_HTML_MODE_LEGACY, null, HtmlParser(handler)) return HtmlCompat.fromHtml(
html,
HtmlCompat.FROM_HTML_MODE_LEGACY,
null,
HtmlParser(handler)
)
} }
@JvmStatic fun getValue(attributes: Attributes, name: String): String? { @JvmStatic fun getValue(attributes: Attributes, name: String): String? {

View File

@ -4,7 +4,6 @@ import android.text.Editable
import android.text.Spanned import android.text.Spanned
import android.text.TextPaint import android.text.TextPaint
import android.text.style.ClickableSpan import android.text.style.ClickableSpan
import android.util.Log
import android.view.View import android.view.View
import com.github.libretube.util.HtmlParser.Companion.getValue import com.github.libretube.util.HtmlParser.Companion.getValue
import org.xml.sax.Attributes import org.xml.sax.Attributes
@ -12,7 +11,12 @@ import org.xml.sax.Attributes
class LinkHandler(private val clickCallback: ((String) -> Unit)?) : HtmlParser.TagHandler { class LinkHandler(private val clickCallback: ((String) -> Unit)?) : HtmlParser.TagHandler {
private var linkTagStartIndex = -1 private var linkTagStartIndex = -1
private var link: String? = null private var link: String? = null
override fun handleTag(opening: Boolean, tag: String?, output: Editable?, attributes: Attributes?): Boolean { override fun handleTag(
opening: Boolean,
tag: String?,
output: Editable?,
attributes: Attributes?
): Boolean {
if (output != null) { if (output != null) {
if ("a" == tag) { if ("a" == tag) {
if (opening && attributes != null) { if (opening && attributes != null) {
@ -29,7 +33,8 @@ class LinkHandler(private val clickCallback: ((String) -> Unit)?) : HtmlParser.T
} }
private fun setLinkSpans(output: Editable, start: Int, end: Int, link: String?) { private fun setLinkSpans(output: Editable, start: Int, end: Int, link: String?) {
output.setSpan(object : ClickableSpan() { output.setSpan(
object : ClickableSpan() {
override fun onClick(widget: View) { override fun onClick(widget: View) {
if (clickCallback != null && link != null) { if (clickCallback != null && link != null) {
clickCallback.invoke(link) clickCallback.invoke(link)
@ -40,6 +45,10 @@ class LinkHandler(private val clickCallback: ((String) -> Unit)?) : HtmlParser.T
super.updateDrawState(ds) super.updateDrawState(ds)
ds.isUnderlineText = false ds.isUnderlineText = false
} }
}, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) },
start,
end,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
)
} }
} }