Merge branch 'libre-tube:master' into master

This commit is contained in:
XelXen 2022-11-26 18:26:40 +05:30 committed by GitHub
commit 1e9f2d0bd9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
67 changed files with 1701 additions and 316 deletions

View File

@ -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
@ -82,6 +83,9 @@ object PreferenceKeys {
const val ALTERNATIVE_PLAYER_LAYOUT = "alternative_player_layout"
const val USE_HLS_OVER_DASH = "use_hls"
const val QUEUE_AUTO_INSERT_RELATED = "queue_insert_related_videos"
const val PLAYER_SWIPE_CONTROLS = "player_swipe_controls"
const val PLAYER_SCREEN_BRIGHTNESS = "player_screen_brightness"
const val SHOW_OPEN_WITH = "show_open_with"
/**
* Background mode

View File

@ -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
}

View File

@ -53,7 +53,7 @@ class MainActivity : BaseActivity() {
val autoRotationEnabled = PreferenceHelper.getBoolean(PreferenceKeys.AUTO_ROTATION, false)
lateinit var searchView: SearchView
lateinit var searchItem: MenuItem
private lateinit var searchItem: MenuItem
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -131,9 +131,20 @@ class MainActivity : BaseActivity() {
setupSubscriptionsBadge()
val playerViewModel = ViewModelProvider(this)[PlayerViewModel::class.java]
// new way of handling back presses
onBackPressedDispatcher.addCallback(object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
if (playerViewModel.isFullscreen.value == true) {
for (fragment in supportFragmentManager.fragments) {
if (fragment is PlayerFragment) {
fragment.unsetFullscreen()
return
}
}
}
if (binding.mainMotionLayout.progress == 0F) {
try {
minimizePlayer()

View File

@ -70,6 +70,7 @@ class OfflinePlayerActivity : BaseActivity() {
binding.player.initialize(
null,
binding.doubleTapOverlay.binding,
binding.playerGestureControlsView.binding,
null
)
}

View File

@ -10,7 +10,8 @@ import com.github.libretube.databinding.NavOptionsItemBinding
import com.github.libretube.ui.viewholders.NavBarOptionsViewHolder
class NavBarOptionsAdapter(
val items: MutableList<MenuItem>
val items: MutableList<MenuItem>,
var selectedHomeTabId: Int
) : RecyclerView.Adapter<NavBarOptionsViewHolder>() {
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
}
}
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -21,6 +21,7 @@ import com.github.libretube.ui.adapters.PlaylistsAdapter
import com.github.libretube.ui.base.BaseFragment
import com.github.libretube.ui.dialogs.CreatePlaylistDialog
import com.github.libretube.ui.models.PlayerViewModel
import com.github.libretube.util.NavBarHelper
import com.github.libretube.util.PreferenceHelper
class LibraryFragment : BaseFragment() {
@ -68,6 +69,11 @@ class LibraryFragment : BaseFragment() {
findNavController().navigate(R.id.downloadsFragment)
}
val navBarItems = NavBarHelper.getNavBarItems(requireContext())
if (navBarItems.filter { it.isVisible }.any { it.itemId == R.id.downloadsFragment }) {
binding.downloads.visibility = View.GONE
}
fetchPlaylists()
binding.playlistRefresh.isEnabled = true

View File

@ -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
@ -25,6 +24,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
@ -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.PlayerGestureControlsViewBinding
import com.github.libretube.db.DatabaseHelper
import com.github.libretube.db.DatabaseHolder.Companion.Database
import com.github.libretube.db.obj.WatchPosition
@ -72,6 +73,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
@ -117,6 +119,7 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
lateinit var binding: FragmentPlayerBinding
private lateinit var playerBinding: ExoStyledPlayerControlViewBinding
private lateinit var doubleTapOverlayBinding: DoubleTapOverlayBinding
private lateinit var playerGestureControlsViewBinding: PlayerGestureControlsViewBinding
private val viewModel: PlayerViewModel by activityViewModels()
/**
@ -158,7 +161,6 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
/**
* user preferences
*/
private val token = PreferenceHelper.getToken()
private var videoShownInExternalPlayer = false
/**
@ -183,6 +185,7 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
exoPlayerView = binding.player
playerBinding = binding.player.binding
doubleTapOverlayBinding = binding.doubleTapOverlay.binding
playerGestureControlsViewBinding = binding.playerGestureControlsView.binding
// Inflate the layout for this fragment
return binding.root
@ -283,6 +286,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
@ -398,6 +403,11 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
LinearLayoutManager.HORIZONTAL,
false
)
if (!PreferenceHelper.getBoolean(PreferenceKeys.SHOW_OPEN_WITH, false)) {
binding.relPlayerOpen.visibility = View.GONE
binding.optionsLL.weightSum = 4f
}
}
private fun setFullscreen() {
@ -422,7 +432,7 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
}
@SuppressLint("SourceLockedOrientationActivity")
private fun unsetFullscreen() {
fun unsetFullscreen() {
// leave fullscreen mode
with(binding.playerMotionLayout) {
getConstraintSet(R.id.start).constrainHeight(R.id.player, 0)
@ -501,6 +511,9 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
override fun onDestroy() {
super.onDestroy()
try {
// disable the auto PiP mode for SDK >= 32
disableAutoPiP()
saveWatchPosition()
// clear the playing queue and release the player
@ -518,16 +531,18 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
}
}
private fun disableAutoPiP() {
if (SDK_INT < Build.VERSION_CODES.S) {
return
}
activity?.setPictureInPictureParams(
PictureInPictureParams.Builder().setAutoEnterEnabled(false).build()
)
}
// 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 +641,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 +660,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
*/
@ -766,6 +788,7 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
binding.player.initialize(
this,
doubleTapOverlayBinding,
playerGestureControlsViewBinding,
trackSelector
)
@ -830,7 +853,7 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
) {
transitioning = true
// check whether autoplay is enabled
if (binding.player.autoplayEnabled) playNextVideo()
playNextVideo()
}
when (playbackState) {
@ -855,10 +878,11 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
query {
Database.watchPositionDao().insertAll(watchPosition)
}
disableAutoPiP()
}
// 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()
}
@ -952,19 +976,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 {
@ -1388,13 +1406,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)
@ -1421,14 +1444,20 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
}
fun onUserLeaveHint() {
if (SDK_INT >= Build.VERSION_CODES.O && shouldStartPiP()) {
activity?.enterPictureInPictureMode(
PictureInPictureParams.Builder()
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 ||
@ -1438,15 +1467,9 @@ 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 exoPlayer.isPlaying && !backgroundModeRunning
}
private fun isServiceRunning(context: Context, serviceClass: Class<*>): Boolean {

View File

@ -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()
}

View File

@ -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()
}

View File

@ -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
}
}

View File

@ -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()
}

View File

@ -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
@ -11,15 +12,20 @@ import android.view.View
import com.github.libretube.R
import com.github.libretube.databinding.DoubleTapOverlayBinding
import com.github.libretube.databinding.ExoStyledPlayerControlViewBinding
import com.github.libretube.databinding.PlayerGestureControlsViewBinding
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
@ -33,8 +39,16 @@ import com.google.android.exoplayer2.util.RepeatModeUtil
internal class CustomExoPlayerView(
context: Context,
attributeSet: AttributeSet? = null
) : StyledPlayerView(context, attributeSet), PlayerOptions {
) : StyledPlayerView(context, attributeSet), PlayerOptions, PlayerGestureOptions {
val binding: ExoStyledPlayerControlViewBinding = ExoStyledPlayerControlViewBinding.bind(this)
/**
* Objects for player tap and swipe gesture
*/
private lateinit var gestureViewBinding: PlayerGestureControlsViewBinding
private lateinit var playerGestureController: PlayerGestureController
private lateinit var brightnessHelper: BrightnessHelper
private lateinit var audioHelper: AudioHelper
private var doubleTapOverlayBinding: DoubleTapOverlayBinding? = null
/**
@ -45,16 +59,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 +75,23 @@ 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()
}
}
}
}
}
override fun onSingleClick() {
toggleController()
}
}
fun initialize(
playerViewInterface: OnlinePlayerOptions?,
doubleTapOverlayBinding: DoubleTapOverlayBinding,
playerGestureControlsViewBinding: PlayerGestureControlsViewBinding,
trackSelector: TrackSelector?
) {
this.playerOptionsInterface = playerViewInterface
this.doubleTapOverlayBinding = doubleTapOverlayBinding
this.trackSelector = trackSelector
this.gestureViewBinding = playerGestureControlsViewBinding
this.playerGestureController = PlayerGestureController(context, this)
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 +135,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 +248,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 +318,53 @@ internal class CustomExoPlayerView(
}
}
private fun initializeGestureProgress() {
gestureViewBinding.brightnessProgressBar.let { bar ->
bar.progress = brightnessHelper.getBrightnessWithScale(bar.max.toFloat(), saved = true).toInt()
}
gestureViewBinding.volumeProgressBar.let { bar ->
bar.progress = audioHelper.getVolumeWithScale(bar.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()
@ -407,5 +441,55 @@ internal class CustomExoPlayerView(
params.bottomMargin = offset.toInt()
it.layoutParams = params
}
if (PlayerHelper.swipeGestureEnabled) {
when (newConfig?.orientation) {
Configuration.ORIENTATION_LANDSCAPE -> brightnessHelper.restoreSavedBrightness()
else -> brightnessHelper.resetToSystemBrightness(false)
}
}
}
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 onDoubleTapLeftScreen() {
rewind()
}
override fun onDoubleTapRightScreen() {
forward()
}
override fun onSwipeLeftScreen(distanceY: Float) {
if (!PlayerHelper.swipeGestureEnabled || resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT) return
if (isControllerFullyVisible) hideController()
updateBrightness(distanceY)
}
override fun onSwipeRightScreen(distanceY: Float) {
if (!PlayerHelper.swipeGestureEnabled || 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
}
}

View File

@ -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.PlayerGestureControlsViewBinding
class PlayerGestureControlsView(
context: Context,
attrs: AttributeSet? = null
) : ConstraintLayout(context, attrs) {
var binding: PlayerGestureControlsViewBinding
init {
val layoutInflater = LayoutInflater.from(context)
binding = PlayerGestureControlsViewBinding.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()
}
}

View File

@ -6,6 +6,7 @@ import android.view.LayoutInflater
import androidx.preference.Preference
import com.github.libretube.R
import com.github.libretube.databinding.DialogSliderBinding
import com.github.libretube.extensions.round
import com.github.libretube.util.PreferenceHelper
import com.google.android.material.dialog.MaterialAlertDialogBuilder
@ -20,11 +21,33 @@ class SliderPreference(
attributeSet
) {
private lateinit var sliderBinding: DialogSliderBinding
private var defValue = 0f
val typedArray = context.obtainStyledAttributes(attributeSet, R.styleable.SliderPreference)
private var prefValue: Float
get() = PreferenceHelper.getString(
key,
defValue.toString()
).toFloat()
set(value) {
PreferenceHelper.putString(
key,
value.toString()
)
}
private val typedArray = context.obtainStyledAttributes(attributeSet, R.styleable.SliderPreference)
override fun onAttached() {
super.onAttached()
defValue = typedArray.getFloat(R.styleable.SliderPreference_defValue, 1.0f)
}
override fun getSummary(): CharSequence {
return prefValue.toString()
}
override fun onClick() {
val defValue = typedArray.getFloat(R.styleable.SliderPreference_defValue, 1.0f)
val valueFrom = typedArray.getFloat(R.styleable.SliderPreference_valueFrom, 1.0f)
val valueTo = typedArray.getFloat(R.styleable.SliderPreference_valueTo, 10.0f)
val stepSize = typedArray.getFloat(R.styleable.SliderPreference_stepSize, 1.0f)
@ -34,26 +57,46 @@ class SliderPreference(
)
sliderBinding.slider.apply {
value = PreferenceHelper.getString(
key,
defValue.toString()
).toFloat()
this.value = prefValue
this.valueFrom = valueFrom
this.valueTo = valueTo
this.stepSize = stepSize
}
sliderBinding.minus.setOnClickListener {
sliderBinding.slider.value = maxOf(valueFrom, sliderBinding.slider.value - stepSize)
}
sliderBinding.plus.setOnClickListener {
sliderBinding.slider.value = minOf(valueTo, sliderBinding.slider.value + stepSize)
}
sliderBinding.slider.addOnChangeListener { slider, _, _ ->
listOf(sliderBinding.minus, sliderBinding.plus).forEach {
it.alpha = 1f
}
when (slider.value) {
slider.valueFrom -> sliderBinding.minus.alpha = 0.5f
slider.valueTo -> sliderBinding.plus.alpha = 0.5f
}
updateCurrentValueText()
}
updateCurrentValueText()
MaterialAlertDialogBuilder(context)
.setTitle(title)
.setView(sliderBinding.root)
.setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.okay) { _, _ ->
PreferenceHelper.putString(
key,
sliderBinding.slider.value.toString()
)
prefValue = sliderBinding.slider.value
summary = sliderBinding.slider.value.toString()
}
.show()
super.onClick()
}
private fun updateCurrentValueText() {
sliderBinding.currentValue.text = sliderBinding.slider.value.round(2).toString()
}
}

View File

@ -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)
}
}

View File

@ -0,0 +1,75 @@
package com.github.libretube.util
import android.app.Activity
import android.os.Build
import android.view.WindowManager
import com.github.libretube.constants.PreferenceKeys
import com.github.libretube.extensions.normalize
class BrightnessHelper(private val activity: Activity) {
private val window = activity.window
private val minBrightness = 0.0f
private val maxBrightness = 1.0f
/**
* Wrapper for the current screen brightness
*/
private var brightness: Float
get() = window.attributes.screenBrightness
set(value) {
val lp = window.attributes
lp.screenBrightness = value
window.attributes = lp
}
/**
* Wrapper for the brightness persisted in the shared preferences.
*/
private var savedBrightness: Float
get() = PreferenceHelper.getFloat(PreferenceKeys.PLAYER_SCREEN_BRIGHTNESS, brightness)
set(value) = PreferenceHelper.putFloat(PreferenceKeys.PLAYER_SCREEN_BRIGHTNESS, value)
/**
* Restore screen brightness to device system brightness.
* if [forced] is false then value will be stored only if it's not
* [WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE] value.
*/
fun resetToSystemBrightness(forced: Boolean = true) {
if (forced || brightness != WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE) {
savedBrightness = brightness
}
brightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE
}
/**
* Set current screen brightness to saved brightness value.
*/
fun restoreSavedBrightness() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && activity.isInPictureInPictureMode) {
return
}
brightness = savedBrightness
}
/**
* Set current brightness value with scaling to given range.
* [shouldSave] determines whether the value should be persisted.
*/
fun setBrightnessWithScale(value: Float, maxValue: Float, minValue: Float = 0.0f, shouldSave: Boolean = false) {
brightness = value.normalize(minValue, maxValue, minBrightness, maxBrightness)
if (shouldSave) savedBrightness = brightness
}
/**
* Get scaled brightness with given range. if [saved] is
* ture value will be retrived from shared preferences.
*/
fun getBrightnessWithScale(maxValue: Float, minValue: Float = 0.0f, saved: Boolean = false): Float {
return if (saved) {
savedBrightness.normalize(minBrightness, maxBrightness, minValue, maxValue)
} else {
brightness.normalize(minBrightness, maxBrightness, minValue, maxValue)
}
}
}

View File

@ -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)
}
}

View File

@ -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
}
}

View File

@ -294,6 +294,12 @@ object PlayerHelper {
true
)
val swipeGestureEnabled: Boolean
get() = PreferenceHelper.getBoolean(
PreferenceKeys.PLAYER_SWIPE_CONTROLS,
true
)
fun getDefaultResolution(context: Context): String {
return if (NetworkHelper.isNetworkMobile(context)) {
PreferenceHelper.getString(

View File

@ -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) {

View File

@ -37,6 +37,14 @@ object PreferenceHelper {
editor.putBoolean(key, value).commit()
}
fun putInt(key: String, value: Int) {
editor.putInt(key, value).commit()
}
fun putFloat(key: String, value: Float) {
editor.putFloat(key, value).commit()
}
fun getString(key: String?, defValue: String): String {
return settings.getString(key, defValue) ?: defValue
}
@ -49,6 +57,10 @@ object PreferenceHelper {
return settings.getInt(key, defValue)
}
fun getFloat(key: String?, defValue: Float): Float {
return settings.getFloat(key, defValue)
}
fun clearPreferences() {
editor.clear().apply()
}

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#4d000000" />
<corners android:radius="8dp" />
<padding
android:bottom="8dp"
android:left="8dp"
android:right="8dp"
android:top="8dp" />
</shape>

View File

@ -1,7 +1,7 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorSurface"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="@android:color/white"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M20,15.31L23.31,12 20,8.69V4h-4.69L12,0.69 8.69,4H4v4.69L0.69,12 4,15.31V20h4.69L12,23.31 15.31,20H20v-4.69zM12,18V6c3.31,0 6,2.69 6,6s-2.69,6 -6,6z" />
</vector>

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="@android:color/white"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M10.85,12.65h2.3L12,9l-1.15,3.65zM20,8.69V4h-4.69L12,0.69 8.69,4H4v4.69L0.69,12 4,15.31V20h4.69L12,23.31 15.31,20H20v-4.69L23.31,12 20,8.69zM14.3,16l-0.7,-2h-3.2l-0.7,2H7.8L11,7h2l3.2,9h-1.9z" />
</vector>

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="48"
android:viewportHeight="48">
<path
android:fillColor="#FF000000"
android:pathData="M11,39h7.5L18.5,26.5h11L29.5,39L37,39L37,19.5L24,9.75 11,19.5ZM8,42L8,18L24,6l16,12v24L26.5,42L26.5,29.5h-5L21.5,42ZM24,24.35Z" />
</vector>

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M19,13H5v-2h14v2z" />
</vector>

View File

@ -0,0 +1,16 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="427"
android:viewportHeight="427.97">
<path
android:fillColor="#ffffff"
android:pathData="m352.85,188.96h-0.63c-11.65,0 -20.96,9.86 -20.96,22.62v18.05c0,3.87 -3.14,7 -7,7 -3.87,0 -7,-3.13 -7,-7v-33.33c0,-12.76 -9.32,-23.13 -20.97,-23.13 -11.71,-0.01 -21.03,10.38 -21.03,23.13v35.33c0,3.87 -3.14,7 -7,7 -3.87,0 -7,-3.13 -7,-7v-45.03c0,-12.76 -9.98,-22.64 -21.63,-22.64h-0.66c-11.36,0 -20.71,9.36 -20.71,21.67v50.7c0,3.86 -3.14,7 -7,7 -3.87,0 -7,-3.14 -7,-7v-49.23c0,-0.17 -0.02,-0.34 -0.02,-0.51 0,-0.4 0.02,-0.8 0.02,-1.2v-115.11c0,-12.76 -9.68,-23.13 -21.33,-23.13 -11.65,0 -21.32,10.37 -21.34,23.11l-0.13,190.9c0,2.96 -1.86,5.59 -4.64,6.59 -2.79,1 -5.89,0.14 -7.77,-2.15l-22.79,-27.74c-5.93,-7.43 -14.68,-12.06 -24.15,-12.78 -9.27,-0.61 -18.38,2.66 -25.15,9.03 -0.09,0.08 -0.18,0.16 -0.27,0.24l-4.16,3.46 78.84,151.49c12.39,23.81 35.82,38.65 61.14,38.65h91.35c38.61,0 70.05,-33.93 70.09,-75.55 0.02,-22.16 0.04,-38.73 0.06,-52.13 0.05,-35.86 0.06,-49.01 -0.03,-88.51 -0.03,-12.72 -9.51,-22.81 -21.13,-22.81zM352.85,188.96" />
<path
android:fillColor="#ffffff"
android:pathData="m58.83,47.74c2.73,2.73 7.17,2.73 9.9,0s2.73,-7.16 0,-9.9l-25.71,-25.71c-0.68,-2.57 -2.76,-4.53 -5.36,-5.06 -2.61,-0.53 -5.29,0.46 -6.91,2.57 -0.02,0.02 -0.04,0.04 -0.06,0.05l-28.15,28.15c-2.73,2.73 -2.73,7.17 0,9.9 2.73,2.73 7.16,2.73 9.9,0l16.83,-16.83v173.77l-16.83,-16.83c-2.73,-2.73 -7.17,-2.73 -9.9,0 -2.73,2.73 -2.73,7.17 0,9.9l28.15,28.15c2.73,2.73 7.16,2.73 9.9,0l28.15,-28.15c2.73,-2.73 2.73,-7.16 0,-9.9s-7.16,-2.73 -9.9,0l-15.57,15.57v-171.25zM58.83,47.74" />
<path
android:fillColor="#ffffff"
android:pathData="m130.59,66.05c0,-28.75 23.3,-52.05 52.05,-52.05 28.75,0 52.05,23.3 52.05,52.05 0,3.86 3.14,7 7,7 3.87,0 7,-3.14 7,-7 0,-36.48 -29.57,-66.05 -66.05,-66.05 -36.48,0 -66.05,29.57 -66.05,66.05 0,3.86 3.13,7 7,7 3.87,0 7,-3.14 7,-7zM130.59,66.05" />
</vector>

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="@android:color/white"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M16.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v2.21l2.45,2.45c0.03,-0.2 0.05,-0.41 0.05,-0.63zM19,12c0,0.94 -0.2,1.82 -0.54,2.64l1.51,1.51C20.63,14.91 21,13.5 21,12c0,-4.28 -2.99,-7.86 -7,-8.77v2.06c2.89,0.86 5,3.54 5,6.71zM4.27,3L3,4.27 7.73,9L3,9v6h4l5,5v-6.73l4.25,4.25c-0.67,0.52 -1.42,0.93 -2.25,1.18v2.06c1.38,-0.31 2.63,-0.95 3.69,-1.81L19.73,21 21,19.73l-9,-9L4.27,3zM12,4L9.91,6.09 12,8.18L12,4z" />
</vector>

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="@android:color/white"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M3,9v6h4l5,5L12,4L7,9L3,9zM16.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v8.05c1.48,-0.73 2.5,-2.25 2.5,-4.02zM14,3.23v2.06c2.89,0.86 5,3.54 5,6.71s-2.11,5.85 -5,6.71v2.06c4.01,-0.91 7,-4.49 7,-8.77s-2.99,-7.86 -7,-8.77z" />
</vector>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape>
<solid android:color="#40ffffff" />
<corners android:radius="20dip" />
</shape>
</item>
<item android:id="@android:id/progress">
<scale
android:scaleWidth="0%"
android:scaleHeight="100%"
android:scaleGravity="bottom">
<shape>
<solid android:color="?attr/colorPrimary" />
<corners android:radius="20dip" />
</shape>
</scale>
</item>
</layer-list>

View File

@ -19,6 +19,13 @@
android:layout_gravity="center"
android:gravity="center" />
<com.github.libretube.ui.views.PlayerGestureControlsView
android:id="@+id/playerGestureControlsView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:gravity="center" />
</com.github.libretube.ui.views.CustomExoPlayerView>
</LinearLayout>

View File

@ -1,17 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingHorizontal="10dp"
android:paddingVertical="10dp">
<TextView
android:id="@+id/currentValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginVertical="10dp"
android:textSize="18sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@+id/minus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="?attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_remove" />
<com.google.android.material.slider.Slider
android:id="@+id/slider"
android:layout_width="match_parent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="10dp"
android:layout_marginTop="10dp"
android:layout_gravity="center"
android:layout_weight="1"
android:stepSize="0.1"
android:value="1"
android:valueFrom="0"
android:valueTo="5" />
<ImageView
android:id="@+id/plus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="?attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_add" />
</LinearLayout>
</LinearLayout>

View File

@ -140,6 +140,7 @@
app:cardCornerRadius="27dp">
<LinearLayout
android:id="@+id/optionsLL"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
@ -397,6 +398,13 @@
android:layout_gravity="center"
android:gravity="center" />
<com.github.libretube.ui.views.PlayerGestureControlsView
android:id="@+id/playerGestureControlsView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:gravity="center" />
<com.google.android.material.card.MaterialCardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"

View File

@ -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" />
</RelativeLayout>
</LinearLayout>

View File

@ -32,7 +32,6 @@
android:layout_height="wrap_content"
android:clipToPadding="false"
android:nestedScrollingEnabled="false"
android:paddingBottom="64dp"
android:visibility="gone" />
</FrameLayout>

View File

@ -11,6 +11,14 @@
android:paddingEnd="0dp"
tools:gravity="start|center_vertical">
<ImageView
android:id="@+id/home"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="?attr/selectableItemBackgroundBorderless"
android:paddingHorizontal="10dp"
android:src="@drawable/ic_home_outlined"/>
<com.google.android.material.checkbox.MaterialCheckBox
android:id="@+id/checkbox"
style="@style/Widget.Material3.CompoundButton.CheckBox"

View File

@ -0,0 +1,83 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/volumeControlView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="36dp"
android:background="@drawable/controls_layout_bg"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="RtlHardcoded">
<TextView
android:id="@+id/volume_textView"
style="@style/SwipeControlString"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
<ProgressBar
android:id="@+id/volume_progressBar"
style="@android:style/Widget.ProgressBar.Horizontal"
android:layout_width="7dp"
android:layout_height="100dp"
android:layout_marginVertical="4dp"
android:progressDrawable="@drawable/vertical_progressbar" />
<ImageView
android:id="@+id/volume_imageView"
android:layout_width="24dp"
android:layout_height="24dp"
android:contentDescription="@string/volume"
android:src="@drawable/ic_volume_up" />
</LinearLayout>
<LinearLayout
android:id="@+id/brightnessControlView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="36dp"
android:background="@drawable/controls_layout_bg"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="RtlHardcoded">
<TextView
android:id="@+id/brightness_textView"
style="@style/SwipeControlString"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
<ProgressBar
android:id="@+id/brightness_progressBar"
style="@android:style/Widget.ProgressBar.Horizontal"
android:layout_width="7dp"
android:layout_height="100dp"
android:layout_marginVertical="4dp"
android:progressDrawable="@drawable/vertical_progressbar" />
<ImageView
android:id="@+id/brightness_imageView"
android:layout_width="24dp"
android:layout_height="24dp"
android:contentDescription="@string/brightness"
android:src="@drawable/ic_brightness" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -391,4 +391,8 @@
<string name="bookmark">الاشاره المرجعيه</string>
<string name="clear_bookmarks">مسح الإشارات المرجعية</string>
<string name="bookmarks_empty">لا توجد إشارات مرجعية حتى الآن!</string>
<string name="local_playlists">قوائم التشغيل المحلية</string>
<string name="queue_insert_related_videos">إدراج مقاطع فيديو ذات صلة</string>
<string name="not_enabled">لم يتم تمكين عنصر القائمة!</string>
<string name="select_other_start_tab">يرجى تحديد علامة تبويب بدء أخرى أولا!</string>
</resources>

View File

@ -392,4 +392,15 @@
<string name="clear_bookmarks">Əlfəcinləri təmizlə</string>
<string name="bookmarks_empty">Hələ əlfəcin yoxdur!</string>
<string name="queue_insert_related_videos">Əlaqədar videoları yerləşdir</string>
<string name="local_playlists">Yerli pleylistlər</string>
<string name="select_other_start_tab">Lütfən, əvvəla başqa başlanğıc paneli seç!</string>
<string name="not_enabled">Menyu elementi aktiv deyil!</string>
<string name="brightness">Parlaqlıq</string>
<string name="auto">Avtomatik</string>
<string name="swipe_controls_summary">Parlaqlığı və səs səviyyəsini nizamlamaq üçün sürüşdürmə jesti istifadə et.</string>
<string name="volume">Səs səviyyəsi</string>
<string name="swipe_controls">Sürüşdürmə nəzarətləri</string>
<string name="show_open_with">İlə aç</string>
<string name="defaults">Defolt</string>
<string name="show_open_with_summary">Videonu oynadıcıda 3-cü tərəf tətbiq ilə açmaq üçün düymə göstər.</string>
</resources>

View File

@ -392,4 +392,7 @@
<string name="clear_bookmarks">Vymazat záložky</string>
<string name="bookmarks_empty">Zatím žádné záložky!</string>
<string name="queue_insert_related_videos">Vložit související videa</string>
<string name="local_playlists">Místní playlisty</string>
<string name="not_enabled">Položka nabídky není povolena!</string>
<string name="select_other_start_tab">Nejprve vyberte jinou kartu spuštění!</string>
</resources>

View File

@ -23,7 +23,7 @@
<string name="importsuccess">Abonniert</string>
<string name="subscribeIsEmpty">Abonniere erst einige Kanäle.</string>
<string name="cannotDownload">Video kann nicht heruntergeladen werden.</string>
<string name="dlisinprogress">Eine weitere Datenübertragung ist bereits im Gange, bitte warten Sie, bis sie beendet ist.</string>
<string name="dlisinprogress">Ein weiterer Download läuft bereits, bitte warte, bis er beendet ist.</string>
<string name="downloadfailed">Herunterladen fehlgeschlagen.</string>
<string name="vlcerror">Konnte nicht in VLC geöffnet werden, möglicherweise ist es nicht installiert.</string>
<string name="app_theme">Design</string>
@ -65,7 +65,7 @@
<string name="systemLanguage">System</string>
<string name="comments">Kommentare</string>
<string name="retry">Erneut versuchen</string>
<string name="noInternet">Stelle zunächst eine Verbindung zum Internet her.</string>
<string name="noInternet">Stelle zuerst eine Verbindung zum Internet her.</string>
<string name="videoCount">%1$s Videos</string>
<string name="settings">Einstellungen</string>
<string name="location">Standort</string>
@ -128,7 +128,7 @@
<string name="download_directory_summary">Der Ort, an dem deine heruntergeladenen Medien gespeichert werden.</string>
<string name="donate">Spenden</string>
<string name="update">Auf neue Version überprüfen</string>
<string name="update_summary">Klicke hier, um herauszufinden, ob die Anwendung auf dem neuesten Stand ist.</string>
<string name="update_summary">Nach Update suchen</string>
<string name="app_uptodate">Es läuft die neueste Version.</string>
<string name="no_update_available">Du verwendest die neueste Version.</string>
<string name="playback_speed">Wiedergabegeschwindigkeit</string>
@ -152,9 +152,9 @@
<string name="instance_name">Instanzname</string>
<string name="instance_api_url">URL zur Instanz-API</string>
<string name="addInstance">Instanz hinzufügen</string>
<string name="empty_instance">Geben Sie den Namen und die API URL ein.</string>
<string name="empty_instance">Gebe den Namen und die API-URL ein.</string>
<string name="clear_customInstances">Benutzerdefinierte Instanzen löschen</string>
<string name="invalid_url">Bitte geben Sie eine gültige URL ein</string>
<string name="invalid_url">Bitte eine funktionierende URL angeben</string>
<string name="instance_summary">Piped, Anmeldung &amp; Abonnements</string>
<string name="customInstance_summary">Hinzufügen…</string>
<string name="category_music_offtopic">Musik: Nicht-musikalische Sektion</string>
@ -166,10 +166,10 @@
<string name="category_music_offtopic_description">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.</string>
<string name="playerVideoFormat">Videoformat für Player</string>
<string name="version">Version %1$s</string>
<string name="about_summary">Lernen Sie das LibreTube-Team kennen und erfahren Sie, wie das alles abläuft.</string>
<string name="about_summary">Lerne das LibreTube-Team kennen und erfahre, wie alles abläuft.</string>
<string name="category_preview_description">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.</string>
<string name="player_autoplay">Automatische Wiedergabe</string>
<string name="related_streams_summary">Zeigen Sie ähnliche Streams neben dem, was Sie sehen.</string>
<string name="related_streams_summary">Zeige ähnliche Streams neben dem, was du siehst.</string>
<string name="related_streams">Verwandte Inhalte</string>
<string name="no_audio">Kein Ton</string>
<string name="no_video">Kein Video</string>
@ -194,16 +194,16 @@
<string name="autoplay_summary">Das nächste Video automatisch abspielen, wenn das aktuelle beendet ist.</string>
<string name="watch_positions">Position merken</string>
<string name="auth_instance">Authentifizierungsinstanz</string>
<string name="auth_instance_summary">Verwenden Sie für authentifizierte Anrufe eine andere Instanz.</string>
<string name="auth_instances">Wählen Sie eine Autorisierungsinstanz</string>
<string name="auth_instance_summary">Verwende für authentifizierte Aufrufe eine andere Instanz.</string>
<string name="auth_instances">Wähle eine Authentifizierungsinstanz</string>
<string name="github">GitHub</string>
<string name="hls">Auto</string>
<string name="turnInternetOn">Bitte stellen Sie eine Internetverbindung her, indem Sie WLAN oder mobile Daten aktivieren.</string>
<string name="hls">HLS</string>
<string name="turnInternetOn">Bitte stelle eine Internetverbindung her, indem du WLAN oder mobile Daten aktivierst.</string>
<string name="open">Öffnen…</string>
<string name="chapters">Kapitel</string>
<string name="change_playback_speed">Wiedergabegeschwindigkeit</string>
<string name="require_restart">Neustart der App erforderlich</string>
<string name="require_restart_message">Diese Änderung erfordert einen Neustart der App. Drücken Sie \'Ok\', um jetzt neu zu starten.</string>
<string name="require_restart_message">Starte die App neu, um die Änderungen anzuwenden.</string>
<string name="audio_video">Audio und Video</string>
<string name="fullscreen_orientation">Ausrichtung im Vollbildmodus</string>
<string name="aspect_ratio">Video-Seitenverhältnis</string>
@ -219,13 +219,13 @@
<string name="legacyIcon">Verlorenes Vermächtnis</string>
<string name="category_filler">Füllungstangente/Witze</string>
<string name="none">Keine</string>
<string name="update_now">Wollen Sie die Anwendung jetzt aktualisieren\?</string>
<string name="update_now">Möchtest du die neue LibreTube-Version jetzt installieren\?</string>
<string name="category_filler_description">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.</string>
<string name="selected">Ausgewählt</string>
<string name="autoRotatePlayer">Automatischer Vollbildmodus</string>
<string name="never">Nie</string>
<string name="autoRotatePlayer_summary">Vollbild-Modus des Players wird aktiviert, wenn das Gerät gedreht wird.</string>
<string name="no_player_found">Kein externer Player gefunden. Bitte stellen Sie sicher, dass Sie einen installiert haben.</string>
<string name="no_player_found">Kein externer Player gefunden. Stelle bitte sicher, dass du einen installiert hast.</string>
<string name="fireIcon">Modisches Feuer</string>
<string name="torchIcon">Trendige Fackel</string>
<string name="shapedIcon">Albern geformt</string>
@ -245,7 +245,7 @@
<string name="best_quality">Beste Qualität</string>
<string name="seekbar_preview">Video-Vorschau</string>
<string name="watch_positions_summary">Von letzter Position weiter abspielen</string>
<string name="navLabelVisibility">Navigationsleistensichtbarkeit</string>
<string name="navLabelVisibility">Label-Sichtbarkeit</string>
<string name="watch_history_summary">Angesehene Videos lokal speichern</string>
<string name="history_summary">Wiedergabe- und Suchverlauf</string>
<string name="captions">Untertitel</string>
@ -258,11 +258,11 @@
<string name="system_caption_style">System Untertitel</string>
<string name="playerAudioFormat">Audioformat für Player</string>
<string name="no_search_result">Keine Ergebnisse.</string>
<string name="copied_to_clipboard">In Zwischenablage kopiert! 👌</string>
<string name="copied_to_clipboard">In Zwischenablage kopiert</string>
<string name="default_subtitle_language">Untertitelsprache</string>
<string name="notify_new_streams_summary">Erhalten Sie Benachrichtigungen, wenn ihre Abonnierten Kanäle Videos veröffentlichen.</string>
<string name="notify_new_streams_summary">Erhalte Benachrichtigungen, wenn abonnierte Kanäle Videos veröffentlichen.</string>
<string name="notify_new_streams">Benachrichtigungen bei neuen Videos</string>
<string name="irreversible">Sind Sie sicher\? Dies kann nicht rückgängig gemacht werden!</string>
<string name="irreversible">Bist du sicher\? Dies kann nicht rückgängig gemacht werden!</string>
<string name="caption_settings">Untertitel</string>
<string name="new_streams_by">%1$s haben neue Videos hochgeladen…</string>
<string name="new_streams_count">Es sind %1$s neue Videos verfügbar</string>
@ -285,7 +285,7 @@
<string name="channel_name_za">Kanalnamen (Z-A)</string>
<string name="error_occurred">Fehler :(</string>
<string name="network_metered">Mobiles Internet</string>
<string name="copied">Kopiert!</string>
<string name="copied">Kopiert</string>
<string name="break_reminder">Pausenerinnerung</string>
<string name="least_views">Geringste Aufrufe</string>
<string name="required_network">Internetverbindung erforderlich</string>
@ -303,7 +303,7 @@
<string name="push_channel_name">Benachrichtigungs-dienst</string>
<string name="skip_buttons">Überspringungs Knöpfe</string>
<string name="history_size">Maximale Verlaufsgröße</string>
<string name="already_spent_time">Du guckst schon seit %1$s Minuten Videos, gönn dir \'ne Pause!</string>
<string name="already_spent_time">Du hast bereits %1$s Minuten in der App verbracht, Zeit für eine Pause.</string>
<string name="resize_mode_fill">Ausfüllen</string>
<string name="audio_video_summary">Qualität und Format</string>
<string name="repeat_mode_current">Aktuelles Video</string>
@ -323,7 +323,7 @@
<string name="share_with_time">Mit Zeitstempel teilen</string>
<string name="export_subscriptions">Abos exportieren</string>
<string name="limit_hls">HLS auf 1080p beschränken</string>
<string name="save_feed_summary">Laden Sie den Abo-Feed im Hintergrund und verhindern Sie, dass er automatisch aktualisiert wird.</string>
<string name="save_feed_summary">Lade den Abo-Feed im Hintergrund und verhindere, dass er automatisch aktualisiert wird.</string>
<string name="delete">Aus Downloads löschen</string>
<string name="views_placeholder">Aufrufe</string>
<string name="skip_buttons_summary">Knöpfe um zum nächsten oder letzten Video zu kommen anzeigen.</string>
@ -351,4 +351,46 @@
<string name="playlistNameReversed">Wiedergabelistenname (umgekehrt)</string>
<string name="recentlyUpdated">Kürzlich aktualisiert</string>
<string name="recentlyUpdatedReversed">Kürzlich aktualisiert (umgekehrt)</string>
<string name="playlistCloned">Playlist dupliziert</string>
<string name="confirm_unsubscribing">Deabonnieren bestätigen</string>
<string name="sb_markers_summary">Markiere die Abschnitte auf der Zeitleiste.</string>
<string name="defaultIconLight">Standard hell</string>
<string name="confirm_unsubscribing_summary">Zeige Bestätigungsdialog vor dem Deabonnieren.</string>
<string name="confirm_unsubscribe">Bist du sicher, dass du %1$s deabbonieren möchtest\?</string>
<string name="local_playlists">Lokale Playlists</string>
<string name="play_all">Alles abspielen</string>
<string name="playing_queue">Warteschlange wird abgespielt</string>
<string name="queue">Warteschlange</string>
<string name="time">Zeit</string>
<string name="start_time">Startzeit</string>
<string name="end_time">Endzeit</string>
<string name="notification_time">Benachrichtigungszeit</string>
<string name="notification_time_summary">Zeitspanne, in der Benachrichtigungen angezeigt werden dürfen.</string>
<string name="alternative_trending_layout">Alternatives Trending-Layout</string>
<string name="navbar_order">Anordnung</string>
<string name="layout">Layout</string>
<string name="alternative_player_layout">Alternatives Player-Layout</string>
<string name="alternative_player_layout_summary">Zeige verwandte Videos in einer Reihe über den Kommentaren an, anstatt darunter.</string>
<string name="added_to_playlist">Zur Playlist hinzugefügt</string>
<string name="sb_markers">Markierungen</string>
<string name="audio_track">Tonspur</string>
<string name="default_audio_track">Standard</string>
<string name="livestreams">Livestreams</string>
<string name="alternative_videos_layout">Alternatives Video-Layout</string>
<string name="unsupported_file_format">Nicht unterstütztes Dateiformat!</string>
<string name="hls_instead_of_dash">Verwende HLS</string>
<string name="hls_instead_of_dash_summary">Verwende HLS statt DASH (wird langsamer sein, nicht empfohlen)</string>
<string name="auto_quality">Automatisch</string>
<string name="limit_to_runtime">Auf Laufzeit beschränken</string>
<string name="open_queue_from_notification">Öffne Warteschlange aus Benachrichtigung</string>
<string name="show_more">Mehr anzeigen</string>
<string name="time_code">Zeitstempel (Sekunden)</string>
<string name="trends">Trends</string>
<string name="featured">Vorgestellt</string>
<string name="trending">Was jetzt angesagt ist</string>
<string name="queue_insert_related_videos">Verwandte Videos einfügen</string>
<string name="bookmarks">Lesezeichen</string>
<string name="bookmark">Lesezeichen</string>
<string name="clear_bookmarks">Lesezeichen löschen</string>
<string name="bookmarks_empty">Noch keine Lesezeichen vorhanden!</string>
</resources>

View File

@ -266,7 +266,7 @@
<string name="best_quality">Mejor</string>
<string name="worst_quality">Peor calidad</string>
<string name="default_subtitle_language">Idioma subtítulo</string>
<string name="notify_new_streams">Norificaciones para nuevos directos</string>
<string name="notify_new_streams">Notificaciones para nuevos directos</string>
<string name="checking_frequency">Comprobando todo …</string>
<string name="new_streams_count">%1$s nuevo directo disponible</string>
<string name="most_recent">Novedades</string>
@ -392,4 +392,15 @@
<string name="bookmarks_empty">¡Aún no hay marcadores!</string>
<string name="clear_bookmarks">Borrar marcadores</string>
<string name="queue_insert_related_videos">Insertar videos relacionados</string>
<string name="local_playlists">Listas de reproducción locales</string>
<string name="select_other_start_tab">¡Seleccione otra pestaña para el inicio primero!</string>
<string name="not_enabled">¡Elemento del menú no habilitado!</string>
<string name="volume">Volumen</string>
<string name="auto">Automático</string>
<string name="swipe_controls">Controles del deslizamiento</string>
<string name="brightness">Brillo</string>
<string name="swipe_controls_summary">Use el gesto de deslizar para ajustar el brillo y el volumen.</string>
<string name="defaults">Por defecto</string>
<string name="show_open_with">Abrir con</string>
<string name="show_open_with_summary">Mostrar un botón para abrir el vídeo con una aplicación de terceros en el reproductor.</string>
</resources>

View File

@ -1,59 +1,406 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="yes">हाँ</string>
<string name="search_hint">सर्च</string>
<string name="subscribe">दस्यता ले</string>
<string name="search_hint">खोज करें</string>
<string name="subscribe">ब्सक्राइब</string>
<string name="unsubscribe">अनसब्सक्राइब</string>
<string name="share">शेयर</string>
<string name="share">सांझा करें</string>
<string name="download">डाउनलोड</string>
<string name="save">ेव</string>
<string name="save">॔भालें</string>
<string name="username">यूज़रनेम</string>
<string name="password">पासवर्ड</string>
<string name="login">लॉगिन</string>
<string name="register">रजिस्टर</string>
<string name="logout">लॉगआउट</string>
<string name="cancel">कैंसल</string>
<string name="loggedIn">सफलतापूर्वक लॉग इन हो चुका है!</string>
<string name="loggedout">सफलतापूर्वक लॉग आउट किया!</string>
<string name="cancel">रद्द करें</string>
<string name="loggedIn">सफलतापूर्वक लॉग इन हो चुका है</string>
<string name="loggedout">सफलतापूर्वक लॉग आउट किया</string>
<string name="registered">सफलतापूर्वक रजिस्टर हो गया! अब आप अपने मनचाहे चैनल को सब्सक्राइब कर सकते हैं।</string>
<string name="already_logged_in">आप पहले ही लॉग इन हैं, आप अपने खाते से लॉगआउट कर सकते हैं।</string>
<string name="login_first">कृपया पुनः लॉगिन करें और पुनः प्रयास करें!</string>
<string name="instances">इंस्टेंस चुनें</string>
<string name="login_first">कृपया पुनः लॉगिन करें और पुनः प्रयास करें</string>
<string name="instances">इंस्टेंस चुनें</string>
<string name="customInstance">अलग इंस्टेंस जोड़ें</string>
<string name="login_register">लॉग इन/रजिस्टर</string>
<string name="importsuccess">सफलतापूर्वक सब्सक्राइब ही गया!</string>
<string name="cannotDownload">इस स्ट्रीम को डाउनलोड नहीं कर सकते!</string>
<string name="downloadfailed">डाउनलोड विफल!</string>
<string name="importsuccess">सफलतापूर्वक सब्सक्राइब हो गया</string>
<string name="cannotDownload">इस स्ट्रीम को डाउनलोड नहीं कर सकते</string>
<string name="downloadfailed">डाउनलोड विफल</string>
<string name="vlc">वीएलसी में खोलें</string>
<string name="vlcerror">वीएलसी में नहीं खुल सका। शायद यह अभी तक इंस्टॉल्ड नहीं है\?</string>
<string name="import_from_yt">यूट्यूब से सब्सक्रिप्शन आयात करें</string>
<string name="vlcerror">वीएलसी में नहीं खुल सका। शायद यह अभी तक इंस्टॉल्ड नहीं है</string>
<string name="import_from_yt">सब्सक्रिप्शन आयात करें</string>
<string name="app_theme">ऐप थीम</string>
<string name="server_error">सर्वर में समस्या है। शायद कोई और इंस्टेंस चुनकर प्रयास करें\?</string>
<string name="error">कुछ गलत हो गया!</string>
<string name="empty">उपयोगकर्ता नाम और पासवर्ड खाली नहीं हो सकता!</string>
<string name="notgmail">हे Piped अकाउंटसाठी आहे.</string>
<string name="error">कुछ गलत हो गया</string>
<string name="empty">उपयोगकर्ता नाम और पासवर्ड खाली नहीं हो सकता</string>
<string name="notgmail">यह एक पाइप्ड खाते के लिए है।</string>
<string name="defres">वीडियो रेजोल्यूशन</string>
<string name="grid">ग्रिड कॉलम</string>
<string name="emptyList">यहाँ कुछ भी नहीं है!</string>
<string name="emptyList">यहाँ कुछ भी नहीं है</string>
<string name="deletePlaylist">प्लेलिस्ट डिलीट करें</string>
<string name="areYouSure">क्या आप वाकई इस प्लेलिस्ट को हटाना चाहते हैं\?</string>
<string name="createPlaylist">प्लेलिस्ट बनायें</string>
<string name="playlistCreated">प्लेलिस्ट बनाई गई!</string>
<string name="playlistCreated">प्लेलिस्ट बन गई।</string>
<string name="playlistName">प्लेलिस्ट का नाम</string>
<string name="addToPlaylist">प्लेलिस्ट में जोड़ें</string>
<string name="success">सफलता!</string>
<string name="success">सफलता</string>
<string name="fail">अनुत्तीर्ण होना :(</string>
<string name="unknown_error">नेटवर्क त्रुटि!</string>
<string name="subscribeIsEmpty">पहले कुछ चैनलों को सब्सक्राइब करें!</string>
<string name="unknown_error">नेटवर्क त्रुटि</string>
<string name="subscribeIsEmpty">पहले कुछ चैनलों को सब्सक्राइब करें</string>
<string name="region">क्षेत्र चुनें</string>
<string name="please_login">कृपया पहले सेटिंग में लॉग इन या रजिस्टर करें!</string>
<string name="dlcomplete">डाउनलोड पूरा हो गया है!</string>
<string name="dlisinprogress">एक और डाउनलोड पहले से ही हो रहा है कृपया इसके समाप्त होने तक प्रतीक्षा करें!</string>
<string name="choose_quality_dialog">क्वालिटी चुनें:</string>
<string name="dlcomplete">डाउनलोड पूरा हो गया है</string>
<string name="dlisinprogress">एक और डाउनलोड पहले से ही हो रहा है कृपया इसके समाप्त होने तक प्रतीक्षा करें</string>
<string name="choose_quality_dialog">गुणवत्ता चुनें:</string>
<string name="about">के बारे में</string>
<string name="startpage">होम</string>
<string name="subscriptions">दस्यता</string>
<string name="library">लायब्ररी</string>
<string name="startpage">घर</string>
<string name="subscriptions">ब्सक्रिप्शनें</string>
<string name="library">लायब्ररी</string>
<string name="videos">वीडियो</string>
<string name="import_from_yt_summary">YouTube किंवा NewPipe वरून</string>
<string name="import_from_yt_summary">यूट्यूब या न्यूपाइप से</string>
<string name="customization">समायोजन</string>
<string name="noInternet">पहले इंटरनेट से कनेक्ट करें।</string>
<string name="emptyPlaylistName">प्लेलिस्ट का नाम खाली नहीं छोड़ा जा सकता</string>
<string name="changeLanguage">भाषा</string>
<string name="systemLanguage">सिस्टम</string>
<string name="systemDefault">सिस्टम डिफ़ॉल्ट</string>
<string name="lightTheme">हलका</string>
<string name="darkTheme">गहरा</string>
<string name="subscribers">%1$s सब्सक्राइब्रस</string>
<string name="settings">सेटिंग्स</string>
<string name="location">स्थान</string>
<string name="instance">इंस्टेंस</string>
<string name="website">वैबसाइट</string>
<string name="videoCount">%1$s वीडियोज</string>
<string name="retry">फिर से कोशिश करें</string>
<string name="comments">टिॅपणीयां</string>
<string name="playlistCloned">प्लेलिस्ट क्लोन की गई</string>
<string name="confirm_unsubscribe">क्या आप वाकई %1$s को अनसब्सक्राईब करना चाहते हैं\?</string>
<string name="confirm_unsubscribing">अनसब्सक्राईब करने की पुष्टि करें</string>
<string name="confirm_unsubscribing_summary">अनसब्सक्राईब करने से पहले एक पुष्टिकरण संवाद दिखाएं।</string>
<string name="piped">पाइप्ड</string>
<string name="youtube">यूट्यूब</string>
<string name="play_all">सभी चलाएं</string>
<string name="category_interaction_description">जब सामग्री के बीच में लाइक, सब्सक्राइब या फॉलो करने का एक छोटा सा रिमाइंडर आता है। यदि लंबा है या किसी विशिष्ट चीज के बारे में है, तो इसके बजाय यह स्वयं प्रचार होना चाहिए।</string>
<string name="enabled">आन</string>
<string name="music_playlists">वाईटी संगीत पलेलिसटें</string>
<string name="music_songs">वाईटी संगीत गानें</string>
<string name="category_selfpromo_description">अवैतनिक या स्वयं प्रचार को छोड़कर \"प्रायोजक\" के समान। इसमें मर्चेंडाइज, दान या उन लोगों के बारे में जानकारी शामिल है जिनके साथ उन्होंने सहयोग किया है।</string>
<string name="category_interaction">इंटरेक्शन रिमाइंडर (लाइक और सब्सक्राइब)</string>
<string name="category_music_offtopic_description">केवल संगीत वीडियो में उपयोग के लिए। इसमें वीडियो के कुछ हिस्से शामिल होने चाहिए जो आधिकारिक मिक्स का हिस्सा नहीं हैं। अंत में, वीडियो को Spotify या किसी अन्य मिश्रित संस्करण के जितना संभव हो उतना करीब से मिलना चाहिए, या बात करने या अन्य विकर्षणों को कम करना चाहिए।</string>
<string name="update">नए संस्करण की तलाश करें</string>
<string name="no_update_available">आप नवीनतम संस्करण चला रहे हैं।</string>
<string name="no_replies">इस टिप्पणी का कोई उत्तर नहीं है।</string>
<string name="download_folder_summary">डाउनलोड किए गए मीडिया के फ़ोल्डर का नाम इसमें संग्रहीत है।</string>
<string name="network_metered">मीटर किए गए</string>
<string name="play_next">अगला चलाएं</string>
<string name="authors">लेखक</string>
<string name="choose_filter">खोज फ़िल्टर चुनें</string>
<string name="channels">चैनल</string>
<string name="all">सभी</string>
<string name="playlists">प्लेलिस्ट</string>
<string name="okay">ठीक है</string>
<string name="history">इतिहास</string>
<string name="search_history">खोज इतिहास</string>
<string name="clear_history">इतिहास को मिटाएं</string>
<string name="music_videos">वाईटी संगीत वीडियोज</string>
<string name="music_albums">वाईटी संगीत एलबमें</string>
<string name="defaultTab">डिफ़ॉल्ट टैब</string>
<string name="sponsorblock">प्रायोजक ब्लॉक</string>
<string name="segment_skipped">छोड़ा गया खंड</string>
<string name="category_sponsor">प्रायोजक</string>
<string name="category_sponsor_description">पेड प्रमोशन, पेड रेफरल और सीधे विज्ञापन। स्व-प्रचार या कारणों, रचनाकारों, वेबसाइटों और उत्पादों के लिए मुफ्त वास्तविक चिल्लाहट के लिए नहीं।</string>
<string name="category_selfpromo">अवैतनिक / स्वयं प्रचार</string>
<string name="category_intro">इंटरमिशन/इंट्रो एनिमेशन</string>
<string name="category_outro_description">समाप्ति के बाद की जानकारी। जानकारी के साथ निष्कर्ष के लिए नहीं।</string>
<string name="category_segments">खंड</string>
<string name="category_intro_description">वास्तविक सामग्री के बिना एक अंतराल। एक ठहराव, स्थिर फ्रेम, दोहराए जाने वाला एनीमेशन हो सकता है। जानकारी वाले संक्रमणों के लिए उपयोग नहीं किया जाना चाहिए।</string>
<string name="internal_storage">आंतरिक स्टोरेज</string>
<string name="sdcard">एसडी कार्ड</string>
<string name="views">%1$s व्यूज</string>
<string name="defaultIcon">डिफॉल्ट</string>
<string name="sponsorblock_summary">https://sponsor.ajay.app API का उपयोग करता है</string>
<string name="sponsorblock_state">आन</string>
<string name="category_outro">अंत कार्ड और क्रेडिट</string>
<string name="color_accent">लहजे</string>
<string name="color_red">आराम लाल</string>
<string name="color_yellow">पीला पीला</string>
<string name="app_uptodate">नवीनतम संस्करण चला रहा है।</string>
<string name="flameIcon">उड़ती हुई लौ</string>
<string name="shapedIcon">सिली आकार की</string>
<string name="playing_queue">बजने वाली कतार</string>
<string name="queue">कतार</string>
<string name="time">समय</string>
<string name="start_time">समय शुरू</string>
<string name="end_time">समय समाप्त</string>
<string name="notification_time">सूचना का समय</string>
<string name="notification_time_summary">समय अवधि जिसमें सूचनाओं को दिखाने की अनुमति है।</string>
<string name="views_placeholder">व्यूज</string>
<string name="birdIcon">बूसटड पक्षी</string>
<string name="channel_name_az">चैनल का नाम (ए-जेड)</string>
<string name="channel_name_za">चैनल का नाम (जेड-ए)</string>
<string name="sort">छंटाई</string>
<string name="required_network">कनेक्शन आवश्यक</string>
<string name="share_with_time">समय कोड के साथ साझा करें</string>
<string name="export_subscriptions">सब्सक्रिप्शनें निर्यात करें</string>
<string name="history_size">अधिकतम इतिहास आकार</string>
<string name="unlimited">असीमित</string>
<string name="background_mode">पृष्ठभूमि मोड</string>
<string name="add_to_queue">क़तार में जोड़ें</string>
<string name="misc">विविध</string>
<string name="break_reminder">ब्रेक रिमाइंडर</string>
<string name="take_a_break">ब्रेक लेने का समय</string>
<string name="already_spent_time">आप पहले ही ऐप में %1$s मिनट बिता चुके हैं, ब्रेक लेने का समय आ गया है।</string>
<string name="yt_shorts">शॉर्ट</string>
<string name="no_subtitles_available">कोई उपशीर्षक उपलब्ध नहीं है</string>
<string name="repeat_mode">रिपीट मोड</string>
<string name="resize_mode_fit">फिॅट</string>
<string name="resize_mode_fill">फिल</string>
<string name="resize_mode_zoom">जूम</string>
<string name="repeat_mode_none">कोई भी नहीं</string>
<string name="repeat_mode_current">मौजूदा</string>
<string name="backup_restore">बैकअप और बहाली</string>
<string name="backup">बैकअप</string>
<string name="picture_in_picture">चित्र में चित्र</string>
<string name="player_resize_mode">आकार बदलें मोड</string>
<string name="maximum_image_cache">अधिकतम इमेज कैश आकार</string>
<string name="copied_to_clipboard">क्लिपबोर्ड पर कापी हुआ</string>
<string name="open_copied">खोलें</string>
<string name="break_reminder_time">याद दिलाने से पहले मिनट</string>
<string name="legacy_subscriptions">लीगेसी सब्सक्रिप्शन दृश्य</string>
<string name="audio_video_summary">गुणवत्ता और प्रारूप</string>
<string name="delete">डाउनलोडस से हटाएं</string>
<string name="trending_layout">वैकल्पिक ट्रेंडिंग लेआउट</string>
<string name="renamePlaylist">प्लेलिस्ट का नाम बदलें</string>
<string name="wifi">वाई - फाई</string>
<string name="mobile_data">मोबाइल डाटा</string>
<string name="new_videos_badge">नए वीडियो के लिए संकेतक</string>
<string name="new_videos_badge_summary">यदि कुछ हैं तो नए वीडियो की मात्रा के साथ बैज दिखाएं।</string>
<string name="skip_segment">खंड छोड़ें</string>
<string name="sb_skip_manual">मैन्युअली छोड़ें</string>
<string name="sb_skip_manual_summary">खंडों को स्वचालित रूप से न छोड़ें, हमेशा पहले संकेत दें।</string>
<string name="local_subscriptions">स्थानीय सब्सक्रिप्शनें</string>
<string name="preferences">तरजीहें</string>
<string name="backup_customInstances">कस्टम इंस्टैंस</string>
<string name="save_feed">पृष्ठभूमि में फ़ीड लोड करें</string>
<string name="save_feed_summary">सब्सक्रिप्शन फीड को बैकग्राउंड में लोड करें और इसे ऑटो-रीफ्रेश होने से रोकें।</string>
<string name="navigation_bar">नेविगेशन पट्टी</string>
<string name="select_at_least_one">कृपया कम से कम एक आइटम चुनें</string>
<string name="progressive_load_interval">प्रगतिशील लोड अंतराल आकार</string>
<string name="progressive_load_interval_summary">एक कम मान आरंभिक वीडियो लोडिंग को गति दे सकता है।</string>
<string name="default_load_interval">डिफॉल्ट</string>
<string name="playback_pitch">पिॅच</string>
<string name="error_occurred">ख़राबी</string>
<string name="copied">कॉपी किया गया</string>
<string name="alternative_trending_layout">वैकल्पिक ट्रेंडिंग लेआउट</string>
<string name="navbar_order">क्रम</string>
<string name="layout">लेआउट</string>
<string name="alternative_player_layout">वैकल्पिक प्लेयर लेआउट</string>
<string name="alternative_player_layout_summary">संबंधित वीडियो को नीचे की बजाय टिप्पणियों के ऊपर एक पंक्ति के रूप में दिखाएं।</string>
<string name="change_region">वर्तमान क्षेत्र के लिए रुझान अनुपलब्ध प्रतीत होता है। कृपया सेटिंग में दूसरे का चयन करें।</string>
<string name="device_info">डिवाइस की जानकारी</string>
<string name="disabled">आफ</string>
<string name="added_to_playlist">प्लेलिस्ट में जोड़ा गया</string>
<string name="category_filler">भराव स्पर्शरेखा/चुटकुले</string>
<string name="category_music_offtopic">संगीत: गैर-संगीत अनुभाग</string>
<string name="category_preview">पूर्वावलोकन/रिकैप</string>
<string name="license">लाइसेंस</string>
<string name="color_blue">आनंदमय नीला</string>
<string name="color_green">ग्रूवी हरा</string>
<string name="color_purple">सुखद बैंगनी</string>
<string name="material_you">मैटेरियल यू</string>
<string name="sponsorblock_notifications">सूचनाएं</string>
<string name="app_icon">आइकन</string>
<string name="playOnBackground">पृष्ठभूमि में चलाएं</string>
<string name="update_available_text">इसे डाउनलोड करने के लिए GitHub पर रिलीज़ पर जाएं\?</string>
<string name="appearance">दिखावट</string>
<string name="app_behavior">व्‍यवहार</string>
<string name="download_directory">डाउनलोड करें</string>
<string name="download_directory_summary">जहां डाउनलोड किया गया मीडिया स्टोर होता है।</string>
<string name="movies_directory">मूवी फ़ोल्डर</string>
<string name="shareTo">URL को साझा करें</string>
<string name="legacyIcon">खोई हुई विरासत</string>
<string name="gradientIcon">ग्लिब ग्रेडिएंट</string>
<string name="fireIcon">फैशनेबल आग</string>
<string name="torchIcon">ट्रेंडी मशाल</string>
<string name="skip_buttons">स्किप बटन</string>
<string name="skip_buttons_summary">अगले या पिछले वीडियो पर जाने के लिए बटन दिखाएं।</string>
<string name="limit_hls">HLS को 1080p तक सीमित करें</string>
<string name="filename">फ़ाइल का नाम</string>
<string name="invalid_filename">अमान्य फ़ाइल नाम!</string>
<string name="playlists_order">प्लेलिस्ट का क्रम</string>
<string name="playlistNameReversed">प्लेलिस्ट का नाम (उलट)</string>
<string name="recentlyUpdated">हाल ही में अपडेट हुए</string>
<string name="recentlyUpdatedReversed">हाल ही में अपडेट हुए (उलट)</string>
<string name="category_preview_description">इस श्रृंखला में आगामी सामग्री या भविष्य के वीडियो का विवरण देने वाले खंडों के लिए, लेकिन अतिरिक्त जानकारी प्रदान न करें। यदि इसमें क्लिप शामिल हैं जो केवल यहां दिखाई देती हैं, तो बहुत संभव है कि यह गलत श्रेणी हो।</string>
<string name="oledTheme">काला</string>
<string name="category_filler_description">केवल फिलर या हास्य के लिए जोड़े गए स्पर्शरेखा दृश्यों के लिए वीडियो की मुख्य सामग्री को समझने की आवश्यकता नहीं है।</string>
<string name="sb_markers">मार्करज</string>
<string name="sb_markers_summary">समय पट्टी पर खंडों को चिह्नित करें।</string>
<string name="update_available">संस्करण %1$s उपलब्ध है</string>
<string name="audio_track">ऑडियो ट्रैक</string>
<string name="default_audio_track">डिफ़ॉल्ट</string>
<string name="downloads">डाउनलोडस</string>
<string name="video_format">वीडियो फार्मेट</string>
<string name="video_format_summary">ऑडियो और वीडियो दोनों डाउनलोड होने पर फाइलों का रूपांतरण।</string>
<string name="livestreams">लाइव स्ट्रीम</string>
<string name="alternative_videos_layout">वैकल्पिक वीडियो लेआउट</string>
<string name="defaultIconLight">डिफ़ॉल्ट हलका</string>
<string name="unsupported_file_format">असमर्थित फ़ाइल स्वरूप!</string>
<string name="contributing">योगदान</string>
<string name="donate">दान</string>
<string name="update_summary">अपडेट के लिये जांचें</string>
<string name="playback_speed">प्लेबैक गति</string>
<string name="advanced">विकसित</string>
<string name="player">पलेयर</string>
<string name="appearance_summary">अपनी पसंद के हिसाब से ऐप को एडजस्ट करें।</string>
<string name="advanced_summary">डाउनलोडस, और रीसेट</string>
<string name="live">लाईव्ह</string>
<string name="download_folder">नाम</string>
<string name="downloads_directory">डाउनलोड फ़ोल्डर</string>
<string name="music_directory">संगीत फ़ोल्डर</string>
<string name="network_all">सभी</string>
<string name="network_wifi">केवल वाई-फाई पर</string>
<string name="translate">अनुवाद</string>
<string name="no_search_result">कोई परिणाम नहीं।</string>
<string name="downloadsucceeded">डाउनलोड सफल रहा</string>
<string name="hls_instead_of_dash">एचएलएस का प्रयोग करें</string>
<string name="hls_instead_of_dash_summary">डीएएसएच के बजाय एचएलएस का प्रयोग करें (धीमा होगा, अनुशंसित नहीं)</string>
<string name="auto_quality">ऑटो</string>
<string name="limit_to_runtime">रनटाइम तक सीमित करें</string>
<string name="open_queue_from_notification">सूचना से कतार खोलें</string>
<string name="trends">प्रवृत्तियां</string>
<string name="featured">विशेष रुप से प्रदर्शित</string>
<string name="trending">अभी क्या चलन में है</string>
<string name="show_more">और दिखाओ</string>
<string name="time_code">समय कोड (सेकंडस)</string>
<string name="bookmark">बुकमार्क</string>
<string name="bookmarks">बुकमार्कस</string>
<string name="clear_bookmarks">बुकमार्कस मिटाएं</string>
<string name="bookmarks_empty">अभी तक कोई बुकमार्क नहीं!</string>
<string name="background_channel_name">पृष्ठभूमि मोड</string>
<string name="local_playlists">स्थानीय प्लेलिस्ट</string>
<string name="volume">ध्वनि</string>
<string name="auto">ऑटो</string>
<string name="push_channel_name">सूचना कार्यकर्ता</string>
<string name="select_other_start_tab">कृपया पहले कोई दूसरा स्टार्ट टैब चुनें!</string>
<string name="not_enabled">मेनू आइटम सक्षम नहीं!</string>
<string name="brightness">चमक</string>
<string name="swipe_controls">स्वाइप नियंत्रण</string>
<string name="swipe_controls_summary">चमक और ध्वनि को समायोजित करने के लिए स्वाइप जेस्चर का उपयोग करें।</string>
<string name="background_channel_description">ऑडियो प्लेयर को नियंत्रित करने के लिए बटनों के साथ सूचना दिखाता है।</string>
<string name="download_channel_name">डाउनलोड सेवा</string>
<string name="download_channel_description">मीडिया डाउनलोड करते समय एक सूचना दिखाता है।</string>
<string name="queue_insert_related_videos">संबंधित वीडियो डालें</string>
<string name="push_channel_description">नई स्ट्रीमें उपलब्ध होने पर एक सूचना दिखाता है।</string>
<string name="related_streams_summary">आप जो देखते हैं उसके साथ मिलती-जुलती स्ट्रीम दिखाएं.</string>
<string name="empty_instance">नाम और एपीआई यूआरएल भरें।</string>
<string name="invalid_url">कृपया वह URL दर्ज करें जो काम करता हो</string>
<string name="hide_chapters">अध्याय छुपाएं</string>
<string name="buffering_goal">प्रीलोडिंग</string>
<string name="buffering_goal_summary">बफ़र करने के लिए वीडियो की सेकंडस में उच्चतम मात्रा।</string>
<string name="instance_summary">पाइप्ड, लॉगिन और सब्सक्रिप्शन</string>
<string name="clear_customInstances">जोड़े गये हटाएं</string>
<string name="version">वर्शन %1$s</string>
<string name="about_summary">टीम लिब्रेट्यूब के बारे में जानें और जानें कि यह सब कैसे होता है।</string>
<string name="show_chapters">अध्याय दिखाएँ</string>
<string name="customInstance_summary">जोड़ें…</string>
<string name="instance_name">इंस्टेंस का नाम</string>
<string name="instance_api_url">इंस्टेंस API के लिए URL</string>
<string name="addInstance">इंस्टेंस जोड़ें</string>
<string name="related_streams">संबंधित सामग्री</string>
<string name="default_subtitle_language">उपशीर्षक भाषा</string>
<string name="reset_message">सभी सेटिंग रीसेट करें और लॉग आउट करें\?</string>
<string name="account">खाता</string>
<string name="autoRotatePlayer_summary">डिवाइस घूमाने पर फ़ुलस्क्रीन प्लेबैक।</string>
<string name="require_restart_message">नए परिवर्तनों का उपयोग करने के लिए ऐप को पुनरारंभ करें।</string>
<string name="no_player_found">कोई बाहरी प्लेयर नहीं मिला। कृपया सुनिश्चित करें कि आपके पास एक इन्स्टाल है।</string>
<string name="defaults">डिफ़ॉल्टस</string>
<string name="show_open_with">के साथ खोलें</string>
<string name="least_recent">सबसे पुराने</string>
<string name="playerVideoFormat">प्लेयर के लिए विडिओ फॉर्मेट</string>
<string name="no_video">विडियो नहीं</string>
<string name="audio">ऑडियो</string>
<string name="no_audio">ऑडियो नहीं</string>
<string name="video">विडिओ</string>
<string name="downloading">डाउनलोड हो रहा है…</string>
<string name="player_autoplay">आटो-प्ले</string>
<string name="hideTrendingPage">ट्रेंडिंग पेज छुपाएं</string>
<string name="quality">गुणवत्ता</string>
<string name="behavior">व्‍यवहार</string>
<string name="player_summary">डिफ़ॉल्टस और व्यवहार</string>
<string name="instance_frontend_url">URL से इंस्टेंस का फर॔टऐंड</string>
<string name="seek_increment">सीक में वृद्धि</string>
<string name="pauseOnScreenOff">ऑटो ठहराव</string>
<string name="pauseOnScreenOff_summary">स्क्रीन बंद होने पर प्लेबैक रोकें।</string>
<string name="autoplay_summary">मौजूदा वीडियो के बाद अगला वीडियो ऑटो-प्ले करें।</string>
<string name="clonePlaylist">क्लोन प्लेलिस्ट</string>
<string name="reset">डिफॉल्ट्स का पुनःस्थापन</string>
<string name="deleteAccount">खाता डिलीट करें</string>
<string name="deleteAccount_summary">अपना पाइप्ड खाता डिलीट करें</string>
<string name="restore">पुनर्स्थापित</string>
<string name="watch_positions">पोजीशन याद रखें</string>
<string name="watch_positions_summary">पिछली प्लेबैक स्थिति से जारी रखें</string>
<string name="auth_instance">प्रमाणीकरण इंस्टेंस</string>
<string name="auth_instance_summary">प्रमाणीकृत कॉल के लिए एक अलग इंस्टेंस का उपयोग करें।</string>
<string name="auth_instances">एक प्रमाणीकरण इंस्टेंस चुनें</string>
<string name="audio_video">ऑडियो और वीडियो</string>
<string name="github">गिटहब</string>
<string name="fullscreen_orientation">फुलस्क्रीन ओरिएंटेशन</string>
<string name="community">समुदाय</string>
<string name="discord">डिसकौरड</string>
<string name="matrix">मैट्रिक्स</string>
<string name="telegram">टेलीग्राम</string>
<string name="reddit">रैडिट</string>
<string name="twitter">ट्विटर</string>
<string name="open">खोलें…</string>
<string name="chapters">अध्याय</string>
<string name="change_playback_speed">प्लेबैक गति</string>
<string name="require_restart">ऐप को पुनरारंभ करना आवश्यक है</string>
<string name="navLabelVisibility">लेबल दृश्यता</string>
<string name="always">हमेशा</string>
<string name="selected">सिलेक्टिड</string>
<string name="never">कभी नहीँ</string>
<string name="data_saver_mode">डेटा-सेवर मोड</string>
<string name="data_saver_mode_summary">थंमनेल और अन्य छवियों को छोड़ें।</string>
<string name="search_history_summary">खोजें याद रखें</string>
<string name="watch_history_summary">देखे गए वीडियो की स्थानीय रूप से सूची रखें</string>
<string name="history_summary">खोज और देखा इतिहास</string>
<string name="watch_positions_title">याद प्लेबैक स्थितियां</string>
<string name="reset_watch_positions">रीसेट</string>
<string name="system_caption_style">सिस्टम कैप्शन शैली</string>
<string name="captions">कैप्शनज</string>
<string name="none">कोई भी नहीं</string>
<string name="update_now">नया लिब्रेट्यूब संस्करण अभी इंस्टाल करें\?</string>
<string name="seekbar_preview">वीडियो पूर्वावलोकन</string>
<string name="seekbar_preview_summary">प्लेबैक सूचक को खींचते समय एक स्नैपशॉट दिखाएँ।</string>
<string name="general_summary">भाषा और क्षेत्र</string>
<string name="playingOnBackground">बैकग्राउंड में चल रहा है…</string>
<string name="caption_settings">कैप्शनज</string>
<string name="downloading_apk">एपीके डाउनलोड हो रहा है…</string>
<string name="notifications">सूचनाएं</string>
<string name="notify_new_streams">नई स्ट्रीमों के लिए सूचनाएं</string>
<string name="notify_new_streams_summary">आपके द्वारा अनुसरण किए जाने वाले रचनाकारों की ताज़ा सामग्री के बारे में सूचनाएं।</string>
<string name="irreversible">क्या आपको यकीन है\? इसे पूर्ववत नहीं किया जा सकता!</string>
<string name="history_empty">अभी तक कोई इतिहास नहीं है।</string>
<string name="most_recent">नवीनतम</string>
<string name="most_views">सबसे ज्यादा देखे गए</string>
<string name="least_views">सबसे कम देखे गए</string>
<string name="turnInternetOn">कृपया इंटरनेट से कनेक्ट करने के लिए वाई-फ़ाई या मोबाइल डेटा चालू करें.</string>
<string name="new_streams_count">%1$s नई स्ट्रीम उपलब्ध हैं</string>
<string name="new_streams_by">%1$s द्वारा नई स्ट्रीम…</string>
<string name="checking_frequency">चेकिंग हर…</string>
<string name="watch_history">देखा इतिहास</string>
<string name="hls">एचएलएस</string>
<string name="aspect_ratio">वीडियो पहलू अनुपात</string>
<string name="auto_rotation">ऑटो रोटेशन</string>
<string name="landscape">लैंडस्केप</string>
<string name="portrait">पोट्रेट</string>
<string name="pure_theme">शुद्ध थीम</string>
<string name="pure_theme_summary">शुद्ध सफेद / काला थीम</string>
<string name="autoRotatePlayer">ऑटो-फुलस्क्रीन</string>
<string name="general">सामान्य</string>
<string name="playerAudioFormat">प्लेयर के लिए ऑडियो फार्मेट</string>
<string name="playerAudioQuality">ऑडियो गुणवत्ता</string>
<string name="best_quality">श्रेष्ठ</string>
<string name="worst_quality">न्यूनतम</string>
<string name="show_open_with_summary">वीडियो को तीसरे पक्ष के ऐप्लिकेशन के साथ प्लेयर पर खोलने के लिए बटन दिखाएं।</string>
</resources>

View File

@ -225,7 +225,7 @@
<string name="empty_instance">Töltse be a nevet és az API URL-t.</string>
<string name="buffering_goal_summary">Maximális másodpercnyi videó a puffereléshez.</string>
<string name="seek_increment">Léptetés időköze</string>
<string name="require_restart_message">Ehhez a módosításhoz az alkalmazás újraindítása szükséges. Nyomja meg az \'OK\' gombot az újraindításhoz.</string>
<string name="require_restart_message">Indítsa újra az alkalmazást a változtatások használatához.</string>
<string name="pure_theme_summary">Tiszta fehér/fekete téma</string>
<string name="data_saver_mode">Adattakarékos üzemmód</string>
<string name="seekbar_preview">Videó előnézet</string>
@ -390,4 +390,9 @@
<string name="bookmark">Könyvjelző</string>
<string name="bookmarks_empty">Nincsenek még könyvjelzők!</string>
<string name="clear_bookmarks">Könyvjelzők törlése</string>
<string name="local_playlists">Helyi lejátszási listák</string>
<string name="queue_insert_related_videos">Kapcsolódó videók beillesztése</string>
<string name="trends">Felkapottak</string>
<string name="select_other_start_tab">Válasszon egy másik kezdőlapot először!</string>
<string name="not_enabled">Menüelem nincs engedélyezve!</string>
</resources>

View File

@ -392,4 +392,15 @@
<string name="clear_bookmarks">Hapus markah</string>
<string name="bookmarks_empty">Belum ada markah!</string>
<string name="queue_insert_related_videos">Masukkan video terkait</string>
<string name="local_playlists">Daftar putar lokal</string>
<string name="not_enabled">Item menu tidak diaktifkan!</string>
<string name="select_other_start_tab">Mohon pilih tab mulai yang lain terlebih dahulu!</string>
<string name="volume">Volume</string>
<string name="auto">Otomatis</string>
<string name="swipe_controls">Kendali usap</string>
<string name="swipe_controls_summary">Gunakan gestur usap untuk mengatur kecerahan dan volume.</string>
<string name="show_open_with">Buka Dengan</string>
<string name="defaults">Bawaan</string>
<string name="show_open_with_summary">Tampilkan tombol dalam pemain untuk membuka video dengan aplikasi pihak ketiga.</string>
<string name="brightness">Kecerahan</string>
</resources>

View File

@ -392,4 +392,7 @@
<string name="clear_bookmarks">פינוי סימניות</string>
<string name="bookmarks_empty">אין סימניות עדיין!</string>
<string name="queue_insert_related_videos">הוספת סרטונים קשורים</string>
<string name="local_playlists">רשימות נגינה מקומיות</string>
<string name="not_enabled">פריט התפריט לא פעיל!</string>
<string name="select_other_start_tab">נא לבחור לשונית התחלה אחרת תחילה!</string>
</resources>

View File

@ -81,7 +81,7 @@
<string name="authors">Autoriai</string>
<string name="download_folder_summary">Aplanko, kuriame saugoma atsisiųsta medija, pavadinimas.</string>
<string name="internal_storage">Vidinė atmintis</string>
<string name="defaultIcon">Numatytoji</string>
<string name="defaultIcon">Numatyta</string>
<string name="instance_summary">Piped, prisijungimas ir prenumeratos</string>
<string name="customInstance_summary">Pridėti…</string>
<string name="instance_name">Perdavimo šaltinio pavadinimas</string>
@ -106,7 +106,7 @@
<string name="pauseOnScreenOff">Automatinis pristabdymas</string>
<string name="pauseOnScreenOff_summary">Pristabdyti atkūrimą, kai ekranas išjungtas.</string>
<string name="autoplay_summary">Automatiškai paleisti kitą vaizdo įrašą po dabartinio.</string>
<string name="reset">Atkurti numatytuosius nustatymus</string>
<string name="reset">Atkurti numatytus nustatymus</string>
<string name="account">Paskyra</string>
<string name="watch_positions_summary">Tęsti nuo paskutinės buvusios atkūrimo pozicijos</string>
<string name="auth_instance">Autentifikavimo perdavimo šaltinis</string>
@ -179,7 +179,7 @@
<string name="change_region">Atrodo, kad dabartiniame regione tendencijos yra neprieinamos. Nustatymuose pasirinkite kitą.</string>
<string name="limit_hls">Apriboti HLS iki 1080p</string>
<string name="progressive_load_interval_summary">Mažesnė vertė gali pagreitinti pradinį vaizdo įrašų įkėlimą.</string>
<string name="default_load_interval">Numatytoji</string>
<string name="default_load_interval">Numatyta</string>
<string name="playback_pitch">Pikinė</string>
<string name="filename">Failo pavadinimas</string>
<string name="invalid_filename">Netinkamas failo pavadinimas!</string>
@ -295,7 +295,7 @@
<string name="customization">Pritaikymas</string>
<string name="videoCount">%1$s vaizdo įrašai</string>
<string name="retry">Bandyti dar kartą</string>
<string name="defaultTab">Numatytoji kortelė</string>
<string name="defaultTab">Numatyta kortelė</string>
<string name="category_sponsor_description">Apmokama reklama, apmokamos rekomendacijos ir tiesioginė reklama. Ne savireklama ar neapmokamas nuoširdus, kūrėjų, svetainių ir produktų reklamavimas.</string>
<string name="category_interaction">Sąveikos priminimas (skatinimas pamėgti ir prenumeruoti)</string>
<string name="category_intro">Pertrauka / įžanginė animacija</string>
@ -326,7 +326,7 @@
<string name="clear_customInstances">Ištrinti pridėtą</string>
<string name="related_streams_summary">Rodyti panašias transliacijas šalia to, ką žiūrite.</string>
<string name="buffering_goal_summary">Didžiausias užkrauto vaizdo įrašo sekundžių skaičius atmintyje.</string>
<string name="player_summary">Numatytieji nustatymai ir elgsena</string>
<string name="player_summary">Numatyti nustatymai ir elgsena</string>
<string name="seek_increment">Prasukimo žingsnio dydis</string>
<string name="hls">HLS</string>
<string name="fullscreen_orientation">Viso ekrano padėtis</string>
@ -360,7 +360,7 @@
<string name="sb_markers_summary">Žymėti segmentus laiko juostoje.</string>
<string name="livestreams">Tiesioginės transliacijos</string>
<string name="alternative_videos_layout">Alternatyvus vaizdo įrašų išdėstymas</string>
<string name="defaultIconLight">Numatytoji šviesi</string>
<string name="defaultIconLight">Numatyta šviesi</string>
<string name="playlistCloned">Grojaraštis klonuotas</string>
<string name="confirm_unsubscribe">Ar tikrai norite atšaukti %1$s prenumeratą\?</string>
<string name="confirm_unsubscribing">Patvirtinkite prenumeratos atšaukimą</string>
@ -377,7 +377,7 @@
<string name="alternative_trending_layout">Alternatyvus tendencijų išdėstymas</string>
<string name="alternative_player_layout">Alternatyvus grotuvo išdėstymas</string>
<string name="audio_track">Garso takelis</string>
<string name="default_audio_track">Numatytasis</string>
<string name="default_audio_track">Numatytas</string>
<string name="unsupported_file_format">Nepalaikomas failo formatas!</string>
<string name="auto_quality">Automatinė</string>
<string name="hls_instead_of_dash">Naudoti HLS</string>
@ -392,4 +392,15 @@
<string name="clear_bookmarks">Išvalyti žymes</string>
<string name="bookmarks_empty">Dar nėra jokių žymų!</string>
<string name="queue_insert_related_videos">Įterpti susijusius vaizdo įrašus</string>
<string name="local_playlists">Vietiniai grojaraščiai</string>
<string name="not_enabled">Meniu elementas neįjungtas!</string>
<string name="select_other_start_tab">Pirmiausia pasirinkite kitą pradžios kortelę!</string>
<string name="auto">Automatinis</string>
<string name="swipe_controls">Perbraukimo valdikliai</string>
<string name="brightness">Ryškumas</string>
<string name="volume">Garsas</string>
<string name="swipe_controls_summary">Braukimo gestu sureguliuokite ryškumą ir garsumą.</string>
<string name="defaults">Numatyti</string>
<string name="show_open_with">Atidaryti naudojant</string>
<string name="show_open_with_summary">Rodyti mygtuką grotuve, kad galima būtų atidaryti vaizdo įrašą naudojant trečiosios šalies programėlę.</string>
</resources>

View File

@ -387,4 +387,20 @@
<string name="trends">På vei opp</string>
<string name="alternative_player_layout">Alternativ avspillertilpasning</string>
<string name="featured">Framhevet</string>
<string name="local_playlists">Lokale spillelister</string>
<string name="queue_insert_related_videos">Legg til relaterte videoer</string>
<string name="bookmarks">Bokmerke</string>
<string name="bookmark">Bokmerke</string>
<string name="clear_bookmarks">Tøm bokmerker</string>
<string name="bookmarks_empty">Ingen bokmerker enda.</string>
<string name="not_enabled">Menyelementet er ikke påskrudd.</string>
<string name="select_other_start_tab">Velg en annen startfane først.</string>
<string name="swipe_controls">Dragningskontroller</string>
<string name="swipe_controls_summary">Bruk dragnings-håndvendinger for å justere lys- og lydstyrke.</string>
<string name="show_open_with">Åpne med</string>
<string name="defaults">Forvalg</string>
<string name="brightness">Lysstyrke</string>
<string name="volume">Lydstyrke</string>
<string name="auto">Auto</string>
<string name="show_open_with_summary">Vis en knapp i avspilleren for å åpne video med tredjepartsprogram.</string>
</resources>

View File

@ -392,4 +392,12 @@
<string name="bookmarks_empty">ଏବେ ଯାଏଁ କୌଣସି ବୁକ୍ ମାର୍କ୍ ନାହିଁ!</string>
<string name="clear_bookmarks">ବୁକ୍ ମାର୍କ୍ ଗୁଡ଼ିକୁ ଖାଲି କରନ୍ତୁ</string>
<string name="queue_insert_related_videos">ସମ୍ପର୍କୀୟ ଭିଡିଓ ଯୋଡ଼ନ୍ତୁ</string>
<string name="local_playlists">ସ୍ଥାନୀୟ ପ୍ଲେଲିଷ୍ଟଗୁଡିକ</string>
<string name="not_enabled">ମେନୁ ଆଇଟମ୍ ସକ୍ଷମ ନୁହେଁ!</string>
<string name="select_other_start_tab">ଦୟାକରି ପ୍ରଥମେ ଅନ୍ୟ ଏକ ଆରମ୍ଭ ଟ୍ୟାବ୍ ଚୟନ କରନ୍ତୁ!</string>
<string name="brightness">ଉଜ୍ଜଳତା</string>
<string name="volume">ଶବ୍ଦ</string>
<string name="auto">ସ୍ଵତଃ</string>
<string name="swipe_controls">ସ୍ୱାଇପ୍ ନିୟନ୍ତ୍ରଣ</string>
<string name="swipe_controls_summary">ଉଜ୍ଜ୍ୱଳତା ଏବଂ ଭଲ୍ୟୁମ୍ ସଜାଡିବା ପାଇଁ ସ୍ୱାଇପ୍ ଅଙ୍ଗଭଙ୍ଗୀ ବ୍ୟବହାର କରନ୍ତୁ ।</string>
</resources>

View File

@ -183,7 +183,7 @@
<string name="restore">Przywróć kopię zapasową</string>
<string name="require_restart_message">Naciśnij „OK”, aby zastosować zmiany. Aplikacja zostanie zrestartowana.</string>
<string name="notifications">Powiadomienia</string>
<string name="notify_new_streams">Nowe treści</string>
<string name="notify_new_streams">Przypomnij o nowych treściach</string>
<string name="notify_new_streams_summary">Informuj o nowych treściach od twórców, których śledzisz.</string>
<string name="irreversible">Czy na pewno\? Tego nie da się cofnąć!</string>
<string name="require_restart">Wymagany restart aplikacji</string>
@ -210,11 +210,11 @@
<string name="downloadsucceeded">Pobieranie ukończone</string>
<string name="skip_buttons">Przyciski pomijania</string>
<string name="skip_buttons_summary">Pokaż przyciski umożliwiające przejście do następnego lub poprzedniego filmu.</string>
<string name="watch_positions">Zapamiętane pozycje</string>
<string name="watch_positions_summary">Kontynuuj odtwarzanie od ostatniej pozycji</string>
<string name="watch_positions">Zapamiętaj pozycje</string>
<string name="watch_positions_summary">Kontynuuj odtwarzanie od ostatnio zapamiętanej pozycji</string>
<string name="hls">HLS</string>
<string name="github">GitHub</string>
<string name="landscape">Pozioma</string>
<string name="landscape">Wymuś tryb poziomy</string>
<string name="add_to_queue">Dodaj do kolejki</string>
<string name="misc">Różne</string>
<string name="shapedIcon">Stos kart</string>
@ -236,7 +236,7 @@
<string name="auth_instances">Wybierz instancję autoryzacyjną</string>
<string name="audio_video">Dźwięk i wideo</string>
<string name="fullscreen_orientation">Wyświetlanie pełnoekranowe</string>
<string name="portrait">Pionowa</string>
<string name="portrait">Wymuś tryb pionowy</string>
<string name="community">Społeczność</string>
<string name="discord">Discord</string>
<string name="matrix">Matrix</string>
@ -246,7 +246,7 @@
<string name="no_player_found">Nie znaleziono zewnętrznego odtwarzacza. Upewnij się, że masz takowy zainstalowany.</string>
<string name="data_saver_mode">Tryb oszczędzania danych</string>
<string name="data_saver_mode_summary">Pomiń miniatury i inne obrazy.</string>
<string name="search_history_summary">Zapamiętane wyszukiwania</string>
<string name="search_history_summary">Zapamiętaj wyszukiwania</string>
<string name="watch_history_summary">Przechowuj lokalnie historię obejrzanych filmów</string>
<string name="history_summary">Historia oglądania i wyszukiwania</string>
<string name="watch_positions_title">Zapamiętane pozycje odtwarzania</string>
@ -392,4 +392,15 @@
<string name="clear_bookmarks">Usuń zakładki</string>
<string name="bookmarks_empty">Nie dodano zakładek.</string>
<string name="queue_insert_related_videos">Wstaw powiązane filmy</string>
<string name="local_playlists">Lokalne playlisty</string>
<string name="not_enabled">Najpierw włącz kartę!</string>
<string name="select_other_start_tab">Najpierw wybierz inną kartę główną!</string>
<string name="brightness">Jasność</string>
<string name="volume">Głośność</string>
<string name="auto">Auto</string>
<string name="swipe_controls">Sterowanie gestami</string>
<string name="swipe_controls_summary">Steruj jasnością i głośnością za pomocą gestów.</string>
<string name="defaults">Domyślne</string>
<string name="show_open_with">Przycisk „Otwórz w…”</string>
<string name="show_open_with_summary">Pozwala pzekierować odtwarzanie do zewnętrznej aplikacji.</string>
</resources>

View File

@ -391,4 +391,13 @@
<string name="bookmark">Favorito</string>
<string name="clear_bookmarks">Limpar favoritos</string>
<string name="bookmarks_empty">Ainda não há favoritos!</string>
<string name="local_playlists">Playlists locais</string>
<string name="queue_insert_related_videos">Inserir vídeos relacionados</string>
<string name="not_enabled">Item de menu não ativado!</string>
<string name="auto">Auto</string>
<string name="swipe_controls">Controles deslizantes</string>
<string name="swipe_controls_summary">Use o gesto de deslizar para ajustar o brilho e o volume.</string>
<string name="select_other_start_tab">Selecione outra aba inicial primeiro!</string>
<string name="brightness">Brilho</string>
<string name="volume">Volume</string>
</resources>

View File

@ -183,7 +183,7 @@
<string name="auth_instance">Instância de autenticação</string>
<string name="auth_instance_summary">Utilize outra instância para invocações autenticadas.</string>
<string name="auth_instances">Escolha uma instância</string>
<string name="hls">Automático</string>
<string name="hls">HLS</string>
<string name="github">GitHub</string>
<string name="buffering_goal">Pré-carregamento</string>
<string name="buffering_goal_summary">Número máximo de segundos para colocar em memória.</string>
@ -224,9 +224,9 @@
<string name="always">Sempre</string>
<string name="selected">Seleção</string>
<string name="change_playback_speed">Velocidade de reprodução</string>
<string name="require_restart_message">Esta alteração exige que a aplicação seja reiniciada. Prima \'Ok\' para reiniciar agora.</string>
<string name="require_restart_message">Esta alteração exige que a aplicação seja reiniciada.</string>
<string name="require_restart">Tem que reiniciar a aplicação</string>
<string name="navLabelVisibility">Visibilidade da barra de navegação</string>
<string name="navLabelVisibility">Visibilidade do rótulo</string>
<string name="autoRotatePlayer_summary">Ativar modo de ecrã completo ao ligar o ecrã.</string>
<string name="pure_theme">Tema</string>
<string name="pure_theme_summary">Branco/preto puro</string>
@ -358,7 +358,41 @@
<string name="alternative_videos_layout">Esquema alternativo de vídeos</string>
<string name="defaultIconLight">Claro por omissão</string>
<string name="show_more">Mostrar mais</string>
<string name="time_code">Código de tempo</string>
<string name="time_code">Código de tempo (segundos)</string>
<string name="category_filler_description">Para cenas tangenciais adicionadas apenas para preencher ou humor não necessário para compreender o conteúdo do vídeo.</string>
<string name="category_music_offtopic_description">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.</string>
<string name="playlistCloned">Lista de reprodução clonada</string>
<string name="confirm_unsubscribing">Confirmar a anulação da subscrição</string>
<string name="local_playlists">Listas de jogos locais</string>
<string name="play_all">Reproduzir tudo</string>
<string name="confirm_unsubscribe">Tem a certeza de que quer anular a subscrição %1$s\?</string>
<string name="confirm_unsubscribing_summary">Mostrar um diálogo de confirmação antes de cancelar a inscrição.</string>
<string name="select_other_start_tab">Por favor, seleccione primeiro um outro separador de arranque!</string>
<string name="not_enabled">Item do menu não activado!</string>
<string name="time">Tempo</string>
<string name="start_time">Hora de início</string>
<string name="end_time">Tempo final</string>
<string name="notification_time">Hora de notificação</string>
<string name="notification_time_summary">Período de tempo em que é permitida a apresentação de notificações.</string>
<string name="navbar_order">Ordem</string>
<string name="alternative_trending_layout">Traçado alternativo de tendências</string>
<string name="layout">Layout</string>
<string name="alternative_player_layout">Layout alternativo do reprodutor</string>
<string name="alternative_player_layout_summary">Mostrar os vídeos relacionados como uma linha acima dos comentários em vez de abaixo.</string>
<string name="audio_track">Pista de áudio</string>
<string name="default_audio_track">Padrão</string>
<string name="unsupported_file_format">Formato de ficheiro não suportado!</string>
<string name="hls_instead_of_dash">Usar HLS</string>
<string name="hls_instead_of_dash_summary">Usar HLS em vez de DASH (será mais lento, não recomendado)</string>
<string name="auto_quality">Auto</string>
<string name="limit_to_runtime">Limite de tempo de execução</string>
<string name="open_queue_from_notification">Fila aberta de notificação</string>
<string name="trends">Tendências</string>
<string name="featured">Destaque</string>
<string name="trending">O que está nas tendências agora</string>
<string name="queue_insert_related_videos">Inserir vídeos relacionados</string>
<string name="bookmarks">Marcadores</string>
<string name="bookmark">Marcadores</string>
<string name="clear_bookmarks">Limpar Marcadores</string>
<string name="bookmarks_empty">Ainda sem marcadores!</string>
</resources>

View File

@ -158,7 +158,7 @@
<string name="instance_api_url">URL-адрес API экземпляра</string>
<string name="buffering_goal_summary">Максимальное количество секунд видео для буферизации</string>
<string name="clear_customInstances">Очистить добавленные</string>
<string name="related_streams_summary">Показывать похожие видео рядом с тем, что вы смотрите.</string>
<string name="related_streams_summary">Показывать связанные видео рядом с тем, что вы смотрите.</string>
<string name="invalid_url">Пожалуйста, введите рабочий URL</string>
<string name="buffering_goal">Предзагрузка</string>
<string name="downloads">Загрузки</string>
@ -391,4 +391,8 @@
<string name="bookmarks_empty">Закладок пока нет!</string>
<string name="featured">Рекомендации</string>
<string name="bookmark">Закладка</string>
<string name="select_other_start_tab">Сначала выберите другую начальную вкладку!</string>
<string name="local_playlists">Локальные плейлисты</string>
<string name="not_enabled">Пункт меню не включен!</string>
<string name="queue_insert_related_videos">Вставить связанные видео</string>
</resources>

View File

@ -392,4 +392,12 @@
<string name="clear_bookmarks">Yer imlerini temizle</string>
<string name="bookmarks_empty">Henüz yer imi yok!</string>
<string name="queue_insert_related_videos">İlgili videoları ekle</string>
<string name="local_playlists">Yerel oynatma listeleri</string>
<string name="not_enabled">Menü ögesi etkinleştirilmedi!</string>
<string name="select_other_start_tab">Lütfen önce başka bir başlangıç sekmesi seçin!</string>
<string name="volume">Ses</string>
<string name="auto">Otomatik</string>
<string name="swipe_controls">Kaydırma kontrolleri</string>
<string name="brightness">Parlaklık</string>
<string name="swipe_controls_summary">Parlaklığı ve sesi ayarlamak için kaydırma hareketini kullan.</string>
</resources>

View File

@ -392,4 +392,15 @@
<string name="clear_bookmarks">Очистити закладки</string>
<string name="bookmarks_empty">Ще немає закладок!</string>
<string name="queue_insert_related_videos">Вставити пов\'язані відео</string>
<string name="local_playlists">Локальні добірки</string>
<string name="not_enabled">Пункт меню не увімкнено!</string>
<string name="select_other_start_tab">Спочатку виберіть іншу вкладку для запуску!</string>
<string name="brightness">Яскравість</string>
<string name="auto">Авто</string>
<string name="swipe_controls">Керування посуваннями</string>
<string name="swipe_controls_summary">Для регулювання яскравості та гучності використовувати жест посування.</string>
<string name="volume">Гучність</string>
<string name="defaults">Типові</string>
<string name="show_open_with">Відкрити в</string>
<string name="show_open_with_summary">Показувати на програвачі кнопку для відкриття відео за допомогою стороннього застосунку.</string>
</resources>

View File

@ -6,7 +6,7 @@
<string name="yes"></string>
<string name="choose_quality_dialog">Chất lượng</string>
<string name="search_hint">Tìm kiếm</string>
<string name="videos">Videos</string>
<string name="videos">Các video</string>
<string name="subscribe">Đăng kí</string>
<string name="unsubscribe">Hủy đăng kí</string>
<string name="share">Chia sẻ</string>
@ -50,7 +50,7 @@
<string name="changeLanguage">Ngôn ngữ</string>
<string name="systemLanguage">Ngôn ngữ hệ thống</string>
<string name="instance">Server</string>
<string name="videoCount">%1$s videos</string>
<string name="videoCount">%1$s các video</string>
<string name="website">Website</string>
<string name="noInternet">Kết nối với mạng trước.</string>
<string name="retry">Thử lại</string>
@ -82,7 +82,7 @@
<string name="color_green">Màu xanh lá vui vẻ</string>
<string name="color_red">Màu đỏ resting</string>
<string name="sponsorblock_notifications">Thông báo</string>
<string name="piped">Piped</string>
<string name="piped">Đã thông qua</string>
<string name="youtube">YouTube</string>
<string name="update_available">Phiên bản %1$s đã có sẵn</string>
<string name="downloads">Tải xuống</string>
@ -131,7 +131,7 @@
<string name="category_filler">Filler Tangent / Trò đùa</string>
<string name="category_preview">Xem trước/Tóm tắt</string>
<string name="category_preview_description">Cho các phân đoạn mà thể hiện điều sắp diễn ra hay ở videos tới ở trong cùng series đó, nhưng không có cung cấp thông tin thêm. Nếu nó bao gồm các clips mà chỉ xuất hiện ở đây thì có thể không phải là một phân loại thích hợp.</string>
<string name="material_you">Material You</string>
<string name="material_you">Tài liệu bạn</string>
<string name="app_icon">Biểu tượng app</string>
<string name="enabled">Kích hoạt</string>
<string name="disabled">Vô hiệu hóa</string>
@ -311,7 +311,7 @@
<string name="resize_mode_zoom">Phóng to</string>
<string name="repeat_mode_none">Không</string>
<string name="maximum_image_cache">Dung lượng cache ảnh tối đa</string>
<string name="auth_instance_summary">Dùng instance khác để xác minh.</string>
<string name="auth_instance_summary">Dùng một yêu cầu khác cho cuộc gọi được xác minh.</string>
<string name="network_wifi">Chỉ trên Wi-Fi</string>
<string name="copied">Đã sao chép</string>
<string name="export_subscriptions">Xuất mục đăng ký</string>
@ -324,7 +324,7 @@
<string name="break_reminder">Nhắc nhở nghỉ giải lao</string>
<string name="take_a_break">Đến lúc nghỉ ngơi</string>
<string name="already_spent_time">Bạn đã dùng app được %1$s phút rồi, nghỉ ngơi nhá bạn yêu.</string>
<string name="yt_shorts">Shorts</string>
<string name="yt_shorts">Các đoạn video short</string>
<string name="backup_restore">Sao lưu và phục hồi</string>
<string name="backup">Sao lưu</string>
<string name="picture_in_picture">Ảnh trong ảnh</string>
@ -388,7 +388,19 @@
<string name="featured">Tính năng</string>
<string name="trending">Xu hướng hiện tại</string>
<string name="queue_insert_related_videos">Chèn thêm các video liên quan</string>
<string name="bookmarks">Bookmarks</string>
<string name="bookmarks">Đánh dấu trang</string>
<string name="clear_bookmarks">Xóa tất cả bookmark</string>
<string name="bookmarks_empty">Chưa có bookmark!</string>
<string name="local_playlists">Danh sách phát cục bộ</string>
<string name="not_enabled">Mục menu không được kích hoạt!</string>
<string name="brightness">Độ sáng</string>
<string name="volume">Âm lượng</string>
<string name="auto">Tự động</string>
<string name="show_open_with">Mở với</string>
<string name="defaults">Mặc định</string>
<string name="select_other_start_tab">Vui lòng chọn một tab bắt đầu khác trước tiên!</string>
<string name="swipe_controls">Điều khiển vuốt</string>
<string name="swipe_controls_summary">Sử dụng thao tác vuốt để điều chỉnh độ sáng và âm lượng.</string>
<string name="show_open_with_summary">Hiển thị một nút trong trình phát để mở video bằng ứng dụng của bên thứ ba.</string>
<string name="bookmark">Đánh dấu trang</string>
</resources>

View File

@ -392,4 +392,7 @@
<string name="clear_bookmarks">清除书签</string>
<string name="bookmarks_empty">尚无书签!</string>
<string name="queue_insert_related_videos">插入相关视频</string>
<string name="local_playlists">本地播放列表</string>
<string name="not_enabled">菜单项未启用!</string>
<string name="select_other_start_tab">请先选择其他启动选项卡!</string>
</resources>

View File

@ -387,7 +387,16 @@
<string name="bookmarks_empty">No bookmarks yet!</string>
<string name="queue_insert_related_videos">Insert related videos</string>
<string name="local_playlists">Local playlists</string>
<string name="not_enabled">Menu item not enabled!</string>
<string name="select_other_start_tab">Please select an other start tab first!</string>
<string name="brightness">Brightness</string>
<string name="volume">Volume</string>
<string name="auto">Auto</string>
<string name="swipe_controls">Swipe controls</string>
<string name="swipe_controls_summary">Use swipe gesture to adjust the brightness and volume.</string>
<string name="defaults">Defaults</string>
<string name="show_open_with">Open With</string>
<string name="show_open_with_summary">Show a button in the player to open the video with a third-party app.</string>
<!-- Notification channel strings -->
<string name="download_channel_name">Download Service</string>
<string name="download_channel_description">Shows a notification when downloading media.</string>

View File

@ -149,6 +149,18 @@
<item name="android:textColor">@android:color/white</item>
</style>
<style name="SwipeControlString">
<item name="android:gravity">center</item>
<item name="android:layout_gravity">center_vertical</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_width">wrap_content</item>
<item name="paddingEnd">5dp</item>
<item name="android:textSize">14sp</item>
<item name="android:textStyle">normal</item>
<item name="android:textColor">@android:color/white</item>
<item name="android:text">0</item>
</style>
<style name="Chip" parent="Widget.Material3.Chip.Suggestion">
<item name="android:layout_height">wrap_content</item>

View File

@ -2,49 +2,14 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory app:title="@string/player">
<PreferenceCategory app:title="@string/behavior">
<com.github.libretube.ui.views.SliderPreference
android:icon="@drawable/ic_speed"
app:defValue="1.0"
app:key="playback_speed"
app:stepSize="0.1"
app:title="@string/playback_speed"
app:valueFrom="0.2"
app:valueTo="4.0" />
<com.github.libretube.ui.views.SliderPreference
android:icon="@drawable/ic_skip"
app:defValue="10.0"
app:key="seek_increment"
app:stepSize="5.0"
app:title="@string/seek_increment"
app:valueFrom="5.0"
app:valueTo="60.0" />
<ListPreference
android:icon="@drawable/ic_time"
app:defaultValue="50"
app:entries="@array/bufferingGoal"
app:entryValues="@array/bufferingGoalValues"
app:key="buffering_goal"
app:summary="@string/buffering_goal_summary"
app:title="@string/buffering_goal" />
<ListPreference
android:defaultValue=""
android:icon="@drawable/ic_caption"
app:key="default_subtitle"
app:title="@string/default_subtitle_language" />
<ListPreference
android:defaultValue="fit"
android:entries="@array/resizeMode"
android:entryValues="@array/resizeModeValues"
android:icon="@drawable/ic_zoom"
app:key="player_resize_mode"
app:title="@string/player_resize_mode"
app:useSimpleSummaryProvider="true" />
<SwitchPreferenceCompat
android:defaultValue="true"
android:icon="@drawable/ic_swipe_gesture"
android:summary="@string/swipe_controls_summary"
app:key="player_swipe_controls"
app:title="@string/swipe_controls" />
<SwitchPreferenceCompat
android:defaultValue="false"
@ -53,45 +18,12 @@
app:key="skip_buttons"
app:title="@string/skip_buttons" />
</PreferenceCategory>
<PreferenceCategory app:title="@string/appearance">
<SwitchPreferenceCompat
android:icon="@drawable/ic_caption"
app:defaultValue="true"
app:key="system_caption_style"
app:title="@string/system_caption_style" />
<Preference
android:icon="@drawable/ic_settings"
app:key="caption_settings"
app:title="@string/caption_settings" />
</PreferenceCategory>
<PreferenceCategory app:title="@string/behavior">
<SwitchPreferenceCompat
android:icon="@drawable/ic_play_filled"
android:summary="@string/autoplay_summary"
app:defaultValue="true"
app:key="autoplay"
app:title="@string/player_autoplay" />
<SwitchPreferenceCompat
android:defaultValue="true"
android:icon="@drawable/ic_window"
app:key="picture_in_picture"
app:title="@string/picture_in_picture" />
<SwitchPreferenceCompat
android:icon="@drawable/ic_pause_filled"
android:summary="@string/pauseOnScreenOff_summary"
app:defaultValue="false"
app:key="pause_screen_off"
app:title="@string/pauseOnScreenOff" />
<SwitchPreferenceCompat
android:icon="@drawable/ic_rotating_circle"
android:summary="@string/autoRotatePlayer_summary"
@ -110,6 +42,43 @@
</PreferenceCategory>
<PreferenceCategory app:title="@string/player">
<com.github.libretube.ui.views.SliderPreference
android:icon="@drawable/ic_skip"
app:defValue="10.0"
app:key="seek_increment"
app:stepSize="5.0"
app:title="@string/seek_increment"
app:valueFrom="5.0"
app:valueTo="60.0" />
<ListPreference
android:icon="@drawable/ic_time"
app:defaultValue="50"
app:entries="@array/bufferingGoal"
app:entryValues="@array/bufferingGoalValues"
app:key="buffering_goal"
app:summary="@string/buffering_goal_summary"
app:title="@string/buffering_goal" />
</PreferenceCategory>
<PreferenceCategory app:title="@string/appearance">
<SwitchPreferenceCompat
android:icon="@drawable/ic_caption"
app:defaultValue="true"
app:key="system_caption_style"
app:title="@string/system_caption_style" />
<Preference
android:icon="@drawable/ic_settings"
app:key="caption_settings"
app:title="@string/caption_settings" />
</PreferenceCategory>
<PreferenceCategory app:title="@string/queue">
<SwitchPreferenceCompat
@ -120,4 +89,58 @@
</PreferenceCategory>
<PreferenceCategory app:title="@string/defaults">
<com.github.libretube.ui.views.SliderPreference
android:icon="@drawable/ic_speed"
app:defValue="1.0"
app:key="playback_speed"
app:stepSize="0.1"
app:title="@string/playback_speed"
app:valueFrom="0.2"
app:valueTo="4.0" />
<ListPreference
android:defaultValue=""
android:icon="@drawable/ic_caption"
app:key="default_subtitle"
app:title="@string/default_subtitle_language" />
<ListPreference
android:defaultValue="fit"
android:entries="@array/resizeMode"
android:entryValues="@array/resizeModeValues"
android:icon="@drawable/ic_zoom"
app:key="player_resize_mode"
app:title="@string/player_resize_mode"
app:useSimpleSummaryProvider="true" />
<SwitchPreferenceCompat
android:icon="@drawable/ic_play_filled"
android:summary="@string/autoplay_summary"
app:defaultValue="true"
app:key="autoplay"
app:title="@string/player_autoplay" />
</PreferenceCategory>
<PreferenceCategory app:title="@string/misc">
<SwitchPreferenceCompat
android:icon="@drawable/ic_pause_filled"
android:summary="@string/pauseOnScreenOff_summary"
app:defaultValue="false"
app:key="pause_screen_off"
app:title="@string/pauseOnScreenOff" />
<SwitchPreferenceCompat
android:icon="@drawable/ic_open"
android:summary="@string/show_open_with_summary"
app:defaultValue="false"
app:key="show_open_with"
app:title="@string/show_open_with" />
</PreferenceCategory>
</PreferenceScreen>

Binary file not shown.

View File

@ -1,5 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

12
gradlew vendored
View File

@ -55,7 +55,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@ -80,10 +80,10 @@ do
esac
done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
@ -143,12 +143,16 @@ fi
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac

1
gradlew.bat vendored
View File

@ -26,6 +26,7 @@ if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%