Fixed quotes breaking command, removed format sorting by default, moved to advanced settings

This commit is contained in:
deniscerri 2025-02-22 17:44:20 +01:00
parent 1a4c515262
commit 0bb9d9d8fb
No known key found for this signature in database
GPG key ID: 95C43D517D830350
14 changed files with 326 additions and 203 deletions

View file

@ -532,12 +532,19 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
fun getFormat(formats: List<Format>, type: Type, url: String? = null) : Format {
val sortFormats = sharedPreferences.getBoolean("use_format_sorting", false)
when(type) {
Type.audio -> {
return cloneFormat (
try {
val theFormats = formats.filter { it.vcodec.isBlank() || it.vcodec == "none" }
FormatUtil(application).sortAudioFormats(theFormats).first()
if (sortFormats) {
FormatUtil(application).sortAudioFormats(theFormats).first()
}else {
theFormats.first()
}
}catch (e: Exception){
formatUtil.getGenericAudioFormats(resources).first()
}
@ -551,9 +558,11 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
formatUtil.getGenericVideoFormats(resources).sortedByDescending { it.filesize }
}
val sorted = FormatUtil(application).sortVideoFormats(theFormats)
println(sorted.map { it.vcodec })
sorted.first()
if (sortFormats) {
FormatUtil(application).sortVideoFormats(theFormats).first()
}else {
theFormats.first()
}
}catch (e: Exception){
formatUtil.getGenericVideoFormats(resources).first()
}

View file

@ -5,6 +5,7 @@ import android.app.Activity
import android.content.SharedPreferences
import android.content.res.ColorStateList
import android.graphics.Color
import android.text.TextUtils
import android.util.TypedValue
import android.view.LayoutInflater
import android.view.MotionEvent
@ -23,6 +24,8 @@ import com.deniscerri.ytdl.database.models.CommandTemplate
import com.deniscerri.ytdl.database.models.YoutubePlayerClientItem
import com.deniscerri.ytdl.util.Extensions.popup
import com.google.android.material.card.MaterialCardView
import com.google.android.material.chip.Chip
import com.google.android.material.chip.ChipGroup
import com.google.android.material.materialswitch.MaterialSwitch
class YoutubePlayerClientAdapter(onItemClickListener: OnItemClickListener, activity: Activity, private var itemTouchHelper: ItemTouchHelper) : ListAdapter<YoutubePlayerClientItem?, YoutubePlayerClientAdapter.ViewHolder>(AsyncDifferConfig.Builder(
@ -61,21 +64,38 @@ class YoutubePlayerClientAdapter(onItemClickListener: OnItemClickListener, activ
val title = card.findViewById<TextView>(R.id.title)
title.text = item.playerClient
val content = card.findViewById<TextView>(R.id.content)
content.isVisible = item.poTokens.isNotEmpty()
if (item.poTokens.isNotEmpty()) {
val text = item.poTokens.joinToString("\n") { "PO Token (${it.context}): ${it.token}" }
content.text = text
val content = card.findViewById<ChipGroup>(R.id.content)
val chips = mutableListOf<TextView>()
item.poTokens.forEach {
val tmp = activity.layoutInflater.inflate(R.layout.textview_chip, content, false) as TextView
tmp.maxWidth = 500
tmp.maxLines = 1
tmp.ellipsize = TextUtils.TruncateAt.END
val text = "PO Token (${it.context}): ${it.token}"
tmp.text = text
chips.add(tmp)
}
for (chip in chips.reversed()) {
content.addView(chip, 0)
}
if (item.urlRegex.isNotEmpty()) {
val text = content.text.toString() + "\nURL Regex: " + item.urlRegex.joinToString(", ")
content.text = text
val text = "URL Regex: " + item.urlRegex.joinToString(", ")
content.findViewById<TextView>(R.id.urlRegex).apply {
isVisible = true
setText(text)
}
}
title.alpha = if (item.enabled) 1f else 0.3f
content.alpha = if (item.enabled) 1f else 0.3f
val switch = card.findViewById<MaterialSwitch>(R.id.materialSwitch)
switch.isChecked = item.enabled
switch.setOnClickListener {
title.alpha = if (switch.isChecked) 1f else 0.3f
content.alpha = if (switch.isChecked) 1f else 0.3f
onItemClickListener.onStatusToggle(item, switch.isChecked, position)
}

View file

@ -30,8 +30,7 @@ class ProcessingSettingsFragment : BaseSettingsFragment() {
val preferredFormatID : EditTextPreference? = findPreference("format_id")
val preferredFormatIDAudio : EditTextPreference? = findPreference("format_id_audio")
val subtitleLanguages : Preference? = findPreference("subs_lang")
val formatImportanceAudio: Preference? = findPreference("format_importance_audio")
val formatImportanceVideo: Preference? = findPreference("format_importance_video")
preferredFormatID?.title = "${getString(R.string.preferred_format_id)} [${getString(R.string.video)}]"
preferredFormatID?.dialogTitle = "${getString(R.string.file_name_template)} [${getString(R.string.video)}]"
@ -50,50 +49,6 @@ class ProcessingSettingsFragment : BaseSettingsFragment() {
}
formatImportanceAudio?.apply {
title = "${getString(R.string.format_importance)} [${getString(R.string.audio)}]"
val items = requireContext().getStringArray(R.array.format_importance_audio)
val itemValues = requireContext().getStringArray(R.array.format_importance_audio_values).toSet()
val prefVideo = prefs.getString("format_importance_audio", itemValues.joinToString(","))!!
summary = prefVideo.split(",").mapIndexed { index, s -> "${index + 1}. ${items[itemValues.indexOf(s)]}" }.joinToString("\n")
setOnPreferenceClickListener {
val pref = prefs.getString("format_importance_audio", itemValues.joinToString(","))!!
val prefArr = pref.split(",")
val itms = itemValues.sortedBy { prefArr.indexOf(it) }.map {
Pair(it, items[itemValues.indexOf(it)])
}.toMutableList()
showFormatImportanceDialog(title.toString(), itms) { new ->
editor.putString("format_importance_audio", new.joinToString(",") { it.first }).apply()
formatImportanceAudio.summary = new.map { it.second }.mapIndexed { index, s -> "${index + 1}. $s" }.joinToString("\n")
}
true
}
}
formatImportanceVideo?.apply {
title = "${getString(R.string.format_importance)} [${getString(R.string.video)}]"
val items = requireContext().getStringArray(R.array.format_importance_video)
val itemValues = requireContext().getStringArray(R.array.format_importance_video_values).toSet()
val prefVideo = prefs.getString("format_importance_video", itemValues.joinToString(","))!!
summary = prefVideo.split(",").mapIndexed { index, s -> "${index + 1}. ${items[itemValues.indexOf(s)]}" }.joinToString("\n")
setOnPreferenceClickListener {
val pref = prefs.getString("format_importance_video", itemValues.joinToString(","))!!
val prefArr = pref.split(",")
val itms = itemValues.sortedBy { prefArr.indexOf(it) }.map {
Pair(it, items[itemValues.indexOf(it)])
}.toMutableList()
showFormatImportanceDialog(title.toString(), itms) {new ->
editor.putString("format_importance_video", new.joinToString(",") { it.first }).apply()
formatImportanceVideo.summary = new.map { it.second }.mapIndexed { index, s -> "${index + 1}. $s" }.joinToString("\n")
}
true
}
}
findPreference<EditTextPreference>("format_id")?.apply {
val s = getString(R.string.preferred_format_id_summary)
summary = if (text.isNullOrBlank()) {
@ -128,77 +83,4 @@ class ProcessingSettingsFragment : BaseSettingsFragment() {
}
}
}
private fun showFormatImportanceDialog(t: String, items: MutableList<Pair<String, String>>, onChange: (items: List<Pair<String, String>>) -> Unit){
val builder = MaterialAlertDialogBuilder(requireContext())
builder.setTitle(t)
val adapter = SortableTextItemAdapter(items)
val itemTouchCallback = object : ItemTouchHelper.Callback() {
override fun getMovementFlags(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder
): Int {
val dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN
return makeMovementFlags(dragFlags, 0)
}
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
val itemToMove = adapter.items[viewHolder.absoluteAdapterPosition]
adapter.items.remove(itemToMove)
adapter.items.add(target.absoluteAdapterPosition, itemToMove)
adapter.notifyItemMoved(
viewHolder.absoluteAdapterPosition,
target.absoluteAdapterPosition
)
return true
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
// do nothing
}
}
val linear = LinearLayout(requireActivity())
linear.orientation = LinearLayout.VERTICAL
val note = TextView(requireActivity())
note.text = getString(R.string.format_importance_note)
note.textSize = 16f
note.setTypeface(note.typeface, Typeface.BOLD)
note.setPadding(20,20,20,20)
linear.addView(note)
val recycler = RecyclerView(requireContext())
recycler.layoutManager = LinearLayoutManager(requireContext())
recycler.adapter = adapter
linear.addView(recycler)
val itemTouchHelper = ItemTouchHelper(itemTouchCallback)
itemTouchHelper.attachToRecyclerView(recycler)
builder.setView(linear)
builder.setPositiveButton(
getString(android.R.string.ok)
) { _: DialogInterface?, _: Int ->
onChange(adapter.items)
}
// handle the negative button of the alert dialog
builder.setNegativeButton(
getString(R.string.cancel)
) { _: DialogInterface?, _: Int -> }
val dialog = builder.create()
dialog.show()
}
}

View file

@ -1,13 +1,23 @@
package com.deniscerri.ytdl.ui.more.settings.advanced
import android.annotation.SuppressLint
import android.content.DialogInterface
import android.graphics.Typeface
import android.os.Bundle
import android.widget.LinearLayout
import android.widget.TextView
import androidx.navigation.fragment.findNavController
import androidx.preference.Preference
import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.afollestad.materialdialogs.utils.MDUtil.getStringArray
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.ui.adapter.SortableTextItemAdapter
import com.deniscerri.ytdl.ui.more.settings.BaseSettingsFragment
import com.deniscerri.ytdl.util.UiUtil
import com.google.android.material.dialog.MaterialAlertDialogBuilder
class AdvancedSettingsFragment : BaseSettingsFragment() {
@ -15,9 +25,132 @@ class AdvancedSettingsFragment : BaseSettingsFragment() {
@SuppressLint("RestrictedApi")
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.advanced_preferences, rootKey)
val prefs = PreferenceManager.getDefaultSharedPreferences(requireActivity())
val editor = prefs.edit()
findPreference<Preference>("yt_player_client")?.setOnPreferenceClickListener {
findNavController().navigate(R.id.youtubePlayerClientFragment)
false
}
val formatImportanceAudio: Preference? = findPreference("format_importance_audio")
val formatImportanceVideo: Preference? = findPreference("format_importance_video")
formatImportanceAudio?.apply {
title = "${getString(R.string.format_importance)} [${getString(R.string.audio)}]"
val items = requireContext().getStringArray(R.array.format_importance_audio)
val itemValues = requireContext().getStringArray(R.array.format_importance_audio_values).toSet()
val prefVideo = prefs.getString("format_importance_audio", itemValues.joinToString(","))!!
summary = prefVideo.split(",").mapIndexed { index, s -> "${index + 1}. ${items[itemValues.indexOf(s)]}" }.joinToString("\n")
setOnPreferenceClickListener {
val pref = prefs.getString("format_importance_audio", itemValues.joinToString(","))!!
val prefArr = pref.split(",")
val itms = itemValues.sortedBy { prefArr.indexOf(it) }.map {
Pair(it, items[itemValues.indexOf(it)])
}.toMutableList()
showFormatImportanceDialog(title.toString(), itms) { new ->
editor.putString("format_importance_audio", new.joinToString(",") { it.first }).apply()
formatImportanceAudio.summary = new.map { it.second }.mapIndexed { index, s -> "${index + 1}. $s" }.joinToString("\n")
}
true
}
}
formatImportanceVideo?.apply {
title = "${getString(R.string.format_importance)} [${getString(R.string.video)}]"
val items = requireContext().getStringArray(R.array.format_importance_video)
val itemValues = requireContext().getStringArray(R.array.format_importance_video_values).toSet()
val prefVideo = prefs.getString("format_importance_video", itemValues.joinToString(","))!!
summary = prefVideo.split(",").mapIndexed { index, s -> "${index + 1}. ${items[itemValues.indexOf(s)]}" }.joinToString("\n")
setOnPreferenceClickListener {
val pref = prefs.getString("format_importance_video", itemValues.joinToString(","))!!
val prefArr = pref.split(",")
val itms = itemValues.sortedBy { prefArr.indexOf(it) }.map {
Pair(it, items[itemValues.indexOf(it)])
}.toMutableList()
showFormatImportanceDialog(title.toString(), itms) {new ->
editor.putString("format_importance_video", new.joinToString(",") { it.first }).apply()
formatImportanceVideo.summary = new.map { it.second }.mapIndexed { index, s -> "${index + 1}. $s" }.joinToString("\n")
}
true
}
}
}
private fun showFormatImportanceDialog(t: String, items: MutableList<Pair<String, String>>, onChange: (items: List<Pair<String, String>>) -> Unit){
val builder = MaterialAlertDialogBuilder(requireContext())
builder.setTitle(t)
val adapter = SortableTextItemAdapter(items)
val itemTouchCallback = object : ItemTouchHelper.Callback() {
override fun getMovementFlags(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder
): Int {
val dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN
return makeMovementFlags(dragFlags, 0)
}
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
val itemToMove = adapter.items[viewHolder.absoluteAdapterPosition]
adapter.items.remove(itemToMove)
adapter.items.add(target.absoluteAdapterPosition, itemToMove)
adapter.notifyItemMoved(
viewHolder.absoluteAdapterPosition,
target.absoluteAdapterPosition
)
return true
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
// do nothing
}
}
val linear = LinearLayout(requireActivity())
linear.orientation = LinearLayout.VERTICAL
val note = TextView(requireActivity())
note.text = getString(R.string.format_importance_note)
note.textSize = 16f
note.setTypeface(note.typeface, Typeface.BOLD)
note.setPadding(20,20,20,20)
linear.addView(note)
val recycler = RecyclerView(requireContext())
recycler.layoutManager = LinearLayoutManager(requireContext())
recycler.adapter = adapter
linear.addView(recycler)
val itemTouchHelper = ItemTouchHelper(itemTouchCallback)
itemTouchHelper.attachToRecyclerView(recycler)
builder.setView(linear)
builder.setPositiveButton(
getString(android.R.string.ok)
) { _: DialogInterface?, _: Int ->
onChange(adapter.items)
}
// handle the negative button of the alert dialog
builder.setNegativeButton(
getString(R.string.cancel)
) { _: DialogInterface?, _: Int -> }
val dialog = builder.create()
dialog.show()
}
}

View file

@ -364,8 +364,8 @@ class TerminalFragment : Fragment() {
.observe(viewLifecycleOwner, workerObserver)
}
private val workerObserver = object: Observer<MutableList<WorkInfo>> {
override fun onChanged(value: MutableList<WorkInfo>) {
private val workerObserver = object: Observer<List<WorkInfo>> {
override fun onChanged(value: List<WorkInfo>) {
value.forEach { work ->
if (listOf(WorkInfo.State.SUCCEEDED, WorkInfo.State.FAILED, WorkInfo.State.CANCELLED).contains(work.state)) {
requireActivity().runOnUiThread {

View file

@ -1500,6 +1500,7 @@ object UiUtil {
val cut = view.findViewById<Chip>(R.id.cut)
if (items.size > 1 || items.first().url.isEmpty()) cut.isVisible = false
else{
cut.setOnClickListener(null)
val invalidDuration = items[0].duration == "-1"
if(items[0].duration.isNotEmpty() && !invalidDuration){
val downloadItem = items[0]
@ -1664,6 +1665,7 @@ object UiUtil {
val cut = view.findViewById<Chip>(R.id.cut)
if (items.size > 1 || items.first().url.isEmpty()) cut.isVisible = false
else{
cut.setOnClickListener(null)
val downloadItem = items[0]
val invalidDuration = downloadItem.duration == "-1"
if (downloadItem.duration.isNotEmpty() && !invalidDuration){

View file

@ -823,40 +823,49 @@ class YTDLPUtil(private val context: Context, private val commandTemplateDao: Co
}
request.addOption("-x")
val formatSorting = mutableListOf("hasaud")
val formatImportance = formatUtil.getAudioFormatImportance()
for(order in formatImportance) {
when(order) {
"file_size" -> {
formatSorting.add("size")
}
"language" -> {
if (preferredLanguage.isNotBlank()) {
formatSorting.add("lang:${preferredLanguage}")
val formatSorting = mutableListOf<String>()
if (sharedPreferences.getBoolean("use_format_sorting", false)) {
formatSorting.add("hasaud")
val formatImportance = formatUtil.getAudioFormatImportance()
for(order in formatImportance) {
when(order) {
"file_size" -> {
formatSorting.add("size")
}
}
"codec" -> {
if (aCodecPref.isNotBlank()){
formatSorting.add("acodec:$aCodecPref")
"language" -> {
if (preferredLanguage.isNotBlank()) {
formatSorting.add("lang:${preferredLanguage}")
}
}
}
"container" -> {
if(ext.isNotBlank()){
if(!ext.matches("(webm)|(Default)|(${context.getString(R.string.defaultValue)})".toRegex()) && supportedContainers.contains(ext)){
request.addOption("--audio-format", ext)
formatSorting.add("aext:$ext")
"codec" -> {
if (aCodecPref.isNotBlank()){
formatSorting.add("acodec:$aCodecPref")
}
}
"container" -> {
if(ext.isNotBlank()){
if(!ext.matches("(webm)|(Default)|(${context.getString(R.string.defaultValue)})".toRegex()) && supportedContainers.contains(ext)){
request.addOption("--audio-format", ext)
formatSorting.add("aext:$ext")
}
}
}
}
}
if (downloadItem.format.format_id == context.resources.getString(R.string.worst_quality) || downloadItem.format.format_id == "wa" || downloadItem.format.format_id == "worst") {
if(formatSorting.contains("size")) {
formatSorting.remove("size")
}
formatSorting.addAll(0,listOf("+br", "+res", "+fps"))
}
}else if (preferredLanguage.isNotBlank()) {
formatSorting.add("lang:${preferredLanguage}")
}
if (downloadItem.format.format_id == context.resources.getString(R.string.worst_quality) || downloadItem.format.format_id == "wa" || downloadItem.format.format_id == "worst") {
if(formatSorting.contains("size")) {
formatSorting.remove("size")
}
formatSorting.addAll(0,listOf("+br", "+res", "+fps"))
if (sharedPreferences.getBoolean("prefer_smaller_formats", false) && !formatSorting.contains("+size")) {
formatSorting.remove("size")
formatSorting.add(0, "+size")
}
if (abrSort.isNotBlank()){
@ -867,7 +876,6 @@ class YTDLPUtil(private val context: Context, private val commandTemplateDao: Co
request.addOption("-S", formatSorting.joinToString(","))
}
request.addOption("-P", downDir.absolutePath)
@ -1119,38 +1127,41 @@ class YTDLPUtil(private val context: Context, private val commandTemplateDao: Co
val formatImportance = formatUtil.getVideoFormatImportance()
val formatSorting = mutableListOf<String>()
for(order in formatImportance) {
when(order) {
"no_audio" -> {
formatSorting.add("+hasaud")
}
"codec" -> {
if (vCodecPref.isNotBlank()) formatSorting.add("vcodec:$vCodecPref")
if (aCodecPref.isNotBlank()) formatSorting.add("acodec:$aCodecPref")
}
"resolution" -> {
if (hasGenericResulutionFormat.isNotBlank()) {
formatSorting.add("res:${hasGenericResulutionFormat}")
if (sharedPreferences.getBoolean("use_format_sorting", false)) {
for(order in formatImportance) {
when(order) {
"no_audio" -> {
formatSorting.add("+hasaud")
}
"codec" -> {
if (vCodecPref.isNotBlank()) formatSorting.add("vcodec:$vCodecPref")
if (aCodecPref.isNotBlank()) formatSorting.add("acodec:$aCodecPref")
}
"resolution" -> {
if (hasGenericResulutionFormat.isNotBlank()) {
formatSorting.add("res:${hasGenericResulutionFormat}")
}
}
"container" -> {
if (cont.isNotBlank()) formatSorting.add("vext:$cont")
if (acont.isNotBlank()) formatSorting.add("aext:$acont")
}
}
"container" -> {
if (cont.isNotBlank()) formatSorting.add("vext:$cont")
if (acont.isNotBlank()) formatSorting.add("aext:$acont")
}
if (downloadItem.format.format_id == context.resources.getString(R.string.worst_quality) || downloadItem.format.format_id == "worst") {
formatSorting.addAll(0, listOf("+br","+res","+fps"))
}else {
if (sharedPreferences.getBoolean("prefer_smaller_formats", false)) {
formatSorting.add(0, "+size")
}
}
}
if (downloadItem.format.format_id == context.resources.getString(R.string.worst_quality) || downloadItem.format.format_id == "worst") {
formatSorting.addAll(0, listOf("+br","+res","+fps"))
}else {
if (sharedPreferences.getBoolean("prefer_smaller_formats", false)) {
formatSorting.add(0, "+size")
}else {
formatSorting.add(0, "size")
}
if (sharedPreferences.getBoolean("prefer_smaller_formats", false) && !formatSorting.contains("+br")) {
formatSorting.add(0, "+size")
}
if (abrSort.isNotBlank()) {
formatSorting.add("abr~${abrSort}")
}
@ -1324,7 +1335,11 @@ class YTDLPUtil(private val context: Context, private val commandTemplateDao: Co
this.add(elements.first().toString())
if (elements.size > 1) {
for (el in elements.drop(1)) {
this.add(""""$el"""")
val arg = el.toString()
.replace("\\", "\\\\")
.replace("\"", "\\\"")
this.add("\"$arg\"")
}
}
}

View file

@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="?android:colorAccent" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M4,12l1.41,1.41L11,7.83V20h2V7.83l5.58,5.59L20,12l-8,-8 -8,8z"/>
</vector>

View file

@ -49,17 +49,41 @@
app:layout_constraintStart_toEndOf="@id/drag_view"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="3"
android:textSize="14sp"
<com.google.android.material.chip.ChipGroup
android:layout_marginEnd="20dp"
android:layout_marginTop="10dp"
app:layout_constraintEnd_toStartOf="@+id/materialSwitch"
app:layout_constraintStart_toEndOf="@id/drag_view"
app:layout_constraintTop_toBottomOf="@+id/title" />
app:layout_constraintTop_toBottomOf="@+id/title"
app:layout_constraintHorizontal_bias="0.0"
android:id="@+id/content"
app:chipSpacing="0dp"
android:layout_width="0dp"
android:layout_height="wrap_content">
<TextView
android:id="@+id/urlRegex"
style="@style/Widget.Material3.FloatingActionButton.Large.Secondary"
android:layout_width="wrap_content"
android:visibility="gone"
android:layout_height="wrap_content"
android:text="URL Regex"
android:background="@drawable/rounded_corner"
android:backgroundTint="?attr/colorAccent"
android:clickable="false"
android:gravity="center"
android:minWidth="30dp"
android:paddingHorizontal="5dp"
android:textSize="12sp"
android:textStyle="bold"
app:cornerRadius="10dp"
app:layout_constraintTop_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:ignore="HardcodedText" />
</com.google.android.material.chip.ChipGroup>
<com.google.android.material.materialswitch.MaterialSwitch
android:id="@+id/materialSwitch"

View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView
style="@style/Widget.Material3.FloatingActionButton.Large.Primary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/rounded_corner"
android:backgroundTint="?attr/colorTertiaryContainer"
android:clickable="false"
android:gravity="center"
android:minWidth="30dp"
android:paddingHorizontal="5dp"
android:textSize="12sp"
android:textStyle="bold"
app:cornerRadius="10dp"
app:layout_constraintTop_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" />

View file

@ -464,4 +464,5 @@
<string name="cache_directory">Cache Folder</string>
<string name="cache_directory_warning">Changing the Cache Folder might cause unexpected issues. If the app cannot write to the configured path, it will resort to the default internal cache directory</string>
<string name="app_icon_change">Icon could change and Application will close</string>
<string name="use_format_sorting">Use Format Importance Ordering</string>
</resources>

View file

@ -34,7 +34,29 @@
android:title="@string/data_fetching_extra_command" />
</PreferenceCategory>
<PreferenceCategory android:title="@string/downloading" android:enabled="false">
<PreferenceCategory android:title="@string/format">
<SwitchPreferenceCompat
android:widgetLayout="@layout/preferece_material_switch"
app:defaultValue="false"
app:icon="@drawable/baseline_arrow_upward_24"
app:key="use_format_sorting"
app:title="@string/use_format_sorting" />
<Preference
android:icon="@drawable/ic_format"
android:key="format_importance_video"
android:dependency="use_format_sorting"
app:title="@string/format_importance" />
<Preference
android:icon="@drawable/ic_format"
android:key="format_importance_audio"
android:dependency="use_format_sorting"
app:title="@string/format_importance" />
</PreferenceCategory>
<PreferenceCategory android:title="@string/downloading" android:enabled="false" app:isPreferenceVisible="false">
<SwitchPreferenceCompat
android:widgetLayout="@layout/preferece_material_switch"
android:icon="@drawable/if_file_rename"

View file

@ -285,15 +285,6 @@
app:key="prefer_smaller_formats"
app:title="@string/prefer_smaller_formats" />
<Preference
android:icon="@drawable/ic_format"
android:key="format_importance_video"
app:title="@string/format_importance" />
<Preference
android:icon="@drawable/ic_format"
android:key="format_importance_audio"
app:title="@string/format_importance" />
</PreferenceCategory>

View file

@ -18,7 +18,7 @@ buildscript {
youtubedlAndroidVerNoPyCrypto = "97bee6c0e8"
youtubedlAndroidVerMine = "8831745ea3"
oldytdlAndroidVer = "0.14.0"
workVer = "2.9.1"
workVer = "2.10.0"
composeVer = '1.4.2'
kotlinVer = "1.7.21"
coroutineVer = '1.7.3'