add function to modify selected items in multiple download card
This commit is contained in:
parent
ffc4ded5af
commit
ece2cdf631
17 changed files with 751 additions and 131 deletions
|
|
@ -54,11 +54,16 @@ interface DownloadDao {
|
||||||
""")
|
""")
|
||||||
fun getProcessingDownloadTypes() : List<String>
|
fun getProcessingDownloadTypes() : List<String>
|
||||||
|
|
||||||
@Query("""
|
|
||||||
SELECT DISTINCT container from downloads where status = 'Processing'
|
@Query("SELECT DISTINCT type from downloads where status = 'Processing' and id in (:ids)")
|
||||||
""")
|
fun getProcessingDownloadTypesByIDs(ids: List<Long>) : List<String>
|
||||||
|
|
||||||
|
@Query("""SELECT DISTINCT container from downloads where status = 'Processing'""")
|
||||||
fun getProcessingDownloadContainers() : List<String>
|
fun getProcessingDownloadContainers() : List<String>
|
||||||
|
|
||||||
|
@Query("""SELECT DISTINCT container from downloads where id in (:ids)""")
|
||||||
|
fun getDownloadContainersByIDs(ids: List<Long>) : List<String>
|
||||||
|
|
||||||
|
|
||||||
@Query("UPDATE downloads set status = 'Processing' WHERE id in (:ids)")
|
@Query("UPDATE downloads set status = 'Processing' WHERE id in (:ids)")
|
||||||
suspend fun updateItemsToProcessing(ids: List<Long>)
|
suspend fun updateItemsToProcessing(ids: List<Long>)
|
||||||
|
|
@ -74,9 +79,15 @@ interface DownloadDao {
|
||||||
@Query("UPDATE downloads set downloadPath=:path WHERE status ='Processing'")
|
@Query("UPDATE downloads set downloadPath=:path WHERE status ='Processing'")
|
||||||
suspend fun updateProcessingDownloadPath(path: String)
|
suspend fun updateProcessingDownloadPath(path: String)
|
||||||
|
|
||||||
|
@Query("UPDATE downloads set downloadPath=:path WHERE id in (:ids)")
|
||||||
|
suspend fun updateDownloadPathByIDs(ids: List<Long>, path: String)
|
||||||
|
|
||||||
@Query("UPDATE downloads set container=:cont WHERE status ='Processing'")
|
@Query("UPDATE downloads set container=:cont WHERE status ='Processing'")
|
||||||
suspend fun updateProcessingContainer(cont: String)
|
suspend fun updateProcessingContainer(cont: String)
|
||||||
|
|
||||||
|
@Query("UPDATE downloads set container=:cont WHERE id in (:ids)")
|
||||||
|
suspend fun updateContainerByIds(ids: List<Long>, cont: String)
|
||||||
|
|
||||||
@Query("SELECT * FROM downloads WHERE status='Active'")
|
@Query("SELECT * FROM downloads WHERE status='Active'")
|
||||||
fun getActiveDownloadsList() : List<DownloadItem>
|
fun getActiveDownloadsList() : List<DownloadItem>
|
||||||
|
|
||||||
|
|
@ -356,6 +367,12 @@ interface DownloadDao {
|
||||||
@Query("UPDATE downloads set incognito=:incognito WHERE status='Processing'")
|
@Query("UPDATE downloads set incognito=:incognito WHERE status='Processing'")
|
||||||
suspend fun updateProcessingIncognito(incognito: Boolean)
|
suspend fun updateProcessingIncognito(incognito: Boolean)
|
||||||
|
|
||||||
|
@Query("UPDATE downloads set incognito=:incognito WHERE id in (:ids)")
|
||||||
|
suspend fun updateIncognitoByIDs(incognito: Boolean, ids: List<Long>)
|
||||||
|
|
||||||
@Query("SELECT COUNT(id) FROM downloads WHERE status='Processing' AND incognito='1'")
|
@Query("SELECT COUNT(id) FROM downloads WHERE status='Processing' AND incognito='1'")
|
||||||
fun getProcessingAsIncognitoCount(): Int
|
fun getProcessingAsIncognitoCount(): Int
|
||||||
|
|
||||||
|
@Query("SELECT COUNT(id) FROM downloads WHERE status='Processing' AND incognito='1' and id in (:ids)")
|
||||||
|
fun getProcessingAsIncognitoCountByIDs(ids: List<Long>): Int
|
||||||
}
|
}
|
||||||
|
|
@ -140,7 +140,7 @@ class DownloadRepository(private val downloadDao: DownloadDao) {
|
||||||
downloadDao.deleteProcessingByUrl(url)
|
downloadDao.deleteProcessingByUrl(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getProcessingDownloads() : List<DownloadItem> {
|
fun getAllProcessingDownloads() : List<DownloadItem> {
|
||||||
return downloadDao.getProcessingDownloadsList()
|
return downloadDao.getProcessingDownloadsList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -890,7 +890,7 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun queueProcessingDownloads() : QueueDownloadsResult {
|
suspend fun queueProcessingDownloads() : QueueDownloadsResult {
|
||||||
val processingItems = repository.getProcessingDownloads()
|
val processingItems = repository.getAllProcessingDownloads()
|
||||||
return queueDownloads(processingItems)
|
return queueDownloads(processingItems)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1087,13 +1087,22 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
||||||
return dbManager.downloadDao.getDownloadIDsNotPresentInList(items.ifEmpty { listOf(-1L) }, status.map { it.toString() })
|
return dbManager.downloadDao.getDownloadIDsNotPresentInList(items.ifEmpty { listOf(-1L) }, status.map { it.toString() })
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun moveProcessingToSavedCategory(){
|
suspend fun moveProcessingToSavedCategory(selectedItems: List<Long>?){
|
||||||
dao.updateProcessingtoSavedStatus()
|
if (selectedItems.isNullOrEmpty()) {
|
||||||
|
dao.updateProcessingtoSavedStatus()
|
||||||
|
}else {
|
||||||
|
repository.setDownloadStatusMultiple(selectedItems, DownloadRepository.Status.Saved)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun updateAllProcessingFormats(formatTuples : List<MultipleItemFormatTuple>) = viewModelScope.launch(Dispatchers.IO) {
|
fun updateAllProcessingFormats(selectedItems: List<Long>?, formatTuples : List<MultipleItemFormatTuple>) = viewModelScope.launch(Dispatchers.IO) {
|
||||||
val items = repository.getProcessingDownloads()
|
val items = if (selectedItems.isNullOrEmpty()) {
|
||||||
|
repository.getAllProcessingDownloads()
|
||||||
|
}else {
|
||||||
|
repository.getAllItemsByIDs(selectedItems)
|
||||||
|
}
|
||||||
|
|
||||||
items.forEach {
|
items.forEach {
|
||||||
val ft = formatTuples.first { ft -> ft.url == it.url }.formatTuple
|
val ft = formatTuples.first { ft -> ft.url == it.url }.formatTuple
|
||||||
ft.format?.apply {
|
ft.format?.apply {
|
||||||
|
|
@ -1112,28 +1121,48 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun updateProcessingCommandFormat(format: Format){
|
suspend fun updateProcessingCommandFormat(selectedItems: List<Long>?, format: Format){
|
||||||
val items = repository.getProcessingDownloads()
|
val items = if (selectedItems.isNullOrEmpty()) {
|
||||||
|
repository.getAllProcessingDownloads()
|
||||||
|
}else {
|
||||||
|
repository.getAllItemsByIDs(selectedItems)
|
||||||
|
}
|
||||||
|
|
||||||
items.forEach {
|
items.forEach {
|
||||||
it.format = format
|
it.format = format
|
||||||
repository.update(it)
|
repository.update(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun updateProcessingContainer(cont: String) {
|
suspend fun updateProcessingContainer(checkedItems: List<Long>?, cont: String) {
|
||||||
var container = ""
|
var container = ""
|
||||||
if (cont != resources.getString(R.string.defaultValue)) {
|
if (cont != resources.getString(R.string.defaultValue)) {
|
||||||
container = cont
|
container = cont
|
||||||
}
|
}
|
||||||
dao.updateProcessingContainer(container)
|
|
||||||
|
if (checkedItems.isNullOrEmpty()) {
|
||||||
|
dao.updateProcessingContainer(container)
|
||||||
|
}else {
|
||||||
|
dao.updateContainerByIds(checkedItems, container)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun updateProcessingDownloadPath(path: String){
|
suspend fun updateProcessingDownloadPath(selectedItems: List<Long>?, path: String){
|
||||||
dao.updateProcessingDownloadPath(path)
|
if (selectedItems.isNullOrEmpty()) {
|
||||||
|
dao.updateProcessingDownloadPath(path)
|
||||||
|
}else {
|
||||||
|
dao.updateDownloadPathByIDs(selectedItems, path)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getProcessingDownloads() : List<DownloadItem> {
|
fun getProcessingDownloads(checkedItems: List<Long>?) : List<DownloadItem> {
|
||||||
return repository.getProcessingDownloads()
|
return if (checkedItems.isNullOrEmpty()) {
|
||||||
|
repository.getAllProcessingDownloads()
|
||||||
|
}else {
|
||||||
|
repository.getAllItemsByIDs(checkedItems)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateDownloadItemFormats(id: Long, list: List<Format>) = viewModelScope.launch(Dispatchers.IO) {
|
fun updateDownloadItemFormats(id: Long, list: List<Format>) = viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
|
@ -1174,9 +1203,14 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
||||||
resultRepository.deleteByUrl(url)
|
resultRepository.deleteByUrl(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun continueUpdatingFormatsOnBackground(){
|
suspend fun continueUpdatingFormatsOnBackground(selectedItems: List<Long>?){
|
||||||
val ids = repository.getProcessingDownloads().map { it.id }
|
val ids = if (selectedItems.isNullOrEmpty()) {
|
||||||
dao.updateProcessingtoSavedStatus()
|
repository.getAllProcessingDownloads().map { it.id }
|
||||||
|
}else {
|
||||||
|
selectedItems
|
||||||
|
}
|
||||||
|
|
||||||
|
moveProcessingToSavedCategory(selectedItems)
|
||||||
|
|
||||||
val id = System.currentTimeMillis().toInt()
|
val id = System.currentTimeMillis().toInt()
|
||||||
val workRequest = OneTimeWorkRequestBuilder<UpdateMultipleDownloadsFormatsWorker>()
|
val workRequest = OneTimeWorkRequestBuilder<UpdateMultipleDownloadsFormatsWorker>()
|
||||||
|
|
@ -1213,8 +1247,13 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun updateProcessingType(newType: Type) {
|
suspend fun updateProcessingType(selectedItems: List<Long>?, newType: Type) {
|
||||||
val processing = repository.getProcessingDownloads()
|
val processing = if (selectedItems.isNullOrEmpty()) {
|
||||||
|
repository.getAllProcessingDownloads()
|
||||||
|
}else{
|
||||||
|
repository.getAllItemsByIDs(selectedItems)
|
||||||
|
}
|
||||||
|
|
||||||
processing.apply {
|
processing.apply {
|
||||||
val new = switchDownloadType(this, newType)
|
val new = switchDownloadType(this, newType)
|
||||||
new.forEach {
|
new.forEach {
|
||||||
|
|
@ -1224,7 +1263,7 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun updateProcessingDownloadTimeAndQueueScheduled(time: Long) : QueueDownloadsResult {
|
suspend fun updateProcessingDownloadTimeAndQueueScheduled(time: Long) : QueueDownloadsResult {
|
||||||
val processing = repository.getProcessingDownloads()
|
val processing = repository.getAllProcessingDownloads()
|
||||||
processing.forEach {
|
processing.forEach {
|
||||||
it.downloadStartTime = time
|
it.downloadStartTime = time
|
||||||
it.status = DownloadRepository.Status.Scheduled.toString()
|
it.status = DownloadRepository.Status.Scheduled.toString()
|
||||||
|
|
@ -1232,8 +1271,13 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
||||||
return queueDownloads(processing)
|
return queueDownloads(processing)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkIfAllProcessingItemsHaveSameType() : Pair<Boolean, Type> {
|
fun checkIfAllProcessingItemsHaveSameType(selectedItems: List<Long>?) : Pair<Boolean, Type> {
|
||||||
val types = dao.getProcessingDownloadTypes()
|
val types = if (!selectedItems.isNullOrEmpty()) {
|
||||||
|
dao.getProcessingDownloadTypesByIDs(selectedItems)
|
||||||
|
}else {
|
||||||
|
dao.getProcessingDownloadTypes()
|
||||||
|
}
|
||||||
|
|
||||||
if (types.isEmpty()) {
|
if (types.isEmpty()) {
|
||||||
return Pair(false, Type.command)
|
return Pair(false, Type.command)
|
||||||
}
|
}
|
||||||
|
|
@ -1241,8 +1285,13 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
||||||
return Pair(types.size == 1, Type.valueOf(types.first()))
|
return Pair(types.size == 1, Type.valueOf(types.first()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkIfAllProcessingItemsHaveSameContainer() : Pair<Boolean, String> {
|
fun checkIfAllProcessingItemsHaveSameContainer(checkedItems: List<Long>?) : Pair<Boolean, String> {
|
||||||
val containers = dao.getProcessingDownloadContainers()
|
val containers = if (checkedItems.isNullOrEmpty()) {
|
||||||
|
dao.getProcessingDownloadContainers()
|
||||||
|
}else {
|
||||||
|
dao.getDownloadContainersByIDs(checkedItems)
|
||||||
|
}
|
||||||
|
|
||||||
return Pair(containers.size == 1, containers.first())
|
return Pair(containers.size == 1, containers.first())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1277,12 +1326,20 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
||||||
return dao.getScheduledIDsBetweenTwoItems(item1, item2)
|
return dao.getScheduledIDsBetweenTwoItems(item1, item2)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun updateProcessingIncognito(incognito: Boolean) {
|
suspend fun updateProcessingIncognito(selectedItems: List<Long>?, incognito: Boolean) {
|
||||||
dao.updateProcessingIncognito(incognito)
|
if (selectedItems.isNullOrEmpty()) {
|
||||||
|
dao.updateProcessingIncognito(incognito)
|
||||||
|
}else {
|
||||||
|
dao.updateIncognitoByIDs(incognito, selectedItems)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun areAllProcessingIncognito() : Boolean {
|
fun areAllProcessingIncognito(selectedItems: List<Long>?) : Boolean {
|
||||||
return dao.getProcessingAsIncognitoCount() > 0
|
return if (selectedItems.isNullOrEmpty()) {
|
||||||
|
dao.getProcessingAsIncognitoCount() > 0
|
||||||
|
}else {
|
||||||
|
dao.getProcessingAsIncognitoCountByIDs(selectedItems) > 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun cancelDownloadOnly(id : Long) {
|
fun cancelDownloadOnly(id : Long) {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package com.deniscerri.ytdl.ui.adapter
|
package com.deniscerri.ytdl.ui.adapter
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
|
|
@ -7,6 +8,7 @@ import android.os.Looper
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import android.widget.CheckBox
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
|
@ -32,6 +34,10 @@ class ConfigureMultipleDownloadsAdapter(onItemClickListener: OnItemClickListener
|
||||||
private val onItemClickListener: OnItemClickListener
|
private val onItemClickListener: OnItemClickListener
|
||||||
private val activity: Activity
|
private val activity: Activity
|
||||||
private val sharedPreferences : SharedPreferences
|
private val sharedPreferences : SharedPreferences
|
||||||
|
private var checkedItems: MutableSet<Long> = mutableSetOf()
|
||||||
|
private var currentItems: Set<Long> = setOf()
|
||||||
|
private var _isCheckingItems: Boolean = false
|
||||||
|
private var inverted: Boolean = false
|
||||||
|
|
||||||
init {
|
init {
|
||||||
this.onItemClickListener = onItemClickListener
|
this.onItemClickListener = onItemClickListener
|
||||||
|
|
@ -53,6 +59,69 @@ class ConfigureMultipleDownloadsAdapter(onItemClickListener: OnItemClickListener
|
||||||
return ViewHolder(cardView)
|
return ViewHolder(cardView)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun isCheckingItems() : Boolean {
|
||||||
|
return _isCheckingItems
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getCheckedItemsOrNull(): List<Long>? {
|
||||||
|
val res = if (inverted) {
|
||||||
|
currentItems.filter { !checkedItems.contains(it) }
|
||||||
|
}else {
|
||||||
|
checkedItems
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.toList().ifEmpty { null }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getCheckedItemsSize() : Int {
|
||||||
|
return if (inverted){
|
||||||
|
currentItems.size - checkedItems.size
|
||||||
|
}else{
|
||||||
|
checkedItems.size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun removeItemsFromCheckList(ids: List<Long>) {
|
||||||
|
checkedItems.removeAll(ids.toSet())
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
|
fun clearCheckedItems() {
|
||||||
|
_isCheckingItems = false
|
||||||
|
inverted = false
|
||||||
|
checkedItems = mutableSetOf()
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
|
fun selectItems(ids: List<Long>) {
|
||||||
|
checkedItems = mutableSetOf()
|
||||||
|
inverted = false
|
||||||
|
checkedItems.addAll(ids)
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
|
fun checkAll() {
|
||||||
|
checkedItems = mutableSetOf()
|
||||||
|
inverted = true
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
|
fun invertSelected() {
|
||||||
|
inverted = !inverted
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
|
fun initCheckingItems(itemIDs: List<Long>) {
|
||||||
|
currentItems = itemIDs.toSet()
|
||||||
|
_isCheckingItems = true
|
||||||
|
checkedItems = mutableSetOf()
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
val item = getItem(position)
|
val item = getItem(position)
|
||||||
val card = holder.cardView
|
val card = holder.cardView
|
||||||
|
|
@ -162,18 +231,48 @@ class ConfigureMultipleDownloadsAdapter(onItemClickListener: OnItemClickListener
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val checkbox = card.findViewById<CheckBox>(R.id.checkBox)
|
||||||
|
checkbox.isVisible = _isCheckingItems
|
||||||
|
checkbox.isChecked = (checkedItems.contains(item.id) && !inverted) || (inverted && !checkedItems.contains(item.id))
|
||||||
|
checkbox.setOnClickListener {
|
||||||
|
if (checkbox.isChecked) {
|
||||||
|
if (inverted) checkedItems.remove(item.id)
|
||||||
|
else checkedItems.add(item.id)
|
||||||
|
onItemClickListener.onCardChecked(item.id)
|
||||||
|
}else {
|
||||||
|
if (inverted) checkedItems.add(item.id)
|
||||||
|
else checkedItems.remove(item.id)
|
||||||
|
onItemClickListener.onCardUnChecked(item.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val index = card.findViewById<TextView>(R.id.index)
|
||||||
|
index.isVisible = _isCheckingItems
|
||||||
|
index.text = (position + 1).toString()
|
||||||
|
|
||||||
card.setOnClickListener {
|
card.setOnClickListener {
|
||||||
onItemClickListener.onCardClick(item.id)
|
if (_isCheckingItems) {
|
||||||
|
checkbox.performClick()
|
||||||
|
}else {
|
||||||
|
onItemClickListener.onCardClick(item.id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
card.setOnLongClickListener {
|
card.setOnLongClickListener {
|
||||||
onItemClickListener.onDelete(item.id); true
|
if (_isCheckingItems) {
|
||||||
|
checkbox.performClick()
|
||||||
|
}else{
|
||||||
|
onItemClickListener.onDelete(item.id)
|
||||||
|
}
|
||||||
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface OnItemClickListener {
|
interface OnItemClickListener {
|
||||||
fun onButtonClick(id: Long)
|
fun onButtonClick(id: Long)
|
||||||
fun onCardClick(id: Long)
|
fun onCardClick(id: Long)
|
||||||
|
fun onCardChecked(id: Long)
|
||||||
|
fun onCardUnChecked(id: Long)
|
||||||
fun onDelete(id: Long)
|
fun onDelete(id: Long)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import android.content.SharedPreferences
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.graphics.Canvas
|
import android.graphics.Canvas
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.DisplayMetrics
|
import android.util.DisplayMetrics
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
|
@ -16,14 +17,18 @@ import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.Window
|
import android.view.Window
|
||||||
|
import android.widget.CheckBox
|
||||||
|
import android.widget.LinearLayout
|
||||||
import android.widget.PopupMenu
|
import android.widget.PopupMenu
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.ViewCompat
|
||||||
import androidx.core.view.WindowInsetsCompat
|
import androidx.core.view.WindowInsetsCompat
|
||||||
import androidx.core.view.children
|
import androidx.core.view.children
|
||||||
|
import androidx.core.view.get
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.core.view.setPadding
|
import androidx.core.view.setPadding
|
||||||
import androidx.core.view.updatePadding
|
import androidx.core.view.updatePadding
|
||||||
|
|
@ -59,6 +64,7 @@ import com.google.android.material.button.MaterialButton
|
||||||
import com.google.android.material.color.MaterialColors
|
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.elevation.SurfaceColors
|
import com.google.android.material.elevation.SurfaceColors
|
||||||
|
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
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.CancellationException
|
import kotlinx.coroutines.CancellationException
|
||||||
|
|
@ -68,6 +74,7 @@ import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import kotlin.math.abs
|
||||||
|
|
||||||
class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), ConfigureMultipleDownloadsAdapter.OnItemClickListener, View.OnClickListener,
|
class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), ConfigureMultipleDownloadsAdapter.OnItemClickListener, View.OnClickListener,
|
||||||
ConfigureDownloadBottomSheetDialog.OnDownloadItemUpdateListener {
|
ConfigureDownloadBottomSheetDialog.OnDownloadItemUpdateListener {
|
||||||
|
|
@ -81,6 +88,7 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
|
||||||
private lateinit var behavior: BottomSheetBehavior<View>
|
private lateinit var behavior: BottomSheetBehavior<View>
|
||||||
private lateinit var bottomAppBar: BottomAppBar
|
private lateinit var bottomAppBar: BottomAppBar
|
||||||
private lateinit var filesize : TextView
|
private lateinit var filesize : TextView
|
||||||
|
private var itemsFileSize: Long = 0L
|
||||||
private lateinit var count : TextView
|
private lateinit var count : TextView
|
||||||
private lateinit var downloadBtn : MaterialButton
|
private lateinit var downloadBtn : MaterialButton
|
||||||
private lateinit var scheduleBtn : MaterialButton
|
private lateinit var scheduleBtn : MaterialButton
|
||||||
|
|
@ -98,6 +106,10 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
|
||||||
private lateinit var containerBtn : MenuItem
|
private lateinit var containerBtn : MenuItem
|
||||||
private lateinit var containerTextView: TextView
|
private lateinit var containerTextView: TextView
|
||||||
|
|
||||||
|
private lateinit var multipleSelectHeader: ConstraintLayout
|
||||||
|
private lateinit var selectItemsMenuBtn: MaterialButton
|
||||||
|
private lateinit var selectRangeBtn: MaterialButton
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
downloadViewModel = ViewModelProvider(requireActivity())[DownloadViewModel::class.java]
|
downloadViewModel = ViewModelProvider(requireActivity())[DownloadViewModel::class.java]
|
||||||
|
|
@ -182,28 +194,51 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
downloadViewModel.processingDownloads.collectLatest { items ->
|
downloadViewModel.processingDownloads.collectLatest { items ->
|
||||||
processingItemsCount = items.size
|
processingItemsCount = items.size
|
||||||
|
currentDownloadIDs = items.map { it.id }
|
||||||
count.text = "$processingItemsCount ${getString(R.string.selected)}"
|
count.text = "$processingItemsCount ${getString(R.string.selected)}"
|
||||||
listAdapter.submitList(items)
|
listAdapter.submitList(items)
|
||||||
|
|
||||||
updateFileSize(items)
|
updateFileSize(items)
|
||||||
|
|
||||||
if (items.isNotEmpty()){
|
if (items.isNotEmpty()){
|
||||||
if (items.all { it2 -> it2.type == items[0].type }) {
|
lifecycleScope.launch {
|
||||||
formatBtn.icon?.alpha = 255
|
val haveSameType = if (listAdapter.isCheckingItems()) {
|
||||||
if (items[0].type != DownloadViewModel.Type.command) {
|
val res = withContext(Dispatchers.IO) {
|
||||||
moreBtn.icon?.alpha = 255
|
downloadViewModel.checkIfAllProcessingItemsHaveSameType(listAdapter.getCheckedItemsOrNull())
|
||||||
|
}
|
||||||
|
|
||||||
|
res.first
|
||||||
|
}else {
|
||||||
|
items.all { it2 -> it2.type == items[0].type }
|
||||||
}
|
}
|
||||||
|
|
||||||
containerBtn.isVisible = items.first().type != DownloadViewModel.Type.command
|
if (haveSameType) {
|
||||||
} else {
|
formatBtn.icon?.alpha = 255
|
||||||
formatBtn.icon?.alpha = 30
|
if (items[0].type != DownloadViewModel.Type.command) {
|
||||||
moreBtn.icon?.alpha = 30
|
moreBtn.icon?.alpha = 255
|
||||||
}
|
}
|
||||||
|
|
||||||
if (items.all { it.container == items[0].container }) {
|
containerBtn.isVisible = items.first().type != DownloadViewModel.Type.command
|
||||||
setContainerText(items[0].container)
|
}else {
|
||||||
}else{
|
formatBtn.icon?.alpha = 30
|
||||||
setContainerText("")
|
moreBtn.icon?.alpha = 30
|
||||||
|
}
|
||||||
|
|
||||||
|
val haveSameContainer = if (listAdapter.isCheckingItems()) {
|
||||||
|
val res = withContext(Dispatchers.IO) {
|
||||||
|
downloadViewModel.checkIfAllProcessingItemsHaveSameContainer(listAdapter.getCheckedItemsOrNull())
|
||||||
|
}
|
||||||
|
|
||||||
|
res.first
|
||||||
|
}else {
|
||||||
|
items.all { it.container == items[0].container }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (haveSameContainer) {
|
||||||
|
setContainerText(items[0].container)
|
||||||
|
}else {
|
||||||
|
setContainerText("")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val type = items.first().type
|
val type = items.first().type
|
||||||
|
|
@ -233,7 +268,6 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
|
||||||
toggleLoading(true)
|
toggleLoading(true)
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
withContext(Dispatchers.IO){
|
withContext(Dispatchers.IO){
|
||||||
downloadViewModel.deleteAllWithID(currentDownloadIDs)
|
|
||||||
historyViewModel.deleteAllWithIDsCheckFiles(currentHistoryIDs)
|
historyViewModel.deleteAllWithIDsCheckFiles(currentHistoryIDs)
|
||||||
val result = downloadViewModel.updateProcessingDownloadTimeAndQueueScheduled(cal.timeInMillis)
|
val result = downloadViewModel.updateProcessingDownloadTimeAndQueueScheduled(cal.timeInMillis)
|
||||||
if (result.message.isNotBlank()){
|
if (result.message.isNotBlank()){
|
||||||
|
|
@ -257,7 +291,6 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
|
||||||
toggleLoading(true)
|
toggleLoading(true)
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
withContext(Dispatchers.IO){
|
withContext(Dispatchers.IO){
|
||||||
downloadViewModel.deleteAllWithID(currentDownloadIDs)
|
|
||||||
historyViewModel.deleteAllWithIDsCheckFiles(currentHistoryIDs)
|
historyViewModel.deleteAllWithIDsCheckFiles(currentHistoryIDs)
|
||||||
val result = downloadViewModel.queueProcessingDownloads()
|
val result = downloadViewModel.queueProcessingDownloads()
|
||||||
if (result.message.isNotBlank()){
|
if (result.message.isNotBlank()){
|
||||||
|
|
@ -283,8 +316,7 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
|
||||||
dd.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
|
dd.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
|
||||||
lifecycleScope.launch{
|
lifecycleScope.launch{
|
||||||
withContext(Dispatchers.IO){
|
withContext(Dispatchers.IO){
|
||||||
downloadViewModel.deleteAllWithID(currentDownloadIDs)
|
downloadViewModel.moveProcessingToSavedCategory(null)
|
||||||
downloadViewModel.moveProcessingToSavedCategory()
|
|
||||||
historyViewModel.deleteAllWithIDsCheckFiles(currentHistoryIDs)
|
historyViewModel.deleteAllWithIDsCheckFiles(currentHistoryIDs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -300,7 +332,7 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
|
||||||
|
|
||||||
val formatListener = object : OnMultipleFormatClickListener {
|
val formatListener = object : OnMultipleFormatClickListener {
|
||||||
override fun onFormatClick(formatTuple: List<MultipleItemFormatTuple>) {
|
override fun onFormatClick(formatTuple: List<MultipleItemFormatTuple>) {
|
||||||
downloadViewModel.updateAllProcessingFormats(formatTuple)
|
downloadViewModel.updateAllProcessingFormats(listAdapter.getCheckedItemsOrNull(), formatTuple)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFormatUpdated(url: String, formats: List<Format>) {
|
override fun onFormatUpdated(url: String, formats: List<Format>) {
|
||||||
|
|
@ -314,7 +346,7 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
|
||||||
override fun onContinueOnBackground() {
|
override fun onContinueOnBackground() {
|
||||||
requireActivity().lifecycleScope.launch {
|
requireActivity().lifecycleScope.launch {
|
||||||
withContext(Dispatchers.IO){
|
withContext(Dispatchers.IO){
|
||||||
downloadViewModel.continueUpdatingFormatsOnBackground()
|
downloadViewModel.continueUpdatingFormatsOnBackground(listAdapter.getCheckedItemsOrNull())
|
||||||
}
|
}
|
||||||
downloadViewModel.processingItemsJob?.cancel(CancellationException())
|
downloadViewModel.processingItemsJob?.cancel(CancellationException())
|
||||||
downloadViewModel.processingItemsJob = null
|
downloadViewModel.processingItemsJob = null
|
||||||
|
|
@ -326,7 +358,7 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
|
||||||
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
val allIncognito = withContext(Dispatchers.IO){
|
val allIncognito = withContext(Dispatchers.IO){
|
||||||
downloadViewModel.areAllProcessingIncognito()
|
downloadViewModel.areAllProcessingIncognito(listAdapter.getCheckedItemsOrNull())
|
||||||
}
|
}
|
||||||
|
|
||||||
incognitoBtn.icon!!.apply {
|
incognitoBtn.icon!!.apply {
|
||||||
|
|
@ -359,40 +391,6 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
|
||||||
|
|
||||||
bottomAppBar.setOnMenuItemClickListener { m: MenuItem ->
|
bottomAppBar.setOnMenuItemClickListener { m: MenuItem ->
|
||||||
when (m.itemId) {
|
when (m.itemId) {
|
||||||
R.id.incognito -> {
|
|
||||||
lifecycleScope.launch {
|
|
||||||
if (m.icon!!.alpha == 255) {
|
|
||||||
incognitoBtn.isEnabled = false
|
|
||||||
withContext(Dispatchers.IO) {
|
|
||||||
downloadViewModel.updateProcessingIncognito(false)
|
|
||||||
withContext(Dispatchers.Main){
|
|
||||||
m.icon!!.alpha = 30
|
|
||||||
m.isEnabled = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
incognitoBtn.icon?.alpha = 30
|
|
||||||
incognitoBtn.isEnabled = true
|
|
||||||
Toast.makeText(requireContext(), "${getString(R.string.incognito)}: ${getString(R.string.disabled)}", Toast.LENGTH_SHORT).show()
|
|
||||||
}else{
|
|
||||||
incognitoBtn.isEnabled = false
|
|
||||||
withContext(Dispatchers.IO) {
|
|
||||||
downloadViewModel.updateProcessingIncognito(true)
|
|
||||||
withContext(Dispatchers.Main){
|
|
||||||
}
|
|
||||||
}
|
|
||||||
incognitoBtn.icon?.alpha = 255
|
|
||||||
incognitoBtn.isEnabled = true
|
|
||||||
Toast.makeText(requireContext(), "${getString(R.string.incognito)}: ${getString(R.string.ok)}", Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
R.id.folder -> {
|
|
||||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
|
||||||
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
|
||||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
|
||||||
intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
|
|
||||||
pathResultLauncher.launch(intent)
|
|
||||||
}
|
|
||||||
R.id.preferred_download_type -> {
|
R.id.preferred_download_type -> {
|
||||||
lifecycleScope.launch{
|
lifecycleScope.launch{
|
||||||
val bottomSheet = BottomSheetDialog(requireContext())
|
val bottomSheet = BottomSheetDialog(requireContext())
|
||||||
|
|
@ -416,7 +414,7 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
|
||||||
|
|
||||||
audio!!.setOnClickListener {
|
audio!!.setOnClickListener {
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
downloadViewModel.updateProcessingType(DownloadViewModel.Type.audio)
|
downloadViewModel.updateProcessingType(listAdapter.getCheckedItemsOrNull(), DownloadViewModel.Type.audio)
|
||||||
withContext(Dispatchers.Main){
|
withContext(Dispatchers.Main){
|
||||||
preferredDownloadType.setIcon(R.drawable.baseline_audio_file_24)
|
preferredDownloadType.setIcon(R.drawable.baseline_audio_file_24)
|
||||||
formatBtn.icon?.alpha = 255
|
formatBtn.icon?.alpha = 255
|
||||||
|
|
@ -424,7 +422,7 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
|
||||||
bottomSheet.cancel()
|
bottomSheet.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
val res = downloadViewModel.checkIfAllProcessingItemsHaveSameContainer()
|
val res = downloadViewModel.checkIfAllProcessingItemsHaveSameContainer(listAdapter.getCheckedItemsOrNull())
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
if (!res.first) {
|
if (!res.first) {
|
||||||
setContainerText("")
|
setContainerText("")
|
||||||
|
|
@ -438,7 +436,7 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
|
||||||
|
|
||||||
video!!.setOnClickListener {
|
video!!.setOnClickListener {
|
||||||
CoroutineScope(Dispatchers.IO).launch{
|
CoroutineScope(Dispatchers.IO).launch{
|
||||||
downloadViewModel.updateProcessingType(DownloadViewModel.Type.video)
|
downloadViewModel.updateProcessingType(listAdapter.getCheckedItemsOrNull(), DownloadViewModel.Type.video)
|
||||||
withContext(Dispatchers.Main){
|
withContext(Dispatchers.Main){
|
||||||
preferredDownloadType.setIcon(R.drawable.baseline_video_file_24)
|
preferredDownloadType.setIcon(R.drawable.baseline_video_file_24)
|
||||||
formatBtn.icon?.alpha = 255
|
formatBtn.icon?.alpha = 255
|
||||||
|
|
@ -446,7 +444,7 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
|
||||||
bottomSheet.cancel()
|
bottomSheet.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
val res = downloadViewModel.checkIfAllProcessingItemsHaveSameContainer()
|
val res = downloadViewModel.checkIfAllProcessingItemsHaveSameContainer(listAdapter.getCheckedItemsOrNull())
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
if (!res.first) {
|
if (!res.first) {
|
||||||
setContainerText("")
|
setContainerText("")
|
||||||
|
|
@ -459,7 +457,7 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
|
||||||
|
|
||||||
command!!.setOnClickListener {
|
command!!.setOnClickListener {
|
||||||
CoroutineScope(Dispatchers.IO).launch{
|
CoroutineScope(Dispatchers.IO).launch{
|
||||||
downloadViewModel.updateProcessingType(DownloadViewModel.Type.command)
|
downloadViewModel.updateProcessingType(listAdapter.getCheckedItemsOrNull(), DownloadViewModel.Type.command)
|
||||||
withContext(Dispatchers.Main){
|
withContext(Dispatchers.Main){
|
||||||
preferredDownloadType.setIcon(R.drawable.baseline_insert_drive_file_24)
|
preferredDownloadType.setIcon(R.drawable.baseline_insert_drive_file_24)
|
||||||
formatBtn.icon?.alpha = 255
|
formatBtn.icon?.alpha = 255
|
||||||
|
|
@ -485,7 +483,7 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
|
||||||
R.id.format -> {
|
R.id.format -> {
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
val res = withContext(Dispatchers.IO){
|
val res = withContext(Dispatchers.IO){
|
||||||
downloadViewModel.checkIfAllProcessingItemsHaveSameType()
|
downloadViewModel.checkIfAllProcessingItemsHaveSameType(listAdapter.getCheckedItemsOrNull())
|
||||||
}
|
}
|
||||||
if (!res.first){
|
if (!res.first){
|
||||||
Toast.makeText(requireContext(), getString(R.string.format_filtering_hint), Toast.LENGTH_SHORT).show()
|
Toast.makeText(requireContext(), getString(R.string.format_filtering_hint), Toast.LENGTH_SHORT).show()
|
||||||
|
|
@ -505,13 +503,13 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
|
||||||
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
withContext(Dispatchers.IO){
|
withContext(Dispatchers.IO){
|
||||||
downloadViewModel.updateProcessingCommandFormat(format)
|
downloadViewModel.updateProcessingCommandFormat(listAdapter.getCheckedItemsOrNull(), format)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
val items = withContext(Dispatchers.IO){
|
val items = withContext(Dispatchers.IO){
|
||||||
downloadViewModel.getProcessingDownloads()
|
downloadViewModel.getProcessingDownloads(listAdapter.getCheckedItemsOrNull())
|
||||||
}
|
}
|
||||||
formatViewModel.setItems(items)
|
formatViewModel.setItems(items)
|
||||||
val bottomSheet = FormatSelectionBottomSheetDialog( _multipleFormatsListener = formatListener)
|
val bottomSheet = FormatSelectionBottomSheetDialog( _multipleFormatsListener = formatListener)
|
||||||
|
|
@ -520,10 +518,63 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
R.id.folder -> {
|
||||||
|
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
||||||
|
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
||||||
|
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||||
|
intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
|
||||||
|
pathResultLauncher.launch(intent)
|
||||||
|
}
|
||||||
|
R.id.select_items -> {
|
||||||
|
if (listAdapter.isCheckingItems()) {
|
||||||
|
multipleSelectHeader.isVisible = false
|
||||||
|
view.findViewById<ConstraintLayout>(R.id.downloadHeader).isVisible = true
|
||||||
|
filesize.isVisible = itemsFileSize > 0L
|
||||||
|
selectRangeBtn.isVisible = false
|
||||||
|
count.text = "${currentDownloadIDs.size} ${getString(R.string.selected)}"
|
||||||
|
listAdapter.clearCheckedItems()
|
||||||
|
}else {
|
||||||
|
multipleSelectHeader.apply {
|
||||||
|
isVisible = true
|
||||||
|
}
|
||||||
|
view.findViewById<ConstraintLayout>(R.id.downloadHeader).isVisible = false
|
||||||
|
filesize.isVisible = false
|
||||||
|
listAdapter.initCheckingItems(currentDownloadIDs)
|
||||||
|
selectRangeBtn.isVisible = true
|
||||||
|
count.text = "0 ${getString(R.string.selected)}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
R.id.incognito -> {
|
||||||
|
lifecycleScope.launch {
|
||||||
|
if (m.icon!!.alpha == 255) {
|
||||||
|
incognitoBtn.isEnabled = false
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
downloadViewModel.updateProcessingIncognito(listAdapter.getCheckedItemsOrNull(), false)
|
||||||
|
withContext(Dispatchers.Main){
|
||||||
|
m.icon!!.alpha = 30
|
||||||
|
m.isEnabled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
incognitoBtn.icon?.alpha = 30
|
||||||
|
incognitoBtn.isEnabled = true
|
||||||
|
Toast.makeText(requireContext(), "${getString(R.string.incognito)}: ${getString(R.string.disabled)}", Toast.LENGTH_SHORT).show()
|
||||||
|
}else{
|
||||||
|
incognitoBtn.isEnabled = false
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
downloadViewModel.updateProcessingIncognito(listAdapter.getCheckedItemsOrNull(),true)
|
||||||
|
withContext(Dispatchers.Main){
|
||||||
|
}
|
||||||
|
}
|
||||||
|
incognitoBtn.icon?.alpha = 255
|
||||||
|
incognitoBtn.isEnabled = true
|
||||||
|
Toast.makeText(requireContext(), "${getString(R.string.incognito)}: ${getString(R.string.ok)}", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
R.id.more -> {
|
R.id.more -> {
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
val res = withContext(Dispatchers.IO){
|
val res = withContext(Dispatchers.IO){
|
||||||
downloadViewModel.checkIfAllProcessingItemsHaveSameType()
|
downloadViewModel.checkIfAllProcessingItemsHaveSameType(listAdapter.getCheckedItemsOrNull())
|
||||||
}
|
}
|
||||||
if (!res.first) {
|
if (!res.first) {
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
|
|
@ -544,7 +595,7 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
|
||||||
sheetView.findViewById<View>(R.id.adjust).setPadding(padding)
|
sheetView.findViewById<View>(R.id.adjust).setPadding(padding)
|
||||||
|
|
||||||
val items = withContext(Dispatchers.IO){
|
val items = withContext(Dispatchers.IO){
|
||||||
downloadViewModel.getProcessingDownloads()
|
downloadViewModel.getProcessingDownloads(listAdapter.getCheckedItemsOrNull())
|
||||||
}
|
}
|
||||||
|
|
||||||
UiUtil.configureAudio(
|
UiUtil.configureAudio(
|
||||||
|
|
@ -626,7 +677,7 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
|
||||||
sheetView.findViewById<View>(R.id.adjust).setPadding(padding)
|
sheetView.findViewById<View>(R.id.adjust).setPadding(padding)
|
||||||
|
|
||||||
val items = withContext(Dispatchers.IO){
|
val items = withContext(Dispatchers.IO){
|
||||||
downloadViewModel.getProcessingDownloads()
|
downloadViewModel.getProcessingDownloads(listAdapter.getCheckedItemsOrNull())
|
||||||
}
|
}
|
||||||
|
|
||||||
UiUtil.configureVideo(
|
UiUtil.configureVideo(
|
||||||
|
|
@ -731,7 +782,7 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
|
||||||
containerTextView.setOnClickListener {
|
containerTextView.setOnClickListener {
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
val res = withContext(Dispatchers.IO){
|
val res = withContext(Dispatchers.IO){
|
||||||
downloadViewModel.checkIfAllProcessingItemsHaveSameType()
|
downloadViewModel.checkIfAllProcessingItemsHaveSameType(listAdapter.getCheckedItemsOrNull())
|
||||||
}
|
}
|
||||||
if (!res.first){
|
if (!res.first){
|
||||||
Toast.makeText(requireContext(), getString(R.string.format_filtering_hint), Toast.LENGTH_SHORT).show()
|
Toast.makeText(requireContext(), getString(R.string.format_filtering_hint), Toast.LENGTH_SHORT).show()
|
||||||
|
|
@ -749,7 +800,7 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
|
||||||
val container = mm.title
|
val container = mm.title
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
withContext(Dispatchers.IO){
|
withContext(Dispatchers.IO){
|
||||||
downloadViewModel.updateProcessingContainer(container.toString())
|
downloadViewModel.updateProcessingContainer(listAdapter.getCheckedItemsOrNull(), container.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setContainerText(container.toString())
|
setContainerText(container.toString())
|
||||||
|
|
@ -758,11 +809,92 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
|
||||||
|
|
||||||
popup.show()
|
popup.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
multipleSelectHeader = view.findViewById(R.id.multipleSelectHeader)
|
||||||
|
selectItemsMenuBtn = view.findViewById(R.id.selectItemsMenu)
|
||||||
|
selectItemsMenuBtn.setOnClickListener {
|
||||||
|
val popup = PopupMenu(activity, it)
|
||||||
|
popup.menuInflater.inflate(R.menu.select_multiple_items_menu_context, popup.menu)
|
||||||
|
if (Build.VERSION.SDK_INT > 27) popup.menu.setGroupDividerEnabled(true)
|
||||||
|
|
||||||
|
val selectedItems = listAdapter.getCheckedItemsOrNull() ?: listOf()
|
||||||
|
popup.menu.findItem(R.id.delete).isVisible = selectedItems.isNotEmpty()
|
||||||
|
popup.menu.findItem(R.id.select_between).apply {
|
||||||
|
if (selectedItems.size == 2) {
|
||||||
|
val firstIndex = currentDownloadIDs.indexOf(selectedItems.first())
|
||||||
|
val secondIndex = currentDownloadIDs.indexOf(selectedItems.last())
|
||||||
|
|
||||||
|
isVisible = abs(firstIndex - secondIndex) > 1
|
||||||
|
}else{
|
||||||
|
isVisible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
popup.setOnMenuItemClickListener { m: MenuItem ->
|
||||||
|
when(m.itemId) {
|
||||||
|
R.id.select_between -> {
|
||||||
|
val firstIndex = currentDownloadIDs.indexOf(selectedItems.first())
|
||||||
|
val secondIndex = currentDownloadIDs.indexOf(selectedItems.last())
|
||||||
|
|
||||||
|
val itemsBetween = currentDownloadIDs.filterIndexed { index, _ -> index >= firstIndex && index <= secondIndex }
|
||||||
|
listAdapter.selectItems(itemsBetween)
|
||||||
|
count.text = "${itemsBetween.size} ${getString(R.string.selected)}"
|
||||||
|
}
|
||||||
|
R.id.delete -> {
|
||||||
|
UiUtil.showGenericDeleteAllDialog(requireContext()) {
|
||||||
|
lifecycleScope.launch {
|
||||||
|
val deletedAll = processingItemsCount == listAdapter.getCheckedItemsSize()
|
||||||
|
val toDelete = listAdapter.getCheckedItemsOrNull() ?: listOf()
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
downloadViewModel.deleteAllWithID(toDelete)
|
||||||
|
}
|
||||||
|
listAdapter.removeItemsFromCheckList(toDelete)
|
||||||
|
val checkedSize = listAdapter.getCheckedItemsSize()
|
||||||
|
count.text = "$checkedSize ${getString(R.string.selected)}"
|
||||||
|
if (deletedAll) dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
R.id.select_all -> {
|
||||||
|
listAdapter.checkAll()
|
||||||
|
val checkedSize = listAdapter.getCheckedItemsSize()
|
||||||
|
count.text = "$checkedSize ${getString(R.string.selected)}"
|
||||||
|
}
|
||||||
|
R.id.invert_selected -> {
|
||||||
|
listAdapter.invertSelected()
|
||||||
|
val checkedSize = listAdapter.getCheckedItemsSize()
|
||||||
|
count.text = "$checkedSize ${getString(R.string.selected)}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
popup.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
selectRangeBtn = view.findViewById(R.id.selectRangeBtn)
|
||||||
|
selectRangeBtn.setOnClickListener {
|
||||||
|
UiUtil.showSelectRangeDialog(requireActivity(), currentDownloadIDs.size) {
|
||||||
|
val itemsBetween = currentDownloadIDs.filterIndexed { index, _ -> index >= it.first && index <= it.second }
|
||||||
|
listAdapter.selectItems(itemsBetween)
|
||||||
|
selectItemsMenuBtn.isVisible = true
|
||||||
|
count.text = "${itemsBetween.size} ${getString(R.string.selected)}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val editSelectedOkBtn = view.findViewById<MaterialButton>(R.id.bottomsheet_ok_button)
|
||||||
|
editSelectedOkBtn.setOnClickListener {
|
||||||
|
multipleSelectHeader.isVisible = false
|
||||||
|
view.findViewById<ConstraintLayout>(R.id.downloadHeader).isVisible = true
|
||||||
|
selectItemsMenuBtn.isVisible = false
|
||||||
|
filesize.isVisible = itemsFileSize > 0
|
||||||
|
count.text = "${currentDownloadIDs.size} ${getString(R.string.selected)}"
|
||||||
|
selectRangeBtn.isVisible = false
|
||||||
|
listAdapter.clearCheckedItems()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
|
|
@ -819,7 +951,8 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
|
||||||
|
|
||||||
if (fileSizes.all { it > 5L }){
|
if (fileSizes.all { it > 5L }){
|
||||||
val size = FileUtil.convertFileSize(fileSizes.sum())
|
val size = FileUtil.convertFileSize(fileSizes.sum())
|
||||||
filesize.isVisible = size != "?"
|
itemsFileSize = fileSizes.sum()
|
||||||
|
filesize.isVisible = size != "?" && !listAdapter.isCheckingItems()
|
||||||
filesize.text = "${getString(R.string.file_size)}: >~ $size"
|
filesize.text = "${getString(R.string.file_size)}: >~ $size"
|
||||||
}else{
|
}else{
|
||||||
filesize.visibility = View.GONE
|
filesize.visibility = View.GONE
|
||||||
|
|
@ -839,7 +972,7 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
|
||||||
}
|
}
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
downloadViewModel.updateProcessingDownloadPath(result.data?.data.toString())
|
downloadViewModel.updateProcessingDownloadPath(listAdapter.getCheckedItemsOrNull(), result.data?.data.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
val path = FileUtil.formatPath(result.data!!.data.toString())
|
val path = FileUtil.formatPath(result.data!!.data.toString())
|
||||||
|
|
@ -926,6 +1059,20 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onCardChecked(id: Long) {
|
||||||
|
selectItemsMenuBtn.isVisible = true
|
||||||
|
val checkedSize = listAdapter.getCheckedItemsSize()
|
||||||
|
count.text = "$checkedSize ${getString(R.string.selected)}"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCardUnChecked(id: Long) {
|
||||||
|
val checkedSize = listAdapter.getCheckedItemsSize()
|
||||||
|
if (checkedSize == 0) {
|
||||||
|
selectItemsMenuBtn.isVisible = false
|
||||||
|
}
|
||||||
|
count.text = "$checkedSize ${getString(R.string.selected)}"
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDelete(id: Long) {
|
override fun onDelete(id: Long) {
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
val deletedItem = withContext(Dispatchers.IO){
|
val deletedItem = withContext(Dispatchers.IO){
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import android.os.Environment
|
||||||
import android.text.Editable
|
import android.text.Editable
|
||||||
import android.text.TextWatcher
|
import android.text.TextWatcher
|
||||||
import android.text.format.DateFormat
|
import android.text.format.DateFormat
|
||||||
|
import android.text.method.DigitsKeyListener
|
||||||
import android.text.method.LinkMovementMethod
|
import android.text.method.LinkMovementMethod
|
||||||
import android.util.DisplayMetrics
|
import android.util.DisplayMetrics
|
||||||
import android.view.Gravity
|
import android.view.Gravity
|
||||||
|
|
@ -2014,6 +2015,73 @@ object UiUtil {
|
||||||
dialog.getButton(AlertDialog.BUTTON_NEUTRAL).gravity = Gravity.START
|
dialog.getButton(AlertDialog.BUTTON_NEUTRAL).gravity = Gravity.START
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun showSelectRangeDialog(context: Activity, itemCount: Int, rangeSelected: (rangeSelected: Pair<Int, Int>) -> Unit) {
|
||||||
|
val builder = MaterialAlertDialogBuilder(context)
|
||||||
|
builder.setTitle(context.getString(R.string.select_between))
|
||||||
|
builder.setMessage(context.getString(R.string.select_between_desc))
|
||||||
|
builder.setIcon(R.drawable.baseline_format_list_numbered_24)
|
||||||
|
val view = context.layoutInflater.inflate(R.layout.select_range_dialog, null)
|
||||||
|
|
||||||
|
val fromTextInput = view.findViewById<TextInputLayout>(R.id.from_textinput)
|
||||||
|
fromTextInput.editText!!.keyListener = DigitsKeyListener.getInstance("0123456789")
|
||||||
|
val toTextInput = view.findViewById<TextInputLayout>(R.id.to_textinput)
|
||||||
|
toTextInput.editText!!.keyListener = DigitsKeyListener.getInstance("0123456789")
|
||||||
|
|
||||||
|
|
||||||
|
builder.setView(view)
|
||||||
|
builder.setPositiveButton(
|
||||||
|
context.getString(R.string.ok)
|
||||||
|
) { _: DialogInterface?, _: Int ->
|
||||||
|
val firstIndex = fromTextInput.editText!!.text.toString().toInt() - 1
|
||||||
|
val secondIndex = toTextInput.editText!!.text.toString().toInt() - 1
|
||||||
|
|
||||||
|
rangeSelected(Pair(firstIndex,secondIndex))
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle the negative button of the alert dialog
|
||||||
|
builder.setNegativeButton(
|
||||||
|
context.getString(R.string.cancel)
|
||||||
|
) { _: DialogInterface?, _: Int -> }
|
||||||
|
|
||||||
|
val dialog = builder.create()
|
||||||
|
dialog.show()
|
||||||
|
|
||||||
|
|
||||||
|
fun checkRanges(start: String, end: String) : Boolean {
|
||||||
|
fromTextInput.error = ""
|
||||||
|
toTextInput.error = ""
|
||||||
|
|
||||||
|
if (start.isBlank() || end.isBlank()) return false
|
||||||
|
|
||||||
|
val startValid = start.toInt() >= 0
|
||||||
|
val endValid = end.toInt() <= itemCount
|
||||||
|
|
||||||
|
if (!startValid) {
|
||||||
|
fromTextInput.editText?.setText("")
|
||||||
|
fromTextInput.error = "Invalid Number"
|
||||||
|
}
|
||||||
|
if (!endValid) {
|
||||||
|
toTextInput.editText?.setText("")
|
||||||
|
toTextInput.error = "Invalid Number"
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = startValid && endValid
|
||||||
|
return startValid && endValid
|
||||||
|
}
|
||||||
|
|
||||||
|
fromTextInput.editText!!.doAfterTextChanged { editable ->
|
||||||
|
val start = editable.toString()
|
||||||
|
val end = toTextInput.editText!!.text.toString()
|
||||||
|
checkRanges(start, end)
|
||||||
|
}
|
||||||
|
|
||||||
|
toTextInput.editText!!.doAfterTextChanged { editable ->
|
||||||
|
val start = fromTextInput.editText!!.text.toString()
|
||||||
|
val end = editable.toString()
|
||||||
|
checkRanges(start, end)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun createPersonalFilenameTemplateChip(context: Activity, text: String, myChipGroup: ChipGroup, onClick: (f: Chip) -> Unit, onLongClick: (f: Chip) -> Unit) : Chip {
|
private fun createPersonalFilenameTemplateChip(context: Activity, text: String, myChipGroup: ChipGroup, onClick: (f: Chip) -> Unit, onLongClick: (f: Chip) -> Unit) : Chip {
|
||||||
val tmp = context.layoutInflater.inflate(R.layout.filter_chip, myChipGroup, false) as Chip
|
val tmp = context.layoutInflater.inflate(R.layout.filter_chip, myChipGroup, false) as Chip
|
||||||
tmp.text = text
|
tmp.text = text
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="?attr/colorAccent" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||||
|
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M2,17h2v0.5L3,17.5v1h1v0.5L2,19v1h3v-4L2,16v1zM3,8h1L4,4L2,4v1h1v3zM2,11h1.8L2,13.1v0.9h3v-1L3.2,13L5,10.9L5,10L2,10v1zM7,5v2h14L21,5L7,5zM7,19h14v-2L7,17v2zM7,13h14v-2L7,11v2z"/>
|
||||||
|
|
||||||
|
</vector>
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<vector android:height="24dp" android:tint="#000000"
|
<vector android:height="24dp" android:tint="?attr/colorAccent"
|
||||||
android:viewportHeight="24" android:viewportWidth="24"
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<path android:fillColor="@android:color/white" android:pathData="M3,5h2L5,3c-1.1,0 -2,0.9 -2,2zM3,13h2v-2L3,11v2zM7,21h2v-2L7,19v2zM3,9h2L5,7L3,7v2zM13,3h-2v2h2L13,3zM19,3v2h2c0,-1.1 -0.9,-2 -2,-2zM5,21v-2L3,19c0,1.1 0.9,2 2,2zM3,17h2v-2L3,15v2zM9,3L7,3v2h2L9,3zM11,21h2v-2h-2v2zM19,13h2v-2h-2v2zM19,21c1.1,0 2,-0.9 2,-2h-2v2zM19,9h2L21,7h-2v2zM19,17h2v-2h-2v2zM15,21h2v-2h-2v2zM15,5h2L17,3h-2v2zM7,17h10L17,7L7,7v10zM9,9h6v6L9,15L9,9z"/>
|
<path android:fillColor="@android:color/white" android:pathData="M3,5h2L5,3c-1.1,0 -2,0.9 -2,2zM3,13h2v-2L3,11v2zM7,21h2v-2L7,19v2zM3,9h2L5,7L3,7v2zM13,3h-2v2h2L13,3zM19,3v2h2c0,-1.1 -0.9,-2 -2,-2zM5,21v-2L3,19c0,1.1 0.9,2 2,2zM3,17h2v-2L3,15v2zM9,3L7,3v2h2L9,3zM11,21h2v-2h-2v2zM19,13h2v-2h-2v2zM19,21c1.1,0 2,-0.9 2,-2h-2v2zM19,9h2L21,7h-2v2zM19,17h2v-2h-2v2zM15,21h2v-2h-2v2zM15,5h2L17,3h-2v2zM7,17h10L17,7L7,7v10zM9,9h6v6L9,15L9,9z"/>
|
||||||
|
|
|
||||||
14
app/src/main/res/drawable/rounded_corner_index.xml
Normal file
14
app/src/main/res/drawable/rounded_corner_index.xml
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||||
|
<solid android:color="?android:colorBackground" />
|
||||||
|
|
||||||
|
<padding
|
||||||
|
android:left="1dp"
|
||||||
|
android:right="1dp"
|
||||||
|
android:bottom="1dp"
|
||||||
|
android:top="1dp" />
|
||||||
|
|
||||||
|
<corners
|
||||||
|
android:topLeftRadius="5dp"
|
||||||
|
android:bottomRightRadius="5dp" />
|
||||||
|
</shape>
|
||||||
|
|
@ -21,25 +21,57 @@
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:paddingHorizontal="20dp"
|
android:paddingEnd="20dp"
|
||||||
|
android:paddingStart="10dp"
|
||||||
android:paddingVertical="10dp"
|
android:paddingVertical="10dp"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<com.google.android.material.checkbox.MaterialCheckBox
|
||||||
|
android:id="@+id/checkBox"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:minWidth="0dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<com.google.android.material.imageview.ShapeableImageView
|
<com.google.android.material.imageview.ShapeableImageView
|
||||||
android:id="@+id/downloads_image_view"
|
android:id="@+id/downloads_image_view"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
android:background="?attr/colorSurfaceVariant"
|
android:background="?attr/colorSurfaceVariant"
|
||||||
android:scaleType="centerCrop"
|
android:scaleType="centerCrop"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintDimensionRatio="H,16:9"
|
app:layout_constraintDimensionRatio="H,16:9"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/download_item_data"
|
app:layout_constraintEnd_toStartOf="@+id/download_item_data"
|
||||||
app:layout_constraintHorizontal_weight="0.3"
|
app:layout_constraintHorizontal_weight="0.3"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toEndOf="@id/checkBox"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:shapeAppearance="@style/ShapeAppearanceOverlay.Avatar2" />
|
app:shapeAppearance="@style/ShapeAppearanceOverlay.Avatar2" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/index"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:clickable="false"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:background="@drawable/rounded_corner_index"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:maxLength="17"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:text="1"
|
||||||
|
android:minWidth="10dp"
|
||||||
|
android:paddingHorizontal="5dp"
|
||||||
|
android:textSize="12sp"
|
||||||
|
app:layout_constraintTop_toTopOf="@+id/downloads_image_view"
|
||||||
|
app:layout_constraintStart_toStartOf="@+id/downloads_image_view" />
|
||||||
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/incognitoLabel"
|
android:id="@+id/incognitoLabel"
|
||||||
style="?attr/materialIconButtonStyle"
|
style="?attr/materialIconButtonStyle"
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
|
|
@ -34,6 +35,7 @@
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:id="@+id/downloadHeader"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="20dp"
|
android:layout_marginHorizontal="20dp"
|
||||||
|
|
@ -137,39 +139,126 @@
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:id="@+id/multiple_top_info"
|
android:id="@+id/multipleSelectHeader"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="20dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingTop="20dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/bottom_sheet_edit_title"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/edit"
|
||||||
|
android:textSize="25sp"
|
||||||
|
android:maxLines="2"
|
||||||
|
android:singleLine="false"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/bottomsheet_ok_button"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/bottom_sheet_edit_subtitle"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/edit_selected"
|
||||||
|
android:textSize="12sp"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/bottomsheet_ok_button"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/bottom_sheet_edit_title" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/bottomsheet_ok_button"
|
||||||
|
style="@style/Widget.Material3.Button.ElevatedButton.Icon"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:autoLink="all"
|
||||||
|
android:outlineProvider="none"
|
||||||
|
android:stateListAnimator="@null"
|
||||||
|
android:text="@string/ok"
|
||||||
|
app:icon="@drawable/ic_check"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
<TextView
|
<LinearLayout
|
||||||
android:id="@+id/count"
|
android:id="@+id/multiple_top_info"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingHorizontal="20dp"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
android:paddingTop="10dp"
|
app:layout_constraintEnd_toStartOf="@+id/selectRangeBtn"
|
||||||
android:textStyle="bold"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintHorizontal_bias="0.0"
|
app:layout_constraintHorizontal_bias="0.0"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/filesize"
|
android:id="@+id/count"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingHorizontal="20dp"
|
||||||
|
android:paddingTop="10dp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0.0"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/filesize"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="0dp"
|
||||||
|
android:paddingTop="10dp"
|
||||||
|
android:paddingEnd="20dp"
|
||||||
|
android:text="@string/file_size"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0.0"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/selectRangeBtn"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
android:paddingEnd="20dp"
|
style="@style/Widget.Material3.Button.IconButton"
|
||||||
android:paddingStart="0dp"
|
android:layout_width="wrap_content"
|
||||||
android:paddingTop="10dp"
|
app:icon="@drawable/baseline_format_list_numbered_24"
|
||||||
android:text="@string/file_size"
|
android:layout_height="wrap_content"
|
||||||
android:textStyle="bold"
|
android:contentDescription="@string/select_between"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/selectItemsMenu"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/selectItemsMenu"
|
||||||
|
android:visibility="gone"
|
||||||
|
style="@style/Widget.Material3.Button.IconButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:contentDescription="@string/settings"
|
||||||
|
app:icon="@drawable/baseline_more_vert_24"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintHorizontal_bias="0.0"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
</LinearLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/downloadMultipleRecyclerview"
|
android:id="@+id/downloadMultipleRecyclerview"
|
||||||
|
|
|
||||||
|
|
@ -38,8 +38,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:clickable="false"
|
android:clickable="false"
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:layout_margin="5dp"
|
android:background="@drawable/rounded_corner_index"
|
||||||
android:background="#80000000"
|
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
android:maxLength="17"
|
android:maxLength="17"
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,7 @@
|
||||||
app:borderWidth="0dp"
|
app:borderWidth="0dp"
|
||||||
android:contentDescription="@string/select_all"
|
android:contentDescription="@string/select_all"
|
||||||
android:layout_height="55dp"
|
android:layout_height="55dp"
|
||||||
|
android:backgroundTint="@android:color/transparent"
|
||||||
app:layout_anchor="@id/bottomAppBar"
|
app:layout_anchor="@id/bottomAppBar"
|
||||||
android:layout_marginHorizontal="5dp"
|
android:layout_marginHorizontal="5dp"
|
||||||
android:src="@drawable/ic_select_all"
|
android:src="@drawable/ic_select_all"
|
||||||
|
|
@ -129,6 +130,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:autoLink="all"
|
android:autoLink="all"
|
||||||
android:text="@string/ok"
|
android:text="@string/ok"
|
||||||
|
android:outlineProvider="none"
|
||||||
app:icon="@drawable/ic_check"
|
app:icon="@drawable/ic_check"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
|
|
||||||
54
app/src/main/res/layout/select_range_dialog.xml
Normal file
54
app/src/main/res/layout/select_range_dialog.xml
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginVertical="20dp"
|
||||||
|
android:layout_marginHorizontal="20dp"
|
||||||
|
android:gravity="center"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/from_textinput"
|
||||||
|
style="@style/Widget.Material3.TextInputLayout.FilledBox.Dense"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="45"
|
||||||
|
android:layout_marginEnd="10dp"
|
||||||
|
android:hint="@string/start">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="number"
|
||||||
|
android:maxLength="9" />
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/to_textinput"
|
||||||
|
style="@style/Widget.Material3.TextInputLayout.FilledBox.Dense"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/end"
|
||||||
|
android:layout_weight="45"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/colon">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="text"
|
||||||
|
android:maxLength="9" />
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
@ -28,13 +28,19 @@
|
||||||
app:actionLayout="@layout/bottom_app_bar_text"
|
app:actionLayout="@layout/bottom_app_bar_text"
|
||||||
app:showAsAction="always"/>
|
app:showAsAction="always"/>
|
||||||
|
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/select_items"
|
||||||
|
android:title="@string/select"
|
||||||
|
android:icon="@drawable/ic_select_all"
|
||||||
|
app:showAsAction="always"/>
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/incognito"
|
android:id="@+id/incognito"
|
||||||
android:title="@string/incognito"
|
android:title="@string/incognito"
|
||||||
android:icon="@drawable/ic_nightly"
|
android:icon="@drawable/ic_nightly"
|
||||||
app:showAsAction="always"/>
|
app:showAsAction="always"/>
|
||||||
|
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/more"
|
android:id="@+id/more"
|
||||||
android:title="@string/more"
|
android:title="@string/more"
|
||||||
|
|
|
||||||
30
app/src/main/res/menu/select_multiple_items_menu_context.xml
Normal file
30
app/src/main/res/menu/select_multiple_items_menu_context.xml
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
<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/select_between"
|
||||||
|
android:visible="false"
|
||||||
|
android:title="@string/select_between"
|
||||||
|
android:icon="@drawable/ic_select_between"
|
||||||
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/delete"
|
||||||
|
android:title="@string/Remove"
|
||||||
|
android:icon="@drawable/baseline_delete_24"
|
||||||
|
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>
|
||||||
|
|
||||||
|
|
@ -477,4 +477,5 @@
|
||||||
<string name="generate_potokens_warning">* By enabling this, you need to disable cookies</string>
|
<string name="generate_potokens_warning">* By enabling this, you need to disable cookies</string>
|
||||||
<string name="custom">Custom</string>
|
<string name="custom">Custom</string>
|
||||||
<string name="cut_unsupported">Cutting is not available for this item</string>
|
<string name="cut_unsupported">Cutting is not available for this item</string>
|
||||||
|
<string name="select_between_desc">Specify the range of items to select</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue