From 68c3d28b4bc7b5cc4038648d5f187fe4da9a42a9 Mon Sep 17 00:00:00 2001 From: Jay Date: Tue, 7 Jan 2020 23:32:30 -0800 Subject: [PATCH] The Downloads Update Pending downloads can be move to the top or bottom of the queue with a menu button on the right side, they can also be cancelled Mass Migration now shows progress and total manga in the title Fixed the issue where deleted downloads using the old folder format said they weren't (they were) Fixed cancelled downloads not deleting the temp folder Changed the format of downloads yet again, now it's just chapter id and the name Added option to reorder pending downloads by newest or oldest chapter --- .../tachiyomi/data/download/DownloadCache.kt | 11 +- .../data/download/DownloadManager.kt | 17 ++- .../data/download/DownloadProvider.kt | 31 ++++- .../tachiyomi/ui/download/DownloadAdapter.kt | 6 +- .../ui/download/DownloadController.kt | 50 +++++++- .../tachiyomi/ui/download/DownloadHolder.kt | 42 ++++++- .../ui/download/DownloadPresenter.kt | 5 + .../tachiyomi/ui/library/LibraryController.kt | 3 +- .../manga/process/MigrationListController.kt | 9 +- .../manga/process/MigrationProcessAdapter.kt | 2 + app/src/main/res/layout/download_item.xml | 117 +++++++++++------- app/src/main/res/menu/download_queue.xml | 15 +++ app/src/main/res/menu/download_single.xml | 11 ++ app/src/main/res/menu/library.xml | 4 +- app/src/main/res/menu/library_selection.xml | 2 +- app/src/main/res/values/strings.xml | 18 +-- 16 files changed, 268 insertions(+), 75 deletions(-) create mode 100644 app/src/main/res/menu/download_single.xml diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadCache.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadCache.kt index 2912cdca57..b1029b5fbc 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadCache.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadCache.kt @@ -7,6 +7,7 @@ import eu.kanade.tachiyomi.data.database.models.Chapter import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.getOrDefault +import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.SourceManager import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get @@ -203,13 +204,15 @@ class DownloadCache( * @param manga the manga of the chapter. */ @Synchronized - fun removeChapters(chapters: List, manga: Manga) { + fun removeChapters(chapters: List, manga: Manga, source: Source) { val sourceDir = rootDir.files[manga.source] ?: return val mangaDir = sourceDir.files[provider.getMangaDirName(manga)] ?: return for (chapter in chapters) { - val chapterDirName = provider.getChapterDirName(chapter) - if (chapterDirName in mangaDir.files) { - mangaDir.files -= chapterDirName + val list = provider.getValidChapterDirNames(chapter) + list.forEach { + if (it in mangaDir.files) { + mangaDir.files -= it + } } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt index 2a0b92aca2..ec8fc455d0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt @@ -20,7 +20,7 @@ import uy.kohesive.injekt.injectLazy * * @param context the application context. */ -class DownloadManager(context: Context) { +class DownloadManager(val context: Context) { /** * The sources manager. @@ -99,7 +99,12 @@ class DownloadManager(context: Context) { * @param downloads value to set the download queue to */ fun reorderQueue(downloads: List) { - val wasPaused = downloader.isPaused() + val wasPaused = isPaused() + if (downloads.isEmpty()) { + DownloadService.stop(context) + downloader.queue.clear() + return + } downloader.pause() downloader.queue.clear() downloader.queue.addAll(downloads) @@ -108,6 +113,8 @@ class DownloadManager(context: Context) { } } + fun isPaused() = downloader.isPaused() + /** * Tells the downloader to enqueue the given list of chapters. @@ -175,7 +182,7 @@ class DownloadManager(context: Context) { } /** - * Deletes the directories of a list of downloaded chapters. + * Deletes the directories of a list of partially downloaded chapters. * * @param chapters the list of chapters to delete. * @param manga the manga of the chapters. @@ -183,9 +190,9 @@ class DownloadManager(context: Context) { */ fun deleteChapters(chapters: List, manga: Manga, source: Source) { queue.remove(chapters) - val chapterDirs = provider.findChapterDirs(chapters, manga, source) + val chapterDirs = provider.findChapterDirs(chapters, manga, source) + provider.findTempChapterDirs(chapters, manga, source) chapterDirs.forEach { it.delete() } - cache.removeChapters(chapters, manga) + cache.removeChapters(chapters, manga, source) if (cache.getDownloadCount(manga) == 0) { // Delete manga directory if empty chapterDirs.firstOrNull()?.parentFile?.delete() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadProvider.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadProvider.kt index 087891444d..6581e6c711 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadProvider.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadProvider.kt @@ -95,6 +95,19 @@ class DownloadProvider(private val context: Context) { return chapters.flatMap { getValidChapterDirNames(it) }.mapNotNull { mangaDir.findFile(it) } } + /** + * Returns a list of downloaded directories for the chapters that exist. + * + * @param chapters the chapters to query. + * @param manga the manga of the chapter. + * @param source the source of the chapter. + */ + fun findTempChapterDirs(chapters: List, manga: Manga, source: Source): List { + val mangaDir = findMangaDir(manga, source) ?: return emptyList() + return chapters.mapNotNull { mangaDir.findFile("${getChapterDirName(it)}_tmp") } + } + + /** * Returns the download directory name for a source. * @@ -119,6 +132,16 @@ class DownloadProvider(private val context: Context) { * @param chapter the chapter to query. */ fun getChapterDirName(chapter: Chapter): String { + return DiskUtil.buildValidFilename("${chapter.id} - ${chapter.name}") + } + + /** + * Returns the chapter directory name for a chapter (that used the scanlator + * + * @param chapter the chapter to query. + */ + //TODO: Delete this in due time. N2Self, merging that pr was a mistake + private fun getChapterDirNameWithScanlator(chapter: Chapter): String { return DiskUtil.buildValidFilename("${chapter.id}_${chapter.scanlator}_${chapter.name}") } @@ -129,10 +152,10 @@ class DownloadProvider(private val context: Context) { */ fun getValidChapterDirNames(chapter: Chapter): List { return listOf( - getChapterDirName(chapter), - - // Legacy chapter directory name used in v0.8.4 and before - DiskUtil.buildValidFilename(chapter.name) + getChapterDirName(chapter), + // Legacy chapter directory name used in v0.8.4 and before + getChapterDirNameWithScanlator(chapter), + DiskUtil.buildValidFilename(chapter.name) ) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadAdapter.kt index 76bc02a33f..458ca153c7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadAdapter.kt @@ -1,5 +1,6 @@ package eu.kanade.tachiyomi.ui.download +import android.view.MenuItem import eu.davidea.flexibleadapter.FlexibleAdapter /** @@ -13,12 +14,13 @@ class DownloadAdapter(controller: DownloadController) : FlexibleAdapter(), - DownloadAdapter.OnItemReleaseListener { + DownloadAdapter.DownloadItemListener { /** * Adapter containing the active downloads. @@ -110,6 +113,9 @@ class DownloadController : NucleusController(), // Set clear button visibility. menu.findItem(R.id.clear_queue).isVisible = !presenter.downloadQueue.isEmpty() + + // Set reorder button visibility. + menu.findItem(R.id.reorder).isVisible = !presenter.downloadQueue.isEmpty() } override fun onOptionsItemSelected(item: MenuItem): Boolean { @@ -124,6 +130,16 @@ class DownloadController : NucleusController(), DownloadService.stop(context) presenter.clearQueue() } + R.id.newest, R.id.oldest -> { + val adapter = adapter ?: return false + val items = adapter.currentItems.sortedBy { it.download.chapter.date_upload } + .toMutableList() + if (item.itemId == R.id.newest) + items.reverse() + adapter.updateDataSet(items) + val downloads = items.mapNotNull { it.download } + presenter.reorder(downloads) + } else -> return super.onOptionsItemSelected(item) } return true @@ -264,4 +280,36 @@ class DownloadController : NucleusController(), presenter.reorder(downloads) } + /** + * Called when the menu item of a download is pressed + * + * @param position The position of the item + * @param menuItem The menu Item pressed + */ + override fun onMenuItemClick(position: Int, menuItem: MenuItem) { + when (menuItem.itemId) { + R.id.move_to_top, R.id.move_to_bottom -> { + val items = adapter?.currentItems?.toMutableList() ?: return + val item = items[position] + items.remove(item) + if (menuItem.itemId == R.id.move_to_top) + items.add(0, item) + else + items.add(item) + adapter?.updateDataSet(items) + val downloads = items.mapNotNull { it.download } + presenter.reorder(downloads) + } + R.id.cancel_download -> { + val download = adapter?.getItem(position)?.download ?: return + presenter.cancelDownload(download) + + adapter?.removeItem(position) + val adapter = adapter ?: return + val downloads = (0 until adapter.itemCount).mapNotNull { adapter.getItem(it)?.download } + presenter.reorder(downloads) + } + } + } + } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadHolder.kt index 8428a8b30f..b7cb6527ed 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadHolder.kt @@ -1,9 +1,14 @@ package eu.kanade.tachiyomi.ui.download import android.view.View +import android.widget.PopupMenu +import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.download.model.Download import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder +import eu.kanade.tachiyomi.util.getResourceColor +import eu.kanade.tachiyomi.util.setVectorCompat import kotlinx.android.synthetic.main.download_item.* +import kotlinx.android.synthetic.main.download_item.migration_menu /** * Class used to hold the data of a download. @@ -12,10 +17,12 @@ import kotlinx.android.synthetic.main.download_item.* * @param view the inflated view for this holder. * @constructor creates a new download holder. */ -class DownloadHolder(view: View, val adapter: DownloadAdapter) : BaseFlexibleViewHolder(view, adapter) { +class DownloadHolder(private val view: View, val adapter: DownloadAdapter) : + BaseFlexibleViewHolder(view, adapter) { init { setDragHandleView(reorder) + migration_menu.setOnClickListener { it.post { showPopupMenu(it) } } } private lateinit var download: Download @@ -44,6 +51,10 @@ class DownloadHolder(view: View, val adapter: DownloadAdapter) : BaseFlexibleVie notifyProgress() notifyDownloadedPages() } + + migration_menu.setVectorCompat( + R.drawable.ic_more_vert_black_24dp, view.context + .getResourceColor(R.attr.icon_color)) } @@ -68,7 +79,34 @@ class DownloadHolder(view: View, val adapter: DownloadAdapter) : BaseFlexibleVie override fun onItemReleased(position: Int) { super.onItemReleased(position) - adapter.onItemReleaseListener.onItemReleased(position) + adapter.downloadItemListener.onItemReleased(position) + } + + + private fun showPopupMenu(view: View) { + val item = adapter.getItem(adapterPosition) ?: return + + // Create a PopupMenu, giving it the clicked view for an anchor + val popup = PopupMenu(view.context, view) + + // Inflate our menu resource into the PopupMenu's Menu + popup.menuInflater.inflate(R.menu.download_single, popup.menu) + + val download = item.download + + popup.menu.findItem(R.id.move_to_top).isVisible = adapterPosition != 0 + popup.menu.findItem(R.id.move_to_bottom).isVisible = adapterPosition != adapter + .itemCount - 1 + + + // Set a listener so we are notified if a menu item is clicked + popup.setOnMenuItemClickListener { menuItem -> + adapter.downloadItemListener.onMenuItemClick(adapterPosition, menuItem) + true + } + + // Finally show the PopupMenu + popup.show() } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadPresenter.kt index a0b28d0807..3daccb8e02 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadPresenter.kt @@ -65,4 +65,9 @@ class DownloadPresenter : BasePresenter() { downloadManager.reorderQueue(downloads) } + fun cancelDownload(download: Download) { + downloadManager.deleteChapters(listOf(download.chapter), download.manga, + download.source) + } + } \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt index 74f70f7dab..a8db98c746 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt @@ -26,7 +26,6 @@ import com.google.android.material.snackbar.Snackbar import com.google.android.material.tabs.TabLayout import com.jakewharton.rxbinding.support.v4.view.pageSelections import com.jakewharton.rxbinding.support.v7.widget.queryTextChanges -import com.jakewharton.rxbinding.view.visible import com.jakewharton.rxrelay.BehaviorRelay import com.jakewharton.rxrelay.PublishRelay import eu.kanade.tachiyomi.R @@ -469,7 +468,7 @@ class LibraryController( val showAll = (selectedMangas.filter { (it as? LibraryManga)?.hide_title == true }).size == selectedMangas.size menu.findItem(R.id.action_hide_title)?.title = activity?.getString( - if (showAll) R.string.label_show_title else R.string.label_hide_title + if (showAll) R.string.action_show_title else R.string.action_hide_title ) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationListController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationListController.kt index 9b2b3deae8..24754100e8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationListController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationListController.kt @@ -78,7 +78,8 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle), } override fun getTitle(): String? { - return resources?.getString(R.string.migration) + return resources?.getString(R.string.migration) + " (${adapter?.items?.count { it.manga + .migrationStatus != MigrationStatus.RUNNUNG }}/${adapter?.itemCount ?: 0})" } override fun onViewCreated(view: View) { @@ -240,6 +241,12 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle), } } + override fun updateCount() { + launchUI { + setTitle() + } + } + override fun onDestroy() { super.onDestroy() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationProcessAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationProcessAdapter.kt index d70f91e687..e97b52103a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationProcessAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationProcessAdapter.kt @@ -38,9 +38,11 @@ class MigrationProcessAdapter( fun enableButtons() fun removeManga(item: MigrationProcessItem) fun noMigration() + fun updateCount() } fun sourceFinished() { + menuItemListener.updateCount() if (itemCount == 0) menuItemListener.noMigration() if (allMangasDone()) menuItemListener.enableButtons() } diff --git a/app/src/main/res/layout/download_item.xml b/app/src/main/res/layout/download_item.xml index ac4f28f530..af8210432c 100644 --- a/app/src/main/res/layout/download_item.xml +++ b/app/src/main/res/layout/download_item.xml @@ -1,60 +1,89 @@ - + + + + + + + + - - - - - - + app:layout_constraintBottom_toBottomOf="@+id/manga_title" + app:layout_constraintEnd_toStartOf="@+id/migration_menu" + app:layout_constraintTop_toTopOf="@+id/manga_title" + tools:text="(0/10)" /> + android:layout_toEndOf="@id/download_progress_text" + android:contentDescription="@string/description_cover" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:srcCompat="@drawable/ic_more_vert_black_24dp" /> - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/menu/download_queue.xml b/app/src/main/res/menu/download_queue.xml index caeb280807..864d395020 100644 --- a/app/src/main/res/menu/download_queue.xml +++ b/app/src/main/res/menu/download_queue.xml @@ -19,4 +19,19 @@ android:visible="false" app:showAsAction="never"/> + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/download_single.xml b/app/src/main/res/menu/download_single.xml new file mode 100644 index 0000000000..e1dc2fa65a --- /dev/null +++ b/app/src/main/res/menu/download_single.xml @@ -0,0 +1,11 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/library.xml b/app/src/main/res/menu/library.xml index d0c51bd161..cc0197d29f 100644 --- a/app/src/main/res/menu/library.xml +++ b/app/src/main/res/menu/library.xml @@ -34,7 +34,7 @@ + android:title="@string/action_alpha_reverse"/> diff --git a/app/src/main/res/menu/library_selection.xml b/app/src/main/res/menu/library_selection.xml index 879131d5ca..05ffadb0f3 100644 --- a/app/src/main/res/menu/library_selection.xml +++ b/app/src/main/res/menu/library_selection.xml @@ -32,7 +32,7 @@ \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index dd137d2a20..dbfa7e535e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -22,10 +22,6 @@ Selected: %1$d Backup Source migration - Reorder - Alpha. (descending) - Hide title - Show title Extensions Extension info Help @@ -44,8 +40,6 @@ Enabled Total chapters Last read - Last updated - First updated Drag & Drop Search Don\'t migrate @@ -75,7 +69,7 @@ Start Stop Pause - Clear + Cancel all Close Previous chapter Next chapter @@ -111,6 +105,16 @@ Search manually Migrate now Copy now + Reorder + Alpha. (descending) + Last updated + Last updated (desc.) + Hide title + Show title + Newest + Oldest + Move to top + Move to bottom Deleting…