added context app bar for cancelled and errored downloads

This commit is contained in:
deniscerri 2023-04-28 21:45:03 +02:00
parent a6a4754bb2
commit d24b56835f
No known key found for this signature in database
GPG key ID: 95C43D517D830350
16 changed files with 384 additions and 51 deletions

View file

@ -1,5 +1,6 @@
package com.deniscerri.ytdlnis.adapter package com.deniscerri.ytdlnis.adapter
import android.annotation.SuppressLint
import android.app.Activity import android.app.Activity
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
@ -15,24 +16,29 @@ import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.deniscerri.ytdlnis.R import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.models.DownloadItem 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.repository.DownloadRepository
import com.deniscerri.ytdlnis.util.FileUtil import com.deniscerri.ytdlnis.util.FileUtil
import com.google.android.material.button.MaterialButton import com.google.android.material.button.MaterialButton
import com.google.android.material.card.MaterialCardView
import com.squareup.picasso.Picasso import com.squareup.picasso.Picasso
import java.util.ArrayList
class GenericDownloadAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<DownloadItem?, GenericDownloadAdapter.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 onItemClickListener: OnItemClickListener
private val activity: Activity private val activity: Activity
private var fileUtil: FileUtil private var fileUtil: FileUtil
private val checkedItems: ArrayList<Long>
init { init {
checkedItems = ArrayList()
this.onItemClickListener = onItemClickListener this.onItemClickListener = onItemClickListener
this.activity = activity this.activity = activity
fileUtil = FileUtil() fileUtil = FileUtil()
} }
class ViewHolder(itemView: View, onItemClickListener: OnItemClickListener?) : RecyclerView.ViewHolder(itemView) { class ViewHolder(itemView: View, onItemClickListener: OnItemClickListener?) : RecyclerView.ViewHolder(itemView) {
val cardView: FrameLayout val cardView: MaterialCardView
init { init {
cardView = itemView.findViewById(R.id.download_card_view) cardView = itemView.findViewById(R.id.download_card_view)
} }
@ -116,15 +122,75 @@ class GenericDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
actionButton.setOnClickListener { actionButton.setOnClickListener {
onItemClickListener.onActionButtonClick(item.id) onItemClickListener.onActionButtonClick(item.id)
} }
if (checkedItems.contains(item.id)) {
card.isChecked = true
card.strokeWidth = 5
} else {
card.isChecked = false
card.strokeWidth = 0
}
card.setOnClickListener { card.setOnClickListener {
onItemClickListener.onCardClick(item.id) if (checkedItems.size > 0) {
checkCard(card, item.id)
} else {
onItemClickListener.onCardClick(item.id)
}
}
card.setOnLongClickListener {
checkCard(card, item.id)
true
} }
} }
@SuppressLint("NotifyDataSetChanged")
fun clearCheckeditems() {
for (i in 0 until itemCount){
val item = getItem(i)
if (checkedItems.find { it == item?.id } != null){
checkedItems.remove(item?.id)
notifyItemChanged(i)
}
}
checkedItems.clear()
}
@SuppressLint("NotifyDataSetChanged")
fun checkAll(items: List<DownloadItem?>?){
checkedItems.clear()
checkedItems.addAll(items!!.map { it!!.id })
notifyDataSetChanged()
}
@SuppressLint("NotifyDataSetChanged")
fun invertSelected(items: List<DownloadItem?>?){
val invertedList = mutableListOf<Long>()
items?.forEach {
if (!checkedItems.contains(it!!.id)) invertedList.add(it.id)
}
checkedItems.clear()
checkedItems.addAll(invertedList)
notifyDataSetChanged()
}
private fun checkCard(card: MaterialCardView, itemID: Long) {
if (card.isChecked) {
card.strokeWidth = 0
checkedItems.remove(itemID)
} else {
card.strokeWidth = 5
checkedItems.add(itemID)
}
card.isChecked = !card.isChecked
onItemClickListener.onCardSelect(itemID, card.isChecked)
}
interface OnItemClickListener { interface OnItemClickListener {
fun onActionButtonClick(itemID: Long) fun onActionButtonClick(itemID: Long)
fun onCardClick(itemID: Long) fun onCardClick(itemID: Long)
fun onCardSelect(itemID: Long, isChecked: Boolean)
} }
companion object { companion object {

View file

@ -75,7 +75,8 @@ class ResultViewModel(application: Application) : AndroidViewModel(application)
} }
suspend fun parseQuery(inputQuery: String, resetResults: Boolean) : ArrayList<ResultItem?> { suspend fun parseQuery(inputQuery: String, resetResults: Boolean) : ArrayList<ResultItem?> {
if (resetResults) loadingItems.postValue(true) if (resetResults)
loadingItems.postValue(true)
val type = getQueryType(inputQuery) val type = getQueryType(inputQuery)
var res = arrayListOf<ResultItem?>() var res = arrayListOf<ResultItem?>()
return withContext(Dispatchers.IO){ return withContext(Dispatchers.IO){

View file

@ -15,7 +15,6 @@ class CancelDownloadNotificationReceiver : BroadcastReceiver() {
val notificationUtil = NotificationUtil(c) val notificationUtil = NotificationUtil(c)
YoutubeDL.getInstance().destroyProcessById(id.toString()) YoutubeDL.getInstance().destroyProcessById(id.toString())
WorkManager.getInstance(c).cancelUniqueWork(id.toString())
notificationUtil.cancelDownloadNotification(id) notificationUtil.cancelDownloadNotification(id)
} }
} }

View file

@ -191,6 +191,13 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
downloadAllFab.tag = "downloadAll" downloadAllFab.tag = "downloadAll"
downloadAllFab.setOnClickListener(this) downloadAllFab.setOnClickListener(this)
if (arguments?.getString("url") != null){
val url = requireArguments().getString("url")
if (inputQueries == null) inputQueries = mutableListOf()
searchBar?.text = url
inputQueries!!.add(url!!)
}
if (inputQueries != null) { if (inputQueries != null) {
resultViewModel.deleteAll() resultViewModel.deleteAll()
lifecycleScope.launch(Dispatchers.IO){ lifecycleScope.launch(Dispatchers.IO){
@ -470,7 +477,6 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
} }
}else{ }else{
resultViewModel.parseQueries(queryList) resultViewModel.parseQueries(queryList)
} }
} }
} }
@ -654,6 +660,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
super.onStop() super.onStop()
} }
companion object { companion object {
private const val TAG = "HomeFragment" private const val TAG = "HomeFragment"
} }

View file

@ -15,6 +15,7 @@ import android.widget.LinearLayout
import android.widget.Toast import android.widget.Toast
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2 import androidx.viewpager2.widget.ViewPager2
import com.deniscerri.ytdlnis.R import com.deniscerri.ytdlnis.R
@ -195,19 +196,23 @@ class DownloadBottomSheetDialog(private val resultItem: ResultItem, private val
if (quickDownload) { if (quickDownload) {
(updateItem.parent as LinearLayout).visibility = View.VISIBLE (updateItem.parent as LinearLayout).visibility = View.VISIBLE
updateItem.setOnClickListener { updateItem.setOnClickListener {
lifecycleScope.launch(Dispatchers.IO){ if (activity is ShareActivity) {
if (activity is ShareActivity) { val intent = Intent(context, ShareActivity::class.java)
val intent = Intent(context, ShareActivity::class.java) intent.action = Intent.ACTION_SEND
intent.action = Intent.ACTION_SEND intent.type = "text/plain"
intent.type = "text/plain" intent.putExtra(Intent.EXTRA_TEXT, resultItem.url)
intent.putExtra(Intent.EXTRA_TEXT, resultItem.url) intent.putExtra("quick_download", false)
intent.putExtra("quick_download", false) startActivity(intent)
startActivity(intent) dismiss()
dismiss() }else{
}else{ dismiss()
resultViewModel.parseQueries(listOf(resultItem.url)) val bundle = Bundle()
dismiss() bundle.putString("url", resultItem.url)
} findNavController().popBackStack(R.id.homeFragment, true)
findNavController().navigate(
R.id.homeFragment,
bundle
)
} }
} }
}else{ }else{

View file

@ -126,16 +126,16 @@ class ActiveDownloadsFragment() : Fragment(), ActiveDownloadAdapter.OnItemClickL
} }
private fun cancelDownload(itemID: Long){ private fun cancelDownload(itemID: Long){
val id = itemID.toInt()
YoutubeDL.getInstance().destroyProcessById(id.toString())
WorkManager.getInstance(requireContext()).cancelUniqueWork(id.toString())
notificationUtil.cancelDownloadNotification(id)
list.find { it.id == itemID }?.let { list.find { it.id == itemID }?.let {
it.status = DownloadRepository.Status.Cancelled.toString() it.status = DownloadRepository.Status.Cancelled.toString()
downloadViewModel.updateDownload(it) downloadViewModel.updateDownload(it)
} }
val id = itemID.toInt()
YoutubeDL.getInstance().destroyProcessById(id.toString())
WorkManager.getInstance(requireContext()).cancelUniqueWork(id.toString())
notificationUtil.cancelDownloadNotification(id)
} }
override fun onClick(p0: View?) { override fun onClick(p0: View?) {

View file

@ -7,22 +7,25 @@ import android.graphics.Canvas
import android.graphics.Color import android.graphics.Color
import android.os.Bundle import android.os.Bundle
import android.util.DisplayMetrics import android.util.DisplayMetrics
import android.view.LayoutInflater import android.view.*
import android.view.View
import android.view.ViewGroup
import android.view.Window
import android.widget.Button import android.widget.Button
import android.widget.TextView import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.view.ActionMode
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.forEach
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.deniscerri.ytdlnis.MainActivity
import com.deniscerri.ytdlnis.R import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.adapter.GenericDownloadAdapter import com.deniscerri.ytdlnis.adapter.GenericDownloadAdapter
import com.deniscerri.ytdlnis.database.models.DownloadItem 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.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding
import com.deniscerri.ytdlnis.ui.downloadcard.DownloadBottomSheetDialog import com.deniscerri.ytdlnis.ui.downloadcard.DownloadBottomSheetDialog
@ -35,7 +38,11 @@ import com.google.android.material.color.MaterialColors
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import it.xabaras.android.recyclerview.swipedecorator.RecyclerViewSwipeDecorator import it.xabaras.android.recyclerview.swipedecorator.RecyclerViewSwipeDecorator
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import java.util.ArrayList
class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickListener { class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickListener {
@ -45,6 +52,8 @@ class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClic
private lateinit var downloadViewModel : DownloadViewModel private lateinit var downloadViewModel : DownloadViewModel
private lateinit var cancelledRecyclerView : RecyclerView private lateinit var cancelledRecyclerView : RecyclerView
private lateinit var cancelledDownloads : GenericDownloadAdapter private lateinit var cancelledDownloads : GenericDownloadAdapter
private var selectedObjects: ArrayList<DownloadItem>? = null
private var actionMode : ActionMode? = null
private lateinit var items : MutableList<DownloadItem> private lateinit var items : MutableList<DownloadItem>
private lateinit var fileUtil: FileUtil private lateinit var fileUtil: FileUtil
private lateinit var uiUtil : UiUtil private lateinit var uiUtil : UiUtil
@ -57,6 +66,7 @@ class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClic
_binding = FragmentHomeBinding.inflate(inflater, container, false) _binding = FragmentHomeBinding.inflate(inflater, container, false)
fragmentView = inflater.inflate(R.layout.fragment_generic_download_queue, container, false) fragmentView = inflater.inflate(R.layout.fragment_generic_download_queue, container, false)
activity = getActivity() activity = getActivity()
selectedObjects = arrayListOf()
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java] downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
items = mutableListOf() items = mutableListOf()
fileUtil = FileUtil() fileUtil = FileUtil()
@ -213,6 +223,26 @@ class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClic
) )
} }
override fun onCardSelect(itemID: Long, isChecked: Boolean) {
val item = items.find { it.id == itemID }
if (isChecked) {
selectedObjects!!.add(item!!)
if (actionMode == null){
actionMode = (getActivity() as AppCompatActivity?)!!.startSupportActionMode(contextualActionBar)
}else{
actionMode!!.title = "${selectedObjects!!.size} ${getString(R.string.selected)}"
}
}
else {
selectedObjects!!.remove(item)
actionMode?.title = "${selectedObjects!!.size} ${getString(R.string.selected)}"
if (selectedObjects!!.isEmpty()){
actionMode?.finish()
}
}
}
private fun removeItem(item: DownloadItem, bottomSheet: BottomSheetDialog?){ private fun removeItem(item: DownloadItem, bottomSheet: BottomSheetDialog?){
bottomSheet?.hide() bottomSheet?.hide()
@ -225,6 +255,80 @@ class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClic
deleteDialog.show() deleteDialog.show()
} }
private val contextualActionBar = object : ActionMode.Callback {
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
mode!!.menuInflater.inflate(R.menu.cancelled_downloads_menu_context, menu)
mode.title = "${selectedObjects!!.size} ${getString(R.string.selected)}"
return true
}
override fun onPrepareActionMode(
mode: ActionMode?,
menu: Menu?
): Boolean {
return false
}
override fun onActionItemClicked(
mode: ActionMode?,
item: MenuItem?
): Boolean {
return when (item!!.itemId) {
R.id.delete_results -> {
val deleteDialog = MaterialAlertDialogBuilder(requireContext())
deleteDialog.setTitle(getString(R.string.you_are_going_to_delete_multiple_items))
deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
for (obj in selectedObjects!!){
downloadViewModel.deleteDownload(obj)
}
clearCheckedItems()
actionMode?.finish()
}
deleteDialog.show()
true
}
R.id.redownload -> {
runBlocking {
downloadViewModel.queueDownloads(selectedObjects!!.toMutableList())
actionMode?.finish()
}
true
}
R.id.select_all -> {
cancelledDownloads.checkAll(items)
selectedObjects?.clear()
items.forEach { selectedObjects?.add(it) }
mode?.title = getString(R.string.all_items_selected)
true
}
R.id.invert_selected -> {
cancelledDownloads.invertSelected(items)
val invertedList = arrayListOf<DownloadItem>()
items.forEach {
if (!selectedObjects?.contains(it)!!) invertedList.add(it)
}
selectedObjects?.clear()
selectedObjects?.addAll(invertedList)
actionMode!!.title = "${selectedObjects!!.size} ${getString(R.string.selected)}"
true
}
else -> false
}
}
override fun onDestroyActionMode(mode: ActionMode?) {
actionMode = null
clearCheckedItems()
}
}
private fun clearCheckedItems(){
cancelledDownloads.clearCheckeditems()
selectedObjects?.clear()
}
private var simpleCallback: ItemTouchHelper.SimpleCallback = private var simpleCallback: ItemTouchHelper.SimpleCallback =
object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) { object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) {
override fun onMove(recyclerView: RecyclerView,viewHolder: RecyclerView.ViewHolder,target: RecyclerView.ViewHolder override fun onMove(recyclerView: RecyclerView,viewHolder: RecyclerView.ViewHolder,target: RecyclerView.ViewHolder

View file

@ -8,14 +8,13 @@ import android.graphics.Canvas
import android.graphics.Color import android.graphics.Color
import android.os.Bundle import android.os.Bundle
import android.util.DisplayMetrics import android.util.DisplayMetrics
import android.view.LayoutInflater import android.view.*
import android.view.View
import android.view.ViewGroup
import android.view.Window
import android.widget.AdapterView import android.widget.AdapterView
import android.widget.AdapterView.OnItemClickListener import android.widget.AdapterView.OnItemClickListener
import android.widget.Button import android.widget.Button
import android.widget.TextView import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.view.ActionMode
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
@ -40,6 +39,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import it.xabaras.android.recyclerview.swipedecorator.RecyclerViewSwipeDecorator import it.xabaras.android.recyclerview.swipedecorator.RecyclerViewSwipeDecorator
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import java.util.ArrayList
class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickListener, OnItemClickListener { class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickListener, OnItemClickListener {
@ -50,6 +50,8 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL
private lateinit var erroredRecyclerView : RecyclerView private lateinit var erroredRecyclerView : RecyclerView
private lateinit var erroredDownloads : GenericDownloadAdapter private lateinit var erroredDownloads : GenericDownloadAdapter
private lateinit var items : MutableList<DownloadItem> private lateinit var items : MutableList<DownloadItem>
private var selectedObjects: ArrayList<DownloadItem>? = null
private var actionMode : ActionMode? = null
private lateinit var fileUtil: FileUtil private lateinit var fileUtil: FileUtil
private lateinit var uiUtil : UiUtil private lateinit var uiUtil : UiUtil
override fun onCreateView( override fun onCreateView(
@ -62,6 +64,7 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL
activity = getActivity() activity = getActivity()
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java] downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
items = mutableListOf() items = mutableListOf()
selectedObjects = arrayListOf()
fileUtil = FileUtil() fileUtil = FileUtil()
uiUtil = UiUtil(fileUtil) uiUtil = UiUtil(fileUtil)
return fragmentView return fragmentView
@ -213,6 +216,26 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL
) )
} }
override fun onCardSelect(itemID: Long, isChecked: Boolean) {
val item = items.find { it.id == itemID }
if (isChecked) {
selectedObjects!!.add(item!!)
if (actionMode == null){
actionMode = (getActivity() as AppCompatActivity?)!!.startSupportActionMode(contextualActionBar)
}else{
actionMode!!.title = "${selectedObjects!!.size} ${getString(R.string.selected)}"
}
}
else {
selectedObjects!!.remove(item)
actionMode?.title = "${selectedObjects!!.size} ${getString(R.string.selected)}"
if (selectedObjects!!.isEmpty()){
actionMode?.finish()
}
}
}
private fun removeItem(item: DownloadItem, bottomSheet: BottomSheetDialog?){ private fun removeItem(item: DownloadItem, bottomSheet: BottomSheetDialog?){
bottomSheet?.hide() bottomSheet?.hide()
val deleteDialog = MaterialAlertDialogBuilder(requireContext()) val deleteDialog = MaterialAlertDialogBuilder(requireContext())
@ -228,6 +251,81 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL
TODO("Not yet implemented") TODO("Not yet implemented")
} }
private val contextualActionBar = object : ActionMode.Callback {
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
mode!!.menuInflater.inflate(R.menu.cancelled_downloads_menu_context, menu)
mode.title = "${selectedObjects!!.size} ${getString(R.string.selected)}"
return true
}
override fun onPrepareActionMode(
mode: ActionMode?,
menu: Menu?
): Boolean {
return false
}
override fun onActionItemClicked(
mode: ActionMode?,
item: MenuItem?
): Boolean {
return when (item!!.itemId) {
R.id.delete_results -> {
val deleteDialog = MaterialAlertDialogBuilder(requireContext())
deleteDialog.setTitle(getString(R.string.you_are_going_to_delete_multiple_items))
deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
for (obj in selectedObjects!!){
downloadViewModel.deleteDownload(obj)
}
clearCheckedItems()
actionMode?.finish()
}
deleteDialog.show()
true
}
R.id.redownload -> {
runBlocking {
downloadViewModel.queueDownloads(selectedObjects!!.toMutableList())
actionMode?.finish()
}
true
}
R.id.select_all -> {
erroredDownloads.checkAll(items)
selectedObjects?.clear()
items.forEach { selectedObjects?.add(it) }
mode?.title = getString(R.string.all_items_selected)
true
}
R.id.invert_selected -> {
erroredDownloads.invertSelected(items)
val invertedList = arrayListOf<DownloadItem>()
items.forEach {
if (!selectedObjects?.contains(it)!!) invertedList.add(it)
}
selectedObjects?.clear()
selectedObjects?.addAll(invertedList)
actionMode!!.title = "${selectedObjects!!.size} ${getString(R.string.selected)}"
true
}
else -> false
}
}
override fun onDestroyActionMode(mode: ActionMode?) {
actionMode = null
clearCheckedItems()
}
}
private fun clearCheckedItems(){
erroredDownloads.clearCheckeditems()
selectedObjects?.clear()
}
private var simpleCallback: ItemTouchHelper.SimpleCallback = private var simpleCallback: ItemTouchHelper.SimpleCallback =
object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) { object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) {
override fun onMove(recyclerView: RecyclerView,viewHolder: RecyclerView.ViewHolder,target: RecyclerView.ViewHolder override fun onMove(recyclerView: RecyclerView,viewHolder: RecyclerView.ViewHolder,target: RecyclerView.ViewHolder

View file

@ -241,6 +241,10 @@ class QueuedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLi
) )
} }
override fun onCardSelect(itemID: Long, isChecked: Boolean) {
TODO("Not yet implemented")
}
private fun removeItem(itemID: Long){ private fun removeItem(itemID: Long){
val item = items.find { it.id == itemID } val item = items.find { it.id == itemID }
val deleteDialog = MaterialAlertDialogBuilder(requireContext()) val deleteDialog = MaterialAlertDialogBuilder(requireContext())

View file

@ -613,8 +613,10 @@ class InfoUtil(private val context: Context) {
author = jsonObject.getString("uploader") author = jsonObject.getString("uploader")
} }
var duration = "" var duration = ""
if (jsonObject.has("duration")) { runCatching {
duration = formatIntegerDuration(jsonObject.getInt("duration"), Locale.getDefault()) if (jsonObject.has("duration")) {
duration = formatIntegerDuration(jsonObject.getInt("duration"), Locale.getDefault())
}
} }
val url = jsonObject.getString("webpage_url") val url = jsonObject.getString("webpage_url")
var thumb: String? = "" var thumb: String? = ""

View file

@ -388,6 +388,12 @@ class DownloadWorker(
return Result.success() return Result.success()
} }
override fun onStopped() {
YoutubeDL.getInstance().destroyProcessById(itemId.toInt().toString())
super.onStopped()
}
@Throws(Exception::class) @Throws(Exception::class)
private fun moveFile(originDir: File, downLocation: String, progress: (progress: Int) -> Unit) : String{ private fun moveFile(originDir: File, downLocation: String, progress: (progress: Int) -> Unit) : String{
val fileUtil = FileUtil() val fileUtil = FileUtil()

View file

@ -131,6 +131,11 @@ class TerminalDownloadWorker(
return Result.success() return Result.success()
} }
override fun onStopped() {
YoutubeDL.getInstance().destroyProcessById(DownloadWorker.itemId.toInt().toString())
super.onStopped()
}
@Throws(Exception::class) @Throws(Exception::class)
private fun moveFile(originDir: File, downLocation: String, progress: (progress: Int) -> Unit) : String{ private fun moveFile(originDir: File, downLocation: String, progress: (progress: Int) -> Unit) : String{
val fileUtil = FileUtil() val fileUtil = FileUtil()

View file

@ -5,13 +5,13 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<FrameLayout <com.google.android.material.card.MaterialCardView
android:id="@+id/download_card_view" android:id="@+id/download_card_view"
android:layout_width="0dp" android:layout_width="0dp"
app:shapeAppearance="@style/ShapeAppearanceOverlay.Avatar" app:shapeAppearance="@style/ShapeAppearanceOverlay.Avatar"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingHorizontal="20dp" android:layout_marginHorizontal="20dp"
android:paddingVertical="10dp" android:layout_marginVertical="10dp"
android:checkable="true" android:checkable="true"
android:clickable="true" android:clickable="true"
android:focusable="true" android:focusable="true"
@ -193,6 +193,6 @@
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout> </com.google.android.material.card.MaterialCardView>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -1,4 +1,5 @@
<LinearLayout android:layout_width="match_parent" <androidx.constraintlayout.widget.ConstraintLayout xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="horizontal" android:orientation="horizontal"
@ -6,28 +7,33 @@
xmlns:android="http://schemas.android.com/apk/res/android"> xmlns:android="http://schemas.android.com/apk/res/android">
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/materialButton"
style="@style/Widget.Material3.Button.IconButton" style="@style/Widget.Material3.Button.IconButton"
app:iconSize="50dp" android:layout_width="wrap_content"
android:padding="0dp" android:layout_height="wrap_content"
app:iconTint="@null"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:insetBottom="0dp"
android:insetLeft="0dp" android:insetLeft="0dp"
android:insetTop="0dp" android:insetTop="0dp"
android:insetRight="0dp" android:insetRight="0dp"
android:layout_width="wrap_content" android:insetBottom="0dp"
android:layout_height="wrap_content" android:padding="0dp"
app:icon="@drawable/ic_app_icon" /> app:icon="@drawable/ic_app_icon"
app:iconSize="50dp"
app:iconTint="@null"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="20dp" android:layout_gravity="center_vertical"
android:layout_marginBottom="20dp" android:text="@string/app_name"
android:layout_marginStart="0dp"
android:textAppearance="?attr/textAppearanceHeadlineSmall" android:textAppearance="?attr/textAppearanceHeadlineSmall"
android:textColor="?attr/colorOnSurface" android:textColor="?attr/colorOnSurface"
android:text="@string/app_name" /> app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/materialButton"
app:layout_constraintTop_toTopOf="parent" />
</LinearLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -0,0 +1,29 @@
<menu 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"
tools:context=".MainActivity" >
<item
android:id="@+id/delete_results"
android:title="@string/remove_results"
android:icon="@drawable/baseline_delete_24"
app:showAsAction="ifRoom" />
<item
android:id="@+id/redownload"
android:title="@string/redownload"
android:icon="@drawable/ic_refresh"
app:showAsAction="ifRoom" />
<item
android:id="@+id/select_all"
android:title="@string/select_all"
app:showAsAction="never" />
<item
android:id="@+id/invert_selected"
android:title="@string/invert_selected"
app:showAsAction="never" />
</menu>

View file

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<paths> <paths>
<external-path name="external_files" path="."/> <external-path name="external_files" path="."/>
<root-path name="external_files" path="/storage/" />
<cache-path <cache-path
name="cache" name="cache"
path="." /> path="." />