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
import android.annotation.SuppressLint
import android.app.Activity
import android.os.Handler
import android.os.Looper
@ -15,24 +16,29 @@ import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.HistoryItem
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
import com.deniscerri.ytdlnis.util.FileUtil
import com.google.android.material.button.MaterialButton
import com.google.android.material.card.MaterialCardView
import com.squareup.picasso.Picasso
import java.util.ArrayList
class GenericDownloadAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<DownloadItem?, GenericDownloadAdapter.ViewHolder>(AsyncDifferConfig.Builder(DIFF_CALLBACK).build()) {
private val onItemClickListener: OnItemClickListener
private val activity: Activity
private var fileUtil: FileUtil
private val checkedItems: ArrayList<Long>
init {
checkedItems = ArrayList()
this.onItemClickListener = onItemClickListener
this.activity = activity
fileUtil = FileUtil()
}
class ViewHolder(itemView: View, onItemClickListener: OnItemClickListener?) : RecyclerView.ViewHolder(itemView) {
val cardView: FrameLayout
val cardView: MaterialCardView
init {
cardView = itemView.findViewById(R.id.download_card_view)
}
@ -116,15 +122,75 @@ class GenericDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
actionButton.setOnClickListener {
onItemClickListener.onActionButtonClick(item.id)
}
if (checkedItems.contains(item.id)) {
card.isChecked = true
card.strokeWidth = 5
} else {
card.isChecked = false
card.strokeWidth = 0
}
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 {
fun onActionButtonClick(itemID: Long)
fun onCardClick(itemID: Long)
fun onCardSelect(itemID: Long, isChecked: Boolean)
}
companion object {

View file

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

View file

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

View file

@ -191,6 +191,13 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
downloadAllFab.tag = "downloadAll"
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) {
resultViewModel.deleteAll()
lifecycleScope.launch(Dispatchers.IO){
@ -470,7 +477,6 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
}
}else{
resultViewModel.parseQueries(queryList)
}
}
}
@ -654,6 +660,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi
super.onStop()
}
companion object {
private const val TAG = "HomeFragment"
}

View file

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

View file

@ -126,16 +126,16 @@ class ActiveDownloadsFragment() : Fragment(), ActiveDownloadAdapter.OnItemClickL
}
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 {
it.status = DownloadRepository.Status.Cancelled.toString()
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?) {

View file

@ -7,22 +7,25 @@ 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
import android.view.Window
import android.view.*
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.view.ActionMode
import androidx.core.content.ContextCompat
import androidx.core.view.forEach
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.RecyclerView
import com.deniscerri.ytdlnis.MainActivity
import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.adapter.GenericDownloadAdapter
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.databinding.FragmentHomeBinding
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.snackbar.Snackbar
import it.xabaras.android.recyclerview.swipedecorator.RecyclerViewSwipeDecorator
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import java.util.ArrayList
class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickListener {
@ -45,6 +52,8 @@ class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClic
private lateinit var downloadViewModel : DownloadViewModel
private lateinit var cancelledRecyclerView : RecyclerView
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 fileUtil: FileUtil
private lateinit var uiUtil : UiUtil
@ -57,6 +66,7 @@ class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClic
_binding = FragmentHomeBinding.inflate(inflater, container, false)
fragmentView = inflater.inflate(R.layout.fragment_generic_download_queue, container, false)
activity = getActivity()
selectedObjects = arrayListOf()
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
items = mutableListOf()
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?){
bottomSheet?.hide()
@ -225,6 +255,80 @@ class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClic
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 =
object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) {
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.os.Bundle
import android.util.DisplayMetrics
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.Window
import android.view.*
import android.widget.AdapterView
import android.widget.AdapterView.OnItemClickListener
import android.widget.Button
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.view.ActionMode
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
@ -40,6 +39,7 @@ 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
import java.util.ArrayList
class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickListener, OnItemClickListener {
@ -50,6 +50,8 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL
private lateinit var erroredRecyclerView : RecyclerView
private lateinit var erroredDownloads : GenericDownloadAdapter
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 uiUtil : UiUtil
override fun onCreateView(
@ -62,6 +64,7 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL
activity = getActivity()
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
items = mutableListOf()
selectedObjects = arrayListOf()
fileUtil = FileUtil()
uiUtil = UiUtil(fileUtil)
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?){
bottomSheet?.hide()
val deleteDialog = MaterialAlertDialogBuilder(requireContext())
@ -228,6 +251,81 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL
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 =
object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) {
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){
val item = items.find { it.id == itemID }
val deleteDialog = MaterialAlertDialogBuilder(requireContext())

View file

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

View file

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

View file

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

View file

@ -5,13 +5,13 @@
android:layout_width="match_parent"
android:layout_height="wrap_content">
<FrameLayout
<com.google.android.material.card.MaterialCardView
android:id="@+id/download_card_view"
android:layout_width="0dp"
app:shapeAppearance="@style/ShapeAppearanceOverlay.Avatar"
android:layout_height="wrap_content"
android:paddingHorizontal="20dp"
android:paddingVertical="10dp"
android:layout_marginHorizontal="20dp"
android:layout_marginVertical="10dp"
android:checkable="true"
android:clickable="true"
android:focusable="true"
@ -193,6 +193,6 @@
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>
</com.google.android.material.card.MaterialCardView>
</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"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="horizontal"
@ -6,28 +7,33 @@
xmlns:android="http://schemas.android.com/apk/res/android">
<com.google.android.material.button.MaterialButton
android:id="@+id/materialButton"
style="@style/Widget.Material3.Button.IconButton"
app:iconSize="50dp"
android:padding="0dp"
app:iconTint="@null"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:insetBottom="0dp"
android:insetLeft="0dp"
android:insetTop="0dp"
android:insetRight="0dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:icon="@drawable/ic_app_icon" />
android:insetBottom="0dp"
android:padding="0dp"
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
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"
android:layout_marginStart="0dp"
android:layout_gravity="center_vertical"
android:text="@string/app_name"
android:textAppearance="?attr/textAppearanceHeadlineSmall"
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"?>
<paths>
<external-path name="external_files" path="."/>
<root-path name="external_files" path="/storage/" />
<cache-path
name="cache"
path="." />