diff --git a/app/schemas/com.github.libretube.db.AppDatabase/9.json b/app/schemas/com.github.libretube.db.AppDatabase/9.json new file mode 100644 index 000000000..b1129fef3 --- /dev/null +++ b/app/schemas/com.github.libretube.db.AppDatabase/9.json @@ -0,0 +1,330 @@ +{ + "formatVersion": 1, + "database": { + "version": 9, + "identityHash": "8c1e428cb526415347639e49f7757f76", + "entities": [ + { + "tableName": "watchHistoryItem", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`videoId` TEXT NOT NULL, `title` TEXT, `uploadDate` TEXT, `uploader` TEXT, `uploaderUrl` TEXT, `uploaderAvatar` TEXT, `thumbnailUrl` TEXT, `duration` INTEGER, PRIMARY KEY(`videoId`))", + "fields": [ + { + "fieldPath": "videoId", + "columnName": "videoId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "uploadDate", + "columnName": "uploadDate", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "uploader", + "columnName": "uploader", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "uploaderUrl", + "columnName": "uploaderUrl", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "uploaderAvatar", + "columnName": "uploaderAvatar", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "thumbnailUrl", + "columnName": "thumbnailUrl", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "duration", + "columnName": "duration", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "videoId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "watchPosition", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`videoId` TEXT NOT NULL, `position` INTEGER NOT NULL, PRIMARY KEY(`videoId`))", + "fields": [ + { + "fieldPath": "videoId", + "columnName": "videoId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "position", + "columnName": "position", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "videoId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "searchHistoryItem", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`query` TEXT NOT NULL, PRIMARY KEY(`query`))", + "fields": [ + { + "fieldPath": "query", + "columnName": "query", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "query" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "customInstance", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `apiUrl` TEXT NOT NULL, `frontendUrl` TEXT NOT NULL, PRIMARY KEY(`name`))", + "fields": [ + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "apiUrl", + "columnName": "apiUrl", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "frontendUrl", + "columnName": "frontendUrl", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "name" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "localSubscription", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`channelId` TEXT NOT NULL, PRIMARY KEY(`channelId`))", + "fields": [ + { + "fieldPath": "channelId", + "columnName": "channelId", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "channelId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "playlistBookmark", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`playlistId` TEXT NOT NULL, `playlistName` TEXT, `thumbnailUrl` TEXT, `uploader` TEXT, `uploaderUrl` TEXT, `uploaderAvatar` TEXT, PRIMARY KEY(`playlistId`))", + "fields": [ + { + "fieldPath": "playlistId", + "columnName": "playlistId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "playlistName", + "columnName": "playlistName", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "thumbnailUrl", + "columnName": "thumbnailUrl", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "uploader", + "columnName": "uploader", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "uploaderUrl", + "columnName": "uploaderUrl", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "uploaderAvatar", + "columnName": "uploaderAvatar", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "playlistId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "LocalPlaylist", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `thumbnailUrl` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "thumbnailUrl", + "columnName": "thumbnailUrl", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "LocalPlaylistItem", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `playlistId` INTEGER NOT NULL, `videoId` TEXT NOT NULL, `title` TEXT, `uploadDate` TEXT, `uploader` TEXT, `uploaderUrl` TEXT, `uploaderAvatar` TEXT, `thumbnailUrl` TEXT, `duration` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "playlistId", + "columnName": "playlistId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "videoId", + "columnName": "videoId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "uploadDate", + "columnName": "uploadDate", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "uploader", + "columnName": "uploader", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "uploaderUrl", + "columnName": "uploaderUrl", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "uploaderAvatar", + "columnName": "uploaderAvatar", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "thumbnailUrl", + "columnName": "thumbnailUrl", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "duration", + "columnName": "duration", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '8c1e428cb526415347639e49f7757f76')" + ] + } +} \ No newline at end of file diff --git a/app/src/main/java/com/github/libretube/LibreTubeApp.kt b/app/src/main/java/com/github/libretube/LibreTubeApp.kt index 95450a82c..9c75cae9b 100644 --- a/app/src/main/java/com/github/libretube/LibreTubeApp.kt +++ b/app/src/main/java/com/github/libretube/LibreTubeApp.kt @@ -3,7 +3,6 @@ package com.github.libretube import android.app.Application import android.os.StrictMode import android.os.StrictMode.VmPolicy -import android.util.Log import androidx.core.app.NotificationChannelCompat import androidx.core.app.NotificationManagerCompat import androidx.work.ExistingPeriodicWorkPolicy @@ -13,10 +12,6 @@ import com.github.libretube.constants.BACKGROUND_CHANNEL_ID import com.github.libretube.constants.DOWNLOAD_CHANNEL_ID import com.github.libretube.constants.PUSH_CHANNEL_ID import com.github.libretube.db.DatabaseHolder -import com.github.libretube.db.obj.LocalPlaylist -import com.github.libretube.db.obj.LocalPlaylistItem -import com.github.libretube.extensions.awaitQuery -import com.github.libretube.extensions.query import com.github.libretube.util.ExceptionHandler import com.github.libretube.util.ImageHelper import com.github.libretube.util.NotificationHelper @@ -41,8 +36,6 @@ class LibreTubeApp : Application() { */ DatabaseHolder().initializeDatabase(this) - runDatabaseTests() - /** * Bypassing fileUriExposedException, see https://stackoverflow.com/questions/38200282/android-os-fileuriexposedexception-file-storage-emulated-0-test-txt-exposed */ @@ -107,23 +100,4 @@ class LibreTubeApp : Application() { ) ) } - - private fun runDatabaseTests() { - awaitQuery { - val playlist = LocalPlaylist( - name = "TEstlist", - thumbnailUrl = "thumb" - ) - DatabaseHolder.Database.localPlaylistsDao().createPlaylist(playlist) - val playlistId = DatabaseHolder.Database.localPlaylistsDao().getAll().first().playlist.id - val video = LocalPlaylistItem( - videoId = "video", - playlistId = playlistId, - title = "awesomePlaylistTitle" - ) - DatabaseHolder.Database.localPlaylistsDao().addPlaylistVideo(video) - val lists = DatabaseHolder.Database.localPlaylistsDao().getAll() - Log.e("lists", lists.toString()) - } - } } diff --git a/app/src/main/java/com/github/libretube/api/PlaylistsHelper.kt b/app/src/main/java/com/github/libretube/api/PlaylistsHelper.kt new file mode 100644 index 000000000..0cc78455d --- /dev/null +++ b/app/src/main/java/com/github/libretube/api/PlaylistsHelper.kt @@ -0,0 +1,127 @@ +package com.github.libretube.api + +import android.content.Context +import android.util.Log +import com.github.libretube.R +import com.github.libretube.api.obj.Playlist +import com.github.libretube.api.obj.PlaylistId +import com.github.libretube.api.obj.Playlists +import com.github.libretube.db.DatabaseHolder +import com.github.libretube.db.obj.LocalPlaylist +import com.github.libretube.enums.PlaylistType +import com.github.libretube.extensions.TAG +import com.github.libretube.extensions.awaitQuery +import com.github.libretube.extensions.toLocalPlaylistItem +import com.github.libretube.extensions.toStreamItem +import com.github.libretube.extensions.toastFromMainThread +import com.github.libretube.util.PreferenceHelper +import retrofit2.HttpException +import java.io.IOException + +object PlaylistsHelper { + val token get() = PreferenceHelper.getToken() + + suspend fun getPlaylists(): List { + if (token != "") return RetrofitInstance.authApi.getUserPlaylists(token) + + val localPlaylists = awaitQuery { + DatabaseHolder.Database.localPlaylistsDao().getAll() + } + val playlists = mutableListOf() + localPlaylists.forEach { + playlists.add( + Playlists( + id = it.playlist.id.toString(), + name = it.playlist.name, + thumbnail = it.playlist.thumbnailUrl, + videos = it.videos.size.toLong() + ) + ) + } + return playlists + } + + suspend fun getPlaylist(playlistType: PlaylistType, playlistId: String): Playlist { + // load locally stored playlists with the auth api + return when (playlistType) { + PlaylistType.OWNED -> RetrofitInstance.authApi.getPlaylist(playlistId) + PlaylistType.PUBLIC -> RetrofitInstance.api.getPlaylist(playlistId) + PlaylistType.LOCAL -> { + val relation = awaitQuery { + DatabaseHolder.Database.localPlaylistsDao().getAll() + }.first { it.playlist.id.toString() == playlistId } + return Playlist( + name = relation.playlist.name, + thumbnailUrl = relation.playlist.thumbnailUrl, + videos = relation.videos.size, + relatedStreams = relation.videos.map { it.toStreamItem() } + ) + } + } + } + + suspend fun createPlaylist(playlistName: String, appContext: Context, onSuccess: () -> Unit) { + if (token == "") { + awaitQuery { + DatabaseHolder.Database.localPlaylistsDao().createPlaylist( + LocalPlaylist( + name = playlistName, + thumbnailUrl = "" + ) + ) + } + onSuccess.invoke() + return + } + val response = try { + RetrofitInstance.authApi.createPlaylist( + token, + Playlists(name = playlistName) + ) + } catch (e: IOException) { + appContext.toastFromMainThread(R.string.unknown_error) + return + } catch (e: HttpException) { + Log.e(TAG(), e.toString()) + appContext.toastFromMainThread(R.string.server_error) + return + } + if (response.playlistId != null) { + appContext.toastFromMainThread(R.string.playlistCreated) + onSuccess.invoke() + } else { + appContext.toastFromMainThread(R.string.unknown_error) + } + } + + suspend fun addToPlaylist(playlistId: String, videoId: String): Boolean { + if (token == "") { + val localPlaylistItem = RetrofitInstance.api.getStreams(videoId).toLocalPlaylistItem(playlistId, videoId) + awaitQuery { + DatabaseHolder.Database.localPlaylistsDao().addPlaylistVideo(localPlaylistItem) + val localPlaylist = DatabaseHolder.Database.localPlaylistsDao().getAll() + .first { it.playlist.id.toString() == playlistId }.playlist + if (localPlaylist.thumbnailUrl == "") { + localPlaylistItem.thumbnailUrl?.let { + localPlaylist.thumbnailUrl = it + DatabaseHolder.Database.localPlaylistsDao().updatePlaylist(localPlaylist) + } + } + } + return true + } + + return RetrofitInstance.authApi.addToPlaylist( + token, + PlaylistId(playlistId, videoId) + ).message == "ok" + } + + fun getType(): PlaylistType { + return if (PreferenceHelper.getToken() != "") { + PlaylistType.PUBLIC + } else { + PlaylistType.LOCAL + } + } +} diff --git a/app/src/main/java/com/github/libretube/constants/IntentData.kt b/app/src/main/java/com/github/libretube/constants/IntentData.kt index 9eaef14e4..b1f1d6a26 100644 --- a/app/src/main/java/com/github/libretube/constants/IntentData.kt +++ b/app/src/main/java/com/github/libretube/constants/IntentData.kt @@ -9,4 +9,5 @@ object IntentData { const val position = "position" const val fileName = "fileName" const val openQueueOnce = "openQueue" + const val playlistType = "playlistType" } diff --git a/app/src/main/java/com/github/libretube/db/AppDatabase.kt b/app/src/main/java/com/github/libretube/db/AppDatabase.kt index 8bb3f36d3..9342e51b4 100644 --- a/app/src/main/java/com/github/libretube/db/AppDatabase.kt +++ b/app/src/main/java/com/github/libretube/db/AppDatabase.kt @@ -4,16 +4,16 @@ import androidx.room.AutoMigration import androidx.room.Database import androidx.room.RoomDatabase import com.github.libretube.db.dao.CustomInstanceDao -import com.github.libretube.db.dao.LocalSubscriptionDao import com.github.libretube.db.dao.LocalPlaylistsDao +import com.github.libretube.db.dao.LocalSubscriptionDao import com.github.libretube.db.dao.PlaylistBookmarkDao import com.github.libretube.db.dao.SearchHistoryDao import com.github.libretube.db.dao.WatchHistoryDao import com.github.libretube.db.dao.WatchPositionDao import com.github.libretube.db.obj.CustomInstance -import com.github.libretube.db.obj.LocalSubscription import com.github.libretube.db.obj.LocalPlaylist import com.github.libretube.db.obj.LocalPlaylistItem +import com.github.libretube.db.obj.LocalSubscription import com.github.libretube.db.obj.PlaylistBookmark import com.github.libretube.db.obj.SearchHistoryItem import com.github.libretube.db.obj.WatchHistoryItem diff --git a/app/src/main/java/com/github/libretube/db/dao/LocalPlaylistsDao.kt b/app/src/main/java/com/github/libretube/db/dao/LocalPlaylistsDao.kt index ca3a986a9..17d4224a2 100644 --- a/app/src/main/java/com/github/libretube/db/dao/LocalPlaylistsDao.kt +++ b/app/src/main/java/com/github/libretube/db/dao/LocalPlaylistsDao.kt @@ -25,9 +25,15 @@ interface LocalPlaylistsDao { @Delete fun deletePlaylist(playlist: LocalPlaylist) + @Query("DELETE FROM localPlaylist WHERE id = :playlistId") + fun deletePlaylistById(playlistId: String) + @Insert fun addPlaylistVideo(playlistVideo: LocalPlaylistItem) @Delete fun removePlaylistVideo(playlistVideo: LocalPlaylistItem) + + @Query("DELETE FROM localPlaylistItem WHERE playlistId = :playlistId") + fun deletePlaylistItemsByPlaylistId(playlistId: String) } diff --git a/app/src/main/java/com/github/libretube/db/obj/LocalPlaylist.kt b/app/src/main/java/com/github/libretube/db/obj/LocalPlaylist.kt index a60fb6ff1..7e5141bc0 100644 --- a/app/src/main/java/com/github/libretube/db/obj/LocalPlaylist.kt +++ b/app/src/main/java/com/github/libretube/db/obj/LocalPlaylist.kt @@ -8,5 +8,5 @@ data class LocalPlaylist( @PrimaryKey(autoGenerate = true) val id: Int = 0, val name: String, - val thumbnailUrl: String + var thumbnailUrl: String ) diff --git a/app/src/main/java/com/github/libretube/enums/PlaylistType.kt b/app/src/main/java/com/github/libretube/enums/PlaylistType.kt new file mode 100644 index 000000000..f42672538 --- /dev/null +++ b/app/src/main/java/com/github/libretube/enums/PlaylistType.kt @@ -0,0 +1,7 @@ +package com.github.libretube.enums + +enum class PlaylistType { + LOCAL, + OWNED, + PUBLIC +} diff --git a/app/src/main/java/com/github/libretube/extensions/Serializable.kt b/app/src/main/java/com/github/libretube/extensions/Serializable.kt new file mode 100644 index 000000000..df4af9f79 --- /dev/null +++ b/app/src/main/java/com/github/libretube/extensions/Serializable.kt @@ -0,0 +1,10 @@ +package com.github.libretube.ui.extensions + +import android.os.Build +import android.os.Bundle +import java.io.Serializable + +inline fun Bundle.serializable(key: String): T? = when { + Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> getSerializable(key, T::class.java) + else -> @Suppress("DEPRECATION") getSerializable(key) as? T +} diff --git a/app/src/main/java/com/github/libretube/extensions/ToLocalPlaylistItem.kt b/app/src/main/java/com/github/libretube/extensions/ToLocalPlaylistItem.kt new file mode 100644 index 000000000..11146b1f6 --- /dev/null +++ b/app/src/main/java/com/github/libretube/extensions/ToLocalPlaylistItem.kt @@ -0,0 +1,18 @@ +package com.github.libretube.extensions + +import com.github.libretube.api.obj.Streams +import com.github.libretube.db.obj.LocalPlaylistItem + +fun Streams.toLocalPlaylistItem(playlistId: String, videoId: String): LocalPlaylistItem { + return LocalPlaylistItem( + playlistId = playlistId.toInt(), + videoId = videoId, + title = title, + thumbnailUrl = thumbnailUrl, + uploader = uploader, + uploaderUrl = uploaderUrl, + uploaderAvatar = uploaderAvatar, + uploadDate = uploadDate, + duration = duration + ) +} diff --git a/app/src/main/java/com/github/libretube/extensions/ToStreamItem.kt b/app/src/main/java/com/github/libretube/extensions/ToStreamItem.kt index fee0f85a9..87d3671bc 100644 --- a/app/src/main/java/com/github/libretube/extensions/ToStreamItem.kt +++ b/app/src/main/java/com/github/libretube/extensions/ToStreamItem.kt @@ -2,6 +2,7 @@ package com.github.libretube.extensions import com.github.libretube.api.obj.StreamItem import com.github.libretube.api.obj.Streams +import com.github.libretube.db.obj.LocalPlaylistItem fun Streams.toStreamItem(videoId: String): StreamItem { return StreamItem( @@ -19,3 +20,17 @@ fun Streams.toStreamItem(videoId: String): StreamItem { shortDescription = description ) } + +fun LocalPlaylistItem.toStreamItem(): StreamItem { + return StreamItem( + url = videoId, + title = title, + thumbnail = thumbnailUrl, + uploaderName = uploader, + uploaderUrl = uploaderUrl, + uploaderAvatar = uploaderAvatar, + uploadedDate = uploadDate, + uploaded = null, + duration = duration + ) +} diff --git a/app/src/main/java/com/github/libretube/extensions/ToastFromMainThread.kt b/app/src/main/java/com/github/libretube/extensions/ToastFromMainThread.kt index bb823c410..2be369899 100644 --- a/app/src/main/java/com/github/libretube/extensions/ToastFromMainThread.kt +++ b/app/src/main/java/com/github/libretube/extensions/ToastFromMainThread.kt @@ -5,16 +5,6 @@ import android.os.Handler import android.os.Looper import android.widget.Toast -fun Context.toastFromMainThread(stringId: Int) { - Handler(Looper.getMainLooper()).post { - Toast.makeText( - this, - stringId, - Toast.LENGTH_SHORT - ).show() - } -} - fun Context.toastFromMainThread(text: String) { Handler(Looper.getMainLooper()).post { Toast.makeText( @@ -24,3 +14,7 @@ fun Context.toastFromMainThread(text: String) { ).show() } } + +fun Context.toastFromMainThread(stringId: Int) { + toastFromMainThread(getString(stringId)) +} diff --git a/app/src/main/java/com/github/libretube/ui/adapters/PlaylistAdapter.kt b/app/src/main/java/com/github/libretube/ui/adapters/PlaylistAdapter.kt index 1d8780f58..11c690ef5 100644 --- a/app/src/main/java/com/github/libretube/ui/adapters/PlaylistAdapter.kt +++ b/app/src/main/java/com/github/libretube/ui/adapters/PlaylistAdapter.kt @@ -11,6 +11,7 @@ import com.github.libretube.api.RetrofitInstance import com.github.libretube.api.obj.PlaylistId import com.github.libretube.api.obj.StreamItem import com.github.libretube.databinding.PlaylistRowBinding +import com.github.libretube.enums.PlaylistType import com.github.libretube.extensions.TAG import com.github.libretube.extensions.toID import com.github.libretube.ui.base.BaseActivity @@ -30,7 +31,7 @@ import java.io.IOException class PlaylistAdapter( private val videoFeed: MutableList, private val playlistId: String, - private val isOwner: Boolean + private val playlistType: PlaylistType ) : RecyclerView.Adapter() { override fun getItemCount(): Int { @@ -70,7 +71,7 @@ class PlaylistAdapter( true } - if (isOwner) { + if (playlistType != PlaylistType.PUBLIC) { deletePlaylist.visibility = View.VISIBLE deletePlaylist.setOnClickListener { removeFromPlaylist(root.context, position) diff --git a/app/src/main/java/com/github/libretube/ui/adapters/PlaylistBookmarkAdapter.kt b/app/src/main/java/com/github/libretube/ui/adapters/PlaylistBookmarkAdapter.kt index 16ada3c47..3dc6be6f6 100644 --- a/app/src/main/java/com/github/libretube/ui/adapters/PlaylistBookmarkAdapter.kt +++ b/app/src/main/java/com/github/libretube/ui/adapters/PlaylistBookmarkAdapter.kt @@ -6,6 +6,7 @@ import androidx.appcompat.app.AppCompatActivity import androidx.recyclerview.widget.RecyclerView import com.github.libretube.databinding.PlaylistBookmarkRowBinding import com.github.libretube.db.obj.PlaylistBookmark +import com.github.libretube.enums.PlaylistType import com.github.libretube.extensions.toDp import com.github.libretube.ui.sheets.PlaylistOptionsBottomSheet import com.github.libretube.ui.viewholders.PlaylistBookmarkViewHolder @@ -39,14 +40,14 @@ class PlaylistBookmarkAdapter( uploaderName.text = bookmark.uploader root.setOnClickListener { - NavigationHelper.navigatePlaylist(root.context, bookmark.playlistId, false) + NavigationHelper.navigatePlaylist(root.context, bookmark.playlistId, PlaylistType.PUBLIC) } root.setOnLongClickListener { PlaylistOptionsBottomSheet( playlistId = bookmark.playlistId, playlistName = bookmark.playlistName ?: "", - isOwner = false + playlistType = PlaylistType.PUBLIC ).show( (root.context as AppCompatActivity).supportFragmentManager ) diff --git a/app/src/main/java/com/github/libretube/ui/adapters/PlaylistsAdapter.kt b/app/src/main/java/com/github/libretube/ui/adapters/PlaylistsAdapter.kt index 254cb80b1..63dba1787 100644 --- a/app/src/main/java/com/github/libretube/ui/adapters/PlaylistsAdapter.kt +++ b/app/src/main/java/com/github/libretube/ui/adapters/PlaylistsAdapter.kt @@ -6,6 +6,7 @@ import androidx.recyclerview.widget.RecyclerView import com.github.libretube.R import com.github.libretube.api.obj.Playlists import com.github.libretube.databinding.PlaylistsRowBinding +import com.github.libretube.enums.PlaylistType import com.github.libretube.ui.base.BaseActivity import com.github.libretube.ui.dialogs.DeletePlaylistDialog import com.github.libretube.ui.sheets.PlaylistOptionsBottomSheet @@ -14,7 +15,8 @@ import com.github.libretube.util.ImageHelper import com.github.libretube.util.NavigationHelper class PlaylistsAdapter( - private val playlists: MutableList + private val playlists: MutableList, + private val playlistType: PlaylistType ) : RecyclerView.Adapter() { override fun getItemCount(): Int { @@ -48,7 +50,7 @@ class PlaylistsAdapter( videoCount.text = playlist.videos.toString() deletePlaylist.setOnClickListener { - DeletePlaylistDialog(playlist.id!!) { + DeletePlaylistDialog(playlist.id!!, playlistType) { playlists.removeAt(position) (root.context as BaseActivity).runOnUiThread { notifyItemRemoved(position) @@ -60,14 +62,14 @@ class PlaylistsAdapter( ) } root.setOnClickListener { - NavigationHelper.navigatePlaylist(root.context, playlist.id, true) + NavigationHelper.navigatePlaylist(root.context, playlist.id, playlistType) } root.setOnLongClickListener { val playlistOptionsDialog = PlaylistOptionsBottomSheet( playlistId = playlist.id!!, playlistName = playlist.name!!, - isOwner = true + playlistType = playlistType ) playlistOptionsDialog.show( (root.context as BaseActivity).supportFragmentManager, diff --git a/app/src/main/java/com/github/libretube/ui/adapters/SearchAdapter.kt b/app/src/main/java/com/github/libretube/ui/adapters/SearchAdapter.kt index 395e0dc8e..671efeade 100644 --- a/app/src/main/java/com/github/libretube/ui/adapters/SearchAdapter.kt +++ b/app/src/main/java/com/github/libretube/ui/adapters/SearchAdapter.kt @@ -10,6 +10,7 @@ import com.github.libretube.api.obj.ContentItem import com.github.libretube.databinding.ChannelRowBinding import com.github.libretube.databinding.PlaylistsRowBinding import com.github.libretube.databinding.VideoRowBinding +import com.github.libretube.enums.PlaylistType import com.github.libretube.extensions.formatShort import com.github.libretube.extensions.toID import com.github.libretube.ui.base.BaseActivity @@ -140,13 +141,13 @@ class SearchAdapter( playlistTitle.text = item.name playlistDescription.text = item.uploaderName root.setOnClickListener { - NavigationHelper.navigatePlaylist(root.context, item.url, false) + NavigationHelper.navigatePlaylist(root.context, item.url, PlaylistType.PUBLIC) } deletePlaylist.visibility = View.GONE root.setOnLongClickListener { val playlistId = item.url!!.toID() val playlistName = item.name!! - PlaylistOptionsBottomSheet(playlistId, playlistName, false) + PlaylistOptionsBottomSheet(playlistId, playlistName, PlaylistType.PUBLIC) .show((root.context as BaseActivity).supportFragmentManager, PlaylistOptionsBottomSheet::class.java.name) true } diff --git a/app/src/main/java/com/github/libretube/ui/dialogs/AddToPlaylistDialog.kt b/app/src/main/java/com/github/libretube/ui/dialogs/AddToPlaylistDialog.kt index 492f423fa..a75afd19c 100644 --- a/app/src/main/java/com/github/libretube/ui/dialogs/AddToPlaylistDialog.kt +++ b/app/src/main/java/com/github/libretube/ui/dialogs/AddToPlaylistDialog.kt @@ -10,28 +10,23 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.lifecycle.lifecycleScope import com.github.libretube.R -import com.github.libretube.api.RetrofitInstance -import com.github.libretube.api.obj.PlaylistId +import com.github.libretube.api.PlaylistsHelper import com.github.libretube.constants.IntentData import com.github.libretube.databinding.DialogAddtoplaylistBinding import com.github.libretube.extensions.TAG import com.github.libretube.extensions.toastFromMainThread import com.github.libretube.ui.models.PlaylistViewModel -import com.github.libretube.util.PreferenceHelper import com.github.libretube.util.ThemeHelper import com.google.android.material.dialog.MaterialAlertDialogBuilder import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -import retrofit2.HttpException -import java.io.IOException class AddToPlaylistDialog : DialogFragment() { private lateinit var binding: DialogAddtoplaylistBinding private val viewModel: PlaylistViewModel by activityViewModels() private lateinit var videoId: String - private lateinit var token: String override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { videoId = arguments?.getString(IntentData.videoId)!! @@ -46,9 +41,7 @@ class AddToPlaylistDialog : DialogFragment() { } } - token = PreferenceHelper.getToken() - - if (token != "") fetchPlaylists() + fetchPlaylists() return MaterialAlertDialogBuilder(requireContext()) .setView(binding.root) @@ -58,16 +51,11 @@ class AddToPlaylistDialog : DialogFragment() { private fun fetchPlaylists() { lifecycleScope.launchWhenCreated { val response = try { - RetrofitInstance.authApi.getUserPlaylists(token) - } catch (e: IOException) { - println(e) - Log.e(TAG(), "IOException, you might not have internet connection") + PlaylistsHelper.getPlaylists() + } catch (e: Exception) { + Log.e(TAG(), e.toString()) Toast.makeText(context, R.string.unknown_error, Toast.LENGTH_SHORT).show() return@launchWhenCreated - } catch (e: HttpException) { - Log.e(TAG(), "HttpException, unexpected response") - Toast.makeText(context, R.string.server_error, Toast.LENGTH_SHORT).show() - return@launchWhenCreated } if (response.isNotEmpty()) { val names = response.map { it.name } @@ -81,8 +69,7 @@ class AddToPlaylistDialog : DialogFragment() { var selectionIndex = 0 response.forEachIndexed { index, playlist -> if (playlist.id == viewModel.lastSelectedPlaylistId) { - selectionIndex = - index + selectionIndex = index } } binding.playlistsSpinner.setSelection(selectionIndex) @@ -102,23 +89,15 @@ class AddToPlaylistDialog : DialogFragment() { private fun addToPlaylist(playlistId: String) { val appContext = context?.applicationContext ?: return CoroutineScope(Dispatchers.IO).launch { - val response = try { - RetrofitInstance.authApi.addToPlaylist( - token, - PlaylistId(playlistId, videoId) - ) - } catch (e: IOException) { - println(e) - Log.e(TAG(), "IOException, you might not have internet connection") + val success = try { + PlaylistsHelper.addToPlaylist(playlistId, videoId) + } catch (e: Exception) { + Log.e(TAG(), e.toString()) appContext.toastFromMainThread(R.string.unknown_error) return@launch - } catch (e: HttpException) { - Log.e(TAG(), "HttpException, unexpected response") - appContext.toastFromMainThread(R.string.server_error) - return@launch } appContext.toastFromMainThread( - if (response.message == "ok") R.string.added_to_playlist else R.string.fail + if (success) R.string.added_to_playlist else R.string.fail ) } } diff --git a/app/src/main/java/com/github/libretube/ui/dialogs/CreatePlaylistDialog.kt b/app/src/main/java/com/github/libretube/ui/dialogs/CreatePlaylistDialog.kt index 6ea9e2936..253925485 100644 --- a/app/src/main/java/com/github/libretube/ui/dialogs/CreatePlaylistDialog.kt +++ b/app/src/main/java/com/github/libretube/ui/dialogs/CreatePlaylistDialog.kt @@ -2,25 +2,18 @@ package com.github.libretube.ui.dialogs import android.app.Dialog import android.os.Bundle -import android.util.Log import android.widget.Toast import androidx.fragment.app.DialogFragment import androidx.lifecycle.lifecycleScope import com.github.libretube.R -import com.github.libretube.api.RetrofitInstance -import com.github.libretube.api.obj.Playlists +import com.github.libretube.api.PlaylistsHelper import com.github.libretube.databinding.DialogCreatePlaylistBinding -import com.github.libretube.extensions.TAG -import com.github.libretube.util.PreferenceHelper import com.github.libretube.util.ThemeHelper import com.google.android.material.dialog.MaterialAlertDialogBuilder -import retrofit2.HttpException -import java.io.IOException class CreatePlaylistDialog( private val onSuccess: () -> Unit = {} ) : DialogFragment() { - private var token: String = "" private lateinit var binding: DialogCreatePlaylistBinding override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { @@ -32,14 +25,17 @@ class CreatePlaylistDialog( dismiss() } - token = PreferenceHelper.getToken() - binding.createNewPlaylist.setOnClickListener { // avoid creating the same playlist multiple times by spamming the button binding.createNewPlaylist.setOnClickListener(null) val listName = binding.playlistName.text.toString() if (listName != "") { - createPlaylist(listName) + lifecycleScope.launchWhenCreated { + PlaylistsHelper.createPlaylist(listName, requireContext().applicationContext) { + onSuccess.invoke() + dismiss() + } + } } else { Toast.makeText(context, R.string.emptyPlaylistName, Toast.LENGTH_LONG).show() } @@ -49,37 +45,4 @@ class CreatePlaylistDialog( .setView(binding.root) .show() } - - private fun createPlaylist(name: String) { - lifecycleScope.launchWhenCreated { - val response = try { - RetrofitInstance.authApi.createPlaylist( - token, - Playlists(name = name) - ) - } catch (e: IOException) { - println(e) - Log.e(TAG(), "IOException, you might not have internet connection") - Toast.makeText(context, R.string.unknown_error, Toast.LENGTH_SHORT).show() - return@launchWhenCreated - } catch (e: HttpException) { - Log.e(TAG(), "HttpException, unexpected response $e") - Toast.makeText(context, R.string.server_error, Toast.LENGTH_SHORT).show() - return@launchWhenCreated - } - if (response.playlistId != null) { - Toast.makeText(context, R.string.playlistCreated, Toast.LENGTH_SHORT).show() - } else { - Toast.makeText(context, getString(R.string.unknown_error), Toast.LENGTH_SHORT) - .show() - } - // refresh the playlists in the library - try { - onSuccess.invoke() - } catch (e: Exception) { - Log.e(TAG(), e.toString()) - } - dismiss() - } - } } diff --git a/app/src/main/java/com/github/libretube/ui/dialogs/DeletePlaylistDialog.kt b/app/src/main/java/com/github/libretube/ui/dialogs/DeletePlaylistDialog.kt index c943a8e17..cf7dae196 100644 --- a/app/src/main/java/com/github/libretube/ui/dialogs/DeletePlaylistDialog.kt +++ b/app/src/main/java/com/github/libretube/ui/dialogs/DeletePlaylistDialog.kt @@ -7,7 +7,10 @@ import androidx.fragment.app.DialogFragment import com.github.libretube.R import com.github.libretube.api.RetrofitInstance import com.github.libretube.api.obj.PlaylistId +import com.github.libretube.db.DatabaseHolder +import com.github.libretube.enums.PlaylistType import com.github.libretube.extensions.TAG +import com.github.libretube.extensions.awaitQuery import com.github.libretube.util.PreferenceHelper import com.google.android.material.dialog.MaterialAlertDialogBuilder import kotlinx.coroutines.CoroutineScope @@ -16,6 +19,7 @@ import kotlinx.coroutines.launch class DeletePlaylistDialog( private val playlistId: String, + private val playlistType: PlaylistType, private val onSuccess: () -> Unit = {} ) : DialogFragment() { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { @@ -31,6 +35,14 @@ class DeletePlaylistDialog( } private fun deletePlaylist() { + if (playlistType == PlaylistType.LOCAL) { + awaitQuery { + DatabaseHolder.Database.localPlaylistsDao().deletePlaylistById(playlistId) + DatabaseHolder.Database.localPlaylistsDao().deletePlaylistItemsByPlaylistId(playlistId) + } + return + } + CoroutineScope(Dispatchers.IO).launch { val response = try { RetrofitInstance.authApi.deletePlaylist( diff --git a/app/src/main/java/com/github/libretube/ui/fragments/HomeFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/HomeFragment.kt index 82fcefa5d..ebe5afde1 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/HomeFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/HomeFragment.kt @@ -11,6 +11,7 @@ import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.github.libretube.R +import com.github.libretube.api.PlaylistsHelper import com.github.libretube.api.RetrofitInstance import com.github.libretube.api.SubscriptionHelper import com.github.libretube.databinding.FragmentHomeBinding @@ -101,13 +102,12 @@ class HomeFragment : BaseFragment() { } runOrError { - if (token == "") return@runOrError - val playlists = RetrofitInstance.authApi.getUserPlaylists(token).withMaxSize(20) + val playlists = PlaylistsHelper.getPlaylists().withMaxSize(20) if (playlists.isEmpty()) return@runOrError runOnUiThread { makeVisible(binding.playlistsRV, binding.playlistsTV) binding.playlistsRV.layoutManager = LinearLayoutManager(context) - binding.playlistsRV.adapter = PlaylistsAdapter(playlists.toMutableList()) + binding.playlistsRV.adapter = PlaylistsAdapter(playlists.toMutableList(), PlaylistsHelper.getType()) binding.playlistsRV.adapter?.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() { override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) { diff --git a/app/src/main/java/com/github/libretube/ui/fragments/LibraryFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/LibraryFragment.kt index 8799979da..d34f2c6b9 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/LibraryFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/LibraryFragment.kt @@ -12,7 +12,7 @@ import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.github.libretube.R -import com.github.libretube.api.RetrofitInstance +import com.github.libretube.api.PlaylistsHelper import com.github.libretube.constants.PreferenceKeys import com.github.libretube.databinding.FragmentLibraryBinding import com.github.libretube.extensions.TAG @@ -22,8 +22,6 @@ import com.github.libretube.ui.base.BaseFragment import com.github.libretube.ui.dialogs.CreatePlaylistDialog import com.github.libretube.ui.models.PlayerViewModel import com.github.libretube.util.PreferenceHelper -import retrofit2.HttpException -import java.io.IOException class LibraryFragment : BaseFragment() { @@ -70,26 +68,16 @@ class LibraryFragment : BaseFragment() { findNavController().navigate(R.id.downloadsFragment) } - if (token != "") { - binding.boogh.setImageResource(R.drawable.ic_list) - binding.textLike.text = getString(R.string.emptyList) + fetchPlaylists() - binding.loginOrRegister.visibility = View.GONE + binding.playlistRefresh.isEnabled = true + binding.playlistRefresh.setOnRefreshListener { fetchPlaylists() - - binding.playlistRefresh.isEnabled = true - binding.playlistRefresh.setOnRefreshListener { + } + binding.createPlaylist.setOnClickListener { + CreatePlaylistDialog { fetchPlaylists() - } - binding.createPlaylist.setOnClickListener { - val newFragment = CreatePlaylistDialog { - fetchPlaylists() - } - newFragment.show(childFragmentManager, CreatePlaylistDialog::class.java.name) - } - } else { - binding.playlistRefresh.isEnabled = false - binding.createPlaylist.visibility = View.GONE + }.show(childFragmentManager, CreatePlaylistDialog::class.java.name) } } @@ -101,26 +89,19 @@ class LibraryFragment : BaseFragment() { binding.createPlaylist.layoutParams = layoutParams } - fun fetchPlaylists() { + private fun fetchPlaylists() { binding.playlistRefresh.isRefreshing = true lifecycleScope.launchWhenCreated { var playlists = try { - RetrofitInstance.authApi.getUserPlaylists(token) - } catch (e: IOException) { - println(e) - Log.e(TAG(), "IOException, you might not have internet connection") + PlaylistsHelper.getPlaylists() + } catch (e: Exception) { + Log.e(TAG(), e.toString()) Toast.makeText(context, R.string.unknown_error, Toast.LENGTH_SHORT).show() return@launchWhenCreated - } catch (e: HttpException) { - Log.e(TAG(), "HttpException, unexpected response") - Toast.makeText(context, R.string.server_error, Toast.LENGTH_SHORT).show() - return@launchWhenCreated } finally { binding.playlistRefresh.isRefreshing = false } if (playlists.isNotEmpty()) { - binding.loginOrRegister.visibility = View.GONE - playlists = when ( PreferenceHelper.getString( PreferenceKeys.PLAYLISTS_ORDER, @@ -135,16 +116,15 @@ class LibraryFragment : BaseFragment() { } val playlistsAdapter = PlaylistsAdapter( - playlists.toMutableList() + playlists.toMutableList(), + PlaylistsHelper.getType() ) // listen for playlists to become deleted playlistsAdapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() { override fun onChanged() { - if (playlistsAdapter.itemCount == 0) { - binding.loginOrRegister.visibility = View.VISIBLE - } + binding.nothingHere.visibility = if (playlistsAdapter.itemCount == 0) View.VISIBLE else View.GONE super.onChanged() } }) @@ -152,7 +132,7 @@ class LibraryFragment : BaseFragment() { binding.playlistRecView.adapter = playlistsAdapter } else { runOnUiThread { - binding.loginOrRegister.visibility = View.VISIBLE + binding.nothingHere.visibility = View.VISIBLE } } } diff --git a/app/src/main/java/com/github/libretube/ui/fragments/PlaylistFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/PlaylistFragment.kt index cfbde5dc0..46b0dbbc0 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/PlaylistFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/PlaylistFragment.kt @@ -11,17 +11,20 @@ import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.github.libretube.R +import com.github.libretube.api.PlaylistsHelper import com.github.libretube.api.RetrofitInstance import com.github.libretube.constants.IntentData import com.github.libretube.databinding.FragmentPlaylistBinding import com.github.libretube.db.DatabaseHolder import com.github.libretube.db.obj.PlaylistBookmark +import com.github.libretube.enums.PlaylistType import com.github.libretube.extensions.TAG import com.github.libretube.extensions.awaitQuery import com.github.libretube.extensions.query import com.github.libretube.extensions.toID import com.github.libretube.ui.adapters.PlaylistAdapter import com.github.libretube.ui.base.BaseFragment +import com.github.libretube.ui.extensions.serializable import com.github.libretube.ui.sheets.PlaylistOptionsBottomSheet import com.github.libretube.util.ImageHelper import com.github.libretube.util.NavigationHelper @@ -34,7 +37,7 @@ class PlaylistFragment : BaseFragment() { private var playlistId: String? = null private var playlistName: String? = null - private var isOwner: Boolean = false + private var playlistType: PlaylistType = PlaylistType.PUBLIC private var nextPage: String? = null private var playlistAdapter: PlaylistAdapter? = null private var isLoading = true @@ -44,7 +47,7 @@ class PlaylistFragment : BaseFragment() { super.onCreate(savedInstanceState) arguments?.let { playlistId = it.getString(IntentData.playlistId) - isOwner = it.getBoolean("isOwner") + playlistType = it.serializable(IntentData.playlistType)!! } } @@ -84,12 +87,7 @@ class PlaylistFragment : BaseFragment() { binding.playlistScrollview.visibility = View.GONE lifecycleScope.launchWhenCreated { val response = try { - // load locally stored playlists with the auth api - if (isOwner) { - RetrofitInstance.authApi.getPlaylist(playlistId!!) - } else { - RetrofitInstance.api.getPlaylist(playlistId!!) - } + PlaylistsHelper.getPlaylist(playlistType, playlistId!!) } catch (e: IOException) { println(e) Log.e(TAG(), "IOException, you might not have internet connection") @@ -116,7 +114,7 @@ class PlaylistFragment : BaseFragment() { // show playlist options binding.optionsMenu.setOnClickListener { - PlaylistOptionsBottomSheet(playlistId!!, playlistName ?: "", isOwner).show( + PlaylistOptionsBottomSheet(playlistId!!, playlistName ?: "", playlistType).show( childFragmentManager, PlaylistOptionsBottomSheet::class.java.name ) @@ -131,7 +129,7 @@ class PlaylistFragment : BaseFragment() { ) } - if (isOwner) binding.bookmark.visibility = View.GONE + if (playlistType != PlaylistType.PUBLIC) binding.bookmark.visibility = View.GONE binding.bookmark.setOnClickListener { isBookmarked = !isBookmarked @@ -157,7 +155,7 @@ class PlaylistFragment : BaseFragment() { playlistAdapter = PlaylistAdapter( response.relatedStreams.orEmpty().toMutableList(), playlistId!!, - isOwner + playlistType ) // listen for playlist items to become deleted @@ -189,7 +187,7 @@ class PlaylistFragment : BaseFragment() { /** * listener for swiping to the left or right */ - if (isOwner) { + if (playlistType != PlaylistType.PUBLIC) { val itemTouchCallback = object : ItemTouchHelper.SimpleCallback( 0, ItemTouchHelper.LEFT @@ -219,34 +217,27 @@ class PlaylistFragment : BaseFragment() { } private fun fetchNextPage() { - fun run() { - lifecycleScope.launchWhenCreated { - val response = try { - // load locally stored playlists with the auth api - if (isOwner) { - RetrofitInstance.authApi.getPlaylistNextPage( - playlistId!!, - nextPage!! - ) - } else { - RetrofitInstance.api.getPlaylistNextPage( - playlistId!!, - nextPage!! - ) - } - } catch (e: IOException) { - println(e) - Log.e(TAG(), "IOException, you might not have internet connection") - return@launchWhenCreated - } catch (e: HttpException) { - Log.e(TAG(), "HttpException, unexpected response," + e.response()) - return@launchWhenCreated + lifecycleScope.launchWhenCreated { + val response = try { + // load locally stored playlists with the auth api + if (playlistType == PlaylistType.OWNED) { + RetrofitInstance.authApi.getPlaylistNextPage( + playlistId!!, + nextPage!! + ) + } else { + RetrofitInstance.api.getPlaylistNextPage( + playlistId!!, + nextPage!! + ) } - nextPage = response.nextpage - playlistAdapter?.updateItems(response.relatedStreams!!) - isLoading = false + } catch (e: Exception) { + Log.e(TAG(), e.toString()) + return@launchWhenCreated } + nextPage = response.nextpage + playlistAdapter?.updateItems(response.relatedStreams!!) + isLoading = false } - run() } } diff --git a/app/src/main/java/com/github/libretube/ui/sheets/PlaylistOptionsBottomSheet.kt b/app/src/main/java/com/github/libretube/ui/sheets/PlaylistOptionsBottomSheet.kt index 9d1868149..ea3d3ae3a 100644 --- a/app/src/main/java/com/github/libretube/ui/sheets/PlaylistOptionsBottomSheet.kt +++ b/app/src/main/java/com/github/libretube/ui/sheets/PlaylistOptionsBottomSheet.kt @@ -7,6 +7,7 @@ import com.github.libretube.R import com.github.libretube.api.RetrofitInstance import com.github.libretube.api.obj.PlaylistId import com.github.libretube.databinding.DialogTextPreferenceBinding +import com.github.libretube.enums.PlaylistType import com.github.libretube.enums.ShareObjectType import com.github.libretube.extensions.toID import com.github.libretube.extensions.toastFromMainThread @@ -25,8 +26,8 @@ import java.io.IOException class PlaylistOptionsBottomSheet( private val playlistId: String, - private val playlistName: String, - private val isOwner: Boolean + playlistName: String, + private val playlistType: PlaylistType ) : BaseBottomSheet() { private val shareData = ShareData(currentPlaylist = playlistName) override fun onCreate(savedInstanceState: Bundle?) { @@ -37,7 +38,7 @@ class PlaylistOptionsBottomSheet( context?.getString(R.string.share)!! ) - if (isOwner) { + if (playlistType != PlaylistType.PUBLIC) { optionsList = optionsList + context?.getString(R.string.renamePlaylist)!! + context?.getString(R.string.deletePlaylist)!! - @@ -50,7 +51,7 @@ class PlaylistOptionsBottomSheet( context?.getString(R.string.playOnBackground) -> { runBlocking { val playlist = - if (isOwner) { + if (playlistType == PlaylistType.OWNED) { RetrofitInstance.authApi.getPlaylist(playlistId) } else { RetrofitInstance.api.getPlaylist(playlistId) @@ -82,7 +83,7 @@ class PlaylistOptionsBottomSheet( shareDialog.show(parentFragmentManager, ShareDialog::class.java.name) } context?.getString(R.string.deletePlaylist) -> { - DeletePlaylistDialog(playlistId) + DeletePlaylistDialog(playlistId, playlistType) .show(parentFragmentManager, null) } context?.getString(R.string.renamePlaylist) -> { diff --git a/app/src/main/java/com/github/libretube/ui/sheets/VideoOptionsBottomSheet.kt b/app/src/main/java/com/github/libretube/ui/sheets/VideoOptionsBottomSheet.kt index 9e15bc51b..2e26bf4cf 100644 --- a/app/src/main/java/com/github/libretube/ui/sheets/VideoOptionsBottomSheet.kt +++ b/app/src/main/java/com/github/libretube/ui/sheets/VideoOptionsBottomSheet.kt @@ -1,7 +1,7 @@ package com.github.libretube.ui.sheets import android.os.Bundle -import android.widget.Toast +import androidx.core.os.bundleOf import com.github.libretube.R import com.github.libretube.api.RetrofitInstance import com.github.libretube.constants.IntentData @@ -13,7 +13,6 @@ import com.github.libretube.ui.dialogs.DownloadDialog import com.github.libretube.ui.dialogs.ShareDialog import com.github.libretube.util.BackgroundHelper import com.github.libretube.util.PlayingQueue -import com.github.libretube.util.PreferenceHelper import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -37,14 +36,6 @@ class VideoOptionsBottomSheet( context?.getString(R.string.share)!! ) - // remove the add to playlist option if not logged in - if (PreferenceHelper.getToken() == "") { - optionsList.remove( - context?.getString(R.string.addToPlaylist) - - ) - } - /** * Check whether the player is running and add queue options */ @@ -61,19 +52,12 @@ class VideoOptionsBottomSheet( } // Add Video to Playlist Dialog context?.getString(R.string.addToPlaylist) -> { - val token = PreferenceHelper.getToken() - if (token != "") { - val newFragment = AddToPlaylistDialog() - val bundle = Bundle() - bundle.putString(IntentData.videoId, videoId) - newFragment.arguments = bundle - newFragment.show( - parentFragmentManager, - AddToPlaylistDialog::class.java.name - ) - } else { - Toast.makeText(context, R.string.login_first, Toast.LENGTH_SHORT).show() - } + AddToPlaylistDialog().apply { + arguments = bundleOf(IntentData.videoId to videoId) + }.show( + parentFragmentManager, + AddToPlaylistDialog::class.java.name + ) } context?.getString(R.string.download) -> { val downloadDialog = DownloadDialog(videoId) diff --git a/app/src/main/java/com/github/libretube/util/NavigationHelper.kt b/app/src/main/java/com/github/libretube/util/NavigationHelper.kt index 58b1bce9e..0131b8b90 100644 --- a/app/src/main/java/com/github/libretube/util/NavigationHelper.kt +++ b/app/src/main/java/com/github/libretube/util/NavigationHelper.kt @@ -9,6 +9,7 @@ import androidx.appcompat.app.AppCompatActivity import androidx.core.os.bundleOf import com.github.libretube.R import com.github.libretube.constants.IntentData +import com.github.libretube.enums.PlaylistType import com.github.libretube.extensions.toID import com.github.libretube.ui.activities.MainActivity import com.github.libretube.ui.fragments.PlayerFragment @@ -59,14 +60,14 @@ object NavigationHelper { fun navigatePlaylist( context: Context, playlistId: String?, - isOwner: Boolean + playlistType: PlaylistType ) { if (playlistId == null) return val activity = context as MainActivity val bundle = Bundle() bundle.putString(IntentData.playlistId, playlistId) - bundle.putBoolean("isOwner", isOwner) + bundle.putSerializable(IntentData.playlistType, playlistType) activity.navController.navigate(R.id.playlistFragment, bundle) } diff --git a/app/src/main/res/layout/fragment_library.xml b/app/src/main/res/layout/fragment_library.xml index e6d1574c8..e1f503c04 100644 --- a/app/src/main/res/layout/fragment_library.xml +++ b/app/src/main/res/layout/fragment_library.xml @@ -7,9 +7,10 @@ tools:context=".ui.fragments.LibraryFragment"> + android:layout_height="match_parent" + android:visibility="gone"> + android:src="@drawable/ic_list" />