added contextual menus for main and history fragments
This commit is contained in:
parent
9b2d24725f
commit
f5ad2aee1d
23 changed files with 348 additions and 123 deletions
|
|
@ -19,6 +19,7 @@ import android.widget.TextView
|
|||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.forEach
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.NavHostFragment
|
||||
|
|
@ -110,6 +111,14 @@ class MainActivity : AppCompatActivity() {
|
|||
bottomNav.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
fun disableBottomNavigation(){
|
||||
bottomNav.menu.forEach { it.isEnabled = false }
|
||||
}
|
||||
|
||||
fun enableBottomNavigation(){
|
||||
bottomNav.menu.forEach { it.isEnabled = true }
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
val incognitoHeader = findViewById<TextView>(R.id.incognito_header)
|
||||
|
|
|
|||
|
|
@ -167,13 +167,14 @@ class HomeAdapter(onItemClickListener: OnItemClickListener, activity: Activity)
|
|||
fun onCardClick(videoURL: String, add: Boolean)
|
||||
}
|
||||
|
||||
fun clearCheckedVideos() {
|
||||
// val size = checkedVideos.size
|
||||
// for (i in 0 until size) {
|
||||
// val position = checkedVideos[i]
|
||||
// notifyItemChanged(position)
|
||||
// }
|
||||
// checkedVideos.clear()
|
||||
fun checkAll(items: List<ResultItem?>?){
|
||||
checkedVideos.clear()
|
||||
checkedVideos.addAll(items!!.map { it!!.url })
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
fun clearCheckedItems(){
|
||||
checkedVideos.clear()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@ interface ResultDao {
|
|||
@Query("DELETE FROM results")
|
||||
suspend fun deleteAll()
|
||||
|
||||
@Query("DELETE FROM results WHERE id=:id")
|
||||
suspend fun delete(id: Long)
|
||||
|
||||
@Query("SELECT * FROM results WHERE url=:url LIMIT 1")
|
||||
fun getResultByURL(url: String) : ResultItem
|
||||
|
||||
|
|
|
|||
|
|
@ -108,6 +108,9 @@ class ResultRepository(private val resultDao: ResultDao, private val commandTemp
|
|||
return arrayListOf()
|
||||
}
|
||||
|
||||
suspend fun delete(item: ResultItem){
|
||||
resultDao.delete(item.id)
|
||||
}
|
||||
|
||||
suspend fun deleteAll(){
|
||||
itemCount.postValue(0)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import android.app.Application
|
|||
import androidx.lifecycle.*
|
||||
import com.deniscerri.ytdlnis.database.DBManager
|
||||
import com.deniscerri.ytdlnis.database.models.HistoryItem
|
||||
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||
import com.deniscerri.ytdlnis.database.repository.HistoryRepository
|
||||
import com.deniscerri.ytdlnis.database.repository.HistoryRepository.HistorySort
|
||||
import com.deniscerri.ytdlnis.database.repository.HistoryRepository.HistorySortType
|
||||
|
|
@ -103,4 +104,5 @@ class HistoryViewModel(application: Application) : AndroidViewModel(application)
|
|||
fun clearDeleted() = viewModelScope.launch(Dispatchers.IO) {
|
||||
repository.clearDeletedHistory()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -150,4 +150,10 @@ class ResultViewModel(application: Application) : AndroidViewModel(application)
|
|||
fun getSearchHistory() : List<SearchHistoryItem> {
|
||||
return searchHistoryRepository.getAll()
|
||||
}
|
||||
|
||||
fun deleteSelected(selectedItems : List<ResultItem>) = viewModelScope.launch(Dispatchers.IO) {
|
||||
selectedItems.forEach {
|
||||
repository.delete(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -10,16 +10,14 @@ import android.graphics.Color
|
|||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.text.InputType
|
||||
import android.util.Log
|
||||
import android.view.*
|
||||
import android.view.View.*
|
||||
import android.widget.*
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.text.TextUtilsCompat
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.children
|
||||
import androidx.core.view.forEach
|
||||
import androidx.core.widget.addTextChangedListener
|
||||
|
|
@ -29,7 +27,6 @@ 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.MainActivity
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.adapter.HomeAdapter
|
||||
|
|
@ -58,9 +55,7 @@ import java.util.*
|
|||
|
||||
|
||||
class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickListener {
|
||||
private var inputQuery: String? = null
|
||||
private var inputQueries: MutableList<String>? = null
|
||||
private var inputQueriesLength = 0
|
||||
private var homeAdapter: HomeAdapter? = null
|
||||
|
||||
private var searchSuggestions: ScrollView? = null
|
||||
|
|
@ -77,7 +72,6 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
|
|||
private lateinit var resultViewModel : ResultViewModel
|
||||
private lateinit var downloadViewModel : DownloadViewModel
|
||||
|
||||
private var downloading = false
|
||||
private var fragmentView: View? = null
|
||||
private var activity: Activity? = null
|
||||
private var mainActivity: MainActivity? = null
|
||||
|
|
@ -94,9 +88,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
|
|||
private var quickLaunchSheet = false
|
||||
private var sharedPreferences: SharedPreferences? = null
|
||||
private var _binding : FragmentHomeBinding? = null
|
||||
|
||||
private var workManager: WorkManager? = null
|
||||
|
||||
private var actionMode: ActionMode? = null
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
|
|
@ -106,7 +98,6 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
|
|||
activity = getActivity()
|
||||
mainActivity = activity as MainActivity?
|
||||
quickLaunchSheet = false
|
||||
|
||||
return fragmentView
|
||||
}
|
||||
|
||||
|
|
@ -233,7 +224,24 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
|
|||
textView.text = getString(R.string.link_you_copied)
|
||||
textView.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_language, 0, 0, 0)
|
||||
val mb = linkYouCopied.findViewById<ImageButton>(R.id.set_search_query_button)
|
||||
mb.visibility = INVISIBLE
|
||||
mb.setImageResource(R.drawable.ic_plus)
|
||||
|
||||
mb.setOnClickListener {
|
||||
val present = queriesChipGroup!!.children.firstOrNull { (it as Chip).text.toString() == clip.toString() }
|
||||
if (present == null) {
|
||||
val chip = layoutinflater!!.inflate(R.layout.input_chip, queriesChipGroup, false) as Chip
|
||||
chip.text = clip.toString()
|
||||
chip.chipBackgroundColor = ColorStateList.valueOf(MaterialColors.getColor(requireContext(), R.attr.colorSecondaryContainer, Color.BLACK))
|
||||
chip.setOnClickListener {
|
||||
queriesChipGroup!!.removeView(chip)
|
||||
}
|
||||
queriesChipGroup!!.addView(chip)
|
||||
}
|
||||
if (queriesChipGroup!!.childCount == 0) queriesConstraint.visibility = GONE
|
||||
else queriesConstraint.visibility = VISIBLE
|
||||
searchView.editText.setText("")
|
||||
linkYouCopied.visibility = GONE
|
||||
}
|
||||
|
||||
textView.setOnClickListener {
|
||||
searchView.setText(clip.toString())
|
||||
|
|
@ -485,20 +493,23 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
|
|||
|
||||
override fun onCardClick(videoURL: String, add: Boolean) {
|
||||
val item = resultsList?.find { it -> it?.url == videoURL }
|
||||
if (add) selectedObjects!!.add(item!!) else selectedObjects!!.remove(item)
|
||||
if (selectedObjects!!.size > 1) {
|
||||
downloadAllFabCoordinator!!.visibility = GONE
|
||||
downloadFabs!!.visibility = VISIBLE
|
||||
if (add) {
|
||||
selectedObjects!!.add(item!!)
|
||||
if (actionMode == null){
|
||||
actionMode = (getActivity() as AppCompatActivity?)!!.startSupportActionMode(contextualActionBar)
|
||||
|
||||
}else{
|
||||
actionMode!!.title = "${selectedObjects!!.size} ${getString(R.string.selected)}"
|
||||
}
|
||||
} else {
|
||||
downloadFabs!!.visibility = GONE
|
||||
if(resultsList!!.size > 1){
|
||||
if (resultsList!![1]!!.playlistTitle.isNotEmpty() && resultsList!![1]!!.playlistTitle != getString(R.string.trendingPlaylist)){
|
||||
downloadAllFabCoordinator!!.visibility = VISIBLE
|
||||
}else{
|
||||
downloadAllFabCoordinator!!.visibility = GONE
|
||||
}
|
||||
selectedObjects!!.remove(item)
|
||||
actionMode?.title = "${selectedObjects!!.size} ${getString(R.string.selected)}"
|
||||
if (selectedObjects!!.isEmpty()){
|
||||
actionMode?.finish()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
override fun onClick(v: View) {
|
||||
|
|
@ -506,19 +517,6 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
|
|||
v.tag.toString()
|
||||
} catch (e: Exception) {""}
|
||||
if (viewIdName.isNotEmpty()) {
|
||||
if (viewIdName == "downloadSelected") {
|
||||
lifecycleScope.launch {
|
||||
val downloadList = withContext(Dispatchers.IO){
|
||||
downloadViewModel.turnResultItemsToDownloadItems(selectedObjects!!)
|
||||
}
|
||||
if (sharedPreferences!!.getBoolean("download_card", true)) {
|
||||
val bottomSheet = DownloadMultipleBottomSheetDialog(downloadList.toMutableList())
|
||||
bottomSheet.show(parentFragmentManager, "downloadMultipleSheet")
|
||||
} else {
|
||||
downloadViewModel.queueDownloads(downloadList)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (viewIdName == "downloadAll") {
|
||||
lifecycleScope.launch {
|
||||
val downloadList = withContext(Dispatchers.IO){
|
||||
|
|
@ -535,6 +533,94 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
|
|||
}
|
||||
}
|
||||
|
||||
private val contextualActionBar = object : ActionMode.Callback {
|
||||
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
|
||||
mode!!.menuInflater.inflate(R.menu.main_menu_context, menu)
|
||||
mode.title = "${selectedObjects!!.size} ${getString(R.string.selected)}"
|
||||
(activity as MainActivity).disableBottomNavigation()
|
||||
searchBar?.isEnabled = false
|
||||
searchBar!!.menu.forEach { it.isEnabled = false }
|
||||
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(fragmentContext!!)
|
||||
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 ->
|
||||
if (selectedObjects?.size == resultsList?.size){
|
||||
resultViewModel.deleteAll()
|
||||
}else{
|
||||
resultViewModel.deleteSelected(selectedObjects!!.toList())
|
||||
}
|
||||
clearCheckedItems()
|
||||
actionMode?.finish()
|
||||
}
|
||||
deleteDialog.show()
|
||||
true
|
||||
}
|
||||
R.id.download -> {
|
||||
lifecycleScope.launch {
|
||||
val downloadList = withContext(Dispatchers.IO){
|
||||
downloadViewModel.turnResultItemsToDownloadItems(selectedObjects!!)
|
||||
}
|
||||
clearCheckedItems()
|
||||
actionMode?.finish()
|
||||
|
||||
if (sharedPreferences!!.getBoolean("download_card", true)) {
|
||||
val bottomSheet = DownloadMultipleBottomSheetDialog(downloadList.toMutableList())
|
||||
bottomSheet.show(parentFragmentManager, "downloadMultipleSheet")
|
||||
} else {
|
||||
downloadViewModel.queueDownloads(downloadList)
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
R.id.select_all -> {
|
||||
homeAdapter?.checkAll(resultsList)
|
||||
selectedObjects?.clear()
|
||||
resultsList?.forEach { selectedObjects?.add(it!!) }
|
||||
mode?.title = getString(R.string.all_items_selected)
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyActionMode(mode: ActionMode?) {
|
||||
actionMode = null
|
||||
(activity as MainActivity).enableBottomNavigation()
|
||||
clearCheckedItems()
|
||||
searchBar?.isEnabled = true
|
||||
searchBar!!.menu.forEach { it.isEnabled = true }
|
||||
}
|
||||
}
|
||||
|
||||
private fun clearCheckedItems(){
|
||||
homeAdapter?.clearCheckedItems()
|
||||
selectedObjects?.forEach {
|
||||
homeAdapter?.notifyItemChanged(resultsList!!.indexOf(it))
|
||||
}
|
||||
selectedObjects?.clear()
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
actionMode?.finish()
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "HomeFragment"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -399,6 +399,10 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val list
|
|||
chipGroup.removeView(chip)
|
||||
selectedCuts.remove(chip.text.toString())
|
||||
listener.onChangeCut(selectedCuts)
|
||||
if (selectedCuts.isEmpty()){
|
||||
player.stop()
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
deleteDialog.show()
|
||||
true
|
||||
|
|
@ -451,6 +455,10 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val list
|
|||
chipGroup.removeView(chip)
|
||||
selectedCuts.remove(chip.text.toString())
|
||||
listener.onChangeCut(selectedCuts)
|
||||
if (selectedCuts.isEmpty()){
|
||||
player.stop()
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
deleteDialog.show()
|
||||
true
|
||||
|
|
|
|||
|
|
@ -155,11 +155,10 @@ class DownloadAudioFragment(private var resultItem: ResultItem, private var curr
|
|||
}
|
||||
}
|
||||
formatCard.setOnClickListener{_ ->
|
||||
formats.forEach {
|
||||
Log.e("aa", it.toString())
|
||||
if (parentFragmentManager.findFragmentByTag("formatSheet") == null){
|
||||
val bottomSheet = FormatSelectionBottomSheetDialog(downloadItem, formats, listener)
|
||||
bottomSheet.show(parentFragmentManager, "formatSheet")
|
||||
}
|
||||
val bottomSheet = FormatSelectionBottomSheetDialog(downloadItem, formats, listener)
|
||||
bottomSheet.show(parentFragmentManager, "formatSheet")
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -265,8 +264,10 @@ class DownloadAudioFragment(private var resultItem: ResultItem, private var curr
|
|||
}
|
||||
}
|
||||
cut.setOnClickListener {
|
||||
val bottomSheet = CutVideoBottomSheetDialog(downloadItem, cutVideoListener)
|
||||
bottomSheet.show(parentFragmentManager, "cutVideoSheet")
|
||||
if (parentFragmentManager.findFragmentByTag("cutVideoSheet") == null){
|
||||
val bottomSheet = CutVideoBottomSheetDialog(downloadItem, cutVideoListener)
|
||||
bottomSheet.show(parentFragmentManager, "cutVideoSheet")
|
||||
}
|
||||
}
|
||||
|
||||
}catch (e : Exception){
|
||||
|
|
|
|||
|
|
@ -161,8 +161,10 @@ class DownloadVideoFragment(private val resultItem: ResultItem, private var curr
|
|||
}
|
||||
}
|
||||
formatCard.setOnClickListener{
|
||||
val bottomSheet = FormatSelectionBottomSheetDialog(downloadItem, formats, listener)
|
||||
bottomSheet.show(parentFragmentManager, "formatSheet")
|
||||
if (parentFragmentManager.findFragmentByTag("formatSheet") == null){
|
||||
val bottomSheet = FormatSelectionBottomSheetDialog(downloadItem, formats, listener)
|
||||
bottomSheet.show(parentFragmentManager, "formatSheet")
|
||||
}
|
||||
}
|
||||
|
||||
container?.isEnabled = true
|
||||
|
|
@ -295,8 +297,10 @@ class DownloadVideoFragment(private val resultItem: ResultItem, private var curr
|
|||
}
|
||||
}
|
||||
cut.setOnClickListener {
|
||||
val bottomSheet = CutVideoBottomSheetDialog(downloadItem, cutVideoListener)
|
||||
bottomSheet.show(parentFragmentManager, "cutVideoSheet")
|
||||
if (parentFragmentManager.findFragmentByTag("cutVideoSheet") == null){
|
||||
val bottomSheet = CutVideoBottomSheetDialog(downloadItem, cutVideoListener)
|
||||
bottomSheet.show(parentFragmentManager, "cutVideoSheet")
|
||||
}
|
||||
}
|
||||
|
||||
} catch (e: Exception) {
|
||||
|
|
|
|||
|
|
@ -13,10 +13,15 @@ import android.view.*
|
|||
import android.view.View.GONE
|
||||
import android.view.View.VISIBLE
|
||||
import android.widget.*
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.children
|
||||
import androidx.core.view.forEach
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.navigation.ui.AppBarConfiguration
|
||||
import androidx.navigation.ui.setupWithNavController
|
||||
|
|
@ -32,6 +37,7 @@ import com.deniscerri.ytdlnis.database.repository.HistoryRepository.HistorySort
|
|||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.HistoryViewModel
|
||||
import com.deniscerri.ytdlnis.databinding.FragmentHistoryBinding
|
||||
import com.deniscerri.ytdlnis.ui.downloadcard.DownloadMultipleBottomSheetDialog
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.deniscerri.ytdlnis.util.UiUtil
|
||||
import com.facebook.shimmer.ShimmerFrameLayout
|
||||
|
|
@ -43,7 +49,10 @@ import com.google.android.material.chip.Chip
|
|||
import com.google.android.material.chip.ChipGroup
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.File
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
|
@ -72,10 +81,10 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
private var historyList: List<HistoryItem?>? = null
|
||||
private var allhistoryList: List<HistoryItem?>? = null
|
||||
private var selectedObjects: ArrayList<HistoryItem>? = null
|
||||
private var deleteFab: ExtendedFloatingActionButton? = null
|
||||
private var fileUtil: FileUtil? = null
|
||||
private var uiUtil: UiUtil? = null
|
||||
private var _binding : FragmentHistoryBinding? = null
|
||||
private var actionMode : ActionMode? = null
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
|
|
@ -98,13 +107,8 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
noResults = view.findViewById(R.id.no_results)
|
||||
selectionChips = view.findViewById(R.id.history_selection_chips)
|
||||
websiteGroup = view.findViewById(R.id.website_chip_group)
|
||||
deleteFab = view.findViewById(R.id.delete_selected_fab)
|
||||
fileUtil = FileUtil()
|
||||
uiUtil = UiUtil(FileUtil())
|
||||
deleteFab?.tag = "deleteSelected"
|
||||
deleteFab?.setOnClickListener{
|
||||
removeSelectedItems()
|
||||
}
|
||||
uiHandler = Handler(Looper.getMainLooper())
|
||||
selectedObjects = ArrayList()
|
||||
|
||||
|
|
@ -363,27 +367,6 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
}
|
||||
|
||||
|
||||
private fun removeSelectedItems() {
|
||||
if (bottomSheet != null) bottomSheet!!.hide()
|
||||
val deleteFile = booleanArrayOf(false)
|
||||
val deleteDialog = MaterialAlertDialogBuilder(fragmentContext!!)
|
||||
deleteDialog.setTitle(getString(R.string.you_are_going_to_delete_multiple_items))
|
||||
deleteDialog.setMultiChoiceItems(
|
||||
arrayOf(getString(R.string.delete_files_too)),
|
||||
booleanArrayOf(false)
|
||||
) { _: DialogInterface?, _: Int, b: Boolean -> deleteFile[0] = b }
|
||||
deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
|
||||
deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
|
||||
for (item in selectedObjects!!){
|
||||
historyViewModel.delete(item, deleteFile[0])
|
||||
}
|
||||
selectedObjects = ArrayList()
|
||||
historyAdapter!!.clearCheckeditems()
|
||||
deleteFab!!.visibility = GONE
|
||||
}
|
||||
deleteDialog.show()
|
||||
}
|
||||
|
||||
private fun removeItem(item: HistoryItem) {
|
||||
if (bottomSheet != null) bottomSheet!!.hide()
|
||||
val deleteFile = booleanArrayOf(false)
|
||||
|
|
@ -429,7 +412,7 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
|
||||
if (isPresent){
|
||||
btn.setOnClickListener {
|
||||
uiUtil!!.shareFileIntent(requireContext(),item.downloadPath)
|
||||
uiUtil!!.shareFileIntent(requireContext(), listOf(item.downloadPath))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -514,12 +497,21 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
|
||||
override fun onCardSelect(itemID: Long, isChecked: Boolean) {
|
||||
val item = findItem(itemID)
|
||||
if (isChecked) selectedObjects!!.add(item!!)
|
||||
else selectedObjects!!.remove(item)
|
||||
if (selectedObjects!!.size > 1) {
|
||||
deleteFab!!.visibility = VISIBLE
|
||||
} else {
|
||||
deleteFab!!.visibility = GONE
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -527,6 +519,69 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
return historyList?.find { it?.id == id }
|
||||
}
|
||||
|
||||
private val contextualActionBar = object : ActionMode.Callback {
|
||||
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
|
||||
mode!!.menuInflater.inflate(R.menu.history_menu_context, menu)
|
||||
mode.title = "${selectedObjects!!.size} ${getString(R.string.selected)}"
|
||||
(activity as MainActivity).disableBottomNavigation()
|
||||
topAppBar!!.menu.forEach { it.isEnabled = false }
|
||||
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 deleteFile = booleanArrayOf(false)
|
||||
val deleteDialog = MaterialAlertDialogBuilder(fragmentContext!!)
|
||||
deleteDialog.setTitle(getString(R.string.you_are_going_to_delete_multiple_items))
|
||||
deleteDialog.setMultiChoiceItems(
|
||||
arrayOf(getString(R.string.delete_files_too)),
|
||||
booleanArrayOf(false)
|
||||
) { _: DialogInterface?, _: Int, b: Boolean -> deleteFile[0] = b }
|
||||
deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
|
||||
deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
|
||||
for (obj in selectedObjects!!){
|
||||
historyViewModel.delete(obj, deleteFile[0])
|
||||
}
|
||||
clearCheckedItems()
|
||||
actionMode?.finish()
|
||||
}
|
||||
deleteDialog.show()
|
||||
true
|
||||
}
|
||||
R.id.share -> {
|
||||
uiUtil?.shareFileIntent(requireContext(), selectedObjects!!.map { it.downloadPath })
|
||||
clearCheckedItems()
|
||||
actionMode?.finish()
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyActionMode(mode: ActionMode?) {
|
||||
actionMode = null
|
||||
(activity as MainActivity).enableBottomNavigation()
|
||||
clearCheckedItems()
|
||||
topAppBar!!.menu.forEach { it.isEnabled = true }
|
||||
}
|
||||
}
|
||||
|
||||
private fun clearCheckedItems(){
|
||||
historyAdapter?.clearCheckeditems()
|
||||
selectedObjects?.clear()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "historyFragment"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -644,7 +644,7 @@ class InfoUtil(context: Context) {
|
|||
} catch (e: Exception) {
|
||||
arrayOf(youtubeDLResponse.out)
|
||||
}
|
||||
return results.toMutableList()
|
||||
return results.filter { it!!.isNotEmpty() }.toMutableList()
|
||||
} catch (e: Exception) {
|
||||
return mutableListOf()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -226,19 +226,25 @@ class UiUtil(private val fileUtil: FileUtil) {
|
|||
fragmentContext.startActivity(i)
|
||||
}
|
||||
|
||||
fun shareFileIntent(fragmentContext: Context, downloadPath: String){
|
||||
val file = File(downloadPath)
|
||||
val uri = FileProvider.getUriForFile(
|
||||
fragmentContext,
|
||||
"com.deniscerri.ytdl.fileprovider",
|
||||
file
|
||||
)
|
||||
val mime = fragmentContext.contentResolver.getType(uri)
|
||||
fun shareFileIntent(fragmentContext: Context, paths: List<String>){
|
||||
val uris : ArrayList<Uri> = arrayListOf()
|
||||
paths.forEach {
|
||||
val file = File(it)
|
||||
if (! file.exists()) return@forEach
|
||||
val uri = FileProvider.getUriForFile(
|
||||
fragmentContext,
|
||||
"com.deniscerri.ytdl.fileprovider",
|
||||
file
|
||||
)
|
||||
uris.add(uri)
|
||||
}
|
||||
|
||||
|
||||
val shareIntent: Intent = Intent().apply {
|
||||
action = Intent.ACTION_SEND
|
||||
putExtra(Intent.EXTRA_STREAM, uri)
|
||||
type = mime
|
||||
action = Intent.ACTION_SEND_MULTIPLE
|
||||
putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris)
|
||||
type = "*/*"
|
||||
putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
|
||||
}
|
||||
fragmentContext.startActivity(Intent.createChooser(shareIntent, null))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ class DownloadWorker(
|
|||
when(type){
|
||||
DownloadViewModel.Type.audio -> {
|
||||
var audioQualityId : String = downloadItem.format.format_id
|
||||
if (audioQualityId.isBlank() || audioQualityId == "0" || audioQualityId == context.getString(R.string.best_quality)) audioQualityId = "bestaudio"
|
||||
if (audioQualityId.isBlank() || audioQualityId == "0" || audioQualityId == context.getString(R.string.best_quality)) audioQualityId = ""
|
||||
else if (audioQualityId == context.getString(R.string.worst_quality)) audioQualityId = "worstaudio"
|
||||
|
||||
if (audioQualityId.isNotBlank()){
|
||||
|
|
@ -157,7 +157,7 @@ class DownloadWorker(
|
|||
request.addOption("-x")
|
||||
}else{
|
||||
request.addOption("--remux-video", ext)
|
||||
request.addOption("--ppa", "VideoRemuxer:-c:a $codec")
|
||||
request.addOption("--ppa", "VideoRemuxer:-vn -c:a $codec")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
5
app/src/main/res/drawable/baseline_delete_24.xml
Normal file
5
app/src/main/res/drawable/baseline_delete_24.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<vector android:height="24dp"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="?android:colorAccent" android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"/>
|
||||
</vector>
|
||||
5
app/src/main/res/drawable/baseline_download_24.xml
Normal file
5
app/src/main/res/drawable/baseline_download_24.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<vector android:height="24dp"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="?android:colorAccent" android:pathData="M5,20h14v-2H5V20zM19,9h-4V3H9v6H5l7,7L19,9z"/>
|
||||
</vector>
|
||||
5
app/src/main/res/drawable/baseline_share_24.xml
Normal file
5
app/src/main/res/drawable/baseline_share_24.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<vector android:height="24dp"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="?android:colorAccent" android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z"/>
|
||||
</vector>
|
||||
|
|
@ -92,7 +92,7 @@
|
|||
style="@style/Widget.Material3.Button.TextButton.Icon"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="10dp"
|
||||
android:layout_margin="10dp"
|
||||
android:singleLine="true"
|
||||
android:text="@string/app_name"
|
||||
android:textSize="15sp"
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@
|
|||
style="@style/Widget.Material3.Button.TextButton.Icon"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="10dp"
|
||||
android:layout_margin="10dp"
|
||||
android:singleLine="true"
|
||||
android:text="@string/app_name"
|
||||
android:textSize="15sp"
|
||||
|
|
|
|||
|
|
@ -125,25 +125,6 @@
|
|||
|
||||
</androidx.recyclerview.widget.RecyclerView>
|
||||
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/delete_selected_coordinator"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
android:id="@+id/delete_selected_fab"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:visibility="gone"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:text="@string/delete_selected"
|
||||
app:icon="@drawable/ic_delete_all"/>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
|
||||
<include layout="@layout/history_no_results"
|
||||
android:visibility="gone" />
|
||||
|
||||
|
|
|
|||
19
app/src/main/res/menu/history_menu_context.xml
Normal file
19
app/src/main/res/menu/history_menu_context.xml
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<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/share"
|
||||
android:icon="@drawable/baseline_share_24"
|
||||
app:showAsAction="ifRoom"
|
||||
android:title="@string/share" />
|
||||
|
||||
</menu>
|
||||
|
||||
24
app/src/main/res/menu/main_menu_context.xml
Normal file
24
app/src/main/res/menu/main_menu_context.xml
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<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/download"
|
||||
android:title="@string/download"
|
||||
android:icon="@drawable/baseline_download_24"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
<item
|
||||
android:id="@+id/select_all"
|
||||
android:title="@string/select_all"
|
||||
app:showAsAction="never" />
|
||||
|
||||
</menu>
|
||||
|
||||
|
|
@ -195,4 +195,6 @@
|
|||
<string name="add_template_first">You need to have at least one command template created!</string>
|
||||
<string name="formatid_copied_to_clipboard">Format ID copied to clipboard</string>
|
||||
<string name="suggested">Suggested</string>
|
||||
<string name="select_all">Select All</string>
|
||||
<string name="share">Share</string>
|
||||
</resources>
|
||||
Loading…
Reference in a new issue