added download multiple card

pull/44/head
Denis Çerri 4 years ago
parent a6b078f95b
commit ff58bd2dbf
No known key found for this signature in database
GPG Key ID: 95C43D517D830350

@ -2,7 +2,7 @@
"formatVersion": 1,
"database": {
"version": 1,
"identityHash": "2c0fdec170ca54d97ef928dfe28a6992",
"identityHash": "db5c9df3e43ddd5a5131bbd372a7c92b",
"entities": [
{
"tableName": "results",
@ -74,7 +74,7 @@
},
{
"tableName": "formats",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `itemId` INTEGER NOT NULL, `format_id` TEXT NOT NULL, `container` TEXT NOT NULL, `filesize` INTEGER NOT NULL, `format_note` TEXT NOT NULL, `encoding` TEXT NOT NULL)",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `itemId` INTEGER NOT NULL, `format_id` TEXT NOT NULL, `container` TEXT NOT NULL, `filesize` INTEGER NOT NULL, `format_note` TEXT NOT NULL)",
"fields": [
{
"fieldPath": "id",
@ -111,12 +111,6 @@
"columnName": "format_note",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "encoding",
"columnName": "encoding",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
@ -392,7 +386,7 @@
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '2c0fdec170ca54d97ef928dfe28a6992')"
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'db5c9df3e43ddd5a5131bbd372a7c92b')"
]
}
}

@ -19,7 +19,9 @@
android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme" >
android:enableOnBackInvokedCallback="true"
android:theme="@style/AppTheme"
tools:targetApi="tiramisu">
<activity android:name=".MainActivity"
android:windowSoftInputMode="adjustResize"
android:exported="true">

@ -4,10 +4,12 @@ import android.app.Activity
import android.graphics.Color
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.AsyncDifferConfig
@ -16,12 +18,13 @@ import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.ResultItem
import com.google.android.material.button.MaterialButton
import com.google.android.material.card.MaterialCardView
import com.google.android.material.progressindicator.LinearProgressIndicator
import com.squareup.picasso.Picasso
class ConfigureMultipleDownloadsAdapter(onItemClickListener: OnItemClickListener, activity: Activity) :
ListAdapter<DownloadItem?, ConfigureMultipleDownloadsAdapter.ViewHolder?>(AsyncDifferConfig.Builder(DIFF_CALLBACK).build()) {
class ConfigureMultipleDownloadsAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<DownloadItem?, ConfigureMultipleDownloadsAdapter.ViewHolder>(AsyncDifferConfig.Builder(DIFF_CALLBACK).build()) {
private val onItemClickListener: OnItemClickListener
private val activity: Activity
@ -30,18 +33,17 @@ class ConfigureMultipleDownloadsAdapter(onItemClickListener: OnItemClickListener
this.activity = activity
}
class ViewHolder(itemView: View, onItemClickListener: OnItemClickListener?) :
RecyclerView.ViewHolder(itemView) {
class ViewHolder(itemView: View, onItemClickListener: OnItemClickListener?) : RecyclerView.ViewHolder(itemView) {
val cardView: MaterialCardView
init {
cardView = itemView.findViewById(R.id.download_multiple_card_view)
cardView = itemView.findViewById(R.id.download_card_view)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val cardView = LayoutInflater.from(parent.context)
.inflate(R.layout.home_download_multiple_card, parent, false)
.inflate(R.layout.download_card, parent, false)
return ViewHolder(cardView, onItemClickListener)
}
@ -49,7 +51,7 @@ class ConfigureMultipleDownloadsAdapter(onItemClickListener: OnItemClickListener
val item = getItem(position)
val card = holder.cardView
// THUMBNAIL ----------------------------------
val thumbnail = card.findViewById<ImageView>(R.id.result_image_view)
val thumbnail = card.findViewById<ImageView>(R.id.downloads_image_view)
val imageURL = item!!.thumb
if (imageURL.isNotEmpty()) {
val uiHandler = Handler(Looper.getMainLooper())
@ -62,7 +64,7 @@ class ConfigureMultipleDownloadsAdapter(onItemClickListener: OnItemClickListener
}
// TITLE ----------------------------------
val itemTitle = card.findViewById<TextView>(R.id.result_title)
val itemTitle = card.findViewById<TextView>(R.id.title)
var title = item.title
if (title.length > 100) {
title = title.substring(0, 40) + "..."
@ -73,20 +75,16 @@ class ConfigureMultipleDownloadsAdapter(onItemClickListener: OnItemClickListener
val author = card.findViewById<TextView>(R.id.author)
author.text = item.author
// Format
val format = card.findViewById<TextView>(R.id.format)
format.text = item.ext
// Quality
val quality = card.findViewById<TextView>(R.id.quality)
quality.text = item.formatDesc
// Container ----------------------------------
val container = card.findViewById<TextView>(R.id.container)
container.text = item.ext
// File Size
val fileSize = card.findViewById<TextView>(R.id.filesize)
fileSize.text = item.filesize
// Type Icon Button
val btn = card.findViewById<MaterialButton>(R.id.download_type)
val btn = card.findViewById<MaterialButton>(R.id.downloads_download_button_type)
when(item.type) {
"audio" -> {
@ -105,20 +103,19 @@ class ConfigureMultipleDownloadsAdapter(onItemClickListener: OnItemClickListener
}
}
interface OnItemClickListener {
fun onButtonClick(videoURL: String, type: String?)
fun onCardClick(itemID: Long)
}
companion object {
private val DIFF_CALLBACK: DiffUtil.ItemCallback<DownloadItem> =
object : DiffUtil.ItemCallback<DownloadItem>() {
private val DIFF_CALLBACK: DiffUtil.ItemCallback<DownloadItem> = object : DiffUtil.ItemCallback<DownloadItem>() {
override fun areItemsTheSame(oldItem: DownloadItem, newItem: DownloadItem): Boolean {
return oldItem.id === newItem.id
}
override fun areContentsTheSame(oldItem: DownloadItem, newItem: DownloadItem): Boolean {
return oldItem.url == newItem.url
return oldItem.url == newItem.url && oldItem.title == newItem.title && oldItem.author == newItem.author
}
}
}

@ -9,14 +9,17 @@ import com.deniscerri.ytdlnis.util.FileUtil
@Dao
interface DownloadDao {
@Query("SELECT * FROM downloads")
@Query("SELECT * FROM downloads ORDER BY status")
fun getAllDownloads() : LiveData<List<DownloadItem>>
@Query("SELECT * FROM downloads WHERE status='Active'")
fun getActiveDownloads() : LiveData<List<DownloadItem>>
@Query("SELECT * FROM downloads WHERE status='Queued'")
fun getQueuedDownloads() : List<DownloadItem>
fun getQueuedDownloads() : LiveData<List<DownloadItem>>
@Query("SELECT * FROM downloads WHERE status='Processing'")
fun getProcessingDownloads() : LiveData<List<DownloadItem>>
@Query("SELECT * FROM downloads WHERE workID=:workID")
fun getDownloadByWorkId(workID: Int) : DownloadItem
@ -33,6 +36,9 @@ interface DownloadDao {
@Delete
suspend fun delete(item: DownloadItem)
@Query("DELETE FROM downloads WHERE status='Processing'")
suspend fun deleteProcessing()
@Update(onConflict = OnConflictStrategy.REPLACE)
suspend fun update(item: DownloadItem)

@ -7,16 +7,14 @@ import com.google.gson.annotations.SerializedName
@Entity(tableName = "formats")
data class Format(
@PrimaryKey(autoGenerate = true)
var id: Long,
var itemId: Long,
var id: Long = -1,
var itemId: Long = 0,
@SerializedName(value = "format_id", alternate = ["itag"])
val format_id: String,
val format_id: String = "",
@SerializedName(value = "ext", alternate = ["container"])
val container: String,
val container: String = "",
@SerializedName(value = "filesize", alternate = ["clen", "filesize_approx"])
val filesize: Long,
val filesize: Long = 0,
@SerializedName(value = "format_note", alternate = ["resolution", "audioQuality"])
val format_note: String,
@SerializedName(value = "encoding", alternate = ["vcodec", "acodec", "video_ext"])
val encoding: String
val format_note: String = ""
)

@ -3,11 +3,16 @@ package com.deniscerri.ytdlnis.database.repository
import android.util.Log
import androidx.lifecycle.LiveData
import com.deniscerri.ytdlnis.database.dao.DownloadDao
import com.deniscerri.ytdlnis.database.dao.FormatDao
import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.Format
import com.deniscerri.ytdlnis.database.models.ResultItem
class DownloadRepository(private val downloadDao: DownloadDao) {
val allDownloads : LiveData<List<DownloadItem>> = downloadDao.getAllDownloads()
val activeDownloads : LiveData<List<DownloadItem>> = downloadDao.getActiveDownloads()
val queuedDownloads : LiveData<List<DownloadItem>> = downloadDao.getQueuedDownloads()
val processingDownloads : LiveData<List<DownloadItem>> = downloadDao.getProcessingDownloads()
enum class status {
Active, Queued, Errored, Processing
@ -29,9 +34,6 @@ class DownloadRepository(private val downloadDao: DownloadDao) {
return downloadDao.getDownloadByWorkId(workID)
}
fun getQueuedDownloads() : List<DownloadItem>{
return downloadDao.getQueuedDownloads()
}
suspend fun setDownloadStatus(item: DownloadItem, status: status){
item.status = status.toString()
@ -42,4 +44,7 @@ class DownloadRepository(private val downloadDao: DownloadDao) {
return downloadDao.getDownloadById(id)
}
suspend fun deleteProcessing(){
downloadDao.deleteProcessing()
}
}

@ -1,24 +1,35 @@
package com.deniscerri.ytdlnis.database.viewmodel
import android.app.Activity
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.deniscerri.ytdlnis.App
import com.deniscerri.ytdlnis.database.DBManager
import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.Format
import com.deniscerri.ytdlnis.database.models.ResultItem
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class DownloadViewModel(application: Application) : AndroidViewModel(application) {
private val repository : DownloadRepository
private val allDownloads : LiveData<List<DownloadItem>>
val allDownloads : LiveData<List<DownloadItem>>
val queuedDownloads : LiveData<List<DownloadItem>>
val activeDownloads : LiveData<List<DownloadItem>>
val processingDownloads : LiveData<List<DownloadItem>>
init {
val dao = DBManager.getInstance(application).downloadDao
val formatDao = DBManager.getInstance(application).formatDao
repository = DownloadRepository(dao)
allDownloads = repository.allDownloads
queuedDownloads = repository.queuedDownloads
activeDownloads = repository.activeDownloads
processingDownloads = repository.processingDownloads
}
fun startWork(items: List<DownloadItem>){
@ -48,4 +59,51 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
fun getItemByID(id: Long) : DownloadItem {
return repository.getItemByID(id)
}
fun createDownloadItemFromResult(resultItem: ResultItem, type: String) : DownloadItem {
val sharedPreferences =
getApplication<App>().getSharedPreferences("root_preferences", Activity.MODE_PRIVATE)
val embedSubs = sharedPreferences.getBoolean("embed_subtitles", false)
val addChapters = sharedPreferences.getBoolean("add_chapters", false)
val saveThumb = sharedPreferences.getBoolean("write_thumbnail", false)
return DownloadItem(0,
resultItem.url,
resultItem.title,
resultItem.author,
resultItem.thumb,
resultItem.duration,
type,
"", "", 0, "", false,
"", resultItem.website, "", resultItem.playlistTitle, embedSubs, addChapters, saveThumb, "",
"", DownloadRepository.status.Processing.toString(), 0
)
}
fun turnResultItemstoDownloadItems(items: List<ResultItem?>) : List<DownloadItem> {
val list : MutableList<DownloadItem> = mutableListOf()
items.forEach {
list.add(createDownloadItemFromResult(it!!, "video"))
}
return list
}
fun putDownloadsForProcessing(items: List<ResultItem?>) : LiveData<List<Long>> {
val result = MutableLiveData<List<Long>>()
viewModelScope.launch(Dispatchers.IO){
val list : MutableList<Long> = mutableListOf()
items.forEachIndexed { i, it ->
val tmpDownloadItem = createDownloadItemFromResult(it!!, "video")
val id = repository.insert(tmpDownloadItem)
list.add(id)
}
result.postValue(list)
}
return result
}
fun deleteProcessing() = viewModelScope.launch(Dispatchers.IO) {
repository.deleteProcessing()
}
}

@ -10,6 +10,7 @@ import com.deniscerri.ytdlnis.database.DBManager
import com.deniscerri.ytdlnis.database.dao.FormatDao
import com.deniscerri.ytdlnis.database.models.Format
import com.deniscerri.ytdlnis.database.models.ResultItem
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
import com.deniscerri.ytdlnis.database.repository.ResultRepository
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@ -111,7 +112,7 @@ class ResultViewModel(application: Application) : AndroidViewModel(application)
"video" -> {
list = list.filter { !it.format_note.contains("audio", ignoreCase = true) }
if (list.isEmpty()) {
videoFormats.forEach { formats.add(Format(0, item.id, it, "", 0, it, "")) }
videoFormats.forEach { formats.add(Format(0, item.id, it, "", 0, it)) }
return formats
}
return list
@ -120,7 +121,7 @@ class ResultViewModel(application: Application) : AndroidViewModel(application)
val templates = repository.getTemplates()
templates.forEach {
formats.add(Format(0, item.id, it.title, "", 0, it.content, ""))
formats.add(Format(0, item.id, it.title, "", 0, it.content))
}
return formats
}

@ -6,13 +6,13 @@ import java.util.*
class DownloadInfo {
var video: ResultItem? = null
var progress = 0
var downloadQueue: LinkedList<ResultItem>? = null
//var downloadQueue: LinkedList<ResultItem>? = null
var outputLine: String? = null
var downloadStatus: String? = null
var downloadPath: String? = null
var downloadType: String? = null
fun setDownloadQueue(downloadQueue: LinkedList<ResultItem>) {
this.downloadQueue = downloadQueue
video = downloadQueue.peek()
}
// fun setDownloadQueue(downloadQueue: LinkedList<ResultItem>) {
// this.downloadQueue = downloadQueue
// video = downloadQueue.peek()
// }
}

@ -23,13 +23,16 @@ import com.deniscerri.ytdlnis.MainActivity
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.adapter.HomeAdapter
import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.Format
import com.deniscerri.ytdlnis.database.models.ResultItem
import com.deniscerri.ytdlnis.database.models.ResultItemWithFormats
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding
import com.deniscerri.ytdlnis.service.DownloadInfo
import com.deniscerri.ytdlnis.ui.downloadcard.DownloadBottomSheetDialog
import com.deniscerri.ytdlnis.ui.downloadcard.DownloadMultipleBottomSheetDialog
import com.deniscerri.ytdlnis.util.FileUtil
import com.deniscerri.ytdlnis.util.InfoUtil
import com.facebook.shimmer.ShimmerFrameLayout
@ -42,6 +45,7 @@ import com.google.android.material.floatingactionbutton.ExtendedFloatingActionBu
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.progressindicator.LinearProgressIndicator
import java.util.*
import kotlin.collections.ArrayList
class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickListener {
private var progressBar: LinearProgressIndicator? = null
@ -166,12 +170,9 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
homeFabs = view.findViewById(R.id.home_fabs)
downloadFabs = homeFabs!!.findViewById(R.id.download_selected_coordinator)
downloadAllFabCoordinator = homeFabs!!.findViewById(R.id.download_all_coordinator)
val musicFab = downloadFabs!!.findViewById<FloatingActionButton>(R.id.audio_fab)
val videoFab = downloadFabs!!.findViewById<FloatingActionButton>(R.id.video_fab)
musicFab.tag = "SELECT##audio"
videoFab.tag = "SELECT##video"
musicFab.setOnClickListener(this)
videoFab.setOnClickListener(this)
val downloadSelectedFab = downloadFabs!!.findViewById<ExtendedFloatingActionButton>(R.id.download_selected_fab)
downloadSelectedFab.tag = "downloadSelected"
downloadSelectedFab.setOnClickListener(this)
val downloadAllFab =
downloadAllFabCoordinator!!.findViewById<ExtendedFloatingActionButton>(R.id.download_all_fab)
downloadAllFab.tag = "downloadAll"
@ -359,25 +360,11 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
}
private fun showSingleDownloadSheet(resultItem : ResultItem, type: String){
val sharedPreferences =
requireContext().getSharedPreferences("root_preferences", Activity.MODE_PRIVATE)
val embedSubs = sharedPreferences.getBoolean("embed_subtitles", false)
val addChapters = sharedPreferences.getBoolean("add_chapters", false)
val saveThumb = sharedPreferences.getBoolean("write_thumbnail", false)
val downloadItem = DownloadItem(0,
resultItem.url,
resultItem.title,
resultItem.author,
resultItem.thumb,
resultItem.duration,
type,
"", "", 0, "", false,
"", resultItem.website, "", resultItem.playlistTitle, embedSubs, addChapters, saveThumb, "",
"", DownloadRepository.status.Processing.toString(), 0
val item = ResultItemWithFormats(
resultItem,
resultViewModel.getFormats(resultItem, "video") as ArrayList<Format>
)
val downloadItem = downloadViewModel.createDownloadItemFromResult(resultItem, "video")
downloadViewModel.insertDownload(downloadItem).observe(viewLifecycleOwner) {
downloadItem.id = it
val bottomSheet = DownloadBottomSheetDialog(downloadItem)
@ -428,51 +415,27 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
override fun onClick(v: View) {
val viewIdName: String = try {
v.tag.toString()
} catch (e: Exception) {
""
}
} catch (e: Exception) {""}
if (viewIdName.isNotEmpty()) {
if (viewIdName.contains("audio") || viewIdName.contains("video")) {
val buttonData =
viewIdName.split("##".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
if (buttonData[0] == "SELECT") {
initSelectedDownload(buttonData[1])
if (viewIdName == "downloadSelected") {
val downloadList = downloadViewModel.turnResultItemstoDownloadItems(selectedObjects!!)
downloadViewModel.putDownloadsForProcessing(selectedObjects!!).observe(viewLifecycleOwner) {
it.forEachIndexed { i, itemID ->
downloadList[i].id = itemID
}
val bottomSheet = DownloadMultipleBottomSheetDialog(downloadList)
bottomSheet.show(parentFragmentManager, "downloadMultipleSheet")
}
}
if (viewIdName == "downloadAll") {
// //remove previously selected
// for (i in selectedObjects!!.indices) {
// val vid = findVideo(
// selectedObjects!![i].url
// )
// homeAdapter!!.notifyItemChanged(resultsList!!.indexOf(vid))
// }
// selectedObjects = ArrayList()
// downloadFabs!!.visibility = GONE
// bottomSheet = BottomSheetDialog(fragmentContext!!)
// bottomSheet!!.requestWindowFeature(Window.FEATURE_NO_TITLE)
// bottomSheet!!.setContentView(R.layout.home_download_all_bottom_sheet)
// val first = bottomSheet!!.findViewById<TextInputLayout>(R.id.first_textinput)
// first!!.editText!!.setText(1.toString())
// val last = bottomSheet!!.findViewById<TextInputLayout>(R.id.last_textinput)
// last!!.editText!!.setText(resultsList!!.size.toString())
// val audio = bottomSheet!!.findViewById<Button>(R.id.bottomsheet_audio_button)
// audio!!.setOnClickListener {
// val start = first.editText!!.text.toString().toInt()
// val end = last.editText!!.text.toString().toInt()
// initDownloadAll(bottomSheet!!, start, end, "audio")
// }
// val video = bottomSheet!!.findViewById<Button>(R.id.bottomsheet_video_button)
// video!!.setOnClickListener {
// val start = first.editText!!.text.toString().toInt()
// val end = last.editText!!.text.toString().toInt()
// initDownloadAll(bottomSheet!!, start, end, "video")
// }
// bottomSheet!!.show()
// bottomSheet!!.window!!.setLayout(
// ViewGroup.LayoutParams.MATCH_PARENT,
// ViewGroup.LayoutParams.MATCH_PARENT
// )
val downloadList = downloadViewModel.turnResultItemstoDownloadItems(resultsList!!)
downloadViewModel.putDownloadsForProcessing(resultsList!!).observe(viewLifecycleOwner) {
it.forEachIndexed { i, itemID ->
downloadList[i].id = itemID
}
val bottomSheet = DownloadMultipleBottomSheetDialog(downloadList)
bottomSheet.show(parentFragmentManager, "downloadMultipleSheet")
}
}
}
}
@ -518,31 +481,6 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
// }
}
private fun initSelectedDownload(type: String) {
// val sharedPreferences =
// context!!.getSharedPreferences("root_preferences", Activity.MODE_PRIVATE)
// val editor = sharedPreferences.edit()
// if (sharedPreferences.getBoolean("download_card", true)) {
// showConfigureDownloadCard(type)
// } else {
// for (i in selectedObjects!!.indices) {
// val vid = findVideo(
// selectedObjects!![i]!!.getURL()
// )
// vid!!.downloadedType = type
// updateDownloadingStatusOnResult(vid, type, true)
// homeAdapter!!.notifyItemChanged(resultsList!!.indexOf(vid))
// downloadQueue!!.add(vid)
// }
// selectedObjects = ArrayList()
// homeAdapter!!.clearCheckedVideos()
// downloadFabs!!.visibility = View.GONE
// if (isStoragePermissionGranted) {
// mainActivity!!.startDownloadService(downloadQueue, listener)
// downloadQueue!!.clear()
// }
// }
}
companion object {
private const val TAG = "HomeFragment"
}

@ -0,0 +1,127 @@
package com.deniscerri.ytdlnis.ui.downloadcard
import android.annotation.SuppressLint
import android.app.Dialog
import android.content.DialogInterface
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.widget.Button
import androidx.fragment.app.FragmentTransaction
import androidx.fragment.app.findFragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.adapter.ConfigureMultipleDownloadsAdapter
import com.deniscerri.ytdlnis.adapter.HomeAdapter
import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.google.android.material.button.MaterialButton
import com.google.android.material.tabs.TabLayout
class DownloadMultipleBottomSheetDialog(private val items: List<DownloadItem>) : BottomSheetDialogFragment(), ConfigureMultipleDownloadsAdapter.OnItemClickListener, View.OnClickListener {
private lateinit var downloadViewModel: DownloadViewModel
private lateinit var listAdapter : ConfigureMultipleDownloadsAdapter
private lateinit var recyclerView: RecyclerView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val behavior = BottomSheetBehavior.from(view.parent as View)
behavior.state = BottomSheetBehavior.STATE_EXPANDED
}
@SuppressLint("RestrictedApi")
override fun setupDialog(dialog: Dialog, style: Int) {
super.setupDialog(dialog, style)
val view = LayoutInflater.from(context).inflate(R.layout.download_multiple_bottom_sheet, null)
dialog.setContentView(view)
view.minimumHeight = resources.displayMetrics.heightPixels
listAdapter =
ConfigureMultipleDownloadsAdapter(
this,
requireActivity()
)
recyclerView = view.findViewById(R.id.downloadMultipleRecyclerview)
recyclerView.layoutManager = LinearLayoutManager(requireContext())
recyclerView.setHasFixedSize(true)
recyclerView.adapter = listAdapter
downloadViewModel.processingDownloads.observe(this) {
listAdapter.submitList(it)
if (it.isEmpty()){
dismiss()
}
}
val cancelBtn = view.findViewById<MaterialButton>(R.id.bottomsheet_cancel_button)
cancelBtn.setOnClickListener{
dismiss()
}
val download = view.findViewById<Button>(R.id.bottomsheet_download_button)
download!!.setOnClickListener {
// for (i in selectedObjects!!.indices) {
// val vid = findVideo(
// selectedObjects!![i]!!.getURL()
// )
// vid!!.downloadedType = type
// updateDownloadingStatusOnResult(vid, type, true)
// homeAdapter!!.notifyItemChanged(resultsList!!.indexOf(vid))
// downloadQueue!!.add(vid)
// }
// selectedObjects = ArrayList()
// homeAdapter!!.clearCheckedVideos()
// downloadFabs!!.visibility = View.GONE
// if (isStoragePermissionGranted) {
// mainActivity!!.startDownloadService(downloadQueue, listener)
// downloadQueue!!.clear()
// }
dismiss()
}
}
override fun onCancel(dialog: DialogInterface) {
super.onCancel(dialog)
cleanDownloads()
}
override fun onDismiss(dialog: DialogInterface) {
super.onDismiss(dialog)
cleanDownloads()
}
private fun cleanDownloads(){
parentFragmentManager.beginTransaction().remove(parentFragmentManager.findFragmentByTag("downloadMultipleSheet")!!).commit()
downloadViewModel.deleteProcessing()
}
override fun onButtonClick(videoURL: String, type: String?) {
TODO("Not yet implemented")
}
override fun onCardClick(itemID: Long) {
TODO("Not yet implemented")
}
override fun onClick(p0: View?) {
TODO("Not yet implemented")
}
}

@ -177,10 +177,9 @@ class DownloadWorker(
YoutubeDL.getInstance().execute(request, downloadItem.id.toString()){ progress, _, line ->
setProgressAsync(workDataOf("progress" to progress.toInt()))
val title: String = downloadItem.title
val queue = dao.getQueuedDownloads()
notificationUtil.updateDownloadNotification(
workID,
line, progress.toInt(), queue.size, title,
line, progress.toInt(), 0, title,
NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID
)
}

@ -1,36 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/downloads_card_constraintLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<com.google.android.material.button.MaterialButton
android:id="@+id/materialButton"
style="@style/Widget.Material3.Button.IconButton"
android:layout_width="wrap_content"
android:layout_width="28dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="end"
android:padding="0dp"
app:icon="@drawable/ic_handle" />
app:icon="@drawable/ic_handle"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/download_card_view"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.card.MaterialCardView
android:id="@+id/download_card_view"
android:layout_width="match_parent"
android:layout_height="95dp"
android:layout_width="wrap_content"
android:layout_height="100dp"
android:layout_margin="10dp"
android:checkable="true"
app:cardCornerRadius="10dp"
app:cardElevation="10dp"
app:cardMaxElevation="12dp"
app:cardPreventCornerOverlap="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/materialButton"
app:layout_constraintTop_toTopOf="parent"
app:strokeWidth="0dp">
@ -55,10 +56,19 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/title_author"
android:layout_width="300dp"
android:layout_height="70dp"
android:orientation="vertical"
app:layout_constraintEnd_toStartOf="@+id/downloads_download_button_type"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/title"
android:layout_width="296dp"
android:layout_height="41dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="10dp"
android:paddingTop="10dp"
android:paddingEnd="10dp"
@ -68,10 +78,7 @@
android:shadowRadius="2"
android:textColor="@color/white"
android:textSize="17sp"
android:textStyle="bold"
app:layout_constraintEnd_toStartOf="@+id/downloads_download_button_type"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
android:textStyle="bold" />
<TextView
android:id="@+id/author"
@ -87,28 +94,21 @@
android:shadowRadius="1.5"
android:textColor="@color/white"
android:textSize="12sp"
android:textStyle="bold"
app:layout_constraintEnd_toStartOf="@+id/downloads_download_button_type"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/title" />
android:textStyle="bold" />
</LinearLayout>
<TextView
android:id="@+id/container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/author"
app:layout_constraintVertical_bias="1.0" />
<TextView
android:id="@+id/encoding"
android:id="@+id/container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:text="Mp4"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/container" />
app:layout_constraintEnd_toStartOf="@+id/filesize"
app:layout_constraintTop_toBottomOf="@+id/downloads_download_button_type" />
<TextView
android:id="@+id/filesize"
@ -116,7 +116,7 @@
android:layout_height="wrap_content"
android:padding="5dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/encoding" />
app:layout_constraintEnd_toEndOf="parent" />
<com.google.android.material.button.MaterialButton
android:id="@+id/downloads_download_button_type"
@ -124,15 +124,16 @@
android:layout_width="55dp"
android:layout_height="55dp"
android:layout_margin="10dp"
android:layout_marginEnd="8dp"
app:cornerRadius="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.155" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

@ -1,16 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/constraintLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="10dp">
android:padding="10dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/bottom_sheet_title"
@ -48,22 +52,44 @@
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/coordinatorLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/constraintLayout">
<RelativeLayout
android:id="@+id/relativeLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/download_multiple_recyclerview"
android:id="@+id/downloadMultipleRecyclerview"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
android:layout_height="wrap_content"
android:paddingBottom="150dp"
android:focusableInTouchMode="true"
android:orientation="vertical"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
</RelativeLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<LinearLayout
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:orientation="horizontal"
android:padding="10dp"
android:orientation="horizontal">
app:layout_constraintBottom_toBottomOf="parent">
<Button
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
android:id="@+id/bottomsheet_schedule_button"
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
@ -77,25 +103,25 @@
android:orientation="horizontal">
<Button
style="@style/Widget.Material3.Button.OutlinedButton.Icon"
android:id="@+id/bottomsheet_cancel_button"
style="@style/Widget.Material3.Button.OutlinedButton.Icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/cancel"
android:layout_marginEnd="10dp"
android:text="@string/cancel"
app:icon="@drawable/ic_cancel" />
<Button
style="@style/Widget.Material3.Button.ElevatedButton.Icon"
android:id="@+id/bottomsheet_download_button"
style="@style/Widget.Material3.Button.ElevatedButton.Icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:autoLink="all"
android:text="@string/download"
app:icon="@drawable/ic_down"
android:autoLink="all"/>
app:icon="@drawable/ic_down" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

@ -122,43 +122,17 @@
android:visibility="gone"
android:layout_height="match_parent">
<androidx.cardview.widget.CardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
app:cardCornerRadius="20dp"
android:layout_margin="16dp"
>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/colorPrimaryContainer"
android:orientation="horizontal">
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/audio_fab"
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="@+id/download_selected_fab"
app:elevation="0dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_marginRight="5dp"
android:layout_margin="16dp"
app:icon="@drawable/ic_down"
android:text="@string/download"
app:srcCompat="@drawable/ic_music"/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/video_fab"
app:elevation="0dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_marginLeft="5dp"
app:srcCompat="@drawable/ic_video"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

Loading…
Cancel
Save