mirror of
https://git.mihon.tech/mihonapp/mihon
synced 2024-11-28 10:38:48 +03:00
Added category-wise display setting (#5232)
* Added category-wise display setting Co-authored-by: Rogavactive <30288842+Rogavactive@users.noreply.github.com> * Use flag instead of preference * Remove database call in LibraryItem * Remove unnecessary code Co-authored-by: Rogavactive <30288842+Rogavactive@users.noreply.github.com>
This commit is contained in:
parent
fff72b61df
commit
a906e9b302
11 changed files with 153 additions and 25 deletions
|
@ -12,8 +12,21 @@ interface Category : Serializable {
|
|||
|
||||
var flags: Int
|
||||
|
||||
private fun setFlags(flag: Int, mask: Int) {
|
||||
flags = flags and mask.inv() or (flag and mask)
|
||||
}
|
||||
|
||||
var displayMode: Int
|
||||
get() = flags and MASK
|
||||
set(mode) = setFlags(mode, MASK)
|
||||
|
||||
companion object {
|
||||
|
||||
const val COMPACT_GRID = 0b00000000
|
||||
const val COMFORTABLE_GRID = 0b00000001
|
||||
const val LIST = 0b00000010
|
||||
const val MASK = 0b00000011
|
||||
|
||||
fun create(name: String): Category = CategoryImpl().apply {
|
||||
this.name = name
|
||||
}
|
||||
|
|
|
@ -185,6 +185,8 @@ object PreferenceKeys {
|
|||
|
||||
const val defaultCategory = "default_category"
|
||||
|
||||
const val categorizedDisplay = "categorized_display"
|
||||
|
||||
const val skipRead = "skip_read"
|
||||
|
||||
const val skipFiltered = "skip_filtered"
|
||||
|
|
|
@ -284,6 +284,8 @@ class PreferencesHelper(val context: Context) {
|
|||
|
||||
fun defaultCategory() = prefs.getInt(Keys.defaultCategory, -1)
|
||||
|
||||
fun categorisedDisplaySettings() = flowPrefs.getBoolean(Keys.categorizedDisplay, false)
|
||||
|
||||
fun skipRead() = prefs.getBoolean(Keys.skipRead, false)
|
||||
|
||||
fun skipFiltered() = prefs.getBoolean(Keys.skipFiltered, true)
|
||||
|
|
|
@ -5,7 +5,6 @@ import android.util.AttributeSet
|
|||
import android.view.View
|
||||
import android.widget.FrameLayout
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import dev.chrisbanes.insetter.applyInsetter
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.SelectableAdapter
|
||||
|
@ -56,7 +55,7 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
|
|||
/**
|
||||
* Recycler view of the list of manga.
|
||||
*/
|
||||
private lateinit var recycler: RecyclerView
|
||||
private lateinit var recycler: AutofitRecyclerView
|
||||
|
||||
/**
|
||||
* Adapter to hold the manga in this category.
|
||||
|
@ -73,9 +72,11 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
|
|||
fun onCreate(controller: LibraryController, binding: LibraryCategoryBinding) {
|
||||
this.controller = controller
|
||||
|
||||
recycler = if (preferences.libraryDisplayMode().get() == DisplayMode.LIST) {
|
||||
(binding.swipeRefresh.inflate(R.layout.library_list_recycler) as RecyclerView).apply {
|
||||
layoutManager = LinearLayoutManager(context)
|
||||
recycler = if (preferences.libraryDisplayMode().get() == DisplayMode.LIST &&
|
||||
!preferences.categorisedDisplaySettings().get()
|
||||
) {
|
||||
(binding.swipeRefresh.inflate(R.layout.library_list_recycler) as AutofitRecyclerView).apply {
|
||||
spanCount = 1
|
||||
}
|
||||
} else {
|
||||
(binding.swipeRefresh.inflate(R.layout.library_grid_recycler) as AutofitRecyclerView).apply {
|
||||
|
@ -122,6 +123,15 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
|
|||
fun onBind(category: Category) {
|
||||
this.category = category
|
||||
|
||||
// If displayMode should be set from category adjust manga count per row
|
||||
if (preferences.categorisedDisplaySettings().get()) {
|
||||
recycler.spanCount = if (category.displayMode == Category.LIST || (preferences.libraryDisplayMode().get() == DisplayMode.LIST && category.id == 0)) {
|
||||
1
|
||||
} else {
|
||||
controller.mangaPerRow
|
||||
}
|
||||
}
|
||||
|
||||
adapter.mode = if (controller.selectedMangas.isNotEmpty()) {
|
||||
SelectableAdapter.Mode.MULTI
|
||||
} else {
|
||||
|
|
|
@ -262,7 +262,9 @@ class LibraryController(
|
|||
}
|
||||
|
||||
fun showSettingsSheet() {
|
||||
settingsSheet?.show()
|
||||
adapter?.categories?.get(binding.libraryPager.currentItem)?.let { category ->
|
||||
settingsSheet?.show(category)
|
||||
}
|
||||
}
|
||||
|
||||
fun onNextLibraryUpdate(categories: List<Category>, mangaMap: Map<Int, List<LibraryItem>>) {
|
||||
|
|
|
@ -21,17 +21,34 @@ import eu.kanade.tachiyomi.widget.AutofitRecyclerView
|
|||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class LibraryItem(val manga: LibraryManga, private val libraryDisplayMode: Preference<DisplayMode>) :
|
||||
class LibraryItem(
|
||||
val manga: LibraryManga,
|
||||
private val shouldSetFromCategory: Preference<Boolean>,
|
||||
private val defaultLibraryDisplayMode: Preference<DisplayMode>
|
||||
) :
|
||||
AbstractFlexibleItem<LibraryHolder<*>>(), IFilterable<String> {
|
||||
|
||||
private val sourceManager: SourceManager = Injekt.get()
|
||||
|
||||
var displayMode: Int = -1
|
||||
var downloadCount = -1
|
||||
var unreadCount = -1
|
||||
var isLocal = false
|
||||
|
||||
private fun getDisplayMode(): DisplayMode {
|
||||
return if (shouldSetFromCategory.get() && manga.category != 0) {
|
||||
if (displayMode != -1) {
|
||||
DisplayMode.values()[displayMode]
|
||||
} else {
|
||||
DisplayMode.COMPACT_GRID
|
||||
}
|
||||
} else {
|
||||
defaultLibraryDisplayMode.get()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getLayoutRes(): Int {
|
||||
return when (libraryDisplayMode.get()) {
|
||||
return when (getDisplayMode()) {
|
||||
DisplayMode.COMPACT_GRID -> R.layout.source_compact_grid_item
|
||||
DisplayMode.COMFORTABLE_GRID -> R.layout.source_comfortable_grid_item
|
||||
DisplayMode.LIST -> R.layout.source_list_item
|
||||
|
@ -39,7 +56,7 @@ class LibraryItem(val manga: LibraryManga, private val libraryDisplayMode: Prefe
|
|||
}
|
||||
|
||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): LibraryHolder<*> {
|
||||
return when (libraryDisplayMode.get()) {
|
||||
return when (getDisplayMode()) {
|
||||
DisplayMode.COMPACT_GRID -> {
|
||||
val binding = SourceCompactGridItemBinding.bind(view)
|
||||
val parent = adapter.recyclerView as AutofitRecyclerView
|
||||
|
|
|
@ -312,6 +312,13 @@ class LibraryPresenter(
|
|||
dbCategories
|
||||
}
|
||||
|
||||
libraryManga.forEach { (categoryId, libraryManga) ->
|
||||
val category = categories.first { category -> category.id == categoryId }
|
||||
libraryManga.forEach { libraryItem ->
|
||||
libraryItem.displayMode = category.displayMode
|
||||
}
|
||||
}
|
||||
|
||||
this.categories = categories
|
||||
Library(categories, libraryManga)
|
||||
}
|
||||
|
@ -333,10 +340,18 @@ class LibraryPresenter(
|
|||
* value.
|
||||
*/
|
||||
private fun getLibraryMangasObservable(): Observable<LibraryMap> {
|
||||
val libraryDisplayMode = preferences.libraryDisplayMode()
|
||||
val defaultLibraryDisplayMode = preferences.libraryDisplayMode()
|
||||
val shouldSetFromCategory = preferences.categorisedDisplaySettings()
|
||||
return db.getLibraryMangas().asRxObservable()
|
||||
.map { list ->
|
||||
list.map { LibraryItem(it, libraryDisplayMode) }.groupBy { it.manga.category }
|
||||
list.map { libraryManga ->
|
||||
// Display mode based on user preference: take it from global library setting or category
|
||||
LibraryItem(
|
||||
libraryManga,
|
||||
shouldSetFromCategory,
|
||||
defaultLibraryDisplayMode
|
||||
)
|
||||
}.groupBy { it.manga.category }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@ import android.util.AttributeSet
|
|||
import android.view.View
|
||||
import com.bluelinelabs.conductor.Router
|
||||
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.preference.PreferenceValues.DisplayMode
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
|
@ -25,6 +27,7 @@ class LibrarySettingsSheet(
|
|||
val filters: Filter
|
||||
private val sort: Sort
|
||||
private val display: Display
|
||||
private val db: DatabaseHelper by injectLazy()
|
||||
|
||||
init {
|
||||
filters = Filter(router.activity!!)
|
||||
|
@ -37,6 +40,16 @@ class LibrarySettingsSheet(
|
|||
display.onGroupClicked = onGroupClickListener
|
||||
}
|
||||
|
||||
/**
|
||||
* adjusts selected button to match real state.
|
||||
* @param currentCategory ID of currently shown category
|
||||
*/
|
||||
fun show(currentCategory: Category) {
|
||||
display.currentCategory = currentCategory
|
||||
display.adjustDisplaySelection()
|
||||
super.show()
|
||||
}
|
||||
|
||||
override fun getTabViews(): List<View> = listOf(
|
||||
filters,
|
||||
sort,
|
||||
|
@ -232,8 +245,31 @@ class LibrarySettingsSheet(
|
|||
inner class Display @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
||||
Settings(context, attrs) {
|
||||
|
||||
private val displayGroup: DisplayGroup
|
||||
private val badgeGroup: BadgeGroup
|
||||
private val tabsGroup: TabsGroup
|
||||
|
||||
init {
|
||||
setGroups(listOf(DisplayGroup(), BadgeGroup(), TabsGroup()))
|
||||
displayGroup = DisplayGroup()
|
||||
badgeGroup = BadgeGroup()
|
||||
tabsGroup = TabsGroup()
|
||||
setGroups(listOf(displayGroup, badgeGroup, tabsGroup))
|
||||
}
|
||||
|
||||
// Refreshes Display Setting selections
|
||||
fun adjustDisplaySelection() {
|
||||
val mode = getDisplayModePreference()
|
||||
displayGroup.setGroupSelections(mode)
|
||||
displayGroup.items.forEach { adapter.notifyItemChanged(it) }
|
||||
}
|
||||
|
||||
// Gets user preference of currently selected display mode at current category
|
||||
private fun getDisplayModePreference(): DisplayMode {
|
||||
return if (preferences.categorisedDisplaySettings().get() && currentCategory != null && currentCategory?.id != 0) {
|
||||
DisplayMode.values()[currentCategory?.displayMode ?: 0]
|
||||
} else {
|
||||
preferences.libraryDisplayMode().get()
|
||||
}
|
||||
}
|
||||
|
||||
inner class DisplayGroup : Group {
|
||||
|
@ -247,10 +283,8 @@ class LibrarySettingsSheet(
|
|||
override val footer = null
|
||||
|
||||
override fun initModels() {
|
||||
val mode = preferences.libraryDisplayMode().get()
|
||||
compactGrid.checked = mode == DisplayMode.COMPACT_GRID
|
||||
comfortableGrid.checked = mode == DisplayMode.COMFORTABLE_GRID
|
||||
list.checked = mode == DisplayMode.LIST
|
||||
val mode = getDisplayModePreference()
|
||||
setGroupSelections(mode)
|
||||
}
|
||||
|
||||
override fun onItemClicked(item: Item) {
|
||||
|
@ -260,6 +294,31 @@ class LibrarySettingsSheet(
|
|||
item.group.items.forEach { (it as Item.Radio).checked = false }
|
||||
item.checked = true
|
||||
|
||||
setDisplayModePreference(item)
|
||||
|
||||
item.group.items.forEach { adapter.notifyItemChanged(it) }
|
||||
}
|
||||
|
||||
// Sets display group selections based on given mode
|
||||
fun setGroupSelections(mode: DisplayMode) {
|
||||
compactGrid.checked = mode == DisplayMode.COMPACT_GRID
|
||||
comfortableGrid.checked = mode == DisplayMode.COMFORTABLE_GRID
|
||||
list.checked = mode == DisplayMode.LIST
|
||||
}
|
||||
|
||||
private fun setDisplayModePreference(item: Item) {
|
||||
if (preferences.categorisedDisplaySettings().get() && currentCategory != null && currentCategory?.id != 0) {
|
||||
val flag = when (item) {
|
||||
compactGrid -> Category.COMPACT_GRID
|
||||
comfortableGrid -> Category.COMFORTABLE_GRID
|
||||
list -> Category.LIST
|
||||
else -> throw NotImplementedError("Unknown display mode")
|
||||
}
|
||||
|
||||
currentCategory?.displayMode = flag
|
||||
|
||||
db.insertCategory(currentCategory!!).executeAsBlocking()
|
||||
} else {
|
||||
preferences.libraryDisplayMode().set(
|
||||
when (item) {
|
||||
compactGrid -> DisplayMode.COMPACT_GRID
|
||||
|
@ -268,8 +327,7 @@ class LibrarySettingsSheet(
|
|||
else -> throw NotImplementedError("Unknown display mode")
|
||||
}
|
||||
)
|
||||
|
||||
item.group.items.forEach { adapter.notifyItemChanged(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -336,6 +394,8 @@ class LibrarySettingsSheet(
|
|||
*/
|
||||
var onGroupClicked: (Group) -> Unit = {}
|
||||
|
||||
var currentCategory: Category? = null
|
||||
|
||||
fun setGroups(groups: List<Group>) {
|
||||
adapter = Adapter(groups.map { it.createItems() }.flatten())
|
||||
recycler.adapter = adapter
|
||||
|
|
|
@ -124,6 +124,12 @@ class SettingsLibraryController : SettingsController() {
|
|||
true
|
||||
}
|
||||
}
|
||||
|
||||
switchPreference {
|
||||
key = Keys.categorizedDisplay
|
||||
titleRes = R.string.categorized_display_settings
|
||||
defaultValue = false
|
||||
}
|
||||
}
|
||||
|
||||
preferenceCategory {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<eu.kanade.tachiyomi.widget.AutofitRecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/library_list"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -219,6 +219,7 @@
|
|||
|
||||
<string name="default_category">Default category</string>
|
||||
<string name="default_category_summary">Always ask</string>
|
||||
<string name="categorized_display_settings">Per-category display settings</string>
|
||||
<plurals name="num_categories">
|
||||
<item quantity="one">%d category</item>
|
||||
<item quantity="other">%d categories</item>
|
||||
|
|
Loading…
Reference in a new issue