Fixes to connectivity loss playback restart and fixes to added ensureEnoughContentVisible.

This commit is contained in:
Koen 2023-12-01 15:01:41 +01:00
commit 23d1085755
3 changed files with 43 additions and 25 deletions

View file

@ -390,7 +390,7 @@ class Settings : FragmentedStorageFileJson() {
@DropdownFieldOptionsId(R.array.restart_playback_after_loss) @DropdownFieldOptionsId(R.array.restart_playback_after_loss)
var restartPlaybackAfterLoss: Int = 1; var restartPlaybackAfterLoss: Int = 1;
@FormField(R.string.restart_after_connectivity_loss, FieldForm.DROPDOWN, R.string.restart_playback_when_gaining_connectivity_after_a_loss, 11) @FormField(R.string.restart_after_connectivity_loss, FieldForm.DROPDOWN, R.string.restart_playback_when_gaining_connectivity_after_a_loss, 12)
@DropdownFieldOptionsId(R.array.restart_playback_after_loss) @DropdownFieldOptionsId(R.array.restart_playback_after_loss)
var restartPlaybackAfterConnectivityLoss: Int = 1; var restartPlaybackAfterConnectivityLoss: Int = 1;
} }

View file

@ -13,7 +13,6 @@ import androidx.recyclerview.widget.RecyclerView.LayoutManager
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.futo.platformplayer.* import com.futo.platformplayer.*
import com.futo.platformplayer.api.media.IPlatformClient import com.futo.platformplayer.api.media.IPlatformClient
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
import com.futo.platformplayer.api.media.platforms.js.models.JSPager import com.futo.platformplayer.api.media.platforms.js.models.JSPager
import com.futo.platformplayer.api.media.structures.* import com.futo.platformplayer.api.media.structures.*
import com.futo.platformplayer.constructs.Event1 import com.futo.platformplayer.constructs.Event1
@ -21,7 +20,6 @@ import com.futo.platformplayer.constructs.TaskHandler
import com.futo.platformplayer.engine.exceptions.PluginException import com.futo.platformplayer.engine.exceptions.PluginException
import com.futo.platformplayer.logging.Logger import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.views.FeedStyle import com.futo.platformplayer.views.FeedStyle
import com.futo.platformplayer.views.adapters.ContentPreviewViewHolder
import com.futo.platformplayer.views.others.ProgressBar import com.futo.platformplayer.views.others.ProgressBar
import com.futo.platformplayer.views.others.TagsView import com.futo.platformplayer.views.others.TagsView
import com.futo.platformplayer.views.adapters.InsertedViewAdapterWithLoader import com.futo.platformplayer.views.adapters.InsertedViewAdapterWithLoader
@ -64,6 +62,7 @@ abstract class FeedView<TFragment, TResult, TConverted, TPager, TViewHolder> : L
val fragment: TFragment; val fragment: TFragment;
private val _scrollListener: RecyclerView.OnScrollListener; private val _scrollListener: RecyclerView.OnScrollListener;
private var _automaticNextPageCounter = 0;
constructor(fragment: TFragment, inflater: LayoutInflater, cachedRecyclerData: RecyclerData<InsertedViewAdapterWithLoader<TViewHolder>, LinearLayoutManager, TPager, TResult, TConverted, InsertedViewHolder<TViewHolder>>? = null) : super(inflater.context) { constructor(fragment: TFragment, inflater: LayoutInflater, cachedRecyclerData: RecyclerData<InsertedViewAdapterWithLoader<TViewHolder>, LinearLayoutManager, TPager, TResult, TConverted, InsertedViewHolder<TViewHolder>>? = null) : super(inflater.context) {
this.fragment = fragment; this.fragment = fragment;
@ -122,7 +121,6 @@ abstract class FeedView<TFragment, TResult, TConverted, TPager, TViewHolder> : L
_toolbarContentView = findViewById(R.id.container_toolbar_content); _toolbarContentView = findViewById(R.id.container_toolbar_content);
var filteredNextPageCounter = 0;
_nextPageHandler = TaskHandler<TPager, List<TResult>>({fragment.lifecycleScope}, { _nextPageHandler = TaskHandler<TPager, List<TResult>>({fragment.lifecycleScope}, {
if (it is IAsyncPager<*>) if (it is IAsyncPager<*>)
it.nextPageAsync(); it.nextPageAsync();
@ -142,15 +140,8 @@ abstract class FeedView<TFragment, TResult, TConverted, TPager, TViewHolder> : L
val filteredResults = filterResults(it); val filteredResults = filterResults(it);
recyclerData.results.addAll(filteredResults); recyclerData.results.addAll(filteredResults);
recyclerData.resultsUnfiltered.addAll(it); recyclerData.resultsUnfiltered.addAll(it);
if(filteredResults.isEmpty()) { recyclerData.adapter.notifyItemRangeInserted(recyclerData.adapter.childToParentPosition(posBefore), filteredResults.size);
filteredNextPageCounter++ ensureEnoughContentVisible(filteredResults)
if(filteredNextPageCounter <= 4)
loadNextPage()
}
else {
filteredNextPageCounter = 0;
recyclerData.adapter.notifyItemRangeInserted(recyclerData.adapter.childToParentPosition(posBefore), filteredResults.size);
}
}.exception<Throwable> { }.exception<Throwable> {
Logger.w(TAG, "Failed to load next page.", it); Logger.w(TAG, "Failed to load next page.", it);
UIDialogs.showGeneralRetryErrorDialog(context, context.getString(R.string.failed_to_load_next_page), it, { UIDialogs.showGeneralRetryErrorDialog(context, context.getString(R.string.failed_to_load_next_page), it, {
@ -170,8 +161,10 @@ abstract class FeedView<TFragment, TResult, TConverted, TPager, TViewHolder> : L
val visibleItemCount = _recyclerResults.childCount; val visibleItemCount = _recyclerResults.childCount;
val firstVisibleItem = recyclerData.layoutManager.findFirstVisibleItemPosition(); val firstVisibleItem = recyclerData.layoutManager.findFirstVisibleItemPosition();
//Logger.i(TAG, "onScrolled loadNextPage visibleItemCount=$visibleItemCount firstVisibleItem=$visibleItemCount")
if (!_loading && firstVisibleItem + visibleItemCount + visibleThreshold >= recyclerData.results.size && firstVisibleItem > 0) { if (!_loading && firstVisibleItem + visibleItemCount + visibleThreshold >= recyclerData.results.size && firstVisibleItem > 0) {
//Logger.i(TAG, "loadNextPage(): firstVisibleItem=$firstVisibleItem visibleItemCount=$visibleItemCount visibleThreshold=$visibleThreshold _results.size=${_results.size}") //Logger.i(TAG, "onScrolled loadNextPage(): firstVisibleItem=$firstVisibleItem visibleItemCount=$visibleItemCount visibleThreshold=$visibleThreshold recyclerData.results.size=${recyclerData.results.size}")
loadNextPage(); loadNextPage();
} }
} }
@ -180,6 +173,33 @@ abstract class FeedView<TFragment, TResult, TConverted, TPager, TViewHolder> : L
_recyclerResults.addOnScrollListener(_scrollListener); _recyclerResults.addOnScrollListener(_scrollListener);
} }
private fun ensureEnoughContentVisible(filteredResults: List<TConverted>) {
val canScroll = if (recyclerData.results.isEmpty()) false else {
val layoutManager = recyclerData.layoutManager
val firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition()
if (firstVisibleItemPosition != RecyclerView.NO_POSITION) {
val firstVisibleView = layoutManager.findViewByPosition(firstVisibleItemPosition)
val itemHeight = firstVisibleView?.height ?: 0
val occupiedSpace = recyclerData.results.size * itemHeight
val recyclerViewHeight = _recyclerResults.height
Logger.i(TAG, "ensureEnoughContentVisible loadNextPage occupiedSpace=$occupiedSpace recyclerViewHeight=$recyclerViewHeight")
occupiedSpace >= recyclerViewHeight
} else {
false
}
}
Logger.i(TAG, "ensureEnoughContentVisible loadNextPage canScroll=$canScroll _automaticNextPageCounter=$_automaticNextPageCounter")
if (!canScroll || filteredResults.isEmpty()) {
_automaticNextPageCounter++
if(_automaticNextPageCounter <= 4)
loadNextPage()
} else {
_automaticNextPageCounter = 0;
}
}
protected fun setTextCentered(text: String?) { protected fun setTextCentered(text: String?) {
_textCentered.text = text; _textCentered.text = text;
} }
@ -369,6 +389,7 @@ abstract class FeedView<TFragment, TResult, TConverted, TPager, TViewHolder> : L
recyclerData.resultsUnfiltered.addAll(toAdd); recyclerData.resultsUnfiltered.addAll(toAdd);
recyclerData.adapter.notifyDataSetChanged(); recyclerData.adapter.notifyDataSetChanged();
recyclerData.loadedFeedStyle = feedStyle; recyclerData.loadedFeedStyle = feedStyle;
ensureEnoughContentVisible(filteredResults)
} }
private fun detachPagerEvents() { private fun detachPagerEvents() {

View file

@ -156,22 +156,21 @@ abstract class FutoVideoPlayerBase : RelativeLayout {
val dur = duration; val dur = duration;
var shouldRestartPlayback = false var shouldRestartPlayback = false
if (_shouldPlaybackRestartOnConnectivity && abs(pos - dur) > 2000) { if (_shouldPlaybackRestartOnConnectivity && abs(pos - dur) > 2000) {
if (Settings.instance.playback.restartPlaybackAfterLoss == 1) { if (Settings.instance.playback.restartPlaybackAfterConnectivityLoss == 1) {
val lossTime_ms = _connectivityLossTime_ms val lossTime_ms = _connectivityLossTime_ms
if (lossTime_ms != null && System.currentTimeMillis() - lossTime_ms < 1000 * 30) { if (lossTime_ms != null && System.currentTimeMillis() - lossTime_ms < 1000 * 30) {
shouldRestartPlayback = true shouldRestartPlayback = true
} }
} else if (Settings.instance.playback.restartPlaybackAfterLoss == 2) { } else if (Settings.instance.playback.restartPlaybackAfterConnectivityLoss == 2) {
val lossTime_ms = _connectivityLossTime_ms val lossTime_ms = _connectivityLossTime_ms
if (lossTime_ms != null && System.currentTimeMillis() - lossTime_ms < 1000 * 10) { if (lossTime_ms != null && System.currentTimeMillis() - lossTime_ms < 1000 * 10) {
shouldRestartPlayback = true shouldRestartPlayback = true
} }
} else if (Settings.instance.playback.restartPlaybackAfterLoss == 3) { } else if (Settings.instance.playback.restartPlaybackAfterConnectivityLoss == 3) {
shouldRestartPlayback = true shouldRestartPlayback = true
} }
} }
if (shouldRestartPlayback) { if (shouldRestartPlayback) {
Logger.i(TAG, "Playback ended due to connection loss, resuming playback since connection is restored."); Logger.i(TAG, "Playback ended due to connection loss, resuming playback since connection is restored.");
exoPlayer?.player?.playWhenReady = true; exoPlayer?.player?.playWhenReady = true;
@ -529,13 +528,13 @@ abstract class FutoVideoPlayerBase : RelativeLayout {
PlaybackException.ERROR_CODE_IO_BAD_HTTP_STATUS -> { PlaybackException.ERROR_CODE_IO_BAD_HTTP_STATUS -> {
onDatasourceError.emit(error); onDatasourceError.emit(error);
} }
PlaybackException.ERROR_CODE_IO_CLEARTEXT_NOT_PERMITTED, //PlaybackException.ERROR_CODE_IO_CLEARTEXT_NOT_PERMITTED,
PlaybackException.ERROR_CODE_IO_FILE_NOT_FOUND, //PlaybackException.ERROR_CODE_IO_FILE_NOT_FOUND,
PlaybackException.ERROR_CODE_IO_INVALID_HTTP_CONTENT_TYPE, //PlaybackException.ERROR_CODE_IO_INVALID_HTTP_CONTENT_TYPE,
PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_FAILED, PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_FAILED,
PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_TIMEOUT, PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_TIMEOUT,
PlaybackException.ERROR_CODE_IO_NO_PERMISSION, //PlaybackException.ERROR_CODE_IO_NO_PERMISSION,
PlaybackException.ERROR_CODE_IO_READ_POSITION_OUT_OF_RANGE, //PlaybackException.ERROR_CODE_IO_READ_POSITION_OUT_OF_RANGE,
PlaybackException.ERROR_CODE_IO_UNSPECIFIED -> { PlaybackException.ERROR_CODE_IO_UNSPECIFIED -> {
Logger.i(TAG, "IO error, set _shouldPlaybackRestartOnConnectivity=true"); Logger.i(TAG, "IO error, set _shouldPlaybackRestartOnConnectivity=true");
_shouldPlaybackRestartOnConnectivity = true; _shouldPlaybackRestartOnConnectivity = true;
@ -557,8 +556,6 @@ abstract class FutoVideoPlayerBase : RelativeLayout {
Logger.i(TAG, "_shouldPlaybackRestartOnConnectivity=false"); Logger.i(TAG, "_shouldPlaybackRestartOnConnectivity=false");
_shouldPlaybackRestartOnConnectivity = false; _shouldPlaybackRestartOnConnectivity = false;
} }
} }
companion object { companion object {