even more stuff
Added malay language Fixed app not recognising log files if it was quick downloaded Fixed app not closing download item when using -o in CC Added code syntax highlighter in terminal Added filename template on playlist batch download added ability to multi-select audio on playlist download Removed default folder auto creation
This commit is contained in:
parent
7d5d6af5e8
commit
23c469f4bd
29 changed files with 250 additions and 137 deletions
|
|
@ -179,4 +179,5 @@ dependencies {
|
|||
implementation "com.google.android.exoplayer:exoplayer:2.18.5"
|
||||
implementation 'it.xabaras.android:recyclerview-swipedecorator:1.4'
|
||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.6.1"
|
||||
implementation "com.github.Irineu333:Highlight-KT:1.0.4"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import android.graphics.drawable.ColorDrawable
|
|||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.PersistableBundle
|
||||
import android.provider.Settings
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
|
|
@ -184,6 +185,7 @@ class MainActivity : BaseActivity() {
|
|||
handleIntents(intent)
|
||||
}
|
||||
|
||||
|
||||
fun hideBottomNavigation(){
|
||||
if(navigationView is NavigationBarView){
|
||||
if (navigationView is BottomNavigationView){
|
||||
|
|
@ -299,21 +301,6 @@ class MainActivity : BaseActivity() {
|
|||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
else{
|
||||
//coming from errored notification
|
||||
if (intent.hasExtra("logpath")){
|
||||
val bundle = Bundle()
|
||||
bundle.putString("logpath", intent.getStringExtra("logpath"))
|
||||
navController.navigate(
|
||||
R.id.downloadLogFragment,
|
||||
bundle
|
||||
)
|
||||
//coming from active download notification
|
||||
}else if (intent.hasExtra("activedownload")){
|
||||
navController.popBackStack(R.id.downloadQueueMainFragment, true)
|
||||
navController.navigate(R.id.downloadQueueMainFragment)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -352,17 +339,6 @@ class MainActivity : BaseActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private fun createDefaultFolders(){
|
||||
val audio = File(FileUtil.getDefautAudioPath())
|
||||
val video = File(FileUtil.getDefautVideoPath())
|
||||
val command = File(FileUtil.getDefaultCommandPath())
|
||||
|
||||
audio.mkdirs()
|
||||
video.mkdirs()
|
||||
command.mkdirs()
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(
|
||||
requestCode: Int,
|
||||
permissions: Array<String>,
|
||||
|
|
@ -373,8 +349,6 @@ class MainActivity : BaseActivity() {
|
|||
if (permissions.contains(Manifest.permission.POST_NOTIFICATIONS)) continue
|
||||
if (grantResults[i] == PackageManager.PERMISSION_DENIED) {
|
||||
createPermissionRequestDialog()
|
||||
}else{
|
||||
createDefaultFolders()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,8 +105,8 @@ class GenericDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
|
|||
DownloadRepository.Status.Queued.toString() -> actionButton.setIconResource(R.drawable.ic_baseline_delete_outline_24)
|
||||
else -> {
|
||||
actionButton.setIconResource(R.drawable.ic_baseline_file_open_24)
|
||||
val logFile = FileUtil.getLogFile(activity, item)
|
||||
if (!logFile.exists()){
|
||||
val logFile = FileUtil.checkLogFileExists(activity, item)
|
||||
if (logFile == null){
|
||||
actionButton.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -118,7 +118,8 @@ class HistoryAdapter(onItemClickListener: OnItemClickListener, activity: Activit
|
|||
btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_terminal)
|
||||
}
|
||||
if (btn.hasOnClickListeners()) btn.setOnClickListener(null)
|
||||
btn.isClickable = false
|
||||
btn.isClickable = filePresent
|
||||
|
||||
if (checkedItems.contains(item.id)) {
|
||||
card.isChecked = true
|
||||
card.strokeWidth = 5
|
||||
|
|
@ -138,6 +139,10 @@ class HistoryAdapter(onItemClickListener: OnItemClickListener, activity: Activit
|
|||
onItemClickListener.onCardClick(item.id, finalFilePresent)
|
||||
}
|
||||
}
|
||||
|
||||
btn.setOnClickListener {
|
||||
onItemClickListener.onButtonClick(item.id, finalFilePresent)
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkCard(card: MaterialCardView, itemID: Long) {
|
||||
|
|
@ -154,6 +159,7 @@ class HistoryAdapter(onItemClickListener: OnItemClickListener, activity: Activit
|
|||
|
||||
interface OnItemClickListener {
|
||||
fun onCardClick(itemID: Long, isPresent: Boolean)
|
||||
fun onButtonClick(itemID: Long, isPresent: Boolean)
|
||||
fun onCardSelect(itemID: Long, isChecked: Boolean)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import android.content.res.Configuration
|
|||
import android.content.res.Resources
|
||||
import android.net.ConnectivityManager
|
||||
import android.os.Environment
|
||||
import android.os.Looper
|
||||
import android.util.DisplayMetrics
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
|
|
@ -438,7 +439,9 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
d.status = DownloadRepository.Status.Queued.toString()
|
||||
d.toString() == it.toString()
|
||||
} != null) {
|
||||
Toast.makeText(context, context.getString(R.string.download_already_exists), Toast.LENGTH_LONG).show()
|
||||
Looper.prepare().run {
|
||||
Toast.makeText(context, context.getString(R.string.download_already_exists), Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}else{
|
||||
if (it.id == 0L){
|
||||
it.id = lastDownloadId
|
||||
|
|
@ -486,7 +489,9 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
|
||||
val isCurrentNetworkMetered = (context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager).isActiveNetworkMetered
|
||||
if (!allowMeteredNetworks && isCurrentNetworkMetered){
|
||||
Toast.makeText(context, context.getString(R.string.metered_network_download_start_info), Toast.LENGTH_LONG).show()
|
||||
Looper.prepare().run {
|
||||
Toast.makeText(context, context.getString(R.string.metered_network_download_start_info), Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -206,17 +206,6 @@ class ShareActivity : BaseActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private fun createDefaultFolders(){
|
||||
val audio = File(FileUtil.getDefautAudioPath())
|
||||
val video = File(FileUtil.getDefautVideoPath())
|
||||
val command = File(FileUtil.getDefaultCommandPath())
|
||||
|
||||
audio.mkdirs()
|
||||
video.mkdirs()
|
||||
command.mkdirs()
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(
|
||||
requestCode: Int,
|
||||
permissions: Array<String>,
|
||||
|
|
@ -227,8 +216,6 @@ class ShareActivity : BaseActivity() {
|
|||
if (permissions.contains(Manifest.permission.POST_NOTIFICATIONS)) break
|
||||
if (grantResults[i] == PackageManager.PERMISSION_DENIED) {
|
||||
createPermissionRequestDialog()
|
||||
}else{
|
||||
createDefaultFolders()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -186,7 +186,7 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val urls
|
|||
lifecycleScope.launch {
|
||||
try {
|
||||
val data : MutableList<String?> = withContext(Dispatchers.IO){
|
||||
if (urls.isNullOrEmpty() || chapters.isNullOrEmpty()) {
|
||||
if (urls.isNullOrEmpty()) {
|
||||
infoUtil.getStreamingUrlAndChapters(item.url)
|
||||
}else {
|
||||
urls.split("\n").toMutableList()
|
||||
|
|
|
|||
|
|
@ -142,9 +142,9 @@ class DownloadAudioFragment(private var resultItem: ResultItem, private var curr
|
|||
val chosenFormat = downloadItem.format
|
||||
UiUtil.populateFormatCard(formatCard, chosenFormat, null)
|
||||
val listener = object : OnFormatClickListener {
|
||||
override fun onFormatClick(allFormats: List<List<Format>>, item: List<Format>) {
|
||||
downloadItem.format = item.first()
|
||||
UiUtil.populateFormatCard(formatCard, item.first(), null)
|
||||
override fun onFormatClick(allFormats: List<List<Format>>, item: List<FormatTuple>) {
|
||||
downloadItem.format = item.first().format
|
||||
UiUtil.populateFormatCard(formatCard, item.first().format, null)
|
||||
lifecycleScope.launch {
|
||||
withContext(Dispatchers.IO){
|
||||
resultItem.formats.removeAll(formats.toSet())
|
||||
|
|
|
|||
|
|
@ -5,23 +5,32 @@ import android.app.Activity
|
|||
import android.app.Dialog
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Color
|
||||
import android.os.Bundle
|
||||
import android.provider.MediaStore.Video
|
||||
import android.text.format.DateFormat
|
||||
import android.util.DisplayMetrics
|
||||
import android.view.Gravity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.Window
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.Button
|
||||
import android.widget.EditText
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.get
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
|
|
@ -42,7 +51,9 @@ import com.google.android.material.bottomsheet.BottomSheetDialog
|
|||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.google.android.material.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
|
||||
|
|
@ -60,6 +71,7 @@ class DownloadMultipleBottomSheetDialog(private var results: List<ResultItem?>,
|
|||
private lateinit var recyclerView: RecyclerView
|
||||
private lateinit var behavior: BottomSheetBehavior<View>
|
||||
private lateinit var bottomAppBar: BottomAppBar
|
||||
private lateinit var sharedPreferences: SharedPreferences
|
||||
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
|
@ -67,6 +79,7 @@ class DownloadMultipleBottomSheetDialog(private var results: List<ResultItem?>,
|
|||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
|
||||
commandTemplateViewModel = ViewModelProvider(this)[CommandTemplateViewModel::class.java]
|
||||
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
}
|
||||
|
||||
@SuppressLint("RestrictedApi", "NotifyDataSetChanged")
|
||||
|
|
@ -143,15 +156,16 @@ class DownloadMultipleBottomSheetDialog(private var results: List<ResultItem?>,
|
|||
}
|
||||
|
||||
val formatListener = object : OnFormatClickListener {
|
||||
override fun onFormatClick(allFormats: List<List<Format>>, selectedFormats: List<Format>) {
|
||||
override fun onFormatClick(allFormats: List<List<Format>>, selectedFormats: List<FormatTuple>) {
|
||||
val formatCollection = mutableListOf<List<Format>>()
|
||||
allFormats.forEach {f ->
|
||||
formatCollection.add(f.mapTo(mutableListOf()) {it.copy()})
|
||||
}
|
||||
items.forEachIndexed { index, it ->
|
||||
it.allFormats.clear()
|
||||
if (formatCollection.isNotEmpty() && formatCollection[index].isNotEmpty()) it.allFormats.addAll(formatCollection[index])
|
||||
it.format = selectedFormats[index]
|
||||
items.forEachIndexed { index, i ->
|
||||
i.allFormats.clear()
|
||||
if (formatCollection.isNotEmpty() && formatCollection[index].isNotEmpty()) i.allFormats.addAll(formatCollection[index])
|
||||
i.format = selectedFormats[index].format
|
||||
if (i.type == DownloadViewModel.Type.video) selectedFormats[index].audioFormats?.map { it.format_id }?.let { i.videoPreferences.audioFormatIDs.addAll(it) }
|
||||
}
|
||||
listAdapter.submitList(items.toList())
|
||||
listAdapter.notifyDataSetChanged()
|
||||
|
|
@ -193,7 +207,7 @@ class DownloadMultipleBottomSheetDialog(private var results: List<ResultItem?>,
|
|||
listAdapter.submitList(items.toList())
|
||||
listAdapter.notifyDataSetChanged()
|
||||
preferredDownloadType.setIcon(R.drawable.baseline_audio_file_24)
|
||||
bottomAppBar.menu[2].icon?.alpha = 255
|
||||
bottomAppBar.menu[1].icon?.alpha = 255
|
||||
bottomSheet.cancel()
|
||||
}
|
||||
|
||||
|
|
@ -202,7 +216,7 @@ class DownloadMultipleBottomSheetDialog(private var results: List<ResultItem?>,
|
|||
listAdapter.submitList(items.toList())
|
||||
listAdapter.notifyDataSetChanged()
|
||||
preferredDownloadType.setIcon(R.drawable.baseline_video_file_24)
|
||||
bottomAppBar.menu[2].icon?.alpha = 255
|
||||
bottomAppBar.menu[1].icon?.alpha = 255
|
||||
bottomSheet.cancel()
|
||||
}
|
||||
|
||||
|
|
@ -214,7 +228,7 @@ class DownloadMultipleBottomSheetDialog(private var results: List<ResultItem?>,
|
|||
listAdapter.submitList(items.toList())
|
||||
listAdapter.notifyDataSetChanged()
|
||||
preferredDownloadType.setIcon(R.drawable.baseline_insert_drive_file_24)
|
||||
bottomAppBar.menu[2].icon?.alpha = 255
|
||||
bottomAppBar.menu[1].icon?.alpha = 255
|
||||
bottomSheet.cancel()
|
||||
}
|
||||
}
|
||||
|
|
@ -229,6 +243,52 @@ class DownloadMultipleBottomSheetDialog(private var results: List<ResultItem?>,
|
|||
)
|
||||
}
|
||||
|
||||
}
|
||||
R.id.filename_template -> {
|
||||
if (items.count { it.type == DownloadViewModel.Type.command } != 0){
|
||||
Toast.makeText(requireContext(), getString(R.string.format_filtering_hint_2), Toast.LENGTH_SHORT).show()
|
||||
}else{
|
||||
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.setSelection(editText.text.length)
|
||||
builder.setView(inputLayout)
|
||||
builder.setPositiveButton(
|
||||
getString(R.string.ok)
|
||||
) { dialog: DialogInterface?, which: Int ->
|
||||
|
||||
lifecycleScope.launch {
|
||||
items.forEach {
|
||||
it.customFileNameTemplate = editText.text.toString()
|
||||
}
|
||||
listAdapter.submitList(items.toList())
|
||||
listAdapter.notifyDataSetChanged()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// handle the negative button of the alert dialog
|
||||
builder.setNegativeButton(
|
||||
getString(R.string.cancel)
|
||||
) { dialog: DialogInterface?, which: Int -> }
|
||||
|
||||
val filenameTemplateDialog = builder.create()
|
||||
editText.doOnTextChanged { text, start, before, count ->
|
||||
filenameTemplateDialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = editText.text.isNotEmpty()
|
||||
}
|
||||
filenameTemplateDialog.show()
|
||||
val imm = context?.getSystemService(AppCompatActivity.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
editText!!.postDelayed({
|
||||
editText.requestFocus()
|
||||
imm.showSoftInput(editText, 0)
|
||||
}, 300)
|
||||
filenameTemplateDialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = editText.text.isNotEmpty()
|
||||
filenameTemplateDialog.getButton(AlertDialog.BUTTON_NEUTRAL).gravity = Gravity.START
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
R.id.format -> {
|
||||
if (! items.all { it.type == items[0].type }){
|
||||
|
|
@ -390,10 +450,17 @@ class DownloadMultipleBottomSheetDialog(private var results: List<ResultItem?>,
|
|||
val i = items.indexOf(items.find { it.url == item.url })
|
||||
items[i] = item
|
||||
if (! items.all { it.type == items[0].type }){
|
||||
bottomAppBar.menu[2].icon?.alpha = 30
|
||||
bottomAppBar.menu[1].icon?.alpha = 30
|
||||
}else{
|
||||
bottomAppBar.menu[2].icon?.alpha = 255
|
||||
bottomAppBar.menu[1].icon?.alpha = 255
|
||||
}
|
||||
|
||||
if (items.count { it.type == DownloadViewModel.Type.command } == 0){
|
||||
bottomAppBar.menu[2].icon?.alpha = 255
|
||||
}else{
|
||||
bottomAppBar.menu[2].icon?.alpha = 30
|
||||
}
|
||||
|
||||
listAdapter.submitList(items.toList())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -145,9 +145,10 @@ class DownloadVideoFragment(private val resultItem: ResultItem, private var curr
|
|||
val chosenFormat = downloadItem.format
|
||||
UiUtil.populateFormatCard(formatCard, chosenFormat, downloadItem.allFormats.filter { downloadItem.videoPreferences.audioFormatIDs.contains(it.format_id) })
|
||||
val listener = object : OnFormatClickListener {
|
||||
override fun onFormatClick(allFormats: List<List<Format>>, item: List<Format>) {
|
||||
downloadItem.format = item.first()
|
||||
downloadItem.videoPreferences.audioFormatIDs.addAll(item.drop(1).map { it.format_id })
|
||||
override fun onFormatClick(allFormats: List<List<Format>>, item: List<FormatTuple>) {
|
||||
downloadItem.format = item.first().format
|
||||
item.first().audioFormats?.map { it.format_id }
|
||||
?.let { downloadItem.videoPreferences.audioFormatIDs.addAll(it) }
|
||||
lifecycleScope.launch {
|
||||
withContext(Dispatchers.IO){
|
||||
resultItem.formats.removeAll(formats.toSet())
|
||||
|
|
@ -156,7 +157,7 @@ class DownloadVideoFragment(private val resultItem: ResultItem, private var curr
|
|||
}
|
||||
}
|
||||
formats = allFormats.first().toMutableList()
|
||||
UiUtil.populateFormatCard(formatCard, item.first(), item.drop(1))
|
||||
UiUtil.populateFormatCard(formatCard, item.first().format, item.first().audioFormats)
|
||||
}
|
||||
}
|
||||
formatCard.setOnClickListener{
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import androidx.preference.PreferenceManager
|
|||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.models.Format
|
||||
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel.Type
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.deniscerri.ytdlnis.util.InfoUtil
|
||||
|
|
@ -90,7 +91,7 @@ class FormatSelectionBottomSheetDialog(private val items: List<DownloadItem?>, p
|
|||
chosenFormats = commonFormats.mapTo(mutableListOf()) {it.copy()}
|
||||
chosenFormats = when(items.first()?.type){
|
||||
Type.audio -> chosenFormats.filter { it.format_note.contains("audio", ignoreCase = true) }
|
||||
else -> chosenFormats.filter { !it.format_note.contains("audio", ignoreCase = true) }
|
||||
else -> chosenFormats
|
||||
}
|
||||
chosenFormats.forEach {
|
||||
it.filesize =
|
||||
|
|
@ -155,7 +156,7 @@ class FormatSelectionBottomSheetDialog(private val items: List<DownloadItem?>, p
|
|||
chosenFormats = commonFormats.filter { it.filesize != 0L }.mapTo(mutableListOf()) {it.copy()}
|
||||
chosenFormats = when(items.first()?.type){
|
||||
Type.audio -> chosenFormats.filter { it.format_note.contains("audio", ignoreCase = true) }
|
||||
else -> chosenFormats.filter { !it.format_note.contains("audio", ignoreCase = true) }
|
||||
else -> chosenFormats
|
||||
}
|
||||
if (chosenFormats.isEmpty()) throw Exception()
|
||||
chosenFormats.forEach {
|
||||
|
|
@ -185,14 +186,28 @@ class FormatSelectionBottomSheetDialog(private val items: List<DownloadItem?>, p
|
|||
}
|
||||
|
||||
okBtn.setOnClickListener {
|
||||
val selectedFormats = mutableListOf<Format>()
|
||||
if (!::selectedVideo.isInitialized) {
|
||||
selectedVideo =
|
||||
chosenFormats.filter { it.vcodec.isNotBlank() && it.vcodec != "none" }.maxByOrNull { it.filesize }!!
|
||||
}
|
||||
selectedFormats.add(selectedVideo)
|
||||
selectedFormats.addAll(selectedAudios)
|
||||
listener.onFormatClick(List(items.size){chosenFormats}, selectedFormats)
|
||||
|
||||
//simple video format selection
|
||||
if (items.size == 1){
|
||||
listener.onFormatClick(List(items.size){chosenFormats}, listOf(FormatTuple(selectedVideo, selectedAudios)))
|
||||
}else{
|
||||
//playlist format selection
|
||||
val selectedFormats = mutableListOf<Format>()
|
||||
formatCollection.forEach {
|
||||
selectedFormats.add(it.first{ f -> f.format_id == selectedVideo.format_id})
|
||||
}
|
||||
if (selectedFormats.isEmpty()) {
|
||||
items.forEach { _ ->
|
||||
selectedFormats.add(selectedVideo)
|
||||
}
|
||||
}
|
||||
listener.onFormatClick(formatCollection, selectedFormats.map { FormatTuple(it, selectedAudios) })
|
||||
}
|
||||
|
||||
dismiss()
|
||||
}
|
||||
|
||||
|
|
@ -201,7 +216,7 @@ class FormatSelectionBottomSheetDialog(private val items: List<DownloadItem?>, p
|
|||
}
|
||||
}
|
||||
private fun addFormatsToView(){
|
||||
val canMultiSelectAudio = items.first()?.type == Type.video && items.count() == 1 && chosenFormats.find { it.format_note.contains("audio", ignoreCase = true) } != null
|
||||
val canMultiSelectAudio = items.first()?.type == Type.video && chosenFormats.find { it.format_note.contains("audio", ignoreCase = true) } != null
|
||||
videoFormatList.removeAllViews()
|
||||
audioFormatList.removeAllViews()
|
||||
|
||||
|
|
@ -230,12 +245,12 @@ class FormatSelectionBottomSheetDialog(private val items: List<DownloadItem?>, p
|
|||
formatItem.tag = "${format.format_id}${format.format_note}"
|
||||
UiUtil.populateFormatCard(formatItem as MaterialCardView, format, null)
|
||||
formatItem.setOnClickListener{ clickedformat ->
|
||||
//if the context is behind a single download card and its a video, allow the ability to multiselect audio formats
|
||||
//if the context is behind a video or playlist, allow the ability to multiselect audio formats
|
||||
if (canMultiSelectAudio){
|
||||
val clickedCard = (clickedformat as MaterialCardView)
|
||||
if (format.vcodec.isNotBlank() && format.vcodec != "none") {
|
||||
if (clickedCard.isChecked) {
|
||||
listener.onFormatClick(List(items.size){chosenFormats}, listOf(format))
|
||||
listener.onFormatClick(List(items.size){chosenFormats}, listOf(FormatTuple(format, null)))
|
||||
dismiss()
|
||||
}
|
||||
videoFormatList.forEach { (it as MaterialCardView).isChecked = false }
|
||||
|
|
@ -253,20 +268,8 @@ class FormatSelectionBottomSheetDialog(private val items: List<DownloadItem?>, p
|
|||
(it as MaterialCardView).isChecked = selectedAudios.map { a -> "${a.format_id}${a.format_note}" }.contains(it.tag)
|
||||
}
|
||||
}else{
|
||||
if (items.size == 1){
|
||||
listener.onFormatClick(List(items.size){chosenFormats}, listOf(format))
|
||||
}else{
|
||||
val selectedFormats = mutableListOf<Format>()
|
||||
formatCollection.forEach {
|
||||
selectedFormats.add(it.first{ f -> f.format_id == format.format_id})
|
||||
}
|
||||
if (selectedFormats.isEmpty()) {
|
||||
items.forEach {
|
||||
selectedFormats.add(format)
|
||||
}
|
||||
}
|
||||
listener.onFormatClick(formatCollection, selectedFormats)
|
||||
}
|
||||
//if its a simple audio format selection
|
||||
listener.onFormatClick(List(items.size){chosenFormats}, listOf(FormatTuple(format, null)))
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
|
@ -303,5 +306,10 @@ class FormatSelectionBottomSheetDialog(private val items: List<DownloadItem?>, p
|
|||
}
|
||||
|
||||
interface OnFormatClickListener{
|
||||
fun onFormatClick(allFormats: List<List<Format>>, item: List<Format>)
|
||||
}
|
||||
fun onFormatClick(allFormats: List<List<Format>>, item: List<FormatTuple>)
|
||||
}
|
||||
|
||||
class FormatTuple internal constructor(
|
||||
var format: Format,
|
||||
var audioFormats: List<Format>?
|
||||
)
|
||||
|
|
@ -351,7 +351,10 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
if (!websites.contains(item.website.lowercase())) websites.add(item.website.lowercase())
|
||||
}
|
||||
websiteGroup!!.removeAllViews()
|
||||
if (websites.size <= 1) return
|
||||
if (websites.size <= 1) {
|
||||
requireView().findViewById<View>(R.id.website_divider).visibility = GONE
|
||||
return
|
||||
}
|
||||
//val websites = historyRecyclerViewAdapter!!.websites
|
||||
for (i in websites.indices) {
|
||||
val w = websites[i]
|
||||
|
|
@ -374,6 +377,7 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
}
|
||||
websiteGroup!!.addView(tmp)
|
||||
}
|
||||
requireView().findViewById<View>(R.id.website_divider).visibility = VISIBLE
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -458,7 +462,8 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
codec.text = codecText
|
||||
}
|
||||
|
||||
val fileSizeReadable = FileUtil.convertFileSize(item.format.filesize)
|
||||
val file = File(item.downloadPath)
|
||||
val fileSizeReadable = FileUtil.convertFileSize(if (file.exists()) file.length() else item.format.filesize)
|
||||
if (fileSizeReadable == "?") fileSize!!.visibility = GONE
|
||||
else fileSize!!.text = fileSizeReadable
|
||||
|
||||
|
|
@ -686,6 +691,11 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
}
|
||||
}
|
||||
|
||||
override fun onButtonClick(itemID: Long, isPresent: Boolean) {
|
||||
if (isPresent){
|
||||
UiUtil.shareFileIntent(requireContext(), listOf(historyList!!.first { it!!.id == itemID }!!.downloadPath))
|
||||
}
|
||||
}
|
||||
companion object {
|
||||
private const val TAG = "historyFragment"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import android.content.ClipboardManager
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.graphics.Color
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.FileObserver
|
||||
|
|
@ -41,11 +42,16 @@ import com.google.android.material.bottomsheet.BottomSheetDialog
|
|||
import com.google.android.material.chip.Chip
|
||||
import com.google.android.material.chip.ChipGroup
|
||||
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
import com.neo.highlight.core.Highlight
|
||||
import com.neo.highlight.core.Scheme
|
||||
import com.neo.highlight.util.listener.HighlightTextWatcher
|
||||
import com.neo.highlight.util.scheme.ColorScheme
|
||||
import com.yausername.youtubedl_android.YoutubeDL
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.File
|
||||
import java.util.regex.Pattern
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
|
||||
|
|
@ -219,6 +225,28 @@ class TerminalActivity : BaseActivity() {
|
|||
}
|
||||
}
|
||||
initMenu()
|
||||
|
||||
//init syntax highlighter
|
||||
val highlight = Highlight()
|
||||
val highlightWatcher = HighlightTextWatcher()
|
||||
|
||||
val schemes = listOf(
|
||||
ColorScheme(Pattern.compile("([\"'])(?:\\\\1|.)*?\\1"), Color.parseColor("#FC8500")),
|
||||
ColorScheme(Pattern.compile("yt-dlp"), Color.parseColor("#00FF00")),
|
||||
ColorScheme(Pattern.compile("(https?://(?:www\\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\\.[^\\s]{2,}|www\\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\\.[^\\s]{2,}|https?://(?:www\\.|(?!www))[a-zA-Z0-9]+\\.[^\\s]{2,}|www\\.[a-zA-Z0-9]+\\.[^\\s]{2,})"), Color.parseColor("#b5942f")),
|
||||
ColorScheme(Pattern.compile("\\d+(\\.\\d)?%"), Color.parseColor("#43a564"))
|
||||
)
|
||||
|
||||
highlight.addScheme(
|
||||
*schemes.map { it }.toTypedArray()
|
||||
)
|
||||
highlightWatcher.addScheme(
|
||||
*schemes.map { it }.toTypedArray()
|
||||
)
|
||||
highlight.setSpan(output)
|
||||
highlight.setSpan(input)
|
||||
input?.addTextChangedListener(highlightWatcher)
|
||||
output?.addTextChangedListener(highlightWatcher)
|
||||
}
|
||||
|
||||
private fun initMenu() {
|
||||
|
|
|
|||
|
|
@ -92,21 +92,12 @@ object FileUtil {
|
|||
|
||||
//sending to main or SD CARD
|
||||
if (currentDirectory.exists()){
|
||||
val inputStream = context.contentResolver.openInputStream(it.toUri())!!
|
||||
val outputStream = FileOutputStream(destFile)
|
||||
|
||||
val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
|
||||
var bytesRead: Int
|
||||
val totalBytes = it.length()
|
||||
|
||||
// Transfer the file contents
|
||||
while (inputStream.read(buffer).also { bytesRead = it } != -1) {
|
||||
progress((bytesRead / totalBytes).toInt() * 100)
|
||||
outputStream.write(buffer, 0, bytesRead)
|
||||
if (Build.VERSION.SDK_INT >= 26 ){
|
||||
Files.move(it.toPath(), destFile.toPath(), StandardCopyOption.REPLACE_EXISTING)
|
||||
}else{
|
||||
it.renameTo(destFile)
|
||||
}
|
||||
|
||||
inputStream.close()
|
||||
outputStream.closeQuietly()
|
||||
fileList.add(destFile)
|
||||
}else{
|
||||
//sending to USB OTG
|
||||
val mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(it.extension) ?: "*/*"
|
||||
|
|
@ -177,6 +168,12 @@ object FileUtil {
|
|||
val title = item.title.ifEmpty { item.url }
|
||||
return File(context.filesDir.absolutePath + """/logs/${item.id} - ${titleRegex.replace(title, "").take(150)}##${item.type}##${item.format.format_id}.log""")
|
||||
}
|
||||
|
||||
fun checkLogFileExists(context: Context, item: DownloadItem) : File? {
|
||||
val dir = File(context.filesDir.absolutePath + "/logs/")
|
||||
return dir.listFiles()?.toList()?.first { it.name.startsWith(item.id.toString()) }
|
||||
}
|
||||
|
||||
fun getLogFileForTerminal(context: Context, command: String) : File {
|
||||
val titleRegex = Regex("[^A-Za-z\\d ]")
|
||||
return File(context.filesDir.absolutePath + """/logs/Terminal - ${titleRegex.replace(command.take(30), "")}##terminal.log""")
|
||||
|
|
|
|||
|
|
@ -816,7 +816,11 @@ class InfoUtil(private val context: Context) {
|
|||
|
||||
val chaptersInJSON = if (jsonObject.has("formats") && jsonObject.get("formats") is JSONArray) jsonObject.getJSONArray("formats") else null
|
||||
val listType: Type = object : TypeToken<List<ChapterItem>>() {}.type
|
||||
val chapters : ArrayList<ChapterItem> = Gson().fromJson(chaptersInJSON?.toString(), listType)
|
||||
var chapters : ArrayList<ChapterItem> = arrayListOf()
|
||||
|
||||
if (chaptersInJSON != null){
|
||||
chapters = Gson().fromJson(chaptersInJSON.toString(), listType)
|
||||
}
|
||||
|
||||
Log.e("aa", formats.toString())
|
||||
items.add(ResultItem(0,
|
||||
|
|
|
|||
|
|
@ -9,8 +9,10 @@ import android.content.Context
|
|||
import android.content.Intent
|
||||
import android.graphics.BitmapFactory
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.navigation.NavDeepLinkBuilder
|
||||
import com.deniscerri.ytdlnis.MainActivity
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.receiver.CancelDownloadNotificationReceiver
|
||||
|
|
@ -235,14 +237,15 @@ class NotificationUtil(var context: Context) {
|
|||
) {
|
||||
val notificationBuilder = getBuilder(channel)
|
||||
|
||||
val intent = Intent(context, MainActivity::class.java)
|
||||
intent.putExtra("logpath", logFile?.absolutePath)
|
||||
val bundle = Bundle()
|
||||
bundle.putString("logpath", logFile?.absolutePath)
|
||||
|
||||
val errorPendingIntent = NavDeepLinkBuilder(context)
|
||||
.setGraph(R.navigation.nav_graph)
|
||||
.setDestination(R.id.downloadLogFragment)
|
||||
.setArguments(bundle)
|
||||
.createPendingIntent()
|
||||
|
||||
val errorPendingIntent: PendingIntent = TaskStackBuilder.create(context).run {
|
||||
addNextIntentWithParentStack(intent)
|
||||
getPendingIntent(0,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
|
||||
}
|
||||
notificationBuilder
|
||||
.setContentTitle("${context.getString(R.string.failed_download)}: $title")
|
||||
.setContentText(error)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import android.os.Handler
|
|||
import android.os.Looper
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.navigation.NavDeepLinkBuilder
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.work.Data
|
||||
import androidx.work.ForegroundInfo
|
||||
|
|
@ -72,9 +73,11 @@ class DownloadWorker(
|
|||
updateDownloadItem(downloadItem, infoUtil, dao, resultDao, false, notificationUtil)
|
||||
}
|
||||
|
||||
val intent = Intent(context, MainActivity::class.java)
|
||||
intent.putExtra("activedownload", "")
|
||||
val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
|
||||
val pendingIntent = NavDeepLinkBuilder(context)
|
||||
.setGraph(R.navigation.nav_graph)
|
||||
.setDestination(R.id.downloadQueueMainFragment)
|
||||
.createPendingIntent()
|
||||
|
||||
val notification = notificationUtil.createDownloadServiceNotification(pendingIntent, downloadItem.title, downloadItem.id.toInt(), NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID)
|
||||
val foregroundInfo = ForegroundInfo(downloadItem.id.toInt(), notification)
|
||||
setForegroundAsync(foregroundInfo)
|
||||
|
|
@ -129,6 +132,7 @@ class DownloadWorker(
|
|||
if (downloadItem.author.isNotBlank()){
|
||||
request.addCommands(listOf("--replace-in-metadata","uploader",".*.",downloadItem.author.take(25)))
|
||||
}
|
||||
request.addCommands(listOf("--replace-in-metadata","uploader"," - Topic",""))
|
||||
if (downloadItem.customFileNameTemplate.isBlank()) downloadItem.customFileNameTemplate = "%(uploader)s - %(title)s"
|
||||
|
||||
if (downloadItem.downloadSections.isNotBlank()){
|
||||
|
|
@ -281,7 +285,6 @@ class DownloadWorker(
|
|||
writeText(downloadItem.format.format_note)
|
||||
}.absolutePath
|
||||
)
|
||||
|
||||
request.addOption("-P", tempFileDir.absolutePath)
|
||||
|
||||
}
|
||||
|
|
@ -322,7 +325,11 @@ class DownloadWorker(
|
|||
finalPaths = FileUtil.moveFile(tempFileDir.absoluteFile,context, downloadLocation, keepCache){ p ->
|
||||
setProgressAsync(workDataOf("progress" to p, "output" to "Moving file to ${FileUtil.formatPath(downloadLocation)}", "id" to downloadItem.id, "log" to logDownloads))
|
||||
}
|
||||
setProgressAsync(workDataOf("progress" to 100, "output" to "Moved file to $downloadLocation", "id" to downloadItem.id, "log" to logDownloads))
|
||||
if (finalPaths.isNotEmpty()){
|
||||
setProgressAsync(workDataOf("progress" to 100, "output" to "Moved file to $downloadLocation", "id" to downloadItem.id, "log" to logDownloads))
|
||||
}else{
|
||||
finalPaths = listOf(context.getString(R.string.unfound_file))
|
||||
}
|
||||
}catch (e: Exception){
|
||||
finalPaths = listOf(context.getString(R.string.unfound_file))
|
||||
e.printStackTrace()
|
||||
|
|
@ -338,8 +345,8 @@ class DownloadWorker(
|
|||
if (!incognito) {
|
||||
val unixtime = System.currentTimeMillis() / 1000
|
||||
val file = File(finalPaths?.first()!!)
|
||||
downloadItem.format.filesize = if (file.exists()) file.length() else 0L
|
||||
val historyItem = HistoryItem(0, downloadItem.url, downloadItem.title, downloadItem.author, downloadItem.duration, downloadItem.thumb, downloadItem.type, unixtime, finalPaths.first(), downloadItem.website, downloadItem.format, downloadItem.id)
|
||||
downloadItem.format.filesize = file.length()
|
||||
val historyItem = HistoryItem(0, downloadItem.url, downloadItem.title, downloadItem.author, downloadItem.duration, downloadItem.thumb, downloadItem.type, unixtime, finalPaths.first() , downloadItem.website, downloadItem.format, downloadItem.id)
|
||||
runBlocking {
|
||||
historyDao.insert(historyItem)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<vector android:height="24dp"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="?android:colorAccent" android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"/>
|
||||
<path android:fillColor="?android:textColorPrimary" android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"/>
|
||||
</vector>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<vector android:height="24dp"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="?android:colorAccent" android:pathData="M5,20h14v-2H5V20zM19,9h-4V3H9v6H5l7,7L19,9z"/>
|
||||
<path android:fillColor="?android:textColorPrimary" android:pathData="M5,20h14v-2H5V20zM19,9h-4V3H9v6H5l7,7L19,9z"/>
|
||||
</vector>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<vector android:height="24dp"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="?android:colorAccent" android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z"/>
|
||||
<path android:fillColor="?android:textColorPrimary" android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z"/>
|
||||
</vector>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||
<vector android:height="24dp"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M5,20h14v-2H5V20zM19,9h-4V3H9v6H5l7,7L19,9z"/>
|
||||
<path android:fillColor="?android:colorAccent" android:pathData="M5,20h14v-2H5V20zM19,9h-4V3H9v6H5l7,7L19,9z"/>
|
||||
</vector>
|
||||
|
|
|
|||
|
|
@ -9,15 +9,12 @@
|
|||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
android:padding="10dp"
|
||||
android:layout_marginVertical="10dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:text="@string/preferred_download_type"
|
||||
android:paddingBottom="20dp"
|
||||
android:layout_margin="20dp"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<TextView
|
||||
|
|
@ -25,6 +22,7 @@
|
|||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:paddingHorizontal="20dp"
|
||||
android:paddingVertical="10dp"
|
||||
android:drawablePadding="30dp"
|
||||
android:layout_width="match_parent"
|
||||
|
|
@ -39,6 +37,7 @@
|
|||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:paddingHorizontal="20dp"
|
||||
android:paddingVertical="10dp"
|
||||
android:drawablePadding="30dp"
|
||||
android:layout_width="match_parent"
|
||||
|
|
@ -53,6 +52,7 @@
|
|||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:paddingHorizontal="20dp"
|
||||
android:paddingVertical="10dp"
|
||||
android:drawablePadding="30dp"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@
|
|||
|
||||
</com.google.android.material.chip.ChipGroup>
|
||||
|
||||
<View style="@style/Divider.Vertical"/>
|
||||
<View android:id="@+id/website_divider" style="@style/Divider.Vertical"/>
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/website_chip_group"
|
||||
|
|
|
|||
|
|
@ -3,23 +3,31 @@
|
|||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:context=".MainActivity" >
|
||||
|
||||
<item
|
||||
android:id="@+id/folder"
|
||||
android:title="@string/directories"
|
||||
android:icon="@drawable/ic_folders"
|
||||
app:showAsAction="collapseActionView|ifRoom"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/preferred_download_type"
|
||||
android:title="@string/preferred_download_type"
|
||||
android:icon="@drawable/baseline_insert_drive_file_24"
|
||||
app:showAsAction="collapseActionView|ifRoom"/>
|
||||
app:showAsAction="ifRoom"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/format"
|
||||
android:title="@string/format"
|
||||
android:icon="@drawable/baseline_high_quality_24"
|
||||
app:showAsAction="ifRoom"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/filename_template"
|
||||
android:title="@string/file_name_template"
|
||||
android:icon="@drawable/if_file_rename"
|
||||
app:showAsAction="collapseActionView|ifRoom"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/folder"
|
||||
android:title="@string/directories"
|
||||
android:icon="@drawable/ic_folders"
|
||||
app:showAsAction="ifRoom"/>
|
||||
|
||||
|
||||
</menu>
|
||||
|
||||
|
|
|
|||
4
app/src/main/res/values-land/attrs.xml
Normal file
4
app/src/main/res/values-land/attrs.xml
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<resources>
|
||||
<integer name="grid_size">2</integer>
|
||||
<bool name="isTablet">false</bool>
|
||||
</resources>
|
||||
|
|
@ -102,6 +102,7 @@
|
|||
<item>ja</item>
|
||||
<item>ko</item>
|
||||
<item>lv</item>
|
||||
<item>ms</item>
|
||||
<item>nb</item>
|
||||
<item>pl</item>
|
||||
<item>pt</item>
|
||||
|
|
|
|||
|
|
@ -275,4 +275,5 @@
|
|||
<string name="audio_only_item">This item only contains audio formats</string>
|
||||
<string name="move_temporary_files">Move Temporary Files</string>
|
||||
<string name="move_temporary_files_summary">Transfer cached files to the downloads folder</string>
|
||||
<string name="format_filtering_hint_2">All items must either be audio or video to use this option</string>
|
||||
</resources>
|
||||
|
|
@ -13,6 +13,7 @@
|
|||
<locale android:name="ja"/>
|
||||
<locale android:name="ko"/>
|
||||
<locale android:name="lv"/>
|
||||
<locale android:name="ms"/>
|
||||
<locale android:name="nb-NO"/>
|
||||
<locale android:name="pl"/>
|
||||
<locale android:name="pt-BR" />
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
<Preference
|
||||
android:key="downloading"
|
||||
app:icon="@drawable/baseline_download_24"
|
||||
app:icon="@drawable/ic_downloads"
|
||||
android:title="@string/downloading"/>
|
||||
|
||||
<Preference
|
||||
|
|
|
|||
Loading…
Reference in a new issue