Convert watch positions dao to coroutines, fix holes in the feed

This commit is contained in:
Bnyro 2023-02-21 18:28:21 +01:00
parent 06d6c85b25
commit 2d80de9f52
7 changed files with 52 additions and 44 deletions

View File

@ -10,20 +10,20 @@ import com.github.libretube.db.obj.WatchPosition
@Dao
interface WatchPositionDao {
@Query("SELECT * FROM watchPosition")
fun getAll(): List<WatchPosition>
suspend fun getAll(): List<WatchPosition>
@Query("SELECT * FROM watchPosition WHERE videoId LIKE :videoId LIMIT 1")
fun findById(videoId: String): WatchPosition?
suspend fun findById(videoId: String): WatchPosition?
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAll(vararg watchPositions: WatchPosition)
suspend fun insertAll(vararg watchPositions: WatchPosition)
@Delete
fun delete(watchPosition: WatchPosition)
suspend fun delete(watchPosition: WatchPosition)
@Query("DELETE FROM watchHistoryItem WHERE videoId = :videoId")
fun deleteById(videoId: String)
suspend fun deleteById(videoId: String)
@Query("DELETE FROM watchPosition")
fun deleteAll()
suspend fun deleteAll()
}

View File

@ -25,8 +25,6 @@ import com.github.libretube.constants.PLAYER_NOTIFICATION_ID
import com.github.libretube.db.DatabaseHolder.Database
import com.github.libretube.db.obj.WatchPosition
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.helpers.PlayerHelper
import com.github.libretube.helpers.PlayerHelper.checkForSegments
@ -37,8 +35,10 @@ import com.google.android.exoplayer2.ExoPlayer
import com.google.android.exoplayer2.MediaItem
import com.google.android.exoplayer2.PlaybackException
import com.google.android.exoplayer2.Player
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import kotlinx.serialization.encodeToString
@ -154,7 +154,7 @@ class BackgroundMode : LifecycleService() {
// indicator that a new video is getting loaded
this.streams ?: return@let
query {
CoroutineScope(Dispatchers.IO).launch {
Database.watchPositionDao().insertAll(watchPosition)
}
}
@ -213,7 +213,7 @@ class BackgroundMode : LifecycleService() {
player?.seekTo(seekToPosition)
} else if (PlayerHelper.watchPositionsAudio) {
runCatching {
val watchPosition = awaitQuery {
val watchPosition = runBlocking {
Database.watchPositionDao().findById(videoId)
}
streams?.duration?.let {

View File

@ -33,8 +33,7 @@ import com.github.libretube.util.TextUtils
class VideosAdapter(
private val streamItems: MutableList<StreamItem>,
private val showAllAtOnce: Boolean = true,
private val forceMode: ForceMode = ForceMode.NONE,
private val hideWatched: Boolean = false
private val forceMode: ForceMode = ForceMode.NONE
) : RecyclerView.Adapter<VideosViewHolder>() {
private var visibleCount = minOf(10, streamItems.size)
@ -116,13 +115,8 @@ class VideosAdapter(
}
videoId?.let {
val shouldHide =
(holder.trendingRowBinding?.watchProgress ?: holder.videoRowBinding!!.watchProgress)
.setWatchProgressLength(it, video.duration ?: 0L)
if (hideWatched && shouldHide) {
hideItemView(holder)
return
}
(holder.trendingRowBinding?.watchProgress ?: holder.videoRowBinding!!.watchProgress)
.setWatchProgressLength(it, video.duration ?: 0L)
}
// Trending layout

View File

@ -4,37 +4,34 @@ import android.view.View
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.updateLayoutParams
import com.github.libretube.db.DatabaseHolder.Database
import com.github.libretube.extensions.awaitQuery
import kotlinx.coroutines.runBlocking
/**
* Shows the already watched time under the video
* @param videoId The id of the video to inspect
* @param duration The duration of the video in seconds
* @return Whether the video is already watched more than 90%
*/
fun View.setWatchProgressLength(videoId: String, duration: Long): Boolean {
fun View.setWatchProgressLength(videoId: String, duration: Long) {
updateLayoutParams<ConstraintLayout.LayoutParams> {
matchConstraintPercentWidth = 0f
}
visibility = View.GONE
val progress = try {
awaitQuery {
runBlocking {
Database.watchPositionDao().findById(videoId)?.position
}
} catch (e: Exception) {
return false
return
} // divide by 1000 to convert ms to seconds
?.toFloat()?.div(1000)
if (progress == null || duration == 0L) {
return false
return
}
updateLayoutParams<ConstraintLayout.LayoutParams> {
matchConstraintPercentWidth = progress / duration.toFloat()
}
visibility = View.VISIBLE
return progress / duration.toFloat() > 0.9
}

View File

@ -56,10 +56,8 @@ import com.github.libretube.db.DatabaseHolder.Database
import com.github.libretube.db.obj.WatchPosition
import com.github.libretube.enums.PlayerEvent
import com.github.libretube.enums.ShareObjectType
import com.github.libretube.extensions.awaitQuery
import com.github.libretube.extensions.formatShort
import com.github.libretube.extensions.hideKeyboard
import com.github.libretube.extensions.query
import com.github.libretube.extensions.toID
import com.github.libretube.extensions.updateParameters
import com.github.libretube.helpers.BackgroundHelper
@ -114,6 +112,7 @@ import kotlin.math.abs
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
@ -609,7 +608,7 @@ class PlayerFragment : Fragment(R.layout.fragment_player), OnlinePlayerOptions {
private fun saveWatchPosition() {
if (!PlayerHelper.watchPositionsVideo) return
val watchPosition = WatchPosition(videoId!!, exoPlayer.currentPosition)
query {
CoroutineScope(Dispatchers.IO).launch {
Database.watchPositionDao().insertAll(watchPosition)
}
}
@ -765,7 +764,7 @@ class PlayerFragment : Fragment(R.layout.fragment_player), OnlinePlayerOptions {
private fun seekToWatchPosition() {
// browse the watch positions
val position = try {
awaitQuery {
runBlocking {
Database.watchPositionDao().findById(videoId!!)?.position
}
} catch (e: Exception) {

View File

@ -13,6 +13,8 @@ import com.github.libretube.R
import com.github.libretube.api.obj.StreamItem
import com.github.libretube.constants.PreferenceKeys
import com.github.libretube.databinding.FragmentSubscriptionsBinding
import com.github.libretube.db.DatabaseHolder
import com.github.libretube.extensions.toID
import com.github.libretube.helpers.PreferenceHelper
import com.github.libretube.ui.adapters.LegacySubscriptionAdapter
import com.github.libretube.ui.adapters.SubscriptionChannelAdapter
@ -20,6 +22,8 @@ import com.github.libretube.ui.adapters.VideosAdapter
import com.github.libretube.ui.base.BaseFragment
import com.github.libretube.ui.models.SubscriptionsViewModel
import com.github.libretube.ui.sheets.BaseBottomSheet
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
class SubscriptionsFragment : BaseFragment() {
private lateinit var binding: FragmentSubscriptionsBinding
@ -159,7 +163,16 @@ class SubscriptionsFragment : BaseFragment() {
2 -> it.isShort
else -> throw IllegalArgumentException()
}
}.let { streams ->
runBlocking {
if (!PreferenceHelper.getBoolean(PreferenceKeys.HIDE_WATCHED_FROM_FEED, false)) {
streams
} else {
removeWatchVideosFromFeed(streams)
}
}
}
// sort the feed
val sortedFeed = when (selectedSortOrder) {
0 -> feed
@ -191,14 +204,27 @@ class SubscriptionsFragment : BaseFragment() {
binding.subProgress.visibility = View.GONE
subscriptionsAdapter = VideosAdapter(
sortedFeed.toMutableList(),
showAllAtOnce = false,
hideWatched = PreferenceHelper.getBoolean(PreferenceKeys.HIDE_WATCHED_FROM_FEED, false)
showAllAtOnce = false
)
binding.subFeed.adapter = subscriptionsAdapter
PreferenceHelper.updateLastFeedWatchedTime()
}
private fun removeWatchVideosFromFeed(streams: List<StreamItem>): List<StreamItem> {
return runBlocking {
streams.filter {
runBlocking(Dispatchers.IO) {
runCatching {
val watchPosition = DatabaseHolder.Database.watchPositionDao()
.findById(it.url.orEmpty().toID())?.position?.div(1000)
(watchPosition ?: 0) < 0.9 * (it.duration ?: 1L)
}.getOrDefault(false)
}
}
}
}
private fun showSubscriptions() {
if (viewModel.subscriptions.value == null) return

View File

@ -1,7 +1,6 @@
package com.github.libretube.ui.sheets
import android.os.Bundle
import android.util.Log
import androidx.navigation.fragment.NavHostFragment
import com.github.libretube.R
import com.github.libretube.api.RetrofitInstance
@ -9,7 +8,6 @@ import com.github.libretube.constants.PreferenceKeys
import com.github.libretube.db.DatabaseHolder
import com.github.libretube.db.obj.WatchPosition
import com.github.libretube.enums.ShareObjectType
import com.github.libretube.extensions.awaitQuery
import com.github.libretube.helpers.BackgroundHelper
import com.github.libretube.helpers.PlayerHelper
import com.github.libretube.helpers.PreferenceHelper
@ -102,22 +100,16 @@ class VideoOptionsBottomSheet(
}
getString(R.string.mark_as_watched) -> {
val watchPosition = WatchPosition(videoId, Long.MAX_VALUE)
awaitQuery {
CoroutineScope(Dispatchers.IO).launch {
DatabaseHolder.Database.watchPositionDao().insertAll(watchPosition)
}
if (PreferenceHelper.getBoolean(PreferenceKeys.HIDE_WATCHED_FROM_FEED, false)) {
// get the host fragment containing the current fragment
val navHostFragment =
(context as MainActivity).supportFragmentManager.findFragmentById(
R.id.fragment
) as NavHostFragment?
(context as MainActivity).supportFragmentManager
.findFragmentById(R.id.fragment) as NavHostFragment?
// get the current fragment
val fragment = navHostFragment?.childFragmentManager?.fragments?.firstOrNull()
Log.e(
"fragments",
navHostFragment?.childFragmentManager?.fragments.orEmpty()
.joinToString(", ") { it::class.java.name.toString() }
)
(fragment as? SubscriptionsFragment)?.subscriptionsAdapter?.removeItemById(
videoId
)