more stuff
tapping running download notification, will open download queue screen now fixed app closing running application when trying to share a file from the notification trending videos and search results will use piped now
This commit is contained in:
parent
4061f3878a
commit
3289a4fb96
33 changed files with 351 additions and 185 deletions
|
|
@ -128,18 +128,6 @@
|
|||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".receiver.SharedDownloadNotificationReceiver"
|
||||
android:exported="true"
|
||||
android:excludeFromRecents="true"
|
||||
android:launchMode="singleInstance"
|
||||
android:theme="@style/Theme.BottomSheet">
|
||||
<intent-filter>
|
||||
<action android:name="ytdlnis.SharedDownloadNotificationReceiver" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<service
|
||||
android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
|
||||
android:enabled="false"
|
||||
|
|
@ -149,6 +137,10 @@
|
|||
android:value="true" />
|
||||
</service>
|
||||
|
||||
<service
|
||||
android:name=".receiver.ShareFileService"
|
||||
android:exported="false" />
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="com.deniscerri.ytdl.fileprovider"
|
||||
|
|
|
|||
|
|
@ -299,6 +299,21 @@ 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
|
|||
import com.deniscerri.ytdlnis.ui.BaseActivity
|
||||
import com.deniscerri.ytdlnis.ui.downloadcard.DownloadBottomSheetDialog
|
||||
import com.deniscerri.ytdlnis.ui.downloadcard.SelectPlaylistItemsBottomSheetDialog
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.deniscerri.ytdlnis.util.ThemeUtil
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
|
|
@ -207,9 +208,9 @@ class ShareActivity : BaseActivity() {
|
|||
|
||||
|
||||
private fun createDefaultFolders(){
|
||||
val audio = File(getString(R.string.music_path))
|
||||
val video = File(getString(R.string.video_path))
|
||||
val command = File(getString(R.string.command_path))
|
||||
val audio = File(FileUtil.getDefautAudioPath())
|
||||
val video = File(FileUtil.getDefautVideoPath())
|
||||
val command = File(FileUtil.getDefaultCommandPath())
|
||||
|
||||
audio.mkdirs()
|
||||
video.mkdirs()
|
||||
|
|
@ -267,8 +268,4 @@ class ShareActivity : BaseActivity() {
|
|||
startActivity(Intent(this, MainActivity::class.java))
|
||||
super.onConfigurationChanged(newConfig)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "ShareActivity"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package com.deniscerri.ytdlnis.receiver
|
||||
|
||||
import android.app.Service
|
||||
import android.content.Intent
|
||||
import android.os.IBinder
|
||||
import com.deniscerri.ytdlnis.util.NotificationUtil
|
||||
import com.deniscerri.ytdlnis.util.UiUtil
|
||||
|
||||
class ShareFileService : Service() {
|
||||
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
|
||||
val paths = intent.getStringArrayExtra("path")
|
||||
val notificationId = intent.getIntExtra("notificationID", 0)
|
||||
NotificationUtil(this).cancelDownloadNotification(notificationId)
|
||||
UiUtil.shareFileIntent(this, paths!!.toList())
|
||||
return START_NOT_STICKY
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent): IBinder? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
stopForeground(true)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
package com.deniscerri.ytdlnis.receiver
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.deniscerri.ytdlnis.util.NotificationUtil
|
||||
import com.deniscerri.ytdlnis.util.UiUtil
|
||||
|
||||
class SharedDownloadNotificationReceiver : AppCompatActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.blank)
|
||||
val intent = intent
|
||||
val message = intent.getStringExtra("share")
|
||||
val path = intent.getStringExtra("path")
|
||||
val notificationId = intent.getIntExtra("notificationID", 0)
|
||||
if (message != null && path != null) {
|
||||
if (notificationId != 0) NotificationUtil(this).cancelDownloadNotification(notificationId)
|
||||
val uiUtil = UiUtil()
|
||||
uiUtil.shareFileIntent(this, listOf(path))
|
||||
this.finishAffinity()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -42,7 +42,6 @@ class ConfigureDownloadBottomSheetDialog(private val resultItem: ResultItem, pri
|
|||
private lateinit var commandTemplateDao: CommandTemplateDao
|
||||
private lateinit var behavior: BottomSheetBehavior<View>
|
||||
private lateinit var onDownloadItemUpdateListener: OnDownloadItemUpdateListener
|
||||
private lateinit var uiUtil: UiUtil
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
|
@ -50,7 +49,6 @@ class ConfigureDownloadBottomSheetDialog(private val resultItem: ResultItem, pri
|
|||
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
|
||||
commandTemplateDao = DBManager.getInstance(requireContext()).commandTemplateDao
|
||||
onDownloadItemUpdateListener = listener
|
||||
uiUtil = UiUtil()
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
|
|
@ -188,10 +186,10 @@ class ConfigureDownloadBottomSheetDialog(private val resultItem: ResultItem, pri
|
|||
val link = view.findViewById<Button>(R.id.bottom_sheet_link)
|
||||
link.text = resultItem.url
|
||||
link.setOnClickListener{
|
||||
uiUtil.openLinkIntent(requireContext(), resultItem.url, null)
|
||||
UiUtil.openLinkIntent(requireContext(), resultItem.url, null)
|
||||
}
|
||||
link.setOnLongClickListener{
|
||||
uiUtil.copyLinkToClipBoard(requireContext(), resultItem.url, null)
|
||||
UiUtil.copyLinkToClipBoard(requireContext(), resultItem.url, null)
|
||||
true
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,9 +18,7 @@ import androidx.lifecycle.lifecycleScope
|
|||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.models.ChapterItem
|
||||
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
|
||||
|
|
@ -63,7 +61,6 @@ import kotlin.properties.Delegates
|
|||
class CutVideoBottomSheetDialog(private val item: DownloadItem, private val urls : String?, private var chapters: List<ChapterItem>?, private val listener: VideoCutListener) : BottomSheetDialogFragment() {
|
||||
private lateinit var behavior: BottomSheetBehavior<View>
|
||||
private lateinit var infoUtil: InfoUtil
|
||||
private lateinit var uiUtil: UiUtil
|
||||
private lateinit var player: Player
|
||||
|
||||
private lateinit var cutSection : ConstraintLayout
|
||||
|
|
@ -90,7 +87,6 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val urls
|
|||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
uiUtil = UiUtil()
|
||||
infoUtil = InfoUtil(requireActivity().applicationContext)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,6 @@ class DownloadAudioFragment(private var resultItem: ResultItem, private var curr
|
|||
private var activity: Activity? = null
|
||||
private lateinit var downloadViewModel : DownloadViewModel
|
||||
private lateinit var resultViewModel : ResultViewModel
|
||||
private lateinit var uiUtil : UiUtil
|
||||
|
||||
private lateinit var title : TextInputLayout
|
||||
private lateinit var author : TextInputLayout
|
||||
|
|
@ -70,7 +69,6 @@ class DownloadAudioFragment(private var resultItem: ResultItem, private var curr
|
|||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
|
||||
|
||||
uiUtil = UiUtil()
|
||||
return fragmentView
|
||||
}
|
||||
|
||||
|
|
@ -142,11 +140,11 @@ class DownloadAudioFragment(private var resultItem: ResultItem, private var curr
|
|||
|
||||
val formatCard = view.findViewById<MaterialCardView>(R.id.format_card_constraintLayout)
|
||||
val chosenFormat = downloadItem.format
|
||||
uiUtil.populateFormatCard(formatCard, chosenFormat, null)
|
||||
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)
|
||||
UiUtil.populateFormatCard(formatCard, item.first(), null)
|
||||
lifecycleScope.launch {
|
||||
withContext(Dispatchers.IO){
|
||||
resultItem.formats.removeAll(formats.toSet())
|
||||
|
|
@ -164,7 +162,7 @@ class DownloadAudioFragment(private var resultItem: ResultItem, private var curr
|
|||
}
|
||||
}
|
||||
formatCard.setOnLongClickListener {
|
||||
uiUtil.showFormatDetails(downloadItem.format, requireActivity())
|
||||
UiUtil.showFormatDetails(downloadItem.format, requireActivity())
|
||||
true
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,6 @@ class DownloadBottomSheetDialog(private val resultItem: ResultItem, private val
|
|||
private lateinit var resultViewModel: ResultViewModel
|
||||
private lateinit var behavior: BottomSheetBehavior<View>
|
||||
private lateinit var commandTemplateDao : CommandTemplateDao
|
||||
private lateinit var uiUtil: UiUtil
|
||||
private lateinit var infoUtil: InfoUtil
|
||||
|
||||
private lateinit var downloadAudioFragment: DownloadAudioFragment
|
||||
|
|
@ -59,7 +58,6 @@ class DownloadBottomSheetDialog(private val resultItem: ResultItem, private val
|
|||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
|
||||
commandTemplateDao = DBManager.getInstance(requireContext()).commandTemplateDao
|
||||
uiUtil = UiUtil()
|
||||
infoUtil = InfoUtil(requireContext())
|
||||
}
|
||||
|
||||
|
|
@ -180,7 +178,7 @@ class DownloadBottomSheetDialog(private val resultItem: ResultItem, private val
|
|||
|
||||
|
||||
scheduleBtn.setOnClickListener{
|
||||
uiUtil.showDatePicker(fragmentManager) {
|
||||
UiUtil.showDatePicker(fragmentManager) {
|
||||
scheduleBtn.isEnabled = false
|
||||
download.isEnabled = false
|
||||
val item: DownloadItem = getDownloadItem();
|
||||
|
|
@ -206,10 +204,10 @@ class DownloadBottomSheetDialog(private val resultItem: ResultItem, private val
|
|||
val link = view.findViewById<Button>(R.id.bottom_sheet_link)
|
||||
link.text = resultItem.url
|
||||
link.setOnClickListener{
|
||||
uiUtil.openLinkIntent(requireContext(), resultItem.url, null)
|
||||
UiUtil.openLinkIntent(requireContext(), resultItem.url, null)
|
||||
}
|
||||
link.setOnLongClickListener{
|
||||
uiUtil.copyLinkToClipBoard(requireContext(), resultItem.url, null)
|
||||
UiUtil.copyLinkToClipBoard(requireContext(), resultItem.url, null)
|
||||
true
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@ class DownloadCommandFragment(private val resultItem: ResultItem, private var cu
|
|||
private var activity: Activity? = null
|
||||
private lateinit var downloadViewModel : DownloadViewModel
|
||||
private lateinit var commandTemplateViewModel : CommandTemplateViewModel
|
||||
private lateinit var uiUtil : UiUtil
|
||||
private lateinit var saveDir : TextInputLayout
|
||||
private lateinit var freeSpace : TextView
|
||||
|
||||
|
|
@ -58,7 +57,6 @@ class DownloadCommandFragment(private val resultItem: ResultItem, private var cu
|
|||
activity = getActivity()
|
||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
commandTemplateViewModel = ViewModelProvider(this)[CommandTemplateViewModel::class.java]
|
||||
uiUtil = UiUtil()
|
||||
return fragmentView
|
||||
}
|
||||
|
||||
|
|
@ -155,7 +153,7 @@ class DownloadCommandFragment(private val resultItem: ResultItem, private var cu
|
|||
|
||||
val newTemplate : Chip = view.findViewById(R.id.newTemplate)
|
||||
newTemplate.setOnClickListener {
|
||||
uiUtil.showCommandTemplateCreationOrUpdatingSheet(null, requireActivity(), viewLifecycleOwner, commandTemplateViewModel) {
|
||||
UiUtil.showCommandTemplateCreationOrUpdatingSheet(null, requireActivity(), viewLifecycleOwner, commandTemplateViewModel) {
|
||||
templates.add(it)
|
||||
chosenCommandView.editText!!.setText(it.content)
|
||||
downloadItem.format = Format(
|
||||
|
|
@ -175,7 +173,7 @@ class DownloadCommandFragment(private val resultItem: ResultItem, private var cu
|
|||
editSelected.setOnClickListener {
|
||||
var current = templates.find { it.title == autoCompleteTextView.text.toString() }
|
||||
if (current == null) current = CommandTemplate(0, "", chosenCommandView.editText!!.text.toString())
|
||||
uiUtil.showCommandTemplateCreationOrUpdatingSheet(current, requireActivity(), viewLifecycleOwner, commandTemplateViewModel) {
|
||||
UiUtil.showCommandTemplateCreationOrUpdatingSheet(current, requireActivity(), viewLifecycleOwner, commandTemplateViewModel) {
|
||||
templates.add(it)
|
||||
chosenCommandView.editText!!.setText(it.content)
|
||||
downloadItem.format = Format(
|
||||
|
|
|
|||
|
|
@ -59,7 +59,6 @@ class DownloadMultipleBottomSheetDialog(private var results: List<ResultItem?>,
|
|||
private lateinit var listAdapter : ConfigureMultipleDownloadsAdapter
|
||||
private lateinit var recyclerView: RecyclerView
|
||||
private lateinit var behavior: BottomSheetBehavior<View>
|
||||
private lateinit var uiUtil: UiUtil
|
||||
private lateinit var bottomAppBar: BottomAppBar
|
||||
|
||||
|
||||
|
|
@ -68,7 +67,6 @@ 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]
|
||||
uiUtil = UiUtil()
|
||||
}
|
||||
|
||||
@SuppressLint("RestrictedApi", "NotifyDataSetChanged")
|
||||
|
|
@ -104,7 +102,7 @@ class DownloadMultipleBottomSheetDialog(private var results: List<ResultItem?>,
|
|||
|
||||
|
||||
scheduleBtn.setOnClickListener{
|
||||
uiUtil.showDatePicker(parentFragmentManager) {
|
||||
UiUtil.showDatePicker(parentFragmentManager) {
|
||||
scheduleBtn.isEnabled = false
|
||||
download.isEnabled = false
|
||||
items.forEach { item ->
|
||||
|
|
@ -238,7 +236,7 @@ class DownloadMultipleBottomSheetDialog(private var results: List<ResultItem?>,
|
|||
}else{
|
||||
if (items.first().type == DownloadViewModel.Type.command){
|
||||
lifecycleScope.launch {
|
||||
uiUtil.showCommandTemplates(requireActivity(), commandTemplateViewModel) {
|
||||
UiUtil.showCommandTemplates(requireActivity(), commandTemplateViewModel) {
|
||||
val format = downloadViewModel.generateCommandFormat(it)
|
||||
items.forEach { f ->
|
||||
f.format = format
|
||||
|
|
|
|||
|
|
@ -51,7 +51,6 @@ class DownloadVideoFragment(private val resultItem: ResultItem, private var curr
|
|||
private var activity: Activity? = null
|
||||
private lateinit var downloadViewModel : DownloadViewModel
|
||||
private lateinit var resultViewModel: ResultViewModel
|
||||
private lateinit var uiUtil : UiUtil
|
||||
|
||||
private lateinit var title : TextInputLayout
|
||||
private lateinit var author : TextInputLayout
|
||||
|
|
@ -70,8 +69,6 @@ class DownloadVideoFragment(private val resultItem: ResultItem, private var curr
|
|||
activity = getActivity()
|
||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
resultViewModel = ViewModelProvider(this@DownloadVideoFragment)[ResultViewModel::class.java]
|
||||
|
||||
uiUtil = UiUtil()
|
||||
return fragmentView
|
||||
}
|
||||
|
||||
|
|
@ -146,7 +143,7 @@ class DownloadVideoFragment(private val resultItem: ResultItem, private var curr
|
|||
val formatCard = view.findViewById<MaterialCardView>(R.id.format_card_constraintLayout)
|
||||
|
||||
val chosenFormat = downloadItem.format
|
||||
uiUtil.populateFormatCard(formatCard, chosenFormat, downloadItem.allFormats.filter { downloadItem.videoPreferences.audioFormatIDs.contains(it.format_id) })
|
||||
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()
|
||||
|
|
@ -159,7 +156,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(), item.drop(1))
|
||||
}
|
||||
}
|
||||
formatCard.setOnClickListener{
|
||||
|
|
@ -170,7 +167,7 @@ class DownloadVideoFragment(private val resultItem: ResultItem, private var curr
|
|||
}
|
||||
|
||||
formatCard.setOnLongClickListener {
|
||||
uiUtil.showFormatDetails(downloadItem.format, requireActivity())
|
||||
UiUtil.showFormatDetails(downloadItem.format, requireActivity())
|
||||
true
|
||||
}
|
||||
|
||||
|
|
@ -367,7 +364,7 @@ class DownloadVideoFragment(private val resultItem: ResultItem, private var curr
|
|||
}
|
||||
|
||||
subtitleLanguages.setOnClickListener {
|
||||
uiUtil.showSubtitleLanguagesDialog(requireActivity(), downloadItem.videoPreferences.subsLanguages){
|
||||
UiUtil.showSubtitleLanguagesDialog(requireActivity(), downloadItem.videoPreferences.subsLanguages){
|
||||
downloadItem.videoPreferences.subsLanguages = it
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ import java.util.*
|
|||
class FormatSelectionBottomSheetDialog(private val items: List<DownloadItem?>, private var formats: List<List<Format>>, private val listener: OnFormatClickListener) : BottomSheetDialogFragment() {
|
||||
private lateinit var behavior: BottomSheetBehavior<View>
|
||||
private lateinit var infoUtil: InfoUtil
|
||||
private lateinit var uiUtil: UiUtil
|
||||
private lateinit var sharedPreferences: SharedPreferences
|
||||
private lateinit var formatCollection: MutableList<List<Format>>
|
||||
private lateinit var chosenFormats: List<Format>
|
||||
|
|
@ -47,7 +46,6 @@ class FormatSelectionBottomSheetDialog(private val items: List<DownloadItem?>, p
|
|||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
uiUtil = UiUtil()
|
||||
infoUtil = InfoUtil(requireActivity().applicationContext)
|
||||
formatCollection = mutableListOf()
|
||||
chosenFormats = listOf()
|
||||
|
|
@ -230,7 +228,7 @@ class FormatSelectionBottomSheetDialog(private val items: List<DownloadItem?>, p
|
|||
val format = chosenFormats[i]
|
||||
val formatItem = LayoutInflater.from(context).inflate(R.layout.format_item, null)
|
||||
formatItem.tag = "${format.format_id}${format.format_note}"
|
||||
uiUtil.populateFormatCard(formatItem as MaterialCardView, format, null)
|
||||
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 (canMultiSelectAudio){
|
||||
|
|
@ -273,7 +271,7 @@ class FormatSelectionBottomSheetDialog(private val items: List<DownloadItem?>, p
|
|||
}
|
||||
}
|
||||
formatItem.setOnLongClickListener {
|
||||
uiUtil.showFormatDetails(format, requireActivity())
|
||||
UiUtil.showFormatDetails(format, requireActivity())
|
||||
true
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -52,7 +52,6 @@ class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClic
|
|||
private var selectedObjects: ArrayList<DownloadItem>? = null
|
||||
private var actionMode : ActionMode? = null
|
||||
private lateinit var items : MutableList<DownloadItem>
|
||||
private lateinit var uiUtil : UiUtil
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
|
|
@ -65,7 +64,6 @@ class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClic
|
|||
selectedObjects = arrayListOf()
|
||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
items = mutableListOf()
|
||||
uiUtil = UiUtil()
|
||||
return fragmentView
|
||||
}
|
||||
|
||||
|
|
@ -170,10 +168,10 @@ class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClic
|
|||
link!!.text = url
|
||||
link.tag = itemID
|
||||
link.setOnClickListener{
|
||||
uiUtil.openLinkIntent(requireContext(), item.url, bottomSheet)
|
||||
UiUtil.openLinkIntent(requireContext(), item.url, bottomSheet)
|
||||
}
|
||||
link.setOnLongClickListener{
|
||||
uiUtil.copyLinkToClipBoard(requireContext(), item.url, bottomSheet)
|
||||
UiUtil.copyLinkToClipBoard(requireContext(), item.url, bottomSheet)
|
||||
true
|
||||
}
|
||||
val remove = bottomSheet.findViewById<Button>(R.id.bottomsheet_remove_button)
|
||||
|
|
|
|||
|
|
@ -55,7 +55,6 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL
|
|||
private lateinit var items : MutableList<DownloadItem>
|
||||
private var selectedObjects: ArrayList<DownloadItem>? = null
|
||||
private var actionMode : ActionMode? = null
|
||||
private lateinit var uiUtil : UiUtil
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
|
|
@ -67,7 +66,6 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL
|
|||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
items = mutableListOf()
|
||||
selectedObjects = arrayListOf()
|
||||
uiUtil = UiUtil()
|
||||
return fragmentView
|
||||
}
|
||||
|
||||
|
|
@ -173,10 +171,10 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL
|
|||
link!!.text = url
|
||||
link.tag = itemID
|
||||
link.setOnClickListener{
|
||||
uiUtil.openLinkIntent(requireContext(), item.url, bottomSheet)
|
||||
UiUtil.openLinkIntent(requireContext(), item.url, bottomSheet)
|
||||
}
|
||||
link.setOnLongClickListener{
|
||||
uiUtil.copyLinkToClipBoard(requireContext(), item.url, bottomSheet)
|
||||
UiUtil.copyLinkToClipBoard(requireContext(), item.url, bottomSheet)
|
||||
true
|
||||
}
|
||||
val remove = bottomSheet.findViewById<Button>(R.id.bottomsheet_remove_button)
|
||||
|
|
|
|||
|
|
@ -87,7 +87,6 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
private var historyList: List<HistoryItem?>? = null
|
||||
private var allhistoryList: List<HistoryItem?>? = null
|
||||
private var selectedObjects: ArrayList<HistoryItem>? = null
|
||||
private var uiUtil: UiUtil? = null
|
||||
private var _binding : FragmentHistoryBinding? = null
|
||||
private var actionMode : ActionMode? = null
|
||||
|
||||
|
|
@ -112,7 +111,6 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
noResults = view.findViewById(R.id.no_results)
|
||||
selectionChips = view.findViewById(R.id.history_selection_chips)
|
||||
websiteGroup = view.findViewById(R.id.website_chip_group)
|
||||
uiUtil = UiUtil()
|
||||
uiHandler = Handler(Looper.getMainLooper())
|
||||
selectedObjects = ArrayList()
|
||||
|
||||
|
|
@ -424,7 +422,7 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
|
||||
if (isPresent){
|
||||
btn.setOnClickListener {
|
||||
uiUtil!!.shareFileIntent(requireContext(), listOf(item.downloadPath))
|
||||
UiUtil!!.shareFileIntent(requireContext(), listOf(item.downloadPath))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -469,10 +467,10 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
link!!.text = url
|
||||
link.tag = itemID
|
||||
link.setOnClickListener{
|
||||
uiUtil!!.openLinkIntent(requireContext(), item.url, bottomSheet)
|
||||
UiUtil.openLinkIntent(requireContext(), item.url, bottomSheet)
|
||||
}
|
||||
link.setOnLongClickListener{
|
||||
uiUtil!!.copyLinkToClipBoard(requireContext(), item.url, bottomSheet)
|
||||
UiUtil.copyLinkToClipBoard(requireContext(), item.url, bottomSheet)
|
||||
true
|
||||
}
|
||||
val remove = bottomSheet!!.findViewById<Button>(R.id.bottomsheet_remove_button)
|
||||
|
|
@ -483,7 +481,7 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
val openFile = bottomSheet!!.findViewById<Button>(R.id.bottomsheet_open_file_button)
|
||||
openFile!!.tag = itemID
|
||||
openFile.setOnClickListener{
|
||||
uiUtil!!.openFileIntent(requireContext(), item.downloadPath)
|
||||
UiUtil.openFileIntent(requireContext(), item.downloadPath)
|
||||
}
|
||||
|
||||
val redownload = bottomSheet!!.findViewById<Button>(R.id.bottomsheet_redownload_button)
|
||||
|
|
@ -582,7 +580,7 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
true
|
||||
}
|
||||
R.id.share -> {
|
||||
uiUtil?.shareFileIntent(requireContext(), selectedObjects!!.map { it.downloadPath })
|
||||
UiUtil.shareFileIntent(requireContext(), selectedObjects!!.map { it.downloadPath })
|
||||
clearCheckedItems()
|
||||
actionMode?.finish()
|
||||
true
|
||||
|
|
|
|||
|
|
@ -63,7 +63,6 @@ class QueuedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLi
|
|||
private var selectedObjects: ArrayList<DownloadItem>? = null
|
||||
private var actionMode : ActionMode? = null
|
||||
private lateinit var items : MutableList<DownloadItem>
|
||||
private lateinit var uiUtil: UiUtil
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
|
|
@ -77,7 +76,6 @@ class QueuedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLi
|
|||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
items = mutableListOf()
|
||||
selectedObjects = arrayListOf()
|
||||
uiUtil = UiUtil()
|
||||
return fragmentView
|
||||
}
|
||||
|
||||
|
|
@ -148,7 +146,7 @@ class QueuedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLi
|
|||
time!!.text = SimpleDateFormat(DateFormat.getBestDateTimePattern(Locale.getDefault(), "ddMMMyyyy - HHmm"), Locale.getDefault()).format(calendar.time)
|
||||
|
||||
time.setOnClickListener {
|
||||
uiUtil.showDatePicker(parentFragmentManager) {
|
||||
UiUtil.showDatePicker(parentFragmentManager) {
|
||||
bottomSheet.dismiss()
|
||||
Toast.makeText(context, getString(R.string.download_rescheduled_to) + " " + it.time, Toast.LENGTH_LONG).show()
|
||||
downloadViewModel.deleteDownload(item)
|
||||
|
|
@ -192,10 +190,10 @@ class QueuedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLi
|
|||
link!!.text = url
|
||||
link.tag = itemID
|
||||
link.setOnClickListener{
|
||||
uiUtil.openLinkIntent(requireContext(), item.url, bottomSheet)
|
||||
UiUtil.openLinkIntent(requireContext(), item.url, bottomSheet)
|
||||
}
|
||||
link.setOnLongClickListener{
|
||||
uiUtil.copyLinkToClipBoard(requireContext(), item.url, bottomSheet)
|
||||
UiUtil.copyLinkToClipBoard(requireContext(), item.url, bottomSheet)
|
||||
true
|
||||
}
|
||||
val remove = bottomSheet.findViewById<Button>(R.id.bottomsheet_remove_button)
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ class CommandTemplatesFragment : Fragment(), TemplatesAdapter.OnItemClickListene
|
|||
private lateinit var templatesAdapter: TemplatesAdapter
|
||||
private lateinit var topAppBar: MaterialToolbar
|
||||
private lateinit var commandTemplateViewModel: CommandTemplateViewModel
|
||||
private lateinit var uiUtil: UiUtil
|
||||
private lateinit var templatesList: List<CommandTemplate>
|
||||
private lateinit var noResults: RelativeLayout
|
||||
private lateinit var mainActivity: MainActivity
|
||||
|
|
@ -75,7 +74,6 @@ class CommandTemplatesFragment : Fragment(), TemplatesAdapter.OnItemClickListene
|
|||
itemTouchHelper.attachToRecyclerView(recyclerView)
|
||||
}
|
||||
|
||||
uiUtil = UiUtil()
|
||||
|
||||
commandTemplateViewModel = ViewModelProvider(this)[CommandTemplateViewModel::class.java]
|
||||
commandTemplateViewModel.items.observe(viewLifecycleOwner) {
|
||||
|
|
@ -116,11 +114,11 @@ class CommandTemplatesFragment : Fragment(), TemplatesAdapter.OnItemClickListene
|
|||
private fun initChips() {
|
||||
val new = view?.findViewById<Chip>(R.id.newTemplate)
|
||||
new?.setOnClickListener {
|
||||
uiUtil.showCommandTemplateCreationOrUpdatingSheet(null,mainActivity, this, commandTemplateViewModel) {}
|
||||
UiUtil.showCommandTemplateCreationOrUpdatingSheet(null,mainActivity, this, commandTemplateViewModel) {}
|
||||
}
|
||||
val shortcuts = view?.findViewById<Chip>(R.id.shortcuts)
|
||||
shortcuts?.setOnClickListener {
|
||||
uiUtil.showShortcutsSheet(mainActivity,this, commandTemplateViewModel)
|
||||
UiUtil.showShortcutsSheet(mainActivity,this, commandTemplateViewModel)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -129,7 +127,7 @@ class CommandTemplatesFragment : Fragment(), TemplatesAdapter.OnItemClickListene
|
|||
}
|
||||
|
||||
override fun onItemClick(commandTemplate: CommandTemplate, index: Int) {
|
||||
uiUtil.showCommandTemplateCreationOrUpdatingSheet(commandTemplate,mainActivity, this, commandTemplateViewModel) {
|
||||
UiUtil.showCommandTemplateCreationOrUpdatingSheet(commandTemplate,mainActivity, this, commandTemplateViewModel) {
|
||||
templatesAdapter.notifyItemChanged(index)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,6 @@ class CookiesFragment : Fragment(), CookieAdapter.OnItemClickListener {
|
|||
private lateinit var listAdapter: CookieAdapter
|
||||
private lateinit var topAppBar: MaterialToolbar
|
||||
private lateinit var cookiesViewModel: CookieViewModel
|
||||
private lateinit var uiUtil: UiUtil
|
||||
private lateinit var cookiesList: List<CookieItem>
|
||||
private lateinit var noResults : RelativeLayout
|
||||
private lateinit var mainActivity: MainActivity
|
||||
|
|
@ -79,7 +78,6 @@ class CookiesFragment : Fragment(), CookieAdapter.OnItemClickListener {
|
|||
val itemTouchHelper = ItemTouchHelper(simpleCallback)
|
||||
itemTouchHelper.attachToRecyclerView(recyclerView)
|
||||
}
|
||||
uiUtil = UiUtil()
|
||||
|
||||
cookiesViewModel = ViewModelProvider(this)[CookieViewModel::class.java]
|
||||
cookiesViewModel.items.observe(viewLifecycleOwner) {
|
||||
|
|
|
|||
|
|
@ -63,7 +63,6 @@ class TerminalActivity : BaseActivity() {
|
|||
private lateinit var downloadFile : File
|
||||
private lateinit var observer: FileObserver
|
||||
private lateinit var imm : InputMethodManager
|
||||
private lateinit var uiUtil: UiUtil
|
||||
var context: Context? = null
|
||||
|
||||
public override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
|
@ -74,7 +73,6 @@ class TerminalActivity : BaseActivity() {
|
|||
downloadFile = File(cacheDir.absolutePath + "/$downloadID.txt")
|
||||
if (! downloadFile.exists()) downloadFile.createNewFile()
|
||||
imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
uiUtil = UiUtil()
|
||||
|
||||
context = baseContext
|
||||
scrollView = findViewById(R.id.custom_command_scrollview)
|
||||
|
|
@ -114,7 +112,7 @@ class TerminalActivity : BaseActivity() {
|
|||
Toast.makeText(context, getString(R.string.add_template_first), Toast.LENGTH_SHORT).show()
|
||||
}else{
|
||||
lifecycleScope.launch {
|
||||
uiUtil.showCommandTemplates(this@TerminalActivity, commandTemplateViewModel){ template ->
|
||||
UiUtil.showCommandTemplates(this@TerminalActivity, commandTemplateViewModel){ template ->
|
||||
input!!.text.insert(input!!.selectionStart, template.content + " ")
|
||||
input!!.postDelayed({
|
||||
input!!.requestFocus()
|
||||
|
|
|
|||
|
|
@ -8,12 +8,21 @@ import android.os.Bundle
|
|||
import android.os.Environment
|
||||
import android.provider.Settings
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.preference.EditTextPreference
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.work.Data
|
||||
import androidx.work.ExistingWorkPolicy
|
||||
import androidx.work.OneTimeWorkRequestBuilder
|
||||
import androidx.work.WorkInfo
|
||||
import androidx.work.WorkManager
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.deniscerri.ytdlnis.work.DownloadWorker
|
||||
import com.deniscerri.ytdlnis.work.MoveCacheFilesWorker
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import java.io.File
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
|
||||
class FolderSettingsFragment : BaseSettingsFragment() {
|
||||
|
|
@ -23,7 +32,10 @@ class FolderSettingsFragment : BaseSettingsFragment() {
|
|||
private var videoPath: Preference? = null
|
||||
private var commandPath: Preference? = null
|
||||
private var accessAllFiles : Preference? = null
|
||||
private var audioFilenameTemplate : EditTextPreference? = null
|
||||
private var videoFilenameTemplate : EditTextPreference? = null
|
||||
private var clearCache: Preference? = null
|
||||
private var moveCache: Preference? = null
|
||||
|
||||
private var activeDownloadCount = 0
|
||||
|
||||
|
|
@ -37,7 +49,10 @@ class FolderSettingsFragment : BaseSettingsFragment() {
|
|||
videoPath = findPreference("video_path")
|
||||
commandPath = findPreference("command_path")
|
||||
accessAllFiles = findPreference("access_all_files")
|
||||
videoFilenameTemplate = findPreference("file_name_template")
|
||||
audioFilenameTemplate = findPreference("file_name_template_audio")
|
||||
clearCache = findPreference("clear_cache")
|
||||
moveCache = findPreference("move_cache")
|
||||
|
||||
if (preferences.getString("music_path", "")!!.isEmpty()) {
|
||||
editor.putString("music_path", FileUtil.getDefautAudioPath())
|
||||
|
|
@ -95,6 +110,12 @@ class FolderSettingsFragment : BaseSettingsFragment() {
|
|||
true
|
||||
}
|
||||
|
||||
videoFilenameTemplate?.title = "${getString(R.string.file_name_template)} [${getString(R.string.video)}]"
|
||||
videoFilenameTemplate?.dialogTitle = "${getString(R.string.file_name_template)} [${getString(R.string.video)}]"
|
||||
|
||||
audioFilenameTemplate?.title = "${getString(R.string.file_name_template)} [${getString(R.string.audio)}]"
|
||||
audioFilenameTemplate?.dialogTitle = "${getString(R.string.file_name_template)} [${getString(R.string.audio)}]"
|
||||
|
||||
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 =
|
||||
|
|
@ -110,6 +131,34 @@ class FolderSettingsFragment : BaseSettingsFragment() {
|
|||
true
|
||||
}
|
||||
|
||||
moveCache!!.onPreferenceClickListener =
|
||||
Preference.OnPreferenceClickListener {
|
||||
val workRequest = OneTimeWorkRequestBuilder<MoveCacheFilesWorker>()
|
||||
.addTag("cacheFiles")
|
||||
.build()
|
||||
|
||||
WorkManager.getInstance(requireContext()).beginUniqueWork(
|
||||
System.currentTimeMillis().toString(),
|
||||
ExistingWorkPolicy.KEEP,
|
||||
workRequest
|
||||
).enqueue()
|
||||
|
||||
WorkManager.getInstance(requireContext())
|
||||
.getWorkInfosByTagLiveData("cacheFiles")
|
||||
.observe(viewLifecycleOwner){ list ->
|
||||
if (list == null) return@observe
|
||||
if (list.first() == null) return@observe
|
||||
|
||||
if (list.first().state == WorkInfo.State.SUCCEEDED){
|
||||
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)}"
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private var musicPathResultLauncher = registerForActivityResult(
|
||||
|
|
|
|||
|
|
@ -9,11 +9,6 @@ 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)}]"
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -70,7 +70,7 @@ object FileUtil {
|
|||
|
||||
|
||||
@Throws(Exception::class)
|
||||
fun moveFile(originDir: File, context: Context, destDir: String, keepCache: Boolean, progress: (p: Int) -> Unit) : String {
|
||||
fun moveFile(originDir: File, context: Context, destDir: String, keepCache: Boolean, progress: (p: Int) -> Unit) : List<String> {
|
||||
val fileList = mutableListOf<File>()
|
||||
val dir = File(formatPath(destDir))
|
||||
if (!dir.exists()) dir.mkdirs()
|
||||
|
|
@ -159,17 +159,17 @@ object FileUtil {
|
|||
}
|
||||
return scanMedia(fileList, context)
|
||||
}
|
||||
private fun scanMedia(files: List<File>, context: Context) : String {
|
||||
private fun scanMedia(files: List<File>, context: Context) : List<String> {
|
||||
|
||||
try {
|
||||
val paths = files.map { it.absolutePath }.toTypedArray()
|
||||
MediaScannerConnection.scanFile(context, paths, null, null)
|
||||
return files.reduce(Compare::max).absolutePath
|
||||
return files.sortedByDescending { it.length() }.map { it.absolutePath }
|
||||
}catch (e: Exception){
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
return context.getString(R.string.unfound_file);
|
||||
return listOf(context.getString(R.string.unfound_file))
|
||||
}
|
||||
|
||||
fun getLogFile(context: Context, item: DownloadItem) : File {
|
||||
|
|
|
|||
|
|
@ -56,13 +56,18 @@ class InfoUtil(private val context: Context) {
|
|||
}
|
||||
}
|
||||
|
||||
@Throws(JSONException::class)
|
||||
fun search(query: String): ArrayList<ResultItem?> {
|
||||
init()
|
||||
items = ArrayList()
|
||||
val searchEngine = sharedPreferences.getString("search_engine", "ytsearch")
|
||||
return if (searchEngine == "ytsearch"){
|
||||
if (key!!.isNotEmpty()) searchFromKey(query) else if (useInvidous) searchFromInvidous(query) else getFromYTDL(query)
|
||||
if (key!!.isNotEmpty()) searchFromKey(query) else {
|
||||
try{
|
||||
searchFromPiped(query)
|
||||
}catch (e: Exception){
|
||||
getFromYTDL(query)
|
||||
}
|
||||
}
|
||||
}else getFromYTDL(query)
|
||||
}
|
||||
|
||||
|
|
@ -116,22 +121,15 @@ class InfoUtil(private val context: Context) {
|
|||
}
|
||||
|
||||
@Throws(JSONException::class)
|
||||
fun searchFromInvidous(query: String): ArrayList<ResultItem?> {
|
||||
val dataArray = genericArrayRequest(invidousURL + "search?q=" + query + "?type=video")
|
||||
fun searchFromPiped(query: String): ArrayList<ResultItem?> {
|
||||
val data = genericRequest(pipedURL + "search?q=" + query + "?filter=videos")
|
||||
val dataArray = data.getJSONArray("items")
|
||||
if (dataArray.length() == 0) return getFromYTDL(query)
|
||||
for (i in 0 until dataArray.length()) {
|
||||
val element = dataArray.getJSONObject(i)
|
||||
if (!element.getString("type").equals("video")) continue
|
||||
val duration = formatIntegerDuration(element.getInt("lengthSeconds"), Locale.getDefault())
|
||||
if (duration == "0:00") {
|
||||
continue
|
||||
}
|
||||
element.put("duration", duration)
|
||||
element.put(
|
||||
"thumb",
|
||||
element.getJSONArray("videoThumbnails").getJSONObject(0).getString("url")
|
||||
)
|
||||
val v = createVideoFromInvidiousJSON(element)
|
||||
if (element.getInt("duration") == -1) continue
|
||||
element.put("uploader", element.getString("uploaderName"))
|
||||
val v = createVideoFromPipedJSON(element, element.getString("url").removePrefix("/watch?v="))
|
||||
if (v == null || v.thumb.isEmpty()) {
|
||||
continue
|
||||
}
|
||||
|
|
@ -511,7 +509,7 @@ class InfoUtil(private val context: Context) {
|
|||
init()
|
||||
items = ArrayList()
|
||||
return if (key!!.isEmpty()) {
|
||||
if (useInvidous) getTrendingFromInvidous(context) else ArrayList()
|
||||
getTrendingFromPiped()
|
||||
} else getTrendingFromKey(context)
|
||||
}
|
||||
|
||||
|
|
@ -545,14 +543,15 @@ class InfoUtil(private val context: Context) {
|
|||
return items
|
||||
}
|
||||
|
||||
private fun getTrendingFromInvidous(context: Context): ArrayList<ResultItem?> {
|
||||
val url = invidousURL + "trending?type=music®ion=" + countryCODE
|
||||
private fun getTrendingFromPiped(): ArrayList<ResultItem?> {
|
||||
val url = pipedURL + "trending?region=" + countryCODE
|
||||
val res = genericArrayRequest(url)
|
||||
try {
|
||||
for (i in 0 until res.length()) {
|
||||
val element = res.getJSONObject(i)
|
||||
if (element.getString("type") != "video") continue
|
||||
val v = createVideoFromInvidiousJSON(element)
|
||||
if (element.getInt("duration") < 0) continue
|
||||
element.put("uploader", element.getString("uploaderName"))
|
||||
val v = createVideoFromPipedJSON(element, element.getString("url").removePrefix("/watch?v="))
|
||||
if (v == null || v.thumb.isEmpty()) continue
|
||||
v.playlistTitle = context.getString(R.string.trendingPlaylist)
|
||||
items.add(v)
|
||||
|
|
|
|||
|
|
@ -11,12 +11,12 @@ import android.graphics.BitmapFactory
|
|||
import android.os.Build
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.content.FileProvider
|
||||
import com.deniscerri.ytdlnis.MainActivity
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.receiver.CancelDownloadNotificationReceiver
|
||||
import com.deniscerri.ytdlnis.receiver.PauseDownloadNotificationReceiver
|
||||
import com.deniscerri.ytdlnis.receiver.ResumeActivity
|
||||
import com.deniscerri.ytdlnis.receiver.SharedDownloadNotificationReceiver
|
||||
import com.deniscerri.ytdlnis.ui.more.downloadLogs.DownloadLogFragment
|
||||
import com.deniscerri.ytdlnis.receiver.ShareFileService
|
||||
import java.io.File
|
||||
|
||||
|
||||
|
|
@ -55,6 +55,13 @@ class NotificationUtil(var context: Context) {
|
|||
channel = NotificationChannel(DOWNLOAD_FINISHED_CHANNEL_ID, name, NotificationManager.IMPORTANCE_HIGH)
|
||||
channel.description = description
|
||||
notificationManager.createNotificationChannel(channel)
|
||||
|
||||
//misc
|
||||
name = context.getString(R.string.misc)
|
||||
description = ""
|
||||
channel = NotificationChannel(DOWNLOAD_MISC_CHANNEL_ID, name, NotificationManager.IMPORTANCE_HIGH)
|
||||
channel.description = description
|
||||
notificationManager.createNotificationChannel(channel)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -166,7 +173,7 @@ class NotificationUtil(var context: Context) {
|
|||
}
|
||||
|
||||
fun createDownloadFinished(title: String?,
|
||||
filepath: String?,
|
||||
filepath: List<String>?,
|
||||
channel: String
|
||||
) {
|
||||
val notificationBuilder = getBuilder(channel)
|
||||
|
|
@ -185,7 +192,7 @@ class NotificationUtil(var context: Context) {
|
|||
.clearActions()
|
||||
if (filepath != null){
|
||||
try{
|
||||
val file = File(filepath)
|
||||
val file = File(filepath.first())
|
||||
val uri = FileProvider.getUriForFile(
|
||||
context,
|
||||
"com.deniscerri.ytdl.fileprovider",
|
||||
|
|
@ -204,15 +211,15 @@ class NotificationUtil(var context: Context) {
|
|||
}
|
||||
|
||||
//share intent
|
||||
val shareIntent = Intent(context, SharedDownloadNotificationReceiver::class.java)
|
||||
shareIntent.putExtra("share", "")
|
||||
shareIntent.putExtra("path", filepath)
|
||||
val shareIntent = Intent(context, ShareFileService::class.java)
|
||||
shareIntent.putExtra("path", filepath.toTypedArray())
|
||||
shareIntent.putExtra("notificationID", DOWNLOAD_FINISHED_NOTIFICATION_ID)
|
||||
val shareNotificationPendingIntent: PendingIntent = TaskStackBuilder.create(context).run {
|
||||
addNextIntentWithParentStack(shareIntent)
|
||||
getPendingIntent(0,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
|
||||
}
|
||||
val shareNotificationPendingIntent: PendingIntent = PendingIntent.getService(
|
||||
context,
|
||||
0,
|
||||
shareIntent,
|
||||
PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
|
||||
notificationBuilder.addAction(0, context.getString(R.string.Open_File), openNotificationPendingIntent)
|
||||
notificationBuilder.addAction(0, context.getString(R.string.share), shareNotificationPendingIntent)
|
||||
|
|
@ -228,7 +235,7 @@ class NotificationUtil(var context: Context) {
|
|||
) {
|
||||
val notificationBuilder = getBuilder(channel)
|
||||
|
||||
val intent = Intent(context, DownloadLogFragment::class.java)
|
||||
val intent = Intent(context, MainActivity::class.java)
|
||||
intent.putExtra("logpath", logFile?.absolutePath)
|
||||
|
||||
val errorPendingIntent: PendingIntent = TaskStackBuilder.create(context).run {
|
||||
|
|
@ -283,6 +290,43 @@ class NotificationUtil(var context: Context) {
|
|||
notificationManager.cancel(id)
|
||||
}
|
||||
|
||||
fun createMoveCacheFilesNotification(pendingIntent: PendingIntent?, downloadMiscChannelId: String): Notification {
|
||||
val notificationBuilder = getBuilder(downloadMiscChannelId)
|
||||
|
||||
return notificationBuilder
|
||||
.setContentTitle(context.getString(R.string.move_temporary_files))
|
||||
.setOngoing(true)
|
||||
.setCategory(Notification.CATEGORY_PROGRESS)
|
||||
.setSmallIcon(android.R.drawable.stat_sys_download)
|
||||
.setLargeIcon(
|
||||
BitmapFactory.decodeResource(
|
||||
context.resources,
|
||||
android.R.drawable.stat_sys_download
|
||||
)
|
||||
)
|
||||
.setContentText("")
|
||||
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
|
||||
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||
.setProgress(PROGRESS_MAX, PROGRESS_CURR, false)
|
||||
.setContentIntent(pendingIntent)
|
||||
.setForegroundServiceBehavior(NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE)
|
||||
.clearActions()
|
||||
.build()
|
||||
}
|
||||
|
||||
fun updateCacheMovingNotification(id: Int, progress: Int, totalFiles: Int) {
|
||||
val notificationBuilder = getBuilder(DOWNLOAD_MISC_CHANNEL_ID)
|
||||
val contentText = "${progress}/${totalFiles}"
|
||||
try {
|
||||
notificationBuilder.setProgress(100, progress, false)
|
||||
.setContentTitle(context.getString(R.string.move_temporary_files))
|
||||
.setStyle(NotificationCompat.BigTextStyle().bigText(contentText))
|
||||
notificationManager.notify(id, notificationBuilder.build())
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val DOWNLOAD_SERVICE_CHANNEL_ID = "1"
|
||||
const val COMMAND_DOWNLOAD_SERVICE_CHANNEL_ID = "2"
|
||||
|
|
@ -290,6 +334,8 @@ class NotificationUtil(var context: Context) {
|
|||
const val DOWNLOAD_FINISHED_NOTIFICATION_ID = 3
|
||||
const val DOWNLOAD_RESUME_NOTIFICATION_ID = 4
|
||||
const val DOWNLOAD_UPDATING_NOTIFICATION_ID = 5
|
||||
const val DOWNLOAD_MISC_CHANNEL_ID = "4"
|
||||
const val DOWNLOAD_MISC_NOTIFICATION_ID = 4
|
||||
private const val PROGRESS_MAX = 100
|
||||
private const val PROGRESS_CURR = 0
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ import kotlinx.coroutines.withContext
|
|||
import java.io.File
|
||||
import java.util.Calendar
|
||||
|
||||
class UiUtil() {
|
||||
object UiUtil {
|
||||
@SuppressLint("SetTextI18n")
|
||||
fun populateFormatCard(formatCard : MaterialCardView, chosenFormat: Format, audioFormats: List<Format>?){
|
||||
formatCard.findViewById<TextView>(R.id.container).text = chosenFormat.container.uppercase()
|
||||
|
|
@ -276,9 +276,9 @@ class UiUtil() {
|
|||
putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
|
||||
}
|
||||
try {
|
||||
fragmentContext.startActivity(Intent.createChooser(shareIntent, null))
|
||||
fragmentContext.startActivity(Intent.createChooser(shareIntent, fragmentContext.getString(R.string.share)))
|
||||
}catch (e: Exception){
|
||||
val intent = Intent.createChooser(shareIntent, null)
|
||||
val intent = Intent.createChooser(shareIntent, fragmentContext.getString(R.string.share))
|
||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
fragmentContext.startActivity(intent)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ class DownloadWorker(
|
|||
}
|
||||
|
||||
val intent = Intent(context, MainActivity::class.java)
|
||||
intent.putExtra("activedownload", "")
|
||||
val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
|
||||
val notification = notificationUtil.createDownloadServiceNotification(pendingIntent, downloadItem.title, downloadItem.id.toInt(), NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID)
|
||||
val foregroundInfo = ForegroundInfo(downloadItem.id.toInt(), notification)
|
||||
|
|
@ -316,14 +317,14 @@ class DownloadWorker(
|
|||
}.onSuccess {
|
||||
//move file from internal to set download directory
|
||||
setProgressAsync(workDataOf("progress" to 100, "output" to "Moving file to ${FileUtil.formatPath(downloadLocation)}", "id" to downloadItem.id, "log" to logDownloads))
|
||||
var finalPath : String?
|
||||
var finalPaths : List<String>?
|
||||
try {
|
||||
finalPath = FileUtil.moveFile(tempFileDir.absoluteFile,context, downloadLocation, keepCache){ p ->
|
||||
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 $finalPath", "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))
|
||||
}catch (e: Exception){
|
||||
finalPath = context.getString(R.string.unfound_file)
|
||||
finalPaths = listOf(context.getString(R.string.unfound_file))
|
||||
e.printStackTrace()
|
||||
handler.postDelayed({
|
||||
Toast.makeText(context, e.message, Toast.LENGTH_SHORT).show()
|
||||
|
|
@ -336,9 +337,9 @@ class DownloadWorker(
|
|||
val incognito = sharedPreferences.getBoolean("incognito", false)
|
||||
if (!incognito) {
|
||||
val unixtime = System.currentTimeMillis() / 1000
|
||||
val file = File(finalPath!!)
|
||||
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, finalPath, downloadItem.website, downloadItem.format, downloadItem.id)
|
||||
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)
|
||||
}
|
||||
|
|
@ -346,7 +347,7 @@ class DownloadWorker(
|
|||
notificationUtil.cancelDownloadNotification(downloadItem.id.toInt())
|
||||
|
||||
notificationUtil.createDownloadFinished(
|
||||
downloadItem.title, if (finalPath.equals(context.getString(R.string.unfound_file))) null else finalPath,
|
||||
downloadItem.title, if (finalPaths?.first().equals(context.getString(R.string.unfound_file))) null else finalPaths,
|
||||
NotificationUtil.DOWNLOAD_FINISHED_CHANNEL_ID
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,88 @@
|
|||
package com.deniscerri.ytdlnis.work
|
||||
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.Environment
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.work.Data
|
||||
import androidx.work.ForegroundInfo
|
||||
import androidx.work.Worker
|
||||
import androidx.work.WorkerParameters
|
||||
import androidx.work.workDataOf
|
||||
import com.deniscerri.ytdlnis.MainActivity
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.DBManager
|
||||
import com.deniscerri.ytdlnis.database.dao.DownloadDao
|
||||
import com.deniscerri.ytdlnis.database.dao.ResultDao
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.models.HistoryItem
|
||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.deniscerri.ytdlnis.util.InfoUtil
|
||||
import com.deniscerri.ytdlnis.util.NotificationUtil
|
||||
import com.yausername.youtubedl_android.YoutubeDL
|
||||
import com.yausername.youtubedl_android.YoutubeDLRequest
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.StandardCopyOption
|
||||
|
||||
|
||||
class MoveCacheFilesWorker(
|
||||
private val context: Context,
|
||||
workerParams: WorkerParameters
|
||||
) : Worker(context, workerParams) {
|
||||
override fun doWork(): Result {
|
||||
val notificationUtil = NotificationUtil(context)
|
||||
val id = System.currentTimeMillis().toInt()
|
||||
|
||||
val downloadFolders = File(context.cacheDir.absolutePath + "/downloads")
|
||||
val allContent = downloadFolders.walk()
|
||||
allContent.drop(1)
|
||||
val totalFiles = allContent.count()
|
||||
val destination = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).absolutePath + File.separator + "YTDLnis/CACHE_IMPORT")
|
||||
|
||||
val intent = Intent(context, MainActivity::class.java)
|
||||
val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
|
||||
val notification = notificationUtil.createMoveCacheFilesNotification(pendingIntent, NotificationUtil.DOWNLOAD_MISC_CHANNEL_ID)
|
||||
val foregroundInfo = ForegroundInfo(id, notification)
|
||||
setForegroundAsync(foregroundInfo)
|
||||
|
||||
var progress = 0
|
||||
allContent.forEach {
|
||||
progress++
|
||||
notificationUtil.updateCacheMovingNotification(id, progress, totalFiles)
|
||||
val destFile = File(destination.absolutePath + "/${it.absolutePath.removePrefix(context.cacheDir.absolutePath + "/downloads")}")
|
||||
if (it.isDirectory) {
|
||||
destFile.mkdirs()
|
||||
return@forEach
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 26 ){
|
||||
Files.move(it.toPath(), destFile.toPath(), StandardCopyOption.REPLACE_EXISTING)
|
||||
}else{
|
||||
it.renameTo(destFile)
|
||||
}
|
||||
}
|
||||
val handler = Handler(Looper.getMainLooper())
|
||||
handler.post {
|
||||
Toast.makeText(context, context.getString(R.string.ok), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
return Result.success()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TAG = "MoveCacheFilesWorker"
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -14,6 +14,7 @@ import androidx.work.WorkerParameters
|
|||
import androidx.work.workDataOf
|
||||
import com.deniscerri.ytdlnis.MainActivity
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.ui.more.TerminalActivity
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.deniscerri.ytdlnis.util.NotificationUtil
|
||||
import com.yausername.youtubedl_android.YoutubeDL
|
||||
|
|
@ -34,7 +35,7 @@ class TerminalDownloadWorker(
|
|||
val notificationUtil = NotificationUtil(context)
|
||||
val handler = Handler(Looper.getMainLooper())
|
||||
|
||||
val intent = Intent(context, MainActivity::class.java)
|
||||
val intent = Intent(context, TerminalActivity::class.java)
|
||||
val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
|
||||
val notification = notificationUtil.createDownloadServiceNotification(pendingIntent, command.take(65), itemId, NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID)
|
||||
val foregroundInfo = ForegroundInfo(itemId, notification)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
<vector android:autoMirrored="true" 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="M20,6h-8l-2,-2L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,8c0,-1.1 -0.9,-2 -2,-2zM14,18v-3h-4v-4h4L14,8l5,5 -5,5z"/>
|
||||
</vector>
|
||||
|
|
@ -273,4 +273,6 @@
|
|||
<string name="crop_thumb_summary">Crop the thumbnail into a square for audio downloads</string>
|
||||
<string name="locale">Locale</string>
|
||||
<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>
|
||||
</resources>
|
||||
|
|
@ -23,6 +23,35 @@
|
|||
android:summary="@string/access_all_directories_summary"
|
||||
app:title="@string/access_all_directories" />
|
||||
|
||||
|
||||
<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" />
|
||||
|
||||
<Preference
|
||||
app:icon="@drawable/baseline_drive_file_move_24"
|
||||
app:key="move_cache"
|
||||
android:summary="@string/move_temporary_files_summary"
|
||||
app:title="@string/move_temporary_files" />
|
||||
|
||||
<Preference
|
||||
app:icon="@drawable/ic_folder_delete"
|
||||
app:key="clear_cache"
|
||||
|
|
|
|||
|
|
@ -11,27 +11,6 @@
|
|||
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"
|
||||
|
|
|
|||
Loading…
Reference in a new issue