feat: add badge for downloaded videos

This commit is contained in:
Bnyro 2025-01-09 15:48:43 +01:00
parent 0115e4c070
commit 8a3ea3b695
7 changed files with 86 additions and 10 deletions

View File

@ -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?

View File

@ -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
}
}
}
}

View File

@ -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
}
}
}
}

View File

@ -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<StreamItem>,
@ -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
}
}
}
}

View File

@ -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<WatchHistoryItem>
@ -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
}
}
}
}
}

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?colorControlNormal"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="#FF000000"
android:pathData="m434,663 l226,-227 -56,-56 -170,170 -85,-85 -57,57 142,141ZM160,800q-33,0 -56.5,-23.5T80,720v-480q0,-33 23.5,-56.5T160,160h240l80,80h320q33,0 56.5,23.5T880,320v400q0,33 -23.5,56.5T800,800L160,800ZM160,720h640v-400L447,320l-80,-80L160,240v480ZM160,720v-480,480Z" />
</vector>

View File

@ -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" />
<ImageView
android:id="@+id/download_badge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_download_folder"
app:layout_constraintEnd_toEndOf="parent"
android:paddingStart="6dp"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="RtlSymmetry"
android:visibility="gone"
tools:visibility="visible" />
<LinearLayout
android:id="@+id/channel_container"
android:layout_width="0dp"