mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2025-04-20 03:24:50 +00:00
Added autoplay feature.
This commit is contained in:
parent
e39d862ef3
commit
ec370dd94b
5 changed files with 154 additions and 35 deletions
|
@ -290,6 +290,7 @@ class VideoDetailView : ConstraintLayout {
|
|||
private var _commentsCount = 0;
|
||||
private var _polycentricProfile: PolycentricCache.CachedPolycentricProfile? = null;
|
||||
private var _slideUpOverlay: SlideUpMenuOverlay? = null;
|
||||
private var _autoplayVideo: IPlatformVideo? = null
|
||||
|
||||
//Events
|
||||
val onMinimize = Event0();
|
||||
|
@ -720,6 +721,17 @@ class VideoDetailView : ConstraintLayout {
|
|||
fragment.activity?.window?.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
};
|
||||
|
||||
StatePlayer.instance.autoplayChanged.subscribe(this) {
|
||||
if (it) {
|
||||
val url = _url
|
||||
val autoPlayVideo = _autoplayVideo
|
||||
if (url != null && autoPlayVideo == null) {
|
||||
_taskLoadRecommendations.cancel()
|
||||
_taskLoadRecommendations.run(url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_layoutResume.setOnClickListener {
|
||||
handleSeek(_historicalPosition * 1000);
|
||||
|
||||
|
@ -1006,6 +1018,7 @@ class VideoDetailView : ConstraintLayout {
|
|||
_container_content_queue.cleanup();
|
||||
_container_content_description.cleanup();
|
||||
_container_content_support.cleanup();
|
||||
StatePlayer.instance.autoplayChanged.remove(this)
|
||||
StateCasting.instance.onActiveDevicePlayChanged.remove(this);
|
||||
StateCasting.instance.onActiveDeviceTimeChanged.remove(this);
|
||||
StateCasting.instance.onActiveDeviceConnectionStateChanged.remove(this);
|
||||
|
@ -1102,6 +1115,8 @@ class VideoDetailView : ConstraintLayout {
|
|||
this.video = null;
|
||||
cleanupPlaybackTracker();
|
||||
_searchVideo = video;
|
||||
_autoplayVideo = null
|
||||
Logger.i(TAG, "Autoplay video cleared (setVideoOverview)")
|
||||
_videoResumePositionMilliseconds = resumeSeconds * 1000;
|
||||
setLastPositionMilliseconds(_videoResumePositionMilliseconds, false);
|
||||
_addCommentView.setContext(null, null);
|
||||
|
@ -1191,6 +1206,8 @@ class VideoDetailView : ConstraintLayout {
|
|||
Logger.i(TAG, "setVideoDetails (${videoDetail.name})")
|
||||
_didTriggerDatasourceErrroCount = 0;
|
||||
_didTriggerDatasourceError = false;
|
||||
_autoplayVideo = null
|
||||
Logger.i(TAG, "Autoplay video cleared (setVideoDetails)")
|
||||
|
||||
if(newVideo && this.video?.url == videoDetail.url)
|
||||
return;
|
||||
|
@ -1511,6 +1528,11 @@ class VideoDetailView : ConstraintLayout {
|
|||
_layoutRating.visibility = View.VISIBLE
|
||||
_layoutChangeBottomSection.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
if (StatePlayer.instance.autoplay) {
|
||||
_taskLoadRecommendations.cancel()
|
||||
_taskLoadRecommendations.run(videoDetail.url)
|
||||
}
|
||||
}
|
||||
fun loadLiveChat(video: IPlatformVideoDetails) {
|
||||
_liveChat?.stop();
|
||||
|
@ -1779,6 +1801,14 @@ class VideoDetailView : ConstraintLayout {
|
|||
fun nextVideo(forceLoop: Boolean = false, withoutRemoval: Boolean = false, bypassVideoLoop: Boolean = false): Boolean {
|
||||
Logger.i(TAG, "nextVideo")
|
||||
var next = StatePlayer.instance.nextQueueItem(withoutRemoval || _player.duration < 100 || (_player.position.toFloat() / _player.duration) < 0.9, bypassVideoLoop);
|
||||
val autoplayVideo = _autoplayVideo
|
||||
if (next == null && autoplayVideo != null && StatePlayer.instance.autoplay) {
|
||||
Logger.i(TAG, "Found autoplay video!")
|
||||
StatePlayer.instance.setAutoplayed(autoplayVideo.url)
|
||||
next = autoplayVideo
|
||||
}
|
||||
_autoplayVideo = null
|
||||
Logger.i(TAG, "Autoplay video cleared (nextVideo)")
|
||||
if(next == null && forceLoop)
|
||||
next = StatePlayer.instance.restartQueue();
|
||||
if(next != null) {
|
||||
|
@ -2347,43 +2377,49 @@ class VideoDetailView : ConstraintLayout {
|
|||
}
|
||||
}
|
||||
|
||||
private fun setRecommendations(pager: IPager<IPlatformContent>?, message: String? = null) {
|
||||
_layoutRecommended.removeAllViews()
|
||||
if (pager == null) {
|
||||
_layoutRecommended.addView(TextView(context).apply {
|
||||
layoutParams = LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT).apply {
|
||||
setMargins(20.dp(resources), 20.dp(resources), 20.dp(resources), 20.dp(resources))
|
||||
}
|
||||
textAlignment = TEXT_ALIGNMENT_CENTER
|
||||
textSize = 14.0f
|
||||
text = message
|
||||
})
|
||||
return
|
||||
private fun setRecommendations(results: List<IPlatformVideo>?, message: String? = null) {
|
||||
if (results != null && StatePlayer.instance.autoplay) {
|
||||
_autoplayVideo = results.firstOrNull { !StatePlayer.instance.wasAutoplayed(it.url) }
|
||||
Logger.i(TAG, "Autoplay video set (url = ${_autoplayVideo?.url})")
|
||||
}
|
||||
|
||||
val results = pager.getResults().filter { it is IPlatformVideo }
|
||||
for (result in results) {
|
||||
_layoutRecommended.addView(PreviewVideoView(context, FeedStyle.THUMBNAIL, null, false).apply {
|
||||
layoutParams = LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT)
|
||||
bind(result)
|
||||
|
||||
hideAddTo()
|
||||
|
||||
onVideoClicked.subscribe { video, _ ->
|
||||
fragment.navigate<VideoDetailFragment>(video).maximizeVideoDetail()
|
||||
}
|
||||
|
||||
onChannelClicked.subscribe {
|
||||
fragment.navigate<ChannelFragment>(it)
|
||||
}
|
||||
|
||||
onAddToWatchLaterClicked.subscribe(this) {
|
||||
if(it is IPlatformVideo) {
|
||||
StatePlaylists.instance.addToWatchLater(SerializedPlatformVideo.fromVideo(it));
|
||||
UIDialogs.toast("Added to watch later\n[${it.name}]");
|
||||
if (_tabIndex == 2) {
|
||||
_layoutRecommended.removeAllViews()
|
||||
if (results == null) {
|
||||
_layoutRecommended.addView(TextView(context).apply {
|
||||
layoutParams = LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT).apply {
|
||||
setMargins(20.dp(resources), 20.dp(resources), 20.dp(resources), 20.dp(resources))
|
||||
}
|
||||
}
|
||||
})
|
||||
textAlignment = TEXT_ALIGNMENT_CENTER
|
||||
textSize = 14.0f
|
||||
text = message
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
for (result in results) {
|
||||
_layoutRecommended.addView(PreviewVideoView(context, FeedStyle.THUMBNAIL, null, false).apply {
|
||||
layoutParams = LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT)
|
||||
bind(result)
|
||||
|
||||
hideAddTo()
|
||||
|
||||
onVideoClicked.subscribe { video, _ ->
|
||||
fragment.navigate<VideoDetailFragment>(video).maximizeVideoDetail()
|
||||
}
|
||||
|
||||
onChannelClicked.subscribe {
|
||||
fragment.navigate<ChannelFragment>(it)
|
||||
}
|
||||
|
||||
onAddToWatchLaterClicked.subscribe(this) {
|
||||
if(it is IPlatformVideo) {
|
||||
StatePlaylists.instance.addToWatchLater(SerializedPlatformVideo.fromVideo(it));
|
||||
UIDialogs.toast("Added to watch later\n[${it.name}]");
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2732,7 +2768,7 @@ class VideoDetailView : ConstraintLayout {
|
|||
} else TaskHandler(IPlatformVideoDetails::class.java, {fragment.lifecycleScope});
|
||||
|
||||
private val _taskLoadRecommendations = TaskHandler<String, IPager<IPlatformContent>?>(StateApp.instance.scopeGetter, { video?.getContentRecommendations(StatePlatform.instance.getContentClient(it)) })
|
||||
.success { setRecommendations(it, "No recommendations found") }
|
||||
.success { setRecommendations(it?.getResults()?.filter { it is IPlatformVideo }?.map { it as IPlatformVideo }, "No recommendations found") }
|
||||
.exception<Throwable> {
|
||||
setRecommendations(null, it.message)
|
||||
Logger.w(TAG, "Failed to load recommendations.", it);
|
||||
|
|
|
@ -45,6 +45,33 @@ class StatePlayer {
|
|||
onRotationLockChanged.emit(value)
|
||||
}
|
||||
val onRotationLockChanged = Event1<Boolean>()
|
||||
var autoplay: Boolean = false
|
||||
get() = field
|
||||
set(value) {
|
||||
if (field != value)
|
||||
_autoplayed.clear()
|
||||
field = value
|
||||
autoplayChanged.emit(value)
|
||||
}
|
||||
private val _autoplayed = hashSetOf<String>()
|
||||
fun wasAutoplayed(url: String?): Boolean {
|
||||
if (url == null) {
|
||||
return false
|
||||
}
|
||||
synchronized(_autoplayed) {
|
||||
return _autoplayed.contains(url)
|
||||
}
|
||||
}
|
||||
fun setAutoplayed(url: String?) {
|
||||
if (url == null) {
|
||||
return
|
||||
}
|
||||
synchronized(_autoplayed) {
|
||||
_autoplayed.add(url)
|
||||
}
|
||||
}
|
||||
|
||||
val autoplayChanged = Event1<Boolean>()
|
||||
var loopVideo : Boolean = false;
|
||||
|
||||
val isPlaying: Boolean get() = _exoplayer?.player?.playWhenReady ?: false;
|
||||
|
@ -138,6 +165,12 @@ class StatePlayer {
|
|||
}
|
||||
}
|
||||
|
||||
fun isUrlInQueue(url : String) : Boolean {
|
||||
synchronized(_queue) {
|
||||
return _queue.any { it.url == url };
|
||||
}
|
||||
}
|
||||
|
||||
fun getQueueType() : String {
|
||||
return _queueType;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ import android.widget.ImageButton
|
|||
import android.widget.TextView
|
||||
import androidx.annotation.OptIn
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.setMargins
|
||||
import androidx.media3.common.C
|
||||
import androidx.media3.common.PlaybackParameters
|
||||
|
@ -74,6 +75,7 @@ class FutoVideoPlayer : FutoVideoPlayerBase {
|
|||
|
||||
//Custom buttons
|
||||
private val _control_fullscreen: ImageButton;
|
||||
private val _control_autoplay: ImageButton;
|
||||
private val _control_videosettings: ImageButton;
|
||||
private val _control_minimize: ImageButton;
|
||||
private val _control_rotate_lock: ImageButton;
|
||||
|
@ -92,6 +94,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_autoplay_fullscreen: ImageButton;
|
||||
private val _control_loop_fullscreen: ImageButton;
|
||||
private val _control_cast_fullscreen: ImageButton;
|
||||
private val _control_play_fullscreen: ImageButton;
|
||||
|
@ -149,6 +152,7 @@ class FutoVideoPlayer : FutoVideoPlayerBase {
|
|||
|
||||
videoControls = findViewById(R.id.video_player_controller);
|
||||
_control_fullscreen = videoControls.findViewById(R.id.button_fullscreen);
|
||||
_control_autoplay = videoControls.findViewById(R.id.button_autoplay);
|
||||
_control_videosettings = videoControls.findViewById(R.id.button_settings);
|
||||
_control_minimize = videoControls.findViewById(R.id.button_minimize);
|
||||
_control_rotate_lock = videoControls.findViewById(R.id.button_rotate_lock);
|
||||
|
@ -164,6 +168,7 @@ class FutoVideoPlayer : FutoVideoPlayerBase {
|
|||
_control_duration = videoControls.findViewById(R.id.text_duration);
|
||||
|
||||
_videoControls_fullscreen = findViewById(R.id.video_player_controller_fullscreen);
|
||||
_control_autoplay_fullscreen = _videoControls_fullscreen.findViewById(R.id.button_autoplay);
|
||||
_control_fullscreen_fullscreen = _videoControls_fullscreen.findViewById(R.id.button_fullscreen);
|
||||
_control_minimize_fullscreen = _videoControls_fullscreen.findViewById(R.id.button_minimize);
|
||||
_control_videosettings_fullscreen = _videoControls_fullscreen.findViewById(R.id.button_settings);
|
||||
|
@ -386,6 +391,18 @@ class FutoVideoPlayer : FutoVideoPlayerBase {
|
|||
UIDialogs.showCastingDialog(context);
|
||||
};
|
||||
|
||||
_control_autoplay.setOnClickListener {
|
||||
StatePlayer.instance.autoplay = !StatePlayer.instance.autoplay;
|
||||
updateAutoplayButton()
|
||||
}
|
||||
updateAutoplayButton()
|
||||
|
||||
_control_autoplay_fullscreen.setOnClickListener {
|
||||
StatePlayer.instance.autoplay = !StatePlayer.instance.autoplay;
|
||||
updateAutoplayButton()
|
||||
}
|
||||
updateAutoplayButton()
|
||||
|
||||
val progressUpdateListener = { position: Long, bufferedPosition: Long ->
|
||||
val currentTime = position.formatDuration()
|
||||
val currentDuration = duration.formatDuration()
|
||||
|
@ -433,6 +450,11 @@ class FutoVideoPlayer : FutoVideoPlayerBase {
|
|||
}
|
||||
}
|
||||
|
||||
private fun updateAutoplayButton() {
|
||||
_control_autoplay.setColorFilter(ContextCompat.getColor(context, if (StatePlayer.instance.autoplay) com.futo.futopay.R.color.primary else R.color.white))
|
||||
_control_autoplay_fullscreen.setColorFilter(ContextCompat.getColor(context, if (StatePlayer.instance.autoplay) com.futo.futopay.R.color.primary else R.color.white))
|
||||
}
|
||||
|
||||
private fun setSystemBrightness(brightness: Float) {
|
||||
Log.i(TAG, "setSystemBrightness $brightness")
|
||||
if (android.provider.Settings.System.canWrite(context)) {
|
||||
|
|
|
@ -133,6 +133,20 @@
|
|||
android:scaleType="fitCenter"
|
||||
android:layout_marginBottom="18dp" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/button_autoplay"
|
||||
android:layout_width="55dp"
|
||||
android:layout_height="40dp"
|
||||
android:clickable="true"
|
||||
app:srcCompat="@drawable/autoplay_24px"
|
||||
app:layout_constraintRight_toLeftOf="@id/button_fullscreen"
|
||||
app:layout_constraintBottom_toBottomOf="@id/button_fullscreen"
|
||||
app:layout_constraintTop_toTopOf="@id/button_fullscreen"
|
||||
android:paddingStart="5dp"
|
||||
android:paddingTop="15dp"
|
||||
android:paddingEnd="5dp"
|
||||
android:scaleType="fitCenter"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_position"
|
||||
android:layout_width="wrap_content"
|
||||
|
|
|
@ -147,6 +147,20 @@
|
|||
app:layout_constraintLeft_toRightOf="@id/layout_play_pause"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/button_autoplay"
|
||||
android:layout_width="55dp"
|
||||
android:layout_height="40dp"
|
||||
android:clickable="true"
|
||||
app:srcCompat="@drawable/autoplay_24px"
|
||||
app:layout_constraintRight_toLeftOf="@id/button_fullscreen"
|
||||
app:layout_constraintBottom_toBottomOf="@id/button_fullscreen"
|
||||
app:layout_constraintTop_toTopOf="@id/button_fullscreen"
|
||||
android:paddingStart="5dp"
|
||||
android:paddingTop="15dp"
|
||||
android:paddingEnd="5dp"
|
||||
android:scaleType="fitCenter"/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/button_fullscreen"
|
||||
android:layout_width="55dp"
|
||||
|
|
Loading…
Add table
Reference in a new issue