implemented download queue
This commit is contained in:
parent
8eb0370c69
commit
8ff441172e
15 changed files with 796 additions and 222 deletions
|
|
@ -120,7 +120,7 @@ dependencies {
|
||||||
|
|
||||||
implementation "androidx.appcompat:appcompat:$appCompatVer"
|
implementation "androidx.appcompat:appcompat:$appCompatVer"
|
||||||
implementation "androidx.constraintlayout:constraintlayout:2.1.4"
|
implementation "androidx.constraintlayout:constraintlayout:2.1.4"
|
||||||
implementation 'com.google.android.material:material:1.9.0-alpha02'
|
implementation 'com.google.android.material:material:1.7.0'
|
||||||
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||||
implementation 'androidx.core:core:1.9.0'
|
implementation 'androidx.core:core:1.9.0'
|
||||||
implementation 'androidx.recyclerview:recyclerview:1.2.1'
|
implementation 'androidx.recyclerview:recyclerview:1.2.1'
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,16 @@
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
<activity
|
||||||
|
android:name=".ui.DownloadQueueActivity"
|
||||||
|
android:configChanges="layoutDirection|locale"
|
||||||
|
android:parentActivityName=".MainActivity"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="ytdlnis.DownloadQueueActivity" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.downloadLogs.DownloadLogActivity"
|
android:name=".ui.downloadLogs.DownloadLogActivity"
|
||||||
android:configChanges="layoutDirection|locale"
|
android:configChanges="layoutDirection|locale"
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ import androidx.work.WorkManager
|
||||||
import com.deniscerri.ytdlnis.databinding.ActivityMainBinding
|
import com.deniscerri.ytdlnis.databinding.ActivityMainBinding
|
||||||
import com.deniscerri.ytdlnis.service.IDownloaderListener
|
import com.deniscerri.ytdlnis.service.IDownloaderListener
|
||||||
import com.deniscerri.ytdlnis.service.IDownloaderService
|
import com.deniscerri.ytdlnis.service.IDownloaderService
|
||||||
|
import com.deniscerri.ytdlnis.ui.DownloadQueueActivity
|
||||||
import com.deniscerri.ytdlnis.ui.HistoryFragment
|
import com.deniscerri.ytdlnis.ui.HistoryFragment
|
||||||
import com.deniscerri.ytdlnis.ui.HomeFragment
|
import com.deniscerri.ytdlnis.ui.HomeFragment
|
||||||
import com.deniscerri.ytdlnis.ui.MoreFragment
|
import com.deniscerri.ytdlnis.ui.MoreFragment
|
||||||
|
|
@ -79,7 +80,8 @@ class MainActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
R.id.history -> {
|
R.id.history -> {
|
||||||
if (lastFragment === historyFragment) {
|
if (lastFragment === historyFragment) {
|
||||||
historyFragment.scrollToTop()
|
val intent = Intent(context, DownloadQueueActivity::class.java)
|
||||||
|
startActivity(intent)
|
||||||
} else {
|
} else {
|
||||||
this.title = getString(R.string.downloads)
|
this.title = getString(R.string.downloads)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,56 +1,48 @@
|
||||||
package com.deniscerri.ytdlnis.adapter
|
package com.deniscerri.ytdlnis.adapter
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.graphics.ColorMatrix
|
|
||||||
import android.graphics.ColorMatrixColorFilter
|
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.LinearLayout
|
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import androidx.recyclerview.widget.AsyncDifferConfig
|
import androidx.recyclerview.widget.AsyncDifferConfig
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.ListAdapter
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.database.models.HistoryItem
|
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||||
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.button.MaterialButton
|
||||||
import com.google.android.material.card.MaterialCardView
|
import com.google.android.material.card.MaterialCardView
|
||||||
|
import com.google.android.material.progressindicator.LinearProgressIndicator
|
||||||
import com.squareup.picasso.Picasso
|
import com.squareup.picasso.Picasso
|
||||||
import java.io.File
|
|
||||||
import java.text.DateFormat
|
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<HistoryItem?, ActiveDownloadAdapter.ViewHolder>(AsyncDifferConfig.Builder(DIFF_CALLBACK).build()) {
|
class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<DownloadItem?, ActiveDownloadAdapter.ViewHolder>(AsyncDifferConfig.Builder(DIFF_CALLBACK).build()) {
|
||||||
private val checkedItems: ArrayList<Long>
|
|
||||||
private val onItemClickListener: OnItemClickListener
|
private val onItemClickListener: OnItemClickListener
|
||||||
private val activity: Activity
|
private val activity: Activity
|
||||||
|
private val fileUtil: FileUtil
|
||||||
|
|
||||||
init {
|
init {
|
||||||
checkedItems = ArrayList()
|
|
||||||
this.onItemClickListener = onItemClickListener
|
this.onItemClickListener = onItemClickListener
|
||||||
this.activity = activity
|
this.activity = activity
|
||||||
|
fileUtil = FileUtil()
|
||||||
}
|
}
|
||||||
|
|
||||||
class ViewHolder(itemView: View, onItemClickListener: OnItemClickListener?) : RecyclerView.ViewHolder(itemView) {
|
class ViewHolder(itemView: View, onItemClickListener: OnItemClickListener?) : RecyclerView.ViewHolder(itemView) {
|
||||||
val cardView: MaterialCardView
|
val cardView: MaterialCardView
|
||||||
|
|
||||||
init {
|
init {
|
||||||
cardView = itemView.findViewById(R.id.downloads_card_view)
|
cardView = itemView.findViewById(R.id.active_download_card_view)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
val cardView = LayoutInflater.from(parent.context)
|
val cardView = LayoutInflater.from(parent.context)
|
||||||
.inflate(R.layout.history_card, parent, false)
|
.inflate(R.layout.active_download_card, parent, false)
|
||||||
return ViewHolder(cardView, onItemClickListener)
|
return ViewHolder(cardView, onItemClickListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -58,7 +50,7 @@ class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
|
||||||
val item = getItem(position)
|
val item = getItem(position)
|
||||||
val card = holder.cardView
|
val card = holder.cardView
|
||||||
// THUMBNAIL ----------------------------------
|
// THUMBNAIL ----------------------------------
|
||||||
val thumbnail = card.findViewById<ImageView>(R.id.downloads_image_view)
|
val thumbnail = card.findViewById<ImageView>(R.id.image_view)
|
||||||
val imageURL = item!!.thumb
|
val imageURL = item!!.thumb
|
||||||
val uiHandler = Handler(Looper.getMainLooper())
|
val uiHandler = Handler(Looper.getMainLooper())
|
||||||
if (imageURL.isNotEmpty()) {
|
if (imageURL.isNotEmpty()) {
|
||||||
|
|
@ -68,126 +60,76 @@ class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
|
||||||
}
|
}
|
||||||
thumbnail.setColorFilter(Color.argb(95, 0, 0, 0))
|
thumbnail.setColorFilter(Color.argb(95, 0, 0, 0))
|
||||||
|
|
||||||
|
// PROGRESS BAR ----------------------------------------------------
|
||||||
|
val progressBar = card.findViewById<LinearProgressIndicator>(R.id.progress)
|
||||||
|
progressBar.tag = "${item.id}##progress"
|
||||||
|
progressBar.progress = 0
|
||||||
|
progressBar.isIndeterminate = true
|
||||||
|
|
||||||
// TITLE ----------------------------------
|
// TITLE ----------------------------------
|
||||||
val itemTitle = card.findViewById<TextView>(R.id.downloads_title)
|
val itemTitle = card.findViewById<TextView>(R.id.title)
|
||||||
var title = item.title
|
var title = item.title
|
||||||
if (title.length > 100) {
|
if (title.length > 100) {
|
||||||
title = title.substring(0, 40) + "..."
|
title = title.substring(0, 40) + "..."
|
||||||
}
|
}
|
||||||
itemTitle.text = title
|
itemTitle.text = title
|
||||||
|
|
||||||
// Bottom Info ----------------------------------
|
// Author ----------------------------------
|
||||||
val bottomInfo = card.findViewById<TextView>(R.id.downloads_info_bottom)
|
val author = card.findViewById<TextView>(R.id.author)
|
||||||
var info = item.author
|
var info = item.author
|
||||||
if (item.duration.isNotEmpty()) {
|
if (item.duration.isNotEmpty()) {
|
||||||
if (item.author.isNotEmpty()) info += " • "
|
if (item.author.isNotEmpty()) info += " • "
|
||||||
info += item.duration
|
info += item.duration
|
||||||
}
|
}
|
||||||
bottomInfo.text = info
|
author.text = info
|
||||||
|
|
||||||
// TIME DOWNLOADED ----------------------------------
|
val formatNote = card.findViewById<TextView>(R.id.format_note)
|
||||||
val datetime = card.findViewById<TextView>(R.id.downloads_info_time)
|
formatNote.text = item.format.format_note
|
||||||
val time = item.time
|
val codec = card.findViewById<TextView>(R.id.codec)
|
||||||
val downloadedTime: String
|
val codecText =
|
||||||
if (time == 0L) {
|
if (item.format.encoding != "") {
|
||||||
downloadedTime = activity.getString(R.string.currently_downloading) + " " + item.type
|
item.format.encoding.uppercase()
|
||||||
} else {
|
}else if (item.format.vcodec != "none" && item.format.vcodec != ""){
|
||||||
val cal = Calendar.getInstance()
|
item.format.vcodec.uppercase()
|
||||||
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)
|
|
||||||
downloadedTime = "$day $month $year - $timeString"
|
|
||||||
}
|
|
||||||
datetime.text = downloadedTime
|
|
||||||
|
|
||||||
// BUTTON ----------------------------------
|
|
||||||
val buttonLayout = card.findViewById<LinearLayout>(R.id.downloads_download_button_layout)
|
|
||||||
val btn = buttonLayout.findViewById<MaterialButton>(R.id.downloads_download_button_type)
|
|
||||||
var filePresent = true
|
|
||||||
|
|
||||||
//IS IN THE FILE SYSTEM?
|
|
||||||
val path = item.downloadPath
|
|
||||||
val file = File(path)
|
|
||||||
if (!file.exists() && path.isNotEmpty()) {
|
|
||||||
filePresent = false
|
|
||||||
thumbnail.colorFilter = ColorMatrixColorFilter(object : ColorMatrix() {
|
|
||||||
init {
|
|
||||||
setSaturation(0f)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
thumbnail.alpha = 0.7f
|
|
||||||
}
|
|
||||||
if (item.type == DownloadViewModel.Type.audio) {
|
|
||||||
if (filePresent) btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_music_downloaded) else btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_music)
|
|
||||||
} else {
|
|
||||||
if (filePresent) btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_video_downloaded) else btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_video)
|
|
||||||
}
|
|
||||||
if (btn.hasOnClickListeners()) btn.setOnClickListener(null)
|
|
||||||
if (checkedItems.contains(item.id)) {
|
|
||||||
card.isChecked = true
|
|
||||||
card.strokeWidth = 5
|
|
||||||
} else {
|
|
||||||
card.isChecked = false
|
|
||||||
card.strokeWidth = 0
|
|
||||||
}
|
|
||||||
val finalFilePresent = filePresent
|
|
||||||
card.setOnLongClickListener {
|
|
||||||
checkCard(card, item.id)
|
|
||||||
true
|
|
||||||
}
|
|
||||||
card.setOnClickListener {
|
|
||||||
if (checkedItems.size > 0) {
|
|
||||||
checkCard(card, item.id)
|
|
||||||
} else {
|
} else {
|
||||||
onItemClickListener.onCardClick(item.id, finalFilePresent)
|
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)
|
||||||
|
|
||||||
|
//OUTPUT
|
||||||
|
val output = card.findViewById<TextView>(R.id.output)
|
||||||
|
output.tag = "${item.id}##output"
|
||||||
|
|
||||||
|
|
||||||
|
// CANCEL BUTTON ----------------------------------
|
||||||
|
val cancelButton = card.findViewById<MaterialButton>(R.id.active_download_cancel)
|
||||||
|
if (cancelButton.hasOnClickListeners()) cancelButton.setOnClickListener(null)
|
||||||
|
|
||||||
|
cancelButton.setOnClickListener {
|
||||||
|
onItemClickListener.onCancelClick(item.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkCard(card: MaterialCardView, itemID: Long) {
|
|
||||||
if (card.isChecked) {
|
|
||||||
card.strokeWidth = 0
|
|
||||||
checkedItems.remove(itemID)
|
|
||||||
} else {
|
|
||||||
card.strokeWidth = 5
|
|
||||||
checkedItems.add(itemID)
|
|
||||||
}
|
|
||||||
card.isChecked = !card.isChecked
|
|
||||||
onItemClickListener.onCardSelect(itemID, card.isChecked)
|
|
||||||
}
|
|
||||||
|
|
||||||
interface OnItemClickListener {
|
interface OnItemClickListener {
|
||||||
fun onCardClick(itemID: Long, isPresent: Boolean)
|
fun onCancelClick(itemID: Long)
|
||||||
fun onCardSelect(itemID: Long, isChecked: Boolean)
|
|
||||||
fun onButtonClick(position: Int)
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("NotifyDataSetChanged")
|
|
||||||
fun clearCheckeditems() {
|
|
||||||
for (i in 0 until itemCount){
|
|
||||||
val item = getItem(i)
|
|
||||||
if (checkedItems.find { it == item?.id } != null){
|
|
||||||
checkedItems.remove(item?.id)
|
|
||||||
notifyItemChanged(i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
checkedItems.clear()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val DIFF_CALLBACK: DiffUtil.ItemCallback<HistoryItem> = object : DiffUtil.ItemCallback<HistoryItem>() {
|
private val DIFF_CALLBACK: DiffUtil.ItemCallback<DownloadItem> = object : DiffUtil.ItemCallback<DownloadItem>() {
|
||||||
override fun areItemsTheSame(oldItem: HistoryItem, newItem: HistoryItem): Boolean {
|
override fun areItemsTheSame(oldItem: DownloadItem, newItem: DownloadItem): Boolean {
|
||||||
val ranged = arrayListOf(oldItem.id, newItem.id)
|
val ranged = arrayListOf(oldItem.id, newItem.id)
|
||||||
return ranged[0] == ranged[1]
|
return ranged[0] == ranged[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun areContentsTheSame(oldItem: HistoryItem, newItem: HistoryItem): Boolean {
|
override fun areContentsTheSame(oldItem: DownloadItem, newItem: DownloadItem): Boolean {
|
||||||
return oldItem.time == newItem.time
|
return oldItem.id == newItem.id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import android.graphics.ColorMatrix
|
||||||
import android.graphics.ColorMatrixColorFilter
|
import android.graphics.ColorMatrixColorFilter
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
|
import android.util.Log
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
|
@ -19,38 +20,40 @@ import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.ListAdapter
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
|
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||||
import com.deniscerri.ytdlnis.database.models.HistoryItem
|
import com.deniscerri.ytdlnis.database.models.HistoryItem
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
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.button.MaterialButton
|
||||||
import com.google.android.material.card.MaterialCardView
|
import com.google.android.material.card.MaterialCardView
|
||||||
import com.squareup.picasso.Picasso
|
import com.squareup.picasso.Picasso
|
||||||
|
import org.w3c.dom.Text
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.text.DateFormat
|
import java.text.DateFormat
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class QueuedDownloadAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<HistoryItem?, QueuedDownloadAdapter.ViewHolder>(AsyncDifferConfig.Builder(DIFF_CALLBACK).build()) {
|
class QueuedDownloadAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<DownloadItem?, QueuedDownloadAdapter.ViewHolder>(AsyncDifferConfig.Builder(DIFF_CALLBACK).build()) {
|
||||||
private val checkedItems: ArrayList<Long>
|
|
||||||
private val onItemClickListener: OnItemClickListener
|
private val onItemClickListener: OnItemClickListener
|
||||||
private val activity: Activity
|
private val activity: Activity
|
||||||
|
private var fileUtil: FileUtil
|
||||||
|
|
||||||
init {
|
init {
|
||||||
checkedItems = ArrayList()
|
|
||||||
this.onItemClickListener = onItemClickListener
|
this.onItemClickListener = onItemClickListener
|
||||||
this.activity = activity
|
this.activity = activity
|
||||||
|
fileUtil = FileUtil()
|
||||||
}
|
}
|
||||||
|
|
||||||
class ViewHolder(itemView: View, onItemClickListener: OnItemClickListener?) : RecyclerView.ViewHolder(itemView) {
|
class ViewHolder(itemView: View, onItemClickListener: OnItemClickListener?) : RecyclerView.ViewHolder(itemView) {
|
||||||
val cardView: MaterialCardView
|
val cardView: MaterialCardView
|
||||||
|
|
||||||
init {
|
init {
|
||||||
cardView = itemView.findViewById(R.id.downloads_card_view)
|
cardView = itemView.findViewById(R.id.queued_download_card_view)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
val cardView = LayoutInflater.from(parent.context)
|
val cardView = LayoutInflater.from(parent.context)
|
||||||
.inflate(R.layout.history_card, parent, false)
|
.inflate(R.layout.queued_download_card, parent, false)
|
||||||
return ViewHolder(cardView, onItemClickListener)
|
return ViewHolder(cardView, onItemClickListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -58,7 +61,7 @@ class QueuedDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
|
||||||
val item = getItem(position)
|
val item = getItem(position)
|
||||||
val card = holder.cardView
|
val card = holder.cardView
|
||||||
// THUMBNAIL ----------------------------------
|
// THUMBNAIL ----------------------------------
|
||||||
val thumbnail = card.findViewById<ImageView>(R.id.downloads_image_view)
|
val thumbnail = card.findViewById<ImageView>(R.id.image_view)
|
||||||
val imageURL = item!!.thumb
|
val imageURL = item!!.thumb
|
||||||
val uiHandler = Handler(Looper.getMainLooper())
|
val uiHandler = Handler(Looper.getMainLooper())
|
||||||
if (imageURL.isNotEmpty()) {
|
if (imageURL.isNotEmpty()) {
|
||||||
|
|
@ -69,29 +72,48 @@ class QueuedDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
|
||||||
thumbnail.setColorFilter(Color.argb(95, 0, 0, 0))
|
thumbnail.setColorFilter(Color.argb(95, 0, 0, 0))
|
||||||
|
|
||||||
// TITLE ----------------------------------
|
// TITLE ----------------------------------
|
||||||
val itemTitle = card.findViewById<TextView>(R.id.downloads_title)
|
val itemTitle = card.findViewById<TextView>(R.id.title)
|
||||||
var title = item.title
|
var title = item.title
|
||||||
if (title.length > 100) {
|
if (title.length > 100) {
|
||||||
title = title.substring(0, 40) + "..."
|
title = title.substring(0, 40) + "..."
|
||||||
}
|
}
|
||||||
itemTitle.text = title
|
itemTitle.text = title
|
||||||
|
|
||||||
// Bottom Info ----------------------------------
|
// Author ----------------------------------
|
||||||
val bottomInfo = card.findViewById<TextView>(R.id.downloads_info_bottom)
|
val author = card.findViewById<TextView>(R.id.author)
|
||||||
var info = item.author
|
var info = item.author
|
||||||
if (item.duration.isNotEmpty()) {
|
if (item.duration.isNotEmpty()) {
|
||||||
if (item.author.isNotEmpty()) info += " • "
|
if (item.author.isNotEmpty()) info += " • "
|
||||||
info += item.duration
|
info += item.duration
|
||||||
}
|
}
|
||||||
bottomInfo.text = info
|
author.text = info
|
||||||
|
|
||||||
// TIME DOWNLOADED ----------------------------------
|
val formatNote = card.findViewById<TextView>(R.id.format_note)
|
||||||
val datetime = card.findViewById<TextView>(R.id.downloads_info_time)
|
formatNote.text = item.format.format_note
|
||||||
val time = item.time
|
val codec = card.findViewById<TextView>(R.id.codec)
|
||||||
val downloadedTime: String
|
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) {
|
if (time == 0L) {
|
||||||
downloadedTime = activity.getString(R.string.currently_downloading) + " " + item.type
|
downloadStartTime.visibility = View.GONE
|
||||||
} else {
|
} else {
|
||||||
|
downloadStartTime.visibility = View.VISIBLE
|
||||||
val cal = Calendar.getInstance()
|
val cal = Calendar.getInstance()
|
||||||
val date = Date(time * 1000L)
|
val date = Date(time * 1000L)
|
||||||
cal.time = date
|
cal.time = date
|
||||||
|
|
@ -100,94 +122,31 @@ class QueuedDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
|
||||||
val year = cal[Calendar.YEAR]
|
val year = cal[Calendar.YEAR]
|
||||||
val formatter: DateFormat = SimpleDateFormat("HH:mm", Locale.getDefault())
|
val formatter: DateFormat = SimpleDateFormat("HH:mm", Locale.getDefault())
|
||||||
val timeString = formatter.format(date)
|
val timeString = formatter.format(date)
|
||||||
downloadedTime = "$day $month $year - $timeString"
|
downloadStartTime.text = "$day $month $year - $timeString"
|
||||||
}
|
}
|
||||||
datetime.text = downloadedTime
|
|
||||||
|
|
||||||
// BUTTON ----------------------------------
|
// CANCEL BUTTON ----------------------------------
|
||||||
val buttonLayout = card.findViewById<LinearLayout>(R.id.downloads_download_button_layout)
|
val cancelButton = card.findViewById<MaterialButton>(R.id.queued_download_cancel)
|
||||||
val btn = buttonLayout.findViewById<MaterialButton>(R.id.downloads_download_button_type)
|
if (cancelButton.hasOnClickListeners()) cancelButton.setOnClickListener(null)
|
||||||
var filePresent = true
|
|
||||||
|
|
||||||
//IS IN THE FILE SYSTEM?
|
cancelButton.setOnClickListener {
|
||||||
val path = item.downloadPath
|
onItemClickListener.onQueuedCancelClick(item.id)
|
||||||
val file = File(path)
|
|
||||||
if (!file.exists() && path.isNotEmpty()) {
|
|
||||||
filePresent = false
|
|
||||||
thumbnail.colorFilter = ColorMatrixColorFilter(object : ColorMatrix() {
|
|
||||||
init {
|
|
||||||
setSaturation(0f)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
thumbnail.alpha = 0.7f
|
|
||||||
}
|
|
||||||
if (item.type == DownloadViewModel.Type.audio) {
|
|
||||||
if (filePresent) btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_music_downloaded) else btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_music)
|
|
||||||
} else {
|
|
||||||
if (filePresent) btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_video_downloaded) else btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_video)
|
|
||||||
}
|
|
||||||
if (btn.hasOnClickListeners()) btn.setOnClickListener(null)
|
|
||||||
if (checkedItems.contains(item.id)) {
|
|
||||||
card.isChecked = true
|
|
||||||
card.strokeWidth = 5
|
|
||||||
} else {
|
|
||||||
card.isChecked = false
|
|
||||||
card.strokeWidth = 0
|
|
||||||
}
|
|
||||||
val finalFilePresent = filePresent
|
|
||||||
card.setOnLongClickListener {
|
|
||||||
checkCard(card, item.id)
|
|
||||||
true
|
|
||||||
}
|
|
||||||
card.setOnClickListener {
|
|
||||||
if (checkedItems.size > 0) {
|
|
||||||
checkCard(card, item.id)
|
|
||||||
} else {
|
|
||||||
onItemClickListener.onCardClick(item.id, finalFilePresent)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkCard(card: MaterialCardView, itemID: Long) {
|
|
||||||
if (card.isChecked) {
|
|
||||||
card.strokeWidth = 0
|
|
||||||
checkedItems.remove(itemID)
|
|
||||||
} else {
|
|
||||||
card.strokeWidth = 5
|
|
||||||
checkedItems.add(itemID)
|
|
||||||
}
|
|
||||||
card.isChecked = !card.isChecked
|
|
||||||
onItemClickListener.onCardSelect(itemID, card.isChecked)
|
|
||||||
}
|
|
||||||
|
|
||||||
interface OnItemClickListener {
|
interface OnItemClickListener {
|
||||||
fun onCardClick(itemID: Long, isPresent: Boolean)
|
fun onQueuedCancelClick(itemID: Long)
|
||||||
fun onCardSelect(itemID: Long, isChecked: Boolean)
|
|
||||||
fun onButtonClick(position: Int)
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("NotifyDataSetChanged")
|
|
||||||
fun clearCheckeditems() {
|
|
||||||
for (i in 0 until itemCount){
|
|
||||||
val item = getItem(i)
|
|
||||||
if (checkedItems.find { it == item?.id } != null){
|
|
||||||
checkedItems.remove(item?.id)
|
|
||||||
notifyItemChanged(i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
checkedItems.clear()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val DIFF_CALLBACK: DiffUtil.ItemCallback<HistoryItem> = object : DiffUtil.ItemCallback<HistoryItem>() {
|
private val DIFF_CALLBACK: DiffUtil.ItemCallback<DownloadItem> = object : DiffUtil.ItemCallback<DownloadItem>() {
|
||||||
override fun areItemsTheSame(oldItem: HistoryItem, newItem: HistoryItem): Boolean {
|
override fun areItemsTheSame(oldItem: DownloadItem, newItem: DownloadItem): Boolean {
|
||||||
val ranged = arrayListOf(oldItem.id, newItem.id)
|
val ranged = arrayListOf(oldItem.id, newItem.id)
|
||||||
return ranged[0] == ranged[1]
|
return ranged[0] == ranged[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun areContentsTheSame(oldItem: HistoryItem, newItem: HistoryItem): Boolean {
|
override fun areContentsTheSame(oldItem: DownloadItem, newItem: DownloadItem): Boolean {
|
||||||
return oldItem.time == newItem.time
|
return oldItem.url == newItem.url && oldItem.format.format_id == newItem.format.format_id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,176 @@
|
||||||
|
package com.deniscerri.ytdlnis.ui
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
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.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
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
activeRecyclerView = findViewById(R.id.active_recyclerview)
|
||||||
|
activeRecyclerView.layoutManager = LinearLayoutManager(context)
|
||||||
|
activeRecyclerView.adapter = activeDownloads
|
||||||
|
|
||||||
|
queuedRecyclerView = findViewById(R.id.queued_recyclerview)
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -184,15 +184,10 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
Handler(Looper.getMainLooper()).post {
|
Handler(Looper.getMainLooper()).post {
|
||||||
|
|
||||||
// DOWNLOAD ALL BUTTON
|
// DOWNLOAD ALL BUTTON
|
||||||
if (resultsList!!.size > 1 || inputQueriesLength > 1) {
|
if (resultsList!!.size > 1 || inputQueriesLength > 1) {
|
||||||
downloadAllFabCoordinator!!.visibility = VISIBLE
|
downloadAllFabCoordinator!!.visibility = VISIBLE
|
||||||
}
|
}
|
||||||
// databaseManager = DatabaseManager(context)
|
|
||||||
// databaseManager!!.clearResults()
|
|
||||||
// for (v in resultsList!!) v!!.isPlaylistItem = 1
|
|
||||||
// databaseManager!!.addToResults(resultsList)
|
|
||||||
}
|
}
|
||||||
} catch (ignored: Exception) {
|
} catch (ignored: Exception) {
|
||||||
}
|
}
|
||||||
|
|
@ -202,14 +197,6 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
|
||||||
resultViewModel.checkTrending()
|
resultViewModel.checkTrending()
|
||||||
}
|
}
|
||||||
|
|
||||||
WorkManager.getInstance(requireContext())
|
|
||||||
.getWorkInfosByTagLiveData("download")
|
|
||||||
.observe(viewLifecycleOwner){ list ->
|
|
||||||
list.forEach {
|
|
||||||
//Toast.makeText(context, """${it.progress.getInt("progress", 0)} ${it.progress.getString("output")}""", Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// fragmentView!!.post{
|
// fragmentView!!.post{
|
||||||
// if (shimmerCards!!.visibility == VISIBLE) return@post
|
// if (shimmerCards!!.visibility == VISIBLE) return@post
|
||||||
// val clipboard = requireContext().getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
|
// val clipboard = requireContext().getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
|
||||||
|
|
|
||||||
|
|
@ -209,10 +209,8 @@ class DownloadWorker(
|
||||||
"Format: ${downloadItem.format}\n\n")
|
"Format: ${downloadItem.format}\n\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
YoutubeDL.getInstance().execute(request, downloadItem.id.toString()){ progress, _, line ->
|
YoutubeDL.getInstance().execute(request, downloadItem.id.toString()){ progress, _, line ->
|
||||||
setProgressAsync(workDataOf("progress" to progress.toInt()))
|
setProgressAsync(workDataOf("progress" to progress.toInt(), "output" to line, "id" to downloadItem.id))
|
||||||
setProgressAsync(workDataOf("output" to line))
|
|
||||||
val title: String = downloadItem.title
|
val title: String = downloadItem.title
|
||||||
notificationUtil.updateDownloadNotification(
|
notificationUtil.updateDownloadNotification(
|
||||||
downloadItem.id.toInt(),
|
downloadItem.id.toInt(),
|
||||||
|
|
|
||||||
179
app/src/main/res/layout/active_download_card.xml
Normal file
179
app/src/main/res/layout/active_download_card.xml
Normal file
|
|
@ -0,0 +1,179 @@
|
||||||
|
<?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/active_download_relative_layout"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
app:layout_constraintDimensionRatio="H,2: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/active_download_card_view"
|
||||||
|
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"
|
||||||
|
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" />
|
||||||
|
|
||||||
|
<com.google.android.material.progressindicator.LinearProgressIndicator
|
||||||
|
android:id="@+id/progress"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
android:alpha="0.3"
|
||||||
|
android:scaleY="100"/>
|
||||||
|
|
||||||
|
<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/active_download_cancel"
|
||||||
|
app:layout_constraintHorizontal_bias="0.0"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/author"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
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/linearLayout2"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/active_download_cancel"
|
||||||
|
app:layout_constraintHorizontal_bias="0.0"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/title" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/format_note"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingVertical="10dp"
|
||||||
|
android:paddingStart="10dp"
|
||||||
|
android:paddingEnd="0dp"
|
||||||
|
android:textSize="15sp"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/output"
|
||||||
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/linearLayout2"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="10dp"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/output"
|
||||||
|
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" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/output"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:paddingLeft="10dp"
|
||||||
|
android:paddingTop="10dp"
|
||||||
|
android:paddingRight="10dp"
|
||||||
|
android:paddingBottom="10dp"
|
||||||
|
android:shadowRadius="1.5"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/active_download_cancel"
|
||||||
|
style="@style/Widget.Material3.ExtendedFloatingActionButton.Icon.Secondary"
|
||||||
|
android:layout_width="55dp"
|
||||||
|
android:layout_height="55dp"
|
||||||
|
android:layout_margin="20dp"
|
||||||
|
app:cornerRadius="10dp"
|
||||||
|
app:icon="@drawable/ic_cancel"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
42
app/src/main/res/layout/activity_command_templates.xml
Normal file
42
app/src/main/res/layout/activity_command_templates.xml
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout 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"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context="com.deniscerri.ytdlnis.ui.CustomCommandActivity">
|
||||||
|
|
||||||
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:liftOnScroll="false"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
android:fitsSystemWindows="true">
|
||||||
|
|
||||||
|
<com.google.android.material.appbar.MaterialToolbar
|
||||||
|
android:id="@+id/logs_toolbar"
|
||||||
|
android:elevation="0dp"
|
||||||
|
app:title="@string/command_templates"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
app:navigationIcon="@drawable/ic_back"
|
||||||
|
android:layout_height="match_parent"/>
|
||||||
|
|
||||||
|
|
||||||
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||||
|
android:id="@+id/template_recyclerview"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
>
|
||||||
|
|
||||||
|
</androidx.recyclerview.widget.RecyclerView>
|
||||||
|
|
||||||
|
|
||||||
|
<include layout="@layout/history_no_results"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
99
app/src/main/res/layout/activity_download_queue.xml
Normal file
99
app/src/main/res/layout/activity_download_queue.xml
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout 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"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context="com.deniscerri.ytdlnis.ui.CustomCommandActivity">
|
||||||
|
|
||||||
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:liftOnScroll="false"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
android:fitsSystemWindows="true">
|
||||||
|
|
||||||
|
<com.google.android.material.appbar.MaterialToolbar
|
||||||
|
android:id="@+id/logs_toolbar"
|
||||||
|
android:elevation="0dp"
|
||||||
|
app:title="@string/download_queue"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
app:navigationIcon="@drawable/ic_back"
|
||||||
|
android:layout_height="match_parent"/>
|
||||||
|
|
||||||
|
|
||||||
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
|
<androidx.core.widget.NestedScrollView
|
||||||
|
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:scrollbars="none"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:padding="10dp"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/running_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/running"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
|
||||||
|
<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>
|
||||||
|
|
||||||
|
|
||||||
|
<include layout="@layout/history_no_results"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
169
app/src/main/res/layout/queued_download_card.xml
Normal file
169
app/src/main/res/layout/queued_download_card.xml
Normal file
|
|
@ -0,0 +1,169 @@
|
||||||
|
<?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,2.66: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:cardElevation="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="300dp"
|
||||||
|
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_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/author"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
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_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/title" />
|
||||||
|
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:layout_margin="15dp"
|
||||||
|
android:id="@+id/queued_download_cancel"
|
||||||
|
style="@style/Widget.Material3.ExtendedFloatingActionButton.Icon.Secondary"
|
||||||
|
android:layout_width="55dp"
|
||||||
|
android:layout_height="55dp"
|
||||||
|
app:cornerRadius="10dp"
|
||||||
|
app:icon="@drawable/ic_baseline_delete_outline_24"
|
||||||
|
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"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/author"
|
||||||
|
app:layout_constraintVertical_bias="1.0" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
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>
|
||||||
|
|
@ -4,5 +4,5 @@
|
||||||
<color name="black">#000000</color>
|
<color name="black">#000000</color>
|
||||||
<color name="grey">#323232</color>
|
<color name="grey">#323232</color>
|
||||||
<color name="light_grey">#A6A6A6</color>
|
<color name="light_grey">#A6A6A6</color>
|
||||||
<color name="icon_bg">@android:color/background_light</color>
|
<color name="icon_bg">@android:color/background_dark</color>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
|
|
@ -181,4 +181,6 @@
|
||||||
<string name="log_downloads">Log Downloads</string>
|
<string name="log_downloads">Log Downloads</string>
|
||||||
<string name="log_downloads_summary">Create a log file for each download</string>
|
<string name="log_downloads_summary">Create a log file for each download</string>
|
||||||
<string name="new_update">New Update</string>
|
<string name="new_update">New Update</string>
|
||||||
|
<string name="download_queue">Download Queue</string>
|
||||||
|
<string name="running">Running</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
@ -41,6 +41,15 @@
|
||||||
<intent android:action="ytdlnis.CommandTemplatesActivity" />
|
<intent android:action="ytdlnis.CommandTemplatesActivity" />
|
||||||
</Preference>
|
</Preference>
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
app:icon="@drawable/ic_down"
|
||||||
|
app:key="download_queue"
|
||||||
|
app:allowDividerBelow="true"
|
||||||
|
app:title="@string/download_queue">
|
||||||
|
<intent android:action="ytdlnis.DownloadQueueActivity" />
|
||||||
|
</Preference>
|
||||||
|
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
app:icon="@drawable/ic_settings"
|
app:icon="@drawable/ic_settings"
|
||||||
app:key="open_settings"
|
app:key="open_settings"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue