more stuff lol

This commit is contained in:
Denis Çerri 2023-02-07 17:33:40 +01:00
parent 2b0f1322d3
commit 2fd96cf3b2
No known key found for this signature in database
GPG key ID: 95C43D517D830350
22 changed files with 363 additions and 212 deletions

View file

@ -32,6 +32,10 @@
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity>
<activity android:name=".receiver.ShareActivity"
android:exported="true">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.SEND" /> <action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
@ -42,6 +46,7 @@
<category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="application/txt" /> <data android:mimeType="application/txt" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity <activity
android:name=".ui.settings.SettingsActivity" android:name=".ui.settings.SettingsActivity"

View file

@ -20,6 +20,7 @@ import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.deniscerri.ytdlnis.R import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.models.HistoryItem import com.deniscerri.ytdlnis.database.models.HistoryItem
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.google.android.material.button.MaterialButton import com.google.android.material.button.MaterialButton
import com.google.android.material.card.MaterialCardView import com.google.android.material.card.MaterialCardView
import com.squareup.picasso.Picasso import com.squareup.picasso.Picasso
@ -120,12 +121,10 @@ class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
}) })
thumbnail.alpha = 0.7f thumbnail.alpha = 0.7f
} }
if (item.type.isNotEmpty()) { if (item.type == DownloadViewModel.Type.audio) {
if (item.type == "audio") { if (filePresent) btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_music_downloaded) else btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_music)
if (filePresent) btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_music_downloaded) else btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_music) } else {
} else { if (filePresent) btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_video_downloaded) else btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_video)
if (filePresent) btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_video_downloaded) else btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_video)
}
} }
if (btn.hasOnClickListeners()) btn.setOnClickListener(null) if (btn.hasOnClickListeners()) btn.setOnClickListener(null)
if (checkedItems.contains(item.id)) { if (checkedItems.contains(item.id)) {

View file

@ -19,6 +19,7 @@ import androidx.recyclerview.widget.RecyclerView
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.models.ResultItem
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.util.FileUtil import com.deniscerri.ytdlnis.util.FileUtil
import com.google.android.material.button.MaterialButton import com.google.android.material.button.MaterialButton
import com.google.android.material.card.MaterialCardView import com.google.android.material.card.MaterialCardView
@ -96,13 +97,13 @@ class ConfigureMultipleDownloadsAdapter(onItemClickListener: OnItemClickListener
val btn = card.findViewById<MaterialButton>(R.id.downloads_download_button_type) val btn = card.findViewById<MaterialButton>(R.id.downloads_download_button_type)
when(item.type) { when(item.type) {
"audio" -> { DownloadViewModel.Type.audio -> {
btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_music) btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_music)
} }
"video" -> { DownloadViewModel.Type.video -> {
btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_video) btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_video)
} }
"command" -> { DownloadViewModel.Type.command -> {
btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_baseline_keyboard_arrow_right_24) btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_baseline_keyboard_arrow_right_24)
} }
} }

View file

@ -21,6 +21,7 @@ import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.deniscerri.ytdlnis.R import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.models.HistoryItem import com.deniscerri.ytdlnis.database.models.HistoryItem
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.google.android.material.button.MaterialButton import com.google.android.material.button.MaterialButton
import com.google.android.material.card.MaterialCardView import com.google.android.material.card.MaterialCardView
import com.squareup.picasso.Picasso import com.squareup.picasso.Picasso
@ -121,12 +122,10 @@ class HistoryAdapter(onItemClickListener: OnItemClickListener, activity: Activit
}) })
thumbnail.alpha = 0.7f thumbnail.alpha = 0.7f
} }
if (item.type.isNotEmpty()) { if (item.type == DownloadViewModel.Type.audio) {
if (item.type == "audio") { if (filePresent) btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_music_downloaded) else btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_music)
if (filePresent) btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_music_downloaded) else btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_music) } else {
} else { if (filePresent) btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_video_downloaded) else btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_video)
if (filePresent) btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_video_downloaded) else btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_video)
}
} }
if (btn.hasOnClickListeners()) btn.setOnClickListener(null) if (btn.hasOnClickListeners()) btn.setOnClickListener(null)
if (checkedItems.contains(item.id)) { if (checkedItems.contains(item.id)) {

View file

@ -16,6 +16,7 @@ import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.deniscerri.ytdlnis.R import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.models.ResultItem import com.deniscerri.ytdlnis.database.models.ResultItem
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.google.android.material.button.MaterialButton import com.google.android.material.button.MaterialButton
import com.google.android.material.card.MaterialCardView import com.google.android.material.card.MaterialCardView
import com.google.android.material.progressindicator.LinearProgressIndicator import com.google.android.material.progressindicator.LinearProgressIndicator
@ -84,11 +85,11 @@ class HomeAdapter(onItemClickListener: OnItemClickListener, activity: Activity)
val musicBtn = buttonLayout.findViewById<MaterialButton>(R.id.download_music) val musicBtn = buttonLayout.findViewById<MaterialButton>(R.id.download_music)
musicBtn.tag = "$videoURL##audio" musicBtn.tag = "$videoURL##audio"
musicBtn.setTag(R.id.cancelDownload, "false") musicBtn.setTag(R.id.cancelDownload, "false")
musicBtn.setOnClickListener { onItemClickListener.onButtonClick(videoURL, "audio") } musicBtn.setOnClickListener { onItemClickListener.onButtonClick(videoURL, DownloadViewModel.Type.audio) }
val videoBtn = buttonLayout.findViewById<MaterialButton>(R.id.download_video) val videoBtn = buttonLayout.findViewById<MaterialButton>(R.id.download_video)
videoBtn.tag = "$videoURL##video" videoBtn.tag = "$videoURL##video"
videoBtn.setTag(R.id.cancelDownload, "false") videoBtn.setTag(R.id.cancelDownload, "false")
videoBtn.setOnClickListener { onItemClickListener.onButtonClick(videoURL, "video") } videoBtn.setOnClickListener { onItemClickListener.onButtonClick(videoURL, DownloadViewModel.Type.video) }
// PROGRESS BAR ---------------------------------------------------- // PROGRESS BAR ----------------------------------------------------
@ -159,7 +160,7 @@ class HomeAdapter(onItemClickListener: OnItemClickListener, activity: Activity)
} }
interface OnItemClickListener { interface OnItemClickListener {
fun onButtonClick(videoURL: String, type: String?) fun onButtonClick(videoURL: String, type: DownloadViewModel.Type?)
fun onCardClick(videoURL: String, add: Boolean) fun onCardClick(videoURL: String, add: Boolean)
} }

View file

@ -20,6 +20,7 @@ import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.deniscerri.ytdlnis.R import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.models.HistoryItem import com.deniscerri.ytdlnis.database.models.HistoryItem
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.google.android.material.button.MaterialButton import com.google.android.material.button.MaterialButton
import com.google.android.material.card.MaterialCardView import com.google.android.material.card.MaterialCardView
import com.squareup.picasso.Picasso import com.squareup.picasso.Picasso
@ -120,12 +121,10 @@ class QueuedDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
}) })
thumbnail.alpha = 0.7f thumbnail.alpha = 0.7f
} }
if (item.type.isNotEmpty()) { if (item.type == DownloadViewModel.Type.audio) {
if (item.type == "audio") { if (filePresent) btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_music_downloaded) else btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_music)
if (filePresent) btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_music_downloaded) else btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_music) } else {
} else { if (filePresent) btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_video_downloaded) else btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_video)
if (filePresent) btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_video_downloaded) else btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_video)
}
} }
if (btn.hasOnClickListeners()) btn.setOnClickListener(null) if (btn.hasOnClickListeners()) btn.setOnClickListener(null)
if (checkedItems.contains(item.id)) { if (checkedItems.contains(item.id)) {

View file

@ -2,6 +2,7 @@ package com.deniscerri.ytdlnis.database
import androidx.room.TypeConverter import androidx.room.TypeConverter
import com.deniscerri.ytdlnis.database.models.Format import com.deniscerri.ytdlnis.database.models.Format
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.google.gson.Gson import com.google.gson.Gson
import com.google.gson.reflect.TypeToken import com.google.gson.reflect.TypeToken
import java.lang.reflect.Type import java.lang.reflect.Type
@ -26,4 +27,15 @@ class Converters {
@TypeConverter @TypeConverter
fun stringToFormat(string: String): Format = Gson().fromJson(string, Format::class.java) fun stringToFormat(string: String): Format = Gson().fromJson(string, Format::class.java)
@TypeConverter
fun typeToString(type: DownloadViewModel.Type) : String = type.toString()
@TypeConverter
fun stringToType(string: String) : DownloadViewModel.Type {
return when(string){
"audio" -> DownloadViewModel.Type.audio
"video" -> DownloadViewModel.Type.video
else -> DownloadViewModel.Type.command
}
}
} }

View file

@ -3,6 +3,7 @@ package com.deniscerri.ytdlnis.database.models
import androidx.room.ColumnInfo import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
@Entity(tableName = "downloads") @Entity(tableName = "downloads")
data class DownloadItem( data class DownloadItem(
@ -13,10 +14,10 @@ data class DownloadItem(
var author: String, var author: String,
val thumb: String, val thumb: String,
val duration: String, val duration: String,
var type: String, var type: DownloadViewModel.Type,
var format: Format, var format: Format,
@ColumnInfo(defaultValue = "0") @ColumnInfo(defaultValue = "0")
val removeAudio: Boolean, var removeAudio: Boolean,
var downloadPath: String, var downloadPath: String,
val website: String, val website: String,
val downloadSize: String, val downloadSize: 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 com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
@Entity(tableName = "history") @Entity(tableName = "history")
data class HistoryItem( data class HistoryItem(
@ -12,7 +13,7 @@ data class HistoryItem(
val author: String, val author: String,
val duration: String, val duration: String,
val thumb: String, val thumb: String,
val type: String, val type: DownloadViewModel.Type,
val time: Long, val time: Long,
val downloadPath: String, val downloadPath: String,
val website: String, val website: String,

View file

@ -3,7 +3,6 @@ package com.deniscerri.ytdlnis.database.viewmodel
import android.app.Activity import android.app.Activity
import android.app.Application import android.app.Application
import android.content.SharedPreferences import android.content.SharedPreferences
import android.util.Log
import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
@ -35,7 +34,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
private var bestVideoFormat: Format private var bestVideoFormat: Format
private var bestAudioFormat: Format private var bestAudioFormat: Format
enum class Type { enum class Type {
AUDIO, VIDEO, COMMAND audio, video, command
} }
init { init {
@ -79,7 +78,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
return repository.getItemByID(id) return repository.getItemByID(id)
} }
fun createDownloadItemFromResult(resultItem: ResultItem, type: String) : DownloadItem { fun createDownloadItemFromResult(resultItem: ResultItem, type: Type) : DownloadItem {
val embedSubs = sharedPreferences.getBoolean("embed_subtitles", false) val embedSubs = sharedPreferences.getBoolean("embed_subtitles", false)
val addChapters = sharedPreferences.getBoolean("add_chapters", false) val addChapters = sharedPreferences.getBoolean("add_chapters", false)
val saveThumb = sharedPreferences.getBoolean("write_thumbnail", false) val saveThumb = sharedPreferences.getBoolean("write_thumbnail", false)
@ -97,16 +96,16 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
} }
private fun getFormat(resultItem: ResultItem, type: String) : Format { private fun getFormat(resultItem: ResultItem, type: Type) : Format {
when(type) { when(type) {
"audio" -> { Type.audio -> {
return try { return try {
resultItem.formats.last { it.format_note.contains("audio", ignoreCase = true) } resultItem.formats.last { it.format_note.contains("audio", ignoreCase = true) }
}catch (e: Exception){ }catch (e: Exception){
bestAudioFormat bestAudioFormat
} }
} }
"video" -> { Type.video -> {
return try { return try {
resultItem.formats.last { !it.format_note.contains("audio", ignoreCase = true) } resultItem.formats.last { !it.format_note.contains("audio", ignoreCase = true) }
}catch (e: Exception){ }catch (e: Exception){
@ -119,10 +118,10 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
} }
} }
fun turnResultItemstoDownloadItems(items: List<ResultItem?>) : List<DownloadItem> { fun turnResultItemsToDownloadItems(items: List<ResultItem?>) : List<DownloadItem> {
val list : MutableList<DownloadItem> = mutableListOf() val list : MutableList<DownloadItem> = mutableListOf()
items.forEach { items.forEach {
list.add(createDownloadItemFromResult(it!!, "video")) list.add(createDownloadItemFromResult(it!!, Type.video))
} }
return list return list
} }
@ -150,10 +149,6 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
return result return result
} }
fun deleteSingleProcessing(item: DownloadItem) = viewModelScope.launch(Dispatchers.IO) {
repository.deleteSingleProcessing(item)
}
fun deleteProcessing() = viewModelScope.launch(Dispatchers.IO) { fun deleteProcessing() = viewModelScope.launch(Dispatchers.IO) {
repository.deleteProcessing() repository.deleteProcessing()
} }
@ -167,7 +162,10 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
val context = getApplication<App>().applicationContext val context = getApplication<App>().applicationContext
items.forEach { items.forEach {
it.status = DownloadRepository.Status.Queued.toString() it.status = DownloadRepository.Status.Queued.toString()
repository.update(it) if (it.id == 0L){
val id = repository.insert(it)
it.id = id
}else repository.update(it)
val workRequest = OneTimeWorkRequestBuilder<DownloadWorker>() val workRequest = OneTimeWorkRequestBuilder<DownloadWorker>()
.setInputData(Data.Builder().putLong("id", it.id).build()) .setInputData(Data.Builder().putLong("id", it.id).build())

View file

@ -1,14 +1,7 @@
package com.deniscerri.ytdlnis.database.viewmodel package com.deniscerri.ytdlnis.database.viewmodel
import android.app.Application import android.app.Application
import android.util.Log import androidx.lifecycle.*
import android.widget.Toast
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import androidx.lifecycle.viewModelScope
import com.deniscerri.ytdlnis.database.DBManager import com.deniscerri.ytdlnis.database.DBManager
import com.deniscerri.ytdlnis.database.models.HistoryItem import com.deniscerri.ytdlnis.database.models.HistoryItem
import com.deniscerri.ytdlnis.database.repository.HistoryRepository import com.deniscerri.ytdlnis.database.repository.HistoryRepository
@ -31,26 +24,26 @@ class HistoryViewModel(application: Application) : AndroidViewModel(application)
repository = HistoryRepository(dao) repository = HistoryRepository(dao)
allItems = repository.items allItems = repository.items
_items.addSource(allItems, Observer { _items.addSource(allItems){
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){
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){
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){
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){
filter(queryFilter.value!!, formatFilter.value!!, websiteFilter.value!!, sortType.value!!) filter(queryFilter.value!!, formatFilter.value!!, websiteFilter.value!!, sortType.value!!)
}) }
} }
fun getFilteredList() : LiveData<List<HistoryItem>>{ fun getFilteredList() : LiveData<List<HistoryItem>>{
return _items; return _items
} }
fun setSorting(sort: HistorySort){ fun setSorting(sort: HistorySort){
@ -69,7 +62,7 @@ class HistoryViewModel(application: Application) : AndroidViewModel(application)
formatFilter.value = filter formatFilter.value = filter
} }
fun filter(query : String, format : String, site : String, sort: HistorySort) = viewModelScope.launch(Dispatchers.IO){ private fun filter(query : String, format : String, site : String, sort: HistorySort) = viewModelScope.launch(Dispatchers.IO){
_items.postValue(repository.getFiltered(query, format, site, sort)) _items.postValue(repository.getFiltered(query, format, site, sort))
} }
@ -94,7 +87,7 @@ class HistoryViewModel(application: Application) : AndroidViewModel(application)
} }
fun update(item: HistoryItem) = viewModelScope.launch(Dispatchers.IO){ fun update(item: HistoryItem) = viewModelScope.launch(Dispatchers.IO){
repository.update(item); repository.update(item)
} }
fun clearDeleted() = viewModelScope.launch(Dispatchers.IO) { fun clearDeleted() = viewModelScope.launch(Dispatchers.IO) {

View file

@ -0,0 +1,100 @@
package com.deniscerri.ytdlnis.receiver
import android.content.Context
import android.content.Intent
import android.graphics.drawable.ColorDrawable
import android.net.Uri
import android.os.Bundle
import android.util.Log
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 androidx.activity.ComponentActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
class ShareActivity : ComponentActivity() {
private lateinit var binding: ActivityMainBinding
lateinit var context: Context
private lateinit var resultViewModel: ResultViewModel
private lateinit var downloadViewModel: DownloadViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
WindowCompat.setDecorFitsSystemWindows(window, false)
ViewCompat.setOnApplyWindowInsetsListener(window.decorView) { v, insets ->
v.setPadding(0, 0, 0, 0)
insets
}
window.setBackgroundDrawable(ColorDrawable(0))
window.setLayout(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT
)
handleIntents(intent)
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
handleIntents(intent)
}
private fun handleIntents(intent: Intent) {
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 l = listOf(*textBuilder.toString().split("\n").toTypedArray())
val lines = LinkedList(l)
} catch (e: Exception) {
e.printStackTrace()
}
} else {
//TODO
}
}
}
private fun exit() {
finishAffinity()
exitProcess(0)
}
companion object {
private const val TAG = "ShareActivity"
private lateinit var moreFragment: MoreFragment
private lateinit var fm: FragmentManager
}
}

View file

@ -130,9 +130,11 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
}else{ }else{
downloadAllFabCoordinator!!.visibility = GONE downloadAllFabCoordinator!!.visibility = GONE
} }
}else if (sharedPreferences!!.getBoolean("download_card", true)){ }else if (it.size == 1){
if(it.size == 1 && !firstBoot && parentFragmentManager.findFragmentByTag("downloadSingleSheet") == null){ if (sharedPreferences!!.getBoolean("download_card", true)){
showSingleDownloadSheet(it[0], "audio") if(it.size == 1 && !firstBoot && parentFragmentManager.findFragmentByTag("downloadSingleSheet") == null){
showSingleDownloadSheet(it[0], DownloadViewModel.Type.video)
}
} }
} }
firstBoot = false firstBoot = false
@ -321,8 +323,8 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
} }
@SuppressLint("ResourceType") @SuppressLint("ResourceType")
override fun onButtonClick(videoURL: String, type: String?) { override fun onButtonClick(videoURL: String, type: DownloadViewModel.Type?) {
Log.e(TAG, type!! + " " + videoURL) Log.e(TAG, type.toString() + " " + videoURL)
val item = resultsList!!.find { it?.url == videoURL } val item = resultsList!!.find { it?.url == videoURL }
Log.e(TAG, resultsList!![0].toString() + " " + videoURL) Log.e(TAG, resultsList!![0].toString() + " " + videoURL)
val btn = recyclerView!!.findViewWithTag<MaterialButton>("""${item?.url}##$type""") val btn = recyclerView!!.findViewWithTag<MaterialButton>("""${item?.url}##$type""")
@ -339,7 +341,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)
showSingleDownloadSheet(item!!, type) showSingleDownloadSheet(item!!, type!!)
} else { } else {
// downloadQueue!!.add(vid) // downloadQueue!!.add(vid)
// updateDownloadingStatusOnResult(vid, type, true) // updateDownloadingStatusOnResult(vid, type, true)
@ -350,13 +352,9 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
} }
} }
private fun showSingleDownloadSheet(resultItem : ResultItem, type: String){ private fun showSingleDownloadSheet(resultItem : ResultItem, type: DownloadViewModel.Type){
val downloadItem = downloadViewModel.createDownloadItemFromResult(resultItem, type) val bottomSheet = DownloadBottomSheetDialog(resultItem, type)
downloadViewModel.putDownloadsForProcessing(listOf(resultItem), listOf(downloadItem)).observe(viewLifecycleOwner) { bottomSheet.show(parentFragmentManager, "downloadSingleSheet")
downloadItem.id = it[0]
val bottomSheet = DownloadBottomSheetDialog(downloadItem)
bottomSheet.show(parentFragmentManager, "downloadSingleSheet")
}
} }
@ -393,7 +391,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
downloadFabs!!.visibility = VISIBLE downloadFabs!!.visibility = VISIBLE
} else { } else {
downloadFabs!!.visibility = GONE downloadFabs!!.visibility = GONE
if (resultsList!!.size > 1 && resultsList!![1]!!.playlistTitle.isNotEmpty()) { if (resultsList!!.size > 1 && resultsList!![1]!!.playlistTitle != getString(R.string.trendingPlaylist)) {
downloadAllFabCoordinator!!.visibility = VISIBLE downloadAllFabCoordinator!!.visibility = VISIBLE
} }
} }
@ -405,7 +403,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
} catch (e: Exception) {""} } catch (e: Exception) {""}
if (viewIdName.isNotEmpty()) { if (viewIdName.isNotEmpty()) {
if (viewIdName == "downloadSelected") { if (viewIdName == "downloadSelected") {
val downloadList = downloadViewModel.turnResultItemstoDownloadItems(selectedObjects!!) val downloadList = downloadViewModel.turnResultItemsToDownloadItems(selectedObjects!!)
downloadViewModel.putDownloadsForProcessing(selectedObjects!!, downloadList).observe(viewLifecycleOwner) { downloadViewModel.putDownloadsForProcessing(selectedObjects!!, downloadList).observe(viewLifecycleOwner) {
it.forEachIndexed { i, itemID -> it.forEachIndexed { i, itemID ->
downloadList[i].id = itemID downloadList[i].id = itemID
@ -415,7 +413,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
} }
} }
if (viewIdName == "downloadAll") { if (viewIdName == "downloadAll") {
val downloadList = downloadViewModel.turnResultItemstoDownloadItems(resultsList!!) val downloadList = downloadViewModel.turnResultItemsToDownloadItems(resultsList!!)
downloadViewModel.putDownloadsForProcessing(resultsList!!, downloadList).observe(viewLifecycleOwner) { downloadViewModel.putDownloadsForProcessing(resultsList!!, downloadList).observe(viewLifecycleOwner) {
it.forEachIndexed { i, itemID -> it.forEachIndexed { i, itemID ->
downloadList[i].id = itemID downloadList[i].id = itemID

View file

@ -12,6 +12,7 @@ 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.models.ResultItem
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetBehavior
@ -24,23 +25,17 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel.Type import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel.Type
class ConfigureDownloadBottomSheetDialog(private val downloadItem: DownloadItem) : BottomSheetDialogFragment() { class ConfigureDownloadBottomSheetDialog(private val resultItem: ResultItem, private val type: Type) : BottomSheetDialogFragment() {
private lateinit var tabLayout: TabLayout private lateinit var tabLayout: TabLayout
private lateinit var viewPager2: ViewPager2 private lateinit var viewPager2: ViewPager2
private lateinit var fragmentAdapter : DownloadFragmentAdapter private lateinit var fragmentAdapter : DownloadFragmentAdapter
private lateinit var currentItem : DownloadItem
private lateinit var downloadViewModel: DownloadViewModel private lateinit var downloadViewModel: DownloadViewModel
private lateinit var resultViewModel: ResultViewModel private lateinit var resultViewModel: ResultViewModel
private val audioDownloadItem =clone(downloadItem)
private val videoDownloadItem = clone(downloadItem)
private val commandDownloadItem = clone(downloadItem)
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java] downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java] resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
currentItem = downloadViewModel.cloneDownloadItem(downloadItem)
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -61,23 +56,23 @@ class ConfigureDownloadBottomSheetDialog(private val downloadItem: DownloadItem)
val fragmentManager = parentFragmentManager val fragmentManager = parentFragmentManager
fragmentAdapter = DownloadFragmentAdapter( fragmentAdapter = DownloadFragmentAdapter(
audioDownloadItem,videoDownloadItem,commandDownloadItem, resultItem,
fragmentManager, fragmentManager,
lifecycle lifecycle
) )
viewPager2.adapter = fragmentAdapter viewPager2.adapter = fragmentAdapter
viewPager2.isSaveFromParentEnabled = false viewPager2.isSaveFromParentEnabled = false
when(downloadItem.type) { when(type) {
"audio" -> { Type.audio -> {
tabLayout.selectTab(tabLayout.getTabAt(0)) tabLayout.selectTab(tabLayout.getTabAt(0))
viewPager2.setCurrentItem(0, false) viewPager2.setCurrentItem(0, false)
} }
"video" -> { Type.video -> {
tabLayout.selectTab(tabLayout.getTabAt(1)) tabLayout.selectTab(tabLayout.getTabAt(1))
viewPager2.setCurrentItem(1, false) viewPager2.setCurrentItem(1, false)
} }
"command" -> { Type.command -> {
tabLayout.selectTab(tabLayout.getTabAt(2)) tabLayout.selectTab(tabLayout.getTabAt(2))
viewPager2.setCurrentItem(2, false) viewPager2.setCurrentItem(2, false)
} }
@ -110,18 +105,29 @@ class ConfigureDownloadBottomSheetDialog(private val downloadItem: DownloadItem)
val ok = view.findViewById<Button>(R.id.bottom_sheet_ok) val ok = view.findViewById<Button>(R.id.bottom_sheet_ok)
ok!!.setOnClickListener { ok!!.setOnClickListener {
when(tabLayout.selectedTabPosition){
0 -> downloadViewModel.updateDownload(audioDownloadItem) val item : DownloadItem = when(tabLayout.selectedTabPosition){
1 -> downloadViewModel.updateDownload(videoDownloadItem) 0 -> {
else -> downloadViewModel.updateDownload(commandDownloadItem) val f = fragmentManager.findFragmentByTag("f0") as DownloadAudioFragment
f.downloadItem
}
1 -> {
val f = fragmentManager.findFragmentByTag("f1") as DownloadVideoFragment
f.downloadItem
}
else -> {
val f = fragmentManager.findFragmentByTag("f2") as DownloadCommandFragment
f.downloadItem
}
} }
downloadViewModel.updateDownload(item)
dismiss() dismiss()
} }
} }
override fun onCancel(dialog: DialogInterface) { override fun onCancel(dialog: DialogInterface) {
super.onCancel(dialog) super.onCancel(dialog)
returnPreviousState(); //returnPreviousState();
cleanUp() cleanUp()
} }
@ -130,16 +136,16 @@ class ConfigureDownloadBottomSheetDialog(private val downloadItem: DownloadItem)
cleanUp() cleanUp()
} }
private fun returnPreviousState(){ // private fun returnPreviousState(){
CoroutineScope(Dispatchers.IO).launch { // CoroutineScope(Dispatchers.IO).launch {
val result = resultViewModel.getItemByURL(currentItem.url) // val result = resultViewModel.getItemByURL(currentItem.url)
result.title = currentItem.title // result.title = currentItem.title
result.author = currentItem.author // result.author = currentItem.author
Log.e("TAG, ", currentItem.toString()) // Log.e("TAG, ", currentItem.toString())
resultViewModel.update(result) // resultViewModel.update(result)
downloadViewModel.updateDownload(currentItem) // downloadViewModel.updateDownload(currentItem)
} // }
} // }
private fun cleanUp(){ private fun cleanUp(){
parentFragmentManager.beginTransaction().remove(parentFragmentManager.findFragmentByTag("configureDownloadSingleSheet")!!).commit() parentFragmentManager.beginTransaction().remove(parentFragmentManager.findFragmentByTag("configureDownloadSingleSheet")!!).commit()
@ -150,10 +156,5 @@ class ConfigureDownloadBottomSheetDialog(private val downloadItem: DownloadItem)
} }
} }
private fun clone(item: DownloadItem) : DownloadItem {
val stringItem = Gson().toJson(item, DownloadItem::class.java)
return Gson().fromJson(stringItem, DownloadItem::class.java)
}
} }

View file

@ -17,6 +17,8 @@ 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.repository.DownloadRepository
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel 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
@ -28,7 +30,7 @@ import kotlinx.coroutines.withContext
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel.Type import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel.Type
class DownloadAudioFragment(private var downloadItem: DownloadItem) : Fragment() { class DownloadAudioFragment(private var resultItem: ResultItem) : 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
@ -41,7 +43,7 @@ class DownloadAudioFragment(private var downloadItem: DownloadItem) : Fragment()
private lateinit var author : TextInputLayout private lateinit var author : TextInputLayout
private lateinit var saveDir : TextInputLayout private lateinit var saveDir : TextInputLayout
lateinit var downloadItem: DownloadItem
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
@ -52,20 +54,15 @@ class DownloadAudioFragment(private var downloadItem: DownloadItem) : Fragment()
fragmentView = inflater.inflate(R.layout.fragment_download_audio, container, false) fragmentView = inflater.inflate(R.layout.fragment_download_audio, container, false)
activity = getActivity() activity = getActivity()
mainActivity = activity as MainActivity? mainActivity = activity as MainActivity?
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java] downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
downloadItem = downloadViewModel.createDownloadItemFromResult(resultItem, Type.audio)
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)
downloadItem.type = "audio"
lifecycleScope.launch { lifecycleScope.launch {
val resultItem = withContext(Dispatchers.IO){
resultViewModel.getItemByURL(downloadItem.url)
}
val sharedPreferences = val sharedPreferences =
requireContext().getSharedPreferences("root_preferences", Activity.MODE_PRIVATE) requireContext().getSharedPreferences("root_preferences", Activity.MODE_PRIVATE)
@ -110,10 +107,19 @@ class DownloadAudioFragment(private var downloadItem: DownloadItem) : Fragment()
} }
val format = view.findViewById<TextInputLayout>(R.id.format) val format = view.findViewById<TextInputLayout>(R.id.format)
if (resultItem.formats.isEmpty()) { val 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)
val containerAutoCompleteTextView =
view.findViewById<AutoCompleteTextView>(R.id.container_textview)
if (formats.isEmpty()) {
format.visibility = View.GONE format.visibility = View.GONE
} else { } else {
val formatTitles = resultItem.formats.map { val formatTitles = formats.map {
if (it.format_note.contains("AUDIO_QUALITY_")) { if (it.format_note.contains("AUDIO_QUALITY_")) {
it.format_note.replace( it.format_note.replace(
"AUDIO_QUALITY_", "AUDIO_QUALITY_",
@ -136,19 +142,24 @@ class DownloadAudioFragment(private var downloadItem: DownloadItem) : Fragment()
) )
) )
if (formatTitles.isNotEmpty()) { if (formatTitles.isNotEmpty()) {
autoCompleteTextView!!.setText(formatTitles[resultItem.formats.lastIndex], false) autoCompleteTextView!!.setText(formatTitles[formats.lastIndex], false)
} }
(format!!.editText as AutoCompleteTextView?)!!.onItemClickListener = (format!!.editText as AutoCompleteTextView?)!!.onItemClickListener =
AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, index: Int, _: Long -> AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, index: Int, _: Long ->
downloadItem.format.format_note = resultItem.formats[index].format_note downloadItem.format.format_note = formats[index].format_note
downloadItem.format.format_id = resultItem.formats[index].format_id 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)
}
} }
} }
val containers = requireContext().resources.getStringArray(R.array.audio_containers)
val container = view.findViewById<TextInputLayout>(R.id.downloadContainer)
val containerAutoCompleteTextView =
view.findViewById<AutoCompleteTextView>(R.id.container_textview)
container?.isEnabled = true container?.isEnabled = true
containerAutoCompleteTextView?.setAdapter( containerAutoCompleteTextView?.setAdapter(
@ -158,9 +169,8 @@ class DownloadAudioFragment(private var downloadItem: DownloadItem) : Fragment()
containers containers
) )
) )
Log.e("aa", downloadItem.format.container) val selectedContainer: String = if (containers.contains(formats[formats.lastIndex].container)){
val selectedContainer: String = if (containers.contains(downloadItem.format.container)){ formats[formats.lastIndex].container
downloadItem.format.container
}else{ }else{
containers[0] containers[0]
} }

View file

@ -4,74 +4,71 @@ 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 android.view.View
import android.widget.Button import android.widget.Button
import android.widget.FrameLayout
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.models.ResultItem
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel.Type
import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.google.android.material.button.MaterialButton import com.google.android.material.button.MaterialButton
import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout
import com.google.gson.Gson
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel.Type
class DownloadBottomSheetDialog(private val downloadItem: DownloadItem) : BottomSheetDialogFragment() {
class DownloadBottomSheetDialog(private val resultItem: ResultItem, private val type: Type) : BottomSheetDialogFragment() {
private lateinit var tabLayout: TabLayout private lateinit var tabLayout: TabLayout
private lateinit var viewPager2: ViewPager2 private lateinit var viewPager2: ViewPager2
private lateinit var fragmentAdapter : DownloadFragmentAdapter private lateinit var fragmentAdapter : DownloadFragmentAdapter
private lateinit var downloadViewModel: DownloadViewModel private lateinit var downloadViewModel: DownloadViewModel
private lateinit var behavior: BottomSheetBehavior<View>
private var downloadType = Type.VIDEO
private val audioDownloadItem = clone(downloadItem)
private val videoDownloadItem = clone(downloadItem)
private val commandDownloadItem = clone(downloadItem)
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java] downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val behavior = BottomSheetBehavior.from(view.parent as View)
behavior.state = BottomSheetBehavior.STATE_EXPANDED
}
@SuppressLint("RestrictedApi") @SuppressLint("RestrictedApi")
override fun setupDialog(dialog: Dialog, style: Int) { override fun setupDialog(dialog: Dialog, style: Int) {
super.setupDialog(dialog, style) super.setupDialog(dialog, style)
val view = LayoutInflater.from(context).inflate(R.layout.download_bottom_sheet, null) val view = LayoutInflater.from(context).inflate(R.layout.download_bottom_sheet, null)
dialog.setContentView(view) dialog.setContentView(view)
Log.e("aaa", downloadItem.toString()) dialog.setOnShowListener {
behavior = BottomSheetBehavior.from(view.parent as View)
behavior.skipCollapsed = true
behavior.state = BottomSheetBehavior.STATE_EXPANDED
}
tabLayout = view.findViewById(R.id.download_tablayout) tabLayout = view.findViewById(R.id.download_tablayout)
viewPager2 = view.findViewById(R.id.download_viewpager) viewPager2 = view.findViewById(R.id.download_viewpager)
val fragmentManager = parentFragmentManager val fragmentManager = parentFragmentManager
fragmentAdapter = DownloadFragmentAdapter( fragmentAdapter = DownloadFragmentAdapter(
audioDownloadItem, videoDownloadItem, commandDownloadItem, resultItem,
fragmentManager, fragmentManager,
lifecycle lifecycle
) )
viewPager2.adapter = fragmentAdapter viewPager2.adapter = fragmentAdapter
viewPager2.isSaveFromParentEnabled = false viewPager2.isSaveFromParentEnabled = false
when(downloadItem.type) { when(type) {
"audio" -> { Type.audio -> {
tabLayout.selectTab(tabLayout.getTabAt(0)) tabLayout.selectTab(tabLayout.getTabAt(0))
viewPager2.setCurrentItem(0, false) viewPager2.setCurrentItem(0, false)
} }
"video" -> { Type.video -> {
tabLayout.selectTab(tabLayout.getTabAt(1)) tabLayout.selectTab(tabLayout.getTabAt(1))
viewPager2.setCurrentItem(1, false) viewPager2.setCurrentItem(1, false)
} }
"command" -> { Type.command -> {
tabLayout.selectTab(tabLayout.getTabAt(2)) tabLayout.selectTab(tabLayout.getTabAt(2))
viewPager2.setCurrentItem(2, false) viewPager2.setCurrentItem(2, false)
} }
@ -95,6 +92,16 @@ class DownloadBottomSheetDialog(private val downloadItem: DownloadItem) : Bottom
tabLayout.selectTab(tabLayout.getTabAt(position)) tabLayout.selectTab(tabLayout.getTabAt(position))
} }
}) })
viewPager2.setPageTransformer { v, _ ->
v.post {
val wMeasureSpec = View.MeasureSpec.makeMeasureSpec(v.width, View.MeasureSpec.EXACTLY)
val hMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
v.measure(wMeasureSpec, hMeasureSpec)
viewPager2.layoutParams = (viewPager2.layoutParams).also { lp -> lp.height = v.measuredHeight }
viewPager2.invalidate()
}
}
val cancelBtn = view.findViewById<MaterialButton>(R.id.bottomsheet_cancel_button) val cancelBtn = view.findViewById<MaterialButton>(R.id.bottomsheet_cancel_button)
cancelBtn.setOnClickListener{ cancelBtn.setOnClickListener{
@ -103,13 +110,21 @@ class DownloadBottomSheetDialog(private val downloadItem: DownloadItem) : Bottom
val download = view.findViewById<Button>(R.id.bottomsheet_download_button) val download = view.findViewById<Button>(R.id.bottomsheet_download_button)
download!!.setOnClickListener { download!!.setOnClickListener {
Log.e("aa", tabLayout.selectedTabPosition.toString()) val item: DownloadItem = when(tabLayout.selectedTabPosition){
val item: List<DownloadItem> = when(tabLayout.selectedTabPosition){ 0 -> {
0 -> listOf(audioDownloadItem) val f = fragmentManager.findFragmentByTag("f0") as DownloadAudioFragment
1 -> listOf(videoDownloadItem) f.downloadItem
else -> listOf(commandDownloadItem) }
1 -> {
val f = fragmentManager.findFragmentByTag("f1") as DownloadVideoFragment
f.downloadItem
}
else -> {
val f = fragmentManager.findFragmentByTag("f2") as DownloadCommandFragment
f.downloadItem
}
} }
downloadViewModel.queueDownloads(item) downloadViewModel.queueDownloads(listOf(item))
dismiss() dismiss()
} }
} }
@ -132,17 +147,6 @@ class DownloadBottomSheetDialog(private val downloadItem: DownloadItem) : Bottom
parentFragmentManager.beginTransaction().remove(parentFragmentManager.findFragmentByTag("f$i")!!).commit() parentFragmentManager.beginTransaction().remove(parentFragmentManager.findFragmentByTag("f$i")!!).commit()
} }
} }
downloadViewModel.deleteSingleProcessing(downloadItem)
} }
fun updateType(type: Type){
downloadType = type
}
private fun clone(item: DownloadItem) : DownloadItem {
val stringItem = Gson().toJson(item, DownloadItem::class.java)
return Gson().fromJson(stringItem, DownloadItem::class.java)
}
} }

View file

@ -10,14 +10,17 @@ 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.Format import com.deniscerri.ytdlnis.database.models.Format
import com.deniscerri.ytdlnis.database.models.ResultItem
import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding
class DownloadCommandFragment(private val downloadItem: DownloadItem) : Fragment() { class DownloadCommandFragment(private val resultItem: ResultItem) : 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
lateinit var downloadItem : DownloadItem
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,

View file

@ -7,12 +7,11 @@ 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.deniscerri.ytdlnis.database.models.ResultItem
import com.google.gson.Gson import com.google.gson.Gson
class DownloadFragmentAdapter ( class DownloadFragmentAdapter (
private val audioDownloadItem : DownloadItem, private val resultItem: ResultItem,
private val videoDownloadItem : DownloadItem,
private val commandDownloadItem : DownloadItem,
fragmentManager : FragmentManager, fragmentManager : FragmentManager,
lifecycle : Lifecycle lifecycle : Lifecycle
) : FragmentStateAdapter(fragmentManager, lifecycle) { ) : FragmentStateAdapter(fragmentManager, lifecycle) {
@ -24,13 +23,13 @@ class DownloadFragmentAdapter (
override fun createFragment(position: Int): Fragment { override fun createFragment(position: Int): Fragment {
when (position) { when (position) {
0 -> { 0 -> {
return DownloadAudioFragment(audioDownloadItem) return DownloadAudioFragment(resultItem)
} }
1 -> { 1 -> {
return DownloadVideoFragment(videoDownloadItem) return DownloadVideoFragment(resultItem)
} }
} }
return DownloadCommandFragment(commandDownloadItem) return DownloadCommandFragment(resultItem)
} }
} }

View file

@ -34,6 +34,7 @@ import kotlinx.coroutines.withContext
class DownloadMultipleBottomSheetDialog(private val items: List<DownloadItem>) : BottomSheetDialogFragment(), ConfigureMultipleDownloadsAdapter.OnItemClickListener, View.OnClickListener { class DownloadMultipleBottomSheetDialog(private val items: List<DownloadItem>) : BottomSheetDialogFragment(), ConfigureMultipleDownloadsAdapter.OnItemClickListener, View.OnClickListener {
private lateinit var downloadViewModel: DownloadViewModel private lateinit var downloadViewModel: DownloadViewModel
private lateinit var resultViewModel: ResultViewModel
private lateinit var listAdapter : ConfigureMultipleDownloadsAdapter private lateinit var listAdapter : ConfigureMultipleDownloadsAdapter
private lateinit var recyclerView: RecyclerView private lateinit var recyclerView: RecyclerView
@ -41,6 +42,7 @@ class DownloadMultipleBottomSheetDialog(private val items: List<DownloadItem>) :
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java] downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -110,7 +112,10 @@ class DownloadMultipleBottomSheetDialog(private val items: List<DownloadItem>) :
val downloadItem = withContext(Dispatchers.IO){ val downloadItem = withContext(Dispatchers.IO){
downloadViewModel.getItemByID(itemID) downloadViewModel.getItemByID(itemID)
} }
val bottomSheet = ConfigureDownloadBottomSheetDialog(downloadItem) val resultItem = withContext(Dispatchers.IO){
resultViewModel.getItemByURL(downloadItem.url)
}
val bottomSheet = ConfigureDownloadBottomSheetDialog(resultItem, DownloadViewModel.Type.video)
bottomSheet.show(parentFragmentManager, "configureDownloadSingleSheet") bottomSheet.show(parentFragmentManager, "configureDownloadSingleSheet")
} }
} }

View file

@ -17,6 +17,7 @@ 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.Format 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
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
@ -29,7 +30,7 @@ import kotlinx.coroutines.withContext
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel.Type import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel.Type
class DownloadVideoFragment(private val downloadItem: DownloadItem) : Fragment() { class DownloadVideoFragment(private val resultItem: ResultItem) : 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
@ -42,7 +43,7 @@ class DownloadVideoFragment(private val downloadItem: DownloadItem) : Fragment()
private lateinit var author : TextInputLayout private lateinit var author : TextInputLayout
private lateinit var saveDir : TextInputLayout private lateinit var saveDir : TextInputLayout
lateinit var downloadItem: DownloadItem
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
@ -53,8 +54,8 @@ class DownloadVideoFragment(private val downloadItem: DownloadItem) : Fragment()
fragmentView = inflater.inflate(R.layout.fragment_download_video, container, false) fragmentView = inflater.inflate(R.layout.fragment_download_video, container, false)
activity = getActivity() activity = getActivity()
mainActivity = activity as MainActivity? mainActivity = activity as MainActivity?
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java] downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
downloadItem = downloadViewModel.createDownloadItemFromResult(resultItem, Type.video)
fileUtil = FileUtil() fileUtil = FileUtil()
return fragmentView return fragmentView
} }
@ -62,16 +63,9 @@ class DownloadVideoFragment(private val downloadItem: DownloadItem) : Fragment()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
downloadItem.type = "video"
lifecycleScope.launch { lifecycleScope.launch {
val resultItem = withContext(Dispatchers.IO){
resultViewModel.getItemByURL(downloadItem.url)
}
val type = downloadItem.type
val sharedPreferences = requireContext().getSharedPreferences("root_preferences", Activity.MODE_PRIVATE) val sharedPreferences = requireContext().getSharedPreferences("root_preferences", Activity.MODE_PRIVATE)
val editor = sharedPreferences.edit()
try { try {
title = view.findViewById(R.id.title_textinput) title = view.findViewById(R.id.title_textinput)
title.editText!!.setText(downloadItem.title) title.editText!!.setText(downloadItem.title)
@ -80,9 +74,6 @@ class DownloadVideoFragment(private val downloadItem: DownloadItem) : Fragment()
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()
//esultViewModel.update(resultItem)
//downloadviewmodel.updateDownload(downloadItem)
} }
}) })
@ -93,9 +84,6 @@ class DownloadVideoFragment(private val downloadItem: DownloadItem) : Fragment()
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()
//resultViewModel.update(resultItem)
//downloadviewmodel.updateDownload(downloadItem)
} }
}) })
@ -105,7 +93,6 @@ class DownloadVideoFragment(private val downloadItem: DownloadItem) : Fragment()
getString(R.string.video_path) getString(R.string.video_path)
) )
downloadItem.downloadPath = downloadPath!! downloadItem.downloadPath = downloadPath!!
//downloadviewmodel.updateDownload(downloadItem)
saveDir.editText!!.setText( saveDir.editText!!.setText(
fileUtil.formatPath(downloadPath) fileUtil.formatPath(downloadPath)
) )
@ -133,6 +120,7 @@ class DownloadVideoFragment(private val downloadItem: DownloadItem) : Fragment()
downloadItem.format = formats[formats.lastIndex] downloadItem.format = formats[formats.lastIndex]
val containers = requireContext().resources.getStringArray(R.array.video_containers)
val format = view.findViewById<TextInputLayout>(R.id.format) val format = view.findViewById<TextInputLayout>(R.id.format)
val autoCompleteTextView = val autoCompleteTextView =
@ -147,15 +135,7 @@ class DownloadVideoFragment(private val downloadItem: DownloadItem) : Fragment()
if (formatTitles.isNotEmpty()) { if (formatTitles.isNotEmpty()) {
autoCompleteTextView!!.setText(formatTitles[formats.lastIndex], false) 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
//downloadviewmodel.updateDownload(downloadItem)
}
val containers = requireContext().resources.getStringArray(R.array.video_containers)
val container = view.findViewById<TextInputLayout>(R.id.downloadContainer) val container = view.findViewById<TextInputLayout>(R.id.downloadContainer)
val containerAutoCompleteTextView = val containerAutoCompleteTextView =
view.findViewById<AutoCompleteTextView>(R.id.container_textview) view.findViewById<AutoCompleteTextView>(R.id.container_textview)
@ -170,12 +150,29 @@ class DownloadVideoFragment(private val downloadItem: DownloadItem) : Fragment()
) )
val selectedContainer: String = downloadItem.format.container val selectedContainer: String = downloadItem.format.container
containerAutoCompleteTextView!!.setText(selectedContainer, false) 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
if (containers.contains(formats[index].container)){
downloadItem.format.container = formats[index].container
containerAutoCompleteTextView.setText(formats[index].container, false)
}
}
(container!!.editText as AutoCompleteTextView?)!!.onItemClickListener = (container!!.editText as AutoCompleteTextView?)!!.onItemClickListener =
AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, index: Int, _: Long -> AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, index: Int, _: Long ->
downloadItem.format.container = containers[index] downloadItem.format.container = containers[index]
//downloadviewmodel.updateDownload(downloadItem)
} }
val embedSubs = view.findViewById<Chip>(R.id.embed_subtitles) val embedSubs = view.findViewById<Chip>(R.id.embed_subtitles)
embedSubs!!.isChecked = embedSubs.isChecked embedSubs!!.isChecked = embedSubs.isChecked
embedSubs.setOnClickListener { embedSubs.setOnClickListener {
@ -194,6 +191,11 @@ class DownloadVideoFragment(private val downloadItem: DownloadItem) : Fragment()
downloadItem.SaveThumb = saveThumbnail.isChecked downloadItem.SaveThumb = saveThumbnail.isChecked
} }
val removeAudio = view.findViewById<Chip>(R.id.remove_audio)
removeAudio.setOnClickListener {
downloadItem.removeAudio = removeAudio.isChecked
}
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
} }
@ -216,4 +218,5 @@ class DownloadVideoFragment(private val downloadItem: DownloadItem) : Fragment()
saveDir.editText?.setText(fileUtil.formatPath(result.data?.data.toString()), TextView.BufferType.EDITABLE) saveDir.editText?.setText(fileUtil.formatPath(result.data?.data.toString()), TextView.BufferType.EDITABLE)
} }
} }
} }

View file

@ -18,6 +18,7 @@ import com.deniscerri.ytdlnis.database.DBManager
import com.deniscerri.ytdlnis.database.models.DownloadItem import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.HistoryItem import com.deniscerri.ytdlnis.database.models.HistoryItem
import com.deniscerri.ytdlnis.database.repository.DownloadRepository import com.deniscerri.ytdlnis.database.repository.DownloadRepository
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.util.FileUtil import com.deniscerri.ytdlnis.util.FileUtil
import com.deniscerri.ytdlnis.util.NotificationUtil import com.deniscerri.ytdlnis.util.NotificationUtil
import com.yausername.youtubedl_android.YoutubeDL import com.yausername.youtubedl_android.YoutubeDL
@ -104,7 +105,7 @@ class DownloadWorker(
request.addCommands(listOf("--replace-in-metadata","uploader",".*.",downloadItem.author)); request.addCommands(listOf("--replace-in-metadata","uploader",".*.",downloadItem.author));
when(type){ when(type){
"audio" -> { DownloadViewModel.Type.audio -> {
request.addOption("-x") request.addOption("-x")
var audioQualityId : String = downloadItem.format.format_id var audioQualityId : String = downloadItem.format.format_id
if (audioQualityId == "0" || audioQualityId.isEmpty()) audioQualityId = "ba" if (audioQualityId == "0" || audioQualityId.isEmpty()) audioQualityId = "ba"
@ -142,7 +143,7 @@ class DownloadWorker(
} }
request.addOption("-o", tempFileDir.absolutePath + "/%(uploader)s - %(title)s.%(ext)s") request.addOption("-o", tempFileDir.absolutePath + "/%(uploader)s - %(title)s.%(ext)s")
} }
"video" -> { DownloadViewModel.Type.video -> {
val addChapters = sharedPreferences.getBoolean("add_chapters", false) val addChapters = sharedPreferences.getBoolean("add_chapters", false)
if (addChapters) { if (addChapters) {
request.addOption("--sponsorblock-mark", "all") request.addOption("--sponsorblock-mark", "all")
@ -157,8 +158,9 @@ class DownloadWorker(
if (videoFormatID.isNotEmpty()) { if (videoFormatID.isNotEmpty()) {
if (videoFormatID == "Best Quality") videoFormatID = "bestvideo" if (videoFormatID == "Best Quality") videoFormatID = "bestvideo"
else if (videoFormatID == "Worst Quality") videoFormatID = "worst" else if (videoFormatID == "Worst Quality") videoFormatID = "worst"
formatArgument = videoFormatID + if (downloadItem.removeAudio) "" else "+bestaudio" formatArgument = videoFormatID + if (downloadItem.removeAudio) "" else "+bestaudio/$videoFormatID"
} }
Log.e(TAG, formatArgument)
request.addOption("-f", formatArgument) request.addOption("-f", formatArgument)
val format = downloadItem.format.container val format = downloadItem.format.container
if(format.isNotEmpty()){ if(format.isNotEmpty()){
@ -172,7 +174,7 @@ class DownloadWorker(
} }
request.addOption("-o", tempFileDir.absolutePath + "/%(uploader)s - %(title)s.%(ext)s") request.addOption("-o", tempFileDir.absolutePath + "/%(uploader)s - %(title)s.%(ext)s")
} }
"command" -> { DownloadViewModel.Type.command -> {
val commandRegex = "\"([^\"]*)\"|(\\S+)" val commandRegex = "\"([^\"]*)\"|(\\S+)"
val command = commandTemplateDao.getTemplate(downloadItem.format.format_id.toLong()) val command = commandTemplateDao.getTemplate(downloadItem.format.format_id.toLong())
val m = Pattern.compile(commandRegex).matcher(command.content) val m = Pattern.compile(commandRegex).matcher(command.content)

View file

@ -5,21 +5,35 @@
android:orientation="vertical" android:orientation="vertical"
android:layout_height="match_parent"> android:layout_height="match_parent">
<TextView <LinearLayout
android:id="@+id/bottom_sheet_title"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:textSize="25sp"
android:padding="20dp"
android:layout_gravity="center"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/configure_download" /> android:padding="20dp"
android:paddingBottom="0dp"
android:orientation="vertical">
<TextView
android:id="@+id/bottom_sheet_title"
android:layout_width="wrap_content"
android:textSize="25sp"
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:layout_height="wrap_content"
android:text="@string/configure_download" />
</LinearLayout>
<com.google.android.material.tabs.TabLayout <com.google.android.material.tabs.TabLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:backgroundTint="@android:color/transparent" android:backgroundTint="@android:color/transparent"
app:tabMode="scrollable" app:tabMode="scrollable"
app:tabGravity="center" android:layout_margin="10dp"
app:tabGravity="fill"
android:id="@+id/download_tablayout" > android:id="@+id/download_tablayout" >
<com.google.android.material.tabs.TabItem <com.google.android.material.tabs.TabItem
@ -41,11 +55,14 @@
</com.google.android.material.tabs.TabLayout> </com.google.android.material.tabs.TabLayout>
<androidx.viewpager2.widget.ViewPager2 <androidx.viewpager2.widget.ViewPager2
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:id="@+id/download_viewpager" /> android:id="@+id/download_viewpager" />
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"