mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-12-24 02:21:51 +01:00
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
This commit is contained in:
parent
489ef7a5f8
commit
a07de130a9
@ -9,6 +9,7 @@ import com.bumptech.glide.annotation.GlideModule
|
|||||||
import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader
|
import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader
|
||||||
import com.bumptech.glide.load.DecodeFormat
|
import com.bumptech.glide.load.DecodeFormat
|
||||||
import com.bumptech.glide.load.engine.cache.InternalCacheDiskCacheFactory
|
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.model.GlideUrl
|
||||||
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
|
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
|
||||||
import com.bumptech.glide.module.AppGlideModule
|
import com.bumptech.glide.module.AppGlideModule
|
||||||
@ -28,8 +29,12 @@ class TachiGlideModule : AppGlideModule() {
|
|||||||
override fun applyOptions(context: Context, builder: GlideBuilder) {
|
override fun applyOptions(context: Context, builder: GlideBuilder) {
|
||||||
builder.setDiskCache(InternalCacheDiskCacheFactory(context, 50 * 1024 * 1024))
|
builder.setDiskCache(InternalCacheDiskCacheFactory(context, 50 * 1024 * 1024))
|
||||||
builder.setDefaultRequestOptions(RequestOptions().format(DecodeFormat.PREFER_RGB_565))
|
builder.setDefaultRequestOptions(RequestOptions().format(DecodeFormat.PREFER_RGB_565))
|
||||||
builder.setDefaultTransitionOptions(Drawable::class.java,
|
val memoryCacheSizeBytes = 1024 * 1024 * 100 // 1000mb
|
||||||
DrawableTransitionOptions.withCrossFade())
|
builder.setMemoryCache(LruResourceCache(memoryCacheSizeBytes.toLong()))
|
||||||
|
|
||||||
|
/* builder.setDefaultTransitionOptions(
|
||||||
|
Drawable::class.java,
|
||||||
|
DrawableTransitionOptions.withCrossFade())*/
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
|
override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
|
||||||
|
@ -106,7 +106,7 @@ open class BrowseCatalogueController(bundle: Bundle) :
|
|||||||
/**
|
/**
|
||||||
* Recycler view with the list of results.
|
* 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.
|
* Subscription for the search view.
|
||||||
@ -212,9 +212,9 @@ open class BrowseCatalogueController(bundle: Bundle) :
|
|||||||
private fun setupRecycler(view: View) {
|
private fun setupRecycler(view: View) {
|
||||||
numColumnsSubscription?.unsubscribe()
|
numColumnsSubscription?.unsubscribe()
|
||||||
|
|
||||||
var oldPosition = androidx.recyclerview.widget.RecyclerView.NO_POSITION
|
var oldPosition = RecyclerView.NO_POSITION
|
||||||
val oldRecycler = catalogue_view?.getChildAt(1)
|
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()
|
oldPosition = (oldRecycler.layoutManager as androidx.recyclerview.widget.LinearLayoutManager).findFirstVisibleItemPosition()
|
||||||
oldRecycler.adapter = null
|
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() {
|
(layoutManager as androidx.recyclerview.widget.GridLayoutManager).spanSizeLookup = object : androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup() {
|
||||||
override fun getSpanSize(position: Int): Int {
|
override fun getSpanSize(position: Int): Int {
|
||||||
return when (adapter?.getItemViewType(position)) {
|
return when (adapter?.getItemViewType(position)) {
|
||||||
R.layout.catalogue_grid_item, null -> 1
|
R.layout.catalogue_mat_grid_item, null -> 1
|
||||||
else -> spanCount
|
else -> spanCount
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -251,7 +251,7 @@ open class BrowseCatalogueController(bundle: Bundle) :
|
|||||||
|
|
||||||
catalogue_view.addView(recycler, 1)
|
catalogue_view.addView(recycler, 1)
|
||||||
recycler.setOnApplyWindowInsetsListener(RecyclerWindowInsetsListener)
|
recycler.setOnApplyWindowInsetsListener(RecyclerWindowInsetsListener)
|
||||||
if (oldPosition != androidx.recyclerview.widget.RecyclerView.NO_POSITION) {
|
if (oldPosition != RecyclerView.NO_POSITION) {
|
||||||
recycler.layoutManager?.scrollToPosition(oldPosition)
|
recycler.layoutManager?.scrollToPosition(oldPosition)
|
||||||
}
|
}
|
||||||
this.recycler = recycler
|
this.recycler = recycler
|
||||||
|
@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.ui.catalogue.browse
|
|||||||
import android.view.Gravity
|
import android.view.Gravity
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
|
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
|
||||||
|
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.f2prateek.rx.preferences.Preference
|
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.util.system.dpToPx
|
||||||
import eu.kanade.tachiyomi.widget.AutofitRecyclerView
|
import eu.kanade.tachiyomi.widget.AutofitRecyclerView
|
||||||
import kotlinx.android.synthetic.main.catalogue_grid_item.view.*
|
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<Boolean>) :
|
class CatalogueItem(val manga: Manga, private val catalogueAsList: Preference<Boolean>) :
|
||||||
AbstractFlexibleItem<CatalogueHolder>() {
|
AbstractFlexibleItem<CatalogueHolder>() {
|
||||||
@ -23,19 +25,19 @@ class CatalogueItem(val manga: Manga, private val catalogueAsList: Preference<Bo
|
|||||||
return if (catalogueAsList.getOrDefault())
|
return if (catalogueAsList.getOrDefault())
|
||||||
R.layout.catalogue_list_item
|
R.layout.catalogue_list_item
|
||||||
else
|
else
|
||||||
R.layout.catalogue_grid_item
|
R.layout.catalogue_mat_grid_item
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): CatalogueHolder {
|
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): CatalogueHolder {
|
||||||
val parent = adapter.recyclerView
|
val parent = adapter.recyclerView
|
||||||
return if (parent is AutofitRecyclerView) {
|
return if (parent is AutofitRecyclerView) {
|
||||||
view.apply {
|
view.apply {
|
||||||
card.layoutParams = FrameLayout.LayoutParams(
|
val coverHeight = (parent.itemWidth / 3 * 4f).toInt()
|
||||||
MATCH_PARENT, parent.itemWidth / 3 * 4)
|
constraint_layout.layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT)
|
||||||
gradient.layoutParams = FrameLayout.LayoutParams(
|
cover_thumbnail.adjustViewBounds = false
|
||||||
MATCH_PARENT, parent.itemWidth / 3 * 4 / 2, Gravity.BOTTOM)
|
cover_thumbnail.layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, coverHeight)
|
||||||
}
|
}
|
||||||
CatalogueGridHolder(view, adapter)
|
CatalogueMatGridHolder(view, adapter)
|
||||||
} else {
|
} else {
|
||||||
CatalogueListHolder(view, adapter)
|
CatalogueListHolder(view, adapter)
|
||||||
}
|
}
|
||||||
|
@ -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<IFlexible<RecyclerView.ViewHolder>>) :
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -11,8 +11,9 @@ import eu.kanade.tachiyomi.util.lang.chop
|
|||||||
import eu.kanade.tachiyomi.util.lang.removeArticles
|
import eu.kanade.tachiyomi.util.lang.removeArticles
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
import java.text.SimpleDateFormat
|
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.
|
* Adapter storing a list of manga in a certain category.
|
||||||
@ -29,6 +30,12 @@ class LibraryCategoryAdapter(val view: LibraryCategoryView) :
|
|||||||
|
|
||||||
val onItemReleaseListener: CategoryAdapter.OnItemReleaseListener = view
|
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.
|
* Sets a list of manga in the adapter.
|
||||||
*
|
*
|
||||||
@ -133,4 +140,10 @@ class LibraryCategoryAdapter(val view: LibraryCategoryView) :
|
|||||||
SimpleDateFormat("yyyy", Locale.getDefault()).format(date)
|
SimpleDateFormat("yyyy", Locale.getDefault()).format(date)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface LibraryListener {
|
||||||
|
/**
|
||||||
|
* Called when an item of the list is released.
|
||||||
|
*/
|
||||||
|
fun startReading(position: Int)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,7 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
|
|||||||
FlexibleAdapter.OnItemClickListener,
|
FlexibleAdapter.OnItemClickListener,
|
||||||
FlexibleAdapter.OnItemLongClickListener,
|
FlexibleAdapter.OnItemLongClickListener,
|
||||||
FlexibleAdapter.OnItemMoveListener,
|
FlexibleAdapter.OnItemMoveListener,
|
||||||
|
LibraryCategoryAdapter.LibraryListener,
|
||||||
CategoryAdapter.OnItemReleaseListener {
|
CategoryAdapter.OnItemReleaseListener {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -96,6 +97,7 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
|
|||||||
recycler.adapter = adapter
|
recycler.adapter = adapter
|
||||||
swipe_refresh.addView(recycler)
|
swipe_refresh.addView(recycler)
|
||||||
adapter.fastScroller = fast_scroller
|
adapter.fastScroller = fast_scroller
|
||||||
|
// recycler.addOnScrollListener(adapter.preloader())
|
||||||
|
|
||||||
if (::category.isInitialized) {
|
if (::category.isInitialized) {
|
||||||
val mangaForCategory = controller.presenter.getMangaInCategory(category.id)
|
val mangaForCategory = controller.presenter.getMangaInCategory(category.id)
|
||||||
@ -332,6 +334,11 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
|
|||||||
if (adapter.selectedItemCount == 0) saveDragSort()
|
if (adapter.selectedItemCount == 0) saveDragSort()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun startReading(position: Int) {
|
||||||
|
val manga = adapter.getItem(position)?.manga ?: return
|
||||||
|
controller.startReading(manga)
|
||||||
|
}
|
||||||
|
|
||||||
private fun saveDragSort() {
|
private fun saveDragSort() {
|
||||||
val mangaIds = adapter.currentItems.mapNotNull { it.manga.id }
|
val mangaIds = adapter.currentItems.mapNotNull { it.manga.id }
|
||||||
category.mangaSort = null
|
category.mangaSort = null
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package eu.kanade.tachiyomi.ui.library
|
package eu.kanade.tachiyomi.ui.library
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.os.Bundle
|
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.design.PreMigrationController
|
||||||
import eu.kanade.tachiyomi.ui.migration.manga.process.MigrationListController
|
import eu.kanade.tachiyomi.ui.migration.manga.process.MigrationListController
|
||||||
import eu.kanade.tachiyomi.ui.migration.manga.process.MigrationProcedureConfig
|
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.getResourceColor
|
||||||
import eu.kanade.tachiyomi.util.system.launchUI
|
import eu.kanade.tachiyomi.util.system.launchUI
|
||||||
import eu.kanade.tachiyomi.util.view.setOnQueryTextChangeListener
|
import eu.kanade.tachiyomi.util.view.setOnQueryTextChangeListener
|
||||||
@ -141,6 +144,8 @@ class LibraryController(
|
|||||||
|
|
||||||
private var tabsVisibilitySubscription: Subscription? = null
|
private var tabsVisibilitySubscription: Subscription? = null
|
||||||
|
|
||||||
|
private var observeLater:Boolean = false
|
||||||
|
|
||||||
var snack: Snackbar? = null
|
var snack: Snackbar? = null
|
||||||
|
|
||||||
var presenter = LibraryPresenter(this)
|
var presenter = LibraryPresenter(this)
|
||||||
@ -165,22 +170,11 @@ class LibraryController(
|
|||||||
|
|
||||||
adapter = LibraryAdapter(this)
|
adapter = LibraryAdapter(this)
|
||||||
library_pager.adapter = adapter
|
library_pager.adapter = adapter
|
||||||
|
|
||||||
library_pager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
|
library_pager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
|
||||||
override fun onPageSelected(position: Int) {
|
override fun onPageSelected(position: Int) {
|
||||||
preferences.lastUsedCategory().set(position)
|
preferences.lastUsedCategory().set(position)
|
||||||
activeCategory = 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)
|
bottom_sheet.lastCategory = adapter?.categories?.getOrNull(position)
|
||||||
if (preferences.librarySortingMode().getOrDefault() == LibrarySort.DRAG_AND_DROP) bottom_sheet.updateTitle()
|
if (preferences.librarySortingMode().getOrDefault() == LibrarySort.DRAG_AND_DROP) bottom_sheet.updateTitle()
|
||||||
}
|
}
|
||||||
@ -227,6 +221,7 @@ class LibraryController(
|
|||||||
val library = presenter.getAllManga()
|
val library = presenter.getAllManga()
|
||||||
if (library != null) onNextLibraryUpdate(presenter.categories, library)
|
if (library != null) onNextLibraryUpdate(presenter.categories, library)
|
||||||
else {
|
else {
|
||||||
|
library_pager.alpha = 0f
|
||||||
presenter.getLibraryBlocking()
|
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() {
|
override fun onDestroy() {
|
||||||
presenter.onDestroy()
|
presenter.onDestroy()
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
@ -345,6 +348,8 @@ class LibraryController(
|
|||||||
}
|
}
|
||||||
else if (!freshStart) {
|
else if (!freshStart) {
|
||||||
justStarted = false
|
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)
|
presenter.moveMangasToCategories(categories, mangas)
|
||||||
destroyActionModeIfNeeded()
|
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 {
|
object HeightTopWindowInsetsListener : View.OnApplyWindowInsetsListener {
|
||||||
|
@ -25,7 +25,7 @@ import kotlinx.android.synthetic.main.catalogue_grid_item.*
|
|||||||
*/
|
*/
|
||||||
class LibraryGridHolder(
|
class LibraryGridHolder(
|
||||||
private val view: View,
|
private val view: View,
|
||||||
adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>
|
adapter: LibraryCategoryAdapter
|
||||||
|
|
||||||
) : LibraryHolder(view, adapter) {
|
) : LibraryHolder(view, adapter) {
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ import eu.davidea.flexibleadapter.items.IFlexible
|
|||||||
|
|
||||||
abstract class LibraryHolder(
|
abstract class LibraryHolder(
|
||||||
view: View,
|
view: View,
|
||||||
val adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>
|
val adapter: LibraryCategoryAdapter
|
||||||
) : BaseFlexibleViewHolder(view, adapter) {
|
) : BaseFlexibleViewHolder(view, adapter) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
package eu.kanade.tachiyomi.ui.library
|
package eu.kanade.tachiyomi.ui.library
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.view.Gravity
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
|
|
||||||
import android.widget.FrameLayout
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.f2prateek.rx.preferences.Preference
|
import com.f2prateek.rx.preferences.Preference
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
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.database.models.LibraryManga
|
||||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
|
import eu.kanade.tachiyomi.util.system.dpToPx
|
||||||
import eu.kanade.tachiyomi.widget.AutofitRecyclerView
|
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 uy.kohesive.injekt.injectLazy
|
||||||
import java.io.Serializable
|
|
||||||
|
|
||||||
class LibraryItem(val manga: LibraryManga, private val libraryAsList: Preference<Boolean>) :
|
class LibraryItem(val manga: LibraryManga, private val libraryAsList: Preference<Boolean>) :
|
||||||
AbstractFlexibleItem<LibraryHolder>(), IFilterable<String> {
|
AbstractFlexibleItem<LibraryHolder>(), IFilterable<String> {
|
||||||
@ -30,21 +27,21 @@ class LibraryItem(val manga: LibraryManga, private val libraryAsList: Preference
|
|||||||
return if (libraryAsList.getOrDefault())
|
return if (libraryAsList.getOrDefault())
|
||||||
R.layout.catalogue_list_item
|
R.layout.catalogue_list_item
|
||||||
else
|
else
|
||||||
R.layout.catalogue_grid_item
|
R.layout.catalogue_mat_grid_item
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): LibraryHolder {
|
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): LibraryHolder {
|
||||||
val parent = adapter.recyclerView
|
val parent = adapter.recyclerView
|
||||||
return if (parent is AutofitRecyclerView) {
|
return if (parent is AutofitRecyclerView) {
|
||||||
view.apply {
|
view.apply {
|
||||||
val coverHeight = parent.itemWidth / 3 * 4
|
val coverHeight = (parent.itemWidth / 3 * 4f).toInt()
|
||||||
card.layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, coverHeight)
|
constraint_layout.minHeight = coverHeight
|
||||||
gradient.layoutParams = FrameLayout.LayoutParams(
|
|
||||||
MATCH_PARENT, coverHeight / 2, Gravity.BOTTOM)
|
|
||||||
}
|
}
|
||||||
LibraryGridHolder(view, adapter)
|
LibraryMatGridHolder(view, adapter as LibraryCategoryAdapter, parent.itemWidth - 22.dpToPx, parent
|
||||||
|
.spanCount)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
LibraryListHolder(view, adapter)
|
LibraryListHolder(view, adapter as LibraryCategoryAdapter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,7 +49,6 @@ class LibraryItem(val manga: LibraryManga, private val libraryAsList: Preference
|
|||||||
holder: LibraryHolder,
|
holder: LibraryHolder,
|
||||||
position: Int,
|
position: Int,
|
||||||
payloads: MutableList<Any?>?) {
|
payloads: MutableList<Any?>?) {
|
||||||
|
|
||||||
holder.onSetValues(this)
|
holder.onSetValues(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ import kotlinx.android.synthetic.main.catalogue_list_item.unread_text
|
|||||||
|
|
||||||
class LibraryListHolder(
|
class LibraryListHolder(
|
||||||
private val view: View,
|
private val view: View,
|
||||||
adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>
|
adapter: LibraryCategoryAdapter
|
||||||
) : LibraryHolder(view, adapter) {
|
) : LibraryHolder(view, adapter) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.ui.library
|
|||||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||||
import eu.kanade.tachiyomi.data.database.models.Category
|
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.LibraryManga
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.database.models.MangaCategory
|
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.SChapter
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
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.ui.migration.MigrationFlags
|
||||||
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
||||||
import eu.kanade.tachiyomi.util.lang.removeArticles
|
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.CoroutineStart
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
|
import rx.Subscription
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
import rx.schedulers.Schedulers
|
import rx.schedulers.Schedulers
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
|
import java.util.Calendar
|
||||||
import java.util.Collections
|
import java.util.Collections
|
||||||
import java.util.Comparator
|
import java.util.Comparator
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class containing library information.
|
* Class containing library information.
|
||||||
@ -78,6 +84,8 @@ class LibraryPresenter(
|
|||||||
|
|
||||||
private var currentMangaMap:LibraryMap? = null
|
private var currentMangaMap:LibraryMap? = null
|
||||||
|
|
||||||
|
private var readerSubscription: Subscription? = null
|
||||||
|
|
||||||
fun isDownloading() = downloadManager.hasQueue()
|
fun isDownloading() = downloadManager.hasQueue()
|
||||||
|
|
||||||
fun onDestroy() {
|
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 {
|
private companion object {
|
||||||
var currentLibrary:Library? = null
|
var currentLibrary:Library? = null
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@ import com.afollestad.materialdialogs.MaterialDialog
|
|||||||
import com.afollestad.materialdialogs.list.listItemsSingleChoice
|
import com.afollestad.materialdialogs.list.listItemsSingleChoice
|
||||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||||
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
|
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.target.CustomTarget
|
||||||
import com.bumptech.glide.request.transition.Transition
|
import com.bumptech.glide.request.transition.Transition
|
||||||
import com.bumptech.glide.signature.ObjectKey
|
import com.bumptech.glide.signature.ObjectKey
|
||||||
@ -333,6 +334,7 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
|
|||||||
.load(manga)
|
.load(manga)
|
||||||
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
||||||
.signature(ObjectKey(MangaImpl.getLastCoverFetch(manga.id!!).toString()))
|
.signature(ObjectKey(MangaImpl.getLastCoverFetch(manga.id!!).toString()))
|
||||||
|
.transition(DrawableTransitionOptions.withCrossFade())
|
||||||
//.centerCrop()
|
//.centerCrop()
|
||||||
.into(manga_cover)
|
.into(manga_cover)
|
||||||
if (manga_cover_full != null) {
|
if (manga_cover_full != null) {
|
||||||
@ -356,6 +358,7 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
|
|||||||
.load(manga)
|
.load(manga)
|
||||||
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
||||||
.signature(ObjectKey(MangaImpl.getLastCoverFetch(manga.id!!).toString()))
|
.signature(ObjectKey(MangaImpl.getLastCoverFetch(manga.id!!).toString()))
|
||||||
|
.transition(DrawableTransitionOptions.withCrossFade())
|
||||||
.centerCrop()
|
.centerCrop()
|
||||||
.into(backdrop)
|
.into(backdrop)
|
||||||
}
|
}
|
||||||
|
@ -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
|
* Called when the presenter instance is being saved. It saves the currently active chapter
|
||||||
* id and the last page read.
|
* id and the last page read.
|
||||||
@ -152,6 +138,12 @@ class ReaderPresenter(
|
|||||||
*/
|
*/
|
||||||
fun onBackPressed() {
|
fun onBackPressed() {
|
||||||
deletePendingChapters()
|
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) {
|
private fun saveChapterHistory(chapter: ReaderChapter) {
|
||||||
val history = History.create(chapter.chapter).apply { last_read = Date().time }
|
val history = History.create(chapter.chapter).apply { last_read = Date().time }
|
||||||
db.updateHistoryLastRead(history).asRxCompletable()
|
db.updateHistoryLastRead(history).executeAsBlocking()
|
||||||
.onErrorComplete()
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.subscribe()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -9,7 +9,7 @@ import kotlin.math.max
|
|||||||
class AutofitRecyclerView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
class AutofitRecyclerView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
||||||
androidx.recyclerview.widget.RecyclerView(context, attrs) {
|
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
|
private var columnWidth = -1
|
||||||
|
|
||||||
|
35
app/src/main/res/drawable/library_item_selector.xml
Normal file
35
app/src/main/res/drawable/library_item_selector.xml
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:color="@color/selectorColor">
|
||||||
|
<item android:id="@android:id/mask"
|
||||||
|
android:top="0dp"
|
||||||
|
android:bottom="12dp"
|
||||||
|
android:left="4dp"
|
||||||
|
android:right="4dp">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<corners android:radius="4dp" />
|
||||||
|
<solid android:color="@color/selectorColor" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
android:top="0dp"
|
||||||
|
android:bottom="12dp"
|
||||||
|
android:left="4dp"
|
||||||
|
android:right="4dp">
|
||||||
|
<selector>
|
||||||
|
<item android:state_selected="true">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<corners android:radius="4dp" />
|
||||||
|
<solid android:color="@color/selectorColor" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
|
||||||
|
<item android:state_activated="true">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<corners android:radius="4dp" />
|
||||||
|
<solid android:color="@color/selectorColor" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</selector>
|
||||||
|
</item>
|
||||||
|
</ripple>
|
24
app/src/main/res/drawable/round_play_background.xml
Normal file
24
app/src/main/res/drawable/round_play_background.xml
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
tools:background="#FFFF00"
|
||||||
|
android:color="?android:attr/colorAccent">
|
||||||
|
<item android:id="@android:id/mask">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<solid android:color="?android:attr/colorAccent" />
|
||||||
|
<corners android:radius="13dp" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
|
||||||
|
<item android:id="@android:id/background">
|
||||||
|
<shape
|
||||||
|
android:shape="rectangle">
|
||||||
|
<corners android:radius="16dp"/>
|
||||||
|
<size
|
||||||
|
android:height="32dp"
|
||||||
|
android:width="32dp" />
|
||||||
|
<solid android:color="#AD212121"/>
|
||||||
|
<stroke android:width="0.1dp" android:color="#EDEDED" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</ripple>
|
@ -3,5 +3,5 @@
|
|||||||
<gradient
|
<gradient
|
||||||
android:angle="90"
|
android:angle="90"
|
||||||
android:endColor="@android:color/transparent"
|
android:endColor="@android:color/transparent"
|
||||||
android:startColor="?android:attr/textColorSecondary"/>
|
android:startColor="@color/md_black_1000_54"/>
|
||||||
</shape>
|
</shape>
|
187
app/src/main/res/layout/catalogue_mat_grid_item.xml
Normal file
187
app/src/main/res/layout/catalogue_mat_grid_item.xml
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/manga_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:id="@+id/constraint_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
android:background="@drawable/library_item_selector"
|
||||||
|
android:minHeight="200dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:id="@+id/card"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
android:layout_marginStart="6dp"
|
||||||
|
android:layout_marginEnd="6dp"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/title"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintVertical_bias="1.0">
|
||||||
|
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/cover_thumbnail"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:adjustViewBounds="true"
|
||||||
|
android:background="?android:attr/colorBackground"
|
||||||
|
android:maxHeight="250dp"
|
||||||
|
app:layout_constrainedHeight="true"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:background="?android:attr/colorBackground"
|
||||||
|
tools:ignore="ContentDescription"
|
||||||
|
tools:src="@mipmap/ic_launcher" />
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:id="@+id/badge_layout"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
android:layout_marginTop="4dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/local_text"
|
||||||
|
style="@style/TextAppearance.Regular.Caption.Light"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@color/md_teal_500"
|
||||||
|
android:paddingStart="3dp"
|
||||||
|
android:paddingTop="1dp"
|
||||||
|
android:paddingEnd="3dp"
|
||||||
|
android:paddingBottom="1dp"
|
||||||
|
android:text="@string/local_source_badge"
|
||||||
|
android:textColor="@color/md_white_1000"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/download_text"
|
||||||
|
style="@style/TextAppearance.Regular.Caption.Light"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="-10dp"
|
||||||
|
android:layout_marginTop="-10dp"
|
||||||
|
android:background="@drawable/dialog_rounded_background"
|
||||||
|
android:backgroundTint="@color/md_red_500"
|
||||||
|
android:gravity="start|center"
|
||||||
|
android:paddingStart="14dp"
|
||||||
|
android:paddingTop="10dp"
|
||||||
|
android:paddingEnd="5dp"
|
||||||
|
android:paddingBottom="3dp"
|
||||||
|
android:textColor="@color/md_white_1000"
|
||||||
|
android:textSize="13sp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/local_text"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:text="1" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/bookmark_text"
|
||||||
|
style="@style/TextAppearance.Regular.Caption.Light"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="-10dp"
|
||||||
|
android:layout_marginTop="-10dp"
|
||||||
|
android:background="@drawable/dialog_rounded_background"
|
||||||
|
android:backgroundTint="@color/md_blue_A400_87"
|
||||||
|
android:gravity="start|center"
|
||||||
|
android:paddingStart="14dp"
|
||||||
|
android:paddingTop="10dp"
|
||||||
|
android:paddingEnd="5dp"
|
||||||
|
android:paddingBottom="3dp"
|
||||||
|
android:textColor="@color/md_white_1000"
|
||||||
|
android:textSize="13sp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/local_text"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
android:text="@string/in_library"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/play_button"
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_gravity="end|bottom"
|
||||||
|
android:layout_marginEnd="6dp"
|
||||||
|
android:layout_marginBottom="6dp"
|
||||||
|
android:background="@drawable/round_play_background"
|
||||||
|
android:contentDescription="@string/start_reading"
|
||||||
|
android:src="@drawable/ic_play_arrow_white_24dp"
|
||||||
|
android:tint="@android:color/white"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progress"
|
||||||
|
style="?android:attr/progressBarStyleSmall"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/title"
|
||||||
|
style="@style/TextAppearance.Regular.Body1.Light"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="6dp"
|
||||||
|
android:layout_marginTop="6dp"
|
||||||
|
android:layout_marginEnd="6dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:lineSpacingExtra="-4dp"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
|
android:textSize="12sp"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/subtitle"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
tools:text="Sample name\nsdf" />
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/subtitle"
|
||||||
|
style="@style/TextAppearance.Regular.Body1.Light"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="14dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:lineSpacingExtra="-4dp"
|
||||||
|
android:paddingStart="6dp"
|
||||||
|
android:paddingEnd="6dp"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
|
android:textSize="12sp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
tools:text="Sample artist" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</FrameLayout>
|
@ -1,5 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<eu.kanade.tachiyomi.widget.AutofitRecyclerView
|
<eu.kanade.tachiyomi.widget.AutofitRecyclerView
|
||||||
|
android:id="@+id/catalogue_recycler"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
style="@style/Theme.Widget.GridView.Catalogue"
|
style="@style/Theme.Widget.GridView.Catalogue"
|
||||||
@ -7,4 +8,4 @@
|
|||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:columnWidth="140dp"
|
android:columnWidth="140dp"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
tools:listitem="@layout/catalogue_grid_item" />
|
tools:listitem="@layout/catalogue_mat_grid_item" />
|
@ -33,10 +33,10 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="20dp"
|
android:layout_height="20dp"
|
||||||
android:background="@drawable/shape_gradient_top_shadow"
|
android:background="@drawable/shape_gradient_top_shadow"
|
||||||
android:backgroundTint="@color/md_black_1000_54"
|
|
||||||
android:paddingBottom="10dp"
|
android:paddingBottom="10dp"
|
||||||
app:layout_anchorGravity="top"
|
app:layout_anchorGravity="top"
|
||||||
app:layout_anchor="@id/bottom_sheet" />
|
app:layout_anchor="@id/bottom_sheet" />
|
||||||
|
|
||||||
<!-- Adding bottom sheet after main content -->
|
<!-- Adding bottom sheet after main content -->
|
||||||
<include layout="@layout/filter_bottom_sheet"/>
|
<include layout="@layout/filter_bottom_sheet"/>
|
||||||
|
|
||||||
|
@ -49,6 +49,7 @@
|
|||||||
|
|
||||||
<!-- Text Colors -->
|
<!-- Text Colors -->
|
||||||
<color name="md_black_1000_87">#DE000000</color>
|
<color name="md_black_1000_87">#DE000000</color>
|
||||||
|
<color name="md_black_1000_70">#B3000000</color>
|
||||||
<color name="md_black_1000_54">#8A000000</color>
|
<color name="md_black_1000_54">#8A000000</color>
|
||||||
<color name="md_black_1000_38">#61000000</color>
|
<color name="md_black_1000_38">#61000000</color>
|
||||||
<color name="md_black_1000_12">#1F000000</color>
|
<color name="md_black_1000_12">#1F000000</color>
|
||||||
@ -71,10 +72,13 @@
|
|||||||
<color name="md_blue_A200_50">#80448AFF</color>
|
<color name="md_blue_A200_50">#80448AFF</color>
|
||||||
|
|
||||||
<color name="md_blue_A400">#2979FF</color>
|
<color name="md_blue_A400">#2979FF</color>
|
||||||
|
<color name="md_blue_A400_87">#DE2979FF</color>
|
||||||
<color name="md_blue_A400_38">#612979FF</color>
|
<color name="md_blue_A400_38">#612979FF</color>
|
||||||
|
|
||||||
<color name="md_red_500">#F44336</color>
|
<color name="md_red_500">#F44336</color>
|
||||||
|
|
||||||
|
<color name="md_red_500_87">#DEF44336</color>
|
||||||
|
|
||||||
<color name="md_teal_500">#009688</color>
|
<color name="md_teal_500">#009688</color>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -409,6 +409,12 @@
|
|||||||
<string name="category_already_in_queue">%1$s is already in queue</string>
|
<string name="category_already_in_queue">%1$s is already in queue</string>
|
||||||
<string name="local_source_badge">Local</string>
|
<string name="local_source_badge">Local</string>
|
||||||
<string name="confirm_manga_deletion">Remove from library?</string>
|
<string name="confirm_manga_deletion">Remove from library?</string>
|
||||||
|
<plurals name="unread_count">
|
||||||
|
<item quantity="one">New chapter</item>
|
||||||
|
<item quantity="other">%d Unread</item>
|
||||||
|
</plurals>
|
||||||
|
<string name="new_chapter">New</string>
|
||||||
|
<string name="start_reading">Start Reading</string>
|
||||||
|
|
||||||
<!-- Catalogue fragment -->
|
<!-- Catalogue fragment -->
|
||||||
<string name="source_search_options">Search filters</string>
|
<string name="source_search_options">Search filters</string>
|
||||||
@ -419,6 +425,7 @@
|
|||||||
<string name="action_global_search_hint">Global search…</string>
|
<string name="action_global_search_hint">Global search…</string>
|
||||||
<string name="latest">Latest</string>
|
<string name="latest">Latest</string>
|
||||||
<string name="browse">Browse</string>
|
<string name="browse">Browse</string>
|
||||||
|
<string name="in_library">In Library</string>
|
||||||
|
|
||||||
<!-- Manga activity -->
|
<!-- Manga activity -->
|
||||||
<string name="manga_not_in_db">This manga has been removed from the database.</string>
|
<string name="manga_not_in_db">This manga has been removed from the database.</string>
|
||||||
|
Loading…
Reference in New Issue
Block a user