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