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 43ef84c4ed..14a842476b 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,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 } 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 dc6617740f..fd756ad2fc 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 @@ -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" 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 a195fadfea..9b061c2e58 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 @@ -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) 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 79eba7168f..9851de2cd7 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 @@ -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 { 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 ab10a666a9..409c738f36 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 @@ -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, mangaMap: Map>) { 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 daa6834005..941a2c6469 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 @@ -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) : +class LibraryItem( + val manga: LibraryManga, + private val shouldSetFromCategory: Preference, + private val defaultLibraryDisplayMode: Preference +) : AbstractFlexibleItem>(), IFilterable { 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>): LibraryHolder<*> { - return when (libraryDisplayMode.get()) { + return when (getDisplayMode()) { DisplayMode.COMPACT_GRID -> { val binding = SourceCompactGridItemBinding.bind(view) val parent = adapter.recyclerView as AutofitRecyclerView 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 a528ffba9b..ed8dc3d6c3 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 @@ -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 { - 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 } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsSheet.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsSheet.kt index 7f268532e2..9cc1c4eb04 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsSheet.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsSheet.kt @@ -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 = 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,17 +294,41 @@ class LibrarySettingsSheet( item.group.items.forEach { (it as Item.Radio).checked = false } item.checked = true - preferences.libraryDisplayMode().set( - when (item) { - compactGrid -> DisplayMode.COMPACT_GRID - comfortableGrid -> DisplayMode.COMFORTABLE_GRID - list -> DisplayMode.LIST - else -> throw NotImplementedError("Unknown display mode") - } - ) + 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 + comfortableGrid -> DisplayMode.COMFORTABLE_GRID + list -> DisplayMode.LIST + else -> throw NotImplementedError("Unknown display mode") + } + ) + } + } } inner class BadgeGroup : Group { @@ -336,6 +394,8 @@ class LibrarySettingsSheet( */ var onGroupClicked: (Group) -> Unit = {} + var currentCategory: Category? = null + fun setGroups(groups: List) { adapter = Adapter(groups.map { it.createItems() }.flatten()) recycler.adapter = adapter 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 17c433e33c..3045e25e91 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 @@ -124,6 +124,12 @@ class SettingsLibraryController : SettingsController() { true } } + + switchPreference { + key = Keys.categorizedDisplay + titleRes = R.string.categorized_display_settings + defaultValue = false + } } preferenceCategory { diff --git a/app/src/main/res/layout/library_list_recycler.xml b/app/src/main/res/layout/library_list_recycler.xml index 38f5cfdf61..2604c02bd9 100644 --- a/app/src/main/res/layout/library_list_recycler.xml +++ b/app/src/main/res/layout/library_list_recycler.xml @@ -1,5 +1,5 @@ -Default category Always ask + Per-category display settings %d category %d categories