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:
Jay 2020-02-12 22:03:28 -08:00
parent 489ef7a5f8
commit a07de130a9
24 changed files with 527 additions and 65 deletions

View File

@ -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) {

View File

@ -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

View File

@ -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<Boolean>) :
AbstractFlexibleItem<CatalogueHolder>() {
@ -23,19 +25,19 @@ class CatalogueItem(val manga: Manga, private val catalogueAsList: Preference<Bo
return if (catalogueAsList.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<IFlexible<RecyclerView.ViewHolder>>): 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)
}

View File

@ -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))
}
}
}

View File

@ -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)
}
}

View File

@ -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

View File

@ -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 {

View File

@ -25,7 +25,7 @@ import kotlinx.android.synthetic.main.catalogue_grid_item.*
*/
class LibraryGridHolder(
private val view: View,
adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>
adapter: LibraryCategoryAdapter
) : LibraryHolder(view, adapter) {

View File

@ -15,7 +15,7 @@ import eu.davidea.flexibleadapter.items.IFlexible
abstract class LibraryHolder(
view: View,
val adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>
val adapter: LibraryCategoryAdapter
) : BaseFlexibleViewHolder(view, adapter) {
/**

View File

@ -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<Boolean>) :
AbstractFlexibleItem<LibraryHolder>(), IFilterable<String> {
@ -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<IFlexible<RecyclerView.ViewHolder>>): 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<Any?>?) {
holder.onSetValues(this)
}

View File

@ -30,7 +30,7 @@ import kotlinx.android.synthetic.main.catalogue_list_item.unread_text
class LibraryListHolder(
private val view: View,
adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>
adapter: LibraryCategoryAdapter
) : LibraryHolder(view, adapter) {
/**

View File

@ -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
}
}

View File

@ -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
}

View File

@ -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<MangaInfoPresenter>(),
.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<MangaInfoPresenter>(),
.load(manga)
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.signature(ObjectKey(MangaImpl.getLastCoverFetch(manga.id!!).toString()))
.transition(DrawableTransitionOptions.withCrossFade())
.centerCrop()
.into(backdrop)
}

View File

@ -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()
}
/**

View File

@ -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

View 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>

View 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>

View File

@ -3,5 +3,5 @@
<gradient
android:angle="90"
android:endColor="@android:color/transparent"
android:startColor="?android:attr/textColorSecondary"/>
android:startColor="@color/md_black_1000_54"/>
</shape>

View 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>

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<eu.kanade.tachiyomi.widget.AutofitRecyclerView
android:id="@+id/catalogue_recycler"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
style="@style/Theme.Widget.GridView.Catalogue"
@ -7,4 +8,4 @@
android:layout_height="match_parent"
android:columnWidth="140dp"
android:clipToPadding="false"
tools:listitem="@layout/catalogue_grid_item" />
tools:listitem="@layout/catalogue_mat_grid_item" />

View File

@ -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" />
<!-- Adding bottom sheet after main content -->
<include layout="@layout/filter_bottom_sheet"/>

View File

@ -49,6 +49,7 @@
<!-- Text Colors -->
<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_38">#61000000</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_A400">#2979FF</color>
<color name="md_blue_A400_87">#DE2979FF</color>
<color name="md_blue_A400_38">#612979FF</color>
<color name="md_red_500">#F44336</color>
<color name="md_red_500_87">#DEF44336</color>
<color name="md_teal_500">#009688</color>
</resources>

View File

@ -409,6 +409,12 @@
<string name="category_already_in_queue">%1$s is already in queue</string>
<string name="local_source_badge">Local</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 -->
<string name="source_search_options">Search filters</string>
@ -419,6 +425,7 @@
<string name="action_global_search_hint">Global search…</string>
<string name="latest">Latest</string>
<string name="browse">Browse</string>
<string name="in_library">In Library</string>
<!-- Manga activity -->
<string name="manga_not_in_db">This manga has been removed from the database.</string>