From 5b50ac926ecb6a4e25155f30170e70d6cb499650 Mon Sep 17 00:00:00 2001 From: Koen J Date: Fri, 6 Jun 2025 10:15:15 +0200 Subject: [PATCH 1/2] Freeze fix when clicking link in description. --- .../others/PlatformLinkMovementMethod.kt | 47 ++++++++++++------- .../views/behavior/NonScrollingTextView.kt | 36 +++++++++----- 2 files changed, 54 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/com/futo/platformplayer/others/PlatformLinkMovementMethod.kt b/app/src/main/java/com/futo/platformplayer/others/PlatformLinkMovementMethod.kt index d524b7cf..76652236 100644 --- a/app/src/main/java/com/futo/platformplayer/others/PlatformLinkMovementMethod.kt +++ b/app/src/main/java/com/futo/platformplayer/others/PlatformLinkMovementMethod.kt @@ -8,11 +8,14 @@ import android.text.method.LinkMovementMethod import android.text.style.URLSpan import android.view.MotionEvent import android.widget.TextView +import androidx.lifecycle.lifecycleScope import com.futo.platformplayer.activities.MainActivity import com.futo.platformplayer.logging.Logger import com.futo.platformplayer.receivers.MediaControlReceiver import com.futo.platformplayer.timestampRegex -import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext class PlatformLinkMovementMethod(private val _context: Context) : LinkMovementMethod() { @@ -60,31 +63,39 @@ class PlatformLinkMovementMethod(private val _context: Context) : LinkMovementMe val dx = event.x - downX val dy = event.y - downY if (Math.abs(dx) <= touchSlop && Math.abs(dy) <= touchSlop && isTouchInside(widget, event)) { - runBlocking { - for (link in pressedLinks!!) { - Logger.i(TAG) { "Link clicked '${link.url}'." } + for (link in pressedLinks!!) { + Logger.i(TAG) { "Link clicked '${link.url}'." } - if (_context is MainActivity) { - 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() - } + val c = _context + if (c is MainActivity) { + c.lifecycleScope.launch(Dispatchers.IO) { + if (c.handleUrl(link.url)) { + return@launch + } + 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) { + if (time_s != -1L) { + withContext(Dispatchers.Main) { MediaControlReceiver.onSeekToReceived.emit(time_s * 1000) - continue } + return@launch } } - _context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(link.url))) + + withContext(Dispatchers.Main) { + c.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(link.url))) + } } } + } pressedLinks = null linkPressed = false return true diff --git a/app/src/main/java/com/futo/platformplayer/views/behavior/NonScrollingTextView.kt b/app/src/main/java/com/futo/platformplayer/views/behavior/NonScrollingTextView.kt index cf599176..6e3a8860 100644 --- a/app/src/main/java/com/futo/platformplayer/views/behavior/NonScrollingTextView.kt +++ b/app/src/main/java/com/futo/platformplayer/views/behavior/NonScrollingTextView.kt @@ -8,12 +8,16 @@ import android.text.Spannable import android.text.style.URLSpan import android.util.AttributeSet import android.view.MotionEvent +import androidx.lifecycle.lifecycleScope import com.futo.platformplayer.activities.MainActivity import com.futo.platformplayer.logging.Logger import com.futo.platformplayer.others.PlatformLinkMovementMethod import com.futo.platformplayer.receivers.MediaControlReceiver +import com.futo.platformplayer.states.StateApp import com.futo.platformplayer.timestampRegex -import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext class NonScrollingTextView : androidx.appcompat.widget.AppCompatTextView { private var _lastTouchedLinks: Array? = null @@ -77,12 +81,14 @@ class NonScrollingTextView : androidx.appcompat.widget.AppCompatTextView { val dx = event.x - downX val dy = event.y - downY if (Math.abs(dx) <= touchSlop && Math.abs(dy) <= touchSlop && isTouchInside(event)) { - 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 + for (link in _lastTouchedLinks!!) { + Logger.i(PlatformLinkMovementMethod.TAG) { "Link clicked '${link.url}'." } + val c = context + if (c is MainActivity) { + c.lifecycleScope.launch(Dispatchers.IO) { + if (c.handleUrl(link.url)) { + return@launch + } if (timestampRegex.matches(link.url)) { val tokens = link.url.split(':') var time_s = -1L @@ -92,13 +98,21 @@ class NonScrollingTextView : androidx.appcompat.widget.AppCompatTextView { tokens[1].toLong() * 60 + tokens[2].toLong() } + if (time_s != -1L) { - MediaControlReceiver.onSeekToReceived.emit(time_s * 1000) - continue + withContext(Dispatchers.Main) { + MediaControlReceiver.onSeekToReceived.emit(time_s * 1000) + } + return@launch } } - c.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(link.url))) - } else { + + withContext(Dispatchers.Main) { + c.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(link.url))) + } + } + } else { + StateApp.instance.scopeOrNull?.launch(Dispatchers.Main) { c.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(link.url))) } } From d08dffd9e2001d3445b05342f69a380250c159ff Mon Sep 17 00:00:00 2001 From: Koen J Date: Fri, 6 Jun 2025 11:12:31 +0200 Subject: [PATCH 2/2] Added potential fix for having to restart app to get casting devices to show. Added persistent ordering for creators. --- .../java/com/futo/platformplayer/casting/StateCasting.kt | 5 +++-- .../futo/platformplayer/dialogs/ConnectCastingDialog.kt | 2 -- .../fragment/mainactivity/main/CreatorsFragment.kt | 7 ++++++- .../platformplayer/views/adapters/SubscriptionAdapter.kt | 3 ++- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/futo/platformplayer/casting/StateCasting.kt b/app/src/main/java/com/futo/platformplayer/casting/StateCasting.kt index 58bd772c..b2c2156c 100644 --- a/app/src/main/java/com/futo/platformplayer/casting/StateCasting.kt +++ b/app/src/main/java/com/futo/platformplayer/casting/StateCasting.kt @@ -166,10 +166,11 @@ class StateCasting { Logger.i(TAG, "CastingService started."); _nsdManager = context.getSystemService(Context.NSD_SERVICE) as NsdManager + startDiscovering() } @Synchronized - fun startDiscovering() { + private fun startDiscovering() { _nsdManager?.apply { _discoveryListeners.forEach { discoverServices(it.key, NsdManager.PROTOCOL_DNS_SD, it.value) @@ -178,7 +179,7 @@ class StateCasting { } @Synchronized - fun stopDiscovering() { + private fun stopDiscovering() { _nsdManager?.apply { _discoveryListeners.forEach { try { diff --git a/app/src/main/java/com/futo/platformplayer/dialogs/ConnectCastingDialog.kt b/app/src/main/java/com/futo/platformplayer/dialogs/ConnectCastingDialog.kt index f00bd191..87375779 100644 --- a/app/src/main/java/com/futo/platformplayer/dialogs/ConnectCastingDialog.kt +++ b/app/src/main/java/com/futo/platformplayer/dialogs/ConnectCastingDialog.kt @@ -103,7 +103,6 @@ class ConnectCastingDialog(context: Context?) : AlertDialog(context) { super.show(); Logger.i(TAG, "Dialog shown."); - StateCasting.instance.startDiscovering() (_imageLoader.drawable as Animatable?)?.start(); synchronized(StateCasting.instance.devices) { @@ -148,7 +147,6 @@ class ConnectCastingDialog(context: Context?) : AlertDialog(context) { override fun dismiss() { super.dismiss() (_imageLoader.drawable as Animatable?)?.stop() - StateCasting.instance.stopDiscovering() StateCasting.instance.onDeviceAdded.remove(this) StateCasting.instance.onDeviceChanged.remove(this) StateCasting.instance.onDeviceRemoved.remove(this) diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/CreatorsFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/CreatorsFragment.kt index 54649ebf..345d577e 100644 --- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/CreatorsFragment.kt +++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/CreatorsFragment.kt @@ -16,6 +16,8 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.futo.platformplayer.R import com.futo.platformplayer.UISlideOverlays +import com.futo.platformplayer.stores.FragmentedStorage +import com.futo.platformplayer.stores.StringStorage import com.futo.platformplayer.views.adapters.SubscriptionAdapter class CreatorsFragment : MainFragment() { @@ -29,6 +31,8 @@ class CreatorsFragment : MainFragment() { private var _editSearch: EditText? = null; private var _textMeta: TextView? = null; private var _buttonClearSearch: ImageButton? = null + private var _ordering = FragmentedStorage.get("creators_ordering") + override fun onCreateMainView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { val view = inflater.inflate(R.layout.fragment_creators, container, false); @@ -44,7 +48,7 @@ class CreatorsFragment : MainFragment() { _buttonClearSearch?.visibility = View.INVISIBLE; } - val adapter = SubscriptionAdapter(inflater, getString(R.string.confirm_delete_subscription)) { subs -> + val adapter = SubscriptionAdapter(inflater, getString(R.string.confirm_delete_subscription), _ordering?.value?.toIntOrNull() ?: 5) { subs -> _textMeta?.let { it.text = "${subs.size} creator${if(subs.size > 1) "s" else ""}"; } @@ -61,6 +65,7 @@ class CreatorsFragment : MainFragment() { spinnerSortBy.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { override fun onItemSelected(parent: AdapterView<*>, view: View?, pos: Int, id: Long) { adapter.sortBy = pos; + _ordering.setAndSave(pos.toString()) } override fun onNothingSelected(parent: AdapterView<*>?) = Unit }; diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/SubscriptionAdapter.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/SubscriptionAdapter.kt index 33783e67..fb28c2e4 100644 --- a/app/src/main/java/com/futo/platformplayer/views/adapters/SubscriptionAdapter.kt +++ b/app/src/main/java/com/futo/platformplayer/views/adapters/SubscriptionAdapter.kt @@ -31,10 +31,11 @@ class SubscriptionAdapter : RecyclerView.Adapter { updateDataset(); } - constructor(inflater: LayoutInflater, confirmationMessage: String, onDatasetChanged: ((List)->Unit)? = null) : super() { + constructor(inflater: LayoutInflater, confirmationMessage: String, sortByDefault: Int, onDatasetChanged: ((List)->Unit)? = null) : super() { _inflater = inflater; _confirmationMessage = confirmationMessage; _onDatasetChanged = onDatasetChanged; + sortBy = sortByDefault StateSubscriptions.instance.onSubscriptionsChanged.subscribe { _, _ -> if(Looper.myLooper() != Looper.getMainLooper()) StateApp.instance.scopeOrNull?.launch(Dispatchers.Main) { updateDataset() }