mirror of
https://github.com/libre-tube/LibreTube.git
synced 2024-12-14 14:20:30 +05:30
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
aa998d80a4
18
README.md
18
README.md
@ -1,18 +1,18 @@
|
||||
<div align="center">
|
||||
<img src="https://libre-tube.github.io/images/gh-banner.png" width="auto" height="auto" alt="LibreTube">
|
||||
|
||||
[![GPL-v3](https://libre-tube.github.io/images/license-widget.svg)](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||
[![Matrix](https://libre-tube.github.io/images/mat-widget.svg)](https://matrix.to/#/#LibreTube:matrix.org)
|
||||
[![Telegram](https://libre-tube.github.io/images/tg-widget.svg)](https://t.me/libretube)
|
||||
[![Twitter](https://libre-tube.github.io/images/tw-widget.svg)](https://twitter.com/libretube)
|
||||
[![Reddit](https://libre-tube.github.io/images/rd-widget.svg)](https://www.reddit.com/r/Libretube/)
|
||||
[![Discord](https://libre-tube.github.io/images/discord-widget.svg)](https://discord.gg/Qc34xCj2GV)
|
||||
[![GPL-v3](https://libre-tube.github.io/assets/widgets/license-widget.svg)](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||
[![Matrix](https://libre-tube.github.io/assets/widgets/mat-widget.svg)](https://matrix.to/#/#LibreTube:matrix.org)
|
||||
[![Mastodon](https://libre-tube.github.io/assets/widgets/mast-widget.svg)](https://fosstodon.org/@libretube)
|
||||
[![Telegram](https://libre-tube.github.io/assets/widgets/tg-widget.svg)](https://t.me/libretube)
|
||||
[![Reddit](https://libre-tube.github.io/assets/widgets/rd-widget.svg)](https://www.reddit.com/r/Libretube/)
|
||||
[![Discord](https://libre-tube.github.io/assets/widgets/discord-widget.svg)](https://discord.gg/Qc34xCj2GV)
|
||||
|
||||
</div><div align="center" style="width:100%; display:flex; justify-content:space-between;">
|
||||
|
||||
[<img src="https://libre-tube.github.io/images/fdrload.png" alt="Get it on F-Droid" width="30%">](https://f-droid.org/en/packages/com.github.libretube/)
|
||||
[<img src="https://libre-tube.github.io/images/izzyload.png" alt="Get it on IzzyOnDroid" width="30%">](https://apt.izzysoft.de/fdroid/index/apk/com.github.libretube)<br/>
|
||||
[<img src="https://libre-tube.github.io/images/ghload.png" alt="Get it on GitHub" width="30%">](https://github.com/libre-tube/LibreTube/releases/latest)
|
||||
[<img src="https://libre-tube.github.io/assets/badges/fdrload.png" alt="Get it on F-Droid" width="30%">](https://f-droid.org/en/packages/com.github.libretube/)
|
||||
[<img src="https://libre-tube.github.io/assets/badges/izzyload.png" alt="Get it on IzzyOnDroid" width="30%">](https://apt.izzysoft.de/fdroid/index/apk/com.github.libretube)<br/>
|
||||
[<img src="https://libre-tube.github.io/assets/badges/ghload.png" alt="Get it on GitHub" width="30%">](https://github.com/libre-tube/LibreTube/releases/latest)
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -46,8 +46,6 @@ android {
|
||||
}
|
||||
|
||||
debug {
|
||||
minifyEnabled true
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
debuggable true
|
||||
applicationIdSuffix ".debug"
|
||||
resValue "string", "app_name", "LibreTube Debug"
|
||||
@ -127,4 +125,4 @@ dependencies {
|
||||
|
||||
static def getUnixTime() {
|
||||
return Instant.now().getEpochSecond()
|
||||
}
|
||||
}
|
||||
|
@ -12,12 +12,12 @@ import com.github.libretube.constants.BACKGROUND_CHANNEL_ID
|
||||
import com.github.libretube.constants.DOWNLOAD_CHANNEL_ID
|
||||
import com.github.libretube.constants.PUSH_CHANNEL_ID
|
||||
import com.github.libretube.db.DatabaseHolder
|
||||
import com.github.libretube.helpers.ImageHelper
|
||||
import com.github.libretube.helpers.NotificationHelper
|
||||
import com.github.libretube.helpers.PreferenceHelper
|
||||
import com.github.libretube.helpers.ProxyHelper
|
||||
import com.github.libretube.helpers.ShortcutHelper
|
||||
import com.github.libretube.util.ExceptionHandler
|
||||
import com.github.libretube.util.ImageHelper
|
||||
import com.github.libretube.util.NotificationHelper
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
import com.github.libretube.util.ProxyHelper
|
||||
import com.github.libretube.util.ShortcutHelper
|
||||
|
||||
class LibreTubeApp : Application() {
|
||||
override fun onCreate() {
|
||||
|
@ -109,7 +109,14 @@ interface PipedApi {
|
||||
suspend fun getFeed(@Query("authToken") token: String?): List<StreamItem>
|
||||
|
||||
@GET("feed/unauthenticated")
|
||||
suspend fun getUnauthenticatedFeed(@Query("channels") channels: String): List<StreamItem>
|
||||
suspend fun getUnauthenticatedFeed(
|
||||
@Query("channels") channels: String
|
||||
): List<StreamItem>
|
||||
|
||||
@POST("feed/unauthenticated")
|
||||
suspend fun getUnauthenticatedFeed(
|
||||
@Body channels: List<String>
|
||||
): List<StreamItem>
|
||||
|
||||
@GET("subscribed")
|
||||
suspend fun isSubscribed(
|
||||
@ -121,7 +128,14 @@ interface PipedApi {
|
||||
suspend fun subscriptions(@Header("Authorization") token: String): List<Subscription>
|
||||
|
||||
@GET("subscriptions/unauthenticated")
|
||||
suspend fun unauthenticatedSubscriptions(@Query("channels") channels: String): List<Subscription>
|
||||
suspend fun unauthenticatedSubscriptions(
|
||||
@Query("channels") channels: String
|
||||
): List<Subscription>
|
||||
|
||||
@POST("subscriptions/unauthenticated")
|
||||
suspend fun unauthenticatedSubscriptions(
|
||||
@Body channels: List<String>
|
||||
): List<Subscription>
|
||||
|
||||
@POST("subscribe")
|
||||
suspend fun subscribe(
|
||||
|
@ -2,6 +2,7 @@ package com.github.libretube.api
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import androidx.core.text.isDigitsOnly
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.api.obj.Playlist
|
||||
import com.github.libretube.api.obj.PlaylistId
|
||||
@ -12,20 +13,17 @@ import com.github.libretube.db.DatabaseHolder
|
||||
import com.github.libretube.db.obj.LocalPlaylist
|
||||
import com.github.libretube.enums.PlaylistType
|
||||
import com.github.libretube.extensions.TAG
|
||||
import com.github.libretube.extensions.awaitQuery
|
||||
import com.github.libretube.extensions.toID
|
||||
import com.github.libretube.extensions.toLocalPlaylistItem
|
||||
import com.github.libretube.extensions.toStreamItem
|
||||
import com.github.libretube.extensions.toastFromMainThread
|
||||
import com.github.libretube.helpers.PreferenceHelper
|
||||
import com.github.libretube.helpers.ProxyHelper
|
||||
import com.github.libretube.obj.ImportPlaylist
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
import com.github.libretube.util.ProxyHelper
|
||||
import java.io.IOException
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import retrofit2.HttpException
|
||||
|
||||
@ -35,26 +33,22 @@ object PlaylistsHelper {
|
||||
|
||||
private val token get() = PreferenceHelper.getToken()
|
||||
|
||||
val loggedIn: Boolean get() = token != ""
|
||||
val loggedIn: Boolean get() = token.isNotEmpty()
|
||||
|
||||
suspend fun getPlaylists(): List<Playlists> {
|
||||
if (loggedIn) return RetrofitInstance.authApi.getUserPlaylists(token)
|
||||
|
||||
val localPlaylists = awaitQuery {
|
||||
suspend fun getPlaylists(): List<Playlists> = withContext(Dispatchers.IO) {
|
||||
if (loggedIn) {
|
||||
RetrofitInstance.authApi.getUserPlaylists(token)
|
||||
} else {
|
||||
DatabaseHolder.Database.localPlaylistsDao().getAll()
|
||||
.map {
|
||||
Playlists(
|
||||
id = it.playlist.id.toString(),
|
||||
name = it.playlist.name,
|
||||
thumbnail = ProxyHelper.rewriteUrl(it.playlist.thumbnailUrl),
|
||||
videos = it.videos.size.toLong()
|
||||
)
|
||||
}
|
||||
}
|
||||
val playlists = mutableListOf<Playlists>()
|
||||
localPlaylists.forEach {
|
||||
playlists.add(
|
||||
Playlists(
|
||||
id = it.playlist.id.toString(),
|
||||
name = it.playlist.name,
|
||||
thumbnail = ProxyHelper.rewriteUrl(it.playlist.thumbnailUrl),
|
||||
videos = it.videos.size.toLong()
|
||||
)
|
||||
)
|
||||
}
|
||||
return playlists
|
||||
}
|
||||
|
||||
suspend fun getPlaylist(playlistId: String): Playlist {
|
||||
@ -63,9 +57,8 @@ object PlaylistsHelper {
|
||||
PlaylistType.PRIVATE -> RetrofitInstance.authApi.getPlaylist(playlistId)
|
||||
PlaylistType.PUBLIC -> RetrofitInstance.api.getPlaylist(playlistId)
|
||||
PlaylistType.LOCAL -> {
|
||||
val relation = awaitQuery {
|
||||
DatabaseHolder.Database.localPlaylistsDao().getAll()
|
||||
}.first { it.playlist.id.toString() == playlistId }
|
||||
val relation = DatabaseHolder.Database.localPlaylistsDao().getAll()
|
||||
.first { it.playlist.id.toString() == playlistId }
|
||||
return Playlist(
|
||||
name = relation.playlist.name,
|
||||
thumbnailUrl = ProxyHelper.rewriteUrl(relation.playlist.thumbnailUrl),
|
||||
@ -76,38 +69,26 @@ object PlaylistsHelper {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun createPlaylist(
|
||||
playlistName: String,
|
||||
appContext: Context
|
||||
): String? {
|
||||
suspend fun createPlaylist(playlistName: String, appContext: Context?): String? {
|
||||
if (!loggedIn) {
|
||||
awaitQuery {
|
||||
DatabaseHolder.Database.localPlaylistsDao().createPlaylist(
|
||||
LocalPlaylist(
|
||||
name = playlistName,
|
||||
thumbnailUrl = ""
|
||||
)
|
||||
)
|
||||
val playlist = LocalPlaylist(name = playlistName, thumbnailUrl = "")
|
||||
DatabaseHolder.Database.localPlaylistsDao().createPlaylist(playlist)
|
||||
return DatabaseHolder.Database.localPlaylistsDao().getAll()
|
||||
.last().playlist.id.toString()
|
||||
} else {
|
||||
return try {
|
||||
RetrofitInstance.authApi.createPlaylist(token, Playlists(name = playlistName))
|
||||
} catch (e: IOException) {
|
||||
appContext?.toastFromMainThread(R.string.unknown_error)
|
||||
return null
|
||||
} catch (e: HttpException) {
|
||||
Log.e(TAG(), e.toString())
|
||||
appContext?.toastFromMainThread(R.string.server_error)
|
||||
return null
|
||||
}.playlistId.also {
|
||||
appContext?.toastFromMainThread(R.string.playlistCreated)
|
||||
}
|
||||
return awaitQuery {
|
||||
DatabaseHolder.Database.localPlaylistsDao().getAll()
|
||||
}.last().playlist.id.toString()
|
||||
}
|
||||
val response = try {
|
||||
RetrofitInstance.authApi.createPlaylist(token, Playlists(name = playlistName))
|
||||
} catch (e: IOException) {
|
||||
appContext.toastFromMainThread(R.string.unknown_error)
|
||||
return null
|
||||
} catch (e: HttpException) {
|
||||
Log.e(TAG(), e.toString())
|
||||
appContext.toastFromMainThread(R.string.server_error)
|
||||
return null
|
||||
}
|
||||
if (response.playlistId != null) {
|
||||
appContext.toastFromMainThread(R.string.playlistCreated)
|
||||
return response.playlistId
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
suspend fun addToPlaylist(playlistId: String, vararg videos: StreamItem): Boolean {
|
||||
@ -117,22 +98,19 @@ object PlaylistsHelper {
|
||||
|
||||
for (video in videos) {
|
||||
val localPlaylistItem = video.toLocalPlaylistItem(playlistId)
|
||||
awaitQuery {
|
||||
// avoid duplicated videos in a playlist
|
||||
DatabaseHolder.Database.localPlaylistsDao()
|
||||
.deletePlaylistItemsByVideoId(playlistId, localPlaylistItem.videoId)
|
||||
// avoid duplicated videos in a playlist
|
||||
DatabaseHolder.Database.localPlaylistsDao()
|
||||
.deletePlaylistItemsByVideoId(playlistId, localPlaylistItem.videoId)
|
||||
|
||||
// add the new video to the database
|
||||
DatabaseHolder.Database.localPlaylistsDao().addPlaylistVideo(localPlaylistItem)
|
||||
// add the new video to the database
|
||||
DatabaseHolder.Database.localPlaylistsDao().addPlaylistVideo(localPlaylistItem)
|
||||
|
||||
if (localPlaylist.playlist.thumbnailUrl == "") {
|
||||
// set the new playlist thumbnail URL
|
||||
localPlaylistItem.thumbnailUrl?.let {
|
||||
localPlaylist.playlist.thumbnailUrl = it
|
||||
DatabaseHolder.Database.localPlaylistsDao().updatePlaylist(
|
||||
localPlaylist.playlist
|
||||
)
|
||||
}
|
||||
val playlist = localPlaylist.playlist
|
||||
if (playlist.thumbnailUrl == "") {
|
||||
// set the new playlist thumbnail URL
|
||||
localPlaylistItem.thumbnailUrl?.let {
|
||||
playlist.thumbnailUrl = it
|
||||
DatabaseHolder.Database.localPlaylistsDao().updatePlaylist(playlist)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -144,89 +122,72 @@ object PlaylistsHelper {
|
||||
}
|
||||
|
||||
suspend fun renamePlaylist(playlistId: String, newName: String): Boolean {
|
||||
if (!loggedIn) {
|
||||
val playlist = awaitQuery {
|
||||
DatabaseHolder.Database.localPlaylistsDao().getAll()
|
||||
}.first { it.playlist.id.toString() == playlistId }.playlist
|
||||
return if (!loggedIn) {
|
||||
val playlist = DatabaseHolder.Database.localPlaylistsDao().getAll()
|
||||
.first { it.playlist.id.toString() == playlistId }.playlist
|
||||
playlist.name = newName
|
||||
awaitQuery {
|
||||
DatabaseHolder.Database.localPlaylistsDao().updatePlaylist(playlist)
|
||||
}
|
||||
return true
|
||||
DatabaseHolder.Database.localPlaylistsDao().updatePlaylist(playlist)
|
||||
true
|
||||
} else {
|
||||
val playlist = PlaylistId(playlistId, newName = newName)
|
||||
RetrofitInstance.authApi.renamePlaylist(token, playlist).playlistId != null
|
||||
}
|
||||
|
||||
return RetrofitInstance.authApi.renamePlaylist(
|
||||
token,
|
||||
PlaylistId(playlistId, newName = newName)
|
||||
).playlistId != null
|
||||
}
|
||||
|
||||
suspend fun removeFromPlaylist(playlistId: String, index: Int) {
|
||||
if (!loggedIn) {
|
||||
val transaction = awaitQuery {
|
||||
DatabaseHolder.Database.localPlaylistsDao().getAll()
|
||||
}.first { it.playlist.id.toString() == playlistId }
|
||||
awaitQuery {
|
||||
DatabaseHolder.Database.localPlaylistsDao().removePlaylistVideo(
|
||||
transaction.videos[index]
|
||||
)
|
||||
}
|
||||
if (transaction.videos.size > 1) {
|
||||
if (index == 0) {
|
||||
transaction.videos[1].thumbnailUrl?.let {
|
||||
transaction.playlist.thumbnailUrl = it
|
||||
}
|
||||
awaitQuery {
|
||||
DatabaseHolder.Database.localPlaylistsDao().updatePlaylist(
|
||||
transaction.playlist
|
||||
)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
// remove thumbnail if playlist now empty
|
||||
awaitQuery {
|
||||
transaction.playlist.thumbnailUrl = ""
|
||||
DatabaseHolder.Database.localPlaylistsDao().updatePlaylist(transaction.playlist)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
RetrofitInstance.authApi.removeFromPlaylist(
|
||||
PreferenceHelper.getToken(),
|
||||
PlaylistId(
|
||||
playlistId = playlistId,
|
||||
index = index
|
||||
suspend fun removeFromPlaylist(playlistId: String, index: Int): Boolean {
|
||||
return if (!loggedIn) {
|
||||
val transaction = DatabaseHolder.Database.localPlaylistsDao().getAll()
|
||||
.first { it.playlist.id.toString() == playlistId }
|
||||
DatabaseHolder.Database.localPlaylistsDao().removePlaylistVideo(
|
||||
transaction.videos[index]
|
||||
)
|
||||
)
|
||||
// set a new playlist thumbnail if the first video got removed
|
||||
if (index == 0) {
|
||||
transaction.playlist.thumbnailUrl = transaction.videos.getOrNull(1)?.thumbnailUrl ?: ""
|
||||
}
|
||||
DatabaseHolder.Database.localPlaylistsDao().updatePlaylist(transaction.playlist)
|
||||
true
|
||||
} else {
|
||||
RetrofitInstance.authApi.removeFromPlaylist(
|
||||
PreferenceHelper.getToken(),
|
||||
PlaylistId(playlistId = playlistId, index = index)
|
||||
).message == "ok"
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun importPlaylists(appContext: Context, playlists: List<ImportPlaylist>) {
|
||||
for (playlist in playlists) {
|
||||
val playlistId = createPlaylist(playlist.name!!, appContext) ?: continue
|
||||
// if logged in, add the playlists by their ID via an api call
|
||||
val success: Boolean = if (loggedIn) {
|
||||
addToPlaylist(
|
||||
playlistId,
|
||||
*playlist.videos.map {
|
||||
StreamItem(url = it)
|
||||
}.toTypedArray()
|
||||
)
|
||||
} else {
|
||||
// if not logged in, all video information needs to become fetched manually
|
||||
try {
|
||||
val streamItems = playlist.videos.map {
|
||||
RetrofitInstance.api.getStreams(it).toStreamItem(it)
|
||||
suspend fun importPlaylists(playlists: List<ImportPlaylist>) = withContext(Dispatchers.IO) {
|
||||
playlists.map { playlist ->
|
||||
val playlistId = createPlaylist(playlist.name!!, null)
|
||||
async {
|
||||
playlistId ?: return@async
|
||||
// if logged in, add the playlists by their ID via an api call
|
||||
if (loggedIn) {
|
||||
addToPlaylist(
|
||||
playlistId,
|
||||
*playlist.videos.map {
|
||||
StreamItem(url = it)
|
||||
}.toTypedArray()
|
||||
)
|
||||
} else {
|
||||
// if not logged in, all video information needs to become fetched manually
|
||||
runCatching {
|
||||
val streamItems = playlist.videos.map {
|
||||
async {
|
||||
try {
|
||||
RetrofitInstance.api.getStreams(it).toStreamItem(it)
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
.awaitAll()
|
||||
.filterNotNull()
|
||||
|
||||
addToPlaylist(playlistId, *streamItems.toTypedArray())
|
||||
}
|
||||
addToPlaylist(playlistId, *streamItems.toTypedArray())
|
||||
} catch (e: Exception) {
|
||||
false
|
||||
}
|
||||
}
|
||||
appContext.toastFromMainThread(
|
||||
if (success) R.string.importsuccess else R.string.server_error
|
||||
)
|
||||
}
|
||||
}.awaitAll()
|
||||
}
|
||||
|
||||
suspend fun exportPlaylists(): List<ImportPlaylist> = withContext(Dispatchers.IO) {
|
||||
@ -241,49 +202,35 @@ object PlaylistsHelper {
|
||||
}
|
||||
}
|
||||
|
||||
fun clonePlaylist(context: Context, playlistId: String) {
|
||||
suspend fun clonePlaylist(context: Context, playlistId: String): String? {
|
||||
val appContext = context.applicationContext
|
||||
if (!loggedIn) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val playlist = try {
|
||||
RetrofitInstance.api.getPlaylist(playlistId)
|
||||
} catch (e: Exception) {
|
||||
appContext.toastFromMainThread(R.string.server_error)
|
||||
return@launch
|
||||
}
|
||||
val newPlaylist = createPlaylist(playlist.name ?: "Unknown name", appContext)
|
||||
newPlaylist ?: return@launch
|
||||
|
||||
addToPlaylist(newPlaylist, *playlist.relatedStreams.toTypedArray())
|
||||
|
||||
var nextPage = playlist.nextpage
|
||||
while (nextPage != null) {
|
||||
nextPage = try {
|
||||
RetrofitInstance.api.getPlaylistNextPage(playlistId, nextPage).apply {
|
||||
addToPlaylist(newPlaylist, *relatedStreams.toTypedArray())
|
||||
}.nextpage
|
||||
} catch (e: Exception) {
|
||||
return@launch
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val response = try {
|
||||
RetrofitInstance.authApi.clonePlaylist(
|
||||
token,
|
||||
PlaylistId(playlistId)
|
||||
)
|
||||
val playlist = try {
|
||||
RetrofitInstance.api.getPlaylist(playlistId)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG(), e.toString())
|
||||
return@launch
|
||||
appContext.toastFromMainThread(R.string.server_error)
|
||||
return null
|
||||
}
|
||||
appContext?.toastFromMainThread(
|
||||
if (response.playlistId != null) R.string.playlistCloned else R.string.server_error
|
||||
)
|
||||
val newPlaylist = createPlaylist(playlist.name ?: "Unknown name", appContext) ?: return null
|
||||
|
||||
addToPlaylist(newPlaylist, *playlist.relatedStreams.toTypedArray())
|
||||
|
||||
var nextPage = playlist.nextpage
|
||||
while (nextPage != null) {
|
||||
nextPage = try {
|
||||
RetrofitInstance.api.getPlaylistNextPage(playlistId, nextPage).apply {
|
||||
addToPlaylist(newPlaylist, *relatedStreams.toTypedArray())
|
||||
}.nextpage
|
||||
} catch (e: Exception) {
|
||||
break
|
||||
}
|
||||
}
|
||||
return playlistId
|
||||
}
|
||||
|
||||
return runCatching {
|
||||
RetrofitInstance.authApi.clonePlaylist(token, PlaylistId(playlistId))
|
||||
}.getOrNull()?.playlistId
|
||||
}
|
||||
|
||||
fun getPrivatePlaylistType(): PlaylistType {
|
||||
@ -291,8 +238,12 @@ object PlaylistsHelper {
|
||||
}
|
||||
|
||||
private fun getPrivatePlaylistType(playlistId: String): PlaylistType {
|
||||
if (playlistId.all { it.isDigit() }) return PlaylistType.LOCAL
|
||||
if (playlistId.matches(pipedPlaylistRegex)) return PlaylistType.PRIVATE
|
||||
return PlaylistType.PUBLIC
|
||||
return if (playlistId.isDigitsOnly()) {
|
||||
PlaylistType.LOCAL
|
||||
} else if (playlistId.matches(pipedPlaylistRegex)) {
|
||||
PlaylistType.PRIVATE
|
||||
} else {
|
||||
PlaylistType.PUBLIC
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ package com.github.libretube.api
|
||||
|
||||
import com.github.libretube.constants.PIPED_API_URL
|
||||
import com.github.libretube.constants.PreferenceKeys
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
import com.github.libretube.helpers.PreferenceHelper
|
||||
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import retrofit2.Retrofit
|
||||
|
@ -10,13 +10,15 @@ import com.github.libretube.constants.PreferenceKeys
|
||||
import com.github.libretube.db.DatabaseHolder.Companion.Database
|
||||
import com.github.libretube.db.obj.LocalSubscription
|
||||
import com.github.libretube.extensions.TAG
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
import com.github.libretube.helpers.PreferenceHelper
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
object SubscriptionHelper {
|
||||
private const val GET_SUBSCRIPTIONS_LIMIT = 100
|
||||
|
||||
suspend fun subscribe(channelId: String) {
|
||||
val token = PreferenceHelper.getToken()
|
||||
if (token.isNotEmpty()) {
|
||||
@ -102,17 +104,20 @@ object SubscriptionHelper {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getFormattedLocalSubscriptions(): String {
|
||||
return Database.localSubscriptionDao().getAll()
|
||||
.joinToString(",") { it.channelId }
|
||||
}
|
||||
|
||||
suspend fun getSubscriptions(): List<Subscription> {
|
||||
val token = PreferenceHelper.getToken()
|
||||
return if (token.isNotEmpty()) {
|
||||
RetrofitInstance.authApi.subscriptions(token)
|
||||
} else {
|
||||
RetrofitInstance.authApi.unauthenticatedSubscriptions(getFormattedLocalSubscriptions())
|
||||
val subscriptions = Database.localSubscriptionDao().getAll().map { it.channelId }
|
||||
when {
|
||||
subscriptions.size > GET_SUBSCRIPTIONS_LIMIT -> RetrofitInstance.authApi.unauthenticatedSubscriptions(
|
||||
subscriptions
|
||||
)
|
||||
else -> RetrofitInstance.authApi.unauthenticatedSubscriptions(
|
||||
subscriptions.joinToString(",")
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -121,7 +126,15 @@ object SubscriptionHelper {
|
||||
return if (token.isNotEmpty()) {
|
||||
RetrofitInstance.authApi.getFeed(token)
|
||||
} else {
|
||||
RetrofitInstance.authApi.getUnauthenticatedFeed(getFormattedLocalSubscriptions())
|
||||
val subscriptions = Database.localSubscriptionDao().getAll().map { it.channelId }
|
||||
when {
|
||||
subscriptions.size > GET_SUBSCRIPTIONS_LIMIT -> RetrofitInstance.authApi.getUnauthenticatedFeed(
|
||||
subscriptions
|
||||
)
|
||||
else -> RetrofitInstance.authApi.getUnauthenticatedFeed(
|
||||
subscriptions.joinToString(",")
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,11 +18,11 @@ const val FAQ_URL = "https://libre-tube.github.io/#faq"
|
||||
/**
|
||||
* Social media links for the community fragment
|
||||
*/
|
||||
const val TELEGRAM_URL = "https://t.me/libretube"
|
||||
const val MATRIX_URL = "https://matrix.to/#/#LibreTube:matrix.org"
|
||||
const val MASTODON_URL = "https://fosstodon.org/@libretube"
|
||||
const val TELEGRAM_URL = "https://t.me/libretube"
|
||||
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
|
||||
|
@ -7,7 +7,7 @@ import com.github.libretube.db.obj.SearchHistoryItem
|
||||
import com.github.libretube.db.obj.WatchHistoryItem
|
||||
import com.github.libretube.extensions.query
|
||||
import com.github.libretube.extensions.toID
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
import com.github.libretube.helpers.PreferenceHelper
|
||||
|
||||
object DatabaseHelper {
|
||||
private const val MAX_SEARCH_HISTORY_SIZE = 20
|
||||
|
@ -14,29 +14,26 @@ import com.github.libretube.db.obj.LocalPlaylistWithVideos
|
||||
interface LocalPlaylistsDao {
|
||||
@Transaction
|
||||
@Query("SELECT * FROM LocalPlaylist")
|
||||
fun getAll(): List<LocalPlaylistWithVideos>
|
||||
suspend fun getAll(): List<LocalPlaylistWithVideos>
|
||||
|
||||
@Insert
|
||||
fun createPlaylist(playlist: LocalPlaylist)
|
||||
suspend fun createPlaylist(playlist: LocalPlaylist)
|
||||
|
||||
@Update
|
||||
fun updatePlaylist(playlist: LocalPlaylist)
|
||||
|
||||
@Delete
|
||||
fun deletePlaylist(playlist: LocalPlaylist)
|
||||
suspend fun updatePlaylist(playlist: LocalPlaylist)
|
||||
|
||||
@Query("DELETE FROM localPlaylist WHERE id = :playlistId")
|
||||
fun deletePlaylistById(playlistId: String)
|
||||
suspend fun deletePlaylistById(playlistId: String)
|
||||
|
||||
@Insert
|
||||
fun addPlaylistVideo(playlistVideo: LocalPlaylistItem)
|
||||
suspend fun addPlaylistVideo(playlistVideo: LocalPlaylistItem)
|
||||
|
||||
@Delete
|
||||
fun removePlaylistVideo(playlistVideo: LocalPlaylistItem)
|
||||
suspend fun removePlaylistVideo(playlistVideo: LocalPlaylistItem)
|
||||
|
||||
@Query("DELETE FROM localPlaylistItem WHERE playlistId = :playlistId")
|
||||
fun deletePlaylistItemsByPlaylistId(playlistId: String)
|
||||
suspend fun deletePlaylistItemsByPlaylistId(playlistId: String)
|
||||
|
||||
@Query("DELETE FROM localPlaylistItem WHERE playlistId = :playlistId AND videoId = :videoId")
|
||||
fun deletePlaylistItemsByVideoId(playlistId: String, videoId: String)
|
||||
suspend fun deletePlaylistItemsByVideoId(playlistId: String, videoId: String)
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ package com.github.libretube.extensions
|
||||
import com.github.libretube.api.obj.StreamItem
|
||||
import com.github.libretube.api.obj.Streams
|
||||
import com.github.libretube.db.obj.LocalPlaylistItem
|
||||
import com.github.libretube.util.ProxyHelper
|
||||
import com.github.libretube.helpers.ProxyHelper
|
||||
|
||||
fun Streams.toStreamItem(videoId: String): StreamItem {
|
||||
return StreamItem(
|
||||
|
@ -4,6 +4,8 @@ import android.content.Context
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.widget.Toast
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
fun Context.toastFromMainThread(text: String) {
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
@ -18,3 +20,11 @@ fun Context.toastFromMainThread(text: String) {
|
||||
fun Context.toastFromMainThread(stringId: Int) {
|
||||
toastFromMainThread(getString(stringId))
|
||||
}
|
||||
|
||||
suspend fun Context.toastFromMainDispatcher(text: String) = withContext(Dispatchers.Main) {
|
||||
Toast.makeText(this@toastFromMainDispatcher, text, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
suspend fun Context.toastFromMainDispatcher(stringId: Int) {
|
||||
toastFromMainDispatcher(getString(stringId))
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.github.libretube.util
|
||||
package com.github.libretube.helpers
|
||||
|
||||
import android.content.Context
|
||||
import android.media.AudioManager
|
@ -1,4 +1,4 @@
|
||||
package com.github.libretube.util
|
||||
package com.github.libretube.helpers
|
||||
|
||||
import android.app.ActivityManager
|
||||
import android.content.Context
|
@ -1,4 +1,4 @@
|
||||
package com.github.libretube.util
|
||||
package com.github.libretube.helpers
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
@ -11,8 +11,7 @@ import com.github.libretube.db.DatabaseHolder.Companion.Database
|
||||
import com.github.libretube.extensions.TAG
|
||||
import com.github.libretube.obj.BackupFile
|
||||
import com.github.libretube.obj.PreferenceItem
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.json.booleanOrNull
|
||||
import kotlinx.serialization.json.decodeFromStream
|
||||
import kotlinx.serialization.json.encodeToStream
|
||||
@ -23,67 +22,63 @@ import kotlinx.serialization.json.longOrNull
|
||||
/**
|
||||
* Backup and restore the preferences
|
||||
*/
|
||||
class BackupHelper(private val context: Context) {
|
||||
object BackupHelper {
|
||||
/**
|
||||
* Write a [BackupFile] containing the database content as well as the preferences
|
||||
*/
|
||||
fun createAdvancedBackup(uri: Uri?, backupFile: BackupFile) {
|
||||
uri?.let {
|
||||
try {
|
||||
context.contentResolver.openOutputStream(it)?.use { outputStream ->
|
||||
JsonHelper.json.encodeToStream(backupFile, outputStream)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG(), "Error while writing backup: $e")
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
fun createAdvancedBackup(context: Context, uri: Uri, backupFile: BackupFile) {
|
||||
try {
|
||||
context.contentResolver.openOutputStream(uri)?.use { outputStream ->
|
||||
JsonHelper.json.encodeToStream(backupFile, outputStream)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG(), "Error while writing backup: $e")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore data from a [BackupFile]
|
||||
*/
|
||||
fun restoreAdvancedBackup(uri: Uri?) {
|
||||
val backupFile = uri?.let {
|
||||
context.contentResolver.openInputStream(it)?.use { inputStream ->
|
||||
JsonHelper.json.decodeFromStream<BackupFile>(inputStream)
|
||||
}
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
suspend fun restoreAdvancedBackup(context: Context, uri: Uri) {
|
||||
val backupFile = context.contentResolver.openInputStream(uri)?.use {
|
||||
JsonHelper.json.decodeFromStream<BackupFile>(it)
|
||||
} ?: return
|
||||
|
||||
runBlocking(Dispatchers.IO) {
|
||||
Database.watchHistoryDao().insertAll(
|
||||
*backupFile.watchHistory.orEmpty().toTypedArray()
|
||||
)
|
||||
Database.searchHistoryDao().insertAll(
|
||||
*backupFile.searchHistory.orEmpty().toTypedArray()
|
||||
)
|
||||
Database.watchPositionDao().insertAll(
|
||||
*backupFile.watchPositions.orEmpty().toTypedArray()
|
||||
)
|
||||
Database.localSubscriptionDao().insertAll(backupFile.localSubscriptions.orEmpty())
|
||||
Database.customInstanceDao().insertAll(
|
||||
*backupFile.customInstances.orEmpty().toTypedArray()
|
||||
)
|
||||
Database.playlistBookmarkDao().insertAll(
|
||||
*backupFile.playlistBookmarks.orEmpty().toTypedArray()
|
||||
)
|
||||
Database.watchHistoryDao().insertAll(
|
||||
*backupFile.watchHistory.orEmpty().toTypedArray()
|
||||
)
|
||||
Database.searchHistoryDao().insertAll(
|
||||
*backupFile.searchHistory.orEmpty().toTypedArray()
|
||||
)
|
||||
Database.watchPositionDao().insertAll(
|
||||
*backupFile.watchPositions.orEmpty().toTypedArray()
|
||||
)
|
||||
Database.localSubscriptionDao().insertAll(backupFile.localSubscriptions.orEmpty())
|
||||
Database.customInstanceDao().insertAll(
|
||||
*backupFile.customInstances.orEmpty().toTypedArray()
|
||||
)
|
||||
Database.playlistBookmarkDao().insertAll(
|
||||
*backupFile.playlistBookmarks.orEmpty().toTypedArray()
|
||||
)
|
||||
|
||||
backupFile.localPlaylists.orEmpty().forEach {
|
||||
Database.localPlaylistsDao().createPlaylist(it.playlist)
|
||||
val playlistId = Database.localPlaylistsDao().getAll().last().playlist.id
|
||||
it.videos.forEach {
|
||||
it.playlistId = playlistId
|
||||
Database.localPlaylistsDao().addPlaylistVideo(it)
|
||||
}
|
||||
backupFile.localPlaylists.orEmpty().forEach {
|
||||
Database.localPlaylistsDao().createPlaylist(it.playlist)
|
||||
val playlistId = Database.localPlaylistsDao().getAll().last().playlist.id
|
||||
it.videos.forEach {
|
||||
it.playlistId = playlistId
|
||||
Database.localPlaylistsDao().addPlaylistVideo(it)
|
||||
}
|
||||
|
||||
restorePreferences(backupFile.preferences)
|
||||
}
|
||||
|
||||
restorePreferences(context, backupFile.preferences)
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the shared preferences from a backup file
|
||||
*/
|
||||
private fun restorePreferences(preferences: List<PreferenceItem>?) {
|
||||
private fun restorePreferences(context: Context, preferences: List<PreferenceItem>?) {
|
||||
if (preferences == null) return
|
||||
PreferenceManager.getDefaultSharedPreferences(context).edit(commit = true) {
|
||||
// clear the previous settings
|
@ -1,4 +1,4 @@
|
||||
package com.github.libretube.util
|
||||
package com.github.libretube.helpers
|
||||
|
||||
import android.app.Activity
|
||||
import android.view.WindowManager
|
@ -0,0 +1,14 @@
|
||||
package com.github.libretube.helpers
|
||||
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import androidx.core.content.getSystemService
|
||||
import com.github.libretube.R
|
||||
|
||||
object ClipboardHelper {
|
||||
fun save(context: Context, text: String) {
|
||||
val clip = ClipData.newPlainText(context.getString(R.string.copied), text)
|
||||
context.getSystemService<ClipboardManager>()!!.setPrimaryClip(clip)
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.github.libretube.util
|
||||
package com.github.libretube.helpers
|
||||
|
||||
import com.github.libretube.api.obj.PipedStream
|
||||
import com.github.libretube.api.obj.Streams
|
@ -1,4 +1,4 @@
|
||||
package com.github.libretube.util
|
||||
package com.github.libretube.helpers
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
@ -1,4 +1,4 @@
|
||||
package com.github.libretube.util
|
||||
package com.github.libretube.helpers
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
@ -13,6 +13,7 @@ import coil.request.CachePolicy
|
||||
import coil.request.ImageRequest
|
||||
import com.github.libretube.api.CronetHelper
|
||||
import com.github.libretube.constants.PreferenceKeys
|
||||
import com.github.libretube.util.DataSaverMode
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import okio.use
|
@ -1,60 +1,51 @@
|
||||
package com.github.libretube.util
|
||||
package com.github.libretube.helpers
|
||||
|
||||
import android.app.Activity
|
||||
import android.net.Uri
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.api.JsonHelper
|
||||
import com.github.libretube.api.PlaylistsHelper
|
||||
import com.github.libretube.api.RetrofitInstance
|
||||
import com.github.libretube.api.SubscriptionHelper
|
||||
import com.github.libretube.db.DatabaseHolder.Companion.Database
|
||||
import com.github.libretube.extensions.TAG
|
||||
import com.github.libretube.extensions.toastFromMainThread
|
||||
import com.github.libretube.extensions.toastFromMainDispatcher
|
||||
import com.github.libretube.obj.ImportPlaylist
|
||||
import com.github.libretube.obj.ImportPlaylistFile
|
||||
import com.github.libretube.obj.NewPipeSubscription
|
||||
import com.github.libretube.obj.NewPipeSubscriptions
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.json.decodeFromStream
|
||||
import kotlinx.serialization.json.encodeToStream
|
||||
import okio.use
|
||||
|
||||
class ImportHelper(
|
||||
private val activity: Activity
|
||||
) {
|
||||
object ImportHelper {
|
||||
/**
|
||||
* Import subscriptions by a file uri
|
||||
*/
|
||||
fun importSubscriptions(uri: Uri?) {
|
||||
if (uri == null) return
|
||||
suspend fun importSubscriptions(activity: Activity, uri: Uri) {
|
||||
try {
|
||||
val applicationContext = activity.applicationContext
|
||||
val channels = getChannelsFromUri(uri)
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
SubscriptionHelper.importSubscriptions(channels)
|
||||
}.invokeOnCompletion {
|
||||
applicationContext.toastFromMainThread(R.string.importsuccess)
|
||||
}
|
||||
SubscriptionHelper.importSubscriptions(getChannelsFromUri(activity, uri))
|
||||
activity.toastFromMainDispatcher(R.string.importsuccess)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
Log.e(TAG(), e.toString())
|
||||
activity.toastFromMainThread(
|
||||
activity.toastFromMainDispatcher(
|
||||
activity.getString(R.string.unsupported_file_format) +
|
||||
" (${activity.contentResolver.getType(uri)})"
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG(), e.toString())
|
||||
Toast.makeText(activity, e.localizedMessage, Toast.LENGTH_SHORT).show()
|
||||
e.localizedMessage?.let {
|
||||
activity.toastFromMainDispatcher(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of channel IDs from a file [Uri]
|
||||
*/
|
||||
private fun getChannelsFromUri(uri: Uri): List<String> {
|
||||
private fun getChannelsFromUri(activity: Activity, uri: Uri): List<String> {
|
||||
return when (val fileType = activity.contentResolver.getType(uri)) {
|
||||
"application/json", "application/*", "application/octet-stream" -> {
|
||||
// NewPipe subscriptions format
|
||||
@ -82,36 +73,31 @@ class ImportHelper(
|
||||
/**
|
||||
* Write the text to the document
|
||||
*/
|
||||
fun exportSubscriptions(uri: Uri?) {
|
||||
if (uri == null) return
|
||||
runBlocking(Dispatchers.IO) {
|
||||
val token = PreferenceHelper.getToken()
|
||||
val subs = if (token.isNotEmpty()) {
|
||||
RetrofitInstance.authApi.subscriptions(token)
|
||||
} else {
|
||||
RetrofitInstance.authApi.unauthenticatedSubscriptions(
|
||||
SubscriptionHelper.getFormattedLocalSubscriptions()
|
||||
)
|
||||
}
|
||||
val newPipeChannels = subs.map {
|
||||
NewPipeSubscription(it.name, 0, "https://www.youtube.com${it.url}")
|
||||
}
|
||||
val newPipeSubscriptions = NewPipeSubscriptions(subscriptions = newPipeChannels)
|
||||
|
||||
activity.contentResolver.openOutputStream(uri)?.use {
|
||||
JsonHelper.json.encodeToStream(newPipeSubscriptions, it)
|
||||
}
|
||||
|
||||
activity.toastFromMainThread(R.string.exportsuccess)
|
||||
suspend fun exportSubscriptions(activity: Activity, uri: Uri) {
|
||||
val token = PreferenceHelper.getToken()
|
||||
val subs = if (token.isNotEmpty()) {
|
||||
RetrofitInstance.authApi.subscriptions(token)
|
||||
} else {
|
||||
val subscriptions = Database.localSubscriptionDao().getAll().map { it.channelId }
|
||||
RetrofitInstance.authApi.unauthenticatedSubscriptions(subscriptions)
|
||||
}
|
||||
val newPipeChannels = subs.map {
|
||||
NewPipeSubscription(it.name, 0, "https://www.youtube.com${it.url}")
|
||||
}
|
||||
val newPipeSubscriptions = NewPipeSubscriptions(subscriptions = newPipeChannels)
|
||||
|
||||
activity.contentResolver.openOutputStream(uri)?.use {
|
||||
JsonHelper.json.encodeToStream(newPipeSubscriptions, it)
|
||||
}
|
||||
|
||||
activity.toastFromMainDispatcher(R.string.exportsuccess)
|
||||
}
|
||||
|
||||
/**
|
||||
* Import Playlists
|
||||
*/
|
||||
fun importPlaylists(uri: Uri?) {
|
||||
if (uri == null) return
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
suspend fun importPlaylists(activity: Activity, uri: Uri) {
|
||||
val importPlaylists = mutableListOf<ImportPlaylist>()
|
||||
|
||||
when (val fileType = activity.contentResolver.getType(uri)) {
|
||||
@ -136,20 +122,22 @@ class ImportHelper(
|
||||
importPlaylists.addAll(playlistFile?.playlists.orEmpty())
|
||||
}
|
||||
else -> {
|
||||
activity.applicationContext.toastFromMainThread("Unsupported file type $fileType")
|
||||
activity.toastFromMainDispatcher("Unsupported file type $fileType")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
try {
|
||||
PlaylistsHelper.importPlaylists(activity, importPlaylists)
|
||||
activity.applicationContext.toastFromMainThread(R.string.success)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG(), e.toString())
|
||||
e.localizedMessage?.let {
|
||||
activity.applicationContext.toastFromMainThread(it)
|
||||
}
|
||||
// convert the YouTube URLs to videoIds
|
||||
importPlaylists.forEach { playlist ->
|
||||
playlist.videos = playlist.videos.map { it.takeLast(11) }
|
||||
}
|
||||
try {
|
||||
PlaylistsHelper.importPlaylists(importPlaylists)
|
||||
activity.toastFromMainDispatcher(R.string.success)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG(), e.toString())
|
||||
e.localizedMessage?.let {
|
||||
activity.toastFromMainDispatcher(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -157,18 +145,14 @@ class ImportHelper(
|
||||
/**
|
||||
* Export Playlists
|
||||
*/
|
||||
fun exportPlaylists(uri: Uri?) {
|
||||
if (uri == null) return
|
||||
suspend fun exportPlaylists(activity: Activity, uri: Uri) {
|
||||
val playlists = PlaylistsHelper.exportPlaylists()
|
||||
val playlistFile = ImportPlaylistFile("Piped", 1, playlists)
|
||||
|
||||
runBlocking {
|
||||
val playlists = PlaylistsHelper.exportPlaylists()
|
||||
val playlistFile = ImportPlaylistFile("Piped", 1, playlists)
|
||||
|
||||
activity.contentResolver.openOutputStream(uri)?.use {
|
||||
JsonHelper.json.encodeToStream(playlistFile, it)
|
||||
}
|
||||
|
||||
activity.toastFromMainThread(R.string.exportsuccess)
|
||||
activity.contentResolver.openOutputStream(uri)?.use {
|
||||
JsonHelper.json.encodeToStream(playlistFile, it)
|
||||
}
|
||||
|
||||
activity.toastFromMainDispatcher(R.string.exportsuccess)
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package com.github.libretube.helpers
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
|
||||
object IntentHelper {
|
||||
fun openLinkFromHref(context: Context, link: String) {
|
||||
val uri = Uri.parse(link)
|
||||
val launchIntent = Intent(Intent.ACTION_VIEW).setData(uri)
|
||||
context.startActivity(launchIntent)
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.github.libretube.util
|
||||
package com.github.libretube.helpers
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
@ -1,4 +1,4 @@
|
||||
package com.github.libretube.util
|
||||
package com.github.libretube.helpers
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
@ -1,4 +1,4 @@
|
||||
package com.github.libretube.util
|
||||
package com.github.libretube.helpers
|
||||
|
||||
import android.app.NotificationManager
|
||||
import android.content.Context
|
||||
@ -10,6 +10,8 @@ import android.os.Looper
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.core.os.postDelayed
|
||||
import androidx.fragment.app.commitNow
|
||||
import androidx.fragment.app.replace
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.constants.IntentData
|
||||
import com.github.libretube.constants.PreferenceKeys
|
||||
@ -90,17 +92,9 @@ object NavigationHelper {
|
||||
)
|
||||
|
||||
val activity = context as AppCompatActivity
|
||||
activity.supportFragmentManager.beginTransaction()
|
||||
.remove(PlayerFragment())
|
||||
.commit()
|
||||
activity.supportFragmentManager.beginTransaction()
|
||||
.replace(
|
||||
R.id.container,
|
||||
PlayerFragment().apply {
|
||||
arguments = bundle
|
||||
}
|
||||
)
|
||||
.commitNow()
|
||||
activity.supportFragmentManager.commitNow {
|
||||
replace<PlayerFragment>(R.id.container, args = bundle)
|
||||
}
|
||||
}
|
||||
|
||||
fun navigatePlaylist(
|
@ -1,4 +1,4 @@
|
||||
package com.github.libretube.util
|
||||
package com.github.libretube.helpers
|
||||
|
||||
import android.content.Context
|
||||
import android.net.ConnectivityManager
|
@ -1,10 +1,10 @@
|
||||
package com.github.libretube.util
|
||||
package com.github.libretube.helpers
|
||||
|
||||
import android.content.Context
|
||||
import androidx.work.Constraints
|
||||
import androidx.work.ExistingPeriodicWorkPolicy
|
||||
import androidx.work.NetworkType
|
||||
import androidx.work.PeriodicWorkRequest
|
||||
import androidx.work.PeriodicWorkRequestBuilder
|
||||
import androidx.work.WorkManager
|
||||
import com.github.libretube.constants.NOTIFICATION_WORK_NAME
|
||||
import com.github.libretube.constants.PreferenceKeys
|
||||
@ -56,8 +56,7 @@ object NotificationHelper {
|
||||
.build()
|
||||
|
||||
// create the worker
|
||||
val notificationWorker = PeriodicWorkRequest.Builder(
|
||||
NotificationWorker::class.java,
|
||||
val notificationWorker = PeriodicWorkRequestBuilder<NotificationWorker>(
|
||||
checkingFrequency,
|
||||
TimeUnit.MINUTES
|
||||
)
|
@ -1,4 +1,4 @@
|
||||
package com.github.libretube.util
|
||||
package com.github.libretube.helpers
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.PendingIntent
|
@ -1,4 +1,4 @@
|
||||
package com.github.libretube.util
|
||||
package com.github.libretube.helpers
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
@ -1,4 +1,4 @@
|
||||
package com.github.libretube.util
|
||||
package com.github.libretube.helpers
|
||||
|
||||
import com.github.libretube.api.RetrofitInstance
|
||||
import com.github.libretube.constants.PreferenceKeys
|
@ -1,4 +1,4 @@
|
||||
package com.github.libretube.util
|
||||
package com.github.libretube.helpers
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
@ -1,4 +1,4 @@
|
||||
package com.github.libretube.util
|
||||
package com.github.libretube.helpers
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.ComponentName
|
@ -1,4 +1,4 @@
|
||||
package com.github.libretube.util
|
||||
package com.github.libretube.helpers
|
||||
|
||||
import android.os.Build
|
||||
import android.view.WindowManager
|
@ -29,9 +29,9 @@ import com.github.libretube.extensions.awaitQuery
|
||||
import com.github.libretube.extensions.query
|
||||
import com.github.libretube.extensions.toID
|
||||
import com.github.libretube.extensions.toStreamItem
|
||||
import com.github.libretube.helpers.PlayerHelper
|
||||
import com.github.libretube.helpers.PlayerHelper.loadPlaybackParams
|
||||
import com.github.libretube.util.NowPlayingNotification
|
||||
import com.github.libretube.util.PlayerHelper
|
||||
import com.github.libretube.util.PlayerHelper.loadPlaybackParams
|
||||
import com.github.libretube.util.PlayingQueue
|
||||
import com.google.android.exoplayer2.ExoPlayer
|
||||
import com.google.android.exoplayer2.MediaItem
|
||||
|
@ -25,14 +25,14 @@ import com.github.libretube.extensions.getContentLength
|
||||
import com.github.libretube.extensions.query
|
||||
import com.github.libretube.extensions.toDownloadItems
|
||||
import com.github.libretube.extensions.toastFromMainThread
|
||||
import com.github.libretube.helpers.DownloadHelper
|
||||
import com.github.libretube.helpers.DownloadHelper.getNotificationId
|
||||
import com.github.libretube.helpers.ImageHelper
|
||||
import com.github.libretube.obj.DownloadStatus
|
||||
import com.github.libretube.receivers.NotificationReceiver
|
||||
import com.github.libretube.receivers.NotificationReceiver.Companion.ACTION_DOWNLOAD_PAUSE
|
||||
import com.github.libretube.receivers.NotificationReceiver.Companion.ACTION_DOWNLOAD_RESUME
|
||||
import com.github.libretube.ui.activities.MainActivity
|
||||
import com.github.libretube.util.DownloadHelper
|
||||
import com.github.libretube.util.DownloadHelper.getNotificationId
|
||||
import com.github.libretube.util.ImageHelper
|
||||
import java.io.File
|
||||
import java.net.HttpURLConnection
|
||||
import java.net.SocketTimeoutException
|
||||
|
@ -11,7 +11,7 @@ import android.os.Environment
|
||||
import android.os.IBinder
|
||||
import android.widget.Toast
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.util.DownloadHelper
|
||||
import com.github.libretube.helpers.DownloadHelper
|
||||
import java.io.File
|
||||
|
||||
class UpdateService : Service() {
|
||||
|
@ -1,10 +1,6 @@
|
||||
package com.github.libretube.ui.activities
|
||||
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import androidx.core.text.HtmlCompat
|
||||
@ -16,7 +12,10 @@ import com.github.libretube.constants.PIPED_GITHUB_URL
|
||||
import com.github.libretube.constants.WEBLATE_URL
|
||||
import com.github.libretube.constants.WEBSITE_URL
|
||||
import com.github.libretube.databinding.ActivityAboutBinding
|
||||
import com.github.libretube.helpers.ClipboardHelper
|
||||
import com.github.libretube.helpers.IntentHelper
|
||||
import com.github.libretube.ui.base.BaseActivity
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
|
||||
@ -34,7 +33,7 @@ class AboutActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
binding.appIcon.setOnClickListener {
|
||||
val sendIntent: Intent = Intent().apply {
|
||||
val sendIntent = Intent().apply {
|
||||
action = Intent.ACTION_SEND
|
||||
putExtra(Intent.EXTRA_TEXT, GITHUB_URL)
|
||||
type = "text/plain"
|
||||
@ -44,37 +43,10 @@ class AboutActivity : BaseActivity() {
|
||||
startActivity(shareIntent)
|
||||
}
|
||||
|
||||
binding.website.setOnClickListener {
|
||||
openLinkFromHref(WEBSITE_URL)
|
||||
}
|
||||
binding.website.setOnLongClickListener {
|
||||
onLongClick(WEBSITE_URL)
|
||||
true
|
||||
}
|
||||
|
||||
binding.piped.setOnClickListener {
|
||||
openLinkFromHref(PIPED_GITHUB_URL)
|
||||
}
|
||||
binding.piped.setOnLongClickListener {
|
||||
onLongClick(PIPED_GITHUB_URL)
|
||||
true
|
||||
}
|
||||
|
||||
binding.translate.setOnClickListener {
|
||||
openLinkFromHref(WEBLATE_URL)
|
||||
}
|
||||
binding.translate.setOnLongClickListener {
|
||||
onLongClick(WEBLATE_URL)
|
||||
true
|
||||
}
|
||||
|
||||
binding.github.setOnClickListener {
|
||||
openLinkFromHref(GITHUB_URL)
|
||||
}
|
||||
binding.github.setOnLongClickListener {
|
||||
onLongClick(GITHUB_URL)
|
||||
true
|
||||
}
|
||||
setupCard(binding.website, WEBSITE_URL)
|
||||
setupCard(binding.piped, PIPED_GITHUB_URL)
|
||||
setupCard(binding.translate, WEBLATE_URL)
|
||||
setupCard(binding.github, GITHUB_URL)
|
||||
|
||||
binding.license.setOnClickListener {
|
||||
showLicense()
|
||||
@ -89,18 +61,19 @@ class AboutActivity : BaseActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun openLinkFromHref(link: String) {
|
||||
val uri = Uri.parse(link)
|
||||
val intent = Intent(Intent.ACTION_VIEW).setData(uri)
|
||||
startActivity(intent)
|
||||
private fun setupCard(card: MaterialCardView, link: String) {
|
||||
card.setOnClickListener {
|
||||
IntentHelper.openLinkFromHref(this, link)
|
||||
}
|
||||
card.setOnLongClickListener {
|
||||
onLongClick(link)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
private fun onLongClick(href: String) {
|
||||
// copy the link to the clipboard
|
||||
val clipboard: ClipboardManager =
|
||||
getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clip = ClipData.newPlainText(getString(R.string.copied), href)
|
||||
clipboard.setPrimaryClip(clip)
|
||||
ClipboardHelper.save(this, href)
|
||||
// show the snackBar with open action
|
||||
Snackbar.make(
|
||||
binding.root,
|
||||
@ -108,7 +81,7 @@ class AboutActivity : BaseActivity() {
|
||||
Snackbar.LENGTH_LONG
|
||||
)
|
||||
.setAction(R.string.open_copied) {
|
||||
openLinkFromHref(href)
|
||||
IntentHelper.openLinkFromHref(this, href)
|
||||
}
|
||||
.setAnimationMode(Snackbar.ANIMATION_MODE_FADE)
|
||||
.show()
|
||||
|
@ -1,16 +1,16 @@
|
||||
package com.github.libretube.ui.activities
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import com.github.libretube.constants.DISCORD_URL
|
||||
import com.github.libretube.constants.FAQ_URL
|
||||
import com.github.libretube.constants.MASTODON_URL
|
||||
import com.github.libretube.constants.MATRIX_URL
|
||||
import com.github.libretube.constants.REDDIT_URL
|
||||
import com.github.libretube.constants.TELEGRAM_URL
|
||||
import com.github.libretube.constants.TWITTER_URL
|
||||
import com.github.libretube.databinding.ActivityHelpBinding
|
||||
import com.github.libretube.helpers.IntentHelper
|
||||
import com.github.libretube.ui.base.BaseActivity
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
|
||||
class HelpActivity : BaseActivity() {
|
||||
private lateinit var binding: ActivityHelpBinding
|
||||
@ -25,34 +25,17 @@ class HelpActivity : BaseActivity() {
|
||||
onBackPressedDispatcher.onBackPressed()
|
||||
}
|
||||
|
||||
binding.faq.setOnClickListener {
|
||||
openLinkFromHref(FAQ_URL)
|
||||
}
|
||||
|
||||
binding.matrix.setOnClickListener {
|
||||
openLinkFromHref(MATRIX_URL)
|
||||
}
|
||||
|
||||
binding.telegram.setOnClickListener {
|
||||
openLinkFromHref(TELEGRAM_URL)
|
||||
}
|
||||
|
||||
binding.discord.setOnClickListener {
|
||||
openLinkFromHref(DISCORD_URL)
|
||||
}
|
||||
|
||||
binding.reddit.setOnClickListener {
|
||||
openLinkFromHref(REDDIT_URL)
|
||||
}
|
||||
|
||||
binding.twitter.setOnClickListener {
|
||||
openLinkFromHref(TWITTER_URL)
|
||||
}
|
||||
setupCard(binding.faq, FAQ_URL)
|
||||
setupCard(binding.matrix, MATRIX_URL)
|
||||
setupCard(binding.mastodon, MASTODON_URL)
|
||||
setupCard(binding.telegram, TELEGRAM_URL)
|
||||
setupCard(binding.discord, DISCORD_URL)
|
||||
setupCard(binding.reddit, REDDIT_URL)
|
||||
}
|
||||
|
||||
private fun openLinkFromHref(link: String) {
|
||||
val uri = Uri.parse(link)
|
||||
val intent = Intent(Intent.ACTION_VIEW).setData(uri)
|
||||
startActivity(intent)
|
||||
private fun setupCard(card: MaterialCardView, link: String) {
|
||||
card.setOnClickListener {
|
||||
IntentHelper.openLinkFromHref(this, link)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,12 @@ import com.github.libretube.constants.IntentData
|
||||
import com.github.libretube.constants.PreferenceKeys
|
||||
import com.github.libretube.databinding.ActivityMainBinding
|
||||
import com.github.libretube.extensions.toID
|
||||
import com.github.libretube.helpers.NavBarHelper
|
||||
import com.github.libretube.helpers.NavigationHelper
|
||||
import com.github.libretube.helpers.NetworkHelper
|
||||
import com.github.libretube.helpers.PreferenceHelper
|
||||
import com.github.libretube.helpers.ThemeHelper
|
||||
import com.github.libretube.helpers.WindowHelper
|
||||
import com.github.libretube.services.ClosingService
|
||||
import com.github.libretube.ui.base.BaseActivity
|
||||
import com.github.libretube.ui.dialogs.ErrorDialog
|
||||
@ -36,12 +42,6 @@ import com.github.libretube.ui.models.PlayerViewModel
|
||||
import com.github.libretube.ui.models.SearchViewModel
|
||||
import com.github.libretube.ui.models.SubscriptionsViewModel
|
||||
import com.github.libretube.ui.tools.SleepTimer
|
||||
import com.github.libretube.util.NavBarHelper
|
||||
import com.github.libretube.util.NavigationHelper
|
||||
import com.github.libretube.util.NetworkHelper
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
import com.github.libretube.util.ThemeHelper
|
||||
import com.github.libretube.util.WindowHelper
|
||||
import com.google.android.material.elevation.SurfaceColors
|
||||
|
||||
class MainActivity : BaseActivity() {
|
||||
|
@ -4,12 +4,13 @@ import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.activity.addCallback
|
||||
import androidx.fragment.app.commit
|
||||
import androidx.fragment.app.replace
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.databinding.ActivityNointernetBinding
|
||||
import com.github.libretube.helpers.NavigationHelper
|
||||
import com.github.libretube.helpers.NetworkHelper
|
||||
import com.github.libretube.ui.base.BaseActivity
|
||||
import com.github.libretube.ui.fragments.DownloadsFragment
|
||||
import com.github.libretube.util.NavigationHelper
|
||||
import com.github.libretube.util.NetworkHelper
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
|
||||
class NoInternetActivity : BaseActivity() {
|
||||
@ -33,10 +34,10 @@ class NoInternetActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
binding.downloads.setOnClickListener {
|
||||
supportFragmentManager.beginTransaction()
|
||||
.replace(R.id.noInternet_container, DownloadsFragment())
|
||||
.addToBackStack(null)
|
||||
.commit()
|
||||
supportFragmentManager.commit {
|
||||
replace<DownloadsFragment>(R.id.noInternet_container)
|
||||
addToBackStack(null)
|
||||
}
|
||||
}
|
||||
|
||||
setContentView(binding.root)
|
||||
|
@ -16,12 +16,12 @@ import com.github.libretube.db.DatabaseHolder.Companion.Database
|
||||
import com.github.libretube.enums.FileType
|
||||
import com.github.libretube.extensions.awaitQuery
|
||||
import com.github.libretube.extensions.updateParameters
|
||||
import com.github.libretube.helpers.PlayerHelper
|
||||
import com.github.libretube.helpers.PlayerHelper.loadPlaybackParams
|
||||
import com.github.libretube.helpers.WindowHelper
|
||||
import com.github.libretube.ui.base.BaseActivity
|
||||
import com.github.libretube.ui.extensions.setAspectRatio
|
||||
import com.github.libretube.ui.models.PlayerViewModel
|
||||
import com.github.libretube.util.PlayerHelper
|
||||
import com.github.libretube.util.PlayerHelper.loadPlaybackParams
|
||||
import com.github.libretube.util.WindowHelper
|
||||
import com.google.android.exoplayer2.C
|
||||
import com.google.android.exoplayer2.ExoPlayer
|
||||
import com.google.android.exoplayer2.MediaItem
|
||||
|
@ -7,8 +7,8 @@ import android.os.Bundle
|
||||
import android.util.Log
|
||||
import com.github.libretube.constants.IntentData
|
||||
import com.github.libretube.extensions.TAG
|
||||
import com.github.libretube.helpers.NavigationHelper
|
||||
import com.github.libretube.ui.base.BaseActivity
|
||||
import com.github.libretube.util.NavigationHelper
|
||||
import com.github.libretube.util.TextUtils
|
||||
|
||||
class RouterActivity : BaseActivity() {
|
||||
|
@ -24,10 +24,9 @@ class SettingsActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
supportFragmentManager
|
||||
.beginTransaction()
|
||||
.replace(R.id.settings, MainSettings())
|
||||
.commit()
|
||||
supportFragmentManager.commit {
|
||||
replace<MainSettings>(R.id.settings)
|
||||
}
|
||||
}
|
||||
|
||||
// new way of dealing with back presses instead of onBackPressed()
|
||||
|
@ -1,11 +1,11 @@
|
||||
package com.github.libretube.ui.adapters
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.github.libretube.databinding.BottomSheetItemBinding
|
||||
import com.github.libretube.obj.BottomSheetItem
|
||||
import com.github.libretube.ui.extensions.setDrawables
|
||||
import com.github.libretube.ui.viewholders.BottomSheetViewHolder
|
||||
|
||||
class BottomSheetAdapter(
|
||||
@ -23,17 +23,12 @@ class BottomSheetAdapter(
|
||||
|
||||
override fun onBindViewHolder(holder: BottomSheetViewHolder, position: Int) {
|
||||
val item = items[position]
|
||||
holder.binding.apply {
|
||||
holder.binding.root.apply {
|
||||
val current = item.getCurrent()
|
||||
title.text =
|
||||
if (current != null) "${item.title} ($current)" else item.title
|
||||
if (item.drawable != null) {
|
||||
drawable.setImageResource(item.drawable)
|
||||
} else {
|
||||
drawable.visibility = View.GONE
|
||||
}
|
||||
text = if (current != null) "${item.title} ($current)" else item.title
|
||||
setDrawables(start = item.drawable)
|
||||
|
||||
root.setOnClickListener {
|
||||
setOnClickListener {
|
||||
item.onClick.invoke()
|
||||
listener.invoke(position)
|
||||
}
|
||||
|
@ -7,9 +7,9 @@ import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.github.libretube.api.obj.ChapterSegment
|
||||
import com.github.libretube.databinding.ChapterColumnBinding
|
||||
import com.github.libretube.helpers.ImageHelper
|
||||
import com.github.libretube.helpers.ThemeHelper
|
||||
import com.github.libretube.ui.viewholders.ChaptersViewHolder
|
||||
import com.github.libretube.util.ImageHelper
|
||||
import com.github.libretube.util.ThemeHelper
|
||||
import com.google.android.exoplayer2.ExoPlayer
|
||||
|
||||
class ChaptersAdapter(
|
||||
|
@ -1,17 +1,19 @@
|
||||
package com.github.libretube.ui.adapters
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewGroup.MarginLayoutParams
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.core.text.parseAsHtml
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.commit
|
||||
import androidx.fragment.app.replace
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.api.JsonHelper
|
||||
@ -19,13 +21,14 @@ import com.github.libretube.api.obj.Comment
|
||||
import com.github.libretube.constants.IntentData
|
||||
import com.github.libretube.databinding.CommentsRowBinding
|
||||
import com.github.libretube.extensions.formatShort
|
||||
import com.github.libretube.helpers.ClipboardHelper
|
||||
import com.github.libretube.helpers.ImageHelper
|
||||
import com.github.libretube.helpers.NavigationHelper
|
||||
import com.github.libretube.helpers.ThemeHelper
|
||||
import com.github.libretube.ui.fragments.CommentsRepliesFragment
|
||||
import com.github.libretube.ui.viewholders.CommentsViewHolder
|
||||
import com.github.libretube.util.ClipboardHelper
|
||||
import com.github.libretube.util.ImageHelper
|
||||
import com.github.libretube.util.NavigationHelper
|
||||
import com.github.libretube.util.TextUtils
|
||||
import com.github.libretube.util.ThemeHelper
|
||||
import kotlinx.serialization.encodeToString
|
||||
|
||||
class CommentsAdapter(
|
||||
private val fragment: Fragment?,
|
||||
@ -65,7 +68,7 @@ class CommentsAdapter(
|
||||
if (comment.verified) verifiedImageView.visibility = View.VISIBLE
|
||||
if (comment.pinned) pinnedImageView.visibility = View.VISIBLE
|
||||
if (comment.hearted) heartedImageView.visibility = View.VISIBLE
|
||||
if (comment.repliesPage != null) repliesAvailable.visibility = View.VISIBLE
|
||||
if (comment.repliesPage != null) repliesCount.visibility = View.VISIBLE
|
||||
if (comment.replyCount > 0L) {
|
||||
repliesCount.text = comment.replyCount.formatShort()
|
||||
}
|
||||
@ -77,7 +80,6 @@ class CommentsAdapter(
|
||||
|
||||
if (isRepliesAdapter) {
|
||||
repliesCount.visibility = View.GONE
|
||||
repliesAvailable.visibility = View.GONE
|
||||
|
||||
// highlight the comment that is being replied to
|
||||
if (comment == comments.firstOrNull()) {
|
||||
@ -87,31 +89,28 @@ class CommentsAdapter(
|
||||
root.updatePadding(top = 20)
|
||||
root.updateLayoutParams<MarginLayoutParams> { bottomMargin = 20 }
|
||||
} else {
|
||||
root.background = AppCompatResources.getDrawable(root.context, R.drawable.rounded_ripple)
|
||||
root.background = AppCompatResources.getDrawable(
|
||||
root.context,
|
||||
R.drawable.rounded_ripple
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (!isRepliesAdapter && comment.repliesPage != null) {
|
||||
val repliesFragment = CommentsRepliesFragment().apply {
|
||||
arguments = Bundle().apply {
|
||||
putString(IntentData.videoId, videoId)
|
||||
putString(
|
||||
IntentData.comment,
|
||||
JsonHelper.json.encodeToString(Comment.serializer(), comment)
|
||||
)
|
||||
}
|
||||
}
|
||||
root.setOnClickListener {
|
||||
fragment!!.parentFragmentManager
|
||||
.beginTransaction()
|
||||
.replace(R.id.commentFragContainer, repliesFragment)
|
||||
.addToBackStack(null)
|
||||
.commit()
|
||||
val args = bundleOf(
|
||||
IntentData.videoId to videoId,
|
||||
IntentData.comment to JsonHelper.json.encodeToString(comment)
|
||||
)
|
||||
fragment!!.parentFragmentManager.commit {
|
||||
replace<CommentsRepliesFragment>(R.id.commentFragContainer, args = args)
|
||||
addToBackStack(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
root.setOnLongClickListener {
|
||||
ClipboardHelper(root.context).save(comment.commentText ?: "")
|
||||
ClipboardHelper.save(root.context, comment.commentText ?: "")
|
||||
Toast.makeText(root.context, R.string.copied, Toast.LENGTH_SHORT).show()
|
||||
true
|
||||
}
|
||||
|
@ -14,9 +14,9 @@ import com.github.libretube.db.DatabaseHolder
|
||||
import com.github.libretube.db.obj.DownloadWithItems
|
||||
import com.github.libretube.extensions.formatAsFileSize
|
||||
import com.github.libretube.extensions.query
|
||||
import com.github.libretube.helpers.ImageHelper
|
||||
import com.github.libretube.ui.activities.OfflinePlayerActivity
|
||||
import com.github.libretube.ui.viewholders.DownloadsViewHolder
|
||||
import com.github.libretube.util.ImageHelper
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import java.io.File
|
||||
|
||||
|
@ -8,9 +8,9 @@ import androidx.recyclerview.widget.RecyclerView
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.constants.PreferenceKeys
|
||||
import com.github.libretube.databinding.AppIconItemBinding
|
||||
import com.github.libretube.helpers.PreferenceHelper
|
||||
import com.github.libretube.helpers.ThemeHelper
|
||||
import com.github.libretube.ui.viewholders.IconsSheetViewHolder
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
import com.github.libretube.util.ThemeHelper
|
||||
|
||||
class IconsSheetAdapter : RecyclerView.Adapter<IconsSheetViewHolder>() {
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): IconsSheetViewHolder {
|
||||
|
@ -5,11 +5,11 @@ import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.github.libretube.databinding.LegacySubscriptionChannelBinding
|
||||
import com.github.libretube.extensions.toID
|
||||
import com.github.libretube.helpers.ImageHelper
|
||||
import com.github.libretube.helpers.NavigationHelper
|
||||
import com.github.libretube.ui.base.BaseActivity
|
||||
import com.github.libretube.ui.sheets.ChannelOptionsBottomSheet
|
||||
import com.github.libretube.ui.viewholders.LegacySubscriptionViewHolder
|
||||
import com.github.libretube.util.ImageHelper
|
||||
import com.github.libretube.util.NavigationHelper
|
||||
|
||||
class LegacySubscriptionAdapter(
|
||||
private val subscriptions: List<com.github.libretube.api.obj.Subscription>
|
||||
|
@ -8,10 +8,10 @@ import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.github.libretube.databinding.QueueRowBinding
|
||||
import com.github.libretube.extensions.toID
|
||||
import com.github.libretube.helpers.ImageHelper
|
||||
import com.github.libretube.helpers.ThemeHelper
|
||||
import com.github.libretube.ui.viewholders.PlayingQueueViewHolder
|
||||
import com.github.libretube.util.ImageHelper
|
||||
import com.github.libretube.util.PlayingQueue
|
||||
import com.github.libretube.util.ThemeHelper
|
||||
|
||||
class PlayingQueueAdapter : RecyclerView.Adapter<PlayingQueueViewHolder>() {
|
||||
|
||||
|
@ -13,13 +13,13 @@ import com.github.libretube.databinding.VideoRowBinding
|
||||
import com.github.libretube.enums.PlaylistType
|
||||
import com.github.libretube.extensions.TAG
|
||||
import com.github.libretube.extensions.toID
|
||||
import com.github.libretube.helpers.ImageHelper
|
||||
import com.github.libretube.helpers.NavigationHelper
|
||||
import com.github.libretube.ui.base.BaseActivity
|
||||
import com.github.libretube.ui.extensions.setFormattedDuration
|
||||
import com.github.libretube.ui.extensions.setWatchProgressLength
|
||||
import com.github.libretube.ui.sheets.VideoOptionsBottomSheet
|
||||
import com.github.libretube.ui.viewholders.PlaylistViewHolder
|
||||
import com.github.libretube.util.ImageHelper
|
||||
import com.github.libretube.util.NavigationHelper
|
||||
import java.io.IOException
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@ -84,9 +84,7 @@ class PlaylistAdapter(
|
||||
|
||||
if (!streamItem.uploaderUrl.isNullOrBlank()) {
|
||||
channelContainer.setOnClickListener {
|
||||
streamItem.uploaderUrl?.toID()?.let {
|
||||
NavigationHelper.navigateChannel(root.context, it)
|
||||
}
|
||||
NavigationHelper.navigateChannel(root.context, streamItem.uploaderUrl.toID())
|
||||
}
|
||||
}
|
||||
|
||||
@ -96,7 +94,7 @@ class PlaylistAdapter(
|
||||
removeFromPlaylist(root.context, position)
|
||||
}
|
||||
}
|
||||
watchProgress.setWatchProgressLength(videoId, streamItem.duration!!)
|
||||
watchProgress.setWatchProgressLength(videoId, streamItem.duration)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,10 +12,10 @@ import com.github.libretube.db.DatabaseHolder
|
||||
import com.github.libretube.db.obj.PlaylistBookmark
|
||||
import com.github.libretube.enums.PlaylistType
|
||||
import com.github.libretube.extensions.query
|
||||
import com.github.libretube.helpers.ImageHelper
|
||||
import com.github.libretube.helpers.NavigationHelper
|
||||
import com.github.libretube.ui.sheets.PlaylistOptionsBottomSheet
|
||||
import com.github.libretube.ui.viewholders.PlaylistBookmarkViewHolder
|
||||
import com.github.libretube.util.ImageHelper
|
||||
import com.github.libretube.util.NavigationHelper
|
||||
|
||||
class PlaylistBookmarkAdapter(
|
||||
private val bookmarks: List<PlaylistBookmark>,
|
||||
|
@ -7,12 +7,12 @@ import com.github.libretube.R
|
||||
import com.github.libretube.api.obj.Playlists
|
||||
import com.github.libretube.databinding.PlaylistsRowBinding
|
||||
import com.github.libretube.enums.PlaylistType
|
||||
import com.github.libretube.helpers.ImageHelper
|
||||
import com.github.libretube.helpers.NavigationHelper
|
||||
import com.github.libretube.ui.base.BaseActivity
|
||||
import com.github.libretube.ui.dialogs.DeletePlaylistDialog
|
||||
import com.github.libretube.ui.sheets.PlaylistOptionsBottomSheet
|
||||
import com.github.libretube.ui.viewholders.PlaylistsViewHolder
|
||||
import com.github.libretube.util.ImageHelper
|
||||
import com.github.libretube.util.NavigationHelper
|
||||
|
||||
class PlaylistsAdapter(
|
||||
private val playlists: MutableList<Playlists>,
|
||||
|
@ -4,7 +4,8 @@ import android.annotation.SuppressLint
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.api.obj.ContentItem
|
||||
import com.github.libretube.databinding.ChannelRowBinding
|
||||
@ -13,6 +14,8 @@ import com.github.libretube.databinding.VideoRowBinding
|
||||
import com.github.libretube.enums.PlaylistType
|
||||
import com.github.libretube.extensions.formatShort
|
||||
import com.github.libretube.extensions.toID
|
||||
import com.github.libretube.helpers.ImageHelper
|
||||
import com.github.libretube.helpers.NavigationHelper
|
||||
import com.github.libretube.ui.base.BaseActivity
|
||||
import com.github.libretube.ui.extensions.setFormattedDuration
|
||||
import com.github.libretube.ui.extensions.setWatchProgressLength
|
||||
@ -21,25 +24,9 @@ import com.github.libretube.ui.sheets.ChannelOptionsBottomSheet
|
||||
import com.github.libretube.ui.sheets.PlaylistOptionsBottomSheet
|
||||
import com.github.libretube.ui.sheets.VideoOptionsBottomSheet
|
||||
import com.github.libretube.ui.viewholders.SearchViewHolder
|
||||
import com.github.libretube.util.ImageHelper
|
||||
import com.github.libretube.util.NavigationHelper
|
||||
import com.github.libretube.util.TextUtils
|
||||
|
||||
class SearchAdapter(
|
||||
private val searchItems: MutableList<ContentItem>
|
||||
) :
|
||||
RecyclerView.Adapter<SearchViewHolder>() {
|
||||
|
||||
fun updateItems(newItems: List<ContentItem>) {
|
||||
val searchItemsSize = searchItems.size
|
||||
searchItems.addAll(newItems)
|
||||
notifyItemRangeInserted(searchItemsSize, newItems.size)
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return searchItems.size
|
||||
}
|
||||
|
||||
class SearchAdapter : ListAdapter<ContentItem, SearchViewHolder>(SearchCallback) {
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SearchViewHolder {
|
||||
val layoutInflater = LayoutInflater.from(parent.context)
|
||||
|
||||
@ -58,7 +45,7 @@ class SearchAdapter(
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: SearchViewHolder, position: Int) {
|
||||
val searchItem = searchItems[position]
|
||||
val searchItem = currentList[position]
|
||||
|
||||
val videoRowBinding = holder.videoRowBinding
|
||||
val channelRowBinding = holder.channelRowBinding
|
||||
@ -68,11 +55,13 @@ class SearchAdapter(
|
||||
bindWatch(searchItem, videoRowBinding)
|
||||
} else if (channelRowBinding != null) {
|
||||
bindChannel(searchItem, channelRowBinding)
|
||||
} else if (playlistRowBinding != null) bindPlaylist(searchItem, playlistRowBinding)
|
||||
} else if (playlistRowBinding != null) {
|
||||
bindPlaylist(searchItem, playlistRowBinding)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
return when (searchItems[position].type) {
|
||||
return when (currentList[position].type) {
|
||||
"stream" -> 0
|
||||
"channel" -> 1
|
||||
"playlist" -> 2
|
||||
@ -116,10 +105,7 @@ class SearchAdapter(
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
private fun bindChannel(
|
||||
item: ContentItem,
|
||||
binding: ChannelRowBinding
|
||||
) {
|
||||
private fun bindChannel(item: ContentItem, binding: ChannelRowBinding) {
|
||||
binding.apply {
|
||||
ImageHelper.loadImage(item.thumbnail, searchChannelImage)
|
||||
searchChannelName.text = item.name
|
||||
@ -144,10 +130,7 @@ class SearchAdapter(
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindPlaylist(
|
||||
item: ContentItem,
|
||||
binding: PlaylistsRowBinding
|
||||
) {
|
||||
private fun bindPlaylist(item: ContentItem, binding: PlaylistsRowBinding) {
|
||||
binding.apply {
|
||||
ImageHelper.loadImage(item.thumbnail, playlistThumbnail)
|
||||
if (item.videos != -1L) videoCount.text = item.videos.toString()
|
||||
@ -169,4 +152,14 @@ class SearchAdapter(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private object SearchCallback : DiffUtil.ItemCallback<ContentItem>() {
|
||||
override fun areItemsTheSame(oldItem: ContentItem, newItem: ContentItem): Boolean {
|
||||
return oldItem.url == newItem.url
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: ContentItem, newItem: ContentItem): Boolean {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,12 +6,12 @@ import androidx.recyclerview.widget.RecyclerView
|
||||
import com.github.libretube.api.obj.Subscription
|
||||
import com.github.libretube.databinding.ChannelSubscriptionRowBinding
|
||||
import com.github.libretube.extensions.toID
|
||||
import com.github.libretube.helpers.ImageHelper
|
||||
import com.github.libretube.helpers.NavigationHelper
|
||||
import com.github.libretube.ui.base.BaseActivity
|
||||
import com.github.libretube.ui.extensions.setupSubscriptionButton
|
||||
import com.github.libretube.ui.sheets.ChannelOptionsBottomSheet
|
||||
import com.github.libretube.ui.viewholders.SubscriptionChannelViewHolder
|
||||
import com.github.libretube.util.ImageHelper
|
||||
import com.github.libretube.util.NavigationHelper
|
||||
|
||||
class SubscriptionChannelAdapter(
|
||||
private val subscriptions: MutableList<Subscription>
|
||||
|
@ -20,14 +20,14 @@ import com.github.libretube.databinding.VideoRowBinding
|
||||
import com.github.libretube.extensions.dpToPx
|
||||
import com.github.libretube.extensions.formatShort
|
||||
import com.github.libretube.extensions.toID
|
||||
import com.github.libretube.helpers.ImageHelper
|
||||
import com.github.libretube.helpers.NavigationHelper
|
||||
import com.github.libretube.helpers.PreferenceHelper
|
||||
import com.github.libretube.ui.base.BaseActivity
|
||||
import com.github.libretube.ui.extensions.setFormattedDuration
|
||||
import com.github.libretube.ui.extensions.setWatchProgressLength
|
||||
import com.github.libretube.ui.sheets.VideoOptionsBottomSheet
|
||||
import com.github.libretube.ui.viewholders.VideosViewHolder
|
||||
import com.github.libretube.util.ImageHelper
|
||||
import com.github.libretube.util.NavigationHelper
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
import com.github.libretube.util.TextUtils
|
||||
|
||||
class VideosAdapter(
|
||||
|
@ -8,13 +8,13 @@ import com.github.libretube.databinding.VideoRowBinding
|
||||
import com.github.libretube.db.DatabaseHolder
|
||||
import com.github.libretube.db.obj.WatchHistoryItem
|
||||
import com.github.libretube.extensions.query
|
||||
import com.github.libretube.helpers.ImageHelper
|
||||
import com.github.libretube.helpers.NavigationHelper
|
||||
import com.github.libretube.ui.base.BaseActivity
|
||||
import com.github.libretube.ui.extensions.setFormattedDuration
|
||||
import com.github.libretube.ui.extensions.setWatchProgressLength
|
||||
import com.github.libretube.ui.sheets.VideoOptionsBottomSheet
|
||||
import com.github.libretube.ui.viewholders.WatchHistoryViewHolder
|
||||
import com.github.libretube.util.ImageHelper
|
||||
import com.github.libretube.util.NavigationHelper
|
||||
|
||||
class WatchHistoryAdapter(
|
||||
private val watchHistory: MutableList<WatchHistoryItem>
|
||||
|
@ -2,8 +2,8 @@ package com.github.libretube.ui.base
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.github.libretube.util.LocaleHelper
|
||||
import com.github.libretube.util.ThemeHelper
|
||||
import com.github.libretube.helpers.LocaleHelper
|
||||
import com.github.libretube.helpers.ThemeHelper
|
||||
|
||||
/**
|
||||
* Activity that applies the LibreTube theme and the in-app language
|
||||
|
@ -7,8 +7,8 @@ import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.databinding.DialogTextPreferenceBinding
|
||||
import com.github.libretube.helpers.PreferenceHelper
|
||||
import com.github.libretube.ui.activities.SettingsActivity
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
|
||||
/**
|
||||
|
@ -7,9 +7,9 @@ import androidx.fragment.app.DialogFragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.db.DatabaseHolder.Companion.Database
|
||||
import com.github.libretube.helpers.PreferenceHelper
|
||||
import com.github.libretube.obj.BackupFile
|
||||
import com.github.libretube.obj.PreferenceItem
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
@ -7,6 +7,7 @@ import androidx.fragment.app.DialogFragment
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.api.PlaylistsHelper
|
||||
import com.github.libretube.databinding.DialogCreatePlaylistBinding
|
||||
import com.github.libretube.extensions.toastFromMainThread
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@ -24,8 +25,19 @@ class CreatePlaylistDialog(
|
||||
|
||||
binding.clonePlaylist.setOnClickListener {
|
||||
val playlistUrl = binding.playlistUrl.text.toString().toHttpUrlOrNull()
|
||||
val appContext = context?.applicationContext
|
||||
|
||||
playlistUrl?.queryParameter("list")?.let {
|
||||
PlaylistsHelper.clonePlaylist(requireContext(), it)
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val playlistId = PlaylistsHelper.clonePlaylist(requireContext(), it)?.also {
|
||||
withContext(Dispatchers.Main) {
|
||||
onSuccess.invoke()
|
||||
}
|
||||
}
|
||||
appContext?.toastFromMainThread(
|
||||
if (playlistId != null) R.string.playlistCloned else R.string.server_error
|
||||
)
|
||||
}
|
||||
dismiss()
|
||||
} ?: run {
|
||||
Toast.makeText(context, R.string.invalid_url, Toast.LENGTH_SHORT).show()
|
||||
|
@ -12,7 +12,7 @@ import com.github.libretube.api.RetrofitInstance
|
||||
import com.github.libretube.api.obj.DeleteUserRequest
|
||||
import com.github.libretube.databinding.DialogDeleteAccountBinding
|
||||
import com.github.libretube.extensions.TAG
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
import com.github.libretube.helpers.PreferenceHelper
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
|
||||
class DeleteAccountDialog : DialogFragment() {
|
||||
|
@ -4,16 +4,15 @@ import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.api.RetrofitInstance
|
||||
import com.github.libretube.api.obj.PlaylistId
|
||||
import com.github.libretube.db.DatabaseHolder
|
||||
import com.github.libretube.enums.PlaylistType
|
||||
import com.github.libretube.extensions.TAG
|
||||
import com.github.libretube.extensions.awaitQuery
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
import com.github.libretube.helpers.PreferenceHelper
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
@ -28,44 +27,41 @@ class DeletePlaylistDialog(
|
||||
.setTitle(R.string.deletePlaylist)
|
||||
.setMessage(R.string.areYouSure)
|
||||
.setPositiveButton(R.string.yes) { _, _ ->
|
||||
PreferenceHelper.getToken()
|
||||
deletePlaylist()
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
deletePlaylist()
|
||||
}
|
||||
}
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun deletePlaylist() {
|
||||
private suspend fun deletePlaylist() {
|
||||
if (playlistType == PlaylistType.LOCAL) {
|
||||
awaitQuery {
|
||||
DatabaseHolder.Database.localPlaylistsDao().deletePlaylistById(playlistId)
|
||||
DatabaseHolder.Database.localPlaylistsDao().deletePlaylistItemsByPlaylistId(
|
||||
playlistId
|
||||
)
|
||||
DatabaseHolder.Database.localPlaylistsDao().deletePlaylistById(playlistId)
|
||||
DatabaseHolder.Database.localPlaylistsDao().deletePlaylistItemsByPlaylistId(playlistId)
|
||||
withContext(Dispatchers.Main) {
|
||||
onSuccess()
|
||||
}
|
||||
onSuccess.invoke()
|
||||
return
|
||||
}
|
||||
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val response = try {
|
||||
RetrofitInstance.authApi.deletePlaylist(
|
||||
PreferenceHelper.getToken(),
|
||||
PlaylistId(playlistId)
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG(), e.toString())
|
||||
return@launch
|
||||
}
|
||||
try {
|
||||
if (response.message == "ok") {
|
||||
withContext(Dispatchers.Main) {
|
||||
onSuccess.invoke()
|
||||
}
|
||||
val response = try {
|
||||
RetrofitInstance.authApi.deletePlaylist(
|
||||
PreferenceHelper.getToken(),
|
||||
PlaylistId(playlistId)
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG(), e.toString())
|
||||
return
|
||||
}
|
||||
try {
|
||||
if (response.message == "ok") {
|
||||
withContext(Dispatchers.Main) {
|
||||
onSuccess()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG(), e.toString())
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG(), e.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ import com.github.libretube.api.RetrofitInstance
|
||||
import com.github.libretube.api.obj.Streams
|
||||
import com.github.libretube.databinding.DialogDownloadBinding
|
||||
import com.github.libretube.extensions.TAG
|
||||
import com.github.libretube.util.DownloadHelper
|
||||
import com.github.libretube.helpers.DownloadHelper
|
||||
import com.github.libretube.util.TextUtils
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import java.io.IOException
|
||||
|
@ -6,8 +6,8 @@ import android.os.Bundle
|
||||
import android.widget.Toast
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.util.ClipboardHelper
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
import com.github.libretube.helpers.ClipboardHelper
|
||||
import com.github.libretube.helpers.PreferenceHelper
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
|
||||
class ErrorDialog : DialogFragment() {
|
||||
@ -22,7 +22,7 @@ class ErrorDialog : DialogFragment() {
|
||||
.setMessage(errorLog)
|
||||
.setNegativeButton(R.string.okay, null)
|
||||
.setPositiveButton(R.string.copy) { _, _ ->
|
||||
ClipboardHelper(requireContext()).save(errorLog)
|
||||
ClipboardHelper.save(requireContext(), errorLog)
|
||||
Toast.makeText(context, R.string.copied, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
.show()
|
||||
|
@ -12,7 +12,7 @@ import com.github.libretube.api.RetrofitInstance
|
||||
import com.github.libretube.api.obj.Login
|
||||
import com.github.libretube.databinding.DialogLoginBinding
|
||||
import com.github.libretube.extensions.TAG
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
import com.github.libretube.helpers.PreferenceHelper
|
||||
import com.github.libretube.util.TextUtils
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
|
||||
|
@ -8,7 +8,7 @@ import androidx.core.app.ActivityCompat
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.databinding.DialogLogoutBinding
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
import com.github.libretube.helpers.PreferenceHelper
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
|
||||
class LogoutDialog : DialogFragment() {
|
||||
|
@ -8,8 +8,8 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.databinding.DialogNavbarOptionsBinding
|
||||
import com.github.libretube.helpers.NavBarHelper
|
||||
import com.github.libretube.ui.adapters.NavBarOptionsAdapter
|
||||
import com.github.libretube.util.NavBarHelper
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
|
||||
class NavBarOptionsDialog : DialogFragment() {
|
||||
|
@ -5,7 +5,7 @@ import android.os.Bundle
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.util.NavigationHelper
|
||||
import com.github.libretube.helpers.NavigationHelper
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
|
||||
class RequireRestartDialog : DialogFragment() {
|
||||
|
@ -13,8 +13,8 @@ import com.github.libretube.databinding.DialogShareBinding
|
||||
import com.github.libretube.db.DatabaseHolder.Companion.Database
|
||||
import com.github.libretube.enums.ShareObjectType
|
||||
import com.github.libretube.extensions.awaitQuery
|
||||
import com.github.libretube.helpers.PreferenceHelper
|
||||
import com.github.libretube.obj.ShareData
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
|
||||
class ShareDialog(
|
||||
|
@ -0,0 +1,18 @@
|
||||
package com.github.libretube.ui.extensions
|
||||
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
|
||||
fun TextView.setDrawables(
|
||||
start: Int? = null,
|
||||
top: Int? = null,
|
||||
end: Int? = null,
|
||||
bottom: Int? = null
|
||||
) {
|
||||
setCompoundDrawablesRelativeWithIntrinsicBounds(
|
||||
start?.let { AppCompatResources.getDrawable(context, it) },
|
||||
top?.let { AppCompatResources.getDrawable(context, it) },
|
||||
end?.let { AppCompatResources.getDrawable(context, it) },
|
||||
bottom?.let { AppCompatResources.getDrawable(context, it) }
|
||||
)
|
||||
}
|
@ -1,8 +1,7 @@
|
||||
package com.github.libretube.ui.extensions
|
||||
|
||||
import android.view.View
|
||||
import android.view.ViewTreeObserver
|
||||
import android.widget.LinearLayout
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import com.github.libretube.db.DatabaseHolder.Companion.Database
|
||||
import com.github.libretube.extensions.awaitQuery
|
||||
@ -13,8 +12,11 @@ import com.github.libretube.extensions.awaitQuery
|
||||
* @param duration The duration of the video in seconds
|
||||
* @return Whether the video is already watched more than 90%
|
||||
*/
|
||||
fun View?.setWatchProgressLength(videoId: String, duration: Long): Boolean {
|
||||
val view = this!!
|
||||
fun View.setWatchProgressLength(videoId: String, duration: Long): Boolean {
|
||||
updateLayoutParams<ConstraintLayout.LayoutParams> {
|
||||
matchConstraintPercentWidth = 0f
|
||||
}
|
||||
visibility = View.GONE
|
||||
|
||||
val progress = try {
|
||||
awaitQuery {
|
||||
@ -26,22 +28,13 @@ fun View?.setWatchProgressLength(videoId: String, duration: Long): Boolean {
|
||||
?.toFloat()?.div(1000)
|
||||
|
||||
if (progress == null || duration == 0L) {
|
||||
view.visibility = View.GONE
|
||||
return false
|
||||
}
|
||||
|
||||
view.viewTreeObserver
|
||||
.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
|
||||
override fun onGlobalLayout() {
|
||||
this@setWatchProgressLength.viewTreeObserver.removeOnGlobalLayoutListener(this)
|
||||
val fullWidth = (parent as LinearLayout).width
|
||||
val newWidth = fullWidth * (progress / duration.toFloat())
|
||||
view.updateLayoutParams {
|
||||
width = newWidth.toInt()
|
||||
}
|
||||
view.visibility = View.VISIBLE
|
||||
}
|
||||
})
|
||||
updateLayoutParams<ConstraintLayout.LayoutParams> {
|
||||
matchConstraintPercentWidth = progress / duration.toFloat()
|
||||
}
|
||||
visibility = View.VISIBLE
|
||||
|
||||
return progress / duration.toFloat() > 0.9
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.github.libretube.ui.extensions
|
||||
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
import com.github.libretube.helpers.PreferenceHelper
|
||||
import com.google.android.material.button.MaterialButton
|
||||
|
||||
fun MaterialButton.setupNotificationBell(channelId: String) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.github.libretube.ui.fragments
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
@ -17,22 +18,28 @@ import com.github.libretube.R
|
||||
import com.github.libretube.api.obj.StreamItem
|
||||
import com.github.libretube.databinding.FragmentAudioPlayerBinding
|
||||
import com.github.libretube.enums.ShareObjectType
|
||||
import com.github.libretube.extensions.normalize
|
||||
import com.github.libretube.extensions.toID
|
||||
import com.github.libretube.helpers.AudioHelper
|
||||
import com.github.libretube.helpers.BackgroundHelper
|
||||
import com.github.libretube.helpers.ImageHelper
|
||||
import com.github.libretube.helpers.NavigationHelper
|
||||
import com.github.libretube.obj.ShareData
|
||||
import com.github.libretube.services.BackgroundMode
|
||||
import com.github.libretube.ui.activities.MainActivity
|
||||
import com.github.libretube.ui.base.BaseFragment
|
||||
import com.github.libretube.ui.dialogs.ShareDialog
|
||||
import com.github.libretube.ui.interfaces.AudioPlayerOptions
|
||||
import com.github.libretube.ui.listeners.AudioPlayerThumbnailListener
|
||||
import com.github.libretube.ui.sheets.PlaybackOptionsSheet
|
||||
import com.github.libretube.ui.sheets.PlayingQueueSheet
|
||||
import com.github.libretube.ui.sheets.VideoOptionsBottomSheet
|
||||
import com.github.libretube.util.BackgroundHelper
|
||||
import com.github.libretube.util.ImageHelper
|
||||
import com.github.libretube.util.NavigationHelper
|
||||
import com.github.libretube.util.PlayingQueue
|
||||
|
||||
class AudioPlayerFragment : BaseFragment() {
|
||||
class AudioPlayerFragment : BaseFragment(), AudioPlayerOptions {
|
||||
private lateinit var binding: FragmentAudioPlayerBinding
|
||||
private lateinit var audioHelper: AudioHelper
|
||||
|
||||
private val onTrackChangeListener: (StreamItem) -> Unit = {
|
||||
updateStreamInfo()
|
||||
}
|
||||
@ -64,6 +71,7 @@ class AudioPlayerFragment : BaseFragment() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
audioHelper = AudioHelper(requireContext())
|
||||
Intent(activity, BackgroundMode::class.java).also { intent ->
|
||||
activity?.bindService(intent, connection, Context.BIND_AUTO_CREATE)
|
||||
}
|
||||
@ -78,6 +86,7 @@ class AudioPlayerFragment : BaseFragment() {
|
||||
return binding.root
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
@ -129,13 +138,8 @@ class AudioPlayerFragment : BaseFragment() {
|
||||
).show(childFragmentManager, null)
|
||||
}
|
||||
|
||||
binding.thumbnail.setOnClickListener {
|
||||
val current = PlayingQueue.getCurrent()
|
||||
current?.let {
|
||||
VideoOptionsBottomSheet(it.url!!.toID(), it.title!!)
|
||||
.show(childFragmentManager)
|
||||
}
|
||||
}
|
||||
val listener = AudioPlayerThumbnailListener(requireContext(), this)
|
||||
binding.thumbnail.setOnTouchListener(listener)
|
||||
|
||||
// Listen for track changes due to autoplay or the notification
|
||||
PlayingQueue.addOnTrackChangedListener(onTrackChangeListener)
|
||||
@ -146,6 +150,11 @@ class AudioPlayerFragment : BaseFragment() {
|
||||
|
||||
// load the stream info into the UI
|
||||
updateStreamInfo()
|
||||
|
||||
// update the currently shown volume
|
||||
binding.volumeProgressBar.let { bar ->
|
||||
bar.progress = audioHelper.getVolumeWithScale(bar.max)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -232,4 +241,48 @@ class AudioPlayerFragment : BaseFragment() {
|
||||
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
override fun onSingleTap() {
|
||||
if (isPaused) playerService?.play() else playerService?.pause()
|
||||
}
|
||||
|
||||
override fun onLongTap() {
|
||||
val current = PlayingQueue.getCurrent()
|
||||
VideoOptionsBottomSheet(current?.url?.toID() ?: return, current.title ?: return)
|
||||
.show(childFragmentManager)
|
||||
}
|
||||
|
||||
override fun onSwipe(distanceY: Float) {
|
||||
binding.volumeControls.visibility = View.VISIBLE
|
||||
updateVolume(distanceY)
|
||||
}
|
||||
|
||||
override fun onSwipeEnd() {
|
||||
binding.volumeControls.visibility = View.GONE
|
||||
}
|
||||
|
||||
private fun updateVolume(distance: Float) {
|
||||
val bar = binding.volumeProgressBar
|
||||
binding.volumeControls.apply {
|
||||
if (visibility == View.GONE) {
|
||||
visibility = View.VISIBLE
|
||||
// Volume could be changed using other mediums, sync progress
|
||||
// bar with new value.
|
||||
bar.progress = audioHelper.getVolumeWithScale(bar.max)
|
||||
}
|
||||
}
|
||||
|
||||
if (bar.progress == 0) {
|
||||
binding.volumeImageView.setImageResource(
|
||||
when {
|
||||
distance > 0 -> R.drawable.ic_volume_up
|
||||
else -> R.drawable.ic_volume_off
|
||||
}
|
||||
)
|
||||
}
|
||||
bar.incrementProgressBy(distance.toInt() / 3)
|
||||
audioHelper.setVolumeWithScale(bar.progress, bar.max)
|
||||
|
||||
binding.volumeTextView.text = "${bar.progress.normalize(0, bar.max, 0, 100)}"
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ import com.github.libretube.enums.ShareObjectType
|
||||
import com.github.libretube.extensions.TAG
|
||||
import com.github.libretube.extensions.formatShort
|
||||
import com.github.libretube.extensions.toID
|
||||
import com.github.libretube.helpers.ImageHelper
|
||||
import com.github.libretube.obj.ChannelTabs
|
||||
import com.github.libretube.obj.ShareData
|
||||
import com.github.libretube.ui.adapters.SearchAdapter
|
||||
@ -26,11 +27,10 @@ import com.github.libretube.ui.adapters.VideosAdapter
|
||||
import com.github.libretube.ui.base.BaseFragment
|
||||
import com.github.libretube.ui.dialogs.ShareDialog
|
||||
import com.github.libretube.ui.extensions.setupSubscriptionButton
|
||||
import com.github.libretube.util.ImageHelper
|
||||
import java.io.IOException
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import retrofit2.HttpException
|
||||
|
||||
class ChannelFragment : BaseFragment() {
|
||||
@ -45,8 +45,6 @@ class ChannelFragment : BaseFragment() {
|
||||
|
||||
private var onScrollEnd: () -> Unit = {}
|
||||
|
||||
private val scope = CoroutineScope(Dispatchers.IO)
|
||||
|
||||
val possibleTabs = listOf(
|
||||
ChannelTabs.Channels,
|
||||
ChannelTabs.Playlists,
|
||||
@ -227,18 +225,18 @@ class ChannelFragment : BaseFragment() {
|
||||
}
|
||||
|
||||
private fun loadTab(tab: ChannelTab) {
|
||||
scope.launch {
|
||||
lifecycleScope.launch {
|
||||
val response = try {
|
||||
RetrofitInstance.api.getChannelTab(tab.data)
|
||||
withContext(Dispatchers.IO) {
|
||||
RetrofitInstance.api.getChannelTab(tab.data)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
return@launch
|
||||
}
|
||||
|
||||
val adapter = SearchAdapter(response.content.toMutableList())
|
||||
|
||||
runOnUiThread {
|
||||
binding.channelRecView.adapter = adapter
|
||||
}
|
||||
val adapter = SearchAdapter()
|
||||
binding.channelRecView.adapter = adapter
|
||||
adapter.submitList(response.content)
|
||||
|
||||
var tabNextPage = response.nextpage
|
||||
onScrollEnd = {
|
||||
@ -284,18 +282,18 @@ class ChannelFragment : BaseFragment() {
|
||||
adapter: SearchAdapter,
|
||||
onNewNextPage: (String?) -> Unit
|
||||
) {
|
||||
scope.launch {
|
||||
lifecycleScope.launch {
|
||||
val newContent = try {
|
||||
RetrofitInstance.api.getChannelTab(tab.data, nextPage)
|
||||
withContext(Dispatchers.IO) {
|
||||
RetrofitInstance.api.getChannelTab(tab.data, nextPage)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG(), "Exception: $e")
|
||||
null
|
||||
}
|
||||
onNewNextPage.invoke(newContent?.nextpage)
|
||||
runOnUiThread {
|
||||
newContent?.content?.let {
|
||||
adapter.updateItems(it)
|
||||
}
|
||||
onNewNextPage(newContent?.nextpage)
|
||||
newContent?.content?.let {
|
||||
adapter.submitList(adapter.currentList + it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ class CommentsMainFragment : Fragment() {
|
||||
viewModel.commentsPage.observe(viewLifecycleOwner) {
|
||||
it ?: return@observe
|
||||
binding.progress.visibility = View.GONE
|
||||
if (it.disabled == true) {
|
||||
if (it.disabled) {
|
||||
binding.errorTV.visibility = View.VISIBLE
|
||||
return@observe
|
||||
}
|
||||
|
@ -19,13 +19,13 @@ import com.github.libretube.db.DatabaseHolder.Companion.Database
|
||||
import com.github.libretube.db.obj.DownloadWithItems
|
||||
import com.github.libretube.extensions.awaitQuery
|
||||
import com.github.libretube.extensions.formatAsFileSize
|
||||
import com.github.libretube.helpers.DownloadHelper
|
||||
import com.github.libretube.obj.DownloadStatus
|
||||
import com.github.libretube.receivers.DownloadReceiver
|
||||
import com.github.libretube.services.DownloadService
|
||||
import com.github.libretube.ui.adapters.DownloadsAdapter
|
||||
import com.github.libretube.ui.base.BaseFragment
|
||||
import com.github.libretube.ui.viewholders.DownloadsViewHolder
|
||||
import com.github.libretube.util.DownloadHelper
|
||||
import java.io.File
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
|
@ -18,11 +18,11 @@ import com.github.libretube.databinding.FragmentHomeBinding
|
||||
import com.github.libretube.db.DatabaseHolder
|
||||
import com.github.libretube.extensions.awaitQuery
|
||||
import com.github.libretube.extensions.toastFromMainThread
|
||||
import com.github.libretube.helpers.LocaleHelper
|
||||
import com.github.libretube.ui.adapters.PlaylistBookmarkAdapter
|
||||
import com.github.libretube.ui.adapters.PlaylistsAdapter
|
||||
import com.github.libretube.ui.adapters.VideosAdapter
|
||||
import com.github.libretube.ui.base.BaseFragment
|
||||
import com.github.libretube.util.LocaleHelper
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
@ -21,13 +21,13 @@ import com.github.libretube.db.DatabaseHolder
|
||||
import com.github.libretube.extensions.TAG
|
||||
import com.github.libretube.extensions.awaitQuery
|
||||
import com.github.libretube.extensions.dpToPx
|
||||
import com.github.libretube.helpers.NavBarHelper
|
||||
import com.github.libretube.helpers.PreferenceHelper
|
||||
import com.github.libretube.ui.adapters.PlaylistBookmarkAdapter
|
||||
import com.github.libretube.ui.adapters.PlaylistsAdapter
|
||||
import com.github.libretube.ui.base.BaseFragment
|
||||
import com.github.libretube.ui.dialogs.CreatePlaylistDialog
|
||||
import com.github.libretube.ui.models.PlayerViewModel
|
||||
import com.github.libretube.util.NavBarHelper
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
|
||||
class LibraryFragment : BaseFragment() {
|
||||
|
||||
|
@ -35,6 +35,7 @@ import androidx.core.os.postDelayed
|
||||
import androidx.core.text.parseAsHtml
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.fragment.app.commit
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
@ -67,6 +68,13 @@ import com.github.libretube.extensions.query
|
||||
import com.github.libretube.extensions.toID
|
||||
import com.github.libretube.extensions.toStreamItem
|
||||
import com.github.libretube.extensions.updateParameters
|
||||
import com.github.libretube.helpers.BackgroundHelper
|
||||
import com.github.libretube.helpers.DashHelper
|
||||
import com.github.libretube.helpers.ImageHelper
|
||||
import com.github.libretube.helpers.NavigationHelper
|
||||
import com.github.libretube.helpers.PlayerHelper
|
||||
import com.github.libretube.helpers.PlayerHelper.loadPlaybackParams
|
||||
import com.github.libretube.helpers.PreferenceHelper
|
||||
import com.github.libretube.obj.ShareData
|
||||
import com.github.libretube.obj.VideoResolution
|
||||
import com.github.libretube.services.BackgroundMode
|
||||
@ -81,24 +89,17 @@ import com.github.libretube.ui.dialogs.ShareDialog
|
||||
import com.github.libretube.ui.extensions.setAspectRatio
|
||||
import com.github.libretube.ui.extensions.setupSubscriptionButton
|
||||
import com.github.libretube.ui.interfaces.OnlinePlayerOptions
|
||||
import com.github.libretube.ui.listeners.SeekbarPreviewListener
|
||||
import com.github.libretube.ui.models.CommentsViewModel
|
||||
import com.github.libretube.ui.models.PlayerViewModel
|
||||
import com.github.libretube.ui.sheets.BaseBottomSheet
|
||||
import com.github.libretube.ui.sheets.CommentsSheet
|
||||
import com.github.libretube.ui.sheets.PlayingQueueSheet
|
||||
import com.github.libretube.util.BackgroundHelper
|
||||
import com.github.libretube.util.DashHelper
|
||||
import com.github.libretube.util.DataSaverMode
|
||||
import com.github.libretube.util.HtmlParser
|
||||
import com.github.libretube.util.ImageHelper
|
||||
import com.github.libretube.util.LinkHandler
|
||||
import com.github.libretube.util.NavigationHelper
|
||||
import com.github.libretube.util.NowPlayingNotification
|
||||
import com.github.libretube.util.PlayerHelper
|
||||
import com.github.libretube.util.PlayerHelper.loadPlaybackParams
|
||||
import com.github.libretube.util.PlayingQueue
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
import com.github.libretube.util.SeekbarPreviewListener
|
||||
import com.github.libretube.util.TextUtils
|
||||
import com.google.android.exoplayer2.C
|
||||
import com.google.android.exoplayer2.ExoPlayer
|
||||
@ -1510,9 +1511,9 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
|
||||
private fun killPlayerFragment() {
|
||||
viewModel.isFullscreen.value = false
|
||||
binding.playerMotionLayout.transitionToEnd()
|
||||
mainActivity.supportFragmentManager.beginTransaction()
|
||||
.remove(this)
|
||||
.commit()
|
||||
mainActivity.supportFragmentManager.commit {
|
||||
remove(this@PlayerFragment)
|
||||
}
|
||||
|
||||
onDestroy()
|
||||
}
|
||||
|
@ -26,13 +26,13 @@ import com.github.libretube.extensions.dpToPx
|
||||
import com.github.libretube.extensions.query
|
||||
import com.github.libretube.extensions.toID
|
||||
import com.github.libretube.extensions.toPlaylistBookmark
|
||||
import com.github.libretube.helpers.ImageHelper
|
||||
import com.github.libretube.helpers.NavigationHelper
|
||||
import com.github.libretube.ui.adapters.PlaylistAdapter
|
||||
import com.github.libretube.ui.base.BaseFragment
|
||||
import com.github.libretube.ui.extensions.serializable
|
||||
import com.github.libretube.ui.models.PlayerViewModel
|
||||
import com.github.libretube.ui.sheets.PlaylistOptionsBottomSheet
|
||||
import com.github.libretube.util.ImageHelper
|
||||
import com.github.libretube.util.NavigationHelper
|
||||
import com.github.libretube.util.PlayingQueue
|
||||
import com.github.libretube.util.TextUtils
|
||||
|
||||
|
@ -16,9 +16,11 @@ import com.github.libretube.db.DatabaseHelper
|
||||
import com.github.libretube.db.obj.SearchHistoryItem
|
||||
import com.github.libretube.extensions.TAG
|
||||
import com.github.libretube.extensions.hideKeyboard
|
||||
import com.github.libretube.helpers.PreferenceHelper
|
||||
import com.github.libretube.ui.adapters.SearchAdapter
|
||||
import com.github.libretube.ui.base.BaseFragment
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.IOException
|
||||
import retrofit2.HttpException
|
||||
|
||||
@ -85,7 +87,9 @@ class SearchResultFragment : BaseFragment() {
|
||||
lifecycleScope.launchWhenCreated {
|
||||
view?.let { context?.hideKeyboard(it) }
|
||||
val response = try {
|
||||
RetrofitInstance.api.getSearchResults(query, apiSearchFilter)
|
||||
withContext(Dispatchers.IO) {
|
||||
RetrofitInstance.api.getSearchResults(query, apiSearchFilter)
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
println(e)
|
||||
Log.e(TAG(), "IOException, you might not have internet connection $e")
|
||||
@ -94,11 +98,10 @@ class SearchResultFragment : BaseFragment() {
|
||||
Log.e(TAG(), "HttpException, unexpected response")
|
||||
return@launchWhenCreated
|
||||
}
|
||||
runOnUiThread {
|
||||
searchAdapter = SearchAdapter(response.items.toMutableList())
|
||||
binding.searchRecycler.adapter = searchAdapter
|
||||
binding.noSearchResult.isVisible = response.items.isEmpty()
|
||||
}
|
||||
searchAdapter = SearchAdapter()
|
||||
binding.searchRecycler.adapter = searchAdapter
|
||||
searchAdapter.submitList(response.items)
|
||||
binding.noSearchResult.isVisible = response.items.isEmpty()
|
||||
nextPage = response.nextpage
|
||||
}
|
||||
}
|
||||
@ -106,11 +109,13 @@ class SearchResultFragment : BaseFragment() {
|
||||
private fun fetchNextSearchItems() {
|
||||
lifecycleScope.launchWhenCreated {
|
||||
val response = try {
|
||||
RetrofitInstance.api.getSearchResultsNextPage(
|
||||
query,
|
||||
apiSearchFilter,
|
||||
nextPage!!
|
||||
)
|
||||
withContext(Dispatchers.IO) {
|
||||
RetrofitInstance.api.getSearchResultsNextPage(
|
||||
query,
|
||||
apiSearchFilter,
|
||||
nextPage!!
|
||||
)
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
println(e)
|
||||
Log.e(TAG(), "IOException, you might not have internet connection")
|
||||
@ -120,10 +125,8 @@ class SearchResultFragment : BaseFragment() {
|
||||
return@launchWhenCreated
|
||||
}
|
||||
nextPage = response.nextpage!!
|
||||
kotlin.runCatching {
|
||||
if (response.items.isNotEmpty()) {
|
||||
searchAdapter.updateItems(response.items)
|
||||
}
|
||||
if (response.items.isNotEmpty()) {
|
||||
searchAdapter.submitList(searchAdapter.currentList + response.items)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,13 +13,13 @@ import com.github.libretube.R
|
||||
import com.github.libretube.api.obj.StreamItem
|
||||
import com.github.libretube.constants.PreferenceKeys
|
||||
import com.github.libretube.databinding.FragmentSubscriptionsBinding
|
||||
import com.github.libretube.helpers.PreferenceHelper
|
||||
import com.github.libretube.ui.adapters.LegacySubscriptionAdapter
|
||||
import com.github.libretube.ui.adapters.SubscriptionChannelAdapter
|
||||
import com.github.libretube.ui.adapters.VideosAdapter
|
||||
import com.github.libretube.ui.base.BaseFragment
|
||||
import com.github.libretube.ui.models.SubscriptionsViewModel
|
||||
import com.github.libretube.ui.sheets.BaseBottomSheet
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
|
||||
class SubscriptionsFragment : BaseFragment() {
|
||||
private lateinit var binding: FragmentSubscriptionsBinding
|
||||
|
@ -12,10 +12,10 @@ import com.github.libretube.R
|
||||
import com.github.libretube.api.RetrofitInstance
|
||||
import com.github.libretube.databinding.FragmentTrendsBinding
|
||||
import com.github.libretube.extensions.TAG
|
||||
import com.github.libretube.helpers.LocaleHelper
|
||||
import com.github.libretube.ui.activities.SettingsActivity
|
||||
import com.github.libretube.ui.adapters.VideosAdapter
|
||||
import com.github.libretube.ui.base.BaseFragment
|
||||
import com.github.libretube.util.LocaleHelper
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import java.io.IOException
|
||||
import retrofit2.HttpException
|
||||
|
@ -19,12 +19,12 @@ import com.github.libretube.db.DatabaseHolder.Companion.Database
|
||||
import com.github.libretube.extensions.awaitQuery
|
||||
import com.github.libretube.extensions.dpToPx
|
||||
import com.github.libretube.extensions.query
|
||||
import com.github.libretube.helpers.NavigationHelper
|
||||
import com.github.libretube.helpers.ProxyHelper
|
||||
import com.github.libretube.ui.adapters.WatchHistoryAdapter
|
||||
import com.github.libretube.ui.base.BaseFragment
|
||||
import com.github.libretube.ui.models.PlayerViewModel
|
||||
import com.github.libretube.util.NavigationHelper
|
||||
import com.github.libretube.util.PlayingQueue
|
||||
import com.github.libretube.util.ProxyHelper
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
|
||||
class WatchHistoryFragment : BaseFragment() {
|
||||
|
@ -0,0 +1,12 @@
|
||||
package com.github.libretube.ui.interfaces
|
||||
|
||||
interface AudioPlayerOptions {
|
||||
|
||||
fun onSingleTap()
|
||||
|
||||
fun onLongTap()
|
||||
|
||||
fun onSwipe(distanceY: Float)
|
||||
|
||||
fun onSwipeEnd()
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package com.github.libretube.ui.listeners
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.GestureDetector
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewConfiguration
|
||||
import androidx.core.os.postDelayed
|
||||
import com.github.libretube.ui.interfaces.AudioPlayerOptions
|
||||
import kotlin.math.abs
|
||||
|
||||
class AudioPlayerThumbnailListener(context: Context, private val listener: AudioPlayerOptions) :
|
||||
View.OnTouchListener {
|
||||
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
private val gestureDetector = GestureDetector(context, GestureListener(), handler)
|
||||
private var isMoving = false
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun onTouch(v: View, event: MotionEvent): Boolean {
|
||||
if (event.action == MotionEvent.ACTION_UP && isMoving) {
|
||||
isMoving = false
|
||||
listener.onSwipeEnd()
|
||||
return false
|
||||
}
|
||||
|
||||
runCatching {
|
||||
gestureDetector.onTouchEvent(event)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private inner class GestureListener : GestureDetector.SimpleOnGestureListener() {
|
||||
|
||||
override fun onDown(e: MotionEvent): Boolean {
|
||||
if (isMoving) return false
|
||||
|
||||
handler.postDelayed(ACTION_INTERVAL, SINGLE_PRESS_TOKEN) {
|
||||
if (!isMoving) listener.onSingleTap()
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onScroll(
|
||||
e1: MotionEvent,
|
||||
e2: MotionEvent,
|
||||
distanceX: Float,
|
||||
distanceY: Float
|
||||
): Boolean {
|
||||
val insideThreshHold = abs(e2.y - e1.y) <= MOVEMENT_THRESHOLD
|
||||
|
||||
// If the movement is inside threshold or scroll is horizontal then return false
|
||||
if (!isMoving && (insideThreshHold || abs(distanceX) > abs(distanceY))) {
|
||||
return false
|
||||
}
|
||||
|
||||
isMoving = true
|
||||
|
||||
listener.onSwipe(distanceY)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onLongPress(e: MotionEvent) {
|
||||
// remove to single press action from the queue
|
||||
handler.removeCallbacksAndMessages(SINGLE_PRESS_TOKEN)
|
||||
|
||||
listener.onLongTap()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val MOVEMENT_THRESHOLD = 10
|
||||
private val ACTION_INTERVAL = ViewConfiguration.getLongPressTimeout().toLong()
|
||||
private const val SINGLE_PRESS_TOKEN = "singlePress"
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.github.libretube.util
|
||||
package com.github.libretube.ui.listeners
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.res.Configuration
|
||||
@ -12,6 +12,7 @@ import android.view.ScaleGestureDetector
|
||||
import android.view.View
|
||||
import androidx.activity.viewModels
|
||||
import androidx.core.os.postDelayed
|
||||
import com.github.libretube.helpers.PlayerHelper
|
||||
import com.github.libretube.ui.base.BaseActivity
|
||||
import com.github.libretube.ui.interfaces.PlayerGestureOptions
|
||||
import com.github.libretube.ui.models.PlayerViewModel
|
@ -1,4 +1,4 @@
|
||||
package com.github.libretube.util
|
||||
package com.github.libretube.ui.listeners
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.view.View
|
||||
@ -9,6 +9,7 @@ import androidx.core.math.MathUtils
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import coil.request.ImageRequest
|
||||
import com.github.libretube.api.obj.PreviewFrames
|
||||
import com.github.libretube.helpers.ImageHelper
|
||||
import com.github.libretube.obj.PreviewFrame
|
||||
import com.google.android.exoplayer2.ui.TimeBar
|
||||
|
@ -9,7 +9,7 @@ import com.github.libretube.api.obj.StreamItem
|
||||
import com.github.libretube.api.obj.Subscription
|
||||
import com.github.libretube.extensions.TAG
|
||||
import com.github.libretube.extensions.toID
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
import com.github.libretube.helpers.PreferenceHelper
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
@ -6,9 +6,9 @@ import androidx.preference.ListPreference
|
||||
import androidx.preference.Preference
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.constants.PreferenceKeys
|
||||
import com.github.libretube.helpers.ImageHelper
|
||||
import com.github.libretube.helpers.PreferenceHelper
|
||||
import com.github.libretube.ui.base.BasePreferenceFragment
|
||||
import com.github.libretube.util.ImageHelper
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
|
||||
class AdvancedSettings : BasePreferenceFragment() {
|
||||
|
@ -7,12 +7,12 @@ import androidx.preference.Preference
|
||||
import androidx.preference.SwitchPreferenceCompat
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.constants.PreferenceKeys
|
||||
import com.github.libretube.helpers.PreferenceHelper
|
||||
import com.github.libretube.ui.adapters.IconsSheetAdapter
|
||||
import com.github.libretube.ui.base.BasePreferenceFragment
|
||||
import com.github.libretube.ui.dialogs.NavBarOptionsDialog
|
||||
import com.github.libretube.ui.dialogs.RequireRestartDialog
|
||||
import com.github.libretube.ui.sheets.IconsBottomSheet
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
|
||||
class AppearanceSettings : BasePreferenceFragment() {
|
||||
override val titleResourceId: Int = R.string.appearance
|
||||
|
@ -1,79 +1,79 @@
|
||||
package com.github.libretube.ui.preferences
|
||||
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.activity.result.contract.ActivityResultContracts.CreateDocument
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.Preference
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.helpers.BackupHelper
|
||||
import com.github.libretube.helpers.ImportHelper
|
||||
import com.github.libretube.obj.BackupFile
|
||||
import com.github.libretube.ui.base.BasePreferenceFragment
|
||||
import com.github.libretube.ui.dialogs.BackupDialog
|
||||
import com.github.libretube.util.BackupHelper
|
||||
import com.github.libretube.util.ImportHelper
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import java.time.LocalDateTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
|
||||
class BackupRestoreSettings : BasePreferenceFragment() {
|
||||
private val backupDateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH:mm:ss")
|
||||
private var backupFile = BackupFile()
|
||||
|
||||
override val titleResourceId: Int = R.string.backup_restore
|
||||
|
||||
// backup and restore database
|
||||
private lateinit var getBackupFile: ActivityResultLauncher<String>
|
||||
private lateinit var createBackupFile: ActivityResultLauncher<String>
|
||||
private var backupFile = BackupFile()
|
||||
private val getBackupFile = registerForActivityResult(ActivityResultContracts.GetContent()) {
|
||||
it?.let {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
BackupHelper.restoreAdvancedBackup(requireContext(), it)
|
||||
}
|
||||
}
|
||||
}
|
||||
private val createBackupFile = registerForActivityResult(CreateDocument(JSON)) {
|
||||
it?.let {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
BackupHelper.createAdvancedBackup(requireContext(), it, backupFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* result listeners for importing and exporting subscriptions
|
||||
*/
|
||||
private lateinit var getSubscriptionsFile: ActivityResultLauncher<String>
|
||||
private lateinit var createSubscriptionsFile: ActivityResultLauncher<String>
|
||||
private val getSubscriptionsFile = registerForActivityResult(
|
||||
ActivityResultContracts.GetContent()
|
||||
) {
|
||||
it?.let {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
ImportHelper.importSubscriptions(requireActivity(), it)
|
||||
}
|
||||
}
|
||||
}
|
||||
private val createSubscriptionsFile = registerForActivityResult(CreateDocument(JSON)) {
|
||||
it?.let {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
ImportHelper.exportSubscriptions(requireActivity(), it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* result listeners for importing and exporting playlists
|
||||
*/
|
||||
private lateinit var getPlaylistsFile: ActivityResultLauncher<String>
|
||||
private lateinit var createPlaylistsFile: ActivityResultLauncher<String>
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
getSubscriptionsFile =
|
||||
registerForActivityResult(
|
||||
ActivityResultContracts.GetContent()
|
||||
) { uri ->
|
||||
ImportHelper(requireActivity()).importSubscriptions(uri)
|
||||
private val getPlaylistsFile = registerForActivityResult(ActivityResultContracts.GetContent()) {
|
||||
it?.let {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
ImportHelper.importPlaylists(requireActivity(), it)
|
||||
}
|
||||
createSubscriptionsFile = registerForActivityResult(
|
||||
CreateDocument("application/json")
|
||||
) { uri ->
|
||||
ImportHelper(requireActivity()).exportSubscriptions(uri)
|
||||
}
|
||||
|
||||
getPlaylistsFile = registerForActivityResult(ActivityResultContracts.GetContent()) { uri ->
|
||||
ImportHelper(requireActivity()).importPlaylists(uri)
|
||||
}
|
||||
|
||||
createPlaylistsFile = registerForActivityResult(
|
||||
CreateDocument("application/json")
|
||||
) { uri ->
|
||||
ImportHelper(requireActivity()).exportPlaylists(uri)
|
||||
}
|
||||
|
||||
getBackupFile =
|
||||
registerForActivityResult(
|
||||
ActivityResultContracts.GetContent()
|
||||
) { uri: Uri? ->
|
||||
BackupHelper(requireContext()).restoreAdvancedBackup(uri)
|
||||
}
|
||||
private val createPlaylistsFile = registerForActivityResult(CreateDocument(JSON)) {
|
||||
it?.let {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
ImportHelper.exportPlaylists(requireActivity(), it)
|
||||
}
|
||||
|
||||
createBackupFile = registerForActivityResult(
|
||||
CreateDocument("application/json")
|
||||
) { uri: Uri? ->
|
||||
BackupHelper(requireContext()).createAdvancedBackup(uri, backupFile)
|
||||
}
|
||||
|
||||
super.onCreate(savedInstanceState)
|
||||
}
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
@ -116,8 +116,12 @@ class BackupRestoreSettings : BasePreferenceFragment() {
|
||||
|
||||
val restoreAdvancedBackup = findPreference<Preference>("restore")
|
||||
restoreAdvancedBackup?.setOnPreferenceClickListener {
|
||||
getBackupFile.launch("application/json")
|
||||
getBackupFile.launch(JSON)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val JSON = "application/json"
|
||||
}
|
||||
}
|
||||
|
@ -7,10 +7,10 @@ import androidx.preference.Preference
|
||||
import androidx.preference.SwitchPreferenceCompat
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.constants.PreferenceKeys
|
||||
import com.github.libretube.helpers.LocaleHelper
|
||||
import com.github.libretube.helpers.PreferenceHelper
|
||||
import com.github.libretube.ui.base.BasePreferenceFragment
|
||||
import com.github.libretube.ui.dialogs.RequireRestartDialog
|
||||
import com.github.libretube.util.LocaleHelper
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
|
||||
class GeneralSettings : BasePreferenceFragment() {
|
||||
override val titleResourceId: Int = R.string.general
|
||||
|
@ -15,12 +15,12 @@ import com.github.libretube.constants.PreferenceKeys
|
||||
import com.github.libretube.db.DatabaseHolder.Companion.Database
|
||||
import com.github.libretube.extensions.awaitQuery
|
||||
import com.github.libretube.extensions.toastFromMainThread
|
||||
import com.github.libretube.helpers.PreferenceHelper
|
||||
import com.github.libretube.ui.base.BasePreferenceFragment
|
||||
import com.github.libretube.ui.dialogs.CustomInstanceDialog
|
||||
import com.github.libretube.ui.dialogs.DeleteAccountDialog
|
||||
import com.github.libretube.ui.dialogs.LoginDialog
|
||||
import com.github.libretube.ui.dialogs.LogoutDialog
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
|
||||
class InstanceSettings : BasePreferenceFragment() {
|
||||
override val titleResourceId: Int = R.string.instance
|
||||
|
@ -4,6 +4,7 @@ import android.os.Bundle
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.commitNow
|
||||
import androidx.preference.Preference
|
||||
import com.github.libretube.BuildConfig
|
||||
import com.github.libretube.R
|
||||
@ -124,9 +125,9 @@ class MainSettings : BasePreferenceFragment() {
|
||||
}
|
||||
|
||||
private fun navigateToSettingsFragment(newFragment: Fragment): Boolean {
|
||||
parentFragmentManager.beginTransaction()
|
||||
.replace(R.id.settings, newFragment)
|
||||
.commitNow()
|
||||
parentFragmentManager.commitNow {
|
||||
replace(R.id.settings, newFragment)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -6,9 +6,9 @@ import androidx.preference.SwitchPreferenceCompat
|
||||
import androidx.work.ExistingPeriodicWorkPolicy
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.constants.PreferenceKeys
|
||||
import com.github.libretube.helpers.NotificationHelper
|
||||
import com.github.libretube.ui.base.BasePreferenceFragment
|
||||
import com.github.libretube.ui.views.TimePickerPreference
|
||||
import com.github.libretube.util.NotificationHelper
|
||||
|
||||
class NotificationSettings : BasePreferenceFragment() {
|
||||
override val titleResourceId: Int = R.string.notifications
|
||||
|
@ -12,9 +12,9 @@ import androidx.preference.Preference
|
||||
import androidx.preference.SwitchPreferenceCompat
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.constants.PreferenceKeys
|
||||
import com.github.libretube.helpers.LocaleHelper
|
||||
import com.github.libretube.helpers.PreferenceHelper
|
||||
import com.github.libretube.ui.base.BasePreferenceFragment
|
||||
import com.github.libretube.util.LocaleHelper
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
|
||||
class PlayerSettings : BasePreferenceFragment() {
|
||||
override val titleResourceId: Int = R.string.player
|
||||
|
@ -7,10 +7,10 @@ import com.github.libretube.api.RetrofitInstance
|
||||
import com.github.libretube.enums.ShareObjectType
|
||||
import com.github.libretube.extensions.TAG
|
||||
import com.github.libretube.extensions.toID
|
||||
import com.github.libretube.helpers.BackgroundHelper
|
||||
import com.github.libretube.helpers.NavigationHelper
|
||||
import com.github.libretube.obj.ShareData
|
||||
import com.github.libretube.ui.dialogs.ShareDialog
|
||||
import com.github.libretube.util.BackgroundHelper
|
||||
import com.github.libretube.util.NavigationHelper
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
/**
|
||||
|
@ -7,7 +7,7 @@ import android.view.ViewGroup
|
||||
import com.github.libretube.constants.PreferenceKeys
|
||||
import com.github.libretube.databinding.PlaybackBottomSheetBinding
|
||||
import com.github.libretube.extensions.round
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
import com.github.libretube.helpers.PreferenceHelper
|
||||
import com.google.android.exoplayer2.ExoPlayer
|
||||
import com.google.android.exoplayer2.PlaybackParameters
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user