mirror of
https://github.com/libre-tube/LibreTube.git
synced 2025-04-27 23:40:33 +05:30
chore: reformat code using ktlint
This commit is contained in:
parent
5532301aa4
commit
70bfaddb2e
@ -1,7 +1,6 @@
|
|||||||
package com.github.libretube.api
|
package com.github.libretube.api
|
||||||
|
|
||||||
import com.github.libretube.api.obj.*
|
import com.github.libretube.api.obj.*
|
||||||
import kotlinx.serialization.json.JsonObject
|
|
||||||
import retrofit2.http.Body
|
import retrofit2.http.Body
|
||||||
import retrofit2.http.GET
|
import retrofit2.http.GET
|
||||||
import retrofit2.http.Header
|
import retrofit2.http.Header
|
||||||
|
@ -187,7 +187,9 @@ object PlaylistsHelper {
|
|||||||
} else {
|
} else {
|
||||||
// if not logged in, all video information needs to become fetched manually
|
// if not logged in, all video information needs to become fetched manually
|
||||||
// Only do so with `MAX_CONCURRENT_IMPORT_CALLS` videos at once to prevent performance issues
|
// Only do so with `MAX_CONCURRENT_IMPORT_CALLS` videos at once to prevent performance issues
|
||||||
val streams = playlist.videos.chunked(MAX_CONCURRENT_IMPORT_CALLS).map { videos ->
|
val streams = playlist.videos.chunked(
|
||||||
|
MAX_CONCURRENT_IMPORT_CALLS
|
||||||
|
).map { videos ->
|
||||||
videos.parallelMap {
|
videos.parallelMap {
|
||||||
runCatching { RetrofitInstance.api.getStreams(it) }
|
runCatching { RetrofitInstance.api.getStreams(it) }
|
||||||
.getOrNull()
|
.getOrNull()
|
||||||
|
@ -20,5 +20,5 @@ data class PipedInstance(
|
|||||||
@SerialName("uptime_24h") val uptimeToday: Float? = null,
|
@SerialName("uptime_24h") val uptimeToday: Float? = null,
|
||||||
@SerialName("uptime_7d") val uptimeWeek: Float? = null,
|
@SerialName("uptime_7d") val uptimeWeek: Float? = null,
|
||||||
@SerialName("uptime_30d") val uptimeMonth: Float? = null,
|
@SerialName("uptime_30d") val uptimeMonth: Float? = null,
|
||||||
val isCurrentlyDown: Boolean = false,
|
val isCurrentlyDown: Boolean = false
|
||||||
)
|
)
|
||||||
|
@ -10,7 +10,9 @@ import kotlinx.serialization.Serializable
|
|||||||
@Entity(tableName = "localSubscription")
|
@Entity(tableName = "localSubscription")
|
||||||
data class LocalSubscription(
|
data class LocalSubscription(
|
||||||
@PrimaryKey val channelId: String,
|
@PrimaryKey val channelId: String,
|
||||||
@Ignore val url: String = "",
|
@Ignore val url: String = ""
|
||||||
) {
|
) {
|
||||||
constructor(channelId: String): this(channelId, "${ShareDialog.YOUTUBE_FRONTEND_URL}/channel/$channelId")
|
constructor(
|
||||||
|
channelId: String
|
||||||
|
) : this(channelId, "${ShareDialog.YOUTUBE_FRONTEND_URL}/channel/$channelId")
|
||||||
}
|
}
|
||||||
|
@ -4,4 +4,4 @@ enum class NotificationId(val id: Int) {
|
|||||||
PLAYER_PLAYBACK(1),
|
PLAYER_PLAYBACK(1),
|
||||||
DOWNLOAD_IN_PROGRESS(2),
|
DOWNLOAD_IN_PROGRESS(2),
|
||||||
ENQUEUE_PLAYLIST_DOWNLOAD(3)
|
ENQUEUE_PLAYLIST_DOWNLOAD(3)
|
||||||
}
|
}
|
||||||
|
@ -4,4 +4,4 @@ import androidx.lifecycle.MutableLiveData
|
|||||||
|
|
||||||
fun <T> MutableLiveData<T>.updateIfChanged(newValue: T) {
|
fun <T> MutableLiveData<T>.updateIfChanged(newValue: T) {
|
||||||
if (value != newValue) value = newValue
|
if (value != newValue) value = newValue
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ import kotlinx.coroutines.withContext
|
|||||||
|
|
||||||
suspend fun <T> runSafely(
|
suspend fun <T> runSafely(
|
||||||
onSuccess: (List<T>) -> Unit = { },
|
onSuccess: (List<T>) -> Unit = { },
|
||||||
ioBlock: suspend () -> List<T>,
|
ioBlock: suspend () -> List<T>
|
||||||
) {
|
) {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
val result = runCatching { ioBlock.invoke() }
|
val result = runCatching { ioBlock.invoke() }
|
||||||
@ -18,4 +18,4 @@ suspend fun <T> runSafely(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,6 @@ import android.widget.ImageView
|
|||||||
import androidx.core.graphics.drawable.toBitmapOrNull
|
import androidx.core.graphics.drawable.toBitmapOrNull
|
||||||
import coil.ImageLoader
|
import coil.ImageLoader
|
||||||
import coil.disk.DiskCache
|
import coil.disk.DiskCache
|
||||||
import coil.load
|
|
||||||
import coil.request.CachePolicy
|
import coil.request.CachePolicy
|
||||||
import coil.request.ImageRequest
|
import coil.request.ImageRequest
|
||||||
import com.github.libretube.api.CronetHelper
|
import com.github.libretube.api.CronetHelper
|
||||||
@ -17,10 +16,10 @@ import com.github.libretube.constants.PreferenceKeys
|
|||||||
import com.github.libretube.extensions.toAndroidUri
|
import com.github.libretube.extensions.toAndroidUri
|
||||||
import com.github.libretube.extensions.toAndroidUriOrNull
|
import com.github.libretube.extensions.toAndroidUriOrNull
|
||||||
import com.github.libretube.util.DataSaverMode
|
import com.github.libretube.util.DataSaverMode
|
||||||
|
import java.io.File
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
object ImageHelper {
|
object ImageHelper {
|
||||||
lateinit var imageLoader: ImageLoader
|
lateinit var imageLoader: ImageLoader
|
||||||
|
@ -116,7 +116,11 @@ object ImportHelper {
|
|||||||
|
|
||||||
ImportFormat.FREETUBE -> {
|
ImportFormat.FREETUBE -> {
|
||||||
val freeTubeChannels = subs.map {
|
val freeTubeChannels = subs.map {
|
||||||
FreetubeSubscription(it.name, "", "${ShareDialog.YOUTUBE_FRONTEND_URL}${it.url}")
|
FreetubeSubscription(
|
||||||
|
it.name,
|
||||||
|
"",
|
||||||
|
"${ShareDialog.YOUTUBE_FRONTEND_URL}${it.url}"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
val freeTubeSubscriptions = FreetubeSubscriptions(subscriptions = freeTubeChannels)
|
val freeTubeSubscriptions = FreetubeSubscriptions(subscriptions = freeTubeChannels)
|
||||||
activity.contentResolver.openOutputStream(uri)?.use {
|
activity.contentResolver.openOutputStream(uri)?.use {
|
||||||
|
@ -139,5 +139,4 @@ object NavBarHelper {
|
|||||||
.getString(PreferenceKeys.NAVBAR_ITEMS, "")
|
.getString(PreferenceKeys.NAVBAR_ITEMS, "")
|
||||||
.split(SEPARATOR)
|
.split(SEPARATOR)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,8 @@ object NavigationHelper {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val playerData = PlayerData(videoUrlOrId.toID(), playlistId, channelId, keepQueue, timestamp)
|
val playerData =
|
||||||
|
PlayerData(videoUrlOrId.toID(), playlistId, channelId, keepQueue, timestamp)
|
||||||
val bundle = bundleOf(IntentData.playerData to playerData)
|
val bundle = bundleOf(IntentData.playerData to playerData)
|
||||||
|
|
||||||
val activity = ContextHelper.unwrapActivity(context)
|
val activity = ContextHelper.unwrapActivity(context)
|
||||||
@ -86,7 +87,9 @@ object NavigationHelper {
|
|||||||
if (playlistUrlOrId == null) return
|
if (playlistUrlOrId == null) return
|
||||||
|
|
||||||
val activity = ContextHelper.unwrapActivity(context)
|
val activity = ContextHelper.unwrapActivity(context)
|
||||||
activity.navController.navigate(NavDirections.openPlaylist(playlistUrlOrId.toID(), playlistType))
|
activity.navController.navigate(
|
||||||
|
NavDirections.openPlaylist(playlistUrlOrId.toID(), playlistType)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -18,8 +18,8 @@ object NetworkHelper {
|
|||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
val activeNetwork = connectivityManager.activeNetwork
|
val activeNetwork = connectivityManager.activeNetwork
|
||||||
val caps = connectivityManager.getNetworkCapabilities(activeNetwork) ?: return false
|
val caps = connectivityManager.getNetworkCapabilities(activeNetwork) ?: return false
|
||||||
return caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
return caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) ||
|
||||||
|| caps.hasTransport(NetworkCapabilities.TRANSPORT_VPN)
|
caps.hasTransport(NetworkCapabilities.TRANSPORT_VPN)
|
||||||
} else {
|
} else {
|
||||||
// activeNetworkInfo might return null instead of the VPN, so better check it explicitly
|
// activeNetworkInfo might return null instead of the VPN, so better check it explicitly
|
||||||
val networkInfo = connectivityManager.activeNetworkInfo
|
val networkInfo = connectivityManager.activeNetworkInfo
|
||||||
|
@ -42,14 +42,14 @@ import com.github.libretube.enums.SbSkipOptions
|
|||||||
import com.github.libretube.extensions.updateParameters
|
import com.github.libretube.extensions.updateParameters
|
||||||
import com.github.libretube.obj.VideoStats
|
import com.github.libretube.obj.VideoStats
|
||||||
import com.github.libretube.util.TextUtils
|
import com.github.libretube.util.TextUtils
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
import kotlin.math.absoluteValue
|
import kotlin.math.absoluteValue
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
|
||||||
object PlayerHelper {
|
object PlayerHelper {
|
||||||
private const val ACTION_MEDIA_CONTROL = "media_control"
|
private const val ACTION_MEDIA_CONTROL = "media_control"
|
||||||
@ -344,11 +344,11 @@ object PlayerHelper {
|
|||||||
|
|
||||||
fun shouldPlayNextVideo(isPlaylist: Boolean = false): Boolean {
|
fun shouldPlayNextVideo(isPlaylist: Boolean = false): Boolean {
|
||||||
return autoPlayEnabled || (
|
return autoPlayEnabled || (
|
||||||
isPlaylist && PreferenceHelper.getBoolean(
|
isPlaylist && PreferenceHelper.getBoolean(
|
||||||
PreferenceKeys.AUTOPLAY_PLAYLISTS,
|
PreferenceKeys.AUTOPLAY_PLAYLISTS,
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val handleAudioFocus
|
private val handleAudioFocus
|
||||||
@ -760,9 +760,9 @@ object PlayerHelper {
|
|||||||
*/
|
*/
|
||||||
fun haveAudioTrackRoleFlagSet(@C.RoleFlags roleFlags: Int): Boolean {
|
fun haveAudioTrackRoleFlagSet(@C.RoleFlags roleFlags: Int): Boolean {
|
||||||
return isFlagSet(roleFlags, C.ROLE_FLAG_DESCRIBES_VIDEO) ||
|
return isFlagSet(roleFlags, C.ROLE_FLAG_DESCRIBES_VIDEO) ||
|
||||||
isFlagSet(roleFlags, C.ROLE_FLAG_DUB) ||
|
isFlagSet(roleFlags, C.ROLE_FLAG_DUB) ||
|
||||||
isFlagSet(roleFlags, C.ROLE_FLAG_MAIN) ||
|
isFlagSet(roleFlags, C.ROLE_FLAG_MAIN) ||
|
||||||
isFlagSet(roleFlags, C.ROLE_FLAG_ALTERNATE)
|
isFlagSet(roleFlags, C.ROLE_FLAG_ALTERNATE)
|
||||||
}
|
}
|
||||||
|
|
||||||
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
|
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
|
||||||
|
@ -36,20 +36,30 @@ object ThemeHelper {
|
|||||||
window.statusBarColor = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
window.statusBarColor = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
getThemeColor(context, android.R.attr.colorBackground)
|
getThemeColor(context, android.R.attr.colorBackground)
|
||||||
} else {
|
} else {
|
||||||
if (isDarkMode(context)) getThemeColor(context, android.R.attr.colorBackground)
|
if (isDarkMode(context)) {
|
||||||
else getThemeColor(context, com.google.android.material.R.attr.colorOnBackground)
|
getThemeColor(context, android.R.attr.colorBackground)
|
||||||
|
} else {
|
||||||
|
getThemeColor(context, com.google.android.material.R.attr.colorOnBackground)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the background color of the navigation bar
|
* Set the background color of the navigation bar
|
||||||
*/
|
*/
|
||||||
private fun setNavigationBarColor(context: Context, window: Window, isBottomNavVisible: Boolean) {
|
private fun setNavigationBarColor(
|
||||||
|
context: Context,
|
||||||
|
window: Window,
|
||||||
|
isBottomNavVisible: Boolean
|
||||||
|
) {
|
||||||
window.navigationBarColor = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M && !isDarkMode(context)) {
|
window.navigationBarColor = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M && !isDarkMode(context)) {
|
||||||
getThemeColor(context, com.google.android.material.R.attr.colorOnBackground)
|
getThemeColor(context, com.google.android.material.R.attr.colorOnBackground)
|
||||||
} else {
|
} else {
|
||||||
if (isBottomNavVisible) getThemeColor(context, com.google.android.material.R.attr.colorSurfaceContainer)
|
if (isBottomNavVisible) {
|
||||||
else getThemeColor(context, android.R.attr.colorBackground)
|
getThemeColor(context, com.google.android.material.R.attr.colorSurfaceContainer)
|
||||||
|
} else {
|
||||||
|
getThemeColor(context, android.R.attr.colorBackground)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,5 +46,5 @@ data class BackupFile(
|
|||||||
|
|
||||||
// playlists are exported in two different formats because the formats differ too much unfortunately
|
// playlists are exported in two different formats because the formats differ too much unfortunately
|
||||||
var localPlaylists: List<LocalPlaylistWithVideos>? = emptyList(),
|
var localPlaylists: List<LocalPlaylistWithVideos>? = emptyList(),
|
||||||
var playlists: List<PipedImportPlaylist>? = emptyList(),
|
var playlists: List<PipedImportPlaylist>? = emptyList()
|
||||||
)
|
)
|
||||||
|
@ -7,4 +7,4 @@ import kotlinx.parcelize.Parcelize
|
|||||||
data class SelectableOption(
|
data class SelectableOption(
|
||||||
val isSelected: Boolean,
|
val isSelected: Boolean,
|
||||||
val name: String
|
val name: String
|
||||||
): Parcelable
|
) : Parcelable
|
||||||
|
@ -10,5 +10,5 @@ import kotlinx.serialization.Serializable
|
|||||||
data class UpdateInfo(
|
data class UpdateInfo(
|
||||||
val name: String,
|
val name: String,
|
||||||
val body: String,
|
val body: String,
|
||||||
@SerialName("html_url") val htmlUrl: String,
|
@SerialName("html_url") val htmlUrl: String
|
||||||
) : Parcelable
|
) : Parcelable
|
||||||
|
@ -72,7 +72,9 @@ class PlaylistDownloadEnqueueService : LifecycleService() {
|
|||||||
private fun buildNotification(): Notification {
|
private fun buildNotification(): Notification {
|
||||||
return NotificationCompat.Builder(this, PLAYLIST_DOWNLOAD_ENQUEUE_CHANNEL_NAME)
|
return NotificationCompat.Builder(this, PLAYLIST_DOWNLOAD_ENQUEUE_CHANNEL_NAME)
|
||||||
.setSmallIcon(R.drawable.ic_download)
|
.setSmallIcon(R.drawable.ic_download)
|
||||||
.setContentTitle(getString(R.string.enqueueing_playlist_download, playlistName ?: "..."))
|
.setContentTitle(
|
||||||
|
getString(R.string.enqueueing_playlist_download, playlistName ?: "...")
|
||||||
|
)
|
||||||
.setProgress(amountOfVideos, amountOfVideosDone, false)
|
.setProgress(amountOfVideos, amountOfVideosDone, false)
|
||||||
.setOnlyAlertOnce(true)
|
.setOnlyAlertOnce(true)
|
||||||
.build()
|
.build()
|
||||||
@ -183,4 +185,4 @@ class PlaylistDownloadEnqueueService : LifecycleService() {
|
|||||||
|
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,7 +168,7 @@ class MainActivity : BaseActivity() {
|
|||||||
|
|
||||||
R.id.searchResultFragment -> {
|
R.id.searchResultFragment -> {
|
||||||
navController.popBackStack(R.id.searchFragment, true) ||
|
navController.popBackStack(R.id.searchFragment, true) ||
|
||||||
navController.popBackStack()
|
navController.popBackStack()
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
|
@ -112,9 +112,9 @@ class VideosAdapter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val context = (
|
val context = (
|
||||||
holder.videoRowBinding ?: holder.trendingRowBinding
|
holder.videoRowBinding ?: holder.trendingRowBinding
|
||||||
?: holder.allCaughtUpBinding
|
?: holder.allCaughtUpBinding
|
||||||
)!!.root.context
|
)!!.root.context
|
||||||
val activity = (context as BaseActivity)
|
val activity = (context as BaseActivity)
|
||||||
val fragmentManager = activity.supportFragmentManager
|
val fragmentManager = activity.supportFragmentManager
|
||||||
|
|
||||||
|
@ -40,8 +40,9 @@ open class BaseActivity : AppCompatActivity() {
|
|||||||
ThemeHelper.updateTheme(this)
|
ThemeHelper.updateTheme(this)
|
||||||
|
|
||||||
// Set the navigation and statusBar color if SDK < 23
|
// Set the navigation and statusBar color if SDK < 23
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M)
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
||||||
ThemeHelper.setSystemBarColors(this, window, false)
|
ThemeHelper.setSystemBarColors(this, window, false)
|
||||||
|
}
|
||||||
|
|
||||||
// set the apps language
|
// set the apps language
|
||||||
LocaleHelper.updateLanguage(this)
|
LocaleHelper.updateLanguage(this)
|
||||||
|
@ -5,7 +5,6 @@ import android.app.Dialog
|
|||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.widget.ArrayAdapter
|
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
|
@ -24,11 +24,11 @@ import com.github.libretube.helpers.PreferenceHelper
|
|||||||
import com.github.libretube.parcelable.DownloadData
|
import com.github.libretube.parcelable.DownloadData
|
||||||
import com.github.libretube.util.TextUtils
|
import com.github.libretube.util.TextUtils
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import java.io.IOException
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import retrofit2.HttpException
|
import retrofit2.HttpException
|
||||||
import java.io.IOException
|
|
||||||
|
|
||||||
class DownloadDialog : DialogFragment() {
|
class DownloadDialog : DialogFragment() {
|
||||||
private lateinit var videoId: String
|
private lateinit var videoId: String
|
||||||
|
@ -52,21 +52,31 @@ class DownloadPlaylistDialog : DialogFragment() {
|
|||||||
.setView(binding.root)
|
.setView(binding.root)
|
||||||
.setPositiveButton(R.string.download) { _, _ ->
|
.setPositiveButton(R.string.download) { _, _ ->
|
||||||
with(binding) {
|
with(binding) {
|
||||||
val maxVideoQuality = if (videoSpinner.selectedItemPosition >= 1)
|
val maxVideoQuality = if (videoSpinner.selectedItemPosition >= 1) {
|
||||||
possibleVideoQualities[videoSpinner.selectedItemPosition - 1]
|
possibleVideoQualities[videoSpinner.selectedItemPosition - 1]
|
||||||
.getWhileDigit() else null
|
.getWhileDigit()
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
val maxAudioQuality = if (audioSpinner.selectedItemPosition >= 1)
|
val maxAudioQuality = if (audioSpinner.selectedItemPosition >= 1) {
|
||||||
possibleAudioQualities[audioSpinner.selectedItemPosition - 1]
|
possibleAudioQualities[audioSpinner.selectedItemPosition - 1]
|
||||||
.getWhileDigit() else null
|
.getWhileDigit()
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
val captionLanguage = if (subtitleSpinner.selectedItemPosition >= 1)
|
val captionLanguage = if (subtitleSpinner.selectedItemPosition >= 1) {
|
||||||
availableLanguages[subtitleSpinner.selectedItemPosition - 1].code
|
availableLanguages[subtitleSpinner.selectedItemPosition - 1].code
|
||||||
else null
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
val audioLanguage = if (audioLanguageSpinner.selectedItemPosition >= 1)
|
val audioLanguage = if (audioLanguageSpinner.selectedItemPosition >= 1) {
|
||||||
availableLanguages[audioLanguageSpinner.selectedItemPosition - 1].code
|
availableLanguages[audioLanguageSpinner.selectedItemPosition - 1].code
|
||||||
else null
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
if (maxVideoQuality == null && maxAudioQuality == null) {
|
if (maxVideoQuality == null && maxAudioQuality == null) {
|
||||||
Toast.makeText(context, R.string.nothing_selected, Toast.LENGTH_SHORT)
|
Toast.makeText(context, R.string.nothing_selected, Toast.LENGTH_SHORT)
|
||||||
@ -89,6 +99,5 @@ class DownloadPlaylistDialog : DialogFragment() {
|
|||||||
}
|
}
|
||||||
.setNegativeButton(R.string.cancel, null)
|
.setNegativeButton(R.string.cancel, null)
|
||||||
.show()
|
.show()
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import android.app.Dialog
|
|||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.widget.ArrayAdapter
|
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
@ -5,7 +5,6 @@ import android.content.DialogInterface
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.format.DateUtils
|
import android.text.format.DateUtils
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.widget.ArrayAdapter
|
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
@ -100,7 +99,7 @@ class VoteForSegmentDialog : DialogFragment() {
|
|||||||
binding.segmentsDropdown.items = segments.map {
|
binding.segmentsDropdown.items = segments.map {
|
||||||
val (start, end) = it.segmentStartAndEnd
|
val (start, end) = it.segmentStartAndEnd
|
||||||
val (startStr, endStr) = DateUtils.formatElapsedTime(start.toLong()) to
|
val (startStr, endStr) = DateUtils.formatElapsedTime(start.toLong()) to
|
||||||
DateUtils.formatElapsedTime(end.toLong())
|
DateUtils.formatElapsedTime(end.toLong())
|
||||||
"${it.category} ($startStr - $endStr)"
|
"${it.category} ($startStr - $endStr)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,4 +6,4 @@ fun RecyclerView.addOnBottomReachedListener(onBottomReached: () -> Unit) {
|
|||||||
viewTreeObserver.addOnScrollChangedListener {
|
viewTreeObserver.addOnScrollChangedListener {
|
||||||
if (!canScrollVertically(1)) onBottomReached()
|
if (!canScrollVertically(1)) onBottomReached()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,4 +20,4 @@ fun View.animateDown(
|
|||||||
.y(dy)
|
.y(dy)
|
||||||
.setDuration(duration)
|
.setDuration(duration)
|
||||||
.start()
|
.start()
|
||||||
}
|
}
|
||||||
|
@ -34,11 +34,11 @@ import com.github.libretube.ui.extensions.addOnBottomReachedListener
|
|||||||
import com.github.libretube.ui.extensions.setupSubscriptionButton
|
import com.github.libretube.ui.extensions.setupSubscriptionButton
|
||||||
import com.github.libretube.ui.sheets.AddChannelToGroupSheet
|
import com.github.libretube.ui.sheets.AddChannelToGroupSheet
|
||||||
import com.github.libretube.util.deArrow
|
import com.github.libretube.util.deArrow
|
||||||
|
import java.io.IOException
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import retrofit2.HttpException
|
import retrofit2.HttpException
|
||||||
import java.io.IOException
|
|
||||||
|
|
||||||
class ChannelFragment : DynamicLayoutManagerFragment() {
|
class ChannelFragment : DynamicLayoutManagerFragment() {
|
||||||
private var _binding: FragmentChannelBinding? = null
|
private var _binding: FragmentChannelBinding? = null
|
||||||
|
@ -62,7 +62,7 @@ class CommentsMainFragment : Fragment() {
|
|||||||
this,
|
this,
|
||||||
viewModel.videoIdLiveData.value ?: return,
|
viewModel.videoIdLiveData.value ?: return,
|
||||||
viewModel.channelAvatar ?: return,
|
viewModel.channelAvatar ?: return,
|
||||||
handleLink = viewModel.handleLink,
|
handleLink = viewModel.handleLink
|
||||||
) {
|
) {
|
||||||
viewModel.commentsSheetDismiss?.invoke()
|
viewModel.commentsSheetDismiss?.invoke()
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ class CommentsRepliesFragment : Fragment() {
|
|||||||
videoId,
|
videoId,
|
||||||
viewModel.channelAvatar,
|
viewModel.channelAvatar,
|
||||||
comment,
|
comment,
|
||||||
viewModel.handleLink,
|
viewModel.handleLink
|
||||||
) {
|
) {
|
||||||
viewModel.commentsSheetDismiss?.invoke()
|
viewModel.commentsSheetDismiss?.invoke()
|
||||||
}
|
}
|
||||||
|
@ -156,15 +156,13 @@ class DownloadsFragment : DynamicLayoutManagerFragment() {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (dbDownloads.isNotEmpty()) {
|
||||||
if (dbDownloads.isNotEmpty()){
|
|
||||||
binding.deleteAll.isVisible = true
|
binding.deleteAll.isVisible = true
|
||||||
binding.deleteAll.setOnClickListener{
|
binding.deleteAll.setOnClickListener {
|
||||||
showDeleteAllDialog(binding.root.context, adapter)
|
showDeleteAllDialog(binding.root.context, adapter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
binding.shuffleBackground.setOnClickListener {
|
binding.shuffleBackground.setOnClickListener {
|
||||||
BackgroundHelper.playOnBackgroundOffline(requireContext(), null)
|
BackgroundHelper.playOnBackgroundOffline(requireContext(), null)
|
||||||
}
|
}
|
||||||
@ -191,7 +189,6 @@ class DownloadsFragment : DynamicLayoutManagerFragment() {
|
|||||||
super.onStart()
|
super.onStart()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
|
|
||||||
@ -199,7 +196,12 @@ class DownloadsFragment : DynamicLayoutManagerFragment() {
|
|||||||
addAction(DownloadService.ACTION_SERVICE_STARTED)
|
addAction(DownloadService.ACTION_SERVICE_STARTED)
|
||||||
addAction(DownloadService.ACTION_SERVICE_STOPPED)
|
addAction(DownloadService.ACTION_SERVICE_STOPPED)
|
||||||
}
|
}
|
||||||
ContextCompat.registerReceiver(requireContext(), downloadReceiver, filter, ContextCompat.RECEIVER_NOT_EXPORTED)
|
ContextCompat.registerReceiver(
|
||||||
|
requireContext(),
|
||||||
|
downloadReceiver,
|
||||||
|
filter,
|
||||||
|
ContextCompat.RECEIVER_NOT_EXPORTED
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun bindDownloadService(ids: IntArray? = null) {
|
fun bindDownloadService(ids: IntArray? = null) {
|
||||||
|
@ -95,7 +95,7 @@ class HomeFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun observeChanges() {
|
private fun observeChanges() {
|
||||||
with (homeViewModel) {
|
with(homeViewModel) {
|
||||||
trending.observe(viewLifecycleOwner, ::showTrending)
|
trending.observe(viewLifecycleOwner, ::showTrending)
|
||||||
feed.observe(viewLifecycleOwner, ::showFeed)
|
feed.observe(viewLifecycleOwner, ::showFeed)
|
||||||
bookmarks.observe(viewLifecycleOwner, ::showBookmarks)
|
bookmarks.observe(viewLifecycleOwner, ::showBookmarks)
|
||||||
@ -111,7 +111,7 @@ class HomeFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun stopObservingChanges() {
|
private fun stopObservingChanges() {
|
||||||
with (homeViewModel) {
|
with(homeViewModel) {
|
||||||
trending.removeObserver(::showTrending)
|
trending.removeObserver(::showTrending)
|
||||||
feed.removeObserver(::showFeed)
|
feed.removeObserver(::showFeed)
|
||||||
bookmarks.removeObserver(::showBookmarks)
|
bookmarks.removeObserver(::showBookmarks)
|
||||||
@ -151,11 +151,11 @@ class HomeFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun showFeed(streamItems: List<StreamItem>?) {
|
private fun showFeed(streamItems: List<StreamItem>?) {
|
||||||
if (streamItems == null) return
|
if (streamItems == null) return
|
||||||
|
|
||||||
makeVisible(binding.featuredRV, binding.featuredTV)
|
makeVisible(binding.featuredRV, binding.featuredTV)
|
||||||
val feedVideos = streamItems.take(20).toMutableList()
|
val feedVideos = streamItems.take(20).toMutableList()
|
||||||
with (binding.featuredRV) {
|
with(binding.featuredRV) {
|
||||||
layoutManager = LinearLayoutManager(context, HORIZONTAL, false)
|
layoutManager = LinearLayoutManager(context, HORIZONTAL, false)
|
||||||
adapter = VideosAdapter(feedVideos, forceMode = LayoutMode.RELATED_COLUMN)
|
adapter = VideosAdapter(feedVideos, forceMode = LayoutMode.RELATED_COLUMN)
|
||||||
}
|
}
|
||||||
@ -165,7 +165,7 @@ class HomeFragment : Fragment() {
|
|||||||
if (bookmarks == null) return
|
if (bookmarks == null) return
|
||||||
|
|
||||||
makeVisible(binding.bookmarksTV, binding.bookmarksRV)
|
makeVisible(binding.bookmarksTV, binding.bookmarksRV)
|
||||||
with (binding.bookmarksRV) {
|
with(binding.bookmarksRV) {
|
||||||
layoutManager = LinearLayoutManager(context, HORIZONTAL, false)
|
layoutManager = LinearLayoutManager(context, HORIZONTAL, false)
|
||||||
adapter = PlaylistBookmarkAdapter(
|
adapter = PlaylistBookmarkAdapter(
|
||||||
bookmarks.toMutableList(),
|
bookmarks.toMutableList(),
|
||||||
@ -263,4 +263,4 @@ class HomeFragment : Fragment() {
|
|||||||
private fun makeVisible(vararg views: View) {
|
private fun makeVisible(vararg views: View) {
|
||||||
views.forEach { it.isVisible = true }
|
views.forEach { it.isVisible = true }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,12 +113,12 @@ import com.github.libretube.util.PlayingQueue
|
|||||||
import com.github.libretube.util.TextUtils
|
import com.github.libretube.util.TextUtils
|
||||||
import com.github.libretube.util.TextUtils.toTimeInSeconds
|
import com.github.libretube.util.TextUtils.toTimeInSeconds
|
||||||
import com.github.libretube.util.YoutubeHlsPlaylistParser
|
import com.github.libretube.util.YoutubeHlsPlaylistParser
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
|
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
|
||||||
class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||||
@ -497,7 +497,7 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
|||||||
.animateDown(
|
.animateDown(
|
||||||
duration = 300L,
|
duration = 300L,
|
||||||
dy = 500F,
|
dy = 500F,
|
||||||
onEnd = ::onManualPlayerClose,
|
onEnd = ::onManualPlayerClose
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -868,7 +868,11 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
|||||||
handler.postDelayed(this::checkForSegments, 100)
|
handler.postDelayed(this::checkForSegments, 100)
|
||||||
if (!sponsorBlockEnabled || viewModel.segments.isEmpty()) return
|
if (!sponsorBlockEnabled || viewModel.segments.isEmpty()) return
|
||||||
|
|
||||||
exoPlayer.checkForSegments(requireContext(), viewModel.segments, viewModel.sponsorBlockConfig)
|
exoPlayer.checkForSegments(
|
||||||
|
requireContext(),
|
||||||
|
viewModel.segments,
|
||||||
|
viewModel.sponsorBlockConfig
|
||||||
|
)
|
||||||
?.let { segment ->
|
?.let { segment ->
|
||||||
if (viewModel.isMiniPlayerVisible.value == true) return@let
|
if (viewModel.isMiniPlayerVisible.value == true) return@let
|
||||||
binding.sbSkipBtn.isVisible = true
|
binding.sbSkipBtn.isVisible = true
|
||||||
@ -913,7 +917,7 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
|||||||
|
|
||||||
val videoStream = streams.videoStreams.firstOrNull()
|
val videoStream = streams.videoStreams.firstOrNull()
|
||||||
val isShort = PlayingQueue.getCurrent()?.isShort == true ||
|
val isShort = PlayingQueue.getCurrent()?.isShort == true ||
|
||||||
(videoStream?.height ?: 0) > (videoStream?.width ?: 0)
|
(videoStream?.height ?: 0) > (videoStream?.width ?: 0)
|
||||||
|
|
||||||
PlayingQueue.setOnQueueTapListener { streamItem ->
|
PlayingQueue.setOnQueueTapListener { streamItem ->
|
||||||
streamItem.url?.toID()?.let { playNextVideo(it) }
|
streamItem.url?.toID()?.let { playNextVideo(it) }
|
||||||
@ -950,7 +954,7 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
|||||||
if (binding.playerMotionLayout.progress != 1.0f) {
|
if (binding.playerMotionLayout.progress != 1.0f) {
|
||||||
// show controllers when not in picture in picture mode
|
// show controllers when not in picture in picture mode
|
||||||
val inPipMode = PlayerHelper.pipEnabled &&
|
val inPipMode = PlayerHelper.pipEnabled &&
|
||||||
PictureInPictureCompat.isInPictureInPictureMode(requireActivity())
|
PictureInPictureCompat.isInPictureInPictureMode(requireActivity())
|
||||||
if (!inPipMode) {
|
if (!inPipMode) {
|
||||||
binding.player.useController = true
|
binding.player.useController = true
|
||||||
}
|
}
|
||||||
@ -1621,7 +1625,7 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
|||||||
|
|
||||||
private fun shouldStartPiP(): Boolean {
|
private fun shouldStartPiP(): Boolean {
|
||||||
return shouldUsePip() && exoPlayer.isPlaying &&
|
return shouldUsePip() && exoPlayer.isPlaying &&
|
||||||
!BackgroundHelper.isBackgroundServiceRunning(requireContext())
|
!BackgroundHelper.isBackgroundServiceRunning(requireContext())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun killPlayerFragment() {
|
private fun killPlayerFragment() {
|
||||||
|
@ -61,20 +61,22 @@ class SearchResultFragment : DynamicLayoutManagerFragment() {
|
|||||||
|
|
||||||
// filter options
|
// filter options
|
||||||
binding.filterChipGroup.setOnCheckedStateChangeListener { _, _ ->
|
binding.filterChipGroup.setOnCheckedStateChangeListener { _, _ ->
|
||||||
viewModel.setFilter(when (
|
viewModel.setFilter(
|
||||||
binding.filterChipGroup.checkedChipId
|
when (
|
||||||
) {
|
binding.filterChipGroup.checkedChipId
|
||||||
R.id.chip_all -> "all"
|
) {
|
||||||
R.id.chip_videos -> "videos"
|
R.id.chip_all -> "all"
|
||||||
R.id.chip_channels -> "channels"
|
R.id.chip_videos -> "videos"
|
||||||
R.id.chip_playlists -> "playlists"
|
R.id.chip_channels -> "channels"
|
||||||
R.id.chip_music_songs -> "music_songs"
|
R.id.chip_playlists -> "playlists"
|
||||||
R.id.chip_music_videos -> "music_videos"
|
R.id.chip_music_songs -> "music_songs"
|
||||||
R.id.chip_music_albums -> "music_albums"
|
R.id.chip_music_videos -> "music_videos"
|
||||||
R.id.chip_music_playlists -> "music_playlists"
|
R.id.chip_music_albums -> "music_albums"
|
||||||
R.id.chip_music_artists -> "music_artists"
|
R.id.chip_music_playlists -> "music_playlists"
|
||||||
else -> throw IllegalArgumentException("Filter out of range")
|
R.id.chip_music_artists -> "music_artists"
|
||||||
})
|
else -> throw IllegalArgumentException("Filter out of range")
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val timeStamp = args.query.toHttpUrlOrNull()?.queryParameter("t")?.toTimeInSeconds()
|
val timeStamp = args.query.toHttpUrlOrNull()?.queryParameter("t")?.toTimeInSeconds()
|
||||||
|
@ -17,7 +17,6 @@ import androidx.lifecycle.lifecycleScope
|
|||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.github.libretube.R
|
import com.github.libretube.R
|
||||||
import com.github.libretube.api.obj.Channel
|
|
||||||
import com.github.libretube.api.obj.StreamItem
|
import com.github.libretube.api.obj.StreamItem
|
||||||
import com.github.libretube.api.obj.Subscription
|
import com.github.libretube.api.obj.Subscription
|
||||||
import com.github.libretube.constants.IntentData
|
import com.github.libretube.constants.IntentData
|
||||||
@ -191,7 +190,10 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment() {
|
|||||||
val fragManager = activityCompat
|
val fragManager = activityCompat
|
||||||
.supportFragmentManager
|
.supportFragmentManager
|
||||||
.apply {
|
.apply {
|
||||||
setFragmentResultListener(FILTER_SORT_REQUEST_KEY, activityCompat) { _, resultBundle ->
|
setFragmentResultListener(
|
||||||
|
FILTER_SORT_REQUEST_KEY,
|
||||||
|
activityCompat
|
||||||
|
) { _, resultBundle ->
|
||||||
selectedSortOrder = resultBundle.getInt(IntentData.sortOptions)
|
selectedSortOrder = resultBundle.getInt(IntentData.sortOptions)
|
||||||
hideWatched = resultBundle.getBoolean(IntentData.hideWatched)
|
hideWatched = resultBundle.getBoolean(IntentData.hideWatched)
|
||||||
showFeed()
|
showFeed()
|
||||||
@ -301,9 +303,13 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return if (hideWatched) runBlocking {
|
return if (hideWatched) {
|
||||||
DatabaseHelper.filterUnwatched(streamItems)
|
runBlocking {
|
||||||
} else streamItems
|
DatabaseHelper.filterUnwatched(streamItems)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
streamItems
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun List<StreamItem>.sortedBySelectedOrder() = when (selectedSortOrder) {
|
private fun List<StreamItem>.sortedBySelectedOrder() = when (selectedSortOrder) {
|
||||||
|
@ -25,6 +25,7 @@ class CommentsViewModel : ViewModel() {
|
|||||||
}.flow
|
}.flow
|
||||||
}
|
}
|
||||||
.cachedIn(viewModelScope)
|
.cachedIn(viewModelScope)
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
val commentRepliesFlow = videoIdLiveData.asFlow()
|
val commentRepliesFlow = videoIdLiveData.asFlow()
|
||||||
.combine(selectedCommentLiveData.asFlow()) { videoId, comment -> videoId to comment }
|
.combine(selectedCommentLiveData.asFlow()) { videoId, comment -> videoId to comment }
|
||||||
|
@ -28,7 +28,7 @@ import kotlinx.coroutines.delay
|
|||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
class HomeViewModel: ViewModel() {
|
class HomeViewModel : ViewModel() {
|
||||||
private val hideWatched get() = PreferenceHelper.getBoolean(HIDE_WATCHED_FROM_FEED, false)
|
private val hideWatched get() = PreferenceHelper.getBoolean(HIDE_WATCHED_FROM_FEED, false)
|
||||||
|
|
||||||
val trending: MutableLiveData<List<StreamItem>> = MutableLiveData(null)
|
val trending: MutableLiveData<List<StreamItem>> = MutableLiveData(null)
|
||||||
@ -147,4 +147,4 @@ class HomeViewModel: ViewModel() {
|
|||||||
private const val BOOKMARKS = "bookmarks"
|
private const val BOOKMARKS = "bookmarks"
|
||||||
private const val PLAYLISTS = "playlists"
|
private const val PLAYLISTS = "playlists"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,11 +19,11 @@ import com.github.libretube.api.obj.Subtitle
|
|||||||
import com.github.libretube.helpers.PlayerHelper
|
import com.github.libretube.helpers.PlayerHelper
|
||||||
import com.github.libretube.util.NowPlayingNotification
|
import com.github.libretube.util.NowPlayingNotification
|
||||||
import com.github.libretube.util.deArrow
|
import com.github.libretube.util.deArrow
|
||||||
|
import java.io.IOException
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import retrofit2.HttpException
|
import retrofit2.HttpException
|
||||||
import java.io.IOException
|
|
||||||
|
|
||||||
class PlayerViewModel : ViewModel() {
|
class PlayerViewModel : ViewModel() {
|
||||||
var player: ExoPlayer? = null
|
var player: ExoPlayer? = null
|
||||||
|
@ -17,11 +17,13 @@ import kotlinx.coroutines.flow.flatMapLatest
|
|||||||
|
|
||||||
class SearchResultViewModel(savedStateHandle: SavedStateHandle) : ViewModel() {
|
class SearchResultViewModel(savedStateHandle: SavedStateHandle) : ViewModel() {
|
||||||
private val args = SearchResultFragmentArgs.fromSavedStateHandle(savedStateHandle)
|
private val args = SearchResultFragmentArgs.fromSavedStateHandle(savedStateHandle)
|
||||||
|
|
||||||
// parse search URLs from YouTube entered in the search bar
|
// parse search URLs from YouTube entered in the search bar
|
||||||
private val videoId = TextUtils.getVideoIdFromUri(args.query.toUri()) ?: args.query
|
private val videoId = TextUtils.getVideoIdFromUri(args.query.toUri()) ?: args.query
|
||||||
private val searchQuery = "${ShareDialog.YOUTUBE_FRONTEND_URL}/watch?v=$videoId"
|
private val searchQuery = "${ShareDialog.YOUTUBE_FRONTEND_URL}/watch?v=$videoId"
|
||||||
|
|
||||||
private val filterMutableData = MutableStateFlow("all")
|
private val filterMutableData = MutableStateFlow("all")
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
val searchResultsFlow = filterMutableData.flatMapLatest {
|
val searchResultsFlow = filterMutableData.flatMapLatest {
|
||||||
Pager(
|
Pager(
|
||||||
|
@ -13,24 +13,24 @@ import com.github.libretube.api.obj.StreamItem
|
|||||||
import com.github.libretube.extensions.TAG
|
import com.github.libretube.extensions.TAG
|
||||||
import com.github.libretube.helpers.LocaleHelper
|
import com.github.libretube.helpers.LocaleHelper
|
||||||
import com.github.libretube.util.deArrow
|
import com.github.libretube.util.deArrow
|
||||||
|
import java.io.IOException
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import retrofit2.HttpException
|
import retrofit2.HttpException
|
||||||
import java.io.IOException
|
|
||||||
|
|
||||||
class TrendsViewModel: ViewModel() {
|
class TrendsViewModel : ViewModel() {
|
||||||
val trendingVideos = MutableLiveData<List<StreamItem>>()
|
val trendingVideos = MutableLiveData<List<StreamItem>>()
|
||||||
var recyclerViewState: Parcelable? = null
|
var recyclerViewState: Parcelable? = null
|
||||||
|
|
||||||
fun fetchTrending(context: Context) {
|
fun fetchTrending(context: Context) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
try {
|
try {
|
||||||
val region = LocaleHelper.getTrendingRegion(context)
|
val region = LocaleHelper.getTrendingRegion(context)
|
||||||
val response = withContext(Dispatchers.IO) {
|
val response = withContext(Dispatchers.IO) {
|
||||||
RetrofitInstance.api.getTrending(region).deArrow()
|
RetrofitInstance.api.getTrending(region).deArrow()
|
||||||
}
|
}
|
||||||
trendingVideos.postValue(response)
|
trendingVideos.postValue(response)
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
println(e)
|
println(e)
|
||||||
Log.e(TAG(), "IOException, you might not have internet connection")
|
Log.e(TAG(), "IOException, you might not have internet connection")
|
||||||
|
@ -7,7 +7,7 @@ import com.github.libretube.api.obj.Comment
|
|||||||
|
|
||||||
class CommentRepliesPagingSource(
|
class CommentRepliesPagingSource(
|
||||||
private val videoId: String,
|
private val videoId: String,
|
||||||
private val commentNextPage: String?,
|
private val commentNextPage: String?
|
||||||
) : PagingSource<String, Comment>() {
|
) : PagingSource<String, Comment>() {
|
||||||
override fun getRefreshKey(state: PagingState<String, Comment>) = null
|
override fun getRefreshKey(state: PagingState<String, Comment>) = null
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ import retrofit2.HttpException
|
|||||||
class SearchPagingSource(
|
class SearchPagingSource(
|
||||||
private val searchQuery: String,
|
private val searchQuery: String,
|
||||||
private val searchFilter: String
|
private val searchFilter: String
|
||||||
): PagingSource<String, ContentItem>() {
|
) : PagingSource<String, ContentItem>() {
|
||||||
override fun getRefreshKey(state: PagingState<String, ContentItem>) = null
|
override fun getRefreshKey(state: PagingState<String, ContentItem>) = null
|
||||||
|
|
||||||
override suspend fun load(params: LoadParams<String>): LoadResult<String, ContentItem> {
|
override suspend fun load(params: LoadParams<String>): LoadResult<String, ContentItem> {
|
||||||
|
@ -30,13 +30,14 @@ import kotlinx.coroutines.Dispatchers
|
|||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
|
||||||
|
|
||||||
class InstanceSettings : BasePreferenceFragment() {
|
class InstanceSettings : BasePreferenceFragment() {
|
||||||
override val titleResourceId: Int = R.string.instance
|
override val titleResourceId: Int = R.string.instance
|
||||||
private val token get() = PreferenceHelper.getToken()
|
private val token get() = PreferenceHelper.getToken()
|
||||||
private var instances = mutableListOf<PipedInstance>()
|
private var instances = mutableListOf<PipedInstance>()
|
||||||
private val authInstanceToggle get() = findPreference<SwitchPreferenceCompat>(PreferenceKeys.AUTH_INSTANCE_TOGGLE)!!
|
private val authInstanceToggle get() = findPreference<SwitchPreferenceCompat>(
|
||||||
|
PreferenceKeys.AUTH_INSTANCE_TOGGLE
|
||||||
|
)!!
|
||||||
|
|
||||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
setPreferencesFromResource(R.xml.instance_settings, rootKey)
|
setPreferencesFromResource(R.xml.instance_settings, rootKey)
|
||||||
|
@ -21,7 +21,6 @@ class MainSettings : BasePreferenceFragment() {
|
|||||||
|
|
||||||
// check app update manually
|
// check app update manually
|
||||||
update?.setOnPreferenceClickListener {
|
update?.setOnPreferenceClickListener {
|
||||||
|
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
UpdateChecker(requireContext()).checkUpdate(true)
|
UpdateChecker(requireContext()).checkUpdate(true)
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
package com.github.libretube.ui.sheets
|
package com.github.libretube.ui.sheets
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import androidx.fragment.app.setFragmentResult
|
import androidx.fragment.app.setFragmentResult
|
||||||
import com.github.libretube.R
|
import com.github.libretube.R
|
||||||
@ -11,7 +9,6 @@ import com.github.libretube.enums.ShareObjectType
|
|||||||
import com.github.libretube.helpers.BackgroundHelper
|
import com.github.libretube.helpers.BackgroundHelper
|
||||||
import com.github.libretube.helpers.NavigationHelper
|
import com.github.libretube.helpers.NavigationHelper
|
||||||
import com.github.libretube.obj.ShareData
|
import com.github.libretube.obj.ShareData
|
||||||
import com.github.libretube.services.OfflinePlayerService
|
|
||||||
import com.github.libretube.ui.dialogs.ShareDialog
|
import com.github.libretube.ui.dialogs.ShareDialog
|
||||||
|
|
||||||
class DownloadOptionsBottomSheet : BaseBottomSheet() {
|
class DownloadOptionsBottomSheet : BaseBottomSheet() {
|
||||||
|
@ -13,7 +13,7 @@ import com.github.libretube.enums.ContentFilter
|
|||||||
import com.github.libretube.extensions.parcelableArrayList
|
import com.github.libretube.extensions.parcelableArrayList
|
||||||
import com.github.libretube.obj.SelectableOption
|
import com.github.libretube.obj.SelectableOption
|
||||||
|
|
||||||
class FilterSortBottomSheet: ExpandedBottomSheet() {
|
class FilterSortBottomSheet : ExpandedBottomSheet() {
|
||||||
private var _binding: FilterSortSheetBinding? = null
|
private var _binding: FilterSortSheetBinding? = null
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ class FilterSortBottomSheet: ExpandedBottomSheet() {
|
|||||||
|
|
||||||
private fun setInitialFiltersState() {
|
private fun setInitialFiltersState() {
|
||||||
binding.filterVideos.isChecked = ContentFilter.VIDEOS.isEnabled
|
binding.filterVideos.isChecked = ContentFilter.VIDEOS.isEnabled
|
||||||
binding.filterShorts.isChecked = ContentFilter.SHORTS.isEnabled
|
binding.filterShorts.isChecked = ContentFilter.SHORTS.isEnabled
|
||||||
binding.filterLivestreams.isChecked = ContentFilter.LIVESTREAMS.isEnabled
|
binding.filterLivestreams.isChecked = ContentFilter.LIVESTREAMS.isEnabled
|
||||||
binding.hideWatchedCheckbox.isChecked = hideWatched
|
binding.hideWatchedCheckbox.isChecked = hideWatched
|
||||||
}
|
}
|
||||||
@ -115,4 +115,4 @@ class FilterSortBottomSheet: ExpandedBottomSheet() {
|
|||||||
companion object {
|
companion object {
|
||||||
const val FILTER_SORT_REQUEST_KEY = "filter_sort_request_key"
|
const val FILTER_SORT_REQUEST_KEY = "filter_sort_request_key"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,7 +171,9 @@ open class CustomExoPlayerView(
|
|||||||
Player.EVENT_PLAY_WHEN_READY_CHANGED
|
Player.EVENT_PLAY_WHEN_READY_CHANGED
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
binding.playPauseBTN.setImageResource(PlayerHelper.getPlayPauseActionIcon(player))
|
binding.playPauseBTN.setImageResource(
|
||||||
|
PlayerHelper.getPlayPauseActionIcon(player)
|
||||||
|
)
|
||||||
|
|
||||||
// keep screen on if the video is playing
|
// keep screen on if the video is playing
|
||||||
keepScreenOn = player.isPlaying == true
|
keepScreenOn = player.isPlaying == true
|
||||||
|
@ -67,7 +67,6 @@ class SingleViewTouchableMotionLayout(context: Context, attributeSet: AttributeS
|
|||||||
distanceX: Float,
|
distanceX: Float,
|
||||||
distanceY: Float
|
distanceY: Float
|
||||||
): Boolean {
|
): Boolean {
|
||||||
|
|
||||||
if (isStrictlyDownSwipe && distanceY > 0) {
|
if (isStrictlyDownSwipe && distanceY > 0) {
|
||||||
isStrictlyDownSwipe = false
|
isStrictlyDownSwipe = false
|
||||||
}
|
}
|
||||||
|
@ -262,13 +262,13 @@ class NowPlayingNotification(
|
|||||||
|
|
||||||
private fun createPlaybackState(@PlaybackStateCompat.State state: Int): PlaybackStateCompat {
|
private fun createPlaybackState(@PlaybackStateCompat.State state: Int): PlaybackStateCompat {
|
||||||
val stateActions = PlaybackStateCompat.ACTION_SKIP_TO_NEXT or
|
val stateActions = PlaybackStateCompat.ACTION_SKIP_TO_NEXT or
|
||||||
PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS or
|
PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS or
|
||||||
PlaybackStateCompat.ACTION_REWIND or
|
PlaybackStateCompat.ACTION_REWIND or
|
||||||
PlaybackStateCompat.ACTION_FAST_FORWARD or
|
PlaybackStateCompat.ACTION_FAST_FORWARD or
|
||||||
PlaybackStateCompat.ACTION_PLAY_PAUSE or
|
PlaybackStateCompat.ACTION_PLAY_PAUSE or
|
||||||
PlaybackStateCompat.ACTION_PAUSE or
|
PlaybackStateCompat.ACTION_PAUSE or
|
||||||
PlaybackStateCompat.ACTION_PLAY or
|
PlaybackStateCompat.ACTION_PLAY or
|
||||||
PlaybackStateCompat.ACTION_SEEK_TO
|
PlaybackStateCompat.ACTION_SEEK_TO
|
||||||
|
|
||||||
return PlaybackStateCompat.Builder()
|
return PlaybackStateCompat.Builder()
|
||||||
.setActions(stateActions)
|
.setActions(stateActions)
|
||||||
@ -302,8 +302,13 @@ class NowPlayingNotification(
|
|||||||
|
|
||||||
STOP -> {
|
STOP -> {
|
||||||
when (notificationType) {
|
when (notificationType) {
|
||||||
NowPlayingNotificationType.AUDIO_ONLINE -> BackgroundHelper.stopBackgroundPlay(context)
|
NowPlayingNotificationType.AUDIO_ONLINE -> BackgroundHelper.stopBackgroundPlay(
|
||||||
NowPlayingNotificationType.AUDIO_OFFLINE -> BackgroundHelper.stopBackgroundPlay(context, OfflinePlayerService::class.java)
|
context
|
||||||
|
)
|
||||||
|
NowPlayingNotificationType.AUDIO_OFFLINE -> BackgroundHelper.stopBackgroundPlay(
|
||||||
|
context,
|
||||||
|
OfflinePlayerService::class.java
|
||||||
|
)
|
||||||
else -> Unit
|
else -> Unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -381,7 +386,12 @@ class NowPlayingNotification(
|
|||||||
addAction(it)
|
addAction(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ContextCompat.registerReceiver(context, notificationActionReceiver, filter, ContextCompat.RECEIVER_NOT_EXPORTED)
|
ContextCompat.registerReceiver(
|
||||||
|
context,
|
||||||
|
notificationActionReceiver,
|
||||||
|
filter,
|
||||||
|
ContextCompat.RECEIVER_NOT_EXPORTED
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -417,7 +427,7 @@ class NowPlayingNotification(
|
|||||||
VIDEO_ONLINE,
|
VIDEO_ONLINE,
|
||||||
VIDEO_OFFLINE,
|
VIDEO_OFFLINE,
|
||||||
AUDIO_ONLINE,
|
AUDIO_ONLINE,
|
||||||
AUDIO_OFFLINE,
|
AUDIO_OFFLINE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,11 +20,15 @@ class PauseableTimer(
|
|||||||
fun resume() {
|
fun resume() {
|
||||||
if (timer == null) timer = Timer()
|
if (timer == null) timer = Timer()
|
||||||
|
|
||||||
timer?.scheduleAtFixedRate(object : TimerTask() {
|
timer?.scheduleAtFixedRate(
|
||||||
override fun run() {
|
object : TimerTask() {
|
||||||
handler.post(onTick)
|
override fun run() {
|
||||||
}
|
handler.post(onTick)
|
||||||
}, delayMillis, delayMillis)
|
}
|
||||||
|
},
|
||||||
|
delayMillis,
|
||||||
|
delayMillis
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun pause() {
|
fun pause() {
|
||||||
@ -36,4 +40,4 @@ class PauseableTimer(
|
|||||||
timer?.cancel()
|
timer?.cancel()
|
||||||
timer = null
|
timer = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,9 +12,9 @@ import com.github.libretube.constants.IntentData.appUpdateURL
|
|||||||
import com.github.libretube.extensions.TAG
|
import com.github.libretube.extensions.TAG
|
||||||
import com.github.libretube.extensions.toastFromMainDispatcher
|
import com.github.libretube.extensions.toastFromMainDispatcher
|
||||||
import com.github.libretube.ui.dialogs.UpdateAvailableDialog
|
import com.github.libretube.ui.dialogs.UpdateAvailableDialog
|
||||||
|
import java.util.Locale
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import java.util.Locale
|
|
||||||
|
|
||||||
class UpdateChecker(private val context: Context) {
|
class UpdateChecker(private val context: Context) {
|
||||||
suspend fun checkUpdate(isManualCheck: Boolean = false) {
|
suspend fun checkUpdate(isManualCheck: Boolean = false) {
|
||||||
@ -40,7 +40,7 @@ class UpdateChecker(private val context: Context) {
|
|||||||
|
|
||||||
private fun showUpdateAvailableDialog(
|
private fun showUpdateAvailableDialog(
|
||||||
changelog: String,
|
changelog: String,
|
||||||
url: String,
|
url: String
|
||||||
) {
|
) {
|
||||||
val dialog = UpdateAvailableDialog()
|
val dialog = UpdateAvailableDialog()
|
||||||
val args =
|
val args =
|
||||||
|
@ -7,7 +7,6 @@ import androidx.benchmark.macro.StartupTimingMetric
|
|||||||
import androidx.benchmark.macro.junit4.MacrobenchmarkRule
|
import androidx.benchmark.macro.junit4.MacrobenchmarkRule
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
import androidx.test.filters.LargeTest
|
import androidx.test.filters.LargeTest
|
||||||
|
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
@ -72,4 +71,4 @@ class StartupBenchmarks {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user