finish history pagination & other features

This commit is contained in:
zaednasr 2024-11-14 22:09:29 +01:00
parent f6c9b011f2
commit 448c4bc66d
No known key found for this signature in database
GPG key ID: 92B1DE23AD3D0E9E
16 changed files with 199 additions and 170 deletions

View file

@ -8,31 +8,12 @@ import androidx.room.Query
import androidx.room.Update
import com.deniscerri.ytdl.database.models.DownloadItem
import com.deniscerri.ytdl.database.models.HistoryItem
import com.deniscerri.ytdl.database.repository.HistoryRepository
import kotlinx.coroutines.flow.Flow
@Dao
interface HistoryDao {
@Query("SELECT * FROM history WHERE (title LIKE '%'||:query||'%' OR author LIKE '%'||:query||'%') AND type LIKE '%'||:type||'%' AND website LIKE '%'||:site||'%' ORDER BY " +
"CASE WHEN :sort = 'ASC' THEN id END ASC," +
"CASE WHEN :sort = 'DESC' THEN id END DESC," +
"CASE WHEN :sort = '' THEN id END DESC ")
fun getHistorySortedByID(query : String, type : String, site : String, sort : String) : List<HistoryItem>
@Query("SELECT * FROM history WHERE (title LIKE '%'||:query||'%' OR author LIKE '%'||:query||'%') AND type LIKE '%'||:type||'%' AND website LIKE '%'||:site||'%' ORDER BY " +
"CASE WHEN :sort = 'ASC' THEN title END ASC," +
"CASE WHEN :sort = 'DESC' THEN title END DESC," +
"CASE WHEN :sort = '' THEN title END DESC ")
fun getHistorySortedByTitle(query : String, type : String, site : String, sort : String) : List<HistoryItem>
@Query("SELECT * FROM history WHERE (title LIKE '%'||:query||'%' OR author LIKE '%'||:query||'%') AND type LIKE '%'||:type||'%' AND website LIKE '%'||:site||'%' ORDER BY " +
"CASE WHEN :sort = 'ASC' THEN author END ASC," +
"CASE WHEN :sort = 'DESC' THEN author END DESC," +
"CASE WHEN :sort = '' THEN author END DESC ")
fun getHistorySortedByAuthor(query : String, type : String, site : String, sort : String) : List<HistoryItem>
@Query("SELECT * FROM history WHERE (title LIKE '%'||:query||'%' OR author LIKE '%'||:query||'%') AND type LIKE '%'||:type||'%' AND website LIKE '%'||:site||'%' ORDER BY " +
"CASE WHEN :sort = 'ASC' THEN id END ASC," +
"CASE WHEN :sort = 'DESC' THEN id END DESC," +
@ -57,6 +38,29 @@ interface HistoryDao {
"CASE WHEN :sort = '' THEN filesize END DESC ")
fun getHistorySortedByFilesizePaginated(query : String, type : String, site : String, sort : String) : PagingSource<Int, HistoryItem>
@Query("SELECT id, downloadPath FROM history WHERE (title LIKE '%'||:query||'%' OR author LIKE '%'||:query||'%') AND type LIKE '%'||:type||'%' AND website LIKE '%'||:site||'%' ORDER BY " +
"CASE WHEN :sort = 'ASC' THEN id END ASC," +
"CASE WHEN :sort = 'DESC' THEN id END DESC," +
"CASE WHEN :sort = '' THEN id END DESC ")
fun getHistoryIDsSortedByID(query : String, type : String, site : String, sort : String) : List<HistoryRepository.HistoryIDsAndPaths>
@Query("SELECT id, downloadPath FROM history WHERE (title LIKE '%'||:query||'%' OR author LIKE '%'||:query||'%') AND type LIKE '%'||:type||'%' AND website LIKE '%'||:site||'%' ORDER BY " +
"CASE WHEN :sort = 'ASC' THEN title END ASC," +
"CASE WHEN :sort = 'DESC' THEN title END DESC," +
"CASE WHEN :sort = '' THEN title END DESC ")
fun getHistoryIDsSortedByTitle(query : String, type : String, site : String, sort : String) : List<HistoryRepository.HistoryIDsAndPaths>
@Query("SELECT id, downloadPath FROM history WHERE (title LIKE '%'||:query||'%' OR author LIKE '%'||:query||'%') AND type LIKE '%'||:type||'%' AND website LIKE '%'||:site||'%' ORDER BY " +
"CASE WHEN :sort = 'ASC' THEN author END ASC," +
"CASE WHEN :sort = 'DESC' THEN author END DESC," +
"CASE WHEN :sort = '' THEN author END DESC ")
fun getHistoryIDsSortedByAuthor(query : String, type : String, site : String, sort : String) : List<HistoryRepository.HistoryIDsAndPaths>
@Query("SELECT id, downloadPath FROM history WHERE (title LIKE '%'||:query||'%' OR author LIKE '%'||:query||'%') AND type LIKE '%'||:type||'%' AND website LIKE '%'||:site||'%' ORDER BY " +
"CASE WHEN :sort = 'ASC' THEN filesize END ASC," +
"CASE WHEN :sort = 'DESC' THEN filesize END DESC," +
"CASE WHEN :sort = '' THEN filesize END DESC ")
fun getHistoryIDsSortedByFilesize(query : String, type : String, site : String, sort : String) : List<HistoryRepository.HistoryIDsAndPaths>
@Query("SELECT * FROM history")
fun getAllHistory() : Flow<List<HistoryItem>>
@ -79,6 +83,12 @@ interface HistoryDao {
@Query("SELECT * FROM history WHERE url=:url")
fun getAllHistoryByURL(url: String) : List<HistoryItem>
@Query("SELECT * FROM history WHERE id in (:ids)")
fun getAllHistoryByIDs(ids: List<Long>) : List<HistoryItem>
@Query("SELECT downloadPath FROM history WHERE id in (:ids)")
fun getDownloadPathsFromIDs(ids: List<Long>) : List<HistoryRepository.HistoryItemDownloadPaths>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(item: HistoryItem)
@ -88,6 +98,9 @@ interface HistoryDao {
@Query("DELETE FROM history")
suspend fun deleteAll()
@Query("DELETE FROM history where id in (:ids)")
suspend fun deleteAllByIDs(ids: List<Long>)
@Query("DELETE FROM history WHERE id > (SELECT MIN(h.id) FROM history h WHERE h.url = history.url AND h.type = history.type)")
suspend fun deleteDuplicates()

View file

@ -35,19 +35,17 @@ class HistoryRepository(private val historyDao: HistoryDao) {
return historyDao.getAllHistoryByURL(url)
}
data class HistoryIDsAndPaths(
val id: Long,
val downloadPath: List<String>
)
fun getFiltered(query : String, type : String, site : String, sortType: HistorySortType, sort: SORTING, statusFilter: HistoryViewModel.HistoryStatus) : List<HistoryItem> {
fun getFilteredIDs (query : String, type : String, site : String, sortType: HistorySortType, sort: SORTING, statusFilter: HistoryViewModel.HistoryStatus) : List<Long> {
var filtered = when(sortType){
HistorySortType.DATE -> historyDao.getHistorySortedByID(query, type, site, sort.toString())
HistorySortType.TITLE -> historyDao.getHistorySortedByTitle(query, type, site, sort.toString())
HistorySortType.AUTHOR -> historyDao.getHistorySortedByAuthor(query, type, site, sort.toString())
HistorySortType.FILESIZE -> {
val items = historyDao.getHistorySortedByID(query, type, site, sort.toString())
when(sort){
SORTING.DESC -> items.sortedByDescending { it.format.filesize }
SORTING.ASC -> items.sortedBy { it.format.filesize }
}
}
HistorySortType.DATE -> historyDao.getHistoryIDsSortedByID(query, type, site, sort.toString())
HistorySortType.TITLE -> historyDao.getHistoryIDsSortedByTitle(query, type, site, sort.toString())
HistorySortType.AUTHOR -> historyDao.getHistoryIDsSortedByAuthor(query, type, site, sort.toString())
HistorySortType.FILESIZE -> historyDao.getHistoryIDsSortedByFilesize(query, type, site, sort.toString())
}
when(statusFilter) {
@ -59,8 +57,7 @@ class HistoryRepository(private val historyDao: HistoryDao) {
}
else -> {}
}
return filtered
return filtered.map { it.id }
}
fun getPaginatedSource(query : String, type : String, site : String, sortType: HistorySortType, sort: SORTING) : PagingSource<Int, HistoryItem> {
@ -101,6 +98,26 @@ class HistoryRepository(private val historyDao: HistoryDao) {
historyDao.deleteAll()
}
suspend fun deleteAllWithIDs(ids: List<Long>, deleteFile: Boolean = false){
if (deleteFile){
historyDao.getAllHistoryByIDs(ids).forEach { item ->
item.downloadPath.forEach {
FileUtil.deleteFile(it)
}
}
}
historyDao.deleteAllByIDs(ids)
}
data class HistoryItemDownloadPaths(
val downloadPath: List<String>
)
fun getDownloadPathsFromIDs(ids: List<Long>) : List<List<String>> {
val res = historyDao.getDownloadPathsFromIDs(ids)
return res.map { it.downloadPath }
}
suspend fun deleteDuplicates(){
historyDao.deleteDuplicates()
}

View file

@ -118,7 +118,6 @@ class ResultRepository(private val resultDao: ResultDao, private val context: Co
if (resetResults) deleteAll()
//throw YoutubeDLException("Youtube Watch Videos is not yet supported in data fetching. You can download it directly by clicking Continue Anyway or by Quick Downloading it!")
//TODO use below code after youtubedl-android has fixed issue #295 in their repo
val items = mutableListOf<ResultItem>()
val ytExtractorResult = newPipeUtil?.getPlaylistData(inputQuery) {
if (addToResults){

View file

@ -33,6 +33,7 @@ import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@OptIn(ExperimentalCoroutinesApi::class)
class HistoryViewModel(application: Application) : AndroidViewModel(application) {
@ -52,7 +53,7 @@ class HistoryViewModel(application: Application) : AndroidViewModel(application)
var paginatedItems : Flow<PagingData<HistoryItem>>
var websites : Flow<List<String>>
var totalCount : Flow<Int>
var totalCount = MutableStateFlow(0)
data class HistoryFilters(
var type: String = "",
@ -67,7 +68,6 @@ class HistoryViewModel(application: Application) : AndroidViewModel(application)
val dao = DBManager.getInstance(application).historyDao
repository = HistoryRepository(dao)
websites = repository.websites
totalCount = repository.count
val filters = listOf(dao.getAllHistory(), sortOrder, sortType, websiteFilter, statusFilter, queryFilter, typeFilter)
paginatedItems = combine(filters) { f ->
@ -107,6 +107,10 @@ class HistoryViewModel(application: Application) : AndroidViewModel(application)
else -> {}
}
withContext(Dispatchers.IO) {
totalCount.value = repository.getFilteredIDs(query, type, website, sortType, sortOrder, status).count()
}
pager
}.flatMapLatest { it }
}
@ -138,9 +142,16 @@ class HistoryViewModel(application: Application) : AndroidViewModel(application)
statusFilter.value = status
}
private fun filter(query : String, format : String, site : String, sortType: HistorySortType, sort: SORTING, statusFilter: HistoryStatus) = viewModelScope.launch(Dispatchers.IO){
fun getIDsBetweenTwoItems(firstID: Long, secondID: Long): List<Long> {
val ids = repository.getFilteredIDs(queryFilter.value, typeFilter.value, websiteFilter.value, sortType.value, sortOrder.value, statusFilter.value)
val firstIndex = ids.indexOf(firstID)
val secondIndex = ids.indexOf(secondID)
return ids.filterIndexed {index, _ -> index in (firstIndex + 1) until secondIndex }
}
fun getItemIDsNotPresentIn(not: List<Long>) : List<Long> {
val ids = repository.getFilteredIDs(queryFilter.value, typeFilter.value, websiteFilter.value, sortType.value, sortOrder.value, statusFilter.value)
return ids.filter { !not.contains(it) }
}
fun getAll() : List<HistoryItem> {
@ -159,6 +170,14 @@ class HistoryViewModel(application: Application) : AndroidViewModel(application)
repository.delete(item, deleteFile)
}
fun deleteAllWithIDs(ids: List<Long>, deleteFile: Boolean = false) = viewModelScope.launch(Dispatchers.IO) {
repository.deleteAllWithIDs(ids, deleteFile)
}
fun getDownloadPathsFromIDs(ids: List<Long>) : List<List<String>> {
return repository.getDownloadPathsFromIDs(ids)
}
fun deleteAll(deleteFile: Boolean = false) = viewModelScope.launch(Dispatchers.IO) {
repository.deleteAll(deleteFile)
}
@ -175,16 +194,4 @@ class HistoryViewModel(application: Application) : AndroidViewModel(application)
repository.clearDeletedHistory()
}
fun getRecordsBetweenTwoItems(item1: Long, item2: Long) : List<HistoryItem> {
val filtered = repository.getFiltered(queryFilter.value!!, typeFilter.value!!, websiteFilter.value!!, sortType.value!!, sortOrder.value!!, statusFilter.value!!)
val firstIndex = filtered.indexOfFirst { it.id == item1 }
val secondIndex = filtered.indexOfFirst { it.id == item2 }
return if(firstIndex > secondIndex) {
filtered.filterIndexed { index, _ -> index in (secondIndex + 1) until firstIndex }
}else{
filtered.filterIndexed { index, _ -> index in (firstIndex + 1) until secondIndex }
}
}
}

View file

@ -84,6 +84,7 @@ class HistoryPaginatedAdapter(onItemClickListener: OnItemClickListener, activity
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = getItem(position) ?: return
val card = holder.cardView
holder.itemView.tag = item.id.toString()
card.tag = item.id.toString()
card.popup()
@ -147,7 +148,7 @@ class HistoryPaginatedAdapter(onItemClickListener: OnItemClickListener, activity
if (btn.hasOnClickListeners()) btn.setOnClickListener(null)
btn.isClickable = filesPresent
if (checkedItems.contains(item.id)) {
if ((checkedItems.contains(item.id) && !inverted) || (!checkedItems.contains(item.id) && inverted)) {
card.isChecked = true
card.strokeWidth = 5
} else {
@ -156,12 +157,12 @@ class HistoryPaginatedAdapter(onItemClickListener: OnItemClickListener, activity
}
val finalFilePresent = filesPresent
card.setOnLongClickListener {
checkCard(card, item.id)
checkCard(card, item.id, position)
true
}
card.setOnClickListener {
if (checkedItems.size > 0) {
checkCard(card, item.id)
checkCard(card, item.id, position)
} else {
onItemClickListener.onCardClick(item.id, finalFilePresent)
}
@ -208,7 +209,7 @@ class HistoryPaginatedAdapter(onItemClickListener: OnItemClickListener, activity
}
}
private fun checkCard(card: MaterialCardView, itemID: Long) {
private fun checkCard(card: MaterialCardView, itemID: Long, position: Int) {
if (card.isChecked) {
card.strokeWidth = 0
if (inverted) checkedItems.add(itemID)
@ -219,13 +220,13 @@ class HistoryPaginatedAdapter(onItemClickListener: OnItemClickListener, activity
else checkedItems.add(itemID)
}
card.isChecked = !card.isChecked
onItemClickListener.onCardSelect(itemID, card.isChecked)
onItemClickListener.onCardSelect(card.isChecked, position)
}
interface OnItemClickListener {
fun onCardClick(itemID: Long, isPresent: Boolean)
fun onButtonClick(itemID: Long, isPresent: Boolean)
fun onCardSelect(itemID: Long, isChecked: Boolean)
fun onButtonClick(itemID: Long, filePresent: Boolean)
fun onCardClick(itemID: Long, filePresent: Boolean)
fun onCardSelect(isChecked: Boolean, position: Int)
}
companion object {

View file

@ -309,7 +309,7 @@ class DownloadBottomSheetDialog : BottomSheetDialogFragment() {
scheduleBtn.setOnClickListener{
UiUtil.showDatePicker(fragmentManager) {
UiUtil.showDatePicker(fragmentManager, sharedPreferences) {
lifecycleScope.launch {
resultViewModel.cancelUpdateItemData()
resultViewModel.cancelUpdateFormatsItemData()

View file

@ -220,7 +220,7 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
scheduleBtn.setOnClickListener{
UiUtil.showDatePicker(parentFragmentManager) { cal ->
UiUtil.showDatePicker(parentFragmentManager, preferences) { cal ->
toggleLoading(true)
lifecycleScope.launch {
withContext(Dispatchers.IO){

View file

@ -315,7 +315,7 @@ class ObserveSourcesBottomSheetDialog : BottomSheetDialogFragment() {
isFocusable = false
isClickable = false
setOnClickListener{
UiUtil.showTimePicker(fragmentManager){
UiUtil.showTimePicker(fragmentManager, sharedPreferences){
everyTime.editText?.setText(
SimpleDateFormat(DateFormat.getBestDateTimePattern(Locale.getDefault(), "HHmm"), Locale.getDefault()).format(it.timeInMillis)
)

View file

@ -228,7 +228,7 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL
}
override fun onItemClick(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) {
TODO("Not yet implemented")
}

View file

@ -48,6 +48,7 @@ import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdl.database.viewmodel.HistoryViewModel
import com.deniscerri.ytdl.ui.adapter.HistoryPaginatedAdapter
import com.deniscerri.ytdl.util.Extensions.enableFastScroll
import com.deniscerri.ytdl.util.Extensions.toListString
import com.deniscerri.ytdl.util.FileUtil
import com.deniscerri.ytdl.util.NavbarUtil
import com.deniscerri.ytdl.util.UiUtil
@ -523,14 +524,10 @@ class HistoryFragment : Fragment(), HistoryPaginatedAdapter.OnItemClickListener{
}
}
override fun onCardSelect(itemID: Long, isChecked: Boolean) {
override fun onCardSelect(isChecked: Boolean, position: Int) {
lifecycleScope.launch {
val item = withContext(Dispatchers.IO) {
historyViewModel.getByID(itemID)
}
if (actionMode == null) actionMode = (activity as AppCompatActivity?)!!.startSupportActionMode(contextualActionBar)
val selectedObjects = historyAdapter.getSelectedObjectsCount(totalCount)
if (actionMode == null) actionMode = (activity as AppCompatActivity?)!!.startSupportActionMode(contextualActionBar)
actionMode?.apply {
if (selectedObjects == 0){
this.finish()
@ -538,15 +535,28 @@ class HistoryFragment : Fragment(), HistoryPaginatedAdapter.OnItemClickListener{
actionMode?.title = "$selectedObjects ${getString(R.string.selected)}"
this.menu.findItem(R.id.select_between).isVisible = false
if(selectedObjects == 2){
//TODO
// val selectedIDs = contextualActionBar.getSelectedIDs().sortedBy { it }
// val resultsInMiddle = withContext(Dispatchers.IO){
// historyViewModel.getRecordsBetweenTwoItems(selectedIDs.first().id, selectedIDs.last().id)
// }.toMutableList()
// this.menu.findItem(R.id.select_between).isVisible = resultsInMiddle.isNotEmpty()
val selectedIDs = contextualActionBar.getSelectedIDs().sortedBy { it }
val idsInMiddle = withContext(Dispatchers.IO){
historyViewModel.getIDsBetweenTwoItems(selectedIDs.first(), selectedIDs.last())
}
this.menu.findItem(R.id.select_between).isVisible = idsInMiddle.isNotEmpty()
}
}
}
if (isChecked) {
if (actionMode == null){
actionMode = (getActivity() as AppCompatActivity?)!!.startSupportActionMode(contextualActionBar)
}else{
actionMode!!.title = "$selectedObjects ${getString(R.string.selected)}"
}
}
else {
actionMode?.title = "$selectedObjects ${getString(R.string.selected)}"
if (selectedObjects == 0){
actionMode?.finish()
}
}
}
}
@ -573,66 +583,63 @@ class HistoryFragment : Fragment(), HistoryPaginatedAdapter.OnItemClickListener{
): Boolean {
return when (item!!.itemId) {
R.id.select_between -> {
//TODO
// lifecycleScope.launch {
// val selectedIDs = selectedObjects.sortedBy { it.id }
// val resultsInMiddle = withContext(Dispatchers.IO){
// historyViewModel.getRecordsBetweenTwoItems(selectedIDs.first().id, selectedIDs.last().id)
// }.toMutableList()
// if (resultsInMiddle.isNotEmpty()){
// selectedObjects.addAll(resultsInMiddle)
// historyAdapter.checkMultipleItems(selectedObjects.map { it.id })
// actionMode?.title = "${selectedObjects.count()} ${getString(R.string.selected)}"
// }
// mode?.menu?.findItem(R.id.select_between)?.isVisible = false
// }
lifecycleScope.launch {
val selectedIDs = getSelectedIDs().sortedBy { it }
val idsInMiddle = withContext(Dispatchers.IO){
historyViewModel.getIDsBetweenTwoItems(selectedIDs.first(), selectedIDs.last())
}.toMutableList()
idsInMiddle.addAll(selectedIDs)
if (idsInMiddle.isNotEmpty()){
historyAdapter.checkMultipleItems(idsInMiddle)
actionMode?.title = "${idsInMiddle.count()} ${getString(R.string.selected)}"
}
mode?.menu?.findItem(R.id.select_between)?.isVisible = false
}
true
}
R.id.delete_results -> {
//TODO
// val deleteFile = booleanArrayOf(false)
// val deleteDialog = MaterialAlertDialogBuilder(fragmentContext!!)
// deleteDialog.setTitle(getString(R.string.you_are_going_to_delete_multiple_items))
// deleteDialog.setMultiChoiceItems(
// arrayOf(getString(R.string.delete_files_too)),
// booleanArrayOf(false)
// ) { _: DialogInterface?, _: Int, b: Boolean -> deleteFile[0] = b }
// deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
// deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
// for (obj in selectedObjects){
// historyViewModel.delete(obj, deleteFile[0])
// }
// clearCheckedItems()
// actionMode?.finish()
// }
// deleteDialog.show()
val deleteFile = booleanArrayOf(false)
val deleteDialog = MaterialAlertDialogBuilder(fragmentContext!!)
deleteDialog.setTitle(getString(R.string.you_are_going_to_delete_multiple_items))
deleteDialog.setMultiChoiceItems(
arrayOf(getString(R.string.delete_files_too)),
booleanArrayOf(false)
) { _: DialogInterface?, _: Int, b: Boolean -> deleteFile[0] = b }
deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
lifecycleScope.launch {
val selectedObjects = getSelectedIDs()
historyAdapter.clearCheckedItems()
historyViewModel.deleteAllWithIDs(selectedObjects, deleteFile[0])
actionMode?.finish()
}
}
deleteDialog.show()
true
}
R.id.share -> {
//TODO
// FileUtil.shareFileIntent(requireContext(), selectedObjects.map { it.downloadPath }.flatten())
// clearCheckedItems()
// actionMode?.finish()
lifecycleScope.launch {
val selectedObjects = getSelectedIDs()
val paths = withContext(Dispatchers.IO){
historyViewModel.getDownloadPathsFromIDs(selectedObjects)
}
FileUtil.shareFileIntent(requireContext(), paths.flatten())
historyAdapter.clearCheckedItems()
actionMode?.finish()
}
true
}
R.id.select_all -> {
//TODO
// historyAdapter.checkAll()
// historyList?.forEach { selectedObjects.add(it!!) }
// mode?.title = "(${selectedObjects.size}) ${resources.getString(R.string.all_items_selected)}"
historyAdapter.checkAll()
val selectedCount = historyAdapter.getSelectedObjectsCount(totalCount)
mode?.title = "(${selectedCount}) ${resources.getString(R.string.all_items_selected)}"
true
}
R.id.invert_selected -> {
//TODO
// historyAdapter.invertSelected()
// val invertedList = arrayListOf<HistoryItem>()
// historyList?.forEach {
// if (!selectedObjects.contains(it)!!) invertedList.add(it!!)
// }
// selectedObjects.clear()
// selectedObjects.addAll(invertedList)
// actionMode!!.title = "${selectedObjects.size} ${getString(R.string.selected)}"
// if (invertedList.isEmpty()) actionMode?.finish()
historyAdapter.invertSelected()
val selectedCount = historyAdapter.getSelectedObjectsCount(totalCount)
actionMode?.title = "$selectedCount ${getString(R.string.selected)}"
if (selectedCount == 0) actionMode?.finish()
true
}
else -> false
@ -647,15 +654,13 @@ class HistoryFragment : Fragment(), HistoryPaginatedAdapter.OnItemClickListener{
}
suspend fun getSelectedIDs() : List<Long>{
//TODO
// return if (historyAdapter.inverted || historyAdapter.checkedItems.isEmpty()) {
// withContext(Dispatchers.IO){
// historyViewModel.getItemIDsNotPresentIn(historyAdapter.checkedItems.toList())
// }
// }else{
// historyAdapter.checkedItems.toList()
// }
return listOf()
return if (historyAdapter.inverted || historyAdapter.checkedItems.isEmpty()){
withContext(Dispatchers.IO){
historyViewModel.getItemIDsNotPresentIn(historyAdapter.checkedItems.toList())
}
}else{
historyAdapter.checkedItems.toList()
}
}
}

View file

@ -4,6 +4,7 @@ import android.animation.AnimatorSet
import android.annotation.SuppressLint
import android.app.Activity
import android.content.DialogInterface
import android.content.SharedPreferences
import android.graphics.Canvas
import android.graphics.Color
import android.os.Bundle
@ -66,6 +67,7 @@ class QueuedDownloadsFragment : Fragment(), QueuedDownloadAdapter.OnItemClickLis
private lateinit var notificationUtil: NotificationUtil
private lateinit var fileSize: TextView
private lateinit var dragHandleToggle: TextView
private lateinit var sharedPreferences: SharedPreferences
private var totalSize: Int = 0
private var actionMode : ActionMode? = null
@ -84,6 +86,7 @@ class QueuedDownloadsFragment : Fragment(), QueuedDownloadAdapter.OnItemClickLis
@SuppressLint("SetTextI18n", "RestrictedApi")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
fileSize = view.findViewById(R.id.filesize)
dragHandleToggle = view.findViewById(R.id.drag)
val itemTouchHelper = ItemTouchHelper(queuedDragDropHelper)
@ -473,7 +476,7 @@ class QueuedDownloadsFragment : Fragment(), QueuedDownloadAdapter.OnItemClickLis
}
},
scheduleButtonClick = {downloadItem ->
UiUtil.showDatePicker(parentFragmentManager) {
UiUtil.showDatePicker(parentFragmentManager, sharedPreferences) {
Toast.makeText(context, getString(R.string.download_rescheduled_to) + " " + it.time, Toast.LENGTH_LONG).show()
downloadViewModel.deleteDownload(downloadItem.id)
downloadItem.downloadStartTime = it.timeInMillis

View file

@ -198,7 +198,7 @@ class ScheduledDownloadsFragment : Fragment(), ScheduledDownloadAdapter.OnItemCl
)
},
scheduleButtonClick = {downloadItem ->
UiUtil.showDatePicker(parentFragmentManager) {
UiUtil.showDatePicker(parentFragmentManager, preferences) {
Toast.makeText(context, getString(R.string.download_rescheduled_to) + " " + it.time, Toast.LENGTH_LONG).show()
downloadViewModel.deleteDownload(downloadItem.id)
downloadItem.downloadStartTime = it.timeInMillis

View file

@ -35,17 +35,6 @@ class DownloadSettingsFragment : BaseSettingsFragment() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.downloading_preferences, rootKey)
val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
findPreference<Preference>("prevent_duplicate_downloads")?.apply {
//TODO transitioning code, delete after couple releases
if (preferences.getBoolean("download_archive", false)){
preferences.edit(commit = true){
putBoolean("download_archive", false).apply()
putString("prevent_duplicate_downloads", "download_archive")
}
}
}
val rememberDownloadType = findPreference<SwitchPreferenceCompat>("remember_download_type")
val downloadType = findPreference<ListPreference>("preferred_download_type")
downloadType?.isEnabled = rememberDownloadType?.isChecked == false
@ -163,7 +152,7 @@ class DownloadSettingsFragment : BaseSettingsFragment() {
}
scheduleStart?.setOnPreferenceClickListener {
UiUtil.showTimePicker(parentFragmentManager){
UiUtil.showTimePicker(parentFragmentManager, preferences){
val hr = it.get(Calendar.HOUR_OF_DAY)
val mn = it.get(Calendar.MINUTE)
val formattedTime = String.format("%02d", hr) + ":" + String.format("%02d", mn)
@ -176,7 +165,7 @@ class DownloadSettingsFragment : BaseSettingsFragment() {
}
scheduleEnd?.setOnPreferenceClickListener {
UiUtil.showTimePicker(parentFragmentManager){
UiUtil.showTimePicker(parentFragmentManager, preferences){
val hr = it.get(Calendar.HOUR_OF_DAY)
val mn = it.get(Calendar.MINUTE)
val formattedTime = String.format("%02d", hr) + ":" + String.format("%02d", mn)

View file

@ -10,6 +10,7 @@ import android.content.ClipboardManager
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.content.SharedPreferences
import android.net.Uri
import android.os.Build
import android.text.Editable
@ -413,7 +414,7 @@ object UiUtil {
datePicker.show(fragmentManager, "datepicker")
}
fun showDatePicker(fragmentManager: FragmentManager , onSubmit : (chosenDate: Calendar) -> Unit ){
fun showDatePicker(fragmentManager: FragmentManager , preferences: SharedPreferences, onSubmit : (chosenDate: Calendar) -> Unit ){
val currentDate = Calendar.getInstance()
currentDate.timeInMillis = (currentDate.timeInMillis - (currentDate.timeInMillis % 1800000)) + 1800000
val date = Calendar.getInstance()
@ -430,38 +431,35 @@ object UiUtil {
datePicker.addOnPositiveButtonClickListener{
date.timeInMillis = it
val timepicker = MaterialTimePicker.Builder()
.setTimeFormat(TimeFormat.CLOCK_24H)
.setHour(currentDate.get(Calendar.HOUR_OF_DAY))
.setMinute(currentDate.get(Calendar.MINUTE))
.build()
timepicker.addOnPositiveButtonClickListener{
date[Calendar.HOUR_OF_DAY] = timepicker.hour
date[Calendar.MINUTE] = timepicker.minute
showTimePicker(fragmentManager, preferences) { chosenTime ->
date[Calendar.HOUR_OF_DAY] = chosenTime[Calendar.HOUR_OF_DAY]
date[Calendar.MINUTE] = chosenTime[Calendar.MINUTE]
onSubmit(date)
}
timepicker.show(fragmentManager, "timepicker")
}
datePicker.show(fragmentManager, "datepicker")
}
fun showTimePicker(fragmentManager: FragmentManager , onSubmit : (chosenTime: Calendar) -> Unit ){
fun showTimePicker(fragmentManager: FragmentManager , preferences: SharedPreferences, onSubmit : (chosenTime: Calendar) -> Unit ){
val currentDate = Calendar.getInstance()
currentDate.timeInMillis = (currentDate.timeInMillis - (currentDate.timeInMillis % 1800000)) + 1800000
val date = Calendar.getInstance()
val lastTime = preferences.getString("latest_timepicker_date", "${currentDate.get(Calendar.HOUR_OF_DAY)}:${currentDate.get(Calendar.MINUTE)}")!!
val hour = lastTime.split(":")[0].toInt()
val minute = lastTime.split(":")[1].toInt()
val timepicker = MaterialTimePicker.Builder()
.setTimeFormat(TimeFormat.CLOCK_24H)
.setHour(currentDate.get(Calendar.HOUR_OF_DAY))
.setMinute(currentDate.get(Calendar.MINUTE))
.setHour(hour)
.setMinute(minute)
.build()
timepicker.addOnPositiveButtonClickListener{
date[Calendar.HOUR_OF_DAY] = timepicker.hour
date[Calendar.MINUTE] = timepicker.minute
preferences.edit().putString("latest_timepicker_date", "${timepicker.hour}:${timepicker.minute}").apply()
onSubmit(date)
}
timepicker.show(fragmentManager, "timepicker")

View file

@ -151,8 +151,7 @@ class NewPipeUtil(context: Context) {
fun getChannelData(url: String, progress: (pagedResults: MutableList<ResultItem>) -> Unit) : Result<List<ResultItem>> {
try {
//TODO BROKEN FOR NOW
return Result.failure(Throwable())
//return Result.failure(Throwable())
val req = ChannelInfo.getInfo(ServiceList.YouTube, url)
println(Gson().toJson(req))
val items = mutableListOf<ResultItem>()

View file

@ -49,17 +49,15 @@
</shortcut>
<shortcut
android:shortcutId="newTemplate"
android:shortcutId="terminal"
android:enabled="true"
android:icon="@drawable/ic_terminal_red"
android:shortcutShortLabel="@string/new_template"
android:shortcutDisabledMessage="@string/new_template">
android:shortcutShortLabel="@string/terminal"
android:shortcutDisabledMessage="@string/terminal">
<intent
android:action="android.intent.action.VIEW"
android:action="android.intent.category.DEFAULT"
android:targetPackage="com.deniscerri.ytdl"
android:targetClass="com.deniscerri.ytdl.receiver.TransparentActivity">
<extra android:name="action" android:value="NEW_TEMPLATE" />
android:targetClass="com.deniscerri.ytdl.ui.more.terminal.TerminalActivity">
</intent>
</shortcut>