added more details on format selection & implemented download card in share intent

pull/44/head
Denis Çerri 3 years ago
parent aa8a9270bd
commit 0047f8a833
No known key found for this signature in database
GPG Key ID: 95C43D517D830350

@ -5,7 +5,8 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
@ -35,12 +36,6 @@
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT"/>
@ -49,20 +44,16 @@
</activity>
<activity android:name=".receiver.ShareActivity"
android:theme="@style/Theme.BottomSheet"
android:configChanges="layoutDirection|locale"
android:launchMode="singleInstance"
android:excludeFromRecents="true"
android:exported="true">
<!-- <intent-filter>-->
<!-- <action android:name="android.intent.action.SEND" />-->
<!-- <category android:name="android.intent.category.DEFAULT" />-->
<!-- <data android:mimeType="text/plain" />-->
<!-- </intent-filter>-->
<!-- <intent-filter>-->
<!-- <action android:name="android.intent.action.SEND" />-->
<!-- <category android:name="android.intent.category.DEFAULT"/>-->
<!-- <data android:mimeType="application/txt" />-->
<!-- </intent-filter>-->
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
<activity
android:name=".ui.settings.SettingsActivity"

@ -7,6 +7,12 @@ data class Format(
var format_id: String = "",
@SerializedName(value = "ext", alternate = ["container"])
var container: String = "",
@SerializedName(value = "vcodec")
var vcodec: String = "",
@SerializedName(value = "acodec")
var acodec: String = "",
@SerializedName(value = "encoding")
var encoding: String = "",
@SerializedName(value = "filesize", alternate = ["clen", "filesize_approx"])
var filesize: Long = 0,
@SerializedName(value = "format_note", alternate = ["resolution", "audioQuality"])

@ -3,6 +3,7 @@ package com.deniscerri.ytdlnis.database.repository
import android.content.Context
import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.deniscerri.ytdlnis.database.dao.CommandTemplateDao
import com.deniscerri.ytdlnis.database.dao.ResultDao
import com.deniscerri.ytdlnis.database.models.CommandTemplate
@ -13,6 +14,7 @@ import com.deniscerri.ytdlnis.util.InfoUtil
class ResultRepository(private val resultDao: ResultDao, private val commandTemplateDao: CommandTemplateDao, private val context: Context) {
private val tag: String = "ResultRepository"
val allResults : LiveData<List<ResultItem>> = resultDao.getResults()
var itemCount = MutableLiveData(0)
suspend fun insert(it: ResultItem){
resultDao.insert(it)
@ -26,23 +28,27 @@ class ResultRepository(private val resultDao: ResultDao, private val commandTemp
deleteAll()
val infoUtil = InfoUtil(context)
val items = infoUtil.getTrending(context)
itemCount.postValue(items.size)
for (i in items){
resultDao.insert(i!!)
}
}
suspend fun search(inputQuery: String, resetResults: Boolean){
suspend fun search(inputQuery: String, resetResults: Boolean) : ArrayList<ResultItem?>{
val infoUtil = InfoUtil(context)
try{
if (resetResults) deleteAll()
val res = infoUtil.search(inputQuery)
itemCount.postValue(res.size)
res.forEach {
resultDao.insert(it!!)
}
return res
}catch (ignored: Exception){}
return arrayListOf()
}
suspend fun getOne(inputQuery: String, resetResults: Boolean){
suspend fun getOne(inputQuery: String, resetResults: Boolean) : ArrayList<ResultItem?>{
var el: Array<String?> =
inputQuery.split("/".toRegex()).dropLastWhile { it.isEmpty() }
.toTypedArray()
@ -60,13 +66,16 @@ class ResultRepository(private val resultDao: ResultDao, private val commandTemp
try {
val v = infoUtil.getVideo(query!!)
if (resetResults) deleteAll()
itemCount.postValue(1)
resultDao.insert(v!!)
return arrayListOf(v)
} catch (e: Exception) {
Log.e(tag, e.toString())
}
return arrayListOf()
}
suspend fun getPlaylist(inputQuery: String, resetResults: Boolean){
suspend fun getPlaylist(inputQuery: String, resetResults: Boolean) : ArrayList<ResultItem?>{
val query = inputQuery.split("list=".toRegex()).dropLastWhile { it.isEmpty() }
.toTypedArray()[1]
var nextPageToken = ""
@ -81,26 +90,32 @@ class ResultRepository(private val resultDao: ResultDao, private val commandTemp
if (tmpToken == nextPageToken) break
nextPageToken = tmpToken
} while (true)
itemCount.postValue(items.size)
items.forEach {
resultDao.insert(it!!)
}
return items
}
suspend fun getDefault(inputQuery: String, resetResults: Boolean){
suspend fun getDefault(inputQuery: String, resetResults: Boolean) : ArrayList<ResultItem?> {
val infoUtil = InfoUtil(context)
try {
if (resetResults) deleteAll()
val items = infoUtil.getFromYTDL(inputQuery)
itemCount.postValue(items.size)
items.forEach {
resultDao.insert(it!!)
}
return items
} catch (e: Exception) {
Log.e(tag, e.toString())
}
return arrayListOf()
}
suspend fun deleteAll(){
itemCount.postValue(0)
resultDao.deleteAll()
}

@ -57,6 +57,9 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
bestVideoFormat = Format(
videoFormat[videoFormat.lastIndex],
videoContainer!!,
"",
"",
"",
0,
videoFormat[videoFormat.lastIndex]
)
@ -65,6 +68,9 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
bestAudioFormat = Format(
"",
audioContainer!!,
"",
"",
"",
0,
""
)

@ -17,6 +17,7 @@ class ResultViewModel(application: Application) : AndroidViewModel(application)
private val repository : ResultRepository
val items : LiveData<List<ResultItem>>
val loadingItems = MutableLiveData<Boolean>()
var itemCount : LiveData<Int>
init {
val dao = DBManager.getInstance(application).resultDao
@ -24,6 +25,7 @@ class ResultViewModel(application: Application) : AndroidViewModel(application)
repository = ResultRepository(dao, commandDao, getApplication<Application>().applicationContext)
items = repository.allResults
loadingItems.postValue(false)
itemCount = repository.itemCount
}
fun checkTrending() = viewModelScope.launch(Dispatchers.IO){
@ -41,7 +43,7 @@ class ResultViewModel(application: Application) : AndroidViewModel(application)
}
fun getTrending() = viewModelScope.launch(Dispatchers.IO){
loadingItems.postValue(true)
repository.updateTrending();
repository.updateTrending()
loadingItems.postValue(false)
}

@ -1,34 +1,50 @@
package com.deniscerri.ytdlnis.receiver
import android.Manifest
import android.app.Activity
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.content.res.Configuration
import android.graphics.drawable.ColorDrawable
import android.net.Uri
import android.os.Build
import android.os.Build.VERSION_CODES
import android.os.Bundle
import android.util.Log
import android.provider.Settings
import android.view.Window
import android.view.WindowManager
import androidx.fragment.app.FragmentManager
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
import com.deniscerri.ytdlnis.databinding.ActivityMainBinding
import com.deniscerri.ytdlnis.ui.MoreFragment
import java.io.BufferedReader
import java.io.InputStreamReader
import java.io.Reader
import java.nio.charset.Charset
import java.nio.charset.StandardCharsets
import java.util.*
import kotlin.system.exitProcess
import android.widget.TextView
import androidx.activity.ComponentActivity
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.lifecycle.ViewModelProvider
import com.deniscerri.ytdlnis.MainActivity
import com.deniscerri.ytdlnis.R
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.ui.downloadcard.DownloadBottomSheetDialog
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.io.File
import kotlin.system.exitProcess
class ShareActivity : ComponentActivity() {
class ShareActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
lateinit var context: Context
private lateinit var resultViewModel: ResultViewModel
private lateinit var downloadViewModel: DownloadViewModel
private lateinit var sharedPreferences: SharedPreferences
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -37,12 +53,28 @@ class ShareActivity : ComponentActivity() {
v.setPadding(0, 0, 0, 0)
insets
}
window.setBackgroundDrawable(ColorDrawable(0))
window.setLayout(
window.run {
setBackgroundDrawable(ColorDrawable(0))
setLayout(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY)
} else {
setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT)
}
}
setContentView(R.layout.activity_share)
context = baseContext
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
sharedPreferences = getSharedPreferences("root_preferences", Activity.MODE_PRIVATE)
askPermissions()
val intent = intent
handleIntents(intent)
}
@ -55,46 +87,130 @@ class ShareActivity : ComponentActivity() {
val action = intent.action
val type = intent.type
if (Intent.ACTION_SEND == action && type != null) {
Log.e(TAG, action)
moreFragment = MoreFragment()
if (type.equals("application/txt", ignoreCase = true)) {
try {
val uri = intent.getParcelableExtra<Uri>(Intent.EXTRA_STREAM)
val `is` = contentResolver.openInputStream(uri!!)
val textBuilder = StringBuilder()
val reader: Reader = BufferedReader(
InputStreamReader(
`is`, Charset.forName(
StandardCharsets.UTF_8.name()
)
)
)
var c: Int
while (reader.read().also { c = it } != -1) {
textBuilder.append(c.toChar())
val loadingBottomSheet = BottomSheetDialog(this)
loadingBottomSheet.requestWindowFeature(Window.FEATURE_NO_TITLE)
loadingBottomSheet.setContentView(R.layout.please_wait_bottom_sheet)
loadingBottomSheet.show()
val cancel = loadingBottomSheet.findViewById<TextView>(R.id.cancel)
cancel!!.setOnClickListener {
this.finish()
}
val l = listOf(*textBuilder.toString().split("\n").toTypedArray())
val lines = LinkedList(l)
val inputQuery = intent.getStringExtra(Intent.EXTRA_TEXT)
try {
val result = resultViewModel.getItemByURL(inputQuery!!)
loadingBottomSheet.cancel()
showDownloadSheet(result)
}catch (e: Exception){
e.printStackTrace()
resultViewModel.deleteAll()
CoroutineScope(Dispatchers.IO).launch {
resultViewModel.parseQuery(inputQuery!!, true)
}
resultViewModel.items.observe(this) {
if (it.isNotEmpty()){
if(resultViewModel.itemCount.value!! == it.size){
loadingBottomSheet.cancel()
showDownloadSheet(it[0])
}
}
}
}
}
}
private fun showDownloadSheet(it: ResultItem){
if (sharedPreferences.getBoolean("download_card", true)){
val bottomSheet = DownloadBottomSheetDialog(it, DownloadViewModel.Type.video)
bottomSheet.show(supportFragmentManager, "downloadSingleSheet")
}else{
//TODO
val downloadItem = downloadViewModel.createDownloadItemFromResult(it, DownloadViewModel.Type.video)
downloadViewModel.queueDownloads(listOf(downloadItem))
this.finish()
}
}
private fun askPermissions() {
if (Build.VERSION.SDK_INT < VERSION_CODES.TIRAMISU && !checkFilePermission()) {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
1
)
}else if (!checkNotificationPermission()){
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.POST_NOTIFICATIONS),
1
)
}
}
private fun createDefaultFolders(){
val audio = File(getString(R.string.music_path))
val video = File(getString(R.string.video_path))
val command = File(getString(R.string.command_path))
audio.mkdirs()
video.mkdirs()
command.mkdirs()
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
for (i in permissions.indices) {
if (permissions.contains(Manifest.permission.POST_NOTIFICATIONS)) break
if (grantResults[i] == PackageManager.PERMISSION_DENIED) {
createPermissionRequestDialog()
}else{
createDefaultFolders()
}
}
}
private fun exit() {
finishAffinity()
exitProcess(0)
}
private fun checkFilePermission(): Boolean {
return (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED)
}
private fun checkNotificationPermission(): Boolean {
return (ActivityCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS)
== PackageManager.PERMISSION_GRANTED)
}
private fun createPermissionRequestDialog() {
val dialog = MaterialAlertDialogBuilder(this)
dialog.setTitle(getString(R.string.warning))
dialog.setMessage(getString(R.string.request_permission_desc))
dialog.setOnCancelListener { exit() }
dialog.setNegativeButton(getString(R.string.exit_app)) { _: DialogInterface?, _: Int -> exit() }
dialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
val intent = Intent(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.fromParts("package", packageName, null)
)
startActivity(intent)
exitProcess(0)
}
dialog.show()
}
override fun onConfigurationChanged(newConfig: Configuration) {
startActivity(Intent(this, MainActivity::class.java))
super.onConfigurationChanged(newConfig)
}
companion object {
private const val TAG = "ShareActivity"
private lateinit var moreFragment: MoreFragment
private lateinit var fm: FragmentManager
}
}

@ -128,13 +128,14 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
resultViewModel.items.observe(viewLifecycleOwner) {
homeAdapter!!.submitList(it)
resultsList = it
if(it.size > 1){
Log.e(TAG, resultViewModel.itemCount.toString())
if(resultViewModel.itemCount.value!! > 1){
if (it[0].playlistTitle.isNotEmpty() && it[0].playlistTitle != getString(R.string.trendingPlaylist)){
downloadAllFabCoordinator!!.visibility = VISIBLE
}else{
downloadAllFabCoordinator!!.visibility = GONE
}
}else if (it.size == 1){
}else if (resultViewModel.itemCount.value!! == 1){
if (sharedPreferences!!.getBoolean("download_card", true)){
if(it.size == 1 && !firstBoot && parentFragmentManager.findFragmentByTag("downloadSingleSheet") == null){
showSingleDownloadSheet(it[0], DownloadViewModel.Type.video)

@ -14,17 +14,21 @@ import android.widget.ArrayAdapter
import android.widget.AutoCompleteTextView
import android.widget.TextView
import androidx.activity.result.contract.ActivityResultContracts
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.coordinatorlayout.widget.CoordinatorLayout
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.Format
import com.deniscerri.ytdlnis.database.models.ResultItem
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel.Type
import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding
import com.deniscerri.ytdlnis.util.FileUtil
import com.deniscerri.ytdlnis.util.UiUtil
import com.google.android.material.chip.Chip
import com.google.android.material.textfield.TextInputLayout
import kotlinx.coroutines.launch
@ -34,9 +38,9 @@ class DownloadAudioFragment(private var resultItem: ResultItem) : Fragment() {
private var _binding : FragmentHomeBinding? = null
private var fragmentView: View? = null
private var activity: Activity? = null
private var mainActivity: MainActivity? = null
private lateinit var downloadViewModel : DownloadViewModel
private lateinit var fileUtil : FileUtil
private lateinit var uiUtil : UiUtil
private lateinit var title : TextInputLayout
private lateinit var author : TextInputLayout
@ -56,10 +60,10 @@ class DownloadAudioFragment(private var resultItem: ResultItem) : Fragment() {
_binding = FragmentHomeBinding.inflate(inflater, container, false)
fragmentView = inflater.inflate(R.layout.fragment_download_audio, container, false)
activity = getActivity()
mainActivity = activity as MainActivity?
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
downloadItem = downloadViewModel.createDownloadItemFromResult(resultItem, Type.audio)
fileUtil = FileUtil()
uiUtil = UiUtil(fileUtil)
return fragmentView
}
@ -109,8 +113,7 @@ class DownloadAudioFragment(private var resultItem: ResultItem) : Fragment() {
audioPathResultLauncher.launch(intent)
}
val format = view.findViewById<TextInputLayout>(R.id.format)
val formats = resultItem.formats.filter { it.format_note.contains("audio", ignoreCase = true) }
var formats = resultItem.formats.filter { it.format_note.contains("audio", ignoreCase = true) }
val containers = requireContext().resources.getStringArray(R.array.audio_containers)
val container = view.findViewById<TextInputLayout>(R.id.downloadContainer)
@ -118,49 +121,35 @@ class DownloadAudioFragment(private var resultItem: ResultItem) : Fragment() {
view.findViewById<AutoCompleteTextView>(R.id.container_textview)
val formatCard = view.findViewById<ConstraintLayout>(R.id.format_card_constraintLayout)
if (formats.isEmpty()) {
format.visibility = View.GONE
formatCard.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)
val chosenFormat = formats[formats.lastIndex]
uiUtil.populateFormatCard(formatCard, chosenFormat)
val listener = object : OnFormatClickListener {
override fun onFormatClick(allFormats: List<Format>, item: Format) {
downloadItem.format = item
if (containers.contains(item.container)){
downloadItem.format.container = item.container
containerAutoCompleteTextView.setText(item.container, false)
}else{
it.format_note + if (it.filesize == 0L) "" else " / " + fileUtil.convertFileSize(
it.filesize
)
downloadItem.format.container = containers[0]
containerAutoCompleteTextView.setText(containers[0], false)
}
uiUtil.populateFormatCard(formatCard, item)
formats = allFormats
}
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.format.format_note = formats[index].format_note
downloadItem.format.format_id = formats[index].format_id
downloadItem.format.filesize = formats[index].filesize
if (containers.contains(formats[index].container)){
downloadItem.format.container = formats[index].container
containerAutoCompleteTextView.setText(formats[index].container, false)
}else{
downloadItem.format.container = containers[0]
containerAutoCompleteTextView.setText(containers[0], false)
formatCard.setOnClickListener{_ ->
formats.forEach {
Log.e("aa", it.toString())
}
val bottomSheet = FormatSelectionBottomSheetDialog(formats, listener)
bottomSheet.show(parentFragmentManager, "formatSheet")
}
}

@ -16,12 +16,14 @@ import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.get
import androidx.core.view.size
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
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.DownloadViewModel.Type
import com.deniscerri.ytdlnis.receiver.ShareActivity
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.google.android.material.button.MaterialButton
@ -57,12 +59,18 @@ class DownloadBottomSheetDialog(private val resultItem: ResultItem, private val
behavior = BottomSheetBehavior.from(view.parent as View)
val displayMetrics = DisplayMetrics()
requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics)
behavior.peekHeight = displayMetrics.heightPixels - 400
behavior.peekHeight = displayMetrics.heightPixels - 700
}
tabLayout = view.findViewById(R.id.download_tablayout)
viewPager2 = view.findViewById(R.id.download_viewpager)
(viewPager2.getChildAt(0) as? RecyclerView)?.apply {
isNestedScrollingEnabled = false
overScrollMode = View.OVER_SCROLL_NEVER
}
val fragmentManager = parentFragmentManager
fragmentAdapter = DownloadFragmentAdapter(
resultItem,
@ -158,18 +166,18 @@ class DownloadBottomSheetDialog(private val resultItem: ResultItem, private val
}
private fun getDownloadItem() : DownloadItem{
when(tabLayout.selectedTabPosition){
return when(tabLayout.selectedTabPosition){
0 -> {
val f = fragmentManager?.findFragmentByTag("f0") as DownloadAudioFragment
return f.downloadItem
f.downloadItem
}
1 -> {
val f = fragmentManager?.findFragmentByTag("f1") as DownloadVideoFragment
return f.downloadItem
f.downloadItem
}
else -> {
val f = fragmentManager?.findFragmentByTag("f2") as DownloadCommandFragment
return f.downloadItem
f.downloadItem
}
}
}
@ -192,6 +200,9 @@ class DownloadBottomSheetDialog(private val resultItem: ResultItem, private val
parentFragmentManager.beginTransaction().remove(parentFragmentManager.findFragmentByTag("f$i")!!).commit()
}
}
if (activity is ShareActivity){
(activity as ShareActivity).finish()
}
}
}

@ -35,7 +35,6 @@ class DownloadCommandFragment(private val resultItem: ResultItem) : Fragment() {
private var _binding : FragmentHomeBinding? = null
private var fragmentView: View? = null
private var activity: Activity? = null
private var mainActivity: MainActivity? = null
private lateinit var downloadViewModel : DownloadViewModel
private lateinit var fileUtil : FileUtil
@ -52,7 +51,6 @@ class DownloadCommandFragment(private val resultItem: ResultItem) : Fragment() {
_binding = FragmentHomeBinding.inflate(inflater, container, false)
fragmentView = inflater.inflate(R.layout.fragment_download_command, container, false)
activity = getActivity()
mainActivity = activity as MainActivity?
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
downloadItem = downloadViewModel.createDownloadItemFromResult(resultItem, DownloadViewModel.Type.command)
fileUtil = FileUtil()
@ -73,6 +71,9 @@ class DownloadCommandFragment(private val resultItem: ResultItem) : Fragment() {
downloadItem.format = Format(
chosenCommand!!.title,
"",
"",
"",
"",
0,
chosenCommand.content
)

@ -10,6 +10,7 @@ import android.view.View
import android.view.ViewGroup
import android.widget.*
import androidx.activity.result.contract.ActivityResultContracts
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
@ -28,16 +29,16 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel.Type
import com.deniscerri.ytdlnis.util.UiUtil
class DownloadVideoFragment(private val resultItem: ResultItem) : 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 lateinit var uiUtil : UiUtil
private lateinit var title : TextInputLayout
private lateinit var author : TextInputLayout
@ -53,10 +54,10 @@ class DownloadVideoFragment(private val resultItem: ResultItem) : Fragment() {
_binding = FragmentHomeBinding.inflate(inflater, container, false)
fragmentView = inflater.inflate(R.layout.fragment_download_video, container, false)
activity = getActivity()
mainActivity = activity as MainActivity?
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
downloadItem = downloadViewModel.createDownloadItemFromResult(resultItem, Type.video)
fileUtil = FileUtil()
uiUtil = UiUtil(fileUtil)
return fragmentView
}
@ -111,30 +112,12 @@ class DownloadVideoFragment(private val resultItem: ResultItem) : Fragment() {
if (formats.isEmpty()) {
val videoFormats = resources.getStringArray(R.array.video_formats)
val container = sharedPreferences.getString("video_format", "Default")
videoFormats.forEach { formats.add(Format(it, container!!, 0, it)) }
videoFormats.forEach { formats.add(Format(it, container!!,"","", "",0, it)) }
}
val formatTitles = formats.map {
it.format_note + if (it.filesize == 0L) "" else " / " + fileUtil.convertFileSize(it.filesize)
}
downloadItem.format = formats[formats.lastIndex]
val containers = requireContext().resources.getStringArray(R.array.video_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
)
)
if (formatTitles.isNotEmpty()) {
autoCompleteTextView!!.setText(formatTitles[formats.lastIndex], false)
}
val container = view.findViewById<TextInputLayout>(R.id.downloadContainer)
val containerAutoCompleteTextView =
@ -151,27 +134,27 @@ class DownloadVideoFragment(private val resultItem: ResultItem) : Fragment() {
val selectedContainer: String = downloadItem.format.container
containerAutoCompleteTextView!!.setText(selectedContainer, false)
(format!!.editText as AutoCompleteTextView?)!!.onItemClickListener =
AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, index: Int, _: Long ->
downloadItem.format.format_note = formats[index].format_note
downloadItem.format.format_id = formats[index].format_id
downloadItem.format.filesize = formats[index].filesize
val formatCard = view.findViewById<ConstraintLayout>(R.id.format_card_constraintLayout)
val chosenFormat = formats[formats.lastIndex]
uiUtil.populateFormatCard(formatCard, chosenFormat)
val listener = object : OnFormatClickListener {
override fun onFormatClick(allFormats: List<Format>, item: Format) {
downloadItem.format = item
if (containers.contains(formats[index].container)){
downloadItem.format.container = formats[index].container
containerAutoCompleteTextView.setText(formats[index].container, false)
if (containers.contains(item.container)){
downloadItem.format.container = item.container
containerAutoCompleteTextView.setText(item.container, false)
}else{
downloadItem.format.container = containers[0]
containerAutoCompleteTextView.setText(containers[0], false)
}
uiUtil.populateFormatCard(formatCard, item)
}
(container!!.editText as AutoCompleteTextView?)!!.onItemClickListener =
AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, index: Int, _: Long ->
downloadItem.format.container = containers[index]
}
formatCard.setOnClickListener{_ ->
val bottomSheet = FormatSelectionBottomSheetDialog(formats, listener)
bottomSheet.show(parentFragmentManager, "formatSheet")
}
val embedSubs = view.findViewById<Chip>(R.id.embed_subtitles)
embedSubs!!.isChecked = downloadItem.videoPreferences.embedSubs

@ -0,0 +1,104 @@
package com.deniscerri.ytdlnis.ui.downloadcard
import android.annotation.SuppressLint
import android.app.DatePickerDialog
import android.app.Dialog
import android.app.TimePickerDialog
import android.content.DialogInterface
import android.os.Bundle
import android.util.DisplayMetrics
import android.util.Log
import android.view.Display
import android.view.LayoutInflater
import android.view.View
import android.widget.Adapter
import android.widget.Button
import android.widget.LinearLayout
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.get
import androidx.core.view.size
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.models.Format
import com.deniscerri.ytdlnis.database.models.ResultItem
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel.Type
import com.deniscerri.ytdlnis.util.FileUtil
import com.deniscerri.ytdlnis.util.UiUtil
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.google.android.material.button.MaterialButton
import com.google.android.material.datepicker.CalendarConstraints
import com.google.android.material.datepicker.DateValidatorPointBackward
import com.google.android.material.datepicker.DateValidatorPointForward
import com.google.android.material.datepicker.MaterialDatePicker
import com.google.android.material.tabs.TabLayout
import com.google.android.material.timepicker.MaterialTimePicker
import com.google.android.material.timepicker.TimeFormat
import java.util.*
class FormatSelectionBottomSheetDialog(private val formats: List<Format>, private val listener: OnFormatClickListener) : BottomSheetDialogFragment() {
private lateinit var behavior: BottomSheetBehavior<View>
private lateinit var fileUtil: FileUtil
private lateinit var uiUtil: UiUtil
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
fileUtil = FileUtil()
uiUtil = UiUtil(fileUtil)
}
@SuppressLint("RestrictedApi")
override fun setupDialog(dialog: Dialog, style: Int) {
super.setupDialog(dialog, style)
val view = LayoutInflater.from(context).inflate(R.layout.format_select_bottom_sheet, null)
dialog.setContentView(view)
dialog.setOnShowListener {
behavior = BottomSheetBehavior.from(view.parent as View)
val displayMetrics = DisplayMetrics()
requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics)
behavior.peekHeight = displayMetrics.heightPixels / 2
}
val linearLayout = view.findViewById<LinearLayout>(R.id.format_list_linear_layout)
for (i in formats.lastIndex downTo 0){
val it = formats[i]
val formatItem = LayoutInflater.from(context).inflate(R.layout.format_item, null)
uiUtil.populateFormatCard(formatItem as ConstraintLayout, it)
formatItem.setOnClickListener{_ ->
listener.onFormatClick(formats, it)
dismiss()
}
linearLayout.addView(formatItem)
}
}
override fun onCancel(dialog: DialogInterface) {
super.onCancel(dialog)
cleanUp()
}
override fun onDismiss(dialog: DialogInterface) {
super.onDismiss(dialog)
cleanUp()
}
private fun cleanUp(){
parentFragmentManager.beginTransaction().remove(parentFragmentManager.findFragmentByTag("formatSheet")!!).commit()
}
}
interface OnFormatClickListener{
fun onFormatClick(allFormats: List<Format>, item: Format)
}

@ -0,0 +1,30 @@
package com.deniscerri.ytdlnis.util
import android.view.View
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.models.Format
class UiUtil(private val fileUtil: FileUtil) {
fun populateFormatCard(formatCard : ConstraintLayout, chosenFormat: Format){
formatCard.findViewById<TextView>(R.id.container).text = chosenFormat.container.uppercase()
formatCard.findViewById<TextView>(R.id.format_note).text = chosenFormat.format_note.uppercase()
formatCard.findViewById<TextView>(R.id.format_id).text = "id: ${chosenFormat.format_id}"
val codec =
if (chosenFormat.encoding != "") {
chosenFormat.encoding.uppercase()
}else if (chosenFormat.vcodec != "none" && chosenFormat.vcodec != ""){
chosenFormat.vcodec.uppercase()
} else {
chosenFormat.acodec.uppercase()
}
if (codec == "" || codec == "none"){
formatCard.findViewById<TextView>(R.id.codec).visibility = View.GONE
}else{
formatCard.findViewById<TextView>(R.id.codec).text = codec
}
formatCard.findViewById<TextView>(R.id.file_size).text = fileUtil.convertFileSize(chosenFormat.filesize)
}
}

@ -114,11 +114,13 @@ class DownloadWorker(
DownloadViewModel.Type.audio -> {
request.addOption("-x")
var audioQualityId : String = downloadItem.format.format_id
if (audioQualityId == "0" || audioQualityId.isEmpty()) audioQualityId = "ba"
if (audioQualityId.isEmpty() || audioQualityId == "0") audioQualityId = ""
if (audioQualityId.isNotEmpty()){
request.addOption("-f", audioQualityId)
}
val ext = downloadItem.format.container
if(ext != context.getString(R.string.defaultValue)){
if(ext != context.getString(R.string.defaultValue) && ext != "webm"){
request.addOption("--audio-format", ext)
}else{
request.addOption("--audio-format", sharedPreferences.getString("audio_format", "mp3")!!)

@ -0,0 +1,8 @@
<?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"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".receiver.ShareActivity"
android:layout_height="match_parent">
</androidx.constraintlayout.widget.ConstraintLayout>

@ -6,25 +6,19 @@
android:orientation="vertical"
android:layout_height="match_parent">
<ScrollView
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginHorizontal="20dp"
android:orientation="horizontal"
android:paddingTop="20dp">
<TextView
@ -50,8 +44,8 @@
android:id="@+id/bottomsheet_schedule_button"
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
android:layout_width="wrap_content"
android:layout_marginEnd="10dp"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
app:icon="@drawable/ic_clock"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/bottomsheet_download_button"
@ -70,7 +64,6 @@
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.tabs.TabLayout
@ -100,7 +93,6 @@
</com.google.android.material.tabs.TabLayout>
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/download_viewpager"
android:layout_width="match_parent"
@ -110,7 +102,6 @@
</LinearLayout>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>

@ -0,0 +1,103 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/format_card_constraintLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingVertical="10dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:id="@+id/container"
android:layout_width="60dp"
android:background="?attr/colorPrimaryInverse"
android:textColor="@color/white"
android:clickable="false"
android:layout_height="55dp"
android:gravity="center"
android:minWidth="30dp"
app:cornerRadius="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/constraintLayout2"
android:layout_width="wrap_content"
android:layout_height="55dp"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/container"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/format_note"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:textSize="20sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_marginStart="10dp"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent">
<TextView
android:id="@+id/codec"
style="@style/Widget.Material3.FloatingActionButton.Large.Secondary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="5dp"
android:background="?attr/colorSecondary"
android:clickable="false"
android:gravity="center"
android:minWidth="30dp"
android:paddingHorizontal="10dp"
app:cornerRadius="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/file_size"
style="@style/Widget.Material3.FloatingActionButton.Large.Tertiary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="5dp"
android:background="?attr/colorSecondary"
android:clickable="false"
android:gravity="center"
android:minWidth="30dp"
android:paddingHorizontal="10dp"
app:cornerRadius="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:id="@+id/format_id"
android:layout_width="wrap_content"
android:layout_height="55dp"
android:clickable="false"
android:gravity="bottom|end"
android:minWidth="30dp"
android:textColor="@color/white"
app:cornerRadius="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -0,0 +1,49 @@
<?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"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="20dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/format"
android:textSize="25sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/select_format"
android:paddingBottom="20dp"
android:textSize="12sp" />
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:scrollbars="none"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/format_list_linear_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

@ -1,4 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="none"
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"
@ -66,7 +71,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
app:errorEnabled="true"
android:paddingBottom="10dp"
android:hint="@string/title"
style="@style/Widget.Material3.TextInputLayout.FilledBox">
@ -81,6 +86,7 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="10dp"
android:orientation="horizontal">
<com.google.android.material.textfield.TextInputLayout
@ -88,7 +94,6 @@
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">
@ -122,27 +127,16 @@
</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="10dp"
android:hint="@string/audio_format">
<AutoCompleteTextView
android:id="@+id/format_textview"
android:layout_width="match_parent"
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="none"
app:simpleItems="@array/video_formats"
/>
</com.google.android.material.textfield.TextInputLayout>
android:text="@string/audio_format" />
<include layout="@layout/format_item" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/outputPath"
android:paddingTop="10dp"
style="@style/Widget.Material3.TextInputLayout.FilledBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -201,3 +195,5 @@
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>

@ -1,15 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.core.widget.NestedScrollView 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"
android:layout_height="wrap_content"
android:scrollbars="none"
xmlns:app="http://schemas.android.com/apk/res-auto">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp"
android:orientation="vertical">
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent">
<!-- <androidx.constraintlayout.widget.ConstraintLayout-->
@ -62,40 +65,38 @@
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/title_textinput"
style="@style/Widget.Material3.TextInputLayout.FilledBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
app:errorEnabled="true"
android:hint="@string/title"
style="@style/Widget.Material3.TextInputLayout.FilledBox">
android:paddingBottom="10dp">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:inputType="text"
android:layout_height="wrap_content"
/>
android:inputType="text" />
</com.google.android.material.textfield.TextInputLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
android:orientation="horizontal"
android:paddingBottom="10dp">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/author_textinput"
style="@style/Widget.Material3.TextInputLayout.FilledBox"
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">
android:hint="@string/author">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:inputType="text"
android:layout_height="wrap_content"
/>
android:inputType="text" />
</com.google.android.material.textfield.TextInputLayout>
@ -104,70 +105,58 @@
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">
android:layout_weight="45"
android:hint="@string/container"
android:paddingStart="10dp">
<AutoCompleteTextView
android:id="@+id/container_textview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="none"
app:simpleItems="@array/audio_containers"
/>
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="10dp"
android:hint="@string/video_format">
<AutoCompleteTextView
android:id="@+id/format_textview"
android:layout_width="match_parent"
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="none"
app:simpleItems="@array/video_formats"
/>
android:text="@string/video_format" />
</com.google.android.material.textfield.TextInputLayout>
<include layout="@layout/format_item" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/outputPath"
style="@style/Widget.Material3.TextInputLayout.FilledBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/save_dir"
style="@style/Widget.Material3.TextInputLayout.FilledBox">
android:paddingTop="10dp">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:inputType="text"
android:layout_height="wrap_content"/>
android:layout_height="wrap_content"
android:inputType="text" />
</com.google.android.material.textfield.TextInputLayout>
<LinearLayout
android:id="@+id/adjust_video"
android:layout_width="match_parent"
android:padding="10dp"
android:layout_height="wrap_content"
android:orientation="vertical"
>
android:padding="10dp">
<TextView
android:layout_width="wrap_content"
android:paddingBottom="5dp"
android:textSize="15sp"
android:layout_height="wrap_content"
android:text="@string/adjust_video" />
android:paddingBottom="5dp"
android:text="@string/adjust_video"
android:textSize="15sp" />
<HorizontalScrollView
android:layout_width="wrap_content"
@ -176,8 +165,8 @@
<com.google.android.material.chip.ChipGroup
android:id="@+id/chipGroup"
android:layout_width="wrap_content"
app:singleLine="false"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
app:singleLine="false">
<com.google.android.material.chip.Chip
android:id="@+id/embed_subtitles"
@ -215,4 +204,4 @@
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:padding="20dp"
android:layout_height="match_parent">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/please_wait"
android:textSize="20sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/cancel"
android:layout_width="wrap_content"
android:textColor="?attr/colorAccent"
android:layout_height="wrap_content"
android:text="@string/cancel"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -170,4 +170,7 @@
<string name="language">Language</string>
<string name="command_templates">Command Templates</string>
<string name="terminal">Terminal</string>
<string name="format">Format</string>
<string name="select_format">Select Format</string>
<string name="please_wait">Please Wait</string>
</resources>

@ -9,6 +9,14 @@
<item name="dialogCornerRadius">28dp</item>
</style>
<style name="Theme.BottomSheet" parent="Theme.Material3.DayNight.NoActionBar">
<item name="windowNoTitle">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:colorBackgroundCacheHint">@null</item>
<item name="android:windowContentOverlay">@null</item>
</style>
<style name="AppTheme" parent="AppDefaultTheme" />

Loading…
Cancel
Save