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 8bf8e6dbd1..84842121c0 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 @@ -239,6 +239,8 @@ class PreferencesHelper(val context: Context) { fun lastExtCheck() = rxPrefs.getLong("last_ext_check", 0) + fun unreadBadgeType() = rxPrefs.getInteger("unread_badge_type", 1) + fun upgradeFilters() { val filterDl = rxPrefs.getBoolean(Keys.filterDownloaded, false).getOrDefault() val filterUn = rxPrefs.getBoolean(Keys.filterUnread, false).getOrDefault() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/browse/CatalogueItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/browse/CatalogueItem.kt index 311bd46345..a31b5fbf86 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/browse/CatalogueItem.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/browse/CatalogueItem.kt @@ -12,6 +12,7 @@ import eu.davidea.flexibleadapter.items.IFlexible import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.preference.getOrDefault +import eu.kanade.tachiyomi.util.system.dpToPx import eu.kanade.tachiyomi.widget.AutofitRecyclerView import kotlinx.android.synthetic.main.catalogue_grid_item.view.* @@ -29,8 +30,11 @@ class CatalogueItem(val manga: Manga, private val catalogueAsList: Preference v.updatePaddingRelative(bottom = padding.bottom + insets.systemWindowInsetBottom) 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 d27378ead0..7d3ff9aecc 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 @@ -228,7 +228,9 @@ class LibraryController( FilterBottomSheet.ACTION_FILTER -> onFilterChanged() FilterBottomSheet.ACTION_SORT -> onSortChanged() FilterBottomSheet.ACTION_DISPLAY -> reattachAdapter() - FilterBottomSheet.ACTION_BADGE -> onDownloadBadgeChanged() + FilterBottomSheet.ACTION_DOWNLOAD_BADGE -> + presenter.requestDownloadBadgesUpdate() + FilterBottomSheet.ACTION_UNREAD_BADGE -> presenter.requestUnreadBadgesUpdate() FilterBottomSheet.ACTION_CAT_SORT -> onCatSortChanged() } } @@ -566,8 +568,14 @@ class LibraryController( when (item.itemId) { R.id.action_search -> expandActionViewFromInteraction = true R.id.action_library_filter -> { - if (MainActivity.bottomNav) bottom_sheet.sheetBehavior?.state = - BottomSheetBehavior.STATE_EXPANDED + if (MainActivity.bottomNav) { + if (bottom_sheet.sheetBehavior?.state != BottomSheetBehavior.STATE_EXPANDED) + bottom_sheet.sheetBehavior?.state = + BottomSheetBehavior.STATE_EXPANDED + else + bottom_sheet.sheetBehavior?.state = + BottomSheetBehavior.STATE_COLLAPSED + } else navView?.let { activity?.drawer?.openDrawer(GravityCompat.END) } } R.id.action_edit_categories -> { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryGridHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryGridHolder.kt index 6d576fdf00..36ba87f93c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryGridHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryGridHolder.kt @@ -1,6 +1,7 @@ package eu.kanade.tachiyomi.ui.library import android.view.View +import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import com.bumptech.glide.load.engine.DiskCacheStrategy import com.bumptech.glide.signature.ObjectKey @@ -9,6 +10,8 @@ import eu.davidea.flexibleadapter.items.IFlexible import eu.kanade.tachiyomi.data.database.models.MangaImpl import eu.kanade.tachiyomi.data.glide.GlideApp import eu.kanade.tachiyomi.source.LocalSource +import eu.kanade.tachiyomi.util.system.dpToPx +import eu.kanade.tachiyomi.util.view.updateLayoutParams import kotlinx.android.synthetic.main.catalogue_grid_item.* /** @@ -42,25 +45,27 @@ class LibraryGridHolder( // Update the unread count and its visibility. with(unread_text) { - visibility = if (item.manga.unread > 0) View.VISIBLE else View.GONE + visibility = + if (item.manga.unread > 0 && item.unreadType == 1) View.VISIBLE else View.GONE text = item.manga.unread.toString() } // Update the download count and its visibility. + unread_badge.visibility = + if (item.manga.unread > 0 && item.unreadType == 0) View.VISIBLE else View.GONE with(download_text) { visibility = if (item.downloadCount > 0) View.VISIBLE else View.GONE text = item.downloadCount.toString() } //set local visibility if its local manga - local_text.visibility = if(item.manga.source == LocalSource.ID) View.VISIBLE else View.GONE + local_text.visibility = if (item.manga.source == LocalSource.ID) View.VISIBLE else View.GONE // Update the cover. GlideApp.with(view.context).clear(thumbnail) GlideApp.with(view.context) - .load(item.manga) - .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC) - .signature(ObjectKey(MangaImpl.getLastCoverFetch(item.manga.id!!).toString())) - .centerCrop() - .into(thumbnail) + .load(item.manga) + .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC) + .signature(ObjectKey(MangaImpl.getLastCoverFetch(item.manga.id!!).toString())) + .centerCrop().into(thumbnail) } } 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 062fb173eb..1e0a00308c 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 @@ -23,6 +23,7 @@ class LibraryItem(val manga: LibraryManga, private val libraryAsList: Preference AbstractFlexibleItem(), IFilterable { var downloadCount = -1 + var unreadType = 1 override fun getLayoutRes(): Int { return if (libraryAsList.getOrDefault()) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryListHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryListHolder.kt index ab3a2ca3d8..5e8e6862cf 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryListHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryListHolder.kt @@ -10,6 +10,13 @@ import androidx.recyclerview.widget.RecyclerView import com.bumptech.glide.signature.ObjectKey import eu.davidea.flexibleadapter.items.IFlexible import eu.kanade.tachiyomi.data.database.models.MangaImpl +import kotlinx.android.synthetic.main.catalogue_grid_item.* +import kotlinx.android.synthetic.main.catalogue_list_item.download_text +import kotlinx.android.synthetic.main.catalogue_list_item.local_text +import kotlinx.android.synthetic.main.catalogue_list_item.thumbnail +import kotlinx.android.synthetic.main.catalogue_list_item.title +import kotlinx.android.synthetic.main.catalogue_list_item.unread_badge +import kotlinx.android.synthetic.main.catalogue_list_item.unread_text /** * Class used to hold the displayed data of a manga in the library, like the cover or the title. @@ -38,9 +45,12 @@ class LibraryListHolder( // Update the unread count and its visibility. with(unread_text) { - visibility = if (item.manga.unread > 0) View.VISIBLE else View.GONE + visibility = if (item.manga.unread > 0 && item.unreadType == 1) View.VISIBLE else + View.GONE text = item.manga.unread.toString() } + unread_badge.visibility = + if (item.manga.unread > 0 && item.unreadType == 0) View.VISIBLE else View.GONE // Update the download count and its visibility. with(download_text) { visibility = if (item.downloadCount > 0) View.VISIBLE else View.GONE 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 b34f1e015f..60d077d820 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 @@ -217,6 +217,15 @@ class LibraryPresenter( } } + private fun setUnreadBadge(map: LibraryMap) { + val unreadType = preferences.unreadBadgeType().getOrDefault() + for ((_, itemList) in map) { + for (item in itemList) { + item.unreadType = unreadType + } + } + } + private fun applyCatSort(map: LibraryMap, catId: Int?): LibraryMap { if (catId == null) return map val categoryManga = map[catId] ?: return map @@ -400,11 +409,12 @@ class LibraryPresenter( val categories = db.getCategories().executeAsBlocking().toMutableList() val libraryAsList = preferences.libraryAsList() val showCategories = !preferences.hideCategories().getOrDefault() + val unreadBadgeType = preferences.unreadBadgeType().getOrDefault() var libraryManga = db.getLibraryMangas().executeAsBlocking() if (!showCategories) libraryManga = libraryManga.distinctBy { it.id } val libraryMap = libraryManga.map { manga -> - LibraryItem(manga, libraryAsList) + LibraryItem(manga, libraryAsList).apply { unreadType = unreadBadgeType } }.groupBy { if (showCategories) it.manga.category else 0 } @@ -488,7 +498,7 @@ class LibraryPresenter( } /** - * Requests the library to have download badges added. + * Requests the library to have download badges added/removed. */ fun requestDownloadBadgesUpdate() { //getLibrary() @@ -503,6 +513,22 @@ class LibraryPresenter( } } + /** + * Requests the library to have unread badges changed. + */ + fun requestUnreadBadgesUpdate() { + //getLibrary() + launchUI { + val mangaMap = rawMangaMap ?: return@launchUI + withContext(Dispatchers.IO) { setUnreadBadge(mangaMap) } + rawMangaMap = mangaMap + val current = currentMangaMap ?: return@launchUI + withContext(Dispatchers.IO) { setUnreadBadge(current) } + currentMangaMap = current + view?.onNextLibraryUpdate(categories, current) + } + } + /** * Requests the library to be sorted. */ diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/filter/FilterBottomSheet.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/filter/FilterBottomSheet.kt index 561b9c5fcb..94b4bcb863 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/filter/FilterBottomSheet.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/filter/FilterBottomSheet.kt @@ -41,6 +41,7 @@ import kotlinx.coroutines.withContext import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import uy.kohesive.injekt.injectLazy +import kotlin.math.min import kotlin.math.roundToInt class FilterBottomSheet @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) @@ -103,7 +104,7 @@ class FilterBottomSheet @JvmOverloads constructor(context: Context, attrs: Attri topbar.setOnClickListener { if (sheetBehavior?.state != BottomSheetBehavior.STATE_EXPANDED) { sheetBehavior?.state = BottomSheetBehavior.STATE_EXPANDED - topbar.animate().alpha(0f).setDuration(100).start() + //topbar.animate().alpha(0f).setDuration(100).start() } else { sheetBehavior?.state = BottomSheetBehavior.STATE_COLLAPSED } @@ -131,8 +132,7 @@ class FilterBottomSheet @JvmOverloads constructor(context: Context, attrs: Attri } }) topbar.viewTreeObserver.addOnGlobalLayoutListener { - val phoneLandscape = (context.resources.configuration?.orientation == - Configuration.ORIENTATION_LANDSCAPE && !isTablet()) + val phoneLandscape = (isLandscape() && !isTablet()) sheetBehavior?.peekHeight = if (phoneLandscape) { if (shadow2.visibility != View.GONE) { shadow.gone() @@ -162,7 +162,11 @@ class FilterBottomSheet @JvmOverloads constructor(context: Context, attrs: Attri downloadCheckbox.isChecked = preferences.downloadBadge().getOrDefault() downloadCheckbox.setOnCheckedChangeListener { _, isChecked -> preferences.downloadBadge().set(isChecked) - onGroupClicked(ACTION_BADGE) + onGroupClicked(ACTION_DOWNLOAD_BADGE) + } + setUnreadIcon() + unread_badge.setOnClickListener { + showUnreadMenu() } displayGroup.bindToPreference(preferences.libraryAsList()) @@ -376,7 +380,7 @@ class FilterBottomSheet @JvmOverloads constructor(context: Context, attrs: Attri !preferences.librarySortingAscending().getOrDefault() -> R.drawable.ic_arrow_down_white_24dp else -> R.drawable.ic_arrow_up_white_24dp - }, android.R.attr.colorAccent + } ) // Finally show the PopupMenu @@ -417,8 +421,7 @@ class FilterBottomSheet @JvmOverloads constructor(context: Context, attrs: Attri currentItem?.icon = tintVector( if (category.isAscending()) R.drawable.ic_arrow_up_white_24dp - else R.drawable.ic_arrow_down_white_24dp, - android.R.attr.colorAccent + else R.drawable.ic_arrow_down_white_24dp ) // Finally show the PopupMenu @@ -498,7 +501,7 @@ class FilterBottomSheet @JvmOverloads constructor(context: Context, attrs: Attri sortId == LibrarySort.DRAG_AND_DROP -> R.drawable.ic_sort_white_24dp preferences.librarySortingAscending().getOrDefault() -> R.drawable.ic_arrow_up_white_24dp else -> R.drawable.ic_arrow_down_white_24dp - }, android.R.attr.colorAccent + } ) } mainSortTextView.text = withContext(Dispatchers.IO) { @@ -534,7 +537,7 @@ class FilterBottomSheet @JvmOverloads constructor(context: Context, attrs: Attri sortId == LibrarySort.DRAG_AND_DROP -> R.drawable.ic_label_outline_white_24dp lastCategory?.isAscending() == true -> R.drawable.ic_arrow_up_white_24dp else -> R.drawable.ic_arrow_down_white_24dp - }, android.R.attr.colorAccent + } ) } catSortTextView.text = withContext(Dispatchers.IO) { @@ -573,9 +576,9 @@ class FilterBottomSheet @JvmOverloads constructor(context: Context, attrs: Attri private fun Boolean.toInt() = if (this) 1 else 0 - private fun tintVector(resId: Int, attrId: Int? = null): Drawable? { + private fun tintVector(resId: Int): Drawable? { return ContextCompat.getDrawable(context, resId)?.mutate()?.apply { - setTint(context.getResourceColor(attrId ?: android.R.attr.textColorPrimary)) + setTint(context.getResourceColor(android.R.attr.colorAccent)) } } @@ -639,12 +642,54 @@ class FilterBottomSheet @JvmOverloads constructor(context: Context, attrs: Attri filterScrollView.scrollTo(0, 0) } + private fun showUnreadMenu() { + val popup = PopupMenu(context, unread_badge) + + popup.menuInflater.inflate(R.menu.unread_badge, popup.menu) + + popup.menu.getItem(min(preferences.unreadBadgeType().getOrDefault(), 1) + 1).isChecked = + true + + popup.setOnMenuItemClickListener { menuItem -> + preferences.unreadBadgeType().set(when (menuItem.itemId) { + R.id.action_no_unread -> -1 + R.id.action_any_unread -> 0 + else -> 1 + }) + setUnreadIcon() + onGroupClicked(ACTION_UNREAD_BADGE) + true + } + + // Finally show the PopupMenu + popup.show() + } + + private fun setUnreadIcon() { + launchUI { + val unreadType = preferences.unreadBadgeType().getOrDefault() + val drawableL = withContext(Dispatchers.IO) { + tintVector( + when (unreadType){ + -1 -> R.drawable.ic_check_box_outline_blank_24dp + 0 -> R.drawable.ic_unread_circle_white_24dp + else -> R.drawable.ic_looks_two_white_24dp + } + ) + } + unread_badge.setCompoundDrawablesRelativeWithIntrinsicBounds( + drawableL, null, null, null + ) + } + } + companion object { const val ACTION_REFRESH = 0 const val ACTION_SORT = 1 const val ACTION_FILTER = 2 const val ACTION_DISPLAY = 3 - const val ACTION_BADGE = 4 - const val ACTION_CAT_SORT = 5 + const val ACTION_DOWNLOAD_BADGE = 4 + const val ACTION_UNREAD_BADGE = 5 + const val ACTION_CAT_SORT = 6 } } \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_looks_two_white_24dp.xml b/app/src/main/res/drawable/ic_looks_two_white_24dp.xml new file mode 100644 index 0000000000..ee5c6813bd --- /dev/null +++ b/app/src/main/res/drawable/ic_looks_two_white_24dp.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_unread_circle_white_24dp.xml b/app/src/main/res/drawable/ic_unread_circle_white_24dp.xml new file mode 100644 index 0000000000..30ca019ba8 --- /dev/null +++ b/app/src/main/res/drawable/ic_unread_circle_white_24dp.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/unread_circle_badge.xml b/app/src/main/res/drawable/unread_circle_badge.xml new file mode 100644 index 0000000000..ddccd146f3 --- /dev/null +++ b/app/src/main/res/drawable/unread_circle_badge.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout-land/filter_bottom_sheet.xml b/app/src/main/res/layout-land/filter_bottom_sheet.xml index a708f43901..30e8c0bcd2 100644 --- a/app/src/main/res/layout-land/filter_bottom_sheet.xml +++ b/app/src/main/res/layout-land/filter_bottom_sheet.xml @@ -127,7 +127,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="7dp" - android:layout_marginEnd="14dp" + android:layout_marginEnd="30dp" android:baselineAligned="false" android:gravity="center|start" android:orientation="horizontal"> @@ -166,11 +166,39 @@ - + android:orientation="horizontal" + android:baselineAligned="false" + android:gravity="center|start" + > + + + + + + diff --git a/app/src/main/res/layout-sw600dp/filter_bottom_sheet.xml b/app/src/main/res/layout-sw600dp/filter_bottom_sheet.xml index a708f43901..30e8c0bcd2 100644 --- a/app/src/main/res/layout-sw600dp/filter_bottom_sheet.xml +++ b/app/src/main/res/layout-sw600dp/filter_bottom_sheet.xml @@ -127,7 +127,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="7dp" - android:layout_marginEnd="14dp" + android:layout_marginEnd="30dp" android:baselineAligned="false" android:gravity="center|start" android:orientation="horizontal"> @@ -166,11 +166,39 @@ - + android:orientation="horizontal" + android:baselineAligned="false" + android:gravity="center|start" + > + + + + + + diff --git a/app/src/main/res/layout/catalogue_grid_item.xml b/app/src/main/res/layout/catalogue_grid_item.xml index 40f28733b3..818ad16e42 100644 --- a/app/src/main/res/layout/catalogue_grid_item.xml +++ b/app/src/main/res/layout/catalogue_grid_item.xml @@ -30,6 +30,7 @@ android:background="@drawable/gradient_shape"/> + + + diff --git a/app/src/main/res/layout/catalogue_list_item.xml b/app/src/main/res/layout/catalogue_list_item.xml index 9ebe487993..4a8c1374b9 100644 --- a/app/src/main/res/layout/catalogue_list_item.xml +++ b/app/src/main/res/layout/catalogue_list_item.xml @@ -59,6 +59,32 @@ android:textColor="@color/md_white_1000" tools:visibility="visible" android:layout_marginEnd="8dp" + app:layout_constraintEnd_toStartOf="@+id/download_text" + app:layout_constraintTop_toTopOf="parent" + android:layout_marginTop="8dp" + app:layout_constraintBottom_toBottomOf="parent" + android:layout_marginBottom="8dp"/> + + + + - + android:src="@drawable/unread_circle_badge"/> diff --git a/app/src/main/res/layout/filter_bottom_sheet.xml b/app/src/main/res/layout/filter_bottom_sheet.xml index 6fe0dba0af..d9f5008fd6 100644 --- a/app/src/main/res/layout/filter_bottom_sheet.xml +++ b/app/src/main/res/layout/filter_bottom_sheet.xml @@ -162,11 +162,39 @@ - + android:orientation="horizontal" + android:baselineAligned="false" + android:gravity="center|start" + > + + + + + + diff --git a/app/src/main/res/menu/unread_badge.xml b/app/src/main/res/menu/unread_badge.xml new file mode 100644 index 0000000000..c38db226fd --- /dev/null +++ b/app/src/main/res/menu/unread_badge.xml @@ -0,0 +1,17 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9b175c3ac3..519ef79208 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -97,6 +97,10 @@ Grid List Download badges + Unread badges + All unread + Any unread + Hide unread Set filter Cancel Sort