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…