Loop support, Improve add to queue behavior, home retry, fix history search pager, defaults progressbar

This commit is contained in:
Kelvin 2023-12-06 19:46:09 +01:00
parent 58da91eae8
commit b284176072
13 changed files with 123 additions and 7 deletions

View file

@ -181,7 +181,7 @@ class Settings : FragmentedStorageFileJson() {
@FormField(R.string.progress_bar, FieldForm.TOGGLE, R.string.progress_bar_description, 6)
var progressBar: Boolean = false;
var progressBar: Boolean = true;
@FormField(R.string.clear_hidden, FieldForm.BUTTON, R.string.clear_hidden_description, 8)
@ -212,7 +212,7 @@ class Settings : FragmentedStorageFileJson() {
var previewFeedItems: Boolean = true;
@FormField(R.string.progress_bar, FieldForm.TOGGLE, R.string.progress_bar_description, 6)
var progressBar: Boolean = false;
var progressBar: Boolean = true;
fun getSearchFeedStyle(): FeedStyle {
@ -230,7 +230,7 @@ class Settings : FragmentedStorageFileJson() {
class ChannelSettings {
@FormField(R.string.progress_bar, FieldForm.TOGGLE, R.string.progress_bar_description, 6)
var progressBar: Boolean = false;
var progressBar: Boolean = true;
}
@FormField(R.string.subscriptions, "group", R.string.configure_how_your_subscriptions_works_and_feels, 4)
@ -252,7 +252,7 @@ class Settings : FragmentedStorageFileJson() {
var previewFeedItems: Boolean = true;
@FormField(R.string.progress_bar, FieldForm.TOGGLE, R.string.progress_bar_description, 6)
var progressBar: Boolean = false;
var progressBar: Boolean = true;
@FormField(R.string.fetch_on_app_boot, FieldForm.TOGGLE, R.string.shortly_after_opening_the_app_start_fetching_subscriptions, 7)
@Serializable(with = FlexibleBooleanSerializer::class)

View file

@ -168,7 +168,7 @@ abstract class ContentFeedView<TFragment> : FeedView<TFragment, IPlatformContent
protected open fun onContentClicked(content: IPlatformContent, time: Long) {
if(content is IPlatformVideo) {
if (StatePlayer.instance.hasQueue) {
StatePlayer.instance.addToQueue(content)
StatePlayer.instance.insertToQueue(content, true);
} else {
if (Settings.instance.playback.shouldResumePreview(time))
fragment.navigate<VideoDetailFragment>(content.withTimestamp(time)).maximizeVideoDetail();

View file

@ -18,6 +18,7 @@ import com.futo.platformplayer.*
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
import com.futo.platformplayer.api.media.structures.IAsyncPager
import com.futo.platformplayer.api.media.structures.IPager
import com.futo.platformplayer.api.media.structures.PlatformContentPager
import com.futo.platformplayer.constructs.TaskHandler
import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.models.HistoryVideo
@ -181,6 +182,7 @@ class HistoryFragment : MainFragment() {
val query = _editSearch.text.toString();
if (_editSearch.text.isNotEmpty()) {
setPager(StateHistory.instance.getHistorySearchPager(query));
//setPager(StateHistory.instance.getHistorySearchPager(query));
} else {
setPager(StateHistory.instance.getHistoryPager());
}

View file

@ -100,7 +100,7 @@ class StateHistory {
return _historyDBStore.getObjectPager();
}
fun getHistorySearchPager(query: String): IPager<HistoryVideo> {
return _historyDBStore.queryLikeObjectPager(DBHistory.Index::url, "%${query}%", 10);
return _historyDBStore.queryLikeObjectPager(DBHistory.Index::name, "%${query}%", 10);
}
fun getHistoryIndexByUrl(url: String): DBHistory.Index? {
return historyIndex[url];

View file

@ -40,6 +40,7 @@ import com.futo.platformplayer.models.ImageVariable
import com.futo.platformplayer.stores.*
import kotlinx.coroutines.*
import okhttp3.internal.concat
import java.lang.Thread.sleep
import java.time.OffsetDateTime
import kotlin.reflect.jvm.internal.impl.builtins.jvm.JavaToKotlinClassMap.PlatformMutabilityMapping
import kotlin.streams.asSequence
@ -405,7 +406,12 @@ class StatePlatform {
val deferred: List<Pair<IPlatformClient, Deferred<IPager<IPlatformContent>?>>> = clients.map {
return@map Pair(it, scope.async(Dispatchers.IO) {
try {
val searchResult = it.fromPool(_pagerClientPool).getHome();
var searchResult = it.fromPool(_pagerClientPool).getHome();
if(searchResult.getResults().size == 0) {
Logger.i(TAG, "No home results, retrying");
sleep(500);
searchResult = it.fromPool(_pagerClientPool).getHome();
}
return@async searchResult;
} catch(ex: Throwable) {
Logger.e(TAG, "getHomeRefresh", ex);

View file

@ -37,6 +37,7 @@ class StatePlayer {
//Video Status
var rotationLock : Boolean = false;
var loopVideo : Boolean = false;
val isPlaying: Boolean get() = _exoplayer?.player?.playWhenReady ?: false;
@ -286,6 +287,31 @@ class StatePlayer {
}
onQueueChanged.emit(true);
}
fun insertToQueue(video: IPlatformVideo, playNow: Boolean = false) {
synchronized(_queue) {
if(_queue.isEmpty()) {
setQueueType(TYPE_QUEUE);
currentVideo?.let {
_queue.add(it);
}
}
if(_queue.isEmpty())
_queue.add(video);
else
_queue.add(_queuePosition.coerceAtLeast(0).coerceAtMost(_queue.size - 1), video);
if (queueShuffle) {
addToShuffledQueue(video);
}
if (_queuePosition < 0) {
_queuePosition = 0;
}
}
onQueueChanged.emit(true);
if(playNow)
setQueuePosition(video);
}
fun setQueuePosition(video: IPlatformVideo) {
synchronized(_queue) {
if (getCurrentQueueItem() == video) {
@ -348,6 +374,8 @@ class StatePlayer {
}
fun getNextQueueItem() : IPlatformVideo? {
if(loopVideo)
return currentVideo;
synchronized(_queue) {
val shuffledQueue = _queueShuffled;
val queue = if (queueShuffle && shuffledQueue != null) {
@ -375,6 +403,8 @@ class StatePlayer {
}
};
fun nextQueueItem(withoutRemoval: Boolean = false) : IPlatformVideo? {
if(loopVideo)
return currentVideo;
synchronized(_queue) {
if (_queue.isEmpty())
return null;

View file

@ -26,6 +26,7 @@ class CastView : ConstraintLayout {
private val _thumbnail: ImageView;
private val _buttonMinimize: ImageButton;
private val _buttonSettings: ImageButton;
private val _buttonLoop: ImageButton;
private val _buttonPlay: ImageButton;
private val _buttonPause: ImageButton;
private val _buttonCast: CastButton;
@ -49,6 +50,7 @@ class CastView : ConstraintLayout {
_thumbnail = findViewById(R.id.image_thumbnail);
_buttonMinimize = findViewById(R.id.button_minimize);
_buttonSettings = findViewById(R.id.button_settings);
_buttonLoop = findViewById(R.id.button_loop);
_buttonPlay = findViewById(R.id.button_play);
_buttonPause = findViewById(R.id.button_pause);
_buttonCast = findViewById(R.id.button_cast);
@ -65,6 +67,12 @@ class CastView : ConstraintLayout {
StateCasting.instance.videoSeekTo(d.expectedCurrentTime + it / 1000);
};
_buttonLoop.setOnClickListener {
StatePlayer.instance.loopVideo = !StatePlayer.instance.loopVideo;
_buttonLoop.setImageResource(if(StatePlayer.instance.loopVideo) R.drawable.ic_loop_active else R.drawable.ic_loop);
}
_buttonLoop.setImageResource(if(StatePlayer.instance.loopVideo) R.drawable.ic_loop_active else R.drawable.ic_loop);
_timeBar.addListener(object : OnScrubListener {
override fun onScrubStart(timeBar: TimeBar, position: Long) {
StateCasting.instance.videoSeekTo(position.toDouble());

View file

@ -68,6 +68,7 @@ class FutoVideoPlayer : FutoVideoPlayerBase {
private val _control_videosettings: ImageButton;
private val _control_minimize: ImageButton;
private val _control_rotate_lock: ImageButton;
private val _control_loop: ImageButton;
private val _control_cast: ImageButton;
private val _control_play: ImageButton;
private val _control_chapter: TextView;
@ -77,6 +78,7 @@ class FutoVideoPlayer : FutoVideoPlayerBase {
private val _control_videosettings_fullscreen: ImageButton;
private val _control_minimize_fullscreen: ImageButton;
private val _control_rotate_lock_fullscreen: ImageButton;
private val _control_loop_fullscreen: ImageButton;
private val _control_cast_fullscreen: ImageButton;
private val _control_play_fullscreen: ImageButton;
private val _time_bar_fullscreen: TimeBar;
@ -128,6 +130,7 @@ class FutoVideoPlayer : FutoVideoPlayerBase {
_control_videosettings = videoControls.findViewById(R.id.exo_settings);
_control_minimize = videoControls.findViewById(R.id.exo_minimize);
_control_rotate_lock = videoControls.findViewById(R.id.exo_rotate_lock);
_control_loop = videoControls.findViewById(R.id.exo_loop);
_control_cast = videoControls.findViewById(R.id.exo_cast);
_control_play = videoControls.findViewById(com.google.android.exoplayer2.ui.R.id.exo_play);
_time_bar = videoControls.findViewById(com.google.android.exoplayer2.ui.R.id.exo_progress);
@ -138,6 +141,7 @@ class FutoVideoPlayer : FutoVideoPlayerBase {
_control_minimize_fullscreen = _videoControls_fullscreen.findViewById(R.id.exo_minimize);
_control_videosettings_fullscreen = _videoControls_fullscreen.findViewById(R.id.exo_settings);
_control_rotate_lock_fullscreen = _videoControls_fullscreen.findViewById(R.id.exo_rotate_lock);
_control_loop_fullscreen = videoControls.findViewById(R.id.exo_loop);
_control_cast_fullscreen = _videoControls_fullscreen.findViewById(R.id.exo_cast);
_control_play_fullscreen = videoControls.findViewById(com.google.android.exoplayer2.ui.R.id.exo_play);
_control_chapter_fullscreen = _videoControls_fullscreen.findViewById(R.id.text_chapter_current);
@ -244,6 +248,16 @@ class FutoVideoPlayer : FutoVideoPlayerBase {
UIDialogs.showCastingDialog(context);
};
_control_loop.setOnClickListener {
StatePlayer.instance.loopVideo = !StatePlayer.instance.loopVideo;
updateLoopVideoUI();
}
_control_loop_fullscreen.setOnClickListener {
StatePlayer.instance.loopVideo = !StatePlayer.instance.loopVideo;
updateLoopVideoUI();
}
_control_minimize_fullscreen.setOnClickListener {
onMinimize.emit(this);
};
@ -273,6 +287,8 @@ class FutoVideoPlayer : FutoVideoPlayerBase {
}
}
updateLoopVideoUI();
if(!isInEditMode) {
gestureControl.hideControls();
}
@ -555,6 +571,17 @@ class FutoVideoPlayer : FutoVideoPlayerBase {
_control_rotate_lock.setImageResource(R.drawable.ic_screen_lock_rotation);
}
}
fun updateLoopVideoUI() {
if(StatePlayer.instance.loopVideo) {
_control_loop.setImageResource(R.drawable.ic_loop_active);
_control_loop_fullscreen.setImageResource(R.drawable.ic_loop_active);
}
else {
_control_loop.setImageResource(R.drawable.ic_loop);
_control_loop_fullscreen.setImageResource(R.drawable.ic_loop);
}
}
fun setGestureSoundFactor(soundFactor: Float) {
gestureControl.setSoundFactor(soundFactor);

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@android:color/white"
android:pathData="M292.31,840L160,707.69L292.31,575.39L320.61,604.15L237.08,687.69L692.31,687.69L692.31,527.69L732.31,527.69L732.31,727.69L237.08,727.69L320.61,811.23L292.31,840ZM227.69,432.31L227.69,232.31L722.92,232.31L639.39,148.77L667.69,120L800,252.31L667.69,384.61L639.39,355.85L722.92,272.31L267.69,272.31L267.69,432.31L227.69,432.31Z"/>
</vector>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@color/colorPrimary"
android:pathData="M292.31,840L160,707.69L292.31,575.39L320.61,604.15L237.08,687.69L692.31,687.69L692.31,527.69L732.31,527.69L732.31,727.69L237.08,727.69L320.61,811.23L292.31,840ZM227.69,432.31L227.69,232.31L722.92,232.31L639.39,148.77L667.69,120L800,252.31L667.69,384.61L639.39,355.85L722.92,272.31L267.69,272.31L267.69,432.31L227.69,432.31Z"/>
</vector>

View file

@ -45,6 +45,14 @@
android:clickable="true"
android:padding="12dp"
app:srcCompat="@drawable/ic_screen_lock_rotation" />
<ImageButton
android:id="@+id/exo_loop"
android:layout_width="50dp"
android:layout_height="50dp"
android:scaleType="fitCenter"
android:clickable="true"
android:padding="12dp"
app:srcCompat="@drawable/ic_loop" />
<ImageButton
android:id="@+id/exo_settings"
android:layout_width="50dp"

View file

@ -73,6 +73,14 @@
android:clickable="true"
android:padding="12dp"
app:srcCompat="@drawable/ic_screen_lock_rotation" />
<ImageButton
android:id="@+id/exo_loop"
android:layout_width="50dp"
android:layout_height="50dp"
android:scaleType="fitCenter"
android:clickable="true"
android:padding="12dp"
app:srcCompat="@drawable/ic_loop" />
<ImageButton
android:id="@+id/exo_settings"
android:layout_width="50dp"

View file

@ -54,6 +54,15 @@
android:clickable="true"
android:padding="12dp"
app:srcCompat="@drawable/ic_cast" />
<ImageButton
android:id="@+id/button_loop"
android:layout_width="50dp"
android:layout_height="50dp"
android:scaleType="fitCenter"
android:clickable="true"
android:padding="12dp"
app:srcCompat="@drawable/ic_loop" />
<ImageButton
android:id="@+id/button_settings"
android:layout_width="50dp"