From a07de130a9775c0b2b0588a2b2d8f8b9cf95842b Mon Sep 17 00:00:00 2001 From: Jay Date: Wed, 12 Feb 2020 22:03:28 -0800 Subject: [PATCH] Added material library grid Like the old grid but using a card view + play button Increased memory size of glide + remove cross fade being on by default --- .../tachiyomi/data/glide/TachiGlideModule.kt | 9 +- .../browse/BrowseCatalogueController.kt | 10 +- .../ui/catalogue/browse/CatalogueItem.kt | 14 +- .../browse/CatalogueMatGridHolder.kt | 63 ++++++ .../ui/library/LibraryCategoryAdapter.kt | 17 +- .../ui/library/LibraryCategoryView.kt | 7 + .../tachiyomi/ui/library/LibraryController.kt | 37 ++-- .../tachiyomi/ui/library/LibraryGridHolder.kt | 2 +- .../tachiyomi/ui/library/LibraryHolder.kt | 2 +- .../tachiyomi/ui/library/LibraryItem.kt | 22 +-- .../tachiyomi/ui/library/LibraryListHolder.kt | 2 +- .../ui/library/LibraryMatGridHolder.kt | 99 ++++++++++ .../tachiyomi/ui/library/LibraryPresenter.kt | 14 ++ .../ui/manga/info/MangaInfoController.kt | 3 + .../tachiyomi/ui/reader/ReaderPresenter.kt | 25 +-- .../tachiyomi/widget/AutofitRecyclerView.kt | 2 +- .../res/drawable/library_item_selector.xml | 35 ++++ .../res/drawable/round_play_background.xml | 24 +++ .../drawable/shape_gradient_top_shadow.xml | 2 +- .../res/layout/catalogue_mat_grid_item.xml | 187 ++++++++++++++++++ .../res/layout/catalogue_recycler_autofit.xml | 3 +- .../main/res/layout/library_controller.xml | 2 +- app/src/main/res/values/colors.xml | 4 + app/src/main/res/values/strings.xml | 7 + 24 files changed, 527 insertions(+), 65 deletions(-) create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/browse/CatalogueMatGridHolder.kt create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryMatGridHolder.kt create mode 100644 app/src/main/res/drawable/library_item_selector.xml create mode 100644 app/src/main/res/drawable/round_play_background.xml create mode 100644 app/src/main/res/layout/catalogue_mat_grid_item.xml diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/glide/TachiGlideModule.kt b/app/src/main/java/eu/kanade/tachiyomi/data/glide/TachiGlideModule.kt index 1eecf3eedb..77faee50a0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/glide/TachiGlideModule.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/glide/TachiGlideModule.kt @@ -9,6 +9,7 @@ import com.bumptech.glide.annotation.GlideModule import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader import com.bumptech.glide.load.DecodeFormat import com.bumptech.glide.load.engine.cache.InternalCacheDiskCacheFactory +import com.bumptech.glide.load.engine.cache.LruResourceCache import com.bumptech.glide.load.model.GlideUrl import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions import com.bumptech.glide.module.AppGlideModule @@ -28,8 +29,12 @@ class TachiGlideModule : AppGlideModule() { override fun applyOptions(context: Context, builder: GlideBuilder) { builder.setDiskCache(InternalCacheDiskCacheFactory(context, 50 * 1024 * 1024)) builder.setDefaultRequestOptions(RequestOptions().format(DecodeFormat.PREFER_RGB_565)) - builder.setDefaultTransitionOptions(Drawable::class.java, - DrawableTransitionOptions.withCrossFade()) + val memoryCacheSizeBytes = 1024 * 1024 * 100 // 1000mb + builder.setMemoryCache(LruResourceCache(memoryCacheSizeBytes.toLong())) + + /* builder.setDefaultTransitionOptions( + Drawable::class.java, + DrawableTransitionOptions.withCrossFade())*/ } override fun registerComponents(context: Context, glide: Glide, registry: Registry) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/browse/BrowseCatalogueController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/browse/BrowseCatalogueController.kt index c71cb6d533..2354601929 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/browse/BrowseCatalogueController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/browse/BrowseCatalogueController.kt @@ -106,7 +106,7 @@ open class BrowseCatalogueController(bundle: Bundle) : /** * Recycler view with the list of results. */ - private var recycler: androidx.recyclerview.widget.RecyclerView? = null + private var recycler: RecyclerView? = null /** * Subscription for the search view. @@ -212,9 +212,9 @@ open class BrowseCatalogueController(bundle: Bundle) : private fun setupRecycler(view: View) { numColumnsSubscription?.unsubscribe() - var oldPosition = androidx.recyclerview.widget.RecyclerView.NO_POSITION + var oldPosition = RecyclerView.NO_POSITION val oldRecycler = catalogue_view?.getChildAt(1) - if (oldRecycler is androidx.recyclerview.widget.RecyclerView) { + if (oldRecycler is RecyclerView) { oldPosition = (oldRecycler.layoutManager as androidx.recyclerview.widget.LinearLayoutManager).findFirstVisibleItemPosition() oldRecycler.adapter = null @@ -239,7 +239,7 @@ open class BrowseCatalogueController(bundle: Bundle) : (layoutManager as androidx.recyclerview.widget.GridLayoutManager).spanSizeLookup = object : androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup() { override fun getSpanSize(position: Int): Int { return when (adapter?.getItemViewType(position)) { - R.layout.catalogue_grid_item, null -> 1 + R.layout.catalogue_mat_grid_item, null -> 1 else -> spanCount } } @@ -251,7 +251,7 @@ open class BrowseCatalogueController(bundle: Bundle) : catalogue_view.addView(recycler, 1) recycler.setOnApplyWindowInsetsListener(RecyclerWindowInsetsListener) - if (oldPosition != androidx.recyclerview.widget.RecyclerView.NO_POSITION) { + if (oldPosition != RecyclerView.NO_POSITION) { recycler.layoutManager?.scrollToPosition(oldPosition) } this.recycler = recycler 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 781ca75c82..a7c2944387 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 @@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.ui.catalogue.browse import android.view.Gravity import android.view.View import android.view.ViewGroup.LayoutParams.MATCH_PARENT +import android.view.ViewGroup.LayoutParams.WRAP_CONTENT import android.widget.FrameLayout import androidx.recyclerview.widget.RecyclerView import com.f2prateek.rx.preferences.Preference @@ -15,6 +16,7 @@ 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.* +import kotlinx.android.synthetic.main.catalogue_mat_grid_item.view.* class CatalogueItem(val manga: Manga, private val catalogueAsList: Preference) : AbstractFlexibleItem() { @@ -23,19 +25,19 @@ class CatalogueItem(val manga: Manga, private val catalogueAsList: Preference>): CatalogueHolder { val parent = adapter.recyclerView return if (parent is AutofitRecyclerView) { view.apply { - card.layoutParams = FrameLayout.LayoutParams( - MATCH_PARENT, parent.itemWidth / 3 * 4) - gradient.layoutParams = FrameLayout.LayoutParams( - MATCH_PARENT, parent.itemWidth / 3 * 4 / 2, Gravity.BOTTOM) + val coverHeight = (parent.itemWidth / 3 * 4f).toInt() + constraint_layout.layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT) + cover_thumbnail.adjustViewBounds = false + cover_thumbnail.layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, coverHeight) } - CatalogueGridHolder(view, adapter) + CatalogueMatGridHolder(view, adapter) } else { CatalogueListHolder(view, adapter) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/browse/CatalogueMatGridHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/browse/CatalogueMatGridHolder.kt new file mode 100644 index 0000000000..6ad671ec24 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/browse/CatalogueMatGridHolder.kt @@ -0,0 +1,63 @@ +package eu.kanade.tachiyomi.ui.catalogue.browse + +import android.view.View +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import com.bumptech.glide.load.engine.DiskCacheStrategy +import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions +import com.bumptech.glide.signature.ObjectKey +import eu.davidea.flexibleadapter.FlexibleAdapter +import eu.davidea.flexibleadapter.items.IFlexible +import eu.kanade.tachiyomi.data.database.models.Manga +import eu.kanade.tachiyomi.data.database.models.MangaImpl +import eu.kanade.tachiyomi.data.glide.GlideApp +import eu.kanade.tachiyomi.ui.library.LibraryCategoryAdapter +import eu.kanade.tachiyomi.util.view.gone +import eu.kanade.tachiyomi.widget.StateImageViewTarget +import kotlinx.android.synthetic.main.catalogue_mat_grid_item.* + +/** + * Class used to hold the displayed data of a manga in the library, like the cover or the title. + * All the elements from the layout file "item_catalogue_grid" are available in this class. + * + * @param view the inflated view for this holder. + * @param adapter the adapter handling this holder. + * @param listener a listener to react to single tap and long tap events. + * @constructor creates a new library holder. + */ +class CatalogueMatGridHolder( + private val view: View, + private val adapter: FlexibleAdapter>) : + CatalogueHolder(view, adapter) { + + /** + * Method called from [LibraryCategoryAdapter.onBindViewHolder]. It updates the data for this + * holder with the given manga. + * + * @param manga the manga item to bind. + */ + override fun onSetValues(manga: Manga) { + // Update the title of the manga. + title.text = manga.currentTitle() + subtitle.gone() + + bookmark_text.visibility = if (manga.favorite) View.VISIBLE else View.GONE + + // Update the cover. + setImage(manga) + } + + override fun setImage(manga: Manga) { + if (manga.thumbnail_url == null) + Glide.with(view.context).clear(cover_thumbnail) + else { + GlideApp.with(view.context) + .load(manga) + .diskCacheStrategy(DiskCacheStrategy.DATA) + .centerCrop() + .placeholder(android.R.color.transparent) + .transition(DrawableTransitionOptions.withCrossFade()) + .into(StateImageViewTarget(cover_thumbnail, progress)) + } + } +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.kt index 174e3512f8..811b69ad49 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.kt @@ -11,8 +11,9 @@ import eu.kanade.tachiyomi.util.lang.chop import eu.kanade.tachiyomi.util.lang.removeArticles import uy.kohesive.injekt.injectLazy import java.text.SimpleDateFormat -import java.util.* - +import java.util.Calendar +import java.util.Date +import java.util.Locale /** * Adapter storing a list of manga in a certain category. @@ -29,6 +30,12 @@ class LibraryCategoryAdapter(val view: LibraryCategoryView) : val onItemReleaseListener: CategoryAdapter.OnItemReleaseListener = view + + /** + * Listener called when an item of the list press start reading. + */ + val libraryListener: LibraryListener = view + /** * Sets a list of manga in the adapter. * @@ -133,4 +140,10 @@ class LibraryCategoryAdapter(val view: LibraryCategoryView) : SimpleDateFormat("yyyy", Locale.getDefault()).format(date) } + interface LibraryListener { + /** + * Called when an item of the list is released. + */ + fun startReading(position: Int) + } } 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 4727afa939..07831f2f1d 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 @@ -39,6 +39,7 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att FlexibleAdapter.OnItemClickListener, FlexibleAdapter.OnItemLongClickListener, FlexibleAdapter.OnItemMoveListener, + LibraryCategoryAdapter.LibraryListener, CategoryAdapter.OnItemReleaseListener { /** @@ -96,6 +97,7 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att recycler.adapter = adapter swipe_refresh.addView(recycler) adapter.fastScroller = fast_scroller + // recycler.addOnScrollListener(adapter.preloader()) if (::category.isInitialized) { val mangaForCategory = controller.presenter.getMangaInCategory(category.id) @@ -332,6 +334,11 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att if (adapter.selectedItemCount == 0) saveDragSort() } + override fun startReading(position: Int) { + val manga = adapter.getItem(position)?.manga ?: return + controller.startReading(manga) + } + private fun saveDragSort() { val mangaIds = adapter.currentItems.mapNotNull { it.manga.id } category.mangaSort = null 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 ce5365f9eb..5839728d38 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 @@ -1,6 +1,8 @@ package eu.kanade.tachiyomi.ui.library +import android.app.Activity import android.content.Context +import android.content.Intent import android.content.res.Configuration import android.graphics.Color import android.os.Bundle @@ -50,6 +52,7 @@ import eu.kanade.tachiyomi.ui.migration.MigrationInterface import eu.kanade.tachiyomi.ui.migration.manga.design.PreMigrationController import eu.kanade.tachiyomi.ui.migration.manga.process.MigrationListController import eu.kanade.tachiyomi.ui.migration.manga.process.MigrationProcedureConfig +import eu.kanade.tachiyomi.ui.reader.ReaderActivity import eu.kanade.tachiyomi.util.system.getResourceColor import eu.kanade.tachiyomi.util.system.launchUI import eu.kanade.tachiyomi.util.view.setOnQueryTextChangeListener @@ -141,6 +144,8 @@ class LibraryController( private var tabsVisibilitySubscription: Subscription? = null + private var observeLater:Boolean = false + var snack: Snackbar? = null var presenter = LibraryPresenter(this) @@ -165,22 +170,11 @@ class LibraryController( adapter = LibraryAdapter(this) library_pager.adapter = adapter + library_pager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { override fun onPageSelected(position: Int) { preferences.lastUsedCategory().set(position) activeCategory = position - } - - override fun onPageScrollStateChanged(state: Int) {} - - override fun onPageScrolled( - position: Int, positionOffset: Float, positionOffsetPixels: Int - ) { - } - }) - - library_pager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { - override fun onPageSelected(position: Int) { bottom_sheet.lastCategory = adapter?.categories?.getOrNull(position) if (preferences.librarySortingMode().getOrDefault() == LibrarySort.DRAG_AND_DROP) bottom_sheet.updateTitle() } @@ -227,6 +221,7 @@ class LibraryController( val library = presenter.getAllManga() if (library != null) onNextLibraryUpdate(presenter.categories, library) else { + library_pager.alpha = 0f presenter.getLibraryBlocking() } } @@ -242,6 +237,14 @@ class LibraryController( } } + override fun onActivityResumed(activity: Activity) { + super.onActivityResumed(activity) + if (observeLater) { + presenter.getLibrary() + observeLater = false + } + } + override fun onDestroy() { presenter.onDestroy() super.onDestroy() @@ -345,6 +348,8 @@ class LibraryController( } else if (!freshStart) { justStarted = false + if (library_pager.alpha == 0f) + library_pager.animate().alpha(1f).setDuration(500).start() } } @@ -666,6 +671,14 @@ class LibraryController( presenter.moveMangasToCategories(categories, mangas) destroyActionModeIfNeeded() } + + fun startReading(manga: Manga) { + val activity = activity ?: return + val chapter = presenter.getFirstUnread(manga) ?: return + val intent = ReaderActivity.newIntent(activity, manga, chapter) + observeLater = true + startActivity(intent) + } } object HeightTopWindowInsetsListener : View.OnApplyWindowInsetsListener { 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 8132eefc93..c4537e2c34 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 @@ -25,7 +25,7 @@ import kotlinx.android.synthetic.main.catalogue_grid_item.* */ class LibraryGridHolder( private val view: View, - adapter: FlexibleAdapter> + adapter: LibraryCategoryAdapter ) : LibraryHolder(view, adapter) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryHolder.kt index 1cc6144314..f08fd847df 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryHolder.kt @@ -15,7 +15,7 @@ import eu.davidea.flexibleadapter.items.IFlexible abstract class LibraryHolder( view: View, - val adapter: FlexibleAdapter> + val adapter: LibraryCategoryAdapter ) : BaseFlexibleViewHolder(view, adapter) { /** 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 b2843a439a..3427b01ef3 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 @@ -1,10 +1,7 @@ package eu.kanade.tachiyomi.ui.library import android.annotation.SuppressLint -import android.view.Gravity import android.view.View -import android.view.ViewGroup.LayoutParams.MATCH_PARENT -import android.widget.FrameLayout import androidx.recyclerview.widget.RecyclerView import com.f2prateek.rx.preferences.Preference import eu.davidea.flexibleadapter.FlexibleAdapter @@ -15,10 +12,10 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.models.LibraryManga import eu.kanade.tachiyomi.data.preference.getOrDefault import eu.kanade.tachiyomi.source.SourceManager +import eu.kanade.tachiyomi.util.system.dpToPx import eu.kanade.tachiyomi.widget.AutofitRecyclerView -import kotlinx.android.synthetic.main.catalogue_grid_item.view.* +import kotlinx.android.synthetic.main.catalogue_mat_grid_item.view.* import uy.kohesive.injekt.injectLazy -import java.io.Serializable class LibraryItem(val manga: LibraryManga, private val libraryAsList: Preference) : AbstractFlexibleItem(), IFilterable { @@ -30,21 +27,21 @@ class LibraryItem(val manga: LibraryManga, private val libraryAsList: Preference return if (libraryAsList.getOrDefault()) R.layout.catalogue_list_item else - R.layout.catalogue_grid_item + R.layout.catalogue_mat_grid_item } override fun createViewHolder(view: View, adapter: FlexibleAdapter>): LibraryHolder { val parent = adapter.recyclerView return if (parent is AutofitRecyclerView) { view.apply { - val coverHeight = parent.itemWidth / 3 * 4 - card.layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, coverHeight) - gradient.layoutParams = FrameLayout.LayoutParams( - MATCH_PARENT, coverHeight / 2, Gravity.BOTTOM) + val coverHeight = (parent.itemWidth / 3 * 4f).toInt() + constraint_layout.minHeight = coverHeight } - LibraryGridHolder(view, adapter) + LibraryMatGridHolder(view, adapter as LibraryCategoryAdapter, parent.itemWidth - 22.dpToPx, parent + .spanCount) + } else { - LibraryListHolder(view, adapter) + LibraryListHolder(view, adapter as LibraryCategoryAdapter) } } @@ -52,7 +49,6 @@ class LibraryItem(val manga: LibraryManga, private val libraryAsList: Preference holder: LibraryHolder, position: Int, payloads: MutableList?) { - holder.onSetValues(this) } 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 5e8e6862cf..df8fba1fe8 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 @@ -30,7 +30,7 @@ import kotlinx.android.synthetic.main.catalogue_list_item.unread_text class LibraryListHolder( private val view: View, - adapter: FlexibleAdapter> + adapter: LibraryCategoryAdapter ) : LibraryHolder(view, adapter) { /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryMatGridHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryMatGridHolder.kt new file mode 100644 index 0000000000..947dc2a24d --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryMatGridHolder.kt @@ -0,0 +1,99 @@ +package eu.kanade.tachiyomi.ui.library + +import android.view.View +import com.bumptech.glide.Glide +import com.bumptech.glide.load.engine.DiskCacheStrategy +import com.bumptech.glide.signature.ObjectKey +import eu.kanade.tachiyomi.R +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.getResourceColor +import kotlinx.android.synthetic.main.catalogue_mat_grid_item.* +import kotlinx.android.synthetic.main.catalogue_mat_grid_item.view.* + +/** + * Class used to hold the displayed data of a manga in the library, like the cover or the title. + * All the elements from the layout file "item_catalogue_grid" are available in this class. + * + * @param view the inflated view for this holder. + * @param adapter the adapter handling this holder. + * @param listener a listener to react to single tap and long tap events. + * @constructor creates a new library holder. + */ +class LibraryMatGridHolder( + private val view: View, + adapter: LibraryCategoryAdapter, + var width:Int, + var rowCount: Int +) : LibraryHolder(view, adapter) { + + /** + * Method called from [LibraryCategoryAdapter.onBindViewHolder]. It updates the data for this + * holder with the given manga. + * + * @param item the manga item to bind. + */ + override fun onSetValues(item: LibraryItem) { + // Update the title of the manga. + title.text = item.manga.currentTitle() + + // Update the unread count and its visibility. + val unread = item.manga.unread + + // Update the subtitle of the manga with artist or the unread count + with(subtitle) { + text = when { + item.manga.unread > 0 -> when (item.unreadType) { + 1 -> view.resources.getQuantityString(R.plurals.unread_count, unread, unread) + 0 -> view.resources.getString(R.string.new_chapter) + else -> item.manga.originalAuthor() + } + else -> item.manga.originalAuthor() + } + setTextColor( + view.context.getResourceColor( + if (item.manga.unread > 0 && item.unreadType > -1) android.R.attr.colorAccent + else android.R.attr.textColorSecondary + ) + ) + } + play_button.visibility = if (unread > 0) View.VISIBLE else View.GONE + play_button.setOnClickListener { playButtonClicked() } + + // Update the download count and its visibility. + 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 + + // Update the cover. + if (item.manga.thumbnail_url == null) Glide.with(view.context).clear(cover_thumbnail) + else { + val id = item.manga.id ?: return + GlideApp.with(view.context).load(item.manga) + .diskCacheStrategy(DiskCacheStrategy.RESOURCE) + .signature(ObjectKey(MangaImpl.getLastCoverFetch(id).toString())) + .into(cover_thumbnail) + } + } + + private fun playButtonClicked() { + adapter.libraryListener.startReading(adapterPosition) + } + + override fun onActionStateChanged(position: Int, actionState: Int) { + super.onActionStateChanged(position, actionState) + if (actionState == 2) { + view.card.isDragged = true + } + } + + override fun onItemReleased(position: Int) { + super.onItemReleased(position) + view.card.isDragged = false + } + +} 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 8d375a407a..579b45258c 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 @@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.ui.library import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.models.Category +import eu.kanade.tachiyomi.data.database.models.Chapter import eu.kanade.tachiyomi.data.database.models.LibraryManga import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.MangaCategory @@ -16,6 +17,7 @@ import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.online.HttpSource +import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem import eu.kanade.tachiyomi.ui.migration.MigrationFlags import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource import eu.kanade.tachiyomi.util.lang.removeArticles @@ -27,16 +29,20 @@ import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.Comp import kotlinx.coroutines.CoroutineStart import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import rx.Observable +import rx.Subscription import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import java.util.ArrayList +import java.util.Calendar import java.util.Collections import java.util.Comparator +import java.util.Date /** * Class containing library information. @@ -78,6 +84,8 @@ class LibraryPresenter( private var currentMangaMap:LibraryMap? = null + private var readerSubscription: Subscription? = null + fun isDownloading() = downloadManager.hasQueue() fun onDestroy() { @@ -684,6 +692,12 @@ class LibraryPresenter( } } + fun getFirstUnread(manga: Manga): Chapter? { + val chapters = db.getChapters(manga).executeAsBlocking() + return chapters.sortedByDescending { it.source_order }.find { !it.read } + + } + private companion object { var currentLibrary:Library? = null } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoController.kt index 17b24e42a6..7ef2fec77d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoController.kt @@ -34,6 +34,7 @@ import com.afollestad.materialdialogs.MaterialDialog import com.afollestad.materialdialogs.list.listItemsSingleChoice import com.bumptech.glide.load.engine.DiskCacheStrategy import com.bumptech.glide.load.resource.bitmap.RoundedCorners +import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions import com.bumptech.glide.request.target.CustomTarget import com.bumptech.glide.request.transition.Transition import com.bumptech.glide.signature.ObjectKey @@ -333,6 +334,7 @@ class MangaInfoController : NucleusController(), .load(manga) .diskCacheStrategy(DiskCacheStrategy.RESOURCE) .signature(ObjectKey(MangaImpl.getLastCoverFetch(manga.id!!).toString())) + .transition(DrawableTransitionOptions.withCrossFade()) //.centerCrop() .into(manga_cover) if (manga_cover_full != null) { @@ -356,6 +358,7 @@ class MangaInfoController : NucleusController(), .load(manga) .diskCacheStrategy(DiskCacheStrategy.RESOURCE) .signature(ObjectKey(MangaImpl.getLastCoverFetch(manga.id!!).toString())) + .transition(DrawableTransitionOptions.withCrossFade()) .centerCrop() .into(backdrop) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt index 79f5877839..a696b0d9e0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt @@ -119,20 +119,6 @@ class ReaderPresenter( } } - /** - * Called when the presenter is destroyed. It saves the current progress and cleans up - * references on the currently active chapters. - */ - override fun onDestroy() { - super.onDestroy() - val currentChapters = viewerChaptersRelay.value - if (currentChapters != null) { - currentChapters.unref() - saveChapterProgress(currentChapters.currChapter) - saveChapterHistory(currentChapters.currChapter) - } - } - /** * Called when the presenter instance is being saved. It saves the currently active chapter * id and the last page read. @@ -152,6 +138,12 @@ class ReaderPresenter( */ fun onBackPressed() { deletePendingChapters() + val currentChapters = viewerChaptersRelay.value + if (currentChapters != null) { + currentChapters.unref() + saveChapterProgress(currentChapters.currChapter) + saveChapterHistory(currentChapters.currChapter) + } } /** @@ -364,10 +356,7 @@ class ReaderPresenter( */ private fun saveChapterHistory(chapter: ReaderChapter) { val history = History.create(chapter.chapter).apply { last_read = Date().time } - db.updateHistoryLastRead(history).asRxCompletable() - .onErrorComplete() - .subscribeOn(Schedulers.io()) - .subscribe() + db.updateHistoryLastRead(history).executeAsBlocking() } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/AutofitRecyclerView.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/AutofitRecyclerView.kt index 738e2e70f9..53b062b6af 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/AutofitRecyclerView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/AutofitRecyclerView.kt @@ -9,7 +9,7 @@ import kotlin.math.max class AutofitRecyclerView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : androidx.recyclerview.widget.RecyclerView(context, attrs) { - private val manager = androidx.recyclerview.widget.GridLayoutManager(context, 1) + private val manager = GridLayoutManager(context, 1) private var columnWidth = -1 diff --git a/app/src/main/res/drawable/library_item_selector.xml b/app/src/main/res/drawable/library_item_selector.xml new file mode 100644 index 0000000000..07a4041479 --- /dev/null +++ b/app/src/main/res/drawable/library_item_selector.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/round_play_background.xml b/app/src/main/res/drawable/round_play_background.xml new file mode 100644 index 0000000000..9452dd735c --- /dev/null +++ b/app/src/main/res/drawable/round_play_background.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_gradient_top_shadow.xml b/app/src/main/res/drawable/shape_gradient_top_shadow.xml index 8b67330a76..e709d2332a 100644 --- a/app/src/main/res/drawable/shape_gradient_top_shadow.xml +++ b/app/src/main/res/drawable/shape_gradient_top_shadow.xml @@ -3,5 +3,5 @@ + android:startColor="@color/md_black_1000_54"/> \ No newline at end of file diff --git a/app/src/main/res/layout/catalogue_mat_grid_item.xml b/app/src/main/res/layout/catalogue_mat_grid_item.xml new file mode 100644 index 0000000000..dc289c5e27 --- /dev/null +++ b/app/src/main/res/layout/catalogue_mat_grid_item.xml @@ -0,0 +1,187 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/catalogue_recycler_autofit.xml b/app/src/main/res/layout/catalogue_recycler_autofit.xml index 50ff838a71..8003036795 100644 --- a/app/src/main/res/layout/catalogue_recycler_autofit.xml +++ b/app/src/main/res/layout/catalogue_recycler_autofit.xml @@ -1,5 +1,6 @@ \ No newline at end of file + tools:listitem="@layout/catalogue_mat_grid_item" /> \ No newline at end of file diff --git a/app/src/main/res/layout/library_controller.xml b/app/src/main/res/layout/library_controller.xml index 538a037856..b74570b268 100644 --- a/app/src/main/res/layout/library_controller.xml +++ b/app/src/main/res/layout/library_controller.xml @@ -33,10 +33,10 @@ android:layout_width="match_parent" android:layout_height="20dp" android:background="@drawable/shape_gradient_top_shadow" - android:backgroundTint="@color/md_black_1000_54" android:paddingBottom="10dp" app:layout_anchorGravity="top" app:layout_anchor="@id/bottom_sheet" /> + diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 1101531eda..ef8c665b41 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -49,6 +49,7 @@ #DE000000 + #B3000000 #8A000000 #61000000 #1F000000 @@ -71,10 +72,13 @@ #80448AFF #2979FF + #DE2979FF #612979FF #F44336 + #DEF44336 + #009688 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 25713775c9..4391dc3010 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -409,6 +409,12 @@ %1$s is already in queue Local Remove from library? + + New chapter + %d Unread + + New + Start Reading Search filters @@ -419,6 +425,7 @@ Global search… Latest Browse + In Library This manga has been removed from the database.