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
This commit is contained in:
Jay 2020-02-22 00:01:26 -08:00
parent 3044dca9bb
commit c3a10692a1
13 changed files with 160 additions and 54 deletions

View File

@ -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"

View File

@ -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()

View File

@ -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<Int> {
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)
}
}

View File

@ -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) { }
}

View File

@ -446,7 +446,7 @@ open class LibraryController(
/**
* Destroys the action mode.
*/
private fun destroyActionModeIfNeeded() {
protected fun destroyActionModeIfNeeded() {
actionMode?.finish()
}

View File

@ -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()
}
}

View File

@ -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 ""
}
}

View File

@ -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
}

View File

@ -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 {

View File

@ -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 {

View File

@ -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()

View File

@ -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 {

View File

@ -226,6 +226,13 @@
when updating library (overwrites local covers)</string>
<string name="pref_category_library_migration">Migration</string>
<string name="pref_keep_category_sorting">Change category sorting when moving</string>
<string name="pref_keep_category_sorting_summary">In single list mode, should dragging and
dropping an entry into a new category change the category\'s sorting to drag &amp;
drop?</string>
<string name="always_ask">Always ask</string>
<string name="option_keep_category_sort">Keep current sorting method</string>
<string name="option_switch_to_dnd">Switch to Drag &amp; Drop</string>
<!-- Extension section -->
@ -430,6 +437,8 @@
<item quantity="one">1 downloaded</item>
<item quantity="other">%d downloaded</item>
</plurals>
<string name="remember_choice">Remember this choice</string>
<string name="already_in_category">Manga already in category</string>
<!-- Catalogue fragment -->
<string name="source_search_options">Search filters</string>