added tab layout on download queue screen
This commit is contained in:
parent
24fa1d1509
commit
895476aa01
20 changed files with 1100 additions and 283 deletions
|
|
@ -65,7 +65,7 @@
|
|||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".ui.DownloadQueueActivity"
|
||||
android:name=".ui.downloadqueue.DownloadQueueActivity"
|
||||
android:configChanges="layoutDirection|locale"
|
||||
android:parentActivityName=".MainActivity"
|
||||
android:exported="true">
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import androidx.work.WorkManager
|
|||
import com.deniscerri.ytdlnis.databinding.ActivityMainBinding
|
||||
import com.deniscerri.ytdlnis.service.IDownloaderListener
|
||||
import com.deniscerri.ytdlnis.service.IDownloaderService
|
||||
import com.deniscerri.ytdlnis.ui.DownloadQueueActivity
|
||||
import com.deniscerri.ytdlnis.ui.downloadqueue.DownloadQueueActivity
|
||||
import com.deniscerri.ytdlnis.ui.HistoryFragment
|
||||
import com.deniscerri.ytdlnis.ui.HomeFragment
|
||||
import com.deniscerri.ytdlnis.ui.more.MoreFragment
|
||||
|
|
|
|||
|
|
@ -0,0 +1,144 @@
|
|||
package com.deniscerri.ytdlnis.adapter
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.graphics.Color
|
||||
import android.graphics.ColorMatrix
|
||||
import android.graphics.ColorMatrixColorFilter
|
||||
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
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
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.HistoryItem
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
import com.squareup.picasso.Picasso
|
||||
import org.w3c.dom.Text
|
||||
import java.io.File
|
||||
import java.text.DateFormat
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
class CancelledDownloadAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<DownloadItem?, CancelledDownloadAdapter.ViewHolder>(AsyncDifferConfig.Builder(DIFF_CALLBACK).build()) {
|
||||
private val onItemClickListener: OnItemClickListener
|
||||
private val activity: Activity
|
||||
private var fileUtil: FileUtil
|
||||
|
||||
init {
|
||||
this.onItemClickListener = onItemClickListener
|
||||
this.activity = activity
|
||||
fileUtil = FileUtil()
|
||||
}
|
||||
|
||||
class ViewHolder(itemView: View, onItemClickListener: OnItemClickListener?) : RecyclerView.ViewHolder(itemView) {
|
||||
val cardView: MaterialCardView
|
||||
init {
|
||||
cardView = itemView.findViewById(R.id.queued_download_card_view)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val cardView = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.queued_download_card, parent, false)
|
||||
return ViewHolder(cardView, onItemClickListener)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val item = getItem(position)
|
||||
val card = holder.cardView
|
||||
// THUMBNAIL ----------------------------------
|
||||
val thumbnail = card.findViewById<ImageView>(R.id.image_view)
|
||||
val imageURL = item!!.thumb
|
||||
val uiHandler = Handler(Looper.getMainLooper())
|
||||
if (imageURL.isNotEmpty()) {
|
||||
uiHandler.post { Picasso.get().load(imageURL).into(thumbnail) }
|
||||
} else {
|
||||
uiHandler.post { Picasso.get().load(R.color.black).into(thumbnail) }
|
||||
}
|
||||
thumbnail.setColorFilter(Color.argb(95, 0, 0, 0))
|
||||
|
||||
// TITLE ----------------------------------
|
||||
val itemTitle = card.findViewById<TextView>(R.id.title)
|
||||
var title = item.title
|
||||
if (title.length > 100) {
|
||||
title = title.substring(0, 40) + "..."
|
||||
}
|
||||
itemTitle.text = title
|
||||
|
||||
val formatNote = card.findViewById<TextView>(R.id.format_note)
|
||||
formatNote.text = item.format.format_note
|
||||
val codec = card.findViewById<TextView>(R.id.codec)
|
||||
val codecText =
|
||||
if (item.format.encoding != "") {
|
||||
item.format.encoding.uppercase()
|
||||
}else if (item.format.vcodec != "none" && item.format.vcodec != ""){
|
||||
item.format.vcodec.uppercase()
|
||||
} else {
|
||||
item.format.acodec.uppercase()
|
||||
}
|
||||
if (codecText == "" || codecText == "none"){
|
||||
codec.visibility = View.GONE
|
||||
}else{
|
||||
codec.visibility = View.VISIBLE
|
||||
codec.text = codecText
|
||||
}
|
||||
|
||||
val fileSize = card.findViewById<TextView>(R.id.file_size)
|
||||
fileSize.text = fileUtil.convertFileSize(item.format.filesize)
|
||||
val downloadStartTime = card.findViewById<TextView>(R.id.time)
|
||||
val time = item.downloadStartTime
|
||||
if (time == 0L) {
|
||||
downloadStartTime.visibility = View.GONE
|
||||
} else {
|
||||
downloadStartTime.visibility = View.VISIBLE
|
||||
val cal = Calendar.getInstance()
|
||||
val date = Date(time * 1000L)
|
||||
cal.time = date
|
||||
val day = cal[Calendar.DAY_OF_MONTH]
|
||||
val month = cal.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.getDefault())
|
||||
val year = cal[Calendar.YEAR]
|
||||
val formatter: DateFormat = SimpleDateFormat("HH:mm", Locale.getDefault())
|
||||
val timeString = formatter.format(date)
|
||||
downloadStartTime.text = "$day $month $year - $timeString"
|
||||
}
|
||||
|
||||
// CANCEL BUTTON ----------------------------------
|
||||
val cancelButton = card.findViewById<MaterialButton>(R.id.queued_download_cancel)
|
||||
if (cancelButton.hasOnClickListeners()) cancelButton.setOnClickListener(null)
|
||||
|
||||
cancelButton.setOnClickListener {
|
||||
onItemClickListener.onQueuedCancelClick(item.id)
|
||||
}
|
||||
|
||||
}
|
||||
interface OnItemClickListener {
|
||||
fun onQueuedCancelClick(itemID: Long)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val DIFF_CALLBACK: DiffUtil.ItemCallback<DownloadItem> = object : DiffUtil.ItemCallback<DownloadItem>() {
|
||||
override fun areItemsTheSame(oldItem: DownloadItem, newItem: DownloadItem): Boolean {
|
||||
val ranged = arrayListOf(oldItem.id, newItem.id)
|
||||
return ranged[0] == ranged[1]
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: DownloadItem, newItem: DownloadItem): Boolean {
|
||||
return oldItem.url == newItem.url && oldItem.format.format_id == newItem.format.format_id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,144 @@
|
|||
package com.deniscerri.ytdlnis.adapter
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.graphics.Color
|
||||
import android.graphics.ColorMatrix
|
||||
import android.graphics.ColorMatrixColorFilter
|
||||
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
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
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.HistoryItem
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
import com.squareup.picasso.Picasso
|
||||
import org.w3c.dom.Text
|
||||
import java.io.File
|
||||
import java.text.DateFormat
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
class ErroredDownloadAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<DownloadItem?, ErroredDownloadAdapter.ViewHolder>(AsyncDifferConfig.Builder(DIFF_CALLBACK).build()) {
|
||||
private val onItemClickListener: OnItemClickListener
|
||||
private val activity: Activity
|
||||
private var fileUtil: FileUtil
|
||||
|
||||
init {
|
||||
this.onItemClickListener = onItemClickListener
|
||||
this.activity = activity
|
||||
fileUtil = FileUtil()
|
||||
}
|
||||
|
||||
class ViewHolder(itemView: View, onItemClickListener: OnItemClickListener?) : RecyclerView.ViewHolder(itemView) {
|
||||
val cardView: MaterialCardView
|
||||
init {
|
||||
cardView = itemView.findViewById(R.id.queued_download_card_view)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val cardView = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.queued_download_card, parent, false)
|
||||
return ViewHolder(cardView, onItemClickListener)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val item = getItem(position)
|
||||
val card = holder.cardView
|
||||
// THUMBNAIL ----------------------------------
|
||||
val thumbnail = card.findViewById<ImageView>(R.id.image_view)
|
||||
val imageURL = item!!.thumb
|
||||
val uiHandler = Handler(Looper.getMainLooper())
|
||||
if (imageURL.isNotEmpty()) {
|
||||
uiHandler.post { Picasso.get().load(imageURL).into(thumbnail) }
|
||||
} else {
|
||||
uiHandler.post { Picasso.get().load(R.color.black).into(thumbnail) }
|
||||
}
|
||||
thumbnail.setColorFilter(Color.argb(95, 0, 0, 0))
|
||||
|
||||
// TITLE ----------------------------------
|
||||
val itemTitle = card.findViewById<TextView>(R.id.title)
|
||||
var title = item.title
|
||||
if (title.length > 100) {
|
||||
title = title.substring(0, 40) + "..."
|
||||
}
|
||||
itemTitle.text = title
|
||||
|
||||
val formatNote = card.findViewById<TextView>(R.id.format_note)
|
||||
formatNote.text = item.format.format_note
|
||||
val codec = card.findViewById<TextView>(R.id.codec)
|
||||
val codecText =
|
||||
if (item.format.encoding != "") {
|
||||
item.format.encoding.uppercase()
|
||||
}else if (item.format.vcodec != "none" && item.format.vcodec != ""){
|
||||
item.format.vcodec.uppercase()
|
||||
} else {
|
||||
item.format.acodec.uppercase()
|
||||
}
|
||||
if (codecText == "" || codecText == "none"){
|
||||
codec.visibility = View.GONE
|
||||
}else{
|
||||
codec.visibility = View.VISIBLE
|
||||
codec.text = codecText
|
||||
}
|
||||
|
||||
val fileSize = card.findViewById<TextView>(R.id.file_size)
|
||||
fileSize.text = fileUtil.convertFileSize(item.format.filesize)
|
||||
val downloadStartTime = card.findViewById<TextView>(R.id.time)
|
||||
val time = item.downloadStartTime
|
||||
if (time == 0L) {
|
||||
downloadStartTime.visibility = View.GONE
|
||||
} else {
|
||||
downloadStartTime.visibility = View.VISIBLE
|
||||
val cal = Calendar.getInstance()
|
||||
val date = Date(time * 1000L)
|
||||
cal.time = date
|
||||
val day = cal[Calendar.DAY_OF_MONTH]
|
||||
val month = cal.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.getDefault())
|
||||
val year = cal[Calendar.YEAR]
|
||||
val formatter: DateFormat = SimpleDateFormat("HH:mm", Locale.getDefault())
|
||||
val timeString = formatter.format(date)
|
||||
downloadStartTime.text = "$day $month $year - $timeString"
|
||||
}
|
||||
|
||||
// CANCEL BUTTON ----------------------------------
|
||||
val cancelButton = card.findViewById<MaterialButton>(R.id.queued_download_cancel)
|
||||
if (cancelButton.hasOnClickListeners()) cancelButton.setOnClickListener(null)
|
||||
|
||||
cancelButton.setOnClickListener {
|
||||
onItemClickListener.onQueuedCancelClick(item.id)
|
||||
}
|
||||
|
||||
}
|
||||
interface OnItemClickListener {
|
||||
fun onQueuedCancelClick(itemID: Long)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val DIFF_CALLBACK: DiffUtil.ItemCallback<DownloadItem> = object : DiffUtil.ItemCallback<DownloadItem>() {
|
||||
override fun areItemsTheSame(oldItem: DownloadItem, newItem: DownloadItem): Boolean {
|
||||
val ranged = arrayListOf(oldItem.id, newItem.id)
|
||||
return ranged[0] == ranged[1]
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: DownloadItem, newItem: DownloadItem): Boolean {
|
||||
return oldItem.url == newItem.url && oldItem.format.format_id == newItem.format.format_id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -79,15 +79,6 @@ class QueuedDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
|
|||
}
|
||||
itemTitle.text = title
|
||||
|
||||
// Author ----------------------------------
|
||||
val author = card.findViewById<TextView>(R.id.author)
|
||||
var info = item.author
|
||||
if (item.duration.isNotEmpty()) {
|
||||
if (item.author.isNotEmpty()) info += " • "
|
||||
info += item.duration
|
||||
}
|
||||
author.text = info
|
||||
|
||||
val formatNote = card.findViewById<TextView>(R.id.format_note)
|
||||
formatNote.text = item.format.format_note
|
||||
val codec = card.findViewById<TextView>(R.id.codec)
|
||||
|
|
|
|||
|
|
@ -16,6 +16,12 @@ interface DownloadDao {
|
|||
@Query("SELECT * FROM downloads WHERE status='Queued'")
|
||||
fun getQueuedDownloads() : LiveData<List<DownloadItem>>
|
||||
|
||||
@Query("SELECT * FROM downloads WHERE status='Cancelled'")
|
||||
fun getCancelledDownloads() : LiveData<List<DownloadItem>>
|
||||
|
||||
@Query("SELECT * FROM downloads WHERE status='Error'")
|
||||
fun getErroredDownloads() : LiveData<List<DownloadItem>>
|
||||
|
||||
@Query("SELECT * FROM downloads WHERE status='Processing'")
|
||||
fun getProcessingDownloads() : LiveData<List<DownloadItem>>
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ 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 cancelledDownloads : LiveData<List<DownloadItem>> = downloadDao.getCancelledDownloads()
|
||||
val erroredDownloads : LiveData<List<DownloadItem>> = downloadDao.getErroredDownloads()
|
||||
val processingDownloads : LiveData<List<DownloadItem>> = downloadDao.getProcessingDownloads()
|
||||
|
||||
enum class Status {
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
val allDownloads : LiveData<List<DownloadItem>>
|
||||
val queuedDownloads : LiveData<List<DownloadItem>>
|
||||
val activeDownloads : LiveData<List<DownloadItem>>
|
||||
val cancelledDownloads : LiveData<List<DownloadItem>>
|
||||
val erroredDownloads : LiveData<List<DownloadItem>>
|
||||
val processingDownloads : LiveData<List<DownloadItem>>
|
||||
|
||||
private var bestVideoFormat : Format
|
||||
|
|
@ -51,6 +53,8 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
queuedDownloads = repository.queuedDownloads
|
||||
activeDownloads = repository.activeDownloads
|
||||
processingDownloads = repository.processingDownloads
|
||||
cancelledDownloads = repository.cancelledDownloads
|
||||
erroredDownloads = repository.erroredDownloads
|
||||
|
||||
val videoFormat = getApplication<App>().resources.getStringArray(R.array.video_formats)
|
||||
val videoContainer = sharedPreferences.getString("video_format", "Default")
|
||||
|
|
|
|||
|
|
@ -1,188 +0,0 @@
|
|||
package com.deniscerri.ytdlnis.ui
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.RelativeLayout
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.work.WorkManager
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.adapter.ActiveDownloadAdapter
|
||||
import com.deniscerri.ytdlnis.adapter.QueuedDownloadAdapter
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdlnis.util.NotificationUtil
|
||||
import com.google.android.material.appbar.MaterialToolbar
|
||||
import com.google.android.material.progressindicator.LinearProgressIndicator
|
||||
import com.yausername.youtubedl_android.YoutubeDL
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.File
|
||||
|
||||
|
||||
class DownloadQueueActivity : AppCompatActivity(), ActiveDownloadAdapter.OnItemClickListener, QueuedDownloadAdapter.OnItemClickListener {
|
||||
private lateinit var activeRecyclerView: RecyclerView
|
||||
private lateinit var activeDownloads: ActiveDownloadAdapter
|
||||
private lateinit var queuedRecyclerView: RecyclerView
|
||||
private lateinit var queuedDownloads: QueuedDownloadAdapter
|
||||
private lateinit var noResults: RelativeLayout
|
||||
private lateinit var downloadViewModel: DownloadViewModel
|
||||
private lateinit var topAppBar: MaterialToolbar
|
||||
private lateinit var notificationUtil: NotificationUtil
|
||||
|
||||
private lateinit var runningLayout: LinearLayout
|
||||
private lateinit var queuedLayout: LinearLayout
|
||||
var context: Context? = null
|
||||
|
||||
public override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_download_queue)
|
||||
context = baseContext
|
||||
val view : View = window.decorView.findViewById(android.R.id.content)
|
||||
|
||||
|
||||
topAppBar = findViewById(R.id.logs_toolbar)
|
||||
topAppBar.setNavigationOnClickListener { onBackPressedDispatcher.onBackPressed() }
|
||||
|
||||
activeDownloads =
|
||||
ActiveDownloadAdapter(
|
||||
this,
|
||||
this@DownloadQueueActivity
|
||||
)
|
||||
|
||||
queuedDownloads =
|
||||
QueuedDownloadAdapter(
|
||||
this,
|
||||
this@DownloadQueueActivity
|
||||
)
|
||||
|
||||
val landScapeOrTablet = resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE || resources.getBoolean(R.bool.isTablet)
|
||||
|
||||
|
||||
activeRecyclerView = findViewById(R.id.active_recyclerview)
|
||||
if (landScapeOrTablet){
|
||||
activeRecyclerView.layoutManager = GridLayoutManager(context, 2)
|
||||
}else{
|
||||
activeRecyclerView.layoutManager = LinearLayoutManager(context)
|
||||
}
|
||||
activeRecyclerView.adapter = activeDownloads
|
||||
|
||||
queuedRecyclerView = findViewById(R.id.queued_recyclerview)
|
||||
if (landScapeOrTablet){
|
||||
queuedRecyclerView.layoutManager = GridLayoutManager(context, 2)
|
||||
}else{
|
||||
queuedRecyclerView.layoutManager = LinearLayoutManager(context)
|
||||
}
|
||||
queuedRecyclerView.adapter = queuedDownloads
|
||||
|
||||
noResults = findViewById(R.id.no_results)
|
||||
noResults.visibility = View.GONE
|
||||
|
||||
runningLayout = findViewById(R.id.running_layout)
|
||||
queuedLayout = findViewById(R.id.queued_layout)
|
||||
|
||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
notificationUtil = NotificationUtil(this)
|
||||
|
||||
|
||||
//active downloads livedata
|
||||
downloadViewModel.activeDownloads.observe(this) {
|
||||
activeDownloads.submitList(it)
|
||||
if (it.isEmpty()){
|
||||
if (queuedLayout.visibility == View.GONE) noResults.visibility = View.VISIBLE
|
||||
runningLayout.visibility = View.GONE
|
||||
}else{
|
||||
noResults.visibility = View.GONE
|
||||
runningLayout.visibility = View.VISIBLE
|
||||
|
||||
it.forEach{item ->
|
||||
WorkManager.getInstance(this)
|
||||
.getWorkInfosForUniqueWorkLiveData(item.id.toString())
|
||||
.observe(this){ list ->
|
||||
list.forEach {work ->
|
||||
if (work == null) return@observe
|
||||
val id = work.progress.getLong("id", 0L)
|
||||
if(id == 0L) return@observe
|
||||
|
||||
val progress = work.progress.getInt("progress", 0)
|
||||
val output = work.progress.getString("output")
|
||||
|
||||
val progressBar = view.findViewWithTag<LinearProgressIndicator>("$id##progress")
|
||||
val outputText = view.findViewWithTag<TextView>("$id##output")
|
||||
|
||||
runOnUiThread {
|
||||
progressBar.setProgressCompat(progress, true)
|
||||
outputText.text = output
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//queued downloads livedata
|
||||
downloadViewModel.queuedDownloads.observe(this) {
|
||||
queuedDownloads.submitList(it)
|
||||
if (it.isEmpty()){
|
||||
if (runningLayout.visibility == View.GONE) noResults.visibility = View.VISIBLE
|
||||
queuedLayout.visibility = View.GONE
|
||||
}else{
|
||||
noResults.visibility = View.GONE
|
||||
queuedLayout.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun initMenu(logFolder: File) {
|
||||
topAppBar.setOnMenuItemClickListener { m: MenuItem ->
|
||||
val itemId = m.itemId
|
||||
if (itemId == R.id.remove_logs) {
|
||||
try{
|
||||
logFolder.listFiles()!!.forEach {
|
||||
it.delete()
|
||||
}
|
||||
}catch (e: Exception){
|
||||
Toast.makeText(context, e.message, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
private const val TAG = "DownloadQueueActivity"
|
||||
}
|
||||
|
||||
override fun onCancelClick(itemID: Long) {
|
||||
cancelDownload(itemID)
|
||||
}
|
||||
|
||||
override fun onQueuedCancelClick(itemID: Long) {
|
||||
lifecycleScope.launch{
|
||||
withContext(Dispatchers.IO){
|
||||
downloadViewModel.deleteDownload(downloadViewModel.getItemByID(itemID))
|
||||
}
|
||||
}
|
||||
cancelDownload(itemID)
|
||||
}
|
||||
|
||||
private fun cancelDownload(itemID: Long){
|
||||
val id = itemID.toInt()
|
||||
YoutubeDL.getInstance().destroyProcessById(id.toString())
|
||||
WorkManager.getInstance(this).cancelUniqueWork(id.toString())
|
||||
notificationUtil.cancelDownloadNotification(id)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
package com.deniscerri.ytdlnis.ui.downloadqueue
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.res.Configuration
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.View.OnClickListener
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.work.WorkManager
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.adapter.ActiveDownloadAdapter
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding
|
||||
import com.deniscerri.ytdlnis.util.NotificationUtil
|
||||
import com.google.android.material.progressindicator.LinearProgressIndicator
|
||||
import com.yausername.youtubedl_android.YoutubeDL
|
||||
|
||||
|
||||
class ActiveDownloadsFragment() : Fragment(), ActiveDownloadAdapter.OnItemClickListener, OnClickListener {
|
||||
private var _binding : FragmentHomeBinding? = null
|
||||
private var fragmentView: View? = null
|
||||
private var activity: Activity? = null
|
||||
private lateinit var downloadViewModel : DownloadViewModel
|
||||
private lateinit var activeRecyclerView : RecyclerView
|
||||
private lateinit var activeDownloads : ActiveDownloadAdapter
|
||||
lateinit var downloadItem: DownloadItem
|
||||
private lateinit var notificationUtil: NotificationUtil
|
||||
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
_binding = FragmentHomeBinding.inflate(inflater, container, false)
|
||||
fragmentView = inflater.inflate(R.layout.fragment_generic_download_queue, container, false)
|
||||
activity = getActivity()
|
||||
notificationUtil = NotificationUtil(requireContext())
|
||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
return fragmentView
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
activeDownloads =
|
||||
ActiveDownloadAdapter(
|
||||
this,
|
||||
requireActivity()
|
||||
)
|
||||
|
||||
activeRecyclerView = view.findViewById(R.id.download_recyclerview)
|
||||
activeRecyclerView.adapter = activeDownloads
|
||||
|
||||
val landScapeOrTablet = resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE || resources.getBoolean(R.bool.isTablet)
|
||||
if (landScapeOrTablet){
|
||||
activeRecyclerView.layoutManager = GridLayoutManager(context, 2)
|
||||
}else{
|
||||
activeRecyclerView.layoutManager = LinearLayoutManager(context)
|
||||
}
|
||||
|
||||
downloadViewModel.activeDownloads.observe(viewLifecycleOwner) {
|
||||
activeDownloads.submitList(it)
|
||||
it.forEach{item ->
|
||||
WorkManager.getInstance(requireContext())
|
||||
.getWorkInfosForUniqueWorkLiveData(item.id.toString())
|
||||
.observe(viewLifecycleOwner){ list ->
|
||||
list.forEach {work ->
|
||||
if (work == null) return@observe
|
||||
val id = work.progress.getLong("id", 0L)
|
||||
if(id == 0L) return@observe
|
||||
|
||||
val progress = work.progress.getInt("progress", 0)
|
||||
val output = work.progress.getString("output")
|
||||
|
||||
val progressBar = view.findViewWithTag<LinearProgressIndicator>("$id##progress")
|
||||
val outputText = view.findViewWithTag<TextView>("$id##output")
|
||||
|
||||
requireActivity().runOnUiThread {
|
||||
progressBar.setProgressCompat(progress, true)
|
||||
outputText.text = output
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCancelClick(itemID: Long) {
|
||||
cancelDownload(itemID)
|
||||
}
|
||||
|
||||
private fun cancelDownload(itemID: Long){
|
||||
val id = itemID.toInt()
|
||||
YoutubeDL.getInstance().destroyProcessById(id.toString())
|
||||
WorkManager.getInstance(requireContext()).cancelUniqueWork(id.toString())
|
||||
notificationUtil.cancelDownloadNotification(id)
|
||||
}
|
||||
|
||||
override fun onClick(p0: View?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
package com.deniscerri.ytdlnis.ui.downloadqueue
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.content.res.Configuration
|
||||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.AdapterView
|
||||
import android.widget.AdapterView.OnItemClickListener
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.AutoCompleteTextView
|
||||
import android.widget.TextView
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.work.WorkManager
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.adapter.ActiveDownloadAdapter
|
||||
import com.deniscerri.ytdlnis.adapter.CancelledDownloadAdapter
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.models.Format
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel.Type
|
||||
import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding
|
||||
import com.deniscerri.ytdlnis.ui.downloadcard.FormatSelectionBottomSheetDialog
|
||||
import com.deniscerri.ytdlnis.ui.downloadcard.OnFormatClickListener
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.deniscerri.ytdlnis.util.UiUtil
|
||||
import com.google.android.material.chip.Chip
|
||||
import com.google.android.material.progressindicator.LinearProgressIndicator
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
||||
class CancelledDownloadsFragment() : Fragment(), CancelledDownloadAdapter.OnItemClickListener, OnItemClickListener {
|
||||
private var _binding : FragmentHomeBinding? = null
|
||||
private var fragmentView: View? = null
|
||||
private var activity: Activity? = null
|
||||
private lateinit var downloadViewModel : DownloadViewModel
|
||||
private lateinit var cancelledRecyclerView : RecyclerView
|
||||
private lateinit var cancelledDownloads : CancelledDownloadAdapter
|
||||
lateinit var downloadItem: DownloadItem
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
_binding = FragmentHomeBinding.inflate(inflater, container, false)
|
||||
fragmentView = inflater.inflate(R.layout.fragment_generic_download_queue, container, false)
|
||||
activity = getActivity()
|
||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
return fragmentView
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
cancelledDownloads =
|
||||
CancelledDownloadAdapter(
|
||||
this,
|
||||
requireActivity()
|
||||
)
|
||||
|
||||
cancelledRecyclerView = view.findViewById(R.id.download_recyclerview)
|
||||
cancelledRecyclerView.adapter = cancelledDownloads
|
||||
|
||||
val landScapeOrTablet = resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE || resources.getBoolean(R.bool.isTablet)
|
||||
if (landScapeOrTablet){
|
||||
cancelledRecyclerView.layoutManager = GridLayoutManager(context, 2)
|
||||
}else{
|
||||
cancelledRecyclerView.layoutManager = LinearLayoutManager(context)
|
||||
}
|
||||
|
||||
downloadViewModel.cancelledDownloads.observe(viewLifecycleOwner) {
|
||||
cancelledDownloads.submitList(it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onQueuedCancelClick(itemID: Long) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun onItemClick(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package com.deniscerri.ytdlnis.ui.downloadqueue
|
||||
|
||||
import android.util.Log
|
||||
import androidx.annotation.NonNull
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||
import com.google.gson.Gson
|
||||
|
||||
class DownloadListFragmentAdapter (
|
||||
fragmentManager : FragmentManager,
|
||||
lifecycle : Lifecycle,
|
||||
private val fragments: List<Fragment>
|
||||
) : FragmentStateAdapter(fragmentManager, lifecycle) {
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return fragments.size
|
||||
}
|
||||
|
||||
override fun createFragment(position: Int): Fragment {
|
||||
return fragments[position]
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
package com.deniscerri.ytdlnis.ui.downloadqueue
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.RelativeLayout
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
import androidx.work.WorkManager
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.adapter.ActiveDownloadAdapter
|
||||
import com.deniscerri.ytdlnis.adapter.QueuedDownloadAdapter
|
||||
import com.deniscerri.ytdlnis.database.dao.CommandTemplateDao
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdlnis.ui.downloadcard.*
|
||||
import com.deniscerri.ytdlnis.util.NotificationUtil
|
||||
import com.google.android.material.appbar.MaterialToolbar
|
||||
import com.google.android.material.progressindicator.LinearProgressIndicator
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
import com.yausername.youtubedl_android.YoutubeDL
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.File
|
||||
|
||||
|
||||
class DownloadQueueActivity : AppCompatActivity(){
|
||||
private lateinit var downloadViewModel: DownloadViewModel
|
||||
private lateinit var topAppBar: MaterialToolbar
|
||||
|
||||
private lateinit var tabLayout: TabLayout
|
||||
private lateinit var viewPager2: ViewPager2
|
||||
private lateinit var fragmentAdapter : DownloadListFragmentAdapter
|
||||
var context: Context? = null
|
||||
|
||||
public override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_download_queue)
|
||||
context = baseContext
|
||||
val view : View = window.decorView.findViewById(android.R.id.content)
|
||||
|
||||
|
||||
topAppBar = findViewById(R.id.logs_toolbar)
|
||||
topAppBar.setNavigationOnClickListener { onBackPressedDispatcher.onBackPressed() }
|
||||
|
||||
tabLayout = view.findViewById(R.id.download_tablayout)
|
||||
viewPager2 = view.findViewById(R.id.download_viewpager)
|
||||
|
||||
(viewPager2.getChildAt(0) as? RecyclerView)?.apply {
|
||||
isNestedScrollingEnabled = false
|
||||
overScrollMode = View.OVER_SCROLL_NEVER
|
||||
}
|
||||
|
||||
val fragments = mutableListOf(ActiveDownloadsFragment(), QueuedDownloadsFragment(), CancelledDownloadsFragment(), ErroredDownloadsFragment())
|
||||
//
|
||||
// lifecycleScope.launch{
|
||||
// withContext(Dispatchers.IO){
|
||||
// val active = commandTemplateDao.getTotalNumber()
|
||||
// if(nr > 0){
|
||||
// fragments.add(DownloadCommandFragment(resultItem))
|
||||
// }else{
|
||||
// (tabLayout.getChildAt(0) as? ViewGroup)?.getChildAt(2)?.isEnabled = false
|
||||
// (tabLayout.getChildAt(0) as? ViewGroup)?.getChildAt(2)?.alpha = 0.3f
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
fragmentAdapter = DownloadListFragmentAdapter(
|
||||
supportFragmentManager,
|
||||
lifecycle,
|
||||
fragments
|
||||
)
|
||||
|
||||
viewPager2.adapter = fragmentAdapter
|
||||
viewPager2.isSaveFromParentEnabled = false
|
||||
|
||||
tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
|
||||
override fun onTabSelected(tab: TabLayout.Tab?) {
|
||||
viewPager2.setCurrentItem(tab!!.position, true)
|
||||
}
|
||||
|
||||
override fun onTabUnselected(tab: TabLayout.Tab?) {
|
||||
}
|
||||
|
||||
override fun onTabReselected(tab: TabLayout.Tab?) {
|
||||
}
|
||||
})
|
||||
|
||||
viewPager2.registerOnPageChangeCallback(object: ViewPager2.OnPageChangeCallback() {
|
||||
override fun onPageSelected(position: Int) {
|
||||
tabLayout.selectTab(tabLayout.getTabAt(position))
|
||||
}
|
||||
})
|
||||
|
||||
//initMenu()
|
||||
}
|
||||
|
||||
// private fun initMenu() {
|
||||
// topAppBar.setOnMenuItemClickListener { m: MenuItem ->
|
||||
// val itemId = m.itemId
|
||||
// if (itemId == R.id.remove_logs) {
|
||||
// try{
|
||||
// logFolder.listFiles()!!.forEach {
|
||||
// it.delete()
|
||||
// }
|
||||
// }catch (e: Exception){
|
||||
// Toast.makeText(context, e.message, Toast.LENGTH_LONG).show()
|
||||
// }
|
||||
// }
|
||||
// true
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
companion object {
|
||||
private const val TAG = "DownloadQueueActivity"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
package com.deniscerri.ytdlnis.ui.downloadqueue
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.content.res.Configuration
|
||||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.AdapterView
|
||||
import android.widget.AdapterView.OnItemClickListener
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.AutoCompleteTextView
|
||||
import android.widget.TextView
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.work.WorkManager
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.adapter.ActiveDownloadAdapter
|
||||
import com.deniscerri.ytdlnis.adapter.ErroredDownloadAdapter
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.models.Format
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel.Type
|
||||
import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding
|
||||
import com.deniscerri.ytdlnis.ui.downloadcard.FormatSelectionBottomSheetDialog
|
||||
import com.deniscerri.ytdlnis.ui.downloadcard.OnFormatClickListener
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.deniscerri.ytdlnis.util.UiUtil
|
||||
import com.google.android.material.chip.Chip
|
||||
import com.google.android.material.progressindicator.LinearProgressIndicator
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
||||
class ErroredDownloadsFragment() : Fragment(), ErroredDownloadAdapter.OnItemClickListener, OnItemClickListener {
|
||||
private var _binding : FragmentHomeBinding? = null
|
||||
private var fragmentView: View? = null
|
||||
private var activity: Activity? = null
|
||||
private lateinit var downloadViewModel : DownloadViewModel
|
||||
private lateinit var erroredRecyclerView : RecyclerView
|
||||
private lateinit var erroredDownloads : ErroredDownloadAdapter
|
||||
lateinit var downloadItem: DownloadItem
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
_binding = FragmentHomeBinding.inflate(inflater, container, false)
|
||||
fragmentView = inflater.inflate(R.layout.fragment_generic_download_queue, container, false)
|
||||
activity = getActivity()
|
||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
return fragmentView
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
erroredDownloads =
|
||||
ErroredDownloadAdapter(
|
||||
this,
|
||||
requireActivity()
|
||||
)
|
||||
|
||||
erroredRecyclerView = view.findViewById(R.id.download_recyclerview)
|
||||
erroredRecyclerView.adapter = erroredDownloads
|
||||
|
||||
val landScapeOrTablet = resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE || resources.getBoolean(R.bool.isTablet)
|
||||
if (landScapeOrTablet){
|
||||
erroredRecyclerView.layoutManager = GridLayoutManager(context, 2)
|
||||
}else{
|
||||
erroredRecyclerView.layoutManager = LinearLayoutManager(context)
|
||||
}
|
||||
|
||||
downloadViewModel.erroredDownloads.observe(viewLifecycleOwner) {
|
||||
erroredDownloads.submitList(it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onQueuedCancelClick(itemID: Long) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun onItemClick(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
package com.deniscerri.ytdlnis.ui.downloadqueue
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.content.res.Configuration
|
||||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.View.OnClickListener
|
||||
import android.view.ViewGroup
|
||||
import android.widget.AdapterView
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.AutoCompleteTextView
|
||||
import android.widget.TextView
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.work.WorkManager
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.adapter.ActiveDownloadAdapter
|
||||
import com.deniscerri.ytdlnis.adapter.QueuedDownloadAdapter
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.models.Format
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel.Type
|
||||
import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding
|
||||
import com.deniscerri.ytdlnis.ui.downloadcard.FormatSelectionBottomSheetDialog
|
||||
import com.deniscerri.ytdlnis.ui.downloadcard.OnFormatClickListener
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.deniscerri.ytdlnis.util.NotificationUtil
|
||||
import com.deniscerri.ytdlnis.util.UiUtil
|
||||
import com.google.android.material.chip.Chip
|
||||
import com.google.android.material.progressindicator.LinearProgressIndicator
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import com.yausername.youtubedl_android.YoutubeDL
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
|
||||
class QueuedDownloadsFragment() : Fragment(), QueuedDownloadAdapter.OnItemClickListener, OnClickListener {
|
||||
private var _binding : FragmentHomeBinding? = null
|
||||
private var fragmentView: View? = null
|
||||
private var activity: Activity? = null
|
||||
private lateinit var downloadViewModel : DownloadViewModel
|
||||
private lateinit var queuedRecyclerView : RecyclerView
|
||||
private lateinit var queuedDownloads : QueuedDownloadAdapter
|
||||
private lateinit var notificationUtil: NotificationUtil
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
_binding = FragmentHomeBinding.inflate(inflater, container, false)
|
||||
fragmentView = inflater.inflate(R.layout.fragment_generic_download_queue, container, false)
|
||||
activity = getActivity()
|
||||
notificationUtil = NotificationUtil(requireContext())
|
||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
return fragmentView
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
queuedDownloads =
|
||||
QueuedDownloadAdapter(
|
||||
this,
|
||||
requireActivity()
|
||||
)
|
||||
|
||||
queuedRecyclerView = view.findViewById(R.id.download_recyclerview)
|
||||
queuedRecyclerView.adapter = queuedDownloads
|
||||
|
||||
val landScapeOrTablet = resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE || resources.getBoolean(R.bool.isTablet)
|
||||
if (landScapeOrTablet){
|
||||
queuedRecyclerView.layoutManager = GridLayoutManager(context, 2)
|
||||
}else{
|
||||
queuedRecyclerView.layoutManager = LinearLayoutManager(context)
|
||||
}
|
||||
|
||||
downloadViewModel.queuedDownloads.observe(viewLifecycleOwner) {
|
||||
queuedDownloads.submitList(it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onQueuedCancelClick(itemID: Long) {
|
||||
lifecycleScope.launch{
|
||||
withContext(Dispatchers.IO){
|
||||
downloadViewModel.deleteDownload(downloadViewModel.getItemByID(itemID))
|
||||
}
|
||||
}
|
||||
cancelDownload(itemID)
|
||||
}
|
||||
|
||||
private fun cancelDownload(itemID: Long){
|
||||
val id = itemID.toInt()
|
||||
YoutubeDL.getInstance().destroyProcessById(id.toString())
|
||||
WorkManager.getInstance(requireContext()).cancelUniqueWork(id.toString())
|
||||
notificationUtil.cancelDownloadNotification(id)
|
||||
}
|
||||
|
||||
override fun onClick(p0: View?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -24,74 +24,49 @@
|
|||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
<LinearLayout
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
android:layout_width="match_parent"
|
||||
android:scrollbars="none"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:padding="10dp"
|
||||
android:orientation="vertical"
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/download_tablayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
android:backgroundTint="@android:color/transparent"
|
||||
app:tabGravity="fill"
|
||||
app:tabMode="scrollable">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/running_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
<com.google.android.material.tabs.TabItem
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@string/running" />
|
||||
|
||||
<TextView
|
||||
android:padding="10dp"
|
||||
android:textSize="15sp"
|
||||
android:textStyle="bold"
|
||||
android:text="@string/running"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
<com.google.android.material.tabs.TabItem
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@string/added_to_queue" />
|
||||
|
||||
<com.google.android.material.tabs.TabItem
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@string/cancelled" />
|
||||
|
||||
<com.google.android.material.tabs.TabItem
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@string/errored" />
|
||||
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/active_recyclerview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipToPadding="false"
|
||||
>
|
||||
|
||||
</androidx.recyclerview.widget.RecyclerView>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/queued_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:padding="10dp"
|
||||
android:textSize="15sp"
|
||||
android:textStyle="bold"
|
||||
android:text="@string/added_to_queue"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/queued_recyclerview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipToPadding="false"
|
||||
>
|
||||
|
||||
</androidx.recyclerview.widget.RecyclerView>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
</com.google.android.material.tabs.TabLayout>
|
||||
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/download_viewpager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
</LinearLayout>
|
||||
<include layout="@layout/history_no_results"
|
||||
android:visibility="gone" />
|
||||
|
||||
|
|
|
|||
160
app/src/main/res/layout/errored_download_card.xml
Normal file
160
app/src/main/res/layout/errored_download_card.xml
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout 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"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/queued_download_relative_layout"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintDimensionRatio="H,3:1"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/queued_download_card_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:cardCornerRadius="10dp"
|
||||
app:cardMaxElevation="12dp"
|
||||
android:checkable="true"
|
||||
app:strokeWidth="0dp"
|
||||
app:cardPreventCornerOverlap="true"
|
||||
android:layout_margin="10dp">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/image_view"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="centerCrop"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="10dp"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingEnd="10dp"
|
||||
android:paddingBottom="10dp"
|
||||
android:shadowColor="@color/black"
|
||||
android:shadowDx="4"
|
||||
android:shadowDy="4"
|
||||
android:shadowRadius="2"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="15sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toStartOf="@+id/queued_download_cancel"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_bias="0.0" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/queued_download_cancel"
|
||||
style="@style/Widget.Material3.ExtendedFloatingActionButton.Icon.Secondary"
|
||||
android:layout_width="55dp"
|
||||
android:layout_height="55dp"
|
||||
android:layout_margin="15dp"
|
||||
app:cornerRadius="10dp"
|
||||
app:icon="@drawable/ic_baseline_delete_outline_24"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/format_note"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="10dp"
|
||||
android:textSize="15sp"
|
||||
android:shadowColor="@color/black"
|
||||
android:shadowDx="4"
|
||||
android:shadowDy="4"
|
||||
android:shadowRadius="1.5"
|
||||
android:textColor="@color/white"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/title"
|
||||
app:layout_constraintVertical_bias="1.0" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/linearLayout3"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
android:orientation="horizontal"
|
||||
android:padding="10dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/format_note">
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/codec"
|
||||
style="@style/Widget.Material3.FloatingActionButton.Large.Secondary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:background="?attr/colorSecondary"
|
||||
android:clickable="false"
|
||||
android:gravity="center"
|
||||
android:minWidth="30dp"
|
||||
android:paddingHorizontal="10dp"
|
||||
app:cornerRadius="10dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/file_size"
|
||||
style="@style/Widget.Material3.FloatingActionButton.Large.Tertiary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:background="?attr/colorSecondary"
|
||||
android:clickable="false"
|
||||
android:gravity="center"
|
||||
android:minWidth="30dp"
|
||||
android:paddingHorizontal="10dp"
|
||||
app:cornerRadius="10dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/time"
|
||||
style="@style/Widget.Material3.FloatingActionButton.Large.Primary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:background="?attr/colorPrimary"
|
||||
android:clickable="false"
|
||||
android:gravity="center"
|
||||
android:minWidth="30dp"
|
||||
android:paddingHorizontal="10dp"
|
||||
app:cornerRadius="10dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
</RelativeLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
17
app/src/main/res/layout/fragment_generic_download_queue.xml
Normal file
17
app/src/main/res/layout/fragment_generic_download_queue.xml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fillViewport="true"
|
||||
android:scrollbars="none">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/download_recyclerview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
</androidx.recyclerview.widget.RecyclerView>
|
||||
|
||||
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
android:id="@+id/queued_download_relative_layout"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintDimensionRatio="H,2.66:1"
|
||||
app:layout_constraintDimensionRatio="H,3:1"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
|
@ -20,7 +20,6 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:cardCornerRadius="10dp"
|
||||
app:cardElevation="10dp"
|
||||
app:cardMaxElevation="12dp"
|
||||
android:checkable="true"
|
||||
app:strokeWidth="0dp"
|
||||
|
|
@ -54,34 +53,12 @@
|
|||
android:textColor="@color/white"
|
||||
android:textSize="15sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toTopOf="@+id/author"
|
||||
app:layout_constraintEnd_toStartOf="@+id/queued_download_cancel"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_bias="0.0" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/author"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:gravity="bottom"
|
||||
android:paddingLeft="10dp"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingRight="10dp"
|
||||
android:paddingBottom="10dp"
|
||||
android:shadowColor="@color/black"
|
||||
android:shadowDx="4"
|
||||
android:shadowDy="4"
|
||||
android:shadowRadius="1.5"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toTopOf="@+id/linearLayout3"
|
||||
app:layout_constraintEnd_toStartOf="@+id/queued_download_cancel"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/queued_download_cancel"
|
||||
style="@style/Widget.Material3.ExtendedFloatingActionButton.Icon.Secondary"
|
||||
|
|
@ -90,6 +67,7 @@
|
|||
android:layout_margin="15dp"
|
||||
app:cornerRadius="10dp"
|
||||
app:icon="@drawable/ic_baseline_delete_outline_24"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
|
|
@ -108,7 +86,7 @@
|
|||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/author"
|
||||
app:layout_constraintTop_toBottomOf="@+id/title"
|
||||
app:layout_constraintVertical_bias="1.0" />
|
||||
|
||||
<LinearLayout
|
||||
|
|
|
|||
|
|
@ -191,4 +191,6 @@
|
|||
<string name="create_template">Create Template</string>
|
||||
<string name="edit">Edit</string>
|
||||
<string name="shortcuts_desc">Use commonly used commands to create templates</string>
|
||||
<string name="cancelled">Cancelled</string>
|
||||
<string name="errored">Errored</string>
|
||||
</resources>
|
||||
Loading…
Reference in a new issue