From b872ab837a9f9e30b7f5369facfd36cae526470d Mon Sep 17 00:00:00 2001 From: Jay Date: Sun, 5 Jan 2020 23:04:29 -0800 Subject: [PATCH] Drag & Drop Sorting in Library --- .../tachiyomi/data/database/DbOpenCallback.kt | 5 +- .../database/mappers/CategoryTypeMapping.kt | 7 ++ .../data/database/models/Category.kt | 2 + .../data/database/models/CategoryImpl.kt | 2 + .../data/database/tables/CategoryTable.kt | 8 +- .../data/preference/PreferencesHelper.kt | 3 + .../ui/library/LibraryCategoryAdapter.kt | 4 + .../ui/library/LibraryCategoryView.kt | 78 ++++++++++++++++++- .../tachiyomi/ui/library/LibraryController.kt | 20 +++++ .../tachiyomi/ui/library/LibraryGridHolder.kt | 2 +- .../tachiyomi/ui/library/LibraryHolder.kt | 13 +++- .../tachiyomi/ui/library/LibraryItem.kt | 7 ++ .../tachiyomi/ui/library/LibraryListHolder.kt | 2 +- .../ui/library/LibraryNavigationView.kt | 24 ++++-- .../tachiyomi/ui/library/LibraryPresenter.kt | 8 +- .../tachiyomi/ui/library/LibrarySort.kt | 1 + .../kanade/tachiyomi/util/StringExtensions.kt | 4 + app/src/main/res/menu/library.xml | 20 +++++ app/src/main/res/values/strings.xml | 4 + 19 files changed, 194 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/DbOpenCallback.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/DbOpenCallback.kt index e8c1a4ed3a..bba9db5068 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/DbOpenCallback.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/DbOpenCallback.kt @@ -18,7 +18,7 @@ class DbOpenCallback : SupportSQLiteOpenHelper.Callback(DATABASE_VERSION) { /** * Version of the database. */ - const val DATABASE_VERSION = 9 + const val DATABASE_VERSION = 10 } override fun onCreate(db: SupportSQLiteDatabase) = with(db) { @@ -70,6 +70,9 @@ class DbOpenCallback : SupportSQLiteOpenHelper.Callback(DATABASE_VERSION) { if (oldVersion < 9) { db.execSQL(MangaTable.addHideTitle) } + if (oldVersion < 10) { + db.execSQL(CategoryTable.addMangaOrder) + } } override fun onConfigure(db: SupportSQLiteDatabase) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/CategoryTypeMapping.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/CategoryTypeMapping.kt index 0069934be1..3ed871eab9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/CategoryTypeMapping.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/CategoryTypeMapping.kt @@ -13,6 +13,7 @@ import eu.kanade.tachiyomi.data.database.models.Category import eu.kanade.tachiyomi.data.database.models.CategoryImpl import eu.kanade.tachiyomi.data.database.tables.CategoryTable.COL_FLAGS import eu.kanade.tachiyomi.data.database.tables.CategoryTable.COL_ID +import eu.kanade.tachiyomi.data.database.tables.CategoryTable.COL_MANGA_ORDER import eu.kanade.tachiyomi.data.database.tables.CategoryTable.COL_NAME import eu.kanade.tachiyomi.data.database.tables.CategoryTable.COL_ORDER import eu.kanade.tachiyomi.data.database.tables.CategoryTable.TABLE @@ -40,6 +41,9 @@ class CategoryPutResolver : DefaultPutResolver() { put(COL_NAME, obj.name) put(COL_ORDER, obj.order) put(COL_FLAGS, obj.flags) + val orderString = obj.mangaOrder.joinToString("/") + put(COL_MANGA_ORDER, orderString) + } } @@ -50,6 +54,9 @@ class CategoryGetResolver : DefaultGetResolver() { name = cursor.getString(cursor.getColumnIndex(COL_NAME)) order = cursor.getInt(cursor.getColumnIndex(COL_ORDER)) flags = cursor.getInt(cursor.getColumnIndex(COL_FLAGS)) + + val orderString = cursor.getString(cursor.getColumnIndex(COL_MANGA_ORDER)) + mangaOrder = orderString?.split("/")?.mapNotNull { it.toLongOrNull() } ?: emptyList() } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Category.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Category.kt index c88d932610..7e827bcace 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Category.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Category.kt @@ -12,6 +12,8 @@ interface Category : Serializable { var flags: Int + var mangaOrder:List + val nameLower: String get() = name.toLowerCase() diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/CategoryImpl.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/CategoryImpl.kt index 65a004477b..f4c6d14376 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/CategoryImpl.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/CategoryImpl.kt @@ -10,6 +10,8 @@ class CategoryImpl : Category { override var flags: Int = 0 + override var mangaOrder: List = emptyList() + override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || javaClass != other.javaClass) return false diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/CategoryTable.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/CategoryTable.kt index 65af41013e..675103c974 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/CategoryTable.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/CategoryTable.kt @@ -12,12 +12,18 @@ object CategoryTable { const val COL_FLAGS = "flags" + const val COL_MANGA_ORDER = "manga_order" + val createTableQuery: String get() = """CREATE TABLE $TABLE( $COL_ID INTEGER NOT NULL PRIMARY KEY, $COL_NAME TEXT NOT NULL, $COL_ORDER INTEGER NOT NULL, - $COL_FLAGS INTEGER NOT NULL + $COL_FLAGS INTEGER NOT NULL, + $COL_MANGA_ORDER TEXT NOT NULL )""" + + val addMangaOrder: String + get() = "ALTER TABLE $TABLE ADD COLUMN $COL_MANGA_ORDER TEXT" } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt index cc81e18ab9..5fe9335b78 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt @@ -7,6 +7,7 @@ import androidx.preference.PreferenceManager import com.f2prateek.rx.preferences.Preference import com.f2prateek.rx.preferences.RxSharedPreferences import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.track.TrackService import eu.kanade.tachiyomi.source.Source import java.io.File @@ -198,6 +199,8 @@ class PreferencesHelper(val context: Context) { fun skipPreMigration() = rxPrefs.getBoolean(Keys.skipPreMigration, false) + fun defaultMangaOrder() = rxPrefs.getString("default_manga_order", "") + fun upgradeFilters() { val filterDl = rxPrefs.getBoolean(Keys.filterDownloaded, false).getOrDefault() val filterUn = rxPrefs.getBoolean(Keys.filterUnread, false).getOrDefault() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.kt index 645274ffc5..994faad7a0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.kt @@ -3,7 +3,9 @@ package eu.kanade.tachiyomi.ui.library import eu.davidea.flexibleadapter.FlexibleAdapter import eu.kanade.tachiyomi.data.database.models.Manga import androidx.recyclerview.widget.RecyclerView +import eu.davidea.flexibleadapter.SelectableAdapter import eu.davidea.flexibleadapter.items.IFlexible +import eu.kanade.tachiyomi.ui.category.CategoryAdapter /** * Adapter storing a list of manga in a certain category. @@ -18,6 +20,8 @@ class LibraryCategoryAdapter(view: LibraryCategoryView) : */ private var mangas: List = emptyList() + val onItemReleaseListener: CategoryAdapter.OnItemReleaseListener = view + /** * Sets a list of manga in the adapter. * diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt index b81bcf9911..3f9f4804ad 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt @@ -7,15 +7,16 @@ import android.util.AttributeSet import android.view.MotionEvent import android.view.View import android.widget.FrameLayout -import com.google.android.material.snackbar.Snackbar import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.SelectableAdapter import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.models.Category import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.library.LibraryUpdateService import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.getOrDefault +import eu.kanade.tachiyomi.ui.category.CategoryAdapter import eu.kanade.tachiyomi.util.* import eu.kanade.tachiyomi.widget.AutofitRecyclerView import kotlinx.android.synthetic.main.library_category.view.* @@ -28,7 +29,9 @@ import uy.kohesive.injekt.injectLazy class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : FrameLayout(context, attrs), FlexibleAdapter.OnItemClickListener, - FlexibleAdapter.OnItemLongClickListener { + FlexibleAdapter.OnItemLongClickListener, + FlexibleAdapter.OnItemMoveListener, + CategoryAdapter.OnItemReleaseListener { /** * Preferences. @@ -117,6 +120,8 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att } else { SelectableAdapter.Mode.SINGLE } + val sortingMode = preferences.librarySortingMode().getOrDefault() + adapter.isLongPressDragEnabled = sortingMode == LibrarySort.DRAG_AND_DROP subscriptions += controller.searchRelay .doOnNext { adapter.setFilter(it) } @@ -138,6 +143,27 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att controller.invalidateActionMode() } } + + subscriptions += controller.reorganizeRelay + .subscribe { + if (it.first == category.id) { + var items = when (it.second) { + 1, 2 -> adapter.currentItems.sortedBy { + if (preferences.removeArticles().getOrDefault()) + it.manga.title.removeArticles() + else + it.manga.title + } + 3, 4 -> adapter.currentItems.sortedBy { it.manga.last_update } + else -> adapter.currentItems.sortedBy { it.manga.title } + } + if (it.second % 2 == 0) + items = items.reversed() + adapter.setItems(items) + adapter.notifyDataSetChanged() + onItemReleased(0) + } + } } fun onRecycle() { @@ -158,8 +184,18 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att */ fun onNextLibraryManga(event: LibraryMangaEvent) { // Get the manga list for this category. - val mangaForCategory = event.getMangaForCategory(category).orEmpty() + + val sortingMode = preferences.librarySortingMode().getOrDefault() + adapter.isLongPressDragEnabled = sortingMode == LibrarySort.DRAG_AND_DROP + var mangaForCategory = event.getMangaForCategory(category).orEmpty() + if (sortingMode == LibrarySort.DRAG_AND_DROP) { + if (category.name == "Default") + category.mangaOrder = preferences.defaultMangaOrder().getOrDefault().split("/") + .mapNotNull { it.toLongOrNull() } + mangaForCategory = mangaForCategory.sortedBy { category.mangaOrder.indexOf(it.manga + .id) } + } // Update the category with its manga. adapter.setItems(mangaForCategory) @@ -185,6 +221,7 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att is LibrarySelectionEvent.Selected -> { if (adapter.mode != SelectableAdapter.Mode.MULTI) { adapter.mode = SelectableAdapter.Mode.MULTI + adapter.isLongPressDragEnabled = false } findAndToggleSelection(event.manga) } @@ -193,12 +230,16 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att if (adapter.indexOf(event.manga) != -1) lastClickPosition = -1 if (controller.selectedMangas.isEmpty()) { adapter.mode = SelectableAdapter.Mode.SINGLE + adapter.isLongPressDragEnabled = preferences.librarySortingMode() + .getOrDefault() == LibrarySort.DRAG_AND_DROP } } is LibrarySelectionEvent.Cleared -> { adapter.mode = SelectableAdapter.Mode.SINGLE adapter.clearSelection() lastClickPosition = -1 + adapter.isLongPressDragEnabled = preferences.librarySortingMode() + .getOrDefault() == LibrarySort.DRAG_AND_DROP } } } @@ -249,6 +290,7 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att */ override fun onItemLongClick(position: Int) { controller.createActionModeIfNeeded() + adapter.isLongPressDragEnabled = false when { lastClickPosition == -1 -> setSelection(position) lastClickPosition > position -> for (i in position until lastClickPosition) @@ -260,6 +302,36 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att lastClickPosition = position } + override fun onItemMove(fromPosition: Int, toPosition: Int) { + + } + + override fun onItemReleased(position: Int) { + if (adapter.selectedItemCount == 0) { + val mangaIds = adapter.currentItems.mapNotNull { it.manga.id } + category.mangaOrder = mangaIds + val db: DatabaseHelper by injectLazy() + if (category.name == "Default") + preferences.defaultMangaOrder().set(mangaIds.joinToString("/")) + else + db.insertCategory(category).asRxObservable().subscribe() + } + } + + override fun shouldMoveItem(fromPosition: Int, toPosition: Int): Boolean { + if (adapter.selectedItemCount > 1) + return false + if (adapter.isSelected(fromPosition)) + toggleSelection(fromPosition) + return true + } + + override fun onActionStateChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) { + val position = viewHolder?.adapterPosition ?: return + if (actionState == 2) + onItemLongClick(position) + } + /** * Opens a manga. * 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 cb6a55c131..f1ab4e7426 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,6 +26,7 @@ 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 @@ -120,6 +121,11 @@ class LibraryController( */ val selectAllRelay: PublishRelay = PublishRelay.create() + /** + * Relay to notify the library's viewpager to reotagnize all + */ + val reorganizeRelay: PublishRelay> = PublishRelay.create() + /** * Number of manga per row in grid mode. */ @@ -328,6 +334,7 @@ class LibraryController( * Called when the sorting mode is changed. */ private fun onSortChanged() { + activity?.invalidateOptionsMenu() presenter.requestSortUpdate() } @@ -364,6 +371,9 @@ class LibraryController( override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { inflater.inflate(R.menu.library, menu) + val reorganizeItem = menu.findItem(R.id.action_reorganize) + reorganizeItem.isVisible = preferences.librarySortingMode().getOrDefault() == LibrarySort.DRAG_AND_DROP + val searchItem = menu.findItem(R.id.action_search) val searchView = searchItem.actionView as SearchView @@ -417,12 +427,22 @@ class LibraryController( R.id.action_source_migration -> { router.pushController(MigrationController().withFadeTransaction()) } + R.id.action_alpha_asc -> reOrder(1) + R.id.action_alpha_dsc -> reOrder(2) + R.id.action_update_asc -> reOrder(3) + R.id.action_update_dsc -> reOrder(4) else -> return super.onOptionsItemSelected(item) } return true } + private fun reOrder(type: Int) { + adapter?.categories?.getOrNull(library_pager.currentItem)?.id?.let { + reorganizeRelay.call(it to type) + } + } + /** * Invalidates the action mode, forcing it to refresh its content. */ diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryGridHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryGridHolder.kt index b2ad7f1eac..1be2e10e4f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryGridHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryGridHolder.kt @@ -20,7 +20,7 @@ import eu.davidea.flexibleadapter.items.IFlexible */ class LibraryGridHolder( private val view: View, - private val adapter: FlexibleAdapter> + adapter: FlexibleAdapter> ) : LibraryHolder(view, adapter) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryHolder.kt index 4fe647ca98..1cc6144314 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryHolder.kt @@ -15,7 +15,7 @@ import eu.davidea.flexibleadapter.items.IFlexible abstract class LibraryHolder( view: View, - adapter: FlexibleAdapter> + val adapter: FlexibleAdapter> ) : BaseFlexibleViewHolder(view, adapter) { /** @@ -26,4 +26,15 @@ abstract class LibraryHolder( */ abstract fun onSetValues(item: LibraryItem) + + /** + * Called when an item is released. + * + * @param position The position of the released item. + */ + override fun onItemReleased(position: Int) { + super.onItemReleased(position) + (adapter as? LibraryCategoryAdapter)?.onItemReleaseListener?.onItemReleased(position) + } + } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryItem.kt index 0ce3a302d9..2c560231be 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryItem.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryItem.kt @@ -51,6 +51,13 @@ class LibraryItem(val manga: LibraryManga, private val libraryAsList: Preference holder.onSetValues(this) } + /** + * Returns true if this item is draggable. + */ + override fun isDraggable(): Boolean { + return true + } + /** * Filters a manga depending on a query. * diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryListHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryListHolder.kt index 9d5a06db01..8783da5b96 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryListHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryListHolder.kt @@ -21,7 +21,7 @@ import eu.davidea.flexibleadapter.items.IFlexible class LibraryListHolder( private val view: View, - private val adapter: FlexibleAdapter> + adapter: FlexibleAdapter> ) : LibraryHolder(view, adapter) { /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryNavigationView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryNavigationView.kt index b82a71fce0..343cc6e328 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryNavigationView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryNavigationView.kt @@ -131,7 +131,10 @@ class LibraryNavigationView @JvmOverloads constructor(context: Context, attrs: A private val source = Item.MultiSort(R.string.manga_info_source_label, this) - override val items = listOf(alphabetically, lastRead, lastUpdated, unread, total, source) + private val dragAndDrop = Item.MultiSort(R.string.action_sort_drag_and_drop, this) + + override val items = listOf(alphabetically, lastRead, lastUpdated, unread, total, source, + dragAndDrop) override val header = Item.Header(R.string.action_sort) @@ -148,6 +151,7 @@ class LibraryNavigationView @JvmOverloads constructor(context: Context, attrs: A unread.state = if (sorting == LibrarySort.UNREAD) order else SORT_NONE total.state = if (sorting == LibrarySort.TOTAL) order else SORT_NONE source.state = if (sorting == LibrarySort.SOURCE) order else SORT_NONE + dragAndDrop.state = if (sorting == LibrarySort.DRAG_AND_DROP) order else SORT_NONE } override fun onItemClicked(item: Item) { @@ -155,12 +159,15 @@ class LibraryNavigationView @JvmOverloads constructor(context: Context, attrs: A val prevState = item.state item.group.items.forEach { (it as Item.MultiStateGroup).state = SORT_NONE } - item.state = when (prevState) { - SORT_NONE -> SORT_ASC - SORT_ASC -> SORT_DESC - SORT_DESC -> SORT_ASC - else -> throw Exception("Unknown state") - } + if (item == dragAndDrop) + item.state = SORT_ASC + else + item.state = when (prevState) { + SORT_NONE -> SORT_ASC + SORT_ASC -> SORT_DESC + SORT_DESC -> SORT_ASC + else -> throw Exception("Unknown state") + } preferences.librarySortingMode().set(when (item) { alphabetically -> LibrarySort.ALPHA @@ -169,9 +176,10 @@ class LibraryNavigationView @JvmOverloads constructor(context: Context, attrs: A unread -> LibrarySort.UNREAD total -> LibrarySort.TOTAL source -> LibrarySort.SOURCE + dragAndDrop -> LibrarySort.DRAG_AND_DROP else -> throw Exception("Unknown sorting") }) - preferences.librarySortingAscending().set(if (item.state == SORT_ASC) true else false) + preferences.librarySortingAscending().set(item.state == SORT_ASC) item.group.items.forEach { adapter.notifyItemChanged(it) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt index f61db6c20d..86928c4782 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt @@ -20,6 +20,7 @@ import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter import eu.kanade.tachiyomi.ui.migration.MigrationFlags import eu.kanade.tachiyomi.util.combineLatest import eu.kanade.tachiyomi.util.isNullOrUnsubscribed +import eu.kanade.tachiyomi.util.removeArticles import eu.kanade.tachiyomi.util.syncChaptersWithSource import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.Companion.STATE_EXCLUDE import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.Companion.STATE_IGNORE @@ -210,6 +211,9 @@ class LibraryPresenter( val mangaCompare = source1Name.compareTo(source2Name) if (mangaCompare == 0) sortAlphabetical(i1, i2) else mangaCompare } + LibrarySort.DRAG_AND_DROP -> { + 0 + } else -> throw Exception("Unknown sorting mode") } } @@ -228,10 +232,6 @@ class LibraryPresenter( else i1.manga.title.compareTo(i2.manga.title, true) } - private fun String.removeArticles(): String { - return this.replace(Regex("^(an|a|the) ", RegexOption.IGNORE_CASE), "") - } - /** * Get the categories and all its manga from the database. * diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySort.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySort.kt index a67b793fef..170a61388c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySort.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySort.kt @@ -8,4 +8,5 @@ object LibrarySort { const val UNREAD = 3 const val TOTAL = 4 const val SOURCE = 5 + const val DRAG_AND_DROP = 6 } \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/StringExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/StringExtensions.kt index 862514e96d..7f7ad4d2b7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/StringExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/StringExtensions.kt @@ -14,6 +14,10 @@ fun String.chop(count: Int, replacement: String = "..."): String { } +fun String.removeArticles(): String { + return this.replace(Regex("^(an|a|the) ", RegexOption.IGNORE_CASE), "") +} + /** * Replaces the given string to have at most [count] characters using [replacement] near the center. * If [replacement] is longer than [count] an exception will be thrown when `length > count`. diff --git a/app/src/main/res/menu/library.xml b/app/src/main/res/menu/library.xml index ad53ae03a1..d0c51bd161 100644 --- a/app/src/main/res/menu/library.xml +++ b/app/src/main/res/menu/library.xml @@ -32,4 +32,24 @@ android:title="@string/label_migration" app:showAsAction="never"/> + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b9ebe5f69b..53c3e9e02b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -22,6 +22,8 @@ Selected: %1$d Backup Source migration + Re-order + Alphabetically (descending) Hide title Show title Extensions @@ -43,6 +45,8 @@ Total chapters Last read Last updated + First updated + Drag & Drop Search Skip manga Global search