From c3a10692a1ff1f9010cb19c651dedac8c77caa58 Mon Sep 17 00:00:00 2001 From: Jay Date: Sat, 22 Feb 2020 00:01:26 -0800 Subject: [PATCH] Fixed being able to drag n drop the a manga into a category that already has it Sometimes you have to save users from themselves Added checkbox to also default switching category sorting when moving manga --- .../data/preference/PreferenceKeys.kt | 2 + .../data/preference/PreferencesHelper.kt | 2 + .../ui/library/LibraryCategoryAdapter.kt | 13 +- .../ui/library/LibraryCategoryView.kt | 13 +- .../tachiyomi/ui/library/LibraryController.kt | 2 +- .../tachiyomi/ui/library/LibraryItem.kt | 4 +- .../ui/library/LibraryListController.kt | 112 +++++++++++++----- .../tachiyomi/ui/library/LibraryPresenter.kt | 5 + .../tachiyomi/ui/setting/PreferenceDSL.kt | 18 ++- .../ui/setting/SettingsLibraryController.kt | 12 ++ .../widget/preference/IntListMatPreference.kt | 10 +- .../widget/preference/MatPreference.kt | 12 +- app/src/main/res/values/strings.xml | 9 ++ 13 files changed, 160 insertions(+), 54 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt index 65eeea5d4a..d735bab70c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt @@ -137,6 +137,8 @@ object PreferenceKeys { const val refreshCoversToo = "refresh_covers_too" + const val keepCatSort = "keep_cat_sort" + @Deprecated("Use the preferences of the source") fun sourceUsername(sourceId: Long) = "pref_source_username_$sourceId" 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 a8fcadff69..f6840c9a30 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 @@ -239,6 +239,8 @@ class PreferencesHelper(val context: Context) { fun unreadBadgeType() = rxPrefs.getInteger("unread_badge_type", 1) + fun keepCatSort() = rxPrefs.getInteger(Keys.keepCatSort, 0) + 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 998238883e..1e774fa80d 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 @@ -67,6 +67,17 @@ class LibraryCategoryAdapter(val libraryListener: LibraryListener) : else false } } + /** + * Returns the position in the adapter for the given manga. + * + * @param manga the manga to find. + */ + fun allIndexOf(manga: Manga): List { + return currentItems.mapIndexedNotNull { index, it -> + if (it is LibraryItem && it.manga.id == manga.id) index + else null } + } + fun performFilter() { val s = getFilter(String::class.java) if (s.isNullOrBlank()) { @@ -161,6 +172,6 @@ class LibraryCategoryAdapter(val libraryListener: LibraryListener) : fun onItemReleased(position: Int) fun canDrag(): Boolean fun updateCategory(catId: Int): Boolean - fun sortCategory(catId: Int, sortBy: Int): String + fun sortCategory(catId: Int, sortBy: Int) } } 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 e0b9713646..8cfdad1e14 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 @@ -221,7 +221,7 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att val position = adapter.indexOf(manga) if (position != -1 && !adapter.isSelected(position)) { adapter.toggleSelection(position) - (recycler.findViewHolderForItemId(manga.id!!) as? LibraryHolder)?.toggleActivation() + (recycler.findViewHolderForAdapterPosition(position) as? LibraryHolder)?.toggleActivation() } } } @@ -272,7 +272,7 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att val position = adapter.indexOf(manga) if (position != -1) { adapter.toggleSelection(position) - (recycler.findViewHolderForItemId(manga.id!!) as? LibraryHolder)?.toggleActivation() + (recycler.findViewHolderForAdapterPosition(position) as? LibraryHolder)?.toggleActivation() } } @@ -320,9 +320,7 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att lastClickPosition = position } - override fun onItemMove(fromPosition: Int, toPosition: Int) { - - } + override fun onItemMove(fromPosition: Int, toPosition: Int) { } override fun onItemReleased(position: Int) { if (adapter.selectedItemCount == 0) saveDragSort() @@ -395,8 +393,5 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att return true } - override fun sortCategory(catId: Int, sortBy: Int): String { - return "" - } - + override fun sortCategory(catId: Int, sortBy: Int) { } } 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 70e20d0834..9c00b41f16 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 @@ -446,7 +446,7 @@ open class LibraryController( /** * Destroys the action mode. */ - private fun destroyActionModeIfNeeded() { + protected fun destroyActionModeIfNeeded() { actionMode?.finish() } 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 b6c6b12974..1b7607feca 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 @@ -131,12 +131,12 @@ class LibraryItem(val manga: LibraryManga, override fun equals(other: Any?): Boolean { if (other is LibraryItem) { - return manga.id == other.manga.id + return manga.id == other.manga.id && manga.category == other.manga.category } return false } override fun hashCode(): Int { - return manga.id!!.hashCode() + return (manga.id!! + (manga.category shl 50).toLong()).hashCode() //!!.hashCode() } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryListController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryListController.kt index 1fe979f744..358a886952 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryListController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryListController.kt @@ -17,10 +17,13 @@ import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.afollestad.materialdialogs.MaterialDialog +import com.afollestad.materialdialogs.checkbox.checkBoxPrompt +import com.afollestad.materialdialogs.checkbox.isCheckPromptChecked import com.bluelinelabs.conductor.ControllerChangeHandler import com.bluelinelabs.conductor.ControllerChangeType import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.SelectableAdapter +import eu.davidea.flexibleadapter.items.IFlexible import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.models.LibraryManga import eu.kanade.tachiyomi.data.database.models.Manga @@ -58,6 +61,9 @@ class LibraryListController(bundle: Bundle? = null) : LibraryController(bundle), private var spinnerAdapter: SpinnerAdapter? = null + private var lastItemPostion:Int? = null + private var lastItem:IFlexible<*>? = null + /** * Recycler view of the list of manga. */ @@ -261,7 +267,7 @@ class LibraryListController(bundle: Bundle? = null) : LibraryController(bundle), override fun setSelection(manga: Manga, selected: Boolean) { if (selected) { if (selectedMangas.add(manga)) { - val position = adapter.indexOf(manga) + val positions = adapter.allIndexOf(manga) if (adapter.mode != SelectableAdapter.Mode.MULTI) { adapter.mode = SelectableAdapter.Mode.MULTI } @@ -269,19 +275,23 @@ class LibraryListController(bundle: Bundle? = null) : LibraryController(bundle), delay(100) adapter.isLongPressDragEnabled = false } - adapter.toggleSelection(position) - (recycler.findViewHolderForItemId(manga.id!!) as? LibraryHolder)?.toggleActivation() + positions.forEach { position -> + adapter.addSelection(position) + (recycler.findViewHolderForAdapterPosition(position) as? LibraryHolder)?.toggleActivation() + } } } else { if (selectedMangas.remove(manga)) { - val position = adapter.indexOf(manga) + val positions = adapter.allIndexOf(manga) lastClickPosition = -1 if (selectedMangas.isEmpty()) { adapter.mode = SelectableAdapter.Mode.SINGLE adapter.isLongPressDragEnabled = canDrag() } - adapter.toggleSelection(position) - (recycler.findViewHolderForItemId(manga.id!!) as? LibraryHolder)?.toggleActivation() + positions.forEach { position -> + adapter.removeSelection(position) + (recycler.findViewHolderForAdapterPosition(position) as? LibraryHolder)?.toggleActivation() + } } } } @@ -358,7 +368,20 @@ class LibraryListController(bundle: Bundle? = null) : LibraryController(bundle), override fun onActionStateChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) { val position = viewHolder?.adapterPosition ?: return - if (actionState == 2) onItemLongClick(position) + if (actionState == 2) { + if (lastItemPostion != null && position != lastItemPostion + && lastItem == adapter.getItem(position)) { + // because for whatever reason you can re + adapter.removeSelection(position) + (recycler.findViewHolderForAdapterPosition(position) as? LibraryHolder)?.toggleActivation() + adapter.moveItem(position, lastItemPostion!!) + } + else { + lastItem = adapter.getItem(position) + lastItemPostion = position + onItemLongClick(position) + } + } } override fun onUpdateManga(manga: LibraryManga) { @@ -378,10 +401,17 @@ class LibraryListController(bundle: Bundle? = null) : LibraryController(bundle), invalidateActionMode() } - override fun onItemMove(fromPosition: Int, toPosition: Int) { } + override fun onItemMove(fromPosition: Int, toPosition: Int) { + if (lastItemPostion == toPosition) + lastItemPostion = null + } override fun onItemReleased(position: Int) { - if (adapter.selectedItemCount > 0) return + if (adapter.selectedItemCount > 0) { + lastItemPostion = null + return + } + destroyActionModeIfNeeded() val item = adapter.getItem(position) as? LibraryItem ?: return val newHeader = adapter.getSectionHeader(position) as? LibraryHeaderItem val libraryItems = adapter.getSectionItems(adapter.getSectionHeader(position)) @@ -390,35 +420,58 @@ class LibraryListController(bundle: Bundle? = null) : LibraryController(bundle), if (newHeader?.category?.id == item.manga.category) { presenter.rearrangeCategory(item.manga.category, mangaIds) } else { + if (presenter.mangaIsInCategory(item.manga, newHeader?.category?.id)) { + adapter.moveItem(position, lastItemPostion!!) + snack = snackbar_layout?.snack(R.string.already_in_category) + return + } if (newHeader?.category?.mangaSort == null) { presenter.moveMangaToCategory(item, newHeader?.category?.id, mangaIds, true) } else { - MaterialDialog(activity!!).message(R.string.switch_to_dnd) - .positiveButton(R.string.action_switch) { - presenter.moveMangaToCategory(item, newHeader.category.id, mangaIds, true) - }.negativeButton( - text = resources?.getString( - R.string.keep_current_sort, - resources!!.getString(newHeader.category.sortRes()).toLowerCase - (Locale.getDefault()) - ) - ) { - presenter.moveMangaToCategory( - item, newHeader.category.id, mangaIds, false - ) - } - .cancelOnTouchOutside(false) - .show() + val keepCatSort = preferences.keepCatSort().getOrDefault() + if (keepCatSort == 0) { + MaterialDialog(activity!!).message(R.string.switch_to_dnd) + .positiveButton(R.string.action_switch) { + presenter.moveMangaToCategory( + item, newHeader.category.id, mangaIds, true + ) + if (it.isCheckPromptChecked()) preferences.keepCatSort().set(2) + } + .checkBoxPrompt(R.string.remember_choice) {} + .negativeButton( + text = resources?.getString( + R.string.keep_current_sort, + resources!!.getString(newHeader.category.sortRes()).toLowerCase( + Locale.getDefault() + ) + ) + ) { + presenter.moveMangaToCategory( + item, newHeader.category.id, mangaIds, false + ) + if (it.isCheckPromptChecked()) preferences.keepCatSort().set(1) + }.cancelOnTouchOutside(false).show() + } + else { + presenter.moveMangaToCategory( + item, newHeader.category.id, mangaIds, keepCatSort == 2 + ) + } } } + lastItemPostion = null } override fun shouldMoveItem(fromPosition: Int, toPosition: Int): Boolean { - if (adapter.selectedItemCount > 1) - return false + //if (adapter.selectedItemCount > 1) + // return false if (adapter.isSelected(fromPosition)) toggleSelection(fromPosition) - return true + val item = adapter.getItem(fromPosition) as? LibraryItem ?: return false + val newHeader = adapter.getSectionHeader(toPosition) as? LibraryHeaderItem + //if (adapter.getItem(toPosition) is LibraryHeaderItem) return false + return newHeader?.category?.id == item.manga.category || + !presenter.mangaIsInCategory(item.manga, newHeader?.category?.id) } override fun updateCategory(catId: Int): Boolean { @@ -438,8 +491,7 @@ class LibraryListController(bundle: Bundle? = null) : LibraryController(bundle), return true } - override fun sortCategory(catId: Int, sortBy: Int): String { + override fun sortCategory(catId: Int, sortBy: Int) { presenter.sortCategory(catId, sortBy) - return "" } } \ No newline at end of file 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 ac9e7452ea..963875cad3 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 @@ -843,6 +843,11 @@ class LibraryPresenter( } } + fun mangaIsInCategory(manga: LibraryManga, catId: Int?): Boolean { + val categories = db.getCategoriesForManga(manga).executeAsBlocking().map { it.id } + return catId in categories + } + private companion object { var currentLibrary:Library? = null } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/PreferenceDSL.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/PreferenceDSL.kt index 446b0bf952..0447043caa 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/PreferenceDSL.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/PreferenceDSL.kt @@ -1,9 +1,18 @@ package eu.kanade.tachiyomi.ui.setting import android.app.Activity -import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat import androidx.core.graphics.drawable.DrawableCompat -import androidx.preference.* +import androidx.preference.CheckBoxPreference +import androidx.preference.DialogPreference +import androidx.preference.DropDownPreference +import androidx.preference.EditTextPreference +import androidx.preference.Preference +import androidx.preference.PreferenceCategory +import androidx.preference.PreferenceGroup +import androidx.preference.PreferenceManager +import androidx.preference.PreferenceScreen +import androidx.preference.SwitchPreferenceCompat +import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat import eu.kanade.tachiyomi.widget.preference.ExtensionPreference import eu.kanade.tachiyomi.widget.preference.IntListMatPreference import eu.kanade.tachiyomi.widget.preference.ListMatPreference @@ -38,6 +47,11 @@ inline fun PreferenceGroup.editTextPreference(block: (@DSL EditTextPreference).( return initThenAdd(EditTextPreference(context), block).also(::initDialog) } +inline fun PreferenceGroup.dropDownPreference(block: (@DSL DropDownPreference).() -> Unit): + DropDownPreference { + return initThenAdd(DropDownPreference(context), block).also(::initDialog) +} + inline fun PreferenceGroup.listPreference(activity: Activity?, block: (@DSL ListMatPreference).() -> Unit): ListMatPreference { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsLibraryController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsLibraryController.kt index b96608326b..e105962436 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsLibraryController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsLibraryController.kt @@ -182,6 +182,18 @@ class SettingsLibraryController : SettingsController() { true } } + intListPreference(activity) { + titleRes = R.string.pref_keep_category_sorting + key = Keys.keepCatSort + summaryRes = R.string.pref_keep_category_sorting_summary + entries = listOf( + context.getString(R.string.always_ask), + context.getString(R.string.option_keep_category_sort), + context.getString(R.string.option_switch_to_dnd) + ) + entryRange = 0..2 + defaultValue = 0 + } } if (preferences.skipPreMigration().getOrDefault() || preferences.migrationSources().getOrDefault().isNotEmpty()) { preferenceCategory { diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/IntListMatPreference.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/IntListMatPreference.kt index b423304bb8..0b3b8a37a3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/IntListMatPreference.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/IntListMatPreference.kt @@ -3,15 +3,9 @@ package eu.kanade.tachiyomi.widget.preference import android.app.Activity import android.content.Context import android.util.AttributeSet -import androidx.preference.Preference import com.afollestad.materialdialogs.MaterialDialog -import com.afollestad.materialdialogs.callbacks.onDismiss import com.afollestad.materialdialogs.list.listItemsSingleChoice -import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.getOrDefault -import eu.kanade.tachiyomi.ui.setting.defaultValue -import uy.kohesive.injekt.Injekt -import uy.kohesive.injekt.api.get class IntListMatPreference @JvmOverloads constructor(activity: Activity?, context: Context, attrs: @@ -33,6 +27,7 @@ AttributeSet? = defValue = defaultValue as? Int ?: defValue } override fun getSummary(): CharSequence { + if (key == null || useCustomSummary) return super.getSummary() val index = entryValues.indexOf(prefs.getInt(key, defValue).getOrDefault()) return if (entries.isEmpty() || index == -1) "" else entries[index] @@ -46,7 +41,8 @@ AttributeSet? = initialSelection = default) { _, pos, _ -> val value = entryValues[pos] - prefs.getInt(key, defValue).set(value) + if (key != null) + prefs.getInt(key, defValue).set(value) callChangeListener(value) this@IntListMatPreference.summary = this@IntListMatPreference.summary dismiss() diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/MatPreference.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/MatPreference.kt index 491c895165..604620ee87 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/MatPreference.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/MatPreference.kt @@ -6,9 +6,7 @@ import android.util.AttributeSet import androidx.preference.Preference import com.afollestad.materialdialogs.MaterialDialog import com.afollestad.materialdialogs.callbacks.onDismiss -import com.afollestad.materialdialogs.list.listItemsSingleChoice import eu.kanade.tachiyomi.data.preference.PreferencesHelper -import eu.kanade.tachiyomi.data.preference.getOrDefault import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get @@ -18,9 +16,19 @@ open class MatPreference @JvmOverloads constructor(val activity: Activity?, cont null) : Preference(context, attrs) { + protected var useCustomSummary = false protected val prefs: PreferencesHelper = Injekt.get() private var isShowing = false + override fun setSummary(summaryResId: Int) { + useCustomSummary = true + super.setSummary(summaryResId) + } + + override fun setSummary(summary: CharSequence?) { + useCustomSummary = true + super.setSummary(summary) + } override fun onClick() { if (!isShowing) dialog().apply { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index de71627375..3e784d4eb9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -226,6 +226,13 @@ when updating library (overwrites local covers) Migration + Change category sorting when moving + In single list mode, should dragging and + dropping an entry into a new category change the category\'s sorting to drag & + drop? + Always ask + Keep current sorting method + Switch to Drag & Drop @@ -430,6 +437,8 @@ 1 downloaded %d downloaded + Remember this choice + Manga already in category Search filters