From 8a3ea3b6951454c9c0720b718cc67cffe87cc2ed Mon Sep 17 00:00:00 2001 From: Bnyro Date: Thu, 9 Jan 2025 15:48:43 +0100 Subject: [PATCH] feat: add badge for downloaded videos --- .../github/libretube/db/dao/DownloadDao.kt | 3 ++ .../libretube/ui/adapters/PlaylistAdapter.kt | 11 ++++++++ .../ui/adapters/SearchResultsAdapter.kt | 15 ++++++++++ .../libretube/ui/adapters/VideosAdapter.kt | 28 +++++++++++++------ .../ui/adapters/WatchHistoryAdapter.kt | 13 +++++++++ .../main/res/drawable/ic_download_folder.xml | 10 +++++++ app/src/main/res/layout/video_row.xml | 16 +++++++++-- 7 files changed, 86 insertions(+), 10 deletions(-) create mode 100644 app/src/main/res/drawable/ic_download_folder.xml diff --git a/app/src/main/java/com/github/libretube/db/dao/DownloadDao.kt b/app/src/main/java/com/github/libretube/db/dao/DownloadDao.kt index f60448a43..ab4fdb75f 100644 --- a/app/src/main/java/com/github/libretube/db/dao/DownloadDao.kt +++ b/app/src/main/java/com/github/libretube/db/dao/DownloadDao.kt @@ -23,6 +23,9 @@ interface DownloadDao { @Query("SELECT * FROM download WHERE videoId = :videoId") suspend fun findById(videoId: String): DownloadWithItems? + @Query("SELECT EXISTS (SELECT * FROM download WHERE videoId = :videoId)") + suspend fun exists(videoId: String): Boolean + @Query("SELECT videoId FROM downloadItem WHERE type = :fileType ORDER BY RANDOM() LIMIT 1") suspend fun getRandomVideoIdByFileType(fileType: FileType): String? diff --git a/app/src/main/java/com/github/libretube/ui/adapters/PlaylistAdapter.kt b/app/src/main/java/com/github/libretube/ui/adapters/PlaylistAdapter.kt index 7581bbad8..5d20a9084 100644 --- a/app/src/main/java/com/github/libretube/ui/adapters/PlaylistAdapter.kt +++ b/app/src/main/java/com/github/libretube/ui/adapters/PlaylistAdapter.kt @@ -8,6 +8,7 @@ import android.view.View import android.view.ViewGroup import androidx.core.os.bundleOf import androidx.core.view.isGone +import androidx.core.view.isVisible import androidx.core.view.updatePadding import androidx.recyclerview.widget.RecyclerView import com.github.libretube.R @@ -15,6 +16,7 @@ import com.github.libretube.api.PlaylistsHelper import com.github.libretube.api.obj.StreamItem import com.github.libretube.constants.IntentData import com.github.libretube.databinding.VideoRowBinding +import com.github.libretube.db.DatabaseHolder import com.github.libretube.enums.PlaylistType import com.github.libretube.extensions.TAG import com.github.libretube.extensions.dpToPx @@ -118,6 +120,15 @@ class PlaylistAdapter( } streamItem.duration?.let { watchProgress.setWatchProgressLength(videoId, it) } + + CoroutineScope(Dispatchers.IO).launch { + val isDownloaded = + DatabaseHolder.Database.downloadDao().exists(videoId) + + withContext(Dispatchers.Main) { + downloadBadge.isVisible = isDownloaded + } + } } } diff --git a/app/src/main/java/com/github/libretube/ui/adapters/SearchResultsAdapter.kt b/app/src/main/java/com/github/libretube/ui/adapters/SearchResultsAdapter.kt index 7fb0f0e1b..45785b017 100644 --- a/app/src/main/java/com/github/libretube/ui/adapters/SearchResultsAdapter.kt +++ b/app/src/main/java/com/github/libretube/ui/adapters/SearchResultsAdapter.kt @@ -3,6 +3,7 @@ package com.github.libretube.ui.adapters import android.view.LayoutInflater import android.view.ViewGroup import androidx.core.os.bundleOf +import androidx.core.view.isVisible import androidx.paging.PagingDataAdapter import com.github.libretube.R import com.github.libretube.api.JsonHelper @@ -12,6 +13,7 @@ import com.github.libretube.constants.IntentData import com.github.libretube.databinding.ChannelRowBinding import com.github.libretube.databinding.PlaylistsRowBinding import com.github.libretube.databinding.VideoRowBinding +import com.github.libretube.db.DatabaseHolder import com.github.libretube.enums.PlaylistType import com.github.libretube.extensions.formatShort import com.github.libretube.extensions.toID @@ -27,6 +29,10 @@ import com.github.libretube.ui.sheets.PlaylistOptionsBottomSheet import com.github.libretube.ui.sheets.VideoOptionsBottomSheet import com.github.libretube.ui.viewholders.SearchViewHolder import com.github.libretube.util.TextUtils +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import kotlinx.serialization.encodeToString class SearchResultsAdapter( @@ -112,6 +118,15 @@ class SearchResultsAdapter( NavigationHelper.navigateChannel(root.context, item.uploaderUrl) } watchProgress.setWatchProgressLength(videoId, item.duration) + + CoroutineScope(Dispatchers.IO).launch { + val isDownloaded = + DatabaseHolder.Database.downloadDao().exists(videoId) + + withContext(Dispatchers.Main) { + downloadBadge.isVisible = isDownloaded + } + } } } 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 c09ef09ce..596ae1605 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 @@ -2,11 +2,11 @@ package com.github.libretube.ui.adapters import android.annotation.SuppressLint import android.content.Context -import android.text.format.DateUtils import android.view.LayoutInflater import android.view.ViewGroup import androidx.core.os.bundleOf import androidx.core.view.isGone +import androidx.core.view.isVisible import androidx.core.view.updateLayoutParams import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView @@ -17,6 +17,7 @@ import com.github.libretube.constants.PreferenceKeys import com.github.libretube.databinding.AllCaughtUpRowBinding import com.github.libretube.databinding.TrendingRowBinding import com.github.libretube.databinding.VideoRowBinding +import com.github.libretube.db.DatabaseHolder import com.github.libretube.extensions.ceilHalf import com.github.libretube.extensions.dpToPx import com.github.libretube.extensions.toID @@ -29,6 +30,10 @@ import com.github.libretube.ui.extensions.setWatchProgressLength import com.github.libretube.ui.sheets.VideoOptionsBottomSheet import com.github.libretube.ui.viewholders.VideosViewHolder import com.github.libretube.util.TextUtils +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext class VideosAdapter( private val streamItems: MutableList, @@ -86,12 +91,10 @@ class VideosAdapter( @SuppressLint("SetTextI18n") override fun onBindViewHolder(holder: VideosViewHolder, position: Int) { val video = streamItems[position] - val videoId = video.url?.toID() + val videoId = video.url.orEmpty().toID() - videoId?.let { - (holder.trendingRowBinding?.watchProgress ?: holder.videoRowBinding!!.watchProgress) - .setWatchProgressLength(it, video.duration ?: 0L) - } + (holder.trendingRowBinding?.watchProgress ?: holder.videoRowBinding!!.watchProgress) + .setWatchProgressLength(videoId, video.duration ?: 0L) val context = ( holder.videoRowBinding ?: holder.trendingRowBinding @@ -119,7 +122,7 @@ class VideosAdapter( ImageHelper.loadImage(video.thumbnail, thumbnail) ImageHelper.loadImage(video.uploaderAvatar, channelImage, true) root.setOnClickListener { - NavigationHelper.navigateVideo(root.context, video.url) + NavigationHelper.navigateVideo(root.context, videoId) } root.setOnLongClickListener { @@ -156,7 +159,7 @@ class VideosAdapter( } root.setOnClickListener { - NavigationHelper.navigateVideo(root.context, video.url) + NavigationHelper.navigateVideo(root.context, videoId) } root.setOnLongClickListener { @@ -171,6 +174,15 @@ class VideosAdapter( sheet.show(fragmentManager, VideosAdapter::class.java.name) true } + + CoroutineScope(Dispatchers.IO).launch { + val isDownloaded = + DatabaseHolder.Database.downloadDao().exists(videoId) + + withContext(Dispatchers.Main) { + downloadBadge.isVisible = isDownloaded + } + } } } diff --git a/app/src/main/java/com/github/libretube/ui/adapters/WatchHistoryAdapter.kt b/app/src/main/java/com/github/libretube/ui/adapters/WatchHistoryAdapter.kt index 051bd1799..2191c5627 100644 --- a/app/src/main/java/com/github/libretube/ui/adapters/WatchHistoryAdapter.kt +++ b/app/src/main/java/com/github/libretube/ui/adapters/WatchHistoryAdapter.kt @@ -4,6 +4,7 @@ import android.view.LayoutInflater import android.view.ViewGroup import androidx.core.os.bundleOf import androidx.core.view.isGone +import androidx.core.view.isVisible import androidx.recyclerview.widget.RecyclerView import com.github.libretube.constants.IntentData import com.github.libretube.databinding.VideoRowBinding @@ -17,8 +18,11 @@ import com.github.libretube.ui.extensions.setWatchProgressLength import com.github.libretube.ui.sheets.VideoOptionsBottomSheet import com.github.libretube.ui.viewholders.WatchHistoryViewHolder import com.github.libretube.util.TextUtils +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withContext class WatchHistoryAdapter( private val watchHistory: MutableList @@ -98,6 +102,15 @@ class WatchHistoryAdapter( video.videoId, video.duration ) + + CoroutineScope(Dispatchers.IO).launch { + val isDownloaded = + DatabaseHolder.Database.downloadDao().exists(video.videoId) + + withContext(Dispatchers.Main) { + downloadBadge.isVisible = isDownloaded + } + } } } } diff --git a/app/src/main/res/drawable/ic_download_folder.xml b/app/src/main/res/drawable/ic_download_folder.xml new file mode 100644 index 000000000..ba0320bfb --- /dev/null +++ b/app/src/main/res/drawable/ic_download_folder.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/layout/video_row.xml b/app/src/main/res/layout/video_row.xml index c54c04de5..d0e8c5934 100644 --- a/app/src/main/res/layout/video_row.xml +++ b/app/src/main/res/layout/video_row.xml @@ -107,7 +107,7 @@ android:ellipsize="end" android:maxLines="2" android:textAlignment="viewStart" - app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintEnd_toStartOf="@id/download_badge" app:layout_constraintStart_toEndOf="@id/thumbnail_card" app:layout_constraintTop_toTopOf="parent" /> @@ -119,10 +119,22 @@ android:ellipsize="end" android:maxLines="1" android:textAlignment="viewStart" - app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintEnd_toStartOf="@id/download_badge" app:layout_constraintStart_toEndOf="@id/thumbnail_card" app:layout_constraintTop_toBottomOf="@id/video_title" /> + +