added restrict filenames preference and changed download card design

This commit is contained in:
deniscerri 2023-03-19 16:25:37 +01:00
parent cb6fd86239
commit d3887dd7d9
No known key found for this signature in database
GPG key ID: 95C43D517D830350
25 changed files with 399 additions and 242 deletions

View file

@ -320,7 +320,7 @@
<PersistentState>
<option name="values">
<map>
<entry key="url" value="file:/$USER_HOME$/AppData/Local/Android/Sdk/icons/material/materialicons/folder_delete/baseline_folder_delete_24.xml" />
<entry key="url" value="file:/$USER_HOME$/AppData/Local/Android/Sdk/icons/material/materialicons/drive_file_rename_outline/baseline_drive_file_rename_outline_24.xml" />
</map>
</option>
</PersistentState>
@ -330,7 +330,7 @@
</option>
<option name="values">
<map>
<entry key="outputName" value="ic_folder_delete" />
<entry key="outputName" value="if_file_rename" />
<entry key="sourceFile" value="C:\Users\denis\Desktop\FREKUENCA\icons8-google-translate.svg" />
</map>
</option>

View file

@ -101,10 +101,10 @@
android:configChanges="layoutDirection|locale"
android:theme="@style/AppDefaultTheme"
android:parentActivityName=".MainActivity"
android:label="@string/run_command"
android:label="@string/terminal"
android:exported="true">
<intent-filter>
<action android:name="ytdlnis.CustomCommandActivity" />
<action android:name="ytdlnis.TerminalActivity" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>

View file

@ -1,12 +1,12 @@
package com.deniscerri.ytdlnis.adapter
import android.app.Activity
import android.graphics.Color
import android.os.Handler
import android.os.Looper
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.TextView
import androidx.core.content.ContextCompat
@ -26,16 +26,16 @@ import java.util.*
class ConfigureMultipleDownloadsAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<DownloadItem?, ConfigureMultipleDownloadsAdapter.ViewHolder>(AsyncDifferConfig.Builder(DIFF_CALLBACK).build()) {
private val onItemClickListener: OnItemClickListener
private val activity: Activity
private val fileUtil: FileUtil
private var fileUtil: FileUtil
init {
this.onItemClickListener = onItemClickListener
this.activity = activity
this.fileUtil = FileUtil()
fileUtil = FileUtil()
}
class ViewHolder(itemView: View, onItemClickListener: OnItemClickListener?) : RecyclerView.ViewHolder(itemView) {
val cardView: MaterialCardView
val cardView: FrameLayout
init {
cardView = itemView.findViewById(R.id.download_card_view)
@ -54,16 +54,16 @@ class ConfigureMultipleDownloadsAdapter(onItemClickListener: OnItemClickListener
// THUMBNAIL ----------------------------------
val thumbnail = card.findViewById<ImageView>(R.id.downloads_image_view)
val imageURL = item!!.thumb
val uiHandler = Handler(Looper.getMainLooper())
if (imageURL.isNotEmpty()) {
val uiHandler = Handler(Looper.getMainLooper())
uiHandler.post { Picasso.get().load(imageURL).into(thumbnail) }
thumbnail.setColorFilter(Color.argb(70, 0, 0, 0))
} else {
val uiHandler = Handler(Looper.getMainLooper())
uiHandler.post { Picasso.get().load(R.color.black).into(thumbnail) }
thumbnail.setColorFilter(Color.argb(70, 0, 0, 0))
}
val duration = card.findViewById<TextView>(R.id.duration)
duration.text = item.duration
// TITLE ----------------------------------
val itemTitle = card.findViewById<TextView>(R.id.title)
var title = item.title
@ -72,10 +72,6 @@ class ConfigureMultipleDownloadsAdapter(onItemClickListener: OnItemClickListener
}
itemTitle.text = title
// Author ----------------------------------
val author = card.findViewById<TextView>(R.id.subtitle)
author.text = item.author
// Format Note ----------------------------------
val formatNote = card.findViewById<TextView>(R.id.format_note)
if (item.format.format_note.isNotEmpty()){
@ -111,16 +107,17 @@ class ConfigureMultipleDownloadsAdapter(onItemClickListener: OnItemClickListener
// Type Icon Button
val btn = card.findViewById<MaterialButton>(R.id.action_button)
if (btn.hasOnClickListeners()) btn.setOnClickListener(null)
when(item.type) {
DownloadViewModel.Type.audio -> {
btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_music)
btn.setIconResource(R.drawable.ic_music)
}
DownloadViewModel.Type.video -> {
btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_video)
btn.setIconResource(R.drawable.ic_video)
}
else -> {
btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_terminal)
btn.setIconResource(R.drawable.ic_terminal)
}
}

View file

@ -7,6 +7,7 @@ import android.os.Looper
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.AsyncDifferConfig
@ -35,7 +36,7 @@ class GenericDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
}
class ViewHolder(itemView: View, onItemClickListener: OnItemClickListener?) : RecyclerView.ViewHolder(itemView) {
val cardView: MaterialCardView
val cardView: FrameLayout
init {
cardView = itemView.findViewById(R.id.download_card_view)
}
@ -60,25 +61,24 @@ class GenericDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
} else {
uiHandler.post { Picasso.get().load(R.color.black).into(thumbnail) }
}
thumbnail.setColorFilter(Color.argb(95, 0, 0, 0))
val duration = card.findViewById<TextView>(R.id.duration)
duration.text = item.duration
// TITLE ----------------------------------
val itemTitle = card.findViewById<TextView>(R.id.title)
var title = item!!.title
var title = item.title
if (title.length > 100) {
title = title.substring(0, 40) + "..."
}
itemTitle.text = title
val itemUrl = card.findViewById<TextView>(R.id.subtitle)
itemUrl.text = item.url
val formatNote = card.findViewById<Chip>(R.id.format_note)
val formatNote = card.findViewById<TextView>(R.id.format_note)
if (item.format.format_note == "?" || item.format.format_note == "") formatNote!!.visibility =
View.GONE
else formatNote!!.text = item.format.format_note.uppercase()
val codec = card.findViewById<Chip>(R.id.codec)
val codec = card.findViewById<TextView>(R.id.codec)
val codecText =
if (item.format.encoding != "") {
item.format.encoding.uppercase()
@ -94,7 +94,7 @@ class GenericDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
codec.text = codecText
}
val fileSize = card.findViewById<Chip>(R.id.file_size)
val fileSize = card.findViewById<TextView>(R.id.file_size)
val fileSizeReadable = fileUtil.convertFileSize(item.format.filesize)
if (fileSizeReadable == "?") fileSize.visibility = View.GONE
else fileSize.text = fileSizeReadable

View file

@ -69,6 +69,10 @@ class PlaylistAdapter(onItemClickListener: OnItemClickListener, activity: Activi
}
itemTitle.text = title
val duration = card.findViewById<TextView>(R.id.duration)
duration.text = item.duration
// CHECKBOX ----------------------------------
val check = card.findViewById<CheckBox>(R.id.checkBox)
check.isChecked = checkedItems.contains(item.url)

View file

@ -37,6 +37,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
private var bestVideoFormat : Format
private var bestAudioFormat : Format
private var defaultVideoFormats : MutableList<Format>
enum class Type {
audio, video, command
}
@ -57,15 +58,22 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
val videoFormat = getApplication<App>().resources.getStringArray(R.array.video_formats)
val videoContainer = sharedPreferences.getString("video_format", getApplication<App>().resources.getString(R.string.defaultValue))
bestVideoFormat = Format(
videoFormat[videoFormat.lastIndex],
videoContainer!!,
"",
"",
"",
0,
videoFormat[videoFormat.lastIndex]
)
defaultVideoFormats = mutableListOf()
videoFormat.forEach {
val tmp = Format(
it,
videoContainer!!,
"",
"",
"",
0,
it
)
defaultVideoFormats.add(tmp)
}
bestVideoFormat = defaultVideoFormats.last()
val audioContainer = sharedPreferences.getString("audio_format", "mp3")
bestAudioFormat = Format(
@ -172,17 +180,19 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
}
Type.video -> {
return try {
val theFormats = formats.ifEmpty { defaultVideoFormats }
val qualityPreference = sharedPreferences.getString("video_quality", getApplication<App>().resources.getString(R.string.best_quality))
if (qualityPreference == getApplication<App>().resources.getString(R.string.worst_quality)){
formats.first { !it.format_note.contains("audio", ignoreCase = true) }
theFormats.first { !it.format_note.contains("audio", ignoreCase = true) }
}
if (qualityPreference == getApplication<App>().resources.getString(R.string.best_quality)){
formats.last { !it.format_note.contains("audio", ignoreCase = true) }
theFormats.last { !it.format_note.contains("audio", ignoreCase = true) }
}
try{
formats.last { format -> format.format_note.contains(qualityPreference!!.substring(0, qualityPreference.length -1)) }
theFormats.last { format -> format.format_note.contains(qualityPreference!!.substring(0, qualityPreference.length - 1)) }
}catch (e: Exception){
formats.last { !it.format_note.contains("audio", ignoreCase = true) }
theFormats.last { !it.format_note.contains("audio", ignoreCase = true) }
}
}catch (e: Exception){
bestVideoFormat

View file

@ -266,7 +266,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
.inflate(R.layout.search_suggestion_item, null)
val textView = v.findViewById<TextView>(R.id.suggestion_text)
textView.text = suggestions[i]
textView.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_refresh, 0, 0, 0)
textView.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_restore, 0, 0, 0)
Handler(Looper.getMainLooper()).post {
searchHistoryLinearLayout!!.addView(
v
@ -291,6 +291,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
val mb = v.findViewById<ImageButton>(R.id.set_search_query_button)
mb.setOnClickListener {
searchView.setText(textView.text)
searchView.editText.setSelection(searchView.editText.length())
}
}
searchHistoryLinearLayout!!.visibility = VISIBLE
@ -315,6 +316,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
val mb = v.findViewById<ImageButton>(R.id.set_search_query_button)
mb.setOnClickListener {
searchView.setText(textView.text)
searchView.editText.setSelection(searchView.editText.length())
}
}
searchSuggestionsLinearLayout!!.visibility = VISIBLE
@ -437,23 +439,27 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
} catch (e: Exception) {""}
if (viewIdName.isNotEmpty()) {
if (viewIdName == "downloadSelected") {
val downloadList = downloadViewModel.turnResultItemsToDownloadItems(selectedObjects!!)
if (sharedPreferences!!.getBoolean("download_card", true)) {
val bottomSheet = DownloadMultipleBottomSheetDialog(downloadList.toMutableList())
bottomSheet.show(parentFragmentManager, "downloadMultipleSheet")
} else {
lifecycleScope.launch {
lifecycleScope.launch {
val downloadList = withContext(Dispatchers.IO){
downloadViewModel.turnResultItemsToDownloadItems(selectedObjects!!)
}
if (sharedPreferences!!.getBoolean("download_card", true)) {
val bottomSheet = DownloadMultipleBottomSheetDialog(downloadList.toMutableList())
bottomSheet.show(parentFragmentManager, "downloadMultipleSheet")
} else {
downloadViewModel.queueDownloads(downloadList)
}
}
}
if (viewIdName == "downloadAll") {
val downloadList = downloadViewModel.turnResultItemsToDownloadItems(resultsList!!)
if (sharedPreferences!!.getBoolean("download_card", true)) {
val bottomSheet = DownloadMultipleBottomSheetDialog(downloadList.toMutableList())
bottomSheet.show(parentFragmentManager, "downloadMultipleSheet")
} else {
lifecycleScope.launch {
lifecycleScope.launch {
val downloadList = withContext(Dispatchers.IO){
downloadViewModel.turnResultItemsToDownloadItems(resultsList!!)
}
if (sharedPreferences!!.getBoolean("download_card", true)) {
val bottomSheet = DownloadMultipleBottomSheetDialog(downloadList.toMutableList())
bottomSheet.show(parentFragmentManager, "downloadMultipleSheet")
} else {
downloadViewModel.queueDownloads(downloadList)
}
}

View file

@ -22,6 +22,7 @@ import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
import com.deniscerri.ytdlnis.receiver.ShareActivity
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.google.android.material.floatingactionbutton.FloatingActionButton
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.util.*
@ -74,7 +75,7 @@ class SelectPlaylistItemsBottomSheetDialog(private val items: List<ResultItem?>,
selectedText = view.findViewById<Button>(R.id.selected)
selectedText.text = "0 ${resources.getString(R.string.selected)}"
val checkAll = view.findViewById<Button>(R.id.check_all)
val checkAll = view.findViewById<FloatingActionButton>(R.id.check_all)
checkAll!!.setOnClickListener {
if (listAdapter.getCheckedItems().size != items.size){
listAdapter.checkAll()

View file

@ -44,6 +44,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
private var logDownloads: SwitchPreferenceCompat? = null
private var sponsorblockFilters: MultiSelectListPreference? = null
private var filenameTemplate: EditTextPreference? = null
private var restrictFilenames: SwitchPreferenceCompat? = null
private var mtime: SwitchPreferenceCompat? = null
private var embedSubtitles: SwitchPreferenceCompat? = null
private var embedThumbnail: SwitchPreferenceCompat? = null
@ -106,6 +107,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
mtime = findPreference("mtime")
embedSubtitles = findPreference("embed_subtitles")
filenameTemplate = findPreference("file_name_template")
restrictFilenames = findPreference("restrict_filenames")
embedThumbnail = findPreference("embed_thumbnail")
addChapters = findPreference("add_chapters")
writeThumbnail = findPreference("write_thumbnail")
@ -162,6 +164,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
editor.putBoolean("log_downloads", logDownloads!!.isChecked)
editor.putStringSet("sponsorblock_filters", sponsorblockFilters!!.values)
editor.putString("file_name_template", filenameTemplate!!.text)
editor.putBoolean("restrict_filenames", restrictFilenames!!.isChecked)
editor.putBoolean("mtime", mtime!!.isChecked)
editor.putBoolean("embed_subtitles", embedSubtitles!!.isChecked)
editor.putBoolean("embed_thumbnail", embedThumbnail!!.isChecked)
@ -337,6 +340,13 @@ class SettingsFragment : PreferenceFragmentCompat() {
editor.apply()
true
}
restrictFilenames!!.onPreferenceChangeListener =
Preference.OnPreferenceChangeListener { _: Preference?, newValue: Any ->
val embed = newValue as Boolean
editor.putBoolean("restrict_filenames", embed)
editor.apply()
true
}
mtime!!.onPreferenceChangeListener =
Preference.OnPreferenceChangeListener { _: Preference?, newValue: Any ->
val embed = newValue as Boolean

View file

@ -280,6 +280,9 @@ class InfoUtil(context: Context) {
val id = obj.getString("videoId")
val title = obj.getString("title").toString()
val author = obj.getString("author").toString()
if (author.isNullOrBlank()) throw Exception()
val duration = formatIntegerDuration(obj.getInt("lengthSeconds"))
val thumb = "https://i.ytimg.com/vi/$id/hqdefault.jpg"
val url = "https://www.youtube.com/watch?v=$id"

View file

@ -68,7 +68,8 @@ class DownloadWorker(
val type = downloadItem.type
val downloadLocation = downloadItem.downloadPath
val tempFolder = StringBuilder(context.cacheDir.absolutePath + """/${downloadItem.title}##${downloadItem.type}""")
val titleRegex = Regex("[^A-Za-z\\d ]")
val tempFolder = StringBuilder(context.cacheDir.absolutePath + """/${titleRegex.replace(downloadItem.title, "")}##${downloadItem.type}""")
tempFolder.append("##${downloadItem.format.format_id}")
val tempFileDir = File(tempFolder.toString())
tempFileDir.delete()
@ -110,7 +111,9 @@ class DownloadWorker(
if (downloadItem.customFileNameTemplate.isEmpty()) downloadItem.customFileNameTemplate = "%(uploader)s - %(title)s"
}
request.addOption("--restrict-filenames")
if (sharedPreferences.getBoolean("restrict_filenames", true)) {
request.addOption("--restrict-filenames")
}
when(type){
DownloadViewModel.Type.audio -> {
@ -210,8 +213,7 @@ class DownloadWorker(
runCatching {
val logDownloads = sharedPreferences.getBoolean("log_downloads", false) && !sharedPreferences.getBoolean("incognito", false)
val logFolder = File(context.filesDir.absolutePath + "/logs")
val regex = Regex("[^A-Za-z\\d ]")
val logFile = File(context.filesDir.absolutePath + """/logs/${downloadItem.id} - ${regex.replace(downloadItem.title, "")}##${downloadItem.type}##${downloadItem.format.format_id}.log""")
val logFile = File(context.filesDir.absolutePath + """/logs/${downloadItem.id} - ${titleRegex.replace(downloadItem.title, "")}##${downloadItem.type}##${downloadItem.format.format_id}.log""")
Log.e("aa", logFile.name)
if (logDownloads){
logFolder.mkdirs()

View file

@ -0,0 +1,14 @@
<vector android:height="24dp"
android:viewportHeight="24"
android:viewportWidth="24"
android:width="24dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<group
android:rotation="270"
android:pivotY="12"
android:pivotX="12"
>
<path android:fillColor="?android:textColorPrimary" android:pathData="M6,6l0,2l8.59,0l-9.59,9.59l1.41,1.41l9.59,-9.59l0,8.59l2,0l0,-12z"/>
</group>
</vector>

View file

@ -0,0 +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:textColorPrimary" android:pathData="M13,3c-4.97,0 -9,4.03 -9,9L1,12l3.89,3.89 0.07,0.14L9,12L6,12c0,-3.87 3.13,-7 7,-7s7,3.13 7,7 -3.13,7 -7,7c-1.93,0 -3.68,-0.79 -4.94,-2.06l-1.42,1.42C8.27,19.99 10.51,21 13,21c4.97,0 9,-4.03 9,-9s-4.03,-9 -9,-9zM12,8v5l4.28,2.54 0.72,-1.21 -3.5,-2.08L13.5,8L12,8z"/>
</vector>

View file

@ -0,0 +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.41,5.8L17.2,4.59c-0.78,-0.78 -2.05,-0.78 -2.83,0l-2.68,2.68L3,15.96V20h4.04l8.74,-8.74 2.63,-2.63c0.79,-0.78 0.79,-2.05 0,-2.83zM6.21,18H5v-1.21l8.66,-8.66 1.21,1.21L6.21,18zM11,20l4,-4h6v4H11z"/>
</vector>

View file

@ -50,6 +50,7 @@
android:layout_width="0dp"
android:layout_height="0dp"
android:orientation="vertical"
android:dividerPadding="5dp"
app:layout_constraintBottom_toTopOf="@+id/linearlayout2_horizontalscrollview"
app:layout_constraintEnd_toStartOf="@+id/active_download_cancel"
app:layout_constraintStart_toStartOf="parent"
@ -59,39 +60,32 @@
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="2"
android:paddingStart="10dp"
android:scrollbars="none"
android:paddingTop="10dp"
android:paddingEnd="10dp"
android:shadowColor="@color/black"
android:paddingStart="10dp"
android:textSize="17sp"
android:textColor="@color/white"
android:textStyle="bold"
android:shadowRadius="2"
android:shadowDx="4"
android:shadowDy="4"
android:shadowRadius="2"
android:textColor="@color/white"
android:textSize="17sp"
android:textStyle="bold" />
android:shadowColor="@color/black" />
<TextView
android:id="@+id/author"
android:layout_width="296dp"
android:layout_height="20dp"
android:ellipsize="end"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="bottom"
android:maxLines="1"
android:layout_marginTop="5dp"
android:paddingStart="10dp"
android:scrollbars="none"
android:paddingEnd="10dp"
android:paddingBottom="5dp"
android:shadowColor="@color/black"
android:paddingStart="10dp"
android:textSize="12sp"
android:textColor="@color/white"
android:textStyle="bold"
android:shadowRadius="1.5"
android:shadowDx="4"
android:shadowDy="4"
android:shadowRadius="1.5"
android:textColor="@color/white"
android:textSize="13sp"
android:textStyle="bold" />
android:shadowColor="@color/black" />
</LinearLayout>
@ -103,15 +97,17 @@
android:layout_height="wrap_content"
android:scrollbars="none"
app:layout_constraintBottom_toTopOf="@+id/output"
app:layout_constraintStart_toStartOf="parent">
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/active_download_cancel"
app:layout_constraintVertical_bias="1.0">
<com.google.android.material.chip.ChipGroup
android:id="@+id/linearLayout2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingHorizontal="10dp"
android:layout_gravity="bottom"
android:orientation="horizontal">
android:orientation="horizontal"
android:paddingHorizontal="10dp">
<com.google.android.material.chip.Chip
android:id="@+id/type"
@ -157,7 +153,6 @@
</HorizontalScrollView>
<TextView
android:id="@+id/output"
android:layout_width="match_parent"

View file

@ -1,19 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/downloads_card_constraintLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.card.MaterialCardView
<FrameLayout
android:id="@+id/download_card_view"
android:layout_width="0dp"
android:layout_height="120dp"
app:shapeAppearance="@style/ShapeAppearanceOverlay.Avatar"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:checkable="true"
app:cardCornerRadius="10dp"
app:cardMaxElevation="12dp"
app:cardElevation="5dp"
android:clickable="true"
android:focusable="true"
android:background="?android:attr/selectableItemBackground"
app:cardPreventCornerOverlap="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
@ -21,149 +23,172 @@
app:layout_constraintTop_toTopOf="parent"
app:strokeWidth="0dp">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/downloads_image_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:scaleType="centerCrop" />
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/title_author"
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/downloads_image_view"
android:layout_width="0dp"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintEnd_toStartOf="@+id/action_button"
android:layout_height="0dp"
app:layout_constraintHorizontal_weight="0.3"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="H,16:9"
app:layout_constraintEnd_toStartOf="@+id/download_item_data"
app:layout_constraintStart_toStartOf="parent"
app:shapeAppearance="@style/ShapeAppearanceOverlay.Avatar"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#80000000"
android:clickable="false"
android:layout_margin="5dp"
android:ellipsize="end"
android:gravity="center"
android:textStyle="bold"
android:maxLength="17"
android:maxLines="1"
android:minWidth="30dp"
android:paddingHorizontal="5dp"
android:textColor="@color/white"
android:textSize="12sp"
app:cornerRadius="10dp"
app:layout_constraintBottom_toBottomOf="@+id/downloads_image_view"
app:layout_constraintEnd_toEndOf="@+id/downloads_image_view" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/download_item_data"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintHorizontal_weight="0.7"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/downloads_image_view"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="2"
android:paddingHorizontal="5dp"
android:scrollbars="none"
android:paddingTop="10dp"
android:paddingEnd="10dp"
android:shadowColor="@color/black"
android:shadowDx="4"
android:shadowDy="4"
android:shadowRadius="2"
android:textColor="@color/white"
android:textSize="15sp"
android:textStyle="bold" />
android:textStyle="bold"
app:layout_constraintEnd_toStartOf="@+id/action_button"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<TextView
android:id="@+id/subtitle"
android:layout_width="296dp"
android:layout_height="20dp"
android:ellipsize="end"
android:gravity="bottom"
android:maxLines="1"
android:scrollbars="none"
android:paddingEnd="10dp"
android:paddingBottom="5dp"
android:shadowColor="@color/black"
android:shadowDx="4"
android:shadowDy="4"
android:shadowRadius="1.5"
android:textColor="@color/white"
android:textSize="11sp"
android:textStyle="bold" />
</LinearLayout>
<HorizontalScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="bottom"
android:paddingStart="10dp"
android:paddingEnd="0dp"
android:scrollbars="none"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/title_author"
app:layout_constraintVertical_bias="1.0">
<com.google.android.material.chip.ChipGroup
<HorizontalScrollView
android:layout_width="wrap_content"
android:layout_height="match_parent">
android:layout_height="wrap_content"
android:gravity="bottom"
android:paddingStart="5dp"
android:paddingEnd="0dp"
android:scrollbars="none"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/action_button"
app:layout_constraintVertical_bias="1.0">
<com.google.android.material.chip.Chip
android:id="@+id/format_note"
style="@style/Widget.Material3.FloatingActionButton.Large.Primary"
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false"
android:ellipsize="end"
android:gravity="center"
android:maxLines="1"
android:minWidth="30dp"
android:paddingHorizontal="10dp"
app:cornerRadius="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
android:layout_height="match_parent">
<com.google.android.material.chip.Chip
android:id="@+id/codec"
style="@style/Widget.Material3.FloatingActionButton.Large.Secondary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false"
android:gravity="center"
android:minWidth="30dp"
app:cornerRadius="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
style="@style/Widget.Material3.FloatingActionButton.Large.Secondary"
android:background="?attr/colorSecondary"
android:id="@+id/format_note"
android:layout_marginEnd="5dp"
android:maxLength="17"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false"
android:ellipsize="end"
android:gravity="center"
android:textSize="12sp"
android:maxLines="1"
android:minWidth="30dp"
android:textStyle="bold"
android:paddingHorizontal="5dp"
app:cornerRadius="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.chip.Chip
android:id="@+id/file_size"
style="@style/Widget.Material3.FloatingActionButton.Large.Tertiary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false"
android:gravity="center"
android:minWidth="30dp"
app:cornerRadius="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
style="@style/Widget.Material3.FloatingActionButton.Large.Tertiary"
android:background="?attr/colorSecondary"
android:id="@+id/codec"
android:layout_marginEnd="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false"
android:gravity="center"
android:minWidth="30dp"
android:textSize="12sp"
android:textStyle="bold"
android:paddingHorizontal="5dp"
app:cornerRadius="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:background="?attr/colorPrimaryInverse"
android:id="@+id/file_size"
android:layout_marginEnd="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false"
android:gravity="center"
android:textStyle="bold"
android:paddingHorizontal="5dp"
android:minWidth="30dp"
app:cornerRadius="10dp"
android:textSize="12sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</com.google.android.material.chip.ChipGroup>
</LinearLayout>
</HorizontalScrollView>
</HorizontalScrollView>
<com.google.android.material.button.MaterialButton
android:id="@+id/action_button"
style="@style/Widget.Material3.ExtendedFloatingActionButton.Icon.Secondary"
android:layout_width="55dp"
android:layout_height="55dp"
android:layout_margin="10dp"
android:layout_marginEnd="8dp"
app:cornerRadius="10dp"
app:icon="@drawable/ic_video"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.155" />
<com.google.android.material.button.MaterialButton
android:id="@+id/action_button"
style="?attr/materialIconButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cornerRadius="10dp"
app:icon="@drawable/ic_video"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -99,9 +99,8 @@
android:layout_width="match_parent"
android:paddingTop="10dp"
android:layout_height="wrap_content"
android:focusableInTouchMode="true"
android:orientation="vertical"
android:paddingBottom="80dp"
android:paddingBottom="70dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />

View file

@ -65,7 +65,8 @@
android:clickable="false"
android:gravity="center"
android:minWidth="30dp"
android:paddingHorizontal="10dp"
android:textStyle="bold"
android:paddingHorizontal="5dp"
app:cornerRadius="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
@ -81,7 +82,8 @@
android:clickable="false"
android:gravity="center"
android:minWidth="30dp"
android:paddingHorizontal="10dp"
android:textStyle="bold"
android:paddingHorizontal="5dp"
app:cornerRadius="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"

View file

@ -4,36 +4,108 @@
android:id="@+id/playlist_card_constraintLayout"
android:layout_width="match_parent"
android:layout_marginBottom="10dp"
android:layout_height="50dp">
android:layout_height="wrap_content">
<FrameLayout
android:id="@+id/download_card_view"
android:layout_width="0dp"
android:layout_marginStart="10dp"
app:shapeAppearance="@style/ShapeAppearanceOverlay.Avatar"
android:layout_height="wrap_content"
android:checkable="true"
android:clickable="true"
android:focusable="true"
app:cardPreventCornerOverlap="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/checkBox"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:strokeWidth="0dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/downloads_image_view"
android:clickable="false"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintHorizontal_weight="0.3"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="H,16:9"
app:layout_constraintEnd_toStartOf="@+id/download_item_data"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:shapeAppearance="@style/ShapeAppearanceOverlay.Avatar"
/>
<TextView
android:id="@+id/duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#80000000"
android:clickable="false"
android:layout_margin="5dp"
android:ellipsize="end"
android:gravity="center"
android:textStyle="bold"
android:maxLength="17"
android:maxLines="1"
android:minWidth="30dp"
android:paddingHorizontal="5dp"
android:textColor="@color/white"
android:textSize="12sp"
app:cornerRadius="10dp"
app:layout_constraintBottom_toBottomOf="@+id/downloads_image_view"
app:layout_constraintEnd_toEndOf="@+id/downloads_image_view" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/download_item_data"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintHorizontal_weight="0.7"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/downloads_image_view"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="2"
android:paddingHorizontal="10dp"
android:scrollbars="none"
android:shadowColor="@color/black"
android:shadowDx="4"
android:shadowDy="4"
android:shadowRadius="2"
android:textColor="@color/white"
android:textSize="15sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>
<CheckBox
android:id="@+id/checkBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/downloads_image_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
app:layout_constraintDimensionRatio="H,16:9"
android:layout_marginEnd="10dp"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
app:layout_constraintStart_toEndOf="@+id/checkBox" />
<TextView
android:id="@+id/title"
android:layout_width="0dp"
android:layout_height="0dp"
android:padding="15dp"
android:lines="2"
android:maxLines="2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/downloads_image_view"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -57,7 +57,7 @@
android:focusable="true"
android:clickable="true"
android:layout_height="match_parent"
android:src="@drawable/ic_arrow_up"
android:src="@drawable/ic_arrow_outward"
android:layout_weight="0.01"
/>

View file

@ -8,7 +8,7 @@
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical"
android:elevation="10dp"
app:layout_constraintBottom_toBottomOf="parent"
@ -19,32 +19,24 @@
android:id="@+id/bottomAppBar"
style="@style/Widget.Material3.BottomAppBar"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_height="wrap_content"
android:layout_gravity="bottom">
<Button
style="?attr/materialIconButtonStyle"
android:id="@+id/check_all"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:icon="@drawable/ic_select_all" />
<TextView
android:id="@+id/selected"
android:layout_width="wrap_content"
android:textStyle="bold"
android:paddingStart="17dp"
android:paddingEnd="0dp"
android:layout_height="wrap_content" />
</com.google.android.material.bottomappbar.BottomAppBar>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/edit_selected"
android:id="@+id/check_all"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:srcCompat="@drawable/ic_edit" />
app:layout_anchor="@id/bottomAppBar"
app:srcCompat="@drawable/ic_select_all" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
@ -100,7 +92,7 @@
android:layout_height="wrap_content"
android:focusableInTouchMode="true"
android:orientation="vertical"
android:paddingBottom="70dp"
android:paddingBottom="80dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />

View file

@ -181,4 +181,6 @@
<string name="ytdl_version">yt-dlp Version</string>
<string name="freespace">Free space</string>
<string name="link_you_copied">Link you copied</string>
<string name="restrict_filenames">Restrict Filenames</string>
<string name="restrict_filenames_summary"><![CDATA[Restrict filenames to only ASCII characters, and avoid \"&\" and spaces in filenames]]></string>
</resources>

View file

@ -48,4 +48,9 @@
<item name="android:layout_marginStart">5dp</item>
</style>
<style name="ShapeAppearanceOverlay.Avatar" parent="ShapeAppearance.MaterialComponents.SmallComponent">
<item name="cornerFamily">rounded</item>
<item name="cornerSize">5dp</item>
</style>
</resources>

View file

@ -10,7 +10,7 @@
app:icon="@drawable/ic_terminal"
app:key="run_command"
app:title="@string/terminal">
<intent android:action="ytdlnis.CustomCommandActivity" />
<intent android:action="ytdlnis.TerminalActivity" />
</Preference>
<Preference

View file

@ -143,6 +143,14 @@
app:defaultValue="%(uploader)s - %(title)s"
app:title="@string/file_name_template" />
<SwitchPreferenceCompat
android:widgetLayout="@layout/preferece_material_switch"
app:defaultValue="true"
app:icon="@drawable/if_file_rename"
app:key="restrict_filenames"
app:summary="@string/restrict_filenames_summary"
app:title="@string/restrict_filenames" />
<SwitchPreferenceCompat
android:widgetLayout="@layout/preferece_material_switch"
app:defaultValue="false"