mirror of
https://github.com/libre-tube/LibreTube.git
synced 2025-04-28 16:00:31 +05:30
feat: watch history pagination
This commit is contained in:
parent
0c39a25a4c
commit
6970bf6ee2
@ -46,12 +46,27 @@ object DatabaseHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// delete the first watch history entry if the limit is reached
|
// delete the first watch history entry if the limit is reached
|
||||||
val watchHistory = Database.watchHistoryDao().getAll()
|
val historySize = Database.watchHistoryDao().getSize()
|
||||||
if (watchHistory.size > maxHistorySize.toInt()) {
|
if (historySize > maxHistorySize.toInt()) {
|
||||||
Database.watchHistoryDao().delete(watchHistory.first())
|
Database.watchHistoryDao().delete(Database.watchHistoryDao().getOldest())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun getWatchHistoryPage(page: Int, pageSize: Int): List<WatchHistoryItem> {
|
||||||
|
val watchHistoryDao = Database.watchHistoryDao()
|
||||||
|
val historySize = watchHistoryDao.getSize()
|
||||||
|
|
||||||
|
if (historySize < pageSize * (page-1)) return emptyList()
|
||||||
|
|
||||||
|
val offset = historySize - (pageSize * page)
|
||||||
|
val limit = if (offset < 0) {
|
||||||
|
offset + pageSize
|
||||||
|
} else {
|
||||||
|
pageSize
|
||||||
|
}
|
||||||
|
return watchHistoryDao.getN(limit, maxOf(offset, 0)).reversed()
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun addToSearchHistory(searchHistoryItem: SearchHistoryItem) {
|
suspend fun addToSearchHistory(searchHistoryItem: SearchHistoryItem) {
|
||||||
Database.searchHistoryDao().insert(searchHistoryItem)
|
Database.searchHistoryDao().insert(searchHistoryItem)
|
||||||
|
|
||||||
|
@ -12,6 +12,12 @@ interface WatchHistoryDao {
|
|||||||
@Query("SELECT * FROM watchHistoryItem")
|
@Query("SELECT * FROM watchHistoryItem")
|
||||||
suspend fun getAll(): List<WatchHistoryItem>
|
suspend fun getAll(): List<WatchHistoryItem>
|
||||||
|
|
||||||
|
@Query("SELECT * FROM watchHistoryItem LIMIT :limit OFFSET :offset")
|
||||||
|
suspend fun getN(limit: Int, offset: Int): List<WatchHistoryItem>
|
||||||
|
|
||||||
|
@Query("SELECT COUNT(videoId) FROM watchHistoryItem")
|
||||||
|
suspend fun getSize(): Int
|
||||||
|
|
||||||
@Query("SELECT * FROM watchHistoryItem WHERE videoId LIKE :videoId LIMIT 1")
|
@Query("SELECT * FROM watchHistoryItem WHERE videoId LIKE :videoId LIMIT 1")
|
||||||
suspend fun findById(videoId: String): WatchHistoryItem?
|
suspend fun findById(videoId: String): WatchHistoryItem?
|
||||||
|
|
||||||
@ -24,6 +30,9 @@ interface WatchHistoryDao {
|
|||||||
@Delete
|
@Delete
|
||||||
suspend fun delete(watchHistoryItem: WatchHistoryItem)
|
suspend fun delete(watchHistoryItem: WatchHistoryItem)
|
||||||
|
|
||||||
|
@Query("SELECT * FROM watchHistoryItem LIMIT 1 OFFSET 0")
|
||||||
|
suspend fun getOldest(): WatchHistoryItem
|
||||||
|
|
||||||
@Query("DELETE FROM watchHistoryItem WHERE videoId = :id")
|
@Query("DELETE FROM watchHistoryItem WHERE videoId = :id")
|
||||||
suspend fun deleteByVideoId(id: String)
|
suspend fun deleteByVideoId(id: String)
|
||||||
|
|
||||||
|
@ -24,9 +24,7 @@ class WatchHistoryAdapter(
|
|||||||
) :
|
) :
|
||||||
RecyclerView.Adapter<WatchHistoryViewHolder>() {
|
RecyclerView.Adapter<WatchHistoryViewHolder>() {
|
||||||
|
|
||||||
private var visibleCount = minOf(10, watchHistory.size)
|
override fun getItemCount() = watchHistory.size
|
||||||
|
|
||||||
override fun getItemCount() = visibleCount
|
|
||||||
|
|
||||||
fun removeFromWatchHistory(position: Int) {
|
fun removeFromWatchHistory(position: Int) {
|
||||||
val history = watchHistory[position]
|
val history = watchHistory[position]
|
||||||
@ -34,16 +32,14 @@ class WatchHistoryAdapter(
|
|||||||
DatabaseHolder.Database.watchHistoryDao().delete(history)
|
DatabaseHolder.Database.watchHistoryDao().delete(history)
|
||||||
}
|
}
|
||||||
watchHistory.removeAt(position)
|
watchHistory.removeAt(position)
|
||||||
visibleCount--
|
|
||||||
notifyItemRemoved(position)
|
notifyItemRemoved(position)
|
||||||
notifyItemRangeChanged(position, itemCount)
|
notifyItemRangeChanged(position, itemCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun showMoreItems() {
|
fun insertItems(items: List<WatchHistoryItem>) {
|
||||||
val oldSize = visibleCount
|
val oldSize = itemCount
|
||||||
visibleCount += minOf(10, watchHistory.size - oldSize)
|
this.watchHistory.addAll(items)
|
||||||
if (visibleCount == oldSize) return
|
notifyItemRangeInserted(oldSize, itemCount)
|
||||||
notifyItemRangeInserted(oldSize, visibleCount)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WatchHistoryViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WatchHistoryViewHolder {
|
||||||
|
@ -40,6 +40,8 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
|||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import kotlin.math.ceil
|
||||||
|
|
||||||
class WatchHistoryFragment : DynamicLayoutManagerFragment() {
|
class WatchHistoryFragment : DynamicLayoutManagerFragment() {
|
||||||
private var _binding: FragmentWatchHistoryBinding? = null
|
private var _binding: FragmentWatchHistoryBinding? = null
|
||||||
@ -88,11 +90,12 @@ class WatchHistoryFragment : DynamicLayoutManagerFragment() {
|
|||||||
_binding?.watchHistoryRecView?.updatePadding(bottom = if (it) 64f.dpToPx() else 0)
|
_binding?.watchHistoryRecView?.updatePadding(bottom = if (it) 64f.dpToPx() else 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
val allHistory = runBlocking(Dispatchers.IO) {
|
lifecycleScope.launch {
|
||||||
Database.watchHistoryDao().getAll().reversed()
|
val history = withContext(Dispatchers.IO) {
|
||||||
|
DatabaseHelper.getWatchHistoryPage(1, HISTORY_PAGE_SIZE)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allHistory.isEmpty()) return
|
if (history.isEmpty()) return@launch
|
||||||
|
|
||||||
binding.filterTypeTV.text =
|
binding.filterTypeTV.text =
|
||||||
resources.getStringArray(R.array.filterOptions)[selectedTypeFilter]
|
resources.getStringArray(R.array.filterOptions)[selectedTypeFilter]
|
||||||
@ -129,7 +132,7 @@ class WatchHistoryFragment : DynamicLayoutManagerFragment() {
|
|||||||
setSimpleItems(filterOptions.toList()) { index ->
|
setSimpleItems(filterOptions.toList()) { index ->
|
||||||
binding.filterTypeTV.text = filterOptions[index]
|
binding.filterTypeTV.text = filterOptions[index]
|
||||||
selectedTypeFilter = index
|
selectedTypeFilter = index
|
||||||
showWatchHistory(allHistory)
|
showWatchHistory(history)
|
||||||
}
|
}
|
||||||
}.show(childFragmentManager)
|
}.show(childFragmentManager)
|
||||||
}
|
}
|
||||||
@ -141,7 +144,7 @@ class WatchHistoryFragment : DynamicLayoutManagerFragment() {
|
|||||||
setSimpleItems(filterOptions.toList()) { index ->
|
setSimpleItems(filterOptions.toList()) { index ->
|
||||||
binding.filterStatusTV.text = filterOptions[index]
|
binding.filterStatusTV.text = filterOptions[index]
|
||||||
selectedStatusFilter = index
|
selectedStatusFilter = index
|
||||||
showWatchHistory(allHistory)
|
showWatchHistory(history)
|
||||||
}
|
}
|
||||||
}.show(childFragmentManager)
|
}.show(childFragmentManager)
|
||||||
}
|
}
|
||||||
@ -154,20 +157,19 @@ class WatchHistoryFragment : DynamicLayoutManagerFragment() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
showWatchHistory(allHistory)
|
showWatchHistory(history)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showWatchHistory(allHistory: List<WatchHistoryItem>) {
|
private fun showWatchHistory(history: List<WatchHistoryItem>) {
|
||||||
val watchHistory = allHistory.filterByStatusAndWatchPosition()
|
val watchHistory = history.filterByStatusAndWatchPosition()
|
||||||
|
|
||||||
watchHistory.forEach {
|
watchHistory.forEach {
|
||||||
it.thumbnailUrl = ProxyHelper.rewriteUrl(it.thumbnailUrl)
|
it.thumbnailUrl = ProxyHelper.rewriteUrl(it.thumbnailUrl)
|
||||||
it.uploaderAvatar = ProxyHelper.rewriteUrl(it.uploaderAvatar)
|
it.uploaderAvatar = ProxyHelper.rewriteUrl(it.uploaderAvatar)
|
||||||
}
|
}
|
||||||
|
|
||||||
val watchHistoryAdapter = WatchHistoryAdapter(
|
val watchHistoryAdapter = WatchHistoryAdapter(watchHistory.toMutableList())
|
||||||
watchHistory.toMutableList()
|
|
||||||
)
|
|
||||||
|
|
||||||
binding.playAll.setOnClickListener {
|
binding.playAll.setOnClickListener {
|
||||||
PlayingQueue.resetToDefaults()
|
PlayingQueue.resetToDefaults()
|
||||||
@ -234,13 +236,20 @@ class WatchHistoryFragment : DynamicLayoutManagerFragment() {
|
|||||||
|
|
||||||
binding.watchHistoryRecView.addOnBottomReachedListener {
|
binding.watchHistoryRecView.addOnBottomReachedListener {
|
||||||
if (isLoading) return@addOnBottomReachedListener
|
if (isLoading) return@addOnBottomReachedListener
|
||||||
|
|
||||||
isLoading = true
|
isLoading = true
|
||||||
watchHistoryAdapter.showMoreItems()
|
|
||||||
|
lifecycleScope.launch {
|
||||||
|
val newHistory = withContext(Dispatchers.IO) {
|
||||||
|
val currentPage = ceil(watchHistoryAdapter.itemCount.toFloat() / HISTORY_PAGE_SIZE).toInt()
|
||||||
|
DatabaseHelper.getWatchHistoryPage( currentPage + 1, HISTORY_PAGE_SIZE)
|
||||||
|
}.filterByStatusAndWatchPosition()
|
||||||
|
|
||||||
|
watchHistoryAdapter.insertItems(newHistory)
|
||||||
isLoading = false
|
isLoading = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun List<WatchHistoryItem>.filterByStatusAndWatchPosition(): List<WatchHistoryItem> {
|
private fun List<WatchHistoryItem>.filterByStatusAndWatchPosition(): List<WatchHistoryItem> {
|
||||||
val watchHistoryItem = this.filter {
|
val watchHistoryItem = this.filter {
|
||||||
@ -277,4 +286,8 @@ class WatchHistoryFragment : DynamicLayoutManagerFragment() {
|
|||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
_binding = null
|
_binding = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val HISTORY_PAGE_SIZE = 10
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,10 +112,10 @@ class HomeViewModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun loadWatchingFromDB(): List<StreamItem> {
|
private suspend fun loadWatchingFromDB(): List<StreamItem> {
|
||||||
val videos = DatabaseHolder.Database.watchHistoryDao().getAll()
|
val videos = DatabaseHelper.getWatchHistoryPage(1, 50)
|
||||||
|
|
||||||
return DatabaseHelper
|
return DatabaseHelper
|
||||||
.filterUnwatched(videos.map { it.toStreamItem() })
|
.filterUnwatched(videos.map { it.toStreamItem() })
|
||||||
.reversed()
|
|
||||||
.take(20)
|
.take(20)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user