Recents Options

*Show Downloads on all, unread, or none of the items
*Show manga title first
*Show/Hide Reset History Button
*Show read chapters in Grouped/All
This commit is contained in:
Jays2Kings 2021-04-06 21:36:30 -04:00
parent 3492117cb1
commit 0545780ae9
15 changed files with 337 additions and 69 deletions

View File

@ -32,24 +32,34 @@ interface ChapterQueries : DbProvider {
) )
.prepare() .prepare()
fun getRecentChapters(date: Date) = db.get() fun getRecentChapters(date: Date) = getRecentChapters(Date(), date)
fun getRecentChapters(startDate: Date, date: Date) = db.get()
.listOfObjects(MangaChapter::class.java) .listOfObjects(MangaChapter::class.java)
.withQuery( .withQuery(
RawQuery.builder() RawQuery.builder()
.query(getRecentsQuery()) .query(getRecentsQuery())
.args(date.time) .args(date.time, startDate.time)
.observesTables(ChapterTable.TABLE) .observesTables(ChapterTable.TABLE)
.build() .build()
) )
.withGetResolver(MangaChapterGetResolver.INSTANCE) .withGetResolver(MangaChapterGetResolver.INSTANCE)
.prepare() .prepare()
fun getUpdatedManga(date: Date, search: String = "", endless: Boolean) = db.get() /**
* Returns history of recent manga containing last read chapter in 25s
* @param date recent date range
* @offset offset the db by
*/
fun getUpdatedManga(date: Date, search: String = "", endless: Boolean) =
getUpdatedManga(Date(), date, search, endless)
fun getUpdatedManga(startDate: Date, date: Date, search: String = "", endless: Boolean) = db.get()
.listOfObjects(MangaChapterHistory::class.java) .listOfObjects(MangaChapterHistory::class.java)
.withQuery( .withQuery(
RawQuery.builder() RawQuery.builder()
.query(getRecentsQueryDistinct(search.sqLite, endless)) .query(getRecentsQueryDistinct(search.sqLite, endless))
.args(date.time) .args(date.time, startDate.time)
.observesTables(ChapterTable.TABLE) .observesTables(ChapterTable.TABLE)
.build() .build()
) )

View File

@ -42,12 +42,12 @@ interface HistoryQueries : DbProvider {
* @param date recent date range * @param date recent date range
* @offset offset the db by * @offset offset the db by
*/ */
fun getRecentlyAdded(date: Date, search: String = "", endless: Boolean) = db.get() fun getRecentlyAdded(startDate: Date, date: Date, search: String = "", endless: Boolean) = db.get()
.listOfObjects(MangaChapterHistory::class.java) .listOfObjects(MangaChapterHistory::class.java)
.withQuery( .withQuery(
RawQuery.builder() RawQuery.builder()
.query(getRecentAdditionsQuery(search.sqLite, endless)) .query(getRecentAdditionsQuery(search.sqLite, endless))
.args(date.time) .args(date.time, startDate.time)
.observesTables(MangaTable.TABLE) .observesTables(MangaTable.TABLE)
.build() .build()
) )
@ -59,12 +59,20 @@ interface HistoryQueries : DbProvider {
* @param date recent date range * @param date recent date range
* @offset offset the db by * @offset offset the db by
*/ */
fun getRecentMangaLimit(date: Date, limit: Int = 0, search: String = "") = db.get() fun getRecentMangaLimit(date: Date, limit: Int = 0, search: String = "") =
getRecentMangaLimit(Date(), date, limit, search)
/**
* Returns history of recent manga containing last read chapter in 25s
* @param date recent date range
* @offset offset the db by
*/
fun getRecentMangaLimit(startDate: Date, date: Date, limit: Int = 0, search: String = "") = db.get()
.listOfObjects(MangaChapterHistory::class.java) .listOfObjects(MangaChapterHistory::class.java)
.withQuery( .withQuery(
RawQuery.builder() RawQuery.builder()
.query(getRecentMangasLimitQuery(limit, search.sqLite)) .query(getRecentMangasLimitQuery(limit, search.sqLite))
.args(date.time) .args(date.time, startDate.time)
.observesTables(HistoryTable.TABLE) .observesTables(HistoryTable.TABLE)
.build() .build()
) )
@ -76,12 +84,29 @@ interface HistoryQueries : DbProvider {
* @param date recent date range * @param date recent date range
* @offset offset the db by * @offset offset the db by
*/ */
fun getRecentsWithUnread(date: Date, search: String = "", endless: Boolean) = db.get() fun getRecentsWithUnread(startDate: Date, date: Date, search: String = "", endless: Boolean) = db.get()
.listOfObjects(MangaChapterHistory::class.java) .listOfObjects(MangaChapterHistory::class.java)
.withQuery( .withQuery(
RawQuery.builder() RawQuery.builder()
.query(getRecentReadWithUnreadChapters(search.sqLite, endless)) .query(getRecentReadWithUnreadChapters(search.sqLite, endless))
.args(date.time) .args(date.time, startDate.time)
.observesTables(HistoryTable.TABLE)
.build()
)
.withGetResolver(MangaChapterHistoryGetResolver.INSTANCE)
.prepare()
/**
* Returns history of recent manga containing last read chapter in 25s
* @param date recent date range
* @offset offset the db by
*/
fun getAllRecents(startDate: Date, date: Date, search: String = "", endless: Boolean) = db.get()
.listOfObjects(MangaChapterHistory::class.java)
.withQuery(
RawQuery.builder()
.query(getRecentRead(search.sqLite, endless))
.args(date.time, startDate.time)
.observesTables(HistoryTable.TABLE) .observesTables(HistoryTable.TABLE)
.build() .build()
) )

View File

@ -47,6 +47,7 @@ fun getRecentsQuery() =
ON ${Manga.TABLE}.${Manga.COL_ID} = ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} ON ${Manga.TABLE}.${Manga.COL_ID} = ${Chapter.TABLE}.${Chapter.COL_MANGA_ID}
WHERE ${Manga.COL_FAVORITE} = 1 WHERE ${Manga.COL_FAVORITE} = 1
AND ${Chapter.COL_DATE_UPLOAD} > ? AND ${Chapter.COL_DATE_UPLOAD} > ?
AND ${Chapter.COL_DATE_UPLOAD} < ?
AND ${Chapter.COL_DATE_FETCH} > ${Manga.COL_DATE_ADDED} AND ${Chapter.COL_DATE_FETCH} > ${Manga.COL_DATE_ADDED}
ORDER BY ${Chapter.COL_DATE_UPLOAD} DESC ORDER BY ${Chapter.COL_DATE_UPLOAD} DESC
""" """
@ -59,6 +60,7 @@ fun getRecentAdditionsQuery(search: String, endless: Boolean) =
SELECT ${Manga.TABLE}.${Manga.COL_URL} as mangaUrl, * FROM ${Manga.TABLE} SELECT ${Manga.TABLE}.${Manga.COL_URL} as mangaUrl, * FROM ${Manga.TABLE}
WHERE ${Manga.COL_FAVORITE} = 1 WHERE ${Manga.COL_FAVORITE} = 1
AND ${Manga.COL_DATE_ADDED} > ? AND ${Manga.COL_DATE_ADDED} > ?
AND ${Manga.COL_DATE_ADDED} < ?
AND lower(${Manga.COL_TITLE}) LIKE '%$search%' AND lower(${Manga.COL_TITLE}) LIKE '%$search%'
ORDER BY ${Manga.COL_DATE_ADDED} DESC ORDER BY ${Manga.COL_DATE_ADDED} DESC
${if (endless) "" else "LIMIT 8"} ${if (endless) "" else "LIMIT 8"}
@ -78,6 +80,7 @@ fun getRecentsQueryDistinct(search: String, endless: Boolean) =
FROM ${Chapter.TABLE} JOIN ${Manga.TABLE} FROM ${Chapter.TABLE} JOIN ${Manga.TABLE}
ON ${Manga.TABLE}.${Manga.COL_ID} = ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} ON ${Manga.TABLE}.${Manga.COL_ID} = ${Chapter.TABLE}.${Chapter.COL_MANGA_ID}
WHERE ${Chapter.COL_DATE_UPLOAD} > ? WHERE ${Chapter.COL_DATE_UPLOAD} > ?
AND ${Chapter.COL_DATE_UPLOAD} < ?
AND ${Chapter.COL_READ} = 0 AND ${Chapter.COL_READ} = 0
GROUP BY ${Chapter.TABLE}.${Chapter.COL_MANGA_ID}) AS newest_chapter GROUP BY ${Chapter.TABLE}.${Chapter.COL_MANGA_ID}) AS newest_chapter
ON ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} = newest_chapter.${Chapter.COL_MANGA_ID} ON ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} = newest_chapter.${Chapter.COL_MANGA_ID}
@ -138,6 +141,7 @@ fun getRecentMangasLimitQuery(limit: Int = 25, search: String = "") =
GROUP BY ${Chapter.TABLE}.${Chapter.COL_MANGA_ID}) AS max_last_read GROUP BY ${Chapter.TABLE}.${Chapter.COL_MANGA_ID}) AS max_last_read
ON ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} = max_last_read.${Chapter.COL_MANGA_ID} ON ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} = max_last_read.${Chapter.COL_MANGA_ID}
WHERE ${History.TABLE}.${History.COL_LAST_READ} > ? WHERE ${History.TABLE}.${History.COL_LAST_READ} > ?
AND ${History.TABLE}.${History.COL_LAST_READ} < ?
AND max_last_read.${History.COL_CHAPTER_ID} = ${History.TABLE}.${History.COL_CHAPTER_ID} AND max_last_read.${History.COL_CHAPTER_ID} = ${History.TABLE}.${History.COL_CHAPTER_ID}
AND lower(${Manga.TABLE}.${Manga.COL_TITLE}) LIKE '%$search%' AND lower(${Manga.TABLE}.${Manga.COL_TITLE}) LIKE '%$search%'
ORDER BY max_last_read.${History.COL_LAST_READ} DESC ORDER BY max_last_read.${History.COL_LAST_READ} DESC
@ -179,6 +183,48 @@ fun getRecentReadWithUnreadChapters(search: String = "", endless: Boolean) =
GROUP BY ${Chapter.TABLE}.${Chapter.COL_MANGA_ID}) AS max_last_read GROUP BY ${Chapter.TABLE}.${Chapter.COL_MANGA_ID}) AS max_last_read
ON ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} = max_last_read.${Chapter.COL_MANGA_ID} ON ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} = max_last_read.${Chapter.COL_MANGA_ID}
WHERE ${History.TABLE}.${History.COL_LAST_READ} > ? WHERE ${History.TABLE}.${History.COL_LAST_READ} > ?
AND ${History.TABLE}.${History.COL_LAST_READ} < ?
AND max_last_read.${History.COL_CHAPTER_ID} = ${History.TABLE}.${History.COL_CHAPTER_ID}
AND lower(${Manga.TABLE}.${Manga.COL_TITLE}) LIKE '%$search%'
ORDER BY max_last_read.${History.COL_LAST_READ} DESC
${if (endless) "" else "LIMIT 8"}
"""
/**
* Query to get the recently read manga that has more chapters to read
* The first from checks that there's an unread chapter
* The max_last_read table contains the most recent chapters grouped by manga
* The select statement returns all information of chapters that have the same id as the chapter in max_last_read
* and are read after the given time period
*/
fun getRecentRead(search: String = "", endless: Boolean) =
"""
SELECT ${Manga.TABLE}.${Manga.COL_URL} as mangaUrl, ${Manga.TABLE}.*, ${Chapter.TABLE}.*, ${History.TABLE}.*
FROM (
SELECT ${Manga.TABLE}.*
FROM ${Manga.TABLE}
LEFT JOIN (
SELECT ${Chapter.COL_MANGA_ID}, COUNT(*) AS unread
FROM ${Chapter.TABLE}
GROUP BY ${Chapter.COL_MANGA_ID}
) AS C
ON ${Manga.COL_ID} = C.${Chapter.COL_MANGA_ID}
WHERE C.unread > 0
GROUP BY ${Manga.COL_ID}
ORDER BY ${Manga.COL_TITLE}
) AS ${Manga.TABLE}
JOIN ${Chapter.TABLE}
ON ${Manga.TABLE}.${Manga.COL_ID} = ${Chapter.TABLE}.${Chapter.COL_MANGA_ID}
JOIN ${History.TABLE}
ON ${Chapter.TABLE}.${Chapter.COL_ID} = ${History.TABLE}.${History.COL_CHAPTER_ID}
JOIN (
SELECT ${Chapter.TABLE}.${Chapter.COL_MANGA_ID},${Chapter.TABLE}.${Chapter.COL_ID} as ${History.COL_CHAPTER_ID}, MAX(${History.TABLE}.${History.COL_LAST_READ}) as ${History.COL_LAST_READ}
FROM ${Chapter.TABLE} JOIN ${History.TABLE}
ON ${Chapter.TABLE}.${Chapter.COL_ID} = ${History.TABLE}.${History.COL_CHAPTER_ID}
GROUP BY ${Chapter.TABLE}.${Chapter.COL_MANGA_ID}) AS max_last_read
ON ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} = max_last_read.${Chapter.COL_MANGA_ID}
WHERE ${History.TABLE}.${History.COL_LAST_READ} > ?
AND ${History.TABLE}.${History.COL_LAST_READ} < ?
AND max_last_read.${History.COL_CHAPTER_ID} = ${History.TABLE}.${History.COL_CHAPTER_ID} AND max_last_read.${History.COL_CHAPTER_ID} = ${History.TABLE}.${History.COL_CHAPTER_ID}
AND lower(${Manga.TABLE}.${Manga.COL_TITLE}) LIKE '%$search%' AND lower(${Manga.TABLE}.${Manga.COL_TITLE}) LIKE '%$search%'
ORDER BY max_last_read.${History.COL_LAST_READ} DESC ORDER BY max_last_read.${History.COL_LAST_READ} DESC

View File

@ -170,6 +170,11 @@ object PreferenceKeys {
const val updateOnRefresh = "update_on_refresh" const val updateOnRefresh = "update_on_refresh"
const val showDLsInRecents = "show_dls_in_recents"
const val showRemHistoryInRecents = "show_rem_history_in_recents"
const val showReadInAllRecents = "show_read_in_all_recents"
const val showTitleFirstInRecents = "show_title_first_in_recents"
const val showLibraryUpdateErrors = "show_library_update_errors" const val showLibraryUpdateErrors = "show_library_update_errors"
const val alwaysShowChapterTransition = "always_show_chapter_transition" const val alwaysShowChapterTransition = "always_show_chapter_transition"

View File

@ -12,6 +12,7 @@ import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.track.TrackService import eu.kanade.tachiyomi.data.track.TrackService
import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation
import eu.kanade.tachiyomi.ui.reader.viewer.pager.PageLayout import eu.kanade.tachiyomi.ui.reader.viewer.pager.PageLayout
import eu.kanade.tachiyomi.ui.recents.RecentMangaAdapter
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import java.io.File import java.io.File
@ -285,6 +286,14 @@ class PreferencesHelper(val context: Context) {
fun recentsViewType() = flowPrefs.getInt("recents_view_type", 0) fun recentsViewType() = flowPrefs.getInt("recents_view_type", 0)
fun showRecentsDownloads() = flowPrefs.getEnum(Keys.showDLsInRecents, RecentMangaAdapter.ShowRecentsDLs.All)
fun showRecentsRemHistory() = flowPrefs.getBoolean(Keys.showRemHistoryInRecents, true)
fun showReadInAllRecents() = flowPrefs.getBoolean(Keys.showReadInAllRecents, false)
fun showTitleFirstInRecents() = flowPrefs.getBoolean(Keys.showTitleFirstInRecents, false)
fun lastExtCheck() = rxPrefs.getLong("last_ext_check", 0) fun lastExtCheck() = rxPrefs.getLong("last_ext_check", 0)
fun lastAppCheck() = flowPrefs.getLong("last_app_check", 0) fun lastAppCheck() = flowPrefs.getLong("last_app_check", 0)

View File

@ -2,16 +2,23 @@ package eu.kanade.tachiyomi.ui.recents
import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.ItemTouchHelper
import eu.davidea.flexibleadapter.items.IFlexible import eu.davidea.flexibleadapter.items.IFlexible
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.ui.manga.chapter.BaseChapterAdapter import eu.kanade.tachiyomi.ui.manga.chapter.BaseChapterAdapter
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import uy.kohesive.injekt.injectLazy
import java.text.DecimalFormat import java.text.DecimalFormat
import java.text.DecimalFormatSymbols import java.text.DecimalFormatSymbols
class RecentMangaAdapter(val delegate: RecentsInterface) : class RecentMangaAdapter(val delegate: RecentsInterface) :
BaseChapterAdapter<IFlexible<*>>(delegate) { BaseChapterAdapter<IFlexible<*>>(delegate) {
init { private val preferences: PreferencesHelper by injectLazy()
setDisplayHeadersAtStartUp(true)
} var showDownloads = ShowRecentsDLs.All
var showRemoveHistory = true
var showTitleFirst = false
fun updateItems(items: List<IFlexible<*>>?) { fun updateItems(items: List<IFlexible<*>>?) {
updateDataSet(items) updateDataSet(items)
@ -23,6 +30,31 @@ class RecentMangaAdapter(val delegate: RecentsInterface) :
.apply { decimalSeparator = '.' } .apply { decimalSeparator = '.' }
) )
init {
setDisplayHeadersAtStartUp(true)
preferences.showRecentsDownloads()
.asFlow()
.onEach {
showDownloads = it
notifyDataSetChanged()
}
.launchIn(delegate.scope())
preferences.showRecentsRemHistory()
.asFlow()
.onEach {
showRemoveHistory = it
notifyDataSetChanged()
}
.launchIn(delegate.scope())
preferences.showTitleFirstInRecents()
.asFlow()
.onEach {
showTitleFirst = it
notifyDataSetChanged()
}
.launchIn(delegate.scope())
}
interface RecentsInterface : RecentMangaInterface, DownloadInterface interface RecentsInterface : RecentMangaInterface, DownloadInterface
interface RecentMangaInterface { interface RecentMangaInterface {
@ -32,6 +64,7 @@ class RecentMangaAdapter(val delegate: RecentsInterface) :
fun isSearching(): Boolean fun isSearching(): Boolean
fun setViewType(viewType: Int) fun setViewType(viewType: Int)
fun getViewType(): Int fun getViewType(): Int
fun scope(): CoroutineScope
} }
override fun onItemSwiped(position: Int, direction: Int) { override fun onItemSwiped(position: Int, direction: Int) {
@ -40,4 +73,10 @@ class RecentMangaAdapter(val delegate: RecentsInterface) :
ItemTouchHelper.LEFT -> delegate.markAsRead(position) ItemTouchHelper.LEFT -> delegate.markAsRead(position)
} }
} }
enum class ShowRecentsDLs {
None,
OnlyUnread,
All,
}
} }

View File

@ -4,14 +4,13 @@ import android.app.Activity
import android.view.View import android.view.View
import androidx.core.view.isVisible import androidx.core.view.isVisible
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.image.coil.loadLibraryManga
import eu.kanade.tachiyomi.data.download.model.Download import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.data.image.coil.loadLibraryManga
import eu.kanade.tachiyomi.databinding.RecentMangaItemBinding import eu.kanade.tachiyomi.databinding.RecentMangaItemBinding
import eu.kanade.tachiyomi.source.LocalSource import eu.kanade.tachiyomi.source.LocalSource
import eu.kanade.tachiyomi.ui.manga.chapter.BaseChapterHolder import eu.kanade.tachiyomi.ui.manga.chapter.BaseChapterHolder
import eu.kanade.tachiyomi.util.chapter.ChapterUtil import eu.kanade.tachiyomi.util.chapter.ChapterUtil
import eu.kanade.tachiyomi.util.system.timeSpanFromNow import eu.kanade.tachiyomi.util.system.timeSpanFromNow
import eu.kanade.tachiyomi.util.view.visibleIf
class RecentMangaHolder( class RecentMangaHolder(
view: View, view: View,
@ -25,16 +24,28 @@ class RecentMangaHolder(
binding.removeHistory.setOnClickListener { adapter.delegate.onRemoveHistoryClicked(flexibleAdapterPosition) } binding.removeHistory.setOnClickListener { adapter.delegate.onRemoveHistoryClicked(flexibleAdapterPosition) }
} }
fun bind(item: RecentMangaItem) { fun bind(item: RecentMangaItem, showDLs: RecentMangaAdapter.ShowRecentsDLs, showRemoveHistory: Boolean, showTitleFirst: Boolean) {
binding.downloadButton.downloadButton.visibleIf(item.mch.manga.source != LocalSource.ID) binding.downloadButton.downloadButton.isVisible = item.mch.manga.source != LocalSource.ID && when (showDLs) {
RecentMangaAdapter.ShowRecentsDLs.None -> false
RecentMangaAdapter.ShowRecentsDLs.OnlyUnread -> !item.mch.chapter.read
RecentMangaAdapter.ShowRecentsDLs.All -> true
}
binding.removeHistory.isVisible = item.mch.history.id != null binding.removeHistory.isVisible = item.mch.history.id != null && showRemoveHistory
binding.title.apply { binding.title.apply {
text = item.chapter.name text = if (!showTitleFirst) {
item.chapter.name
} else {
item.mch.manga.title
}
ChapterUtil.setTextViewForChapter(this, item) ChapterUtil.setTextViewForChapter(this, item)
} }
binding.subtitle.apply { binding.subtitle.apply {
text = item.mch.manga.title text = if (!showTitleFirst) {
item.mch.manga.title
} else {
item.chapter.name
}
setTextColor(ChapterUtil.readColor(context, item)) setTextColor(ChapterUtil.readColor(context, item))
} }
val notValidNum = item.mch.chapter.chapter_number <= 0 val notValidNum = item.mch.chapter.chapter_number <= 0

View File

@ -57,7 +57,10 @@ class RecentMangaItem(
position: Int, position: Int,
payloads: MutableList<Any?>? payloads: MutableList<Any?>?
) { ) {
val showDLs = (adapter as? RecentMangaAdapter)?.showDownloads ?: RecentMangaAdapter.ShowRecentsDLs.All
val showRemoveHistory = (adapter as? RecentMangaAdapter)?.showRemoveHistory ?: true
val showTitleFirst = (adapter as? RecentMangaAdapter)?.showTitleFirst ?: false
if (mch.manga.id == null) (holder as? RecentMangaFooterHolder)?.bind((header as? RecentMangaHeaderItem)?.recentsType ?: 0) if (mch.manga.id == null) (holder as? RecentMangaFooterHolder)?.bind((header as? RecentMangaHeaderItem)?.recentsType ?: 0)
else (holder as? RecentMangaHolder)?.bind(this) else (holder as? RecentMangaHolder)?.bind(this, showDLs, showRemoveHistory, showTitleFirst)
} }
} }

View File

@ -9,7 +9,6 @@ import android.view.MenuInflater
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.Toast
import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SearchView
import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
@ -38,7 +37,6 @@ import eu.kanade.tachiyomi.ui.recently_read.RemoveHistoryDialog
import eu.kanade.tachiyomi.ui.source.browse.ProgressItem import eu.kanade.tachiyomi.ui.source.browse.ProgressItem
import eu.kanade.tachiyomi.util.system.dpToPx import eu.kanade.tachiyomi.util.system.dpToPx
import eu.kanade.tachiyomi.util.system.spToPx import eu.kanade.tachiyomi.util.system.spToPx
import eu.kanade.tachiyomi.util.system.toast
import eu.kanade.tachiyomi.util.view.activityBinding import eu.kanade.tachiyomi.util.view.activityBinding
import eu.kanade.tachiyomi.util.view.expand import eu.kanade.tachiyomi.util.view.expand
import eu.kanade.tachiyomi.util.view.isExpanded import eu.kanade.tachiyomi.util.view.isExpanded
@ -50,6 +48,10 @@ import eu.kanade.tachiyomi.util.view.snack
import eu.kanade.tachiyomi.util.view.updateLayoutParams import eu.kanade.tachiyomi.util.view.updateLayoutParams
import eu.kanade.tachiyomi.util.view.updatePaddingRelative import eu.kanade.tachiyomi.util.view.updatePaddingRelative
import eu.kanade.tachiyomi.util.view.withFadeTransaction import eu.kanade.tachiyomi.util.view.withFadeTransaction
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancel
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.max import kotlin.math.max
@ -78,6 +80,8 @@ class RecentsController(bundle: Bundle? = null) :
presenter.toggleGroupRecents(viewType, false) presenter.toggleGroupRecents(viewType, false)
} }
private val adapterScope: CoroutineScope = CoroutineScope(Job() + Dispatchers.Main)
/** /**
* Adapter containing the recent manga. * Adapter containing the recent manga.
*/ */
@ -290,6 +294,8 @@ class RecentsController(bundle: Bundle? = null) :
snack?.dismiss() snack?.dismiss()
presenter.onDestroy() presenter.onDestroy()
snack = null snack = null
adapterScope.cancel()
presenter.cancelScope()
} }
fun refresh() = presenter.getRecents() fun refresh() = presenter.getRecents()
@ -384,6 +390,8 @@ class RecentsController(bundle: Bundle? = null) :
override fun getViewType() = presenter.viewType override fun getViewType() = presenter.viewType
override fun scope() = adapterScope
override fun onItemClick(view: View?, position: Int): Boolean { override fun onItemClick(view: View?, position: Int): Boolean {
val item = adapter.getItem(position) ?: return false val item = adapter.getItem(position) ?: return false
if (item is RecentMangaItem) { if (item is RecentMangaItem) {
@ -462,14 +470,6 @@ class RecentsController(bundle: Bundle? = null) :
} else { } else {
inflater.inflate(R.menu.recents, menu) inflater.inflate(R.menu.recents, menu)
when (presenter.viewType) {
0 -> menu.findItem(R.id.action_group_all)
1 -> menu.findItem(R.id.action_ungroup_all)
2 -> menu.findItem(R.id.action_only_history)
3 -> menu.findItem(R.id.action_only_updates)
else -> null
}?.isChecked = true
val searchItem = menu.findItem(R.id.action_search) val searchItem = menu.findItem(R.id.action_search)
val searchView = searchItem.actionView as SearchView val searchView = searchItem.actionView as SearchView
searchView.queryHint = view?.context?.getString(R.string.search_recents) searchView.queryHint = view?.context?.getString(R.string.search_recents)
@ -539,21 +539,7 @@ class RecentsController(bundle: Bundle? = null) :
return binding.downloadBottomSheet.dlBottomSheet.onOptionsItemSelected(item) return binding.downloadBottomSheet.dlBottomSheet.onOptionsItemSelected(item)
} }
when (item.itemId) { when (item.itemId) {
R.id.action_group_all, R.id.action_ungroup_all, R.id.action_only_history, R.id.display_options -> RecentsOptionsSheet(activity!!).show()
R.id.action_only_updates -> {
presenter.toggleGroupRecents(
when (item.itemId) {
R.id.action_ungroup_all -> 1
R.id.action_only_history -> 2
R.id.action_only_updates -> 3
else -> 0
}
)
if (item.itemId == R.id.action_only_history) {
activity?.toast(R.string.press_and_hold_to_reset_history, Toast.LENGTH_LONG)
}
activity?.invalidateOptionsMenu()
}
} }
return super.onOptionsItemSelected(item) return super.onOptionsItemSelected(item)
} }

View File

@ -0,0 +1,55 @@
package eu.kanade.tachiyomi.ui.recents
import android.app.Activity
import android.text.Spannable
import android.text.SpannableStringBuilder
import android.text.style.ForegroundColorSpan
import android.view.ViewGroup
import androidx.core.text.set
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.databinding.RecentsOptionsSheetBinding
import eu.kanade.tachiyomi.util.bindToPreference
import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.view.RecyclerWindowInsetsListener
import eu.kanade.tachiyomi.util.view.setEdgeToEdge
import uy.kohesive.injekt.injectLazy
class RecentsOptionsSheet(activity: Activity) :
BottomSheetDialog(activity, R.style.BottomSheetDialogTheme) {
private val binding = RecentsOptionsSheetBinding.inflate(activity.layoutInflater)
private val preferences by injectLazy<PreferencesHelper>()
init {
setContentView(binding.root)
setEdgeToEdge(activity, binding.root)
initGeneralPreferences()
binding.settingsScrollView.setOnApplyWindowInsetsListener(RecyclerWindowInsetsListener)
}
override fun onStart() {
super.onStart()
BottomSheetBehavior.from(binding.root.parent as ViewGroup).skipCollapsed = true
val titleText = context.getString(R.string.show_reset_history_button)
val subtitleText = context.getString(R.string.press_and_hold_to_also_reset)
val spannable = SpannableStringBuilder(titleText + "\n" + subtitleText)
spannable.setSpan(
ForegroundColorSpan(binding.showRemoveHistory.context.getResourceColor(android.R.attr.textColorSecondary)),
titleText.length + 1,
spannable.length,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
binding.showRemoveHistory.text = spannable
}
private fun initGeneralPreferences() {
binding.showRecentsDownload.bindToPreference(preferences.showRecentsDownloads())
binding.showRemoveHistory.bindToPreference(preferences.showRecentsRemHistory())
binding.showReadInAll.bindToPreference(preferences.showReadInAllRecents())
binding.showTitleFirst.bindToPreference(preferences.showTitleFirstInRecents())
}
}

View File

@ -19,6 +19,9 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.cancel import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
@ -74,6 +77,13 @@ class RecentsPresenter(
lastRecents = null lastRecents = null
} }
getRecents() getRecents()
preferences.showReadInAllRecents()
.asFlow()
.drop(1)
.onEach {
getRecents()
}
.launchIn(scope)
} }
fun getRecents(updatePageCount: Boolean = false, retryCount: Int = 0, itemCount: Int = 0) { fun getRecents(updatePageCount: Boolean = false, retryCount: Int = 0, itemCount: Int = 0) {
@ -85,6 +95,7 @@ class RecentsPresenter(
withContext(Dispatchers.Main) { controller.showLists(recentItems, false) } withContext(Dispatchers.Main) { controller.showLists(recentItems, false) }
} }
val showRead = preferences.showReadInAllRecents().get()
if (updatePageCount) { if (updatePageCount) {
page++ page++
} }
@ -129,8 +140,13 @@ class RecentsPresenter(
val cReading = if (viewType != VIEW_TYPE_ONLY_UPDATES) { val cReading = if (viewType != VIEW_TYPE_ONLY_UPDATES) {
if (query.isEmpty() && viewType != VIEW_TYPE_ONLY_HISTORY) { if (query.isEmpty() && viewType != VIEW_TYPE_ONLY_HISTORY) {
if (showRead) {
db.getAllRecents(startCal.time, cal.time, query, isUngrouped)
.executeOnIO()
} else {
db.getRecentsWithUnread(startCal.time, cal.time, query, isUngrouped) db.getRecentsWithUnread(startCal.time, cal.time, query, isUngrouped)
.executeOnIO() .executeOnIO()
}
} else db.getRecentMangaLimit( } else db.getRecentMangaLimit(
startCal.time, startCal.time,
cal.time, cal.time,
@ -164,7 +180,9 @@ class RecentsPresenter(
val chapter = when { val chapter = when {
viewType == VIEW_TYPE_ONLY_HISTORY -> it.chapter viewType == VIEW_TYPE_ONLY_HISTORY -> it.chapter
it.chapter.read || it.chapter.id == null -> getNextChapter(it.manga) it.chapter.read || it.chapter.id == null -> getNextChapter(it.manga)
?: if (showRead && it.chapter.id != null) it.chapter else null
it.history.id == null -> getFirstUpdatedChapter(it.manga, it.chapter) it.history.id == null -> getFirstUpdatedChapter(it.manga, it.chapter)
?: if (showRead && it.chapter.id != null) it.chapter else null
else -> it.chapter else -> it.chapter
} }
if (chapter == null) if ((query.isNotEmpty() || viewType > VIEW_TYPE_UNGROUP_ALL) && if (chapter == null) if ((query.isNotEmpty() || viewType > VIEW_TYPE_UNGROUP_ALL) &&

View File

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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/display_bottom_sheet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bottom_sheet_rounded_background">
<androidx.core.widget.NestedScrollView
android:id="@+id/settings_scroll_view"
android:layout_width="match_parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/sort_layout"
style="@style/BottomSheetDialogTheme"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:orientation="vertical"
android:background="@android:color/transparent"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
<eu.kanade.tachiyomi.widget.MaterialSpinnerView
android:id="@+id/show_recents_download"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:entries="@array/show_recent_download"
app:title="@string/show_download_button" />
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/show_remove_history"
android:layout_width="match_parent"
android:layout_marginTop="4dp"
android:layout_height="wrap_content"
android:text="@string/show_reset_history_button"
android:textColor="?android:attr/textColorPrimary"
app:layout_constraintBottom_toTopOf="@+id/show_read_in_all" />
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/show_read_in_all"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="@string/show_read_in_all"
android:textColor="?android:attr/textColorPrimary" />
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/show_title_first"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/show_title_first"
android:textColor="?android:attr/textColorPrimary"
android:layout_marginTop="4dp" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -9,28 +9,13 @@
android:visible="false" android:visible="false"
app:actionViewClass="androidx.appcompat.widget.SearchView" app:actionViewClass="androidx.appcompat.widget.SearchView"
app:showAsAction="ifRoom|collapseActionView" /> app:showAsAction="ifRoom|collapseActionView" />
<item <item
android:id="@+id/action_filter" android:id="@+id/display_options"
android:icon="@drawable/ic_filter_list_24dp" android:icon="@drawable/ic_tune_24dp"
android:title="@string/filter" android:title="@string/display_options"
app:showAsAction="ifRoom"> app:showAsAction="ifRoom" />
<menu>
<group android:checkableBehavior="single">
<item
android:id="@+id/action_group_all"
android:title="@string/group_all" />
<item
android:id="@+id/action_ungroup_all"
android:title="@string/ungroup_all" />
<item
android:id="@+id/action_only_history"
android:title="@string/only_history" />
<item
android:id="@+id/action_only_updates"
android:title="@string/only_updates" />
</group>
</menu>
</item>
<item <item
android:id="@+id/action_settings" android:id="@+id/action_settings"
android:icon="@drawable/ic_settings_24dp" android:icon="@drawable/ic_settings_24dp"

View File

@ -62,6 +62,12 @@
<item>@string/screen</item> <item>@string/screen</item>
</string-array> </string-array>
<string-array name="show_recent_download">
<item>@string/never</item>
<item>@string/only_unread</item>
<item>@string/always</item>
</string-array>
<string-array name="reader_nav"> <string-array name="reader_nav">
<item>@string/default_value</item> <item>@string/default_value</item>
<item>@string/l_nav</item> <item>@string/l_nav</item>

View File

@ -231,6 +231,12 @@
<string name="only_updates">Only updates</string> <string name="only_updates">Only updates</string>
<string name="reset_chapter_question">Reset chapter?</string> <string name="reset_chapter_question">Reset chapter?</string>
<string name="press_and_hold_to_reset_history">Press and hold to reset chapter history</string> <string name="press_and_hold_to_reset_history">Press and hold to reset chapter history</string>
<string name="press_and_hold_to_also_reset">Press and hold can also reset chapter history</string>
<string name="show_download_button">Show download button</string>
<string name="only_unread">Only unread</string>
<string name="show_reset_history_button">Show reset history button</string>
<string name="show_read_in_all">Show read in all</string>
<string name="show_title_first">Show title first</string>
<!-- Browse --> <!-- Browse -->
<string name="search_filters">Search filters</string> <string name="search_filters">Search filters</string>