implemented fetching common formats for a playlist (WIP)

This commit is contained in:
deniscerri 2023-04-18 23:12:30 +02:00
parent a91110d23e
commit 81a47c3407
No known key found for this signature in database
GPG key ID: 95C43D517D830350
18 changed files with 320 additions and 175 deletions

View file

@ -4,6 +4,7 @@ import android.app.Activity
import android.app.Application import android.app.Application
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import android.content.res.Resources
import android.net.ConnectivityManager import android.net.ConnectivityManager
import android.widget.Toast import android.widget.Toast
import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.AndroidViewModel
@ -24,7 +25,7 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
class DownloadViewModel(application: Application) : AndroidViewModel(application) { class DownloadViewModel(private val application: Application) : AndroidViewModel(application) {
private val repository : DownloadRepository private val repository : DownloadRepository
private val sharedPreferences: SharedPreferences private val sharedPreferences: SharedPreferences
private val commandTemplateDao: CommandTemplateDao private val commandTemplateDao: CommandTemplateDao
@ -213,19 +214,39 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
} }
else -> { else -> {
val c = commandTemplateDao.getFirst() val c = commandTemplateDao.getFirst()
return Format( return generateCommandFormat(c)
c.title,
"",
"",
"",
"",
0,
c.content.replace("\n", " ")
)
} }
} }
} }
fun generateCommandFormat(c: CommandTemplate) : Format {
return Format(
c.title,
"",
"",
"",
"",
0,
c.content.replace("\n", " ")
)
}
fun getGenericAudioFormats() : MutableList<Format>{
val audioFormats = application.resources.getStringArray(R.array.audio_formats)
val formats = mutableListOf<Format>()
val containerPreference = sharedPreferences.getString("audio_format", "Default")
audioFormats.forEach { formats.add(Format(it, containerPreference!!,"","", "",0, it)) }
return formats
}
fun getGenericVideoFormats() : MutableList<Format>{
val videoFormats = application.resources.getStringArray(R.array.video_formats)
val formats = mutableListOf<Format>()
val containerPreference = sharedPreferences.getString("video_format", "Default")
videoFormats.forEach { formats.add(Format(it, containerPreference!!,"","", "",0, it)) }
return formats
}
fun getLatestCommandTemplateAsFormat() : Format { fun getLatestCommandTemplateAsFormat() : Format {
val t = commandTemplateDao.getFirst() val t = commandTemplateDao.getFirst()
return Format(t.title, "", "", "", "", 0, t.content) return Format(t.title, "", "", "", "", 0, t.content)

View file

@ -45,7 +45,6 @@ class ConfigureDownloadBottomSheetDialog(private val resultItem: ResultItem, pri
private lateinit var onDownloadItemUpdateListener: OnDownloadItemUpdateListener private lateinit var onDownloadItemUpdateListener: OnDownloadItemUpdateListener
private lateinit var uiUtil: UiUtil private lateinit var uiUtil: UiUtil
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]
@ -71,7 +70,7 @@ class ConfigureDownloadBottomSheetDialog(private val resultItem: ResultItem, pri
behavior = BottomSheetBehavior.from(view.parent as View) behavior = BottomSheetBehavior.from(view.parent as View)
val displayMetrics = DisplayMetrics() val displayMetrics = DisplayMetrics()
requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics) requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics)
behavior.peekHeight = displayMetrics.heightPixels - 700 behavior.peekHeight = displayMetrics.heightPixels - 400
} }
tabLayout = view.findViewById(R.id.download_tablayout) tabLayout = view.findViewById(R.id.download_tablayout)
@ -82,7 +81,7 @@ class ConfigureDownloadBottomSheetDialog(private val resultItem: ResultItem, pri
overScrollMode = View.OVER_SCROLL_NEVER overScrollMode = View.OVER_SCROLL_NEVER
} }
val fragments = mutableListOf<Fragment>(DownloadAudioFragment(resultItem, downloadItem), DownloadVideoFragment(resultItem, downloadItem)) val fragments = mutableListOf(DownloadAudioFragment(resultItem, downloadItem), DownloadVideoFragment(resultItem, downloadItem))
var commandTemplateNr = 0 var commandTemplateNr = 0
lifecycleScope.launch{ lifecycleScope.launch{
withContext(Dispatchers.IO){ withContext(Dispatchers.IO){
@ -211,10 +210,12 @@ class ConfigureDownloadBottomSheetDialog(private val resultItem: ResultItem, pri
// } // }
private fun cleanUp(){ private fun cleanUp(){
parentFragmentManager.beginTransaction().remove(parentFragmentManager.findFragmentByTag("configureDownloadSingleSheet")!!).commit() kotlin.runCatching {
for (i in 0 until viewPager2.adapter?.itemCount!!){ parentFragmentManager.beginTransaction().remove(parentFragmentManager.findFragmentByTag("configureDownloadSingleSheet")!!).commit()
if (parentFragmentManager.findFragmentByTag("f${i}") != null){ for (i in 0 until viewPager2.adapter?.itemCount!!){
parentFragmentManager.beginTransaction().remove(parentFragmentManager.findFragmentByTag("f$i")!!).commit() if (parentFragmentManager.findFragmentByTag("f${i}") != null){
parentFragmentManager.beginTransaction().remove(parentFragmentManager.findFragmentByTag("f$i")!!).commit()
}
} }
} }
} }

View file

@ -570,9 +570,11 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val list
private fun cleanUp(){ private fun cleanUp(){
player.stop() kotlin.runCatching {
cache.release() player.stop()
parentFragmentManager.beginTransaction().remove(parentFragmentManager.findFragmentByTag("cutVideoSheet")!!).commit() cache.release()
parentFragmentManager.beginTransaction().remove(parentFragmentManager.findFragmentByTag("cutVideoSheet")!!).commit()
}
} }
} }

View file

@ -123,42 +123,40 @@ class DownloadAudioFragment(private var resultItem: ResultItem, private var curr
var formats = mutableListOf<Format>() var formats = mutableListOf<Format>()
formats.addAll(resultItem.formats.filter { it.format_note.contains("audio", ignoreCase = true) }) formats.addAll(resultItem.formats.filter { it.format_note.contains("audio", ignoreCase = true) })
val audioFormats = resources.getStringArray(R.array.audio_formats) if (formats.isEmpty()) formats.addAll(downloadItem.allFormats.filter { it.format_note.contains("audio", ignoreCase = true) })
val containers = requireContext().resources.getStringArray(R.array.audio_containers) val containers = requireContext().resources.getStringArray(R.array.audio_containers)
val containerPreference = sharedPreferences.getString("audio_format", getString(R.string.defaultValue)) val containerPreference = sharedPreferences.getString("audio_format", "Default")
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)
if (formats.isEmpty()) { if (formats.isEmpty()) formats = downloadViewModel.getGenericAudioFormats()
audioFormats.forEach { formats.add(Format(it, containerPreference!!,"","", "",0, it)) }
}
val formatCard = view.findViewById<ConstraintLayout>(R.id.format_card_constraintLayout) val formatCard = view.findViewById<ConstraintLayout>(R.id.format_card_constraintLayout)
val chosenFormat = downloadItem.format 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<List<Format>>, item: List<Format>) {
downloadItem.format = item downloadItem.format = item.first()
uiUtil.populateFormatCard(formatCard, item) uiUtil.populateFormatCard(formatCard, item.first())
if (containers.contains(item.container)){ if (containers.contains(item.first().container)){
downloadItem.format.container = item.container downloadItem.format.container = item.first().container
containerAutoCompleteTextView.setText(item.container, false) containerAutoCompleteTextView.setText(item.first().container, false)
} }
lifecycleScope.launch { lifecycleScope.launch {
withContext(Dispatchers.IO){ withContext(Dispatchers.IO){
resultItem.formats.removeAll(formats.toSet()) resultItem.formats.removeAll(formats.toSet())
resultItem.formats.addAll(allFormats) resultItem.formats.addAll(allFormats.first())
resultViewModel.update(resultItem) resultViewModel.update(resultItem)
} }
} }
formats = allFormats.toMutableList() formats = allFormats.first().toMutableList()
} }
} }
formatCard.setOnClickListener{_ -> formatCard.setOnClickListener{_ ->
if (parentFragmentManager.findFragmentByTag("formatSheet") == null){ if (parentFragmentManager.findFragmentByTag("formatSheet") == null){
val bottomSheet = FormatSelectionBottomSheetDialog(downloadItem, formats, listener) val bottomSheet = FormatSelectionBottomSheetDialog(listOf(downloadItem), listOf(formats), listener)
bottomSheet.show(parentFragmentManager, "formatSheet") bottomSheet.show(parentFragmentManager, "formatSheet")
} }
} }

View file

@ -15,6 +15,7 @@ import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager.widget.ViewPager
import androidx.viewpager2.widget.ViewPager2 import androidx.viewpager2.widget.ViewPager2
import com.deniscerri.ytdlnis.R import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.DBManager import com.deniscerri.ytdlnis.database.DBManager
@ -30,6 +31,8 @@ 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.button.MaterialButton
import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayout.TabLayoutOnPageChangeListener
import com.google.android.material.tabs.TabLayoutMediator
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
@ -64,7 +67,7 @@ class DownloadBottomSheetDialog(private val resultItem: ResultItem, private val
behavior = BottomSheetBehavior.from(view.parent as View) behavior = BottomSheetBehavior.from(view.parent as View)
val displayMetrics = DisplayMetrics() val displayMetrics = DisplayMetrics()
requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics) requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics)
behavior.peekHeight = displayMetrics.heightPixels - 700 behavior.peekHeight = displayMetrics.heightPixels - 400
} }
@ -158,7 +161,6 @@ class DownloadBottomSheetDialog(private val resultItem: ResultItem, private val
dismiss() dismiss()
} }
} }
val download = view.findViewById<Button>(R.id.bottomsheet_download_button) val download = view.findViewById<Button>(R.id.bottomsheet_download_button)
download!!.setOnClickListener { download!!.setOnClickListener {
val item: DownloadItem = getDownloadItem(); val item: DownloadItem = getDownloadItem();
@ -208,14 +210,16 @@ class DownloadBottomSheetDialog(private val resultItem: ResultItem, private val
private fun cleanUp(){ private fun cleanUp(){
parentFragmentManager.beginTransaction().remove(parentFragmentManager.findFragmentByTag("downloadSingleSheet")!!).commit() kotlin.runCatching {
for (i in 0 until viewPager2.adapter?.itemCount!!){ parentFragmentManager.beginTransaction().remove(parentFragmentManager.findFragmentByTag("downloadSingleSheet")!!).commit()
if (parentFragmentManager.findFragmentByTag("f${i}") != null){ for (i in 0 until viewPager2.adapter?.itemCount!!){
parentFragmentManager.beginTransaction().remove(parentFragmentManager.findFragmentByTag("f$i")!!).commit() if (parentFragmentManager.findFragmentByTag("f${i}") != null){
parentFragmentManager.beginTransaction().remove(parentFragmentManager.findFragmentByTag("f$i")!!).commit()
}
}
if (activity is ShareActivity){
(activity as ShareActivity).finish()
} }
}
if (activity is ShareActivity){
(activity as ShareActivity).finish()
} }
} }
} }

View file

@ -8,12 +8,12 @@ import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.text.format.DateFormat import android.text.format.DateFormat
import android.util.DisplayMetrics import android.util.DisplayMetrics
import android.util.Log
import android.view.* import android.view.*
import android.widget.Button import android.widget.Button
import android.widget.TextView import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.view.get
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
@ -21,6 +21,7 @@ import androidx.recyclerview.widget.RecyclerView
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.database.models.DownloadItem import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.Format
import com.deniscerri.ytdlnis.database.models.ResultItem import com.deniscerri.ytdlnis.database.models.ResultItem
import com.deniscerri.ytdlnis.database.viewmodel.CommandTemplateViewModel import com.deniscerri.ytdlnis.database.viewmodel.CommandTemplateViewModel
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
@ -34,7 +35,6 @@ 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 kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@ -51,6 +51,7 @@ class DownloadMultipleBottomSheetDialog(private var results: List<ResultItem?>,
private lateinit var behavior: BottomSheetBehavior<View> private lateinit var behavior: BottomSheetBehavior<View>
private lateinit var fileUtil: FileUtil private lateinit var fileUtil: FileUtil
private lateinit var uiUtil: UiUtil private lateinit var uiUtil: UiUtil
private lateinit var bottomAppBar: BottomAppBar
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@ -68,7 +69,7 @@ class DownloadMultipleBottomSheetDialog(private var results: List<ResultItem?>,
behavior.state = BottomSheetBehavior.STATE_EXPANDED behavior.state = BottomSheetBehavior.STATE_EXPANDED
} }
@SuppressLint("RestrictedApi") @SuppressLint("RestrictedApi", "NotifyDataSetChanged")
override fun setupDialog(dialog: Dialog, style: Int) { override fun setupDialog(dialog: Dialog, style: Int) {
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)
@ -116,7 +117,7 @@ class DownloadMultipleBottomSheetDialog(private var results: List<ResultItem?>,
dismiss() dismiss()
} }
val bottomAppBar = view.findViewById<BottomAppBar>(R.id.bottomAppBar) bottomAppBar = view.findViewById(R.id.bottomAppBar)
val preferredDownloadType = bottomAppBar.menu.findItem(R.id.preferred_download_type) val preferredDownloadType = bottomAppBar.menu.findItem(R.id.preferred_download_type)
when(items.first().type){ when(items.first().type){
DownloadViewModel.Type.audio -> { DownloadViewModel.Type.audio -> {
@ -131,7 +132,19 @@ class DownloadMultipleBottomSheetDialog(private var results: List<ResultItem?>,
} }
} }
bottomAppBar!!.setOnMenuItemClickListener { m: MenuItem -> val formatListener = object : OnFormatClickListener {
override fun onFormatClick(allFormats: List<List<Format>>, selectedFormats: List<Format>) {
items.forEachIndexed { index, it ->
it.allFormats.clear()
it.allFormats.addAll(allFormats[index])
it.format = selectedFormats[index]
}
listAdapter.submitList(items.toList())
listAdapter.notifyDataSetChanged()
}
}
bottomAppBar.setOnMenuItemClickListener { m: MenuItem ->
when (m.itemId) { when (m.itemId) {
R.id.folder -> { R.id.folder -> {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE) val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
@ -166,6 +179,7 @@ class DownloadMultipleBottomSheetDialog(private var results: List<ResultItem?>,
listAdapter.submitList(items.toList()) listAdapter.submitList(items.toList())
listAdapter.notifyDataSetChanged() listAdapter.notifyDataSetChanged()
preferredDownloadType.setIcon(R.drawable.baseline_audio_file_24) preferredDownloadType.setIcon(R.drawable.baseline_audio_file_24)
bottomAppBar.menu[2].icon?.alpha = 255
bottomSheet.cancel() bottomSheet.cancel()
} }
@ -174,6 +188,7 @@ class DownloadMultipleBottomSheetDialog(private var results: List<ResultItem?>,
listAdapter.submitList(items.toList()) listAdapter.submitList(items.toList())
listAdapter.notifyDataSetChanged() listAdapter.notifyDataSetChanged()
preferredDownloadType.setIcon(R.drawable.baseline_video_file_24) preferredDownloadType.setIcon(R.drawable.baseline_video_file_24)
bottomAppBar.menu[2].icon?.alpha = 255
bottomSheet.cancel() bottomSheet.cancel()
} }
@ -185,11 +200,15 @@ class DownloadMultipleBottomSheetDialog(private var results: List<ResultItem?>,
listAdapter.submitList(items.toList()) listAdapter.submitList(items.toList())
listAdapter.notifyDataSetChanged() listAdapter.notifyDataSetChanged()
preferredDownloadType.setIcon(R.drawable.baseline_insert_drive_file_24) preferredDownloadType.setIcon(R.drawable.baseline_insert_drive_file_24)
bottomAppBar.menu[2].icon?.alpha = 255
bottomSheet.cancel() bottomSheet.cancel()
} }
} }
bottomSheet.show() bottomSheet.show()
val displayMetrics = DisplayMetrics()
requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics)
bottomSheet.behavior.peekHeight = displayMetrics.heightPixels
bottomSheet.window!!.setLayout( bottomSheet.window!!.setLayout(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT ViewGroup.LayoutParams.MATCH_PARENT
@ -198,47 +217,48 @@ class DownloadMultipleBottomSheetDialog(private var results: List<ResultItem?>,
} }
R.id.format -> { R.id.format -> {
if (results.first()!!.formats.isEmpty()){ if (! items.all { it.type == items[0].type }){
Toast.makeText(requireContext(), getString(R.string.format_filtering_hint), Toast.LENGTH_SHORT).show()
}else{
if (items.first().type == DownloadViewModel.Type.command){
lifecycleScope.launch {
uiUtil.showCommandTemplates(requireActivity(), commandTemplateViewModel) {
val format = downloadViewModel.generateCommandFormat(it)
items.forEach { f ->
f.format = format
}
listAdapter.submitList(items.toList())
listAdapter.notifyDataSetChanged()
}
}
}else{
lifecycleScope.launch {
val flatFormatCollection = items.map { it.allFormats }.flatten()
val commonFormats = withContext(Dispatchers.IO){
flatFormatCollection.groupingBy { it.format_id }.eachCount().filter { it.value == items.size }.mapValues { flatFormatCollection.first { f -> f.format_id == it.key } }.map { it.value }
}
val formats = if (commonFormats.isNotEmpty() && items.none{it.allFormats.isEmpty()}) {
items.map { it.allFormats }
}else{
when(items.first().type){
DownloadViewModel.Type.audio -> listOf<List<Format>>(downloadViewModel.getGenericAudioFormats())
else -> listOf<List<Format>>(downloadViewModel.getGenericVideoFormats())
}
}
val bottomSheet = FormatSelectionBottomSheetDialog(items, formats, formatListener)
bottomSheet.show(parentFragmentManager, "formatSheet")
}
}
} }
// val formatListCollection = items.map { it.format }
// val commonFormats = getCommonFormats(formatListCollection)
//
// val listener = object : OnFormatClickListener {
// override fun onFormatClick(allFormats: List<Format>, item: Format) {
//
// }
// }
// if (parentFragmentManager.findFragmentByTag("formatSheet") == null){
// val bottomSheet = FormatSelectionBottomSheetDialog(null, commonFormats.toList(), listener)
// bottomSheet.show(parentFragmentManager, "formatSheet")
// }
} }
} }
true true
} }
val itemsLiveData = items.asFlow()
} }
// private fun getCommonFormats(vararg lists: MutableList<List<Format>>): Set<Format> {
// val commons: MutableList<Format> = mutableListOf()
// commons.addAll(lists[1])
// {
// lists[1].forEach {
// commons.retainAll(it)
// }
// }
//
// for (numbers in list) {
// result = Sets.intersection(result, Sets.newHashSet(numbers))
// }
// return result
//
//
// }
private var pathResultLauncher = registerForActivityResult( private var pathResultLauncher = registerForActivityResult(
ActivityResultContracts.StartActivityForResult() ActivityResultContracts.StartActivityForResult()
) { result -> ) { result ->
@ -268,9 +288,11 @@ class DownloadMultipleBottomSheetDialog(private var results: List<ResultItem?>,
} }
private fun cleanup(){ private fun cleanup(){
parentFragmentManager.beginTransaction().remove(parentFragmentManager.findFragmentByTag("downloadMultipleSheet")!!).commit() kotlin.runCatching {
if (parentFragmentManager.fragments.size == 1){ parentFragmentManager.beginTransaction().remove(parentFragmentManager.findFragmentByTag("downloadMultipleSheet")!!).commit()
(activity as ShareActivity).finish() if (parentFragmentManager.fragments.size == 1){
(activity as ShareActivity).finish()
}
} }
} }
@ -298,7 +320,11 @@ class DownloadMultipleBottomSheetDialog(private var results: List<ResultItem?>,
override fun onDownloadItemUpdate(resultItemID: Long, item: DownloadItem) { override fun onDownloadItemUpdate(resultItemID: Long, item: DownloadItem) {
val i = items.indexOf(items.find { it.url == item.url }) val i = items.indexOf(items.find { it.url == item.url })
items[i] = item items[i] = item
Log.e("aa", items.toList().toString()) if (! items.all { it.type == items[0].type }){
bottomAppBar.menu[2].icon?.alpha = 30
}else{
bottomAppBar.menu[2].icon?.alpha = 255
}
listAdapter.submitList(items.toList()) listAdapter.submitList(items.toList())
} }

View file

@ -129,44 +129,42 @@ class DownloadVideoFragment(private val resultItem: ResultItem, private var curr
var formats = mutableListOf<Format>() var formats = mutableListOf<Format>()
formats.addAll(resultItem.formats.filter { !it.format_note.contains("audio", ignoreCase = true) }) formats.addAll(resultItem.formats.filter { !it.format_note.contains("audio", ignoreCase = true) })
val videoFormats = resources.getStringArray(R.array.video_formats) if (formats.isEmpty()) formats.addAll(downloadItem.allFormats.filter { !it.format_note.contains("audio", ignoreCase = true) })
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)
val containerPreference = sharedPreferences.getString("video_format", getString(R.string.defaultValue)) val containerPreference = sharedPreferences.getString("video_format", "Default")
if (formats.isEmpty()) { if (formats.isEmpty()) formats = downloadViewModel.getGenericVideoFormats()
videoFormats.forEach { formats.add(Format(it, containerPreference!!,"","", "",0, it)) }
}
val formatCard = view.findViewById<ConstraintLayout>(R.id.format_card_constraintLayout) val formatCard = view.findViewById<ConstraintLayout>(R.id.format_card_constraintLayout)
val chosenFormat = downloadItem.format 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<List<Format>>, item: List<Format>) {
downloadItem.format = item downloadItem.format = item.first()
if (containers.contains(item.container)){ if (containers.contains(item.first().container)){
downloadItem.format.container = item.container downloadItem.format.container = item.first().container
containerAutoCompleteTextView.setText(item.container, false) containerAutoCompleteTextView.setText(item.first().container, false)
} }
lifecycleScope.launch { lifecycleScope.launch {
withContext(Dispatchers.IO){ withContext(Dispatchers.IO){
resultItem.formats.removeAll(formats.toSet()) resultItem.formats.removeAll(formats.toSet())
resultItem.formats.addAll(allFormats) resultItem.formats.addAll(allFormats.first())
resultViewModel.update(resultItem) resultViewModel.update(resultItem)
} }
} }
formats = allFormats.toMutableList() formats = allFormats.first().toMutableList()
uiUtil.populateFormatCard(formatCard, item) uiUtil.populateFormatCard(formatCard, item.first())
} }
} }
formatCard.setOnClickListener{ formatCard.setOnClickListener{
if (parentFragmentManager.findFragmentByTag("formatSheet") == null){ if (parentFragmentManager.findFragmentByTag("formatSheet") == null){
val bottomSheet = FormatSelectionBottomSheetDialog(downloadItem, formats, listener) val bottomSheet = FormatSelectionBottomSheetDialog(listOf(downloadItem), listOf(formats), listener)
bottomSheet.show(parentFragmentManager, "formatSheet") bottomSheet.show(parentFragmentManager, "formatSheet")
} }
} }

View file

@ -5,6 +5,7 @@ import android.app.Activity
import android.app.Dialog import android.app.Dialog
import android.content.* import android.content.*
import android.os.Bundle import android.os.Bundle
import android.os.Looper
import android.util.DisplayMetrics import android.util.DisplayMetrics
import android.util.Log import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
@ -27,20 +28,25 @@ 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 FormatSelectionBottomSheetDialog(private val item: DownloadItem?, private var formats: List<Format>, private val listener: OnFormatClickListener) : BottomSheetDialogFragment() { class FormatSelectionBottomSheetDialog(private val items: List<DownloadItem?>, private var formats: List<List<Format>>, private val listener: OnFormatClickListener) : BottomSheetDialogFragment() {
private lateinit var behavior: BottomSheetBehavior<View> private lateinit var behavior: BottomSheetBehavior<View>
private lateinit var fileUtil: FileUtil private lateinit var fileUtil: FileUtil
private lateinit var infoUtil: InfoUtil private lateinit var infoUtil: InfoUtil
private lateinit var uiUtil: UiUtil private lateinit var uiUtil: UiUtil
private lateinit var sharedPreferences: SharedPreferences private lateinit var sharedPreferences: SharedPreferences
private lateinit var formatCollection: MutableList<List<Format>>
private lateinit var chosenFormats: List<Format>
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
fileUtil = FileUtil() fileUtil = FileUtil()
uiUtil = UiUtil(fileUtil) uiUtil = UiUtil(fileUtil)
infoUtil = InfoUtil(requireActivity().applicationContext) infoUtil = InfoUtil(requireActivity().applicationContext)
formatCollection = mutableListOf()
chosenFormats = listOf()
sharedPreferences = requireContext().getSharedPreferences("root_preferences", Activity.MODE_PRIVATE) sharedPreferences = requireContext().getSharedPreferences("root_preferences", Activity.MODE_PRIVATE)
} }
@ -61,10 +67,35 @@ class FormatSelectionBottomSheetDialog(private val item: DownloadItem?, private
val linearLayout = view.findViewById<LinearLayout>(R.id.format_list_linear_layout) val linearLayout = view.findViewById<LinearLayout>(R.id.format_list_linear_layout)
val shimmers = view.findViewById<ShimmerFrameLayout>(R.id.format_list_shimmer) val shimmers = view.findViewById<ShimmerFrameLayout>(R.id.format_list_shimmer)
shimmers.visibility = View.GONE shimmers.visibility = View.GONE
addFormatsToView(linearLayout)
if (items.size > 1){
val hasGenericFormats = when(items.first()!!.type){
Type.audio -> formats.flatten().size == resources.getStringArray(R.array.audio_formats).size
else -> formats.flatten().size == resources.getStringArray(R.array.video_formats).size
}
if (!hasGenericFormats){
formatCollection.addAll(formats)
val flattenFormats = formats.flatten()
val commonFormats = flattenFormats.groupingBy { it.format_id }.eachCount().filter { it.value == items.size }.mapValues { flattenFormats.first { f -> f.format_id == it.key } }.map { it.value }
commonFormats.forEach {
it.filesize =
flattenFormats.filter { f -> f.format_id == it.format_id }
.sumOf { itt -> itt.filesize }
}
chosenFormats = commonFormats
}else{
chosenFormats = formats.flatten()
}
addFormatsToView(linearLayout)
}else{
chosenFormats = formats.flatten()
addFormatsToView(linearLayout)
}
val refreshBtn = view.findViewById<Button>(R.id.format_refresh) val refreshBtn = view.findViewById<Button>(R.id.format_refresh)
if (formats.none { it.filesize == 0L } || item == null) refreshBtn.visibility = View.GONE if (formats.flatten().none { it.filesize == 0L } || items.isEmpty()) refreshBtn.visibility = View.GONE
refreshBtn.setOnClickListener { refreshBtn.setOnClickListener {
lifecycleScope.launch { lifecycleScope.launch {
try { try {
@ -73,15 +104,45 @@ class FormatSelectionBottomSheetDialog(private val item: DownloadItem?, private
shimmers.visibility = View.VISIBLE shimmers.visibility = View.VISIBLE
shimmers.startShimmer() shimmers.startShimmer()
val res = withContext(Dispatchers.IO){ //simple download
infoUtil.getFormats(item!!.url) if (items.size == 1){
val res = withContext(Dispatchers.IO){
infoUtil.getFormats(items.first()!!.url)
}
chosenFormats = res.formats.filter { it.filesize != 0L }
chosenFormats = when(items.first()?.type){
Type.audio -> chosenFormats.filter { it.format_note.contains("audio", ignoreCase = true) }
else -> chosenFormats.filter { !it.format_note.contains("audio", ignoreCase = true) }
}
if (chosenFormats.isEmpty()) throw Exception()
//playlist format filtering
}else{
var progress = "0/${items.size}"
refreshBtn.text = progress
withContext(Dispatchers.IO){
infoUtil.getFormatsMultiple(items.map { it!!.url }) {
lifecycleScope.launch(Dispatchers.Main){
progress = "${formatCollection.size}/${items.size}"
refreshBtn.text = progress
}
formatCollection.add(it)
}
}
val flatFormatCollection = formatCollection.flatten()
val commonFormats = flatFormatCollection.groupingBy { it.format_id }.eachCount().filter { it.value == items.size }.mapValues { flatFormatCollection.first { f -> f.format_id == it.key } }.map { it.value }
chosenFormats = commonFormats.filter { it.filesize != 0L }.mapTo(mutableListOf()) {it.copy()}
chosenFormats = when(items.first()?.type){
Type.audio -> chosenFormats.filter { it.format_note.contains("audio", ignoreCase = true) }
else -> chosenFormats.filter { !it.format_note.contains("audio", ignoreCase = true) }
}
if (chosenFormats.isEmpty()) throw Exception()
chosenFormats.forEach {
it.filesize =
flatFormatCollection.filter { f -> f.format_id == it.format_id }
.sumOf { itt -> itt.filesize }
}
} }
formats = res.formats.filter { it.filesize != 0L }
formats = when(item?.type){
Type.audio -> formats.filter { it.format_note.contains("audio", ignoreCase = true) }
else -> formats.filter { !it.format_note.contains("audio", ignoreCase = true) }
}
if (formats.isEmpty()) throw Exception()
addFormatsToView(linearLayout) addFormatsToView(linearLayout)
refreshBtn.visibility = View.GONE refreshBtn.visibility = View.GONE
@ -90,6 +151,7 @@ class FormatSelectionBottomSheetDialog(private val item: DownloadItem?, private
shimmers.stopShimmer() shimmers.stopShimmer()
}catch (e: Exception){ }catch (e: Exception){
refreshBtn.isEnabled = true refreshBtn.isEnabled = true
refreshBtn.text = getString(R.string.update_formats)
linearLayout.visibility = View.VISIBLE linearLayout.visibility = View.VISIBLE
shimmers.visibility = View.GONE shimmers.visibility = View.GONE
shimmers.stopShimmer() shimmers.stopShimmer()
@ -99,20 +161,27 @@ class FormatSelectionBottomSheetDialog(private val item: DownloadItem?, private
} }
} }
} }
if (sharedPreferences.getBoolean("update_formats", false) && refreshBtn.isVisible){ if (sharedPreferences.getBoolean("update_formats", false) && refreshBtn.isVisible && items.size == 1){
refreshBtn.performClick() refreshBtn.performClick()
} }
} }
private fun addFormatsToView(linearLayout: LinearLayout){ private fun addFormatsToView(linearLayout: LinearLayout){
linearLayout.removeAllViews() linearLayout.removeAllViews()
Log.e("aa", formats.toString()) Log.e("aa", chosenFormats.toString())
for (i in formats.lastIndex downTo 0){ for (i in chosenFormats.lastIndex downTo 0){
val format = formats[i] val format = chosenFormats[i]
val formatItem = LayoutInflater.from(context).inflate(R.layout.format_item, null) val formatItem = LayoutInflater.from(context).inflate(R.layout.format_item, null)
uiUtil.populateFormatCard(formatItem as ConstraintLayout, format) uiUtil.populateFormatCard(formatItem as ConstraintLayout, format)
formatItem.setOnClickListener{_ -> formatItem.setOnClickListener{_ ->
listener.onFormatClick(formats, format) if (items.size == 1){
listener.onFormatClick(List(items.size){chosenFormats}, listOf(format))
}else{
val selectedFormats = mutableListOf<Format>()
formatCollection.forEach {
selectedFormats.add(it.first{ f -> f.format_id == format.format_id})
}
listener.onFormatClick(formatCollection, selectedFormats)
}
dismiss() dismiss()
} }
formatItem.setOnLongClickListener { formatItem.setOnLongClickListener {
@ -141,10 +210,12 @@ class FormatSelectionBottomSheetDialog(private val item: DownloadItem?, private
private fun cleanUp(){ private fun cleanUp(){
parentFragmentManager.beginTransaction().remove(parentFragmentManager.findFragmentByTag("formatSheet")!!).commit() kotlin.runCatching {
parentFragmentManager.beginTransaction().remove(parentFragmentManager.findFragmentByTag("formatSheet")!!).commit()
}
} }
} }
interface OnFormatClickListener{ interface OnFormatClickListener{
fun onFormatClick(allFormats: List<Format>, item: Format) fun onFormatClick(allFormats: List<List<Format>>, item: List<Format>)
} }

View file

@ -179,9 +179,11 @@ class SelectPlaylistItemsBottomSheetDialog(private val items: List<ResultItem?>,
} }
private fun cleanup(){ private fun cleanup(){
parentFragmentManager.beginTransaction().remove(parentFragmentManager.findFragmentByTag("downloadPlaylistSheet")!!).commit() kotlin.runCatching {
if (parentFragmentManager.fragments.size == 1){ parentFragmentManager.beginTransaction().remove(parentFragmentManager.findFragmentByTag("downloadPlaylistSheet")!!).commit()
(activity as ShareActivity).finish() if (parentFragmentManager.fragments.size == 1){
(activity as ShareActivity).finish()
}
} }
} }

View file

@ -184,6 +184,7 @@ class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClic
openFile.visibility = View.GONE openFile.visibility = View.GONE
bottomSheet.show() bottomSheet.show()
bottomSheet.behavior.peekHeight = 512
bottomSheet.window!!.setLayout( bottomSheet.window!!.setLayout(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT ViewGroup.LayoutParams.MATCH_PARENT

View file

@ -183,6 +183,7 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL
openFile.visibility = View.GONE openFile.visibility = View.GONE
bottomSheet.show() bottomSheet.show()
bottomSheet.behavior.peekHeight = 512
bottomSheet.window!!.setLayout( bottomSheet.window!!.setLayout(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT ViewGroup.LayoutParams.MATCH_PARENT

View file

@ -483,6 +483,7 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
else redownload.visibility = GONE else redownload.visibility = GONE
bottomSheet!!.show() bottomSheet!!.show()
bottomSheet!!.behavior.peekHeight = 512
bottomSheet!!.window!!.setLayout( bottomSheet!!.window!!.setLayout(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT ViewGroup.LayoutParams.MATCH_PARENT

View file

@ -202,6 +202,7 @@ class QueuedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLi
redownload!!.visibility = View.GONE redownload!!.visibility = View.GONE
bottomSheet.show() bottomSheet.show()
bottomSheet.behavior.peekHeight = 512
bottomSheet.window!!.setLayout( bottomSheet.window!!.setLayout(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT ViewGroup.LayoutParams.MATCH_PARENT

View file

@ -25,7 +25,9 @@ import androidx.lifecycle.lifecycleScope
import androidx.work.* import androidx.work.*
import com.deniscerri.ytdlnis.R import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.viewmodel.CommandTemplateViewModel import com.deniscerri.ytdlnis.database.viewmodel.CommandTemplateViewModel
import com.deniscerri.ytdlnis.util.FileUtil
import com.deniscerri.ytdlnis.util.NotificationUtil import com.deniscerri.ytdlnis.util.NotificationUtil
import com.deniscerri.ytdlnis.util.UiUtil
import com.deniscerri.ytdlnis.work.TerminalDownloadWorker import com.deniscerri.ytdlnis.work.TerminalDownloadWorker
import com.google.android.material.appbar.MaterialToolbar import com.google.android.material.appbar.MaterialToolbar
import com.google.android.material.bottomappbar.BottomAppBar import com.google.android.material.bottomappbar.BottomAppBar
@ -55,6 +57,7 @@ class TerminalActivity : AppCompatActivity() {
private lateinit var downloadFile : File private lateinit var downloadFile : File
private lateinit var observer: FileObserver private lateinit var observer: FileObserver
private lateinit var imm : InputMethodManager private lateinit var imm : InputMethodManager
private lateinit var uiUtil: UiUtil
var context: Context? = null var context: Context? = null
public override fun onCreate(savedInstanceState: Bundle?) { public override fun onCreate(savedInstanceState: Bundle?) {
@ -65,6 +68,7 @@ class TerminalActivity : AppCompatActivity() {
downloadFile = File(cacheDir.absolutePath + "/$downloadID.txt") downloadFile = File(cacheDir.absolutePath + "/$downloadID.txt")
if (! downloadFile.exists()) downloadFile.createNewFile() if (! downloadFile.exists()) downloadFile.createNewFile()
imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
uiUtil = UiUtil(FileUtil())
context = baseContext context = baseContext
scrollView = findViewById(R.id.custom_command_scrollview) scrollView = findViewById(R.id.custom_command_scrollview)
@ -89,7 +93,17 @@ class TerminalActivity : AppCompatActivity() {
} }
bottomAppBar.setOnMenuItemClickListener { bottomAppBar.setOnMenuItemClickListener {
when(it.itemId){ when(it.itemId){
R.id.command_templates -> showCommandTemplates() R.id.command_templates -> {
lifecycleScope.launch {
uiUtil.showCommandTemplates(this@TerminalActivity, commandTemplateViewModel){ template ->
input!!.text.insert(input!!.selectionStart, template.content + " ")
input!!.postDelayed({
input!!.requestFocus()
imm.showSoftInput(input!!, 0)
}, 200)
}
}
}
R.id.shortcuts -> showShortcuts() R.id.shortcuts -> showShortcuts()
else -> {} else -> {}
} }
@ -210,41 +224,6 @@ class TerminalActivity : AppCompatActivity() {
fab!!.setIconResource(R.drawable.ic_cancel) fab!!.setIconResource(R.drawable.ic_cancel)
} }
private fun showCommandTemplates(){
lifecycleScope.launch {
val bottomSheet = BottomSheetDialog(this@TerminalActivity)
bottomSheet.requestWindowFeature(Window.FEATURE_NO_TITLE)
bottomSheet.setContentView(R.layout.command_template_list)
val linearLayout = bottomSheet.findViewById<LinearLayout>(R.id.command_list_linear_layout)
val list = withContext(Dispatchers.IO){
commandTemplateViewModel.getAll()
}
linearLayout!!.removeAllViews()
list.forEach {template ->
val item = layoutInflater.inflate(R.layout.command_template_item, linearLayout, false) as ConstraintLayout
item.findViewById<TextView>(R.id.title).text = template.title
item.findViewById<TextView>(R.id.content).text = template.content
item.setOnClickListener {
input!!.text.insert(input!!.selectionStart, template.content + " ")
bottomSheet.cancel()
input!!.postDelayed({
input!!.requestFocus()
imm.showSoftInput(input!!, 0)
}, 200)
}
linearLayout.addView(item)
}
bottomSheet.show()
bottomSheet.window!!.setLayout(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
}
}
private fun showShortcuts() { private fun showShortcuts() {
lifecycleScope.launch { lifecycleScope.launch {
val bottomSheet = BottomSheetDialog(this@TerminalActivity) val bottomSheet = BottomSheetDialog(this@TerminalActivity)

View file

@ -504,7 +504,7 @@ class InfoUtil(private val context: Context) {
} }
} }
fun getFormatsTest(urls: List<String>, progress: (progress: List<Format>) -> Unit){ fun getFormatsMultiple(urls: List<String>, progress: (progress: List<Format>) -> Unit){
init() init()
val urlsFile = File(context.cacheDir, "urls.txt") val urlsFile = File(context.cacheDir, "urls.txt")
urlsFile.delete() urlsFile.delete()
@ -524,26 +524,30 @@ class InfoUtil(private val context: Context) {
request.addOption("--cookies", cookiesFile.absolutePath) request.addOption("--cookies", cookiesFile.absolutePath)
} }
val youtubeDLResponse = YoutubeDL.getInstance().execute(request){ progress, _, line -> YoutubeDL.getInstance().execute(request){ progress, _, line ->
val formats = mutableListOf<Format>() try{
val listOfStrings = JSONArray(line) val formats = mutableListOf<Format>()
for (f in 0 until listOfStrings.length()){ val listOfStrings = JSONArray(line)
val format = listOfStrings.get(f) as JSONObject for (f in 0 until listOfStrings.length()){
try{ val format = listOfStrings.get(f) as JSONObject
if (format.getString("filesize") == "None") continue try{
}catch (e: Exception) { continue } if (format.getString("filesize") == "None") continue
val formatProper = Gson().fromJson(format.toString(), Format::class.java) }catch (e: Exception) { continue }
if (formatProper.filesize > 0){ val formatProper = Gson().fromJson(format.toString(), Format::class.java)
if ( !formatProper.format_note.contains("audio only", true)) { if (formatProper.filesize > 0){
formatProper.format_note = format.getString("format_note") if ( !formatProper.format_note.contains("audio only", true)) {
}else{ formatProper.format_note = format.getString("format_note")
formatProper.format_note = "${format.getString("format_note")} audio" }else{
formatProper.format_note = "${format.getString("format_note")} audio"
}
formatProper.container = format.getString("ext")
formats.add(formatProper)
} }
formatProper.container = format.getString("ext")
formats.add(formatProper)
} }
progress(formats)
}catch (e: Exception){
progress(emptyList())
} }
progress(formats)
} }
} catch (e: Exception) { } catch (e: Exception) {
Looper.prepare().run { Looper.prepare().run {

View file

@ -13,6 +13,7 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.Window import android.view.Window
import android.widget.Button import android.widget.Button
import android.widget.LinearLayout
import android.widget.TextView import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
@ -21,6 +22,7 @@ import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import com.deniscerri.ytdlnis.R import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.models.CommandTemplate import com.deniscerri.ytdlnis.database.models.CommandTemplate
import com.deniscerri.ytdlnis.database.models.Format import com.deniscerri.ytdlnis.database.models.Format
@ -35,6 +37,9 @@ import com.google.android.material.datepicker.MaterialDatePicker
import com.google.android.material.textfield.TextInputLayout import com.google.android.material.textfield.TextInputLayout
import com.google.android.material.timepicker.MaterialTimePicker import com.google.android.material.timepicker.MaterialTimePicker
import com.google.android.material.timepicker.TimeFormat import com.google.android.material.timepicker.TimeFormat
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File import java.io.File
import java.util.* import java.util.*
@ -282,4 +287,33 @@ class UiUtil(private val fileUtil: FileUtil) {
} }
datePicker.show(fragmentManager, "datepicker") datePicker.show(fragmentManager, "datepicker")
} }
suspend fun showCommandTemplates(activity: Activity, commandTemplateViewModel: CommandTemplateViewModel, itemSelected: (itemSelected: CommandTemplate) -> Unit) {
val bottomSheet = BottomSheetDialog(activity)
bottomSheet.requestWindowFeature(Window.FEATURE_NO_TITLE)
bottomSheet.setContentView(R.layout.command_template_list)
val linearLayout = bottomSheet.findViewById<LinearLayout>(R.id.command_list_linear_layout)
val list = withContext(Dispatchers.IO){
commandTemplateViewModel.getAll()
}
linearLayout!!.removeAllViews()
list.forEach {template ->
val item = activity.layoutInflater.inflate(R.layout.command_template_item, linearLayout, false) as ConstraintLayout
item.findViewById<TextView>(R.id.title).text = template.title
item.findViewById<TextView>(R.id.content).text = template.content
item.setOnClickListener {
itemSelected(template)
bottomSheet.cancel()
}
linearLayout.addView(item)
}
bottomSheet.show()
bottomSheet.window!!.setLayout(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
}
} }

View file

@ -145,7 +145,7 @@ class DownloadWorker(
val ext = downloadItem.format.container val ext = downloadItem.format.container
if (audioQualityId.isBlank() || ext == "Default") request.addOption("-x") if (audioQualityId.isBlank() || ext == "Default") request.addOption("-x")
request.addOption("-f", audioQualityId) else request.addOption("-f", audioQualityId)
if(ext != "webm"){ if(ext != "webm"){
val codec = when(downloadItem.format.container){ val codec = when(downloadItem.format.container){

View file

@ -216,4 +216,5 @@
<string name="video_recommendations_summary">Get Recommended Youtube Videos on the Home Screen from Invidious</string> <string name="video_recommendations_summary">Get Recommended Youtube Videos on the Home Screen from Invidious</string>
<string name="preferred_search_engine">Preferred Search Engine</string> <string name="preferred_search_engine">Preferred Search Engine</string>
<string name="preferred_search_engine_summary">The search engine to use for in-app searches</string> <string name="preferred_search_engine_summary">The search engine to use for in-app searches</string>
<string name="format_filtering_hint">All items must be of the same type to use this option</string>
</resources> </resources>