From e80b2f1e3951aacdb959cfdf43b5942a839c37aa Mon Sep 17 00:00:00 2001 From: Bnyro Date: Thu, 24 Nov 2022 16:20:47 +0100 Subject: [PATCH 01/76] use the new PiP transitions --- .../libretube/ui/fragments/PlayerFragment.kt | 40 +++++++++++-------- 1 file changed, 24 insertions(+), 16 deletions(-) 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 50fde12b9..6bfc30951 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 @@ -25,6 +25,7 @@ import android.view.MotionEvent import android.view.View import android.view.ViewGroup import android.widget.Toast +import androidx.annotation.RequiresApi import androidx.constraintlayout.motion.widget.MotionLayout import androidx.core.net.toUri import androidx.core.os.bundleOf @@ -158,7 +159,6 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions { /** * user preferences */ - private val token = PreferenceHelper.getToken() private var videoShownInExternalPlayer = false /** @@ -283,6 +283,8 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions { binding.playerMotionLayout.setTransitionDuration(300) binding.playerMotionLayout.transitionToStart() } + + if (usePiP()) (activity as MainActivity).setPictureInPictureParams(getPipParams()) } // actions that don't depend on video information @@ -521,13 +523,6 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions { // save the watch position if video isn't finished and option enabled private fun saveWatchPosition() { if (!PlayerHelper.watchPositionsEnabled) return - Log.e( - "watchpositions", - PreferenceHelper.getBoolean( - PreferenceKeys.WATCH_POSITION_TOGGLE, - true - ).toString() - ) val watchPosition = WatchPosition(videoId!!, exoPlayer.currentPosition) query { Database.watchPositionDao().insertAll(watchPosition) @@ -626,7 +621,7 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions { if (binding.playerMotionLayout.progress != 1.0f) { // show controllers when not in picture in picture mode - if (!(SDK_INT >= Build.VERSION_CODES.O && activity?.isInPictureInPictureMode!!)) { + if (!(usePiP() && activity?.isInPictureInPictureMode!!)) { exoPlayerView.useController = true } } @@ -645,6 +640,13 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions { } } + /** + * Detect whether PiP is supported and enabled + */ + private fun usePiP(): Boolean { + return SDK_INT >= Build.VERSION_CODES.O && PlayerHelper.pipEnabled + } + /** * fetch the segments for SponsorBlock */ @@ -858,7 +860,7 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions { } // listen for the stop button in the notification - if (playbackState == PlaybackState.STATE_STOPPED && SDK_INT >= Build.VERSION_CODES.O) { + if (playbackState == PlaybackState.STATE_STOPPED && usePiP()) { // finish PiP by finishing the activity if (activity?.isInPictureInPictureMode!!) activity?.finish() } @@ -1421,15 +1423,21 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions { } fun onUserLeaveHint() { - if (SDK_INT >= Build.VERSION_CODES.O && shouldStartPiP()) { - activity?.enterPictureInPictureMode( - PictureInPictureParams.Builder() - .setActions(emptyList()) - .build() - ) + if (usePiP() && shouldStartPiP()) { + activity?.enterPictureInPictureMode(getPipParams()) } } + @RequiresApi(Build.VERSION_CODES.O) + fun getPipParams(): PictureInPictureParams = PictureInPictureParams.Builder() + .setActions(emptyList()) + .apply { + if (SDK_INT >= Build.VERSION_CODES.S) { + setAutoEnterEnabled(true) + } + } + .build() + private fun shouldStartPiP(): Boolean { if (!PlayerHelper.pipEnabled || exoPlayer.playbackState == PlaybackState.STATE_PAUSED || From 0aa783abc54c764bd0288d092eb4aa40100cf68d Mon Sep 17 00:00:00 2001 From: Bnyro Date: Thu, 24 Nov 2022 16:31:02 +0100 Subject: [PATCH 02/76] pip from mini player --- .../libretube/ui/fragments/PlayerFragment.kt | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) 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 6bfc30951..d908a43c7 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 @@ -7,7 +7,6 @@ import android.content.Context import android.content.Intent import android.content.pm.ActivityInfo import android.content.res.Configuration -import android.graphics.Rect import android.media.session.PlaybackState import android.net.Uri import android.os.Build @@ -1390,13 +1389,18 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions { override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean) { super.onPictureInPictureModeChanged(isInPictureInPictureMode) if (isInPictureInPictureMode) { - // set portrait mode - unsetFullscreen() - // hide and disable exoPlayer controls exoPlayerView.hideController() exoPlayerView.useController = false + // set portrait mode + unsetFullscreen() + + if (viewModel.isMiniPlayerVisible.value == true) { + binding.playerMotionLayout.transitionToStart() + viewModel.isMiniPlayerVisible.value = false + } + with(binding.playerMotionLayout) { getConstraintSet(R.id.start).constrainHeight(R.id.player, -1) enableTransition(R.id.yt_transition, false) @@ -1446,15 +1450,10 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions { return false } - val bounds = Rect() - binding.playerScrollView.getHitRect(bounds) - val backgroundModeRunning = isServiceRunning(requireContext(), BackgroundMode::class.java) - return ( - binding.playerScrollView.getLocalVisibleRect(bounds) || - viewModel.isFullscreen.value == true - ) && (exoPlayer.isPlaying || !backgroundModeRunning) + return viewModel.isFullscreen.value == true && + (exoPlayer.isPlaying || !backgroundModeRunning) } private fun isServiceRunning(context: Context, serviceClass: Class<*>): Boolean { From 66a3d6563d2d113637ab814d8024e2b065c4f168 Mon Sep 17 00:00:00 2001 From: Bnyro Date: Thu, 24 Nov 2022 16:49:38 +0100 Subject: [PATCH 03/76] fix the next video button at the player --- .../libretube/ui/extensions/SetInvisible.kt | 7 +++++++ .../libretube/ui/fragments/PlayerFragment.kt | 15 +++++---------- .../com/github/libretube/util/PlayingQueue.kt | 9 ++++++--- 3 files changed, 18 insertions(+), 13 deletions(-) create mode 100644 app/src/main/java/com/github/libretube/ui/extensions/SetInvisible.kt diff --git a/app/src/main/java/com/github/libretube/ui/extensions/SetInvisible.kt b/app/src/main/java/com/github/libretube/ui/extensions/SetInvisible.kt new file mode 100644 index 000000000..b5cb0f836 --- /dev/null +++ b/app/src/main/java/com/github/libretube/ui/extensions/SetInvisible.kt @@ -0,0 +1,7 @@ +package com.github.libretube.ui.extensions + +import android.view.View + +fun View.setInvisible(value: Boolean) { + this.visibility = if (value) View.INVISIBLE else View.VISIBLE +} 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 d908a43c7..5f64086b5 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 @@ -72,6 +72,7 @@ import com.github.libretube.ui.base.BaseFragment import com.github.libretube.ui.dialogs.AddToPlaylistDialog import com.github.libretube.ui.dialogs.DownloadDialog import com.github.libretube.ui.dialogs.ShareDialog +import com.github.libretube.ui.extensions.setInvisible import com.github.libretube.ui.extensions.setupSubscriptionButton import com.github.libretube.ui.interfaces.OnlinePlayerOptions import com.github.libretube.ui.models.PlayerViewModel @@ -953,19 +954,13 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions { } // next and previous buttons - playerBinding.skipPrev.visibility = if ( - PlayerHelper.skipButtonsEnabled && PlayingQueue.hasPrev() - ) { - View.VISIBLE - } else { - View.INVISIBLE + if (PlayerHelper.skipButtonsEnabled) { + playerBinding.skipPrev.setInvisible(!PlayingQueue.hasPrev()) + playerBinding.skipNext.setInvisible(!PlayingQueue.hasNext()) } - playerBinding.skipNext.visibility = - if (PlayerHelper.skipButtonsEnabled) View.VISIBLE else View.INVISIBLE playerBinding.skipPrev.setOnClickListener { - videoId = PlayingQueue.getPrev() - playVideo() + playNextVideo(PlayingQueue.getPrev()) } playerBinding.skipNext.setOnClickListener { diff --git a/app/src/main/java/com/github/libretube/util/PlayingQueue.kt b/app/src/main/java/com/github/libretube/util/PlayingQueue.kt index 7f2cfdaf1..e6171bb5b 100644 --- a/app/src/main/java/com/github/libretube/util/PlayingQueue.kt +++ b/app/src/main/java/com/github/libretube/util/PlayingQueue.kt @@ -45,12 +45,15 @@ object PlayingQueue { } fun getPrev(): String? { - val index = queue.indexOf(currentStream) - return if (index > 0) queue[index - 1].url?.toID() else null + return if (currentIndex() > 0) queue[currentIndex() - 1].url?.toID() else null } fun hasPrev(): Boolean { - return queue.indexOf(currentStream) > 0 + return currentIndex() > 0 + } + + fun hasNext(): Boolean { + return currentIndex() + 1 < size() } fun updateCurrent(streamItem: StreamItem) { From 975930625fd7b44f1f342e74cbc6ce616ef93256 Mon Sep 17 00:00:00 2001 From: Bnyro Date: Thu, 24 Nov 2022 16:58:39 +0100 Subject: [PATCH 04/76] bind the recview padding of playlists and watch history to the mini player visibility --- .../libretube/ui/fragments/PlaylistFragment.kt | 12 ++++++++++++ .../libretube/ui/fragments/WatchHistoryFragment.kt | 12 ++++++++++++ app/src/main/res/layout/fragment_playlist.xml | 3 +-- app/src/main/res/layout/fragment_watch_history.xml | 1 - 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/github/libretube/ui/fragments/PlaylistFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/PlaylistFragment.kt index 168926a41..8205dafdc 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/PlaylistFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/PlaylistFragment.kt @@ -6,6 +6,8 @@ import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.core.view.updatePadding +import androidx.fragment.app.activityViewModels import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager @@ -21,10 +23,12 @@ import com.github.libretube.enums.PlaylistType import com.github.libretube.extensions.TAG import com.github.libretube.extensions.awaitQuery import com.github.libretube.extensions.query +import com.github.libretube.extensions.toDp import com.github.libretube.extensions.toID import com.github.libretube.ui.adapters.PlaylistAdapter import com.github.libretube.ui.base.BaseFragment import com.github.libretube.ui.extensions.serializable +import com.github.libretube.ui.models.PlayerViewModel import com.github.libretube.ui.sheets.PlaylistOptionsBottomSheet import com.github.libretube.util.ImageHelper import com.github.libretube.util.NavigationHelper @@ -43,6 +47,8 @@ class PlaylistFragment : BaseFragment() { private var isLoading = true private var isBookmarked = false + private val playerViewModel: PlayerViewModel by activityViewModels() + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) arguments?.let { @@ -73,6 +79,12 @@ class PlaylistFragment : BaseFragment() { } updateBookmarkRes() + playerViewModel.isMiniPlayerVisible.observe(viewLifecycleOwner) { + binding.playlistRecView.updatePadding( + bottom = if (it) (64).toDp(resources).toInt() else 0 + ) + } + fetchPlaylist() } diff --git a/app/src/main/java/com/github/libretube/ui/fragments/WatchHistoryFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/WatchHistoryFragment.kt index a9ae97a9a..69a06d390 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/WatchHistoryFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/WatchHistoryFragment.kt @@ -4,19 +4,25 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.core.view.updatePadding +import androidx.fragment.app.activityViewModels import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.github.libretube.databinding.FragmentWatchHistoryBinding import com.github.libretube.db.DatabaseHolder.Companion.Database import com.github.libretube.extensions.awaitQuery +import com.github.libretube.extensions.toDp import com.github.libretube.ui.adapters.WatchHistoryAdapter import com.github.libretube.ui.base.BaseFragment +import com.github.libretube.ui.models.PlayerViewModel import com.github.libretube.util.ProxyHelper class WatchHistoryFragment : BaseFragment() { private lateinit var binding: FragmentWatchHistoryBinding + private val playerViewModel: PlayerViewModel by activityViewModels() + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -29,6 +35,12 @@ class WatchHistoryFragment : BaseFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + playerViewModel.isMiniPlayerVisible.observe(viewLifecycleOwner) { + binding.watchHistoryRecView.updatePadding( + bottom = if (it) (64).toDp(resources).toInt() else 0 + ) + } + val watchHistory = awaitQuery { Database.watchHistoryDao().getAll() } diff --git a/app/src/main/res/layout/fragment_playlist.xml b/app/src/main/res/layout/fragment_playlist.xml index 1cdbeebc4..649896e25 100644 --- a/app/src/main/res/layout/fragment_playlist.xml +++ b/app/src/main/res/layout/fragment_playlist.xml @@ -109,8 +109,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:clipToPadding="false" - android:nestedScrollingEnabled="false" - android:paddingBottom="64dp" /> + android:nestedScrollingEnabled="false" /> diff --git a/app/src/main/res/layout/fragment_watch_history.xml b/app/src/main/res/layout/fragment_watch_history.xml index f8328f484..2cb061f89 100644 --- a/app/src/main/res/layout/fragment_watch_history.xml +++ b/app/src/main/res/layout/fragment_watch_history.xml @@ -32,7 +32,6 @@ android:layout_height="wrap_content" android:clipToPadding="false" android:nestedScrollingEnabled="false" - android:paddingBottom="64dp" android:visibility="gone" /> \ No newline at end of file From 77be9424fc3e321be23d8cbc942a2edb641d631f Mon Sep 17 00:00:00 2001 From: Bnyro Date: Thu, 24 Nov 2022 17:38:14 +0100 Subject: [PATCH 05/76] add option to set default start tab --- .../libretube/constants/PreferenceKeys.kt | 1 + .../ui/adapters/NavBarOptionsAdapter.kt | 26 +++++++++++++++++-- .../ui/dialogs/NavBarOptionsDialog.kt | 3 ++- .../com/github/libretube/util/NavBarHelper.kt | 17 +++++++++++- .../github/libretube/util/PreferenceHelper.kt | 4 +++ .../main/res/drawable/ic_home_outlined.xml | 10 +++++++ app/src/main/res/layout/nav_options_item.xml | 8 ++++++ app/src/main/res/values/strings.xml | 2 ++ 8 files changed, 67 insertions(+), 4 deletions(-) create mode 100644 app/src/main/res/drawable/ic_home_outlined.xml 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 e87a00604..b28968f45 100644 --- a/app/src/main/java/com/github/libretube/constants/PreferenceKeys.kt +++ b/app/src/main/java/com/github/libretube/constants/PreferenceKeys.kt @@ -22,6 +22,7 @@ object PreferenceKeys { const val BREAK_REMINDER = "break_reminder" const val SAVE_FEED = "save_feed" const val NAVBAR_ITEMS = "navbar_items" + const val START_FRAGMENT = "start_fragment" /** * Appearance diff --git a/app/src/main/java/com/github/libretube/ui/adapters/NavBarOptionsAdapter.kt b/app/src/main/java/com/github/libretube/ui/adapters/NavBarOptionsAdapter.kt index cdb366228..a58ad475d 100644 --- a/app/src/main/java/com/github/libretube/ui/adapters/NavBarOptionsAdapter.kt +++ b/app/src/main/java/com/github/libretube/ui/adapters/NavBarOptionsAdapter.kt @@ -10,7 +10,8 @@ import com.github.libretube.databinding.NavOptionsItemBinding import com.github.libretube.ui.viewholders.NavBarOptionsViewHolder class NavBarOptionsAdapter( - val items: MutableList + val items: MutableList, + var selectedHomeTabId: Int ) : RecyclerView.Adapter() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NavBarOptionsViewHolder { @@ -31,7 +32,28 @@ class NavBarOptionsAdapter( holder.binding.apply { title.text = item.title checkbox.isChecked = item.isVisible + home.setImageResource( + if (item.itemId == selectedHomeTabId) R.drawable.ic_home else R.drawable.ic_home_outlined + ) + home.setOnClickListener { + if (selectedHomeTabId == item.itemId) { + return@setOnClickListener + } + if (!item.isVisible) { + Toast.makeText(root.context, R.string.not_enabled, Toast.LENGTH_SHORT).show() + return@setOnClickListener + } + val oldSelection = items.indexOfFirst { it.itemId == selectedHomeTabId } + selectedHomeTabId = item.itemId + listOf(position, oldSelection).forEach { + notifyItemChanged(it) + } + } checkbox.setOnClickListener { + if (item.itemId == selectedHomeTabId) { + Toast.makeText(root.context, R.string.select_other_start_tab, Toast.LENGTH_SHORT).show() + return@setOnClickListener + } if (!checkbox.isChecked && getVisibleItemsCount() < 2) { checkbox.isChecked = true Toast.makeText( @@ -41,7 +63,7 @@ class NavBarOptionsAdapter( ).show() return@setOnClickListener } - items[position].isVisible = checkbox.isChecked + item.isVisible = checkbox.isChecked } } } diff --git a/app/src/main/java/com/github/libretube/ui/dialogs/NavBarOptionsDialog.kt b/app/src/main/java/com/github/libretube/ui/dialogs/NavBarOptionsDialog.kt index 391766a6d..686ac218e 100644 --- a/app/src/main/java/com/github/libretube/ui/dialogs/NavBarOptionsDialog.kt +++ b/app/src/main/java/com/github/libretube/ui/dialogs/NavBarOptionsDialog.kt @@ -20,7 +20,7 @@ class NavBarOptionsDialog : DialogFragment() { val options = NavBarHelper.getNavBarItems(requireContext()) - val adapter = NavBarOptionsAdapter(options.toMutableList()) + val adapter = NavBarOptionsAdapter(options.toMutableList(), NavBarHelper.getStartFragmentId(requireContext())) val itemTouchCallback = object : ItemTouchHelper.Callback() { override fun getMovementFlags( @@ -63,6 +63,7 @@ class NavBarOptionsDialog : DialogFragment() { .setView(binding.root) .setPositiveButton(R.string.okay) { _, _ -> NavBarHelper.setNavBarItems(adapter.items, requireContext()) + NavBarHelper.setStartFragment(requireContext(), adapter.selectedHomeTabId) RequireRestartDialog() .show(requireParentFragment().childFragmentManager, null) } diff --git a/app/src/main/java/com/github/libretube/util/NavBarHelper.kt b/app/src/main/java/com/github/libretube/util/NavBarHelper.kt index b1dc00330..f95a2f5fe 100644 --- a/app/src/main/java/com/github/libretube/util/NavBarHelper.kt +++ b/app/src/main/java/com/github/libretube/util/NavBarHelper.kt @@ -106,6 +106,21 @@ object NavBarHelper { ).icon = menuItem.icon } } - return navBarItems.first { it.isVisible }.itemId + return getStartFragmentId(bottomNav.context) + } + + fun getStartFragmentId(context: Context): Int { + val pref = PreferenceHelper.getInt(PreferenceKeys.START_FRAGMENT, Int.MAX_VALUE) + val defaultNavItems = getDefaultNavBarItems(context) + return if (pref == Int.MAX_VALUE) { + getNavBarItems(context).first { it.isVisible }.itemId + } else { + defaultNavItems.get(pref).itemId + } + } + + fun setStartFragment(context: Context, itemId: Int) { + val index = getDefaultNavBarItems(context).indexOfFirst { it.itemId == itemId } + PreferenceHelper.putInt(PreferenceKeys.START_FRAGMENT, index) } } diff --git a/app/src/main/java/com/github/libretube/util/PreferenceHelper.kt b/app/src/main/java/com/github/libretube/util/PreferenceHelper.kt index e9ac81e0d..2d5a81967 100644 --- a/app/src/main/java/com/github/libretube/util/PreferenceHelper.kt +++ b/app/src/main/java/com/github/libretube/util/PreferenceHelper.kt @@ -37,6 +37,10 @@ object PreferenceHelper { editor.putBoolean(key, value).commit() } + fun putInt(key: String, value: Int) { + editor.putInt(key, value).commit() + } + fun getString(key: String?, defValue: String): String { return settings.getString(key, defValue) ?: defValue } diff --git a/app/src/main/res/drawable/ic_home_outlined.xml b/app/src/main/res/drawable/ic_home_outlined.xml new file mode 100644 index 000000000..e1b9248ab --- /dev/null +++ b/app/src/main/res/drawable/ic_home_outlined.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/layout/nav_options_item.xml b/app/src/main/res/layout/nav_options_item.xml index b0acb177a..a20ceacab 100644 --- a/app/src/main/res/layout/nav_options_item.xml +++ b/app/src/main/res/layout/nav_options_item.xml @@ -11,6 +11,14 @@ android:paddingEnd="0dp" tools:gravity="start|center_vertical"> + + No bookmarks yet! Insert related videos Local playlists + Menu item not enabled! + Please select an other start tab first! Download Service From ffbff0c23c30b2664a033fd621749e77627ef523 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Allan=20Nordh=C3=B8y?= Date: Wed, 23 Nov 2022 18:10:58 +0000 Subject: [PATCH 06/76] =?UTF-8?q?Translated=20using=20Weblate=20(Norwegian?= =?UTF-8?q?=20Bokm=C3=A5l)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 83.9% (330 of 393 strings) Translation: LibreTube/LibreTube Translate-URL: https://hosted.weblate.org/projects/libretube/libretube/nb_NO/ --- app/src/main/res/values-nb-rNO/strings.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/res/values-nb-rNO/strings.xml b/app/src/main/res/values-nb-rNO/strings.xml index 26b05f455..5d00010e2 100644 --- a/app/src/main/res/values-nb-rNO/strings.xml +++ b/app/src/main/res/values-nb-rNO/strings.xml @@ -387,4 +387,10 @@ På vei opp Alternativ avspillertilpasning Framhevet + Lokale spillelister + Legg til relaterte videoer + Bokmerke + Bokmerke + Tøm bokmerker + Ingen bokmerker enda. \ No newline at end of file From 7a67d626379696ba1c9963e342edd7817f0c70b3 Mon Sep 17 00:00:00 2001 From: Rex_sa Date: Wed, 23 Nov 2022 19:29:16 +0000 Subject: [PATCH 07/76] Translated using Weblate (Arabic) Currently translated at 100.0% (393 of 393 strings) Translation: LibreTube/LibreTube Translate-URL: https://hosted.weblate.org/projects/libretube/libretube/ar/ --- app/src/main/res/values-ar/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index ac5293c28..727234139 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -391,4 +391,6 @@ الاشاره المرجعيه مسح الإشارات المرجعية لا توجد إشارات مرجعية حتى الآن! + قوائم التشغيل المحلية + إدراج مقاطع فيديو ذات صلة \ No newline at end of file From 877a6e7d252969c0912ae95c27fc82e8f8d6fe16 Mon Sep 17 00:00:00 2001 From: Michael Weinberger Date: Thu, 24 Nov 2022 01:31:26 +0000 Subject: [PATCH 08/76] Translated using Weblate (German) Currently translated at 100.0% (393 of 393 strings) Translation: LibreTube/LibreTube Translate-URL: https://hosted.weblate.org/projects/libretube/libretube/de/ --- app/src/main/res/values-de/strings.xml | 84 +++++++++++++++++++------- 1 file changed, 63 insertions(+), 21 deletions(-) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index ab762826d..f1ce82221 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -23,7 +23,7 @@ Abonniert Abonniere erst einige Kanäle. Video kann nicht heruntergeladen werden. - Eine weitere Datenübertragung ist bereits im Gange, bitte warten Sie, bis sie beendet ist. + Ein weiterer Download läuft bereits, bitte warte, bis er beendet ist. Herunterladen fehlgeschlagen. Konnte nicht in VLC geöffnet werden, möglicherweise ist es nicht installiert. Design @@ -65,7 +65,7 @@ System Kommentare Erneut versuchen - Stelle zunächst eine Verbindung zum Internet her. + Stelle zuerst eine Verbindung zum Internet her. %1$s Videos Einstellungen Standort @@ -128,7 +128,7 @@ Der Ort, an dem deine heruntergeladenen Medien gespeichert werden. Spenden Auf neue Version überprüfen - Klicke hier, um herauszufinden, ob die Anwendung auf dem neuesten Stand ist. + Nach Update suchen Es läuft die neueste Version. Du verwendest die neueste Version. Wiedergabegeschwindigkeit @@ -152,9 +152,9 @@ Instanzname URL zur Instanz-API Instanz hinzufügen - Geben Sie den Namen und die API URL ein. + Gebe den Namen und die API-URL ein. Benutzerdefinierte Instanzen löschen - Bitte geben Sie eine gültige URL ein + Bitte eine funktionierende URL angeben Piped, Anmeldung & Abonnements Hinzufügen… Musik: Nicht-musikalische Sektion @@ -166,10 +166,10 @@ Nur zur Verwendung in Musikvideos. Es sollte Teile des Videos abdecken, die nicht Teil der offiziellen Abmischungen sind. Am Ende sollte das Video der Spotify- oder einer anderen abgemischten Version so nahe wie möglich kommen oder das Sprechen und andere Ablenkungen reduzieren. Videoformat für Player Version %1$s - Lernen Sie das LibreTube-Team kennen und erfahren Sie, wie das alles abläuft. + Lerne das LibreTube-Team kennen und erfahre, wie alles abläuft. Für Segmente, die auf kommende Inhalte in diesem oder zukünftigen Videos der Serie hinweisen, aber keine zusätzlichen Informationen liefern. Wenn es Clips enthält, die nur hier erscheinen, ist dies sehr wahrscheinlich die falsche Kategorie. Automatische Wiedergabe - Zeigen Sie ähnliche Streams neben dem, was Sie sehen. + Zeige ähnliche Streams neben dem, was du siehst. Verwandte Inhalte Kein Ton Kein Video @@ -194,16 +194,16 @@ Das nächste Video automatisch abspielen, wenn das aktuelle beendet ist. Position merken Authentifizierungsinstanz - Verwenden Sie für authentifizierte Anrufe eine andere Instanz. - Wählen Sie eine Autorisierungsinstanz + Verwende für authentifizierte Aufrufe eine andere Instanz. + Wähle eine Authentifizierungsinstanz GitHub - Auto - Bitte stellen Sie eine Internetverbindung her, indem Sie WLAN oder mobile Daten aktivieren. + HLS + Bitte stelle eine Internetverbindung her, indem du WLAN oder mobile Daten aktivierst. Öffnen… Kapitel Wiedergabegeschwindigkeit Neustart der App erforderlich - Diese Änderung erfordert einen Neustart der App. Drücken Sie \'Ok\', um jetzt neu zu starten. + Starte die App neu, um die Änderungen anzuwenden. Audio und Video Ausrichtung im Vollbildmodus Video-Seitenverhältnis @@ -219,13 +219,13 @@ Verlorenes Vermächtnis Füllungstangente/Witze Keine - Wollen Sie die Anwendung jetzt aktualisieren\? + Möchtest du die neue LibreTube-Version jetzt installieren\? Für tangentiale Szenen, die nur als Füllmaterial oder für den Humor hinzugefügt wurden und für das Verständnis des Hauptinhalts des Videos nicht erforderlich sind. Ausgewählt Automatischer Vollbildmodus Nie Vollbild-Modus des Players wird aktiviert, wenn das Gerät gedreht wird. - Kein externer Player gefunden. Bitte stellen Sie sicher, dass Sie einen installiert haben. + Kein externer Player gefunden. Stelle bitte sicher, dass du einen installiert hast. Modisches Feuer Trendige Fackel Albern geformt @@ -245,7 +245,7 @@ Beste Qualität Video-Vorschau Von letzter Position weiter abspielen - Navigationsleistensichtbarkeit + Label-Sichtbarkeit Angesehene Videos lokal speichern Wiedergabe- und Suchverlauf Untertitel @@ -258,11 +258,11 @@ System Untertitel Audioformat für Player Keine Ergebnisse. - In Zwischenablage kopiert! 👌 + In Zwischenablage kopiert Untertitelsprache - Erhalten Sie Benachrichtigungen, wenn ihre Abonnierten Kanäle Videos veröffentlichen. + Erhalte Benachrichtigungen, wenn abonnierte Kanäle Videos veröffentlichen. Benachrichtigungen bei neuen Videos - Sind Sie sicher\? Dies kann nicht rückgängig gemacht werden! + Bist du sicher\? Dies kann nicht rückgängig gemacht werden! Untertitel %1$s haben neue Videos hochgeladen… Es sind %1$s neue Videos verfügbar @@ -285,7 +285,7 @@ Kanalnamen (Z-A) Fehler :( Mobiles Internet - Kopiert! + Kopiert Pausenerinnerung Geringste Aufrufe Internetverbindung erforderlich @@ -303,7 +303,7 @@ Benachrichtigungs-dienst Überspringungs Knöpfe Maximale Verlaufsgröße - Du guckst schon seit %1$s Minuten Videos, gönn dir \'ne Pause! + Du hast bereits %1$s Minuten in der App verbracht, Zeit für eine Pause. Ausfüllen Qualität und Format Aktuelles Video @@ -323,7 +323,7 @@ Mit Zeitstempel teilen Abos exportieren HLS auf 1080p beschränken - Laden Sie den Abo-Feed im Hintergrund und verhindern Sie, dass er automatisch aktualisiert wird. + Lade den Abo-Feed im Hintergrund und verhindere, dass er automatisch aktualisiert wird. Aus Downloads löschen Aufrufe Knöpfe um zum nächsten oder letzten Video zu kommen anzeigen. @@ -351,4 +351,46 @@ Wiedergabelistenname (umgekehrt) Kürzlich aktualisiert Kürzlich aktualisiert (umgekehrt) + Playlist dupliziert + Deabonnieren bestätigen + Markiere die Abschnitte auf der Zeitleiste. + Standard hell + Zeige Bestätigungsdialog vor dem Deabonnieren. + Bist du sicher, dass du %1$s deabbonieren möchtest\? + Lokale Playlists + Alles abspielen + Warteschlange wird abgespielt + Warteschlange + Zeit + Startzeit + Endzeit + Benachrichtigungszeit + Zeitspanne, in der Benachrichtigungen angezeigt werden dürfen. + Alternatives Trending-Layout + Anordnung + Layout + Alternatives Player-Layout + Zeige verwandte Videos in einer Reihe über den Kommentaren an, anstatt darunter. + Zur Playlist hinzugefügt + Markierungen + Tonspur + Standard + Livestreams + Alternatives Video-Layout + Nicht unterstütztes Dateiformat! + Verwende HLS + Verwende HLS statt DASH (wird langsamer sein, nicht empfohlen) + Automatisch + Auf Laufzeit beschränken + Öffne Warteschlange aus Benachrichtigung + Mehr anzeigen + Zeitstempel (Sekunden) + Trends + Vorgestellt + Was jetzt angesagt ist + Verwandte Videos einfügen + Lesezeichen + Lesezeichen + Lesezeichen löschen + Noch keine Lesezeichen vorhanden! \ No newline at end of file From 03739cc70055fa73abbe5eb93b3f9d8831ea63fb Mon Sep 17 00:00:00 2001 From: Mario Ruiz Date: Wed, 23 Nov 2022 18:43:56 +0000 Subject: [PATCH 09/76] Translated using Weblate (Spanish) Currently translated at 100.0% (393 of 393 strings) Translation: LibreTube/LibreTube Translate-URL: https://hosted.weblate.org/projects/libretube/libretube/es/ --- app/src/main/res/values-es/strings.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 62964e200..c9e94c6d8 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -266,7 +266,7 @@ Mejor Peor calidad Idioma subtítulo - Norificaciones para nuevos directos + Notificaciones para nuevos directos Comprobando todo … %1$s nuevo directo disponible Novedades @@ -392,4 +392,5 @@ ¡Aún no hay marcadores! Borrar marcadores Insertar videos relacionados + Listas de reproducción locales \ No newline at end of file From 9ae1b26aff4730414487047d531beda6181514ee Mon Sep 17 00:00:00 2001 From: Linerly Date: Wed, 23 Nov 2022 23:20:06 +0000 Subject: [PATCH 10/76] Translated using Weblate (Indonesian) Currently translated at 100.0% (393 of 393 strings) Translation: LibreTube/LibreTube Translate-URL: https://hosted.weblate.org/projects/libretube/libretube/id/ --- app/src/main/res/values-in/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index 6098846b9..dc78cc480 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -392,4 +392,5 @@ Hapus markah Belum ada markah! Masukkan video terkait + Daftar putar lokal \ No newline at end of file From 0616e4abbc5d4f6ddc6281ece6dcf2c7e8e59902 Mon Sep 17 00:00:00 2001 From: Fjuro Date: Wed, 23 Nov 2022 20:40:07 +0000 Subject: [PATCH 11/76] Translated using Weblate (Czech) Currently translated at 100.0% (393 of 393 strings) Translation: LibreTube/LibreTube Translate-URL: https://hosted.weblate.org/projects/libretube/libretube/cs/ --- app/src/main/res/values-cs/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 7b85f697c..56e57105e 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -392,4 +392,5 @@ Vymazat záložky Zatím žádné záložky! Vložit související videa + Místní playlisty \ No newline at end of file From c4f580b17763526e66867ac59d8a038172d0ed62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81cs=20Zolt=C3=A1n?= Date: Thu, 24 Nov 2022 06:38:45 +0000 Subject: [PATCH 12/76] Translated using Weblate (Hungarian) Currently translated at 100.0% (393 of 393 strings) Translation: LibreTube/LibreTube Translate-URL: https://hosted.weblate.org/projects/libretube/libretube/hu/ --- app/src/main/res/values-hu/strings.xml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index ce739c19f..4acddb87f 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -225,7 +225,7 @@ Töltse be a nevet és az API URL-t. Maximális másodpercnyi videó a puffereléshez. Léptetés időköze - Ehhez a módosításhoz az alkalmazás újraindítása szükséges. Nyomja meg az \'OK\' gombot az újraindításhoz. + Indítsa újra az alkalmazást a változtatások használatához. Tiszta fehér/fekete téma Adattakarékos üzemmód Videó előnézet @@ -390,4 +390,7 @@ Könyvjelző Nincsenek még könyvjelzők! Könyvjelzők törlése + Helyi lejátszási listák + Kapcsolódó videók beillesztése + Felkapottak \ No newline at end of file From 83a892dbf322dc2f1a4c607925f14a2a78abeb6a Mon Sep 17 00:00:00 2001 From: Daviteusz Date: Wed, 23 Nov 2022 17:27:03 +0000 Subject: [PATCH 13/76] Translated using Weblate (Polish) Currently translated at 100.0% (393 of 393 strings) Translation: LibreTube/LibreTube Translate-URL: https://hosted.weblate.org/projects/libretube/libretube/pl/ --- app/src/main/res/values-pl/strings.xml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index e9a5ff8ac..76e40a75a 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -183,7 +183,7 @@ Przywróć kopię zapasową Naciśnij „OK”, aby zastosować zmiany. Aplikacja zostanie zrestartowana. Powiadomienia - Nowe treści + Przypomnij o nowych treściach Informuj o nowych treściach od twórców, których śledzisz. Czy na pewno\? Tego nie da się cofnąć! Wymagany restart aplikacji @@ -210,11 +210,11 @@ Pobieranie ukończone Przyciski pomijania Pokaż przyciski umożliwiające przejście do następnego lub poprzedniego filmu. - Zapamiętane pozycje - Kontynuuj odtwarzanie od ostatniej pozycji + Zapamiętaj pozycje + Kontynuuj odtwarzanie od ostatnio zapamiętanej pozycji HLS GitHub - Pozioma + Wymuś tryb poziomy Dodaj do kolejki Różne Stos kart @@ -236,7 +236,7 @@ Wybierz instancję autoryzacyjną Dźwięk i wideo Wyświetlanie pełnoekranowe - Pionowa + Wymuś tryb pionowy Społeczność Discord Matrix @@ -246,7 +246,7 @@ Nie znaleziono zewnętrznego odtwarzacza. Upewnij się, że masz takowy zainstalowany. Tryb oszczędzania danych Pomiń miniatury i inne obrazy. - Zapamiętane wyszukiwania + Zapamiętaj wyszukiwania Przechowuj lokalnie historię obejrzanych filmów Historia oglądania i wyszukiwania Zapamiętane pozycje odtwarzania @@ -392,4 +392,5 @@ Usuń zakładki Nie dodano zakładek. Wstaw powiązane filmy + Lokalne playlisty \ No newline at end of file From 1ee858881199d4c350355e2fc822d24b02a57e57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?O=C4=9Fuz=20Ersen?= Date: Wed, 23 Nov 2022 17:22:02 +0000 Subject: [PATCH 14/76] Translated using Weblate (Turkish) Currently translated at 100.0% (393 of 393 strings) Translation: LibreTube/LibreTube Translate-URL: https://hosted.weblate.org/projects/libretube/libretube/tr/ --- app/src/main/res/values-tr/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 1c8172d46..54a03e823 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -392,4 +392,5 @@ Yer imlerini temizle Henüz yer imi yok! İlgili videoları ekle + Yerel oynatma listeleri \ No newline at end of file From d3c90843656ff952932b7d506ddd51bd04c50ddd Mon Sep 17 00:00:00 2001 From: Ricardo Date: Thu, 24 Nov 2022 02:50:26 +0000 Subject: [PATCH 15/76] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (393 of 393 strings) Translation: LibreTube/LibreTube Translate-URL: https://hosted.weblate.org/projects/libretube/libretube/pt_BR/ --- app/src/main/res/values-pt-rBR/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index d6386f144..7638f1fce 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -391,4 +391,6 @@ Favorito Limpar favoritos Ainda não há favoritos! + Playlists locais + Inserir vídeos relacionados \ No newline at end of file From eaf831b86c2e987e6e326fd86994beec2a25d5d3 Mon Sep 17 00:00:00 2001 From: Net Date: Wed, 23 Nov 2022 17:29:18 +0000 Subject: [PATCH 16/76] Translated using Weblate (Azerbaijani) Currently translated at 100.0% (393 of 393 strings) Translation: LibreTube/LibreTube Translate-URL: https://hosted.weblate.org/projects/libretube/libretube/az/ --- app/src/main/res/values-az/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-az/strings.xml b/app/src/main/res/values-az/strings.xml index 31794dfc1..7cd02685f 100644 --- a/app/src/main/res/values-az/strings.xml +++ b/app/src/main/res/values-az/strings.xml @@ -392,4 +392,5 @@ Əlfəcinləri təmizlə Hələ əlfəcin yoxdur! Əlaqədar videoları yerləşdir + Yerli pleylistlər \ No newline at end of file From 9067feb29086a4d32a0d58d1f5e8848ab06b7edf Mon Sep 17 00:00:00 2001 From: Eric Date: Thu, 24 Nov 2022 01:06:58 +0000 Subject: [PATCH 17/76] Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (393 of 393 strings) Translation: LibreTube/LibreTube Translate-URL: https://hosted.weblate.org/projects/libretube/libretube/zh_Hans/ --- app/src/main/res/values-zh-rCN/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index ccd8c49b1..fda932cef 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -392,4 +392,5 @@ 清除书签 尚无书签! 插入相关视频 + 本地播放列表 \ No newline at end of file From 668c405e29ae6405052ccbc0de1ca8c8f4a94579 Mon Sep 17 00:00:00 2001 From: Ihor Hordiichuk Date: Thu, 24 Nov 2022 01:13:00 +0000 Subject: [PATCH 18/76] Translated using Weblate (Ukrainian) Currently translated at 100.0% (393 of 393 strings) Translation: LibreTube/LibreTube Translate-URL: https://hosted.weblate.org/projects/libretube/libretube/uk/ --- app/src/main/res/values-uk/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index daee26081..387fb13fb 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -392,4 +392,5 @@ Очистити закладки Ще немає закладок! Вставити пов\'язані відео + Локальні добірки \ No newline at end of file From a026026bca9919c10b5537635cbc3461910ba11b Mon Sep 17 00:00:00 2001 From: Gediminas Murauskas Date: Wed, 23 Nov 2022 17:59:30 +0000 Subject: [PATCH 19/76] Translated using Weblate (Lithuanian) Currently translated at 100.0% (393 of 393 strings) Translation: LibreTube/LibreTube Translate-URL: https://hosted.weblate.org/projects/libretube/libretube/lt/ --- app/src/main/res/values-lt/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-lt/strings.xml b/app/src/main/res/values-lt/strings.xml index 7820fcea3..e931dbf02 100644 --- a/app/src/main/res/values-lt/strings.xml +++ b/app/src/main/res/values-lt/strings.xml @@ -392,4 +392,5 @@ Išvalyti žymes Dar nėra jokių žymų! Įterpti susijusius vaizdo įrašus + Vietiniai grojaraščiai \ No newline at end of file From 3d03c2731b677fd5c8f341e6bbd6367f14145c49 Mon Sep 17 00:00:00 2001 From: GET100PERCENT Date: Thu, 24 Nov 2022 05:07:08 +0000 Subject: [PATCH 20/76] Translated using Weblate (Odia) Currently translated at 100.0% (393 of 393 strings) Translation: LibreTube/LibreTube Translate-URL: https://hosted.weblate.org/projects/libretube/libretube/or/ --- app/src/main/res/values-or/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-or/strings.xml b/app/src/main/res/values-or/strings.xml index cb715bd1b..ef41ed566 100644 --- a/app/src/main/res/values-or/strings.xml +++ b/app/src/main/res/values-or/strings.xml @@ -392,4 +392,5 @@ ଏବେ ଯାଏଁ କୌଣସି ବୁକ୍ ମାର୍କ୍ ନାହିଁ! ବୁକ୍ ମାର୍କ୍ ଗୁଡ଼ିକୁ ଖାଲି କରନ୍ତୁ ସମ୍ପର୍କୀୟ ଭିଡିଓ ଯୋଡ଼ନ୍ତୁ + ସ୍ଥାନୀୟ ପ୍ଲେଲିଷ୍ଟଗୁଡିକ \ No newline at end of file From d837dedb12f755fc705ce2008a3bcb8bc6b909e8 Mon Sep 17 00:00:00 2001 From: Bnyro Date: Fri, 25 Nov 2022 14:15:07 +0100 Subject: [PATCH 21/76] fix pip when video ended --- .../com/github/libretube/ui/fragments/PlayerFragment.kt | 7 +++++++ 1 file changed, 7 insertions(+) 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 5f64086b5..9d5fc24fc 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 @@ -503,6 +503,13 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions { override fun onDestroy() { super.onDestroy() try { + // disable the auto PiP mode for SDK >= 32 + if (SDK_INT >= Build.VERSION_CODES.S) { + activity?.setPictureInPictureParams( + PictureInPictureParams.Builder().setAutoEnterEnabled(false).build() + ) + } + saveWatchPosition() // clear the playing queue and release the player From cc1eae833504013f42072cd3919645f7559f7733 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Allan=20Nordh=C3=B8y?= Date: Fri, 25 Nov 2022 00:19:07 +0000 Subject: [PATCH 22/76] =?UTF-8?q?Translated=20using=20Weblate=20(Norwegian?= =?UTF-8?q?=20Bokm=C3=A5l)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 83.5% (330 of 395 strings) Translation: LibreTube/LibreTube Translate-URL: https://hosted.weblate.org/projects/libretube/libretube/nb_NO/ --- app/src/main/res/values-nb-rNO/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/values-nb-rNO/strings.xml b/app/src/main/res/values-nb-rNO/strings.xml index 5d00010e2..ba4aa2b23 100644 --- a/app/src/main/res/values-nb-rNO/strings.xml +++ b/app/src/main/res/values-nb-rNO/strings.xml @@ -393,4 +393,6 @@ Bokmerke Tøm bokmerker Ingen bokmerker enda. + Menyelementet er ikke påskrudd. + Velg en annen startfane først. \ No newline at end of file From ff2937cc7cca2843098fd97452690cbf52623dfa Mon Sep 17 00:00:00 2001 From: Rex_sa Date: Fri, 25 Nov 2022 05:24:44 +0000 Subject: [PATCH 23/76] Translated using Weblate (Arabic) Currently translated at 100.0% (395 of 395 strings) Translation: LibreTube/LibreTube Translate-URL: https://hosted.weblate.org/projects/libretube/libretube/ar/ --- app/src/main/res/values-ar/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 727234139..e6ae09fe9 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -393,4 +393,6 @@ لا توجد إشارات مرجعية حتى الآن! قوائم التشغيل المحلية إدراج مقاطع فيديو ذات صلة + لم يتم تمكين عنصر القائمة! + يرجى تحديد علامة تبويب بدء أخرى أولا! \ No newline at end of file From a94d62ce1e7442e49aa38c4ae27b29643da7fd38 Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Thu, 24 Nov 2022 20:27:58 +0000 Subject: [PATCH 24/76] Translated using Weblate (Spanish) Currently translated at 100.0% (395 of 395 strings) Translation: LibreTube/LibreTube Translate-URL: https://hosted.weblate.org/projects/libretube/libretube/es/ --- app/src/main/res/values-es/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index c9e94c6d8..d9ff4fd1f 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -393,4 +393,6 @@ Borrar marcadores Insertar videos relacionados Listas de reproducción locales + ¡Seleccione otra pestaña para el inicio primero! + ¡Elemento del menú no habilitado! \ No newline at end of file From f3bee78e1651f6da183408822decdb1f0c887ea0 Mon Sep 17 00:00:00 2001 From: Linerly Date: Fri, 25 Nov 2022 02:32:01 +0000 Subject: [PATCH 25/76] Translated using Weblate (Indonesian) Currently translated at 100.0% (395 of 395 strings) Translation: LibreTube/LibreTube Translate-URL: https://hosted.weblate.org/projects/libretube/libretube/id/ --- app/src/main/res/values-in/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index dc78cc480..044e908d4 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -393,4 +393,6 @@ Belum ada markah! Masukkan video terkait Daftar putar lokal + Item menu tidak diaktifkan! + Mohon pilih tab mulai yang lain terlebih dahulu! \ No newline at end of file From 39f39bf5fba97de6bcba3c4b79264e58fe4747d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81cs=20Zolt=C3=A1n?= Date: Thu, 24 Nov 2022 17:23:43 +0000 Subject: [PATCH 26/76] Translated using Weblate (Hungarian) Currently translated at 100.0% (395 of 395 strings) Translation: LibreTube/LibreTube Translate-URL: https://hosted.weblate.org/projects/libretube/libretube/hu/ --- app/src/main/res/values-hu/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index 4acddb87f..700db8959 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -393,4 +393,6 @@ Helyi lejátszási listák Kapcsolódó videók beillesztése Felkapottak + Válasszon egy másik kezdőlapot először! + Menüelem nincs engedélyezve! \ No newline at end of file From 24f85f11135bbcc191bf53101c9f3557347cc816 Mon Sep 17 00:00:00 2001 From: Daviteusz Date: Fri, 25 Nov 2022 00:59:58 +0000 Subject: [PATCH 27/76] Translated using Weblate (Polish) Currently translated at 100.0% (395 of 395 strings) Translation: LibreTube/LibreTube Translate-URL: https://hosted.weblate.org/projects/libretube/libretube/pl/ --- app/src/main/res/values-pl/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 76e40a75a..1e4dd745e 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -393,4 +393,6 @@ Nie dodano zakładek. Wstaw powiązane filmy Lokalne playlisty + Najpierw włącz kartę! + Najpierw wybierz inną kartę główną! \ No newline at end of file From 0b242c77107725687a7d7a0fee5afecf10b1b951 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?O=C4=9Fuz=20Ersen?= Date: Thu, 24 Nov 2022 17:14:53 +0000 Subject: [PATCH 28/76] Translated using Weblate (Turkish) Currently translated at 100.0% (395 of 395 strings) Translation: LibreTube/LibreTube Translate-URL: https://hosted.weblate.org/projects/libretube/libretube/tr/ --- app/src/main/res/values-tr/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 54a03e823..400bf3eb5 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -393,4 +393,6 @@ Henüz yer imi yok! İlgili videoları ekle Yerel oynatma listeleri + Menü ögesi etkinleştirilmedi! + Lütfen önce başka bir başlangıç sekmesi seçin! \ No newline at end of file From 0a955fd706991feea3983e71a210bc8e09a28f42 Mon Sep 17 00:00:00 2001 From: Net Date: Thu, 24 Nov 2022 17:22:16 +0000 Subject: [PATCH 29/76] Translated using Weblate (Azerbaijani) Currently translated at 100.0% (395 of 395 strings) Translation: LibreTube/LibreTube Translate-URL: https://hosted.weblate.org/projects/libretube/libretube/az/ --- app/src/main/res/values-az/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/values-az/strings.xml b/app/src/main/res/values-az/strings.xml index 7cd02685f..e4bf40340 100644 --- a/app/src/main/res/values-az/strings.xml +++ b/app/src/main/res/values-az/strings.xml @@ -393,4 +393,6 @@ Hələ əlfəcin yoxdur! Əlaqədar videoları yerləşdir Yerli pleylistlər + Lütfən, əvvəla başqa başlanğıc paneli seç! + Menyu elementi aktiv deyil! \ No newline at end of file From 9bc88291012d3f15d8185330fdadf279ec4aafb1 Mon Sep 17 00:00:00 2001 From: Eric Date: Fri, 25 Nov 2022 00:10:54 +0000 Subject: [PATCH 30/76] Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (395 of 395 strings) Translation: LibreTube/LibreTube Translate-URL: https://hosted.weblate.org/projects/libretube/libretube/zh_Hans/ --- app/src/main/res/values-zh-rCN/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index fda932cef..7e5f9cd27 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -393,4 +393,6 @@ 尚无书签! 插入相关视频 本地播放列表 + 菜单项未启用! + 请先选择其他启动选项卡! \ No newline at end of file From 2a76af4464da367b5372045b912bec0a499c702a Mon Sep 17 00:00:00 2001 From: Ihor Hordiichuk Date: Thu, 24 Nov 2022 17:08:03 +0000 Subject: [PATCH 31/76] Translated using Weblate (Ukrainian) Currently translated at 100.0% (395 of 395 strings) Translation: LibreTube/LibreTube Translate-URL: https://hosted.weblate.org/projects/libretube/libretube/uk/ --- app/src/main/res/values-uk/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 387fb13fb..b7cc5e7ff 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -393,4 +393,6 @@ Ще немає закладок! Вставити пов\'язані відео Локальні добірки + Пункт меню не увімкнено! + Спочатку виберіть іншу вкладку для запуску! \ No newline at end of file From 140ca82d67d5bd7e647718442dd70cd729327707 Mon Sep 17 00:00:00 2001 From: Gediminas Murauskas Date: Thu, 24 Nov 2022 18:08:33 +0000 Subject: [PATCH 32/76] Translated using Weblate (Lithuanian) Currently translated at 100.0% (395 of 395 strings) Translation: LibreTube/LibreTube Translate-URL: https://hosted.weblate.org/projects/libretube/libretube/lt/ --- app/src/main/res/values-lt/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/values-lt/strings.xml b/app/src/main/res/values-lt/strings.xml index e931dbf02..5fe3a3dcd 100644 --- a/app/src/main/res/values-lt/strings.xml +++ b/app/src/main/res/values-lt/strings.xml @@ -393,4 +393,6 @@ Dar nėra jokių žymų! Įterpti susijusius vaizdo įrašus Vietiniai grojaraščiai + Meniu elementas neįjungtas! + Pirmiausia pasirinkite kitą pradžios kortelę! \ No newline at end of file From 5482bc966c31f636ac191b7bf039c615eb987355 Mon Sep 17 00:00:00 2001 From: GET100PERCENT Date: Thu, 24 Nov 2022 17:54:22 +0000 Subject: [PATCH 33/76] Translated using Weblate (Odia) Currently translated at 100.0% (395 of 395 strings) Translation: LibreTube/LibreTube Translate-URL: https://hosted.weblate.org/projects/libretube/libretube/or/ --- app/src/main/res/values-or/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/values-or/strings.xml b/app/src/main/res/values-or/strings.xml index ef41ed566..7909e2c55 100644 --- a/app/src/main/res/values-or/strings.xml +++ b/app/src/main/res/values-or/strings.xml @@ -393,4 +393,6 @@ ବୁକ୍ ମାର୍କ୍ ଗୁଡ଼ିକୁ ଖାଲି କରନ୍ତୁ ସମ୍ପର୍କୀୟ ଭିଡିଓ ଯୋଡ଼ନ୍ତୁ ସ୍ଥାନୀୟ ପ୍ଲେଲିଷ୍ଟଗୁଡିକ + ମେନୁ ଆଇଟମ୍ ସକ୍ଷମ ନୁହେଁ! + ଦୟାକରି ପ୍ରଥମେ ଅନ୍ୟ ଏକ ଆରମ୍ଭ ଟ୍ୟାବ୍ ଚୟନ କରନ୍ତୁ! \ No newline at end of file From a1b9f3e2c63b0335bbb1ea2363352aa41050ec60 Mon Sep 17 00:00:00 2001 From: solokot Date: Fri, 25 Nov 2022 10:25:26 +0000 Subject: [PATCH 34/76] Translated using Weblate (Russian) Currently translated at 100.0% (395 of 395 strings) Translation: LibreTube/LibreTube Translate-URL: https://hosted.weblate.org/projects/libretube/libretube/ru/ --- app/src/main/res/values-ru/strings.xml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index d2fd1041a..9da42b4d8 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -158,7 +158,7 @@ URL-адрес API экземпляра Максимальное количество секунд видео для буферизации Очистить добавленные - Показывать похожие видео рядом с тем, что вы смотрите. + Показывать связанные видео рядом с тем, что вы смотрите. Пожалуйста, введите рабочий URL Предзагрузка Загрузки @@ -391,4 +391,8 @@ Закладок пока нет! Рекомендации Закладка + Сначала выберите другую начальную вкладку! + Локальные плейлисты + Пункт меню не включен! + Вставить связанные видео \ No newline at end of file From c42e09e214110f90b5e6ea84aaa5845eb73d11d2 Mon Sep 17 00:00:00 2001 From: jorge Date: Fri, 25 Nov 2022 12:53:34 +0000 Subject: [PATCH 35/76] Translated using Weblate (Portuguese) Currently translated at 100.0% (395 of 395 strings) Translation: LibreTube/LibreTube Translate-URL: https://hosted.weblate.org/projects/libretube/libretube/pt/ --- app/src/main/res/values-pt/strings.xml | 42 +++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 2e7e75cba..551c3d147 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -183,7 +183,7 @@ Instância de autenticação Utilize outra instância para invocações autenticadas. Escolha uma instância - Automático + HLS GitHub Pré-carregamento Número máximo de segundos para colocar em memória. @@ -224,9 +224,9 @@ Sempre Seleção Velocidade de reprodução - Esta alteração exige que a aplicação seja reiniciada. Prima \'Ok\' para reiniciar agora. + Esta alteração exige que a aplicação seja reiniciada. Tem que reiniciar a aplicação - Visibilidade da barra de navegação + Visibilidade do rótulo Ativar modo de ecrã completo ao ligar o ecrã. Tema Branco/preto puro @@ -358,7 +358,41 @@ Esquema alternativo de vídeos Claro por omissão Mostrar mais - Código de tempo + Código de tempo (segundos) Para cenas tangenciais adicionadas apenas para preencher ou humor não necessário para compreender o conteúdo do vídeo. Apenas para utilização em vídeos musicais. Deve abranger partes do vídeo que não façam parte das misturas oficiais. No final, o vídeo deve-se assemelhar ao Spotify ou a qualquer outra versão mista o mais próximo possível ou reduzir a conversa e outras distrações. + Lista de reprodução clonada + Confirmar a anulação da subscrição + Listas de jogos locais + Reproduzir tudo + Tem a certeza de que quer anular a subscrição %1$s\? + Mostrar um diálogo de confirmação antes de cancelar a inscrição. + Por favor, seleccione primeiro um outro separador de arranque! + Item do menu não activado! + Tempo + Hora de início + Tempo final + Hora de notificação + Período de tempo em que é permitida a apresentação de notificações. + Ordem + Traçado alternativo de tendências + Layout + Layout alternativo do reprodutor + Mostrar os vídeos relacionados como uma linha acima dos comentários em vez de abaixo. + Pista de áudio + Padrão + Formato de ficheiro não suportado! + Usar HLS + Usar HLS em vez de DASH (será mais lento, não recomendado) + Auto + Limite de tempo de execução + Fila aberta de notificação + Tendências + Destaque + O que está nas tendências agora + Inserir vídeos relacionados + Marcadores + Marcadores + Limpar Marcadores + Ainda sem marcadores! \ No newline at end of file From 77b19e0bffc1923095d24b88bdf2b804cedd4905 Mon Sep 17 00:00:00 2001 From: Yaron Shahrabani Date: Fri, 25 Nov 2022 09:03:18 +0000 Subject: [PATCH 36/76] Translated using Weblate (Hebrew) Currently translated at 100.0% (395 of 395 strings) Translation: LibreTube/LibreTube Translate-URL: https://hosted.weblate.org/projects/libretube/libretube/he/ --- app/src/main/res/values-iw/strings.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/res/values-iw/strings.xml b/app/src/main/res/values-iw/strings.xml index 1f983572f..37f579273 100644 --- a/app/src/main/res/values-iw/strings.xml +++ b/app/src/main/res/values-iw/strings.xml @@ -392,4 +392,7 @@ פינוי סימניות אין סימניות עדיין! הוספת סרטונים קשורים + רשימות נגינה מקומיות + פריט התפריט לא פעיל! + נא לבחור לשונית התחלה אחרת תחילה! \ No newline at end of file From 7d58a71d270ce14f1f2c96ef023d4f391b246972 Mon Sep 17 00:00:00 2001 From: Krunal Patel Date: Fri, 25 Nov 2022 16:26:45 +0530 Subject: [PATCH 37/76] Add swipe gesture control for brightness and volume Create interface `PlayerGestureOptions` that defines all controlles. `PlayerGestureController` takes this as listner and call apropriate method. Double tap events are also called from this class. --- .../github/libretube/extensions/Normalize.kt | 15 ++ .../ui/activities/OfflinePlayerActivity.kt | 1 + .../libretube/ui/fragments/PlayerFragment.kt | 4 + .../ui/interfaces/DoubleTapListener.kt | 49 ------ .../ui/interfaces/PlayerGestureOptions.kt | 18 +++ .../libretube/ui/views/CustomExoPlayerView.kt | 143 ++++++++++++++---- .../ui/views/PlayerGestureControlView.kt | 26 ++++ .../com/github/libretube/util/AudioHelper.kt | 50 ++++++ .../github/libretube/util/BrightnessHelper.kt | 38 +++++ .../libretube/util/PlayerGestureController.kt | 130 ++++++++++++++++ .../main/res/drawable/controls_layout_bg.xml | 10 ++ app/src/main/res/drawable/ic_brightness.xml | 10 ++ .../main/res/drawable/ic_brightness_auto.xml | 10 ++ app/src/main/res/drawable/ic_volume_off.xml | 10 ++ app/src/main/res/drawable/ic_volume_up.xml | 10 ++ .../res/drawable/vertical_progressbar.xml | 20 +++ .../res/layout/activity_offline_player.xml | 7 + app/src/main/res/layout/fragment_player.xml | 7 + .../layout/player_gesture_control_view.xml | 83 ++++++++++ app/src/main/res/values/strings.xml | 3 + app/src/main/res/values/style.xml | 12 ++ 21 files changed, 576 insertions(+), 80 deletions(-) create mode 100644 app/src/main/java/com/github/libretube/extensions/Normalize.kt delete mode 100644 app/src/main/java/com/github/libretube/ui/interfaces/DoubleTapListener.kt create mode 100644 app/src/main/java/com/github/libretube/ui/interfaces/PlayerGestureOptions.kt create mode 100644 app/src/main/java/com/github/libretube/ui/views/PlayerGestureControlView.kt create mode 100644 app/src/main/java/com/github/libretube/util/AudioHelper.kt create mode 100644 app/src/main/java/com/github/libretube/util/BrightnessHelper.kt create mode 100644 app/src/main/java/com/github/libretube/util/PlayerGestureController.kt create mode 100644 app/src/main/res/drawable/controls_layout_bg.xml create mode 100644 app/src/main/res/drawable/ic_brightness.xml create mode 100644 app/src/main/res/drawable/ic_brightness_auto.xml create mode 100644 app/src/main/res/drawable/ic_volume_off.xml create mode 100644 app/src/main/res/drawable/ic_volume_up.xml create mode 100644 app/src/main/res/drawable/vertical_progressbar.xml create mode 100644 app/src/main/res/layout/player_gesture_control_view.xml diff --git a/app/src/main/java/com/github/libretube/extensions/Normalize.kt b/app/src/main/java/com/github/libretube/extensions/Normalize.kt new file mode 100644 index 000000000..0550a62c0 --- /dev/null +++ b/app/src/main/java/com/github/libretube/extensions/Normalize.kt @@ -0,0 +1,15 @@ +package com.github.libretube.extensions + +fun Int.normalize(oldMin: Int, oldMax: Int, newMin: Int, newMax: Int): Int { + val oldRange = oldMax - oldMin + val newRange = newMax - newMin + + return (this - oldMin) * newRange / oldRange + newMin +} + +fun Float.normalize(oldMin: Float, oldMax: Float, newMin: Float, newMax: Float): Float { + val oldRange = oldMax - oldMin + val newRange = newMax - newMin + + return (this - oldMin) * newRange / oldRange + newMin +} diff --git a/app/src/main/java/com/github/libretube/ui/activities/OfflinePlayerActivity.kt b/app/src/main/java/com/github/libretube/ui/activities/OfflinePlayerActivity.kt index 4f6d26638..946bc365d 100644 --- a/app/src/main/java/com/github/libretube/ui/activities/OfflinePlayerActivity.kt +++ b/app/src/main/java/com/github/libretube/ui/activities/OfflinePlayerActivity.kt @@ -70,6 +70,7 @@ class OfflinePlayerActivity : BaseActivity() { binding.player.initialize( null, binding.doubleTapOverlay.binding, + binding.playerGestureControlView.binding, null ) } 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 9d5fc24fc..cbee0b97f 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 @@ -49,6 +49,7 @@ import com.github.libretube.constants.PreferenceKeys import com.github.libretube.databinding.DoubleTapOverlayBinding import com.github.libretube.databinding.ExoStyledPlayerControlViewBinding import com.github.libretube.databinding.FragmentPlayerBinding +import com.github.libretube.databinding.PlayerGestureControlViewBinding import com.github.libretube.db.DatabaseHelper import com.github.libretube.db.DatabaseHolder.Companion.Database import com.github.libretube.db.obj.WatchPosition @@ -118,6 +119,7 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions { lateinit var binding: FragmentPlayerBinding private lateinit var playerBinding: ExoStyledPlayerControlViewBinding private lateinit var doubleTapOverlayBinding: DoubleTapOverlayBinding + private lateinit var playerGestureControlViewBinding: PlayerGestureControlViewBinding private val viewModel: PlayerViewModel by activityViewModels() /** @@ -183,6 +185,7 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions { exoPlayerView = binding.player playerBinding = binding.player.binding doubleTapOverlayBinding = binding.doubleTapOverlay.binding + playerGestureControlViewBinding = binding.playerGestureControlView.binding // Inflate the layout for this fragment return binding.root @@ -775,6 +778,7 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions { binding.player.initialize( this, doubleTapOverlayBinding, + playerGestureControlViewBinding, trackSelector ) diff --git a/app/src/main/java/com/github/libretube/ui/interfaces/DoubleTapListener.kt b/app/src/main/java/com/github/libretube/ui/interfaces/DoubleTapListener.kt deleted file mode 100644 index 24fd9b1eb..000000000 --- a/app/src/main/java/com/github/libretube/ui/interfaces/DoubleTapListener.kt +++ /dev/null @@ -1,49 +0,0 @@ -package com.github.libretube.ui.interfaces - -import android.os.Handler -import android.os.Looper -import android.os.SystemClock -import android.view.View - -abstract class DoubleTapListener : View.OnClickListener { - - private val handler = Handler(Looper.getMainLooper()) - - private var lastClick = 0L - private var lastDoubleClick = 0L - - abstract fun onDoubleClick() - abstract fun onSingleClick() - - override fun onClick(v: View?) { - if (isSecondClick()) { - handler.removeCallbacks(runnable) - lastDoubleClick = elapsedTime() - onDoubleClick() - } else { - if (recentDoubleClick()) return - handler.removeCallbacks(runnable) - handler.postDelayed(runnable, MAX_TIME_DIFF) - lastClick = elapsedTime() - } - } - - private val runnable = Runnable { - if (isSecondClick()) return@Runnable - onSingleClick() - } - - private fun isSecondClick(): Boolean { - return elapsedTime() - lastClick < MAX_TIME_DIFF - } - - private fun recentDoubleClick(): Boolean { - return elapsedTime() - lastDoubleClick < MAX_TIME_DIFF / 2 - } - - fun elapsedTime() = SystemClock.elapsedRealtime() - - companion object { - private const val MAX_TIME_DIFF = 400L - } -} diff --git a/app/src/main/java/com/github/libretube/ui/interfaces/PlayerGestureOptions.kt b/app/src/main/java/com/github/libretube/ui/interfaces/PlayerGestureOptions.kt new file mode 100644 index 000000000..ee6e60dd1 --- /dev/null +++ b/app/src/main/java/com/github/libretube/ui/interfaces/PlayerGestureOptions.kt @@ -0,0 +1,18 @@ +package com.github.libretube.ui.interfaces + +interface PlayerGestureOptions { + + fun onSingleTap() + + fun onDoubleTapCenterScreen() + + fun onDoubleTapLeftScreen() + + fun onDoubleTapRightScreen() + + fun onSwipeLeftScreen(distanceY: Float) + + fun onSwipeRightScreen(distanceY: Float) + + fun onSwipeEnd() +} diff --git a/app/src/main/java/com/github/libretube/ui/views/CustomExoPlayerView.kt b/app/src/main/java/com/github/libretube/ui/views/CustomExoPlayerView.kt index dd51ca16f..32b0f1f62 100644 --- a/app/src/main/java/com/github/libretube/ui/views/CustomExoPlayerView.kt +++ b/app/src/main/java/com/github/libretube/ui/views/CustomExoPlayerView.kt @@ -1,6 +1,7 @@ package com.github.libretube.ui.views import android.annotation.SuppressLint +import android.app.Activity import android.content.Context import android.content.res.Configuration import android.os.Handler @@ -8,18 +9,24 @@ import android.os.Looper import android.util.AttributeSet import android.view.MotionEvent import android.view.View +import android.view.WindowManager import com.github.libretube.R import com.github.libretube.databinding.DoubleTapOverlayBinding import com.github.libretube.databinding.ExoStyledPlayerControlViewBinding +import com.github.libretube.databinding.PlayerGestureControlViewBinding +import com.github.libretube.extensions.normalize import com.github.libretube.extensions.toDp import com.github.libretube.obj.BottomSheetItem import com.github.libretube.ui.activities.MainActivity import com.github.libretube.ui.base.BaseActivity -import com.github.libretube.ui.interfaces.DoubleTapListener import com.github.libretube.ui.interfaces.OnlinePlayerOptions +import com.github.libretube.ui.interfaces.PlayerGestureOptions import com.github.libretube.ui.interfaces.PlayerOptions import com.github.libretube.ui.sheets.BaseBottomSheet import com.github.libretube.ui.sheets.PlaybackSpeedSheet +import com.github.libretube.util.AudioHelper +import com.github.libretube.util.BrightnessHelper +import com.github.libretube.util.PlayerGestureController import com.github.libretube.util.PlayerHelper import com.github.libretube.util.PlayingQueue import com.google.android.exoplayer2.PlaybackParameters @@ -35,6 +42,14 @@ internal class CustomExoPlayerView( attributeSet: AttributeSet? = null ) : StyledPlayerView(context, attributeSet), PlayerOptions { val binding: ExoStyledPlayerControlViewBinding = ExoStyledPlayerControlViewBinding.bind(this) + + /** + * Objects for player tap and swipe gesture + */ + private lateinit var gestureViewBinding: PlayerGestureControlViewBinding + private lateinit var playerGestureController: PlayerGestureController + private lateinit var brightnessHelper: BrightnessHelper + private lateinit var audioHelper: AudioHelper private var doubleTapOverlayBinding: DoubleTapOverlayBinding? = null /** @@ -45,16 +60,12 @@ internal class CustomExoPlayerView( private val runnableHandler = Handler(Looper.getMainLooper()) - // the x-position of where the user clicked - private var xPos = 0F - var isPlayerLocked: Boolean = false /** * Preferences */ var autoplayEnabled = PlayerHelper.autoPlayEnabled - private var doubleTapAllowed = true private var resizeModePref = PlayerHelper.resizeModePref @@ -65,42 +76,66 @@ internal class CustomExoPlayerView( if (isControllerFullyVisible) hideController() else showController() } - private val doubleTouchListener = object : DoubleTapListener() { - override fun onDoubleClick() { - if (!doubleTapAllowed) return - val eventPositionPercentageX = xPos / width - when { - eventPositionPercentageX < 0.4 -> rewind() - eventPositionPercentageX > 0.6 -> forward() - else -> { - player?.let { player -> - if (player.isPlaying) { - player.pause() - } else { - player.play() - } - } + private val playerGestureListner = object : PlayerGestureOptions { + override fun onSingleTap() { + toggleController() + } + + override fun onDoubleTapCenterScreen() { + player?.let { player -> + if (player.isPlaying) { + player.pause() + if (!isControllerFullyVisible) showController() + } else { + player.play() + if (isControllerFullyVisible) hideController() } } } - override fun onSingleClick() { - toggleController() + override fun onDoubleTapLeftScreen() { + rewind() + } + + override fun onDoubleTapRightScreen() { + forward() + } + + override fun onSwipeLeftScreen(distanceY: Float) { + if (resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT) return + if (isControllerFullyVisible) hideController() + updateBrightness(distanceY) + } + + override fun onSwipeRightScreen(distanceY: Float) { + if (resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT) return + if (isControllerFullyVisible) hideController() + updateVolume(distanceY) + } + + override fun onSwipeEnd() { + gestureViewBinding.brightnessControlView.visibility = View.GONE + gestureViewBinding.volumeControlView.visibility = View.GONE } } fun initialize( playerViewInterface: OnlinePlayerOptions?, doubleTapOverlayBinding: DoubleTapOverlayBinding, + playerGestureControlViewBinding: PlayerGestureControlViewBinding, trackSelector: TrackSelector? ) { this.playerOptionsInterface = playerViewInterface this.doubleTapOverlayBinding = doubleTapOverlayBinding this.trackSelector = trackSelector + this.gestureViewBinding = playerGestureControlViewBinding + this.playerGestureController = PlayerGestureController(context, playerGestureListner) + this.brightnessHelper = BrightnessHelper(context as Activity) + this.audioHelper = AudioHelper(context) - // set the double click listener for rewind/forward - setOnClickListener(doubleTouchListener) - + // Set touch listner for tap and swipe gestures. + setOnTouchListener(playerGestureController) + initializeGestureProgress() enableDoubleTapToSeek() initializeAdvancedOptions(context) @@ -144,10 +179,6 @@ internal class CustomExoPlayerView( } override fun onTouchEvent(event: MotionEvent): Boolean { - // save the x position of the touch event - xPos = event.x - // listen for a double touch - doubleTouchListener.onClick(this) return false } @@ -261,8 +292,8 @@ internal class CustomExoPlayerView( binding.exoBottomBar.visibility = visibility binding.closeImageButton.visibility = visibility - // disable double tap to seek if the player is locked - doubleTapAllowed = !isLocked + // disable tap and swipe gesture if the player is locked + playerGestureController.isEnabled = isLocked } private fun enableDoubleTapToSeek() { @@ -331,6 +362,56 @@ internal class CustomExoPlayerView( } } + private fun initializeGestureProgress() { + val brightnessBar = gestureViewBinding.brightnessProgressBar + val volumeBar = gestureViewBinding.volumeProgressBar + + brightnessBar.progress = if (brightnessHelper.brightness == WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE) { + 25.normalize(0, 100, 0, volumeBar.max) + } else { + brightnessHelper.getBrightnessWithScale(brightnessBar.max.toFloat()).toInt() + } + volumeBar.progress = audioHelper.getVolumeWithScale(volumeBar.max) + } + + private fun updateBrightness(distance: Float) { + gestureViewBinding.brightnessControlView.visibility = View.VISIBLE + val bar = gestureViewBinding.brightnessProgressBar + + if (bar.progress == 0) { + // If brightness progress goes to below 0, set to system brightness + if (distance <= 0) { + brightnessHelper.resetToSystemBrightness() + gestureViewBinding.brightnessImageView.setImageResource(R.drawable.ic_brightness_auto) + gestureViewBinding.brightnessTextView.text = resources.getString(R.string.auto) + return + } + gestureViewBinding.brightnessImageView.setImageResource(R.drawable.ic_brightness) + } + + bar.incrementProgressBy(distance.toInt()) + gestureViewBinding.brightnessTextView.text = "${bar.progress.normalize(0, bar.max, 0, 100)}" + brightnessHelper.setBrightnessWithScale(bar.progress.toFloat(), bar.max.toFloat()) + } + + private fun updateVolume(distance: Float) { + gestureViewBinding.volumeControlView.visibility = View.VISIBLE + val bar = gestureViewBinding.volumeProgressBar + + if (bar.progress == 0) { + gestureViewBinding.volumeImageView.setImageResource( + when { + distance > 0 -> R.drawable.ic_volume_up + else -> R.drawable.ic_volume_off + } + ) + } + bar.incrementProgressBy(distance.toInt()) + audioHelper.setVolumeWithScale(bar.progress, bar.max) + + gestureViewBinding.volumeTextView.text = "${bar.progress.normalize(0, bar.max, 0, 100)}" + } + override fun onAutoplayClicked() { // autoplay options dialog BaseBottomSheet() diff --git a/app/src/main/java/com/github/libretube/ui/views/PlayerGestureControlView.kt b/app/src/main/java/com/github/libretube/ui/views/PlayerGestureControlView.kt new file mode 100644 index 000000000..0185f4c08 --- /dev/null +++ b/app/src/main/java/com/github/libretube/ui/views/PlayerGestureControlView.kt @@ -0,0 +1,26 @@ +package com.github.libretube.ui.views + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import androidx.constraintlayout.widget.ConstraintLayout +import com.github.libretube.databinding.PlayerGestureControlViewBinding + +class PlayerGestureControlView( + context: Context, + attrs: AttributeSet? = null +) : ConstraintLayout(context, attrs) { + var binding: PlayerGestureControlViewBinding + + init { + val layoutInflater = LayoutInflater.from(context) + binding = PlayerGestureControlViewBinding.inflate(layoutInflater, this, true) + } + + override fun onSizeChanged(width: Int, height: Int, oldWidth: Int, oldHeight: Int) { + super.onSizeChanged(width, height, oldHeight, oldHeight) + + binding.brightnessProgressBar.max = (height * 0.7).toInt() + binding.volumeProgressBar.max = (height * 0.7).toInt() + } +} diff --git a/app/src/main/java/com/github/libretube/util/AudioHelper.kt b/app/src/main/java/com/github/libretube/util/AudioHelper.kt new file mode 100644 index 000000000..603933cd5 --- /dev/null +++ b/app/src/main/java/com/github/libretube/util/AudioHelper.kt @@ -0,0 +1,50 @@ +package com.github.libretube.util + +import android.content.Context +import android.media.AudioManager +import android.os.Build +import androidx.core.math.MathUtils +import com.github.libretube.extensions.normalize + +class AudioHelper( + context: Context, + private val stream: Int = AudioManager.STREAM_MUSIC +) { + + private lateinit var audioManager: AudioManager + private var minimumVolumeIndex = 0 + private var maximumVolumeIndex = 16 + + init { + (context.getSystemService(Context.AUDIO_SERVICE) as? AudioManager)?.let { + audioManager = it + maximumVolumeIndex = it.getStreamMaxVolume(stream) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + minimumVolumeIndex = it.getStreamMinVolume(stream) + } + } + } + + var volume: Int + get() { + return if (this::audioManager.isInitialized) { + audioManager.getStreamVolume(stream) - minimumVolumeIndex + } else { + 0 + } + } + set(value) { + if (this::audioManager.isInitialized) { + val vol = MathUtils.clamp(value, minimumVolumeIndex, maximumVolumeIndex) + audioManager.setStreamVolume(stream, vol, 0) + } + } + + fun setVolumeWithScale(value: Int, maxValue: Int, minValue: Int = 0) { + volume = value.normalize(minValue, maxValue, minimumVolumeIndex, maximumVolumeIndex) + } + + fun getVolumeWithScale(maxValue: Int, minValue: Int = 0): Int { + return volume.normalize(minimumVolumeIndex, maximumVolumeIndex, minValue, maxValue) + } +} diff --git a/app/src/main/java/com/github/libretube/util/BrightnessHelper.kt b/app/src/main/java/com/github/libretube/util/BrightnessHelper.kt new file mode 100644 index 000000000..e03581191 --- /dev/null +++ b/app/src/main/java/com/github/libretube/util/BrightnessHelper.kt @@ -0,0 +1,38 @@ +package com.github.libretube.util + +import android.app.Activity +import android.view.WindowManager +import com.github.libretube.extensions.normalize + +class BrightnessHelper(activity: Activity) { + + private val window = activity.window + private val minBrightness = 0.0f + private val maxBrightness = 1.0f + + /** + * Wrapper for the current screen brightness + */ + var brightness: Float + get() = window.attributes.screenBrightness + private set(value) { + val lp = window.attributes + lp.screenBrightness = value + window.attributes = lp + } + + /** + * Restore screen brightness to device system brightness. + */ + fun resetToSystemBrightness() { + brightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE + } + + fun setBrightnessWithScale(value: Float, maxValue: Float, minValue: Float = 0.0f) { + brightness = value.normalize(minValue, maxValue, minBrightness, maxBrightness) + } + + fun getBrightnessWithScale(maxValue: Float, minValue: Float = 0.0f): Float { + return brightness.normalize(minBrightness, maxBrightness, minValue, maxValue) + } +} diff --git a/app/src/main/java/com/github/libretube/util/PlayerGestureController.kt b/app/src/main/java/com/github/libretube/util/PlayerGestureController.kt new file mode 100644 index 000000000..d647306b8 --- /dev/null +++ b/app/src/main/java/com/github/libretube/util/PlayerGestureController.kt @@ -0,0 +1,130 @@ +package com.github.libretube.util + +import android.annotation.SuppressLint +import android.content.Context +import android.content.res.Configuration +import android.content.res.Resources +import android.os.Handler +import android.os.Looper +import android.os.SystemClock +import android.view.GestureDetector +import android.view.MotionEvent +import android.view.View +import com.github.libretube.ui.interfaces.PlayerGestureOptions +import kotlin.math.abs + +class PlayerGestureController(context: Context, private val listner: PlayerGestureOptions) : + View.OnTouchListener { + + // width and height should be obtained each time using getter to adopt layout size changes. + private val width get() = Resources.getSystem().displayMetrics.widthPixels + private val height get() = Resources.getSystem().displayMetrics.heightPixels + private val orientation get() = Resources.getSystem().configuration.orientation + private val elapsedTime get() = SystemClock.elapsedRealtime() + + private val handler: Handler = Handler(Looper.getMainLooper()) + private val gestureDetector: GestureDetector + private var isMoving = false + var isEnabled = true + + init { + gestureDetector = GestureDetector(context, GestureListener(), handler) + } + + @SuppressLint("ClickableViewAccessibility") + override fun onTouch(v: View, event: MotionEvent): Boolean { + if (event.action == MotionEvent.ACTION_UP && isMoving) { + isMoving = false + listner.onSwipeEnd() + } + + // Event can be already consumed by some view which may lead to NPE. + try { + gestureDetector.onTouchEvent(event) + } catch (_: Exception) { } + + // If orientation is landscape then allow `onScroll` to consume event and return true. + return orientation == Configuration.ORIENTATION_LANDSCAPE + } + + private inner class GestureListener : GestureDetector.SimpleOnGestureListener() { + private var lastClick = 0L + private var lastDoubleClick = 0L + private var xPos = 0.0F + + override fun onDown(e: MotionEvent): Boolean { + if (isMoving) return false + + if (isEnabled && isSecondClick()) { + handler.removeCallbacks(runnable) + lastDoubleClick = elapsedTime + val eventPositionPercentageX = xPos / width + + when { + eventPositionPercentageX < 0.4 -> listner.onDoubleTapLeftScreen() + eventPositionPercentageX > 0.6 -> listner.onDoubleTapRightScreen() + else -> listner.onDoubleTapCenterScreen() + } + } else { + if (recentDoubleClick()) return true + handler.removeCallbacks(runnable) + handler.postDelayed(runnable, MAX_TIME_DIFF) + lastClick = elapsedTime + xPos = e.x + } + return true + } + + override fun onScroll( + e1: MotionEvent, + e2: MotionEvent, + distanceX: Float, + distanceY: Float + ): Boolean { + if (!isEnabled) return false + + val insideThreshHold = abs(e2.y - e1.y) <= MOVEMENT_THRESHOLD + val insideBorder = (e1.x < BORDER_THRESHOLD || e1.y < BORDER_THRESHOLD || e1.x > width - BORDER_THRESHOLD || e1.y > height - BORDER_THRESHOLD) + + // If the movement is inside threshold or scroll is horizontal then return false + if ( + !isMoving && ( + insideThreshHold || insideBorder || + abs(distanceX) > abs( + distanceY + ) + ) + ) { + return false + } + + isMoving = true + + when { + width * 0.5 > e1.x -> listner.onSwipeLeftScreen(distanceY) + width * 0.5 < e1.x -> listner.onSwipeRightScreen(distanceY) + } + return true + } + + private val runnable = Runnable { + // If user is scrolling then avoid single tap call + if (isMoving || isSecondClick()) return@Runnable + listner.onSingleTap() + } + + private fun isSecondClick(): Boolean { + return elapsedTime - lastClick < MAX_TIME_DIFF + } + + private fun recentDoubleClick(): Boolean { + return elapsedTime - lastDoubleClick < MAX_TIME_DIFF / 2 + } + } + + companion object { + private const val MAX_TIME_DIFF = 400L + private const val MOVEMENT_THRESHOLD = 30 + private const val BORDER_THRESHOLD = 90 + } +} diff --git a/app/src/main/res/drawable/controls_layout_bg.xml b/app/src/main/res/drawable/controls_layout_bg.xml new file mode 100644 index 000000000..9e7c439b7 --- /dev/null +++ b/app/src/main/res/drawable/controls_layout_bg.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_brightness.xml b/app/src/main/res/drawable/ic_brightness.xml new file mode 100644 index 000000000..ecf23dfb9 --- /dev/null +++ b/app/src/main/res/drawable/ic_brightness.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_brightness_auto.xml b/app/src/main/res/drawable/ic_brightness_auto.xml new file mode 100644 index 000000000..aa74c4915 --- /dev/null +++ b/app/src/main/res/drawable/ic_brightness_auto.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_volume_off.xml b/app/src/main/res/drawable/ic_volume_off.xml new file mode 100644 index 000000000..767b08878 --- /dev/null +++ b/app/src/main/res/drawable/ic_volume_off.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_volume_up.xml b/app/src/main/res/drawable/ic_volume_up.xml new file mode 100644 index 000000000..cdd4aac9e --- /dev/null +++ b/app/src/main/res/drawable/ic_volume_up.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/vertical_progressbar.xml b/app/src/main/res/drawable/vertical_progressbar.xml new file mode 100644 index 000000000..c4350b1f8 --- /dev/null +++ b/app/src/main/res/drawable/vertical_progressbar.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_offline_player.xml b/app/src/main/res/layout/activity_offline_player.xml index f7c5345ec..beebfa6fb 100644 --- a/app/src/main/res/layout/activity_offline_player.xml +++ b/app/src/main/res/layout/activity_offline_player.xml @@ -19,6 +19,13 @@ android:layout_gravity="center" android:gravity="center" /> + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_player.xml b/app/src/main/res/layout/fragment_player.xml index 775e8af8c..3a5f5ddba 100644 --- a/app/src/main/res/layout/fragment_player.xml +++ b/app/src/main/res/layout/fragment_player.xml @@ -397,6 +397,13 @@ android:layout_gravity="center" android:gravity="center" /> + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 771ca0c8c..d572549f4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -389,6 +389,9 @@ Local playlists Menu item not enabled! Please select an other start tab first! + Brightness + Volume + Auto Download Service diff --git a/app/src/main/res/values/style.xml b/app/src/main/res/values/style.xml index c4c8be643..72cbd129c 100644 --- a/app/src/main/res/values/style.xml +++ b/app/src/main/res/values/style.xml @@ -149,6 +149,18 @@ @android:color/white + +