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.ShareDialog
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.interfaces.OnlinePlayerOptions
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.CommentsSheet
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.DefaultLoadControl
import com.google.android.exoplayer2.ExoPlayer
@ -851,7 +862,7 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
binding.apply {
playerViewsInfo.text =
context?.getString(R.string.views, streams.views.formatShort()) +
if (!isLive) TextUtils.SEPARATOR + localizedDate(streams.uploadDate) else ""
if (!isLive) TextUtils.SEPARATOR + localizedDate(streams.uploadDate) else ""
textLike.text = streams.likes.formatShort()
textDislike.text = streams.dislikes.formatShort()
@ -918,9 +929,9 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
override fun onPlaybackStateChanged(playbackState: Int) {
exoPlayerView.keepScreenOn = !(
playbackState == Player.STATE_IDLE ||
playbackState == Player.STATE_ENDED
)
playbackState == Player.STATE_IDLE ||
playbackState == Player.STATE_ENDED
)
// save the watch position to the database
// only called when the position is unequal to 0, otherwise it would become reset
@ -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
if (description.contains("<") && description.contains(">")) {
descTextView.movementMethod = LinkMovementMethod.getInstance()
@ -1065,7 +1080,6 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(link))
startActivity(intent)
}
} else {
// not a youtube link
// handle normally

View File

@ -4,10 +4,15 @@ import android.text.Editable
import android.text.Html
import android.text.Spanned
import androidx.core.text.HtmlCompat
import org.xml.sax.*
import java.util.*
import org.xml.sax.Attributes
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 var wrapped: ContentHandler? = 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)
tagStatus.addLast(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()) {
wrapped?.endElement(uri, localName, qName)
}
@ -46,47 +58,65 @@ class HtmlParser private constructor(private val handler: TagHandler) : Html.Tag
wrapped?.setDocumentLocator(locator)
}
@Throws(SAXException::class) override fun startDocument() {
@Throws(SAXException::class)
override fun startDocument() {
wrapped?.startDocument()
}
@Throws(SAXException::class) override fun endDocument() {
@Throws(SAXException::class)
override fun 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)
}
@Throws(SAXException::class) override fun endPrefixMapping(prefix: String) {
@Throws(SAXException::class)
override fun endPrefixMapping(prefix: String) {
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)
}
@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)
}
@Throws(SAXException::class) override fun processingInstruction(target: String, data: String) {
@Throws(SAXException::class)
override fun processingInstruction(target: String, data: String) {
wrapped?.processingInstruction(target, data)
}
@Throws(SAXException::class) override fun skippedEntity(name: String) {
@Throws(SAXException::class)
override fun skippedEntity(name: String) {
wrapped?.skippedEntity(name)
}
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 {
fun createSpannedText(html: String, handler: TagHandler): Spanned {
// add a tag at the start that is not handled by default,
// 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? {
@ -101,4 +131,4 @@ class HtmlParser private constructor(private val handler: TagHandler) : Html.Tag
return null
}
}
}
}

View File

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