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
This commit is contained in:
Jay 2020-01-07 23:32:30 -08:00
parent b6e4869d30
commit 68c3d28b4b
16 changed files with 268 additions and 75 deletions

View File

@ -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.database.models.Manga
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.getOrDefault import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.SourceManager
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
@ -203,13 +204,15 @@ class DownloadCache(
* @param manga the manga of the chapter. * @param manga the manga of the chapter.
*/ */
@Synchronized @Synchronized
fun removeChapters(chapters: List<Chapter>, manga: Manga) { fun removeChapters(chapters: List<Chapter>, manga: Manga, source: Source) {
val sourceDir = rootDir.files[manga.source] ?: return val sourceDir = rootDir.files[manga.source] ?: return
val mangaDir = sourceDir.files[provider.getMangaDirName(manga)] ?: return val mangaDir = sourceDir.files[provider.getMangaDirName(manga)] ?: return
for (chapter in chapters) { for (chapter in chapters) {
val chapterDirName = provider.getChapterDirName(chapter) val list = provider.getValidChapterDirNames(chapter)
if (chapterDirName in mangaDir.files) { list.forEach {
mangaDir.files -= chapterDirName if (it in mangaDir.files) {
mangaDir.files -= it
}
} }
} }
} }

View File

@ -20,7 +20,7 @@ import uy.kohesive.injekt.injectLazy
* *
* @param context the application context. * @param context the application context.
*/ */
class DownloadManager(context: Context) { class DownloadManager(val context: Context) {
/** /**
* The sources manager. * The sources manager.
@ -99,7 +99,12 @@ class DownloadManager(context: Context) {
* @param downloads value to set the download queue to * @param downloads value to set the download queue to
*/ */
fun reorderQueue(downloads: List<Download>) { fun reorderQueue(downloads: List<Download>) {
val wasPaused = downloader.isPaused() val wasPaused = isPaused()
if (downloads.isEmpty()) {
DownloadService.stop(context)
downloader.queue.clear()
return
}
downloader.pause() downloader.pause()
downloader.queue.clear() downloader.queue.clear()
downloader.queue.addAll(downloads) 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. * 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 chapters the list of chapters to delete.
* @param manga the manga of the chapters. * @param manga the manga of the chapters.
@ -183,9 +190,9 @@ class DownloadManager(context: Context) {
*/ */
fun deleteChapters(chapters: List<Chapter>, manga: Manga, source: Source) { fun deleteChapters(chapters: List<Chapter>, manga: Manga, source: Source) {
queue.remove(chapters) 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() } chapterDirs.forEach { it.delete() }
cache.removeChapters(chapters, manga) cache.removeChapters(chapters, manga, source)
if (cache.getDownloadCount(manga) == 0) { // Delete manga directory if empty if (cache.getDownloadCount(manga) == 0) { // Delete manga directory if empty
chapterDirs.firstOrNull()?.parentFile?.delete() chapterDirs.firstOrNull()?.parentFile?.delete()
} }

View File

@ -95,6 +95,19 @@ class DownloadProvider(private val context: Context) {
return chapters.flatMap { getValidChapterDirNames(it) }.mapNotNull { mangaDir.findFile(it) } 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<Chapter>, manga: Manga, source: Source): List<UniFile> {
val mangaDir = findMangaDir(manga, source) ?: return emptyList()
return chapters.mapNotNull { mangaDir.findFile("${getChapterDirName(it)}_tmp") }
}
/** /**
* Returns the download directory name for a source. * Returns the download directory name for a source.
* *
@ -119,6 +132,16 @@ class DownloadProvider(private val context: Context) {
* @param chapter the chapter to query. * @param chapter the chapter to query.
*/ */
fun getChapterDirName(chapter: Chapter): String { 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}") return DiskUtil.buildValidFilename("${chapter.id}_${chapter.scanlator}_${chapter.name}")
} }
@ -129,10 +152,10 @@ class DownloadProvider(private val context: Context) {
*/ */
fun getValidChapterDirNames(chapter: Chapter): List<String> { fun getValidChapterDirNames(chapter: Chapter): List<String> {
return listOf( return listOf(
getChapterDirName(chapter), getChapterDirName(chapter),
// Legacy chapter directory name used in v0.8.4 and before
// Legacy chapter directory name used in v0.8.4 and before getChapterDirNameWithScanlator(chapter),
DiskUtil.buildValidFilename(chapter.name) DiskUtil.buildValidFilename(chapter.name)
) )
} }

View File

@ -1,5 +1,6 @@
package eu.kanade.tachiyomi.ui.download package eu.kanade.tachiyomi.ui.download
import android.view.MenuItem
import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.FlexibleAdapter
/** /**
@ -13,12 +14,13 @@ class DownloadAdapter(controller: DownloadController) : FlexibleAdapter<Download
/** /**
* Listener called when an item of the list is released. * Listener called when an item of the list is released.
*/ */
val onItemReleaseListener: OnItemReleaseListener = controller val downloadItemListener: DownloadItemListener = controller
interface OnItemReleaseListener { interface DownloadItemListener {
/** /**
* Called when an item of the list is released. * Called when an item of the list is released.
*/ */
fun onItemReleased(position: Int) fun onItemReleased(position: Int)
fun onMenuItemClick(position: Int, menuItem: MenuItem)
} }
} }

View File

@ -8,6 +8,7 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.download.DownloadManager
import eu.kanade.tachiyomi.data.download.DownloadService import eu.kanade.tachiyomi.data.download.DownloadService
import eu.kanade.tachiyomi.data.download.model.Download import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.Page
@ -17,6 +18,8 @@ import kotlinx.android.synthetic.main.download_controller.*
import rx.Observable import rx.Observable
import rx.Subscription import rx.Subscription
import rx.android.schedulers.AndroidSchedulers import rx.android.schedulers.AndroidSchedulers
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.injectLazy
import java.util.HashMap import java.util.HashMap
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@ -25,7 +28,7 @@ import java.util.concurrent.TimeUnit
* Uses R.layout.fragment_download_queue. * Uses R.layout.fragment_download_queue.
*/ */
class DownloadController : NucleusController<DownloadPresenter>(), class DownloadController : NucleusController<DownloadPresenter>(),
DownloadAdapter.OnItemReleaseListener { DownloadAdapter.DownloadItemListener {
/** /**
* Adapter containing the active downloads. * Adapter containing the active downloads.
@ -110,6 +113,9 @@ class DownloadController : NucleusController<DownloadPresenter>(),
// Set clear button visibility. // Set clear button visibility.
menu.findItem(R.id.clear_queue).isVisible = !presenter.downloadQueue.isEmpty() 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 { override fun onOptionsItemSelected(item: MenuItem): Boolean {
@ -124,6 +130,16 @@ class DownloadController : NucleusController<DownloadPresenter>(),
DownloadService.stop(context) DownloadService.stop(context)
presenter.clearQueue() 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) else -> return super.onOptionsItemSelected(item)
} }
return true return true
@ -264,4 +280,36 @@ class DownloadController : NucleusController<DownloadPresenter>(),
presenter.reorder(downloads) 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)
}
}
}
} }

View File

@ -1,9 +1,14 @@
package eu.kanade.tachiyomi.ui.download package eu.kanade.tachiyomi.ui.download
import android.view.View 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.data.download.model.Download
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder 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.*
import kotlinx.android.synthetic.main.download_item.migration_menu
/** /**
* Class used to hold the data of a download. * 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. * @param view the inflated view for this holder.
* @constructor creates a new download 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 { init {
setDragHandleView(reorder) setDragHandleView(reorder)
migration_menu.setOnClickListener { it.post { showPopupMenu(it) } }
} }
private lateinit var download: Download private lateinit var download: Download
@ -44,6 +51,10 @@ class DownloadHolder(view: View, val adapter: DownloadAdapter) : BaseFlexibleVie
notifyProgress() notifyProgress()
notifyDownloadedPages() 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) { override fun onItemReleased(position: Int) {
super.onItemReleased(position) 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()
} }
} }

View File

@ -65,4 +65,9 @@ class DownloadPresenter : BasePresenter<DownloadController>() {
downloadManager.reorderQueue(downloads) downloadManager.reorderQueue(downloads)
} }
fun cancelDownload(download: Download) {
downloadManager.deleteChapters(listOf(download.chapter), download.manga,
download.source)
}
} }

View File

@ -26,7 +26,6 @@ import com.google.android.material.snackbar.Snackbar
import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout
import com.jakewharton.rxbinding.support.v4.view.pageSelections import com.jakewharton.rxbinding.support.v4.view.pageSelections
import com.jakewharton.rxbinding.support.v7.widget.queryTextChanges import com.jakewharton.rxbinding.support.v7.widget.queryTextChanges
import com.jakewharton.rxbinding.view.visible
import com.jakewharton.rxrelay.BehaviorRelay import com.jakewharton.rxrelay.BehaviorRelay
import com.jakewharton.rxrelay.PublishRelay import com.jakewharton.rxrelay.PublishRelay
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
@ -469,7 +468,7 @@ class LibraryController(
val showAll = val showAll =
(selectedMangas.filter { (it as? LibraryManga)?.hide_title == true }).size == selectedMangas.size (selectedMangas.filter { (it as? LibraryManga)?.hide_title == true }).size == selectedMangas.size
menu.findItem(R.id.action_hide_title)?.title = activity?.getString( 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
) )
} }
} }

View File

@ -78,7 +78,8 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle),
} }
override fun getTitle(): String? { 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) { override fun onViewCreated(view: View) {
@ -240,6 +241,12 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle),
} }
} }
override fun updateCount() {
launchUI {
setTitle()
}
}
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()

View File

@ -38,9 +38,11 @@ class MigrationProcessAdapter(
fun enableButtons() fun enableButtons()
fun removeManga(item: MigrationProcessItem) fun removeManga(item: MigrationProcessItem)
fun noMigration() fun noMigration()
fun updateCount()
} }
fun sourceFinished() { fun sourceFinished() {
menuItemListener.updateCount()
if (itemCount == 0) menuItemListener.noMigration() if (itemCount == 0) menuItemListener.noMigration()
if (allMangasDone()) menuItemListener.enableButtons() if (allMangasDone()) menuItemListener.enableButtons()
} }

View File

@ -1,60 +1,89 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/relativeLayout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingRight="@dimen/material_layout_keylines_screen_edge_margin" android:paddingStart="0dp"
android:paddingTop="@dimen/material_component_lists_padding_above_list"> android:paddingTop="@dimen/material_component_lists_padding_above_list">
<ImageView
android:id="@+id/reorder"
android:layout_width="@dimen/material_component_lists_single_line_with_avatar_height"
android:layout_height="0dp"
android:layout_alignParentStart="true"
android:layout_gravity="start"
android:contentDescription="@string/action_reorganize_by"
android:scaleType="center"
android:tint="?android:attr/textColorPrimary"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_reorder_grey_24dp" />
<TextView
android:id="@+id/manga_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_toEndOf="@id/reorder"
android:ellipsize="end"
android:maxLines="1"
android:textAppearance="@style/TextAppearance.Regular.Body1"
app:layout_constraintEnd_toStartOf="@+id/download_progress_text"
app:layout_constraintStart_toEndOf="@+id/reorder"
app:layout_constraintTop_toTopOf="parent"
tools:text="Manga title" />
<TextView
android:id="@+id/chapter_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_toEndOf="@id/reorder"
android:ellipsize="end"
android:maxLines="1"
android:textAppearance="@style/TextAppearance.Regular.Caption"
app:layout_constraintEnd_toStartOf="@+id/migration_menu"
app:layout_constraintStart_toStartOf="@+id/manga_title"
app:layout_constraintTop_toBottomOf="@+id/manga_title"
tools:text="Chapter Title" />
<ProgressBar
android:id="@+id/download_progress"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/migration_menu"
app:layout_constraintStart_toEndOf="@+id/reorder"
app:layout_constraintTop_toBottomOf="@+id/chapter_title" />
<TextView <TextView
android:id="@+id/download_progress_text" android:id="@+id/download_progress_text"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentRight="true" android:layout_toEndOf="@id/manga_title"
android:maxLines="1" android:maxLines="1"
android:textAppearance="@style/TextAppearance.Regular.Caption.Hint" android:textAppearance="@style/TextAppearance.Regular.Caption.Hint"
tools:text="(0/10)"/> app:layout_constraintBottom_toBottomOf="@+id/manga_title"
app:layout_constraintEnd_toStartOf="@+id/migration_menu"
<TextView app:layout_constraintTop_toTopOf="@+id/manga_title"
android:id="@+id/manga_title" tools:text="(0/10)" />
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toLeftOf="@id/download_progress_text"
android:layout_alignParentLeft="true"
android:maxLines="1"
android:ellipsize="end"
android:layout_marginStart="@dimen/material_component_lists_single_line_with_avatar_height"
android:textAppearance="@style/TextAppearance.Regular.Body1"
tools:text="Manga title"/>
<TextView
android:id="@+id/chapter_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/manga_title"
android:maxLines="1"
android:ellipsize="end"
tools:text="Chapter Title"
android:layout_marginStart="@dimen/material_component_lists_single_line_with_avatar_height"
android:textAppearance="@style/TextAppearance.Regular.Caption"/>
<ProgressBar
android:id="@+id/download_progress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/chapter_title"
android:layout_marginStart="@dimen/material_component_lists_single_line_with_avatar_height"
style="?android:attr/progressBarStyleHorizontal"/>
<ImageView <ImageView
android:id="@+id/reorder" android:id="@+id/migration_menu"
android:layout_width="@dimen/material_component_lists_single_line_with_avatar_height" android:layout_width="44dp"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:layout_height="@dimen/material_component_lists_single_line_with_avatar_height" android:layout_height="@dimen/material_component_lists_single_line_with_avatar_height"
android:layout_gravity="start" android:layout_toEndOf="@id/download_progress_text"
android:scaleType="center" android:contentDescription="@string/description_cover"
android:tint="?android:attr/textColorPrimary" app:layout_constraintBottom_toBottomOf="parent"
app:srcCompat="@drawable/ic_reorder_grey_24dp" /> app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_more_vert_black_24dp" />
</RelativeLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -19,4 +19,19 @@
android:visible="false" android:visible="false"
app:showAsAction="never"/> app:showAsAction="never"/>
<item
android:id="@+id/reorder"
android:title="@string/action_reorganize_by"
android:visible="false"
app:showAsAction="never">
<menu>
<item
android:id="@+id/newest"
android:title="@string/action_newest"/>
<item
android:id="@+id/oldest"
android:title="@string/action_oldest"/>
</menu>
</item>
</menu> </menu>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/move_to_top"
android:title="@string/action_move_to_top" />
<item android:id="@+id/move_to_bottom"
android:title="@string/action_move_to_bottom" />
<item android:id="@+id/cancel_download"
android:title="@string/action_cancel" />
</menu>

View File

@ -34,7 +34,7 @@
<item <item
android:id="@+id/action_reorganize" android:id="@+id/action_reorganize"
android:title="@string/label_reorganize_by" android:title="@string/action_reorganize_by"
app:showAsAction="never"> app:showAsAction="never">
<menu> <menu>
<item <item
@ -42,7 +42,7 @@
android:title="@string/action_sort_alpha"/> android:title="@string/action_sort_alpha"/>
<item <item
android:id="@+id/action_alpha_dsc" android:id="@+id/action_alpha_dsc"
android:title="@string/label_alpha_reverse"/> android:title="@string/action_alpha_reverse"/>
<item <item
android:id="@+id/action_update_asc" android:id="@+id/action_update_asc"
android:title="@string/action_sort_last_updated"/> android:title="@string/action_sort_last_updated"/>

View File

@ -32,7 +32,7 @@
<item <item
android:id="@+id/action_hide_title" android:id="@+id/action_hide_title"
android:icon="@drawable/ic_swap_calls_white_24dp" android:icon="@drawable/ic_swap_calls_white_24dp"
android:title="@string/label_hide_title" android:title="@string/action_hide_title"
app:showAsAction="never" /> app:showAsAction="never" />
</menu> </menu>

View File

@ -22,10 +22,6 @@
<string name="label_selected">Selected: %1$d</string> <string name="label_selected">Selected: %1$d</string>
<string name="label_backup">Backup</string> <string name="label_backup">Backup</string>
<string name="label_migration">Source migration</string> <string name="label_migration">Source migration</string>
<string name="label_reorganize_by">Reorder</string>
<string name="label_alpha_reverse">Alpha. (descending)</string>
<string name="label_hide_title">Hide title</string>
<string name="label_show_title">Show title</string>
<string name="label_extensions">Extensions</string> <string name="label_extensions">Extensions</string>
<string name="label_extension_info">Extension info</string> <string name="label_extension_info">Extension info</string>
<string name="label_help">Help</string> <string name="label_help">Help</string>
@ -44,8 +40,6 @@
<string name="action_sort_enabled">Enabled</string> <string name="action_sort_enabled">Enabled</string>
<string name="action_sort_total">Total chapters</string> <string name="action_sort_total">Total chapters</string>
<string name="action_sort_last_read">Last read</string> <string name="action_sort_last_read">Last read</string>
<string name="action_sort_last_updated">Last updated</string>
<string name="action_sort_first_updated">First updated</string>
<string name="action_sort_drag_and_drop">Drag &amp; Drop</string> <string name="action_sort_drag_and_drop">Drag &amp; Drop</string>
<string name="action_search">Search</string> <string name="action_search">Search</string>
<string name="action_skip_manga">Don\'t migrate</string> <string name="action_skip_manga">Don\'t migrate</string>
@ -75,7 +69,7 @@
<string name="action_start">Start</string> <string name="action_start">Start</string>
<string name="action_stop">Stop</string> <string name="action_stop">Stop</string>
<string name="action_pause">Pause</string> <string name="action_pause">Pause</string>
<string name="action_clear">Clear</string> <string name="action_clear">Cancel all</string>
<string name="action_close">Close</string> <string name="action_close">Close</string>
<string name="action_previous_chapter">Previous chapter</string> <string name="action_previous_chapter">Previous chapter</string>
<string name="action_next_chapter">Next chapter</string> <string name="action_next_chapter">Next chapter</string>
@ -111,6 +105,16 @@
<string name="action_search_manually">Search manually</string> <string name="action_search_manually">Search manually</string>
<string name="action_migrate_now">Migrate now</string> <string name="action_migrate_now">Migrate now</string>
<string name="action_copy_now">Copy now</string> <string name="action_copy_now">Copy now</string>
<string name="action_reorganize_by">Reorder</string>
<string name="action_alpha_reverse">Alpha. (descending)</string>
<string name="action_sort_last_updated">Last updated</string>
<string name="action_sort_first_updated">Last updated (desc.)</string>
<string name="action_hide_title">Hide title</string>
<string name="action_show_title">Show title</string>
<string name="action_newest">Newest</string>
<string name="action_oldest">Oldest</string>
<string name="action_move_to_top">Move to top</string>
<string name="action_move_to_bottom">Move to bottom</string>
<!-- Operations --> <!-- Operations -->
<string name="deleting">Deleting…</string> <string name="deleting">Deleting…</string>