implemented processing multiple items from a playlist
This commit is contained in:
parent
44f33e1508
commit
cc8614d175
28 changed files with 999 additions and 467 deletions
|
|
@ -320,7 +320,7 @@
|
||||||
<PersistentState>
|
<PersistentState>
|
||||||
<option name="values">
|
<option name="values">
|
||||||
<map>
|
<map>
|
||||||
<entry key="url" value="file:/$USER_HOME$/AppData/Local/Android/Sdk/icons/material/materialicons/content_copy/baseline_content_copy_24.xml" />
|
<entry key="url" value="file:/$USER_HOME$/AppData/Local/Android/Sdk/icons/material/materialicons/select_all/baseline_select_all_24.xml" />
|
||||||
</map>
|
</map>
|
||||||
</option>
|
</option>
|
||||||
</PersistentState>
|
</PersistentState>
|
||||||
|
|
@ -330,7 +330,7 @@
|
||||||
</option>
|
</option>
|
||||||
<option name="values">
|
<option name="values">
|
||||||
<map>
|
<map>
|
||||||
<entry key="outputName" value="ic_copy" />
|
<entry key="outputName" value="ic_select_all" />
|
||||||
<entry key="sourceFile" value="C:\Users\denis\Desktop\adaptiveproduct_youtube_foreground_color_108 (1).svg" />
|
<entry key="sourceFile" value="C:\Users\denis\Desktop\adaptiveproduct_youtube_foreground_color_108 (1).svg" />
|
||||||
</map>
|
</map>
|
||||||
</option>
|
</option>
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ 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.google.android.material.progressindicator.LinearProgressIndicator
|
||||||
import com.squareup.picasso.Picasso
|
import com.squareup.picasso.Picasso
|
||||||
|
import okhttp3.internal.format
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class ConfigureMultipleDownloadsAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<DownloadItem?, ConfigureMultipleDownloadsAdapter.ViewHolder>(AsyncDifferConfig.Builder(DIFF_CALLBACK).build()) {
|
class ConfigureMultipleDownloadsAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<DownloadItem?, ConfigureMultipleDownloadsAdapter.ViewHolder>(AsyncDifferConfig.Builder(DIFF_CALLBACK).build()) {
|
||||||
|
|
@ -77,24 +78,45 @@ class ConfigureMultipleDownloadsAdapter(onItemClickListener: OnItemClickListener
|
||||||
itemTitle.text = title
|
itemTitle.text = title
|
||||||
|
|
||||||
// Author ----------------------------------
|
// Author ----------------------------------
|
||||||
val author = card.findViewById<TextView>(R.id.author)
|
val author = card.findViewById<TextView>(R.id.subtitle)
|
||||||
author.text = item.author
|
author.text = item.author
|
||||||
|
|
||||||
// Container ----------------------------------
|
// Format Note ----------------------------------
|
||||||
val container = card.findViewById<TextView>(R.id.container)
|
val formatNote = card.findViewById<TextView>(R.id.format_note)
|
||||||
container.text = item.format.container.uppercase(Locale.getDefault())
|
if (item.format.format_note.isNotEmpty()){
|
||||||
|
formatNote.text = item.format.format_note.uppercase(Locale.getDefault())
|
||||||
|
}else{
|
||||||
|
formatNote.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
// File Size
|
val codec = card.findViewById<TextView>(R.id.codec)
|
||||||
val fileSize = card.findViewById<TextView>(R.id.filesize)
|
val codecText =
|
||||||
val formattedSize = fileUtil.convertFileSize(item.format.filesize)
|
if (item.format.encoding != "") {
|
||||||
fileSize.text = if (formattedSize == "?") "" else formattedSize.uppercase(Locale.getDefault())
|
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
|
||||||
|
}
|
||||||
|
|
||||||
// Quality
|
val fileSize = card.findViewById<TextView>(R.id.file_size)
|
||||||
val quality = card.findViewById<TextView>(R.id.quality)
|
Log.e("aa", item.format.filesize.toString())
|
||||||
quality.text = item.format.format_note
|
val fileSizeReadable = fileUtil.convertFileSize(item.format.filesize)
|
||||||
|
Log.e("aa", fileSizeReadable)
|
||||||
|
if (fileSizeReadable == "?") fileSize.visibility = View.GONE
|
||||||
|
else {
|
||||||
|
fileSize.text = fileSizeReadable
|
||||||
|
fileSize.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
// Type Icon Button
|
// Type Icon Button
|
||||||
val btn = card.findViewById<MaterialButton>(R.id.downloads_download_button_type)
|
val btn = card.findViewById<MaterialButton>(R.id.action_button)
|
||||||
|
|
||||||
when(item.type) {
|
when(item.type) {
|
||||||
DownloadViewModel.Type.audio -> {
|
DownloadViewModel.Type.audio -> {
|
||||||
|
|
@ -109,23 +131,23 @@ class ConfigureMultipleDownloadsAdapter(onItemClickListener: OnItemClickListener
|
||||||
}
|
}
|
||||||
|
|
||||||
card.setOnClickListener {
|
card.setOnClickListener {
|
||||||
onItemClickListener.onCardClick(item.id)
|
onItemClickListener.onCardClick(item.url)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface OnItemClickListener {
|
interface OnItemClickListener {
|
||||||
fun onButtonClick(videoURL: String, type: String?)
|
fun onButtonClick(videoURL: String, type: String?)
|
||||||
fun onCardClick(itemID: Long)
|
fun onCardClick(itemURL: String)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val DIFF_CALLBACK: DiffUtil.ItemCallback<DownloadItem> = object : DiffUtil.ItemCallback<DownloadItem>() {
|
private val DIFF_CALLBACK: DiffUtil.ItemCallback<DownloadItem> = object : DiffUtil.ItemCallback<DownloadItem>() {
|
||||||
override fun areItemsTheSame(oldItem: DownloadItem, newItem: DownloadItem): Boolean {
|
override fun areItemsTheSame(oldItem: DownloadItem, newItem: DownloadItem): Boolean {
|
||||||
return oldItem.id === newItem.id
|
return oldItem.url == newItem.url
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun areContentsTheSame(oldItem: DownloadItem, newItem: DownloadItem): Boolean {
|
override fun areContentsTheSame(oldItem: DownloadItem, newItem: DownloadItem): Boolean {
|
||||||
return oldItem.url == newItem.url && oldItem.title == newItem.title && oldItem.author == newItem.author && oldItem.type == newItem.type && oldItem.format == newItem.format
|
return oldItem.title == newItem.title && oldItem.author == newItem.author && oldItem.type == newItem.type && oldItem.format == newItem.format
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ 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 okhttp3.internal.format
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.text.DateFormat
|
import java.text.DateFormat
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
|
|
@ -48,7 +49,7 @@ class GenericDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
|
||||||
|
|
||||||
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.generic_download_card, parent, false)
|
.inflate(R.layout.download_card, parent, false)
|
||||||
return ViewHolder(cardView, onItemClickListener)
|
return ViewHolder(cardView, onItemClickListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -56,6 +57,17 @@ class GenericDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
|
||||||
val item = getItem(position)
|
val item = getItem(position)
|
||||||
val card = holder.cardView
|
val card = holder.cardView
|
||||||
|
|
||||||
|
// THUMBNAIL ----------------------------------
|
||||||
|
val thumbnail = card.findViewById<ImageView>(R.id.downloads_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 ----------------------------------
|
// TITLE ----------------------------------
|
||||||
val itemTitle = card.findViewById<TextView>(R.id.title)
|
val itemTitle = card.findViewById<TextView>(R.id.title)
|
||||||
var title = item!!.title
|
var title = item!!.title
|
||||||
|
|
@ -64,12 +76,11 @@ class GenericDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
|
||||||
}
|
}
|
||||||
itemTitle.text = title
|
itemTitle.text = title
|
||||||
|
|
||||||
// TITLE ----------------------------------
|
val itemUrl = card.findViewById<TextView>(R.id.subtitle)
|
||||||
val itemUrl = card.findViewById<TextView>(R.id.url)
|
|
||||||
itemUrl.text = item.url
|
itemUrl.text = item.url
|
||||||
|
|
||||||
val type = card.findViewById<TextView>(R.id.type)
|
val formatNote = card.findViewById<TextView>(R.id.format_note)
|
||||||
type!!.text = item.type.toString().uppercase()
|
formatNote!!.text = item.format.format_note.uppercase()
|
||||||
|
|
||||||
val codec = card.findViewById<TextView>(R.id.codec)
|
val codec = card.findViewById<TextView>(R.id.codec)
|
||||||
val codecText =
|
val codecText =
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,136 @@
|
||||||
|
package com.deniscerri.ytdlnis.adapter
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.Activity
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.CheckBox
|
||||||
|
import android.widget.CompoundButton
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
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.ResultItem
|
||||||
|
import com.squareup.picasso.Picasso
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
|
class PlaylistAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<ResultItem?, PlaylistAdapter.ViewHolder>(AsyncDifferConfig.Builder(DIFF_CALLBACK).build()) {
|
||||||
|
private val checkedItems: ArrayList<Long>
|
||||||
|
private val onItemClickListener: OnItemClickListener
|
||||||
|
private val activity: Activity
|
||||||
|
|
||||||
|
init {
|
||||||
|
checkedItems = ArrayList()
|
||||||
|
this.onItemClickListener = onItemClickListener
|
||||||
|
this.activity = activity
|
||||||
|
}
|
||||||
|
|
||||||
|
class ViewHolder(itemView: View, onItemClickListener: OnItemClickListener?) : RecyclerView.ViewHolder(itemView) {
|
||||||
|
val cardView: ConstraintLayout
|
||||||
|
|
||||||
|
init {
|
||||||
|
cardView = itemView.findViewById(R.id.playlist_card_constraintLayout)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
|
val cardView = LayoutInflater.from(parent.context)
|
||||||
|
.inflate(R.layout.playlist_item, 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.downloads_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
|
||||||
|
|
||||||
|
// CHECKBOX ----------------------------------
|
||||||
|
val check = card.findViewById<CheckBox>(R.id.checkBox)
|
||||||
|
check.isChecked = checkedItems.contains(item.id)
|
||||||
|
check.setOnCheckedChangeListener { buttonView, isChecked ->
|
||||||
|
checkCard(isChecked, item.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
card.setOnClickListener {
|
||||||
|
check.isChecked = !check.isChecked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkCard(isChecked: Boolean, itemID: Long) {
|
||||||
|
if (isChecked) {
|
||||||
|
checkedItems.add(itemID)
|
||||||
|
} else {
|
||||||
|
checkedItems.remove(itemID)
|
||||||
|
}
|
||||||
|
onItemClickListener.onCardSelect(itemID, isChecked, checkedItems)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OnItemClickListener {
|
||||||
|
fun onCardSelect(itemID: Long, isChecked: Boolean, checkedItems: List<Long>)
|
||||||
|
}
|
||||||
|
|
||||||
|
@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()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun checkAll(){
|
||||||
|
checkedItems.clear()
|
||||||
|
for (i in 0 until itemCount){
|
||||||
|
val item = getItem(i)
|
||||||
|
checkedItems.add(item!!.id)
|
||||||
|
notifyItemChanged(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getCheckedItems() : List<Long>{
|
||||||
|
return checkedItems
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val DIFF_CALLBACK: DiffUtil.ItemCallback<ResultItem> = object : DiffUtil.ItemCallback<ResultItem>() {
|
||||||
|
override fun areItemsTheSame(oldItem: ResultItem, newItem: ResultItem): Boolean {
|
||||||
|
val ranged = arrayListOf(oldItem.id, newItem.id)
|
||||||
|
return ranged[0] == ranged[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun areContentsTheSame(oldItem: ResultItem, newItem: ResultItem): Boolean {
|
||||||
|
return oldItem.id == newItem.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -9,6 +9,9 @@ interface ResultDao {
|
||||||
@Query("SELECT * FROM results")
|
@Query("SELECT * FROM results")
|
||||||
fun getResults() : LiveData<List<ResultItem>>
|
fun getResults() : LiveData<List<ResultItem>>
|
||||||
|
|
||||||
|
@Query("SELECT COUNT(id) FROM results")
|
||||||
|
fun getCount() : LiveData<Int>
|
||||||
|
|
||||||
@Query("SELECT * FROM results LIMIT 1")
|
@Query("SELECT * FROM results LIMIT 1")
|
||||||
fun getFirstResult() : ResultItem
|
fun getFirstResult() : ResultItem
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import com.deniscerri.ytdlnis.util.InfoUtil
|
||||||
class ResultRepository(private val resultDao: ResultDao, private val commandTemplateDao: CommandTemplateDao, private val context: Context) {
|
class ResultRepository(private val resultDao: ResultDao, private val commandTemplateDao: CommandTemplateDao, private val context: Context) {
|
||||||
private val tag: String = "ResultRepository"
|
private val tag: String = "ResultRepository"
|
||||||
val allResults : LiveData<List<ResultItem>> = resultDao.getResults()
|
val allResults : LiveData<List<ResultItem>> = resultDao.getResults()
|
||||||
var itemCount = MutableLiveData(0)
|
var itemCount = MutableLiveData(-1)
|
||||||
|
|
||||||
suspend fun insert(it: ResultItem){
|
suspend fun insert(it: ResultItem){
|
||||||
resultDao.insert(it)
|
resultDao.insert(it)
|
||||||
|
|
|
||||||
|
|
@ -144,6 +144,11 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getLatestCommandTemplateAsFormat() : Format {
|
||||||
|
val t = commandTemplateDao.getFirst()
|
||||||
|
return Format(t.title, "", "", "", "", 0, t.content)
|
||||||
|
}
|
||||||
|
|
||||||
fun turnResultItemsToDownloadItems(items: List<ResultItem?>) : List<DownloadItem> {
|
fun turnResultItemsToDownloadItems(items: List<ResultItem?>) : List<DownloadItem> {
|
||||||
val list : MutableList<DownloadItem> = mutableListOf()
|
val list : MutableList<DownloadItem> = mutableListOf()
|
||||||
items.forEach {
|
items.forEach {
|
||||||
|
|
|
||||||
|
|
@ -14,22 +14,29 @@ import android.os.Build
|
||||||
import android.os.Build.VERSION_CODES
|
import android.os.Build.VERSION_CODES
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import android.view.Window
|
import android.view.Window
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
|
import android.widget.Button
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.activity.ComponentActivity
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.app.ActivityCompat
|
import androidx.core.app.ActivityCompat
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.ViewCompat
|
||||||
import androidx.core.view.WindowCompat
|
import androidx.core.view.WindowCompat
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.deniscerri.ytdlnis.MainActivity
|
import com.deniscerri.ytdlnis.MainActivity
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
|
import com.deniscerri.ytdlnis.adapter.PlaylistAdapter
|
||||||
|
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||||
import com.deniscerri.ytdlnis.database.models.ResultItem
|
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
|
||||||
import com.deniscerri.ytdlnis.ui.downloadcard.DownloadBottomSheetDialog
|
import com.deniscerri.ytdlnis.ui.downloadcard.DownloadBottomSheetDialog
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
import com.deniscerri.ytdlnis.ui.downloadcard.SelectPlaylistItemsBottomSheetDialog
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
|
@ -111,7 +118,11 @@ class ShareActivity : AppCompatActivity() {
|
||||||
if (it.isNotEmpty() && supportFragmentManager.findFragmentByTag("downloadSingleSheet") == null){
|
if (it.isNotEmpty() && supportFragmentManager.findFragmentByTag("downloadSingleSheet") == null){
|
||||||
if(resultViewModel.itemCount.value!! == it.size){
|
if(resultViewModel.itemCount.value!! == it.size){
|
||||||
loadingBottomSheet.cancel()
|
loadingBottomSheet.cancel()
|
||||||
showDownloadSheet(it[0])
|
if (it.size == 1){
|
||||||
|
showDownloadSheet(it[0])
|
||||||
|
}else{
|
||||||
|
showSelectPlaylistItems(it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -130,6 +141,24 @@ class ShareActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun showSelectPlaylistItems(it: List<ResultItem>){
|
||||||
|
if (sharedPreferences.getBoolean("download_card", true)){
|
||||||
|
val bottomSheet = SelectPlaylistItemsBottomSheetDialog(it, DownloadViewModel.Type.valueOf(sharedPreferences.getString("preferred_download_type", "video")!!))
|
||||||
|
bottomSheet.show(supportFragmentManager, "downloadPlaylistSheet")
|
||||||
|
}else{
|
||||||
|
lifecycleScope.launch(Dispatchers.IO){
|
||||||
|
val downloadItems = mutableListOf<DownloadItem>()
|
||||||
|
it.forEach { res ->
|
||||||
|
val i = downloadViewModel.createDownloadItemFromResult(res, DownloadViewModel.Type.valueOf(sharedPreferences.getString("preferred_download_type", "video")!!))
|
||||||
|
i.format = downloadViewModel.getLatestCommandTemplateAsFormat()
|
||||||
|
downloadItems.add(i)
|
||||||
|
}
|
||||||
|
downloadViewModel.queueDownloads(downloadItems)
|
||||||
|
}
|
||||||
|
this.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun askPermissions() {
|
private fun askPermissions() {
|
||||||
if (Build.VERSION.SDK_INT < VERSION_CODES.TIRAMISU && !checkFilePermission()) {
|
if (Build.VERSION.SDK_INT < VERSION_CODES.TIRAMISU && !checkFilePermission()) {
|
||||||
ActivityCompat.requestPermissions(
|
ActivityCompat.requestPermissions(
|
||||||
|
|
|
||||||
|
|
@ -134,8 +134,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
|
||||||
resultViewModel.items.observe(viewLifecycleOwner) {
|
resultViewModel.items.observe(viewLifecycleOwner) {
|
||||||
homeAdapter!!.submitList(it)
|
homeAdapter!!.submitList(it)
|
||||||
resultsList = it
|
resultsList = it
|
||||||
Log.e(TAG, resultViewModel.itemCount.toString())
|
if(resultViewModel.itemCount.value!! > 1 || resultViewModel.itemCount.value!! == -1){
|
||||||
if(resultViewModel.itemCount.value!! > 1){
|
|
||||||
if (it[0].playlistTitle.isNotEmpty() && it[0].playlistTitle != getString(R.string.trendingPlaylist)){
|
if (it[0].playlistTitle.isNotEmpty() && it[0].playlistTitle != getString(R.string.trendingPlaylist)){
|
||||||
downloadAllFabCoordinator!!.visibility = VISIBLE
|
downloadAllFabCoordinator!!.visibility = VISIBLE
|
||||||
}else{
|
}else{
|
||||||
|
|
@ -388,30 +387,20 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
|
||||||
if (viewIdName.isNotEmpty()) {
|
if (viewIdName.isNotEmpty()) {
|
||||||
if (viewIdName == "downloadSelected") {
|
if (viewIdName == "downloadSelected") {
|
||||||
val downloadList = downloadViewModel.turnResultItemsToDownloadItems(selectedObjects!!)
|
val downloadList = downloadViewModel.turnResultItemsToDownloadItems(selectedObjects!!)
|
||||||
downloadViewModel.putDownloadsForProcessing(selectedObjects!!, downloadList).observe(viewLifecycleOwner) {
|
if (sharedPreferences!!.getBoolean("download_card", true)) {
|
||||||
it.forEachIndexed { i, itemID ->
|
val bottomSheet = DownloadMultipleBottomSheetDialog(downloadList.toMutableList())
|
||||||
downloadList[i].id = itemID
|
bottomSheet.show(parentFragmentManager, "downloadMultipleSheet")
|
||||||
}
|
} else {
|
||||||
if (sharedPreferences!!.getBoolean("download_card", true)) {
|
downloadViewModel.queueDownloads(downloadList)
|
||||||
val bottomSheet = DownloadMultipleBottomSheetDialog(downloadList)
|
|
||||||
bottomSheet.show(parentFragmentManager, "downloadMultipleSheet")
|
|
||||||
} else {
|
|
||||||
downloadViewModel.queueDownloads(downloadList)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (viewIdName == "downloadAll") {
|
if (viewIdName == "downloadAll") {
|
||||||
val downloadList = downloadViewModel.turnResultItemsToDownloadItems(resultsList!!)
|
val downloadList = downloadViewModel.turnResultItemsToDownloadItems(resultsList!!)
|
||||||
downloadViewModel.putDownloadsForProcessing(resultsList!!, downloadList).observe(viewLifecycleOwner) {
|
if (sharedPreferences!!.getBoolean("download_card", true)) {
|
||||||
it.forEachIndexed { i, itemID ->
|
val bottomSheet = DownloadMultipleBottomSheetDialog(downloadList.toMutableList())
|
||||||
downloadList[i].id = itemID
|
bottomSheet.show(parentFragmentManager, "downloadMultipleSheet")
|
||||||
}
|
} else {
|
||||||
if (sharedPreferences!!.getBoolean("download_card", true)) {
|
downloadViewModel.queueDownloads(downloadList)
|
||||||
val bottomSheet = DownloadMultipleBottomSheetDialog(downloadList)
|
|
||||||
bottomSheet.show(parentFragmentManager, "downloadMultipleSheet")
|
|
||||||
} else {
|
|
||||||
downloadViewModel.queueDownloads(downloadList)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.Button
|
import android.widget.Button
|
||||||
import android.widget.LinearLayout
|
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
|
@ -20,31 +19,33 @@ import com.deniscerri.ytdlnis.database.dao.CommandTemplateDao
|
||||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||||
import com.deniscerri.ytdlnis.database.models.ResultItem
|
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||||
|
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel.Type
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
|
||||||
|
import com.google.android.exoplayer2.Player
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
import com.google.android.material.button.MaterialButton
|
|
||||||
import com.google.android.material.tabs.TabLayout
|
import com.google.android.material.tabs.TabLayout
|
||||||
import com.google.gson.Gson
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel.Type
|
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
class ConfigureDownloadBottomSheetDialog(private val resultItem: ResultItem, private val type: Type) : BottomSheetDialogFragment() {
|
|
||||||
|
class ConfigureDownloadBottomSheetDialog(private val resultItem: ResultItem, private val downloadItem: DownloadItem, private val listener: OnDownloadItemUpdateListener) : BottomSheetDialogFragment() {
|
||||||
private lateinit var tabLayout: TabLayout
|
private lateinit var tabLayout: TabLayout
|
||||||
private lateinit var viewPager2: ViewPager2
|
private lateinit var viewPager2: ViewPager2
|
||||||
private lateinit var fragmentAdapter : DownloadFragmentAdapter
|
private lateinit var fragmentAdapter : DownloadFragmentAdapter
|
||||||
private lateinit var downloadViewModel: DownloadViewModel
|
private lateinit var downloadViewModel: DownloadViewModel
|
||||||
private lateinit var resultViewModel: ResultViewModel
|
private lateinit var resultViewModel: ResultViewModel
|
||||||
private lateinit var commandTemplateDao: CommandTemplateDao
|
private lateinit var commandTemplateDao: CommandTemplateDao
|
||||||
|
private lateinit var onDownloadItemUpdateListener: OnDownloadItemUpdateListener
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||||
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
|
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
|
||||||
commandTemplateDao = DBManager.getInstance(requireContext()).commandTemplateDao
|
commandTemplateDao = DBManager.getInstance(requireContext()).commandTemplateDao
|
||||||
|
onDownloadItemUpdateListener = listener
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
|
@ -63,13 +64,13 @@ class ConfigureDownloadBottomSheetDialog(private val resultItem: ResultItem, pri
|
||||||
tabLayout = view.findViewById(R.id.download_tablayout)
|
tabLayout = view.findViewById(R.id.download_tablayout)
|
||||||
viewPager2 = view.findViewById(R.id.download_viewpager)
|
viewPager2 = view.findViewById(R.id.download_viewpager)
|
||||||
|
|
||||||
val fragments = mutableListOf<Fragment>(DownloadAudioFragment(resultItem), DownloadVideoFragment(resultItem))
|
val fragments = mutableListOf<Fragment>(DownloadAudioFragment(resultItem, downloadItem), DownloadVideoFragment(resultItem, downloadItem))
|
||||||
|
|
||||||
lifecycleScope.launch{
|
lifecycleScope.launch{
|
||||||
withContext(Dispatchers.IO){
|
withContext(Dispatchers.IO){
|
||||||
val nr = commandTemplateDao.getTotalNumber()
|
val nr = commandTemplateDao.getTotalNumber()
|
||||||
if(nr > 0){
|
if(nr > 0){
|
||||||
fragments.add(DownloadCommandFragment(resultItem))
|
fragments.add(DownloadCommandFragment(resultItem, downloadItem))
|
||||||
}else{
|
}else{
|
||||||
(tabLayout.getChildAt(0) as? ViewGroup)?.getChildAt(2)?.isEnabled = false
|
(tabLayout.getChildAt(0) as? ViewGroup)?.getChildAt(2)?.isEnabled = false
|
||||||
}
|
}
|
||||||
|
|
@ -77,7 +78,6 @@ class ConfigureDownloadBottomSheetDialog(private val resultItem: ResultItem, pri
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
val fragmentManager = parentFragmentManager
|
val fragmentManager = parentFragmentManager
|
||||||
fragmentAdapter = DownloadFragmentAdapter(
|
fragmentAdapter = DownloadFragmentAdapter(
|
||||||
resultItem,
|
resultItem,
|
||||||
|
|
@ -88,7 +88,7 @@ class ConfigureDownloadBottomSheetDialog(private val resultItem: ResultItem, pri
|
||||||
viewPager2.adapter = fragmentAdapter
|
viewPager2.adapter = fragmentAdapter
|
||||||
viewPager2.isSaveFromParentEnabled = false
|
viewPager2.isSaveFromParentEnabled = false
|
||||||
|
|
||||||
when(type) {
|
when(downloadItem.type) {
|
||||||
Type.audio -> {
|
Type.audio -> {
|
||||||
tabLayout.selectTab(tabLayout.getTabAt(0))
|
tabLayout.selectTab(tabLayout.getTabAt(0))
|
||||||
viewPager2.setCurrentItem(0, false)
|
viewPager2.setCurrentItem(0, false)
|
||||||
|
|
@ -99,7 +99,9 @@ class ConfigureDownloadBottomSheetDialog(private val resultItem: ResultItem, pri
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
tabLayout.selectTab(tabLayout.getTabAt(2))
|
tabLayout.selectTab(tabLayout.getTabAt(2))
|
||||||
viewPager2.setCurrentItem(2, false)
|
viewPager2.postDelayed( {
|
||||||
|
viewPager2.setCurrentItem(2, false)
|
||||||
|
}, 200)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -121,11 +123,7 @@ class ConfigureDownloadBottomSheetDialog(private val resultItem: ResultItem, pri
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
viewPager2.setPageTransformer(BackgroundToForegroundPageTransformer())
|
||||||
val cancelBtn = view.findViewById<MaterialButton>(R.id.bottomsheet_cancel_button)
|
|
||||||
cancelBtn.setOnClickListener{
|
|
||||||
dismiss()
|
|
||||||
}
|
|
||||||
|
|
||||||
val ok = view.findViewById<Button>(R.id.bottom_sheet_ok)
|
val ok = view.findViewById<Button>(R.id.bottom_sheet_ok)
|
||||||
ok!!.setOnClickListener {
|
ok!!.setOnClickListener {
|
||||||
|
|
@ -144,12 +142,18 @@ class ConfigureDownloadBottomSheetDialog(private val resultItem: ResultItem, pri
|
||||||
f.downloadItem
|
f.downloadItem
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
downloadViewModel.updateDownload(item)
|
Log.e("aa", item.toString())
|
||||||
|
onDownloadItemUpdateListener.onDownloadItemUpdate(resultItem.id, item)
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
interface OnDownloadItemUpdateListener {
|
||||||
|
fun onDownloadItemUpdate(resultItemID: Long, item: DownloadItem)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCancel(dialog: DialogInterface) {
|
override fun onCancel(dialog: DialogInterface) {
|
||||||
super.onCancel(dialog)
|
super.onCancel(dialog)
|
||||||
//returnPreviousState();
|
//returnPreviousState();
|
||||||
|
|
@ -182,4 +186,3 @@ class ConfigureDownloadBottomSheetDialog(private val resultItem: ResultItem, pri
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,10 +31,11 @@ import com.deniscerri.ytdlnis.util.FileUtil
|
||||||
import com.deniscerri.ytdlnis.util.UiUtil
|
import com.deniscerri.ytdlnis.util.UiUtil
|
||||||
import com.google.android.material.chip.Chip
|
import com.google.android.material.chip.Chip
|
||||||
import com.google.android.material.textfield.TextInputLayout
|
import com.google.android.material.textfield.TextInputLayout
|
||||||
|
import com.google.gson.Gson
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
|
||||||
class DownloadAudioFragment(private var resultItem: ResultItem) : Fragment() {
|
class DownloadAudioFragment(private var resultItem: ResultItem, private var currentDownloadItem: DownloadItem?) : Fragment() {
|
||||||
private var _binding : FragmentHomeBinding? = null
|
private var _binding : FragmentHomeBinding? = null
|
||||||
private var fragmentView: View? = null
|
private var fragmentView: View? = null
|
||||||
private var activity: Activity? = null
|
private var activity: Activity? = null
|
||||||
|
|
@ -46,8 +47,7 @@ class DownloadAudioFragment(private var resultItem: ResultItem) : Fragment() {
|
||||||
private lateinit var author : TextInputLayout
|
private lateinit var author : TextInputLayout
|
||||||
private lateinit var saveDir : TextInputLayout
|
private lateinit var saveDir : TextInputLayout
|
||||||
|
|
||||||
lateinit var downloadItem: DownloadItem
|
lateinit var downloadItem : DownloadItem
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
|
|
@ -57,7 +57,14 @@ class DownloadAudioFragment(private var resultItem: ResultItem) : Fragment() {
|
||||||
fragmentView = inflater.inflate(R.layout.fragment_download_audio, container, false)
|
fragmentView = inflater.inflate(R.layout.fragment_download_audio, container, false)
|
||||||
activity = getActivity()
|
activity = getActivity()
|
||||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||||
downloadItem = downloadViewModel.createDownloadItemFromResult(resultItem, Type.audio)
|
|
||||||
|
downloadItem = if (currentDownloadItem != null && currentDownloadItem!!.type == Type.audio){
|
||||||
|
val string = Gson().toJson(currentDownloadItem, DownloadItem::class.java)
|
||||||
|
Gson().fromJson(string, DownloadItem::class.java)
|
||||||
|
}else{
|
||||||
|
downloadViewModel.createDownloadItemFromResult(resultItem, Type.audio)
|
||||||
|
}
|
||||||
|
|
||||||
fileUtil = FileUtil()
|
fileUtil = FileUtil()
|
||||||
uiUtil = UiUtil(fileUtil)
|
uiUtil = UiUtil(fileUtil)
|
||||||
return fragmentView
|
return fragmentView
|
||||||
|
|
@ -90,14 +97,8 @@ class DownloadAudioFragment(private var resultItem: ResultItem) : Fragment() {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
saveDir = view.findViewById(R.id.outputPath)
|
saveDir = view.findViewById(R.id.outputPath)
|
||||||
val downloadPath = sharedPreferences.getString(
|
|
||||||
"music_path",
|
|
||||||
getString(R.string.music_path)
|
|
||||||
)
|
|
||||||
downloadItem.downloadPath = downloadPath!!
|
|
||||||
//downloadViewModel.updateDownload(downloadItem)
|
|
||||||
saveDir.editText!!.setText(
|
saveDir.editText!!.setText(
|
||||||
fileUtil.formatPath(downloadPath)
|
fileUtil.formatPath(downloadItem.downloadPath)
|
||||||
)
|
)
|
||||||
saveDir.editText!!.isFocusable = false;
|
saveDir.editText!!.isFocusable = false;
|
||||||
saveDir.editText!!.isClickable = true;
|
saveDir.editText!!.isClickable = true;
|
||||||
|
|
@ -121,7 +122,7 @@ class DownloadAudioFragment(private var resultItem: ResultItem) : Fragment() {
|
||||||
if (formats.isEmpty()) {
|
if (formats.isEmpty()) {
|
||||||
formatCard.visibility = View.GONE
|
formatCard.visibility = View.GONE
|
||||||
} else {
|
} else {
|
||||||
val chosenFormat = formats[formats.lastIndex]
|
val chosenFormat = downloadItem.format
|
||||||
uiUtil.populateFormatCard(formatCard, chosenFormat)
|
uiUtil.populateFormatCard(formatCard, chosenFormat)
|
||||||
val listener = object : OnFormatClickListener {
|
val listener = object : OnFormatClickListener {
|
||||||
override fun onFormatClick(allFormats: List<Format>, item: Format) {
|
override fun onFormatClick(allFormats: List<Format>, item: Format) {
|
||||||
|
|
@ -158,19 +159,7 @@ class DownloadAudioFragment(private var resultItem: ResultItem) : Fragment() {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
val selectedContainer: String = try {
|
containerAutoCompleteTextView!!.setText(downloadItem.format.container, false)
|
||||||
if (containers.contains(formats[formats.lastIndex].container)){
|
|
||||||
formats[formats.lastIndex].container
|
|
||||||
}else{
|
|
||||||
sharedPreferences.getString("audio_format", "mp3")!!
|
|
||||||
}
|
|
||||||
}catch (e: Exception){
|
|
||||||
sharedPreferences.getString("audio_format", "mp3")!!
|
|
||||||
}
|
|
||||||
|
|
||||||
downloadItem.format.container = selectedContainer
|
|
||||||
Log.e("TAG", selectedContainer)
|
|
||||||
containerAutoCompleteTextView!!.setText(selectedContainer, false)
|
|
||||||
(container!!.editText as AutoCompleteTextView?)!!.onItemClickListener =
|
(container!!.editText as AutoCompleteTextView?)!!.onItemClickListener =
|
||||||
AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, index: Int, _: Long ->
|
AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, index: Int, _: Long ->
|
||||||
downloadItem.format.container = containers[index]
|
downloadItem.format.container = containers[index]
|
||||||
|
|
|
||||||
|
|
@ -81,13 +81,13 @@ class DownloadBottomSheetDialog(private val resultItem: ResultItem, private val
|
||||||
overScrollMode = View.OVER_SCROLL_NEVER
|
overScrollMode = View.OVER_SCROLL_NEVER
|
||||||
}
|
}
|
||||||
|
|
||||||
val fragments = mutableListOf<Fragment>(DownloadAudioFragment(resultItem), DownloadVideoFragment(resultItem))
|
val fragments = mutableListOf<Fragment>(DownloadAudioFragment(resultItem, null), DownloadVideoFragment(resultItem, null))
|
||||||
|
|
||||||
lifecycleScope.launch{
|
lifecycleScope.launch{
|
||||||
withContext(Dispatchers.IO){
|
withContext(Dispatchers.IO){
|
||||||
val nr = commandTemplateDao.getTotalNumber()
|
val nr = commandTemplateDao.getTotalNumber()
|
||||||
if(nr > 0){
|
if(nr > 0){
|
||||||
fragments.add(DownloadCommandFragment(resultItem))
|
fragments.add(DownloadCommandFragment(resultItem, null))
|
||||||
}else{
|
}else{
|
||||||
(tabLayout.getChildAt(0) as? ViewGroup)?.getChildAt(2)?.isEnabled = false
|
(tabLayout.getChildAt(0) as? ViewGroup)?.getChildAt(2)?.isEnabled = false
|
||||||
(tabLayout.getChildAt(0) as? ViewGroup)?.getChildAt(2)?.alpha = 0.3f
|
(tabLayout.getChildAt(0) as? ViewGroup)?.getChildAt(2)?.alpha = 0.3f
|
||||||
|
|
|
||||||
|
|
@ -31,11 +31,12 @@ import com.deniscerri.ytdlnis.util.FileUtil
|
||||||
import com.deniscerri.ytdlnis.util.UiUtil
|
import com.deniscerri.ytdlnis.util.UiUtil
|
||||||
import com.google.android.material.chip.Chip
|
import com.google.android.material.chip.Chip
|
||||||
import com.google.android.material.textfield.TextInputLayout
|
import com.google.android.material.textfield.TextInputLayout
|
||||||
|
import com.google.gson.Gson
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
class DownloadCommandFragment(private val resultItem: ResultItem) : Fragment() {
|
class DownloadCommandFragment(private val resultItem: ResultItem, private var currentDownloadItem: DownloadItem?) : Fragment() {
|
||||||
private var _binding : FragmentHomeBinding? = null
|
private var _binding : FragmentHomeBinding? = null
|
||||||
private var fragmentView: View? = null
|
private var fragmentView: View? = null
|
||||||
private var activity: Activity? = null
|
private var activity: Activity? = null
|
||||||
|
|
@ -57,7 +58,14 @@ class DownloadCommandFragment(private val resultItem: ResultItem) : Fragment() {
|
||||||
activity = getActivity()
|
activity = getActivity()
|
||||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||||
commandTemplateViewModel = ViewModelProvider(this)[CommandTemplateViewModel::class.java]
|
commandTemplateViewModel = ViewModelProvider(this)[CommandTemplateViewModel::class.java]
|
||||||
downloadItem = downloadViewModel.createDownloadItemFromResult(resultItem, DownloadViewModel.Type.command)
|
|
||||||
|
downloadItem = if (currentDownloadItem != null && currentDownloadItem!!.type == DownloadViewModel.Type.command){
|
||||||
|
val string = Gson().toJson(currentDownloadItem, DownloadItem::class.java)
|
||||||
|
Gson().fromJson(string, DownloadItem::class.java)
|
||||||
|
}else{
|
||||||
|
downloadViewModel.createDownloadItemFromResult(resultItem, DownloadViewModel.Type.command)
|
||||||
|
}
|
||||||
|
|
||||||
fileUtil = FileUtil()
|
fileUtil = FileUtil()
|
||||||
uiUtil = UiUtil(fileUtil)
|
uiUtil = UiUtil(fileUtil)
|
||||||
return fragmentView
|
return fragmentView
|
||||||
|
|
@ -138,13 +146,8 @@ class DownloadCommandFragment(private val resultItem: ResultItem) : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
saveDir = view.findViewById(R.id.outputPath)
|
saveDir = view.findViewById(R.id.outputPath)
|
||||||
val downloadPath = sharedPreferences.getString(
|
|
||||||
"command_path",
|
|
||||||
getString(R.string.command_path)
|
|
||||||
)
|
|
||||||
downloadItem.downloadPath = downloadPath!!
|
|
||||||
saveDir.editText!!.setText(
|
saveDir.editText!!.setText(
|
||||||
fileUtil.formatPath(downloadPath)
|
fileUtil.formatPath(downloadItem.downloadPath)
|
||||||
)
|
)
|
||||||
saveDir.editText!!.isFocusable = false;
|
saveDir.editText!!.isFocusable = false;
|
||||||
saveDir.editText!!.isClickable = true;
|
saveDir.editText!!.isClickable = true;
|
||||||
|
|
|
||||||
|
|
@ -1,52 +1,61 @@
|
||||||
package com.deniscerri.ytdlnis.ui.downloadcard
|
package com.deniscerri.ytdlnis.ui.downloadcard
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.DatePickerDialog
|
import android.app.Activity
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
import android.app.TimePickerDialog
|
|
||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.util.DisplayMetrics
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.Button
|
import android.widget.Button
|
||||||
import androidx.fragment.app.FragmentTransaction
|
import android.widget.TextView
|
||||||
import androidx.fragment.app.findFragment
|
import android.widget.Toast
|
||||||
import androidx.lifecycle.Observer
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import androidx.viewpager2.widget.ViewPager2
|
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.adapter.ConfigureMultipleDownloadsAdapter
|
import com.deniscerri.ytdlnis.adapter.ConfigureMultipleDownloadsAdapter
|
||||||
import com.deniscerri.ytdlnis.adapter.HomeAdapter
|
|
||||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
import com.deniscerri.ytdlnis.database.models.Format
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
|
||||||
|
import com.deniscerri.ytdlnis.util.FileUtil
|
||||||
|
import com.google.android.material.bottomappbar.BottomAppBar
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
import com.google.android.material.button.MaterialButton
|
import com.google.android.material.button.MaterialButton
|
||||||
import com.google.android.material.tabs.TabLayout
|
import com.google.android.material.datepicker.CalendarConstraints
|
||||||
|
import com.google.android.material.datepicker.DateValidatorPointForward
|
||||||
|
import com.google.android.material.datepicker.MaterialDatePicker
|
||||||
|
import com.google.android.material.timepicker.MaterialTimePicker
|
||||||
|
import com.google.android.material.timepicker.TimeFormat
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
class DownloadMultipleBottomSheetDialog(private val items: List<DownloadItem>) : BottomSheetDialogFragment(), ConfigureMultipleDownloadsAdapter.OnItemClickListener, View.OnClickListener {
|
class DownloadMultipleBottomSheetDialog(private val items: MutableList<DownloadItem>) : BottomSheetDialogFragment(), ConfigureMultipleDownloadsAdapter.OnItemClickListener, View.OnClickListener,
|
||||||
|
ConfigureDownloadBottomSheetDialog.OnDownloadItemUpdateListener {
|
||||||
private lateinit var downloadViewModel: DownloadViewModel
|
private lateinit var downloadViewModel: DownloadViewModel
|
||||||
private lateinit var resultViewModel: ResultViewModel
|
private lateinit var resultViewModel: ResultViewModel
|
||||||
private lateinit var listAdapter : ConfigureMultipleDownloadsAdapter
|
private lateinit var listAdapter : ConfigureMultipleDownloadsAdapter
|
||||||
private lateinit var recyclerView: RecyclerView
|
private lateinit var recyclerView: RecyclerView
|
||||||
private lateinit var behavior: BottomSheetBehavior<View>
|
private lateinit var behavior: BottomSheetBehavior<View>
|
||||||
|
private lateinit var fileUtil: FileUtil
|
||||||
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||||
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
|
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
|
||||||
|
fileUtil = FileUtil()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
|
@ -60,12 +69,13 @@ class DownloadMultipleBottomSheetDialog(private val items: List<DownloadItem>) :
|
||||||
super.setupDialog(dialog, style)
|
super.setupDialog(dialog, style)
|
||||||
val view = LayoutInflater.from(context).inflate(R.layout.download_multiple_bottom_sheet, null)
|
val view = LayoutInflater.from(context).inflate(R.layout.download_multiple_bottom_sheet, null)
|
||||||
dialog.setContentView(view)
|
dialog.setContentView(view)
|
||||||
view.minimumHeight = resources.displayMetrics.heightPixels
|
//view.minimumHeight = resources.displayMetrics.heightPixels
|
||||||
|
|
||||||
dialog.setOnShowListener {
|
dialog.setOnShowListener {
|
||||||
behavior = BottomSheetBehavior.from(view.parent as View)
|
behavior = BottomSheetBehavior.from(view.parent as View)
|
||||||
behavior.skipCollapsed = true
|
val displayMetrics = DisplayMetrics()
|
||||||
behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics)
|
||||||
|
behavior.peekHeight = displayMetrics.heightPixels / 2
|
||||||
}
|
}
|
||||||
|
|
||||||
listAdapter =
|
listAdapter =
|
||||||
|
|
@ -77,50 +87,48 @@ class DownloadMultipleBottomSheetDialog(private val items: List<DownloadItem>) :
|
||||||
recyclerView = view.findViewById(R.id.downloadMultipleRecyclerview)
|
recyclerView = view.findViewById(R.id.downloadMultipleRecyclerview)
|
||||||
recyclerView.layoutManager = LinearLayoutManager(requireContext())
|
recyclerView.layoutManager = LinearLayoutManager(requireContext())
|
||||||
recyclerView.adapter = listAdapter
|
recyclerView.adapter = listAdapter
|
||||||
|
listAdapter.submitList(items.toList())
|
||||||
downloadViewModel.processingDownloads.observe(this) {
|
|
||||||
listAdapter.submitList(it)
|
|
||||||
if (it.isEmpty()){
|
|
||||||
dismiss()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val scheduleBtn = view.findViewById<MaterialButton>(R.id.bottomsheet_schedule_button)
|
val scheduleBtn = view.findViewById<MaterialButton>(R.id.bottomsheet_schedule_button)
|
||||||
scheduleBtn.setOnClickListener{
|
scheduleBtn.setOnClickListener{
|
||||||
val currentDate = Calendar.getInstance()
|
val currentDate = Calendar.getInstance()
|
||||||
val date = Calendar.getInstance()
|
val date = Calendar.getInstance()
|
||||||
|
|
||||||
val datepicker = DatePickerDialog(
|
val datepicker = MaterialDatePicker.Builder.datePicker()
|
||||||
requireContext(),
|
.setCalendarConstraints(
|
||||||
{ view, year, monthOfYear, dayOfMonth ->
|
CalendarConstraints.Builder()
|
||||||
date[year, monthOfYear] = dayOfMonth
|
.setValidator(DateValidatorPointForward.now())
|
||||||
TimePickerDialog(context,
|
.build()
|
||||||
{ _, hourOfDay, minute ->
|
)
|
||||||
date[Calendar.HOUR_OF_DAY] = hourOfDay
|
.setSelection(MaterialDatePicker.todayInUtcMilliseconds())
|
||||||
date[Calendar.MINUTE] = minute
|
.build()
|
||||||
|
|
||||||
items.forEach {
|
datepicker.addOnPositiveButtonClickListener{
|
||||||
it.downloadStartTime = date.timeInMillis
|
date.timeInMillis = it
|
||||||
}
|
|
||||||
downloadViewModel.queueDownloads(items)
|
|
||||||
dismiss()
|
val timepicker = MaterialTimePicker.Builder()
|
||||||
},
|
.setTimeFormat(TimeFormat.CLOCK_24H)
|
||||||
currentDate.get(Calendar.HOUR_OF_DAY),
|
.setHour(currentDate.get(Calendar.HOUR_OF_DAY))
|
||||||
currentDate.get(Calendar.MINUTE),
|
.setMinute(currentDate.get(Calendar.MINUTE))
|
||||||
false
|
.build()
|
||||||
).show()
|
|
||||||
},
|
timepicker.addOnPositiveButtonClickListener{
|
||||||
currentDate.get(Calendar.YEAR),
|
date[Calendar.HOUR_OF_DAY] = timepicker.hour
|
||||||
currentDate.get(Calendar.MONTH),
|
date[Calendar.MINUTE] = timepicker.minute
|
||||||
currentDate.get(Calendar.DATE)
|
|
||||||
)
|
|
||||||
datepicker.datePicker.minDate = System.currentTimeMillis() - 1000
|
items.forEach { item ->
|
||||||
datepicker.show()
|
item.downloadStartTime = date.timeInMillis
|
||||||
}
|
}
|
||||||
|
downloadViewModel.queueDownloads(items)
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
timepicker.show(parentFragmentManager, "timepicker")
|
||||||
|
|
||||||
|
}
|
||||||
|
datepicker.show(parentFragmentManager, "datepicker")
|
||||||
|
|
||||||
val cancelBtn = view.findViewById<MaterialButton>(R.id.bottomsheet_cancel_button)
|
|
||||||
cancelBtn.setOnClickListener{
|
|
||||||
dismiss()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val download = view.findViewById<Button>(R.id.bottomsheet_download_button)
|
val download = view.findViewById<Button>(R.id.bottomsheet_download_button)
|
||||||
|
|
@ -128,6 +136,40 @@ class DownloadMultipleBottomSheetDialog(private val items: List<DownloadItem>) :
|
||||||
downloadViewModel.queueDownloads(items)
|
downloadViewModel.queueDownloads(items)
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val bottomAppBar = view.findViewById<BottomAppBar>(R.id.bottomAppBar)
|
||||||
|
bottomAppBar!!.setOnMenuItemClickListener { m: MenuItem ->
|
||||||
|
val itemId = m.itemId
|
||||||
|
if (itemId == R.id.folder) {
|
||||||
|
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
||||||
|
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
||||||
|
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||||
|
intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
|
||||||
|
pathResultLauncher.launch(intent)
|
||||||
|
} else if (itemId == R.id.edit){
|
||||||
|
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private var pathResultLauncher = registerForActivityResult(
|
||||||
|
ActivityResultContracts.StartActivityForResult()
|
||||||
|
) { result ->
|
||||||
|
if (result.resultCode == Activity.RESULT_OK) {
|
||||||
|
result.data?.data?.let {
|
||||||
|
activity?.contentResolver?.takePersistableUriPermission(
|
||||||
|
it,
|
||||||
|
Intent.FLAG_GRANT_READ_URI_PERMISSION or
|
||||||
|
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||||
|
)
|
||||||
|
}
|
||||||
|
items.forEach {
|
||||||
|
it.downloadPath = result.data?.data.toString()
|
||||||
|
}
|
||||||
|
Toast.makeText(requireContext(), "Changed every item's download path to: ${fileUtil.formatPath(result.data!!.data.toString())}", Toast.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCancel(dialog: DialogInterface) {
|
override fun onCancel(dialog: DialogInterface) {
|
||||||
|
|
@ -149,15 +191,13 @@ class DownloadMultipleBottomSheetDialog(private val items: List<DownloadItem>) :
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCardClick(itemID: Long) {
|
override fun onCardClick(itemURL: String) {
|
||||||
lifecycleScope.launch{
|
lifecycleScope.launch{
|
||||||
val downloadItem = withContext(Dispatchers.IO){
|
val downloadItem = items.find { it.url == itemURL }
|
||||||
downloadViewModel.getItemByID(itemID)
|
|
||||||
}
|
|
||||||
val resultItem = withContext(Dispatchers.IO){
|
val resultItem = withContext(Dispatchers.IO){
|
||||||
resultViewModel.getItemByURL(downloadItem.url)
|
resultViewModel.getItemByURL(downloadItem!!.url)
|
||||||
}
|
}
|
||||||
val bottomSheet = ConfigureDownloadBottomSheetDialog(resultItem, DownloadViewModel.Type.video)
|
val bottomSheet = ConfigureDownloadBottomSheetDialog(resultItem, downloadItem!!, this@DownloadMultipleBottomSheetDialog)
|
||||||
bottomSheet.show(parentFragmentManager, "configureDownloadSingleSheet")
|
bottomSheet.show(parentFragmentManager, "configureDownloadSingleSheet")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -166,5 +206,12 @@ class DownloadMultipleBottomSheetDialog(private val items: List<DownloadItem>) :
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onDownloadItemUpdate(resultItemID: Long, item: DownloadItem) {
|
||||||
|
val i = items.indexOf(items.find { it.url == item.url })
|
||||||
|
items[i] = item
|
||||||
|
Log.e("aa", items.toList().toString())
|
||||||
|
listAdapter.submitList(items.toList())
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,12 +30,13 @@ import com.deniscerri.ytdlnis.util.FileUtil
|
||||||
import com.deniscerri.ytdlnis.util.UiUtil
|
import com.deniscerri.ytdlnis.util.UiUtil
|
||||||
import com.google.android.material.chip.Chip
|
import com.google.android.material.chip.Chip
|
||||||
import com.google.android.material.textfield.TextInputLayout
|
import com.google.android.material.textfield.TextInputLayout
|
||||||
|
import com.google.gson.Gson
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
|
||||||
class DownloadVideoFragment(private val resultItem: ResultItem) : Fragment() {
|
class DownloadVideoFragment(private val resultItem: ResultItem, private var currentDownloadItem: DownloadItem?) : Fragment() {
|
||||||
private var _binding : FragmentHomeBinding? = null
|
private var _binding : FragmentHomeBinding? = null
|
||||||
private var fragmentView: View? = null
|
private var fragmentView: View? = null
|
||||||
private var activity: Activity? = null
|
private var activity: Activity? = null
|
||||||
|
|
@ -60,7 +61,14 @@ class DownloadVideoFragment(private val resultItem: ResultItem) : Fragment() {
|
||||||
activity = getActivity()
|
activity = getActivity()
|
||||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||||
resultViewModel = ViewModelProvider(this@DownloadVideoFragment)[ResultViewModel::class.java]
|
resultViewModel = ViewModelProvider(this@DownloadVideoFragment)[ResultViewModel::class.java]
|
||||||
downloadItem = downloadViewModel.createDownloadItemFromResult(resultItem, Type.video)
|
|
||||||
|
downloadItem = if (currentDownloadItem != null && currentDownloadItem!!.type == Type.video){
|
||||||
|
val string = Gson().toJson(currentDownloadItem, DownloadItem::class.java)
|
||||||
|
Gson().fromJson(string, DownloadItem::class.java)
|
||||||
|
}else{
|
||||||
|
downloadViewModel.createDownloadItemFromResult(resultItem, Type.video)
|
||||||
|
}
|
||||||
|
|
||||||
fileUtil = FileUtil()
|
fileUtil = FileUtil()
|
||||||
uiUtil = UiUtil(fileUtil)
|
uiUtil = UiUtil(fileUtil)
|
||||||
return fragmentView
|
return fragmentView
|
||||||
|
|
@ -94,13 +102,8 @@ class DownloadVideoFragment(private val resultItem: ResultItem) : Fragment() {
|
||||||
})
|
})
|
||||||
|
|
||||||
saveDir = view.findViewById(R.id.outputPath)
|
saveDir = view.findViewById(R.id.outputPath)
|
||||||
val downloadPath = sharedPreferences.getString(
|
|
||||||
"video_path",
|
|
||||||
getString(R.string.video_path)
|
|
||||||
)
|
|
||||||
downloadItem.downloadPath = downloadPath!!
|
|
||||||
saveDir.editText!!.setText(
|
saveDir.editText!!.setText(
|
||||||
fileUtil.formatPath(downloadPath)
|
fileUtil.formatPath(downloadItem.downloadPath)
|
||||||
)
|
)
|
||||||
saveDir.editText!!.isFocusable = false;
|
saveDir.editText!!.isFocusable = false;
|
||||||
saveDir.editText!!.isClickable = true;
|
saveDir.editText!!.isClickable = true;
|
||||||
|
|
@ -120,10 +123,8 @@ class DownloadVideoFragment(private val resultItem: ResultItem) : Fragment() {
|
||||||
videoFormats.forEach { formats.add(Format(it, container!!,"","", "",0, it)) }
|
videoFormats.forEach { formats.add(Format(it, container!!,"","", "",0, it)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
downloadItem.format = formats[formats.lastIndex]
|
|
||||||
val containers = requireContext().resources.getStringArray(R.array.video_containers)
|
val containers = requireContext().resources.getStringArray(R.array.video_containers)
|
||||||
|
|
||||||
|
|
||||||
val container = view.findViewById<TextInputLayout>(R.id.downloadContainer)
|
val container = view.findViewById<TextInputLayout>(R.id.downloadContainer)
|
||||||
val containerAutoCompleteTextView =
|
val containerAutoCompleteTextView =
|
||||||
view.findViewById<AutoCompleteTextView>(R.id.container_textview)
|
view.findViewById<AutoCompleteTextView>(R.id.container_textview)
|
||||||
|
|
@ -146,7 +147,7 @@ class DownloadVideoFragment(private val resultItem: ResultItem) : Fragment() {
|
||||||
containerAutoCompleteTextView!!.setText(selectedContainer, false)
|
containerAutoCompleteTextView!!.setText(selectedContainer, false)
|
||||||
|
|
||||||
val formatCard = view.findViewById<ConstraintLayout>(R.id.format_card_constraintLayout)
|
val formatCard = view.findViewById<ConstraintLayout>(R.id.format_card_constraintLayout)
|
||||||
val chosenFormat = formats[formats.lastIndex]
|
val chosenFormat = downloadItem.format
|
||||||
uiUtil.populateFormatCard(formatCard, chosenFormat)
|
uiUtil.populateFormatCard(formatCard, chosenFormat)
|
||||||
val listener = object : OnFormatClickListener {
|
val listener = object : OnFormatClickListener {
|
||||||
override fun onFormatClick(allFormats: List<Format>, item: Format) {
|
override fun onFormatClick(allFormats: List<Format>, item: Format) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,141 @@
|
||||||
|
package com.deniscerri.ytdlnis.ui.downloadcard
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.Dialog
|
||||||
|
import android.content.DialogInterface
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.util.DisplayMetrics
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.Button
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.deniscerri.ytdlnis.R
|
||||||
|
import com.deniscerri.ytdlnis.adapter.ConfigureMultipleDownloadsAdapter
|
||||||
|
import com.deniscerri.ytdlnis.adapter.PlaylistAdapter
|
||||||
|
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||||
|
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||||
|
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||||
|
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
|
import com.google.android.material.button.MaterialButton
|
||||||
|
import com.google.android.material.datepicker.CalendarConstraints
|
||||||
|
import com.google.android.material.datepicker.DateValidatorPointForward
|
||||||
|
import com.google.android.material.datepicker.MaterialDatePicker
|
||||||
|
import com.google.android.material.timepicker.MaterialTimePicker
|
||||||
|
import com.google.android.material.timepicker.TimeFormat
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class SelectPlaylistItemsBottomSheetDialog(private val items: List<ResultItem>, private val type: DownloadViewModel.Type) : BottomSheetDialogFragment(), PlaylistAdapter.OnItemClickListener {
|
||||||
|
private lateinit var downloadViewModel: DownloadViewModel
|
||||||
|
private lateinit var resultViewModel: ResultViewModel
|
||||||
|
private lateinit var listAdapter : PlaylistAdapter
|
||||||
|
private lateinit var recyclerView: RecyclerView
|
||||||
|
private lateinit var behavior: BottomSheetBehavior<View>
|
||||||
|
private lateinit var selectedText: TextView
|
||||||
|
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||||
|
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
val behavior = BottomSheetBehavior.from(view.parent as View)
|
||||||
|
behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("RestrictedApi")
|
||||||
|
override fun setupDialog(dialog: Dialog, style: Int) {
|
||||||
|
super.setupDialog(dialog, style)
|
||||||
|
val view = LayoutInflater.from(context).inflate(R.layout.select_playlist_items, null)
|
||||||
|
dialog.setContentView(view)
|
||||||
|
|
||||||
|
dialog.setOnShowListener {
|
||||||
|
behavior = BottomSheetBehavior.from(view.parent as View)
|
||||||
|
val displayMetrics = DisplayMetrics()
|
||||||
|
requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics)
|
||||||
|
behavior.peekHeight = displayMetrics.heightPixels / 2
|
||||||
|
}
|
||||||
|
|
||||||
|
listAdapter =
|
||||||
|
PlaylistAdapter(
|
||||||
|
this,
|
||||||
|
requireActivity()
|
||||||
|
)
|
||||||
|
|
||||||
|
recyclerView = view.findViewById(R.id.downloadMultipleRecyclerview)
|
||||||
|
recyclerView.layoutManager = LinearLayoutManager(requireContext())
|
||||||
|
recyclerView.adapter = listAdapter
|
||||||
|
listAdapter.submitList(items)
|
||||||
|
|
||||||
|
selectedText = view.findViewById<Button>(R.id.selected)
|
||||||
|
selectedText.text = "0 ${resources.getString(R.string.selected)}"
|
||||||
|
|
||||||
|
val checkAll = view.findViewById<Button>(R.id.check_all)
|
||||||
|
checkAll!!.setOnClickListener {
|
||||||
|
if (listAdapter.getCheckedItems().isEmpty()){
|
||||||
|
listAdapter.checkAll()
|
||||||
|
selectedText.text = resources.getString(R.string.all_items_selected)
|
||||||
|
|
||||||
|
}else{
|
||||||
|
listAdapter.clearCheckeditems()
|
||||||
|
selectedText.text = "0 ${resources.getString(R.string.selected)}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
val ok = view.findViewById<Button>(R.id.bottomsheet_ok)
|
||||||
|
ok!!.setOnClickListener {
|
||||||
|
lifecycleScope.launch(Dispatchers.IO){
|
||||||
|
val checkedItems = listAdapter.getCheckedItems()
|
||||||
|
val checkedResultItems = items.filter { checkedItems.contains(it.id) }
|
||||||
|
val downloadItems = mutableListOf<DownloadItem>()
|
||||||
|
checkedResultItems.forEach {c ->
|
||||||
|
val i = downloadViewModel.createDownloadItemFromResult(c,type)
|
||||||
|
i.format = downloadViewModel.getLatestCommandTemplateAsFormat()
|
||||||
|
downloadItems.add(i)
|
||||||
|
}
|
||||||
|
val bottomSheet = DownloadMultipleBottomSheetDialog(downloadItems)
|
||||||
|
bottomSheet.show(parentFragmentManager, "downloadMultipleSheet")
|
||||||
|
resultViewModel.deleteAll()
|
||||||
|
resultViewModel.insert(ArrayList(checkedResultItems))
|
||||||
|
}
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCancel(dialog: DialogInterface) {
|
||||||
|
super.onCancel(dialog)
|
||||||
|
cleanup()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDismiss(dialog: DialogInterface) {
|
||||||
|
super.onDismiss(dialog)
|
||||||
|
cleanup()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun cleanup(){
|
||||||
|
parentFragmentManager.beginTransaction().remove(parentFragmentManager.findFragmentByTag("downloadPlaylistSheet")!!).commit()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun onCardSelect(itemID: Long, isChecked: Boolean, checkedItems: List<Long>) {
|
||||||
|
if (checkedItems.size == items.size){
|
||||||
|
selectedText.text = resources.getString(R.string.all_items_selected)
|
||||||
|
}else{
|
||||||
|
selectedText.text = "${checkedItems.size} ${resources.getString(R.string.selected)}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -1,19 +1,17 @@
|
||||||
package com.deniscerri.ytdlnis.util
|
package com.deniscerri.ytdlnis.util
|
||||||
|
|
||||||
import android.R.attr.src
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.media.MediaScannerConnection
|
import android.media.MediaScannerConnection
|
||||||
import android.os.Build
|
import android.net.Uri
|
||||||
|
import android.provider.DocumentsContract
|
||||||
|
import android.webkit.MimeTypeMap
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
|
import okhttp3.internal.closeQuietly
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileInputStream
|
|
||||||
import java.io.FileOutputStream
|
|
||||||
import java.net.URLDecoder
|
import java.net.URLDecoder
|
||||||
import java.nio.channels.FileChannel
|
|
||||||
import java.nio.charset.StandardCharsets
|
import java.nio.charset.StandardCharsets
|
||||||
import java.nio.file.Files
|
|
||||||
import java.nio.file.StandardCopyOption
|
|
||||||
import java.text.DecimalFormat
|
import java.text.DecimalFormat
|
||||||
|
import java.util.*
|
||||||
import kotlin.math.log10
|
import kotlin.math.log10
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
|
|
||||||
|
|
@ -26,6 +24,12 @@ class FileUtil() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal object Compare {
|
||||||
|
fun max(a: File, b: File): File {
|
||||||
|
return if (a.length() > b.length()) a else b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun exists(path: String) : Boolean {
|
fun exists(path: String) : Boolean {
|
||||||
val file = File(path)
|
val file = File(path)
|
||||||
if (path.isEmpty()) return false
|
if (path.isEmpty()) return false
|
||||||
|
|
@ -56,18 +60,18 @@ class FileUtil() {
|
||||||
return formattedPath.toString()
|
return formattedPath.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun scanMedia(destDir: String, fileName: String, context: Context) : String {
|
private fun scanMedia(destDir: String, context: Context) : String {
|
||||||
val file : File
|
val file : File
|
||||||
val path = File(formatPath(destDir))
|
val path = File(formatPath(destDir))
|
||||||
|
|
||||||
try {
|
try {
|
||||||
file = path.listFiles()?.find {
|
val files = path.listFiles()!!
|
||||||
it!!.name == fileName
|
files.filter { it.lastModified() > System.currentTimeMillis() - 10000}
|
||||||
}!!
|
Arrays.sort(files) { p0, p1 -> p0!!.lastModified().compareTo(p1!!.lastModified()) }
|
||||||
|
|
||||||
val paths = arrayOf(file.absolutePath)
|
val paths = files.map { it.absolutePath }.toTypedArray()
|
||||||
MediaScannerConnection.scanFile(context, paths, null, null)
|
MediaScannerConnection.scanFile(context, paths, null, null)
|
||||||
return paths[0]
|
return files.reduce(Compare::max).absolutePath
|
||||||
}catch (e: Exception){
|
}catch (e: Exception){
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
|
|
@ -76,81 +80,38 @@ class FileUtil() {
|
||||||
}
|
}
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
fun moveFile(originDir: File, context: Context, destDir: String, progress: (p: Int) -> Unit) : String {
|
fun moveFile(originDir: File, context: Context, destDir: String, progress: (p: Int) -> Unit) : String {
|
||||||
var fileName = ""
|
|
||||||
var maxSize = 0L
|
|
||||||
originDir.listFiles()?.forEach {
|
originDir.listFiles()?.forEach {
|
||||||
if (it.name.equals("rList")){
|
if (it.name.equals("rList")){
|
||||||
it.delete()
|
it.delete()
|
||||||
return@forEach
|
return@forEach
|
||||||
}
|
}
|
||||||
|
|
||||||
if (it.length() > maxSize){
|
val mimeType =
|
||||||
maxSize = it.length()
|
MimeTypeMap.getSingleton().getMimeTypeFromExtension(it.extension) ?: "*/*"
|
||||||
fileName = it.name
|
|
||||||
|
val dest = Uri.parse(destDir).run {
|
||||||
|
DocumentsContract.buildDocumentUriUsingTree(
|
||||||
|
this,
|
||||||
|
DocumentsContract.getTreeDocumentId(this)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
|
val destUri = DocumentsContract.createDocument(
|
||||||
val f = File(formatPath(destDir)+"/"+it.name)
|
context.contentResolver,
|
||||||
f.mkdirs()
|
dest,
|
||||||
Files.move(it.toPath(), f.toPath(), StandardCopyOption.REPLACE_EXISTING)
|
mimeType,
|
||||||
progress(100)
|
it.name
|
||||||
}else{
|
) ?: return@forEach
|
||||||
val f = File(formatPath(destDir)+"/"+it.name)
|
|
||||||
|
|
||||||
val inChannel: FileChannel = FileInputStream(it).channel
|
val inputStream = it.inputStream()
|
||||||
val outChannel: FileChannel = FileOutputStream(f).channel
|
val outputStream =
|
||||||
try {
|
context.contentResolver.openOutputStream(destUri) ?: return@forEach
|
||||||
inChannel.transferTo(0, inChannel.size(), outChannel)
|
inputStream.copyTo(outputStream)
|
||||||
} finally {
|
inputStream.closeQuietly()
|
||||||
inChannel.close()
|
outputStream.closeQuietly()
|
||||||
outChannel.close()
|
|
||||||
}
|
|
||||||
//
|
|
||||||
// val mimeType =
|
|
||||||
// MimeTypeMap.getSingleton().getMimeTypeFromExtension(it.extension) ?: "*/*"
|
|
||||||
//
|
|
||||||
// val destination = Uri.parse(destDir).run {
|
|
||||||
// DocumentsContract.buildChildDocumentsUriUsingTree(this, DocumentsContract.getTreeDocumentId(this))
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// val destUri = DocumentsContract.createDocument(
|
|
||||||
// context.contentResolver,
|
|
||||||
// destination,
|
|
||||||
// mimeType,
|
|
||||||
// it.name
|
|
||||||
// ) ?: return@forEach
|
|
||||||
//
|
|
||||||
// val inputStream = it.inputStream()
|
|
||||||
// val outputStream = context.contentResolver.openOutputStream(destUri) ?: return@forEach
|
|
||||||
// val fileLength = it.length()
|
|
||||||
// var bytesCopied: Long = 0
|
|
||||||
// val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
|
|
||||||
// var bytes = inputStream.read(buffer)
|
|
||||||
//
|
|
||||||
// try {
|
|
||||||
// while (bytes >= 0) {
|
|
||||||
// outputStream.write(buffer, 0, bytes)
|
|
||||||
// bytesCopied += bytes
|
|
||||||
// progress((bytesCopied * 100 / fileLength).toInt())
|
|
||||||
// bytes = inputStream.read(buffer)
|
|
||||||
// }
|
|
||||||
// }catch (e : Exception){
|
|
||||||
// e.printStackTrace()
|
|
||||||
// Toast.makeText(context, e.message, Toast.LENGTH_LONG).show()
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// inputStream.close()
|
|
||||||
// outputStream.close()
|
|
||||||
//
|
|
||||||
// it.delete()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
originDir.delete()
|
originDir.delete()
|
||||||
return if (maxSize > 0L){
|
return scanMedia(destDir, context)
|
||||||
scanMedia(destDir, fileName, context)
|
|
||||||
}else{
|
|
||||||
context.getString(R.string.unfound_file)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun convertFileSize(s: Long): String{
|
fun convertFileSize(s: Long): String{
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<vector android:height="24dp"
|
<vector android:height="24dp" android:tint="#000000"
|
||||||
android:viewportHeight="24" android:viewportWidth="24"
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<path android:fillColor="?android:colorAccent" android:pathData="M3,10h11v2H3V10zM3,8h11V6H3V8zM3,16h7v-2H3V16zM18.01,12.87l0.71,-0.71c0.39,-0.39 1.02,-0.39 1.41,0l0.71,0.71c0.39,0.39 0.39,1.02 0,1.41l-0.71,0.71L18.01,12.87zM17.3,13.58l-5.3,5.3V21h2.12l5.3,-5.3L17.3,13.58z"/>
|
<path android:fillColor="@android:color/white" android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
||||||
5
app/src/main/res/drawable/ic_edit_multiple.xml
Normal file
5
app/src/main/res/drawable/ic_edit_multiple.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:height="24dp"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="?android:textColorPrimary" android:pathData="M3,10h11v2H3V10zM3,8h11V6H3V8zM3,16h7v-2H3V16zM18.01,12.87l0.71,-0.71c0.39,-0.39 1.02,-0.39 1.41,0l0.71,0.71c0.39,0.39 0.39,1.02 0,1.41l-0.71,0.71L18.01,12.87zM17.3,13.58l-5.3,5.3V21h2.12l5.3,-5.3L17.3,13.58z"/>
|
||||||
|
</vector>
|
||||||
6
app/src/main/res/drawable/ic_folders.xml
Normal file
6
app/src/main/res/drawable/ic_folders.xml
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
<vector android:height="24dp"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="?android:textColorPrimary" android:pathData="M3,6H1v13c0,1.1 0.9,2 2,2h17v-2H3V6z"/>
|
||||||
|
<path android:fillColor="?android:textColorPrimary" android:pathData="M21,4h-7l-2,-2H7C5.9,2 5.01,2.9 5.01,4L5,15c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V6C23,4.9 22.1,4 21,4z"/>
|
||||||
|
</vector>
|
||||||
5
app/src/main/res/drawable/ic_select_all.xml
Normal file
5
app/src/main/res/drawable/ic_select_all.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:height="24dp" android:tint="#000000"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M3,5h2L5,3c-1.1,0 -2,0.9 -2,2zM3,13h2v-2L3,11v2zM7,21h2v-2L7,19v2zM3,9h2L5,7L3,7v2zM13,3h-2v2h2L13,3zM19,3v2h2c0,-1.1 -0.9,-2 -2,-2zM5,21v-2L3,19c0,1.1 0.9,2 2,2zM3,17h2v-2L3,15v2zM9,3L7,3v2h2L9,3zM11,21h2v-2h-2v2zM19,13h2v-2h-2v2zM19,21c1.1,0 2,-0.9 2,-2h-2v2zM19,9h2L21,7h-2v2zM19,17h2v-2h-2v2zM15,21h2v-2h-2v2zM15,5h2L17,3h-2v2zM7,17h10L17,7L7,7v10zM9,9h6v6L9,15L9,9z"/>
|
||||||
|
</vector>
|
||||||
|
|
@ -1,86 +1,97 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/bottom_sheet_title"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:textSize="25sp"
|
|
||||||
android:padding="20dp"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/configure_download" />
|
|
||||||
|
|
||||||
<com.google.android.material.tabs.TabLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:backgroundTint="@android:color/transparent"
|
|
||||||
app:tabMode="scrollable"
|
|
||||||
app:tabGravity="center"
|
|
||||||
android:id="@+id/download_tablayout" >
|
|
||||||
|
|
||||||
<com.google.android.material.tabs.TabItem
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:text="@string/audio" />
|
|
||||||
|
|
||||||
<com.google.android.material.tabs.TabItem
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:text="@string/video" />
|
|
||||||
|
|
||||||
<com.google.android.material.tabs.TabItem
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:text="@string/run_command" />
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</com.google.android.material.tabs.TabLayout>
|
|
||||||
|
|
||||||
<androidx.viewpager2.widget.ViewPager2
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:id="@+id/download_viewpager" />
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="bottom"
|
android:orientation="vertical"
|
||||||
android:padding="10dp"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
android:orientation="horizontal">
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="bottom"
|
android:layout_marginHorizontal="20dp"
|
||||||
android:gravity="end"
|
android:orientation="horizontal"
|
||||||
android:orientation="horizontal">
|
android:paddingTop="20dp">
|
||||||
|
|
||||||
<Button
|
<TextView
|
||||||
style="@style/Widget.Material3.Button.OutlinedButton.Icon"
|
android:id="@+id/bottom_sheet_title"
|
||||||
android:id="@+id/bottomsheet_cancel_button"
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/cancel"
|
android:text="@string/download"
|
||||||
android:layout_marginEnd="10dp"
|
android:textSize="25sp"
|
||||||
app:icon="@drawable/ic_cancel" />
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/bottom_sheet_subtitle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/configure_download"
|
||||||
|
android:textSize="12sp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/bottom_sheet_title" />
|
||||||
|
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
style="@style/Widget.Material3.Button.ElevatedButton.Icon"
|
|
||||||
android:id="@+id/bottom_sheet_ok"
|
android:id="@+id/bottom_sheet_ok"
|
||||||
|
style="@style/Widget.Material3.Button.ElevatedButton.Icon"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:autoLink="all"
|
||||||
android:text="@string/ok"
|
android:text="@string/ok"
|
||||||
app:icon="@drawable/ic_check"
|
app:icon="@drawable/ic_check"
|
||||||
android:autoLink="all"/>
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.tabs.TabLayout
|
||||||
|
android:id="@+id/download_tablayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="10dp"
|
||||||
|
android:backgroundTint="@android:color/transparent"
|
||||||
|
app:tabGravity="fill"
|
||||||
|
app:tabMode="scrollable">
|
||||||
|
|
||||||
|
<com.google.android.material.tabs.TabItem
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:text="@string/audio" />
|
||||||
|
|
||||||
|
<com.google.android.material.tabs.TabItem
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:text="@string/video" />
|
||||||
|
|
||||||
|
<com.google.android.material.tabs.TabItem
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:text="@string/command" />
|
||||||
|
|
||||||
|
|
||||||
|
</com.google.android.material.tabs.TabLayout>
|
||||||
|
|
||||||
|
<androidx.viewpager2.widget.ViewPager2
|
||||||
|
android:id="@+id/download_viewpager"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
@ -7,23 +7,9 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
>
|
>
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/materialButton"
|
|
||||||
style="@style/Widget.Material3.Button.IconButton"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:gravity="end"
|
|
||||||
android:padding="5dp"
|
|
||||||
app:icon="@drawable/ic_handle"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toStartOf="@+id/download_card_view"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<com.google.android.material.card.MaterialCardView
|
<com.google.android.material.card.MaterialCardView
|
||||||
android:id="@+id/download_card_view"
|
android:id="@+id/download_card_view"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="0dp"
|
||||||
android:layout_height="100dp"
|
android:layout_height="100dp"
|
||||||
android:layout_margin="10dp"
|
android:layout_margin="10dp"
|
||||||
android:checkable="true"
|
android:checkable="true"
|
||||||
|
|
@ -32,6 +18,7 @@
|
||||||
app:cardPreventCornerOverlap="true"
|
app:cardPreventCornerOverlap="true"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:strokeWidth="0dp">
|
app:strokeWidth="0dp">
|
||||||
|
|
||||||
|
|
@ -42,26 +29,18 @@
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:scaleType="centerCrop" />
|
android:scaleType="centerCrop" />
|
||||||
|
|
||||||
<com.google.android.material.progressindicator.LinearProgressIndicator
|
|
||||||
android:id="@+id/download_progress"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_gravity="bottom"
|
|
||||||
android:alpha="0.7"
|
|
||||||
android:indeterminate="true"
|
|
||||||
android:scaleY="100"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/title_author"
|
android:id="@+id/title_author"
|
||||||
android:layout_width="300dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="70dp"
|
android:paddingStart="10dp"
|
||||||
|
android:paddingEnd="10dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/downloads_download_button_type"
|
app:layout_constraintEnd_toStartOf="@+id/action_button"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
|
@ -69,7 +48,8 @@
|
||||||
android:id="@+id/title"
|
android:id="@+id/title"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingStart="10dp"
|
android:ellipsize="end"
|
||||||
|
android:maxLines="2"
|
||||||
android:paddingTop="10dp"
|
android:paddingTop="10dp"
|
||||||
android:paddingEnd="10dp"
|
android:paddingEnd="10dp"
|
||||||
android:shadowColor="@color/black"
|
android:shadowColor="@color/black"
|
||||||
|
|
@ -77,15 +57,16 @@
|
||||||
android:shadowDy="4"
|
android:shadowDy="4"
|
||||||
android:shadowRadius="2"
|
android:shadowRadius="2"
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/white"
|
||||||
android:textSize="17sp"
|
android:textSize="15sp"
|
||||||
android:textStyle="bold" />
|
android:textStyle="bold" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/author"
|
android:id="@+id/subtitle"
|
||||||
android:layout_width="296dp"
|
android:layout_width="296dp"
|
||||||
android:layout_height="23dp"
|
android:layout_height="20dp"
|
||||||
|
android:ellipsize="end"
|
||||||
android:gravity="bottom"
|
android:gravity="bottom"
|
||||||
android:paddingStart="10dp"
|
android:maxLines="1"
|
||||||
android:paddingEnd="10dp"
|
android:paddingEnd="10dp"
|
||||||
android:paddingBottom="5dp"
|
android:paddingBottom="5dp"
|
||||||
android:shadowColor="@color/black"
|
android:shadowColor="@color/black"
|
||||||
|
|
@ -93,61 +74,87 @@
|
||||||
android:shadowDy="4"
|
android:shadowDy="4"
|
||||||
android:shadowRadius="1.5"
|
android:shadowRadius="1.5"
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/white"
|
||||||
android:textSize="12sp"
|
android:textSize="11sp"
|
||||||
android:textStyle="bold" />
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
<TextView
|
android:layout_width="match_parent"
|
||||||
android:id="@+id/container"
|
android:layout_height="0dp"
|
||||||
android:layout_width="wrap_content"
|
android:paddingStart="10dp"
|
||||||
android:layout_height="wrap_content"
|
android:paddingEnd="10dp"
|
||||||
android:padding="5dp"
|
android:gravity="bottom"
|
||||||
android:textStyle="bold"
|
android:paddingBottom="5dp"
|
||||||
android:shadowColor="@color/black"
|
|
||||||
android:shadowDx="4"
|
|
||||||
android:shadowDy="4"
|
|
||||||
android:shadowRadius="1.5"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/filesize"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/downloads_download_button_type" />
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/title_author">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/filesize"
|
android:id="@+id/format_note"
|
||||||
android:layout_width="wrap_content"
|
style="@style/Widget.Material3.FloatingActionButton.Large.Primary"
|
||||||
android:layout_height="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:padding="5dp"
|
android:layout_height="wrap_content"
|
||||||
android:textStyle="bold"
|
android:layout_marginEnd="5dp"
|
||||||
android:shadowColor="@color/black"
|
android:background="?attr/colorPrimary"
|
||||||
android:shadowDx="4"
|
android:clickable="false"
|
||||||
android:shadowDy="4"
|
android:gravity="center"
|
||||||
android:shadowRadius="1.5"
|
android:minWidth="30dp"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
android:paddingHorizontal="10dp"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/quality" />
|
app:cornerRadius="10dp"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:ellipsize="end"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<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/colorTertiary"
|
||||||
|
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/quality"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:padding="5dp"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:shadowColor="@color/black"
|
|
||||||
android:shadowDx="4"
|
|
||||||
android:shadowDy="4"
|
|
||||||
android:shadowRadius="1.5"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent" />
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/downloads_download_button_type"
|
android:id="@+id/action_button"
|
||||||
style="@style/Widget.Material3.ExtendedFloatingActionButton.Icon.Secondary"
|
style="@style/Widget.Material3.ExtendedFloatingActionButton.Icon.Secondary"
|
||||||
android:layout_width="55dp"
|
android:layout_width="55dp"
|
||||||
android:layout_height="55dp"
|
android:layout_height="55dp"
|
||||||
android:layout_margin="10dp"
|
android:layout_margin="10dp"
|
||||||
android:layout_marginEnd="8dp"
|
android:layout_marginEnd="8dp"
|
||||||
app:cornerRadius="10dp"
|
app:cornerRadius="10dp"
|
||||||
|
app:icon="@drawable/ic_video"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
|
|
||||||
|
|
@ -3,113 +3,82 @@
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:id="@+id/constraintLayout"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:padding="10dp"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/bottom_sheet_title"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/configure_download"
|
|
||||||
android:textSize="20sp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/materialButton"
|
|
||||||
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="end"
|
|
||||||
android:gravity="end"
|
|
||||||
app:icon="@drawable/ic_format"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toStartOf="@+id/materialButton2"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/materialButton2"
|
|
||||||
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="end"
|
|
||||||
android:gravity="end"
|
|
||||||
app:icon="@drawable/ic_download_type"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
android:id="@+id/coordinatorLayout"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/constraintLayout">
|
android:orientation="vertical"
|
||||||
|
android:elevation="10dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent">
|
||||||
|
|
||||||
<RelativeLayout
|
<com.google.android.material.bottomappbar.BottomAppBar
|
||||||
android:id="@+id/relativeLayout"
|
android:id="@+id/bottomAppBar"
|
||||||
|
style="@style/Widget.Material3.BottomAppBar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
app:menu="@menu/download_multiple_menu" />
|
||||||
|
|
||||||
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
android:id="@+id/edit_selected"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:srcCompat="@drawable/ic_edit" />
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:id="@+id/downloadMultipleRecyclerview"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingBottom="150dp"
|
|
||||||
android:focusableInTouchMode="true"
|
|
||||||
android:orientation="vertical"
|
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/linearLayout"
|
android:id="@+id/linearLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="bottom"
|
android:orientation="vertical"
|
||||||
android:orientation="horizontal"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
android:padding="10dp"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintBottom_toBottomOf="parent">
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
<Button
|
|
||||||
android:id="@+id/bottomsheet_schedule_button"
|
|
||||||
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginEnd="10dp"
|
|
||||||
app:icon="@drawable/ic_clock" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="bottom"
|
android:layout_marginHorizontal="20dp"
|
||||||
android:gravity="end"
|
android:orientation="horizontal"
|
||||||
android:orientation="horizontal">
|
android:paddingTop="20dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/bottom_sheet_title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/download"
|
||||||
|
android:textSize="25sp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/bottom_sheet_subtitle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/configure_download"
|
||||||
|
android:textSize="12sp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/bottom_sheet_title" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/bottomsheet_cancel_button"
|
android:id="@+id/bottomsheet_schedule_button"
|
||||||
style="@style/Widget.Material3.Button.OutlinedButton.Icon"
|
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginEnd="10dp"
|
android:layout_marginEnd="10dp"
|
||||||
android:text="@string/cancel"
|
app:icon="@drawable/ic_clock"
|
||||||
app:icon="@drawable/ic_cancel" />
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/bottomsheet_download_button"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/bottomsheet_download_button"
|
android:id="@+id/bottomsheet_download_button"
|
||||||
|
|
@ -118,10 +87,26 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:autoLink="all"
|
android:autoLink="all"
|
||||||
android:text="@string/download"
|
android:text="@string/download"
|
||||||
app:icon="@drawable/ic_down" />
|
app:icon="@drawable/ic_down"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/downloadMultipleRecyclerview"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:paddingTop="10dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:focusableInTouchMode="true"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingBottom="70dp"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
40
app/src/main/res/layout/playlist_item.xml
Normal file
40
app/src/main/res/layout/playlist_item.xml
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/playlist_card_constraintLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_marginBottom="10dp"
|
||||||
|
android:layout_height="50dp">
|
||||||
|
|
||||||
|
<CheckBox
|
||||||
|
android:id="@+id/checkBox"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
|
android:id="@+id/downloads_image_view"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:layout_constraintDimensionRatio="H,16:9"
|
||||||
|
android:layout_marginEnd="10dp"
|
||||||
|
android:adjustViewBounds="true"
|
||||||
|
android:scaleType="centerCrop"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/checkBox" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/title"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:padding="15dp"
|
||||||
|
android:lines="2"
|
||||||
|
android:maxLines="2"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/downloads_image_view"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
111
app/src/main/res/layout/select_playlist_items.xml
Normal file
111
app/src/main/res/layout/select_playlist_items.xml
Normal file
|
|
@ -0,0 +1,111 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:elevation="10dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent">
|
||||||
|
|
||||||
|
<com.google.android.material.bottomappbar.BottomAppBar
|
||||||
|
android:id="@+id/bottomAppBar"
|
||||||
|
style="@style/Widget.Material3.BottomAppBar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
style="?attr/materialIconButtonStyle"
|
||||||
|
android:id="@+id/check_all"
|
||||||
|
android:padding="0dp"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:icon="@drawable/ic_select_all" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/selected"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:paddingStart="17dp"
|
||||||
|
android:paddingEnd="0dp"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
</com.google.android.material.bottomappbar.BottomAppBar>
|
||||||
|
|
||||||
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
android:id="@+id/edit_selected"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:srcCompat="@drawable/ic_edit" />
|
||||||
|
|
||||||
|
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/linearLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="20dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingTop="20dp">
|
||||||
|
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/bottom_sheet_title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:text="@string/select"
|
||||||
|
android:textSize="20sp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/bottomsheet_ok"
|
||||||
|
style="@style/Widget.Material3.Button.ElevatedButton.Icon"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:autoLink="all"
|
||||||
|
android:text="@string/ok"
|
||||||
|
app:icon="@drawable/ic_check"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/downloadMultipleRecyclerview"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:paddingTop="10dp"
|
||||||
|
tools:listitem="@layout/playlist_item"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:focusableInTouchMode="true"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingBottom="70dp"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
|
||||||
|
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
19
app/src/main/res/menu/download_multiple_menu.xml
Normal file
19
app/src/main/res/menu/download_multiple_menu.xml
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
<menu 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"
|
||||||
|
tools:context=".MainActivity" >
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/folder"
|
||||||
|
android:title="@string/directories"
|
||||||
|
android:icon="@drawable/ic_folders"
|
||||||
|
app:showAsAction="collapseActionView|ifRoom"/>
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/edit"
|
||||||
|
android:title="@string/directories"
|
||||||
|
android:icon="@drawable/ic_edit_multiple"
|
||||||
|
app:showAsAction="collapseActionView|ifRoom"/>
|
||||||
|
|
||||||
|
</menu>
|
||||||
|
|
||||||
|
|
@ -203,4 +203,7 @@
|
||||||
<string name="preferred_download_type">Preferred Download Type</string>
|
<string name="preferred_download_type">Preferred Download Type</string>
|
||||||
<string name="preferred_download_type_summary">Default tab the download card will open to</string>
|
<string name="preferred_download_type_summary">Default tab the download card will open to</string>
|
||||||
<string name="confirm_delete_logs_desc">Delete the entire log list, permanently.</string>
|
<string name="confirm_delete_logs_desc">Delete the entire log list, permanently.</string>
|
||||||
|
<string name="select">Select</string>
|
||||||
|
<string name="selected">Selected</string>
|
||||||
|
<string name="all_items_selected">All items selected</string>
|
||||||
</resources>
|
</resources>
|
||||||
Loading…
Reference in a new issue