added multiple pages to settings & more...
Dismiss download multiple sheet when all items are dismissed Add backup for history, queued downloads, cancelled downloads, cookies, shortcuts, templates Add long click format to show details in audio video tab removed check icon from checked state in material cards Implement format fetching on playlist from invidious Invert selected items in playlist bottom sheet Make filename templates for both audio and video and add them as a chip on both tabs Fixed errors when there is no internet and u ask for the latest version of the app Fixed "default" format error
This commit is contained in:
parent
510798d492
commit
880abd503e
62 changed files with 2242 additions and 1324 deletions
|
|
@ -58,7 +58,7 @@ android {
|
|||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled true
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
debuggable false
|
||||
signingConfig signingConfigs.debug
|
||||
|
|
@ -178,4 +178,5 @@ dependencies {
|
|||
implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0'
|
||||
implementation "com.google.android.exoplayer:exoplayer:2.18.6"
|
||||
implementation 'it.xabaras.android:recyclerview-swipedecorator:1.4'
|
||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.6.1"
|
||||
}
|
||||
|
|
|
|||
1
app/proguard-rules.pro
vendored
1
app/proguard-rules.pro
vendored
|
|
@ -61,7 +61,6 @@
|
|||
public <init>(android.content.Context,androidx.work.WorkerParameters);
|
||||
}
|
||||
|
||||
-dontobfuscate
|
||||
-dontwarn com.google.android.exoplayer2.**
|
||||
# Retain generic signatures of TypeToken and its subclasses with R8 version 3.0 and higher.
|
||||
-keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken
|
||||
|
|
|
|||
|
|
@ -29,15 +29,8 @@ class App : Application() {
|
|||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
instance = this
|
||||
createNotificationChannels()
|
||||
PreferenceManager.setDefaultValues(
|
||||
this,
|
||||
"root_preferences",
|
||||
MODE_PRIVATE,
|
||||
R.xml.root_preferences,
|
||||
false
|
||||
)
|
||||
|
||||
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
|
||||
applicationScope = CoroutineScope(SupervisorJob())
|
||||
|
|
@ -80,5 +73,6 @@ class App : Application() {
|
|||
companion object {
|
||||
private const val TAG = "App"
|
||||
private lateinit var applicationScope: CoroutineScope
|
||||
lateinit var instance: App
|
||||
}
|
||||
}
|
||||
|
|
@ -123,7 +123,6 @@ class MainActivity : BaseActivity() {
|
|||
startActivity(intent)
|
||||
}
|
||||
R.id.moreFragment -> {
|
||||
//navController.navigate(R.id.settingsFragment)
|
||||
val intent = Intent(context, SettingsActivity::class.java)
|
||||
startActivity(intent)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import androidx.recyclerview.widget.DiffUtil
|
|||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||
import com.squareup.picasso.Picasso
|
||||
import java.util.*
|
||||
|
|
@ -119,6 +120,16 @@ class PlaylistAdapter(onItemClickListener: OnItemClickListener, activity: Activi
|
|||
}
|
||||
}
|
||||
|
||||
fun invertSelected(items: List<ResultItem?>?){
|
||||
val invertedList = mutableListOf<String>()
|
||||
items?.forEach {
|
||||
if (!checkedItems.contains(it!!.url)) invertedList.add(it.url)
|
||||
}
|
||||
checkedItems.clear()
|
||||
checkedItems.addAll(invertedList)
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
fun checkRange(start: Int, end: Int){
|
||||
checkedItems.clear()
|
||||
if (start == end ){
|
||||
|
|
|
|||
|
|
@ -3,18 +3,19 @@ package com.deniscerri.ytdlnis.database.dao
|
|||
import androidx.lifecycle.LiveData
|
||||
import androidx.room.*
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
interface DownloadDao {
|
||||
|
||||
@Query("SELECT * FROM downloads ORDER BY status")
|
||||
fun getAllDownloads() : LiveData<List<DownloadItem>>
|
||||
fun getAllDownloads() : Flow<List<DownloadItem>>
|
||||
|
||||
@Query("SELECT * FROM downloads WHERE status='Active'")
|
||||
fun getActiveDownloads() : LiveData<List<DownloadItem>>
|
||||
fun getActiveDownloads() : Flow<List<DownloadItem>>
|
||||
|
||||
@Query("SELECT COUNT(*) FROM downloads WHERE status='Active'")
|
||||
fun getActiveDownloadsCount() : LiveData<Int>
|
||||
fun getActiveDownloadsCount() : Flow<Int>
|
||||
|
||||
@Query("SELECT * FROM downloads WHERE status='Active'")
|
||||
fun getActiveDownloadsList() : List<DownloadItem>
|
||||
|
|
@ -23,16 +24,22 @@ interface DownloadDao {
|
|||
fun getActiveAndQueuedDownloadsList() : List<DownloadItem>
|
||||
|
||||
@Query("SELECT * FROM downloads WHERE status='Queued' ORDER BY downloadStartTime, id")
|
||||
fun getQueuedDownloads() : LiveData<List<DownloadItem>>
|
||||
fun getQueuedDownloads() : Flow<List<DownloadItem>>
|
||||
|
||||
@Query("SELECT * FROM downloads WHERE status='Queued' ORDER BY downloadStartTime, id")
|
||||
fun getQueuedDownloadsList() : List<DownloadItem>
|
||||
|
||||
@Query("SELECT * FROM downloads WHERE status='Cancelled' ORDER BY id DESC")
|
||||
fun getCancelledDownloads() : LiveData<List<DownloadItem>>
|
||||
fun getCancelledDownloads() : Flow<List<DownloadItem>>
|
||||
|
||||
@Query("SELECT * FROM downloads WHERE status='Cancelled' ORDER BY id DESC")
|
||||
fun getCancelledDownloadsList() : List<DownloadItem>
|
||||
|
||||
@Query("SELECT * FROM downloads WHERE status='Error' ORDER BY id DESC")
|
||||
fun getErroredDownloads() : LiveData<List<DownloadItem>>
|
||||
fun getErroredDownloads() : Flow<List<DownloadItem>>
|
||||
|
||||
@Query("SELECT * FROM downloads WHERE status='Processing' ORDER BY id DESC")
|
||||
fun getProcessingDownloads() : LiveData<List<DownloadItem>>
|
||||
fun getProcessingDownloads() : Flow<List<DownloadItem>>
|
||||
|
||||
@Query("SELECT * FROM downloads WHERE id=:id LIMIT 1")
|
||||
fun getDownloadById(id: Long) : DownloadItem
|
||||
|
|
|
|||
|
|
@ -29,6 +29,9 @@ interface HistoryDao {
|
|||
@Query("SELECT * FROM history")
|
||||
fun getAllHistory() : LiveData<List<HistoryItem>>
|
||||
|
||||
@Query("SELECT * FROM history")
|
||||
fun getAllHistoryList() : List<HistoryItem>
|
||||
|
||||
@Query("SELECT * FROM history WHERE id=:id LIMIT 1")
|
||||
suspend fun getHistoryItem(id: Int) : HistoryItem
|
||||
|
||||
|
|
|
|||
|
|
@ -3,14 +3,15 @@ package com.deniscerri.ytdlnis.database.dao
|
|||
import androidx.lifecycle.LiveData
|
||||
import androidx.room.*
|
||||
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
interface ResultDao {
|
||||
@Query("SELECT * FROM results")
|
||||
fun getResults() : LiveData<List<ResultItem>>
|
||||
fun getResults() : Flow<List<ResultItem>>
|
||||
|
||||
@Query("SELECT COUNT(id) FROM results")
|
||||
fun getCount() : LiveData<Int>
|
||||
fun getCount() : Flow<Int>
|
||||
|
||||
@Query("SELECT COUNT(id) FROM results")
|
||||
fun getCountInt() :Int
|
||||
|
|
|
|||
|
|
@ -3,5 +3,5 @@ package com.deniscerri.ytdlnis.database.models
|
|||
data class AudioPreferences(
|
||||
var embedThumb: Boolean = true,
|
||||
var splitByChapters: Boolean = false,
|
||||
var sponsorBlockFilters: ArrayList<String>
|
||||
var sponsorBlockFilters: ArrayList<String> = arrayListOf()
|
||||
)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ data class VideoPreferences (
|
|||
var embedSubs: Boolean = true,
|
||||
var addChapters: Boolean = true,
|
||||
var splitByChapters: Boolean = false,
|
||||
var sponsorBlockFilters: ArrayList<String>,
|
||||
var sponsorBlockFilters: ArrayList<String> = arrayListOf(),
|
||||
var writeSubs: Boolean = false,
|
||||
var subsLanguages: String = "en.*,.*-orig",
|
||||
var removeAudio: Boolean = false
|
||||
|
|
|
|||
|
|
@ -5,15 +5,16 @@ import com.deniscerri.ytdlnis.database.Converters
|
|||
import com.deniscerri.ytdlnis.database.dao.DownloadDao
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
class DownloadRepository(private val downloadDao: DownloadDao) {
|
||||
val allDownloads : LiveData<List<DownloadItem>> = downloadDao.getAllDownloads()
|
||||
val activeDownloads : LiveData<List<DownloadItem>> = downloadDao.getActiveDownloads()
|
||||
val activeDownloadsCount : LiveData<Int> = downloadDao.getActiveDownloadsCount()
|
||||
val queuedDownloads : LiveData<List<DownloadItem>> = downloadDao.getQueuedDownloads()
|
||||
val cancelledDownloads : LiveData<List<DownloadItem>> = downloadDao.getCancelledDownloads()
|
||||
val erroredDownloads : LiveData<List<DownloadItem>> = downloadDao.getErroredDownloads()
|
||||
val processingDownloads : LiveData<List<DownloadItem>> = downloadDao.getProcessingDownloads()
|
||||
val allDownloads : Flow<List<DownloadItem>> = downloadDao.getAllDownloads()
|
||||
val activeDownloads : Flow<List<DownloadItem>> = downloadDao.getActiveDownloads()
|
||||
val activeDownloadsCount : Flow<Int> = downloadDao.getActiveDownloadsCount()
|
||||
val queuedDownloads : Flow<List<DownloadItem>> = downloadDao.getQueuedDownloads()
|
||||
val cancelledDownloads : Flow<List<DownloadItem>> = downloadDao.getCancelledDownloads()
|
||||
val erroredDownloads : Flow<List<DownloadItem>> = downloadDao.getErroredDownloads()
|
||||
val processingDownloads : Flow<List<DownloadItem>> = downloadDao.getProcessingDownloads()
|
||||
|
||||
enum class Status {
|
||||
Active, Queued, Error, Processing, Cancelled
|
||||
|
|
@ -53,6 +54,14 @@ class DownloadRepository(private val downloadDao: DownloadDao) {
|
|||
return downloadDao.getActiveAndQueuedDownloadsList()
|
||||
}
|
||||
|
||||
fun getQueuedDownloads() : List<DownloadItem> {
|
||||
return downloadDao.getQueuedDownloadsList();
|
||||
}
|
||||
|
||||
fun getCancelledDownloads() : List<DownloadItem> {
|
||||
return downloadDao.getCancelledDownloadsList()
|
||||
}
|
||||
|
||||
suspend fun deleteCancelled(){
|
||||
downloadDao.deleteCancelled()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,10 @@ class HistoryRepository(private val historyDao: HistoryDao) {
|
|||
return historyDao.getHistoryItem(id)
|
||||
}
|
||||
|
||||
fun getAll() : List<HistoryItem> {
|
||||
return historyDao.getAllHistoryList()
|
||||
}
|
||||
|
||||
fun getFiltered(query : String, format : String, site : String, sortType: HistorySortType, sort: HistorySort) : List<HistoryItem> {
|
||||
return when(sortType){
|
||||
HistorySortType.DATE -> historyDao.getHistorySortedByID(query, format, site, sort.toString())
|
||||
|
|
|
|||
|
|
@ -9,10 +9,11 @@ import com.deniscerri.ytdlnis.database.dao.ResultDao
|
|||
import com.deniscerri.ytdlnis.database.models.CommandTemplate
|
||||
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||
import com.deniscerri.ytdlnis.util.InfoUtil
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
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()
|
||||
val allResults : Flow<List<ResultItem>> = resultDao.getResults()
|
||||
var itemCount = MutableLiveData(-1)
|
||||
|
||||
suspend fun insert(it: ResultItem){
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import android.net.ConnectivityManager
|
|||
import android.widget.Toast
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.work.*
|
||||
|
|
@ -52,13 +53,13 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
|||
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(application)
|
||||
commandTemplateDao = DBManager.getInstance(application).commandTemplateDao
|
||||
|
||||
allDownloads = repository.allDownloads
|
||||
queuedDownloads = repository.queuedDownloads
|
||||
activeDownloads = repository.activeDownloads
|
||||
activeDownloadsCount = repository.activeDownloadsCount
|
||||
processingDownloads = repository.processingDownloads
|
||||
cancelledDownloads = repository.cancelledDownloads
|
||||
erroredDownloads = repository.erroredDownloads
|
||||
allDownloads = repository.allDownloads.asLiveData()
|
||||
queuedDownloads = repository.queuedDownloads.asLiveData()
|
||||
activeDownloads = repository.activeDownloads.asLiveData()
|
||||
activeDownloadsCount = repository.activeDownloadsCount.asLiveData()
|
||||
processingDownloads = repository.processingDownloads.asLiveData()
|
||||
cancelledDownloads = repository.cancelledDownloads.asLiveData()
|
||||
erroredDownloads = repository.erroredDownloads.asLiveData()
|
||||
|
||||
videoQualityPreference = sharedPreferences.getString("video_quality", application.getString(R.string.best_quality)).toString()
|
||||
formatIDPreference = sharedPreferences.getString("format_id", "").toString()
|
||||
|
|
@ -114,7 +115,11 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
|||
val addChapters = sharedPreferences.getBoolean("add_chapters", false)
|
||||
val saveThumb = sharedPreferences.getBoolean("write_thumbnail", false)
|
||||
val embedThumb = sharedPreferences.getBoolean("embed_thumbnail", false)
|
||||
val customFileNameTemplate = sharedPreferences.getString("file_name_template", "%(uploader)s - %(title)s")
|
||||
val customFileNameTemplate = when(type) {
|
||||
Type.audio -> sharedPreferences.getString("file_name_template_audio", "%(uploader)s - %(title)s")
|
||||
Type.video -> sharedPreferences.getString("file_name_template", "%(uploader)s - %(title)s")
|
||||
else -> ""
|
||||
}
|
||||
|
||||
val downloadPath = when(type){
|
||||
Type.audio -> sharedPreferences.getString("music_path", getApplication<App>().resources.getString(R.string.music_path))
|
||||
|
|
@ -205,7 +210,11 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
|||
val addChapters = sharedPreferences.getBoolean("add_chapters", false)
|
||||
val saveThumb = sharedPreferences.getBoolean("write_thumbnail", false)
|
||||
val embedThumb = sharedPreferences.getBoolean("embed_thumbnail", false)
|
||||
val customFileNameTemplate = sharedPreferences.getString("file_name_template", "%(uploader)s - %(title)s")
|
||||
val customFileNameTemplate = when(historyItem.type) {
|
||||
Type.audio -> sharedPreferences.getString("file_name_template_audio", "%(uploader)s - %(title)s")
|
||||
Type.video -> sharedPreferences.getString("file_name_template", "%(uploader)s - %(title)s")
|
||||
else -> ""
|
||||
}
|
||||
|
||||
val downloadPath = when(historyItem.type){
|
||||
Type.audio -> sharedPreferences.getString("music_path", getApplication<App>().resources.getString(R.string.music_path))
|
||||
|
|
@ -345,6 +354,14 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
|||
repository.cancelQueued()
|
||||
}
|
||||
|
||||
fun getQueued() : List<DownloadItem> {
|
||||
return repository.getQueuedDownloads()
|
||||
}
|
||||
|
||||
fun getCancelled() : List<DownloadItem> {
|
||||
return repository.getCancelledDownloads()
|
||||
}
|
||||
|
||||
private fun cloneFormat(item: Format) : Format {
|
||||
val string = Gson().toJson(item, Format::class.java)
|
||||
return Gson().fromJson(string, Format::class.java)
|
||||
|
|
|
|||
|
|
@ -48,7 +48,6 @@ class HistoryViewModel(application: Application) : AndroidViewModel(application)
|
|||
return _items
|
||||
}
|
||||
|
||||
|
||||
fun setSorting(sort: HistorySortType){
|
||||
if (sortType.value != sort){
|
||||
sortOrder.value = HistorySort.DESC
|
||||
|
|
@ -76,6 +75,10 @@ class HistoryViewModel(application: Application) : AndroidViewModel(application)
|
|||
_items.postValue(repository.getFiltered(query, format, site, sortType, sort))
|
||||
}
|
||||
|
||||
fun getAll() : List<HistoryItem> {
|
||||
return repository.getAll()
|
||||
}
|
||||
|
||||
fun insert(item: HistoryItem) = viewModelScope.launch(Dispatchers.IO){
|
||||
repository.insert(item)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import android.util.Log
|
|||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.deniscerri.ytdlnis.App
|
||||
|
|
@ -35,7 +36,7 @@ class ResultViewModel(application: Application) : AndroidViewModel(application)
|
|||
val commandDao = DBManager.getInstance(application).commandTemplateDao
|
||||
repository = ResultRepository(dao, commandDao, getApplication<Application>().applicationContext)
|
||||
searchHistoryRepository = SearchHistoryRepository(DBManager.getInstance(application).searchHistoryDao)
|
||||
items = repository.allResults
|
||||
items = repository.allResults.asLiveData()
|
||||
loadingItems.postValue(false)
|
||||
itemCount = repository.itemCount
|
||||
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(application)
|
||||
|
|
|
|||
|
|
@ -21,12 +21,14 @@ import com.deniscerri.ytdlnis.database.models.DownloadItem
|
|||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.deniscerri.ytdlnis.util.InfoUtil
|
||||
import com.deniscerri.ytdlnis.util.UiUtil
|
||||
import com.google.android.exoplayer2.C
|
||||
import com.google.android.exoplayer2.DefaultLoadControl
|
||||
import com.google.android.exoplayer2.DefaultRenderersFactory
|
||||
import com.google.android.exoplayer2.DefaultRenderersFactory.EXTENSION_RENDERER_MODE_PREFER
|
||||
import com.google.android.exoplayer2.ExoPlayer
|
||||
import com.google.android.exoplayer2.MediaItem.fromUri
|
||||
import com.google.android.exoplayer2.Player
|
||||
import com.google.android.exoplayer2.audio.AudioAttributes
|
||||
import com.google.android.exoplayer2.mediacodec.MediaCodecInfo
|
||||
import com.google.android.exoplayer2.mediacodec.MediaCodecSelector
|
||||
import com.google.android.exoplayer2.source.DefaultMediaSourceFactory
|
||||
|
|
@ -131,9 +133,18 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val list
|
|||
val trackSelector = DefaultTrackSelector(requireContext())
|
||||
val loadControl = DefaultLoadControl()
|
||||
|
||||
player = ExoPlayer.Builder(requireContext(), renderersFactory)
|
||||
player = ExoPlayer.Builder(requireContext())
|
||||
.setUsePlatformDiagnostics(false)
|
||||
.setTrackSelector(trackSelector)
|
||||
.setLoadControl(loadControl)
|
||||
.setHandleAudioBecomingNoisy(true)
|
||||
.setAudioAttributes(
|
||||
AudioAttributes.Builder()
|
||||
.setUsage(C.USAGE_MEDIA)
|
||||
.setContentType(C.AUDIO_CONTENT_TYPE_MOVIE)
|
||||
.build()
|
||||
,
|
||||
true)
|
||||
.build()
|
||||
val frame = view.findViewById<MaterialCardView>(R.id.frame_layout)
|
||||
val videoView = view.findViewById<StyledPlayerView>(R.id.video_view)
|
||||
|
|
@ -207,9 +218,8 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val list
|
|||
progress.visibility = View.GONE
|
||||
populateSuggestedChapters()
|
||||
|
||||
player.prepare().apply {
|
||||
player.play()
|
||||
}
|
||||
player.prepare()
|
||||
player.play()
|
||||
}catch (e: Exception){
|
||||
progress.visibility = View.GONE
|
||||
frame.visibility = View.GONE
|
||||
|
|
|
|||
|
|
@ -3,18 +3,25 @@ package com.deniscerri.ytdlnis.ui.downloadcard
|
|||
import android.app.Activity
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.view.Gravity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.AdapterView
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.AutoCompleteTextView
|
||||
import android.widget.EditText
|
||||
import android.widget.TextView
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
|
|
@ -142,10 +149,6 @@ class DownloadAudioFragment(private var resultItem: ResultItem, private var curr
|
|||
override fun onFormatClick(allFormats: List<List<Format>>, item: List<Format>) {
|
||||
downloadItem.format = item.first()
|
||||
uiUtil.populateFormatCard(formatCard, item.first())
|
||||
if (containers.contains(item.first().container)){
|
||||
downloadItem.format.container = item.first().container
|
||||
containerAutoCompleteTextView.setText(item.first().container, false)
|
||||
}
|
||||
lifecycleScope.launch {
|
||||
withContext(Dispatchers.IO){
|
||||
resultItem.formats.removeAll(formats.toSet())
|
||||
|
|
@ -162,6 +165,10 @@ class DownloadAudioFragment(private var resultItem: ResultItem, private var curr
|
|||
bottomSheet.show(parentFragmentManager, "formatSheet")
|
||||
}
|
||||
}
|
||||
formatCard.setOnLongClickListener {
|
||||
uiUtil.showFormatDetails(downloadItem.format, requireActivity())
|
||||
true
|
||||
}
|
||||
|
||||
|
||||
container?.isEnabled = true
|
||||
|
|
@ -173,12 +180,13 @@ class DownloadAudioFragment(private var resultItem: ResultItem, private var curr
|
|||
)
|
||||
)
|
||||
|
||||
downloadItem.format.container = containerPreference!!
|
||||
containerAutoCompleteTextView.setText(downloadItem.format.container, false)
|
||||
downloadItem.format.container = if (containerPreference == getString(R.string.defaultValue)) "" else containerPreference!!
|
||||
containerAutoCompleteTextView.setText(downloadItem.format.container.ifEmpty { getString(R.string.defaultValue) }, false)
|
||||
|
||||
(container!!.editText as AutoCompleteTextView?)!!.onItemClickListener =
|
||||
AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, index: Int, _: Long ->
|
||||
downloadItem.format.container = containers[index]
|
||||
if (containers[index] == getString(R.string.defaultValue)) downloadItem.format.container = ""
|
||||
}
|
||||
|
||||
val embedThumb = view.findViewById<Chip>(R.id.embed_thumb)
|
||||
|
|
@ -199,6 +207,41 @@ class DownloadAudioFragment(private var resultItem: ResultItem, private var curr
|
|||
downloadItem.audioPreferences.splitByChapters = splitByChapters.isChecked
|
||||
}
|
||||
|
||||
val filenameTemplate = view.findViewById<Chip>(R.id.filename_template)
|
||||
filenameTemplate.setOnClickListener {
|
||||
val builder = MaterialAlertDialogBuilder(requireContext())
|
||||
builder.setTitle(getString(R.string.file_name_template))
|
||||
val inputLayout = layoutInflater.inflate(R.layout.textinput, null)
|
||||
val editText = inputLayout.findViewById<EditText>(R.id.url_edittext)
|
||||
inputLayout.findViewById<TextInputLayout>(R.id.url_textinput).hint = getString(R.string.file_name_template)
|
||||
editText.setText(downloadItem.customFileNameTemplate)
|
||||
editText.setSelection(editText.text.length)
|
||||
builder.setView(inputLayout)
|
||||
builder.setPositiveButton(
|
||||
getString(R.string.ok)
|
||||
) { dialog: DialogInterface?, which: Int ->
|
||||
downloadItem.customFileNameTemplate = editText.text.toString()
|
||||
}
|
||||
|
||||
// handle the negative button of the alert dialog
|
||||
builder.setNegativeButton(
|
||||
getString(R.string.cancel)
|
||||
) { dialog: DialogInterface?, which: Int -> }
|
||||
|
||||
val dialog = builder.create()
|
||||
editText.doOnTextChanged { text, start, before, count ->
|
||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = editText.text.isNotEmpty()
|
||||
}
|
||||
dialog.show()
|
||||
val imm = context?.getSystemService(AppCompatActivity.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
editText!!.postDelayed({
|
||||
editText.requestFocus()
|
||||
imm.showSoftInput(editText, 0)
|
||||
}, 300)
|
||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = editText.text.isNotEmpty()
|
||||
dialog.getButton(AlertDialog.BUTTON_NEUTRAL).gravity = Gravity.START
|
||||
}
|
||||
|
||||
val sponsorblock = view.findViewById<Chip>(R.id.sponsorblock_filters)
|
||||
sponsorblock!!.setOnClickListener {
|
||||
val builder = MaterialAlertDialogBuilder(requireContext())
|
||||
|
|
|
|||
|
|
@ -71,7 +71,9 @@ class DownloadBottomSheetDialog(private val resultItem: ResultItem, private val
|
|||
behavior = BottomSheetBehavior.from(view.parent as View)
|
||||
val displayMetrics = DisplayMetrics()
|
||||
requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics)
|
||||
behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
if(resources.getBoolean(R.bool.isTablet)){
|
||||
behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -79,7 +79,9 @@ class DownloadMultipleBottomSheetDialog(private var results: List<ResultItem?>,
|
|||
behavior = BottomSheetBehavior.from(view.parent as View)
|
||||
val displayMetrics = DisplayMetrics()
|
||||
requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics)
|
||||
behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
if(resources.getBoolean(R.bool.isTablet)){
|
||||
behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
}
|
||||
}
|
||||
|
||||
listAdapter =
|
||||
|
|
@ -409,11 +411,16 @@ class DownloadMultipleBottomSheetDialog(private var results: List<ResultItem?>,
|
|||
val deletedItem = items[position]
|
||||
items.remove(deletedItem)
|
||||
listAdapter.submitList(items.toList())
|
||||
Snackbar.make(recyclerView, getString(R.string.you_are_going_to_delete) + ": " + deletedItem.title, Snackbar.LENGTH_LONG)
|
||||
.setAction(getString(R.string.undo)) {
|
||||
items.add(position, deletedItem)
|
||||
listAdapter.submitList(items.toList())
|
||||
}.show()
|
||||
if (items.isNotEmpty()){
|
||||
Snackbar.make(recyclerView, getString(R.string.you_are_going_to_delete) + ": " + deletedItem.title, Snackbar.LENGTH_LONG)
|
||||
.setAction(getString(R.string.undo)) {
|
||||
items.add(position, deletedItem)
|
||||
listAdapter.submitList(items.toList())
|
||||
}.show()
|
||||
}else{
|
||||
dismiss()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -148,11 +148,6 @@ class DownloadVideoFragment(private val resultItem: ResultItem, private var curr
|
|||
val listener = object : OnFormatClickListener {
|
||||
override fun onFormatClick(allFormats: List<List<Format>>, item: List<Format>) {
|
||||
downloadItem.format = item.first()
|
||||
|
||||
if (containers.contains(item.first().container)){
|
||||
downloadItem.format.container = item.first().container
|
||||
containerAutoCompleteTextView.setText(item.first().container, false)
|
||||
}
|
||||
lifecycleScope.launch {
|
||||
withContext(Dispatchers.IO){
|
||||
resultItem.formats.removeAll(formats.toSet())
|
||||
|
|
@ -171,6 +166,11 @@ class DownloadVideoFragment(private val resultItem: ResultItem, private var curr
|
|||
}
|
||||
}
|
||||
|
||||
formatCard.setOnLongClickListener {
|
||||
uiUtil.showFormatDetails(downloadItem.format, requireActivity())
|
||||
true
|
||||
}
|
||||
|
||||
container?.isEnabled = true
|
||||
containerAutoCompleteTextView?.setAdapter(
|
||||
ArrayAdapter(
|
||||
|
|
@ -187,6 +187,7 @@ class DownloadVideoFragment(private val resultItem: ResultItem, private var curr
|
|||
(container!!.editText as AutoCompleteTextView?)!!.onItemClickListener =
|
||||
AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, index: Int, _: Long ->
|
||||
downloadItem.format.container = containers[index]
|
||||
if (containers[index] == getString(R.string.defaultValue)) downloadItem.format.container = ""
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -313,6 +314,41 @@ class DownloadVideoFragment(private val resultItem: ResultItem, private var curr
|
|||
cut.isEnabled = false
|
||||
}
|
||||
|
||||
val filenameTemplate = view.findViewById<Chip>(R.id.filename_template)
|
||||
filenameTemplate.setOnClickListener {
|
||||
val builder = MaterialAlertDialogBuilder(requireContext())
|
||||
builder.setTitle(getString(R.string.file_name_template))
|
||||
val inputLayout = layoutInflater.inflate(R.layout.textinput, null)
|
||||
val editText = inputLayout.findViewById<EditText>(R.id.url_edittext)
|
||||
inputLayout.findViewById<TextInputLayout>(R.id.url_textinput).hint = getString(R.string.file_name_template)
|
||||
editText.setText(downloadItem.customFileNameTemplate)
|
||||
editText.setSelection(editText.text.length)
|
||||
builder.setView(inputLayout)
|
||||
builder.setPositiveButton(
|
||||
getString(R.string.ok)
|
||||
) { dialog: DialogInterface?, which: Int ->
|
||||
downloadItem.customFileNameTemplate = editText.text.toString()
|
||||
}
|
||||
|
||||
// handle the negative button of the alert dialog
|
||||
builder.setNegativeButton(
|
||||
getString(R.string.cancel)
|
||||
) { dialog: DialogInterface?, which: Int -> }
|
||||
|
||||
val dialog = builder.create()
|
||||
editText.doOnTextChanged { text, start, before, count ->
|
||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = editText.text.isNotEmpty()
|
||||
}
|
||||
dialog.show()
|
||||
val imm = context?.getSystemService(AppCompatActivity.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
editText!!.postDelayed({
|
||||
editText.requestFocus()
|
||||
imm.showSoftInput(editText, 0)
|
||||
}, 300)
|
||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = editText.text.isNotEmpty()
|
||||
dialog.getButton(AlertDialog.BUTTON_NEUTRAL).gravity = Gravity.START
|
||||
}
|
||||
|
||||
val saveSubtitles = view.findViewById<Chip>(R.id.save_subtitles)
|
||||
val subtitleLanguages = view.findViewById<Chip>(R.id.subtitle_languages)
|
||||
if (downloadItem.videoPreferences.writeSubs) {
|
||||
|
|
|
|||
|
|
@ -210,110 +210,13 @@ class FormatSelectionBottomSheetDialog(private val items: List<DownloadItem?>, p
|
|||
dismiss()
|
||||
}
|
||||
formatItem.setOnLongClickListener {
|
||||
val bottomSheet = BottomSheetDialog(requireContext())
|
||||
bottomSheet.requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
bottomSheet.setContentView(R.layout.format_details_sheet)
|
||||
|
||||
val formatIdParent = bottomSheet.findViewById<LinearLayout>(R.id.format_id_parent)
|
||||
val containerParent = bottomSheet.findViewById<LinearLayout>(R.id.container_parent)
|
||||
val codecParent = bottomSheet.findViewById<LinearLayout>(R.id.codec_parent)
|
||||
val filesizeParent = bottomSheet.findViewById<LinearLayout>(R.id.filesize_parent)
|
||||
val formatnoteParent = bottomSheet.findViewById<LinearLayout>(R.id.format_note_parent)
|
||||
val fpsParent = bottomSheet.findViewById<LinearLayout>(R.id.fps_parent)
|
||||
val asrParent = bottomSheet.findViewById<LinearLayout>(R.id.asr_parent)
|
||||
|
||||
if (format.format_id.isBlank()) formatIdParent?.visibility = View.GONE
|
||||
else {
|
||||
formatIdParent?.findViewById<TextView>(R.id.format_id_value)?.text = format.format_id
|
||||
formatIdParent?.setOnClickListener {
|
||||
copyToClipboard(format.format_id)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (format.container.isBlank()) containerParent?.visibility = View.GONE
|
||||
else {
|
||||
containerParent?.findViewById<TextView>(R.id.container_value)?.text = format.container
|
||||
containerParent?.setOnClickListener {
|
||||
copyToClipboard(format.container)
|
||||
}
|
||||
}
|
||||
|
||||
val codecField =
|
||||
if (format.encoding != "") {
|
||||
format.encoding.uppercase()
|
||||
}else if (format.vcodec != "none" && format.vcodec != ""){
|
||||
format.vcodec.uppercase()
|
||||
} else {
|
||||
format.acodec.uppercase()
|
||||
}
|
||||
|
||||
if (codecField.isBlank()) codecParent?.visibility = View.GONE
|
||||
else {
|
||||
codecParent?.findViewById<TextView>(R.id.codec_value)?.text = codecField
|
||||
codecParent?.setOnClickListener {
|
||||
copyToClipboard(codecField)
|
||||
}
|
||||
}
|
||||
|
||||
if (format.filesize != 0L) filesizeParent?.visibility = View.GONE
|
||||
else {
|
||||
filesizeParent?.findViewById<TextView>(R.id.filesize_value)?.text = fileUtil.convertFileSize(format.filesize)
|
||||
filesizeParent?.setOnClickListener {
|
||||
copyToClipboard(fileUtil.convertFileSize(format.filesize))
|
||||
}
|
||||
}
|
||||
|
||||
if (format.format_note.isBlank()) formatnoteParent?.visibility = View.GONE
|
||||
else {
|
||||
formatnoteParent?.findViewById<TextView>(R.id.format_note_value)?.text = format.format_note
|
||||
formatnoteParent?.setOnClickListener {
|
||||
copyToClipboard(format.format_note)
|
||||
}
|
||||
}
|
||||
|
||||
if (format.fps.isNullOrBlank()) fpsParent?.visibility = View.GONE
|
||||
else {
|
||||
fpsParent?.findViewById<TextView>(R.id.fps_value)?.text = format.fps
|
||||
fpsParent?.setOnClickListener {
|
||||
copyToClipboard(format.fps!!)
|
||||
}
|
||||
}
|
||||
|
||||
if (format.asr.isNullOrBlank()) asrParent?.visibility = View.GONE
|
||||
else {
|
||||
asrParent?.findViewById<TextView>(R.id.asr_value)?.text = format.asr
|
||||
asrParent?.setOnClickListener {
|
||||
copyToClipboard(format.asr!!)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bottomSheet.show()
|
||||
val displayMetrics = DisplayMetrics()
|
||||
requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics)
|
||||
bottomSheet.behavior.peekHeight = displayMetrics.heightPixels
|
||||
bottomSheet.window!!.setLayout(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
|
||||
uiUtil.showFormatDetails(format, requireActivity())
|
||||
true
|
||||
}
|
||||
linearLayout.addView(formatItem)
|
||||
}
|
||||
}
|
||||
|
||||
private fun copyToClipboard(text: String){
|
||||
val clipboard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clip = ClipData.newPlainText(text, text)
|
||||
clipboard.setPrimaryClip(clip)
|
||||
Toast.makeText(context, requireContext().getString(R.string.copied_to_clipboard), Toast.LENGTH_SHORT)
|
||||
.show()
|
||||
}
|
||||
|
||||
|
||||
override fun onCancel(dialog: DialogInterface) {
|
||||
super.onCancel(dialog)
|
||||
cleanUp()
|
||||
|
|
|
|||
|
|
@ -2,13 +2,16 @@ package com.deniscerri.ytdlnis.ui.downloadcard
|
|||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Dialog
|
||||
import android.content.ClipboardManager
|
||||
import android.content.DialogInterface
|
||||
import android.os.Bundle
|
||||
import android.util.DisplayMetrics
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.Button
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.widget.doAfterTextChanged
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
|
|
@ -21,8 +24,10 @@ 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.receiver.ShareActivity
|
||||
import com.google.android.material.bottomappbar.BottomAppBar
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
|
@ -115,12 +120,14 @@ class SelectPlaylistItemsBottomSheetDialog(private val items: List<ResultItem?>,
|
|||
}
|
||||
}
|
||||
|
||||
val checkAll = view.findViewById<FloatingActionButton>(R.id.check_all)
|
||||
val checkAll = view.findViewById<ExtendedFloatingActionButton>(R.id.check_all)
|
||||
checkAll!!.setOnClickListener {
|
||||
if (listAdapter.getCheckedItems().size != items.size){
|
||||
fromTextInput.editText!!.setText("1")
|
||||
toTextInput.editText!!.setText(items.size.toString())
|
||||
listAdapter.checkAll()
|
||||
fromTextInput.isEnabled = true
|
||||
toTextInput.isEnabled = true
|
||||
selectedText.text = resources.getString(R.string.all_items_selected)
|
||||
}else{
|
||||
reset()
|
||||
|
|
@ -160,6 +167,24 @@ class SelectPlaylistItemsBottomSheetDialog(private val items: List<ResultItem?>,
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
view.findViewById<BottomAppBar>(R.id.bottomAppBar).setOnMenuItemClickListener { m: MenuItem ->
|
||||
val itemId = m.itemId
|
||||
if (itemId == R.id.invert_selected) {
|
||||
listAdapter.invertSelected(items)
|
||||
val checkedItems = listAdapter.getCheckedItems()
|
||||
if (checkedItems.size == items.size){
|
||||
selectedText.text = resources.getString(R.string.all_items_selected)
|
||||
}else{
|
||||
selectedText.text = "${checkedItems.size} ${resources.getString(R.string.selected)}"
|
||||
}
|
||||
if(checkedItems.isNotEmpty() && checkedItems.size < items.size){
|
||||
fromTextInput.isEnabled = false
|
||||
toTextInput.isEnabled = false
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCancel(dialog: DialogInterface) {
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import com.google.android.material.chip.Chip
|
|||
import com.google.android.material.color.MaterialColors
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import it.xabaras.android.recyclerview.swipedecorator.RecyclerViewSwipeDecorator
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -124,6 +125,7 @@ class CookiesActivity : BaseActivity(), CookieAdapter.OnItemClickListener {
|
|||
builder.setTitle(getString(R.string.cookies))
|
||||
val inputLayout = layoutInflater.inflate(R.layout.textinput, null)
|
||||
val editText = inputLayout.findViewById<EditText>(R.id.url_edittext)
|
||||
inputLayout.findViewById<TextInputLayout>(R.id.url_textinput).hint = "URL"
|
||||
val text = if (url.isNullOrBlank()) "https://" else url
|
||||
editText.setText(text)
|
||||
editText.setSelection(editText.text.length)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,158 @@
|
|||
package com.deniscerri.ytdlnis.ui.more.settings
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.Context.POWER_SERVICE
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.net.Uri
|
||||
import android.os.Build.VERSION
|
||||
import android.os.Build.VERSION_CODES
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
import android.os.PowerManager
|
||||
import android.provider.Settings
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.core.os.LocaleListCompat
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.EditTextPreference
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.preference.SeekBarPreference
|
||||
import androidx.preference.SwitchPreferenceCompat
|
||||
import androidx.work.WorkInfo
|
||||
import androidx.work.WorkManager
|
||||
import com.deniscerri.ytdlnis.BuildConfig
|
||||
import com.deniscerri.ytdlnis.MainActivity
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.models.CommandTemplate
|
||||
import com.deniscerri.ytdlnis.database.models.CookieItem
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.models.HistoryItem
|
||||
import com.deniscerri.ytdlnis.database.models.SearchHistoryItem
|
||||
import com.deniscerri.ytdlnis.database.models.TemplateShortcut
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.CommandTemplateViewModel
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.CookieViewModel
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.HistoryViewModel
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.deniscerri.ytdlnis.util.ThemeUtil
|
||||
import com.deniscerri.ytdlnis.util.UpdateUtil
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonParser
|
||||
import com.yausername.youtubedl_android.YoutubeDL
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.serialization.json.Json
|
||||
import java.io.BufferedReader
|
||||
import java.io.File
|
||||
import java.io.InputStreamReader
|
||||
import java.time.LocalDateTime
|
||||
import java.util.Locale
|
||||
|
||||
|
||||
class AppearanceSettingsFragment : BaseSettingsFragment() {
|
||||
override val title: Int = R.string.appearance
|
||||
|
||||
private var language: ListPreference? = null
|
||||
private var theme: ListPreference? = null
|
||||
private var accent: ListPreference? = null
|
||||
private var highContrast: SwitchPreferenceCompat? = null
|
||||
private var locale: ListPreference? = null
|
||||
|
||||
private var updateUtil: UpdateUtil? = null
|
||||
private var fileUtil: FileUtil? = null
|
||||
private var activeDownloadCount = 0
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.appearance_preferences, rootKey)
|
||||
updateUtil = UpdateUtil(requireContext())
|
||||
fileUtil = FileUtil()
|
||||
|
||||
WorkManager.getInstance(requireContext()).getWorkInfosByTagLiveData("download").observe(this){
|
||||
activeDownloadCount = 0
|
||||
it.forEach {w ->
|
||||
if (w.state == WorkInfo.State.RUNNING) activeDownloadCount++
|
||||
}
|
||||
}
|
||||
|
||||
val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
language = findPreference("app_language")
|
||||
theme = findPreference("ytdlnis_theme")
|
||||
accent = findPreference("theme_accent")
|
||||
highContrast = findPreference("high_contrast")
|
||||
locale = findPreference("locale")
|
||||
|
||||
if(VERSION.SDK_INT < VERSION_CODES.TIRAMISU){
|
||||
val values = resources.getStringArray(R.array.language_values)
|
||||
val entries = mutableListOf<String>()
|
||||
values.forEach {
|
||||
entries.add(Locale(it).getDisplayName(Locale(it)))
|
||||
}
|
||||
language!!.entries = entries.toTypedArray()
|
||||
}else{
|
||||
language!!.isVisible = false
|
||||
}
|
||||
|
||||
if(language!!.value == null) language!!.value = Locale.getDefault().language
|
||||
language!!.summary = Locale(language!!.value).getDisplayLanguage(Locale(language!!.value))
|
||||
language!!.onPreferenceChangeListener =
|
||||
Preference.OnPreferenceChangeListener { _: Preference?, newValue: Any ->
|
||||
language!!.summary = Locale(newValue.toString()).getDisplayLanguage(Locale(newValue.toString()))
|
||||
AppCompatDelegate.setApplicationLocales(LocaleListCompat.forLanguageTags(newValue.toString()))
|
||||
true
|
||||
}
|
||||
|
||||
theme!!.summary = theme!!.entry
|
||||
theme!!.onPreferenceChangeListener =
|
||||
Preference.OnPreferenceChangeListener { _: Preference?, newValue: Any ->
|
||||
when(newValue){
|
||||
"System" -> {
|
||||
theme!!.summary = getString(R.string.system)
|
||||
}
|
||||
"Dark" -> {
|
||||
theme!!.summary = getString(R.string.dark)
|
||||
}
|
||||
else -> {
|
||||
theme!!.summary = getString(R.string.light)
|
||||
}
|
||||
}
|
||||
ThemeUtil.updateTheme(requireActivity() as AppCompatActivity)
|
||||
val intent = Intent(requireContext(), MainActivity::class.java)
|
||||
this.startActivity(intent)
|
||||
requireActivity().finishAffinity()
|
||||
true
|
||||
}
|
||||
accent!!.summary = accent!!.entry
|
||||
accent!!.onPreferenceChangeListener =
|
||||
Preference.OnPreferenceChangeListener { _: Preference?, _: Any ->
|
||||
ThemeUtil.updateTheme(requireActivity() as AppCompatActivity)
|
||||
val intent = Intent(requireContext(), MainActivity::class.java)
|
||||
this.startActivity(intent)
|
||||
requireActivity().finishAffinity()
|
||||
true
|
||||
}
|
||||
highContrast!!.onPreferenceChangeListener =
|
||||
Preference.OnPreferenceChangeListener { _: Preference?, _: Any ->
|
||||
ThemeUtil.updateTheme(requireActivity() as AppCompatActivity)
|
||||
val intent = Intent(requireContext(), MainActivity::class.java)
|
||||
this.startActivity(intent)
|
||||
requireActivity().finishAffinity()
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.deniscerri.ytdlnis.ui.more.settings
|
||||
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
|
||||
|
||||
abstract class BaseSettingsFragment : PreferenceFragmentCompat() {
|
||||
abstract val title: Int
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
(activity as? SettingsActivity)?.changeTopAppbarTitle(getString(title))
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
package com.deniscerri.ytdlnis.ui.more.settings
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context.POWER_SERVICE
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.os.PowerManager
|
||||
import android.provider.Settings
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.SeekBarPreference
|
||||
import com.deniscerri.ytdlnis.MainActivity
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
|
||||
|
||||
class DownloadSettingsFragment : BaseSettingsFragment() {
|
||||
override val title: Int = R.string.downloading
|
||||
|
||||
private var concurrentDownloads: SeekBarPreference? = null
|
||||
private var ignoreBatteryOptimization: Preference? = null
|
||||
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.downloading_preferences, rootKey)
|
||||
|
||||
ignoreBatteryOptimization = findPreference("ignore_battery")
|
||||
val packageName: String = requireContext().packageName
|
||||
val pm = requireContext().applicationContext.getSystemService(POWER_SERVICE) as PowerManager
|
||||
if (pm.isIgnoringBatteryOptimizations(packageName)) {
|
||||
ignoreBatteryOptimization!!.isVisible = false
|
||||
}
|
||||
|
||||
concurrentDownloads = findPreference("concurrent_downloads")
|
||||
concurrentDownloads!!.onPreferenceChangeListener =
|
||||
Preference.OnPreferenceChangeListener { _: Preference?, _: Any ->
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(resources.getString(R.string.warning))
|
||||
.setMessage(resources.getString(R.string.workmanager_updated))
|
||||
.setNegativeButton(resources.getString(R.string.cancel)) { dialog, _ ->
|
||||
dialog.cancel()
|
||||
}
|
||||
.setPositiveButton(resources.getString(R.string.restart)) { _, _ ->
|
||||
val intent = Intent(context, MainActivity::class.java)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
requireContext().startActivity(intent)
|
||||
if (context is Activity) {
|
||||
(context as Activity).finish()
|
||||
}
|
||||
Runtime.getRuntime().exit(0)
|
||||
}
|
||||
.show()
|
||||
|
||||
true
|
||||
}
|
||||
ignoreBatteryOptimization = findPreference("ignore_battery")
|
||||
ignoreBatteryOptimization!!.onPreferenceClickListener =
|
||||
Preference.OnPreferenceClickListener {
|
||||
val intent = Intent()
|
||||
intent.action = Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
|
||||
intent.data = Uri.parse("package:" + requireContext().packageName)
|
||||
startActivity(intent)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,179 @@
|
|||
package com.deniscerri.ytdlnis.ui.more.settings
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build.VERSION
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
import android.provider.Settings
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.deniscerri.ytdlnis.util.UpdateUtil
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import java.io.File
|
||||
|
||||
|
||||
class FolderSettingsFragment : BaseSettingsFragment() {
|
||||
override val title: Int = R.string.directories
|
||||
|
||||
private var musicPath: Preference? = null
|
||||
private var videoPath: Preference? = null
|
||||
private var commandPath: Preference? = null
|
||||
private var accessAllFiles : Preference? = null
|
||||
private var clearCache: Preference? = null
|
||||
|
||||
private var fileUtil: FileUtil? = null
|
||||
private var activeDownloadCount = 0
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.folders_preference, rootKey)
|
||||
|
||||
val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
val editor = preferences.edit()
|
||||
fileUtil = FileUtil()
|
||||
|
||||
musicPath = findPreference("music_path")
|
||||
videoPath = findPreference("video_path")
|
||||
commandPath = findPreference("command_path")
|
||||
accessAllFiles = findPreference("access_all_files")
|
||||
clearCache = findPreference("clear_cache")
|
||||
|
||||
if (preferences.getString("music_path", "")!!.isEmpty()) {
|
||||
editor.putString("music_path", getString(R.string.music_path))
|
||||
}
|
||||
if (preferences.getString("video_path", "")!!.isEmpty()) {
|
||||
editor.putString("video_path", getString(R.string.video_path))
|
||||
}
|
||||
if (preferences.getString("command_path", "")!!.isEmpty()) {
|
||||
editor.putString("command_path", getString(R.string.command_path))
|
||||
}
|
||||
|
||||
if((VERSION.SDK_INT >= 30 && Environment.isExternalStorageManager()) ||
|
||||
VERSION.SDK_INT < 30) {
|
||||
accessAllFiles!!.isVisible = false
|
||||
}
|
||||
|
||||
editor.apply()
|
||||
|
||||
musicPath!!.summary = fileUtil?.formatPath(preferences.getString("music_path", "")!!)
|
||||
musicPath!!.onPreferenceClickListener =
|
||||
Preference.OnPreferenceClickListener {
|
||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
||||
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
|
||||
musicPathResultLauncher.launch(intent)
|
||||
true
|
||||
}
|
||||
videoPath!!.summary = fileUtil?.formatPath(preferences.getString("video_path", "")!!)
|
||||
videoPath!!.onPreferenceClickListener =
|
||||
Preference.OnPreferenceClickListener {
|
||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
||||
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
|
||||
videoPathResultLauncher.launch(intent)
|
||||
true
|
||||
}
|
||||
commandPath!!.summary = fileUtil?.formatPath(preferences.getString("command_path", "")!!)
|
||||
commandPath!!.onPreferenceClickListener =
|
||||
Preference.OnPreferenceClickListener {
|
||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
||||
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
|
||||
commandPathResultLauncher.launch(intent)
|
||||
true
|
||||
}
|
||||
accessAllFiles!!.onPreferenceClickListener =
|
||||
Preference.OnPreferenceClickListener {
|
||||
val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
|
||||
val uri = Uri.parse("package:" + requireContext().packageName)
|
||||
intent.data = uri
|
||||
startActivity(intent)
|
||||
true
|
||||
}
|
||||
|
||||
var cacheSize = File(requireContext().cacheDir.absolutePath + "/downloads").walkBottomUp().fold(0L) { acc, file -> acc + file.length() }
|
||||
clearCache!!.summary = "(${fileUtil!!.convertFileSize(cacheSize)}) ${resources.getString(R.string.clear_temporary_files_summary)}"
|
||||
clearCache!!.onPreferenceClickListener =
|
||||
Preference.OnPreferenceClickListener {
|
||||
if (activeDownloadCount == 0){
|
||||
File(requireContext().cacheDir.absolutePath + "/downloads").deleteRecursively()
|
||||
Snackbar.make(requireView(), getString(R.string.cache_cleared), Snackbar.LENGTH_SHORT).show()
|
||||
cacheSize = File(requireContext().cacheDir.absolutePath + "/downloads").walkBottomUp().fold(0L) { acc, file -> acc + file.length() }
|
||||
clearCache!!.summary = "(${fileUtil!!.convertFileSize(cacheSize)}) ${resources.getString(R.string.clear_temporary_files_summary)}"
|
||||
}else{
|
||||
Snackbar.make(requireView(), getString(R.string.downloads_running_try_later), Snackbar.LENGTH_SHORT).show()
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private var musicPathResultLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.StartActivityForResult()
|
||||
) { result ->
|
||||
if (result.resultCode == Activity.RESULT_OK) {
|
||||
result.data?.data?.let {
|
||||
activity?.contentResolver?.takePersistableUriPermission(
|
||||
it,
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION or
|
||||
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||
)
|
||||
}
|
||||
changePath(musicPath, result.data, MUSIC_PATH_CODE)
|
||||
}
|
||||
}
|
||||
private var videoPathResultLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.StartActivityForResult()
|
||||
) { result ->
|
||||
if (result.resultCode == Activity.RESULT_OK) {
|
||||
result.data?.data?.let {
|
||||
activity?.contentResolver?.takePersistableUriPermission(
|
||||
it,
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION or
|
||||
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||
)
|
||||
}
|
||||
changePath(videoPath, result.data, VIDEO_PATH_CODE)
|
||||
}
|
||||
}
|
||||
private var commandPathResultLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.StartActivityForResult()
|
||||
) { result ->
|
||||
if (result.resultCode == Activity.RESULT_OK) {
|
||||
result.data?.data?.let {
|
||||
activity?.contentResolver?.takePersistableUriPermission(
|
||||
it,
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION or
|
||||
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||
)
|
||||
}
|
||||
changePath(commandPath, result.data, COMMAND_PATH_CODE)
|
||||
}
|
||||
}
|
||||
|
||||
private fun changePath(p: Preference?, data: Intent?, requestCode: Int) {
|
||||
val path = data!!.data.toString()
|
||||
p!!.summary = fileUtil?.formatPath(data.data.toString())
|
||||
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
val editor = sharedPreferences.edit()
|
||||
when (requestCode) {
|
||||
MUSIC_PATH_CODE -> editor.putString("music_path", path)
|
||||
VIDEO_PATH_CODE -> editor.putString("video_path", path)
|
||||
COMMAND_PATH_CODE -> editor.putString("command_path", path)
|
||||
}
|
||||
editor.apply()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val MUSIC_PATH_CODE = 33333
|
||||
const val VIDEO_PATH_CODE = 55555
|
||||
const val COMMAND_PATH_CODE = 77777
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,501 @@
|
|||
package com.deniscerri.ytdlnis.ui.more.settings
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.work.WorkInfo
|
||||
import androidx.work.WorkManager
|
||||
import com.deniscerri.ytdlnis.BuildConfig
|
||||
import com.deniscerri.ytdlnis.MainActivity
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.models.CommandTemplate
|
||||
import com.deniscerri.ytdlnis.database.models.CookieItem
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.models.HistoryItem
|
||||
import com.deniscerri.ytdlnis.database.models.SearchHistoryItem
|
||||
import com.deniscerri.ytdlnis.database.models.TemplateShortcut
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.CommandTemplateViewModel
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.CookieViewModel
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.HistoryViewModel
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.deniscerri.ytdlnis.util.UpdateUtil
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonParser
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.BufferedReader
|
||||
import java.io.File
|
||||
import java.io.InputStreamReader
|
||||
import java.util.Calendar
|
||||
|
||||
|
||||
class MainSettingsFragment : PreferenceFragmentCompat() {
|
||||
private var backup : Preference? = null
|
||||
private var restore : Preference? = null
|
||||
|
||||
private var updateUtil: UpdateUtil? = null
|
||||
private var fileUtil: FileUtil? = null
|
||||
private var activeDownloadCount = 0
|
||||
|
||||
private lateinit var resultViewModel: ResultViewModel
|
||||
private lateinit var historyViewModel: HistoryViewModel
|
||||
private lateinit var downloadViewModel: DownloadViewModel
|
||||
private lateinit var cookieViewModel: CookieViewModel
|
||||
private lateinit var commandTemplateViewModel: CommandTemplateViewModel
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.root_preferences, rootKey)
|
||||
val navController = findNavController()
|
||||
val appearance = findPreference<Preference>("appearance")
|
||||
appearance?.summary = "${getString(R.string.language)}, ${getString(R.string.Theme)}, ${getString(R.string.accents)}"
|
||||
appearance?.setOnPreferenceClickListener {
|
||||
navController.navigate(R.id.action_mainSettingsFragment_to_appearanceSettingsFragment)
|
||||
true
|
||||
}
|
||||
|
||||
val folders = findPreference<Preference>("folders")
|
||||
folders?.summary = "${getString(R.string.music_directory)}, ${getString(R.string.video_directory)}, ${getString(R.string.command_directory)}"
|
||||
folders?.setOnPreferenceClickListener {
|
||||
navController.navigate(R.id.action_mainSettingsFragment_to_folderSettingsFragment)
|
||||
true
|
||||
}
|
||||
|
||||
val downloading = findPreference<Preference>("downloading")
|
||||
downloading?.summary = "${getString(R.string.quick_download)}, ${getString(R.string.concurrent_downloads)}, ${getString(R.string.limit_rate)}"
|
||||
downloading?.setOnPreferenceClickListener {
|
||||
navController.navigate(R.id.action_mainSettingsFragment_to_downloadSettingsFragment)
|
||||
true
|
||||
}
|
||||
|
||||
val processing = findPreference<Preference>("processing")
|
||||
processing?.summary = "${getString(R.string.sponsorblock)}, ${getString(R.string.embed_subtitles)}, ${getString(R.string.add_chapters)}"
|
||||
processing?.setOnPreferenceClickListener {
|
||||
navController.navigate(R.id.action_mainSettingsFragment_to_processingSettingsFragment)
|
||||
true
|
||||
}
|
||||
|
||||
val updating = findPreference<Preference>("updating")
|
||||
updating?.summary = "${getString(R.string.update_ytdl)}, ${getString(R.string.format_source)}, ${getString(R.string.update_app)}"
|
||||
updating?.setOnPreferenceClickListener {
|
||||
navController.navigate(R.id.action_mainSettingsFragment_to_updateSettingsFragment)
|
||||
true
|
||||
}
|
||||
|
||||
//about section -------------------------
|
||||
updateUtil = UpdateUtil(requireContext())
|
||||
fileUtil = FileUtil()
|
||||
|
||||
WorkManager.getInstance(requireContext()).getWorkInfosByTagLiveData("download").observe(this){
|
||||
activeDownloadCount = 0
|
||||
it.forEach {w ->
|
||||
if (w.state == WorkInfo.State.RUNNING) activeDownloadCount++
|
||||
}
|
||||
}
|
||||
|
||||
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
|
||||
historyViewModel = ViewModelProvider(this)[HistoryViewModel::class.java]
|
||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
cookieViewModel = ViewModelProvider(this)[CookieViewModel::class.java]
|
||||
commandTemplateViewModel = ViewModelProvider(this)[CommandTemplateViewModel::class.java]
|
||||
|
||||
val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
backup = findPreference("backup")
|
||||
restore = findPreference("restore")
|
||||
|
||||
backup!!.onPreferenceClickListener =
|
||||
Preference.OnPreferenceClickListener {
|
||||
val builder = MaterialAlertDialogBuilder(requireContext())
|
||||
builder.setTitle(getString(R.string.select_backup_categories))
|
||||
val values = resources.getStringArray(R.array.backup_category_values)
|
||||
val entries = resources.getStringArray(R.array.backup_category_entries)
|
||||
val checkedItems : ArrayList<Boolean> = arrayListOf()
|
||||
values.forEach { _ ->
|
||||
checkedItems.add(true)
|
||||
}
|
||||
|
||||
builder.setMultiChoiceItems(
|
||||
entries,
|
||||
checkedItems.toBooleanArray()
|
||||
) { _, which, isChecked ->
|
||||
checkedItems[which] = isChecked
|
||||
}
|
||||
|
||||
builder.setPositiveButton(
|
||||
getString(R.string.ok)
|
||||
) { _: DialogInterface?, _: Int ->
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val json = JsonObject()
|
||||
json.addProperty("app", "YTDLnis_backup")
|
||||
for (i in 0 until checkedItems.size) {
|
||||
if (checkedItems[i]) {
|
||||
when(values[i]){
|
||||
"settings" -> json.add("settings", backupSettings(preferences))
|
||||
"downloads" -> json.add("downloads", backupHistory())
|
||||
"queued" -> json.add("queued", backupQueuedDownloads() )
|
||||
"cancelled" -> json.add("cancelled", backupCancelledDownloads() )
|
||||
"cookies" -> json.add("cookies", backupCookies() )
|
||||
"templates" -> json.add("templates", backupCommandTemplates() )
|
||||
"shortcuts" -> json.add("shortcuts", backupShortcuts() )
|
||||
"searchHistory" -> json.add("search_history", backupSearchHistory() )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val currentTime = Calendar.getInstance()
|
||||
val saveFile = File(
|
||||
Environment.getExternalStoragePublicDirectory(
|
||||
Environment.DIRECTORY_DOWNLOADS), "YTDLnis_${BuildConfig.VERSION_NAME}_${currentTime.get(
|
||||
Calendar.YEAR)}-${currentTime.get(Calendar.MONTH) + 1}-${currentTime.get(
|
||||
Calendar.DAY_OF_MONTH)}.json")
|
||||
saveFile.delete()
|
||||
saveFile.createNewFile()
|
||||
saveFile.writeText(Gson().toJson(json))
|
||||
Snackbar.make(requireView(), getString(R.string.backup_created_successfully), Snackbar.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
|
||||
// handle the negative button of the alert dialog
|
||||
builder.setNegativeButton(
|
||||
getString(R.string.cancel)
|
||||
) { _: DialogInterface?, _: Int -> }
|
||||
|
||||
|
||||
val dialog = builder.create()
|
||||
dialog.show()
|
||||
true
|
||||
}
|
||||
restore!!.onPreferenceClickListener =
|
||||
Preference.OnPreferenceClickListener {
|
||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
|
||||
addCategory(Intent.CATEGORY_OPENABLE)
|
||||
type = "application/json"
|
||||
}
|
||||
appRestoreResultLauncher.launch(intent)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
private fun backupSettings(preferences: SharedPreferences) : JsonArray {
|
||||
runCatching {
|
||||
val prefs = preferences.all
|
||||
val arr = JsonArray()
|
||||
prefs.forEach {
|
||||
val obj = JsonObject()
|
||||
obj.addProperty("key", it.key)
|
||||
obj.addProperty("value", it.value.toString())
|
||||
obj.addProperty("type", it.value!!::class.simpleName)
|
||||
arr.add(obj)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
return JsonArray()
|
||||
}
|
||||
|
||||
private suspend fun backupHistory() : JsonArray {
|
||||
runCatching {
|
||||
val historyItems = withContext(Dispatchers.IO) {
|
||||
historyViewModel.getAll()
|
||||
}
|
||||
val arr = JsonArray()
|
||||
historyItems.forEach {
|
||||
arr.add(JsonParser().parse(Gson().toJson(it)).asJsonObject)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
return JsonArray()
|
||||
}
|
||||
|
||||
private suspend fun backupQueuedDownloads() : JsonArray {
|
||||
runCatching {
|
||||
val items = withContext(Dispatchers.IO) {
|
||||
downloadViewModel.getQueued()
|
||||
}
|
||||
val arr = JsonArray()
|
||||
items.forEach {
|
||||
arr.add(JsonParser().parse(Gson().toJson(it)).asJsonObject)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
return JsonArray()
|
||||
}
|
||||
|
||||
private suspend fun backupCancelledDownloads() : JsonArray {
|
||||
runCatching {
|
||||
val items = withContext(Dispatchers.IO) {
|
||||
downloadViewModel.getCancelled()
|
||||
}
|
||||
val arr = JsonArray()
|
||||
items.forEach {
|
||||
arr.add(JsonParser().parse(Gson().toJson(it)).asJsonObject)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
return JsonArray()
|
||||
}
|
||||
|
||||
private suspend fun backupCookies() : JsonArray {
|
||||
runCatching {
|
||||
val items = withContext(Dispatchers.IO) {
|
||||
cookieViewModel.getAll()
|
||||
}
|
||||
val arr = JsonArray()
|
||||
items.forEach {
|
||||
arr.add(JsonParser().parse(Gson().toJson(it)).asJsonObject)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
return JsonArray()
|
||||
}
|
||||
|
||||
private suspend fun backupCommandTemplates() : JsonArray {
|
||||
runCatching {
|
||||
val items = withContext(Dispatchers.IO) {
|
||||
commandTemplateViewModel.getAll()
|
||||
}
|
||||
val arr = JsonArray()
|
||||
items.forEach {
|
||||
arr.add(JsonParser().parse(Gson().toJson(it)).asJsonObject)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
return JsonArray()
|
||||
}
|
||||
|
||||
private suspend fun backupShortcuts() : JsonArray {
|
||||
runCatching {
|
||||
val items = withContext(Dispatchers.IO) {
|
||||
commandTemplateViewModel.getAllShortcuts()
|
||||
}
|
||||
val arr = JsonArray()
|
||||
items.forEach {
|
||||
arr.add(JsonParser().parse(Gson().toJson(it)).asJsonObject)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
return JsonArray()
|
||||
}
|
||||
|
||||
private suspend fun backupSearchHistory() : JsonArray {
|
||||
runCatching {
|
||||
val historyItems = withContext(Dispatchers.IO) {
|
||||
resultViewModel.getSearchHistory()
|
||||
}
|
||||
val arr = JsonArray()
|
||||
historyItems.forEach {
|
||||
arr.add(JsonParser().parse(Gson().toJson(it)).asJsonObject)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
return JsonArray()
|
||||
}
|
||||
|
||||
private var appRestoreResultLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.StartActivityForResult()
|
||||
) { result ->
|
||||
if (result.resultCode == Activity.RESULT_OK) {
|
||||
result.data?.data?.let {
|
||||
activity?.contentResolver?.takePersistableUriPermission(
|
||||
it,
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION or
|
||||
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||
)
|
||||
}
|
||||
|
||||
lifecycleScope.launch {
|
||||
val preferences =
|
||||
PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
val editor = preferences.edit()
|
||||
|
||||
runCatching {
|
||||
val ip = requireContext().contentResolver.openInputStream(result.data!!.data!!)
|
||||
val r = BufferedReader(InputStreamReader(ip))
|
||||
val total: java.lang.StringBuilder = java.lang.StringBuilder()
|
||||
var line: String?
|
||||
while (r.readLine().also { line = it } != null) {
|
||||
total.append(line).append('\n')
|
||||
}
|
||||
|
||||
val json = Gson().fromJson(total.toString(), JsonObject::class.java)
|
||||
val finalMessage = StringBuilder("${getString(R.string.restore_complete)}\n")
|
||||
|
||||
//preference restore
|
||||
if(json.has("settings")){
|
||||
val prefs = json.getAsJsonArray("settings")
|
||||
val preferencesKeys = preferences.all.map { it.key }
|
||||
prefs.forEach {
|
||||
val key : String = it.asJsonObject.get("key").toString().replace("\"", "")
|
||||
if (preferencesKeys.contains(key)){
|
||||
when(it.asJsonObject.get("type").toString().replace("\"", "")){
|
||||
"String" -> {
|
||||
val value = it.asJsonObject.get("value").toString().replace("\"", "")
|
||||
editor.putString(key, value)
|
||||
}
|
||||
"Boolean" -> {
|
||||
val value = it.asJsonObject.get("value").toString().replace("\"", "").toBoolean()
|
||||
editor.putBoolean(key, value)
|
||||
}
|
||||
"Int" -> {
|
||||
val value = it.asJsonObject.get("value").toString().replace("\"", "").toInt()
|
||||
editor.putInt(key, value)
|
||||
}
|
||||
"HashSet" -> {
|
||||
val value = hashSetOf(it.asJsonObject.get("value").toString().replace("(\")|(\\[)|(])".toRegex(), ""))
|
||||
editor.putStringSet(key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finalMessage.append("${getString(R.string.settings)}: ${prefs.count()}\n")
|
||||
}
|
||||
//history restore
|
||||
if(json.has("downloads")){
|
||||
val items = json.getAsJsonArray("downloads")
|
||||
items.forEach {
|
||||
val item = Gson().fromJson(it.toString().replace("^\"|\"$", ""), HistoryItem::class.java)
|
||||
item.id = 0L
|
||||
withContext(Dispatchers.IO){
|
||||
historyViewModel.insert(item)
|
||||
}
|
||||
}
|
||||
finalMessage.append("${getString(R.string.downloads)}: ${items.count()}\n")
|
||||
}
|
||||
|
||||
//queued downloads restore
|
||||
if(json.has("queued")){
|
||||
val items = json.getAsJsonArray("queued")
|
||||
val queued = mutableListOf<DownloadItem>()
|
||||
items.forEach {
|
||||
val item = Gson().fromJson(it.toString().replace("^\"|\"$", ""), DownloadItem::class.java)
|
||||
item.id = 0L
|
||||
queued.add(item)
|
||||
}
|
||||
if (queued.isNotEmpty()) {
|
||||
finalMessage.append("${getString(R.string.in_queue)}: ${queued.count()}\n")
|
||||
withContext(Dispatchers.IO){downloadViewModel.queueDownloads(queued)}
|
||||
}
|
||||
}
|
||||
|
||||
//cancelled downloads restore
|
||||
if(json.has("cancelled")){
|
||||
val items = json.getAsJsonArray("cancelled")
|
||||
val cancelled = mutableListOf<DownloadItem>()
|
||||
items.forEach {
|
||||
val item = Gson().fromJson(it.toString().replace("^\"|\"$", ""), DownloadItem::class.java)
|
||||
item.id = 0L
|
||||
cancelled.add(item)
|
||||
}
|
||||
if(cancelled.isNotEmpty()){
|
||||
finalMessage.append("${getString(R.string.cancelled)}: ${cancelled.count()}\n")
|
||||
}
|
||||
}
|
||||
|
||||
//cookies restore
|
||||
if(json.has("cookies")){
|
||||
val items = json.getAsJsonArray("cookies")
|
||||
items.forEach {
|
||||
val item = Gson().fromJson(it.toString().replace("^\"|\"$", ""), CookieItem::class.java)
|
||||
item.id = 0L
|
||||
withContext(Dispatchers.IO){
|
||||
cookieViewModel.insert(item)
|
||||
}
|
||||
}
|
||||
if(items.count() > 0){
|
||||
finalMessage.append("${getString(R.string.cookies)}: ${items.count()}\n")
|
||||
}
|
||||
}
|
||||
|
||||
//command template restore
|
||||
if(json.has("templates")){
|
||||
val items = json.getAsJsonArray("templates")
|
||||
items.forEach {
|
||||
val item = Gson().fromJson(it.toString().replace("^\"|\"$", ""), CommandTemplate::class.java)
|
||||
item.id = 0L
|
||||
withContext(Dispatchers.IO){
|
||||
commandTemplateViewModel.insert(item)
|
||||
}
|
||||
}
|
||||
if(items.count() > 0){
|
||||
finalMessage.append("${getString(R.string.command_templates)}: ${items.count()}\n")
|
||||
}
|
||||
}
|
||||
|
||||
//shortcuts restore
|
||||
if(json.has("shortcuts")){
|
||||
val items = json.getAsJsonArray("shortcuts")
|
||||
items.forEach {
|
||||
val item = Gson().fromJson(it.toString().replace("^\"|\"$", ""), TemplateShortcut::class.java)
|
||||
item.id = 0L
|
||||
withContext(Dispatchers.IO){
|
||||
commandTemplateViewModel.insertShortcut(item)
|
||||
}
|
||||
}
|
||||
if(items.count() > 0){
|
||||
finalMessage.append("${getString(R.string.shortcuts)}: ${items.count()}\n")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//search history restore
|
||||
if(json.has("search_history")){
|
||||
val items = json.getAsJsonArray("search_history")
|
||||
items.forEach {
|
||||
val item = Gson().fromJson(it.toString().replace("^\"|\"$", ""), SearchHistoryItem::class.java)
|
||||
withContext(Dispatchers.IO){
|
||||
resultViewModel.addSearchQueryToHistory(item.query)
|
||||
}
|
||||
}
|
||||
if(items.count() > 0){
|
||||
finalMessage.append("${getString(R.string.search_history)}: ${items.count()}\n")
|
||||
}
|
||||
}
|
||||
|
||||
finalMessage.append("${getString(R.string.restart)}?")
|
||||
|
||||
val builder = MaterialAlertDialogBuilder(requireContext())
|
||||
builder.setTitle(getString(R.string.restore))
|
||||
builder.setMessage(finalMessage)
|
||||
builder.setPositiveButton(
|
||||
getString(R.string.restart)
|
||||
) { _: DialogInterface?, _: Int ->
|
||||
val intent = Intent(context, MainActivity::class.java)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
requireContext().startActivity(intent)
|
||||
if (context is Activity) {
|
||||
(context as Activity).finish()
|
||||
}
|
||||
Runtime.getRuntime().exit(0)
|
||||
}
|
||||
|
||||
// handle the negative button of the alert dialog
|
||||
builder.setNegativeButton(
|
||||
getString(R.string.cancel)
|
||||
) { _: DialogInterface?, _: Int -> }
|
||||
|
||||
val dialog = builder.create()
|
||||
dialog.show()
|
||||
}.onFailure {
|
||||
it.printStackTrace()
|
||||
Snackbar.make(requireView(), getString(R.string.couldnt_parse_file), Snackbar.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.deniscerri.ytdlnis.ui.more.settings
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.preference.EditTextPreference
|
||||
import androidx.preference.Preference
|
||||
import com.deniscerri.ytdlnis.R
|
||||
|
||||
|
||||
class ProcessingSettingsFragment : BaseSettingsFragment() {
|
||||
override val title: Int = R.string.processing
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.processing_preferences, rootKey)
|
||||
findPreference<EditTextPreference>("file_name_template")?.title = "${getString(R.string.file_name_template)} [${getString(R.string.video)}]"
|
||||
findPreference<EditTextPreference>("file_name_template")?.dialogTitle = "${getString(R.string.file_name_template)} [${getString(R.string.video)}]"
|
||||
|
||||
findPreference<EditTextPreference>("file_name_template_audio")?.title = "${getString(R.string.file_name_template)} [${getString(R.string.audio)}]"
|
||||
findPreference<EditTextPreference>("file_name_template_audio")?.dialogTitle = "${getString(R.string.file_name_template)} [${getString(R.string.audio)}]"
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -3,28 +3,56 @@ package com.deniscerri.ytdlnis.ui.more.settings
|
|||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.activity.addCallback
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.commit
|
||||
import androidx.fragment.app.replace
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.fragment.NavHostFragment
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import com.deniscerri.ytdlnis.MainActivity
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.databinding.ActivitySettingsBinding
|
||||
import com.deniscerri.ytdlnis.ui.BaseActivity
|
||||
import com.google.android.material.appbar.MaterialToolbar
|
||||
|
||||
|
||||
class SettingsActivity : BaseActivity() {
|
||||
private var fm: FragmentManager? = null
|
||||
private var topAppBar: MaterialToolbar? = null
|
||||
private lateinit var sharedPreferences: SharedPreferences
|
||||
private lateinit var editor: SharedPreferences.Editor
|
||||
var context: Context? = null
|
||||
lateinit var binding: ActivitySettingsBinding
|
||||
public override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_settings)
|
||||
context = baseContext
|
||||
topAppBar = findViewById(R.id.settings_toolbar)
|
||||
topAppBar!!.setNavigationOnClickListener { onBackPressedDispatcher.onBackPressed() }
|
||||
fm = supportFragmentManager
|
||||
fm!!.beginTransaction()
|
||||
.replace(R.id.settings_frame_layout, SettingsFragment())
|
||||
.commit()
|
||||
binding = ActivitySettingsBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
val navHostFragment = supportFragmentManager.findFragmentById(R.id.frame_layout) as NavHostFragment
|
||||
val navController = navHostFragment.findNavController()
|
||||
|
||||
val listener = NavController.OnDestinationChangedListener { controller, destination, arguments ->
|
||||
if (destination.id == R.id.mainSettingsFragment){
|
||||
changeTopAppbarTitle(getString(R.string.settings))
|
||||
}
|
||||
}
|
||||
|
||||
navController.addOnDestinationChangedListener(listener)
|
||||
binding.settingsToolbar.setNavigationOnClickListener {
|
||||
onBackPressedDispatcher.onBackPressed()
|
||||
}
|
||||
|
||||
onBackPressedDispatcher.addCallback(this) {
|
||||
if (navController.currentDestination?.id == R.id.mainSettingsFragment) {
|
||||
navController.popBackStack()
|
||||
finishAndRemoveTask()
|
||||
}else{
|
||||
navController.navigateUp()
|
||||
}
|
||||
}
|
||||
|
||||
navController.navigate(R.id.mainSettingsFragment)
|
||||
}
|
||||
|
||||
fun changeTopAppbarTitle(text: String) {
|
||||
if (this::binding.isInitialized) binding.collapsingToolbar.title = text
|
||||
}
|
||||
}
|
||||
|
|
@ -1,522 +0,0 @@
|
|||
package com.deniscerri.ytdlnis.ui.more.settings
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context.POWER_SERVICE
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build.VERSION
|
||||
import android.os.Build.VERSION_CODES
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
import android.os.PowerManager
|
||||
import android.provider.Settings
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.core.content.edit
|
||||
import androidx.core.os.LocaleListCompat
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.EditTextPreference
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.preference.SeekBarPreference
|
||||
import androidx.preference.SwitchPreferenceCompat
|
||||
import androidx.work.WorkInfo
|
||||
import androidx.work.WorkManager
|
||||
import com.deniscerri.ytdlnis.BuildConfig
|
||||
import com.deniscerri.ytdlnis.MainActivity
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.deniscerri.ytdlnis.util.ThemeUtil
|
||||
import com.deniscerri.ytdlnis.util.UpdateUtil
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.yausername.youtubedl_android.YoutubeDL
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.json.buildJsonObject
|
||||
import kotlinx.serialization.json.jsonArray
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import kotlinx.serialization.json.put
|
||||
import kotlinx.serialization.json.putJsonArray
|
||||
import java.io.File
|
||||
import java.util.Locale
|
||||
|
||||
|
||||
class SettingsFragment : PreferenceFragmentCompat() {
|
||||
private var language: ListPreference? = null
|
||||
private var theme: ListPreference? = null
|
||||
private var accent: ListPreference? = null
|
||||
private var highContrast: SwitchPreferenceCompat? = null
|
||||
private var ignoreBatteryOptimization: Preference? = null
|
||||
private var musicPath: Preference? = null
|
||||
private var videoPath: Preference? = null
|
||||
private var commandPath: Preference? = null
|
||||
private var accessAllFiles : Preference? = null
|
||||
private var clearCache: Preference? = null
|
||||
private var locale: ListPreference? = null
|
||||
private var concurrentFragments: SeekBarPreference? = null
|
||||
private var concurrentDownloads: SeekBarPreference? = null
|
||||
private var audioFormat: ListPreference? = null
|
||||
private var videoFormat: ListPreference? = null
|
||||
private var videoQuality: ListPreference? = null
|
||||
private var formatID: EditTextPreference? = null
|
||||
private var updateYTDL: Preference? = null
|
||||
private var formatSource: ListPreference? = null
|
||||
private var exportPreferences : Preference? = null
|
||||
private var importPreferences : Preference? = null
|
||||
private var ytdlVersion: Preference? = null
|
||||
private var version: Preference? = null
|
||||
|
||||
|
||||
private var updateUtil: UpdateUtil? = null
|
||||
private var fileUtil: FileUtil? = null
|
||||
private var activeDownloadCount = 0
|
||||
|
||||
private val jsonFormat = Json { prettyPrint = true }
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.root_preferences, rootKey)
|
||||
updateUtil = UpdateUtil(requireContext())
|
||||
fileUtil = FileUtil()
|
||||
|
||||
WorkManager.getInstance(requireContext()).getWorkInfosByTagLiveData("download").observe(this){
|
||||
activeDownloadCount = 0
|
||||
it.forEach {w ->
|
||||
if (w.state == WorkInfo.State.RUNNING) activeDownloadCount++
|
||||
}
|
||||
}
|
||||
|
||||
initPreferences()
|
||||
initListeners()
|
||||
}
|
||||
|
||||
private fun initPreferences() {
|
||||
val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
val editor = preferences.edit()
|
||||
language = findPreference("app_language")
|
||||
theme = findPreference("ytdlnis_theme")
|
||||
accent = findPreference("theme_accent")
|
||||
highContrast = findPreference("high_contrast")
|
||||
ignoreBatteryOptimization = findPreference("ignore_battery")
|
||||
musicPath = findPreference("music_path")
|
||||
videoPath = findPreference("video_path")
|
||||
commandPath = findPreference("command_path")
|
||||
accessAllFiles = findPreference("access_all_files")
|
||||
clearCache = findPreference("clear_cache")
|
||||
|
||||
locale = findPreference("locale")
|
||||
concurrentFragments = findPreference("concurrent_fragments")
|
||||
concurrentDownloads = findPreference("concurrent_downloads")
|
||||
|
||||
audioFormat = findPreference("audio_format")
|
||||
videoFormat = findPreference("video_format")
|
||||
videoQuality = findPreference("video_quality")
|
||||
formatID = findPreference("format_id")
|
||||
updateYTDL = findPreference("update_ytdl")
|
||||
formatSource = findPreference("formats_source")
|
||||
exportPreferences = findPreference("export_preferences")
|
||||
importPreferences = findPreference("import_preferences")
|
||||
ytdlVersion = findPreference("ytdl-version")
|
||||
ytdlVersion!!.summary = preferences.getString("ytdl-version", "NULL")
|
||||
version = findPreference("version")
|
||||
version!!.summary = BuildConfig.VERSION_NAME
|
||||
|
||||
if(VERSION.SDK_INT < VERSION_CODES.TIRAMISU){
|
||||
val values = resources.getStringArray(R.array.language_values)
|
||||
val entries = mutableListOf<String>()
|
||||
values.forEach {
|
||||
entries.add(Locale(it).getDisplayName(Locale(it)))
|
||||
}
|
||||
language!!.entries = entries.toTypedArray()
|
||||
}else{
|
||||
language!!.isVisible = false
|
||||
}
|
||||
|
||||
val packageName: String = requireContext().packageName
|
||||
val pm = requireContext().applicationContext.getSystemService(POWER_SERVICE) as PowerManager
|
||||
if (pm.isIgnoringBatteryOptimizations(packageName)) {
|
||||
ignoreBatteryOptimization!!.isVisible = false
|
||||
}
|
||||
|
||||
|
||||
if (preferences.getString("music_path", "")!!.isEmpty()) {
|
||||
editor.putString("music_path", getString(R.string.music_path))
|
||||
}
|
||||
if (preferences.getString("video_path", "")!!.isEmpty()) {
|
||||
editor.putString("video_path", getString(R.string.video_path))
|
||||
}
|
||||
if (preferences.getString("command_path", "")!!.isEmpty()) {
|
||||
editor.putString("command_path", getString(R.string.command_path))
|
||||
}
|
||||
|
||||
if((VERSION.SDK_INT >= 30 && Environment.isExternalStorageManager()) ||
|
||||
VERSION.SDK_INT < 30) {
|
||||
accessAllFiles!!.isVisible = false
|
||||
}
|
||||
|
||||
editor.apply()
|
||||
}
|
||||
|
||||
@SuppressLint("BatteryLife", "InlinedApi")
|
||||
private fun initListeners() {
|
||||
val preferences =
|
||||
PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
val editor = preferences.edit()
|
||||
|
||||
if(language!!.value == null) language!!.value = Locale.getDefault().language
|
||||
language!!.summary = Locale(language!!.value).getDisplayLanguage(Locale(language!!.value))
|
||||
language!!.onPreferenceChangeListener =
|
||||
Preference.OnPreferenceChangeListener { _: Preference?, newValue: Any ->
|
||||
language!!.summary = Locale(newValue.toString()).getDisplayLanguage(Locale(newValue.toString()))
|
||||
AppCompatDelegate.setApplicationLocales(LocaleListCompat.forLanguageTags(newValue.toString()))
|
||||
true
|
||||
}
|
||||
|
||||
theme!!.summary = theme!!.entry
|
||||
theme!!.onPreferenceChangeListener =
|
||||
Preference.OnPreferenceChangeListener { _: Preference?, newValue: Any ->
|
||||
when(newValue){
|
||||
"System" -> {
|
||||
theme!!.summary = getString(R.string.system)
|
||||
}
|
||||
"Dark" -> {
|
||||
theme!!.summary = getString(R.string.dark)
|
||||
}
|
||||
else -> {
|
||||
theme!!.summary = getString(R.string.light)
|
||||
}
|
||||
}
|
||||
ThemeUtil.updateTheme(requireActivity() as AppCompatActivity)
|
||||
val intent = Intent(requireContext(), MainActivity::class.java)
|
||||
this.startActivity(intent)
|
||||
requireActivity().finishAffinity()
|
||||
true
|
||||
}
|
||||
accent!!.summary = accent!!.entry
|
||||
accent!!.onPreferenceChangeListener =
|
||||
Preference.OnPreferenceChangeListener { _: Preference?, _: Any ->
|
||||
ThemeUtil.updateTheme(requireActivity() as AppCompatActivity)
|
||||
val intent = Intent(requireContext(), MainActivity::class.java)
|
||||
this.startActivity(intent)
|
||||
requireActivity().finishAffinity()
|
||||
true
|
||||
}
|
||||
highContrast!!.onPreferenceChangeListener =
|
||||
Preference.OnPreferenceChangeListener { _: Preference?, _: Any ->
|
||||
ThemeUtil.updateTheme(requireActivity() as AppCompatActivity)
|
||||
val intent = Intent(requireContext(), MainActivity::class.java)
|
||||
this.startActivity(intent)
|
||||
requireActivity().finishAffinity()
|
||||
|
||||
true
|
||||
}
|
||||
ignoreBatteryOptimization!!.onPreferenceClickListener =
|
||||
Preference.OnPreferenceClickListener {
|
||||
val intent = Intent()
|
||||
intent.action = Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
|
||||
intent.data = Uri.parse("package:" + requireContext().packageName)
|
||||
startActivity(intent)
|
||||
true
|
||||
}
|
||||
|
||||
musicPath!!.summary = fileUtil?.formatPath(preferences.getString("music_path", "")!!)
|
||||
musicPath!!.onPreferenceClickListener =
|
||||
Preference.OnPreferenceClickListener {
|
||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
||||
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
|
||||
musicPathResultLauncher.launch(intent)
|
||||
true
|
||||
}
|
||||
videoPath!!.summary = fileUtil?.formatPath(preferences.getString("video_path", "")!!)
|
||||
videoPath!!.onPreferenceClickListener =
|
||||
Preference.OnPreferenceClickListener {
|
||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
||||
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
|
||||
videoPathResultLauncher.launch(intent)
|
||||
true
|
||||
}
|
||||
commandPath!!.summary = fileUtil?.formatPath(preferences.getString("command_path", "")!!)
|
||||
commandPath!!.onPreferenceClickListener =
|
||||
Preference.OnPreferenceClickListener {
|
||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
||||
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
|
||||
commandPathResultLauncher.launch(intent)
|
||||
true
|
||||
}
|
||||
accessAllFiles!!.onPreferenceClickListener =
|
||||
Preference.OnPreferenceClickListener {
|
||||
val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
|
||||
val uri = Uri.parse("package:" + requireContext().packageName)
|
||||
intent.data = uri
|
||||
startActivity(intent)
|
||||
true
|
||||
}
|
||||
|
||||
var cacheSize = File(requireContext().cacheDir.absolutePath + "/downloads").walkBottomUp().fold(0L) { acc, file -> acc + file.length() }
|
||||
clearCache!!.summary = "(${fileUtil!!.convertFileSize(cacheSize)}) ${resources.getString(R.string.clear_temporary_files_summary)}"
|
||||
clearCache!!.onPreferenceClickListener =
|
||||
Preference.OnPreferenceClickListener {
|
||||
if (activeDownloadCount == 0){
|
||||
File(requireContext().cacheDir.absolutePath + "/downloads").deleteRecursively()
|
||||
Snackbar.make(requireView(), getString(R.string.cache_cleared), Snackbar.LENGTH_SHORT).show()
|
||||
cacheSize = File(requireContext().cacheDir.absolutePath + "/downloads").walkBottomUp().fold(0L) { acc, file -> acc + file.length() }
|
||||
clearCache!!.summary = "(${fileUtil!!.convertFileSize(cacheSize)}) ${resources.getString(R.string.clear_temporary_files_summary)}"
|
||||
}else{
|
||||
Snackbar.make(requireView(), getString(R.string.downloads_running_try_later), Snackbar.LENGTH_SHORT).show()
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
locale!!.summary = locale!!.value
|
||||
concurrentDownloads!!.onPreferenceChangeListener =
|
||||
Preference.OnPreferenceChangeListener { _: Preference?, _: Any ->
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(resources.getString(R.string.warning))
|
||||
.setMessage(resources.getString(R.string.workmanager_updated))
|
||||
.setNegativeButton(resources.getString(R.string.cancel)) { dialog, _ ->
|
||||
dialog.cancel()
|
||||
}
|
||||
.setPositiveButton(resources.getString(R.string.restart)) { _, _ ->
|
||||
val intent = Intent(context, MainActivity::class.java)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
requireContext().startActivity(intent)
|
||||
if (context is Activity) {
|
||||
(context as Activity).finish()
|
||||
}
|
||||
Runtime.getRuntime().exit(0)
|
||||
}
|
||||
.show()
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
audioFormat!!.summary = preferences.getString("audio_format", "")!!.replace("Default", getString(R.string.defaultValue))
|
||||
audioFormat!!.onPreferenceChangeListener =
|
||||
Preference.OnPreferenceChangeListener { _: Preference?, newValue: Any ->
|
||||
audioFormat!!.summary = newValue.toString().replace("Default", getString(R.string.defaultValue))
|
||||
true
|
||||
}
|
||||
videoFormat!!.summary = preferences.getString("video_format", "")!!.replace("Default", getString(R.string.defaultValue))
|
||||
videoFormat!!.onPreferenceChangeListener =
|
||||
Preference.OnPreferenceChangeListener { _: Preference?, newValue: Any ->
|
||||
videoFormat!!.summary = newValue.toString().replace("Default", getString(R.string.defaultValue))
|
||||
true
|
||||
}
|
||||
|
||||
videoQuality!!.summary = preferences.getString("video_quality", "")
|
||||
videoQuality!!.onPreferenceChangeListener =
|
||||
Preference.OnPreferenceChangeListener { _: Preference?, newValue: Any ->
|
||||
videoQuality!!.summary = newValue.toString()
|
||||
true
|
||||
}
|
||||
formatID!!.summary = formatID!!.text
|
||||
formatID!!.onPreferenceChangeListener =
|
||||
Preference.OnPreferenceChangeListener { _: Preference?, newValue: Any ->
|
||||
formatID!!.summary = newValue.toString()
|
||||
true
|
||||
}
|
||||
YoutubeDL.getInstance().version(context)?.let {
|
||||
editor.putString("ytdl-version", it)
|
||||
editor.apply()
|
||||
ytdlVersion!!.summary = it
|
||||
}
|
||||
updateYTDL!!.onPreferenceClickListener =
|
||||
Preference.OnPreferenceClickListener {
|
||||
lifecycleScope.launch {
|
||||
Snackbar.make(requireView(),
|
||||
requireContext().getString(R.string.ytdl_updating_started),
|
||||
Snackbar.LENGTH_LONG).show()
|
||||
when (updateUtil!!.updateYoutubeDL()) {
|
||||
YoutubeDL.UpdateStatus.DONE -> {
|
||||
Snackbar.make(requireView(),
|
||||
requireContext().getString(R.string.ytld_update_success),
|
||||
Snackbar.LENGTH_LONG).show()
|
||||
|
||||
YoutubeDL.getInstance().version(context)?.let {
|
||||
editor.putString("ytdl-version", it)
|
||||
editor.apply()
|
||||
ytdlVersion!!.summary = it
|
||||
}
|
||||
}
|
||||
YoutubeDL.UpdateStatus.ALREADY_UP_TO_DATE -> Snackbar.make(requireView(),
|
||||
requireContext().getString(R.string.you_are_in_latest_version),
|
||||
Snackbar.LENGTH_LONG).show()
|
||||
else -> {
|
||||
Snackbar.make(requireView(),
|
||||
requireContext().getString(R.string.errored),
|
||||
Snackbar.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
formatSource!!.summary = preferences.getString("formats_source", "")!!.replace("Default", getString(R.string.defaultValue))
|
||||
formatSource!!.onPreferenceChangeListener =
|
||||
Preference.OnPreferenceChangeListener { _: Preference?, newValue: Any ->
|
||||
formatSource!!.summary = newValue.toString().replace("Default", getString(R.string.defaultValue))
|
||||
true
|
||||
}
|
||||
exportPreferences!!.onPreferenceClickListener =
|
||||
Preference.OnPreferenceClickListener {
|
||||
val prefs = preferences.all
|
||||
val json = buildJsonObject {
|
||||
putJsonArray("YTDLnis_Preferences") {
|
||||
prefs.forEach {
|
||||
add(buildJsonObject {
|
||||
put("key", it.key)
|
||||
put("value", it.value.toString())
|
||||
put("type", it.value!!::class.simpleName)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
val string = jsonFormat.encodeToString(json)
|
||||
val clipboard: ClipboardManager =
|
||||
requireContext().getSystemService(AppCompatActivity.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
clipboard.setText(string)
|
||||
Snackbar.make(requireView(), getString(R.string.copied_to_clipboard), Snackbar.LENGTH_LONG).show()
|
||||
true
|
||||
}
|
||||
importPreferences!!.onPreferenceClickListener =
|
||||
Preference.OnPreferenceClickListener {
|
||||
val clipboard = requireContext().getSystemService(AppCompatActivity.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clip = clipboard.primaryClip!!.getItemAt(0).text.toString()
|
||||
try{
|
||||
PreferenceManager.getDefaultSharedPreferences(requireContext()).edit(commit = true) {
|
||||
clear()
|
||||
|
||||
val preferencesKeys = preferences.all.map { it.key }
|
||||
jsonFormat.decodeFromString<JsonObject>(clip).run {
|
||||
val prefs = this.jsonObject["YTDLnis_Preferences"]!!.jsonArray
|
||||
prefs.forEach {
|
||||
val key : String = it.jsonObject["key"].toString().replace("\"", "")
|
||||
if (preferencesKeys.contains(key)){
|
||||
when(it.jsonObject["type"].toString().replace("\"", "")){
|
||||
"String" -> {
|
||||
val value = it.jsonObject["value"].toString().replace("\"", "")
|
||||
putString(key, value)
|
||||
}
|
||||
"Boolean" -> {
|
||||
val value = it.jsonObject["value"].toString().replace("\"", "").toBoolean()
|
||||
putBoolean(key, value)
|
||||
}
|
||||
"Int" -> {
|
||||
val value = it.jsonObject["value"].toString().replace("\"", "").toInt()
|
||||
putInt(key, value)
|
||||
}
|
||||
"HashSet" -> {
|
||||
val value = hashSetOf(it.jsonObject["value"].toString().replace("(\")|(\\[)|(])".toRegex(), ""))
|
||||
putStringSet(key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val intent = Intent(context, MainActivity::class.java)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
requireContext().startActivity(intent)
|
||||
if (context is Activity) {
|
||||
(context as Activity).finish()
|
||||
}
|
||||
Runtime.getRuntime().exit(0)
|
||||
}catch (e: Exception){
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
version!!.onPreferenceClickListener =
|
||||
Preference.OnPreferenceClickListener {
|
||||
lifecycleScope.launch{
|
||||
withContext(Dispatchers.IO){
|
||||
updateUtil!!.updateApp{ msg ->
|
||||
lifecycleScope.launch(Dispatchers.Main){
|
||||
Snackbar.make(requireView(), msg, Snackbar.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
private var musicPathResultLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.StartActivityForResult()
|
||||
) { result ->
|
||||
if (result.resultCode == Activity.RESULT_OK) {
|
||||
result.data?.data?.let {
|
||||
activity?.contentResolver?.takePersistableUriPermission(
|
||||
it,
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION or
|
||||
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||
)
|
||||
}
|
||||
changePath(musicPath, result.data, MUSIC_PATH_CODE)
|
||||
}
|
||||
}
|
||||
private var videoPathResultLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.StartActivityForResult()
|
||||
) { result ->
|
||||
if (result.resultCode == Activity.RESULT_OK) {
|
||||
result.data?.data?.let {
|
||||
activity?.contentResolver?.takePersistableUriPermission(
|
||||
it,
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION or
|
||||
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||
)
|
||||
}
|
||||
changePath(videoPath, result.data, VIDEO_PATH_CODE)
|
||||
}
|
||||
}
|
||||
private var commandPathResultLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.StartActivityForResult()
|
||||
) { result ->
|
||||
if (result.resultCode == Activity.RESULT_OK) {
|
||||
result.data?.data?.let {
|
||||
activity?.contentResolver?.takePersistableUriPermission(
|
||||
it,
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION or
|
||||
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||
)
|
||||
}
|
||||
changePath(commandPath, result.data, COMMAND_PATH_CODE)
|
||||
}
|
||||
}
|
||||
|
||||
private fun changePath(p: Preference?, data: Intent?, requestCode: Int) {
|
||||
val path = data!!.data.toString()
|
||||
p!!.summary = fileUtil?.formatPath(data.data.toString())
|
||||
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
val editor = sharedPreferences.edit()
|
||||
when (requestCode) {
|
||||
MUSIC_PATH_CODE -> editor.putString("music_path", path)
|
||||
VIDEO_PATH_CODE -> editor.putString("video_path", path)
|
||||
COMMAND_PATH_CODE -> editor.putString("command_path", path)
|
||||
}
|
||||
editor.apply()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val MUSIC_PATH_CODE = 33333
|
||||
const val VIDEO_PATH_CODE = 55555
|
||||
const val COMMAND_PATH_CODE = 77777
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
package com.deniscerri.ytdlnis.ui.more.settings
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.deniscerri.ytdlnis.BuildConfig
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.util.UpdateUtil
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.yausername.youtubedl_android.YoutubeDL
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
|
||||
class UpdateSettingsFragment : BaseSettingsFragment() {
|
||||
override val title: Int = R.string.updating
|
||||
private var updateYTDL: Preference? = null
|
||||
private var ytdlVersion: Preference? = null
|
||||
private var version: Preference? = null
|
||||
private var updateUtil: UpdateUtil? = null
|
||||
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.updating_preferences, rootKey)
|
||||
updateUtil = UpdateUtil(requireContext())
|
||||
val preferences =
|
||||
PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
val editor = preferences.edit()
|
||||
updateYTDL = findPreference("update_ytdl")
|
||||
ytdlVersion = findPreference("ytdl-version")
|
||||
version = findPreference("version")
|
||||
version!!.summary = BuildConfig.VERSION_NAME
|
||||
|
||||
YoutubeDL.getInstance().version(context)?.let {
|
||||
editor.putString("ytdl-version", it)
|
||||
editor.apply()
|
||||
ytdlVersion!!.summary = it
|
||||
}
|
||||
updateYTDL!!.onPreferenceClickListener =
|
||||
Preference.OnPreferenceClickListener {
|
||||
lifecycleScope.launch {
|
||||
Snackbar.make(requireView(),
|
||||
requireContext().getString(R.string.ytdl_updating_started),
|
||||
Snackbar.LENGTH_LONG).show()
|
||||
when (updateUtil!!.updateYoutubeDL()) {
|
||||
YoutubeDL.UpdateStatus.DONE -> {
|
||||
Snackbar.make(requireView(),
|
||||
requireContext().getString(R.string.ytld_update_success),
|
||||
Snackbar.LENGTH_LONG).show()
|
||||
|
||||
YoutubeDL.getInstance().version(context)?.let {
|
||||
editor.putString("ytdl-version", it)
|
||||
editor.apply()
|
||||
ytdlVersion!!.summary = it
|
||||
}
|
||||
}
|
||||
YoutubeDL.UpdateStatus.ALREADY_UP_TO_DATE -> Snackbar.make(requireView(),
|
||||
requireContext().getString(R.string.you_are_in_latest_version),
|
||||
Snackbar.LENGTH_LONG).show()
|
||||
else -> {
|
||||
Snackbar.make(requireView(),
|
||||
requireContext().getString(R.string.errored),
|
||||
Snackbar.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
version!!.onPreferenceClickListener =
|
||||
Preference.OnPreferenceClickListener {
|
||||
lifecycleScope.launch{
|
||||
withContext(Dispatchers.IO){
|
||||
updateUtil!!.updateApp{ msg ->
|
||||
lifecycleScope.launch(Dispatchers.Main){
|
||||
Snackbar.make(requireView(), msg, Snackbar.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -525,49 +525,63 @@ class InfoUtil(private val context: Context) {
|
|||
urls.forEach {
|
||||
urlsFile.appendText(it+"\n")
|
||||
}
|
||||
try {
|
||||
val request = YoutubeDLRequest(emptyList())
|
||||
request.addOption("--print", "%(formats)s")
|
||||
request.addOption("-a", urlsFile.absolutePath)
|
||||
request.addOption("--skip-download")
|
||||
request.addOption("-R", "1")
|
||||
request.addOption("--socket-timeout", "5")
|
||||
val cookiesFile = File(context.cacheDir, "cookies.txt")
|
||||
if (cookiesFile.exists()){
|
||||
request.addOption("--cookies", cookiesFile.absolutePath)
|
||||
}
|
||||
|
||||
YoutubeDL.getInstance().execute(request){ progress, _, line ->
|
||||
try{
|
||||
val formats = mutableListOf<Format>()
|
||||
val listOfStrings = JSONArray(line)
|
||||
for (f in 0 until listOfStrings.length()){
|
||||
val format = listOfStrings.get(f) as JSONObject
|
||||
try{
|
||||
if (format.getString("filesize") == "None") continue
|
||||
}catch (e: Exception) { continue }
|
||||
val formatProper = Gson().fromJson(format.toString(), Format::class.java)
|
||||
if (formatProper.filesize > 0){
|
||||
if ( !formatProper!!.format_note!!.contains("audio only", true)) {
|
||||
formatProper.format_note = format.getString("format_note")
|
||||
}else{
|
||||
formatProper.format_note = "${format.getString("format_note")} audio"
|
||||
}
|
||||
formatProper.container = format.getString("ext")
|
||||
formats.add(formatProper)
|
||||
}
|
||||
}
|
||||
progress(formats)
|
||||
}catch (e: Exception){
|
||||
progress(emptyList())
|
||||
val formatSource = sharedPreferences.getString("formats_source", "yt-dlp")
|
||||
val p = Pattern.compile("^(https?)://(www.)?youtu(.be)?")
|
||||
val allYoutubeLinks = urls.any {p.matcher(it).find() }
|
||||
if (formatSource == "yt-dlp" || !allYoutubeLinks){
|
||||
try {
|
||||
val request = YoutubeDLRequest(emptyList())
|
||||
request.addOption("--print", "%(formats)s")
|
||||
request.addOption("-a", urlsFile.absolutePath)
|
||||
request.addOption("--skip-download")
|
||||
request.addOption("-R", "1")
|
||||
request.addOption("--socket-timeout", "5")
|
||||
val cookiesFile = File(context.cacheDir, "cookies.txt")
|
||||
if (cookiesFile.exists()){
|
||||
request.addOption("--cookies", cookiesFile.absolutePath)
|
||||
}
|
||||
|
||||
YoutubeDL.getInstance().execute(request){ progress, _, line ->
|
||||
try{
|
||||
val formats = mutableListOf<Format>()
|
||||
val listOfStrings = JSONArray(line)
|
||||
for (f in 0 until listOfStrings.length()){
|
||||
val format = listOfStrings.get(f) as JSONObject
|
||||
try{
|
||||
if (format.getString("filesize") == "None") continue
|
||||
}catch (e: Exception) { continue }
|
||||
val formatProper = Gson().fromJson(format.toString(), Format::class.java)
|
||||
if (formatProper.filesize > 0){
|
||||
if ( !formatProper!!.format_note!!.contains("audio only", true)) {
|
||||
formatProper.format_note = format.getString("format_note")
|
||||
}else{
|
||||
formatProper.format_note = "${format.getString("format_note")} audio"
|
||||
}
|
||||
formatProper.container = format.getString("ext")
|
||||
formats.add(formatProper)
|
||||
}
|
||||
}
|
||||
progress(formats)
|
||||
}catch (e: Exception){
|
||||
progress(emptyList())
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Looper.prepare().run {
|
||||
Toast.makeText(context, e.message, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
e.printStackTrace()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Looper.prepare().run {
|
||||
Toast.makeText(context, e.message, Toast.LENGTH_LONG).show()
|
||||
}else{
|
||||
urls.forEach {
|
||||
val id = getIDFromYoutubeURL(it)
|
||||
val res = genericRequest(invidousURL + "videos/" + id)
|
||||
val vid = createVideoFromInvidiousJSON(res)
|
||||
progress(vid!!.formats)
|
||||
}
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
urlsFile.delete()
|
||||
}
|
||||
|
||||
|
|
@ -741,6 +755,7 @@ class InfoUtil(private val context: Context) {
|
|||
val url = "https://suggestqueries.google.com/complete/search?client=youtube&ds=yt&client=firefox&q=$query"
|
||||
// invidousURL + "search/suggestions?q=" + query
|
||||
val res = genericArrayRequest(url)
|
||||
Log.e("aa", res.toString())
|
||||
if (res.length() == 0) return ArrayList()
|
||||
val suggestionList = ArrayList<String>()
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -303,6 +303,107 @@ class UiUtil(private val fileUtil: FileUtil) {
|
|||
datePicker.show(fragmentManager, "datepicker")
|
||||
}
|
||||
|
||||
fun showFormatDetails(format: Format, activity: Activity){
|
||||
val bottomSheet = BottomSheetDialog(activity)
|
||||
bottomSheet.requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
bottomSheet.setContentView(R.layout.format_details_sheet)
|
||||
|
||||
val formatIdParent = bottomSheet.findViewById<LinearLayout>(R.id.format_id_parent)
|
||||
val containerParent = bottomSheet.findViewById<LinearLayout>(R.id.container_parent)
|
||||
val codecParent = bottomSheet.findViewById<LinearLayout>(R.id.codec_parent)
|
||||
val filesizeParent = bottomSheet.findViewById<LinearLayout>(R.id.filesize_parent)
|
||||
val formatnoteParent = bottomSheet.findViewById<LinearLayout>(R.id.format_note_parent)
|
||||
val fpsParent = bottomSheet.findViewById<LinearLayout>(R.id.fps_parent)
|
||||
val asrParent = bottomSheet.findViewById<LinearLayout>(R.id.asr_parent)
|
||||
|
||||
if (format.format_id.isBlank()) formatIdParent?.visibility = View.GONE
|
||||
else {
|
||||
formatIdParent?.findViewById<TextView>(R.id.format_id_value)?.text = format.format_id
|
||||
formatIdParent?.setOnClickListener {
|
||||
copyToClipboard(format.format_id, activity)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (format.container.isBlank()) containerParent?.visibility = View.GONE
|
||||
else {
|
||||
containerParent?.findViewById<TextView>(R.id.container_value)?.text = format.container
|
||||
containerParent?.setOnClickListener {
|
||||
copyToClipboard(format.container, activity)
|
||||
}
|
||||
}
|
||||
|
||||
val codecField =
|
||||
if (format.encoding != "") {
|
||||
format.encoding.uppercase()
|
||||
}else if (format.vcodec != "none" && format.vcodec != ""){
|
||||
format.vcodec.uppercase()
|
||||
} else {
|
||||
format.acodec.uppercase()
|
||||
}
|
||||
|
||||
if (codecField.isBlank()) codecParent?.visibility = View.GONE
|
||||
else {
|
||||
codecParent?.findViewById<TextView>(R.id.codec_value)?.text = codecField
|
||||
codecParent?.setOnClickListener {
|
||||
copyToClipboard(codecField, activity)
|
||||
}
|
||||
}
|
||||
|
||||
if (format.filesize != 0L) filesizeParent?.visibility = View.GONE
|
||||
else {
|
||||
filesizeParent?.findViewById<TextView>(R.id.filesize_value)?.text = fileUtil.convertFileSize(format.filesize)
|
||||
filesizeParent?.setOnClickListener {
|
||||
copyToClipboard(fileUtil.convertFileSize(format.filesize), activity)
|
||||
}
|
||||
}
|
||||
|
||||
if (format.format_note.isBlank()) formatnoteParent?.visibility = View.GONE
|
||||
else {
|
||||
formatnoteParent?.findViewById<TextView>(R.id.format_note_value)?.text = format.format_note
|
||||
formatnoteParent?.setOnClickListener {
|
||||
copyToClipboard(format.format_note, activity)
|
||||
}
|
||||
}
|
||||
|
||||
if (format.fps.isNullOrBlank()) fpsParent?.visibility = View.GONE
|
||||
else {
|
||||
fpsParent?.findViewById<TextView>(R.id.fps_value)?.text = format.fps
|
||||
fpsParent?.setOnClickListener {
|
||||
copyToClipboard(format.fps!!, activity)
|
||||
}
|
||||
}
|
||||
|
||||
if (format.asr.isNullOrBlank()) asrParent?.visibility = View.GONE
|
||||
else {
|
||||
asrParent?.findViewById<TextView>(R.id.asr_value)?.text = format.asr
|
||||
asrParent?.setOnClickListener {
|
||||
copyToClipboard(format.asr!!, activity)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bottomSheet.show()
|
||||
val displayMetrics = DisplayMetrics()
|
||||
activity.windowManager.defaultDisplay.getMetrics(displayMetrics)
|
||||
bottomSheet.behavior.peekHeight = displayMetrics.heightPixels
|
||||
bottomSheet.window!!.setLayout(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
private fun copyToClipboard(text: String, activity: Activity){
|
||||
val clipboard = activity.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clip = ClipData.newPlainText(text, text)
|
||||
clipboard.setPrimaryClip(clip)
|
||||
Toast.makeText(activity, activity.getString(R.string.copied_to_clipboard), Toast.LENGTH_SHORT)
|
||||
.show()
|
||||
}
|
||||
|
||||
|
||||
suspend fun showCommandTemplates(activity: Activity, commandTemplateViewModel: CommandTemplateViewModel, itemSelected: (itemSelected: CommandTemplate) -> Unit) {
|
||||
val bottomSheet = BottomSheetDialog(activity)
|
||||
bottomSheet.requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ class UpdateUtil(var context: Context) {
|
|||
version = res.getString("tag_name")
|
||||
body = res.getString("body")
|
||||
} catch (e: JSONException) {
|
||||
result(e.message.toString())
|
||||
result(context.getString(R.string.network_error))
|
||||
return
|
||||
}
|
||||
val versionNameInt = version.split("v")[1].replace(".","").toInt()
|
||||
|
|
|
|||
|
|
@ -178,8 +178,8 @@ class DownloadWorker(
|
|||
when(type){
|
||||
DownloadViewModel.Type.audio -> {
|
||||
var audioQualityId : String = downloadItem.format.format_id
|
||||
if (audioQualityId.isBlank() || audioQualityId == "0" || audioQualityId == context.getString(R.string.best_quality)) audioQualityId = ""
|
||||
else if (audioQualityId == context.getString(R.string.worst_quality)) audioQualityId = "worstaudio"
|
||||
if (audioQualityId.isBlank() || audioQualityId == "0" || audioQualityId == context.getString(R.string.best_quality) || audioQualityId == "best") audioQualityId = ""
|
||||
else if (audioQualityId == context.getString(R.string.worst_quality) || audioQualityId == "worst") audioQualityId = "worstaudio"
|
||||
|
||||
val ext = downloadItem.format.container
|
||||
if (audioQualityId.isNotBlank()) request.addOption("-f", audioQualityId)
|
||||
|
|
@ -236,15 +236,15 @@ class DownloadWorker(
|
|||
Log.e(TAG, videoFormatID)
|
||||
var formatArgument = if (downloadItem.videoPreferences.removeAudio) "bestvideo" else "bestvideo+bestaudio/best"
|
||||
if (videoFormatID.isNotEmpty()) {
|
||||
if (videoFormatID == context.resources.getString(R.string.best_quality)) videoFormatID = "bestvideo"
|
||||
else if (videoFormatID == context.resources.getString(R.string.worst_quality)) videoFormatID = "worst"
|
||||
if (videoFormatID == context.resources.getString(R.string.best_quality) || videoFormatID == "best") videoFormatID = "bestvideo"
|
||||
else if (videoFormatID == context.resources.getString(R.string.worst_quality) || videoFormatID == "worst") videoFormatID = "worst"
|
||||
else if (defaultFormats.contains(videoFormatID)) videoFormatID = "bestvideo[height<="+videoFormatID.substring(0, videoFormatID.length -1)+"]"
|
||||
if (!downloadItem.videoPreferences.removeAudio) formatArgument = "$videoFormatID+bestaudio/best/$videoFormatID"
|
||||
}
|
||||
Log.e(TAG, formatArgument)
|
||||
request.addOption("-f", formatArgument)
|
||||
val format = downloadItem.format.container
|
||||
if(format.isNotEmpty()){
|
||||
if(format.isNotEmpty() && format != "Default" && format != context.getString(R.string.defaultValue)){
|
||||
request.addOption("--merge-output-format", format)
|
||||
if (format != "webm") {
|
||||
val embedThumb = sharedPreferences.getBoolean("embed_thumbnail", false)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="Incognito"
|
||||
android:text="@string/incognito"
|
||||
android:textStyle="bold"
|
||||
android:translationZ="20dp"
|
||||
android:visibility="gone"
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="Incognito"
|
||||
android:text="@string/incognito"
|
||||
android:textStyle="bold"
|
||||
android:translationZ="20dp"
|
||||
android:visibility="gone"
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
android:id="@+id/logs_recyclerview"
|
||||
android:layout_width="match_parent"
|
||||
android:scrollbars="vertical"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="Incognito"
|
||||
android:text="@string/incognito"
|
||||
android:textStyle="bold"
|
||||
android:visibility="gone"
|
||||
android:padding="5dp"
|
||||
|
|
|
|||
|
|
@ -6,32 +6,44 @@
|
|||
android:layout_height="match_parent"
|
||||
tools:context="com.deniscerri.ytdlnis.ui.more.settings.SettingsActivity">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/settings_frame_layout"
|
||||
android:layout_width="match_parent"
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/frame_layout"
|
||||
android:name="androidx.navigation.fragment.NavHostFragment"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:defaultNavHost="true"
|
||||
app:navGraph="@navigation/settings_nav"
|
||||
app:layout_constraintBottom_toTopOf="@+id/bottomNavigationView"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
app:layout_constraintTop_toBottomOf="@+id/incognito_header"
|
||||
/>
|
||||
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:liftOnScroll="true"
|
||||
android:background="@android:color/transparent"
|
||||
android:fitsSystemWindows="true">
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/settings_toolbar"
|
||||
android:elevation="0dp"
|
||||
app:layout_scrollFlags="scroll|enterAlways|snap"
|
||||
app:title="@string/settings"
|
||||
<com.google.android.material.appbar.CollapsingToolbarLayout
|
||||
android:id="@+id/collapsing_toolbar"
|
||||
style="?attr/collapsingToolbarLayoutLargeStyle"
|
||||
android:layout_width="match_parent"
|
||||
app:navigationIcon="@drawable/ic_back"
|
||||
android:layout_height="match_parent"/>
|
||||
app:title="@string/settings"
|
||||
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
|
||||
android:layout_height="?attr/collapsingToolbarLayoutLargeSize">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/settings_toolbar"
|
||||
android:elevation="0dp"
|
||||
app:layout_collapseMode="pin"
|
||||
app:layout_scrollFlags="scroll"
|
||||
app:navigationIcon="@drawable/ic_back"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"/>
|
||||
|
||||
</com.google.android.material.appbar.CollapsingToolbarLayout>
|
||||
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
|
|
|||
|
|
@ -1,154 +1,147 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.core.widget.NestedScrollView android:layout_width="match_parent"
|
||||
android:scrollbars="none"
|
||||
android:orientation="vertical"
|
||||
android:layout_height="wrap_content"
|
||||
android:fillViewport="true"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:scrollbars="none"
|
||||
android:orientation="vertical"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="20dp"
|
||||
android:orientation="horizontal"
|
||||
android:paddingTop="20dp">
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/bottom_sheet_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:maxLines="2"
|
||||
android:singleLine="false"
|
||||
android:text="@string/download"
|
||||
android:textSize="25sp"
|
||||
app:layout_constraintEnd_toStartOf="@+id/bottomsheet_schedule_button"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/bottom_sheet_subtitle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="2"
|
||||
android:singleLine="false"
|
||||
android:text="@string/configure_download"
|
||||
android:textSize="12sp"
|
||||
app:layout_constraintEnd_toStartOf="@+id/bottomsheet_schedule_button"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/bottom_sheet_title" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/bottomsheet_schedule_button"
|
||||
style="@style/Widget.Material3.Button.IconButton.Filled"
|
||||
android:layout_width="wrap_content"
|
||||
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"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/bottomsheet_download_button"
|
||||
style="@style/Widget.Material3.Button.ElevatedButton.Icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:autoLink="all"
|
||||
android:text="@string/download"
|
||||
app:icon="@drawable/ic_down"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/download_tablayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
android:backgroundTint="@android:color/transparent"
|
||||
app:tabGravity="start"
|
||||
app:tabMode="scrollable">
|
||||
|
||||
<com.google.android.material.tabs.TabItem
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@string/audio" />
|
||||
|
||||
<com.google.android.material.tabs.TabItem
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@string/video" />
|
||||
|
||||
<com.google.android.material.tabs.TabItem
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@string/command" />
|
||||
|
||||
|
||||
</com.google.android.material.tabs.TabLayout>
|
||||
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/download_viewpager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/bottom_sheet_link"
|
||||
style="@style/Widget.Material3.Button.TextButton.Icon"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
android:textAlignment="textStart"
|
||||
android:singleLine="true"
|
||||
android:text="@string/app_name"
|
||||
android:textSize="15sp"
|
||||
app:icon="@drawable/ic_link" />
|
||||
|
||||
<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:layout_marginHorizontal="20dp"
|
||||
android:orientation="horizontal"
|
||||
android:paddingTop="20dp">
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/bottom_sheet_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:maxLines="2"
|
||||
android:singleLine="false"
|
||||
android:text="@string/download"
|
||||
android:textSize="25sp"
|
||||
app:layout_constraintEnd_toStartOf="@+id/bottomsheet_schedule_button"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/bottom_sheet_subtitle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="2"
|
||||
android:singleLine="false"
|
||||
android:text="@string/configure_download"
|
||||
android:textSize="12sp"
|
||||
app:layout_constraintEnd_toStartOf="@+id/bottomsheet_schedule_button"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/bottom_sheet_title" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/bottomsheet_schedule_button"
|
||||
style="?attr/materialIconButtonFilledTonalStyle"
|
||||
android:layout_width="wrap_content"
|
||||
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"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/bottomsheet_download_button"
|
||||
style="@style/Widget.Material3.Button.ElevatedButton.Icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:autoLink="all"
|
||||
android:text="@string/download"
|
||||
app:icon="@drawable/ic_down"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/download_tablayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
android:backgroundTint="@android:color/transparent"
|
||||
app:tabGravity="fill"
|
||||
app:tabMode="scrollable">
|
||||
|
||||
<com.google.android.material.tabs.TabItem
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@string/audio" />
|
||||
|
||||
<com.google.android.material.tabs.TabItem
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@string/video" />
|
||||
|
||||
<com.google.android.material.tabs.TabItem
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@string/command" />
|
||||
|
||||
|
||||
</com.google.android.material.tabs.TabLayout>
|
||||
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/download_viewpager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
android:gravity="end"
|
||||
android:visibility="gone"
|
||||
android:paddingBottom="10dp"
|
||||
android:paddingHorizontal="20dp"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<Button
|
||||
android:id="@+id/bottom_sheet_link"
|
||||
style="@style/Widget.Material3.Button.TextButton.Icon"
|
||||
android:layout_width="match_parent"
|
||||
android:id="@+id/update_item"
|
||||
style="@style/Widget.Material3.Button.ElevatedButton.Icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
android:textAlignment="textStart"
|
||||
android:singleLine="true"
|
||||
android:text="@string/app_name"
|
||||
android:textSize="15sp"
|
||||
app:icon="@drawable/ic_link" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:gravity="end"
|
||||
android:visibility="gone"
|
||||
android:paddingBottom="10dp"
|
||||
android:paddingHorizontal="20dp"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<Button
|
||||
android:id="@+id/update_item"
|
||||
style="@style/Widget.Material3.Button.ElevatedButton.Icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:autoLink="all"
|
||||
android:text="@string/update"
|
||||
app:icon="@drawable/ic_update"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</LinearLayout>
|
||||
android:autoLink="all"
|
||||
android:text="@string/update"
|
||||
app:icon="@drawable/ic_update"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
|
@ -6,6 +6,7 @@
|
|||
android:checkable="true"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
app:checkedIcon="@null"
|
||||
app:cardPreventCornerOverlap="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
|
|
|||
|
|
@ -156,6 +156,21 @@
|
|||
android:checked="false"
|
||||
android:text="@string/split_by_chapters"/>
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/cut"
|
||||
style="@style/Widget.Material3.Chip.Assist.Elevated"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
app:chipIconVisible="true"
|
||||
app:chipIcon="@drawable/ic_cut"
|
||||
android:text="@string/cut"
|
||||
android:minWidth="30dp"
|
||||
app:cornerRadius="10dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
|
||||
</com.google.android.material.chip.ChipGroup>
|
||||
|
||||
|
|
@ -180,7 +195,7 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="SponsorBlock"
|
||||
android:text="@string/sponsorblock"
|
||||
app:chipIconVisible="true"
|
||||
app:chipIcon="@drawable/ic_money"
|
||||
android:minWidth="30dp"
|
||||
|
|
@ -190,14 +205,14 @@
|
|||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/cut"
|
||||
android:id="@+id/filename_template"
|
||||
style="@style/Widget.Material3.Chip.Assist.Elevated"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="@string/file_name_template"
|
||||
app:chipIconVisible="true"
|
||||
app:chipIcon="@drawable/ic_cut"
|
||||
android:text="@string/cut"
|
||||
app:chipIcon="@drawable/ic_edit"
|
||||
android:minWidth="30dp"
|
||||
app:cornerRadius="10dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
|
|
@ -205,7 +220,6 @@
|
|||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
|
||||
|
||||
</com.google.android.material.chip.ChipGroup>
|
||||
|
||||
</HorizontalScrollView>
|
||||
|
|
|
|||
|
|
@ -33,7 +33,8 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="10dp">
|
||||
android:paddingHorizontal="10dp"
|
||||
android:baselineAligned="false">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/author_textinput"
|
||||
|
|
@ -57,8 +58,10 @@
|
|||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="45"
|
||||
android:labelFor="@id/container_textview"
|
||||
android:hint="@string/container"
|
||||
android:paddingStart="10dp">
|
||||
android:paddingStart="10dp"
|
||||
android:paddingEnd="0dp">
|
||||
|
||||
<AutoCompleteTextView
|
||||
android:id="@+id/container_textview"
|
||||
|
|
@ -175,14 +178,12 @@
|
|||
app:singleLine="true">
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/sponsorblock_filters"
|
||||
style="@style/Widget.Material3.Chip.Assist.Elevated"
|
||||
android:id="@+id/remove_audio"
|
||||
style="@style/Widget.Material3.Chip.Filter.Elevated"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="SponsorBlock"
|
||||
app:chipIconVisible="true"
|
||||
app:chipIcon="@drawable/ic_money"
|
||||
android:text="@string/remove_audio"
|
||||
android:minWidth="30dp"
|
||||
app:cornerRadius="10dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
|
|
@ -227,6 +228,36 @@
|
|||
android:layout_height="wrap_content"
|
||||
app:singleLine="true">
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/sponsorblock_filters"
|
||||
style="@style/Widget.Material3.Chip.Assist.Elevated"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="@string/sponsorblock"
|
||||
app:chipIconVisible="true"
|
||||
app:chipIcon="@drawable/ic_money"
|
||||
android:minWidth="30dp"
|
||||
app:cornerRadius="10dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/filename_template"
|
||||
style="@style/Widget.Material3.Chip.Assist.Elevated"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="@string/file_name_template"
|
||||
app:chipIconVisible="true"
|
||||
app:chipIcon="@drawable/ic_edit"
|
||||
android:minWidth="30dp"
|
||||
app:cornerRadius="10dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/save_subtitles"
|
||||
style="@style/Widget.Material3.Chip.Filter.Elevated"
|
||||
|
|
@ -249,19 +280,6 @@
|
|||
android:checked="false"
|
||||
android:text="@string/subtitle_languages"/>
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/remove_audio"
|
||||
style="@style/Widget.Material3.Chip.Filter.Elevated"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="@string/remove_audio"
|
||||
android:minWidth="30dp"
|
||||
app:cornerRadius="10dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</com.google.android.material.chip.ChipGroup>
|
||||
|
||||
</HorizontalScrollView>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
app:liftOnScroll="true"
|
||||
android:background="@android:color/transparent"
|
||||
android:elevation="0dp"
|
||||
app:liftOnScrollTargetViewId="@id/recyclerviewhistorys"
|
||||
app:elevation="0dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
android:layout_height="match_parent"
|
||||
app:cardCornerRadius="10dp"
|
||||
app:cardElevation="5dp"
|
||||
app:checkedIcon="@null"
|
||||
app:cardMaxElevation="12dp"
|
||||
android:checkable="true"
|
||||
app:strokeWidth="0dp"
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:cardCornerRadius="20dp"
|
||||
app:checkedIcon="@null"
|
||||
app:cardElevation="5dp"
|
||||
app:cardMaxElevation="12dp"
|
||||
app:cardPreventCornerOverlap="true"
|
||||
|
|
|
|||
|
|
@ -20,23 +20,26 @@
|
|||
style="@style/Widget.Material3.BottomAppBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:menu="@menu/select_playlist_menu"
|
||||
android:layout_gravity="bottom">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/selected"
|
||||
android:layout_width="wrap_content"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginHorizontal="30dp"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
|
||||
</com.google.android.material.bottomappbar.BottomAppBar>
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
android:id="@+id/check_all"
|
||||
android:layout_width="wrap_content"
|
||||
android:text="@string/select_all"
|
||||
app:icon="@drawable/ic_select_all"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_anchor="@id/bottomAppBar"
|
||||
app:srcCompat="@drawable/ic_select_all" />
|
||||
app:layout_anchor="@id/bottomAppBar"/>
|
||||
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
|
@ -83,6 +86,7 @@
|
|||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
style="@style/Widget.Material3.TextInputLayout.FilledBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="URL"
|
||||
android:padding="10dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
|
|
|||
10
app/src/main/res/menu/select_playlist_menu.xml
Normal file
10
app/src/main/res/menu/select_playlist_menu.xml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:theme="@style/BaseTheme">
|
||||
|
||||
<item android:title="@string/invert_selected"
|
||||
android:icon="@drawable/ic_terminal"
|
||||
app:showAsAction="never"
|
||||
android:id="@+id/invert_selected"/>
|
||||
</menu>
|
||||
|
|
@ -26,13 +26,21 @@
|
|||
android:label="More"
|
||||
tools:layout="@layout/fragment_more" >
|
||||
<action
|
||||
android:id="@+id/action_moreFragment_to_settingsFragment"
|
||||
app:destination="@id/settingsFragment" />
|
||||
android:id="@+id/action_moreFragment_to_terminalActivity"
|
||||
app:destination="@id/terminalActivity" />
|
||||
<action
|
||||
android:id="@+id/action_moreFragment_to_cookiesActivity"
|
||||
app:destination="@id/cookiesActivity" />
|
||||
<action
|
||||
android:id="@+id/action_moreFragment_to_downloadQueueActivity"
|
||||
app:destination="@id/downloadQueueActivity" />
|
||||
<action
|
||||
android:id="@+id/action_moreFragment_to_downloadLogListActivity"
|
||||
app:destination="@id/downloadLogListActivity" />
|
||||
<action
|
||||
android:id="@+id/action_moreFragment_to_commandTemplatesActivity"
|
||||
app:destination="@id/commandTemplatesActivity" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/settingsFragment"
|
||||
android:name="com.deniscerri.ytdlnis.ui.more.settings.SettingsFragment"
|
||||
android:label="SettingsFragment" />
|
||||
<activity
|
||||
android:id="@+id/downloadQueueActivity"
|
||||
android:name="com.deniscerri.ytdlnis.ui.downloads.DownloadQueueActivity"
|
||||
|
|
@ -50,11 +58,6 @@
|
|||
android:id="@+id/cookiesActivity"
|
||||
android:name="com.deniscerri.ytdlnis.ui.more.CookiesActivity"
|
||||
android:label="CookiesActivity" />
|
||||
<activity
|
||||
android:id="@+id/settingsActivity"
|
||||
android:name="com.deniscerri.ytdlnis.ui.more.settings.SettingsActivity"
|
||||
android:label="activity_settings"
|
||||
tools:layout="@layout/activity_settings" />
|
||||
<activity
|
||||
android:id="@+id/terminalActivity"
|
||||
android:name="com.deniscerri.ytdlnis.ui.more.TerminalActivity"
|
||||
|
|
|
|||
47
app/src/main/res/navigation/settings_nav.xml
Normal file
47
app/src/main/res/navigation/settings_nav.xml
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/settings_nav_graph"
|
||||
app:startDestination="@id/mainSettingsFragment">
|
||||
<fragment
|
||||
android:id="@+id/appearanceSettingsFragment"
|
||||
android:name="com.deniscerri.ytdlnis.ui.more.settings.AppearanceSettingsFragment"
|
||||
android:label="AppearanceSettingsFragment" />
|
||||
<fragment
|
||||
android:id="@+id/processingSettingsFragment"
|
||||
android:name="com.deniscerri.ytdlnis.ui.more.settings.ProcessingSettingsFragment"
|
||||
android:label="ProcessingSettingsFragment" />
|
||||
<fragment
|
||||
android:id="@+id/folderSettingsFragment"
|
||||
android:name="com.deniscerri.ytdlnis.ui.more.settings.FolderSettingsFragment"
|
||||
android:label="FolderSettingsFragment" />
|
||||
<fragment
|
||||
android:id="@+id/updateSettingsFragment"
|
||||
android:name="com.deniscerri.ytdlnis.ui.more.settings.UpdateSettingsFragment"
|
||||
android:label="UpdateSettingsFragment" />
|
||||
<fragment
|
||||
android:id="@+id/downloadSettingsFragment"
|
||||
android:name="com.deniscerri.ytdlnis.ui.more.settings.DownloadSettingsFragment"
|
||||
android:label="DownloadSettingsFragment" />
|
||||
<fragment
|
||||
android:id="@+id/mainSettingsFragment"
|
||||
android:name="com.deniscerri.ytdlnis.ui.more.settings.MainSettingsFragment"
|
||||
android:label="MainSettingsFragment" >
|
||||
<action
|
||||
android:id="@+id/action_mainSettingsFragment_to_appearanceSettingsFragment"
|
||||
app:destination="@id/appearanceSettingsFragment" />
|
||||
<action
|
||||
android:id="@+id/action_mainSettingsFragment_to_folderSettingsFragment"
|
||||
app:destination="@id/folderSettingsFragment" />
|
||||
<action
|
||||
android:id="@+id/action_mainSettingsFragment_to_downloadSettingsFragment"
|
||||
app:destination="@id/downloadSettingsFragment" />
|
||||
<action
|
||||
android:id="@+id/action_mainSettingsFragment_to_processingSettingsFragment"
|
||||
app:destination="@id/processingSettingsFragment" />
|
||||
<action
|
||||
android:id="@+id/action_mainSettingsFragment_to_updateSettingsFragment"
|
||||
app:destination="@id/updateSettingsFragment" />
|
||||
</fragment>
|
||||
</navigation>
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
</string-array>
|
||||
|
||||
<string-array name="audio_containers_values">
|
||||
<item />
|
||||
<item>Default</item>
|
||||
<item>mp3</item>
|
||||
<item>m4a</item>
|
||||
<item>aac</item>
|
||||
|
|
@ -29,7 +29,7 @@
|
|||
</string-array>
|
||||
|
||||
<string-array name="video_containers_values">
|
||||
<item />
|
||||
<item>Default</item>
|
||||
<item>mp4</item>
|
||||
<item>mkv</item>
|
||||
<item>webm</item>
|
||||
|
|
@ -46,6 +46,17 @@
|
|||
<item>@string/best_quality</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="video_formats_values">
|
||||
<item>worst</item>
|
||||
<item>360p</item>
|
||||
<item>480p</item>
|
||||
<item>720p</item>
|
||||
<item>1080p</item>
|
||||
<item>1440p</item>
|
||||
<item>2160p</item>
|
||||
<item>best</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="audio_formats">
|
||||
<item>@string/worst_quality</item>
|
||||
<item>@string/best_quality</item>
|
||||
|
|
@ -683,4 +694,28 @@
|
|||
<item>ZW</item>
|
||||
</array>
|
||||
|
||||
|
||||
|
||||
<array name="backup_category_entries">
|
||||
<item>@string/settings</item>
|
||||
<item>@string/downloads</item>
|
||||
<item>@string/in_queue</item>
|
||||
<item>@string/cancelled</item>
|
||||
<item>@string/cookies</item>
|
||||
<item>@string/command_templates</item>
|
||||
<item>@string/shortcuts</item>
|
||||
<item>@string/search_history</item>
|
||||
</array>
|
||||
|
||||
<array name="backup_category_values">
|
||||
<item>settings</item>
|
||||
<item>downloads</item>
|
||||
<item>queued</item>
|
||||
<item>cancelled</item>
|
||||
<item>cookies</item>
|
||||
<item>templates</item>
|
||||
<item>shortcuts</item>
|
||||
<item>searchHistory</item>
|
||||
</array>
|
||||
|
||||
</resources>
|
||||
|
|
@ -255,4 +255,13 @@
|
|||
<string name="keep_cache_summary">Don\'t delete temporary files after the download is finished</string>
|
||||
<string name="backup">Backup</string>
|
||||
<string name="restore">Restore</string>
|
||||
<string name="network_error">Network Error</string>
|
||||
<string name="incognito">Incognito</string>
|
||||
<string name="sponsorblock">SponsorBlock</string>
|
||||
<string name="couldnt_parse_file">Couldn\'t parse file</string>
|
||||
<string name="restore_complete">App Restore Complete. The following items have been restored:</string>
|
||||
<string name="select_backup_categories">Select backup categories</string>
|
||||
<string name="search_history">Search History</string>
|
||||
<string name="backup_created_successfully">Backup file saved in the downloads folder</string>
|
||||
<string name="appearance">Appearance</string>
|
||||
</resources>
|
||||
39
app/src/main/res/xml/appearance_preferences.xml
Normal file
39
app/src/main/res/xml/appearance_preferences.xml
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
|
||||
<ListPreference
|
||||
android:entries="@array/language_values"
|
||||
android:entryValues="@array/language_values"
|
||||
android:icon="@drawable/ic_language"
|
||||
app:key="app_language"
|
||||
app:summary="en"
|
||||
app:title="@string/language" />
|
||||
|
||||
<ListPreference
|
||||
android:entries="@array/themes"
|
||||
android:entryValues="@array/themes_values"
|
||||
android:icon="@drawable/baseline_format_paint_24"
|
||||
app:defaultValue="System"
|
||||
app:key="ytdlnis_theme"
|
||||
app:summary="@string/defaultValue"
|
||||
app:title="@string/Theme" />
|
||||
|
||||
<ListPreference
|
||||
android:entries="@array/accents"
|
||||
android:entryValues="@array/accents_values"
|
||||
android:icon="@drawable/baseline_color_lens_24"
|
||||
app:defaultValue="blue"
|
||||
app:key="theme_accent"
|
||||
app:summary="Blue"
|
||||
app:title="@string/accents" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="false"
|
||||
android:icon="@drawable/baseline_invert_colors_24"
|
||||
android:key="high_contrast"
|
||||
app:summary="@string/pure_theme_summary"
|
||||
app:title="@string/high_contrast" />
|
||||
</PreferenceScreen>
|
||||
140
app/src/main/res/xml/downloading_preferences.xml
Normal file
140
app/src/main/res/xml/downloading_preferences.xml
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="false"
|
||||
android:icon="@drawable/ic_incognito"
|
||||
android:key="incognito"
|
||||
app:summary="@string/incognito_summary"
|
||||
app:title="@string/incognito" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="true"
|
||||
android:icon="@drawable/ic_card"
|
||||
android:key="download_card"
|
||||
app:summary="@string/download_card_summary"
|
||||
app:title="@string/show_download_card" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="false"
|
||||
android:icon="@drawable/ic_speed"
|
||||
android:key="quick_download"
|
||||
app:summary="@string/quick_download_summary"
|
||||
app:title="@string/quick_download" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="true"
|
||||
android:icon="@drawable/metered_networks"
|
||||
android:key="metered_networks"
|
||||
app:summary="@string/download_over_metered_networks_summary"
|
||||
app:title="@string/download_over_metered_networks" />
|
||||
|
||||
<ListPreference
|
||||
android:dependency="download_card"
|
||||
android:defaultValue="video"
|
||||
android:entries="@array/download_types"
|
||||
android:entryValues="@array/download_types_values"
|
||||
android:icon="@drawable/ic_download_type"
|
||||
app:key="preferred_download_type"
|
||||
app:summary="@string/preferred_download_type_summary"
|
||||
app:title="@string/preferred_download_type" />
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="ytsearch"
|
||||
android:entries="@array/search_engines"
|
||||
android:entryValues="@array/search_engines_values"
|
||||
android:icon="@drawable/baseline_manage_search_24"
|
||||
app:key="search_engine"
|
||||
app:summary="@string/preferred_search_engine_summary"
|
||||
app:title="@string/preferred_search_engine" />
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="Home"
|
||||
android:entries="@array/start_destination"
|
||||
android:entryValues="@array/start_destination_values"
|
||||
app:icon="@drawable/baseline_add_to_home_screen_24"
|
||||
app:key="start_destination"
|
||||
app:title="@string/preferred_home_screen" />
|
||||
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="false"
|
||||
android:icon="@drawable/baseline_recommend_24"
|
||||
android:key="home_recommendations"
|
||||
app:summary="@string/video_recommendations_summary"
|
||||
app:title="@string/video_recommendations" />
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue=""
|
||||
android:entries="@array/countries"
|
||||
android:entryValues="@array/countries_values"
|
||||
app:icon="@drawable/ic_language"
|
||||
app:dependency="home_recommendations"
|
||||
app:key="locale"
|
||||
app:title="@string/preferred_locale" />
|
||||
|
||||
<EditTextPreference
|
||||
android:icon="@drawable/ic_key"
|
||||
app:key="api_key"
|
||||
app:defaultValue=""
|
||||
app:summary="@string/api_key_summary"
|
||||
app:title="@string/api_key" />
|
||||
|
||||
<SeekBarPreference
|
||||
app:dependency="aria2"
|
||||
android:defaultValue="3"
|
||||
android:icon="@drawable/ic_lines"
|
||||
android:max="25"
|
||||
app:key="concurrent_fragments"
|
||||
app:min="1"
|
||||
app:showSeekBarValue="true"
|
||||
android:dependency="aria2"
|
||||
app:summary="@string/concurrent_fragments_summary"
|
||||
app:title="@string/concurrent_fragments" />
|
||||
|
||||
<SeekBarPreference
|
||||
android:defaultValue="1"
|
||||
android:icon="@drawable/ic_concurrent_downloads"
|
||||
android:max="10"
|
||||
app:key="concurrent_downloads"
|
||||
app:min="1"
|
||||
app:showSeekBarValue="true"
|
||||
app:summary="@string/concurrent_downloads_summary"
|
||||
app:title="@string/concurrent_downloads" />
|
||||
|
||||
<EditTextPreference
|
||||
android:icon="@drawable/ic_down"
|
||||
app:key="limit_rate"
|
||||
app:summary="@string/limit_rate_summary"
|
||||
app:title="@string/limit_rate" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="false"
|
||||
android:icon="@drawable/ic_speed"
|
||||
android:key="aria2"
|
||||
app:summary="@string/aria2_summary"
|
||||
android:disableDependentsState="true"
|
||||
app:title="Aria2" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="false"
|
||||
android:icon="@drawable/ic_baseline_file_open_24"
|
||||
android:key="log_downloads"
|
||||
app:summary="@string/log_downloads_summary"
|
||||
app:title="@string/log_downloads" />
|
||||
|
||||
<Preference
|
||||
app:icon="@drawable/ic_battery"
|
||||
app:key="ignore_battery"
|
||||
app:title="@string/ignore_battery_optimization" />
|
||||
|
||||
</PreferenceScreen>
|
||||
43
app/src/main/res/xml/folders_preference.xml
Normal file
43
app/src/main/res/xml/folders_preference.xml
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<Preference
|
||||
app:icon="@drawable/ic_music_downloaded"
|
||||
app:key="music_path"
|
||||
app:defaultValue="@string/music_path"
|
||||
app:title="@string/music_directory" />
|
||||
|
||||
<Preference
|
||||
app:icon="@drawable/ic_video_downloaded"
|
||||
app:key="video_path"
|
||||
app:defaultValue="@string/video_path"
|
||||
app:title="@string/video_directory" />
|
||||
|
||||
<Preference
|
||||
app:icon="@drawable/ic_terminal"
|
||||
app:key="command_path"
|
||||
app:defaultValue="@string/command_path"
|
||||
app:title="@string/command_directory" />
|
||||
|
||||
<Preference
|
||||
app:icon="@drawable/ic_access_folder"
|
||||
app:key="access_all_files"
|
||||
android:summary="@string/access_all_directories_summary"
|
||||
app:title="@string/access_all_directories" />
|
||||
|
||||
<Preference
|
||||
app:icon="@drawable/ic_folder_delete"
|
||||
app:key="clear_cache"
|
||||
android:summary="@string/clear_temporary_files_summary"
|
||||
app:title="@string/clear_temporary_files" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="false"
|
||||
android:icon="@drawable/baseline_save_24"
|
||||
android:key="keep_cache"
|
||||
app:summary="@string/keep_cache_summary"
|
||||
app:title="@string/keep_cache" />
|
||||
|
||||
</PreferenceScreen>
|
||||
127
app/src/main/res/xml/processing_preferences.xml
Normal file
127
app/src/main/res/xml/processing_preferences.xml
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<MultiSelectListPreference
|
||||
app:defaultValue="@array/sponsorblock_settings_default"
|
||||
app:icon="@drawable/ic_money"
|
||||
app:dialogTitle="@string/select_sponsorblock_filtering"
|
||||
app:entries="@array/sponsorblock_settings_entries"
|
||||
app:entryValues="@array/sponsorblock_settings_values"
|
||||
app:key="sponsorblock_filters"
|
||||
app:summary="@string/select_sponsorblock_filtering"
|
||||
app:title="SponsorBlock" />
|
||||
|
||||
<EditTextPreference
|
||||
android:icon="@drawable/ic_textformat"
|
||||
app:key="file_name_template"
|
||||
app:useSimpleSummaryProvider="true"
|
||||
app:defaultValue="%(uploader)s - %(title)s"
|
||||
app:title="@string/file_name_template" />
|
||||
|
||||
<EditTextPreference
|
||||
android:icon="@drawable/ic_textformat"
|
||||
app:key="file_name_template_audio"
|
||||
app:useSimpleSummaryProvider="true"
|
||||
app:defaultValue="%(uploader)s - %(title)s"
|
||||
app:title="@string/file_name_template" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="false"
|
||||
app:icon="@drawable/if_file_rename"
|
||||
app:key="restrict_filenames"
|
||||
app:summary="@string/restrict_filenames_summary"
|
||||
app:title="@string/restrict_filenames" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="false"
|
||||
app:icon="@drawable/ic_clock"
|
||||
app:key="mtime"
|
||||
app:summary="@string/enable_mtime_summary"
|
||||
app:title="@string/enable_mtime" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="true"
|
||||
app:icon="@drawable/ic_subtitles"
|
||||
app:key="embed_subtitles"
|
||||
app:summary="@string/embed_subs_summary"
|
||||
app:title="@string/embed_subtitles" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="false"
|
||||
app:icon="@drawable/ic_subtitles_alternative"
|
||||
app:key="write_subtitles"
|
||||
app:summary="@string/save_subs_desc"
|
||||
app:title="@string/save_subs" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="true"
|
||||
app:icon="@drawable/ic_image"
|
||||
app:key="embed_thumbnail"
|
||||
app:summary="@string/embed_thumb_summary"
|
||||
app:title="@string/embed_thumb" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="true"
|
||||
app:icon="@drawable/ic_chapters"
|
||||
app:key="add_chapters"
|
||||
app:summary="@string/add_chapters_summary"
|
||||
app:title="@string/add_chapters" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="false"
|
||||
app:icon="@drawable/ic_image"
|
||||
app:key="write_thumbnail"
|
||||
app:summary="@string/save_thumb_summary"
|
||||
app:title="@string/save_thumb" />
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="Default"
|
||||
android:entries="@array/audio_containers"
|
||||
android:entryValues="@array/audio_containers_values"
|
||||
android:icon="@drawable/ic_code"
|
||||
app:key="audio_format"
|
||||
app:useSimpleSummaryProvider="true"
|
||||
app:title="@string/audio_format" />
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="Default"
|
||||
android:entries="@array/video_containers"
|
||||
android:entryValues="@array/video_containers_values"
|
||||
android:icon="@drawable/ic_code"
|
||||
app:key="video_format"
|
||||
app:useSimpleSummaryProvider="true"
|
||||
app:title="@string/video_format" />
|
||||
|
||||
|
||||
<SeekBarPreference
|
||||
android:defaultValue="0"
|
||||
android:icon="@drawable/ic_music"
|
||||
android:max="10"
|
||||
app:key="audio_quality"
|
||||
app:min="0"
|
||||
app:showSeekBarValue="true"
|
||||
app:summary="@string/audio_quality_summary"
|
||||
app:title="@string/audio_quality" />
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="best"
|
||||
android:entries="@array/video_formats"
|
||||
android:entryValues="@array/video_formats_values"
|
||||
android:icon="@drawable/ic_video"
|
||||
app:key="video_quality"
|
||||
app:useSimpleSummaryProvider="true"
|
||||
app:title="@string/video_quality" />
|
||||
|
||||
<EditTextPreference
|
||||
app:key="format_id"
|
||||
app:defaultValue=""
|
||||
app:useSimpleSummaryProvider="true"
|
||||
app:title="@string/preferred_format_id" />
|
||||
</PreferenceScreen>
|
||||
|
|
@ -1,398 +1,44 @@
|
|||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<ListPreference
|
||||
android:entries="@array/language_values"
|
||||
android:entryValues="@array/language_values"
|
||||
android:icon="@drawable/ic_language"
|
||||
app:key="app_language"
|
||||
app:summary="en"
|
||||
app:title="@string/language" />
|
||||
|
||||
<ListPreference
|
||||
android:entries="@array/themes"
|
||||
android:entryValues="@array/themes_values"
|
||||
android:icon="@drawable/baseline_format_paint_24"
|
||||
app:defaultValue="System"
|
||||
app:key="ytdlnis_theme"
|
||||
app:summary="@string/defaultValue"
|
||||
app:title="@string/Theme" />
|
||||
|
||||
<ListPreference
|
||||
android:entries="@array/accents"
|
||||
android:entryValues="@array/accents_values"
|
||||
android:icon="@drawable/baseline_color_lens_24"
|
||||
app:defaultValue="blue"
|
||||
app:key="theme_accent"
|
||||
app:summary="Blue"
|
||||
app:title="@string/accents" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="false"
|
||||
android:icon="@drawable/baseline_invert_colors_24"
|
||||
android:key="high_contrast"
|
||||
app:summary="@string/pure_theme_summary"
|
||||
app:title="@string/high_contrast" />
|
||||
|
||||
<Preference
|
||||
app:icon="@drawable/ic_battery"
|
||||
app:key="ignore_battery"
|
||||
app:title="@string/ignore_battery_optimization" />
|
||||
android:key="appearance"
|
||||
app:icon="@drawable/baseline_format_paint_24"
|
||||
android:title="@string/appearance"/>
|
||||
|
||||
<PreferenceCategory android:title="@string/directories">
|
||||
<Preference
|
||||
android:key="folders"
|
||||
app:icon="@drawable/baseline_folder_24"
|
||||
android:title="@string/directories"/>
|
||||
|
||||
<Preference
|
||||
android:key="downloading"
|
||||
app:icon="@drawable/baseline_download_24"
|
||||
android:title="@string/downloading"/>
|
||||
|
||||
<Preference
|
||||
app:icon="@drawable/ic_music_downloaded"
|
||||
app:key="music_path"
|
||||
app:defaultValue="@string/music_path"
|
||||
app:title="@string/music_directory" />
|
||||
<Preference
|
||||
android:key="processing"
|
||||
app:icon="@drawable/ic_code"
|
||||
android:title="@string/processing"/>
|
||||
|
||||
<Preference
|
||||
app:icon="@drawable/ic_video_downloaded"
|
||||
app:key="video_path"
|
||||
app:defaultValue="@string/video_path"
|
||||
app:title="@string/video_directory" />
|
||||
|
||||
<Preference
|
||||
app:icon="@drawable/ic_terminal"
|
||||
app:key="command_path"
|
||||
app:defaultValue="@string/command_path"
|
||||
app:title="@string/command_directory" />
|
||||
|
||||
<Preference
|
||||
app:icon="@drawable/ic_access_folder"
|
||||
app:key="access_all_files"
|
||||
android:summary="@string/access_all_directories_summary"
|
||||
app:title="@string/access_all_directories" />
|
||||
|
||||
<Preference
|
||||
app:icon="@drawable/ic_folder_delete"
|
||||
app:key="clear_cache"
|
||||
android:summary="@string/clear_temporary_files_summary"
|
||||
app:title="@string/clear_temporary_files" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="false"
|
||||
android:icon="@drawable/baseline_save_24"
|
||||
android:key="keep_cache"
|
||||
app:summary="@string/keep_cache_summary"
|
||||
app:title="@string/keep_cache" />
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory app:title="@string/downloading">
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="false"
|
||||
android:icon="@drawable/ic_incognito"
|
||||
android:key="incognito"
|
||||
app:summary="@string/incognito_summary"
|
||||
app:title="Incognito" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="true"
|
||||
android:icon="@drawable/ic_card"
|
||||
android:key="download_card"
|
||||
app:summary="@string/download_card_summary"
|
||||
app:title="@string/show_download_card" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="false"
|
||||
android:icon="@drawable/ic_speed"
|
||||
android:key="quick_download"
|
||||
app:summary="@string/quick_download_summary"
|
||||
app:title="@string/quick_download" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="true"
|
||||
android:icon="@drawable/metered_networks"
|
||||
android:key="metered_networks"
|
||||
app:summary="@string/download_over_metered_networks_summary"
|
||||
app:title="@string/download_over_metered_networks" />
|
||||
|
||||
<ListPreference
|
||||
android:dependency="download_card"
|
||||
android:defaultValue="video"
|
||||
android:entries="@array/download_types"
|
||||
android:entryValues="@array/download_types_values"
|
||||
android:icon="@drawable/ic_download_type"
|
||||
app:key="preferred_download_type"
|
||||
app:summary="@string/preferred_download_type_summary"
|
||||
app:title="@string/preferred_download_type" />
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="ytsearch"
|
||||
android:entries="@array/search_engines"
|
||||
android:entryValues="@array/search_engines_values"
|
||||
android:icon="@drawable/baseline_manage_search_24"
|
||||
app:key="search_engine"
|
||||
app:summary="@string/preferred_search_engine_summary"
|
||||
app:title="@string/preferred_search_engine" />
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="Home"
|
||||
android:entries="@array/start_destination"
|
||||
android:entryValues="@array/start_destination_values"
|
||||
app:icon="@drawable/baseline_add_to_home_screen_24"
|
||||
app:key="start_destination"
|
||||
app:title="@string/preferred_home_screen" />
|
||||
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="false"
|
||||
android:icon="@drawable/baseline_recommend_24"
|
||||
android:key="home_recommendations"
|
||||
app:summary="@string/video_recommendations_summary"
|
||||
app:title="@string/video_recommendations" />
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue=""
|
||||
android:entries="@array/countries"
|
||||
android:entryValues="@array/countries_values"
|
||||
app:icon="@drawable/ic_language"
|
||||
app:dependency="home_recommendations"
|
||||
app:key="locale"
|
||||
app:title="@string/preferred_locale" />
|
||||
|
||||
<EditTextPreference
|
||||
android:icon="@drawable/ic_key"
|
||||
app:key="api_key"
|
||||
app:defaultValue=""
|
||||
app:summary="@string/api_key_summary"
|
||||
app:title="@string/api_key" />
|
||||
|
||||
<SeekBarPreference
|
||||
app:dependency="aria2"
|
||||
android:defaultValue="3"
|
||||
android:icon="@drawable/ic_lines"
|
||||
android:max="25"
|
||||
app:key="concurrent_fragments"
|
||||
app:min="1"
|
||||
app:showSeekBarValue="true"
|
||||
android:dependency="aria2"
|
||||
app:summary="@string/concurrent_fragments_summary"
|
||||
app:title="@string/concurrent_fragments" />
|
||||
|
||||
<SeekBarPreference
|
||||
android:defaultValue="1"
|
||||
android:icon="@drawable/ic_concurrent_downloads"
|
||||
android:max="10"
|
||||
app:key="concurrent_downloads"
|
||||
app:min="1"
|
||||
app:showSeekBarValue="true"
|
||||
app:summary="@string/concurrent_downloads_summary"
|
||||
app:title="@string/concurrent_downloads" />
|
||||
|
||||
<EditTextPreference
|
||||
android:icon="@drawable/ic_down"
|
||||
app:key="limit_rate"
|
||||
app:summary="@string/limit_rate_summary"
|
||||
app:title="@string/limit_rate" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="false"
|
||||
android:icon="@drawable/ic_speed"
|
||||
android:key="aria2"
|
||||
app:summary="@string/aria2_summary"
|
||||
android:disableDependentsState="true"
|
||||
app:title="Aria2" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="false"
|
||||
android:icon="@drawable/ic_baseline_file_open_24"
|
||||
android:key="log_downloads"
|
||||
app:summary="@string/log_downloads_summary"
|
||||
app:title="@string/log_downloads" />
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
|
||||
<PreferenceCategory android:title="@string/processing">
|
||||
<MultiSelectListPreference
|
||||
app:defaultValue="@array/sponsorblock_settings_default"
|
||||
app:icon="@drawable/ic_money"
|
||||
app:dialogTitle="@string/select_sponsorblock_filtering"
|
||||
app:entries="@array/sponsorblock_settings_entries"
|
||||
app:entryValues="@array/sponsorblock_settings_values"
|
||||
app:key="sponsorblock_filters"
|
||||
app:summary="@string/select_sponsorblock_filtering"
|
||||
app:title="SponsorBlock" />
|
||||
|
||||
<EditTextPreference
|
||||
android:icon="@drawable/ic_textformat"
|
||||
app:key="file_name_template"
|
||||
app:defaultValue="%(uploader)s - %(title)s"
|
||||
app:title="@string/file_name_template" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="false"
|
||||
app:icon="@drawable/if_file_rename"
|
||||
app:key="restrict_filenames"
|
||||
app:summary="@string/restrict_filenames_summary"
|
||||
app:title="@string/restrict_filenames" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="false"
|
||||
app:icon="@drawable/ic_clock"
|
||||
app:key="mtime"
|
||||
app:summary="@string/enable_mtime_summary"
|
||||
app:title="@string/enable_mtime" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="true"
|
||||
app:icon="@drawable/ic_subtitles"
|
||||
app:key="embed_subtitles"
|
||||
app:summary="@string/embed_subs_summary"
|
||||
app:title="@string/embed_subtitles" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="false"
|
||||
app:icon="@drawable/ic_subtitles_alternative"
|
||||
app:key="write_subtitles"
|
||||
app:summary="@string/save_subs_desc"
|
||||
app:title="@string/save_subs" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="true"
|
||||
app:icon="@drawable/ic_image"
|
||||
app:key="embed_thumbnail"
|
||||
app:summary="@string/embed_thumb_summary"
|
||||
app:title="@string/embed_thumb" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="true"
|
||||
app:icon="@drawable/ic_chapters"
|
||||
app:key="add_chapters"
|
||||
app:summary="@string/add_chapters_summary"
|
||||
app:title="@string/add_chapters" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="false"
|
||||
app:icon="@drawable/ic_image"
|
||||
app:key="write_thumbnail"
|
||||
app:summary="@string/save_thumb_summary"
|
||||
app:title="@string/save_thumb" />
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="Default"
|
||||
android:entries="@array/audio_containers"
|
||||
android:entryValues="@array/audio_containers_values"
|
||||
android:icon="@drawable/ic_code"
|
||||
app:key="audio_format"
|
||||
app:summary="@string/defaultValue"
|
||||
app:title="@string/audio_format" />
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="Default"
|
||||
android:entries="@array/video_containers"
|
||||
android:entryValues="@array/video_containers_values"
|
||||
android:icon="@drawable/ic_code"
|
||||
app:key="video_format"
|
||||
app:summary="@string/defaultValue"
|
||||
app:title="@string/video_format" />
|
||||
|
||||
|
||||
<SeekBarPreference
|
||||
android:defaultValue="0"
|
||||
android:icon="@drawable/ic_music"
|
||||
android:max="10"
|
||||
app:key="audio_quality"
|
||||
app:min="0"
|
||||
app:showSeekBarValue="true"
|
||||
app:summary="@string/audio_quality_summary"
|
||||
app:title="@string/audio_quality" />
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="@string/best_quality"
|
||||
android:entries="@array/video_formats"
|
||||
android:entryValues="@array/video_formats"
|
||||
android:icon="@drawable/ic_video"
|
||||
app:key="video_quality"
|
||||
app:summary="@string/best_quality"
|
||||
app:title="@string/video_quality" />
|
||||
|
||||
<EditTextPreference
|
||||
app:key="format_id"
|
||||
app:defaultValue=""
|
||||
app:title="@string/preferred_format_id" />
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
|
||||
<PreferenceCategory android:title="@string/updating">
|
||||
<Preference
|
||||
app:icon="@drawable/ic_update"
|
||||
app:key="update_ytdl"
|
||||
app:summary="@string/ytdl_update_hint"
|
||||
app:title="@string/update_ytdl" />
|
||||
|
||||
<Preference
|
||||
app:icon="@drawable/ic_info"
|
||||
app:key="ytdl-version"
|
||||
app:title="@string/ytdl_version"/>
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
android:defaultValue="false"
|
||||
app:icon="@drawable/ic_nightly"
|
||||
app:key="nightly_ytdl"
|
||||
android:title="@string/update_ytdl_nightly"
|
||||
/>
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="false"
|
||||
android:icon="@drawable/ic_format"
|
||||
android:key="update_formats"
|
||||
app:summary="@string/update_formats_summary"
|
||||
app:title="@string/update_formats" />
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="yt-dlp"
|
||||
android:entries="@array/formats_source"
|
||||
android:entryValues="@array/formats_source_values"
|
||||
android:icon="@drawable/baseline_manage_search_24"
|
||||
app:key="formats_source"
|
||||
app:summary="yt-dlp"
|
||||
app:title="@string/format_source" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="true"
|
||||
android:icon="@drawable/ic_update_app"
|
||||
android:key="update_app"
|
||||
app:summary="@string/update_app_summary"
|
||||
app:title="@string/update_app" />
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:title="@string/about">
|
||||
<Preference
|
||||
android:key="updating"
|
||||
app:icon="@drawable/ic_update"
|
||||
android:title="@string/updating"/>
|
||||
|
||||
<PreferenceCategory android:title="@string/backup">
|
||||
<Preference
|
||||
app:icon="@drawable/baseline_save_alt_24"
|
||||
app:key="export_preferences"
|
||||
app:key="backup"
|
||||
app:title="@string/backup"/>
|
||||
|
||||
<Preference
|
||||
app:icon="@drawable/baseline_restore_page_24"
|
||||
app:key="import_preferences"
|
||||
app:key="restore"
|
||||
app:title="@string/restore"/>
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:title="@string/about" >
|
||||
<Preference
|
||||
app:icon="@drawable/ic_discord"
|
||||
app:key="discord"
|
||||
|
|
@ -434,11 +80,6 @@
|
|||
android:data="https://github.com/deniscerri/ytdlnis" />
|
||||
</Preference>
|
||||
|
||||
<Preference
|
||||
app:icon="@drawable/ic_info"
|
||||
app:key="version"
|
||||
app:title="@string/version"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
|
||||
|
|
|
|||
52
app/src/main/res/xml/updating_preferences.xml
Normal file
52
app/src/main/res/xml/updating_preferences.xml
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<Preference
|
||||
app:icon="@drawable/ic_update"
|
||||
app:key="update_ytdl"
|
||||
app:summary="@string/ytdl_update_hint"
|
||||
app:title="@string/update_ytdl" />
|
||||
|
||||
<Preference
|
||||
app:icon="@drawable/ic_info"
|
||||
app:key="ytdl-version"
|
||||
app:title="@string/ytdl_version"/>
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
android:defaultValue="false"
|
||||
app:icon="@drawable/ic_nightly"
|
||||
app:key="nightly_ytdl"
|
||||
android:title="@string/update_ytdl_nightly"
|
||||
/>
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="false"
|
||||
android:icon="@drawable/ic_format"
|
||||
android:key="update_formats"
|
||||
app:summary="@string/update_formats_summary"
|
||||
app:title="@string/update_formats" />
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="yt-dlp"
|
||||
android:entries="@array/formats_source"
|
||||
android:entryValues="@array/formats_source_values"
|
||||
android:icon="@drawable/baseline_manage_search_24"
|
||||
app:key="formats_source"
|
||||
app:useSimpleSummaryProvider="true"
|
||||
app:title="@string/format_source" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="true"
|
||||
android:icon="@drawable/ic_update_app"
|
||||
android:key="update_app"
|
||||
app:summary="@string/update_app_summary"
|
||||
app:title="@string/update_app" />
|
||||
<Preference
|
||||
app:icon="@drawable/ic_info"
|
||||
app:key="version"
|
||||
app:title="@string/version"/>
|
||||
</PreferenceScreen>
|
||||
Loading…
Reference in a new issue