added stuff

added file picker for the sheet
cancel
title and author name sync between types
sheet showing when there is one result
trending not refreshing every time app shows
This commit is contained in:
Denis Çerri 2023-01-23 23:42:33 +01:00
parent 7f813ebd96
commit 92d6b2f197
No known key found for this signature in database
GPG key ID: 95C43D517D830350
27 changed files with 420 additions and 510 deletions

View file

@ -167,7 +167,7 @@
</value>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="11" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">

View file

@ -103,6 +103,7 @@ dependencies {
implementation 'androidx.navigation:navigation-fragment:2.5.3'
implementation 'androidx.navigation:navigation-ui:2.5.3'
implementation 'androidx.core:core-ktx:1.9.0'
implementation 'androidx.core:core-ktx:+'
testImplementation "junit:junit:$junitVer"
androidTestImplementation "androidx.test.ext:junit:$androidJunitVer"
androidTestImplementation "androidx.test.espresso:espresso-core:$espressoVer"

View file

@ -2,11 +2,11 @@
"formatVersion": 1,
"database": {
"version": 1,
"identityHash": "94d37ae85390ef5198651df2480a02bf",
"identityHash": "2c0fdec170ca54d97ef928dfe28a6992",
"entities": [
{
"tableName": "results",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `title` TEXT NOT NULL, `author` TEXT NOT NULL, `duration` TEXT NOT NULL, `thumb` TEXT NOT NULL, `website` TEXT NOT NULL, `playlistTitle` TEXT NOT NULL)",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `title` TEXT NOT NULL, `author` TEXT NOT NULL, `duration` TEXT NOT NULL, `thumb` TEXT NOT NULL, `website` TEXT NOT NULL, `playlistTitle` TEXT NOT NULL, `creationTime` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "id",
@ -55,6 +55,12 @@
"columnName": "playlistTitle",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "creationTime",
"columnName": "creationTime",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
@ -386,7 +392,7 @@
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '94d37ae85390ef5198651df2480a02bf')"
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '2c0fdec170ca54d97ef928dfe28a6992')"
]
}
}

View file

@ -31,7 +31,6 @@ abstract class DBManager : RoomDatabase(){
DBManager::class.java,
"YTDLnisDatabase"
)
.allowMainThreadQueries()
.build()
instance = dbInstance
dbInstance

View file

@ -22,7 +22,7 @@ interface DownloadDao {
fun getDownloadByWorkId(workID: Int) : DownloadItem
@Query("SELECT * FROM downloads WHERE id=:id LIMIT 1")
fun getDownloadById(id: Int) : DownloadItem
fun getDownloadById(id: Long) : DownloadItem
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(item: DownloadItem) : Long

View file

@ -20,7 +20,7 @@ data class DownloadItem(
var formatDesc: String,
@ColumnInfo(defaultValue = "0")
val removeAudio: Boolean,
val downloadPath: String,
var downloadPath: String,
val website: String,
val downloadSize: String,
val playlistTitle: String,

View file

@ -2,6 +2,7 @@ package com.deniscerri.ytdlnis.database.models
import androidx.room.Entity
import androidx.room.PrimaryKey
import java.util.*
@Entity(tableName = "results")
data class ResultItem(
@ -13,5 +14,6 @@ data class ResultItem(
val duration: String,
val thumb: String,
val website: String,
var playlistTitle: String
var playlistTitle: String,
var creationTime: Long = System.currentTimeMillis() / 1000,
)

View file

@ -38,8 +38,8 @@ class DownloadRepository(private val downloadDao: DownloadDao) {
update(item);
}
fun getLatest() : DownloadItem {
return downloadDao.getLatest()
fun getItemByID(id: Long) : DownloadItem {
return downloadDao.getDownloadById(id)
}
}

View file

@ -45,7 +45,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
repository.update(item);
}
fun getLatest() : DownloadItem {
return repository.getLatest()
fun getItemByID(id: Long) : DownloadItem {
return repository.getItemByID(id)
}
}

View file

@ -34,15 +34,12 @@ class HistoryViewModel(application: Application) : AndroidViewModel(application)
filter(queryFilter.value!!, formatFilter.value!!, websiteFilter.value!!, sortType.value!!)
})
_items.addSource(formatFilter, Observer {
Log.e("aa", "audio");
filter(queryFilter.value!!, formatFilter.value!!, websiteFilter.value!!, sortType.value!!)
})
_items.addSource(sortType, Observer {
Log.e("aa", "asssssssssssss");
filter(queryFilter.value!!, formatFilter.value!!, websiteFilter.value!!, sortType.value!!)
})
_items.addSource(websiteFilter, Observer {
Log.e("Aa", "website")
filter(queryFilter.value!!, formatFilter.value!!, websiteFilter.value!!, sortType.value!!)
})
_items.addSource(queryFilter, Observer {
@ -56,7 +53,6 @@ class HistoryViewModel(application: Application) : AndroidViewModel(application)
}
fun setSorting(sort: HistorySort){
Log.e("aa", "asssssssssssss");
sortType.value = sort
}
@ -69,7 +65,6 @@ class HistoryViewModel(application: Application) : AndroidViewModel(application)
}
fun setFormatFilter(filter: String){
Log.e("aa", "audio");
formatFilter.value = filter
}

View file

@ -34,7 +34,12 @@ class ResultViewModel(application: Application) : AndroidViewModel(application)
fun checkTrending() = viewModelScope.launch(Dispatchers.IO){
try {
val item = repository.getFirstResult()
if (item.playlistTitle == "ytdlnis-TRENDING") getTrending()
if (
item.playlistTitle == getApplication<App>().getString(R.string.trendingPlaylist)
&& item.creationTime < (System.currentTimeMillis() / 1000) - 86400
){
getTrending()
}
}catch (e : Exception){
getTrending()
}
@ -58,7 +63,6 @@ class ResultViewModel(application: Application) : AndroidViewModel(application)
} else if (inputQuery!!.contains("http")) {
type = "Default"
}
Log.e(tag, "$inputQuery $type")
try {
when (type) {
"Search" -> {
@ -102,12 +106,7 @@ class ResultViewModel(application: Application) : AndroidViewModel(application)
when(type){
"audio" -> {
list = list.filter { it.format_note.contains("audio", ignoreCase = true) }
if (list.isEmpty()) {
audioFormats.forEach { formats.add(Format(0, item.id, it, "", 0, it, "")) }
return formats
}
return list
return list.filter { it.format_note.contains("audio", ignoreCase = true) }
}
"video" -> {
list = list.filter { !it.format_note.contains("audio", ignoreCase = true) }

View file

@ -37,6 +37,7 @@ import com.deniscerri.ytdlnis.util.InfoUtil
import com.facebook.shimmer.ShimmerFrameLayout
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.appbar.MaterialToolbar
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.button.MaterialButton
import com.google.android.material.chip.ChipGroup
@ -86,6 +87,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
private var selectedObjects: ArrayList<ResultItem>? = null
private var deleteFab: ExtendedFloatingActionButton? = null
private var fileUtil: FileUtil? = null
private var firstBoot = true
private var _binding : FragmentHomeBinding? = null
@ -144,10 +146,15 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
homeAdapter!!.submitList(it)
resultsList = it
if(it.size > 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
}else{
downloadAllFabCoordinator!!.visibility = GONE
}
}else if(it.size == 1 && !firstBoot && parentFragmentManager.findFragmentByTag("bottomSheet") == null){
showSingleDownloadSheet(it[0], "audio")
}
firstBoot = false
}
resultViewModel.loadingItems.observe(viewLifecycleOwner){
@ -349,9 +356,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
// selectedObjects!!.clear()
// selectedObjects!!.add(item!!)
//showConfigureSingleDownloadCard(createDownloadItem(item!!, type), item)
createDownloadItem(item!!, type){
showSingleDownloadSheet(it)
}
showSingleDownloadSheet(item!!, type)
} else {
// downloadQueue!!.add(vid)
// updateDownloadingStatusOnResult(vid, type, true)
@ -362,12 +367,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
}
}
private fun showSingleDownloadSheet(item : DownloadItem){
val bottomSheet = DownloadBottomSheetDialog(item)
bottomSheet.show(parentFragmentManager, null)
}
private fun createDownloadItem(item: ResultItem, type: String, itemCreated: (DownloadItem) -> Unit) : DownloadItem {
private fun showSingleDownloadSheet(resultItem : ResultItem, type: String){
val sharedPreferences =
requireContext().getSharedPreferences("root_preferences", Activity.MODE_PRIVATE)
val embedSubs = sharedPreferences.getBoolean("embed_subtitles", false)
@ -376,22 +376,22 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
val downloadItem = DownloadItem(0,
item.url,
item.title,
item.author,
item.thumb,
item.duration,
resultItem.url,
resultItem.title,
resultItem.author,
resultItem.thumb,
resultItem.duration,
type,
"", "", 0, "", false,
"", item.website, "", item.playlistTitle, embedSubs, addChapters, saveThumb, "",
"", resultItem.website, "", resultItem.playlistTitle, embedSubs, addChapters, saveThumb, "",
"", DownloadRepository.status.Processing.toString(), 0
)
downloadViewModel.insertDownload(downloadItem).observe(viewLifecycleOwner) {
downloadItem.id = it
itemCreated(downloadItem)
val bottomSheet = DownloadBottomSheetDialog(downloadItem)
bottomSheet.show(parentFragmentManager, "bottomSheet")
}
return downloadItem
}

View file

@ -1,6 +1,7 @@
package com.deniscerri.ytdlnis.ui.downloadcard
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
@ -8,33 +9,56 @@ import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.Window
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.AutoCompleteTextView
import android.widget.Toast
import android.widget.*
import androidx.activity.result.contract.ActivityResultContracts
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.deniscerri.ytdlnis.MainActivity
import com.deniscerri.ytdlnis.R
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.deniscerri.ytdlnis.databinding.FragmentHomeBinding
import com.deniscerri.ytdlnis.ui.HomeFragment
import com.deniscerri.ytdlnis.util.FileUtil
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.google.android.material.button.MaterialButton
import com.google.android.material.textfield.TextInputLayout
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class DownloadAudioFragment(item: DownloadItem) : Fragment() {
class DownloadAudioFragment(private val downloadItem: DownloadItem) : Fragment() {
private var _binding : FragmentHomeBinding? = null
private var fragmentView: View? = null
private var activity: Activity? = null
private var mainActivity: MainActivity? = null
private lateinit var resultViewModel : ResultViewModel
private lateinit var downloadViewModel : DownloadViewModel
private lateinit var fileUtil : FileUtil
private val downloadItem = item
private lateinit var title : TextInputLayout
private lateinit var author : TextInputLayout
private lateinit var saveDir : TextInputLayout
override fun onResume() {
super.onResume()
lifecycleScope.launch{
val item = withContext(Dispatchers.IO){
downloadViewModel.getItemByID(downloadItem.id)
}
if (::title.isInitialized){
title.editText!!.setText(item.title)
downloadItem.title = item.title
}
if(::author.isInitialized){
author.editText!!.setText(item.author)
downloadItem.author = item.author
}
}
downloadViewModel.updateDownload(downloadItem)
}
override fun onCreateView(
inflater: LayoutInflater,
@ -46,109 +70,176 @@ class DownloadAudioFragment(item: DownloadItem) : Fragment() {
activity = getActivity()
mainActivity = activity as MainActivity?
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
fileUtil = FileUtil()
return fragmentView
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val resultItem = resultViewModel.getItemByURL(downloadItem.url)
val type = downloadItem.type
lifecycleScope.launch {
val resultItem = withContext(Dispatchers.IO){
resultViewModel.getItemByURL(downloadItem.url)
}
val type = downloadItem.type
val sharedPreferences =
requireContext().getSharedPreferences("root_preferences", Activity.MODE_PRIVATE)
val sharedPreferences =
requireContext().getSharedPreferences("root_preferences", Activity.MODE_PRIVATE)
try {
val title = view.findViewById<TextInputLayout>(R.id.title_textinput)
title!!.editText!!.setText(downloadItem.title)
title.editText!!.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
override fun afterTextChanged(p0: Editable?) {
downloadItem.title = p0.toString()
resultItem.title = p0.toString()
resultViewModel.update(resultItem)
}
})
try {
title = view.findViewById(R.id.title_textinput)
title.editText!!.setText(downloadItem.title)
title.editText!!.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
override fun afterTextChanged(p0: Editable?) {
downloadItem.title = p0.toString()
resultItem.title = p0.toString()
resultViewModel.update(resultItem)
downloadViewModel.updateDownload(downloadItem)
}
})
val author = view.findViewById<TextInputLayout>(R.id.author_textinput)
author!!.editText!!.setText(downloadItem.author)
author.editText!!.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
override fun afterTextChanged(p0: Editable?) {
downloadItem.author = p0.toString()
resultItem.author = p0.toString()
resultViewModel.update(resultItem)
}
})
val saveDir = view.findViewById<TextInputLayout>(R.id.outputPath)
saveDir!!.editText!!.setText(
sharedPreferences.getString(
author = view.findViewById(R.id.author_textinput)
author.editText!!.setText(downloadItem.author)
author.editText!!.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
override fun afterTextChanged(p0: Editable?) {
downloadItem.author = p0.toString()
resultItem.author = p0.toString()
resultViewModel.update(resultItem)
downloadViewModel.updateDownload(downloadItem)
}
})
saveDir = view.findViewById(R.id.outputPath)
val downloadPath = sharedPreferences.getString(
"music_path",
getString(R.string.music_path)
)
)
saveDir.editText!!.isFocusable = false;
saveDir.editText!!.isClickable = true;
saveDir.editText!!.setOnClickListener {
Toast.makeText(context, "TEST", Toast.LENGTH_SHORT).show()
}
val formats = resultViewModel.getFormats(resultItem, type)
val formatTitles = formats.map {
if (it.format_note.contains("AUDIO_QUALITY_"))
it.format_note.replace("AUDIO_QUALITY_", "") +
if (it.filesize == 0L) "" else " / " + fileUtil.convertFileSize(it.filesize)
else it.format_note +
if (it.filesize == 0L) "" else " / " + fileUtil.convertFileSize(it.filesize)
}
val format = view.findViewById<TextInputLayout>(R.id.format)
val autoCompleteTextView =
view.findViewById<AutoCompleteTextView>(R.id.format_textview)
autoCompleteTextView?.setAdapter(
ArrayAdapter(
requireContext(),
android.R.layout.simple_dropdown_item_1line,
formatTitles
downloadItem.downloadPath = downloadPath!!
downloadViewModel.updateDownload(downloadItem)
saveDir.editText!!.setText(
fileUtil.formatPath(downloadPath)
)
)
if (formatTitles.isNotEmpty()){
autoCompleteTextView!!.setText(formatTitles[formats.lastIndex], false)
}
(format!!.editText as AutoCompleteTextView?)!!.onItemClickListener =
AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, index: Int, _: Long ->
downloadItem.formatDesc = formats[index].format_note
downloadItem.audioFormatId = formats[index].format_id
saveDir.editText!!.isFocusable = false;
saveDir.editText!!.isClickable = true;
saveDir.editText!!.setOnClickListener {
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)
audioPathResultLauncher.launch(intent)
}
val containers = requireContext().resources.getStringArray(R.array.audio_containers)
val container = view.findViewById<TextInputLayout>(R.id.downloadContainer)
val containerAutoCompleteTextView =
view.findViewById<AutoCompleteTextView>(R.id.container_textview)
val formats = withContext(Dispatchers.IO){
resultViewModel.getFormats(resultItem, type)
}
val format = view.findViewById<TextInputLayout>(R.id.format)
if (formats.isEmpty()) {
format.visibility = View.GONE
} else {
val formatTitles = formats.map {
if (it.format_note.contains("AUDIO_QUALITY_")) {
it.format_note.replace(
"AUDIO_QUALITY_",
""
) + if (it.filesize == 0L) "" else " / " + fileUtil.convertFileSize(it.filesize)
} else {
it.format_note + if (it.filesize == 0L) "" else " / " + fileUtil.convertFileSize(
it.filesize
)
}
}
container?.isEnabled = true
containerAutoCompleteTextView?.setAdapter(
ArrayAdapter(
requireContext(),
android.R.layout.simple_dropdown_item_1line,
containers
)
)
val selectedContainer: String = formats.find { downloadItem.formatDesc == it.format_note }?.container
?: sharedPreferences.getString("audio_format", "mp3")!!
containerAutoCompleteTextView!!.setText(selectedContainer, false)
(container!!.editText as AutoCompleteTextView?)!!.onItemClickListener =
AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, index: Int, _: Long ->
downloadItem.ext = containers[index]
val autoCompleteTextView =
view.findViewById<AutoCompleteTextView>(R.id.format_textview)
autoCompleteTextView?.setAdapter(
ArrayAdapter(
requireContext(),
android.R.layout.simple_dropdown_item_1line,
formatTitles
)
)
if (formatTitles.isNotEmpty()) {
autoCompleteTextView!!.setText(formatTitles[formats.lastIndex], false)
}
(format!!.editText as AutoCompleteTextView?)!!.onItemClickListener =
AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, index: Int, _: Long ->
downloadItem.formatDesc = formats[index].format_note
downloadItem.audioFormatId = formats[index].format_id
}
}
}catch (e : Exception){
e.printStackTrace()
val containers = requireContext().resources.getStringArray(R.array.audio_containers)
val container = view.findViewById<TextInputLayout>(R.id.downloadContainer)
val containerAutoCompleteTextView =
view.findViewById<AutoCompleteTextView>(R.id.container_textview)
container?.isEnabled = true
containerAutoCompleteTextView?.setAdapter(
ArrayAdapter(
requireContext(),
android.R.layout.simple_dropdown_item_1line,
containers
)
)
val selectedContainer: String = formats.find { downloadItem.formatDesc == it.format_note }?.container
?: sharedPreferences.getString("audio_format", "mp3")!!
containerAutoCompleteTextView!!.setText(selectedContainer, false)
(container!!.editText as AutoCompleteTextView?)!!.onItemClickListener =
AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, index: Int, _: Long ->
downloadItem.ext = containers[index]
}
val cancelBtn = view.findViewById<MaterialButton>(R.id.bottomsheet_cancel_button)
cancelBtn.setOnClickListener{
(parentFragmentManager.findFragmentByTag("bottomSheet") as DownloadBottomSheetDialog).dismissSelf()
}
val download = view.findViewById<Button>(R.id.bottomsheet_download_button)
download!!.setOnClickListener {
// for (i in selectedObjects!!.indices) {
// val vid = findVideo(
// selectedObjects!![i]!!.getURL()
// )
// vid!!.downloadedType = type
// updateDownloadingStatusOnResult(vid, type, true)
// homeAdapter!!.notifyItemChanged(resultsList!!.indexOf(vid))
// downloadQueue!!.add(vid)
// }
// selectedObjects = ArrayList()
// homeAdapter!!.clearCheckedVideos()
// downloadFabs!!.visibility = View.GONE
// if (isStoragePermissionGranted) {
// mainActivity!!.startDownloadService(downloadQueue, listener)
// downloadQueue!!.clear()
// }
(parentFragmentManager.findFragmentByTag("bottomSheet") as DownloadBottomSheetDialog).dismissSelf()
}
}catch (e : Exception){
e.printStackTrace()
}
}
}
private var audioPathResultLauncher = 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
)
}
downloadItem.downloadPath = result.data?.data.toString()
downloadViewModel.updateDownload(downloadItem)
saveDir.editText?.setText(fileUtil.formatPath(result.data?.data.toString()), TextView.BufferType.EDITABLE)
}
}
}

View file

@ -4,17 +4,15 @@ import android.annotation.SuppressLint
import android.app.Dialog
import android.content.DialogInterface
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.widget.Toast
import androidx.core.view.get
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentTransaction
import androidx.fragment.app.findFragment
import androidx.lifecycle.ViewModelProvider
import androidx.viewpager2.widget.ViewPager2
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.google.android.material.tabs.TabLayout
@ -42,6 +40,7 @@ class DownloadBottomSheetDialog(item: DownloadItem) : BottomSheetDialogFragment(
val fragmentManager = parentFragmentManager
fragmentAdapter = DownloadFragmentAdapter(downloadItem, fragmentManager, lifecycle)
viewPager2.adapter = fragmentAdapter
viewPager2.isSaveFromParentEnabled = false
when(downloadItem.type) {
"audio" -> {
@ -80,6 +79,12 @@ class DownloadBottomSheetDialog(item: DownloadItem) : BottomSheetDialogFragment(
override fun onCancel(dialog: DialogInterface) {
super.onCancel(dialog)
parentFragmentManager.beginTransaction().remove(parentFragmentManager.findFragmentByTag("bottomSheet")!!).commit()
for (i in 0 until viewPager2.adapter?.itemCount!!){
if (parentFragmentManager.findFragmentByTag("f${i}") != null){
parentFragmentManager.beginTransaction().remove(parentFragmentManager.findFragmentByTag("f$i")!!).commit()
}
}
downloadViewModel.deleteDownload(downloadItem)
}

View file

@ -1,11 +1,13 @@
package com.deniscerri.ytdlnis.ui.downloadcard
import android.util.Log
import androidx.annotation.NonNull
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.Lifecycle
import androidx.viewpager2.adapter.FragmentStateAdapter
import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.google.gson.Gson
class DownloadFragmentAdapter (item : DownloadItem, fragmentManager : FragmentManager, lifecycle : Lifecycle) : FragmentStateAdapter(fragmentManager, lifecycle) {
private val downloadItem = item
@ -18,14 +20,19 @@ class DownloadFragmentAdapter (item : DownloadItem, fragmentManager : FragmentMa
when (position) {
0 -> {
downloadItem.type = "audio"
return DownloadAudioFragment(downloadItem)
return DownloadAudioFragment(clone(downloadItem))
}
1 -> {
downloadItem.type = "video"
return DownloadVideoFragment(downloadItem)
return DownloadVideoFragment(clone(downloadItem))
}
}
downloadItem.type = "command"
return DownloadCommandFragment(downloadItem)
return DownloadCommandFragment(clone(downloadItem))
}
private fun clone(item: DownloadItem) : DownloadItem {
val stringItem = Gson().toJson(item, DownloadItem::class.java)
return Gson().fromJson(stringItem, DownloadItem::class.java)
}
}

View file

@ -1,6 +1,7 @@
package com.deniscerri.ytdlnis.ui.downloadcard
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
@ -8,8 +9,10 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.*
import androidx.activity.result.contract.ActivityResultContracts
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.deniscerri.ytdlnis.MainActivity
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.models.DownloadItem
@ -17,10 +20,14 @@ import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding
import com.deniscerri.ytdlnis.util.FileUtil
import com.google.android.material.button.MaterialButton
import com.google.android.material.chip.Chip
import com.google.android.material.textfield.TextInputLayout
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class DownloadVideoFragment(item: DownloadItem) : Fragment() {
class DownloadVideoFragment(private val downloadItem: DownloadItem) : Fragment() {
private var _binding : FragmentHomeBinding? = null
private var fragmentView: View? = null
private var activity: Activity? = null
@ -28,8 +35,28 @@ class DownloadVideoFragment(item: DownloadItem) : Fragment() {
private lateinit var resultViewModel : ResultViewModel
private lateinit var downloadViewModel : DownloadViewModel
private lateinit var fileUtil : FileUtil
private val downloadItem = item
private lateinit var title : TextInputLayout
private lateinit var author : TextInputLayout
private lateinit var saveDir : TextInputLayout
override fun onResume() {
super.onResume()
lifecycleScope.launch{
val item = withContext(Dispatchers.IO){
downloadViewModel.getItemByID(downloadItem.id)
}
if (::title.isInitialized){
title.editText!!.setText(item.title)
downloadItem.title = item.title
}
if(::author.isInitialized){
author.editText!!.setText(item.author)
downloadItem.author = item.author
}
}
downloadViewModel.updateDownload(downloadItem)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@ -45,122 +72,135 @@ class DownloadVideoFragment(item: DownloadItem) : Fragment() {
return fragmentView
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val resultItem = resultViewModel.getItemByURL(downloadItem.url)
val type = downloadItem.type
lifecycleScope.launch {
val resultItem = withContext(Dispatchers.IO){
resultViewModel.getItemByURL(downloadItem.url)
}
val type = downloadItem.type
val sharedPreferences = requireContext().getSharedPreferences("root_preferences", Activity.MODE_PRIVATE)
val editor = sharedPreferences.edit()
val sharedPreferences = requireContext().getSharedPreferences("root_preferences", Activity.MODE_PRIVATE)
val editor = sharedPreferences.edit()
try {
val title = view.findViewById<TextInputLayout>(R.id.title_textinput)
title!!.editText!!.setText(downloadItem.title)
title.editText!!.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
override fun afterTextChanged(p0: Editable?) {
downloadItem.title = p0.toString()
resultItem.title = p0.toString()
resultViewModel.update(resultItem)
downloadViewModel.updateDownload(downloadItem)
}
})
try {
title = view.findViewById(R.id.title_textinput)
title.editText!!.setText(downloadItem.title)
title.editText!!.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
override fun afterTextChanged(p0: Editable?) {
downloadItem.title = p0.toString()
resultItem.title = p0.toString()
resultViewModel.update(resultItem)
downloadViewModel.updateDownload(downloadItem)
}
})
val author = view.findViewById<TextInputLayout>(R.id.author_textinput)
author!!.editText!!.setText(downloadItem.author)
author.editText!!.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
override fun afterTextChanged(p0: Editable?) {
downloadItem.author = p0.toString()
resultItem.author = p0.toString()
resultViewModel.update(resultItem)
downloadViewModel.updateDownload(downloadItem)
}
})
author = view.findViewById(R.id.author_textinput)
author.editText!!.setText(downloadItem.author)
author.editText!!.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
override fun afterTextChanged(p0: Editable?) {
downloadItem.author = p0.toString()
resultItem.author = p0.toString()
resultViewModel.update(resultItem)
downloadViewModel.updateDownload(downloadItem)
}
})
val saveDir = view.findViewById<TextInputLayout>(R.id.outputPath)
saveDir!!.editText!!.setText(
sharedPreferences.getString(
saveDir = view.findViewById(R.id.outputPath)
val downloadPath = sharedPreferences.getString(
"video_path",
getString(R.string.video_path)
)
)
saveDir.editText!!.isFocusable = false;
saveDir.editText!!.isClickable = true;
saveDir.editText!!.setOnClickListener {
Toast.makeText(context, "TEST", Toast.LENGTH_SHORT).show()
}
downloadItem.downloadPath = downloadPath!!
downloadViewModel.updateDownload(downloadItem)
saveDir.editText!!.setText(
fileUtil.formatPath(downloadPath)
)
saveDir.editText!!.isFocusable = false;
saveDir.editText!!.isClickable = true;
saveDir.editText!!.setOnClickListener {
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)
videoPathResultLauncher.launch(intent)
}
val formats = resultViewModel.getFormats(resultItem, type)
val formats = withContext(Dispatchers.IO){
resultViewModel.getFormats(resultItem, type)
}
val formatTitles = formats.map {
if (it.format_note.contains("AUDIO_QUALITY_"))
it.format_note.replace("AUDIO_QUALITY_", "") +
val formatTitles = formats.map {
if (it.format_note.contains("AUDIO_QUALITY_"))
it.format_note.replace("AUDIO_QUALITY_", "") +
if (it.filesize == 0L) "" else " / " + fileUtil.convertFileSize(it.filesize)
else it.format_note +
if (it.filesize == 0L) "" else " / " + fileUtil.convertFileSize(it.filesize)
else it.format_note +
if (it.filesize == 0L) "" else " / " + fileUtil.convertFileSize(it.filesize)
}
val format = view.findViewById<TextInputLayout>(R.id.format)
val autoCompleteTextView =
view.findViewById<AutoCompleteTextView>(R.id.format_textview)
autoCompleteTextView?.setAdapter(
ArrayAdapter(
requireContext(),
android.R.layout.simple_dropdown_item_1line,
formatTitles
)
)
if (formatTitles.isNotEmpty()) {
autoCompleteTextView!!.setText(formatTitles[formats.lastIndex], false)
}
(format!!.editText as AutoCompleteTextView?)!!.onItemClickListener =
AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, index: Int, _: Long ->
downloadItem.formatDesc = formats[index].format_note
downloadItem.videoFormatId = formats[index].format_id
}
val containers = requireContext().resources.getStringArray(R.array.video_containers)
val container = view.findViewById<TextInputLayout>(R.id.downloadContainer)
val containerAutoCompleteTextView =
view.findViewById<AutoCompleteTextView>(R.id.container_textview)
container?.isEnabled = true
containerAutoCompleteTextView?.setAdapter(
ArrayAdapter(
requireContext(),
android.R.layout.simple_dropdown_item_1line,
containers
val format = view.findViewById<TextInputLayout>(R.id.format)
val autoCompleteTextView =
view.findViewById<AutoCompleteTextView>(R.id.format_textview)
autoCompleteTextView?.setAdapter(
ArrayAdapter(
requireContext(),
android.R.layout.simple_dropdown_item_1line,
formatTitles
)
)
)
val selectedContainer: String =
formats.find { downloadItem.formatDesc == it.format_note }?.container
?: sharedPreferences.getString("video_format", "DEFAULT")!!
containerAutoCompleteTextView!!.setText(selectedContainer, false)
(container!!.editText as AutoCompleteTextView?)!!.onItemClickListener =
AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, index: Int, _: Long ->
downloadItem.ext = containers[index]
if (formatTitles.isNotEmpty()) {
autoCompleteTextView!!.setText(formatTitles[formats.lastIndex], false)
}
(format!!.editText as AutoCompleteTextView?)!!.onItemClickListener =
AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, index: Int, _: Long ->
downloadItem.formatDesc = formats[index].format_note
downloadItem.videoFormatId = formats[index].format_id
}
val embedSubs = view.findViewById<Chip>(R.id.embed_subtitles)
val containers = requireContext().resources.getStringArray(R.array.video_containers)
val container = view.findViewById<TextInputLayout>(R.id.downloadContainer)
val containerAutoCompleteTextView =
view.findViewById<AutoCompleteTextView>(R.id.container_textview)
container?.isEnabled = true
containerAutoCompleteTextView?.setAdapter(
ArrayAdapter(
requireContext(),
android.R.layout.simple_dropdown_item_1line,
containers
)
)
val selectedContainer: String =
formats.find { downloadItem.formatDesc == it.format_note }?.container
?: sharedPreferences.getString("video_format", "DEFAULT")!!
containerAutoCompleteTextView!!.setText(selectedContainer, false)
(container!!.editText as AutoCompleteTextView?)!!.onItemClickListener =
AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, index: Int, _: Long ->
downloadItem.ext = containers[index]
}
val embedSubs = view.findViewById<Chip>(R.id.embed_subtitles)
embedSubs!!.isChecked = sharedPreferences.getBoolean("embed_subtitles", false)
val addChapters = view.findViewById<Chip>(R.id.add_chapters)
addChapters!!.isChecked = sharedPreferences.getBoolean("add_chapters", false)
val addChapters = view.findViewById<Chip>(R.id.add_chapters)
addChapters!!.isChecked = sharedPreferences.getBoolean("add_chapters", false)
val saveThumbnail = view.findViewById<Chip>(R.id.save_thumbnail)
saveThumbnail!!.isChecked = sharedPreferences.getBoolean("write_thumbnail", false)
val saveThumbnail = view.findViewById<Chip>(R.id.save_thumbnail)
saveThumbnail!!.isChecked = sharedPreferences.getBoolean("write_thumbnail", false)
val cancel = view.findViewById<Button>(R.id.bottomsheet_cancel_button)
cancel!!.setOnClickListener {
parentFragmentManager.popBackStack()
}
val download = view.findViewById<Button>(R.id.bottomsheet_download_button)
download!!.setOnClickListener {
val cancel = view.findViewById<Button>(R.id.bottomsheet_cancel_button)
cancel!!.setOnClickListener {
(parentFragmentManager.findFragmentByTag("bottomSheet") as DownloadBottomSheetDialog).dismissSelf()
}
val download = view.findViewById<Button>(R.id.bottomsheet_download_button)
download!!.setOnClickListener {
// for (i in selectedObjects!!.indices) {
// val vid = findVideo(
// selectedObjects!![i]!!.getURL()
@ -177,11 +217,29 @@ class DownloadVideoFragment(item: DownloadItem) : Fragment() {
// mainActivity!!.startDownloadService(downloadQueue, listener)
// downloadQueue!!.clear()
// }
parentFragmentManager.popBackStack()
}
(parentFragmentManager.findFragmentByTag("bottomSheet") as DownloadBottomSheetDialog).dismissSelf()
}
} catch (e: Exception) {
e.printStackTrace()
} catch (e: Exception) {
e.printStackTrace()
}
}
}
private var videoPathResultLauncher = 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
)
}
downloadItem.downloadPath = result.data?.data.toString()
downloadViewModel.updateDownload(downloadItem)
saveDir.editText?.setText(fileUtil.formatPath(result.data?.data.toString()), TextView.BufferType.EDITABLE)
}
}
}

View file

@ -313,8 +313,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
}
private fun changePath(p: Preference?, data: Intent?, requestCode: Int) {
Log.e("TEST", data!!.toUri(0))
val path = data.data.toString()
val path = data!!.data.toString()
p!!.summary = fileUtil?.formatPath(data.data.toString())
val sharedPreferences =
requireContext().getSharedPreferences("root_preferences", Activity.MODE_PRIVATE)

View file

@ -32,6 +32,7 @@ class FileUtil() {
fun formatPath(path: String) : String {
var dataValue = path
if (dataValue.startsWith("/storage/")) return dataValue
dataValue = dataValue.replace("content://com.android.externalstorage.documents/tree/", "")
dataValue = dataValue.replace("%3A".toRegex(), "/")
try {
@ -123,7 +124,7 @@ class FileUtil() {
}
fun convertFileSize(s: Long): String{
if (s <= 0) return "0"
if (s <= 0) return "?"
val units = arrayOf("B", "kB", "MB", "GB", "TB")
val digitGroups = (log10(s.toDouble()) / log10(1024.0)).toInt()
return DecimalFormat("#,##0.#").format(s / 1024.0.pow(digitGroups.toDouble())) + " " + units[digitGroups]

View file

@ -474,11 +474,7 @@ class InfoUtil(context: Context) {
} catch (e: Exception) {
arrayOf(youtubeDLResponse.out)
}
var isPlaylist = 0
val pl = JSONObject(results[0]!!)
if (pl.has("playlist")) {
if (pl.getString("playlist") != query) isPlaylist = 1
}
for (result in results) {
val jsonObject = JSONObject(result!!)
val title = if (jsonObject.has("title")) {
@ -506,6 +502,7 @@ class InfoUtil(context: Context) {
val website = if (jsonObject.has("ie_key")) jsonObject.getString("ie_key") else jsonObject.getString("extractor")
var playlistTitle: String? = ""
if (jsonObject.has("playlist_title")) playlistTitle = jsonObject.getString("playlist_title")
if(playlistTitle.equals(query)) playlistTitle = ""
val formatsInJSON = if (jsonObject.has("formats")) jsonObject.getJSONArray("formats") else null
val formats : ArrayList<Format> = ArrayList()
if (formatsInJSON != null) {

View file

@ -8,17 +8,8 @@
<TextView
android:id="@+id/bottom_sheet_title"
android:layout_width="wrap_content"
android:textSize="20sp"
android:paddingTop="10dp"
android:layout_gravity="center"
android:layout_height="wrap_content"
android:text="@string/download" />
<TextView
android:id="@+id/bottom_sheet_subtitle"
android:layout_width="wrap_content"
android:textSize="15sp"
android:paddingBottom="10dp"
android:textSize="25sp"
android:padding="20dp"
android:layout_gravity="center"
android:layout_height="wrap_content"
android:text="@string/configure_download" />

View file

@ -78,7 +78,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="10dp"
android:hint="@string/format">
android:hint="@string/audio_format">
<AutoCompleteTextView
android:id="@+id/format_textview"

View file

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<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_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
@ -78,7 +77,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="10dp"
android:hint="@string/format">
android:hint="@string/video_format">
<AutoCompleteTextView
android:id="@+id/format_textview"

View file

@ -78,7 +78,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="10dp"
android:hint="@string/format">
android:hint="@string/video_format">
<AutoCompleteTextView
android:id="@+id/format_textview"

View file

@ -23,7 +23,6 @@
android:layout_height="wrap_content"
android:text="@string/configure_download" />
<include layout="@layout/home_download_settings_components" />
<View style="@style/Divider.Horizontal"/>

View file

@ -1,153 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/title_textinput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
app:errorEnabled="true"
android:hint="@string/title"
style="@style/Widget.Material3.TextInputLayout.FilledBox">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:inputType="text"
android:layout_height="wrap_content"
/>
</com.google.android.material.textfield.TextInputLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/author_textinput"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="40"
app:errorEnabled="true"
android:hint="@string/author"
style="@style/Widget.Material3.TextInputLayout.FilledBox">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:inputType="text"
android:layout_height="wrap_content"
/>
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/downloadContainer"
style="@style/Widget.Material3.TextInputLayout.FilledBox.ExposedDropdownMenu"
android:layout_width="0dp"
android:layout_weight="45"
android:paddingStart="10dp"
android:layout_height="wrap_content"
android:hint="@string/container">
<AutoCompleteTextView
android:id="@+id/container_textview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="none"
app:simpleItems="@array/audio_containers"
/>
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/format"
style="@style/Widget.Material3.TextInputLayout.FilledBox.ExposedDropdownMenu"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="20dp"
android:hint="@string/format">
<AutoCompleteTextView
android:id="@+id/format_textview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="none"
app:simpleItems="@array/video_formats"
/>
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/outputPath"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:errorEnabled="true"
android:hint="@string/save_dir"
style="@style/Widget.Material3.TextInputLayout.FilledBox">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:inputType="text"
android:layout_height="wrap_content"/>
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.chip.ChipGroup
android:id="@+id/downloadChipGroup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:selectionRequired="true"
app:singleLine="true"
app:singleSelection="true">
<com.google.android.material.chip.Chip
android:id="@+id/audioChip"
style="@style/Widget.Material3.Chip.Assist"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checkable="true"
app:checkedIcon="@drawable/ic_check"
android:text="@string/audio"
app:chipIcon="@drawable/ic_music" />
<com.google.android.material.chip.Chip
android:id="@+id/videoChip"
style="@style/Widget.Material3.Chip.Assist"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/video"
android:checkable="true"
app:checkedIcon="@drawable/ic_check"
app:chipIcon="@drawable/ic_video" />
<com.google.android.material.chip.Chip
android:id="@+id/commandChip"
style="@style/Widget.Material3.Chip.Assist"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/run_command"
android:checkable="true"
app:checkedIcon="@drawable/ic_check"
app:chipIcon="@drawable/ic_baseline_keyboard_arrow_right_24" />
</com.google.android.material.chip.ChipGroup>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -1,85 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout android:id="@+id/history_element_bottom_sheet"
style="@style/Widget.Material3.BottomSheet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:orientation="vertical"
>
<TextView
android:id="@+id/bottom_sheet_title"
android:layout_width="wrap_content"
android:textSize="25sp"
android:textColor="?attr/colorOnSurface"
android:layout_height="wrap_content"
android:text="@string/download" />
<include layout="@layout/home_download_settings_components" />
<View style="@style/Divider.Horizontal"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:paddingTop="10dp"
android:orientation="horizontal">
<Button
style="@style/Widget.Material3.Button.ElevatedButton.Icon"
android:textSize="11sp"
android:id="@+id/bottomsheet_schedule_button"
android:padding="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
app:icon="@drawable/ic_clock"
android:text="@string/schedule" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="bottom"
android:gravity="end"
android:orientation="horizontal">
<Button
style="@style/Widget.Material3.Button.OutlinedButton.Icon"
android:textSize="11sp"
android:padding="10dp"
android:id="@+id/bottomsheet_cancel_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/cancel"
android:layout_marginEnd="10dp"
app:icon="@drawable/ic_cancel" />
<Button
style="@style/Widget.Material3.Button.ElevatedButton.Icon"
android:textSize="11sp"
android:padding="10dp"
android:id="@+id/bottomsheet_download_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/download"
app:icon="@drawable/ic_down"
android:autoLink="all"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</FrameLayout>

View file

@ -65,9 +65,9 @@
<string name="choose_range_desc">Pick a range to download from the playlist (to not download everything).</string>
<string name="last_cant_be_smaller_than_first">Last index cannot be smaller than the first.</string>
<string name="first_cant_be_larger_than_last">First index cannot be larger than the last.</string>
<string name="music_path" translatable="false">/storage/emulated/0/Download/YTDLnis/Audio</string>
<string name="video_path" translatable="false">/storage/emulated/0/Download/YTDLnis/Video</string>
<string name="command_path" translatable="false">/storage/emulated/0/Download/YTDLnis/Command</string>
<string name="music_path" translatable="false">content://com.android.externalstorage.documents/tree/primary%3ADownload%2FYTDLnis%2FAudio</string>
<string name="video_path" translatable="false">content://com.android.externalstorage.documents/tree/primary%3ADownload%2FYTDLnis%2FVideo</string>
<string name="command_path" translatable="false">content://com.android.externalstorage.documents/tree/primary%3ADownload%2FYTDLnis%2FCommand</string>
<string name="concurrent_fragments_summary">Number of fragments of a DASH/HLS native video to download concurrently</string>
<string name="concurrent_fragments">Concurrent Fragments</string>
<string name="downloading">Downloading</string>
@ -163,7 +163,6 @@
<string name="best">Best</string>
<string name="worst">Worst</string>
<string name="defaultValue">Default</string>
<string name="format">Format</string>
<string name="container">Container</string>
<string name="template">Template</string>
<string name="history">History</string>