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> </value>
</option> </option>
</component> </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" /> <output url="file://$PROJECT_DIR$/build/classes" />
</component> </component>
<component name="ProjectType"> <component name="ProjectType">

View file

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

View file

@ -2,11 +2,11 @@
"formatVersion": 1, "formatVersion": 1,
"database": { "database": {
"version": 1, "version": 1,
"identityHash": "94d37ae85390ef5198651df2480a02bf", "identityHash": "2c0fdec170ca54d97ef928dfe28a6992",
"entities": [ "entities": [
{ {
"tableName": "results", "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": [ "fields": [
{ {
"fieldPath": "id", "fieldPath": "id",
@ -55,6 +55,12 @@
"columnName": "playlistTitle", "columnName": "playlistTitle",
"affinity": "TEXT", "affinity": "TEXT",
"notNull": true "notNull": true
},
{
"fieldPath": "creationTime",
"columnName": "creationTime",
"affinity": "INTEGER",
"notNull": true
} }
], ],
"primaryKey": { "primaryKey": {
@ -386,7 +392,7 @@
"views": [], "views": [],
"setupQueries": [ "setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", "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, DBManager::class.java,
"YTDLnisDatabase" "YTDLnisDatabase"
) )
.allowMainThreadQueries()
.build() .build()
instance = dbInstance instance = dbInstance
dbInstance dbInstance

View file

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

View file

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

View file

@ -2,6 +2,7 @@ package com.deniscerri.ytdlnis.database.models
import androidx.room.Entity import androidx.room.Entity
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import java.util.*
@Entity(tableName = "results") @Entity(tableName = "results")
data class ResultItem( data class ResultItem(
@ -13,5 +14,6 @@ data class ResultItem(
val duration: String, val duration: String,
val thumb: String, val thumb: String,
val website: 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); update(item);
} }
fun getLatest() : DownloadItem { fun getItemByID(id: Long) : DownloadItem {
return downloadDao.getLatest() return downloadDao.getDownloadById(id)
} }
} }

View file

@ -45,7 +45,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
repository.update(item); repository.update(item);
} }
fun getLatest() : DownloadItem { fun getItemByID(id: Long) : DownloadItem {
return repository.getLatest() 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!!) filter(queryFilter.value!!, formatFilter.value!!, websiteFilter.value!!, sortType.value!!)
}) })
_items.addSource(formatFilter, Observer { _items.addSource(formatFilter, Observer {
Log.e("aa", "audio");
filter(queryFilter.value!!, formatFilter.value!!, websiteFilter.value!!, sortType.value!!) filter(queryFilter.value!!, formatFilter.value!!, websiteFilter.value!!, sortType.value!!)
}) })
_items.addSource(sortType, Observer { _items.addSource(sortType, Observer {
Log.e("aa", "asssssssssssss");
filter(queryFilter.value!!, formatFilter.value!!, websiteFilter.value!!, sortType.value!!) filter(queryFilter.value!!, formatFilter.value!!, websiteFilter.value!!, sortType.value!!)
}) })
_items.addSource(websiteFilter, Observer { _items.addSource(websiteFilter, Observer {
Log.e("Aa", "website")
filter(queryFilter.value!!, formatFilter.value!!, websiteFilter.value!!, sortType.value!!) filter(queryFilter.value!!, formatFilter.value!!, websiteFilter.value!!, sortType.value!!)
}) })
_items.addSource(queryFilter, Observer { _items.addSource(queryFilter, Observer {
@ -56,7 +53,6 @@ class HistoryViewModel(application: Application) : AndroidViewModel(application)
} }
fun setSorting(sort: HistorySort){ fun setSorting(sort: HistorySort){
Log.e("aa", "asssssssssssss");
sortType.value = sort sortType.value = sort
} }
@ -69,7 +65,6 @@ class HistoryViewModel(application: Application) : AndroidViewModel(application)
} }
fun setFormatFilter(filter: String){ fun setFormatFilter(filter: String){
Log.e("aa", "audio");
formatFilter.value = filter formatFilter.value = filter
} }

View file

@ -34,7 +34,12 @@ class ResultViewModel(application: Application) : AndroidViewModel(application)
fun checkTrending() = viewModelScope.launch(Dispatchers.IO){ fun checkTrending() = viewModelScope.launch(Dispatchers.IO){
try { try {
val item = repository.getFirstResult() 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){ }catch (e : Exception){
getTrending() getTrending()
} }
@ -58,7 +63,6 @@ class ResultViewModel(application: Application) : AndroidViewModel(application)
} else if (inputQuery!!.contains("http")) { } else if (inputQuery!!.contains("http")) {
type = "Default" type = "Default"
} }
Log.e(tag, "$inputQuery $type")
try { try {
when (type) { when (type) {
"Search" -> { "Search" -> {
@ -102,12 +106,7 @@ class ResultViewModel(application: Application) : AndroidViewModel(application)
when(type){ when(type){
"audio" -> { "audio" -> {
list = list.filter { it.format_note.contains("audio", ignoreCase = true) } return 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
} }
"video" -> { "video" -> {
list = list.filter { !it.format_note.contains("audio", ignoreCase = true) } 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.facebook.shimmer.ShimmerFrameLayout
import com.google.android.material.appbar.AppBarLayout import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.appbar.MaterialToolbar 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.bottomsheet.BottomSheetDialog
import com.google.android.material.button.MaterialButton import com.google.android.material.button.MaterialButton
import com.google.android.material.chip.ChipGroup 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 selectedObjects: ArrayList<ResultItem>? = null
private var deleteFab: ExtendedFloatingActionButton? = null private var deleteFab: ExtendedFloatingActionButton? = null
private var fileUtil: FileUtil? = null private var fileUtil: FileUtil? = null
private var firstBoot = true
private var _binding : FragmentHomeBinding? = null private var _binding : FragmentHomeBinding? = null
@ -144,10 +146,15 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
homeAdapter!!.submitList(it) homeAdapter!!.submitList(it)
resultsList = it resultsList = it
if(it.size > 1){ 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 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){ resultViewModel.loadingItems.observe(viewLifecycleOwner){
@ -349,9 +356,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
// selectedObjects!!.clear() // selectedObjects!!.clear()
// selectedObjects!!.add(item!!) // selectedObjects!!.add(item!!)
//showConfigureSingleDownloadCard(createDownloadItem(item!!, type), item) //showConfigureSingleDownloadCard(createDownloadItem(item!!, type), item)
createDownloadItem(item!!, type){ showSingleDownloadSheet(item!!, type)
showSingleDownloadSheet(it)
}
} else { } else {
// downloadQueue!!.add(vid) // downloadQueue!!.add(vid)
// updateDownloadingStatusOnResult(vid, type, true) // updateDownloadingStatusOnResult(vid, type, true)
@ -362,12 +367,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
} }
} }
private fun showSingleDownloadSheet(item : DownloadItem){ private fun showSingleDownloadSheet(resultItem : ResultItem, type: String){
val bottomSheet = DownloadBottomSheetDialog(item)
bottomSheet.show(parentFragmentManager, null)
}
private fun createDownloadItem(item: ResultItem, type: String, itemCreated: (DownloadItem) -> Unit) : DownloadItem {
val sharedPreferences = val sharedPreferences =
requireContext().getSharedPreferences("root_preferences", Activity.MODE_PRIVATE) requireContext().getSharedPreferences("root_preferences", Activity.MODE_PRIVATE)
val embedSubs = sharedPreferences.getBoolean("embed_subtitles", false) val embedSubs = sharedPreferences.getBoolean("embed_subtitles", false)
@ -376,22 +376,22 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
val downloadItem = DownloadItem(0, val downloadItem = DownloadItem(0,
item.url, resultItem.url,
item.title, resultItem.title,
item.author, resultItem.author,
item.thumb, resultItem.thumb,
item.duration, resultItem.duration,
type, type,
"", "", 0, "", false, "", "", 0, "", false,
"", item.website, "", item.playlistTitle, embedSubs, addChapters, saveThumb, "", "", resultItem.website, "", resultItem.playlistTitle, embedSubs, addChapters, saveThumb, "",
"", DownloadRepository.status.Processing.toString(), 0 "", DownloadRepository.status.Processing.toString(), 0
) )
downloadViewModel.insertDownload(downloadItem).observe(viewLifecycleOwner) { downloadViewModel.insertDownload(downloadItem).observe(viewLifecycleOwner) {
downloadItem.id = it 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 package com.deniscerri.ytdlnis.ui.downloadcard
import android.app.Activity import android.app.Activity
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.text.Editable import android.text.Editable
import android.text.TextWatcher import android.text.TextWatcher
@ -8,33 +9,56 @@ import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.Window import android.widget.*
import android.widget.AdapterView import androidx.activity.result.contract.ActivityResultContracts
import android.widget.ArrayAdapter
import android.widget.AutoCompleteTextView
import android.widget.Toast
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.deniscerri.ytdlnis.MainActivity import com.deniscerri.ytdlnis.MainActivity
import com.deniscerri.ytdlnis.R import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.models.DownloadItem import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.ResultItem import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding
import com.deniscerri.ytdlnis.ui.HomeFragment
import com.deniscerri.ytdlnis.util.FileUtil 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 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 _binding : FragmentHomeBinding? = null
private var fragmentView: View? = null private var fragmentView: View? = null
private var activity: Activity? = null private var activity: Activity? = null
private var mainActivity: MainActivity? = null private var mainActivity: MainActivity? = null
private lateinit var resultViewModel : ResultViewModel private lateinit var resultViewModel : ResultViewModel
private lateinit var downloadViewModel : DownloadViewModel
private lateinit var fileUtil : FileUtil 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( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
@ -46,109 +70,176 @@ class DownloadAudioFragment(item: DownloadItem) : Fragment() {
activity = getActivity() activity = getActivity()
mainActivity = activity as MainActivity? mainActivity = activity as MainActivity?
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java] resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
fileUtil = FileUtil() fileUtil = FileUtil()
return fragmentView return fragmentView
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
lifecycleScope.launch {
val resultItem = resultViewModel.getItemByURL(downloadItem.url) val resultItem = withContext(Dispatchers.IO){
val type = downloadItem.type resultViewModel.getItemByURL(downloadItem.url)
}
val type = downloadItem.type
val sharedPreferences = val sharedPreferences =
requireContext().getSharedPreferences("root_preferences", Activity.MODE_PRIVATE) requireContext().getSharedPreferences("root_preferences", Activity.MODE_PRIVATE)
try { try {
val title = view.findViewById<TextInputLayout>(R.id.title_textinput) title = view.findViewById(R.id.title_textinput)
title!!.editText!!.setText(downloadItem.title) title.editText!!.setText(downloadItem.title)
title.editText!!.addTextChangedListener(object : TextWatcher { title.editText!!.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {} override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {} override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
override fun afterTextChanged(p0: Editable?) { override fun afterTextChanged(p0: Editable?) {
downloadItem.title = p0.toString() downloadItem.title = p0.toString()
resultItem.title = p0.toString() resultItem.title = p0.toString()
resultViewModel.update(resultItem) resultViewModel.update(resultItem)
} downloadViewModel.updateDownload(downloadItem)
}) }
})
val author = view.findViewById<TextInputLayout>(R.id.author_textinput) author = view.findViewById(R.id.author_textinput)
author!!.editText!!.setText(downloadItem.author) author.editText!!.setText(downloadItem.author)
author.editText!!.addTextChangedListener(object : TextWatcher { author.editText!!.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {} override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {} override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
override fun afterTextChanged(p0: Editable?) { override fun afterTextChanged(p0: Editable?) {
downloadItem.author = p0.toString() downloadItem.author = p0.toString()
resultItem.author = p0.toString() resultItem.author = p0.toString()
resultViewModel.update(resultItem) resultViewModel.update(resultItem)
} downloadViewModel.updateDownload(downloadItem)
}) }
})
val saveDir = view.findViewById<TextInputLayout>(R.id.outputPath) saveDir = view.findViewById(R.id.outputPath)
saveDir!!.editText!!.setText( val downloadPath = sharedPreferences.getString(
sharedPreferences.getString(
"music_path", "music_path",
getString(R.string.music_path) getString(R.string.music_path)
) )
) downloadItem.downloadPath = downloadPath!!
saveDir.editText!!.isFocusable = false; downloadViewModel.updateDownload(downloadItem)
saveDir.editText!!.isClickable = true; saveDir.editText!!.setText(
saveDir.editText!!.setOnClickListener { fileUtil.formatPath(downloadPath)
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
) )
) saveDir.editText!!.isFocusable = false;
if (formatTitles.isNotEmpty()){ saveDir.editText!!.isClickable = true;
autoCompleteTextView!!.setText(formatTitles[formats.lastIndex], false) saveDir.editText!!.setOnClickListener {
} val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
(format!!.editText as AutoCompleteTextView?)!!.onItemClickListener = intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, index: Int, _: Long -> intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
downloadItem.formatDesc = formats[index].format_note intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
downloadItem.audioFormatId = formats[index].format_id audioPathResultLauncher.launch(intent)
} }
val containers = requireContext().resources.getStringArray(R.array.audio_containers) val formats = withContext(Dispatchers.IO){
val container = view.findViewById<TextInputLayout>(R.id.downloadContainer) resultViewModel.getFormats(resultItem, type)
val containerAutoCompleteTextView = }
view.findViewById<AutoCompleteTextView>(R.id.container_textview) 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 val autoCompleteTextView =
containerAutoCompleteTextView?.setAdapter( view.findViewById<AutoCompleteTextView>(R.id.format_textview)
ArrayAdapter( autoCompleteTextView?.setAdapter(
requireContext(), ArrayAdapter(
android.R.layout.simple_dropdown_item_1line, requireContext(),
containers android.R.layout.simple_dropdown_item_1line,
) formatTitles
) )
val selectedContainer: String = formats.find { downloadItem.formatDesc == it.format_note }?.container )
?: sharedPreferences.getString("audio_format", "mp3")!! if (formatTitles.isNotEmpty()) {
containerAutoCompleteTextView!!.setText(selectedContainer, false) autoCompleteTextView!!.setText(formatTitles[formats.lastIndex], false)
(container!!.editText as AutoCompleteTextView?)!!.onItemClickListener = }
AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, index: Int, _: Long -> (format!!.editText as AutoCompleteTextView?)!!.onItemClickListener =
downloadItem.ext = containers[index] AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, index: Int, _: Long ->
downloadItem.formatDesc = formats[index].format_note
downloadItem.audioFormatId = formats[index].format_id
}
} }
}catch (e : Exception){ val containers = requireContext().resources.getStringArray(R.array.audio_containers)
e.printStackTrace() 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.app.Dialog
import android.content.DialogInterface import android.content.DialogInterface
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import androidx.fragment.app.FragmentTransaction
import android.widget.Toast import androidx.fragment.app.findFragment
import androidx.core.view.get
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
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.models.DownloadItem import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel 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.bottomsheet.BottomSheetDialogFragment
import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout
@ -42,6 +40,7 @@ class DownloadBottomSheetDialog(item: DownloadItem) : BottomSheetDialogFragment(
val fragmentManager = parentFragmentManager val fragmentManager = parentFragmentManager
fragmentAdapter = DownloadFragmentAdapter(downloadItem, fragmentManager, lifecycle) fragmentAdapter = DownloadFragmentAdapter(downloadItem, fragmentManager, lifecycle)
viewPager2.adapter = fragmentAdapter viewPager2.adapter = fragmentAdapter
viewPager2.isSaveFromParentEnabled = false
when(downloadItem.type) { when(downloadItem.type) {
"audio" -> { "audio" -> {
@ -80,6 +79,12 @@ class DownloadBottomSheetDialog(item: DownloadItem) : BottomSheetDialogFragment(
override fun onCancel(dialog: DialogInterface) { override fun onCancel(dialog: DialogInterface) {
super.onCancel(dialog) 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) downloadViewModel.deleteDownload(downloadItem)
} }

View file

@ -1,11 +1,13 @@
package com.deniscerri.ytdlnis.ui.downloadcard package com.deniscerri.ytdlnis.ui.downloadcard
import android.util.Log
import androidx.annotation.NonNull import androidx.annotation.NonNull
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.viewpager2.adapter.FragmentStateAdapter import androidx.viewpager2.adapter.FragmentStateAdapter
import com.deniscerri.ytdlnis.database.models.DownloadItem import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.google.gson.Gson
class DownloadFragmentAdapter (item : DownloadItem, fragmentManager : FragmentManager, lifecycle : Lifecycle) : FragmentStateAdapter(fragmentManager, lifecycle) { class DownloadFragmentAdapter (item : DownloadItem, fragmentManager : FragmentManager, lifecycle : Lifecycle) : FragmentStateAdapter(fragmentManager, lifecycle) {
private val downloadItem = item private val downloadItem = item
@ -18,14 +20,19 @@ class DownloadFragmentAdapter (item : DownloadItem, fragmentManager : FragmentMa
when (position) { when (position) {
0 -> { 0 -> {
downloadItem.type = "audio" downloadItem.type = "audio"
return DownloadAudioFragment(downloadItem) return DownloadAudioFragment(clone(downloadItem))
} }
1 -> { 1 -> {
downloadItem.type = "video" downloadItem.type = "video"
return DownloadVideoFragment(downloadItem) return DownloadVideoFragment(clone(downloadItem))
} }
} }
downloadItem.type = "command" 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 package com.deniscerri.ytdlnis.ui.downloadcard
import android.app.Activity import android.app.Activity
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.text.Editable import android.text.Editable
import android.text.TextWatcher import android.text.TextWatcher
@ -8,8 +9,10 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.* import android.widget.*
import androidx.activity.result.contract.ActivityResultContracts
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.deniscerri.ytdlnis.MainActivity import com.deniscerri.ytdlnis.MainActivity
import com.deniscerri.ytdlnis.R import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.models.DownloadItem 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.database.viewmodel.ResultViewModel
import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding
import com.deniscerri.ytdlnis.util.FileUtil 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.chip.Chip
import com.google.android.material.textfield.TextInputLayout 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 _binding : FragmentHomeBinding? = null
private var fragmentView: View? = null private var fragmentView: View? = null
private var activity: Activity? = null private var activity: Activity? = null
@ -28,8 +35,28 @@ class DownloadVideoFragment(item: DownloadItem) : Fragment() {
private lateinit var resultViewModel : ResultViewModel private lateinit var resultViewModel : ResultViewModel
private lateinit var downloadViewModel : DownloadViewModel private lateinit var downloadViewModel : DownloadViewModel
private lateinit var fileUtil : FileUtil 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( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
@ -45,122 +72,135 @@ class DownloadVideoFragment(item: DownloadItem) : Fragment() {
return fragmentView return fragmentView
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
val resultItem = resultViewModel.getItemByURL(downloadItem.url) lifecycleScope.launch {
val type = downloadItem.type 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)
val editor = sharedPreferences.edit() val editor = sharedPreferences.edit()
try { try {
val title = view.findViewById<TextInputLayout>(R.id.title_textinput) title = view.findViewById(R.id.title_textinput)
title!!.editText!!.setText(downloadItem.title) title.editText!!.setText(downloadItem.title)
title.editText!!.addTextChangedListener(object : TextWatcher { title.editText!!.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {} override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {} override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
override fun afterTextChanged(p0: Editable?) { override fun afterTextChanged(p0: Editable?) {
downloadItem.title = p0.toString() downloadItem.title = p0.toString()
resultItem.title = p0.toString() resultItem.title = p0.toString()
resultViewModel.update(resultItem) resultViewModel.update(resultItem)
downloadViewModel.updateDownload(downloadItem) downloadViewModel.updateDownload(downloadItem)
} }
}) })
val author = view.findViewById<TextInputLayout>(R.id.author_textinput) author = view.findViewById(R.id.author_textinput)
author!!.editText!!.setText(downloadItem.author) author.editText!!.setText(downloadItem.author)
author.editText!!.addTextChangedListener(object : TextWatcher { author.editText!!.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {} override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {} override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
override fun afterTextChanged(p0: Editable?) { override fun afterTextChanged(p0: Editable?) {
downloadItem.author = p0.toString() downloadItem.author = p0.toString()
resultItem.author = p0.toString() resultItem.author = p0.toString()
resultViewModel.update(resultItem) resultViewModel.update(resultItem)
downloadViewModel.updateDownload(downloadItem) downloadViewModel.updateDownload(downloadItem)
} }
}) })
val saveDir = view.findViewById<TextInputLayout>(R.id.outputPath) saveDir = view.findViewById(R.id.outputPath)
saveDir!!.editText!!.setText( val downloadPath = sharedPreferences.getString(
sharedPreferences.getString(
"video_path", "video_path",
getString(R.string.video_path) getString(R.string.video_path)
) )
) downloadItem.downloadPath = downloadPath!!
saveDir.editText!!.isFocusable = false; downloadViewModel.updateDownload(downloadItem)
saveDir.editText!!.isClickable = true; saveDir.editText!!.setText(
saveDir.editText!!.setOnClickListener { fileUtil.formatPath(downloadPath)
Toast.makeText(context, "TEST", Toast.LENGTH_SHORT).show() )
} 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 { val formatTitles = formats.map {
if (it.format_note.contains("AUDIO_QUALITY_")) if (it.format_note.contains("AUDIO_QUALITY_"))
it.format_note.replace("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) 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 format = view.findViewById<TextInputLayout>(R.id.format)
val container = view.findViewById<TextInputLayout>(R.id.downloadContainer) val autoCompleteTextView =
val containerAutoCompleteTextView = view.findViewById<AutoCompleteTextView>(R.id.format_textview)
view.findViewById<AutoCompleteTextView>(R.id.container_textview) autoCompleteTextView?.setAdapter(
ArrayAdapter(
container?.isEnabled = true requireContext(),
containerAutoCompleteTextView?.setAdapter( android.R.layout.simple_dropdown_item_1line,
ArrayAdapter( formatTitles
requireContext(), )
android.R.layout.simple_dropdown_item_1line,
containers
) )
) if (formatTitles.isNotEmpty()) {
val selectedContainer: String = autoCompleteTextView!!.setText(formatTitles[formats.lastIndex], false)
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]
} }
(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) embedSubs!!.isChecked = sharedPreferences.getBoolean("embed_subtitles", false)
val addChapters = view.findViewById<Chip>(R.id.add_chapters) val addChapters = view.findViewById<Chip>(R.id.add_chapters)
addChapters!!.isChecked = sharedPreferences.getBoolean("add_chapters", false) addChapters!!.isChecked = sharedPreferences.getBoolean("add_chapters", false)
val saveThumbnail = view.findViewById<Chip>(R.id.save_thumbnail) val saveThumbnail = view.findViewById<Chip>(R.id.save_thumbnail)
saveThumbnail!!.isChecked = sharedPreferences.getBoolean("write_thumbnail", false) saveThumbnail!!.isChecked = sharedPreferences.getBoolean("write_thumbnail", false)
val cancel = view.findViewById<Button>(R.id.bottomsheet_cancel_button) val cancel = view.findViewById<Button>(R.id.bottomsheet_cancel_button)
cancel!!.setOnClickListener { cancel!!.setOnClickListener {
parentFragmentManager.popBackStack() (parentFragmentManager.findFragmentByTag("bottomSheet") as DownloadBottomSheetDialog).dismissSelf()
} }
val download = view.findViewById<Button>(R.id.bottomsheet_download_button) val download = view.findViewById<Button>(R.id.bottomsheet_download_button)
download!!.setOnClickListener { download!!.setOnClickListener {
// for (i in selectedObjects!!.indices) { // for (i in selectedObjects!!.indices) {
// val vid = findVideo( // val vid = findVideo(
// selectedObjects!![i]!!.getURL() // selectedObjects!![i]!!.getURL()
@ -177,11 +217,29 @@ class DownloadVideoFragment(item: DownloadItem) : Fragment() {
// mainActivity!!.startDownloadService(downloadQueue, listener) // mainActivity!!.startDownloadService(downloadQueue, listener)
// downloadQueue!!.clear() // downloadQueue!!.clear()
// } // }
parentFragmentManager.popBackStack() (parentFragmentManager.findFragmentByTag("bottomSheet") as DownloadBottomSheetDialog).dismissSelf()
} }
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() 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) { 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()) p!!.summary = fileUtil?.formatPath(data.data.toString())
val sharedPreferences = val sharedPreferences =
requireContext().getSharedPreferences("root_preferences", Activity.MODE_PRIVATE) requireContext().getSharedPreferences("root_preferences", Activity.MODE_PRIVATE)

View file

@ -32,6 +32,7 @@ class FileUtil() {
fun formatPath(path: String) : String { fun formatPath(path: String) : String {
var dataValue = path var dataValue = path
if (dataValue.startsWith("/storage/")) return dataValue
dataValue = dataValue.replace("content://com.android.externalstorage.documents/tree/", "") dataValue = dataValue.replace("content://com.android.externalstorage.documents/tree/", "")
dataValue = dataValue.replace("%3A".toRegex(), "/") dataValue = dataValue.replace("%3A".toRegex(), "/")
try { try {
@ -123,7 +124,7 @@ class FileUtil() {
} }
fun convertFileSize(s: Long): String{ fun convertFileSize(s: Long): String{
if (s <= 0) return "0" if (s <= 0) return "?"
val units = arrayOf("B", "kB", "MB", "GB", "TB") val units = arrayOf("B", "kB", "MB", "GB", "TB")
val digitGroups = (log10(s.toDouble()) / log10(1024.0)).toInt() val digitGroups = (log10(s.toDouble()) / log10(1024.0)).toInt()
return DecimalFormat("#,##0.#").format(s / 1024.0.pow(digitGroups.toDouble())) + " " + units[digitGroups] 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) { } catch (e: Exception) {
arrayOf(youtubeDLResponse.out) arrayOf(youtubeDLResponse.out)
} }
var isPlaylist = 0
val pl = JSONObject(results[0]!!) val pl = JSONObject(results[0]!!)
if (pl.has("playlist")) {
if (pl.getString("playlist") != query) isPlaylist = 1
}
for (result in results) { for (result in results) {
val jsonObject = JSONObject(result!!) val jsonObject = JSONObject(result!!)
val title = if (jsonObject.has("title")) { 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") val website = if (jsonObject.has("ie_key")) jsonObject.getString("ie_key") else jsonObject.getString("extractor")
var playlistTitle: String? = "" var playlistTitle: String? = ""
if (jsonObject.has("playlist_title")) playlistTitle = jsonObject.getString("playlist_title") 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 formatsInJSON = if (jsonObject.has("formats")) jsonObject.getJSONArray("formats") else null
val formats : ArrayList<Format> = ArrayList() val formats : ArrayList<Format> = ArrayList()
if (formatsInJSON != null) { if (formatsInJSON != null) {

View file

@ -8,17 +8,8 @@
<TextView <TextView
android:id="@+id/bottom_sheet_title" android:id="@+id/bottom_sheet_title"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:textSize="20sp" android:textSize="25sp"
android:paddingTop="10dp" android:padding="20dp"
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:layout_gravity="center" android:layout_gravity="center"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/configure_download" /> android:text="@string/configure_download" />

View file

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

View file

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

View file

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

View file

@ -23,7 +23,6 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/configure_download" /> android:text="@string/configure_download" />
<include layout="@layout/home_download_settings_components" />
<View style="@style/Divider.Horizontal"/> <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="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="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="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="music_path" translatable="false">content://com.android.externalstorage.documents/tree/primary%3ADownload%2FYTDLnis%2FAudio</string>
<string name="video_path" translatable="false">/storage/emulated/0/Download/YTDLnis/Video</string> <string name="video_path" translatable="false">content://com.android.externalstorage.documents/tree/primary%3ADownload%2FYTDLnis%2FVideo</string>
<string name="command_path" translatable="false">/storage/emulated/0/Download/YTDLnis/Command</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_summary">Number of fragments of a DASH/HLS native video to download concurrently</string>
<string name="concurrent_fragments">Concurrent Fragments</string> <string name="concurrent_fragments">Concurrent Fragments</string>
<string name="downloading">Downloading</string> <string name="downloading">Downloading</string>
@ -163,7 +163,6 @@
<string name="best">Best</string> <string name="best">Best</string>
<string name="worst">Worst</string> <string name="worst">Worst</string>
<string name="defaultValue">Default</string> <string name="defaultValue">Default</string>
<string name="format">Format</string>
<string name="container">Container</string> <string name="container">Container</string>
<string name="template">Template</string> <string name="template">Template</string>
<string name="history">History</string> <string name="history">History</string>