mirror of
https://github.com/libre-tube/LibreTube.git
synced 2024-12-14 22:30:30 +05:30
Merge branch 'libre-tube:master' into master
This commit is contained in:
commit
d1547fd9b4
@ -3,13 +3,13 @@
|
||||
This represents the larger, bigger impact features and enhancements we have planned. Features are planned, but do not represent a commitment to develop and can change at any time.
|
||||
|
||||
## Contribute
|
||||
Feel free to help us if you have any knowledge concerning the following planned features.
|
||||
Feel free to help us if you have any knowledge concerning the following planned features or anything else you imagine.
|
||||
|
||||
## Planned
|
||||
- Landscape mode support
|
||||
- Rewrite of the Player UI
|
||||
- Notifications for new streams
|
||||
|
||||
## Not planned
|
||||
- Google/MicroG Login
|
||||
- Support for anything else than Android (like iOS, Linux)
|
||||
- Support for Android TV
|
||||
|
@ -37,7 +37,7 @@
|
||||
android:exported="true"
|
||||
android:hardwareAccelerated="true"
|
||||
android:launchMode="singleTop"
|
||||
android:screenOrientation="userPortrait"
|
||||
android:screenOrientation="user"
|
||||
android:supportsPictureInPicture="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
@ -21,3 +21,14 @@ const val MATRIX_URL = "https://matrix.to/#/#LibreTube:matrix.org"
|
||||
const val DISCORD_URL = "https://discord.com/invite/Qc34xCj2GV"
|
||||
const val REDDIT_URL = "https://www.reddit.com/r/Libretube/"
|
||||
const val TWITTER_URL = "https://twitter.com/libretube"
|
||||
|
||||
/**
|
||||
* Share Dialog
|
||||
*/
|
||||
const val PIPED_FRONTEND_URL = "https://piped.kavin.rocks"
|
||||
const val YOUTUBE_FRONTEND_URL = "https://www.youtube.com"
|
||||
|
||||
/**
|
||||
* Retrofit Instance
|
||||
*/
|
||||
const val PIPED_API_URL = "https://pipedapi.kavin.rocks/"
|
||||
|
7
app/src/main/java/com/github/libretube/Globals.kt
Normal file
7
app/src/main/java/com/github/libretube/Globals.kt
Normal file
@ -0,0 +1,7 @@
|
||||
package com.github.libretube
|
||||
|
||||
object Globals {
|
||||
var isFullScreen = false
|
||||
var isMiniPlayerVisible = false
|
||||
var isCurrentViewMainSettings = true
|
||||
}
|
@ -3,7 +3,6 @@ package com.github.libretube.activities
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.content.res.Configuration
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
@ -25,10 +24,11 @@ import androidx.fragment.app.Fragment
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.findNavController
|
||||
import androidx.navigation.ui.setupWithNavController
|
||||
import com.github.libretube.Globals
|
||||
import com.github.libretube.PIPED_API_URL
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.databinding.ActivityMainBinding
|
||||
import com.github.libretube.fragments.PlayerFragment
|
||||
import com.github.libretube.fragments.isFullScreen
|
||||
import com.github.libretube.preferences.PreferenceHelper
|
||||
import com.github.libretube.services.ClosingService
|
||||
import com.github.libretube.util.ConnectionHelper
|
||||
@ -36,8 +36,8 @@ import com.github.libretube.util.CronetHelper
|
||||
import com.github.libretube.util.LocaleHelper
|
||||
import com.github.libretube.util.RetrofitInstance
|
||||
import com.github.libretube.util.ThemeHelper
|
||||
import com.google.android.material.color.DynamicColors
|
||||
import com.google.android.material.elevation.SurfaceColors
|
||||
import com.google.android.material.navigation.NavigationBarView
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
val TAG = "MainActivity"
|
||||
@ -48,20 +48,9 @@ class MainActivity : AppCompatActivity() {
|
||||
private var startFragmentId = R.id.homeFragment
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
/**
|
||||
* apply dynamic colors if enabled
|
||||
*/
|
||||
val materialColorsEnabled = PreferenceHelper
|
||||
.getString(this, "accent_color", "purple") == "my"
|
||||
if (materialColorsEnabled) {
|
||||
// apply dynamic colors to the current activity
|
||||
DynamicColors.applyToActivityIfAvailable(this)
|
||||
// apply dynamic colors to the all other activities
|
||||
DynamicColors.applyToActivitiesIfAvailable(application)
|
||||
}
|
||||
|
||||
// set the theme
|
||||
// set the app theme (e.g. Material You)
|
||||
ThemeHelper.updateTheme(this)
|
||||
|
||||
// set the language
|
||||
LocaleHelper.updateLanguage(this)
|
||||
|
||||
@ -73,14 +62,14 @@ class MainActivity : AppCompatActivity() {
|
||||
CronetHelper.initCronet(this.applicationContext)
|
||||
|
||||
RetrofitInstance.url =
|
||||
PreferenceHelper.getString(this, "selectInstance", "https://pipedapi.kavin.rocks/")!!
|
||||
PreferenceHelper.getString(this, "selectInstance", PIPED_API_URL)!!
|
||||
// set auth instance
|
||||
RetrofitInstance.authUrl =
|
||||
if (PreferenceHelper.getBoolean(this, "auth_instance_toggle", false)) {
|
||||
PreferenceHelper.getString(
|
||||
this,
|
||||
"selectAuthInstance",
|
||||
"https://pipedapi.kavin.rocks/"
|
||||
PIPED_API_URL
|
||||
)!!
|
||||
} else {
|
||||
RetrofitInstance.url
|
||||
@ -94,8 +83,6 @@ class MainActivity : AppCompatActivity() {
|
||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
|
||||
|
||||
navController = findNavController(R.id.fragment)
|
||||
binding.bottomNav.setupWithNavController(navController)
|
||||
|
||||
@ -124,6 +111,16 @@ class MainActivity : AppCompatActivity() {
|
||||
// navigate to the default fragment
|
||||
navController.navigate(startFragmentId)
|
||||
|
||||
val labelVisibilityMode = when (
|
||||
PreferenceHelper.getString(this, "label_visibility", "always")
|
||||
) {
|
||||
"always" -> NavigationBarView.LABEL_VISIBILITY_LABELED
|
||||
"selected" -> NavigationBarView.LABEL_VISIBILITY_SELECTED
|
||||
"never" -> NavigationBarView.LABEL_VISIBILITY_UNLABELED
|
||||
else -> NavigationBarView.LABEL_VISIBILITY_AUTO
|
||||
}
|
||||
binding.bottomNav.labelVisibilityMode = labelVisibilityMode
|
||||
|
||||
binding.bottomNav.setOnItemSelectedListener {
|
||||
// clear backstack if it's the start fragment
|
||||
if (startFragmentId == it.itemId) navController.backQueue.clear()
|
||||
@ -142,12 +139,6 @@ class MainActivity : AppCompatActivity() {
|
||||
false
|
||||
}
|
||||
|
||||
/**
|
||||
* don't remove this line
|
||||
* this prevents reselected items at the bottomNav to be duplicated in the backstack
|
||||
*/
|
||||
binding.bottomNav.setOnItemReselectedListener {}
|
||||
|
||||
binding.toolbar.title = ThemeHelper.getStyledAppName(this)
|
||||
|
||||
binding.toolbar.setNavigationOnClickListener {
|
||||
@ -293,14 +284,15 @@ class MainActivity : AppCompatActivity() {
|
||||
binding.mainMotionLayout.transitionToEnd()
|
||||
findViewById<ConstraintLayout>(R.id.main_container).isClickable = false
|
||||
val motionLayout = findViewById<MotionLayout>(R.id.playerMotionLayout)
|
||||
// set the animation duration
|
||||
motionLayout.setTransitionDuration(250)
|
||||
motionLayout.transitionToEnd()
|
||||
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
|
||||
with(motionLayout) {
|
||||
getConstraintSet(R.id.start).constrainHeight(R.id.player, 0)
|
||||
enableTransition(R.id.yt_transition, true)
|
||||
}
|
||||
findViewById<LinearLayout>(R.id.linLayout).visibility = View.VISIBLE
|
||||
isFullScreen = false
|
||||
Globals.isFullScreen = false
|
||||
}
|
||||
|
||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||
|
@ -5,25 +5,15 @@ import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.databinding.ActivityNointernetBinding
|
||||
import com.github.libretube.preferences.PreferenceHelper
|
||||
import com.github.libretube.util.ConnectionHelper
|
||||
import com.github.libretube.util.ThemeHelper
|
||||
import com.google.android.material.color.DynamicColors
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
|
||||
class NoInternetActivity : AppCompatActivity() {
|
||||
private lateinit var binding: ActivityNointernetBinding
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
/**
|
||||
* apply dynamic colors if enabled
|
||||
*/
|
||||
val materialColorsEnabled = PreferenceHelper
|
||||
.getString(this, "accent_color", "purple") == "my"
|
||||
if (materialColorsEnabled) {
|
||||
DynamicColors.applyToActivityIfAvailable(this)
|
||||
}
|
||||
|
||||
ThemeHelper.updateTheme(this)
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
binding = ActivityNointernetBinding.inflate(layoutInflater)
|
||||
|
@ -1,28 +1,22 @@
|
||||
package com.github.libretube.activities
|
||||
|
||||
import android.app.NotificationManager
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.app.ActivityCompat
|
||||
import com.github.libretube.Globals
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.databinding.ActivitySettingsBinding
|
||||
import com.github.libretube.preferences.MainSettings
|
||||
import com.github.libretube.util.ThemeHelper
|
||||
import com.google.android.material.color.DynamicColors
|
||||
|
||||
var isCurrentViewMainSettings = true
|
||||
var requireMainActivityRestart = false
|
||||
|
||||
class SettingsActivity : AppCompatActivity() {
|
||||
val TAG = "SettingsActivity"
|
||||
lateinit var binding: ActivitySettingsBinding
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
DynamicColors.applyToActivityIfAvailable(this)
|
||||
ThemeHelper.updateTheme(this)
|
||||
|
||||
// makes the preference dialogs use material dialogs
|
||||
// apply the theme for the preference dialogs
|
||||
setTheme(R.style.MaterialAlertDialog)
|
||||
|
||||
super.onCreate(savedInstanceState)
|
||||
@ -49,21 +43,11 @@ class SettingsActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
if (isCurrentViewMainSettings) {
|
||||
if (requireMainActivityRestart) {
|
||||
requireMainActivityRestart = false
|
||||
// kill player notification
|
||||
val nManager =
|
||||
this.getSystemService(NOTIFICATION_SERVICE) as NotificationManager
|
||||
nManager.cancelAll()
|
||||
ThemeHelper.restartMainActivity(this)
|
||||
ActivityCompat.finishAffinity(this)
|
||||
} else {
|
||||
super.onBackPressed()
|
||||
}
|
||||
if (Globals.isCurrentViewMainSettings) {
|
||||
super.onBackPressed()
|
||||
finishAndRemoveTask()
|
||||
} else {
|
||||
isCurrentViewMainSettings = true
|
||||
Globals.isCurrentViewMainSettings = true
|
||||
supportFragmentManager
|
||||
.beginTransaction()
|
||||
.replace(R.id.settings, MainSettings())
|
||||
|
@ -27,7 +27,7 @@ class ChaptersAdapter(
|
||||
chapterTitle.text = chapter.title
|
||||
|
||||
root.setOnClickListener {
|
||||
val chapterStart = chapter.start!!.toLong() * 1000 // s -> ms
|
||||
val chapterStart = chapter.start!! * 1000 // s -> ms
|
||||
exoPlayer.seekTo(chapterStart)
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package com.github.libretube.adapters
|
||||
import android.os.Bundle
|
||||
import android.text.format.DateUtils
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.os.bundleOf
|
||||
@ -17,8 +18,15 @@ import com.github.libretube.dialogs.PlaylistOptionsDialog
|
||||
import com.github.libretube.dialogs.VideoOptionsDialog
|
||||
import com.github.libretube.fragments.PlayerFragment
|
||||
import com.github.libretube.obj.SearchItem
|
||||
import com.github.libretube.obj.Subscribe
|
||||
import com.github.libretube.preferences.PreferenceHelper
|
||||
import com.github.libretube.util.RetrofitInstance
|
||||
import com.github.libretube.util.formatShort
|
||||
import com.squareup.picasso.Picasso
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.IOException
|
||||
|
||||
class SearchAdapter(
|
||||
private val searchItems: MutableList<SearchItem>,
|
||||
@ -134,6 +142,78 @@ class SearchAdapter(
|
||||
val bundle = bundleOf("channel_id" to item.url)
|
||||
activity.navController.navigate(R.id.channelFragment, bundle)
|
||||
}
|
||||
val channelId = item.url?.replace("/channel/", "")!!
|
||||
val token = PreferenceHelper.getToken(root.context)
|
||||
|
||||
// only show subscribe button if logged in
|
||||
if (token != "") isSubscribed(channelId, token, binding)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isSubscribed(channelId: String, token: String, binding: ChannelSearchRowBinding) {
|
||||
var isSubscribed = false
|
||||
|
||||
// check whether the user subscribed to the channel
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
val response = try {
|
||||
RetrofitInstance.authApi.isSubscribed(
|
||||
channelId,
|
||||
token
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
return@launch
|
||||
}
|
||||
|
||||
// if subscribed change text to unsubscribe
|
||||
if (response.subscribed == true) {
|
||||
isSubscribed = true
|
||||
binding.searchSubButton.text = binding.root.context.getString(R.string.unsubscribe)
|
||||
}
|
||||
|
||||
// make sub button visible and set the on click listeners to (un)subscribe
|
||||
if (response.subscribed != null) {
|
||||
binding.searchSubButton.visibility = View.VISIBLE
|
||||
|
||||
binding.searchSubButton.setOnClickListener {
|
||||
if (!isSubscribed) {
|
||||
subscribe(token, channelId)
|
||||
binding.searchSubButton.text =
|
||||
binding.root.context.getString(R.string.unsubscribe)
|
||||
isSubscribed = true
|
||||
} else {
|
||||
unsubscribe(token, channelId)
|
||||
binding.searchSubButton.text =
|
||||
binding.root.context.getString(R.string.subscribe)
|
||||
isSubscribed = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun subscribe(token: String, channelId: String) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
try {
|
||||
RetrofitInstance.authApi.subscribe(
|
||||
token,
|
||||
Subscribe(channelId)
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
return@launch
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun unsubscribe(token: String, channelId: String) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
try {
|
||||
RetrofitInstance.authApi.unsubscribe(
|
||||
token,
|
||||
Subscribe(channelId)
|
||||
)
|
||||
} catch (e: IOException) {
|
||||
return@launch
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,8 +17,6 @@ import com.squareup.picasso.Picasso
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import retrofit2.HttpException
|
||||
import java.io.IOException
|
||||
|
||||
class SubscriptionChannelAdapter(private val subscriptions: MutableList<Subscription>) :
|
||||
RecyclerView.Adapter<SubscriptionChannelViewHolder>() {
|
||||
@ -68,17 +66,14 @@ class SubscriptionChannelAdapter(private val subscriptions: MutableList<Subscrip
|
||||
private fun subscribe(context: Context, channelId: String) {
|
||||
fun run() {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val response = try {
|
||||
try {
|
||||
val token = PreferenceHelper.getToken(context)
|
||||
RetrofitInstance.authApi.subscribe(
|
||||
token,
|
||||
Subscribe(channelId)
|
||||
)
|
||||
} catch (e: IOException) {
|
||||
println(e)
|
||||
Log.e(TAG, "IOException, you might not have internet connection")
|
||||
} catch (e: HttpException) {
|
||||
Log.e(TAG, "HttpException, unexpected response")
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, e.toString())
|
||||
}
|
||||
subscribed = true
|
||||
isLoading = false
|
||||
@ -90,17 +85,14 @@ class SubscriptionChannelAdapter(private val subscriptions: MutableList<Subscrip
|
||||
private fun unsubscribe(context: Context, channelId: String) {
|
||||
fun run() {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val response = try {
|
||||
try {
|
||||
val token = PreferenceHelper.getToken(context)
|
||||
RetrofitInstance.authApi.unsubscribe(
|
||||
token,
|
||||
Subscribe(channelId)
|
||||
)
|
||||
} catch (e: IOException) {
|
||||
println(e)
|
||||
Log.e(TAG, "IOException, you might not have internet connection")
|
||||
} catch (e: HttpException) {
|
||||
Log.e(TAG, "HttpException, unexpected response")
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, e.toString())
|
||||
}
|
||||
subscribed = false
|
||||
isLoading = false
|
||||
|
@ -7,7 +7,6 @@ import android.widget.Toast
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.activities.requireMainActivityRestart
|
||||
import com.github.libretube.databinding.DialogDeleteAccountBinding
|
||||
import com.github.libretube.obj.DeleteUserRequest
|
||||
import com.github.libretube.preferences.PreferenceHelper
|
||||
@ -55,10 +54,10 @@ class DeleteAccountDialog : DialogFragment() {
|
||||
Toast.makeText(context, R.string.unknown_error, Toast.LENGTH_SHORT).show()
|
||||
return@launchWhenCreated
|
||||
}
|
||||
requireMainActivityRestart = true
|
||||
Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show()
|
||||
logout()
|
||||
dialog?.dismiss()
|
||||
val restartDialog = RequireRestartDialog()
|
||||
restartDialog.show(childFragmentManager, "RequireRestartDialog")
|
||||
}
|
||||
}
|
||||
run()
|
||||
|
@ -11,6 +11,7 @@ import android.util.Log
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.Toast
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.view.size
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.github.libretube.R
|
||||
@ -28,7 +29,6 @@ class DownloadDialog : DialogFragment() {
|
||||
private val TAG = "DownloadDialog"
|
||||
private lateinit var binding: DialogDownloadBinding
|
||||
|
||||
private lateinit var streams: Streams
|
||||
private lateinit var videoId: String
|
||||
private var duration = 0
|
||||
|
||||
@ -40,7 +40,7 @@ class DownloadDialog : DialogFragment() {
|
||||
val builder = MaterialAlertDialogBuilder(it)
|
||||
binding = DialogDownloadBinding.inflate(layoutInflater)
|
||||
|
||||
fetchStreams()
|
||||
fetchAvailableSources()
|
||||
|
||||
// request storage permissions if not granted yet
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
@ -83,10 +83,10 @@ class DownloadDialog : DialogFragment() {
|
||||
} ?: throw IllegalStateException("Activity cannot be null")
|
||||
}
|
||||
|
||||
private fun fetchStreams() {
|
||||
private fun fetchAvailableSources() {
|
||||
lifecycleScope.launchWhenCreated {
|
||||
val response = try {
|
||||
RetrofitInstance.api.getStreams(videoId!!)
|
||||
RetrofitInstance.api.getStreams(videoId)
|
||||
} catch (e: IOException) {
|
||||
println(e)
|
||||
Log.e(TAG, "IOException, you might not have internet connection")
|
||||
@ -102,8 +102,8 @@ class DownloadDialog : DialogFragment() {
|
||||
}
|
||||
|
||||
private fun initDownloadOptions(streams: Streams) {
|
||||
var vidName = arrayListOf<String>()
|
||||
var vidUrl = arrayListOf<String>()
|
||||
val vidName = arrayListOf<String>()
|
||||
val vidUrl = arrayListOf<String>()
|
||||
|
||||
// add empty selection
|
||||
vidName.add(getString(R.string.no_video))
|
||||
@ -111,13 +111,15 @@ class DownloadDialog : DialogFragment() {
|
||||
|
||||
// add all available video streams
|
||||
for (vid in streams.videoStreams!!) {
|
||||
val name = vid.quality + " " + vid.format
|
||||
vidName.add(name)
|
||||
vidUrl.add(vid.url!!)
|
||||
if (vid.url != null) {
|
||||
val name = vid.quality + " " + vid.format
|
||||
vidName.add(name)
|
||||
vidUrl.add(vid.url!!)
|
||||
}
|
||||
}
|
||||
|
||||
var audioName = arrayListOf<String>()
|
||||
var audioUrl = arrayListOf<String>()
|
||||
val audioName = arrayListOf<String>()
|
||||
val audioUrl = arrayListOf<String>()
|
||||
|
||||
// add empty selection
|
||||
audioName.add(getString(R.string.no_audio))
|
||||
@ -125,11 +127,14 @@ class DownloadDialog : DialogFragment() {
|
||||
|
||||
// add all available audio streams
|
||||
for (audio in streams.audioStreams!!) {
|
||||
val name = audio.quality + " " + audio.format
|
||||
audioName.add(name)
|
||||
audioUrl.add(audio.url!!)
|
||||
if (audio.url != null) {
|
||||
val name = audio.quality + " " + audio.format
|
||||
audioName.add(name)
|
||||
audioUrl.add(audio.url!!)
|
||||
}
|
||||
}
|
||||
|
||||
// initialize the video sources
|
||||
val videoArrayAdapter = ArrayAdapter(
|
||||
requireContext(),
|
||||
android.R.layout.simple_spinner_item,
|
||||
@ -137,8 +142,9 @@ class DownloadDialog : DialogFragment() {
|
||||
)
|
||||
videoArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
|
||||
binding.videoSpinner.adapter = videoArrayAdapter
|
||||
binding.videoSpinner.setSelection(1)
|
||||
if (binding.videoSpinner.size >= 1) binding.videoSpinner.setSelection(1)
|
||||
|
||||
// initialize the audio sources
|
||||
val audioArrayAdapter = ArrayAdapter(
|
||||
requireContext(),
|
||||
android.R.layout.simple_spinner_item,
|
||||
@ -146,7 +152,7 @@ class DownloadDialog : DialogFragment() {
|
||||
)
|
||||
audioArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
|
||||
binding.audioSpinner.adapter = audioArrayAdapter
|
||||
binding.audioSpinner.setSelection(1)
|
||||
if (binding.audioSpinner.size >= 1) binding.audioSpinner.setSelection(1)
|
||||
|
||||
binding.download.setOnClickListener {
|
||||
val selectedAudioUrl = audioUrl[binding.audioSpinner.selectedItemPosition]
|
||||
|
@ -7,7 +7,6 @@ import android.widget.Toast
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.activities.requireMainActivityRestart
|
||||
import com.github.libretube.databinding.DialogLoginBinding
|
||||
import com.github.libretube.obj.Login
|
||||
import com.github.libretube.preferences.PreferenceHelper
|
||||
@ -82,9 +81,9 @@ class LoginDialog : DialogFragment() {
|
||||
Toast.makeText(context, R.string.loggedIn, Toast.LENGTH_SHORT).show()
|
||||
PreferenceHelper.setToken(requireContext(), response.token!!)
|
||||
PreferenceHelper.setUsername(requireContext(), login.username!!)
|
||||
requireMainActivityRestart = true
|
||||
val restartDialog = RequireRestartDialog()
|
||||
restartDialog.show(parentFragmentManager, "RequireRestartDialog")
|
||||
dialog?.dismiss()
|
||||
activity?.recreate()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ import android.os.Bundle
|
||||
import android.widget.Toast
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.activities.requireMainActivityRestart
|
||||
import com.github.libretube.databinding.DialogLogoutBinding
|
||||
import com.github.libretube.preferences.PreferenceHelper
|
||||
import com.github.libretube.util.ThemeHelper
|
||||
@ -25,7 +24,6 @@ class LogoutDialog : DialogFragment() {
|
||||
binding.user.text =
|
||||
binding.user.text.toString() + " (" + user + ")"
|
||||
binding.logout.setOnClickListener {
|
||||
requireMainActivityRestart = true
|
||||
Toast.makeText(context, R.string.loggedout, Toast.LENGTH_SHORT).show()
|
||||
PreferenceHelper.setToken(requireContext(), "")
|
||||
dialog?.dismiss()
|
||||
|
@ -0,0 +1,25 @@
|
||||
package com.github.libretube.dialogs
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.util.ThemeHelper
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
|
||||
class RequireRestartDialog : DialogFragment() {
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
return activity?.let {
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.require_restart)
|
||||
.setMessage(R.string.require_restart_message)
|
||||
.setPositiveButton(R.string.okay) { _, _ ->
|
||||
activity?.recreate()
|
||||
ThemeHelper.restartMainActivity(requireContext())
|
||||
}
|
||||
.setNegativeButton(R.string.cancel) { _, _ -> }
|
||||
.create()
|
||||
} ?: throw IllegalStateException("Activity cannot be null")
|
||||
}
|
||||
}
|
@ -4,7 +4,9 @@ import android.app.Dialog
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import com.github.libretube.PIPED_FRONTEND_URL
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.YOUTUBE_FRONTEND_URL
|
||||
import com.github.libretube.preferences.PreferenceHelper
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
|
||||
@ -30,8 +32,8 @@ class ShareDialog(
|
||||
shareOptions
|
||||
) { _, which ->
|
||||
val host = when (which) {
|
||||
0 -> "https://piped.kavin.rocks"
|
||||
1 -> "https://youtube.com"
|
||||
0 -> PIPED_FRONTEND_URL
|
||||
1 -> YOUTUBE_FRONTEND_URL
|
||||
// only available for custom instances
|
||||
else -> instanceUrl
|
||||
}
|
||||
@ -57,7 +59,7 @@ class ShareDialog(
|
||||
val instancePref = PreferenceHelper.getString(
|
||||
requireContext(),
|
||||
"selectInstance",
|
||||
"https://pipedapi.kavin.rocks"
|
||||
PIPED_FRONTEND_URL
|
||||
)
|
||||
|
||||
// get the api urls of the other custom instances
|
||||
|
@ -16,7 +16,6 @@ import com.github.libretube.obj.Subscribe
|
||||
import com.github.libretube.preferences.PreferenceHelper
|
||||
import com.github.libretube.util.RetrofitInstance
|
||||
import com.github.libretube.util.formatShort
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.squareup.picasso.Picasso
|
||||
import retrofit2.HttpException
|
||||
import java.io.IOException
|
||||
@ -58,7 +57,7 @@ class ChannelFragment : Fragment() {
|
||||
binding.channelRefresh.isRefreshing = true
|
||||
fetchChannel()
|
||||
if (PreferenceHelper.getToken(requireContext()) != "") {
|
||||
isSubscribed(binding.channelSubscribe)
|
||||
isSubscribed()
|
||||
}
|
||||
}
|
||||
refreshChannel()
|
||||
@ -81,7 +80,7 @@ class ChannelFragment : Fragment() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun isSubscribed(button: MaterialButton) {
|
||||
private fun isSubscribed() {
|
||||
@SuppressLint("ResourceAsColor")
|
||||
fun run() {
|
||||
lifecycleScope.launchWhenCreated {
|
||||
@ -91,28 +90,26 @@ class ChannelFragment : Fragment() {
|
||||
channelId!!,
|
||||
token
|
||||
)
|
||||
} catch (e: IOException) {
|
||||
println(e)
|
||||
Log.e(TAG, "IOException, you might not have internet connection")
|
||||
return@launchWhenCreated
|
||||
} catch (e: HttpException) {
|
||||
Log.e(TAG, "HttpException, unexpected response")
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, e.toString())
|
||||
return@launchWhenCreated
|
||||
}
|
||||
|
||||
runOnUiThread {
|
||||
if (response.subscribed == true) {
|
||||
isSubscribed = true
|
||||
button.text = getString(R.string.unsubscribe)
|
||||
binding.channelSubscribe.text = getString(R.string.unsubscribe)
|
||||
}
|
||||
if (response.subscribed != null) {
|
||||
button.setOnClickListener {
|
||||
if (isSubscribed) {
|
||||
unsubscribe()
|
||||
button.text = getString(R.string.subscribe)
|
||||
} else {
|
||||
subscribe()
|
||||
button.text = getString(R.string.unsubscribe)
|
||||
binding.channelSubscribe.apply {
|
||||
setOnClickListener {
|
||||
text = if (isSubscribed) {
|
||||
unsubscribe()
|
||||
getString(R.string.subscribe)
|
||||
} else {
|
||||
subscribe()
|
||||
getString(R.string.unsubscribe)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -125,19 +122,14 @@ class ChannelFragment : Fragment() {
|
||||
private fun subscribe() {
|
||||
fun run() {
|
||||
lifecycleScope.launchWhenCreated {
|
||||
val response = try {
|
||||
try {
|
||||
val token = PreferenceHelper.getToken(requireContext())
|
||||
RetrofitInstance.authApi.subscribe(
|
||||
token,
|
||||
Subscribe(channelId)
|
||||
)
|
||||
} catch (e: IOException) {
|
||||
println(e)
|
||||
Log.e(TAG, "IOException, you might not have internet connection")
|
||||
return@launchWhenCreated
|
||||
} catch (e: HttpException) {
|
||||
Log.e(TAG, "HttpException, unexpected response$e")
|
||||
return@launchWhenCreated
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, e.toString())
|
||||
}
|
||||
isSubscribed = true
|
||||
}
|
||||
@ -148,19 +140,14 @@ class ChannelFragment : Fragment() {
|
||||
private fun unsubscribe() {
|
||||
fun run() {
|
||||
lifecycleScope.launchWhenCreated {
|
||||
val response = try {
|
||||
try {
|
||||
val token = PreferenceHelper.getToken(requireContext())
|
||||
RetrofitInstance.authApi.unsubscribe(
|
||||
token,
|
||||
Subscribe(channelId)
|
||||
)
|
||||
} catch (e: IOException) {
|
||||
println(e)
|
||||
Log.e(TAG, "IOException, you might not have internet connection")
|
||||
return@launchWhenCreated
|
||||
} catch (e: HttpException) {
|
||||
Log.e(TAG, "HttpException, unexpected response")
|
||||
return@launchWhenCreated
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, e.toString())
|
||||
}
|
||||
isSubscribed = false
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.github.libretube.Globals
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.adapters.PlaylistsAdapter
|
||||
import com.github.libretube.databinding.FragmentLibraryBinding
|
||||
@ -77,7 +78,7 @@ class LibraryFragment : Fragment() {
|
||||
override fun onResume() {
|
||||
// optimize CreatePlaylistFab bottom margin if miniPlayer active
|
||||
val layoutParams = binding.createPlaylist.layoutParams as ViewGroup.MarginLayoutParams
|
||||
layoutParams.bottomMargin = if (isMiniPlayerVisible) 180 else 64
|
||||
layoutParams.bottomMargin = if (Globals.isMiniPlayerVisible) 180 else 64
|
||||
binding.createPlaylist.layoutParams = layoutParams
|
||||
super.onResume()
|
||||
}
|
||||
|
@ -6,6 +6,8 @@ import android.app.PictureInPictureParams
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.Color
|
||||
import android.graphics.Rect
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
@ -31,6 +33,7 @@ import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.github.libretube.Globals
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.activities.MainActivity
|
||||
import com.github.libretube.activities.hideKeyboard
|
||||
@ -53,6 +56,7 @@ import com.github.libretube.obj.Streams
|
||||
import com.github.libretube.obj.Subscribe
|
||||
import com.github.libretube.preferences.PreferenceHelper
|
||||
import com.github.libretube.services.IS_DOWNLOAD_RUNNING
|
||||
import com.github.libretube.util.BackgroundMode
|
||||
import com.github.libretube.util.CronetHelper
|
||||
import com.github.libretube.util.DescriptionAdapter
|
||||
import com.github.libretube.util.RetrofitInstance
|
||||
@ -93,9 +97,6 @@ import java.io.IOException
|
||||
import java.util.concurrent.Executors
|
||||
import kotlin.math.abs
|
||||
|
||||
var isFullScreen = false
|
||||
var isMiniPlayerVisible = false
|
||||
|
||||
class PlayerFragment : Fragment() {
|
||||
|
||||
private val TAG = "PlayerFragment"
|
||||
@ -137,8 +138,11 @@ class PlayerFragment : Fragment() {
|
||||
private lateinit var title: String
|
||||
private lateinit var uploader: String
|
||||
private lateinit var thumbnailUrl: String
|
||||
private lateinit var chapters: List<ChapterSegment>
|
||||
private val sponsorBlockPrefs = SponsorBlockPrefs()
|
||||
|
||||
private var autoRotationEnabled = true
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
arguments?.let {
|
||||
@ -162,6 +166,34 @@ class PlayerFragment : Fragment() {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
hideKeyboard()
|
||||
|
||||
// save whether auto rotation is enabled
|
||||
autoRotationEnabled = PreferenceHelper.getBoolean(
|
||||
requireContext(),
|
||||
"auto_fullscreen",
|
||||
false
|
||||
)
|
||||
val mainActivity = activity as MainActivity
|
||||
if (autoRotationEnabled) {
|
||||
// enable auto rotation
|
||||
mainActivity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER
|
||||
onConfigurationChanged(resources.configuration)
|
||||
} else {
|
||||
// go to portrait mode
|
||||
mainActivity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
|
||||
}
|
||||
|
||||
// save whether related streams and autoplay are enabled
|
||||
autoplay = PreferenceHelper.getBoolean(
|
||||
requireContext(),
|
||||
"autoplay",
|
||||
false
|
||||
)
|
||||
relatedStreamsEnabled = PreferenceHelper.getBoolean(
|
||||
requireContext(),
|
||||
"related_streams_toggle",
|
||||
true
|
||||
)
|
||||
|
||||
setSponsorBlockPrefs()
|
||||
createExoPlayer(view)
|
||||
initializeTransitionLayout(view)
|
||||
@ -205,11 +237,11 @@ class PlayerFragment : Fragment() {
|
||||
val mainMotionLayout =
|
||||
mainActivity.binding.mainMotionLayout
|
||||
if (currentId == eId) {
|
||||
isMiniPlayerVisible = true
|
||||
Globals.isMiniPlayerVisible = true
|
||||
exoPlayerView.useController = false
|
||||
mainMotionLayout.progress = 1F
|
||||
} else if (currentId == sId) {
|
||||
isMiniPlayerVisible = false
|
||||
Globals.isMiniPlayerVisible = false
|
||||
exoPlayerView.useController = true
|
||||
mainMotionLayout.progress = 0F
|
||||
}
|
||||
@ -228,19 +260,17 @@ class PlayerFragment : Fragment() {
|
||||
binding.playerMotionLayout.transitionToStart()
|
||||
|
||||
binding.closeImageView.setOnClickListener {
|
||||
isMiniPlayerVisible = false
|
||||
Globals.isMiniPlayerVisible = false
|
||||
binding.playerMotionLayout.transitionToEnd()
|
||||
val mainActivity = activity as MainActivity
|
||||
mainActivity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
|
||||
mainActivity.supportFragmentManager.beginTransaction()
|
||||
.remove(this)
|
||||
.commit()
|
||||
}
|
||||
playerBinding.closeImageButton.setOnClickListener {
|
||||
isMiniPlayerVisible = false
|
||||
Globals.isMiniPlayerVisible = false
|
||||
binding.playerMotionLayout.transitionToEnd()
|
||||
val mainActivity = activity as MainActivity
|
||||
mainActivity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
|
||||
mainActivity.supportFragmentManager.beginTransaction()
|
||||
.remove(this)
|
||||
.commit()
|
||||
@ -259,9 +289,7 @@ class PlayerFragment : Fragment() {
|
||||
|
||||
// video description and chapters toggle
|
||||
binding.playerTitleLayout.setOnClickListener {
|
||||
binding.playerDescriptionArrow.animate().rotationBy(180F).setDuration(250).start()
|
||||
binding.descLinLayout.visibility =
|
||||
if (binding.descLinLayout.isVisible) View.GONE else View.VISIBLE
|
||||
toggleDescription()
|
||||
}
|
||||
|
||||
binding.commentsToggle.setOnClickListener {
|
||||
@ -269,10 +297,12 @@ class PlayerFragment : Fragment() {
|
||||
}
|
||||
|
||||
// FullScreen button trigger
|
||||
// hide fullscreen button if auto rotation enabled
|
||||
playerBinding.fullscreen.visibility = if (autoRotationEnabled) View.GONE else View.VISIBLE
|
||||
playerBinding.fullscreen.setOnClickListener {
|
||||
// hide player controller
|
||||
exoPlayerView.hideController()
|
||||
if (!isFullScreen) {
|
||||
if (!Globals.isFullScreen) {
|
||||
// go to fullscreen mode
|
||||
setFullscreen()
|
||||
} else {
|
||||
@ -340,27 +370,27 @@ class PlayerFragment : Fragment() {
|
||||
val fullscreenOrientationPref = PreferenceHelper
|
||||
.getString(requireContext(), "fullscreen_orientation", "ratio")
|
||||
|
||||
val scaleFactor = 1.3F
|
||||
playerBinding.exoPlayPause.scaleX = scaleFactor
|
||||
playerBinding.exoPlayPause.scaleY = scaleFactor
|
||||
scaleControls(1.3F)
|
||||
|
||||
val orientation = when (fullscreenOrientationPref) {
|
||||
"ratio" -> {
|
||||
val videoSize = exoPlayer.videoSize
|
||||
// probably a youtube shorts video
|
||||
Log.e(TAG, videoSize.height.toString() + " " + videoSize.width.toString())
|
||||
if (videoSize.height > videoSize.width) ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
|
||||
// a video with normal aspect ratio
|
||||
else ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
|
||||
if (!autoRotationEnabled) {
|
||||
// different orientations of the video are only available when auto rotation is disabled
|
||||
val orientation = when (fullscreenOrientationPref) {
|
||||
"ratio" -> {
|
||||
val videoSize = exoPlayer.videoSize
|
||||
// probably a youtube shorts video
|
||||
if (videoSize.height > videoSize.width) ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
|
||||
// a video with normal aspect ratio
|
||||
else ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
|
||||
}
|
||||
"auto" -> ActivityInfo.SCREEN_ORIENTATION_USER
|
||||
"landscape" -> ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
|
||||
"portrait" -> ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
|
||||
else -> ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
|
||||
}
|
||||
"auto" -> ActivityInfo.SCREEN_ORIENTATION_USER
|
||||
"landscape" -> ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
|
||||
"portrait" -> ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
|
||||
else -> ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
|
||||
mainActivity.requestedOrientation = orientation
|
||||
}
|
||||
mainActivity.requestedOrientation = orientation
|
||||
|
||||
isFullScreen = true
|
||||
Globals.isFullScreen = true
|
||||
}
|
||||
|
||||
private fun unsetFullscreen() {
|
||||
@ -375,14 +405,26 @@ class PlayerFragment : Fragment() {
|
||||
playerBinding.fullscreen.setImageResource(R.drawable.ic_fullscreen)
|
||||
playerBinding.exoTitle.visibility = View.INVISIBLE
|
||||
|
||||
val scaleFactor = 1F
|
||||
scaleControls(1F)
|
||||
|
||||
if (!autoRotationEnabled) {
|
||||
// switch back to portrait mode if auto rotation disabled
|
||||
val mainActivity = activity as MainActivity
|
||||
mainActivity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
|
||||
}
|
||||
|
||||
Globals.isFullScreen = false
|
||||
}
|
||||
|
||||
private fun scaleControls(scaleFactor: Float) {
|
||||
playerBinding.exoPlayPause.scaleX = scaleFactor
|
||||
playerBinding.exoPlayPause.scaleY = scaleFactor
|
||||
}
|
||||
|
||||
val mainActivity = activity as MainActivity
|
||||
mainActivity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
|
||||
|
||||
isFullScreen = false
|
||||
private fun toggleDescription() {
|
||||
binding.playerDescriptionArrow.animate().rotationBy(180F).setDuration(250).start()
|
||||
binding.descLinLayout.visibility =
|
||||
if (binding.descLinLayout.isVisible) View.GONE else View.VISIBLE
|
||||
}
|
||||
|
||||
private fun toggleComments() {
|
||||
@ -492,16 +534,12 @@ class PlayerFragment : Fragment() {
|
||||
uploader = response.uploader!!
|
||||
thumbnailUrl = response.thumbnailUrl!!
|
||||
|
||||
// save whether related streams and autoplay are enabled
|
||||
autoplay = PreferenceHelper.getBoolean(requireContext(), "autoplay", false)
|
||||
relatedStreamsEnabled =
|
||||
PreferenceHelper.getBoolean(requireContext(), "related_streams_toggle", true)
|
||||
// save related streams for autoplay
|
||||
relatedStreams = response.relatedStreams
|
||||
|
||||
runOnUiThread {
|
||||
// set media sources for the player
|
||||
setResolutionAndSubtitles(view, response)
|
||||
setResolutionAndSubtitles(response)
|
||||
prepareExoPlayerView()
|
||||
initializePlayerView(view, response)
|
||||
seekToWatchPosition()
|
||||
@ -682,7 +720,6 @@ class PlayerFragment : Fragment() {
|
||||
setShowSubtitleButton(true)
|
||||
setShowNextButton(false)
|
||||
setShowPreviousButton(false)
|
||||
setRepeatToggleModes(RepeatModeUtil.REPEAT_TOGGLE_MODE_ALL)
|
||||
// controllerShowTimeoutMs = 1500
|
||||
controllerHideOnTouch = true
|
||||
useController = false
|
||||
@ -709,7 +746,33 @@ class PlayerFragment : Fragment() {
|
||||
enableDoubleTapToSeek()
|
||||
|
||||
// init the chapters recyclerview
|
||||
if (response.chapters != null) initializeChapters(response.chapters)
|
||||
if (response.chapters != null) {
|
||||
chapters = response.chapters
|
||||
initializeChapters()
|
||||
}
|
||||
|
||||
// set default playback speed
|
||||
val playbackSpeed =
|
||||
PreferenceHelper.getString(requireContext(), "playback_speed", "1F")!!
|
||||
val playbackSpeeds = context?.resources?.getStringArray(R.array.playbackSpeed)!!
|
||||
val playbackSpeedValues =
|
||||
context?.resources?.getStringArray(R.array.playbackSpeedValues)!!
|
||||
exoPlayer.setPlaybackSpeed(playbackSpeed.toFloat())
|
||||
val speedIndex = playbackSpeedValues.indexOf(playbackSpeed)
|
||||
playerBinding.speedText.text = playbackSpeeds[speedIndex]
|
||||
|
||||
// change playback speed button
|
||||
playerBinding.speedText.setOnClickListener {
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.change_playback_speed)
|
||||
.setItems(playbackSpeeds) { _, index ->
|
||||
// set the new playback speed
|
||||
val newPlaybackSpeed = playbackSpeedValues[index].toFloat()
|
||||
exoPlayer.setPlaybackSpeed(newPlaybackSpeed)
|
||||
playerBinding.speedText.text = playbackSpeeds[index]
|
||||
}
|
||||
.show()
|
||||
}
|
||||
|
||||
// Listener for play and pause icon change
|
||||
exoPlayer.addListener(object : Player.Listener {
|
||||
@ -777,11 +840,37 @@ class PlayerFragment : Fragment() {
|
||||
}
|
||||
})
|
||||
|
||||
// repeat toggle button
|
||||
playerBinding.repeatToggle.setOnClickListener {
|
||||
if (exoPlayer.repeatMode == RepeatModeUtil.REPEAT_TOGGLE_MODE_ALL) {
|
||||
// turn off repeat mode
|
||||
exoPlayer.repeatMode = RepeatModeUtil.REPEAT_TOGGLE_MODE_NONE
|
||||
playerBinding.repeatToggle.setColorFilter(Color.GRAY)
|
||||
} else {
|
||||
exoPlayer.repeatMode = RepeatModeUtil.REPEAT_TOGGLE_MODE_ALL
|
||||
playerBinding.repeatToggle.setColorFilter(Color.WHITE)
|
||||
}
|
||||
}
|
||||
|
||||
// share button
|
||||
binding.relPlayerShare.setOnClickListener {
|
||||
val shareDialog = ShareDialog(videoId!!, false)
|
||||
shareDialog.show(childFragmentManager, "ShareDialog")
|
||||
}
|
||||
|
||||
binding.relPlayerBackground.setOnClickListener {
|
||||
// pause the current player
|
||||
exoPlayer.pause()
|
||||
|
||||
// start the background mode
|
||||
BackgroundMode
|
||||
.getInstance()
|
||||
.playOnBackgroundMode(
|
||||
requireContext(),
|
||||
videoId!!
|
||||
)
|
||||
}
|
||||
|
||||
// check if livestream
|
||||
if (response.duration!! > 0) {
|
||||
// download clicked
|
||||
@ -850,7 +939,7 @@ class PlayerFragment : Fragment() {
|
||||
if (token != "") {
|
||||
val channelId = response.uploaderUrl?.replace("/channel/", "")
|
||||
isSubscribed(binding.playerSubscribe, channelId!!)
|
||||
binding.save.setOnClickListener {
|
||||
binding.relPlayerSave.setOnClickListener {
|
||||
val newFragment = AddtoPlaylistDialog()
|
||||
val bundle = Bundle()
|
||||
bundle.putString("videoId", videoId)
|
||||
@ -903,6 +992,12 @@ class PlayerFragment : Fragment() {
|
||||
)
|
||||
}
|
||||
|
||||
private fun disableDoubleTapToSeek() {
|
||||
// disable fast forward and rewind by double tapping
|
||||
binding.forwardFL.visibility = View.GONE
|
||||
binding.rewindFL.visibility = View.GONE
|
||||
}
|
||||
|
||||
// toggle the visibility of the player controller
|
||||
private fun toggleController() {
|
||||
if (exoPlayerView.isControllerFullyVisible) exoPlayerView.hideController()
|
||||
@ -917,10 +1012,15 @@ class PlayerFragment : Fragment() {
|
||||
}
|
||||
|
||||
override fun onScrubMove(timeBar: TimeBar, position: Long) {
|
||||
exoPlayer.seekTo(position)
|
||||
val minTimeDiff = 10 * 1000 // 10s
|
||||
// get the difference between the new and the old position
|
||||
val diff = abs(exoPlayer.currentPosition - position)
|
||||
// seek only when the difference is greater than 10 seconds
|
||||
if (diff >= minTimeDiff) exoPlayer.seekTo(position)
|
||||
}
|
||||
|
||||
override fun onScrubStop(timeBar: TimeBar, position: Long, canceled: Boolean) {
|
||||
exoPlayer.seekTo(position)
|
||||
exoPlayer.play()
|
||||
Handler(Looper.getMainLooper()).postDelayed({
|
||||
exoPlayerView.hideController()
|
||||
@ -929,15 +1029,69 @@ class PlayerFragment : Fragment() {
|
||||
})
|
||||
}
|
||||
|
||||
private fun initializeChapters(chapters: List<ChapterSegment>) {
|
||||
private fun initializeChapters() {
|
||||
if (chapters.isNotEmpty()) {
|
||||
// enable chapters in the video description
|
||||
binding.chaptersRecView.layoutManager =
|
||||
LinearLayoutManager(this.context, LinearLayoutManager.HORIZONTAL, false)
|
||||
LinearLayoutManager(
|
||||
context,
|
||||
LinearLayoutManager.HORIZONTAL,
|
||||
false
|
||||
)
|
||||
binding.chaptersRecView.adapter = ChaptersAdapter(chapters, exoPlayer)
|
||||
binding.chaptersRecView.visibility = View.VISIBLE
|
||||
|
||||
// enable the chapters dialog in the player
|
||||
val titles = mutableListOf<String>()
|
||||
chapters.forEach {
|
||||
titles += it.title!!
|
||||
}
|
||||
playerBinding.chapterLL.visibility = View.VISIBLE
|
||||
playerBinding.chapterLL.setOnClickListener {
|
||||
if (Globals.isFullScreen) {
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.chapters)
|
||||
.setItems(titles.toTypedArray()) { _, index ->
|
||||
val position = chapters[index].start!! * 1000
|
||||
exoPlayer.seekTo(position)
|
||||
}
|
||||
.show()
|
||||
} else {
|
||||
toggleDescription()
|
||||
}
|
||||
}
|
||||
setCurrentChapterName()
|
||||
}
|
||||
}
|
||||
|
||||
// set the name of the video chapter in the exoPlayerView
|
||||
private fun setCurrentChapterName() {
|
||||
// call the function again in 100ms
|
||||
exoPlayerView.postDelayed(this::setCurrentChapterName, 100)
|
||||
|
||||
val chapterName = getCurrentChapterName()
|
||||
|
||||
// change the chapter name textView text to the chapterName
|
||||
if (chapterName != null && chapterName != playerBinding.chapterName.text) {
|
||||
playerBinding.chapterName.text = chapterName
|
||||
}
|
||||
}
|
||||
|
||||
// get the name of the currently played chapter
|
||||
private fun getCurrentChapterName(): String? {
|
||||
val currentPosition = exoPlayer.currentPosition
|
||||
var chapterName: String? = null
|
||||
|
||||
chapters.forEach {
|
||||
// check whether the chapter start is greater than the current player position
|
||||
if (currentPosition >= it.start!! * 1000) {
|
||||
// save chapter title if found
|
||||
chapterName = it.title
|
||||
}
|
||||
}
|
||||
return chapterName
|
||||
}
|
||||
|
||||
private fun setMediaSource(
|
||||
subtitle: MutableList<SubtitleConfiguration>,
|
||||
videoUri: Uri,
|
||||
@ -960,7 +1114,7 @@ class PlayerFragment : Fragment() {
|
||||
exoPlayer.setMediaSource(mergeSource)
|
||||
}
|
||||
|
||||
private fun setResolutionAndSubtitles(view: View, response: Streams) {
|
||||
private fun setResolutionAndSubtitles(response: Streams) {
|
||||
val videoFormatPreference =
|
||||
PreferenceHelper.getString(requireContext(), "player_video_format", "WEBM")
|
||||
val defres = PreferenceHelper.getString(requireContext(), "default_res", "")!!
|
||||
@ -976,8 +1130,8 @@ class PlayerFragment : Fragment() {
|
||||
|
||||
for (vid in response.videoStreams!!) {
|
||||
// append quality to list if it has the preferred format (e.g. MPEG)
|
||||
if (vid.format.equals(videoFormatPreference)) { // preferred format
|
||||
videosNameArray += vid.quality!!
|
||||
if (vid.format.equals(videoFormatPreference) && vid.url != null) { // preferred format
|
||||
videosNameArray += vid.quality.toString()
|
||||
videosUrlArray += vid.url!!.toUri()
|
||||
} else if (vid.quality.equals("LBRY") && vid.format.equals("MP4")) { // LBRY MP4 format)
|
||||
videosNameArray += "LBRY MP4"
|
||||
@ -1039,7 +1193,7 @@ class PlayerFragment : Fragment() {
|
||||
}
|
||||
}
|
||||
|
||||
playerBinding.qualityLinLayout.setOnClickListener {
|
||||
playerBinding.qualityText.setOnClickListener {
|
||||
// Dialog for quality selection
|
||||
val builder: MaterialAlertDialogBuilder? = activity?.let {
|
||||
MaterialAlertDialogBuilder(it)
|
||||
@ -1074,13 +1228,8 @@ class PlayerFragment : Fragment() {
|
||||
}
|
||||
|
||||
private fun createExoPlayer(view: View) {
|
||||
val playbackSpeed =
|
||||
PreferenceHelper.getString(requireContext(), "playback_speed", "1F")?.toFloat()
|
||||
// multiply by thousand: s -> ms
|
||||
val bufferingGoal =
|
||||
PreferenceHelper.getString(requireContext(), "buffering_goal", "50")?.toInt()!! * 1000
|
||||
val seekIncrement =
|
||||
PreferenceHelper.getString(requireContext(), "seek_increment", "5")?.toLong()!! * 1000
|
||||
|
||||
val cronetEngine: CronetEngine = CronetHelper.getCronetEngine()
|
||||
val cronetDataSourceFactory: CronetDataSource.Factory =
|
||||
@ -1112,13 +1261,9 @@ class PlayerFragment : Fragment() {
|
||||
exoPlayer = ExoPlayer.Builder(view.context)
|
||||
.setMediaSourceFactory(DefaultMediaSourceFactory(dataSourceFactory))
|
||||
.setLoadControl(loadControl)
|
||||
.setSeekBackIncrementMs(seekIncrement)
|
||||
.setSeekForwardIncrementMs(seekIncrement)
|
||||
.build()
|
||||
|
||||
exoPlayer.setAudioAttributes(audioAttributes, true)
|
||||
|
||||
exoPlayer.setPlaybackSpeed(playbackSpeed!!)
|
||||
}
|
||||
|
||||
private fun initializePlayerNotification(c: Context) {
|
||||
@ -1145,13 +1290,18 @@ class PlayerFragment : Fragment() {
|
||||
}
|
||||
}
|
||||
|
||||
// lock the player
|
||||
private fun lockPlayer(isLocked: Boolean) {
|
||||
val visibility = if (isLocked) View.VISIBLE else View.GONE
|
||||
|
||||
playerBinding.exoTopBarRight.visibility = visibility
|
||||
playerBinding.exoPlayPause.visibility = visibility
|
||||
playerBinding.exoBottomBar.visibility = visibility
|
||||
playerBinding.closeImageButton.visibility = visibility
|
||||
playerBinding.exoTitle.visibility = visibility
|
||||
|
||||
// disable double tap to seek when the player is locked
|
||||
if (isLocked) enableDoubleTapToSeek() else disableDoubleTapToSeek()
|
||||
}
|
||||
|
||||
private fun isSubscribed(button: MaterialButton, channel_id: String) {
|
||||
@ -1198,7 +1348,7 @@ class PlayerFragment : Fragment() {
|
||||
private fun subscribe(channel_id: String) {
|
||||
fun run() {
|
||||
lifecycleScope.launchWhenCreated {
|
||||
val response = try {
|
||||
try {
|
||||
val token = PreferenceHelper.getToken(requireContext())
|
||||
RetrofitInstance.authApi.subscribe(
|
||||
token,
|
||||
@ -1221,7 +1371,7 @@ class PlayerFragment : Fragment() {
|
||||
private fun unsubscribe(channel_id: String) {
|
||||
fun run() {
|
||||
lifecycleScope.launchWhenCreated {
|
||||
val response = try {
|
||||
try {
|
||||
val token = PreferenceHelper.getToken(requireContext())
|
||||
RetrofitInstance.authApi.unsubscribe(
|
||||
token,
|
||||
@ -1305,28 +1455,19 @@ class PlayerFragment : Fragment() {
|
||||
override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean) {
|
||||
super.onPictureInPictureModeChanged(isInPictureInPictureMode)
|
||||
if (isInPictureInPictureMode) {
|
||||
// hide and disable exoPlayer controls
|
||||
exoPlayerView.hideController()
|
||||
exoPlayerView.useController = false
|
||||
binding.linLayout.visibility = View.GONE
|
||||
|
||||
with(binding.playerMotionLayout) {
|
||||
getConstraintSet(R.id.start).constrainHeight(R.id.player, -1)
|
||||
enableTransition(R.id.yt_transition, false)
|
||||
}
|
||||
binding.mainContainer.isClickable = true
|
||||
unsetFullscreen()
|
||||
|
||||
val mainActivity = activity as MainActivity
|
||||
mainActivity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
|
||||
isFullScreen = false
|
||||
Globals.isFullScreen = false
|
||||
} else {
|
||||
with(binding.playerMotionLayout) {
|
||||
getConstraintSet(R.id.start).constrainHeight(R.id.player, 0)
|
||||
enableTransition(R.id.yt_transition, true)
|
||||
}
|
||||
|
||||
// enable exoPlayer controls again
|
||||
exoPlayerView.useController = true
|
||||
binding.linLayout.visibility = View.VISIBLE
|
||||
binding.mainContainer.isClickable = false
|
||||
|
||||
// switch back to portrait mode
|
||||
unsetFullscreen()
|
||||
}
|
||||
}
|
||||
|
||||
@ -1335,7 +1476,7 @@ class PlayerFragment : Fragment() {
|
||||
binding.playerScrollView.getHitRect(bounds)
|
||||
|
||||
if (SDK_INT >= Build.VERSION_CODES.O &&
|
||||
exoPlayer.isPlaying && (binding.playerScrollView.getLocalVisibleRect(bounds) || isFullScreen)
|
||||
exoPlayer.isPlaying && (binding.playerScrollView.getLocalVisibleRect(bounds) || Globals.isFullScreen)
|
||||
) {
|
||||
activity?.enterPictureInPictureMode(updatePipParams())
|
||||
}
|
||||
@ -1344,4 +1485,19 @@ class PlayerFragment : Fragment() {
|
||||
private fun updatePipParams() = PictureInPictureParams.Builder()
|
||||
.setActions(emptyList())
|
||||
.build()
|
||||
|
||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||
super.onConfigurationChanged(newConfig)
|
||||
|
||||
if (autoRotationEnabled) {
|
||||
val orientation = newConfig.orientation
|
||||
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
// go to fullscreen mode
|
||||
setFullscreen()
|
||||
} else {
|
||||
// exit fullscreen if not landscape
|
||||
unsetFullscreen()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
data class ChapterSegment(
|
||||
var title: String?,
|
||||
var image: String?,
|
||||
var start: Int?
|
||||
var start: Long?
|
||||
) {
|
||||
constructor() : this("", "", -1)
|
||||
}
|
||||
|
11
app/src/main/java/com/github/libretube/obj/DownloadType.kt
Normal file
11
app/src/main/java/com/github/libretube/obj/DownloadType.kt
Normal file
@ -0,0 +1,11 @@
|
||||
package com.github.libretube.obj
|
||||
|
||||
/**
|
||||
* object for saving the download type
|
||||
*/
|
||||
object DownloadType {
|
||||
const val AUDIO = 0
|
||||
const val VIDEO = 1
|
||||
const val MUX = 2
|
||||
const val NONE = 3
|
||||
}
|
@ -5,7 +5,7 @@ import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.activities.SettingsActivity
|
||||
import com.github.libretube.activities.requireMainActivityRestart
|
||||
import com.github.libretube.dialogs.RequireRestartDialog
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
|
||||
class AdvancedSettings : PreferenceFragmentCompat() {
|
||||
@ -48,8 +48,8 @@ class AdvancedSettings : PreferenceFragmentCompat() {
|
||||
// clear login token
|
||||
PreferenceHelper.setToken(requireContext(), "")
|
||||
|
||||
requireMainActivityRestart = true
|
||||
activity?.recreate()
|
||||
val restartDialog = RequireRestartDialog()
|
||||
restartDialog.show(childFragmentManager, "RequireRestartDialog")
|
||||
}
|
||||
.setNegativeButton(getString(R.string.cancel)) { _, _ -> }
|
||||
.setTitle(R.string.reset)
|
||||
|
@ -6,7 +6,7 @@ import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.SwitchPreference
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.activities.SettingsActivity
|
||||
import com.github.libretube.activities.requireMainActivityRestart
|
||||
import com.github.libretube.dialogs.RequireRestartDialog
|
||||
import com.github.libretube.util.ThemeHelper
|
||||
import com.google.android.material.color.DynamicColors
|
||||
|
||||
@ -18,18 +18,18 @@ class AppearanceSettings : PreferenceFragmentCompat() {
|
||||
val settingsActivity = activity as SettingsActivity
|
||||
settingsActivity.changeTopBarText(getString(R.string.appearance))
|
||||
|
||||
val themeToggle = findPreference<ListPreference>("theme_togglee")
|
||||
val themeToggle = findPreference<ListPreference>("theme_toggle")
|
||||
themeToggle?.setOnPreferenceChangeListener { _, _ ->
|
||||
requireMainActivityRestart = true
|
||||
activity?.recreate()
|
||||
val restartDialog = RequireRestartDialog()
|
||||
restartDialog.show(childFragmentManager, "RequireRestartDialog")
|
||||
true
|
||||
}
|
||||
|
||||
val accentColor = findPreference<ListPreference>("accent_color")
|
||||
updateAccentColorValues(accentColor!!)
|
||||
accentColor.setOnPreferenceChangeListener { _, _ ->
|
||||
requireMainActivityRestart = true
|
||||
activity?.recreate()
|
||||
val restartDialog = RequireRestartDialog()
|
||||
restartDialog.show(childFragmentManager, "RequireRestartDialog")
|
||||
true
|
||||
}
|
||||
|
||||
@ -41,13 +41,22 @@ class AppearanceSettings : PreferenceFragmentCompat() {
|
||||
|
||||
val gridColumns = findPreference<ListPreference>("grid")
|
||||
gridColumns?.setOnPreferenceChangeListener { _, _ ->
|
||||
requireMainActivityRestart = true
|
||||
val restartDialog = RequireRestartDialog()
|
||||
restartDialog.show(childFragmentManager, "RequireRestartDialog")
|
||||
true
|
||||
}
|
||||
|
||||
val hideTrending = findPreference<SwitchPreference>("hide_trending_page")
|
||||
hideTrending?.setOnPreferenceChangeListener { _, _ ->
|
||||
requireMainActivityRestart = true
|
||||
val restartDialog = RequireRestartDialog()
|
||||
restartDialog.show(childFragmentManager, "RequireRestartDialog")
|
||||
true
|
||||
}
|
||||
|
||||
val labelVisibilityMode = findPreference<ListPreference>("label_visibility")
|
||||
labelVisibilityMode?.setOnPreferenceChangeListener { _, _ ->
|
||||
val restartDialog = RequireRestartDialog()
|
||||
restartDialog.show(childFragmentManager, "RequireRestartDialog")
|
||||
true
|
||||
}
|
||||
}
|
||||
|
@ -21,11 +21,11 @@ import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.SwitchPreference
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.activities.SettingsActivity
|
||||
import com.github.libretube.activities.requireMainActivityRestart
|
||||
import com.github.libretube.dialogs.CustomInstanceDialog
|
||||
import com.github.libretube.dialogs.DeleteAccountDialog
|
||||
import com.github.libretube.dialogs.LoginDialog
|
||||
import com.github.libretube.dialogs.LogoutDialog
|
||||
import com.github.libretube.dialogs.RequireRestartDialog
|
||||
import com.github.libretube.util.RetrofitInstance
|
||||
import org.json.JSONObject
|
||||
import org.json.JSONTokener
|
||||
@ -119,7 +119,8 @@ class InstanceSettings : PreferenceFragmentCompat() {
|
||||
// fetchInstance()
|
||||
initCustomInstances(instance!!)
|
||||
instance.setOnPreferenceChangeListener { _, newValue ->
|
||||
requireMainActivityRestart = true
|
||||
val restartDialog = RequireRestartDialog()
|
||||
restartDialog.show(childFragmentManager, "RequireRestartDialog")
|
||||
RetrofitInstance.url = newValue.toString()
|
||||
if (!PreferenceHelper.getBoolean(requireContext(), "auth_instance_toggle", false)) {
|
||||
RetrofitInstance.authUrl = newValue.toString()
|
||||
@ -136,22 +137,24 @@ class InstanceSettings : PreferenceFragmentCompat() {
|
||||
authInstance.isVisible = false
|
||||
}
|
||||
authInstance.setOnPreferenceChangeListener { _, newValue ->
|
||||
requireMainActivityRestart = true
|
||||
// save new auth url
|
||||
RetrofitInstance.authUrl = newValue.toString()
|
||||
RetrofitInstance.lazyMgr.reset()
|
||||
logout()
|
||||
val restartDialog = RequireRestartDialog()
|
||||
restartDialog.show(childFragmentManager, "RequireRestartDialog")
|
||||
true
|
||||
}
|
||||
|
||||
val authInstanceToggle = findPreference<SwitchPreference>("auth_instance_toggle")
|
||||
authInstanceToggle?.setOnPreferenceChangeListener { _, newValue ->
|
||||
requireMainActivityRestart = true
|
||||
authInstance.isVisible = newValue == true
|
||||
logout()
|
||||
// either use new auth url or the normal api url if auth instance disabled
|
||||
RetrofitInstance.authUrl = if (newValue == false) RetrofitInstance.url
|
||||
else authInstance.value
|
||||
val restartDialog = RequireRestartDialog()
|
||||
restartDialog.show(childFragmentManager, "RequireRestartDialog")
|
||||
true
|
||||
}
|
||||
|
||||
|
@ -7,9 +7,9 @@ import androidx.preference.ListPreference
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import com.github.libretube.BuildConfig
|
||||
import com.github.libretube.Globals
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.activities.isCurrentViewMainSettings
|
||||
import com.github.libretube.activities.requireMainActivityRestart
|
||||
import com.github.libretube.dialogs.RequireRestartDialog
|
||||
import com.github.libretube.util.ThemeHelper
|
||||
import com.github.libretube.util.checkUpdate
|
||||
|
||||
@ -25,7 +25,8 @@ class MainSettings : PreferenceFragmentCompat() {
|
||||
|
||||
val region = findPreference<Preference>("region")
|
||||
region?.setOnPreferenceChangeListener { _, _ ->
|
||||
requireMainActivityRestart = true
|
||||
val restartDialog = RequireRestartDialog()
|
||||
restartDialog.show(childFragmentManager, "RequireRestartDialog")
|
||||
true
|
||||
}
|
||||
|
||||
@ -93,7 +94,7 @@ class MainSettings : PreferenceFragmentCompat() {
|
||||
}
|
||||
|
||||
private fun navigateToSettingsFragment(newFragment: Fragment) {
|
||||
isCurrentViewMainSettings = false
|
||||
Globals.isCurrentViewMainSettings = false
|
||||
parentFragmentManager.beginTransaction()
|
||||
.replace(R.id.settings, newFragment)
|
||||
.commitNow()
|
||||
|
@ -1,7 +1,9 @@
|
||||
package com.github.libretube.preferences
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.SwitchPreferenceCompat
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.activities.SettingsActivity
|
||||
|
||||
@ -13,5 +15,20 @@ class PlayerSettings : PreferenceFragmentCompat() {
|
||||
|
||||
val settingsActivity = activity as SettingsActivity
|
||||
settingsActivity.changeTopBarText(getString(R.string.audio_video))
|
||||
|
||||
val playerOrientation = findPreference<ListPreference>("fullscreen_orientation")
|
||||
val autoRotateToFullscreen = findPreference<SwitchPreferenceCompat>("auto_fullscreen")
|
||||
|
||||
// only show the player orientation option if auto fullscreen is disabled
|
||||
playerOrientation?.isEnabled != PreferenceHelper.getBoolean(
|
||||
requireContext(),
|
||||
"auto_fullscreen",
|
||||
false
|
||||
)
|
||||
|
||||
autoRotateToFullscreen?.setOnPreferenceChangeListener { _, newValue ->
|
||||
playerOrientation?.isEnabled = newValue != true
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import com.arthenica.ffmpegkit.FFmpegKit
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.obj.DownloadType
|
||||
import com.github.libretube.preferences.PreferenceHelper
|
||||
import java.io.File
|
||||
|
||||
@ -26,17 +27,19 @@ var IS_DOWNLOAD_RUNNING = false
|
||||
|
||||
class DownloadService : Service() {
|
||||
val TAG = "DownloadService"
|
||||
|
||||
private lateinit var notification: NotificationCompat.Builder
|
||||
|
||||
private var downloadId: Long = -1
|
||||
private lateinit var videoId: String
|
||||
private lateinit var videoUrl: String
|
||||
private lateinit var audioUrl: String
|
||||
private lateinit var extension: String
|
||||
private var duration: Int = 0
|
||||
private var downloadType: Int = 3
|
||||
|
||||
private lateinit var audioDir: File
|
||||
private lateinit var videoDir: File
|
||||
private lateinit var notification: NotificationCompat.Builder
|
||||
private lateinit var downloadType: String
|
||||
private lateinit var libretubeDir: File
|
||||
private lateinit var tempDir: File
|
||||
override fun onCreate() {
|
||||
@ -50,11 +53,11 @@ class DownloadService : Service() {
|
||||
audioUrl = intent.getStringExtra("audioUrl")!!
|
||||
duration = intent.getIntExtra("duration", 1)
|
||||
extension = PreferenceHelper.getString(this, "video_format", ".mp4")!!
|
||||
downloadType = if (audioUrl != "" && videoUrl != "") "mux"
|
||||
else if (audioUrl != "") "audio"
|
||||
else if (videoUrl != "") "video"
|
||||
else "none"
|
||||
if (downloadType != "none") {
|
||||
downloadType = if (audioUrl != "" && videoUrl != "") DownloadType.MUX
|
||||
else if (audioUrl != "") DownloadType.AUDIO
|
||||
else if (videoUrl != "") DownloadType.VIDEO
|
||||
else DownloadType.NONE
|
||||
if (downloadType != DownloadType.NONE) {
|
||||
downloadNotification(intent)
|
||||
downloadManager()
|
||||
} else {
|
||||
@ -108,7 +111,7 @@ class DownloadService : Service() {
|
||||
IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)
|
||||
)
|
||||
when (downloadType) {
|
||||
"mux" -> {
|
||||
DownloadType.MUX -> {
|
||||
audioDir = File(tempDir, "$videoId-audio")
|
||||
videoDir = File(tempDir, "$videoId-video")
|
||||
downloadId = downloadManagerRequest(
|
||||
@ -118,7 +121,7 @@ class DownloadService : Service() {
|
||||
videoDir
|
||||
)
|
||||
}
|
||||
"video" -> {
|
||||
DownloadType.VIDEO -> {
|
||||
videoDir = File(libretubeDir, "$videoId-video")
|
||||
downloadId = downloadManagerRequest(
|
||||
getString(R.string.video),
|
||||
@ -127,7 +130,7 @@ class DownloadService : Service() {
|
||||
videoDir
|
||||
)
|
||||
}
|
||||
"audio" -> {
|
||||
DownloadType.AUDIO -> {
|
||||
audioDir = File(libretubeDir, "$videoId-audio")
|
||||
downloadId = downloadManagerRequest(
|
||||
getString(R.string.audio),
|
||||
@ -148,7 +151,7 @@ class DownloadService : Service() {
|
||||
val id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1)
|
||||
// Checking if the received broadcast is for our enqueued download by matching download id
|
||||
if (downloadId == id) {
|
||||
if (downloadType == "mux") {
|
||||
if (downloadType == DownloadType.MUX) {
|
||||
downloadManagerRequest(
|
||||
getString(R.string.audio),
|
||||
getString(R.string.downloading),
|
||||
|
@ -2,13 +2,14 @@ package com.github.libretube.util
|
||||
|
||||
import android.content.Context
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.NetworkCapabilities
|
||||
import android.os.Build
|
||||
|
||||
object ConnectionHelper {
|
||||
fun isNetworkAvailable(context: Context): Boolean {
|
||||
val connectivityManager =
|
||||
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||
|
||||
// this seems to not recognize vpn connections
|
||||
/*
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
val nw = connectivityManager.activeNetwork ?: return false
|
||||
val actNw = connectivityManager.getNetworkCapabilities(nw) ?: return false
|
||||
@ -28,5 +29,8 @@ object ConnectionHelper {
|
||||
} else {
|
||||
return connectivityManager.activeNetworkInfo?.isConnected ?: false
|
||||
}
|
||||
*/
|
||||
|
||||
return connectivityManager.activeNetworkInfo?.isConnected ?: false
|
||||
}
|
||||
}
|
||||
|
@ -12,35 +12,60 @@ import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.core.text.HtmlCompat
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.preferences.PreferenceHelper
|
||||
import com.google.android.material.color.DynamicColors
|
||||
|
||||
object ThemeHelper {
|
||||
|
||||
fun updateTheme(context: Context) {
|
||||
updateAccentColor(context)
|
||||
updateThemeMode(context)
|
||||
fun updateTheme(activity: AppCompatActivity) {
|
||||
val themeMode = PreferenceHelper.getString(activity, "theme_toggle", "A")!!
|
||||
val blackModeEnabled = themeMode == "O"
|
||||
|
||||
updateAccentColor(activity, blackModeEnabled)
|
||||
updateThemeMode(themeMode)
|
||||
}
|
||||
|
||||
private fun updateAccentColor(context: Context) {
|
||||
when (PreferenceHelper.getString(context, "accent_color", "purple")) {
|
||||
"my" -> context.setTheme(R.style.MaterialYou)
|
||||
"red" -> context.setTheme(R.style.Theme_Red)
|
||||
"blue" -> context.setTheme(R.style.Theme_Blue)
|
||||
"yellow" -> context.setTheme(R.style.Theme_Yellow)
|
||||
"green" -> context.setTheme(R.style.Theme_Green)
|
||||
"purple" -> context.setTheme(R.style.Theme_Purple)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateThemeMode(context: Context) {
|
||||
when (PreferenceHelper.getString(context, "theme_togglee", "A")) {
|
||||
"A" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
|
||||
"L" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
|
||||
"D" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
|
||||
"O" -> {
|
||||
context.setTheme(R.style.OLED)
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
|
||||
private fun updateAccentColor(
|
||||
activity: AppCompatActivity,
|
||||
blackThemeEnabled: Boolean
|
||||
) {
|
||||
val theme = when (
|
||||
PreferenceHelper.getString(
|
||||
activity,
|
||||
"accent_color",
|
||||
"purple"
|
||||
)
|
||||
) {
|
||||
"my" -> {
|
||||
applyDynamicColors(activity)
|
||||
if (blackThemeEnabled) R.style.MaterialYou_Black
|
||||
else R.style.MaterialYou
|
||||
}
|
||||
"red" -> if (blackThemeEnabled) R.style.Theme_Red_Black else R.style.Theme_Red
|
||||
"blue" -> if (blackThemeEnabled) R.style.Theme_Blue_Black else R.style.Theme_Blue
|
||||
"yellow" -> if (blackThemeEnabled) R.style.Theme_Yellow_Black else R.style.Theme_Yellow
|
||||
"green" -> if (blackThemeEnabled) R.style.Theme_Green_Black else R.style.Theme_Green
|
||||
"purple" -> if (blackThemeEnabled) R.style.Theme_Purple_Black else R.style.Theme_Purple
|
||||
else -> if (blackThemeEnabled) R.style.Theme_Purple_Black else R.style.Theme_Purple
|
||||
}
|
||||
activity.setTheme(theme)
|
||||
}
|
||||
|
||||
private fun applyDynamicColors(activity: AppCompatActivity) {
|
||||
/**
|
||||
* apply dynamic colors to the activity
|
||||
*/
|
||||
DynamicColors.applyToActivityIfAvailable(activity)
|
||||
}
|
||||
|
||||
private fun updateThemeMode(themeMode: String) {
|
||||
val mode = when (themeMode) {
|
||||
"A" -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
|
||||
"L" -> AppCompatDelegate.MODE_NIGHT_NO
|
||||
"D" -> AppCompatDelegate.MODE_NIGHT_YES
|
||||
"O" -> AppCompatDelegate.MODE_NIGHT_YES
|
||||
else -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
|
||||
}
|
||||
AppCompatDelegate.setDefaultNightMode(mode)
|
||||
}
|
||||
|
||||
fun changeIcon(context: Context, newLogoActivityAlias: String) {
|
||||
|
@ -5,32 +5,34 @@ import android.os.Looper
|
||||
import android.view.View
|
||||
|
||||
class DoubleClickListener(
|
||||
private val doubleClickTimeLimitMills: Long = 300,
|
||||
private val doubleClickTimeLimitMills: Long = 200,
|
||||
private val callback: Callback
|
||||
) : View.OnClickListener {
|
||||
private var lastClicked: Long = -1L
|
||||
private var doubleClicked: Boolean = false
|
||||
|
||||
override fun onClick(v: View?) {
|
||||
lastClicked = when {
|
||||
lastClicked == -1L -> {
|
||||
doubleClicked = false
|
||||
checkForSingleClick()
|
||||
System.currentTimeMillis()
|
||||
}
|
||||
isDoubleClicked() -> {
|
||||
doubleClicked = true
|
||||
callback.doubleClicked()
|
||||
-1L
|
||||
}
|
||||
else -> {
|
||||
Handler(Looper.getMainLooper()).postDelayed({
|
||||
if (!doubleClicked) callback.singleClicked()
|
||||
}, doubleClickTimeLimitMills)
|
||||
checkForSingleClick()
|
||||
System.currentTimeMillis()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkForSingleClick() {
|
||||
Handler(Looper.getMainLooper()).postDelayed({
|
||||
if (lastClicked != -1L) callback.singleClicked()
|
||||
}, doubleClickTimeLimitMills)
|
||||
}
|
||||
|
||||
private fun getTimeDiff(from: Long, to: Long): Long {
|
||||
return to - from
|
||||
}
|
||||
|
11
app/src/main/res/drawable/ic_arrow_right.xml
Normal file
11
app/src/main/res/drawable/ic_arrow_right.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:autoMirrored="true"
|
||||
android:tint="@android:color/white"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M8.59,16.59L13.17,12 8.59,7.41 10,6l6,6 -6,6 -1.41,-1.41z" />
|
||||
</vector>
|
@ -2,13 +2,9 @@
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?android:attr/colorControlNormal"
|
||||
android:viewportWidth="36"
|
||||
android:viewportHeight="36">
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M23.38,16.77l0.6,-0.6A5,5 0,0 0,24 9.1L18.71,3.84a5,5 0,0 0,-7.07 0L3.09,12.39a5,5 0,0 0,0 7.07l5.26,5.26a5,5 0,0 0,7.07 0l0.45,-0.45 2.1,2.2h3.44v3h3.69v1.63L28,34h6L34,27.45ZM14.82,10.18L9.37,15.64a1,1 0,0 1,-1.41 0l-0.4,-0.4a1,1 0,0 1,0 -1.41L13,8.36a1,1 0,0 1,1.41 0l0.4,0.4A1,1 0,0 1,14.82 10.18ZM32,32L28.86,32l-1.77,-1.76v-2.8L23.41,27.44v-3L18.8,24.44l-1.52,-1.61L22,18.18 32,28.28Z" />
|
||||
<path
|
||||
android:fillAlpha="0"
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M0,0h36v36h-36z" />
|
||||
android:pathData="M14,30.45q2.7,0 4.575,-1.875T20.45,24q0,-2.7 -1.875,-4.575T14,17.55q-2.7,0 -4.575,1.875T7.55,24q0,2.7 1.875,4.575T14,30.45ZM14,36q-5,0 -8.5,-3.5T2,24q0,-5 3.5,-8.5T14,12q4.25,0 7.125,2.325t4.025,5.925h17.2L46,23.9l-7.3,7.3 -4.2,-4.2 -4.2,4.2 -3.55,-3.55h-1.6q-0.95,3.75 -4.025,6.05T14,36Z" />
|
||||
</vector>
|
||||
|
10
app/src/main/res/drawable/ic_flip.xml
Normal file
10
app/src/main/res/drawable/ic_flip.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?android:attr/colorControlNormal"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M32.9,21.5 L28.4,26l1.45,1.8 1.85,-1.85q-0.35,3.3 -2.45,5.6T24,33.85h-1.35q-0.55,0 -1.25,-0.25l-1.9,1.55q1,0.45 2.125,0.825 1.125,0.375 2.375,0.375 4.15,0 7.05,-3 2.9,-3 3.15,-7.85l2.1,2.3 1.45,-1.8ZM15.1,30.85 L19.6,26.35 18.15,24.55 16.3,26.4q0.35,-3.3 2.45,-5.6T24,18.5h1.35q0.55,0 1.25,0.25l1.9,-1.55q-1,-0.45 -2.125,-0.825Q25.25,16 24,16q-4.15,0 -7.05,3 -2.9,3 -3.15,7.85l-2.1,-2.3 -1.45,1.8ZM7,42q-1.2,0 -2.1,-0.9Q4,40.2 4,39L4,13.35q0,-1.15 0.9,-2.075 0.9,-0.925 2.1,-0.925h7.35L18,6h12l3.65,4.35L41,10.35q1.15,0 2.075,0.925Q44,12.2 44,13.35L44,39q0,1.2 -0.925,2.1 -0.925,0.9 -2.075,0.9Z" />
|
||||
</vector>
|
10
app/src/main/res/drawable/ic_headphones.xml
Normal file
10
app/src/main/res/drawable/ic_headphones.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?android:attr/colorControlNormal"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M16.4,42H9q-1.2,0 -2.1,-0.9Q6,40.2 6,39V24q0,-3.75 1.425,-7.025 1.425,-3.275 3.85,-5.7 2.425,-2.425 5.7,-3.85Q20.25,6 24,6q3.75,0 7.025,1.425 3.275,1.425 5.7,3.85 2.425,2.425 3.85,5.7Q42,20.25 42,24v15q0,1.2 -0.9,2.1 -0.9,0.9 -2.1,0.9h-7.4V27.2H39V24q0,-6.25 -4.375,-10.625T24,9q-6.25,0 -10.625,4.375T9,24v3.2h7.4Z" />
|
||||
</vector>
|
10
app/src/main/res/drawable/ic_label.xml
Normal file
10
app/src/main/res/drawable/ic_label.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?android:attr/colorControlNormal"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="m42,24 l-8.45,11.95q-0.65,0.9 -1.55,1.475 -0.9,0.575 -2,0.575H9q-1.25,0 -2.125,-0.875T6,35V13q0,-1.25 0.875,-2.125T9,10h21q1.1,0 2,0.575 0.9,0.575 1.55,1.475Z" />
|
||||
</vector>
|
10
app/src/main/res/drawable/ic_movie.xml
Normal file
10
app/src/main/res/drawable/ic_movie.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?android:attr/colorControlNormal"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="m7,8 l3.7,7.6h6.5L13.5,8h4.45l3.7,7.6h6.5L24.45,8h4.45l3.7,7.6h6.5L35.4,8H41q1.2,0 2.1,0.9 0.9,0.9 0.9,2.1v26q0,1.2 -0.9,2.1 -0.9,0.9 -2.1,0.9H7q-1.2,0 -2.1,-0.9Q4,38.2 4,37V11q0,-1.2 0.9,-2.1Q5.8,8 7,8Z" />
|
||||
</vector>
|
@ -1,12 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?android:attr/colorControlNormal"
|
||||
android:viewportWidth="244.86"
|
||||
android:viewportHeight="244.86">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M240.9,38.89c-2.43,-1.31 -5.39,-1.17 -7.69,0.35l-64.63,42.81V64.38c0,-14.48 -11.78,-26.25 -26.25,-26.25H26.25C11.78,38.13 0,49.91 0,64.38v116.09c0,14.47 11.78,26.25 26.25,26.25h116.09c14.47,0 26.25,-11.78 26.25,-26.25v-17.67l64.63,42.81c1.25,0.83 2.69,1.25 4.14,1.25c1.22,0 2.44,-0.3 3.55,-0.89c2.43,-1.31 3.95,-3.85 3.95,-6.61V45.5C244.86,42.74 243.34,40.2 240.9,38.89zM153.59,180.47c0,6.2 -5.05,11.25 -11.25,11.25H26.25c-6.2,0 -11.25,-5.05 -11.25,-11.25V64.38c0,-6.2 5.05,-11.25 11.25,-11.25h116.09c6.2,0 11.25,5.05 11.25,11.25v31.64v52.82V180.47zM229.86,185.39l-61.27,-40.58v-44.76l61.27,-40.58V185.39z"
|
||||
android:strokeWidth="10"
|
||||
android:strokeColor="#000000" />
|
||||
</vector>
|
10
app/src/main/res/drawable/ic_repeat.xml
Normal file
10
app/src/main/res/drawable/ic_repeat.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?android:attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M7,7h10v3l4,-4 -4,-4v3L5,5v6h2L7,7zM17,17L7,17v-3l-4,4 4,4v-3h12v-6h-2v4z" />
|
||||
</vector>
|
4
app/src/main/res/drawable/ic_rotating_circle.xml
Normal file
4
app/src/main/res/drawable/ic_rotating_circle.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<vector android:height="24dp" android:viewportHeight="48"
|
||||
android:viewportWidth="48" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FF000000" android:pathData="m24.1,38 l5.7,-5.65 -5.7,-5.65 -2.1,2.1 2.15,2.15q-1.4,0.05 -2.725,-0.45 -1.325,-0.5 -2.375,-1.55 -1,-1 -1.525,-2.3 -0.525,-1.3 -0.525,-2.6 0,-0.85 0.225,-1.7t0.625,-1.65l-2.2,-2.2q-0.85,1.25 -1.25,2.65T14,24q0,1.9 0.75,3.75t2.2,3.3q1.45,1.45 3.25,2.175 1.8,0.725 3.7,0.775L22,35.9ZM32.35,29.5q0.85,-1.25 1.25,-2.65T34,24q0,-1.9 -0.725,-3.775T31.1,16.9q-1.45,-1.45 -3.275,-2.15t-3.725,-0.7L26,12.1 23.9,10l-5.7,5.65 5.7,5.65 2.1,-2.1 -2.2,-2.2q1.35,0 2.75,0.525t2.4,1.525q1,1 1.525,2.3 0.525,1.3 0.525,2.6 0,0.85 -0.225,1.7t-0.625,1.65ZM24,44q-4.1,0 -7.75,-1.575 -3.65,-1.575 -6.375,-4.3 -2.725,-2.725 -4.3,-6.375Q4,28.1 4,24q0,-4.15 1.575,-7.8 1.575,-3.65 4.3,-6.35 2.725,-2.7 6.375,-4.275Q19.9,4 24,4q4.15,0 7.8,1.575 3.65,1.575 6.35,4.275 2.7,2.7 4.275,6.35Q44,19.85 44,24q0,4.1 -1.575,7.75 -1.575,3.65 -4.275,6.375t-6.35,4.3Q28.15,44 24,44Z"/>
|
||||
</vector>
|
@ -2,12 +2,9 @@
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?android:attr/colorControlNormal"
|
||||
android:viewportWidth="28"
|
||||
android:viewportHeight="28">
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
android:fillColor="#212121"
|
||||
android:pathData="M5.25,5.5C3.455,5.5 2,6.955 2,8.75V19.25C2,21.045 3.455,22.5 5.25,22.5H14.75C16.545,22.5 18,21.045 18,19.25V8.75C18,6.955 16.545,5.5 14.75,5.5H5.25Z" />
|
||||
<path
|
||||
android:fillColor="#212121"
|
||||
android:pathData="M23.123,20.643L19.5,17.094V10.999L23.112,7.371C23.899,6.58 25.248,7.138 25.248,8.253V19.75C25.248,20.858 23.914,21.418 23.123,20.643Z" />
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M7,40q-1.2,0 -2.1,-0.9Q4,38.2 4,37V11q0,-1.2 0.9,-2.1Q5.8,8 7,8h26q1.2,0 2.1,0.9 0.9,0.9 0.9,2.1v10.75l8,-8v20.5l-8,-8V37q0,1.2 -0.9,2.1 -0.9,0.9 -2.1,0.9Z" />
|
||||
</vector>
|
||||
|
@ -6,7 +6,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layoutDescription="@xml/activity_main_scene"
|
||||
tools:context=".MainActivity">
|
||||
tools:context=".activities.MainActivity">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
|
@ -1,34 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:background="?android:attr/selectableItemBackground">
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<de.hdodenhof.circleimageview.CircleImageView
|
||||
android:id="@+id/search_channel_image"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
android:layout_marginStart="36dp"
|
||||
android:layout_width="90dp"
|
||||
android:layout_height="90dp"
|
||||
android:layout_marginStart="45dp"
|
||||
android:layout_marginEnd="45dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/constraintLayout"
|
||||
android:layout_width="wrap_content"
|
||||
android:id="@+id/search_channel_info"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="40dp"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/search_channel_image"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/search_channel_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginRight="10dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textSize="16sp" />
|
||||
@ -37,6 +36,15 @@
|
||||
android:id="@+id/search_views"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/search_sub_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="2dp"
|
||||
android:text="@string/subscribe"
|
||||
android:textColor="?attr/colorPrimary"
|
||||
android:visibility="gone" />
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</LinearLayout>
|
@ -33,9 +33,9 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:backgroundTint="?attr/colorOnPrimary"
|
||||
android:text="@string/unsubscribe"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="11sp"
|
||||
android:layout_centerVertical="true"
|
||||
android:text="@string/subscribe"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textSize="12sp"
|
||||
app:cornerRadius="20dp" />
|
||||
</RelativeLayout>
|
@ -9,6 +9,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:animateLayoutChanges="true"
|
||||
android:orientation="vertical"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
@ -23,8 +24,8 @@
|
||||
|
||||
<de.hdodenhof.circleimageview.CircleImageView
|
||||
android:id="@+id/commentor_image"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
app:srcCompat="@mipmap/ic_launcher" />
|
||||
|
||||
@ -52,7 +53,7 @@
|
||||
android:id="@+id/verified_imageView"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginLeft="4dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:visibility="gone"
|
||||
app:srcCompat="@drawable/ic_verified" />
|
||||
@ -61,7 +62,7 @@
|
||||
android:id="@+id/pinned_imageView"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginLeft="4dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:visibility="gone"
|
||||
app:srcCompat="@drawable/ic_pinned" />
|
||||
@ -85,7 +86,7 @@
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginTop="2dp"
|
||||
android:layout_marginRight="6dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
app:srcCompat="@drawable/ic_thumb_up" />
|
||||
|
||||
<TextView
|
||||
@ -98,7 +99,7 @@
|
||||
android:id="@+id/hearted_imageView"
|
||||
android:layout_width="14dp"
|
||||
android:layout_height="14dp"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="3dp"
|
||||
android:visibility="gone"
|
||||
app:srcCompat="@drawable/ic_hearted" />
|
||||
@ -110,6 +111,7 @@
|
||||
android:id="@+id/replies_recView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="20dp"
|
||||
android:background="@null"
|
||||
android:nestedScrollingEnabled="false" />
|
||||
|
||||
|
@ -30,7 +30,7 @@
|
||||
android:id="@+id/close_imageButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginRight="5dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:background="#00FFFFFF"
|
||||
android:padding="@dimen/exo_icon_padding"
|
||||
android:src="@drawable/ic_close"
|
||||
@ -74,95 +74,122 @@
|
||||
android:id="@+id/aspect_ratio_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:background="#00FFFFFF"
|
||||
android:layout_marginHorizontal="5dp"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:padding="@dimen/exo_icon_padding"
|
||||
android:src="@drawable/ic_aspect_ratio" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/quality_linLayout"
|
||||
<TextView
|
||||
android:id="@+id/speed_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginHorizontal="5dp"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:padding="@dimen/exo_icon_padding"
|
||||
android:text="1x"
|
||||
android:textColor="#FFFFFF" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/quality_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:padding="@dimen/exo_icon_padding"
|
||||
android:text="@string/hls"
|
||||
android:textColor="#FFFFFF" />
|
||||
<TextView
|
||||
android:id="@+id/quality_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginHorizontal="5dp"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:padding="@dimen/exo_icon_padding"
|
||||
android:text="@string/hls"
|
||||
android:textColor="#FFFFFF" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/quality_select"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="@dimen/exo_icon_padding"
|
||||
android:src="@drawable/ic_arrow_down"
|
||||
app:tint="@android:color/white" />
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<FrameLayout
|
||||
<LinearLayout
|
||||
android:id="@id/exo_bottom_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/exo_styled_bottom_bar_height"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
android:layout_marginTop="@dimen/exo_styled_bottom_bar_margin_top"
|
||||
android:layoutDirection="ltr">
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@id/exo_time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical|start"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:layoutDirection="ltr"
|
||||
android:layout_marginBottom="-5dp"
|
||||
android:paddingStart="@dimen/exo_styled_bottom_bar_time_padding"
|
||||
android:paddingLeft="@dimen/exo_styled_bottom_bar_time_padding"
|
||||
android:paddingEnd="@dimen/exo_styled_bottom_bar_time_padding"
|
||||
android:paddingRight="@dimen/exo_styled_bottom_bar_time_padding">
|
||||
|
||||
<TextView
|
||||
android:id="@id/exo_position"
|
||||
style="@style/ExoStyledControls.TimeText.Position" />
|
||||
<LinearLayout
|
||||
android:id="@id/exo_time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="5dp">
|
||||
|
||||
<TextView style="@style/ExoStyledControls.TimeText.Separator" />
|
||||
<TextView
|
||||
android:id="@id/exo_position"
|
||||
style="@style/ExoStyledControls.TimeText.Position" />
|
||||
|
||||
<TextView
|
||||
android:id="@id/exo_duration"
|
||||
style="@style/ExoStyledControls.TimeText.Duration" />
|
||||
<TextView style="@style/ExoStyledControls.TimeText.Separator" />
|
||||
|
||||
</LinearLayout>
|
||||
<TextView
|
||||
android:id="@id/exo_duration"
|
||||
style="@style/ExoStyledControls.TimeText.Duration" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@id/exo_basic_controls"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:layoutDirection="ltr">
|
||||
</LinearLayout>
|
||||
|
||||
<ImageButton
|
||||
android:id="@id/exo_repeat_toggle"
|
||||
style="@style/ExoStyledControls.Button.Bottom.RepeatToggle" />
|
||||
<LinearLayout
|
||||
android:id="@+id/chapterLL"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_weight="1"
|
||||
android:visibility="invisible">
|
||||
|
||||
<ImageButton
|
||||
android:id="@id/exo_subtitle"
|
||||
style="@style/ExoStyledControls.Button.Bottom.CC" />
|
||||
<TextView
|
||||
android:id="@+id/chapter_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="@android:color/white" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@id/exo_settings"
|
||||
style="@style/ExoStyledControls.Button.Bottom.Settings" />
|
||||
<ImageView
|
||||
android:layout_width="15dp"
|
||||
android:layout_height="15dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="3dp"
|
||||
android:src="@drawable/ic_arrow_right" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/fullscreen"
|
||||
style="@style/ExoStyledControls.Button.Bottom.FullScreen"
|
||||
android:src="@drawable/ic_fullscreen"
|
||||
app:tint="@android:color/white" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@id/exo_basic_controls"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/repeat_toggle"
|
||||
style="@style/PlayerButton"
|
||||
android:src="@drawable/ic_repeat"
|
||||
app:tint="@android:color/darker_gray" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@id/exo_subtitle"
|
||||
style="@style/PlayerButton" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/fullscreen"
|
||||
style="@style/PlayerButton"
|
||||
android:src="@drawable/ic_fullscreen"
|
||||
app:tint="@android:color/white" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@ -187,18 +214,6 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@id/exo_minimal_controls"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_marginBottom="@dimen/exo_styled_minimal_controls_margin_bottom"
|
||||
android:gravity="center_vertical"
|
||||
android:layoutDirection="ltr"
|
||||
android:orientation="horizontal">
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
|
@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.github.libretube.views.CustomSwipeToRefresh 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:id="@+id/channel_refresh"
|
||||
android:layout_width="match_parent"
|
||||
@ -74,15 +75,15 @@
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/channel_subscribe"
|
||||
style="@style/Widget.Material3.Button.ElevatedButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:backgroundTint="?attr/colorOnPrimary"
|
||||
android:drawableStart="@drawable/ic_bell_small"
|
||||
android:drawableTint="@android:color/white"
|
||||
android:drawableLeft="@drawable/ic_bell_small"
|
||||
android:drawableTint="?android:attr/textColorPrimary"
|
||||
android:text="@string/subscribe"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textSize="11sp" />
|
||||
android:textSize="12sp"
|
||||
app:cornerRadius="20dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
@ -49,7 +49,7 @@
|
||||
android:id="@+id/player_description_arrow"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_centerInParent="true"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
@ -73,7 +73,7 @@
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="3dp"
|
||||
android:layout_marginStart="3dp"
|
||||
android:layout_marginTop="2dp">
|
||||
|
||||
<ImageView
|
||||
@ -93,7 +93,7 @@
|
||||
android:layout_width="12dp"
|
||||
android:layout_height="12dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginLeft="5dp"
|
||||
android:layout_marginStart="5dp"
|
||||
android:rotation="180"
|
||||
android:src="@drawable/ic_like" />
|
||||
|
||||
@ -119,7 +119,6 @@
|
||||
android:id="@+id/chapters_recView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/comments_toggle"
|
||||
android:layout_marginHorizontal="3dp"
|
||||
android:layout_marginTop="20dp"
|
||||
android:nestedScrollingEnabled="false"
|
||||
@ -193,7 +192,7 @@
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="25dp"
|
||||
android:padding="2dp"
|
||||
android:src="@drawable/ic_player" />
|
||||
android:src="@drawable/ic_videocam" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
@ -203,7 +202,22 @@
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/save"
|
||||
android:id="@+id/relPlayer_background"
|
||||
style="@style/PlayerActionsLayout">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="25dp"
|
||||
android:src="@drawable/ic_headphones" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/audio" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/relPlayer_save"
|
||||
style="@style/PlayerActionsLayout">
|
||||
|
||||
<ImageView
|
||||
@ -245,7 +259,7 @@
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginLeft="5dp"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_toStartOf="@+id/player_subscribe"
|
||||
android:layout_toEndOf="@+id/player_channelImage"
|
||||
android:ellipsize="end"
|
||||
@ -265,7 +279,7 @@
|
||||
android:drawableTint="?android:attr/textColorPrimary"
|
||||
android:text="@string/subscribe"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textSize="12dp"
|
||||
android:textSize="12sp"
|
||||
app:cornerRadius="11dp" />
|
||||
</RelativeLayout>
|
||||
|
||||
@ -297,7 +311,7 @@
|
||||
android:id="@+id/commentsToggle_textView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:text="@string/comments"
|
||||
android:textSize="17sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
@ -307,7 +321,7 @@
|
||||
android:id="@+id/commentsToggle_imageView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginRight="3dp"
|
||||
android:layout_marginEnd="3dp"
|
||||
android:src="@drawable/ic_arrow_up_down"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
@ -357,49 +371,64 @@
|
||||
android:id="@+id/player"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/colorSurface"
|
||||
android:background="@android:color/black"
|
||||
app:layout_constraintBottom_toBottomOf="@id/main_container"
|
||||
app:layout_constraintStart_toStartOf="@id/main_container"
|
||||
app:layout_constraintTop_toTopOf="@id/main_container"
|
||||
app:show_buffering="when_playing">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/forwardFL"
|
||||
android:layout_width="wrap_content"
|
||||
<!-- double tap to rewind/forward overlay -->
|
||||
<LinearLayout
|
||||
android:id="@+id/doubleTapOverlayLL"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:layout_marginVertical="50dp">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/forwardBTN"
|
||||
android:layout_width="150dp"
|
||||
<!-- double tap rewind btn -->
|
||||
<FrameLayout
|
||||
android:id="@+id/rewindFL"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?android:selectableItemBackgroundBorderless"
|
||||
android:clickable="false"
|
||||
android:src="@drawable/ic_forward"
|
||||
android:visibility="invisible"
|
||||
app:tint="@android:color/white" />
|
||||
android:layout_weight=".35">
|
||||
|
||||
</FrameLayout>
|
||||
<ImageButton
|
||||
android:id="@+id/rewindBTN"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?android:selectableItemBackgroundBorderless"
|
||||
android:clickable="false"
|
||||
android:src="@drawable/ic_rewind"
|
||||
android:visibility="invisible"
|
||||
app:tint="@android:color/white" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/rewindFL"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center_vertical|start"
|
||||
android:layout_marginVertical="50dp">
|
||||
</FrameLayout>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/rewindBTN"
|
||||
android:layout_width="150dp"
|
||||
<!-- place holder for the center controls -->
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?android:selectableItemBackgroundBorderless"
|
||||
android:clickable="false"
|
||||
android:src="@drawable/ic_rewind"
|
||||
android:visibility="invisible"
|
||||
app:tint="@android:color/white" />
|
||||
android:layout_weight=".30" />
|
||||
|
||||
</FrameLayout>
|
||||
<!-- double tap forward btn -->
|
||||
<FrameLayout
|
||||
android:id="@+id/forwardFL"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight=".35">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/forwardBTN"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?android:selectableItemBackgroundBorderless"
|
||||
android:clickable="false"
|
||||
android:src="@drawable/ic_forward"
|
||||
android:visibility="invisible"
|
||||
app:tint="@android:color/white" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</com.github.libretube.views.CustomExoPlayerView>
|
||||
|
||||
|
@ -42,7 +42,7 @@
|
||||
android:id="@+id/verified_imageView"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginLeft="4dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:visibility="gone"
|
||||
app:srcCompat="@drawable/ic_verified" />
|
||||
@ -51,7 +51,7 @@
|
||||
android:id="@+id/pinned_imageView"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginLeft="4dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:visibility="gone"
|
||||
app:srcCompat="@drawable/ic_pinned" />
|
||||
@ -75,7 +75,7 @@
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginTop="2dp"
|
||||
android:layout_marginRight="6dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
app:srcCompat="@drawable/ic_thumb_up" />
|
||||
|
||||
<TextView
|
||||
@ -88,7 +88,7 @@
|
||||
android:id="@+id/hearted_imageView"
|
||||
android:layout_width="14dp"
|
||||
android:layout_height="14dp"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="3dp"
|
||||
android:visibility="gone"
|
||||
app:srcCompat="@drawable/ic_hearted" />
|
||||
|
@ -227,4 +227,6 @@
|
||||
<string name="telegram">تيليجرام</string>
|
||||
<string name="reddit">ريديت</string>
|
||||
<string name="twitter">تويتر</string>
|
||||
<string name="turnInternetOn">يرجى الاتصال بالإنترنت عن طريق تشغيل WiFi أو بيانات الجوال.</string>
|
||||
<string name="open">فتح …</string>
|
||||
</resources>
|
@ -229,4 +229,5 @@
|
||||
<string name="discord">Discord</string>
|
||||
<string name="open">Açıq…</string>
|
||||
<string name="turnInternetOn">Zəhmət olmasa, WiFi və ya mobil datanı yandırmaqla internetə qoşulun.</string>
|
||||
<string name="chapters">Bölmələr</string>
|
||||
</resources>
|
@ -227,4 +227,7 @@
|
||||
<string name="community">Comunidad</string>
|
||||
<string name="discord">Discord</string>
|
||||
<string name="twitter">Twitter</string>
|
||||
<string name="turnInternetOn">Por favor, conéctese a Internet activando el WiFi o los datos móviles.</string>
|
||||
<string name="open">Abrir…</string>
|
||||
<string name="chapters">Capítulos</string>
|
||||
</resources>
|
@ -227,4 +227,7 @@
|
||||
<string name="telegram">Telegram</string>
|
||||
<string name="community">Communauté</string>
|
||||
<string name="discord">Discord</string>
|
||||
<string name="open">Ouvrir …</string>
|
||||
<string name="turnInternetOn">Veuillez vous connecter à l\'internet en activant le WiFi ou les données mobiles.</string>
|
||||
<string name="chapters">Chapitres</string>
|
||||
</resources>
|
@ -227,4 +227,6 @@
|
||||
<string name="matrix">Matrix</string>
|
||||
<string name="telegram">Telegram</string>
|
||||
<string name="reddit">Reddit</string>
|
||||
<string name="turnInternetOn">Connettiti a Internet attivando Wi-Fi o dati mobili.</string>
|
||||
<string name="open">Apri …</string>
|
||||
</resources>
|
@ -227,4 +227,8 @@
|
||||
<string name="portrait">לאורך</string>
|
||||
<string name="aspect_ratio">יחס תצוגת וידאו</string>
|
||||
<string name="twitter">טוויטר</string>
|
||||
<string name="turnInternetOn">נא להתחבר לאינטרנט על ידי הפעלת הרשת האלחוטית או הנתונים הסלולריים.</string>
|
||||
<string name="open">פתיחה…</string>
|
||||
<string name="chapters">פרקים</string>
|
||||
<string name="change_playback_speed">מהירות נגינה</string>
|
||||
</resources>
|
@ -8,6 +8,13 @@
|
||||
|
||||
</style>
|
||||
|
||||
<style name="MaterialYou.Black" parent="MaterialYou">
|
||||
|
||||
<item name="android:colorBackground">@android:color/black</item>
|
||||
<item name="colorSurface">@android:color/black</item>
|
||||
|
||||
</style>
|
||||
|
||||
<style name="Theme.Red" parent="Theme.Material3.Dark.NoActionBar">
|
||||
|
||||
<item name="colorPrimary">@color/red_dark_accentLight</item>
|
||||
@ -26,6 +33,13 @@
|
||||
|
||||
</style>
|
||||
|
||||
<style name="Theme.Red.Black" parent="Theme.Red">
|
||||
|
||||
<item name="android:colorBackground">@android:color/black</item>
|
||||
<item name="colorSurface">@android:color/black</item>
|
||||
|
||||
</style>
|
||||
|
||||
<style name="Theme.Blue" parent="Theme.Material3.Dark.NoActionBar">
|
||||
|
||||
<item name="colorPrimary">@color/blue_dark_accentLight</item>
|
||||
@ -44,6 +58,13 @@
|
||||
|
||||
</style>
|
||||
|
||||
<style name="Theme.Blue.Black" parent="Theme.Blue">
|
||||
|
||||
<item name="android:colorBackground">@android:color/black</item>
|
||||
<item name="colorSurface">@android:color/black</item>
|
||||
|
||||
</style>
|
||||
|
||||
<style name="Theme.Yellow" parent="Theme.Material3.Dark.NoActionBar">
|
||||
|
||||
<item name="colorPrimary">@color/yellow_dark_accentLight</item>
|
||||
@ -62,6 +83,13 @@
|
||||
|
||||
</style>
|
||||
|
||||
<style name="Theme.Yellow.Black" parent="Theme.Yellow">
|
||||
|
||||
<item name="android:colorBackground">@android:color/black</item>
|
||||
<item name="colorSurface">@android:color/black</item>
|
||||
|
||||
</style>
|
||||
|
||||
<style name="Theme.Green" parent="Theme.Material3.Dark.NoActionBar">
|
||||
|
||||
<item name="colorPrimary">@color/green_dark_accentLight</item>
|
||||
@ -80,6 +108,13 @@
|
||||
|
||||
</style>
|
||||
|
||||
<style name="Theme.Green.Black" parent="Theme.Green">
|
||||
|
||||
<item name="android:colorBackground">@android:color/black</item>
|
||||
<item name="colorSurface">@android:color/black</item>
|
||||
|
||||
</style>
|
||||
|
||||
<style name="Theme.Purple" parent="Theme.Material3.Dark.NoActionBar">
|
||||
|
||||
<item name="colorPrimary">@color/purple_dark_accentLight</item>
|
||||
@ -98,4 +133,11 @@
|
||||
|
||||
</style>
|
||||
|
||||
<style name="Theme.Purple.Black" parent="Theme.Purple">
|
||||
|
||||
<item name="android:colorBackground">@android:color/black</item>
|
||||
<item name="colorSurface">@android:color/black</item>
|
||||
|
||||
</style>
|
||||
|
||||
</resources>
|
@ -1,58 +1,75 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="loggedout">Desconectado com sucesso!</string>
|
||||
<string name="loggedout">Sessão terminada.</string>
|
||||
<string name="choose_quality_dialog">Qualidade</string>
|
||||
<string name="search_hint">Procurar</string>
|
||||
<string name="subscribe">Inscrever-se</string>
|
||||
<string name="unsubscribe">CANCELAR INSCRIÇÃO</string>
|
||||
<string name="share">Compartilhar</string>
|
||||
<string name="subscribe">Subscrever</string>
|
||||
<string name="unsubscribe">Cancelar subscrição</string>
|
||||
<string name="share">Partilhar</string>
|
||||
<string name="yes">Sim</string>
|
||||
<string name="username">Nome de usuário</string>
|
||||
<string name="login">Login</string>
|
||||
<string name="register">Registrar</string>
|
||||
<string name="username">Nome de utilizador</string>
|
||||
<string name="login">Iniciar sessão</string>
|
||||
<string name="register">Registar</string>
|
||||
<string name="logout">Sair</string>
|
||||
<string name="cancel">Cancelar</string>
|
||||
<string name="already_logged_in">Você já está logado, você pode sair da sua conta.</string>
|
||||
<string name="login_first">Por favor, faça o login e tente novamente!</string>
|
||||
<string name="already_logged_in">Sessão já iniciada. Pode sair da sua conta.</string>
|
||||
<string name="login_first">Inicie sessão e tente novamente.</string>
|
||||
<string name="instances">Escolha uma instância</string>
|
||||
<string name="customInstance">Adicionar uma instância personalizada</string>
|
||||
<string name="region">Escolha uma região</string>
|
||||
<string name="importsuccess">Inscrito com sucesso!</string>
|
||||
<string name="subscribeIsEmpty">Inscreva-se em alguns canais primeiro!</string>
|
||||
<string name="cannotDownload">Não é possível baixar esta transmissão!</string>
|
||||
<string name="dlcomplete">O download foi concluído!</string>
|
||||
<string name="downloadfailed">Falha no download.</string>
|
||||
<string name="app_theme">Tema do aplicativo</string>
|
||||
<string name="server_error">O servidor encontrou um problema. Talvez tente outra instância\?</string>
|
||||
<string name="unknown_error">Erro de rede!</string>
|
||||
<string name="error">Algo deu errado!</string>
|
||||
<string name="notgmail">Esta não é sua conta do Gmail!</string>
|
||||
<string name="customInstance">Instância personalizada</string>
|
||||
<string name="region">Região</string>
|
||||
<string name="importsuccess">Subscrito</string>
|
||||
<string name="subscribeIsEmpty">Tem que subscrever um canal.</string>
|
||||
<string name="cannotDownload">Não foi possível descarregar a emissão.</string>
|
||||
<string name="dlcomplete">Descarga terminada.</string>
|
||||
<string name="downloadfailed">Falha ao descarregar.</string>
|
||||
<string name="app_theme">Tema</string>
|
||||
<string name="server_error">Existe um problema com o servidor. Experimentar outra instância\?</string>
|
||||
<string name="unknown_error">Erro de rede.</string>
|
||||
<string name="error">Ocorreu um erro.</string>
|
||||
<string name="notgmail">isto é apenas para uma conta Piped.</string>
|
||||
<string name="defres">Resolução de vídeo padrão</string>
|
||||
<string name="grid">Número de colunas da grade</string>
|
||||
<string name="emptyList">Não há nada aqui!</string>
|
||||
<string name="deletePlaylist">Excluir playlist</string>
|
||||
<string name="areYouSure">Tem certeza de que deseja excluir esta playlist\?</string>
|
||||
<string name="createPlaylist">Criar playlist</string>
|
||||
<string name="playlistCreated">Playlist criada!</string>
|
||||
<string name="playlistName">Nome da playlist</string>
|
||||
<string name="addToPlaylist">Adicionar a playlist</string>
|
||||
<string name="success">Sucesso!</string>
|
||||
<string name="download">Download</string>
|
||||
<string name="save">Salvar</string>
|
||||
<string name="loggedIn">Login feito com sucesso!</string>
|
||||
<string name="password">Senha</string>
|
||||
<string name="registered">Registrado com sucesso! Agora você pode se inscrever nos canais que desejar.</string>
|
||||
<string name="login_register">Entrar/Registrar</string>
|
||||
<string name="please_login">Por favor, faça login ou registre-se nas configurações primeiro!</string>
|
||||
<string name="dlisinprogress">Outro download já está em andamento, por favor aguarde até que seja concluído!</string>
|
||||
<string name="grid">Colunas da grelha</string>
|
||||
<string name="emptyList">Nada para ver aqui.</string>
|
||||
<string name="deletePlaylist">Eliminar lista de reprodução</string>
|
||||
<string name="areYouSure">Tem certeza de que deseja eliminar esta lista\?</string>
|
||||
<string name="createPlaylist">Criar lista de reprodução</string>
|
||||
<string name="playlistCreated">Lista de reprodução criada.</string>
|
||||
<string name="playlistName">Nome da lista de reprodução</string>
|
||||
<string name="addToPlaylist">Adicionar à lista de reprodução</string>
|
||||
<string name="success">Feito.</string>
|
||||
<string name="download">Descarregar</string>
|
||||
<string name="save">Guardar</string>
|
||||
<string name="loggedIn">Sessão iniciada.</string>
|
||||
<string name="password">Palavra-passe</string>
|
||||
<string name="registered">Registo efetuado. Agora já pode subscrever canais.</string>
|
||||
<string name="login_register">Entrar/Registar</string>
|
||||
<string name="please_login">deve iniciar sessão ou registar-se nas definições.</string>
|
||||
<string name="dlisinprogress">Já existe uma descarga em curso. Por favor aguarde.</string>
|
||||
<string name="vlc">Abrir no VLC</string>
|
||||
<string name="vlcerror">Não é possível abrir no VLC. Talvez ainda não esteja instalado.</string>
|
||||
<string name="import_from_yt">Importar inscrições do YouTube</string>
|
||||
<string name="empty">Nome de usuário e senha não podem estar vazios!</string>
|
||||
<string name="fail">Falhou</string>
|
||||
<string name="about">Sobre</string>
|
||||
<string name="vlcerror">Não foi possível abrir no VLC. Talvez não esteja instalado.</string>
|
||||
<string name="import_from_yt">Importar inscrições</string>
|
||||
<string name="empty">Não indicou o nome de utilizador ou a palavra-passe.</string>
|
||||
<string name="fail">Falha :(</string>
|
||||
<string name="about">Acerca</string>
|
||||
<string name="videos">Vídeos</string>
|
||||
<string name="library">Biblioteca</string>
|
||||
<string name="startpage">Início</string>
|
||||
<string name="subscriptions">Subscrições</string>
|
||||
<string name="instance">Instância</string>
|
||||
<string name="videoCount">%1$s vídeos</string>
|
||||
<string name="comments">Comentários</string>
|
||||
<string name="retry">Tentar novamente</string>
|
||||
<string name="customization">Ajustes</string>
|
||||
<string name="noInternet">Tem que estar ligado à Internet.</string>
|
||||
<string name="import_from_yt_summary">De YouTube ou NewPipe</string>
|
||||
<string name="changeLanguage">Idioma</string>
|
||||
<string name="emptyPlaylistName">Uma lista de reprodução não pode estar vazia</string>
|
||||
<string name="systemLanguage">Sistema</string>
|
||||
<string name="systemDefault">Sistema</string>
|
||||
<string name="lightTheme">Claro</string>
|
||||
<string name="darkTheme">Escuro</string>
|
||||
<string name="subscribers">%1$s subscritores</string>
|
||||
<string name="settings">Definições</string>
|
||||
<string name="location">Localização</string>
|
||||
<string name="website">Site</string>
|
||||
</resources>
|
@ -28,7 +28,7 @@
|
||||
<string name="subscribeIsEmpty">Сначала подпишитесь на некоторые каналы.</string>
|
||||
<string name="cannotDownload">Невозможно скачать этот поток.</string>
|
||||
<string name="dlcomplete">Загрузка завершена.</string>
|
||||
<string name="dlisinprogress">Пожалуйста, подождите, пока все загрузки завершаться.</string>
|
||||
<string name="dlisinprogress">Пожалуйста, подождите, пока все загрузки завершатся.</string>
|
||||
<string name="downloadfailed">Загрузка не удалась.</string>
|
||||
<string name="vlc">Открыть в VLC</string>
|
||||
<string name="vlcerror">Не удаётся открыть в VLC. Возможно, он не установлен.</string>
|
||||
@ -64,7 +64,7 @@
|
||||
<string name="import_from_yt_summary">Из YouTube или NewPipe</string>
|
||||
<string name="emptyPlaylistName">Название плейлиста не может быть пустым</string>
|
||||
<string name="comments">Комментарии</string>
|
||||
<string name="noInternet">Отсутствует соединение с сетью</string>
|
||||
<string name="noInternet">Сначала подключитесь к Интернету.</string>
|
||||
<string name="videoCount">%1$s видео</string>
|
||||
<string name="retry">Попробовать снова</string>
|
||||
<string name="settings">Настройки</string>
|
||||
@ -227,4 +227,6 @@
|
||||
<string name="matrix">Matrix</string>
|
||||
<string name="telegram">Telegram</string>
|
||||
<string name="twitter">Twitter</string>
|
||||
<string name="turnInternetOn">Пожалуйста, подключитесь к Интернету, включив WiFi или мобильный интернет.</string>
|
||||
<string name="open">Открыть …</string>
|
||||
</resources>
|
@ -229,4 +229,6 @@
|
||||
<string name="discord">Discord</string>
|
||||
<string name="open">Açık …</string>
|
||||
<string name="turnInternetOn">Lütfen, WiFi veya mobil verileri açarak internete bağlanın.</string>
|
||||
<string name="chapters">Bölümler</string>
|
||||
<string name="change_playback_speed">Oynatma hızı</string>
|
||||
</resources>
|
@ -229,4 +229,6 @@
|
||||
<string name="telegram">Telegram</string>
|
||||
<string name="turnInternetOn">请打开 WiFi 或移动数据连接到互联网。</string>
|
||||
<string name="open">打开…</string>
|
||||
<string name="chapters">章节</string>
|
||||
<string name="change_playback_speed">播放速度</string>
|
||||
</resources>
|
@ -709,4 +709,16 @@
|
||||
<item>portrait</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="labelVisibility">
|
||||
<item>@string/always</item>
|
||||
<item>@string/selected</item>
|
||||
<item>@string/never</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="labelVisibilityValues">
|
||||
<item>always</item>
|
||||
<item>selected</item>
|
||||
<item>never</item>
|
||||
</string-array>
|
||||
|
||||
</resources>
|
@ -7,9 +7,9 @@
|
||||
<color name="red_light_accentDark">#EF5350</color>
|
||||
<color name="red_light_background">#EDE3E4</color>
|
||||
|
||||
<color name="red_dark_accentLight">#B71C1C</color>
|
||||
<color name="red_dark_accentDark">#B71C1C</color>
|
||||
<color name="red_dark_background">#130808</color>
|
||||
<color name="red_dark_accentLight">#C96052</color>
|
||||
<color name="red_dark_accentDark">#D25545</color>
|
||||
<color name="red_dark_background">#1B0B09</color>
|
||||
|
||||
<color name="blue_light_accentLight">#1F75FE</color>
|
||||
<color name="blue_light_accentDark">#66A1FE</color>
|
||||
@ -17,15 +17,15 @@
|
||||
|
||||
<color name="blue_dark_accentLight">#1F75FE</color>
|
||||
<color name="blue_dark_accentDark">#0146B6</color>
|
||||
<color name="blue_dark_background">#131426</color>
|
||||
<color name="blue_dark_background">#0A0B15</color>
|
||||
|
||||
<color name="yellow_light_accentLight">#FFA000</color>
|
||||
<color name="yellow_light_accentDark">#FFB300</color>
|
||||
<color name="yellow_light_background">#FFF8E1</color>
|
||||
|
||||
<color name="yellow_dark_accentLight">#FFCA28</color>
|
||||
<color name="yellow_dark_accentDark">#FF8F00</color>
|
||||
<color name="yellow_dark_background">#0E0D04</color>
|
||||
<color name="yellow_dark_accentLight">#D9B95C</color>
|
||||
<color name="yellow_dark_accentDark">#D1B956</color>
|
||||
<color name="yellow_dark_background">#19160B</color>
|
||||
|
||||
<color name="green_light_accentLight">#7CB342</color>
|
||||
<color name="green_light_accentDark">#8BC34A</color>
|
||||
@ -39,8 +39,8 @@
|
||||
<color name="purple_light_accentDark">#B39DDB</color>
|
||||
<color name="purple_light_background">#EFEBF6</color>
|
||||
|
||||
<color name="purple_dark_accentLight">#7E57C2</color>
|
||||
<color name="purple_dark_accentDark">#311B92</color>
|
||||
<color name="purple_dark_background">#1D0B20</color>
|
||||
<color name="purple_dark_accentLight">#AA6F6B</color>
|
||||
<color name="purple_dark_accentDark">#8F415B</color>
|
||||
<color name="purple_dark_background">#201015</color>
|
||||
|
||||
</resources>
|
@ -229,4 +229,14 @@
|
||||
<string name="twitter">Twitter</string>
|
||||
<string name="turnInternetOn">Please connect to the internet by turning on WiFi or mobile data.</string>
|
||||
<string name="open">Open …</string>
|
||||
<string name="chapters">Chapters</string>
|
||||
<string name="change_playback_speed">Playback speed</string>
|
||||
<string name="require_restart">Restart required</string>
|
||||
<string name="require_restart_message">This change requires an app restart. Do you want to restart the app now? Otherwise the changes will be applied on the next app restart.</string>
|
||||
<string name="navLabelVisibility">Navbar label visibility</string>
|
||||
<string name="always">Always</string>
|
||||
<string name="selected">Selected</string>
|
||||
<string name="never">Never</string>
|
||||
<string name="autoRotatePlayer">Auto fullscreen</string>
|
||||
<string name="autoRotatePlayer_summary">Automatically switch to player fullscreen when the device gets turned.</string>
|
||||
</resources>
|
@ -15,16 +15,6 @@
|
||||
|
||||
</style>
|
||||
|
||||
<style name="OLED">
|
||||
|
||||
<item name="android:colorBackground">@android:color/black</item>
|
||||
<item name="colorSurface">@android:color/black</item>
|
||||
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||
|
||||
</style>
|
||||
|
||||
<style name="MaterialAlertDialog">
|
||||
|
||||
<item name="alertDialogTheme">@style/ThemeOverlay.Material3.MaterialAlertDialog</item>
|
||||
@ -114,4 +104,14 @@
|
||||
|
||||
</style>
|
||||
|
||||
<style name="PlayerButton">
|
||||
|
||||
<item name="android:padding">9dp</item>
|
||||
<item name="android:layout_height">36dp</item>
|
||||
<item name="android:layout_width">36dp</item>
|
||||
<item name="android:layout_gravity">center</item>
|
||||
<item name="android:background">?attr/selectableItemBackground</item>
|
||||
|
||||
</style>
|
||||
|
||||
</resources>
|
@ -9,7 +9,7 @@
|
||||
app:defaultValue="A"
|
||||
app:entries="@array/themes"
|
||||
app:entryValues="@array/themesValue"
|
||||
app:key="theme_togglee"
|
||||
app:key="theme_toggle"
|
||||
app:title="@string/app_theme"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
@ -51,6 +51,15 @@
|
||||
app:title="@string/hideTrendingPage"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<ListPreference
|
||||
android:icon="@drawable/ic_label"
|
||||
app:defaultValue="always"
|
||||
app:entries="@array/labelVisibility"
|
||||
app:entryValues="@array/labelVisibilityValues"
|
||||
app:key="label_visibility"
|
||||
app:title="@string/navLabelVisibility"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<ListPreference
|
||||
android:icon="@drawable/ic_grid"
|
||||
app:defaultValue="@integer/grid_items"
|
||||
|
@ -14,7 +14,7 @@
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<ListPreference
|
||||
android:icon="@drawable/ic_player"
|
||||
android:icon="@drawable/ic_videocam"
|
||||
app:defaultValue="WEBM"
|
||||
app:entries="@array/playerVideoFormats"
|
||||
app:entryValues="@array/playerVideoFormats"
|
||||
@ -60,17 +60,26 @@
|
||||
<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: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"
|
||||
app:defaultValue="false"
|
||||
app:key="auto_fullscreen"
|
||||
app:title="@string/autoRotatePlayer" />
|
||||
|
||||
<ListPreference
|
||||
android:icon="@drawable/ic_fullscreen"
|
||||
android:icon="@drawable/ic_flip"
|
||||
app:defaultValue="ratio"
|
||||
app:entries="@array/fullscreenOrientation"
|
||||
app:entryValues="@array/fullscreenOrientationValues"
|
||||
|
@ -45,7 +45,7 @@
|
||||
app:title="@string/sponsorblock" />
|
||||
|
||||
<Preference
|
||||
android:icon="@drawable/ic_player"
|
||||
android:icon="@drawable/ic_movie"
|
||||
app:key="player"
|
||||
app:summary="@string/player_summary"
|
||||
app:title="@string/audio_video" />
|
||||
|
Loading…
Reference in New Issue
Block a user