more fixes

This commit is contained in:
Denis Çerri 2023-01-28 19:14:39 +01:00
parent af4294e092
commit 5e47c98ec5
No known key found for this signature in database
GPG key ID: 95C43D517D830350
11 changed files with 99 additions and 64 deletions

View file

@ -39,9 +39,15 @@ interface DownloadDao {
@Query("DELETE FROM downloads WHERE status='Processing'") @Query("DELETE FROM downloads WHERE status='Processing'")
suspend fun deleteProcessing() suspend fun deleteProcessing()
@Query("DELETE FROM downloads WHERE status='Processing' AND id=:id")
suspend fun deleteSingleProcessing(id: Long)
@Update(onConflict = OnConflictStrategy.REPLACE) @Update(onConflict = OnConflictStrategy.REPLACE)
suspend fun update(item: DownloadItem) suspend fun update(item: DownloadItem)
@Query("SELECT * FROM downloads ORDER BY id DESC LIMIT 1") @Query("SELECT * FROM downloads ORDER BY id DESC LIMIT 1")
fun getLatest() : DownloadItem fun getLatest() : DownloadItem
@Query("UPDATE downloads SET status='Queued' WHERE status='Processing'")
suspend fun queueAllProcessing()
} }

View file

@ -1,5 +1,6 @@
package com.deniscerri.ytdlnis.database.repository package com.deniscerri.ytdlnis.database.repository
import android.util.Log
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import com.deniscerri.ytdlnis.database.dao.DownloadDao import com.deniscerri.ytdlnis.database.dao.DownloadDao
import com.deniscerri.ytdlnis.database.models.DownloadItem import com.deniscerri.ytdlnis.database.models.DownloadItem
@ -43,4 +44,12 @@ class DownloadRepository(private val downloadDao: DownloadDao) {
suspend fun deleteProcessing(){ suspend fun deleteProcessing(){
downloadDao.deleteProcessing() downloadDao.deleteProcessing()
} }
suspend fun deleteSingleProcessing(item: DownloadItem){
downloadDao.deleteSingleProcessing(item.id)
}
suspend fun queueAllProcessing(){
downloadDao.queueAllProcessing()
}
} }

View file

@ -14,6 +14,7 @@ import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.Format import com.deniscerri.ytdlnis.database.models.Format
import com.deniscerri.ytdlnis.database.models.ResultItem import com.deniscerri.ytdlnis.database.models.ResultItem
import com.deniscerri.ytdlnis.database.repository.DownloadRepository import com.deniscerri.ytdlnis.database.repository.DownloadRepository
import com.google.gson.Gson
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -139,7 +140,20 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
return result return result
} }
fun deleteSingleProcessing(item: DownloadItem) = viewModelScope.launch(Dispatchers.IO) {
repository.deleteSingleProcessing(item)
}
fun deleteProcessing() = viewModelScope.launch(Dispatchers.IO) { fun deleteProcessing() = viewModelScope.launch(Dispatchers.IO) {
repository.deleteProcessing() repository.deleteProcessing()
} }
fun cloneDownloadItem(item: DownloadItem) : DownloadItem {
val string = Gson().toJson(item, DownloadItem::class.java)
return Gson().fromJson(string, DownloadItem::class.java)
}
fun queueAllProcessing()= viewModelScope.launch(Dispatchers.IO) {
repository.queueAllProcessing();
}
} }

View file

@ -8,6 +8,7 @@ import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.widget.Button import android.widget.Button
import android.widget.Toast
import androidx.fragment.app.FragmentTransaction import androidx.fragment.app.FragmentTransaction
import androidx.fragment.app.findFragment import androidx.fragment.app.findFragment
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
@ -22,6 +23,7 @@ import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.google.android.material.button.MaterialButton import com.google.android.material.button.MaterialButton
import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@ -30,8 +32,7 @@ class ConfigureDownloadBottomSheetDialog(private val downloadItem: DownloadItem)
private lateinit var tabLayout: TabLayout private lateinit var tabLayout: TabLayout
private lateinit var viewPager2: ViewPager2 private lateinit var viewPager2: ViewPager2
private lateinit var fragmentAdapter : DownloadFragmentAdapter private lateinit var fragmentAdapter : DownloadFragmentAdapter
private val currentItem = downloadItem.copy() private lateinit var currentItem : DownloadItem
private lateinit var downloadViewModel: DownloadViewModel private lateinit var downloadViewModel: DownloadViewModel
private lateinit var resultViewModel: ResultViewModel private lateinit var resultViewModel: ResultViewModel
@ -39,6 +40,7 @@ class ConfigureDownloadBottomSheetDialog(private val downloadItem: DownloadItem)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java] downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java] resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
currentItem = downloadViewModel.cloneDownloadItem(downloadItem)
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -99,12 +101,12 @@ class ConfigureDownloadBottomSheetDialog(private val downloadItem: DownloadItem)
val cancelBtn = view.findViewById<MaterialButton>(R.id.bottomsheet_cancel_button) val cancelBtn = view.findViewById<MaterialButton>(R.id.bottomsheet_cancel_button)
cancelBtn.setOnClickListener{ cancelBtn.setOnClickListener{
returnPreviousState();
dismiss() dismiss()
} }
val download = view.findViewById<Button>(R.id.bottom_sheet_ok) val download = view.findViewById<Button>(R.id.bottom_sheet_ok)
download!!.setOnClickListener { download!!.setOnClickListener {
downloadViewModel.updateDownload(downloadItem)
dismiss() dismiss()
} }
} }
@ -121,12 +123,11 @@ class ConfigureDownloadBottomSheetDialog(private val downloadItem: DownloadItem)
} }
private fun returnPreviousState(){ private fun returnPreviousState(){
lifecycleScope.launch{ CoroutineScope(Dispatchers.IO).launch {
val result = withContext(Dispatchers.IO){ val result = resultViewModel.getItemByURL(currentItem.url)
resultViewModel.getItemByURL(currentItem.url)
}
result.title = currentItem.title result.title = currentItem.title
result.author = currentItem.author result.author = currentItem.author
Log.e("TAG, ", currentItem.toString())
resultViewModel.update(result) resultViewModel.update(result)
downloadViewModel.updateDownload(currentItem) downloadViewModel.updateDownload(currentItem)
} }

View file

@ -45,20 +45,21 @@ class DownloadAudioFragment(private val downloadItem: DownloadItem) : Fragment()
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
downloadItem.type = "audio"
lifecycleScope.launch{ lifecycleScope.launch{
val item = withContext(Dispatchers.IO){ // val item = withContext(Dispatchers.IO){
downloadViewModel.getItemByID(downloadItem.id) // downloadViewModel.getItemByID(downloadItem.id)
} // }
if (::title.isInitialized){ // if (::title.isInitialized){
title.editText!!.setText(item.title) // title.editText!!.setText(item.title)
downloadItem.title = item.title // downloadItem.title = item.title
} // }
if(::author.isInitialized){ // if(::author.isInitialized){
author.editText!!.setText(item.author) // author.editText!!.setText(item.author)
downloadItem.author = item.author // downloadItem.author = item.author
} // }
} }
downloadViewModel.updateDownload(downloadItem) //downloadViewModel.updateDownload(downloadItem)
} }
override fun onCreateView( override fun onCreateView(
@ -96,8 +97,8 @@ class DownloadAudioFragment(private val downloadItem: DownloadItem) : Fragment()
override fun afterTextChanged(p0: Editable?) { override fun afterTextChanged(p0: Editable?) {
downloadItem.title = p0.toString() downloadItem.title = p0.toString()
resultItem.title = p0.toString() resultItem.title = p0.toString()
resultViewModel.update(resultItem) //resultViewModel.update(resultItem)
downloadViewModel.updateDownload(downloadItem) //downloadViewModel.updateDownload(downloadItem)
} }
}) })
@ -109,8 +110,8 @@ class DownloadAudioFragment(private val downloadItem: DownloadItem) : Fragment()
override fun afterTextChanged(p0: Editable?) { override fun afterTextChanged(p0: Editable?) {
downloadItem.author = p0.toString() downloadItem.author = p0.toString()
resultItem.author = p0.toString() resultItem.author = p0.toString()
resultViewModel.update(resultItem) //resultViewModel.update(resultItem)
downloadViewModel.updateDownload(downloadItem) //downloadViewModel.updateDownload(downloadItem)
} }
}) })
saveDir = view.findViewById(R.id.outputPath) saveDir = view.findViewById(R.id.outputPath)
@ -119,7 +120,7 @@ class DownloadAudioFragment(private val downloadItem: DownloadItem) : Fragment()
getString(R.string.music_path) getString(R.string.music_path)
) )
downloadItem.downloadPath = downloadPath!! downloadItem.downloadPath = downloadPath!!
downloadViewModel.updateDownload(downloadItem) //downloadViewModel.updateDownload(downloadItem)
saveDir.editText!!.setText( saveDir.editText!!.setText(
fileUtil.formatPath(downloadPath) fileUtil.formatPath(downloadPath)
) )
@ -168,7 +169,7 @@ class DownloadAudioFragment(private val downloadItem: DownloadItem) : Fragment()
AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, index: Int, _: Long -> AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, index: Int, _: Long ->
downloadItem.format.format_note = formats[index].format_note downloadItem.format.format_note = formats[index].format_note
downloadItem.format.format_id = formats[index].format_id downloadItem.format.format_id = formats[index].format_id
downloadViewModel.updateDownload(downloadItem) //downloadViewModel.updateDownload(downloadItem)
} }
} }
@ -191,10 +192,10 @@ class DownloadAudioFragment(private val downloadItem: DownloadItem) : Fragment()
(container!!.editText as AutoCompleteTextView?)!!.onItemClickListener = (container!!.editText as AutoCompleteTextView?)!!.onItemClickListener =
AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, index: Int, _: Long -> AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, index: Int, _: Long ->
downloadItem.format.container = containers[index] downloadItem.format.container = containers[index]
downloadViewModel.updateDownload(downloadItem) //downloadViewModel.updateDownload(downloadItem)
} }
downloadViewModel.updateDownload(downloadItem) //downloadViewModel.updateDownload(downloadItem)
}catch (e : Exception){ }catch (e : Exception){
e.printStackTrace() e.printStackTrace()
} }
@ -213,7 +214,7 @@ class DownloadAudioFragment(private val downloadItem: DownloadItem) : Fragment()
) )
} }
downloadItem.downloadPath = result.data?.data.toString() downloadItem.downloadPath = result.data?.data.toString()
downloadViewModel.updateDownload(downloadItem) //downloadViewModel.updateDownload(downloadItem)
saveDir.editText?.setText(fileUtil.formatPath(result.data?.data.toString()), TextView.BufferType.EDITABLE) saveDir.editText?.setText(fileUtil.formatPath(result.data?.data.toString()), TextView.BufferType.EDITABLE)
} }
} }

View file

@ -17,6 +17,7 @@ import androidx.lifecycle.ViewModelProvider
import androidx.viewpager2.widget.ViewPager2 import androidx.viewpager2.widget.ViewPager2
import com.deniscerri.ytdlnis.R import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.models.DownloadItem import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.bottomsheet.BottomSheetDialog
@ -97,6 +98,11 @@ class DownloadBottomSheetDialog(item: DownloadItem) : BottomSheetDialogFragment(
val download = view.findViewById<Button>(R.id.bottomsheet_download_button) val download = view.findViewById<Button>(R.id.bottomsheet_download_button)
download!!.setOnClickListener { download!!.setOnClickListener {
downloadItem.status = DownloadRepository.status.Queued.toString()
downloadViewModel.insertDownload(downloadItem)
dismiss()
// for (i in selectedObjects!!.indices) { // for (i in selectedObjects!!.indices) {
// val vid = findVideo( // val vid = findVideo(
// selectedObjects!![i]!!.getURL() // selectedObjects!![i]!!.getURL()
@ -113,7 +119,7 @@ class DownloadBottomSheetDialog(item: DownloadItem) : BottomSheetDialogFragment(
// mainActivity!!.startDownloadService(downloadQueue, listener) // mainActivity!!.startDownloadService(downloadQueue, listener)
// downloadQueue!!.clear() // downloadQueue!!.clear()
// } // }
dismiss()
} }
} }
@ -135,7 +141,7 @@ class DownloadBottomSheetDialog(item: DownloadItem) : BottomSheetDialogFragment(
parentFragmentManager.beginTransaction().remove(parentFragmentManager.findFragmentByTag("f$i")!!).commit() parentFragmentManager.beginTransaction().remove(parentFragmentManager.findFragmentByTag("f$i")!!).commit()
} }
} }
downloadViewModel.deleteDownload(downloadItem) downloadViewModel.deleteSingleProcessing(downloadItem)
} }
} }

View file

@ -12,12 +12,11 @@ import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.Format import com.deniscerri.ytdlnis.database.models.Format
import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding
class DownloadCommandFragment(item: DownloadItem) : Fragment() { class DownloadCommandFragment(private val downloadItem: DownloadItem) : Fragment() {
private var _binding : FragmentHomeBinding? = null private var _binding : FragmentHomeBinding? = null
private var fragmentView: View? = null private var fragmentView: View? = null
private var activity: Activity? = null private var activity: Activity? = null
private var mainActivity: MainActivity? = null private var mainActivity: MainActivity? = null
private val downloadItem = item
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,

View file

@ -9,8 +9,7 @@ import androidx.viewpager2.adapter.FragmentStateAdapter
import com.deniscerri.ytdlnis.database.models.DownloadItem import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.google.gson.Gson import com.google.gson.Gson
class DownloadFragmentAdapter (item : DownloadItem, fragmentManager : FragmentManager, lifecycle : Lifecycle) : FragmentStateAdapter(fragmentManager, lifecycle) { class DownloadFragmentAdapter (private val downloadItem : DownloadItem, fragmentManager : FragmentManager, lifecycle : Lifecycle) : FragmentStateAdapter(fragmentManager, lifecycle) {
private val downloadItem = item
override fun getItemCount(): Int { override fun getItemCount(): Int {
return 3 return 3
@ -19,16 +18,13 @@ class DownloadFragmentAdapter (item : DownloadItem, fragmentManager : FragmentMa
override fun createFragment(position: Int): Fragment { override fun createFragment(position: Int): Fragment {
when (position) { when (position) {
0 -> { 0 -> {
downloadItem.type = "audio" return DownloadAudioFragment(downloadItem)
return DownloadAudioFragment(clone(downloadItem))
} }
1 -> { 1 -> {
downloadItem.type = "video" return DownloadVideoFragment(downloadItem)
return DownloadVideoFragment(clone(downloadItem))
} }
} }
downloadItem.type = "command" return DownloadCommandFragment(downloadItem)
return DownloadCommandFragment(clone(downloadItem))
} }

View file

@ -20,6 +20,7 @@ import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.adapter.ConfigureMultipleDownloadsAdapter import com.deniscerri.ytdlnis.adapter.ConfigureMultipleDownloadsAdapter
import com.deniscerri.ytdlnis.adapter.HomeAdapter import com.deniscerri.ytdlnis.adapter.HomeAdapter
import com.deniscerri.ytdlnis.database.models.DownloadItem import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetBehavior
@ -80,6 +81,7 @@ class DownloadMultipleBottomSheetDialog(private val items: List<DownloadItem>) :
val download = view.findViewById<Button>(R.id.bottomsheet_download_button) val download = view.findViewById<Button>(R.id.bottomsheet_download_button)
download!!.setOnClickListener { download!!.setOnClickListener {
downloadViewModel.queueAllProcessing()
// for (i in selectedObjects!!.indices) { // for (i in selectedObjects!!.indices) {
// val vid = findVideo( // val vid = findVideo(
// selectedObjects!![i]!!.getURL() // selectedObjects!![i]!!.getURL()

View file

@ -45,20 +45,21 @@ class DownloadVideoFragment(private val downloadItem: DownloadItem) : Fragment()
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
lifecycleScope.launch{ downloadItem.type = "video"
val item = withContext(Dispatchers.IO){ // lifecycleScope.launch{
downloadViewModel.getItemByID(downloadItem.id) // val item = withContext(Dispatchers.IO){
} // downloadViewModel.getItemByID(downloadItem.id)
if (::title.isInitialized){ // }
title.editText!!.setText(item.title) // if (::title.isInitialized){
downloadItem.title = item.title // title.editText!!.setText(item.title)
} // downloadItem.title = item.title
if(::author.isInitialized){ // }
author.editText!!.setText(item.author) // if(::author.isInitialized){
downloadItem.author = item.author // author.editText!!.setText(item.author)
} // downloadItem.author = item.author
} // }
downloadViewModel.updateDownload(downloadItem) // }
//downloadviewmodel.updateDownload(downloadItem)
} }
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
@ -97,8 +98,8 @@ class DownloadVideoFragment(private val downloadItem: DownloadItem) : Fragment()
override fun afterTextChanged(p0: Editable?) { override fun afterTextChanged(p0: Editable?) {
downloadItem.title = p0.toString() downloadItem.title = p0.toString()
resultItem.title = p0.toString() resultItem.title = p0.toString()
resultViewModel.update(resultItem) //esultViewModel.update(resultItem)
downloadViewModel.updateDownload(downloadItem) //downloadviewmodel.updateDownload(downloadItem)
} }
}) })
@ -110,8 +111,8 @@ class DownloadVideoFragment(private val downloadItem: DownloadItem) : Fragment()
override fun afterTextChanged(p0: Editable?) { override fun afterTextChanged(p0: Editable?) {
downloadItem.author = p0.toString() downloadItem.author = p0.toString()
resultItem.author = p0.toString() resultItem.author = p0.toString()
resultViewModel.update(resultItem) //resultViewModel.update(resultItem)
downloadViewModel.updateDownload(downloadItem) //downloadviewmodel.updateDownload(downloadItem)
} }
}) })
@ -121,7 +122,7 @@ class DownloadVideoFragment(private val downloadItem: DownloadItem) : Fragment()
getString(R.string.video_path) getString(R.string.video_path)
) )
downloadItem.downloadPath = downloadPath!! downloadItem.downloadPath = downloadPath!!
downloadViewModel.updateDownload(downloadItem) //downloadviewmodel.updateDownload(downloadItem)
saveDir.editText!!.setText( saveDir.editText!!.setText(
fileUtil.formatPath(downloadPath) fileUtil.formatPath(downloadPath)
) )
@ -164,7 +165,7 @@ class DownloadVideoFragment(private val downloadItem: DownloadItem) : Fragment()
downloadItem.format.format_note = formats[index].format_note downloadItem.format.format_note = formats[index].format_note
downloadItem.format.format_id = formats[index].format_id downloadItem.format.format_id = formats[index].format_id
downloadItem.format.filesize = formats[index].filesize downloadItem.format.filesize = formats[index].filesize
downloadViewModel.updateDownload(downloadItem) //downloadviewmodel.updateDownload(downloadItem)
} }
val containers = requireContext().resources.getStringArray(R.array.video_containers) val containers = requireContext().resources.getStringArray(R.array.video_containers)
@ -188,7 +189,7 @@ class DownloadVideoFragment(private val downloadItem: DownloadItem) : Fragment()
(container!!.editText as AutoCompleteTextView?)!!.onItemClickListener = (container!!.editText as AutoCompleteTextView?)!!.onItemClickListener =
AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, index: Int, _: Long -> AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, index: Int, _: Long ->
downloadItem.format.container = containers[index] downloadItem.format.container = containers[index]
downloadViewModel.updateDownload(downloadItem) //downloadviewmodel.updateDownload(downloadItem)
} }
val embedSubs = view.findViewById<Chip>(R.id.embed_subtitles) val embedSubs = view.findViewById<Chip>(R.id.embed_subtitles)
@ -218,7 +219,7 @@ class DownloadVideoFragment(private val downloadItem: DownloadItem) : Fragment()
) )
} }
downloadItem.downloadPath = result.data?.data.toString() downloadItem.downloadPath = result.data?.data.toString()
downloadViewModel.updateDownload(downloadItem) //downloadviewmodel.updateDownload(downloadItem)
saveDir.editText?.setText(fileUtil.formatPath(result.data?.data.toString()), TextView.BufferType.EDITABLE) saveDir.editText?.setText(fileUtil.formatPath(result.data?.data.toString()), TextView.BufferType.EDITABLE)
} }
} }

View file

@ -10,11 +10,11 @@
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/materialButton" android:id="@+id/materialButton"
style="@style/Widget.Material3.Button.IconButton" style="@style/Widget.Material3.Button.IconButton"
android:layout_width="28dp" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
android:gravity="end" android:gravity="end"
android:padding="0dp" android:padding="5dp"
app:icon="@drawable/ic_handle" app:icon="@drawable/ic_handle"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/download_card_view" app:layout_constraintEnd_toStartOf="@+id/download_card_view"