From 48951f13c3be8d11a700edfbb85b13dca5fa5d0a Mon Sep 17 00:00:00 2001 From: Bnyro Date: Fri, 18 Nov 2022 18:01:11 +0100 Subject: [PATCH 1/3] add support for bookmarking playlists --- app/build.gradle | 6 + .../7.json | 174 ++++++++++++++ .../8.json | 224 ++++++++++++++++++ .../com/github/libretube/db/AppDatabase.kt | 16 +- .../libretube/db/dao/PlaylistBookmarkDao.kt | 29 +++ .../libretube/db/obj/PlaylistBookmark.kt | 16 ++ .../ui/adapters/PlaylistBookmarkAdapter.kt | 31 +++ .../libretube/ui/fragments/HomeFragment.kt | 15 ++ .../ui/fragments/PlaylistFragment.kt | 49 +++- .../viewholders/PlaylistBookmarkViewHolder.kt | 8 + app/src/main/res/drawable/ic_bookmark.xml | 10 + .../res/drawable/ic_bookmark_outlined.xml | 10 + app/src/main/res/layout/fragment_home.xml | 12 + app/src/main/res/layout/fragment_playlist.xml | 6 +- .../main/res/layout/playlist_bookmark_row.xml | 33 +++ app/src/main/res/values/strings.xml | 3 + 16 files changed, 628 insertions(+), 14 deletions(-) create mode 100644 app/schemas/com.github.libretube.db.AppDatabase/7.json create mode 100644 app/schemas/com.github.libretube.db.AppDatabase/8.json create mode 100644 app/src/main/java/com/github/libretube/db/dao/PlaylistBookmarkDao.kt create mode 100644 app/src/main/java/com/github/libretube/db/obj/PlaylistBookmark.kt create mode 100644 app/src/main/java/com/github/libretube/ui/adapters/PlaylistBookmarkAdapter.kt create mode 100644 app/src/main/java/com/github/libretube/ui/viewholders/PlaylistBookmarkViewHolder.kt create mode 100644 app/src/main/res/drawable/ic_bookmark.xml create mode 100644 app/src/main/res/drawable/ic_bookmark_outlined.xml create mode 100644 app/src/main/res/layout/playlist_bookmark_row.xml diff --git a/app/build.gradle b/app/build.gradle index f65a4f934..3727b2f6b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -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 { diff --git a/app/schemas/com.github.libretube.db.AppDatabase/7.json b/app/schemas/com.github.libretube.db.AppDatabase/7.json new file mode 100644 index 000000000..17bde0ca2 --- /dev/null +++ b/app/schemas/com.github.libretube.db.AppDatabase/7.json @@ -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')" + ] + } +} \ No newline at end of file diff --git a/app/schemas/com.github.libretube.db.AppDatabase/8.json b/app/schemas/com.github.libretube.db.AppDatabase/8.json new file mode 100644 index 000000000..5d8465e8c --- /dev/null +++ b/app/schemas/com.github.libretube.db.AppDatabase/8.json @@ -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')" + ] + } +} \ No newline at end of file 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 88daecd16..f856c9904 100644 --- a/app/src/main/java/com/github/libretube/db/AppDatabase.kt +++ b/app/src/main/java/com/github/libretube/db/AppDatabase.kt @@ -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 } diff --git a/app/src/main/java/com/github/libretube/db/dao/PlaylistBookmarkDao.kt b/app/src/main/java/com/github/libretube/db/dao/PlaylistBookmarkDao.kt new file mode 100644 index 000000000..34df4e295 --- /dev/null +++ b/app/src/main/java/com/github/libretube/db/dao/PlaylistBookmarkDao.kt @@ -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 + + @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() +} diff --git a/app/src/main/java/com/github/libretube/db/obj/PlaylistBookmark.kt b/app/src/main/java/com/github/libretube/db/obj/PlaylistBookmark.kt new file mode 100644 index 000000000..f8b00ee86 --- /dev/null +++ b/app/src/main/java/com/github/libretube/db/obj/PlaylistBookmark.kt @@ -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 +) \ No newline at end of file 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 new file mode 100644 index 000000000..bc0f96388 --- /dev/null +++ b/app/src/main/java/com/github/libretube/ui/adapters/PlaylistBookmarkAdapter.kt @@ -0,0 +1,31 @@ +package com.github.libretube.ui.adapters + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.github.libretube.databinding.PlaylistBookmarkRowBinding +import com.github.libretube.db.obj.PlaylistBookmark +import com.github.libretube.ui.viewholders.PlaylistBookmarkViewHolder +import com.github.libretube.util.ImageHelper + +class PlaylistBookmarksAdapter( + private val bookmarks: List +) : RecyclerView.Adapter() { + 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 + } + } +} \ No newline at end of file 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 eb59bc672..bd8500766 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 @@ -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.PlaylistBookmarksAdapter 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.bookmarksRV, binding.bookmarksRV) + binding.playlistsRV.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) + binding.playlistsRV.adapter = PlaylistBookmarksAdapter(bookmarkedPlaylists) + } + } } private fun runOrError(action: suspend () -> Unit) { 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 1829ca12b..fc69c015d 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 @@ -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,27 @@ class PlaylistFragment : BaseFragment() { ) } - binding.share.setOnClickListener { - ShareDialog( - playlistId!!, - ShareObjectType.PLAYLIST, - ShareData(currentPlaylist = response.name) - ).show(childFragmentManager, null) + binding.bookmark.setOnClickListener { + 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 + ) + ) + } + } + isBookmarked = !isBookmarked + updateBookmarkRes() } playlistAdapter = PlaylistAdapter( diff --git a/app/src/main/java/com/github/libretube/ui/viewholders/PlaylistBookmarkViewHolder.kt b/app/src/main/java/com/github/libretube/ui/viewholders/PlaylistBookmarkViewHolder.kt new file mode 100644 index 000000000..fc768ea6a --- /dev/null +++ b/app/src/main/java/com/github/libretube/ui/viewholders/PlaylistBookmarkViewHolder.kt @@ -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) diff --git a/app/src/main/res/drawable/ic_bookmark.xml b/app/src/main/res/drawable/ic_bookmark.xml new file mode 100644 index 000000000..d32812f77 --- /dev/null +++ b/app/src/main/res/drawable/ic_bookmark.xml @@ -0,0 +1,10 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_bookmark_outlined.xml b/app/src/main/res/drawable/ic_bookmark_outlined.xml new file mode 100644 index 000000000..00c636e83 --- /dev/null +++ b/app/src/main/res/drawable/ic_bookmark_outlined.xml @@ -0,0 +1,10 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index 20216bec7..587f448df 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -59,6 +59,18 @@ + + + + + android:text="@string/bookmark" + app:icon="@drawable/ic_bookmark_outlined" /> diff --git a/app/src/main/res/layout/playlist_bookmark_row.xml b/app/src/main/res/layout/playlist_bookmark_row.xml new file mode 100644 index 000000000..f229af48b --- /dev/null +++ b/app/src/main/res/layout/playlist_bookmark_row.xml @@ -0,0 +1,33 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 40a9c0f3b..62d3231d3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -381,6 +381,9 @@ Trends Featured What\'s trending now + Bookmarks + Bookmark + Download Service Shows a notification when downloading media. From 7e984dd57fd746ec648fefe2309283d0e754b7ee Mon Sep 17 00:00:00 2001 From: Bnyro Date: Fri, 18 Nov 2022 18:28:41 +0100 Subject: [PATCH 2/3] improve the UI --- .../libretube/db/obj/PlaylistBookmark.kt | 2 +- .../ui/adapters/PlaylistBookmarkAdapter.kt | 22 ++++++++++++++-- .../libretube/ui/fragments/HomeFragment.kt | 8 +++--- .../ui/fragments/PlaylistFragment.kt | 6 +++-- app/src/main/res/layout/fragment_home.xml | 2 +- .../main/res/layout/playlist_bookmark_row.xml | 25 +++++++++++-------- 6 files changed, 45 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/com/github/libretube/db/obj/PlaylistBookmark.kt b/app/src/main/java/com/github/libretube/db/obj/PlaylistBookmark.kt index f8b00ee86..fa7280580 100644 --- a/app/src/main/java/com/github/libretube/db/obj/PlaylistBookmark.kt +++ b/app/src/main/java/com/github/libretube/db/obj/PlaylistBookmark.kt @@ -13,4 +13,4 @@ data class PlaylistBookmark( var uploader: String? = null, var uploaderUrl: String? = null, var uploaderAvatar: String? = null -) \ No newline at end of file +) 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 bc0f96388..b93704cc8 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 @@ -2,13 +2,16 @@ 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 PlaylistBookmarksAdapter( +class PlaylistBookmarkAdapter( private val bookmarks: List ) : RecyclerView.Adapter() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PlaylistBookmarkViewHolder { @@ -26,6 +29,21 @@ class PlaylistBookmarksAdapter( 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 + } } } -} \ No newline at end of file +} 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 bd8500766..29c5f75fc 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 @@ -16,7 +16,7 @@ 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.PlaylistBookmarksAdapter +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 @@ -121,9 +121,9 @@ class HomeFragment : BaseFragment() { } if (bookmarkedPlaylists.isEmpty()) return@runOrError runOnUiThread { - makeVisible(binding.bookmarksRV, binding.bookmarksRV) - binding.playlistsRV.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) - binding.playlistsRV.adapter = PlaylistBookmarksAdapter(bookmarkedPlaylists) + makeVisible(binding.bookmarksTV, binding.bookmarksRV) + binding.bookmarksRV.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) + binding.bookmarksRV.adapter = PlaylistBookmarkAdapter(bookmarkedPlaylists) } } } 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 fc69c015d..dd2c2fbe3 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 @@ -130,7 +130,11 @@ class PlaylistFragment : BaseFragment() { ) } + if (isOwner) binding.bookmark.visibility = View.GONE + binding.bookmark.setOnClickListener { + isBookmarked = !isBookmarked + updateBookmarkRes() query { if (isBookmarked) { DatabaseHolder.Database.playlistBookmarkDao().delete( @@ -149,8 +153,6 @@ class PlaylistFragment : BaseFragment() { ) } } - isBookmarked = !isBookmarked - updateBookmarkRes() } playlistAdapter = PlaylistAdapter( diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index 587f448df..fd3979aa2 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -62,7 +62,7 @@ + android:text="@string/bookmarks" /> + android:layout_margin="5dp" + android:background="@drawable/rounded_ripple" + android:orientation="vertical" + android:padding="5dp"> + android:layout_height="wrap_content" + android:layout_marginTop="10dp" + android:ellipsize="end" + android:maxLines="1" + android:textStyle="bold" /> + android:layout_height="wrap_content" + android:ellipsize="end" + android:maxLines="1" + android:textSize="14sp" /> \ No newline at end of file From 3afff16e301bb5d971bc53efbb32c85974358b6c Mon Sep 17 00:00:00 2001 From: Bnyro Date: Fri, 18 Nov 2022 18:30:17 +0100 Subject: [PATCH 3/3] fix removing bookmarks --- .../java/com/github/libretube/ui/fragments/PlaylistFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 dd2c2fbe3..c72388081 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 @@ -136,7 +136,7 @@ class PlaylistFragment : BaseFragment() { isBookmarked = !isBookmarked updateBookmarkRes() query { - if (isBookmarked) { + if (!isBookmarked) { DatabaseHolder.Database.playlistBookmarkDao().delete( DatabaseHolder.Database.playlistBookmarkDao().findById(playlistId!!) )