From bd5fdadd3b990aca62022f544b105fcf34083104 Mon Sep 17 00:00:00 2001 From: Bnyro Date: Tue, 28 Jun 2022 15:56:26 +0200 Subject: [PATCH 01/32] improve back button --- app/src/main/res/layout/activity_settings.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml index 73ca5679f..0621edddc 100644 --- a/app/src/main/res/layout/activity_settings.xml +++ b/app/src/main/res/layout/activity_settings.xml @@ -10,9 +10,9 @@ Date: Tue, 28 Jun 2022 16:01:40 +0200 Subject: [PATCH 02/32] improve about margins --- app/src/main/res/layout/activity_settings.xml | 6 +++--- app/src/main/res/values/style.xml | 12 ++---------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml index 0621edddc..904b19f13 100644 --- a/app/src/main/res/layout/activity_settings.xml +++ b/app/src/main/res/layout/activity_settings.xml @@ -10,9 +10,9 @@ wrap_content 20dp 20dp - 15dp - 15dp + 12dp + 12dp ?android:attr/selectableItemBackground - - + + \ No newline at end of file From ad509e3b4ebee36bc1d17c40827104224b7c5dc7 Mon Sep 17 00:00:00 2001 From: Bnyro Date: Tue, 28 Jun 2022 17:29:31 +0200 Subject: [PATCH 27/32] format code --- app/src/main/AndroidManifest.xml | 4 ++-- .../java/com/github/libretube/fragments/PlayerFragment.kt | 1 - app/src/main/res/layout/chapter_column.xml | 6 +++--- app/src/main/res/layout/fragment_player.xml | 6 +++--- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e5baf8a8a..b5efba744 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -278,9 +278,9 @@ + android:exported="false" + android:stopWithTask="false" /> \ No newline at end of file diff --git a/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt b/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt index 620d93eb9..3e0c725e5 100644 --- a/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt +++ b/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt @@ -1,6 +1,5 @@ package com.github.libretube.fragments -import android.R.attr.mimeType import android.annotation.SuppressLint import android.app.NotificationManager import android.app.PictureInPictureParams diff --git a/app/src/main/res/layout/chapter_column.xml b/app/src/main/res/layout/chapter_column.xml index ff16c0e82..f323807ab 100644 --- a/app/src/main/res/layout/chapter_column.xml +++ b/app/src/main/res/layout/chapter_column.xml @@ -1,17 +1,17 @@ + android:src="@mipmap/ic_launcher" + app:shapeAppearanceOverlay="@style/roundedImageViewRounded" /> + android:animateLayoutChanges="true" + android:orientation="vertical"> Date: Wed, 29 Jun 2022 09:04:11 +0200 Subject: [PATCH 28/32] basic playlist autoplay implementation --- .../libretube/adapters/PlaylistAdapter.kt | 1 + .../libretube/fragments/PlayerFragment.kt | 75 +++++++++++++++++-- 2 files changed, 70 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/github/libretube/adapters/PlaylistAdapter.kt b/app/src/main/java/com/github/libretube/adapters/PlaylistAdapter.kt index 448060c49..05f26b331 100644 --- a/app/src/main/java/com/github/libretube/adapters/PlaylistAdapter.kt +++ b/app/src/main/java/com/github/libretube/adapters/PlaylistAdapter.kt @@ -60,6 +60,7 @@ class PlaylistAdapter( holder.v.setOnClickListener { var bundle = Bundle() bundle.putString("videoId", streamItem.url!!.replace("/watch?v=", "")) + bundle.putString("playlistId", playlistId) var frag = PlayerFragment() frag.arguments = bundle val activity = holder.v.context as AppCompatActivity diff --git a/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt b/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt index 3e0c725e5..c5f642b70 100644 --- a/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt +++ b/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt @@ -49,6 +49,7 @@ import com.github.libretube.dialogs.ShareDialog import com.github.libretube.hideKeyboard import com.github.libretube.obj.ChapterSegment import com.github.libretube.obj.PipedStream +import com.github.libretube.obj.Playlist import com.github.libretube.obj.Segment import com.github.libretube.obj.Segments import com.github.libretube.obj.SponsorBlockPrefs @@ -86,6 +87,9 @@ import com.google.android.material.button.MaterialButton import com.google.android.material.card.MaterialCardView import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.squareup.picasso.Picasso +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch import org.chromium.net.CronetEngine import retrofit2.HttpException import java.io.IOException @@ -99,6 +103,7 @@ class PlayerFragment : Fragment() { private val TAG = "PlayerFragment" private var videoId: String? = null + private var playlistId: String? = null private var sId: Int = 0 private var eId: Int = 0 private var paused = false @@ -119,8 +124,10 @@ class PlayerFragment : Fragment() { private lateinit var motionLayout: MotionLayout private lateinit var exoPlayer: ExoPlayer private lateinit var segmentData: Segments - private var relatedStreams: List? = arrayListOf() private var relatedStreamsEnabled = true + private var relatedStreams: List? = arrayListOf() + private var nextStreamId: String? = null + private var playlistStreamIds: MutableList = arrayListOf() private var isPlayerLocked: Boolean = false private lateinit var relDownloadVideo: LinearLayout @@ -138,6 +145,7 @@ class PlayerFragment : Fragment() { super.onCreate(savedInstanceState) arguments?.let { videoId = it.getString("videoId") + playlistId = it.getString("playlistId") } } @@ -437,12 +445,13 @@ class PlayerFragment : Fragment() { uploader = response.uploader!! thumbnailUrl = response.thumbnailUrl!! - // check whether related streams and autoplay are enabled + // save whether related streams and autoplay are enabled autoplay = PreferenceHelper.getBoolean(requireContext(), "autoplay", false) relatedStreamsEnabled = PreferenceHelper.getBoolean(requireContext(), "related_streams_toggle", true) // save related streams for autoplay relatedStreams = response.relatedStreams + runOnUiThread { createExoPlayer(view) if (response.chapters != null) initializeChapters(response.chapters) @@ -462,6 +471,61 @@ class PlayerFragment : Fragment() { fetchSponsorBlockSegments() // show comments if related streams disabled if (!relatedStreamsEnabled) toggleComments() + // prepare for autoplay + initAutoPlay() + } + } + } + run() + } + + private fun initAutoPlay() { + // save related streams for autoplay + if (autoplay) { + // save related streams for autoplay + if (playlistId != null) { + if (playlistStreamIds.isEmpty()) { + lateinit var playlist: Playlist + CoroutineScope(Dispatchers.IO).launch { + // fetch the playlists videos + playlist = RetrofitInstance.api.getPlaylist(playlistId!!) + playlist.relatedStreams?.forEach { video -> + playlistStreamIds += video.url?.replace("/watch?v=", "")!! + } + // if the playlists contain the video, then save the next video as next stream + if (playlistStreamIds.contains(videoId)) { + val index = playlistStreamIds.indexOf(videoId) + if (index + 1 <= playlistStreamIds.size) { + nextStreamId = playlistStreamIds[index + 1] + } + } + } + } + } else if (relatedStreams != null && relatedStreams!!.isNotEmpty()) { + // save next video from related streams for autoplay + nextStreamId = relatedStreams!![0].url!!.replace("/watch?v=", "")!! + } + } + } + + private fun playNextVideo() { + // save the id of the next stream as videoId and load the next video + videoId = nextStreamId + fetchJsonAndInitPlayer(view!!) + } + + private fun fetchNextPage() { + fun run() { + lifecycleScope.launchWhenCreated { + val response = try { + RetrofitInstance.api.getPlaylistNextPage(playlistId!!, nextPage!!) + } catch (e: IOException) { + println(e) + Log.e(TAG, "IOException, you might not have internet connection") + return@launchWhenCreated + } catch (e: HttpException) { + Log.e(TAG, "HttpException, unexpected response," + e.response()) + return@launchWhenCreated } } } @@ -599,14 +663,13 @@ class PlayerFragment : Fragment() { // check if video has ended, next video is available and autoplay is enabled. if ( playbackState == Player.STATE_ENDED && - relatedStreams != null && - relatedStreams!!.isNotEmpty() && + nextStreamId != null && !transitioning && autoplay ) { transitioning = true - videoId = relatedStreams!![0].url!!.replace("/watch?v=", "") - fetchJsonAndInitPlayer(view) + // check whether autoplay is enabled + if (autoplay) playNextVideo() } if (playWhenReady && playbackState == Player.STATE_READY) { From d5be2600b061b9cfdb91338fa06dae4c2b127563 Mon Sep 17 00:00:00 2001 From: Bnyro Date: Wed, 29 Jun 2022 09:22:22 +0200 Subject: [PATCH 29/32] playlist autoplay nextpage --- .../libretube/fragments/PlayerFragment.kt | 56 ++++++++++--------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt b/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt index c5f642b70..635576ea1 100644 --- a/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt +++ b/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt @@ -125,9 +125,12 @@ class PlayerFragment : Fragment() { private lateinit var exoPlayer: ExoPlayer private lateinit var segmentData: Segments private var relatedStreamsEnabled = true + private var relatedStreams: List? = arrayListOf() private var nextStreamId: String? = null private var playlistStreamIds: MutableList = arrayListOf() + private var playlistNextPage: String? = null + private var isPlayerLocked: Boolean = false private lateinit var relDownloadVideo: LinearLayout @@ -482,25 +485,42 @@ class PlayerFragment : Fragment() { private fun initAutoPlay() { // save related streams for autoplay if (autoplay) { - // save related streams for autoplay + // if it's a playlist use the next video if (playlistId != null) { + lateinit var playlist: Playlist // var for saving the list in if (playlistStreamIds.isEmpty()) { - lateinit var playlist: Playlist CoroutineScope(Dispatchers.IO).launch { // fetch the playlists videos playlist = RetrofitInstance.api.getPlaylist(playlistId!!) playlist.relatedStreams?.forEach { video -> playlistStreamIds += video.url?.replace("/watch?v=", "")!! } - // if the playlists contain the video, then save the next video as next stream - if (playlistStreamIds.contains(videoId)) { - val index = playlistStreamIds.indexOf(videoId) - if (index + 1 <= playlistStreamIds.size) { - nextStreamId = playlistStreamIds[index + 1] - } - } + // restart the function after videos are loaded + playlistNextPage = playlist.nextpage + initAutoPlay() } } + // if the playlists contain the video, then save the next video as next stream + else if (playlistStreamIds.contains(videoId)) { + val index = playlistStreamIds.indexOf(videoId) + // check whether there's a next video + if (index + 1 <= playlistStreamIds.size) { + nextStreamId = playlistStreamIds[index + 1] + } + // fetch the next page of the playlist if the video isn't contained + } else if (playlistNextPage != null) { + CoroutineScope(Dispatchers.IO).launch { + Log.e(TAG, "fetching next autoplay page list") + RetrofitInstance.api.getPlaylistNextPage(playlistId!!, playlistNextPage!!) + playlist.relatedStreams?.forEach { video -> + playlistStreamIds += video.url?.replace("/watch?v=", "")!! + } + // restart the function after videos are loaded + playlistNextPage = playlist.nextpage + initAutoPlay() + } + } + // if it's not a playlist then use the next related video } else if (relatedStreams != null && relatedStreams!!.isNotEmpty()) { // save next video from related streams for autoplay nextStreamId = relatedStreams!![0].url!!.replace("/watch?v=", "")!! @@ -514,24 +534,6 @@ class PlayerFragment : Fragment() { fetchJsonAndInitPlayer(view!!) } - private fun fetchNextPage() { - fun run() { - lifecycleScope.launchWhenCreated { - val response = try { - RetrofitInstance.api.getPlaylistNextPage(playlistId!!, nextPage!!) - } catch (e: IOException) { - println(e) - Log.e(TAG, "IOException, you might not have internet connection") - return@launchWhenCreated - } catch (e: HttpException) { - Log.e(TAG, "HttpException, unexpected response," + e.response()) - return@launchWhenCreated - } - } - } - run() - } - private fun setSponsorBlockPrefs() { sponsorBlockPrefs.sponsorBlockEnabled = PreferenceHelper.getBoolean(requireContext(), "sb_enabled_key", true) From 787ed2acc49fed18be52a932b868ba2a74b726de Mon Sep 17 00:00:00 2001 From: Bnyro Date: Wed, 29 Jun 2022 09:29:23 +0200 Subject: [PATCH 30/32] added comments --- .../libretube/fragments/PlayerFragment.kt | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt b/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt index 635576ea1..aa5ac3170 100644 --- a/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt +++ b/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt @@ -482,21 +482,25 @@ class PlayerFragment : Fragment() { run() } + // the function is working recursively private fun initAutoPlay() { // save related streams for autoplay if (autoplay) { // if it's a playlist use the next video if (playlistId != null) { lateinit var playlist: Playlist // var for saving the list in + // runs only the first time when starting a video from a playlist if (playlistStreamIds.isEmpty()) { CoroutineScope(Dispatchers.IO).launch { // fetch the playlists videos playlist = RetrofitInstance.api.getPlaylist(playlistId!!) + // save the playlist urls in the array playlist.relatedStreams?.forEach { video -> playlistStreamIds += video.url?.replace("/watch?v=", "")!! } - // restart the function after videos are loaded + // save playlistNextPage for usage if video is not contained playlistNextPage = playlist.nextpage + // restart the function after videos are loaded initAutoPlay() } } @@ -510,16 +514,19 @@ class PlayerFragment : Fragment() { // fetch the next page of the playlist if the video isn't contained } else if (playlistNextPage != null) { CoroutineScope(Dispatchers.IO).launch { - Log.e(TAG, "fetching next autoplay page list") RetrofitInstance.api.getPlaylistNextPage(playlistId!!, playlistNextPage!!) + // append all the playlist item urls to the array playlist.relatedStreams?.forEach { video -> playlistStreamIds += video.url?.replace("/watch?v=", "")!! } - // restart the function after videos are loaded + // save playlistNextPage for usage if video is not contained playlistNextPage = playlist.nextpage + // restart the function after videos are loaded initAutoPlay() } } + // else: the video must be the last video of the playlist so nothing happens + // if it's not a playlist then use the next related video } else if (relatedStreams != null && relatedStreams!!.isNotEmpty()) { // save next video from related streams for autoplay @@ -528,10 +535,15 @@ class PlayerFragment : Fragment() { } } + // used for autoplay and skipping to next video private fun playNextVideo() { - // save the id of the next stream as videoId and load the next video - videoId = nextStreamId - fetchJsonAndInitPlayer(view!!) + // check whether there is a new video in the queue + // by making sure that the next and the current video aren't the same + if (videoId != nextStreamId) { + // save the id of the next stream as videoId and load the next video + videoId = nextStreamId + fetchJsonAndInitPlayer(view!!) + } } private fun setSponsorBlockPrefs() { From 19a46a19c0e4ace1609086c475510845be542436 Mon Sep 17 00:00:00 2001 From: Bnyro Date: Wed, 29 Jun 2022 16:07:58 +0200 Subject: [PATCH 31/32] animations --- .../libretube/fragments/PlayerFragment.kt | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt b/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt index aa5ac3170..05d306338 100644 --- a/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt +++ b/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt @@ -166,8 +166,9 @@ class PlayerFragment : Fragment() { hideKeyboard() setSponsorBlockPrefs() + createExoPlayer(view) initializeTransitionLayout(view) - fetchJsonAndInitPlayer(view) + playVideo(view) } private fun initializeTransitionLayout(view: View) { @@ -267,7 +268,7 @@ class PlayerFragment : Fragment() { val descLinLayout = view.findViewById(R.id.desc_linLayout) view.findViewById(R.id.player_title_layout).setOnClickListener { val arrowImageView = view.findViewById(R.id.player_description_arrow) - arrowImageView.animate().rotationBy(180F).setDuration(100).start() + arrowImageView.animate().rotationBy(180F).setDuration(250).start() descLinLayout.visibility = if (descLinLayout.isVisible) View.GONE else View.VISIBLE } @@ -384,7 +385,12 @@ class PlayerFragment : Fragment() { val isScreenOn = pm.isInteractive // pause player if screen off and setting enabled - if (exoPlayer != null && !isScreenOn && pausePlayerOnScreenOffEnabled) { + if ( + this::exoPlayer.isInitialized && + exoPlayer != null && + !isScreenOn && + pausePlayerOnScreenOffEnabled + ) { exoPlayer.pause() } super.onPause() @@ -428,7 +434,7 @@ class PlayerFragment : Fragment() { } } - private fun fetchJsonAndInitPlayer(view: View) { + private fun playVideo(view: View) { fun run() { lifecycleScope.launchWhenCreated { val response = try { @@ -456,7 +462,6 @@ class PlayerFragment : Fragment() { relatedStreams = response.relatedStreams runOnUiThread { - createExoPlayer(view) if (response.chapters != null) initializeChapters(response.chapters) // set media sources for the player setResolutionAndSubtitles(view, response) @@ -542,7 +547,7 @@ class PlayerFragment : Fragment() { if (videoId != nextStreamId) { // save the id of the next stream as videoId and load the next video videoId = nextStreamId - fetchJsonAndInitPlayer(view!!) + playVideo(view!!) } } @@ -571,7 +576,7 @@ class PlayerFragment : Fragment() { private fun fetchSponsorBlockSegments() { fun run() { - lifecycleScope.launchWhenCreated { + lifecycleScope.launch(Dispatchers.IO) { if (sponsorBlockPrefs.sponsorBlockEnabled) { val categories: ArrayList = arrayListOf() if (sponsorBlockPrefs.introEnabled) { @@ -607,14 +612,10 @@ class PlayerFragment : Fragment() { } catch (e: IOException) { println(e) Log.e(TAG, "IOException, you might not have internet connection") - Toast.makeText(context, R.string.unknown_error, Toast.LENGTH_SHORT) - .show() - return@launchWhenCreated + return@launch } catch (e: HttpException) { Log.e(TAG, "HttpException, unexpected response") - Toast.makeText(context, R.string.server_error, Toast.LENGTH_SHORT) - .show() - return@launchWhenCreated + return@launch } } } From 9320ddf57f9a9bf839cdc5d11a6ca71129729135 Mon Sep 17 00:00:00 2001 From: Bnyro Date: Wed, 29 Jun 2022 18:38:58 +0200 Subject: [PATCH 32/32] fix default theme color --- app/src/main/java/com/github/libretube/util/ThemeHelper.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/github/libretube/util/ThemeHelper.kt b/app/src/main/java/com/github/libretube/util/ThemeHelper.kt index ca9498685..3fb5cd385 100644 --- a/app/src/main/java/com/github/libretube/util/ThemeHelper.kt +++ b/app/src/main/java/com/github/libretube/util/ThemeHelper.kt @@ -17,7 +17,7 @@ object ThemeHelper { } private fun updateAccentColor(context: Context) { - when (PreferenceHelper.getString(context, "accent_color", "red")) { + when (PreferenceHelper.getString(context, "accent_color", "purple")) { "my" -> context.setTheme(R.style.Theme_MY) "red" -> context.setTheme(R.style.Theme_Red) "blue" -> context.setTheme(R.style.Theme_Blue)