From a1655810f01df2e16773c52a4345bd4baf7ab40f Mon Sep 17 00:00:00 2001 From: deniscerri <64997243+deniscerri@users.noreply.github.com> Date: Thu, 20 Apr 2023 22:35:47 +0200 Subject: [PATCH] added swipes for download cards --- app/build.gradle | 1 + .../com/deniscerri/ytdlnis/MainActivity.kt | 13 +++ .../database/viewmodel/ResultViewModel.kt | 26 +++--- .../com/deniscerri/ytdlnis/ui/HomeFragment.kt | 4 +- .../DownloadMultipleBottomSheetDialog.kt | 73 ++++++++++++++++ .../downloads/CancelledDownloadsFragment.kt | 85 +++++++++++++++++-- .../ui/downloads/ErroredDownloadsFragment.kt | 78 ++++++++++++++++- .../ui/downloads/QueuedDownloadsFragment.kt | 79 ++++++++++++++++- .../ytdlnis/ui/more/TerminalActivity.kt | 23 ++++- .../ui/more/settings/SettingsFragment.kt | 9 ++ .../ytdlnis/work/TerminalDownloadWorker.kt | 2 +- .../baseline_add_to_home_screen_24.xml | 5 ++ app/src/main/res/values-sq-rAL/strings.xml | 4 + app/src/main/res/values/arrays.xml | 12 +++ app/src/main/res/values/strings.xml | 2 + app/src/main/res/xml/root_preferences.xml | 18 ++-- 16 files changed, 401 insertions(+), 33 deletions(-) create mode 100644 app/src/main/res/drawable/baseline_add_to_home_screen_24.xml diff --git a/app/build.gradle b/app/build.gradle index 97f94d83..34c4df04 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -179,5 +179,6 @@ dependencies { implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1" implementation "com.google.android.exoplayer:exoplayer:2.18.5" + implementation 'it.xabaras.android:recyclerview-swipedecorator:1.4' } diff --git a/app/src/main/java/com/deniscerri/ytdlnis/MainActivity.kt b/app/src/main/java/com/deniscerri/ytdlnis/MainActivity.kt index e89b4014..985826d5 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/MainActivity.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/MainActivity.kt @@ -1,6 +1,7 @@ package com.deniscerri.ytdlnis import android.Manifest +import android.app.Activity import android.content.Context import android.content.DialogInterface import android.content.Intent @@ -82,6 +83,18 @@ class MainActivity : AppCompatActivity() { if (isImeVisible) View.GONE else View.VISIBLE view.onApplyWindowInsets(windowInsets) } + var sharedPreferences = getSharedPreferences("root_preferences", Activity.MODE_PRIVATE) + + val startDestination = sharedPreferences.getString("start_destination", "") + val graph = navHostFragment.navController.navInflater.inflate(R.navigation.nav_graph) + when(startDestination) { + "History" -> graph.setStartDestination(R.id.historyFragment) + "More" -> graph.setStartDestination(R.id.moreFragment) + else -> graph.setStartDestination(R.id.homeFragment) + } + navHostFragment.navController.graph = graph + + navigationView.setupWithNavController(navController) navigationView.setOnItemReselectedListener { diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/ResultViewModel.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/ResultViewModel.kt index db4820b9..26ef2157 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/ResultViewModel.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/ResultViewModel.kt @@ -41,23 +41,25 @@ class ResultViewModel(application: Application) : AndroidViewModel(application) } fun checkTrending() = viewModelScope.launch(Dispatchers.IO){ - if (sharedPreferences.getBoolean("home_recommendations", false)){ - try { - val item = repository.getFirstResult() - if ( - item.playlistTitle == getApplication().getString(R.string.trendingPlaylist) - && item.creationTime < (System.currentTimeMillis() / 1000) - 86400 - ){ - getTrending() - } - }catch (e : Exception){ - e.printStackTrace() + try { + val item = repository.getFirstResult() + if ( + item.playlistTitle == getApplication().getString(R.string.trendingPlaylist) + && item.creationTime < (System.currentTimeMillis() / 1000) - 86400 + ){ getTrending() } + }catch (e : Exception){ + e.printStackTrace() + getTrending() } } fun getTrending() = viewModelScope.launch(Dispatchers.IO){ - repository.updateTrending() + if (sharedPreferences.getBoolean("home_recommendations", false)){ + repository.updateTrending() + }else{ + deleteAll() + } } suspend fun parseQueries(inputQueries: List){ if (inputQueries.size == 1){ diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/HomeFragment.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/HomeFragment.kt index 98b5d811..c062ddd0 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/HomeFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/HomeFragment.kt @@ -94,6 +94,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi private var sharedPreferences: SharedPreferences? = null private var _binding : FragmentHomeBinding? = null private var actionMode: ActionMode? = null + private var appBarLayout: AppBarLayout? = null override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? @@ -126,6 +127,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi //initViews shimmerCards = view.findViewById(R.id.shimmer_results_framelayout) searchBar = view.findViewById(R.id.search_bar) + appBarLayout = view.findViewById(R.id.home_appbarlayout) queriesChipGroup = view.findViewById(R.id.queries) searchSuggestions = view.findViewById(R.id.search_suggestions_scroll_view) searchSuggestionsLinearLayout = view.findViewById(R.id.search_suggestions_linear_layout) @@ -620,7 +622,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi clearCheckedItems() searchBar!!.isEnabled = true searchBar!!.menu.forEach { it.isEnabled = true } - searchBar?.expand(searchBar!!.parent as AppBarLayout) + searchBar?.expand(appBarLayout!!) } } diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadMultipleBottomSheetDialog.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadMultipleBottomSheetDialog.kt index 91d6f219..9a321e22 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadMultipleBottomSheetDialog.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadMultipleBottomSheetDialog.kt @@ -5,6 +5,8 @@ import android.app.Activity import android.app.Dialog import android.content.DialogInterface import android.content.Intent +import android.graphics.Canvas +import android.graphics.Color import android.os.Bundle import android.text.format.DateFormat import android.util.DisplayMetrics @@ -16,6 +18,7 @@ import androidx.activity.result.contract.ActivityResultContracts import androidx.core.view.get import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope +import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.deniscerri.ytdlnis.R @@ -34,6 +37,9 @@ import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.google.android.material.button.MaterialButton +import com.google.android.material.color.MaterialColors +import com.google.android.material.snackbar.Snackbar +import it.xabaras.android.recyclerview.swipedecorator.RecyclerViewSwipeDecorator import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking @@ -91,6 +97,8 @@ class DownloadMultipleBottomSheetDialog(private var results: List, recyclerView = view.findViewById(R.id.downloadMultipleRecyclerview) recyclerView.layoutManager = LinearLayoutManager(requireContext()) recyclerView.adapter = listAdapter + val itemTouchHelper = ItemTouchHelper(simpleCallback) + itemTouchHelper.attachToRecyclerView(recyclerView) listAdapter.submitList(items.toList()) val scheduleBtn = view.findViewById(R.id.bottomsheet_schedule_button) @@ -332,5 +340,70 @@ class DownloadMultipleBottomSheetDialog(private var results: List, listAdapter.submitList(items.toList()) } + private var simpleCallback: ItemTouchHelper.SimpleCallback = + object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT) { + override fun onMove(recyclerView: RecyclerView,viewHolder: RecyclerView.ViewHolder,target: RecyclerView.ViewHolder + ): Boolean { + return false + } + + override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { + val position = viewHolder.bindingAdapterPosition + when (direction) { + ItemTouchHelper.LEFT -> { + val deletedItem = items[position] + items.remove(deletedItem) + listAdapter.submitList(items.toList()) + Snackbar.make(recyclerView, getString(R.string.you_are_going_to_delete) + ": " + deletedItem.title, Snackbar.LENGTH_LONG) + .setAction(getString(R.string.undo)) { + items.add(position, deletedItem) + listAdapter.submitList(items.toList()) + }.show() + } + + } + } + + override fun onChildDraw( + c: Canvas, + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder, + dX: Float, + dY: Float, + actionState: Int, + isCurrentlyActive: Boolean + ) { + RecyclerViewSwipeDecorator.Builder( + requireContext(), + c, + recyclerView, + viewHolder, + dX, + dY, + actionState, + isCurrentlyActive + ) + .addSwipeLeftBackgroundColor(Color.RED) + .addSwipeLeftActionIcon(R.drawable.baseline_delete_24) + .addSwipeRightBackgroundColor( + MaterialColors.getColor( + requireContext(), + R.attr.colorOnSurfaceInverse, Color.TRANSPARENT + ) + ) + .create() + .decorate() + super.onChildDraw( + c, + recyclerView, + viewHolder!!, + dX, + dY, + actionState, + isCurrentlyActive + ) + } + } + } diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/CancelledDownloadsFragment.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/CancelledDownloadsFragment.kt index d50297e2..0ed7479f 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/CancelledDownloadsFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/CancelledDownloadsFragment.kt @@ -3,8 +3,9 @@ package com.deniscerri.ytdlnis.ui.downloads import android.app.Activity import android.content.DialogInterface import android.content.res.Configuration +import android.graphics.Canvas +import android.graphics.Color import android.os.Bundle -import android.util.DisplayMetrics import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -16,7 +17,7 @@ import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModelProvider import androidx.recyclerview.widget.GridLayoutManager -import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.RecyclerView import com.deniscerri.ytdlnis.R import com.deniscerri.ytdlnis.adapter.GenericDownloadAdapter @@ -28,7 +29,10 @@ import com.deniscerri.ytdlnis.util.UiUtil import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.button.MaterialButton import com.google.android.material.chip.Chip +import com.google.android.material.color.MaterialColors import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.google.android.material.snackbar.Snackbar +import it.xabaras.android.recyclerview.swipedecorator.RecyclerViewSwipeDecorator import kotlinx.coroutines.runBlocking @@ -39,7 +43,7 @@ class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClic private lateinit var downloadViewModel : DownloadViewModel private lateinit var cancelledRecyclerView : RecyclerView private lateinit var cancelledDownloads : GenericDownloadAdapter - private lateinit var items : List + private lateinit var items : MutableList private lateinit var fileUtil: FileUtil private lateinit var uiUtil : UiUtil @@ -52,7 +56,7 @@ class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClic fragmentView = inflater.inflate(R.layout.fragment_generic_download_queue, container, false) activity = getActivity() downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java] - items = listOf() + items = mutableListOf() fileUtil = FileUtil() uiUtil = UiUtil(fileUtil) return fragmentView @@ -69,6 +73,8 @@ class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClic cancelledRecyclerView = view.findViewById(R.id.download_recyclerview) cancelledRecyclerView.adapter = cancelledDownloads + val itemTouchHelper = ItemTouchHelper(simpleCallback) + itemTouchHelper.attachToRecyclerView(cancelledRecyclerView) val landScape = resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE && ! resources.getBoolean(R.bool.isTablet) if (landScape){ @@ -77,7 +83,7 @@ class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClic if (resources.getBoolean(R.bool.isTablet)) cancelledRecyclerView.layoutManager = GridLayoutManager(context, 3) downloadViewModel.cancelledDownloads.observe(viewLifecycleOwner) { - items = it + items = it.toMutableList() cancelledDownloads.submitList(it) } } @@ -202,4 +208,73 @@ class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClic } deleteDialog.show() } + + private var simpleCallback: ItemTouchHelper.SimpleCallback = + object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) { + override fun onMove(recyclerView: RecyclerView,viewHolder: RecyclerView.ViewHolder,target: RecyclerView.ViewHolder + ): Boolean { + return false + } + + override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { + val position = viewHolder.bindingAdapterPosition + when (direction) { + ItemTouchHelper.LEFT -> { + val deletedItem = items[position] + items.remove(deletedItem) + cancelledDownloads.submitList(items.toList()) + Snackbar.make(cancelledRecyclerView, getString(R.string.you_are_going_to_delete) + ": " + deletedItem.title, Snackbar.LENGTH_LONG) + .setAction(getString(R.string.undo)) { + items.add(position, deletedItem) + cancelledDownloads.submitList(items.toList()) + }.show() + } + ItemTouchHelper.RIGHT -> { + onActionButtonClick(items[position].id) + } + } + } + + override fun onChildDraw( + c: Canvas, + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder, + dX: Float, + dY: Float, + actionState: Int, + isCurrentlyActive: Boolean + ) { + RecyclerViewSwipeDecorator.Builder( + requireContext(), + c, + recyclerView, + viewHolder, + dX, + dY, + actionState, + isCurrentlyActive + ) + .addSwipeLeftBackgroundColor(Color.RED) + .addSwipeLeftActionIcon(R.drawable.baseline_delete_24) + .addSwipeRightBackgroundColor( + MaterialColors.getColor( + requireContext(), + R.attr.colorOnSurfaceInverse,Color.TRANSPARENT + ) + ) + .addSwipeRightActionIcon(R.drawable.ic_refresh) + .create() + .decorate() + super.onChildDraw( + c, + recyclerView, + viewHolder!!, + dX, + dY, + actionState, + isCurrentlyActive + ) + } + } + } \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/ErroredDownloadsFragment.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/ErroredDownloadsFragment.kt index 603f0a5c..94123a36 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/ErroredDownloadsFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/ErroredDownloadsFragment.kt @@ -4,6 +4,8 @@ import android.app.Activity import android.content.DialogInterface import android.content.Intent import android.content.res.Configuration +import android.graphics.Canvas +import android.graphics.Color import android.os.Bundle import android.util.DisplayMetrics import android.view.LayoutInflater @@ -18,6 +20,7 @@ import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModelProvider import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.deniscerri.ytdlnis.R @@ -31,7 +34,10 @@ import com.deniscerri.ytdlnis.util.UiUtil import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.button.MaterialButton import com.google.android.material.chip.Chip +import com.google.android.material.color.MaterialColors import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.google.android.material.snackbar.Snackbar +import it.xabaras.android.recyclerview.swipedecorator.RecyclerViewSwipeDecorator import kotlinx.coroutines.runBlocking @@ -42,7 +48,7 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL private lateinit var downloadViewModel : DownloadViewModel private lateinit var erroredRecyclerView : RecyclerView private lateinit var erroredDownloads : GenericDownloadAdapter - private lateinit var items : List + private lateinit var items : MutableList private lateinit var fileUtil: FileUtil private lateinit var uiUtil : UiUtil override fun onCreateView( @@ -54,7 +60,7 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL fragmentView = inflater.inflate(R.layout.fragment_generic_download_queue, container, false) activity = getActivity() downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java] - items = listOf() + items = mutableListOf() fileUtil = FileUtil() uiUtil = UiUtil(fileUtil) return fragmentView @@ -71,6 +77,8 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL erroredRecyclerView = view.findViewById(R.id.download_recyclerview) erroredRecyclerView.adapter = erroredDownloads + val itemTouchHelper = ItemTouchHelper(simpleCallback) + itemTouchHelper.attachToRecyclerView(erroredRecyclerView) val landScape = resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE && ! resources.getBoolean(R.bool.isTablet) if (landScape){ @@ -79,7 +87,7 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL if (resources.getBoolean(R.bool.isTablet)) erroredRecyclerView.layoutManager = GridLayoutManager(context, 3) downloadViewModel.erroredDownloads.observe(viewLifecycleOwner) { - items = it + items = it.toMutableList() erroredDownloads.submitList(it) } } @@ -205,5 +213,69 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL TODO("Not yet implemented") } + private var simpleCallback: ItemTouchHelper.SimpleCallback = + object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT) { + override fun onMove(recyclerView: RecyclerView,viewHolder: RecyclerView.ViewHolder,target: RecyclerView.ViewHolder + ): Boolean { + return false + } + + override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { + val position = viewHolder.bindingAdapterPosition + when (direction) { + ItemTouchHelper.LEFT -> { + val deletedItem = items[position] + items.remove(deletedItem) + erroredDownloads.submitList(items.toList()) + Snackbar.make(erroredRecyclerView, getString(R.string.you_are_going_to_delete) + ": " + deletedItem.title, Snackbar.LENGTH_LONG) + .setAction(getString(R.string.undo)) { + items.add(position, deletedItem) + erroredDownloads.submitList(items.toList()) + }.show() + } + + } + } + + override fun onChildDraw( + c: Canvas, + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder, + dX: Float, + dY: Float, + actionState: Int, + isCurrentlyActive: Boolean + ) { + RecyclerViewSwipeDecorator.Builder( + requireContext(), + c, + recyclerView, + viewHolder, + dX, + dY, + actionState, + isCurrentlyActive + ) + .addSwipeLeftBackgroundColor(Color.RED) + .addSwipeLeftActionIcon(R.drawable.baseline_delete_24) + .addSwipeRightBackgroundColor( + MaterialColors.getColor( + requireContext(), + R.attr.colorOnSurfaceInverse, Color.TRANSPARENT + ) + ) + .create() + .decorate() + super.onChildDraw( + c, + recyclerView, + viewHolder!!, + dX, + dY, + actionState, + isCurrentlyActive + ) + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/QueuedDownloadsFragment.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/QueuedDownloadsFragment.kt index c321b1ff..62d0f2cb 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/QueuedDownloadsFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/QueuedDownloadsFragment.kt @@ -2,6 +2,8 @@ package com.deniscerri.ytdlnis.ui.downloads import android.app.Activity import android.content.res.Configuration +import android.graphics.Canvas +import android.graphics.Color import android.os.Bundle import android.text.format.DateFormat import android.util.DisplayMetrics @@ -17,6 +19,7 @@ import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import androidx.work.WorkManager @@ -31,7 +34,10 @@ import com.deniscerri.ytdlnis.util.UiUtil import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.button.MaterialButton import com.google.android.material.chip.Chip +import com.google.android.material.color.MaterialColors +import com.google.android.material.snackbar.Snackbar import com.yausername.youtubedl_android.YoutubeDL +import it.xabaras.android.recyclerview.swipedecorator.RecyclerViewSwipeDecorator import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking @@ -48,7 +54,7 @@ class QueuedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLi private lateinit var queuedRecyclerView : RecyclerView private lateinit var queuedDownloads : GenericDownloadAdapter private lateinit var notificationUtil: NotificationUtil - private lateinit var items : List + private lateinit var items : MutableList private lateinit var fileUtil: FileUtil private lateinit var uiUtil: UiUtil @@ -62,7 +68,7 @@ class QueuedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLi activity = getActivity() notificationUtil = NotificationUtil(requireContext()) downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java] - items = listOf() + items = mutableListOf() fileUtil = FileUtil() uiUtil = UiUtil(fileUtil) return fragmentView @@ -79,6 +85,8 @@ class QueuedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLi queuedRecyclerView = view.findViewById(R.id.download_recyclerview) queuedRecyclerView.adapter = queuedDownloads + val itemTouchHelper = ItemTouchHelper(simpleCallback) + itemTouchHelper.attachToRecyclerView(queuedRecyclerView) val landScape = resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE && ! resources.getBoolean(R.bool.isTablet) if (landScape){ @@ -87,7 +95,7 @@ class QueuedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLi if (resources.getBoolean(R.bool.isTablet)) queuedRecyclerView.layoutManager = GridLayoutManager(context, 3) downloadViewModel.queuedDownloads.observe(viewLifecycleOwner) { - items = it + items = it.toMutableList() queuedDownloads.submitList(it) } } @@ -216,4 +224,69 @@ class QueuedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLi notificationUtil.cancelDownloadNotification(id) } + private var simpleCallback: ItemTouchHelper.SimpleCallback = + object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT) { + override fun onMove(recyclerView: RecyclerView,viewHolder: RecyclerView.ViewHolder,target: RecyclerView.ViewHolder + ): Boolean { + return false + } + + override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { + val position = viewHolder.bindingAdapterPosition + when (direction) { + ItemTouchHelper.LEFT -> { + val deletedItem = items[position] + cancelDownload(deletedItem.id) + Snackbar.make(queuedRecyclerView, getString(R.string.cancelled) + ": " + deletedItem.title, Snackbar.LENGTH_LONG) + .setAction(getString(R.string.undo)) { + lifecycleScope.launch(Dispatchers.IO) { + downloadViewModel.queueDownloads(listOf(deletedItem)) + } + }.show() + } + + } + } + + override fun onChildDraw( + c: Canvas, + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder, + dX: Float, + dY: Float, + actionState: Int, + isCurrentlyActive: Boolean + ) { + RecyclerViewSwipeDecorator.Builder( + requireContext(), + c, + recyclerView, + viewHolder, + dX, + dY, + actionState, + isCurrentlyActive + ) + .addSwipeLeftBackgroundColor(Color.RED) + .addSwipeLeftActionIcon(R.drawable.baseline_delete_24) + .addSwipeRightBackgroundColor( + MaterialColors.getColor( + requireContext(), + R.attr.colorOnSurfaceInverse, Color.TRANSPARENT + ) + ) + .create() + .decorate() + super.onChildDraw( + c, + recyclerView, + viewHolder!!, + dX, + dY, + actionState, + isCurrentlyActive + ) + } + } + } \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/more/TerminalActivity.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/more/TerminalActivity.kt index 226b4fcb..74b8e64f 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/more/TerminalActivity.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/more/TerminalActivity.kt @@ -8,6 +8,7 @@ import android.content.SharedPreferences import android.os.Build import android.os.Bundle import android.os.FileObserver +import android.os.Looper import android.util.Log import android.view.MenuItem import android.view.View @@ -21,6 +22,7 @@ import android.widget.TextView import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AppCompatActivity import androidx.constraintlayout.widget.ConstraintLayout +import androidx.core.view.forEach import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import androidx.work.* @@ -129,7 +131,6 @@ class TerminalActivity : AppCompatActivity() { input!!.visibility = View.GONE output!!.text = "${output!!.text}\n~ $ ${input!!.text}\n" showCancelFab() - downloadFile.appendText("~ $ ${input!!.text}\n") imm.hideSoftInputFromWindow(input?.windowToken, 0) startDownload( input!!.text.toString() @@ -149,7 +150,8 @@ class TerminalActivity : AppCompatActivity() { runOnUiThread{ try { val newText = downloadFile.readText() - output!!.text = newText + if (newText.isBlank()) return@runOnUiThread + output!!.append(newText) output!!.scrollTo(0, output!!.height) scrollView!!.fullScroll(View.FOCUS_DOWN) }catch (ignored: Exception) {} @@ -163,7 +165,8 @@ class TerminalActivity : AppCompatActivity() { runOnUiThread{ try { val newText = downloadFile.readText() - output!!.text = newText + if (newText.isBlank()) return@runOnUiThread + output!!.append(newText) output!!.scrollTo(0, output!!.height) scrollView!!.fullScroll(View.FOCUS_DOWN) }catch (ignored: Exception) {} @@ -183,7 +186,19 @@ class TerminalActivity : AppCompatActivity() { input!!.requestFocus() input!!.setSelection(input!!.text.length) hideCancelFab() + downloadFile.writeText("") } + val outputData = work.progress.getString("output") + if (!outputData.isNullOrBlank()){ + runOnUiThread{ + try { + output!!.append("\n$outputData") + output!!.scrollTo(0, output!!.height) + scrollView!!.fullScroll(View.FOCUS_DOWN) + }catch (ignored: Exception) {} + } + } + } } initMenu() @@ -227,10 +242,12 @@ class TerminalActivity : AppCompatActivity() { private fun hideCancelFab() { fab!!.text = getString(R.string.run_command) fab!!.setIconResource(R.drawable.ic_baseline_keyboard_arrow_right_24) + topAppBar!!.menu.forEach { it.isEnabled = true } } private fun showCancelFab() { fab!!.text = getString(R.string.cancel_download) fab!!.setIconResource(R.drawable.ic_cancel) + topAppBar!!.menu.forEach { it.isEnabled = false } } private fun showShortcuts() { diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/more/settings/SettingsFragment.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/more/settings/SettingsFragment.kt index e5d0764a..1a6b76de 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/more/settings/SettingsFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/more/settings/SettingsFragment.kt @@ -42,6 +42,7 @@ class SettingsFragment : PreferenceFragmentCompat() { private var incognito: SwitchPreferenceCompat? = null private var preferredDownloadType : ListPreference? = null private var searchEngine : ListPreference? = null + private var startDestination : ListPreference? = null private var downloadCard: SwitchPreferenceCompat? = null private var meteredNetwork: SwitchPreferenceCompat? = null private var apiKey: EditTextPreference? = null @@ -110,6 +111,7 @@ class SettingsFragment : PreferenceFragmentCompat() { incognito = findPreference("incognito") preferredDownloadType = findPreference("preferred_download_type") searchEngine = findPreference("search_engine") + startDestination = findPreference("start_destination") downloadCard = findPreference("download_card") meteredNetwork = findPreference("metered_networks") apiKey = findPreference("api_key") @@ -177,6 +179,7 @@ class SettingsFragment : PreferenceFragmentCompat() { editor.putBoolean("incognito", incognito!!.isChecked) editor.putString("preferred_download_type", preferredDownloadType!!.value) editor.putString("search_engine", searchEngine!!.value) + editor.putString("start_destination", startDestination!!.value) editor.putBoolean("download_card", downloadCard!!.isChecked) editor.putBoolean("metered_networks", meteredNetwork!!.isChecked) editor.putString("api_key", apiKey!!.text) @@ -303,6 +306,12 @@ class SettingsFragment : PreferenceFragmentCompat() { editor.apply() true } + startDestination!!.onPreferenceChangeListener = + Preference.OnPreferenceChangeListener { _: Preference?, newValue: Any -> + editor.putString("start_destination", newValue.toString()) + editor.apply() + true + } downloadCard!!.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _: Preference?, newValue: Any -> val enable = newValue as Boolean diff --git a/app/src/main/java/com/deniscerri/ytdlnis/work/TerminalDownloadWorker.kt b/app/src/main/java/com/deniscerri/ytdlnis/work/TerminalDownloadWorker.kt index 7e5a4293..d4c2555a 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/work/TerminalDownloadWorker.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/work/TerminalDownloadWorker.kt @@ -80,7 +80,7 @@ class TerminalDownloadWorker( } YoutubeDL.getInstance().execute(request, itemId.toString()){ progress, _, line -> - outputFile.appendText("${line}\n") + setProgressAsync(workDataOf("progress" to progress.toInt(), "output" to line.chunked(5000).first().toString(), "id" to itemId, "log" to logDownloads)) val title: String = command.take(65) notificationUtil.updateDownloadNotification( itemId, diff --git a/app/src/main/res/drawable/baseline_add_to_home_screen_24.xml b/app/src/main/res/drawable/baseline_add_to_home_screen_24.xml new file mode 100644 index 00000000..c9d8c432 --- /dev/null +++ b/app/src/main/res/drawable/baseline_add_to_home_screen_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/values-sq-rAL/strings.xml b/app/src/main/res/values-sq-rAL/strings.xml index ae562c1b..a121e4c9 100644 --- a/app/src/main/res/values-sq-rAL/strings.xml +++ b/app/src/main/res/values-sq-rAL/strings.xml @@ -207,4 +207,8 @@ Burimi i Formateve Rekomendimet e Videove Merr video Youtube te rekomanduara në faqen kryesore nga Invidious + Kërkuesi i Preferuar + Kërkuesi që do të përdoret për kërkimet në aplikacion + Të gjithë elementet duhet të jenë të një i njëjti lloj për të përdorur këtë opsion + Faqja e preferuar kryesore \ No newline at end of file diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index d6fb1c6f..8fe39e7f 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -151,4 +151,16 @@ bilisearch netsearch + + + @string/home + @string/downloads + @string/more + + + + Home + History + More + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f8c444f6..caca95a6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -217,4 +217,6 @@ Preferred Search Engine The search engine to use for in-app searches All items must be of the same type to use this option + Preferred Home Screen + Undo \ No newline at end of file diff --git a/app/src/main/res/xml/root_preferences.xml b/app/src/main/res/xml/root_preferences.xml index 46d5f06c..ed6f23f9 100644 --- a/app/src/main/res/xml/root_preferences.xml +++ b/app/src/main/res/xml/root_preferences.xml @@ -92,6 +92,14 @@ app:summary="@string/preferred_search_engine_summary" app:title="@string/preferred_search_engine" /> + + + + - -