More work on single list + fully restored pager

Pager is now back to default preference
Addedname for the setting in lbrary
Single list:
*Popup to when moving manga from one category to another (to switch to D&D or use current category sorting)
*Made current spinner option reselectable
*In filter bottom sheet, sort options are gone in single list, now always using D&D mode for sorting single list since categories have sort options
* When hiding filters, list reverts back to library sorting and header modifies library sorting
Pager:
* Header item no longer shows
* Restored tabs
pull/3117/head
Jay 5 years ago
parent 21d7f342e6
commit da2f3d4524

@ -31,18 +31,31 @@ interface Category : Serializable {
UPDATED_ASC, UPDATED_DSC -> LibrarySort.LAST_UPDATED
UNREAD_ASC, UNREAD_DSC -> LibrarySort.UNREAD
LAST_READ_ASC, LAST_READ_DSC -> LibrarySort.LAST_READ
TOTAL_ASC, TOTAL_DSC -> LibrarySort.TOTAL
DRAG_AND_DROP -> LibrarySort.DRAG_AND_DROP
else -> null
}
fun sortRes(): Int = when (mangaSort) {
ALPHA_ASC, ALPHA_DSC -> R.string.title
UPDATED_ASC, UPDATED_DSC -> R.string.action_sort_last_updated
UNREAD_ASC, UNREAD_DSC -> R.string.action_filter_unread
LAST_READ_ASC, LAST_READ_DSC -> R.string.action_sort_last_read
TOTAL_ASC, TOTAL_DSC -> R.string.action_sort_total
else -> R.string.action_sort_drag_and_drop
}
fun catSortingMode(): Int? = when (mangaSort) {
ALPHA_ASC, ALPHA_DSC -> 0
UPDATED_ASC, UPDATED_DSC -> 1
UNREAD_ASC, UNREAD_DSC -> 2
LAST_READ_ASC, LAST_READ_DSC -> 3
TOTAL_ASC, TOTAL_DSC -> 4
else -> null
}
companion object {
private const val DRAG_AND_DROP = 'D'
private const val ALPHA_ASC = 'a'
private const val ALPHA_DSC = 'b'
private const val UPDATED_ASC = 'c'
@ -51,15 +64,34 @@ interface Category : Serializable {
private const val UNREAD_DSC = 'f'
private const val LAST_READ_ASC = 'g'
private const val LAST_READ_DSC = 'h'
private const val TOTAL_ASC = 'i'
private const val TOTAL_DSC = 'j'
fun create(name: String): Category = CategoryImpl().apply {
this.name = name
}
fun createDefault(context: Context): Category = create(context.getString(R.string.default_columns))
.apply {
id =
0 }
fun createDefault(context: Context): Category =
create(context.getString(R.string.default_columns)).apply {
id = 0
}
fun createAll(context: Context, libSort: Int, ascending: Boolean): Category =
create(context.getString(R.string.all)).apply {
id = -1
mangaSort = when (libSort) {
LibrarySort.ALPHA -> ALPHA_ASC
LibrarySort.LAST_UPDATED -> UPDATED_ASC
LibrarySort.UNREAD -> UNREAD_ASC
LibrarySort.LAST_READ -> LAST_READ_ASC
LibrarySort.TOTAL -> TOTAL_ASC
else -> 'D'
}
if (mangaSort != 'D' && !ascending) {
mangaSort?.plus(1)
}
order = -1
}
}
}

@ -113,7 +113,7 @@ object PreferenceKeys {
const val libraryLayout = "pref_display_library_layout"
const val libraryUsingPager = "library_using_pager"
const val libraryAsSingleList = "library_as_single_list"
const val lang = "app_language"

@ -173,7 +173,7 @@ class PreferencesHelper(val context: Context) {
fun libraryLayout() = rxPrefs.getInteger(Keys.libraryLayout, 1)
fun libraryUsingPager() = rxPrefs.getBoolean(Keys.libraryUsingPager, false)
fun libraryAsSingleList() = rxPrefs.getBoolean(Keys.libraryAsSingleList, false)
fun downloadBadge() = rxPrefs.getBoolean(Keys.downloadBadge, false)

@ -25,7 +25,7 @@ class LibraryCategoryAdapter(val libraryListener: LibraryListener) :
FlexibleAdapter<IFlexible<*>>(null, libraryListener, true) {
init {
setDisplayHeadersAtStartUp(!Injekt.get<PreferencesHelper>().libraryUsingPager()
setDisplayHeadersAtStartUp(Injekt.get<PreferencesHelper>().libraryAsSingleList()
.getOrDefault())
}
/**

@ -184,6 +184,7 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
val filterOff = preferences.filterCompleted().getOrDefault() +
preferences.filterTracked().getOrDefault() +
preferences.filterUnread().getOrDefault() +
preferences.filterMangaType().getOrDefault() +
preferences.filterCompleted().getOrDefault() == 0 &&
!preferences.hideCategories().getOrDefault()
return sortingMode == LibrarySort.DRAG_AND_DROP && filterOff &&
@ -212,7 +213,6 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
val mangaForCategory = event.getMangaForCategory(category).orEmpty()
adapter.setItems(mangaForCategory)
adapter.hideAllHeaders()
swipe_refresh.isEnabled = !preferences.hideCategories().getOrDefault()

@ -5,6 +5,7 @@ import android.content.Context
import android.content.res.Configuration
import android.graphics.Color
import android.os.Bundle
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
@ -15,10 +16,8 @@ import android.view.WindowInsets
import android.view.inputmethod.InputMethodManager
import android.widget.ArrayAdapter
import android.widget.Spinner
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.view.ActionMode
import androidx.appcompat.widget.AppCompatSpinner
import androidx.appcompat.widget.SearchView
import androidx.core.graphics.drawable.DrawableCompat
import androidx.core.math.MathUtils.clamp
@ -33,6 +32,7 @@ import com.f2prateek.rx.preferences.Preference
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.snackbar.BaseTransientBottomBar
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.tabs.TabLayout
import com.jakewharton.rxrelay.BehaviorRelay
import com.jakewharton.rxrelay.PublishRelay
import eu.davidea.flexibleadapter.FlexibleAdapter
@ -48,6 +48,7 @@ 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.base.controller.BaseController
import eu.kanade.tachiyomi.ui.base.controller.TabbedController
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
import eu.kanade.tachiyomi.ui.category.CategoryController
import eu.kanade.tachiyomi.ui.download.DownloadController
@ -73,16 +74,18 @@ import eu.kanade.tachiyomi.widget.AutofitRecyclerView
import eu.kanade.tachiyomi.widget.IgnoreFirstSpinnerListener
import kotlinx.android.synthetic.main.filter_bottom_sheet.*
import kotlinx.android.synthetic.main.library_controller.*
import kotlinx.android.synthetic.main.main_activity.*
import kotlinx.coroutines.delay
import timber.log.Timber
import rx.Subscription
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.util.Locale
import kotlin.math.min
class LibraryController(
bundle: Bundle? = null,
private val preferences: PreferencesHelper = Injekt.get()
) : BaseController(bundle),
//TabbedController,
) : BaseController(bundle), TabbedController,
ActionMode.Callback,
ChangeMangaCategoriesDialog.Listener,
MigrationInterface,
@ -163,9 +166,9 @@ class LibraryController(
/**
* Drawer listener to allow swipe only for closing the drawer.
*/
// private var tabsVisibilityRelay: BehaviorRelay<Boolean> = BehaviorRelay.create(false)
private var tabsVisibilityRelay: BehaviorRelay<Boolean> = BehaviorRelay.create(false)
// private var tabsVisibilitySubscription: Subscription? = null
private var tabsVisibilitySubscription: Subscription? = null
private var observeLater:Boolean = false
@ -196,12 +199,11 @@ class LibraryController(
val category = presenter.categories.find { it.order == order }
bottom_sheet.lastCategory = category
if (preferences.librarySortingMode().getOrDefault() == LibrarySort.DRAG_AND_DROP)
bottom_sheet.updateTitle()
updateScroll = true
spinner.setSelection(order + 1)
spinnerAdapter?.setCustomText(category?.name)
bottom_sheet.updateTitle()
if (spinner.selectedItemPosition != order + 1) {
updateScroll = true
spinner.setSelection(order + 1, true)
}
}
}
}
@ -211,7 +213,7 @@ class LibraryController(
*/
private lateinit var recycler: RecyclerView
var usePager = preferences.libraryUsingPager().getOrDefault()
private var usePager: Boolean = !preferences.libraryAsSingleList().getOrDefault()
init {
setHasOptionsMenu(true)
@ -219,15 +221,9 @@ class LibraryController(
}
override fun getTitle(): String? {
return null//if (title != null) null else resources?.getString(R.string.label_library)
return if (usePager) resources?.getString(R.string.label_library) else null
}
private var title: String? = null
set(value) {
field = value
setTitle()
}
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
return inflater.inflate(R.layout.library_controller, container, false)
}
@ -283,14 +279,15 @@ class LibraryController(
adapter.fastScroller = fast_scroller
recycler.addOnScrollListener(scrollListener)
spinner = recycler_layout.inflate(R.layout.library_spinner) as AppCompatSpinner
spinner = ReSpinner(view.context)
(activity as MainActivity).supportActionBar?.setDisplayShowCustomEnabled(true)
(activity as MainActivity).supportActionBar?.customView = spinner
spinnerAdapter = SpinnerAdapter(view.context, R.layout.library_spinner_textview,
arrayOf(resources!!.getString(R.string.label_library)))
spinnerAdapter?.setDropDownViewResource(R.layout.library_spinner_entry_text)
spinner.adapter = spinnerAdapter
spinnerAdapter?.setCustomText(resources?.getString(R.string.label_library))
//spinnerAdapter?.setCustomText(resources?.getString(R.string.label_library))
}
@ -318,22 +315,14 @@ class LibraryController(
router.pushController(DownloadController().withFadeTransaction())
}
// spinner.onItemSelectedListener = listener
/*spinner.onItemSelectedListener = IgnoreFirstSpinnerListener { position ->
if (!updateScroll) return@IgnoreFirstSpinnerListener
val headerPosition = adapter.indexOf(position) + 1
if (headerPosition > -1) (recycler.layoutManager as LinearLayoutManager)
.scrollToPositionWithOffset(position, 0)
}*/
val config = resources?.configuration
val phoneLandscape = (config?.orientation == Configuration.ORIENTATION_LANDSCAPE &&
(config.screenLayout.and(Configuration.SCREENLAYOUT_SIZE_MASK)) <
Configuration.SCREENLAYOUT_SIZE_LARGE)
// pad the recycler if the filter bottom sheet is visible
if (!usePager && !phoneLandscape) {
val height = view.context.resources.getDimensionPixelSize(R.dimen.rounder_radius) + 5.dpToPx
val height = view.context.resources.getDimensionPixelSize(R.dimen.rounder_radius) + 4.dpToPx
recycler.updatePaddingRelative(bottom = height)
}
@ -358,7 +347,8 @@ class LibraryController(
if (type.isEnter) {
if (!usePager)
(activity as MainActivity).supportActionBar?.setDisplayShowCustomEnabled(true)
//activity?.tabs?.setupWithViewPager(library_pager)
else
activity?.tabs?.setupWithViewPager(library_pager)
presenter.getLibrary()
DownloadService.addListener(this)
DownloadService.callListeners()
@ -389,13 +379,13 @@ class LibraryController(
}
override fun onDestroyView(view: View) {
//adapter.onDestroy()
pagerAdapter?.onDestroy()
DownloadService.removeListener(this)
LibraryUpdateService.removeListener()
//adapter = null
pagerAdapter = null
actionMode = null
//tabsVisibilitySubscription?.unsubscribe()
//tabsVisibilitySubscription = null
tabsVisibilitySubscription?.unsubscribe()
tabsVisibilitySubscription = null
super.onDestroyView(view)
}
@ -421,7 +411,7 @@ class LibraryController(
super.onDetach(view)
}
/*override fun configureTabs(tabs: TabLayout) {
override fun configureTabs(tabs: TabLayout) {
with(tabs) {
tabGravity = TabLayout.GRAVITY_CENTER
tabMode = TabLayout.MODE_SCROLLABLE
@ -440,7 +430,7 @@ class LibraryController(
override fun cleanupTabs(tabs: TabLayout) {
tabsVisibilitySubscription?.unsubscribe()
tabsVisibilitySubscription = null
}*/
}
fun onNextLibraryUpdate(mangaMap: List<LibraryItem>, freshStart: Boolean = false) {
if (mangaMap.isNotEmpty()) {
@ -455,14 +445,14 @@ class LibraryController(
spinner.onItemSelectedListener = null
spinnerAdapter = SpinnerAdapter(view!!.context, R.layout.library_spinner_textview,
presenter.categories.map { it.name }.toTypedArray())
spinnerAdapter?.setDropDownViewResource(R.layout.library_spinner_entry_text)
spinner.adapter = spinnerAdapter
spinnerAdapter?.setCustomText(presenter.categories.find { it.order == activeCategory
}?.name ?: resources?.getString(R.string.label_library))
spinner.setSelection(min(presenter.categories.size - 1, activeCategory + 1))
/* spinnerAdapter?.setCustomText(presenter.categories.find { it.order == activeCategory
}?.name ?: resources?.getString(R.string.label_library))*/
if (!freshStart) {
spinnerAdapter?.setCustomText(presenter.categories.find { it.order == activeCategory
}?.name ?: resources?.getString(R.string.label_library))
justStarted = false
if (recycler_layout.alpha == 0f)
recycler_layout.animate().alpha(1f).setDuration(500).start()
@ -474,6 +464,7 @@ class LibraryController(
.scrollToPositionWithOffset(position, 0)
}
adapter.isLongPressDragEnabled = canDrag()
tabsVisibilityRelay.call(false)
bottom_sheet.lastCategory = presenter.categories[clamp(activeCategory,
0,
@ -527,13 +518,13 @@ class LibraryController(
bottom_sheet.lastCategory = adapter.categories.getOrNull(activeCat)
bottom_sheet.updateTitle()
//tabsVisibilityRelay.call(categories.size > 1)
tabsVisibilityRelay.call(categories.size > 1)
if (freshStart || !justStarted) {
// Delay the scroll position to allow the view to be properly measured.
view.post {
if (isAttached) {
//activity?.tabs?.setScrollPosition(library_pager.currentItem, 0f, true)
activity?.tabs?.setScrollPosition(library_pager.currentItem, 0f, true)
}
}
@ -583,57 +574,72 @@ class LibraryController(
}
fun onCatSortChanged(id: Int? = null) {
val catId = id ?: presenter.categories.find { it.order == activeCategory }?.id ?: return
val catId =
(if (usePager)(id ?: pagerAdapter?.categories?.getOrNull(library_pager.currentItem)?.id)
else (id ?: presenter.categories.find { it.order == activeCategory }?.id))
?: return
presenter.requestCatSortUpdate(catId)
//val catId = id ?: adapter?.categories?.getOrNull(library_pager.currentItem)?.id ?: return
// presenter.requestCatSortUpdate(catId)
}
/**
* Reattaches the adapter to the view pager to recreate fragments
*/
private fun reattachAdapter() {
val position = (recycler.layoutManager as LinearLayoutManager).findFirstVisibleItemPosition()
if (recycler is AutofitRecyclerView && preferences.libraryLayout().getOrDefault() == 0 ||
recycler !is AutofitRecyclerView && preferences.libraryLayout().getOrDefault() > 0) {
destroyActionModeIfNeeded()
recycler_layout.removeView(recycler)
recycler = if (preferences.libraryLayout().getOrDefault() == 0) {
(recycler_layout.inflate(R.layout.library_list_recycler) as RecyclerView).apply {
layoutManager = LinearLayoutManager(context)
if (usePager) {
val adapter = pagerAdapter ?: return
val position = library_pager.currentItem
adapter.recycle = false
library_pager.adapter = adapter
library_pager.currentItem = position
adapter.recycle = true
}
else {
val position =
(recycler.layoutManager as LinearLayoutManager).findFirstVisibleItemPosition()
// if switching from list to grid
if (recycler is AutofitRecyclerView && preferences.libraryLayout().getOrDefault() == 0
|| recycler !is AutofitRecyclerView && preferences.libraryLayout().getOrDefault() > 0) {
destroyActionModeIfNeeded()
recycler_layout.removeView(recycler)
recycler = if (preferences.libraryLayout().getOrDefault() == 0) {
(recycler_layout.inflate(R.layout.library_list_recycler) as RecyclerView).apply {
layoutManager = LinearLayoutManager(context)
}
} else {
(recycler_layout.inflate(R.layout.library_grid_recycler) as AutofitRecyclerView).apply {
spanCount = mangaPerRow
manager.spanSizeLookup = (object : GridLayoutManager.SpanSizeLookup() {
override fun getSpanSize(position: Int): Int {
val item = this@LibraryController.adapter.getItem(position)
return if (item is LibraryHeaderItem) manager.spanCount else 1
}
})
}
}
} else {
(recycler_layout.inflate(R.layout.library_grid_recycler) as AutofitRecyclerView).apply {
spanCount = mangaPerRow
manager.spanSizeLookup = (object : GridLayoutManager.SpanSizeLookup() {
override fun getSpanSize(position: Int): Int {
val item = this@LibraryController.adapter.getItem(position)
return if (item is LibraryHeaderItem)
manager.spanCount else 1
}
})
recycler.setHasFixedSize(true)
adapter = LibraryCategoryAdapter(this)
recycler.adapter = adapter
recycler.addOnScrollListener(scrollListener)
adapter.isLongPressDragEnabled = canDrag()
recycler_layout.addView(recycler)
adapter.setItems(presenter.getList())
val config = resources?.configuration
val phoneLandscape = (config?.orientation == Configuration.ORIENTATION_LANDSCAPE &&
(config.screenLayout.and(Configuration.SCREENLAYOUT_SIZE_MASK)) <
Configuration.SCREENLAYOUT_SIZE_LARGE)
if (!usePager && !phoneLandscape) {
val height = recycler.resources.getDimensionPixelSize(R.dimen
.rounder_radius) + 4.dpToPx
recycler.updatePaddingRelative(bottom = height)
}
} else {
recycler.adapter = adapter
}
recycler.setHasFixedSize(true)
adapter = LibraryCategoryAdapter(this)
recycler.adapter = adapter
recycler.addOnScrollListener(scrollListener)
adapter.isLongPressDragEnabled = canDrag()
recycler_layout.addView(recycler)
adapter.setItems(presenter.getList())
} else {
recycler.adapter = adapter
}
(recycler.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(position, 0)
//val adapter = adapter ?: return
/*val position = library_pager.currentItem
adapter.recycle = false
library_pager.adapter = adapter
library_pager.currentItem = position
adapter.recycle = true*/
(recycler.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(position, 0)
}
}
/**
@ -921,7 +927,10 @@ class LibraryController(
override fun startReading(position: Int) {
val activity = activity ?: return
val manga = (adapter.getItem(position) as? LibraryItem)?.manga ?: return
if (adapter.mode == SelectableAdapter.Mode.MULTI) toggleSelection(position)
if (adapter.mode == SelectableAdapter.Mode.MULTI) {
toggleSelection(position)
return
}
val chapter = presenter.getFirstUnread(manga) ?: return
val intent = ReaderActivity.newIntent(activity, manga, chapter)
destroyActionModeIfNeeded()
@ -937,14 +946,13 @@ class LibraryController(
}
override fun canDrag(): Boolean {
val sortingMode = preferences.librarySortingMode().getOrDefault()
val filterOff = preferences.filterCompleted().getOrDefault() +
preferences.filterTracked().getOrDefault() +
preferences.filterUnread().getOrDefault() +
preferences.filterMangaType().getOrDefault() +
preferences.filterCompleted().getOrDefault() == 0 &&
!preferences.hideCategories().getOrDefault()
return sortingMode == LibrarySort.DRAG_AND_DROP && filterOff &&
adapter.mode != SelectableAdapter.Mode.MULTI
return filterOff && adapter.mode != SelectableAdapter.Mode.MULTI
}
/**
@ -1020,13 +1028,32 @@ class LibraryController(
if (adapter.selectedItemCount > 0) return
val item = adapter.getItem(position) as? LibraryItem ?: return
val newHeader = adapter.getSectionHeader(position) as? LibraryHeaderItem
val libraryItems = adapter.getSectionItems(adapter.getSectionHeader(position)).filterIsInstance<LibraryItem>()
val libraryItems = adapter.getSectionItems(adapter.getSectionHeader(position))
.filterIsInstance<LibraryItem>()
val mangaIds = libraryItems.mapNotNull { (it as? LibraryItem)?.manga?.id }
if (newHeader?.category?.id == item.manga.category) {
presenter.rearrangeCategory(item.manga.category, mangaIds)
} else {
presenter.moveMangaToCategory(item, newHeader?.category?.id, mangaIds)
Timber.d("Manga has Moved")
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()
}
}
}
@ -1077,26 +1104,32 @@ object HeightTopWindowInsetsListener : View.OnApplyWindowInsetsListener {
class SpinnerAdapter(context: Context, layoutId: Int, val array: Array<String>) :
ArrayAdapter<String>
(context, layoutId, array) {
private var mCustomText = ""
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
val view = super.getView(position, convertView, parent)
val tv: TextView = view as TextView
tv.text = mCustomText
return view
}
fun setCustomText(customText: String?) {
// Call to set the text that must be shown in the spinner for the custom option.
val text = customText ?: return
mCustomText = text
notifyDataSetChanged()
(context, layoutId, array)
class ReSpinner : Spinner {
constructor(context: Context?) : super(context) {}
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {}
constructor(context: Context?, attrs: AttributeSet?, defStyle: Int) : super(
context, attrs, defStyle
)
override fun setSelection(position: Int, animate: Boolean) {
val sameSelected = position == selectedItemPosition
super.setSelection(position, animate)
if (sameSelected) { // Spinner does not call the OnItemSelectedListener if the same item is selected, so do it manually now
onItemSelectedListener?.onItemSelected(
this, selectedView, position, selectedItemId
)
}
}
override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View {
val view = parent.inflate(R.layout.library_spinner_entry_text) as TextView
view.text = array[position]
return view
override fun setSelection(position: Int) {
val sameSelected = position == selectedItemPosition
super.setSelection(position)
if (sameSelected) { // Spinner does not call the OnItemSelectedListener if the same item is selected, so do it manually now
onItemSelectedListener?.onItemSelected(
this, selectedView, position, selectedItemId
)
}
}
}

@ -90,12 +90,20 @@ class LibraryHeaderItem(val category: Category) : AbstractHeaderItem<LibraryHead
}
)
if (LibraryUpdateService.categoryInQueue(item.category.id)) {
catProgress.visible()
updateButton.invisible()
} else {
catProgress.gone()
updateButton.visible()
when {
item.category.id == -1 -> {
updateButton.invisible()
catProgress.gone()
}
LibraryUpdateService.categoryInQueue(item.category.id) -> {
catProgress.visible()
updateButton.invisible()
}
else -> {
catProgress.gone()
updateButton.visible()
}
}
}
@ -113,7 +121,9 @@ class LibraryHeaderItem(val category: Category) : AbstractHeaderItem<LibraryHead
val popup = PopupMenu(itemView.context, sortText)
// Inflate our menu resource into the PopupMenu's Menu
popup.menuInflater.inflate(R.menu.cat_sort, popup.menu)
popup.menuInflater.inflate(
if (category.id == -1) R.menu.main_sort
else R.menu.cat_sort, popup.menu)
// Set a listener so we are notified if a menu item is clicked
popup.setOnMenuItemClickListener { menuItem ->
@ -140,8 +150,11 @@ class LibraryHeaderItem(val category: Category) : AbstractHeaderItem<LibraryHead
}
currentItem?.icon = tintVector(
if (category.isAscending()) R.drawable.ic_arrow_up_white_24dp
else R.drawable.ic_arrow_down_white_24dp
when {
sortingMode == LibrarySort.DRAG_AND_DROP -> R.drawable.ic_check_white_24dp
category.isAscending() -> R.drawable.ic_arrow_up_white_24dp
else -> R.drawable.ic_arrow_down_white_24dp
}
)
// Finally show the PopupMenu
@ -162,6 +175,7 @@ class LibraryHeaderItem(val category: Category) : AbstractHeaderItem<LibraryHead
}
else {
val order = when (menuId) {
R.id.action_total_chaps -> 4
R.id.action_last_read -> 3
R.id.action_unread -> 2
R.id.action_update -> 1

@ -23,8 +23,8 @@ import uy.kohesive.injekt.injectLazy
class LibraryItem(val manga: LibraryManga,
private val libraryLayout: Preference<Int>,
header: LibraryHeaderItem) :
AbstractSectionableItem<LibraryHolder, LibraryHeaderItem>(header), IFilterable<String> {
header: LibraryHeaderItem?) :
AbstractSectionableItem<LibraryHolder, LibraryHeaderItem?>(header), IFilterable<String> {
var downloadCount = -1
var unreadType = 1

@ -94,6 +94,8 @@ class LibraryPresenter(
fun getLibrary() {
launchUI {
val freshStart = !preferences.libraryAsSingleList().getOrDefault()
&& (currentMangaMap?.values?.firstOrNull()?.firstOrNull()?.header != null)
val mangaMap = withContext(Dispatchers.IO) {
val library = getLibraryFromDB()
library.apply { setDownloadCount(library.mangaMap) }
@ -104,7 +106,7 @@ class LibraryPresenter(
mangaMap
}
currentMangaMap = mangaMap
updateView(categories, mangaMap)
updateView(categories, mangaMap, freshStart)
}
}
@ -252,41 +254,7 @@ class LibraryPresenter(
}
val sortFn: (LibraryItem, LibraryItem) -> Int = { i1, i2 ->
val compare = when {
category.mangaSort != null -> {
var sort = when (category.sortingMode()) {
LibrarySort.ALPHA -> sortAlphabetical(i1, i2)
LibrarySort.LAST_UPDATED -> i2.manga.last_update.compareTo(i1.manga.last_update)
LibrarySort.UNREAD -> when {
i1.manga.unread == i2.manga.unread -> 0
i1.manga.unread == 0 -> if (category.isAscending()) 1 else -1
i2.manga.unread == 0 -> if (category.isAscending()) -1 else 1
else -> i1.manga.unread.compareTo(i2.manga.unread)
}
LibrarySort.LAST_READ -> {
val manga1LastRead = lastReadManga[i1.manga.id!!] ?: lastReadManga.size
val manga2LastRead = lastReadManga[i2.manga.id!!] ?: lastReadManga.size
manga1LastRead.compareTo(manga2LastRead)
}
else -> sortAlphabetical(i1, i2)
}
if (!category.isAscending()) sort *= -1
sort
}
category.mangaOrder.isNotEmpty() -> {
val order = category.mangaOrder
val index1 = order.indexOf(i1.manga.id!!)
val index2 = order.indexOf(i2.manga.id!!)
when {
index1 == index2 -> 0
index1 == -1 -> -1
index2 == -1 -> 1
else -> index1.compareTo(index2)
}
}
else -> 0
}
compare
sortCategory(i1, i2, lastReadManga, category)
}
val comparator = Comparator(sortFn)
@ -309,80 +277,36 @@ class LibraryPresenter(
var counter = 0
db.getTotalChapterManga().executeAsBlocking().associate { it.id!! to counter++ }
}
val catListing by lazy {
val default = createDefaultCategory()
listOf(default) + db.getCategories().executeAsBlocking()
}
val ascending = preferences.librarySortingAscending().getOrDefault()
val useDnD = preferences.libraryAsSingleList().getOrDefault() && !preferences
.hideCategories().getOrDefault()
val sortFn: (LibraryItem, LibraryItem) -> Int = { i1, i2 ->
val compare = when (sortingMode) {
LibrarySort.ALPHA -> sortAlphabetical(i1, i2)
LibrarySort.LAST_READ -> {
val compare = when {
sortingMode == LibrarySort.DRAG_AND_DROP || useDnD ->
sortCategory(i1, i2, lastReadManga)
sortingMode == LibrarySort.ALPHA -> sortAlphabetical(i1, i2)
sortingMode == LibrarySort.LAST_READ -> {
// Get index of manga, set equal to list if size unknown.
val manga1LastRead = lastReadManga[i1.manga.id!!] ?: lastReadManga.size
val manga2LastRead = lastReadManga[i2.manga.id!!] ?: lastReadManga.size
manga1LastRead.compareTo(manga2LastRead)
}
LibrarySort.LAST_UPDATED -> i2.manga.last_update.compareTo(i1.manga.last_update)
LibrarySort.UNREAD ->
sortingMode == LibrarySort.LAST_UPDATED -> i2.manga.last_update.compareTo(i1
.manga.last_update)
sortingMode == LibrarySort.UNREAD ->
when {
i1.manga.unread == i2.manga.unread -> 0
i1.manga.unread == 0 -> if (ascending) 1 else -1
i2.manga.unread == 0 -> if (ascending) -1 else 1
else -> i1.manga.unread.compareTo(i2.manga.unread)
}
LibrarySort.TOTAL -> {
sortingMode == LibrarySort.TOTAL -> {
val manga1TotalChapter = totalChapterManga[i1.manga.id!!] ?: 0
val mange2TotalChapter = totalChapterManga[i2.manga.id!!] ?: 0
manga1TotalChapter.compareTo(mange2TotalChapter)
}
LibrarySort.DRAG_AND_DROP -> {
if (i1.manga.category == i2.manga.category) {
val category = catListing.find { it.id == i1.manga.category }
when {
category?.mangaSort != null -> {
var sort = when (category.sortingMode()) {
LibrarySort.ALPHA -> sortAlphabetical(i1, i2)
LibrarySort.LAST_UPDATED -> i2.manga.last_update.compareTo(i1.manga.last_update)
LibrarySort.UNREAD -> when {
i1.manga.unread == i2.manga.unread -> 0
i1.manga.unread == 0 -> if (category.isAscending()) 1 else -1
i2.manga.unread == 0 -> if (category.isAscending()) -1 else 1
else -> i1.manga.unread.compareTo(i2.manga.unread)
}
LibrarySort.LAST_READ -> {
val manga1LastRead = lastReadManga[i1.manga.id!!] ?: lastReadManga.size
val manga2LastRead = lastReadManga[i2.manga.id!!] ?: lastReadManga.size
manga1LastRead.compareTo(manga2LastRead)
}
else -> sortAlphabetical(i1, i2)
}
if (!category.isAscending())
sort *= -1
sort
}
category?.mangaOrder?.isEmpty() == false -> {
val order = category.mangaOrder
val index1 = order.indexOf(i1.manga.id!!)
val index2 = order.indexOf(i2.manga.id!!)
when {
index1 == index2 -> 0
index1 == -1 -> -1
index2 == -1 -> 1
else -> index1.compareTo(index2)
}
}
else -> 0
}
}
else {
val category = catListing.find { it.id == i1.manga.category }?.order ?: -1
val category2 = catListing.find { it.id == i2.manga.category }?.order ?: -1
category.compareTo(category2)
}
}
else -> 0
}
if (compare == 0) {
@ -400,6 +324,54 @@ class LibraryPresenter(
return map.mapValues { entry -> entry.value.sortedWith(comparator) }
}
private fun sortCategory(i1: LibraryItem, i2: LibraryItem,
lastReadManga: Map<Long, Int>, initCat: Category? = null): Int {
return if (initCat != null || i1.manga.category == i2.manga.category) {
val category = initCat ?: allCategories.find { it.id == i1.manga.category }
when {
category?.mangaSort != null -> {
var sort = when (category.sortingMode()) {
LibrarySort.ALPHA -> sortAlphabetical(i1, i2)
LibrarySort.LAST_UPDATED -> i2.manga.last_update.compareTo(i1.manga.last_update)
LibrarySort.UNREAD -> when {
i1.manga.unread == i2.manga.unread -> 0
i1.manga.unread == 0 -> if (category.isAscending()) 1 else -1
i2.manga.unread == 0 -> if (category.isAscending()) -1 else 1
else -> i1.manga.unread.compareTo(i2.manga.unread)
}
LibrarySort.LAST_READ -> {
val manga1LastRead = lastReadManga[i1.manga.id!!] ?: lastReadManga.size
val manga2LastRead = lastReadManga[i2.manga.id!!] ?: lastReadManga.size
manga1LastRead.compareTo(manga2LastRead)
}
else -> sortAlphabetical(i1, i2)
}
if (!category.isAscending())
sort *= -1
sort
}
category?.mangaOrder?.isEmpty() == false -> {
val order = category.mangaOrder
val index1 = order.indexOf(i1.manga.id!!)
val index2 = order.indexOf(i2.manga.id!!)
when {
index1 == index2 -> 0
index1 == -1 -> -1
index2 == -1 -> 1
else -> index1.compareTo(index2)
}
}
else -> 0
}
}
else {
val category = allCategories.find { it.id == i1.manga.category }?.order ?: -1
val category2 = allCategories.find { it.id == i2.manga.category }?.order ?: -1
category.compareTo(category2)
}
}
private fun sortAlphabetical(i1: LibraryItem, i2: LibraryItem): Int {
return if (preferences.removeArticles().getOrDefault())
i1.manga.currentTitle().removeArticles().compareTo(i2.manga.currentTitle().removeArticles(), true)
@ -424,11 +396,13 @@ class LibraryPresenter(
}.groupBy {
if (showCategories) it.manga.category else 0
}*/
val catItemMain = LibraryHeaderItem(categories.firstOrNull() ?: createDefaultCategory())
val catItemAll = LibraryHeaderItem(Category.createAll(context,
preferences.librarySortingMode().getOrDefault(),
preferences.librarySortingAscending().getOrDefault()))
val libraryMap =
if (preferences.libraryUsingPager().getOrDefault()) {
if (!preferences.libraryAsSingleList().getOrDefault()) {
libraryManga.map { manga ->
LibraryItem(manga, libraryLayout, catItemMain).apply { unreadType = unreadBadgeType }
LibraryItem(manga, libraryLayout, null).apply { unreadType = unreadBadgeType }
}.groupBy {
if (showCategories) it.manga.category else 0
}
@ -438,8 +412,10 @@ class LibraryPresenter(
if (showCategories) manga.category else 0
//LibraryItem(manga, libraryLayout).apply { unreadType = unreadBadgeType }
}.map { entry ->
val categoryItem = LibraryHeaderItem(categories.find { entry.key == it.id }
?: createDefaultCategory())
val categoryItem =
if (!showCategories) catItemAll else
(LibraryHeaderItem(categories.find { entry.key == it.id }
?: createDefaultCategory()))
entry.value.map {
LibraryItem(
it, libraryLayout, categoryItem
@ -455,8 +431,7 @@ class LibraryPresenter(
categories.add(0, createDefaultCategory())
this.allCategories = categories
this.categories = if (preferences.hideCategories().getOrDefault())
arrayListOf(createDefaultCategory())
this.categories = if (!showCategories) arrayListOf(catItemAll.category)
else categories
return Library(this.categories, libraryMap)
@ -486,8 +461,8 @@ class LibraryPresenter(
suspend fun updateView(categories: List<Category>, mangaMap: LibraryMap, freshStart:Boolean
= false) {
if (preferences.libraryUsingPager().getOrDefault()) {
view.onNextLibraryUpdate(categories, mangaMap, true)
if (!preferences.libraryAsSingleList().getOrDefault()) {
view.onNextLibraryUpdate(categories, mangaMap, freshStart)
}
else {
val mangaList = withContext(Dispatchers.IO) {
@ -514,20 +489,15 @@ class LibraryPresenter(
}
fun updateViewBlocking() {
/* val list = withContext(Dispatchers.IO) {
val showCategories = !preferences.hideCategories().getOrDefault()
val current = mangaMap.values.first()
current.groupBy {
if (showCategories) it.manga.category else 0
}.flatMap { it.value }
}*/
val mangaMap = currentMangaMap ?: return
if (preferences.libraryUsingPager().getOrDefault()) {
if (!preferences.libraryAsSingleList().getOrDefault()) {
if (mangaMap.values.firstOrNull()?.firstOrNull()?.header != null)
return
view.onNextLibraryUpdate(categories, mangaMap, true)
}
else {
val list = mutableListOf<LibraryItem>()
for (element in mangaMap?.toSortedMap(compareBy { entry ->
for (element in mangaMap.toSortedMap(compareBy { entry ->
categories.find { it.id == entry }?.order ?: -1
})) {
list.addAll(element.value)
@ -776,11 +746,17 @@ class LibraryPresenter(
fun sortCategory(catId: Int, order: Int) {
val category = categories.find { catId == it.id } ?: return
category.mangaSort = ('a' + (order - 1))
if (category.id == 0)
preferences.defaultMangaOrder().set(category.mangaSort.toString())
else
Injekt.get<DatabaseHelper>().insertCategory(category).asRxObservable().subscribe()
requestCatSortUpdate(category.id!!)
if (catId == -1) {
val sort = category.sortingMode() ?: LibrarySort.ALPHA
preferences.librarySortingMode().set(sort)
preferences.librarySortingAscending().set(category.isAscending())
requestSortUpdate()
}
else {
if (category.id == 0) preferences.defaultMangaOrder().set(category.mangaSort.toString())
else Injekt.get<DatabaseHelper>().insertCategory(category).asRxObservable().subscribe()
requestCatSortUpdate(category.id!!)
}
}
fun rearrangeCategory(catId: Int?, mangaIds: List<Long>) {
@ -794,7 +770,7 @@ class LibraryPresenter(
}
}
fun moveMangaToCategory(item: LibraryItem, catId: Int?, mangaIds: List<Long>) {
fun moveMangaToCategory(item: LibraryItem, catId: Int?, mangaIds: List<Long>, useDND: Boolean) {
GlobalScope.launch(Dispatchers.IO) {
val categoryId = catId ?: return@launch
val category = categories.find { catId == it.id } ?: return@launch
@ -812,6 +788,7 @@ class LibraryPresenter(
item.manga.category = categoryId
val mc = ArrayList<MangaCategory>()
val categories =
db.getCategoriesForManga(manga).executeAsBlocking().filter { it.id != oldCatId } + listOf(category)
@ -822,13 +799,14 @@ class LibraryPresenter(
db.setMangaCategories(mc, listOf(manga))
category.mangaSort = null
val ids = mangaIds.toMutableList()
if (!ids.contains(manga.id!!))
ids.add(manga.id!!)
category.mangaOrder = ids
if (category.id == 0) preferences.defaultMangaOrder().set(mangaIds.joinToString("/"))
else db.insertCategory(category).executeAsBlocking()
if (useDND) {
category.mangaSort = null
val ids = mangaIds.toMutableList()
if (!ids.contains(manga.id!!)) ids.add(manga.id!!)
category.mangaOrder = ids
if (category.id == 0) preferences.defaultMangaOrder().set(mangaIds.joinToString("/"))
else db.insertCategory(category).executeAsBlocking()
}
getLibrary()
}
}

@ -179,6 +179,9 @@ class SortFilterBottomSheet @JvmOverloads constructor(context: Context, attrs: A
}
}
createTags()
sorting_layout.visibility =
if (preferences.libraryAsSingleList().getOrDefault()) View.GONE
else View.VISIBLE
library_sort_text.setOnClickListener { showMainSortOptions() }
category_sort_text.setOnClickListener { showCatSortOptions() }
@ -290,16 +293,12 @@ class SortFilterBottomSheet @JvmOverloads constructor(context: Context, attrs: A
fun sorting(trueSort:Boolean = false): Int {
val sortingMode = preferences.librarySortingMode().getOrDefault()
return if (!trueSort && sortingMode == LibrarySort.DRAG_AND_DROP &&
val singleList = preferences.libraryAsSingleList().getOrDefault()
return if (!trueSort &&
(sortingMode == LibrarySort.DRAG_AND_DROP || singleList) &&
lastCategory != null &&
!preferences.hideCategories().getOrDefault()) {
when (lastCategory?.mangaSort) {
'a', 'b' -> LibrarySort.ALPHA
'c', 'd' -> LibrarySort.LAST_UPDATED
'e', 'f' -> LibrarySort.UNREAD
'g', 'h' -> LibrarySort.LAST_READ
else -> LibrarySort.DRAG_AND_DROP
}
lastCategory?.sortingMode() ?: LibrarySort.DRAG_AND_DROP
}
else {
sortingMode

@ -40,8 +40,8 @@ class SettingsLibraryController : SettingsController() {
}
Observable.combineLatest(preferences.portraitColumns().asObservable(),
preferences.landscapeColumns().asObservable(),
{ portraitCols, landscapeCols -> Pair(portraitCols, landscapeCols) })
preferences.landscapeColumns().asObservable()
) { portraitCols, landscapeCols -> Pair(portraitCols, landscapeCols) }
.subscribeUntilDestroy { (portraitCols, landscapeCols) ->
val portrait = getColumnValue(portraitCols)
val landscape = getColumnValue(landscapeCols)
@ -53,9 +53,9 @@ class SettingsLibraryController : SettingsController() {
}
switchPreference {
key = Keys.libraryUsingPager
titleRes = R.string.pref_remove_articles
summaryRes = R.string.pref_remove_articles_summary
key = Keys.libraryAsSingleList
titleRes = R.string.pref_library_single_list
summaryRes = R.string.pref_library_single_list_summary
defaultValue = false
}

@ -19,6 +19,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="end"
app:fastScrollerIgnoreTouchesOutsideHandle="true"
app:fastScrollerBubbleEnabled="true"
tools:visibility="visible" />
</eu.kanade.tachiyomi.ui.library.LibraryCategoryView>

@ -30,6 +30,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="end"
app:fastScrollerIgnoreTouchesOutsideHandle="true"
app:fastScrollerBubbleEnabled="false"
tools:visibility="visible" />

@ -129,6 +129,7 @@
<string name="action_move_to_bottom">Move to bottom</string>
<string name="action_track">Track</string>
<string name="action_sort_by">Sort category by…</string>
<string name="action_switch">Switch</string>
<!-- Operations -->
<string name="loading">Loading…</string>
@ -198,8 +199,9 @@
<string name="pref_update_only_non_completed">Only update ongoing manga</string>
<string name="pref_auto_update_manga_sync">Sync chapters after reading</string>
<string name="pref_remove_articles">Sort by ignoring articles</string>
<string name="pref_fixed_grid">Fixed grid size in library</string>
<string name="pref_fixed_grid_summary">Show all covers as the same height by cropping</string>
<string name="pref_library_single_list">Show library as a single list</string>
<string name="pref_library_single_list_summary">Show all categories under a single
sectioned list</string>
<string name="pref_remove_articles_summary">When sorting alphabetically, sort ignoring
articles (a, an, the) at the start of manga titles</string>
<string name="pref_skip_pre_migration">Skip pre-migration</string>
@ -413,6 +415,8 @@
<string name="category_already_in_queue">%1$s is already in queue</string>
<string name="local_source_badge">Local</string>
<string name="confirm_manga_deletion">Remove from library?</string>
<string name="switch_to_dnd">Switch to Drag &amp; Drop mode?</string>
<string name="keep_current_sort">Keep sorting by %1$s</string>
<string name="confirm_category_deletion">Delete category?</string>
<string name="confirm_category_deletion_message">Manga in this category will moved into the
default category.</string>

Loading…
Cancel
Save