Option to collaspe categories

Sort button on category now shows category direction
Category name now a bit larger
This commit is contained in:
Jay 2020-04-16 15:58:10 -04:00
parent 3d6ad28437
commit 877cb43043
16 changed files with 133 additions and 62 deletions

View File

@ -25,6 +25,8 @@ interface Category : Serializable {
val nameLower: String
get() = name.toLowerCase()
var isHidden: Boolean
fun isAscending(): Boolean {
return ((mangaSort?.minus('a') ?: 0) % 2) != 1
}
@ -47,7 +49,7 @@ interface Category : Serializable {
LAST_READ_ASC, LAST_READ_DSC -> R.string.last_read
TOTAL_ASC, TOTAL_DSC -> R.string.total_chapters
DATE_ADDED_ASC, DATE_ADDED_DSC -> R.string.date_added
else -> R.string.drag_and_drop
else -> if (id == -1) R.string.category else R.string.drag_and_drop
}
fun catSortingMode(): Int? = when (mangaSort) {

View File

@ -18,6 +18,8 @@ class CategoryImpl : Category {
override var isLast: Boolean? = null
override var isHidden: Boolean = false
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || javaClass != other.javaClass) return false

View File

@ -14,5 +14,9 @@ class LibraryManga : MangaImpl() {
id = Long.MIN_VALUE
category = categoryId
}
fun createHide(categoryId: Int): LibraryManga = createBlank(categoryId).apply {
status = -1
}
}
}

View File

@ -51,10 +51,6 @@ object PreferenceKeys {
const val readWithVolumeKeysInverted = "reader_volume_keys_inverted"
const val portraitColumns = "pref_library_columns_portrait_key"
const val landscapeColumns = "pref_library_columns_landscape_key"
const val updateOnlyNonCompleted = "pref_update_only_non_completed_key"
const val autoUpdateTrack = "pref_auto_update_manga_sync_key"

View File

@ -103,10 +103,6 @@ class PreferencesHelper(val context: Context) {
fun readWithVolumeKeysInverted() = rxPrefs.getBoolean(Keys.readWithVolumeKeysInverted, false)
fun portraitColumns() = rxPrefs.getInteger(Keys.portraitColumns, 0)
fun landscapeColumns() = rxPrefs.getInteger(Keys.landscapeColumns, 0)
fun updateOnlyNonCompleted() = prefs.getBoolean(Keys.updateOnlyNonCompleted, false)
fun autoUpdateTrack() = prefs.getBoolean(Keys.autoUpdateTrack, true)
@ -205,6 +201,8 @@ class PreferencesHelper(val context: Context) {
fun automaticExtUpdates() = rxPrefs.getBoolean(Keys.automaticExtUpdates, false)
fun collapsedCategories() = rxPrefs.getStringSet("collapsed_categories", mutableSetOf())
fun hiddenCatalogues() = rxPrefs.getStringSet("hidden_catalogues", mutableSetOf())
fun downloadNew() = rxPrefs.getBoolean(Keys.downloadNew, false)

View File

@ -153,7 +153,7 @@ class LibraryCategoryAdapter(val libraryListener: LibraryListener) :
}
private fun getFirstLetter(name: String): String {
val letter = name.first()
val letter = name.firstOrNull() ?: '#'
return if (letter.isLetter()) letter.toString()
.toUpperCase(Locale.ROOT) else "#"
}
@ -272,5 +272,6 @@ class LibraryCategoryAdapter(val libraryListener: LibraryListener) :
fun sortCategory(catId: Int, sortBy: Int)
fun selectAll(position: Int)
fun allSelected(position: Int): Boolean
fun toggleCategoryVisibility(position: Int)
}
}

View File

@ -804,6 +804,11 @@ class LibraryController(
return true
}
override fun toggleCategoryVisibility(position: Int) {
val catId = (adapter.getItem(position) as? LibraryHeaderItem)?.category?.id ?: return
presenter.toggleCategoryVisibility(catId)
}
override fun sortCategory(catId: Int, sortBy: Int) {
presenter.sortCategory(catId, sortBy)
}

View File

@ -18,11 +18,11 @@ import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.SelectableAdapter
import eu.davidea.flexibleadapter.items.AbstractHeaderItem
import eu.davidea.flexibleadapter.items.IFlexible
import eu.davidea.viewholders.FlexibleViewHolder
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Category
import eu.kanade.tachiyomi.data.library.LibraryUpdateService
import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
import eu.kanade.tachiyomi.util.system.dpToPx
import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.view.gone
@ -30,7 +30,6 @@ import eu.kanade.tachiyomi.util.view.invisible
import eu.kanade.tachiyomi.util.view.updateLayoutParams
import eu.kanade.tachiyomi.util.view.visInvisIf
import eu.kanade.tachiyomi.util.view.visible
import kotlinx.android.synthetic.main.library_category_header_item.view.*
class LibraryHeaderItem(
private val categoryF: (Int) -> Category,
@ -83,7 +82,7 @@ class LibraryHeaderItem(
}
class Holder(val view: View, private val adapter: LibraryCategoryAdapter, padEnd: Boolean) :
FlexibleViewHolder(view, adapter, true) {
BaseFlexibleViewHolder(view, adapter, true) {
private val sectionText: TextView = view.findViewById(R.id.category_title)
private val sortText: TextView = view.findViewById(R.id.category_sort)
@ -96,6 +95,10 @@ class LibraryHeaderItem(
marginEnd = (if (padEnd && adapter.recyclerView.paddingEnd == 0) 12 else 2).dpToPx
}
updateButton.setOnClickListener { addCategoryToUpdate() }
sectionText.setOnLongClickListener {
adapter.libraryListener.toggleCategoryVisibility(adapterPosition)
true
}
sortText.setOnClickListener { it.post { showCatSortOptions() } }
checkboxImage.setOnClickListener { selectAll() }
updateButton.drawable.mutate()
@ -109,20 +112,25 @@ class LibraryHeaderItem(
if (category.isFirst == true && category.isLast == true) sectionText.text = ""
else sectionText.text = category.name
sortText.text = itemView.context.getString(R.string.sort_by_,
itemView.context.getString(
when (category.sortingMode()) {
LibrarySort.LATEST_CHAPTER -> R.string.latest_chapter
LibrarySort.DRAG_AND_DROP ->
if (category.id == -1) R.string.category
else R.string.drag_and_drop
LibrarySort.TOTAL -> R.string.total_chapters
LibrarySort.UNREAD -> R.string.unread
LibrarySort.LAST_READ -> R.string.last_read
LibrarySort.ALPHA -> R.string.title
LibrarySort.DATE_ADDED -> R.string.date_added
else -> R.string.drag_and_drop
itemView.context.getString(category.sortRes())
)
val isAscending = category.isAscending()
val sortingMode = category.sortingMode()
val sortDrawable = if (category.isHidden) R.drawable.ic_expand_more_white_24dp
else
when {
sortingMode == LibrarySort.DRAG_AND_DROP || sortingMode == null -> R.drawable
.ic_sort_white_24dp
if (sortingMode == LibrarySort.DATE_ADDED ||
sortingMode == LibrarySort.LATEST_CHAPTER ||
sortingMode == LibrarySort.LAST_READ) !isAscending else isAscending ->
R.drawable.ic_arrow_down_white_24dp
else -> R.drawable.ic_arrow_up_white_24dp
}
))
sortText.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, sortDrawable, 0)
sortText.setText(if (category.isHidden) R.string.collasped else category.sortRes())
when {
adapter.mode == SelectableAdapter.Mode.MULTI -> {
@ -157,8 +165,12 @@ class LibraryHeaderItem(
private fun showCatSortOptions() {
val category =
(adapter.getItem(adapterPosition) as? LibraryHeaderItem)?.category ?: return
if (category.isHidden) {
adapter.libraryListener.toggleCategoryVisibility(adapterPosition)
return
}
// Create a PopupMenu, giving it the clicked view for an anchor
val popup = PopupMenu(itemView.context, view.category_sort)
val popup = PopupMenu(itemView.context, sortText)
// Inflate our menu resource into the PopupMenu's Menu
popup.menuInflater.inflate(
@ -254,14 +266,17 @@ class LibraryHeaderItem(
fun setSelection() {
val allSelected = adapter.libraryListener.allSelected(adapterPosition)
val drawable =
ContextCompat.getDrawable(contentView.context,
if (allSelected) R.drawable.ic_check_circle_white_24dp else
R.drawable.ic_radio_button_unchecked_white_24dp)
val drawable = ContextCompat.getDrawable(
contentView.context,
if (allSelected) R.drawable.ic_check_circle_white_24dp else R.drawable.ic_radio_button_unchecked_white_24dp
)
val tintedDrawable = drawable?.mutate()
tintedDrawable?.setTint(ContextCompat.getColor(contentView.context,
if (allSelected) R.color.colorAccent
else R.color.gray_button))
tintedDrawable?.setTint(
ContextCompat.getColor(
contentView.context, if (allSelected) R.color.colorAccent
else R.color.gray_button
)
)
checkboxImage.setImageDrawable(tintedDrawable)
}

View File

@ -46,13 +46,23 @@ class LibraryListHolder(
*/
override fun onSetValues(item: LibraryItem) {
title.visible()
constraint_layout.minHeight = 56.dpToPx
if (item.manga.isBlank()) {
title.text = itemView.context.getString(R.string.category_is_empty)
constraint_layout.minHeight = 0
if (item.manga.status == -1) {
title.gone()
} else
title.text = itemView.context.getString(R.string.category_is_empty)
title.textAlignment = View.TEXT_ALIGNMENT_CENTER
card.gone()
badge_view.gone()
play_layout.gone()
padding.gone()
subtitle.gone()
return
}
padding.visible()
card.visible()
title.textAlignment = View.TEXT_ALIGNMENT_TEXT_START

View File

@ -425,12 +425,27 @@ class LibraryPresenter(
LibraryItem(it, libraryLayout, preferences.uniformGrid(), seekPref, headerItem)
}.toMutableList()
val categoriesHidden = preferences.collapsedCategories().getOrDefault().mapNotNull {
it.toIntOrNull()
}.toMutableSet()
if (showCategories) {
categories.forEach { category ->
if (category.id ?: 0 <= 0 && !categorySet.contains(category.id)) {
val headerItem = headerItems[category.id ?: 0]
val catId = category.id ?: return@forEach
if (catId > 0 && !categorySet.contains(catId)) {
val headerItem = headerItems[catId]
items.add(LibraryItem(
LibraryManga.createBlank(category.id!!),
LibraryManga.createBlank(catId),
libraryLayout,
preferences.uniformGrid(),
preferences.alwaysShowSeeker(),
headerItem
))
} else if (catId in categoriesHidden) {
val headerItem = headerItems[catId]
items.removeAll { it.manga.category == catId }
items.add(LibraryItem(
LibraryManga.createHide(catId),
libraryLayout,
preferences.uniformGrid(),
preferences.alwaysShowSeeker(),
@ -446,6 +461,10 @@ class LibraryPresenter(
if (categorySet.contains(0))
categories.add(0, createDefaultCategory())
categories.forEach {
it.isHidden = it.id in categoriesHidden
}
this.allCategories = categories
this.categories = if (!showCategories) arrayListOf(categoryAll)
else categories
@ -678,7 +697,21 @@ class LibraryPresenter(
return catId in categories
}
fun toggleCategoryVisibility(categoryId: Int) {
if (categoryId <= -1) return
val categoriesHidden = preferences.collapsedCategories().getOrDefault().mapNotNull {
it.toIntOrNull()
}.toMutableSet()
if (categoryId in categoriesHidden)
categoriesHidden.remove(categoryId)
else
categoriesHidden.add(categoryId)
preferences.collapsedCategories().set(categoriesHidden.map { it.toString() }.toMutableSet())
getLibrary()
}
companion object {
// var catsHidden = mutableListOf<Int>()
private var lastLibraryItems: List<LibraryItem>? = null
private var lastCategories: List<Category>? = null

View File

@ -521,7 +521,7 @@ class MangaDetailsPresenter(
asyncUpdateMangaAndChapters()
}
fun globalSort() = preferences.chaptersDescAsDefault().getOrDefault()
fun globalSort(): Boolean = preferences.chaptersDescAsDefault().getOrDefault()
fun setGlobalChapterSort(descend: Boolean) {
preferences.chaptersDescAsDefault().set(descend)

View File

@ -4,7 +4,7 @@
<item android:id="@android:id/mask">
<shape android:shape="rectangle">
<corners android:radius="4dp" />
<solid android:color="@color/gray_button" />
<solid android:color="@color/fullRippleColor" />
</shape>
</item>
</ripple>

View File

@ -5,6 +5,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:id="@+id/constraint_layout"
android:background="?attr/selectable_list_drawable"
android:minHeight="@dimen/material_component_lists_single_line_with_avatar_height">

View File

@ -6,25 +6,23 @@
android:layout_height="wrap_content"
android:gravity="center_vertical">
<ImageView
android:id="@+id/checkbox"
android:padding="5dp"
android:visibility="gone"
tools:visibility="visible"
tools:tint="?attr/colorAccent"
android:layout_width="wrap_content"
android:contentDescription="@string/select_all"
android:clickable="true"
android:focusable="true"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:clickable="true"
android:contentDescription="@string/select_all"
android:focusable="true"
android:padding="5dp"
android:src="@drawable/ic_check_circle_white_24dp"
android:layout_marginStart="2dp"
app:layout_constraintStart_toStartOf="parent"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@+id/category_title"
app:layout_constraintEnd_toStartOf="@+id/category_title"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/category_title"
/>
tools:tint="?attr/colorAccent"
tools:visibility="visible" />
<TextView
android:id="@+id/category_title"
@ -32,18 +30,20 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="32dp"
android:background="@drawable/square_ripple"
android:layout_marginBottom="10dp"
android:ellipsize="end"
android:gravity="center|start"
android:inputType="none"
android:maxLines="2"
android:layout_marginTop="32dp"
android:textSize="22sp"
app:layout_constrainedWidth="true"
app:layout_constraintStart_toEndOf="@+id/checkbox"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/update_button"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toEndOf="@+id/checkbox"
app:layout_constraintTop_toTopOf="parent"
tools:text="Title dfdsfsfsfsfsfdsfsfsfs" />
<Space
@ -59,15 +59,15 @@
android:id="@+id/update_button"
android:layout_width="wrap_content"
android:layout_height="35dp"
android:padding="5dp"
android:clickable="true"
android:focusable="true"
android:tint="?attr/colorAccent"
android:padding="5dp"
android:src="@drawable/ic_refresh_white_24dp"
android:tint="?attr/colorAccent"
app:layout_constraintBottom_toBottomOf="@id/category_title"
app:layout_constraintTop_toTopOf="@id/category_title"
app:layout_constraintEnd_toStartOf="@id/space"
app:layout_constraintStart_toEndOf="@id/category_title"
app:layout_constraintTop_toTopOf="@id/category_title"
app:rippleColor="@color/fullRippleColor" />
<ProgressBar
@ -76,17 +76,18 @@
android:layout_height="0dp"
android:layout_margin="5dp"
android:visibility="gone"
tools:visibility="visible"
app:layout_constraintTop_toTopOf="@id/update_button"
app:layout_constraintBottom_toBottomOf="@id/update_button"
app:layout_constraintEnd_toEndOf="@id/update_button"
app:layout_constraintStart_toStartOf="@id/update_button"
app:layout_constraintEnd_toEndOf="@id/update_button"/>
app:layout_constraintTop_toTopOf="@id/update_button"
tools:visibility="visible" />
<TextView
android:id="@+id/category_sort"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="2dp"
android:background="@drawable/square_ripple"
android:clickable="true"
android:drawableEnd="@drawable/ic_sort_white_24dp"
android:drawablePadding="6dp"
@ -94,7 +95,6 @@
android:ellipsize="start"
android:focusable="true"
android:gravity="center|end"
android:background="@drawable/square_ripple"
android:maxLines="2"
android:padding="6dp"
android:textAlignment="textEnd"
@ -108,6 +108,5 @@
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toEndOf="@id/space"
app:layout_constraintTop_toTopOf="@id/category_title"
app:layout_constraintWidth_min="100dp"
tools:text="Drag and Drop" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -66,6 +66,7 @@
<string name="_already_in_queue">%1$s is already in queue</string>
<string name="create_new_category">Create new category</string>
<string name="category_is_empty">Category is empty</string>
<string name="category_is_hidden">Category is hidden</string>
<string name="top_category">Top category (%1$s)</string>
<string name="default_category">Default category</string>
<string name="first_category">First category</string>
@ -600,6 +601,7 @@
<string name="charging">Charging</string>
<string name="clear">Clear</string>
<string name="close">Close</string>
<string name="collasped">Collapsed</string>
<string name="common">Common</string>
<string name="cover_of_image">Cover of manga</string>
<string name="create">Create</string>
@ -637,6 +639,8 @@
<string name="options">Options</string>
<string name="pause">Pause</string>
<string name="picture_saved">Picture saved</string>
<string name="refresh">Refresh</string>
<string name="refreshing">Refreshing</string>
<string name="remove">Remove</string>
<string name="reorder">Reorder</string>
<string name="reset">Reset</string>
@ -656,6 +660,7 @@
<string name="top">Top</string>
<string name="undo">Undo</string>
<string name="unknown_error">Unknown error</string>
<string name="un_select_all">Un-select all</string>
<string name="use_default">Use default</string>
<string name="view_all_errors">View all errors</string>
<string name="view_chapters">View chapters</string>

Binary file not shown.