diff --git a/app/src/main/java/com/github/libretube/constants/PreferenceKeys.kt b/app/src/main/java/com/github/libretube/constants/PreferenceKeys.kt index fd840c68f..9f0f69781 100644 --- a/app/src/main/java/com/github/libretube/constants/PreferenceKeys.kt +++ b/app/src/main/java/com/github/libretube/constants/PreferenceKeys.kt @@ -80,6 +80,7 @@ object PreferenceKeys { const val SB_SHOW_MARKERS = "sb_show_markers" const val LIMIT_HLS = "limit_hls" const val PROGRESSIVE_LOADING_INTERVAL_SIZE = "progressive_loading_interval" + const val ALTERNATIVE_PLAYER_LAYOUT = "alternative_player_layout" /** * Background mode diff --git a/app/src/main/java/com/github/libretube/services/BackgroundMode.kt b/app/src/main/java/com/github/libretube/services/BackgroundMode.kt index 0d26ffc45..ddf0249a5 100644 --- a/app/src/main/java/com/github/libretube/services/BackgroundMode.kt +++ b/app/src/main/java/com/github/libretube/services/BackgroundMode.kt @@ -307,16 +307,15 @@ class BackgroundMode : Service() { */ private fun fetchSponsorBlockSegments() { CoroutineScope(Dispatchers.IO).launch { - kotlin.runCatching { + runCatching { val categories = PlayerHelper.getSponsorBlockCategories() - if (categories.size > 0) { - segmentData = - RetrofitInstance.api.getSegments( - videoId, - ObjectMapper().writeValueAsString(categories) - ) - checkForSegments() - } + if (categories.isEmpty()) return@runCatching + segmentData = + RetrofitInstance.api.getSegments( + videoId, + ObjectMapper().writeValueAsString(categories) + ) + checkForSegments() } } } diff --git a/app/src/main/java/com/github/libretube/ui/adapters/VideosAdapter.kt b/app/src/main/java/com/github/libretube/ui/adapters/VideosAdapter.kt index c6bcba59c..a1651cbdd 100644 --- a/app/src/main/java/com/github/libretube/ui/adapters/VideosAdapter.kt +++ b/app/src/main/java/com/github/libretube/ui/adapters/VideosAdapter.kt @@ -17,6 +17,7 @@ import com.github.libretube.constants.PreferenceKeys import com.github.libretube.databinding.TrendingRowBinding import com.github.libretube.databinding.VideoRowBinding import com.github.libretube.extensions.formatShort +import com.github.libretube.extensions.toDp import com.github.libretube.extensions.toID import com.github.libretube.ui.extensions.setFormattedDuration import com.github.libretube.ui.extensions.setWatchProgressLength @@ -59,7 +60,7 @@ class VideosAdapter( override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VideosViewHolder { val layoutInflater = LayoutInflater.from(parent.context) return when { - forceMode == ForceMode.TRENDING -> VideosViewHolder(TrendingRowBinding.inflate(layoutInflater, parent, false)) + forceMode in listOf(ForceMode.TRENDING, ForceMode.RELATED) -> VideosViewHolder(TrendingRowBinding.inflate(layoutInflater, parent, false)) forceMode == ForceMode.CHANNEL -> VideosViewHolder(VideoRowBinding.inflate(layoutInflater, parent, false)) PreferenceHelper.getBoolean( PreferenceKeys.ALTERNATIVE_VIDEOS_LAYOUT, @@ -82,6 +83,12 @@ class VideosAdapter( // Trending layout holder.trendingRowBinding?.apply { + if (forceMode == ForceMode.RELATED) { + val params = root.layoutParams + params.width = (180).toDp(root.context.resources).toInt() + root.layoutParams = params + } + textViewTitle.text = video.title textViewChannel.text = video.uploaderName + TextUtils.SEPARATOR + @@ -160,7 +167,8 @@ class VideosAdapter( NONE, TRENDING, ROW, - CHANNEL + CHANNEL, + RELATED } fun getLayout(context: Context): LayoutManager { diff --git a/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt index df0195ffe..da5be8e6f 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt @@ -27,6 +27,7 @@ import android.widget.Toast import androidx.constraintlayout.motion.widget.MotionLayout import androidx.core.net.toUri import androidx.core.os.bundleOf +import androidx.core.view.isEmpty import androidx.core.view.isVisible import androidx.fragment.app.activityViewModels import androidx.lifecycle.Lifecycle @@ -38,6 +39,8 @@ import com.github.libretube.api.CronetHelper import com.github.libretube.api.RetrofitInstance import com.github.libretube.api.obj.ChapterSegment import com.github.libretube.api.obj.SegmentData +import com.github.libretube.api.obj.StreamItem +import com.github.libretube.api.obj.Streams import com.github.libretube.constants.IntentData import com.github.libretube.constants.PreferenceKeys import com.github.libretube.databinding.DoubleTapOverlayBinding @@ -120,7 +123,7 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions { private var videoId: String? = null private var playlistId: String? = null private var isLive = false - private lateinit var streams: com.github.libretube.api.obj.Streams + private lateinit var streams: Streams /** * for the transition @@ -133,7 +136,6 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions { * for the comments */ private var commentsAdapter: CommentsAdapter? = null - private var commentsLoaded: Boolean? = false private var nextPage: String? = null private var isLoading = true @@ -383,6 +385,12 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions { binding.commentsRecView.setItemViewCacheSize(20) binding.relatedRecView.layoutManager = VideosAdapter.getLayout(requireContext()) + + binding.alternativeTrendingRec.layoutManager = LinearLayoutManager( + context, + LinearLayoutManager.HORIZONTAL, + false + ) } private fun setFullscreen() { @@ -450,11 +458,14 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions { } private fun toggleComments() { - binding.commentsRecView.visibility = - if (binding.commentsRecView.isVisible) View.GONE else View.VISIBLE - binding.relatedRecView.visibility = - if (binding.relatedRecView.isVisible) View.GONE else View.VISIBLE - if (!commentsLoaded!!) fetchComments() + if (binding.commentsRecView.isVisible) { + binding.commentsRecView.visibility = View.GONE + binding.relatedRecView.visibility = View.VISIBLE + } else { + binding.commentsRecView.visibility = View.VISIBLE + binding.relatedRecView.visibility = View.GONE + if (binding.commentsRecView.isEmpty()) fetchComments() + } } override fun onStart() { @@ -610,15 +621,13 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions { // show the player notification initializePlayerNotification() if (PlayerHelper.sponsorBlockEnabled) fetchSponsorBlockSegments() - // show comments if related streams disabled - if (!PlayerHelper.relatedStreamsEnabled) toggleComments() + + // show comments if related streams are disabled or the alternative related streams layout is chosen + if (!PlayerHelper.relatedStreamsEnabled || PlayerHelper.alternativeVideoLayout) toggleComments() // add the video to the watch history if (PlayerHelper.watchHistoryEnabled) { - DatabaseHelper.addToWatchHistory( - videoId!!, - streams - ) + DatabaseHelper.addToWatchHistory(videoId!!, streams) } } } @@ -629,16 +638,15 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions { */ private fun fetchSponsorBlockSegments() { CoroutineScope(Dispatchers.IO).launch { - kotlin.runCatching { + runCatching { val categories = PlayerHelper.getSponsorBlockCategories() - if (categories.size > 0) { - segmentData = - RetrofitInstance.api.getSegments( - videoId!!, - ObjectMapper().writeValueAsString(categories) - ) - playerBinding.exoProgress.setSegments(segmentData.segments) - } + if (categories.isEmpty()) return@runCatching + segmentData = + RetrofitInstance.api.getSegments( + videoId!!, + ObjectMapper().writeValueAsString(categories) + ) + playerBinding.exoProgress.setSegments(segmentData.segments) } } } @@ -699,7 +707,6 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions { videoId = nextVideoId // forces the comments to reload for the new video - commentsLoaded = false binding.commentsRecView.adapter = null playVideo() } @@ -742,7 +749,7 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions { } @SuppressLint("SetTextI18n") - private fun initializePlayerView(response: com.github.libretube.api.obj.Streams) { + private fun initializePlayerView(response: Streams) { // initialize the player view actions binding.player.initialize( childFragmentManager, @@ -891,13 +898,7 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions { } } } - if (PlayerHelper.relatedStreamsEnabled) { - // only show related streams if enabled - binding.relatedRecView.adapter = VideosAdapter( - response.relatedStreams.orEmpty().toMutableList(), - childFragmentManager - ) - } + initializeRelatedVideos(response.relatedStreams) // set video description val description = response.description!! binding.playerDescription.text = @@ -960,6 +961,23 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions { } } + private fun initializeRelatedVideos(relatedStreams: List?) { + if (!PlayerHelper.relatedStreamsEnabled) return + + if (PlayerHelper.alternativeVideoLayout) { + binding.alternativeTrendingRec.adapter = VideosAdapter( + relatedStreams.orEmpty().toMutableList(), + childFragmentManager, + forceMode = VideosAdapter.Companion.ForceMode.RELATED + ) + } else { + binding.relatedRecView.adapter = VideosAdapter( + relatedStreams.orEmpty().toMutableList(), + childFragmentManager + ) + } + } + private fun initializeChapters() { if (chapters.isEmpty()) { binding.chaptersRecView.visibility = View.GONE @@ -1158,7 +1176,7 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions { } private fun setStreamSource( - streams: com.github.libretube.api.obj.Streams, + streams: Streams, videosNameArray: Array, videosUrlArray: Array ) { @@ -1269,7 +1287,6 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions { commentsAdapter = CommentsAdapter(videoId!!, commentsResponse.comments) binding.commentsRecView.adapter = commentsAdapter nextPage = commentsResponse.nextpage - commentsLoaded = true isLoading = false } } diff --git a/app/src/main/java/com/github/libretube/ui/preferences/AppearanceSettings.kt b/app/src/main/java/com/github/libretube/ui/preferences/AppearanceSettings.kt index 799a2d63d..67ec84f5c 100644 --- a/app/src/main/java/com/github/libretube/ui/preferences/AppearanceSettings.kt +++ b/app/src/main/java/com/github/libretube/ui/preferences/AppearanceSettings.kt @@ -1,10 +1,6 @@ package com.github.libretube.ui.preferences -import android.content.ActivityNotFoundException -import android.content.Intent import android.os.Bundle -import android.provider.Settings -import android.widget.Toast import androidx.preference.ListPreference import androidx.preference.Preference import androidx.preference.SwitchPreferenceCompat @@ -14,7 +10,6 @@ import com.github.libretube.ui.activities.SettingsActivity import com.github.libretube.ui.base.BasePreferenceFragment import com.github.libretube.ui.dialogs.NavBarOptionsDialog import com.github.libretube.ui.dialogs.RequireRestartDialog -import com.github.libretube.util.PreferenceHelper import com.github.libretube.util.ThemeHelper import com.google.android.material.color.DynamicColors @@ -69,27 +64,6 @@ class AppearanceSettings : BasePreferenceFragment() { true } - val systemCaptionStyle = - findPreference(PreferenceKeys.SYSTEM_CAPTION_STYLE) - val captionSettings = findPreference(PreferenceKeys.CAPTION_SETTINGS) - - captionSettings?.isVisible = - PreferenceHelper.getBoolean(PreferenceKeys.SYSTEM_CAPTION_STYLE, true) - systemCaptionStyle?.setOnPreferenceChangeListener { _, newValue -> - captionSettings?.isVisible = newValue as Boolean - true - } - - captionSettings?.setOnPreferenceClickListener { - try { - val captionSettingsIntent = Intent(Settings.ACTION_CAPTIONING_SETTINGS) - startActivity(captionSettingsIntent) - } catch (e: ActivityNotFoundException) { - Toast.makeText(activity, R.string.error, Toast.LENGTH_SHORT).show() - } - true - } - val legacySubscriptionView = findPreference(PreferenceKeys.LEGACY_SUBSCRIPTIONS) val legacySubscriptionColumns = diff --git a/app/src/main/java/com/github/libretube/ui/preferences/PlayerSettings.kt b/app/src/main/java/com/github/libretube/ui/preferences/PlayerSettings.kt index 557cb4c7e..75d4d9f40 100644 --- a/app/src/main/java/com/github/libretube/ui/preferences/PlayerSettings.kt +++ b/app/src/main/java/com/github/libretube/ui/preferences/PlayerSettings.kt @@ -1,6 +1,10 @@ package com.github.libretube.ui.preferences +import android.content.ActivityNotFoundException +import android.content.Intent import android.os.Bundle +import android.provider.Settings +import android.widget.Toast import androidx.preference.ListPreference import androidx.preference.Preference import androidx.preference.SwitchPreferenceCompat @@ -37,6 +41,27 @@ class PlayerSettings : BasePreferenceFragment() { val defaultSubtitle = findPreference(PreferenceKeys.DEFAULT_SUBTITLE) defaultSubtitle?.let { setupSubtitlePref(it) } + + val systemCaptionStyle = + findPreference(PreferenceKeys.SYSTEM_CAPTION_STYLE) + val captionSettings = findPreference(PreferenceKeys.CAPTION_SETTINGS) + + captionSettings?.isVisible = + PreferenceHelper.getBoolean(PreferenceKeys.SYSTEM_CAPTION_STYLE, true) + systemCaptionStyle?.setOnPreferenceChangeListener { _, newValue -> + captionSettings?.isVisible = newValue as Boolean + true + } + + captionSettings?.setOnPreferenceClickListener { + try { + val captionSettingsIntent = Intent(Settings.ACTION_CAPTIONING_SETTINGS) + startActivity(captionSettingsIntent) + } catch (e: ActivityNotFoundException) { + Toast.makeText(activity, R.string.error, Toast.LENGTH_SHORT).show() + } + true + } } private fun setupSubtitlePref(preference: ListPreference) { diff --git a/app/src/main/java/com/github/libretube/util/PlayerHelper.kt b/app/src/main/java/com/github/libretube/util/PlayerHelper.kt index 1821de4ae..b8d7281fc 100644 --- a/app/src/main/java/com/github/libretube/util/PlayerHelper.kt +++ b/app/src/main/java/com/github/libretube/util/PlayerHelper.kt @@ -287,6 +287,12 @@ object PlayerHelper { "fit" ) + val alternativeVideoLayout: Boolean + get() = PreferenceHelper.getBoolean( + PreferenceKeys.ALTERNATIVE_PLAYER_LAYOUT, + false + ) + fun getDefaultResolution(context: Context): String { return if (NetworkHelper.isNetworkMobile(context)) { PreferenceHelper.getString( diff --git a/app/src/main/res/layout/fragment_player.xml b/app/src/main/res/layout/fragment_player.xml index 10327cd90..775e8af8c 100644 --- a/app/src/main/res/layout/fragment_player.xml +++ b/app/src/main/res/layout/fragment_player.xml @@ -5,8 +5,7 @@ android:id="@+id/playerMotionLayout" android:layout_width="match_parent" android:layout_height="match_parent" - app:layoutDescription="@xml/player_scene" - tools:context=".ui.fragments.PlayerFragment"> + app:layoutDescription="@xml/player_scene"> + android:orientation="horizontal" + android:weightSum="5"> + style="@style/PlayerActionsLayout" + android:layout_weight="1"> + style="@style/PlayerActionsLayout" + android:layout_weight="1"> + style="@style/PlayerActionsLayout" + android:layout_weight="1"> + style="@style/PlayerActionsLayout" + android:layout_weight="1"> + style="@style/PlayerActionsLayout" + android:layout_weight="1"> @@ -300,6 +299,12 @@ app:cornerRadius="11dp" /> + + Playback speed App restart required This change requires the app to be restarted. Press \'Ok\' to restart now. - Navbar label visibility + Label visibility Always Selected Never @@ -365,6 +365,11 @@ End time Notification time Time span in which notifications are allowed to show. + Alternative trending layout + Order + Layout + Alternative player layout + Show the related videos as a row above the comments instead of below. Download Service diff --git a/app/src/main/res/xml/appearance_settings.xml b/app/src/main/res/xml/appearance_settings.xml index e4759d1f1..c89505e52 100644 --- a/app/src/main/res/xml/appearance_settings.xml +++ b/app/src/main/res/xml/appearance_settings.xml @@ -38,14 +38,14 @@ app:title="@string/app_icon" app:useSimpleSummaryProvider="true" /> + + + + - - - - + app:title="@string/navbar_order" /> - - - - - - - - - - - + + + + + + + + + + + + + + + + +