From 2d80de9f520e67eff307015ac7244fb4ed3de9ea Mon Sep 17 00:00:00 2001 From: Bnyro Date: Tue, 21 Feb 2023 18:28:21 +0100 Subject: [PATCH] Convert watch positions dao to coroutines, fix holes in the feed --- .../libretube/db/dao/WatchPositionDao.kt | 12 ++++---- .../libretube/services/BackgroundMode.kt | 8 ++--- .../libretube/ui/adapters/VideosAdapter.kt | 12 ++------ .../ui/extensions/SetWatchProgressLength.kt | 13 ++++---- .../libretube/ui/fragments/PlayerFragment.kt | 7 ++--- .../ui/fragments/SubscriptionsFragment.kt | 30 +++++++++++++++++-- .../ui/sheets/VideoOptionsBottomSheet.kt | 14 ++------- 7 files changed, 52 insertions(+), 44 deletions(-) diff --git a/app/src/main/java/com/github/libretube/db/dao/WatchPositionDao.kt b/app/src/main/java/com/github/libretube/db/dao/WatchPositionDao.kt index b08f6e2cf..16c37941e 100644 --- a/app/src/main/java/com/github/libretube/db/dao/WatchPositionDao.kt +++ b/app/src/main/java/com/github/libretube/db/dao/WatchPositionDao.kt @@ -10,20 +10,20 @@ import com.github.libretube.db.obj.WatchPosition @Dao interface WatchPositionDao { @Query("SELECT * FROM watchPosition") - fun getAll(): List + suspend fun getAll(): List @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() } diff --git a/app/src/main/java/com/github/libretube/services/BackgroundMode.kt b/app/src/main/java/com/github/libretube/services/BackgroundMode.kt index dd8470fe5..c9cb2b3e4 100644 --- a/app/src/main/java/com/github/libretube/services/BackgroundMode.kt +++ b/app/src/main/java/com/github/libretube/services/BackgroundMode.kt @@ -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 { diff --git a/app/src/main/java/com/github/libretube/ui/adapters/VideosAdapter.kt b/app/src/main/java/com/github/libretube/ui/adapters/VideosAdapter.kt index d205968b4..e385e3d52 100644 --- a/app/src/main/java/com/github/libretube/ui/adapters/VideosAdapter.kt +++ b/app/src/main/java/com/github/libretube/ui/adapters/VideosAdapter.kt @@ -33,8 +33,7 @@ import com.github.libretube.util.TextUtils class VideosAdapter( private val streamItems: MutableList, private val showAllAtOnce: Boolean = true, - private val forceMode: ForceMode = ForceMode.NONE, - private val hideWatched: Boolean = false + private val forceMode: ForceMode = ForceMode.NONE ) : RecyclerView.Adapter() { 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 diff --git a/app/src/main/java/com/github/libretube/ui/extensions/SetWatchProgressLength.kt b/app/src/main/java/com/github/libretube/ui/extensions/SetWatchProgressLength.kt index 7f7487808..acf0bceea 100644 --- a/app/src/main/java/com/github/libretube/ui/extensions/SetWatchProgressLength.kt +++ b/app/src/main/java/com/github/libretube/ui/extensions/SetWatchProgressLength.kt @@ -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 { 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 { matchConstraintPercentWidth = progress / duration.toFloat() } visibility = View.VISIBLE - - return progress / duration.toFloat() > 0.9 } diff --git a/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt index a5a2be9e9..810bf9dd5 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt @@ -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) { diff --git a/app/src/main/java/com/github/libretube/ui/fragments/SubscriptionsFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/SubscriptionsFragment.kt index 046f13da2..97b9fad2e 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/SubscriptionsFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/SubscriptionsFragment.kt @@ -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): List { + 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 diff --git a/app/src/main/java/com/github/libretube/ui/sheets/VideoOptionsBottomSheet.kt b/app/src/main/java/com/github/libretube/ui/sheets/VideoOptionsBottomSheet.kt index b58c81bbe..dbb2ea056 100644 --- a/app/src/main/java/com/github/libretube/ui/sheets/VideoOptionsBottomSheet.kt +++ b/app/src/main/java/com/github/libretube/ui/sheets/VideoOptionsBottomSheet.kt @@ -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 )