mirror of
https://github.com/libre-tube/LibreTube.git
synced 2024-12-14 22:30:30 +05:30
commit
130d9167bd
@ -18,6 +18,12 @@ android {
|
||||
multiDexEnabled true
|
||||
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
||||
resValue "string", "app_name", "LibreTube"
|
||||
|
||||
javaCompileOptions {
|
||||
annotationProcessorOptions {
|
||||
arguments += ["room.schemaLocation": "$projectDir/schemas".toString()]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
|
174
app/schemas/com.github.libretube.db.AppDatabase/7.json
Normal file
174
app/schemas/com.github.libretube.db.AppDatabase/7.json
Normal file
@ -0,0 +1,174 @@
|
||||
{
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 7,
|
||||
"identityHash": "c9803a67ce206dbda6e44ed761f80136",
|
||||
"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": []
|
||||
}
|
||||
],
|
||||
"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, 'c9803a67ce206dbda6e44ed761f80136')"
|
||||
]
|
||||
}
|
||||
}
|
224
app/schemas/com.github.libretube.db.AppDatabase/8.json
Normal file
224
app/schemas/com.github.libretube.db.AppDatabase/8.json
Normal file
@ -0,0 +1,224 @@
|
||||
{
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 8,
|
||||
"identityHash": "eb8d0ff1131448df6216b549bbfa7c21",
|
||||
"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": []
|
||||
}
|
||||
],
|
||||
"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, 'eb8d0ff1131448df6216b549bbfa7c21')"
|
||||
]
|
||||
}
|
||||
}
|
@ -1,14 +1,17 @@
|
||||
package com.github.libretube.db
|
||||
|
||||
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.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.PlaylistBookmark
|
||||
import com.github.libretube.db.obj.SearchHistoryItem
|
||||
import com.github.libretube.db.obj.WatchHistoryItem
|
||||
import com.github.libretube.db.obj.WatchPosition
|
||||
@ -19,9 +22,13 @@ import com.github.libretube.db.obj.WatchPosition
|
||||
WatchPosition::class,
|
||||
SearchHistoryItem::class,
|
||||
CustomInstance::class,
|
||||
LocalSubscription::class
|
||||
LocalSubscription::class,
|
||||
PlaylistBookmark::class
|
||||
],
|
||||
version = 7
|
||||
version = 8,
|
||||
autoMigrations = [
|
||||
AutoMigration(from = 7, to = 8)
|
||||
]
|
||||
)
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
/**
|
||||
@ -48,4 +55,9 @@ abstract class AppDatabase : RoomDatabase() {
|
||||
* Local Subscriptions
|
||||
*/
|
||||
abstract fun localSubscriptionDao(): LocalSubscriptionDao
|
||||
|
||||
/**
|
||||
* Bookmarked Playlists
|
||||
*/
|
||||
abstract fun playlistBookmarkDao(): PlaylistBookmarkDao
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
package com.github.libretube.db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import com.github.libretube.db.obj.PlaylistBookmark
|
||||
|
||||
@Dao
|
||||
interface PlaylistBookmarkDao {
|
||||
@Query("SELECT * FROM playlistBookmark")
|
||||
fun getAll(): List<PlaylistBookmark>
|
||||
|
||||
@Query("SELECT * FROM playlistBookmark WHERE playlistId LIKE :playlistId LIMIT 1")
|
||||
fun findById(playlistId: String): PlaylistBookmark
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
fun insertAll(vararg bookmarks: PlaylistBookmark)
|
||||
|
||||
@Delete
|
||||
fun delete(playlistBookmark: PlaylistBookmark)
|
||||
|
||||
@Query("SELECT EXISTS(SELECT * FROM playlistBookmark WHERE playlistId= :playlistId)")
|
||||
fun includes(playlistId: String): Boolean
|
||||
|
||||
@Query("DELETE FROM playlistBookmark")
|
||||
fun deleteAll()
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
|
||||
package com.github.libretube.db.obj
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(tableName = "playlistBookmark")
|
||||
data class PlaylistBookmark(
|
||||
@PrimaryKey
|
||||
val playlistId: String = "",
|
||||
val playlistName: String? = null,
|
||||
var thumbnailUrl: String? = null,
|
||||
var uploader: String? = null,
|
||||
var uploaderUrl: String? = null,
|
||||
var uploaderAvatar: String? = null
|
||||
)
|
@ -0,0 +1,49 @@
|
||||
package com.github.libretube.ui.adapters
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
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.ui.sheets.PlaylistOptionsBottomSheet
|
||||
import com.github.libretube.ui.viewholders.PlaylistBookmarkViewHolder
|
||||
import com.github.libretube.util.ImageHelper
|
||||
import com.github.libretube.util.NavigationHelper
|
||||
|
||||
class PlaylistBookmarkAdapter(
|
||||
private val bookmarks: List<PlaylistBookmark>
|
||||
) : RecyclerView.Adapter<PlaylistBookmarkViewHolder>() {
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PlaylistBookmarkViewHolder {
|
||||
val binding = PlaylistBookmarkRowBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
return PlaylistBookmarkViewHolder(binding)
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return bookmarks.size
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: PlaylistBookmarkViewHolder, position: Int) {
|
||||
val bookmark = bookmarks[position]
|
||||
holder.binding.apply {
|
||||
ImageHelper.loadImage(bookmark.thumbnailUrl, thumbnail)
|
||||
playlistName.text = bookmark.playlistName
|
||||
uploaderName.text = bookmark.uploader
|
||||
|
||||
root.setOnClickListener {
|
||||
NavigationHelper.navigatePlaylist(root.context, bookmark.playlistId, false)
|
||||
}
|
||||
|
||||
root.setOnLongClickListener {
|
||||
PlaylistOptionsBottomSheet(
|
||||
playlistId = bookmark.playlistId,
|
||||
playlistName = bookmark.playlistName ?: "",
|
||||
isOwner = false
|
||||
).show(
|
||||
(root.context as AppCompatActivity).supportFragmentManager
|
||||
)
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -13,7 +13,10 @@ import com.github.libretube.R
|
||||
import com.github.libretube.api.RetrofitInstance
|
||||
import com.github.libretube.api.SubscriptionHelper
|
||||
import com.github.libretube.databinding.FragmentHomeBinding
|
||||
import com.github.libretube.db.DatabaseHolder
|
||||
import com.github.libretube.extensions.awaitQuery
|
||||
import com.github.libretube.extensions.toastFromMainThread
|
||||
import com.github.libretube.ui.adapters.PlaylistBookmarkAdapter
|
||||
import com.github.libretube.ui.adapters.PlaylistsAdapter
|
||||
import com.github.libretube.ui.adapters.VideosAdapter
|
||||
import com.github.libretube.ui.base.BaseFragment
|
||||
@ -111,6 +114,18 @@ class HomeFragment : BaseFragment() {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
runOrError {
|
||||
val bookmarkedPlaylists = awaitQuery {
|
||||
DatabaseHolder.Database.playlistBookmarkDao().getAll()
|
||||
}
|
||||
if (bookmarkedPlaylists.isEmpty()) return@runOrError
|
||||
runOnUiThread {
|
||||
makeVisible(binding.bookmarksTV, binding.bookmarksRV)
|
||||
binding.bookmarksRV.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
|
||||
binding.bookmarksRV.adapter = PlaylistBookmarkAdapter(bookmarkedPlaylists)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun runOrError(action: suspend () -> Unit) {
|
||||
|
@ -14,13 +14,14 @@ import com.github.libretube.R
|
||||
import com.github.libretube.api.RetrofitInstance
|
||||
import com.github.libretube.constants.IntentData
|
||||
import com.github.libretube.databinding.FragmentPlaylistBinding
|
||||
import com.github.libretube.enums.ShareObjectType
|
||||
import com.github.libretube.db.DatabaseHolder
|
||||
import com.github.libretube.db.obj.PlaylistBookmark
|
||||
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.obj.ShareData
|
||||
import com.github.libretube.ui.adapters.PlaylistAdapter
|
||||
import com.github.libretube.ui.base.BaseFragment
|
||||
import com.github.libretube.ui.dialogs.ShareDialog
|
||||
import com.github.libretube.ui.sheets.PlaylistOptionsBottomSheet
|
||||
import com.github.libretube.util.ImageHelper
|
||||
import com.github.libretube.util.NavigationHelper
|
||||
@ -37,6 +38,7 @@ class PlaylistFragment : BaseFragment() {
|
||||
private var nextPage: String? = null
|
||||
private var playlistAdapter: PlaylistAdapter? = null
|
||||
private var isLoading = true
|
||||
private var isBookmarked = false
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@ -62,11 +64,24 @@ class PlaylistFragment : BaseFragment() {
|
||||
binding.playlistRecView.layoutManager = LinearLayoutManager(context)
|
||||
|
||||
binding.playlistProgress.visibility = View.VISIBLE
|
||||
|
||||
isBookmarked = awaitQuery {
|
||||
DatabaseHolder.Database.playlistBookmarkDao().includes(playlistId!!)
|
||||
}
|
||||
updateBookmarkRes()
|
||||
|
||||
fetchPlaylist()
|
||||
}
|
||||
|
||||
private fun updateBookmarkRes() {
|
||||
binding.bookmark.setIconResource(
|
||||
if (isBookmarked) R.drawable.ic_bookmark else R.drawable.ic_bookmark_outlined
|
||||
)
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
private fun fetchPlaylist() {
|
||||
binding.playlistScrollview.visibility = View.GONE
|
||||
lifecycleScope.launchWhenCreated {
|
||||
val response = try {
|
||||
// load locally stored playlists with the auth api
|
||||
@ -83,6 +98,7 @@ class PlaylistFragment : BaseFragment() {
|
||||
Log.e(TAG(), "HttpException, unexpected response")
|
||||
return@launchWhenCreated
|
||||
}
|
||||
binding.playlistScrollview.visibility = View.VISIBLE
|
||||
nextPage = response.nextpage
|
||||
playlistName = response.name
|
||||
isLoading = false
|
||||
@ -114,12 +130,29 @@ class PlaylistFragment : BaseFragment() {
|
||||
)
|
||||
}
|
||||
|
||||
binding.share.setOnClickListener {
|
||||
ShareDialog(
|
||||
playlistId!!,
|
||||
ShareObjectType.PLAYLIST,
|
||||
ShareData(currentPlaylist = response.name)
|
||||
).show(childFragmentManager, null)
|
||||
if (isOwner) binding.bookmark.visibility = View.GONE
|
||||
|
||||
binding.bookmark.setOnClickListener {
|
||||
isBookmarked = !isBookmarked
|
||||
updateBookmarkRes()
|
||||
query {
|
||||
if (!isBookmarked) {
|
||||
DatabaseHolder.Database.playlistBookmarkDao().delete(
|
||||
DatabaseHolder.Database.playlistBookmarkDao().findById(playlistId!!)
|
||||
)
|
||||
} else {
|
||||
DatabaseHolder.Database.playlistBookmarkDao().insertAll(
|
||||
PlaylistBookmark(
|
||||
playlistId = playlistId!!,
|
||||
playlistName = response.name,
|
||||
thumbnailUrl = response.thumbnailUrl,
|
||||
uploader = response.uploader,
|
||||
uploaderAvatar = response.uploaderAvatar,
|
||||
uploaderUrl = response.uploaderUrl
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
playlistAdapter = PlaylistAdapter(
|
||||
|
@ -0,0 +1,8 @@
|
||||
package com.github.libretube.ui.viewholders
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.github.libretube.databinding.PlaylistBookmarkRowBinding
|
||||
|
||||
class PlaylistBookmarkViewHolder(
|
||||
val binding: PlaylistBookmarkRowBinding
|
||||
) : RecyclerView.ViewHolder(binding.root)
|
10
app/src/main/res/drawable/ic_bookmark.xml
Normal file
10
app/src/main/res/drawable/ic_bookmark.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M17,3H7c-1.1,0 -1.99,0.9 -1.99,2L5,21l7,-3 7,3V5c0,-1.1 -0.9,-2 -2,-2z" />
|
||||
</vector>
|
10
app/src/main/res/drawable/ic_bookmark_outlined.xml
Normal file
10
app/src/main/res/drawable/ic_bookmark_outlined.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M17,3L7,3c-1.1,0 -1.99,0.9 -1.99,2L5,21l7,-3 7,3L19,5c0,-1.1 -0.9,-2 -2,-2zM17,18l-5,-2.18L7,18L7,5h10v13z" />
|
||||
</vector>
|
@ -59,6 +59,18 @@
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/bookmarksTV"
|
||||
style="@style/HomeCategoryTitle"
|
||||
android:text="@string/bookmarks" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/bookmarksRV"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:nestedScrollingEnabled="false"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/playlistsTV"
|
||||
style="@style/HomeCategoryTitle"
|
||||
|
@ -88,14 +88,14 @@
|
||||
app:icon="@drawable/ic_playlist" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/share"
|
||||
android:id="@+id/bookmark"
|
||||
style="@style/Widget.Material3.Button"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="10dp"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/share"
|
||||
app:icon="@drawable/ic_share_outlined" />
|
||||
android:text="@string/bookmark"
|
||||
app:icon="@drawable/ic_bookmark_outlined" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
38
app/src/main/res/layout/playlist_bookmark_row.xml
Normal file
38
app/src/main/res/layout/playlist_bookmark_row.xml
Normal file
@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="5dp"
|
||||
android:background="@drawable/rounded_ripple"
|
||||
android:orientation="vertical"
|
||||
android:padding="5dp">
|
||||
|
||||
<com.google.android.material.imageview.ShapeableImageView
|
||||
android:id="@+id/thumbnail"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="fitCenter"
|
||||
app:shapeAppearanceOverlay="@style/ShapeAppearance.Material3.Corner.Medium"
|
||||
tools:src="@tools:sample/backgrounds/scenic" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/playlistName"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/uploaderName"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textSize="14sp" />
|
||||
|
||||
</LinearLayout>
|
@ -381,6 +381,9 @@
|
||||
<string name="trends">Trends</string>
|
||||
<string name="featured">Featured</string>
|
||||
<string name="trending">What\'s trending now</string>
|
||||
<string name="bookmarks">Bookmarks</string>
|
||||
<string name="bookmark">Bookmark</string>
|
||||
|
||||
<!-- Notification channel strings -->
|
||||
<string name="download_channel_name">Download Service</string>
|
||||
<string name="download_channel_description">Shows a notification when downloading media.</string>
|
||||
|
Loading…
Reference in New Issue
Block a user