fixed bugs with custom command and other small things

This commit is contained in:
Denis Çerri 2023-03-04 18:13:22 +01:00
parent 895476aa01
commit 5fed145313
No known key found for this signature in database
GPG key ID: 95C43D517D830350
24 changed files with 765 additions and 600 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/content_paste/baseline_content_paste_24.xml" />
<entry key="url" value="file:/$USER_HOME$/AppData/Local/Android/Sdk/icons/material/materialicons/content_copy/baseline_content_copy_24.xml" />
</map>
</option>
</PersistentState>
@ -330,7 +330,7 @@
</option>
<option name="values">
<map>
<entry key="outputName" value="ic_clipboard" />
<entry key="outputName" value="ic_copy" />
<entry key="sourceFile" value="C:\Users\denis\Desktop\adaptiveproduct_youtube_foreground_color_108 (1).svg" />
</map>
</option>

View file

@ -1,144 +0,0 @@
package com.deniscerri.ytdlnis.adapter
import android.annotation.SuppressLint
import android.app.Activity
import android.graphics.Color
import android.graphics.ColorMatrix
import android.graphics.ColorMatrixColorFilter
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.AsyncDifferConfig
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.HistoryItem
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.util.FileUtil
import com.google.android.material.button.MaterialButton
import com.google.android.material.card.MaterialCardView
import com.squareup.picasso.Picasso
import org.w3c.dom.Text
import java.io.File
import java.text.DateFormat
import java.text.SimpleDateFormat
import java.util.*
class CancelledDownloadAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<DownloadItem?, CancelledDownloadAdapter.ViewHolder>(AsyncDifferConfig.Builder(DIFF_CALLBACK).build()) {
private val onItemClickListener: OnItemClickListener
private val activity: Activity
private var fileUtil: FileUtil
init {
this.onItemClickListener = onItemClickListener
this.activity = activity
fileUtil = FileUtil()
}
class ViewHolder(itemView: View, onItemClickListener: OnItemClickListener?) : RecyclerView.ViewHolder(itemView) {
val cardView: MaterialCardView
init {
cardView = itemView.findViewById(R.id.queued_download_card_view)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val cardView = LayoutInflater.from(parent.context)
.inflate(R.layout.queued_download_card, parent, false)
return ViewHolder(cardView, onItemClickListener)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = getItem(position)
val card = holder.cardView
// THUMBNAIL ----------------------------------
val thumbnail = card.findViewById<ImageView>(R.id.image_view)
val imageURL = item!!.thumb
val uiHandler = Handler(Looper.getMainLooper())
if (imageURL.isNotEmpty()) {
uiHandler.post { Picasso.get().load(imageURL).into(thumbnail) }
} else {
uiHandler.post { Picasso.get().load(R.color.black).into(thumbnail) }
}
thumbnail.setColorFilter(Color.argb(95, 0, 0, 0))
// TITLE ----------------------------------
val itemTitle = card.findViewById<TextView>(R.id.title)
var title = item.title
if (title.length > 100) {
title = title.substring(0, 40) + "..."
}
itemTitle.text = title
val formatNote = card.findViewById<TextView>(R.id.format_note)
formatNote.text = item.format.format_note
val codec = card.findViewById<TextView>(R.id.codec)
val codecText =
if (item.format.encoding != "") {
item.format.encoding.uppercase()
}else if (item.format.vcodec != "none" && item.format.vcodec != ""){
item.format.vcodec.uppercase()
} else {
item.format.acodec.uppercase()
}
if (codecText == "" || codecText == "none"){
codec.visibility = View.GONE
}else{
codec.visibility = View.VISIBLE
codec.text = codecText
}
val fileSize = card.findViewById<TextView>(R.id.file_size)
fileSize.text = fileUtil.convertFileSize(item.format.filesize)
val downloadStartTime = card.findViewById<TextView>(R.id.time)
val time = item.downloadStartTime
if (time == 0L) {
downloadStartTime.visibility = View.GONE
} else {
downloadStartTime.visibility = View.VISIBLE
val cal = Calendar.getInstance()
val date = Date(time * 1000L)
cal.time = date
val day = cal[Calendar.DAY_OF_MONTH]
val month = cal.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.getDefault())
val year = cal[Calendar.YEAR]
val formatter: DateFormat = SimpleDateFormat("HH:mm", Locale.getDefault())
val timeString = formatter.format(date)
downloadStartTime.text = "$day $month $year - $timeString"
}
// CANCEL BUTTON ----------------------------------
val cancelButton = card.findViewById<MaterialButton>(R.id.queued_download_cancel)
if (cancelButton.hasOnClickListeners()) cancelButton.setOnClickListener(null)
cancelButton.setOnClickListener {
onItemClickListener.onQueuedCancelClick(item.id)
}
}
interface OnItemClickListener {
fun onQueuedCancelClick(itemID: Long)
}
companion object {
private val DIFF_CALLBACK: DiffUtil.ItemCallback<DownloadItem> = object : DiffUtil.ItemCallback<DownloadItem>() {
override fun areItemsTheSame(oldItem: DownloadItem, newItem: DownloadItem): Boolean {
val ranged = arrayListOf(oldItem.id, newItem.id)
return ranged[0] == ranged[1]
}
override fun areContentsTheSame(oldItem: DownloadItem, newItem: DownloadItem): Boolean {
return oldItem.url == newItem.url && oldItem.format.format_id == newItem.format.format_id
}
}
}
}

View file

@ -1,39 +1,33 @@
package com.deniscerri.ytdlnis.adapter
import android.annotation.SuppressLint
import android.app.Activity
import android.graphics.Color
import android.graphics.ColorMatrix
import android.graphics.ColorMatrixColorFilter
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.recyclerview.widget.AsyncDifferConfig
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.HistoryItem
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.ui.downloadcard.DownloadVideoFragment
import com.deniscerri.ytdlnis.util.FileUtil
import com.google.android.material.button.MaterialButton
import com.google.android.material.card.MaterialCardView
import com.squareup.picasso.Picasso
import org.w3c.dom.Text
import java.io.File
import java.text.DateFormat
import java.text.SimpleDateFormat
import java.util.*
class ErroredDownloadAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<DownloadItem?, ErroredDownloadAdapter.ViewHolder>(AsyncDifferConfig.Builder(DIFF_CALLBACK).build()) {
class GenericDownloadAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<DownloadItem?, GenericDownloadAdapter.ViewHolder>(AsyncDifferConfig.Builder(DIFF_CALLBACK).build()) {
private val onItemClickListener: OnItemClickListener
private val activity: Activity
private var fileUtil: FileUtil
@ -47,40 +41,43 @@ class ErroredDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
class ViewHolder(itemView: View, onItemClickListener: OnItemClickListener?) : RecyclerView.ViewHolder(itemView) {
val cardView: MaterialCardView
init {
cardView = itemView.findViewById(R.id.queued_download_card_view)
cardView = itemView.findViewById(R.id.download_card_view)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val cardView = LayoutInflater.from(parent.context)
.inflate(R.layout.queued_download_card, parent, false)
.inflate(R.layout.generic_download_card, parent, false)
return ViewHolder(cardView, onItemClickListener)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = getItem(position)
val card = holder.cardView
// THUMBNAIL ----------------------------------
val thumbnail = card.findViewById<ImageView>(R.id.image_view)
val imageURL = item!!.thumb
val uiHandler = Handler(Looper.getMainLooper())
if (imageURL.isNotEmpty()) {
uiHandler.post { Picasso.get().load(imageURL).into(thumbnail) }
} else {
uiHandler.post { Picasso.get().load(R.color.black).into(thumbnail) }
}
thumbnail.setColorFilter(Color.argb(95, 0, 0, 0))
// 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
// TITLE ----------------------------------
val itemUrl = card.findViewById<TextView>(R.id.url)
itemUrl.text = item.url
val type = card.findViewById<TextView>(R.id.type)
type!!.text = item.type.toString().uppercase()
val formatNote = card.findViewById<TextView>(R.id.format_note)
formatNote.text = item.format.format_note
if (item.type == DownloadViewModel.Type.command){
formatNote.visibility = View.GONE
}else{
formatNote.text = item.format.format_note
}
val codec = card.findViewById<TextView>(R.id.codec)
val codecText =
if (item.format.encoding != "") {
@ -98,35 +95,34 @@ class ErroredDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
}
val fileSize = card.findViewById<TextView>(R.id.file_size)
fileSize.text = fileUtil.convertFileSize(item.format.filesize)
val downloadStartTime = card.findViewById<TextView>(R.id.time)
val time = item.downloadStartTime
if (time == 0L) {
downloadStartTime.visibility = View.GONE
} else {
downloadStartTime.visibility = View.VISIBLE
val cal = Calendar.getInstance()
val date = Date(time * 1000L)
cal.time = date
val day = cal[Calendar.DAY_OF_MONTH]
val month = cal.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.getDefault())
val year = cal[Calendar.YEAR]
val formatter: DateFormat = SimpleDateFormat("HH:mm", Locale.getDefault())
val timeString = formatter.format(date)
downloadStartTime.text = "$day $month $year - $timeString"
val fileSizeReadable = fileUtil.convertFileSize(item.format.filesize)
if (fileSizeReadable == "?") fileSize.visibility = View.GONE
else fileSize.text = fileSizeReadable
// ACTION BUTTON ----------------------------------
val actionButton = card.findViewById<MaterialButton>(R.id.action_button)
if (actionButton.hasOnClickListeners()) actionButton.setOnClickListener(null)
when(item.status){
DownloadRepository.Status.Cancelled.toString() -> actionButton.setIconResource(R.drawable.ic_refresh)
DownloadRepository.Status.Queued.toString() -> actionButton.setIconResource(R.drawable.ic_baseline_delete_outline_24)
else -> actionButton.setIconResource(R.drawable.ic_baseline_file_open_24)
}
// CANCEL BUTTON ----------------------------------
val cancelButton = card.findViewById<MaterialButton>(R.id.queued_download_cancel)
if (cancelButton.hasOnClickListeners()) cancelButton.setOnClickListener(null)
cancelButton.setOnClickListener {
onItemClickListener.onQueuedCancelClick(item.id)
actionButton.setOnClickListener {
onItemClickListener.onActionButtonClick(item.id)
}
card.setOnClickListener {
onItemClickListener.onCardClick(item.id)
}
}
interface OnItemClickListener {
fun onQueuedCancelClick(itemID: Long)
fun onActionButtonClick(itemID: Long)
fun onCardClick(itemID: Long)
}
companion object {

View file

@ -124,8 +124,10 @@ class HistoryAdapter(onItemClickListener: OnItemClickListener, activity: Activit
}
if (item.type == DownloadViewModel.Type.audio) {
if (filePresent) btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_music_downloaded) else btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_music)
} else {
} else if (item.type == DownloadViewModel.Type.video) {
if (filePresent) btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_video_downloaded) else btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_video)
}else{
btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_terminal)
}
if (btn.hasOnClickListeners()) btn.setOnClickListener(null)
if (checkedItems.contains(item.id)) {

View file

@ -1,144 +0,0 @@
package com.deniscerri.ytdlnis.adapter
import android.annotation.SuppressLint
import android.app.Activity
import android.graphics.Color
import android.graphics.ColorMatrix
import android.graphics.ColorMatrixColorFilter
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.AsyncDifferConfig
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.HistoryItem
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.util.FileUtil
import com.google.android.material.button.MaterialButton
import com.google.android.material.card.MaterialCardView
import com.squareup.picasso.Picasso
import org.w3c.dom.Text
import java.io.File
import java.text.DateFormat
import java.text.SimpleDateFormat
import java.util.*
class QueuedDownloadAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<DownloadItem?, QueuedDownloadAdapter.ViewHolder>(AsyncDifferConfig.Builder(DIFF_CALLBACK).build()) {
private val onItemClickListener: OnItemClickListener
private val activity: Activity
private var fileUtil: FileUtil
init {
this.onItemClickListener = onItemClickListener
this.activity = activity
fileUtil = FileUtil()
}
class ViewHolder(itemView: View, onItemClickListener: OnItemClickListener?) : RecyclerView.ViewHolder(itemView) {
val cardView: MaterialCardView
init {
cardView = itemView.findViewById(R.id.queued_download_card_view)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val cardView = LayoutInflater.from(parent.context)
.inflate(R.layout.queued_download_card, parent, false)
return ViewHolder(cardView, onItemClickListener)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = getItem(position)
val card = holder.cardView
// THUMBNAIL ----------------------------------
val thumbnail = card.findViewById<ImageView>(R.id.image_view)
val imageURL = item!!.thumb
val uiHandler = Handler(Looper.getMainLooper())
if (imageURL.isNotEmpty()) {
uiHandler.post { Picasso.get().load(imageURL).into(thumbnail) }
} else {
uiHandler.post { Picasso.get().load(R.color.black).into(thumbnail) }
}
thumbnail.setColorFilter(Color.argb(95, 0, 0, 0))
// TITLE ----------------------------------
val itemTitle = card.findViewById<TextView>(R.id.title)
var title = item.title
if (title.length > 100) {
title = title.substring(0, 40) + "..."
}
itemTitle.text = title
val formatNote = card.findViewById<TextView>(R.id.format_note)
formatNote.text = item.format.format_note
val codec = card.findViewById<TextView>(R.id.codec)
val codecText =
if (item.format.encoding != "") {
item.format.encoding.uppercase()
}else if (item.format.vcodec != "none" && item.format.vcodec != ""){
item.format.vcodec.uppercase()
} else {
item.format.acodec.uppercase()
}
if (codecText == "" || codecText == "none"){
codec.visibility = View.GONE
}else{
codec.visibility = View.VISIBLE
codec.text = codecText
}
val fileSize = card.findViewById<TextView>(R.id.file_size)
fileSize.text = fileUtil.convertFileSize(item.format.filesize)
val downloadStartTime = card.findViewById<TextView>(R.id.time)
val time = item.downloadStartTime
if (time == 0L) {
downloadStartTime.visibility = View.GONE
} else {
downloadStartTime.visibility = View.VISIBLE
val cal = Calendar.getInstance()
val date = Date(time * 1000L)
cal.time = date
val day = cal[Calendar.DAY_OF_MONTH]
val month = cal.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.getDefault())
val year = cal[Calendar.YEAR]
val formatter: DateFormat = SimpleDateFormat("HH:mm", Locale.getDefault())
val timeString = formatter.format(date)
downloadStartTime.text = "$day $month $year - $timeString"
}
// CANCEL BUTTON ----------------------------------
val cancelButton = card.findViewById<MaterialButton>(R.id.queued_download_cancel)
if (cancelButton.hasOnClickListeners()) cancelButton.setOnClickListener(null)
cancelButton.setOnClickListener {
onItemClickListener.onQueuedCancelClick(item.id)
}
}
interface OnItemClickListener {
fun onQueuedCancelClick(itemID: Long)
}
companion object {
private val DIFF_CALLBACK: DiffUtil.ItemCallback<DownloadItem> = object : DiffUtil.ItemCallback<DownloadItem>() {
override fun areItemsTheSame(oldItem: DownloadItem, newItem: DownloadItem): Boolean {
val ranged = arrayListOf(oldItem.id, newItem.id)
return ranged[0] == ranged[1]
}
override fun areContentsTheSame(oldItem: DownloadItem, newItem: DownloadItem): Boolean {
return oldItem.url == newItem.url && oldItem.format.format_id == newItem.format.format_id
}
}
}
}

View file

@ -47,11 +47,11 @@ class TemplatesAdapter(onItemClickListener: OnItemClickListener, activity: Activ
val content = card.findViewById<TextView>(R.id.content)
content.text = item?.content
val check = card.findViewById<Button>(R.id.check)
check.setOnClickListener {
onItemClickListener.onSelected(item!!)
}
// val check = card.findViewById<Button>(R.id.check)
//
// check.setOnClickListener {
// onItemClickListener.onSelected(item!!)
// }
title.setOnClickListener {
onItemClickListener.onItemClick(item!!)

View file

@ -3,7 +3,6 @@ package com.deniscerri.ytdlnis.ui
import android.app.Activity
import android.content.*
import android.content.res.Configuration
import android.net.Uri
import android.os.Bundle
import android.os.Handler
import android.os.Looper
@ -13,7 +12,6 @@ import android.view.*
import android.view.View.*
import android.widget.*
import androidx.appcompat.widget.SearchView
import androidx.core.content.FileProvider
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.GridLayoutManager
@ -28,6 +26,7 @@ import com.deniscerri.ytdlnis.database.repository.HistoryRepository.HistorySort
import com.deniscerri.ytdlnis.database.viewmodel.HistoryViewModel
import com.deniscerri.ytdlnis.databinding.FragmentHistoryBinding
import com.deniscerri.ytdlnis.util.FileUtil
import com.deniscerri.ytdlnis.util.UiUtil
import com.facebook.shimmer.ShimmerFrameLayout
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.appbar.MaterialToolbar
@ -64,7 +63,7 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
private var selectedObjects: ArrayList<HistoryItem>? = null
private var deleteFab: ExtendedFloatingActionButton? = null
private var fileUtil: FileUtil? = null
private var uiUtil: UiUtil? = null
private var _binding : FragmentHistoryBinding? = null
override fun onCreateView(
@ -91,6 +90,7 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
websiteGroup = view.findViewById(R.id.website_chip_group)
deleteFab = view.findViewById(R.id.delete_selected_fab)
fileUtil = FileUtil()
uiUtil = UiUtil(FileUtil())
deleteFab?.tag = "deleteSelected"
deleteFab?.setOnClickListener{
removeSelectedItems()
@ -144,7 +144,7 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
initChips()
}
fun scrollToTop() {
private fun scrollToTop() {
recyclerView!!.scrollToPosition(0)
Handler(Looper.getMainLooper()).post {
(topAppBar!!.parent as AppBarLayout).setExpanded(
@ -372,41 +372,13 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
deleteDialog.show()
}
private fun copyLinkToClipBoard(url: String) {
val clipboard = context?.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText(getString(R.string.url), url)
clipboard.setPrimaryClip(clip)
if (bottomSheet != null) bottomSheet!!.hide()
Toast.makeText(context, getString(R.string.link_copied_to_clipboard), Toast.LENGTH_SHORT)
.show()
}
private fun openLinkIntent(url: String) {
val i = Intent(Intent.ACTION_VIEW)
i.data = Uri.parse(url)
if (bottomSheet != null) bottomSheet!!.hide()
startActivity(i)
}
private fun openFileIntent(downloadPath: String) {
val file = File(downloadPath)
val uri = FileProvider.getUriForFile(
fragmentContext!!,
fragmentContext!!.packageName + ".fileprovider",
file
)
val mime = mainActivity!!.contentResolver.getType(uri)
val i = Intent(Intent.ACTION_VIEW)
i.setDataAndType(uri, mime)
i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
startActivity(i)
}
override fun onCardClick(videoID: Long, isPresent: Boolean) {
override fun onCardClick(itemID: Long, isPresent: Boolean) {
bottomSheet = BottomSheetDialog(fragmentContext!!)
bottomSheet!!.requestWindowFeature(Window.FEATURE_NO_TITLE)
bottomSheet!!.setContentView(R.layout.history_item_details_bottom_sheet)
val video = findItem(videoID)
val video = findItem(itemID)
val title = bottomSheet!!.findViewById<TextView>(R.id.bottom_sheet_title)
title!!.text = video!!.title
val author = bottomSheet!!.findViewById<TextView>(R.id.bottom_sheet_author)
@ -414,23 +386,23 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
val link = bottomSheet!!.findViewById<Button>(R.id.bottom_sheet_link)
val url = video.url
link!!.text = url
link.tag = videoID
link.tag = itemID
link.setOnClickListener{
openLinkIntent(video.url)
uiUtil!!.openLinkIntent(requireContext(), video.url, bottomSheet)
}
link.setOnLongClickListener{
copyLinkToClipBoard(video.url)
uiUtil!!.copyLinkToClipBoard(requireContext(), video.url, bottomSheet)
true
}
val remove = bottomSheet!!.findViewById<Button>(R.id.bottomsheet_remove_button)
remove!!.tag = videoID
remove!!.tag = itemID
remove.setOnClickListener{
removeItem(video)
}
val openFile = bottomSheet!!.findViewById<Button>(R.id.bottomsheet_open_file_button)
openFile!!.tag = videoID
openFile!!.tag = itemID
openFile.setOnClickListener{
openFileIntent(video.downloadPath)
uiUtil!!.openFileIntent(requireContext(), video.downloadPath)
}
if (!isPresent) openFile.visibility = GONE
bottomSheet!!.show()
@ -440,8 +412,8 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
)
}
override fun onCardSelect(videoID: Long, isChecked: Boolean) {
val item = findItem(videoID)
override fun onCardSelect(itemID: Long, isChecked: Boolean) {
val item = findItem(itemID)
if (isChecked) selectedObjects!!.add(item!!)
else selectedObjects!!.remove(item)
if (selectedObjects!!.size > 1) {

View file

@ -1,55 +1,50 @@
package com.deniscerri.ytdlnis.ui.downloadqueue
import android.app.Activity
import android.content.Intent
import android.content.DialogInterface
import android.content.res.Configuration
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.view.Window
import android.widget.AdapterView.OnItemClickListener
import android.widget.ArrayAdapter
import android.widget.AutoCompleteTextView
import android.widget.Button
import android.widget.LinearLayout
import android.widget.TextView
import androidx.activity.result.contract.ActivityResultContracts
import androidx.constraintlayout.widget.ConstraintLayout
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.work.WorkManager
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.adapter.ActiveDownloadAdapter
import com.deniscerri.ytdlnis.adapter.CancelledDownloadAdapter
import com.deniscerri.ytdlnis.adapter.GenericDownloadAdapter
import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.Format
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel.Type
import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding
import com.deniscerri.ytdlnis.ui.downloadcard.FormatSelectionBottomSheetDialog
import com.deniscerri.ytdlnis.ui.downloadcard.OnFormatClickListener
import com.deniscerri.ytdlnis.util.FileUtil
import com.deniscerri.ytdlnis.util.UiUtil
import com.google.android.material.chip.Chip
import com.google.android.material.progressindicator.LinearProgressIndicator
import com.google.android.material.textfield.TextInputLayout
import kotlinx.coroutines.launch
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.w3c.dom.Text
import java.sql.Date
import java.sql.Timestamp
import java.text.DateFormat
import java.text.SimpleDateFormat
import java.util.*
class CancelledDownloadsFragment() : Fragment(), CancelledDownloadAdapter.OnItemClickListener, OnItemClickListener {
class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickListener {
private var _binding : FragmentHomeBinding? = null
private var fragmentView: View? = null
private var activity: Activity? = null
private lateinit var downloadViewModel : DownloadViewModel
private lateinit var cancelledRecyclerView : RecyclerView
private lateinit var cancelledDownloads : CancelledDownloadAdapter
lateinit var downloadItem: DownloadItem
private lateinit var cancelledDownloads : GenericDownloadAdapter
private lateinit var items : List<DownloadItem>
private lateinit var fileUtil: FileUtil
private lateinit var uiUtil : UiUtil
override fun onCreateView(
inflater: LayoutInflater,
@ -60,6 +55,9 @@ class CancelledDownloadsFragment() : Fragment(), CancelledDownloadAdapter.OnItem
fragmentView = inflater.inflate(R.layout.fragment_generic_download_queue, container, false)
activity = getActivity()
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
items = listOf()
fileUtil = FileUtil()
uiUtil = UiUtil(fileUtil)
return fragmentView
}
@ -67,7 +65,7 @@ class CancelledDownloadsFragment() : Fragment(), CancelledDownloadAdapter.OnItem
super.onViewCreated(view, savedInstanceState)
cancelledDownloads =
CancelledDownloadAdapter(
GenericDownloadAdapter(
this,
requireActivity()
)
@ -83,17 +81,112 @@ class CancelledDownloadsFragment() : Fragment(), CancelledDownloadAdapter.OnItem
}
downloadViewModel.cancelledDownloads.observe(viewLifecycleOwner) {
items = it
cancelledDownloads.submitList(it)
}
}
override fun onQueuedCancelClick(itemID: Long) {
TODO("Not yet implemented")
override fun onActionButtonClick(itemID: Long) {
val item = items.find { it.id == itemID }
if (item != null){
downloadViewModel.queueDownloads(listOf(item))
}else{
Toast.makeText(requireContext(), getString(R.string.error_restarting_download), Toast.LENGTH_LONG).show()
}
}
override fun onItemClick(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) {
TODO("Not yet implemented")
override fun onCardClick(itemID: Long) {
val item = items.find { it.id == itemID } ?: return
val bottomSheet = BottomSheetDialog(requireContext())
bottomSheet.requestWindowFeature(Window.FEATURE_NO_TITLE)
bottomSheet.setContentView(R.layout.download_details_bottom_sheet)
val title = bottomSheet.findViewById<TextView>(R.id.bottom_sheet_title)
title!!.text = item.title
val author = bottomSheet.findViewById<TextView>(R.id.bottom_sheet_author)
author!!.text = item.author
val type = bottomSheet.findViewById<TextView>(R.id.type)
val formatNote = bottomSheet.findViewById<TextView>(R.id.format_note)
val codec = bottomSheet.findViewById<TextView>(R.id.codec)
val fileSize = bottomSheet.findViewById<TextView>(R.id.file_size)
val scheduledTime = bottomSheet.findViewById<LinearLayout>(R.id.scheduled_time_linear)
type!!.text = item.type.toString().uppercase()
if (item.format.format_note == "?") formatNote!!.visibility = View.GONE
else formatNote!!.text = item.format.format_note
val codecText =
if (item.format.encoding != "") {
item.format.encoding.uppercase()
}else if (item.format.vcodec != "none" && item.format.vcodec != ""){
item.format.vcodec.uppercase()
} else {
item.format.acodec.uppercase()
}
if (codecText == "" || codecText == "none"){
codec!!.visibility = View.GONE
}else{
codec!!.visibility = View.VISIBLE
codec.text = codecText
}
val fileSizeReadable = fileUtil.convertFileSize(item.format.filesize)
if (fileSizeReadable == "?") fileSize!!.visibility = View.GONE
else fileSize!!.text = fileSizeReadable
val link = bottomSheet.findViewById<Button>(R.id.bottom_sheet_link)
link!!.text = item.url
link.tag = itemID
link.setOnClickListener{
uiUtil.openLinkIntent(requireContext(), item.url, bottomSheet)
}
link.setOnLongClickListener{
uiUtil.copyLinkToClipBoard(requireContext(), item.url, bottomSheet)
true
}
if (item.downloadStartTime == 0L){
scheduledTime!!.visibility = View.GONE
}else{
val time = bottomSheet.findViewById<TextView>(R.id.time)
val cal = Calendar.getInstance()
val date = Date(item.downloadStartTime * 1000L)
cal.time = date
val day = cal[Calendar.DAY_OF_MONTH]
val month = cal.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.getDefault())
val year = cal[Calendar.YEAR]
val formatter: DateFormat = SimpleDateFormat("HH:mm", Locale.getDefault())
val timeString = formatter.format(date)
val formattedTime = "$day $month $year - $timeString"
time!!.text = formattedTime
}
val remove = bottomSheet.findViewById<Button>(R.id.bottomsheet_remove_button)
remove!!.tag = itemID
remove.setOnClickListener{
removeItem(item, bottomSheet)
}
bottomSheet.show()
bottomSheet.window!!.setLayout(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
}
private fun removeItem(item: DownloadItem, bottomSheet: BottomSheetDialog?){
bottomSheet?.hide()
val deleteDialog = MaterialAlertDialogBuilder(requireContext())
deleteDialog.setTitle(getString(R.string.you_are_going_to_delete) + " \"" + item.title + "\"!")
deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
downloadViewModel.deleteDownload(item)
}
deleteDialog.show()
}
}

View file

@ -2,37 +2,14 @@ package com.deniscerri.ytdlnis.ui.downloadqueue
import android.content.Context
import android.os.Bundle
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.RelativeLayout
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
import androidx.work.WorkManager
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.adapter.ActiveDownloadAdapter
import com.deniscerri.ytdlnis.adapter.QueuedDownloadAdapter
import com.deniscerri.ytdlnis.database.dao.CommandTemplateDao
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.ui.downloadcard.*
import com.deniscerri.ytdlnis.util.NotificationUtil
import com.google.android.material.appbar.MaterialToolbar
import com.google.android.material.progressindicator.LinearProgressIndicator
import com.google.android.material.tabs.TabLayout
import com.yausername.youtubedl_android.YoutubeDL
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
class DownloadQueueActivity : AppCompatActivity(){

View file

@ -1,56 +1,49 @@
package com.deniscerri.ytdlnis.ui.downloadqueue
import android.app.Activity
import android.content.Intent
import android.content.DialogInterface
import android.content.res.Configuration
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.Window
import android.widget.AdapterView
import android.widget.AdapterView.OnItemClickListener
import android.widget.ArrayAdapter
import android.widget.AutoCompleteTextView
import android.widget.Button
import android.widget.LinearLayout
import android.widget.TextView
import androidx.activity.result.contract.ActivityResultContracts
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.work.WorkManager
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.adapter.ActiveDownloadAdapter
import com.deniscerri.ytdlnis.adapter.ErroredDownloadAdapter
import com.deniscerri.ytdlnis.adapter.GenericDownloadAdapter
import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.Format
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel.Type
import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding
import com.deniscerri.ytdlnis.ui.downloadcard.FormatSelectionBottomSheetDialog
import com.deniscerri.ytdlnis.ui.downloadcard.OnFormatClickListener
import com.deniscerri.ytdlnis.util.FileUtil
import com.deniscerri.ytdlnis.util.UiUtil
import com.google.android.material.chip.Chip
import com.google.android.material.progressindicator.LinearProgressIndicator
import com.google.android.material.textfield.TextInputLayout
import kotlinx.coroutines.launch
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import java.io.File
import java.sql.Date
import java.text.DateFormat
import java.text.SimpleDateFormat
import java.util.*
class ErroredDownloadsFragment() : Fragment(), ErroredDownloadAdapter.OnItemClickListener, OnItemClickListener {
class ErroredDownloadsFragment() : Fragment(), GenericDownloadAdapter.OnItemClickListener, OnItemClickListener {
private var _binding : FragmentHomeBinding? = null
private var fragmentView: View? = null
private var activity: Activity? = null
private lateinit var downloadViewModel : DownloadViewModel
private lateinit var erroredRecyclerView : RecyclerView
private lateinit var erroredDownloads : ErroredDownloadAdapter
lateinit var downloadItem: DownloadItem
private lateinit var erroredDownloads : GenericDownloadAdapter
private lateinit var items : List<DownloadItem>
private lateinit var fileUtil: FileUtil
private lateinit var uiUtil : UiUtil
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@ -60,6 +53,9 @@ class ErroredDownloadsFragment() : Fragment(), ErroredDownloadAdapter.OnItemClic
fragmentView = inflater.inflate(R.layout.fragment_generic_download_queue, container, false)
activity = getActivity()
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
items = listOf()
fileUtil = FileUtil()
uiUtil = UiUtil(fileUtil)
return fragmentView
}
@ -67,7 +63,7 @@ class ErroredDownloadsFragment() : Fragment(), ErroredDownloadAdapter.OnItemClic
super.onViewCreated(view, savedInstanceState)
erroredDownloads =
ErroredDownloadAdapter(
GenericDownloadAdapter(
this,
requireActivity()
)
@ -83,14 +79,110 @@ class ErroredDownloadsFragment() : Fragment(), ErroredDownloadAdapter.OnItemClic
}
downloadViewModel.erroredDownloads.observe(viewLifecycleOwner) {
items = it
erroredDownloads.submitList(it)
}
}
override fun onQueuedCancelClick(itemID: Long) {
override fun onActionButtonClick(itemID: Long) {
TODO("Not yet implemented")
}
override fun onCardClick(itemID: Long) {
val item = items.find { it.id == itemID } ?: return
val bottomSheet = BottomSheetDialog(requireContext())
bottomSheet.requestWindowFeature(Window.FEATURE_NO_TITLE)
bottomSheet.setContentView(R.layout.download_details_bottom_sheet)
val title = bottomSheet.findViewById<TextView>(R.id.bottom_sheet_title)
title!!.text = item.title
val author = bottomSheet.findViewById<TextView>(R.id.bottom_sheet_author)
author!!.text = item.author
val type = bottomSheet.findViewById<TextView>(R.id.type)
val formatNote = bottomSheet.findViewById<TextView>(R.id.format_note)
val codec = bottomSheet.findViewById<TextView>(R.id.codec)
val fileSize = bottomSheet.findViewById<TextView>(R.id.file_size)
val scheduledTime = bottomSheet.findViewById<LinearLayout>(R.id.scheduled_time_linear)
type!!.text = item.type.toString().uppercase()
if (item.format.format_note == "?") formatNote!!.visibility = View.GONE
else formatNote!!.text = item.format.format_note
val codecText =
if (item.format.encoding != "") {
item.format.encoding.uppercase()
}else if (item.format.vcodec != "none" && item.format.vcodec != ""){
item.format.vcodec.uppercase()
} else {
item.format.acodec.uppercase()
}
if (codecText == "" || codecText == "none"){
codec!!.visibility = View.GONE
}else{
codec!!.visibility = View.VISIBLE
codec.text = codecText
}
val fileSizeReadable = fileUtil.convertFileSize(item.format.filesize)
if (fileSizeReadable == "?") fileSize!!.visibility = View.GONE
else fileSize!!.text = fileSizeReadable
val link = bottomSheet.findViewById<Button>(R.id.bottom_sheet_link)
link!!.text = item.url
link.tag = itemID
link.setOnClickListener{
uiUtil.openLinkIntent(requireContext(), item.url, bottomSheet)
}
link.setOnLongClickListener{
uiUtil.copyLinkToClipBoard(requireContext(), item.url, bottomSheet)
true
}
if (item.downloadStartTime == 0L){
scheduledTime!!.visibility = View.GONE
}else{
val time = bottomSheet.findViewById<TextView>(R.id.time)
val cal = Calendar.getInstance()
val date = Date(item.downloadStartTime * 1000L)
cal.time = date
val day = cal[Calendar.DAY_OF_MONTH]
val month = cal.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.getDefault())
val year = cal[Calendar.YEAR]
val formatter: DateFormat = SimpleDateFormat("HH:mm", Locale.getDefault())
val timeString = formatter.format(date)
val formattedTime = "$day $month $year - $timeString"
time!!.text = formattedTime
}
val remove = bottomSheet.findViewById<Button>(R.id.bottomsheet_remove_button)
remove!!.tag = itemID
remove.setOnClickListener{
removeItem(item, bottomSheet)
}
bottomSheet.show()
bottomSheet.window!!.setLayout(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
}
private fun removeItem(item: DownloadItem, bottomSheet: BottomSheetDialog?){
bottomSheet?.hide()
val deleteDialog = MaterialAlertDialogBuilder(requireContext()!!)
deleteDialog.setTitle(getString(R.string.you_are_going_to_delete) + " \"" + item.title + "\"!")
deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
downloadViewModel.deleteDownload(item)
}
deleteDialog.show()
}
override fun onItemClick(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) {
TODO("Not yet implemented")
}

View file

@ -1,22 +1,16 @@
package com.deniscerri.ytdlnis.ui.downloadqueue
import android.app.Activity
import android.content.Intent
import android.content.res.Configuration
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.View.OnClickListener
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.AutoCompleteTextView
import android.view.Window
import android.widget.Button
import android.widget.LinearLayout
import android.widget.TextView
import androidx.activity.result.contract.ActivityResultContracts
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
@ -25,35 +19,35 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.work.WorkManager
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.adapter.ActiveDownloadAdapter
import com.deniscerri.ytdlnis.adapter.QueuedDownloadAdapter
import com.deniscerri.ytdlnis.adapter.GenericDownloadAdapter
import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.Format
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel.Type
import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding
import com.deniscerri.ytdlnis.ui.downloadcard.FormatSelectionBottomSheetDialog
import com.deniscerri.ytdlnis.ui.downloadcard.OnFormatClickListener
import com.deniscerri.ytdlnis.util.FileUtil
import com.deniscerri.ytdlnis.util.NotificationUtil
import com.deniscerri.ytdlnis.util.UiUtil
import com.google.android.material.chip.Chip
import com.google.android.material.progressindicator.LinearProgressIndicator
import com.google.android.material.textfield.TextInputLayout
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.yausername.youtubedl_android.YoutubeDL
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.sql.Date
import java.text.DateFormat
import java.text.SimpleDateFormat
import java.util.*
class QueuedDownloadsFragment() : Fragment(), QueuedDownloadAdapter.OnItemClickListener, OnClickListener {
class QueuedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickListener {
private var _binding : FragmentHomeBinding? = null
private var fragmentView: View? = null
private var activity: Activity? = null
private lateinit var downloadViewModel : DownloadViewModel
private lateinit var queuedRecyclerView : RecyclerView
private lateinit var queuedDownloads : QueuedDownloadAdapter
private lateinit var queuedDownloads : GenericDownloadAdapter
private lateinit var notificationUtil: NotificationUtil
private lateinit var items : List<DownloadItem>
private lateinit var fileUtil: FileUtil
private lateinit var uiUtil: UiUtil
override fun onCreateView(
inflater: LayoutInflater,
@ -65,6 +59,9 @@ class QueuedDownloadsFragment() : Fragment(), QueuedDownloadAdapter.OnItemClickL
activity = getActivity()
notificationUtil = NotificationUtil(requireContext())
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
items = listOf()
fileUtil = FileUtil()
uiUtil = UiUtil(fileUtil)
return fragmentView
}
@ -72,7 +69,7 @@ class QueuedDownloadsFragment() : Fragment(), QueuedDownloadAdapter.OnItemClickL
super.onViewCreated(view, savedInstanceState)
queuedDownloads =
QueuedDownloadAdapter(
GenericDownloadAdapter(
this,
requireActivity()
)
@ -88,11 +85,12 @@ class QueuedDownloadsFragment() : Fragment(), QueuedDownloadAdapter.OnItemClickL
}
downloadViewModel.queuedDownloads.observe(viewLifecycleOwner) {
items = it
queuedDownloads.submitList(it)
}
}
override fun onQueuedCancelClick(itemID: Long) {
override fun onActionButtonClick(itemID: Long) {
lifecycleScope.launch{
withContext(Dispatchers.IO){
downloadViewModel.deleteDownload(downloadViewModel.getItemByID(itemID))
@ -101,6 +99,86 @@ class QueuedDownloadsFragment() : Fragment(), QueuedDownloadAdapter.OnItemClickL
cancelDownload(itemID)
}
override fun onCardClick(itemID: Long) {
val item = items.find { it.id == itemID } ?: return
val bottomSheet = BottomSheetDialog(requireContext())
bottomSheet.requestWindowFeature(Window.FEATURE_NO_TITLE)
bottomSheet.setContentView(R.layout.download_details_bottom_sheet)
val title = bottomSheet.findViewById<TextView>(R.id.bottom_sheet_title)
title!!.text = item.title
val author = bottomSheet.findViewById<TextView>(R.id.bottom_sheet_author)
author!!.text = item.author
val type = bottomSheet.findViewById<TextView>(R.id.type)
val formatNote = bottomSheet.findViewById<TextView>(R.id.format_note)
val codec = bottomSheet.findViewById<TextView>(R.id.codec)
val fileSize = bottomSheet.findViewById<TextView>(R.id.file_size)
val scheduledTime = bottomSheet.findViewById<LinearLayout>(R.id.scheduled_time_linear)
type!!.text = item.type.toString().uppercase()
if (item.format.format_note == "?") formatNote!!.visibility = View.GONE
else formatNote!!.text = item.format.format_note
val codecText =
if (item.format.encoding != "") {
item.format.encoding.uppercase()
}else if (item.format.vcodec != "none" && item.format.vcodec != ""){
item.format.vcodec.uppercase()
} else {
item.format.acodec.uppercase()
}
if (codecText == "" || codecText == "none"){
codec!!.visibility = View.GONE
}else{
codec!!.visibility = View.VISIBLE
codec.text = codecText
}
val fileSizeReadable = fileUtil.convertFileSize(item.format.filesize)
if (fileSizeReadable == "?") fileSize!!.visibility = View.GONE
else fileSize!!.text = fileSizeReadable
val link = bottomSheet.findViewById<Button>(R.id.bottom_sheet_link)
link!!.text = item.url
link.tag = itemID
link.setOnClickListener{
uiUtil.openLinkIntent(requireContext(), item.url, bottomSheet)
}
link.setOnLongClickListener{
uiUtil.copyLinkToClipBoard(requireContext(), item.url, bottomSheet)
true
}
if (item.downloadStartTime == 0L){
scheduledTime!!.visibility = View.GONE
}else{
val time = bottomSheet.findViewById<TextView>(R.id.time)
val cal = Calendar.getInstance()
val date = Date(item.downloadStartTime)
cal.time = date
val day = cal[Calendar.DAY_OF_MONTH]
val month = cal.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.getDefault())
val year = cal[Calendar.YEAR]
val formatter: DateFormat = SimpleDateFormat("HH:mm", Locale.getDefault())
val timeString = formatter.format(date)
val formattedTime = "$day $month $year - $timeString"
time!!.text = formattedTime
}
val remove = bottomSheet.findViewById<Button>(R.id.bottomsheet_remove_button)
remove!!.visibility = View.GONE
bottomSheet.show()
bottomSheet.window!!.setLayout(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
}
private fun cancelDownload(itemID: Long){
val id = itemID.toInt()
YoutubeDL.getInstance().destroyProcessById(id.toString())
@ -108,9 +186,4 @@ class QueuedDownloadsFragment() : Fragment(), QueuedDownloadAdapter.OnItemClickL
notificationUtil.cancelDownloadNotification(id)
}
override fun onClick(p0: View?) {
TODO("Not yet implemented")
}
}

View file

@ -100,10 +100,8 @@ class TerminalActivity : AppCompatActivity() {
private fun startDownload(command: String?) {
var cmd: String = ""
if (command!!.contains("yt-dlp")) cmd = command.replace("yt-dlp", "")
else cmd = command
cmd = cmd.trim()
val cmd = if (command!!.contains("yt-dlp")) command.replace("yt-dlp", "")
else command
downloadID = System.currentTimeMillis().toInt()
@ -126,23 +124,20 @@ class TerminalActivity : AppCompatActivity() {
notify(downloadID, commandNotification)
}
}
val commandRegex = "(-\\S+)|(\\S+)"
val request = YoutubeDLRequest(emptyList())
val tempFolder = StringBuilder(context!!.cacheDir.absolutePath + """/${command}##terminal""")
val tempFolder = StringBuilder(context!!.cacheDir.absolutePath + """/${System.currentTimeMillis()}##terminal""")
val tempFileDir = File(tempFolder.toString())
tempFileDir.delete()
tempFileDir.mkdir()
Log.e(TAG, cmd)
val m = Pattern.compile(commandRegex).matcher(cmd)
while (m.find()) {
if (m.group(1) != null) {
request.addOption(m.group(1)!!)
} else {
request.addOption(m.group(2)!!)
}
}
request.addOption(
"--config-locations",
File(cacheDir, "config${System.currentTimeMillis()}.txt").apply {
writeText(cmd)
}.absolutePath
)
request.addOption("-P", tempFileDir.absolutePath)

View file

@ -1,22 +1,28 @@
package com.deniscerri.ytdlnis.ui.more.downloadLogs
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.os.Build
import android.os.Bundle
import android.os.FileObserver
import android.text.method.ScrollingMovementMethod
import android.view.View
import android.widget.ScrollView
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.widget.NestedScrollView
import com.deniscerri.ytdlnis.R
import com.google.android.material.appbar.MaterialToolbar
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
import java.io.File
class DownloadLogActivity : AppCompatActivity() {
private lateinit var content: TextView
private lateinit var contentScrollView : NestedScrollView
private lateinit var contentScrollView : ScrollView
private lateinit var topAppBar: MaterialToolbar
private lateinit var observer: FileObserver
private lateinit var copyLog : ExtendedFloatingActionButton
var context: Context? = null
public override fun onCreate(savedInstanceState: Bundle?) {
@ -30,8 +36,17 @@ class DownloadLogActivity : AppCompatActivity() {
}
content = findViewById(R.id.content)
content.movementMethod = ScrollingMovementMethod()
contentScrollView = findViewById(R.id.content_scrollview)
copyLog = findViewById(R.id.copy_log)
copyLog.setOnClickListener {
val clipboard: ClipboardManager =
getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
val clip: ClipData = ClipData.newPlainText("Download Log", content.text)
clipboard.setPrimaryClip(clip)
}
val path = intent.getStringExtra("path")
if (path == null) {
onBackPressedDispatcher.onBackPressed()
@ -57,6 +72,7 @@ class DownloadLogActivity : AppCompatActivity() {
runOnUiThread{
content.text = File(path).readText()
content.scrollTo(0, content.height)
contentScrollView.fullScroll(View.FOCUS_DOWN)
}
}
}

View file

@ -1,8 +1,11 @@
package com.deniscerri.ytdlnis.util
import android.app.Activity
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.text.Editable
import android.text.TextWatcher
import android.util.Log
@ -11,10 +14,12 @@ import android.view.ViewGroup
import android.view.Window
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.content.res.AppCompatResources
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat.getSystemService
import androidx.core.content.FileProvider
import androidx.lifecycle.LifecycleOwner
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.models.CommandTemplate
@ -25,6 +30,7 @@ import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.chip.Chip
import com.google.android.material.chip.ChipGroup
import com.google.android.material.textfield.TextInputLayout
import java.io.File
class UiUtil(private val fileUtil: FileUtil) {
fun populateFormatCard(formatCard : ConstraintLayout, chosenFormat: Format){
@ -165,5 +171,34 @@ class UiUtil(private val fileUtil: FileUtil) {
ViewGroup.LayoutParams.MATCH_PARENT
)
}
fun copyLinkToClipBoard(context: Context, url: String, bottomSheet: BottomSheetDialog?) {
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText(context.getString(R.string.url), url)
clipboard.setPrimaryClip(clip)
bottomSheet?.hide()
Toast.makeText(context, context.getString(R.string.link_copied_to_clipboard), Toast.LENGTH_SHORT)
.show()
}
fun openLinkIntent(context: Context, url: String, bottomSheet: BottomSheetDialog?) {
val i = Intent(Intent.ACTION_VIEW)
i.data = Uri.parse(url)
bottomSheet?.hide()
context.startActivity(i)
}
fun openFileIntent(fragmentContext: Context, downloadPath: String) {
val file = File(downloadPath)
val uri = FileProvider.getUriForFile(
fragmentContext,
fragmentContext.packageName + ".fileprovider",
file
)
val mime = fragmentContext.contentResolver.getType(uri)
val i = Intent(Intent.ACTION_VIEW)
i.setDataAndType(uri, mime)
i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
fragmentContext.startActivity(i)
}
}

View file

@ -184,15 +184,13 @@ class DownloadWorker(
request.addOption("-o", tempFileDir.absolutePath + "/${downloadItem.customFileNameTemplate}.%(ext)s")
}
DownloadViewModel.Type.command -> {
val commandRegex = "\"([^\"]*)\"|(-\\S+)"
val m = Pattern.compile(commandRegex).matcher(downloadItem.format.format_note)
while (m.find()) {
if (m.group(1) != null) {
request.addOption(m.group(1)!!)
} else {
request.addOption(m.group(2)!!)
}
}
request.addOption(
"--config-locations",
File(context.cacheDir, "config${System.currentTimeMillis()}.txt").apply {
writeText(downloadItem.format.format_note)
}.absolutePath
)
request.addOption("-P", tempFileDir.absolutePath)
}

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="?attr/colorAccent" android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM19,5L8,5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h11c1.1,0 2,-0.9 2,-2L21,7c0,-1.1 -0.9,-2 -2,-2zM19,21L8,21L8,7h11v14z"/>
</vector>

View file

@ -23,26 +23,37 @@
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
<ScrollView
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:id="@+id/content_scrollview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:fillViewport="true"
android:paddingBottom="150dp"
>
<TextView
android:id="@+id/content"
android:padding="10dp"
android:scrollHorizontally="true"
android:fontFamily="monospace"
android:textSize="15sp"
android:layout_width="match_parent"
android:layout_width="wrap_content"
android:textIsSelectable="true"
android:gravity="bottom"
android:layout_height="wrap_content" />
</androidx.core.widget.NestedScrollView>
</ScrollView>
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="@+id/copy_log"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:layout_gravity="bottom|end"
android:contentDescription="@string/copy_log"
android:text="@string/copy_log"
app:icon="@drawable/ic_copy"/>
<include layout="@layout/history_no_results"
android:visibility="gone" />

View file

@ -30,7 +30,7 @@
android:layout_height="wrap_content"
android:inputType="textMultiLine"
android:gravity="start"
android:maxLines="5" />
android:maxLines="10" />
<ScrollView
android:id="@+id/custom_command_scrollview"
@ -44,6 +44,7 @@
android:id="@+id/custom_command_output"
android:layout_width="match_parent"
android:textIsSelectable="true"
android:fontFamily="monospace"
android:gravity="bottom"
android:layout_height="wrap_content" />

View file

@ -15,7 +15,7 @@
android:layout_marginEnd="10dp"
android:textSize="15sp"
android:textStyle="bold"
app:layout_constraintEnd_toStartOf="@+id/divider"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
@ -26,28 +26,28 @@
android:layout_marginEnd="15dp"
android:maxLines="2"
android:textSize="12sp"
app:layout_constraintEnd_toStartOf="@+id/divider"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/title" />
<View
android:id="@+id/divider"
style="@style/Divider.Vertical"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/check"
app:layout_constraintStart_toEndOf="@+id/title"
app:layout_constraintTop_toTopOf="parent" />
<!-- <View-->
<!-- android:id="@+id/divider"-->
<!-- style="@style/Divider.Vertical"-->
<!-- android:layout_height="0dp"-->
<!-- app:layout_constraintBottom_toBottomOf="parent"-->
<!-- app:layout_constraintEnd_toStartOf="@+id/check"-->
<!-- app:layout_constraintStart_toEndOf="@+id/title"-->
<!-- app:layout_constraintTop_toTopOf="parent" />-->
<RadioButton
android:id="@+id/check"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:minWidth="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.558" />
<!-- <RadioButton-->
<!-- android:id="@+id/check"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:gravity="center"-->
<!-- android:minWidth="0dp"-->
<!-- app:layout_constraintBottom_toBottomOf="parent"-->
<!-- app:layout_constraintEnd_toEndOf="parent"-->
<!-- app:layout_constraintTop_toTopOf="parent"-->
<!-- app:layout_constraintVertical_bias="0.558" />-->
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -0,0 +1,183 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout android:id="@+id/downloads_element_bottom_sheet"
style="@style/Widget.Material3.BottomSheet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:orientation="vertical">
<TextView
android:id="@+id/bottom_sheet_title"
android:layout_width="wrap_content"
android:textSize="25sp"
android:textColor="?attr/colorOnSurface"
android:layout_height="wrap_content"
android:text="@string/app_name" />
<TextView
android:id="@+id/bottom_sheet_author"
android:layout_width="wrap_content"
android:paddingTop="5dp"
android:textSize="15sp"
android:layout_height="wrap_content"
android:text="@string/app_name" />
</LinearLayout>
<LinearLayout
android:id="@+id/linearLayout3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:orientation="horizontal"
android:layout_marginStart="20dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/url">
<TextView
android:id="@+id/type"
style="@style/Widget.Material3.FloatingActionButton.Large.Primary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="5dp"
android:background="?attr/colorAccent"
android:clickable="false"
android:gravity="center"
android:minWidth="30dp"
android:paddingHorizontal="10dp"
app:cornerRadius="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:id="@+id/format_note"
style="@style/Widget.Material3.FloatingActionButton.Large.Primary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="5dp"
android:background="?attr/colorPrimary"
android:clickable="false"
android:gravity="center"
android:minWidth="30dp"
android:paddingHorizontal="10dp"
app:cornerRadius="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:id="@+id/codec"
style="@style/Widget.Material3.FloatingActionButton.Large.Secondary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="5dp"
android:background="?attr/colorSecondary"
android:clickable="false"
android:gravity="center"
android:minWidth="30dp"
android:paddingHorizontal="10dp"
app:cornerRadius="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/file_size"
style="@style/Widget.Material3.FloatingActionButton.Large.Tertiary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="5dp"
android:background="?attr/colorSecondary"
android:clickable="false"
android:gravity="center"
android:minWidth="30dp"
android:paddingHorizontal="10dp"
app:cornerRadius="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</LinearLayout>
<LinearLayout
android:id="@+id/scheduled_time_linear"
android:layout_width="match_parent"
android:layout_margin="20dp"
android:orientation="horizontal"
android:layout_height="wrap_content">
<Button
android:id="@+id/bottomsheet_schedule_button"
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
app:icon="@drawable/ic_clock"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/bottomsheet_download_button"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15sp"
android:layout_marginEnd="5dp"
android:clickable="false"
android:gravity="center"
android:minWidth="30dp"
android:paddingHorizontal="10dp"
app:cornerRadius="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</LinearLayout>
<Button
style="@style/Widget.Material3.Button.TextButton.Icon"
android:id="@+id/bottom_sheet_link"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15sp"
android:layout_gravity="center"
app:icon="@drawable/ic_link"
android:text="@string/app_name" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:gravity="end"
android:layout_margin="10dp"
android:orientation="horizontal">
<Button
style="@style/Widget.Material3.Button.OutlinedButton.Icon"
android:id="@+id/bottomsheet_remove_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
app:icon="@drawable/ic_baseline_delete_outline_24"
android:text="@string/Remove" />
</LinearLayout>
</LinearLayout>
</FrameLayout>

View file

@ -22,7 +22,7 @@
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:maxLines="4"
android:maxLines="10"
android:inputType="textMultiLine"
android:layout_height="wrap_content"/>

View file

@ -9,30 +9,21 @@
<RelativeLayout
android:id="@+id/queued_download_relative_layout"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="H,3:1"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.card.MaterialCardView
android:id="@+id/queued_download_card_view"
android:id="@+id/download_card_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="10dp"
app:cardMaxElevation="12dp"
android:checkable="true"
app:strokeWidth="0dp"
app:cardPreventCornerOverlap="true"
android:layout_margin="10dp">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/image_view"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -42,53 +33,46 @@
android:id="@+id/title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:paddingStart="10dp"
android:paddingTop="10dp"
android:paddingEnd="10dp"
android:paddingBottom="10dp"
android:shadowColor="@color/black"
android:shadowDx="4"
android:shadowDy="4"
android:shadowRadius="2"
android:textColor="@color/white"
android:textSize="15sp"
android:textSize="16sp"
android:textStyle="bold"
app:layout_constraintEnd_toStartOf="@+id/queued_download_cancel"
app:layout_constraintEnd_toStartOf="@+id/action_button"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />
<TextView
android:id="@+id/url"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:textSize="12sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/title" />
<com.google.android.material.button.MaterialButton
android:id="@+id/queued_download_cancel"
android:id="@+id/action_button"
style="@style/Widget.Material3.ExtendedFloatingActionButton.Icon.Secondary"
android:layout_width="55dp"
android:layout_height="55dp"
android:layout_margin="15dp"
android:layout_margin="10dp"
app:cornerRadius="10dp"
app:icon="@drawable/ic_baseline_delete_outline_24"
app:icon="@drawable/ic_refresh"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/format_note"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:textSize="15sp"
android:shadowColor="@color/black"
android:shadowDx="4"
android:shadowDy="4"
android:shadowRadius="1.5"
android:textColor="@color/white"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/title"
app:layout_constraintVertical_bias="1.0" />
<LinearLayout
android:id="@+id/linearLayout3"
android:layout_width="wrap_content"
@ -96,9 +80,41 @@
android:layout_gravity="bottom"
android:orientation="horizontal"
android:padding="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/format_note">
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/url">
<TextView
style="@style/Widget.Material3.FloatingActionButton.Large.Primary"
android:id="@+id/type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="5dp"
android:background="?attr/colorPrimary"
android:clickable="false"
android:gravity="center"
android:minWidth="30dp"
android:paddingHorizontal="10dp"
app:cornerRadius="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:id="@+id/format_note"
style="@style/Widget.Material3.FloatingActionButton.Large.Primary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="5dp"
android:background="?attr/colorPrimary"
android:clickable="false"
android:gravity="center"
android:minWidth="30dp"
android:paddingHorizontal="10dp"
app:cornerRadius="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:id="@+id/codec"
@ -132,22 +148,6 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/time"
style="@style/Widget.Material3.FloatingActionButton.Large.Primary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="5dp"
android:background="?attr/colorPrimary"
android:clickable="false"
android:gravity="center"
android:minWidth="30dp"
android:paddingHorizontal="10dp"
app:cornerRadius="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</LinearLayout>

View file

@ -58,7 +58,7 @@
android:layout_height="wrap_content"
app:endIconMode="custom"
app:endIconDrawable="@drawable/ic_plus"
android:hint="@string/create_template"
android:hint="@string/create_shortcut"
style="@style/Widget.Material3.TextInputLayout.FilledBox">
<com.google.android.material.textfield.TextInputEditText

View file

@ -193,4 +193,8 @@
<string name="shortcuts_desc">Use commonly used commands to create templates</string>
<string name="cancelled">Cancelled</string>
<string name="errored">Errored</string>
<string name="copy_log">Copy log</string>
<string name="create_shortcut">Create Shortcut</string>
<string name="error_restarting_download">Error trying to restart the download</string>
<string name="delete_temp_file_too">Delete temporary files from the device</string>
</resources>