mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2025-09-26 11:19:05 +00:00
Fixed link scrolling behaviour.
This commit is contained in:
parent
90a1cd8280
commit
752fc8787d
2 changed files with 170 additions and 91 deletions
|
@ -12,70 +12,109 @@ import com.futo.platformplayer.activities.MainActivity
|
||||||
import com.futo.platformplayer.logging.Logger
|
import com.futo.platformplayer.logging.Logger
|
||||||
import com.futo.platformplayer.receivers.MediaControlReceiver
|
import com.futo.platformplayer.receivers.MediaControlReceiver
|
||||||
import com.futo.platformplayer.timestampRegex
|
import com.futo.platformplayer.timestampRegex
|
||||||
import com.futo.platformplayer.views.behavior.NonScrollingTextView
|
|
||||||
import com.futo.platformplayer.views.behavior.NonScrollingTextView.Companion
|
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
|
||||||
class PlatformLinkMovementMethod : LinkMovementMethod {
|
class PlatformLinkMovementMethod(private val _context: Context) : LinkMovementMethod() {
|
||||||
private val _context: Context;
|
|
||||||
|
|
||||||
constructor(context: Context) : super() {
|
private var pressedLinks: Array<URLSpan>? = null
|
||||||
_context = context;
|
private var linkPressed = false
|
||||||
}
|
private var downX = 0f
|
||||||
|
private var downY = 0f
|
||||||
|
private val touchSlop = 20
|
||||||
|
|
||||||
override fun onTouchEvent(widget: TextView, buffer: Spannable, event: MotionEvent): Boolean {
|
override fun onTouchEvent(widget: TextView, buffer: Spannable, event: MotionEvent): Boolean {
|
||||||
val action = event.action;
|
val action = event.actionMasked
|
||||||
Logger.i(TAG, "onTouchEvent (action = $action)")
|
|
||||||
if (action == MotionEvent.ACTION_UP) {
|
|
||||||
val x = event.x.toInt() - widget.totalPaddingLeft + widget.scrollX;
|
|
||||||
val y = event.y.toInt() - widget.totalPaddingTop + widget.scrollY;
|
|
||||||
|
|
||||||
val layout = widget.layout;
|
when (action) {
|
||||||
val line = layout.getLineForVertical(y);
|
MotionEvent.ACTION_DOWN -> {
|
||||||
val off = layout.getOffsetForHorizontal(line, x.toFloat());
|
val links = findLinksAtTouchPosition(widget, buffer, event)
|
||||||
val links = buffer.getSpans(off, off, URLSpan::class.java);
|
if (links.isNotEmpty()) {
|
||||||
|
pressedLinks = links
|
||||||
|
linkPressed = true
|
||||||
|
downX = event.x
|
||||||
|
downY = event.y
|
||||||
|
widget.parent?.requestDisallowInterceptTouchEvent(true)
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
linkPressed = false
|
||||||
|
pressedLinks = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (links.isNotEmpty()) {
|
MotionEvent.ACTION_MOVE -> {
|
||||||
runBlocking {
|
if (linkPressed) {
|
||||||
for (link in links) {
|
val dx = event.x - downX
|
||||||
Logger.i(TAG) { "Link clicked '${link.url}'." };
|
val dy = event.y - downY
|
||||||
|
if (Math.abs(dx) > touchSlop || Math.abs(dy) > touchSlop) {
|
||||||
|
linkPressed = false
|
||||||
|
pressedLinks = null
|
||||||
|
widget.parent?.requestDisallowInterceptTouchEvent(false)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (_context is MainActivity) {
|
MotionEvent.ACTION_UP -> {
|
||||||
if (_context.handleUrl(link.url)) {
|
if (linkPressed && pressedLinks != null) {
|
||||||
continue;
|
val dx = event.x - downX
|
||||||
}
|
val dy = event.y - downY
|
||||||
|
if (Math.abs(dx) <= touchSlop && Math.abs(dy) <= touchSlop) {
|
||||||
|
runBlocking {
|
||||||
|
for (link in pressedLinks!!) {
|
||||||
|
Logger.i(TAG) { "Link clicked '${link.url}'." }
|
||||||
|
|
||||||
if (timestampRegex.matches(link.url)) {
|
if (_context is MainActivity) {
|
||||||
val tokens = link.url.split(':');
|
if (_context.handleUrl(link.url)) continue
|
||||||
|
if (timestampRegex.matches(link.url)) {
|
||||||
|
val tokens = link.url.split(':')
|
||||||
|
var time_s = -1L
|
||||||
|
when (tokens.size) {
|
||||||
|
2 -> time_s = tokens[0].toLong() * 60 + tokens[1].toLong()
|
||||||
|
3 -> time_s = tokens[0].toLong() * 3600 +
|
||||||
|
tokens[1].toLong() * 60 +
|
||||||
|
tokens[2].toLong()
|
||||||
|
}
|
||||||
|
|
||||||
var time_s = -1L;
|
if (time_s != -1L) {
|
||||||
if (tokens.size == 2) {
|
MediaControlReceiver.onSeekToReceived.emit(time_s * 1000)
|
||||||
time_s = tokens[0].toLong() * 60 + tokens[1].toLong();
|
continue
|
||||||
} else if (tokens.size == 3) {
|
}
|
||||||
time_s =
|
}
|
||||||
tokens[0].toLong() * 60 * 60 + tokens[1].toLong() * 60 + tokens[2].toLong();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (time_s != -1L) {
|
|
||||||
MediaControlReceiver.onSeekToReceived.emit(time_s * 1000);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
_context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(link.url)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pressedLinks = null
|
||||||
|
linkPressed = false
|
||||||
_context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(link.url)));
|
return true
|
||||||
|
} else {
|
||||||
|
pressedLinks = null
|
||||||
|
linkPressed = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
MotionEvent.ACTION_CANCEL -> {
|
||||||
|
linkPressed = false
|
||||||
|
pressedLinks = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.onTouchEvent(widget, buffer, event);
|
return super.onTouchEvent(widget, buffer, event)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findLinksAtTouchPosition(widget: TextView, buffer: Spannable, event: MotionEvent): Array<URLSpan> {
|
||||||
|
val x = (event.x - widget.totalPaddingLeft + widget.scrollX).toInt()
|
||||||
|
val y = (event.y - widget.totalPaddingTop + widget.scrollY).toInt()
|
||||||
|
|
||||||
|
val layout = widget.layout ?: return emptyArray()
|
||||||
|
val line = layout.getLineForVertical(y)
|
||||||
|
val off = layout.getOffsetForHorizontal(line, x.toFloat())
|
||||||
|
return buffer.getSpans(off, off, URLSpan::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val TAG = "PlatformLinkMovementMethod";
|
const val TAG = "PlatformLinkMovementMethod"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -16,70 +16,110 @@ import com.futo.platformplayer.timestampRegex
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
|
||||||
class NonScrollingTextView : androidx.appcompat.widget.AppCompatTextView {
|
class NonScrollingTextView : androidx.appcompat.widget.AppCompatTextView {
|
||||||
|
private var _lastTouchedLinks: Array<URLSpan>? = null
|
||||||
|
private var downX = 0f
|
||||||
|
private var downY = 0f
|
||||||
|
private var linkPressed = false
|
||||||
|
private val touchSlop = 20
|
||||||
|
|
||||||
constructor(context: Context) : super(context) {}
|
constructor(context: Context) : super(context) {}
|
||||||
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {}
|
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {}
|
||||||
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {}
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {}
|
||||||
|
|
||||||
override fun scrollTo(x: Int, y: Int) {
|
override fun scrollTo(x: Int, y: Int) {
|
||||||
//do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onTouchEvent(event: MotionEvent?): Boolean {
|
override fun onTouchEvent(event: MotionEvent?): Boolean {
|
||||||
val action = event?.action
|
val action = event?.actionMasked
|
||||||
Logger.i(TAG, "onTouchEvent (action = $action)");
|
if (event == null) return super.onTouchEvent(event)
|
||||||
|
|
||||||
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) {
|
when (action) {
|
||||||
val x = event.x.toInt()
|
MotionEvent.ACTION_DOWN -> {
|
||||||
val y = event.y.toInt()
|
val x = event.x.toInt()
|
||||||
|
val y = event.y.toInt()
|
||||||
|
|
||||||
val layout: Layout? = this.layout
|
val layout: Layout? = this.layout
|
||||||
if (layout != null) {
|
if (layout != null && this.text is Spannable) {
|
||||||
val line = layout.getLineForVertical(y)
|
val offset = layout.getOffsetForHorizontal(layout.getLineForVertical(y), x.toFloat())
|
||||||
val offset = layout.getOffsetForHorizontal(line, x.toFloat())
|
val text = this.text as Spannable
|
||||||
|
|
||||||
val text = this.text
|
|
||||||
if (text is Spannable) {
|
|
||||||
val links = text.getSpans(offset, offset, URLSpan::class.java)
|
val links = text.getSpans(offset, offset, URLSpan::class.java)
|
||||||
if (links.isNotEmpty()) {
|
if (links.isNotEmpty()) {
|
||||||
runBlocking {
|
parent?.requestDisallowInterceptTouchEvent(true)
|
||||||
for (link in links) {
|
_lastTouchedLinks = links
|
||||||
Logger.i(PlatformLinkMovementMethod.TAG) { "Link clicked '${link.url}'." };
|
downX = event.x
|
||||||
|
downY = event.y
|
||||||
val c = context;
|
linkPressed = true
|
||||||
if (c is MainActivity) {
|
|
||||||
if (c.handleUrl(link.url)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (timestampRegex.matches(link.url)) {
|
|
||||||
val tokens = link.url.split(':');
|
|
||||||
|
|
||||||
var time_s = -1L;
|
|
||||||
if (tokens.size == 2) {
|
|
||||||
time_s = tokens[0].toLong() * 60 + tokens[1].toLong();
|
|
||||||
} else if (tokens.size == 3) {
|
|
||||||
time_s = tokens[0].toLong() * 60 * 60 + tokens[1].toLong() * 60 + tokens[2].toLong();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (time_s != -1L) {
|
|
||||||
MediaControlReceiver.onSeekToReceived.emit(time_s * 1000);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
c.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(link.url)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
} else {
|
||||||
|
linkPressed = false
|
||||||
|
_lastTouchedLinks = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MotionEvent.ACTION_MOVE -> {
|
||||||
|
if (linkPressed) {
|
||||||
|
val dx = event.x - downX
|
||||||
|
val dy = event.y - downY
|
||||||
|
if (Math.abs(dx) > touchSlop || Math.abs(dy) > touchSlop) {
|
||||||
|
linkPressed = false
|
||||||
|
_lastTouchedLinks = null
|
||||||
|
parent?.requestDisallowInterceptTouchEvent(false)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MotionEvent.ACTION_UP -> {
|
||||||
|
if (linkPressed && _lastTouchedLinks != null) {
|
||||||
|
val dx = event.x - downX
|
||||||
|
val dy = event.y - downY
|
||||||
|
if (Math.abs(dx) <= touchSlop && Math.abs(dy) <= touchSlop) {
|
||||||
|
runBlocking {
|
||||||
|
for (link in _lastTouchedLinks!!) {
|
||||||
|
Logger.i(PlatformLinkMovementMethod.TAG) { "Link clicked '${link.url}'." }
|
||||||
|
val c = context
|
||||||
|
if (c is MainActivity) {
|
||||||
|
if (c.handleUrl(link.url)) continue
|
||||||
|
if (timestampRegex.matches(link.url)) {
|
||||||
|
val tokens = link.url.split(':')
|
||||||
|
var time_s = -1L
|
||||||
|
when (tokens.size) {
|
||||||
|
2 -> time_s = tokens[0].toLong() * 60 + tokens[1].toLong()
|
||||||
|
3 -> time_s = tokens[0].toLong() * 3600 +
|
||||||
|
tokens[1].toLong() * 60 +
|
||||||
|
tokens[2].toLong()
|
||||||
|
}
|
||||||
|
if (time_s != -1L) {
|
||||||
|
MediaControlReceiver.onSeekToReceived.emit(time_s * 1000)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(link.url)))
|
||||||
|
} else {
|
||||||
|
c.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(link.url)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_lastTouchedLinks = null
|
||||||
|
linkPressed = false
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
linkPressed = false
|
||||||
|
_lastTouchedLinks = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MotionEvent.ACTION_CANCEL -> {
|
||||||
|
linkPressed = false
|
||||||
|
_lastTouchedLinks = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
super.onTouchEvent(event)
|
return super.onTouchEvent(event)
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue