Added Option to make grid fixed size, removed rx logic from recent reads

Cleanup of old filter sidebar
This commit is contained in:
Jay 2020-02-13 19:46:02 -08:00
parent a07de130a9
commit f124dbdd58
14 changed files with 71 additions and 357 deletions

View File

@ -113,6 +113,8 @@ object PreferenceKeys {
const val libraryAsList = "pref_display_library_as_list"
const val libraryGridFixed = "library_grid_fixes"
const val lang = "app_language"
const val dateFormat = "app_date_format"

View File

@ -173,6 +173,8 @@ class PreferencesHelper(val context: Context) {
fun libraryAsList() = rxPrefs.getBoolean(Keys.libraryAsList, false)
fun libraryGridFixedSize() = rxPrefs.getBoolean(Keys.libraryGridFixed, false)
fun downloadBadge() = rxPrefs.getBoolean(Keys.downloadBadge, false)
fun filterDownloaded() = rxPrefs.getInteger(Keys.filterDownloaded, 0)

View File

@ -264,10 +264,11 @@ class LibraryController(
override fun downloadStatusChanged(downloading: Boolean) {
launchUI {
val scale = if (downloading) 1f else 0f
val fab = fab ?: return@launchUI
fab.animate().scaleX(scale).scaleY(scale).setDuration(200).start()
fab.isClickable = downloading
fab.isFocusable = downloading
bottom_sheet.adjustTitleMargin(downloading)
bottom_sheet?.adjustTitleMargin(downloading)
}
}
@ -520,14 +521,6 @@ class LibraryController(
destroyActionModeIfNeeded()
} else {
mode.title = resources?.getString(R.string.label_selected, count)
menu.findItem(R.id.action_hide_title)?.isVisible =
!preferences.libraryAsList().getOrDefault()
if (!preferences.libraryAsList().getOrDefault()) {
val showAll = (selectedMangas.all { (it as? LibraryManga)?.hide_title == true })
menu.findItem(R.id.action_hide_title)?.title = activity?.getString(
if (showAll) R.string.action_show_title else R.string.action_hide_title
)
}
if (preferences.librarySortingMode().getOrDefault() == LibrarySort.DRAG_AND_DROP) {
val catId = (selectedMangas.first() as? LibraryManga)?.category
val sameCat = (adapter?.categories?.getOrNull(library_pager.currentItem)?.id
@ -570,12 +563,6 @@ class LibraryController(
.withFadeTransaction())
destroyActionModeIfNeeded()
}
R.id.action_hide_title -> {
val showAll = (selectedMangas.filter { (it as? LibraryManga)?.hide_title == true }
).size == selectedMangas.size
presenter.hideShowTitle(selectedMangas.toList(), !showAll)
destroyActionModeIfNeeded()
}
R.id.action_to_top, R.id.action_to_bottom -> {
adapter?.categories?.getOrNull(library_pager.currentItem)?.id?.let {
reorganizeRelay.call(it to if (item.itemId == R.id.action_to_top) -1 else -2)
@ -676,6 +663,7 @@ class LibraryController(
val activity = activity ?: return
val chapter = presenter.getFirstUnread(manga) ?: return
val intent = ReaderActivity.newIntent(activity, manga, chapter)
destroyActionModeIfNeeded()
observeLater = true
startActivity(intent)
}

View File

@ -2,6 +2,8 @@ package eu.kanade.tachiyomi.ui.library
import android.annotation.SuppressLint
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.recyclerview.widget.RecyclerView
import com.f2prateek.rx.preferences.Preference
import eu.davidea.flexibleadapter.FlexibleAdapter
@ -12,12 +14,12 @@ 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_mat_grid_item.view.*
import uy.kohesive.injekt.injectLazy
class LibraryItem(val manga: LibraryManga, private val libraryAsList: Preference<Boolean>) :
class LibraryItem(val manga: LibraryManga, private val libraryAsList: Preference<Boolean>,
private val fixedGrid: Preference<Boolean>) :
AbstractFlexibleItem<LibraryHolder>(), IFilterable<String> {
var downloadCount = -1
@ -33,12 +35,23 @@ class LibraryItem(val manga: LibraryManga, private val libraryAsList: Preference
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): LibraryHolder {
val parent = adapter.recyclerView
return if (parent is AutofitRecyclerView) {
val fixedSize = fixedGrid.getOrDefault()
view.apply {
val coverHeight = (parent.itemWidth / 3 * 4f).toInt()
constraint_layout.minHeight = coverHeight
val coverHeight = (parent.itemWidth / 3f * 4f).toInt()
if (fixedSize) {
constraint_layout.layoutParams = FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
cover_thumbnail.adjustViewBounds = false
cover_thumbnail.layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, coverHeight)
}
else {
constraint_layout.minHeight = coverHeight
cover_thumbnail.maxHeight = (parent.itemWidth / 3f * 6f).toInt()
}
}
LibraryMatGridHolder(view, adapter as LibraryCategoryAdapter, parent.itemWidth - 22.dpToPx, parent
.spanCount)
LibraryMatGridHolder(view, adapter as LibraryCategoryAdapter, parent.itemWidth, fixedSize)
} else {
LibraryListHolder(view, adapter as LibraryCategoryAdapter)

View File

@ -25,7 +25,7 @@ class LibraryMatGridHolder(
private val view: View,
adapter: LibraryCategoryAdapter,
var width:Int,
var rowCount: Int
var fixedSize: Boolean
) : LibraryHolder(view, adapter) {
/**
@ -58,8 +58,8 @@ class LibraryMatGridHolder(
)
)
}
play_button.visibility = if (unread > 0) View.VISIBLE else View.GONE
play_button.setOnClickListener { playButtonClicked() }
play_layout.visibility = if (unread > 0) View.VISIBLE else View.GONE
play_layout.setOnClickListener { playButtonClicked() }
// Update the download count and its visibility.
with(download_text) {
@ -73,10 +73,11 @@ class LibraryMatGridHolder(
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)
var glide = GlideApp.with(view.context).load(item.manga)
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.signature(ObjectKey(MangaImpl.getLastCoverFetch(id).toString()))
.into(cover_thumbnail)
glide = if (fixedSize) glide.centerCrop() else glide.override(width)
glide.into(cover_thumbnail)
}
}

View File

@ -1,277 +0,0 @@
package eu.kanade.tachiyomi.ui.library
import android.content.Context
import android.util.AttributeSet
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.widget.ExtendedNavigationView
import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.MultiSort.Companion.SORT_ASC
import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.MultiSort.Companion.SORT_DESC
import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.MultiSort.Companion.SORT_NONE
import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.Companion.STATE_EXCLUDE
import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.Companion.STATE_IGNORE
import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.Companion.STATE_INCLUDE
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy
import kotlin.math.min
/**
* The navigation view shown in a drawer with the different options to show the library.
*/
class LibraryNavigationView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null)
: ExtendedNavigationView(context, attrs) {
/**
* Preferences helper.
*/
private val preferences: PreferencesHelper by injectLazy()
/**
* List of groups shown in the view.
*/
private val groups = listOf(FilterGroup(), SortGroup(), DisplayGroup(), BadgeGroup())
/**
* Adapter instance.
*/
private val adapter = Adapter(groups.map { it.createItems() }.flatten())
/**
* Click listener to notify the parent fragment when an item from a group is clicked.
*/
var onGroupClicked: (Group, Item) -> Unit = { _, _ -> }
init {
recycler.adapter = adapter
addView(recycler)
groups.forEach { it.initModels() }
}
/**
* Returns true if there's at least one filter from [FilterGroup] active.
*/
fun hasActiveFilters(): Boolean {
return (groups[0] as FilterGroup).items.any {
when (it) {
is Item.TriStateGroup ->
if (it.resTitle == R.string.categories) it.state == STATE_IGNORE
else it.state != STATE_IGNORE
is Item.CheckboxGroup -> it.checked
else -> false
}
}
}
/**
* Adapter of the recycler view.
*/
inner class Adapter(items: List<Item>) : ExtendedNavigationView.Adapter(items) {
override fun onItemClicked(item: Item) {
if (item is GroupedItem) {
item.group.onItemClicked(item)
onGroupClicked(item.group, item)
}
}
}
/**
* Filters group (unread, downloaded, ...).
*/
inner class FilterGroup : Group {
private val downloaded = Item.TriStateGroup(R.string.action_filter_downloaded, this)
private val unread = Item.TriStateGroup(R.string.action_filter_unread, this)
private val completed = Item.TriStateGroup(R.string.completed, this)
private val tracked = Item.TriStateGroup(R.string.action_filter_tracked, this)
private val categories = Item.TriStateGroup(R.string.action_hide_categories, this)
override val items:List<Item> = {
val list = mutableListOf<Item>()
if (Injekt.get<DatabaseHelper>().getCategories().executeAsBlocking().isNotEmpty())
list.add(categories)
list.add(downloaded)
list.add(unread)
list.add(completed)
if (Injekt.get<TrackManager>().hasLoggedServices())
list.add(tracked)
list
}()
override val header = Item.Header(R.string.action_filter)
override val footer = Item.Separator()
override fun initModels() {
try {
categories.state =
if (preferences.hideCategories().getOrDefault()) STATE_INCLUDE
else STATE_IGNORE
downloaded.state = min(2, preferences.filterDownloaded().getOrDefault())
unread.state = min(2, preferences.filterUnread().getOrDefault())
completed.state = min(2, preferences.filterCompleted().getOrDefault())
tracked.state = min(2, preferences.filterTracked().getOrDefault())
}
catch (e: Exception) {
preferences.upgradeFilters()
}
}
override fun onItemClicked(item: Item) {
if (item == categories) {
item as Item.TriStateGroup
val newState = when (item.state) {
STATE_IGNORE -> STATE_INCLUDE
else -> STATE_IGNORE
}
item.state = newState
when (item) {
categories -> preferences.hideCategories().set(item.state == STATE_INCLUDE)
}
}
else if (item is Item.TriStateGroup) {
val newState = when (item.state) {
STATE_IGNORE -> STATE_INCLUDE
STATE_INCLUDE -> STATE_EXCLUDE
else -> STATE_IGNORE
}
item.state = newState
when (item) {
downloaded -> preferences.filterDownloaded().set(item.state)
unread -> preferences.filterUnread().set(item.state)
completed -> preferences.filterCompleted().set(item.state)
tracked -> preferences.filterTracked().set(item.state)
}
}
adapter.notifyItemChanged(item)
}
}
/**
* Sorting group (alphabetically, by last read, ...) and ascending or descending.
*/
inner class SortGroup : Group {
private val alphabetically = Item.MultiSort(R.string.action_sort_alpha, this)
private val total = Item.MultiSort(R.string.action_sort_total, this)
private val lastRead = Item.MultiSort(R.string.action_sort_last_read, this)
private val lastUpdated = Item.MultiSort(R.string.action_sort_last_updated, this)
private val unread = Item.MultiSort(R.string.action_filter_unread, this)
private val dragAndDrop = Item.MultiSort(R.string.action_sort_drag_and_drop, this)
override val items = listOf(alphabetically, lastRead, lastUpdated, unread, total,
dragAndDrop)
override val header = Item.Header(R.string.action_sort)
override val footer = Item.Separator()
override fun initModels() {
val sorting = preferences.librarySortingMode().getOrDefault()
val order = if (preferences.librarySortingAscending().getOrDefault())
SORT_ASC else SORT_DESC
alphabetically.state = if (sorting == LibrarySort.ALPHA) order else SORT_NONE
lastRead.state = if (sorting == LibrarySort.LAST_READ) order else SORT_NONE
lastUpdated.state = if (sorting == LibrarySort.LAST_UPDATED) order else SORT_NONE
unread.state = if (sorting == LibrarySort.UNREAD) order else SORT_NONE
total.state = if (sorting == LibrarySort.TOTAL) order else SORT_NONE
dragAndDrop.state = if (sorting == LibrarySort.DRAG_AND_DROP) order else SORT_NONE
}
override fun onItemClicked(item: Item) {
item as Item.MultiStateGroup
val prevState = item.state
item.group.items.forEach { (it as Item.MultiStateGroup).state = SORT_NONE }
if (item == dragAndDrop)
item.state = SORT_ASC
else
item.state = when (prevState) {
SORT_NONE -> SORT_ASC
SORT_ASC -> SORT_DESC
SORT_DESC -> SORT_ASC
else -> throw Exception("Unknown state")
}
preferences.librarySortingMode().set(when (item) {
alphabetically -> LibrarySort.ALPHA
lastRead -> LibrarySort.LAST_READ
lastUpdated -> LibrarySort.LAST_UPDATED
unread -> LibrarySort.UNREAD
total -> LibrarySort.TOTAL
dragAndDrop -> LibrarySort.DRAG_AND_DROP
else -> LibrarySort.ALPHA
})
preferences.librarySortingAscending().set(item.state == SORT_ASC)
item.group.items.forEach { adapter.notifyItemChanged(it) }
}
}
inner class BadgeGroup : Group {
private val downloadBadge = Item.CheckboxGroup(R.string.action_display_download_badge, this)
override val header = null
override val footer = null
override val items = listOf(downloadBadge)
override fun initModels() {
downloadBadge.checked = preferences.downloadBadge().getOrDefault()
}
override fun onItemClicked(item: Item) {
item as Item.CheckboxGroup
item.checked = !item.checked
preferences.downloadBadge().set((item.checked))
adapter.notifyItemChanged(item)
}
}
/**
* Display group, to show the library as a list or a grid.
*/
inner class DisplayGroup : Group {
private val grid = Item.Radio(R.string.action_display_grid, this)
private val list = Item.Radio(R.string.action_display_list, this)
override val items = listOf(grid, list)
override val header = Item.Header(R.string.action_display)
override val footer = null
override fun initModels() {
val asList = preferences.libraryAsList().getOrDefault()
grid.checked = !asList
list.checked = asList
}
override fun onItemClicked(item: Item) {
item as Item.Radio
if (item.checked) return
item.group.items.forEach { (it as Item.Radio).checked = false }
item.checked = true
preferences.libraryAsList().set(item == list)
item.group.items.forEach { adapter.notifyItemChanged(it) }
}
}
}

View File

@ -420,13 +420,14 @@ class LibraryPresenter(
private fun getLibraryFromDB(): Library {
val categories = db.getCategories().executeAsBlocking().toMutableList()
val libraryAsList = preferences.libraryAsList()
val fixedGrid = preferences.libraryGridFixedSize()
val showCategories = !preferences.hideCategories().getOrDefault()
val unreadBadgeType = preferences.unreadBadgeType().getOrDefault()
var libraryManga = db.getLibraryMangas().executeAsBlocking()
if (!showCategories)
libraryManga = libraryManga.distinctBy { it.id }
val libraryMap = libraryManga.map { manga ->
LibraryItem(manga, libraryAsList).apply { unreadType = unreadBadgeType }
LibraryItem(manga, libraryAsList, fixedGrid).apply { unreadType = unreadBadgeType }
}.groupBy {
if (showCategories) it.manga.category else 0
}

View File

@ -101,7 +101,11 @@ class RecentlyReadController(bundle: Bundle? = null) : BaseController(bundle),
override fun onActivityResumed(activity: Activity) {
super.onActivityResumed(activity)
if (observeLater) {
presenter.observe()
launchUI {
val manga = presenter.refresh(query)
recentItems = manga.toMutableList()
adapter?.updateDataSet(manga)
}
observeLater = false
}
}

View File

@ -1,19 +1,12 @@
package eu.kanade.tachiyomi.ui.recently_read
import android.os.Bundle
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.History
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
import eu.kanade.tachiyomi.util.system.launchUI
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okhttp3.Dispatcher
import rx.Observable
import rx.Subscription
import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers
import uy.kohesive.injekt.injectLazy
import java.util.Calendar
import java.util.Comparator
@ -30,7 +23,6 @@ class RecentlyReadPresenter(private val view: RecentlyReadController) {
* Used to connect to database
*/
val db: DatabaseHelper by injectLazy()
private var readerSubscription:Subscription? = null
var lastCount = 25
var lastSearch = ""
@ -54,19 +46,6 @@ class RecentlyReadPresenter(private val view: RecentlyReadController) {
.map(::RecentlyReadItem)
}
fun observe() {
readerSubscription?.unsubscribe()
val cal = Calendar.getInstance()
cal.time = Date()
cal.add(Calendar.YEAR, -50)
readerSubscription = db.getRecentMangaLimit(cal.time, lastCount, "").asRxObservable().map {
val items = it.map(::RecentlyReadItem)
launchUI {
view.onNextManga(items)
}
}.observeOn(Schedulers.io()).skip(1).take(1).subscribe()
}
/**
* Reset last read of chapter to 0L
* @param history history belonging to chapter

View File

@ -58,6 +58,13 @@ class SettingsLibraryController : SettingsController() {
summaryRes = R.string.pref_remove_articles_summary
defaultValue = false
}
switchPreference {
key = Keys.libraryGridFixed
titleRes = R.string.pref_fixed_grid
summaryRes = R.string.pref_fixed_grid_summary
defaultValue = false
}
}
val dbCategories = db.getCategories().executeAsBlocking()

View File

@ -108,29 +108,39 @@
android:paddingTop="10dp"
android:paddingEnd="5dp"
android:paddingBottom="3dp"
android:text="@string/in_library"
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"
<FrameLayout
android:id="@+id/play_layout"
android:layout_width="50dp"
android:layout_height="50dp"
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:clickable="true"
android:focusable="true"
android:visibility="gone"
tools:visibility="visible" />
tools:visibility="visible">
<ImageView
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:padding="3dp"
android:background="@drawable/round_play_background"
android:contentDescription="@string/start_reading"
android:src="@drawable/ic_play_arrow_white_24dp"
android:tint="@android:color/white" />
</FrameLayout>
<ProgressBar
android:id="@+id/progress"

View File

@ -1,14 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<eu.kanade.tachiyomi.ui.library.LibraryNavigationView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="end"
android:fitsSystemWindows="true"
android:clipToPadding="true">
<View
android:id="@+id/status_bar_scrim"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="?attr/colorPrimary" />
</eu.kanade.tachiyomi.ui.library.LibraryNavigationView>

View File

@ -40,9 +40,4 @@
</menu>
</item>
<item
android:id="@+id/action_hide_title"
android:title="@string/action_hide_title"
app:showAsAction="never" />
</menu>

View File

@ -196,6 +196,9 @@
<string name="pref_update_only_non_completed">Only update ongoing manga</string>
<string name="pref_auto_update_manga_sync">Sync chapters after reading</string>
<string name="pref_remove_articles">Sort by ignoring articles</string>
<string name="pref_fixed_grid">Fixed grid size in library</string>
<string name="pref_fixed_grid_summary">Show all covers as the same height by cropping (improves
fast scrolling performance)</string>
<string name="pref_remove_articles_summary">When sorting alphabetically, sort ignoring
articles (a, an, the) at the start of manga titles</string>
<string name="pref_skip_pre_migration">Skip pre-migration</string>