mirror of
https://github.com/libre-tube/LibreTube.git
synced 2025-04-29 16:30:31 +05:30
Convert watch positions dao to coroutines, fix holes in the feed
This commit is contained in:
parent
06d6c85b25
commit
2d80de9f52
@ -10,20 +10,20 @@ import com.github.libretube.db.obj.WatchPosition
|
|||||||
@Dao
|
@Dao
|
||||||
interface WatchPositionDao {
|
interface WatchPositionDao {
|
||||||
@Query("SELECT * FROM watchPosition")
|
@Query("SELECT * FROM watchPosition")
|
||||||
fun getAll(): List<WatchPosition>
|
suspend fun getAll(): List<WatchPosition>
|
||||||
|
|
||||||
@Query("SELECT * FROM watchPosition WHERE videoId LIKE :videoId LIMIT 1")
|
@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)
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
fun insertAll(vararg watchPositions: WatchPosition)
|
suspend fun insertAll(vararg watchPositions: WatchPosition)
|
||||||
|
|
||||||
@Delete
|
@Delete
|
||||||
fun delete(watchPosition: WatchPosition)
|
suspend fun delete(watchPosition: WatchPosition)
|
||||||
|
|
||||||
@Query("DELETE FROM watchHistoryItem WHERE videoId = :videoId")
|
@Query("DELETE FROM watchHistoryItem WHERE videoId = :videoId")
|
||||||
fun deleteById(videoId: String)
|
suspend fun deleteById(videoId: String)
|
||||||
|
|
||||||
@Query("DELETE FROM watchPosition")
|
@Query("DELETE FROM watchPosition")
|
||||||
fun deleteAll()
|
suspend fun deleteAll()
|
||||||
}
|
}
|
||||||
|
@ -25,8 +25,6 @@ import com.github.libretube.constants.PLAYER_NOTIFICATION_ID
|
|||||||
import com.github.libretube.db.DatabaseHolder.Database
|
import com.github.libretube.db.DatabaseHolder.Database
|
||||||
import com.github.libretube.db.obj.WatchPosition
|
import com.github.libretube.db.obj.WatchPosition
|
||||||
import com.github.libretube.extensions.TAG
|
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.extensions.toID
|
||||||
import com.github.libretube.helpers.PlayerHelper
|
import com.github.libretube.helpers.PlayerHelper
|
||||||
import com.github.libretube.helpers.PlayerHelper.checkForSegments
|
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.MediaItem
|
||||||
import com.google.android.exoplayer2.PlaybackException
|
import com.google.android.exoplayer2.PlaybackException
|
||||||
import com.google.android.exoplayer2.Player
|
import com.google.android.exoplayer2.Player
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
|
|
||||||
@ -154,7 +154,7 @@ class BackgroundMode : LifecycleService() {
|
|||||||
// indicator that a new video is getting loaded
|
// indicator that a new video is getting loaded
|
||||||
this.streams ?: return@let
|
this.streams ?: return@let
|
||||||
|
|
||||||
query {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
Database.watchPositionDao().insertAll(watchPosition)
|
Database.watchPositionDao().insertAll(watchPosition)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -213,7 +213,7 @@ class BackgroundMode : LifecycleService() {
|
|||||||
player?.seekTo(seekToPosition)
|
player?.seekTo(seekToPosition)
|
||||||
} else if (PlayerHelper.watchPositionsAudio) {
|
} else if (PlayerHelper.watchPositionsAudio) {
|
||||||
runCatching {
|
runCatching {
|
||||||
val watchPosition = awaitQuery {
|
val watchPosition = runBlocking {
|
||||||
Database.watchPositionDao().findById(videoId)
|
Database.watchPositionDao().findById(videoId)
|
||||||
}
|
}
|
||||||
streams?.duration?.let {
|
streams?.duration?.let {
|
||||||
|
@ -33,8 +33,7 @@ import com.github.libretube.util.TextUtils
|
|||||||
class VideosAdapter(
|
class VideosAdapter(
|
||||||
private val streamItems: MutableList<StreamItem>,
|
private val streamItems: MutableList<StreamItem>,
|
||||||
private val showAllAtOnce: Boolean = true,
|
private val showAllAtOnce: Boolean = true,
|
||||||
private val forceMode: ForceMode = ForceMode.NONE,
|
private val forceMode: ForceMode = ForceMode.NONE
|
||||||
private val hideWatched: Boolean = false
|
|
||||||
) : RecyclerView.Adapter<VideosViewHolder>() {
|
) : RecyclerView.Adapter<VideosViewHolder>() {
|
||||||
|
|
||||||
private var visibleCount = minOf(10, streamItems.size)
|
private var visibleCount = minOf(10, streamItems.size)
|
||||||
@ -116,13 +115,8 @@ class VideosAdapter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
videoId?.let {
|
videoId?.let {
|
||||||
val shouldHide =
|
|
||||||
(holder.trendingRowBinding?.watchProgress ?: holder.videoRowBinding!!.watchProgress)
|
(holder.trendingRowBinding?.watchProgress ?: holder.videoRowBinding!!.watchProgress)
|
||||||
.setWatchProgressLength(it, video.duration ?: 0L)
|
.setWatchProgressLength(it, video.duration ?: 0L)
|
||||||
if (hideWatched && shouldHide) {
|
|
||||||
hideItemView(holder)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trending layout
|
// Trending layout
|
||||||
|
@ -4,37 +4,34 @@ import android.view.View
|
|||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
import androidx.core.view.updateLayoutParams
|
import androidx.core.view.updateLayoutParams
|
||||||
import com.github.libretube.db.DatabaseHolder.Database
|
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
|
* Shows the already watched time under the video
|
||||||
* @param videoId The id of the video to inspect
|
* @param videoId The id of the video to inspect
|
||||||
* @param duration The duration of the video in seconds
|
* @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> {
|
updateLayoutParams<ConstraintLayout.LayoutParams> {
|
||||||
matchConstraintPercentWidth = 0f
|
matchConstraintPercentWidth = 0f
|
||||||
}
|
}
|
||||||
visibility = View.GONE
|
visibility = View.GONE
|
||||||
|
|
||||||
val progress = try {
|
val progress = try {
|
||||||
awaitQuery {
|
runBlocking {
|
||||||
Database.watchPositionDao().findById(videoId)?.position
|
Database.watchPositionDao().findById(videoId)?.position
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
return false
|
return
|
||||||
} // divide by 1000 to convert ms to seconds
|
} // divide by 1000 to convert ms to seconds
|
||||||
?.toFloat()?.div(1000)
|
?.toFloat()?.div(1000)
|
||||||
|
|
||||||
if (progress == null || duration == 0L) {
|
if (progress == null || duration == 0L) {
|
||||||
return false
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
updateLayoutParams<ConstraintLayout.LayoutParams> {
|
updateLayoutParams<ConstraintLayout.LayoutParams> {
|
||||||
matchConstraintPercentWidth = progress / duration.toFloat()
|
matchConstraintPercentWidth = progress / duration.toFloat()
|
||||||
}
|
}
|
||||||
visibility = View.VISIBLE
|
visibility = View.VISIBLE
|
||||||
|
|
||||||
return progress / duration.toFloat() > 0.9
|
|
||||||
}
|
}
|
||||||
|
@ -56,10 +56,8 @@ import com.github.libretube.db.DatabaseHolder.Database
|
|||||||
import com.github.libretube.db.obj.WatchPosition
|
import com.github.libretube.db.obj.WatchPosition
|
||||||
import com.github.libretube.enums.PlayerEvent
|
import com.github.libretube.enums.PlayerEvent
|
||||||
import com.github.libretube.enums.ShareObjectType
|
import com.github.libretube.enums.ShareObjectType
|
||||||
import com.github.libretube.extensions.awaitQuery
|
|
||||||
import com.github.libretube.extensions.formatShort
|
import com.github.libretube.extensions.formatShort
|
||||||
import com.github.libretube.extensions.hideKeyboard
|
import com.github.libretube.extensions.hideKeyboard
|
||||||
import com.github.libretube.extensions.query
|
|
||||||
import com.github.libretube.extensions.toID
|
import com.github.libretube.extensions.toID
|
||||||
import com.github.libretube.extensions.updateParameters
|
import com.github.libretube.extensions.updateParameters
|
||||||
import com.github.libretube.helpers.BackgroundHelper
|
import com.github.libretube.helpers.BackgroundHelper
|
||||||
@ -114,6 +112,7 @@ import kotlin.math.abs
|
|||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import kotlinx.serialization.decodeFromString
|
import kotlinx.serialization.decodeFromString
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
@ -609,7 +608,7 @@ class PlayerFragment : Fragment(R.layout.fragment_player), OnlinePlayerOptions {
|
|||||||
private fun saveWatchPosition() {
|
private fun saveWatchPosition() {
|
||||||
if (!PlayerHelper.watchPositionsVideo) return
|
if (!PlayerHelper.watchPositionsVideo) return
|
||||||
val watchPosition = WatchPosition(videoId!!, exoPlayer.currentPosition)
|
val watchPosition = WatchPosition(videoId!!, exoPlayer.currentPosition)
|
||||||
query {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
Database.watchPositionDao().insertAll(watchPosition)
|
Database.watchPositionDao().insertAll(watchPosition)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -765,7 +764,7 @@ class PlayerFragment : Fragment(R.layout.fragment_player), OnlinePlayerOptions {
|
|||||||
private fun seekToWatchPosition() {
|
private fun seekToWatchPosition() {
|
||||||
// browse the watch positions
|
// browse the watch positions
|
||||||
val position = try {
|
val position = try {
|
||||||
awaitQuery {
|
runBlocking {
|
||||||
Database.watchPositionDao().findById(videoId!!)?.position
|
Database.watchPositionDao().findById(videoId!!)?.position
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
@ -13,6 +13,8 @@ import com.github.libretube.R
|
|||||||
import com.github.libretube.api.obj.StreamItem
|
import com.github.libretube.api.obj.StreamItem
|
||||||
import com.github.libretube.constants.PreferenceKeys
|
import com.github.libretube.constants.PreferenceKeys
|
||||||
import com.github.libretube.databinding.FragmentSubscriptionsBinding
|
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.helpers.PreferenceHelper
|
||||||
import com.github.libretube.ui.adapters.LegacySubscriptionAdapter
|
import com.github.libretube.ui.adapters.LegacySubscriptionAdapter
|
||||||
import com.github.libretube.ui.adapters.SubscriptionChannelAdapter
|
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.base.BaseFragment
|
||||||
import com.github.libretube.ui.models.SubscriptionsViewModel
|
import com.github.libretube.ui.models.SubscriptionsViewModel
|
||||||
import com.github.libretube.ui.sheets.BaseBottomSheet
|
import com.github.libretube.ui.sheets.BaseBottomSheet
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
|
||||||
class SubscriptionsFragment : BaseFragment() {
|
class SubscriptionsFragment : BaseFragment() {
|
||||||
private lateinit var binding: FragmentSubscriptionsBinding
|
private lateinit var binding: FragmentSubscriptionsBinding
|
||||||
@ -159,7 +163,16 @@ class SubscriptionsFragment : BaseFragment() {
|
|||||||
2 -> it.isShort
|
2 -> it.isShort
|
||||||
else -> throw IllegalArgumentException()
|
else -> throw IllegalArgumentException()
|
||||||
}
|
}
|
||||||
|
}.let { streams ->
|
||||||
|
runBlocking {
|
||||||
|
if (!PreferenceHelper.getBoolean(PreferenceKeys.HIDE_WATCHED_FROM_FEED, false)) {
|
||||||
|
streams
|
||||||
|
} else {
|
||||||
|
removeWatchVideosFromFeed(streams)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// sort the feed
|
// sort the feed
|
||||||
val sortedFeed = when (selectedSortOrder) {
|
val sortedFeed = when (selectedSortOrder) {
|
||||||
0 -> feed
|
0 -> feed
|
||||||
@ -191,14 +204,27 @@ class SubscriptionsFragment : BaseFragment() {
|
|||||||
binding.subProgress.visibility = View.GONE
|
binding.subProgress.visibility = View.GONE
|
||||||
subscriptionsAdapter = VideosAdapter(
|
subscriptionsAdapter = VideosAdapter(
|
||||||
sortedFeed.toMutableList(),
|
sortedFeed.toMutableList(),
|
||||||
showAllAtOnce = false,
|
showAllAtOnce = false
|
||||||
hideWatched = PreferenceHelper.getBoolean(PreferenceKeys.HIDE_WATCHED_FROM_FEED, false)
|
|
||||||
)
|
)
|
||||||
binding.subFeed.adapter = subscriptionsAdapter
|
binding.subFeed.adapter = subscriptionsAdapter
|
||||||
|
|
||||||
PreferenceHelper.updateLastFeedWatchedTime()
|
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() {
|
private fun showSubscriptions() {
|
||||||
if (viewModel.subscriptions.value == null) return
|
if (viewModel.subscriptions.value == null) return
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package com.github.libretube.ui.sheets
|
package com.github.libretube.ui.sheets
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
|
||||||
import androidx.navigation.fragment.NavHostFragment
|
import androidx.navigation.fragment.NavHostFragment
|
||||||
import com.github.libretube.R
|
import com.github.libretube.R
|
||||||
import com.github.libretube.api.RetrofitInstance
|
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.DatabaseHolder
|
||||||
import com.github.libretube.db.obj.WatchPosition
|
import com.github.libretube.db.obj.WatchPosition
|
||||||
import com.github.libretube.enums.ShareObjectType
|
import com.github.libretube.enums.ShareObjectType
|
||||||
import com.github.libretube.extensions.awaitQuery
|
|
||||||
import com.github.libretube.helpers.BackgroundHelper
|
import com.github.libretube.helpers.BackgroundHelper
|
||||||
import com.github.libretube.helpers.PlayerHelper
|
import com.github.libretube.helpers.PlayerHelper
|
||||||
import com.github.libretube.helpers.PreferenceHelper
|
import com.github.libretube.helpers.PreferenceHelper
|
||||||
@ -102,22 +100,16 @@ class VideoOptionsBottomSheet(
|
|||||||
}
|
}
|
||||||
getString(R.string.mark_as_watched) -> {
|
getString(R.string.mark_as_watched) -> {
|
||||||
val watchPosition = WatchPosition(videoId, Long.MAX_VALUE)
|
val watchPosition = WatchPosition(videoId, Long.MAX_VALUE)
|
||||||
awaitQuery {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
DatabaseHolder.Database.watchPositionDao().insertAll(watchPosition)
|
DatabaseHolder.Database.watchPositionDao().insertAll(watchPosition)
|
||||||
}
|
}
|
||||||
if (PreferenceHelper.getBoolean(PreferenceKeys.HIDE_WATCHED_FROM_FEED, false)) {
|
if (PreferenceHelper.getBoolean(PreferenceKeys.HIDE_WATCHED_FROM_FEED, false)) {
|
||||||
// get the host fragment containing the current fragment
|
// get the host fragment containing the current fragment
|
||||||
val navHostFragment =
|
val navHostFragment =
|
||||||
(context as MainActivity).supportFragmentManager.findFragmentById(
|
(context as MainActivity).supportFragmentManager
|
||||||
R.id.fragment
|
.findFragmentById(R.id.fragment) as NavHostFragment?
|
||||||
) as NavHostFragment?
|
|
||||||
// get the current fragment
|
// get the current fragment
|
||||||
val fragment = navHostFragment?.childFragmentManager?.fragments?.firstOrNull()
|
val fragment = navHostFragment?.childFragmentManager?.fragments?.firstOrNull()
|
||||||
Log.e(
|
|
||||||
"fragments",
|
|
||||||
navHostFragment?.childFragmentManager?.fragments.orEmpty()
|
|
||||||
.joinToString(", ") { it::class.java.name.toString() }
|
|
||||||
)
|
|
||||||
(fragment as? SubscriptionsFragment)?.subscriptionsAdapter?.removeItemById(
|
(fragment as? SubscriptionsFragment)?.subscriptionsAdapter?.removeItemById(
|
||||||
videoId
|
videoId
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user