More Recents options

Using a tabbed sheet here too, options include:
Updates:
   * Group chapters together (off by default)
   * Show updated time
History:
   * Group chapters together (on by default)
This commit is contained in:
Jays2Kings 2021-04-21 01:11:05 -04:00
parent 91a9b721bc
commit f84ac9f24c
21 changed files with 374 additions and 167 deletions

View File

@ -6,13 +6,11 @@ import eu.kanade.tachiyomi.data.database.DbProvider
import eu.kanade.tachiyomi.data.database.models.Chapter import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.models.MangaChapter import eu.kanade.tachiyomi.data.database.models.MangaChapter
import eu.kanade.tachiyomi.data.database.models.MangaChapterHistory
import eu.kanade.tachiyomi.data.database.resolvers.ChapterBackupPutResolver import eu.kanade.tachiyomi.data.database.resolvers.ChapterBackupPutResolver
import eu.kanade.tachiyomi.data.database.resolvers.ChapterKnownBackupPutResolver import eu.kanade.tachiyomi.data.database.resolvers.ChapterKnownBackupPutResolver
import eu.kanade.tachiyomi.data.database.resolvers.ChapterProgressPutResolver import eu.kanade.tachiyomi.data.database.resolvers.ChapterProgressPutResolver
import eu.kanade.tachiyomi.data.database.resolvers.ChapterSourceOrderPutResolver import eu.kanade.tachiyomi.data.database.resolvers.ChapterSourceOrderPutResolver
import eu.kanade.tachiyomi.data.database.resolvers.MangaChapterGetResolver import eu.kanade.tachiyomi.data.database.resolvers.MangaChapterGetResolver
import eu.kanade.tachiyomi.data.database.resolvers.MangaChapterHistoryGetResolver
import eu.kanade.tachiyomi.data.database.tables.ChapterTable import eu.kanade.tachiyomi.data.database.tables.ChapterTable
import eu.kanade.tachiyomi.util.lang.sqLite import eu.kanade.tachiyomi.util.lang.sqLite
@ -48,16 +46,16 @@ interface ChapterQueries : DbProvider {
* @param date recent date range * @param date recent date range
* @offset offset the db by * @offset offset the db by
*/ */
fun getUpdatedManga(search: String = "", endless: Boolean, offset: Int, isResuming: Boolean) = db.get() fun getUpdatedChaptersDistinct(search: String = "", offset: Int, isResuming: Boolean) = db.get()
.listOfObjects(MangaChapterHistory::class.java) .listOfObjects(MangaChapter::class.java)
.withQuery( .withQuery(
RawQuery.builder() RawQuery.builder()
.query(getRecentsQueryDistinct(search.sqLite, endless, offset, isResuming)) .query(getRecentsQueryDistinct(search.sqLite, offset, isResuming))
// .args(date.time, startDate.time) // .args(date.time, startDate.time)
.observesTables(ChapterTable.TABLE) .observesTables(ChapterTable.TABLE)
.build() .build()
) )
.withGetResolver(MangaChapterHistoryGetResolver.INSTANCE) .withGetResolver(MangaChapterGetResolver.INSTANCE)
.prepare() .prepare()
fun getChapter(id: Long) = db.get() fun getChapter(id: Long) = db.get()

View File

@ -40,11 +40,28 @@ 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(search: String = "", endless: Boolean, offset: Int, isResuming: Boolean) = db.get() fun getRecentMangaLimit(search: String = "", offset: Int, isResuming: Boolean) = db.get()
.listOfObjects(MangaChapterHistory::class.java) .listOfObjects(MangaChapterHistory::class.java)
.withQuery( .withQuery(
RawQuery.builder() RawQuery.builder()
.query(getRecentMangasLimitQuery(search.sqLite, endless, offset, isResuming)) .query(getRecentMangasLimitQuery(search.sqLite, offset, isResuming))
// .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 getHistoryUngrouped(search: String = "", offset: Int, isResuming: Boolean) = db.get()
.listOfObjects(MangaChapterHistory::class.java)
.withQuery(
RawQuery.builder()
.query(getRecentHistoryUngrouped(search.sqLite, offset, isResuming))
// .args(date.time, startDate.time) // .args(date.time, startDate.time)
.observesTables(HistoryTable.TABLE) .observesTables(HistoryTable.TABLE)
.build() .build()

View File

@ -76,25 +76,24 @@ fun limitAndOffset(endless: Boolean, isResuming: Boolean, offset: Int): String {
/** /**
* Query to get the manga with recently uploaded chapters * Query to get the manga with recently uploaded chapters
*/ */
fun getRecentsQueryDistinct(search: String, endless: Boolean, offset: Int = 0, isResuming: Boolean) = fun getRecentsQueryDistinct(search: String, offset: Int = 0, isResuming: Boolean) =
""" """
SELECT ${Manga.TABLE}.${Manga.COL_URL} as mangaUrl, ${Manga.TABLE}.*, ${Chapter.TABLE}.* SELECT ${Manga.TABLE}.${Manga.COL_URL} as mangaUrl, ${Manga.TABLE}.*, ${Chapter.TABLE}.*
FROM ${Manga.TABLE} FROM ${Manga.TABLE}
JOIN ${Chapter.TABLE} JOIN ${Chapter.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}
JOIN ( JOIN (
SELECT ${Chapter.TABLE}.${Chapter.COL_MANGA_ID},${Chapter.TABLE}.${Chapter.COL_ID} as ${History.COL_CHAPTER_ID},MAX(${Chapter.TABLE}.${Chapter.COL_DATE_UPLOAD}) SELECT ${Chapter.TABLE}.${Chapter.COL_MANGA_ID},${Chapter.TABLE}.${Chapter.COL_ID},MAX(${Chapter.TABLE}.${Chapter.COL_DATE_FETCH})
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_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}
WHERE ${Manga.COL_FAVORITE} = 1 WHERE ${Manga.COL_FAVORITE} = 1
AND newest_chapter.${History.COL_CHAPTER_ID} = ${Chapter.TABLE}.${Chapter.COL_ID} AND newest_chapter.${Chapter.COL_ID} = ${Chapter.TABLE}.${Chapter.COL_ID}
AND ${Chapter.COL_DATE_FETCH} > ${Manga.COL_DATE_ADDED} AND ${Chapter.COL_DATE_FETCH} > ${Manga.COL_DATE_ADDED}
AND lower(${Manga.COL_TITLE}) LIKE '%$search%' AND lower(${Manga.COL_TITLE}) LIKE '%$search%'
ORDER BY ${Chapter.COL_DATE_FETCH} DESC ORDER BY ${Chapter.COL_DATE_FETCH} DESC
${limitAndOffset(endless, isResuming, offset)} ${limitAndOffset(true, isResuming, offset)}
""" """
/** /**
@ -105,7 +104,6 @@ fun getRecentsQueryDistinct(search: String, endless: Boolean, offset: Int = 0, i
*/ */
fun getRecentMangasLimitQuery( fun getRecentMangasLimitQuery(
search: String = "", search: String = "",
endless: Boolean,
offset: Int = 0, offset: Int = 0,
isResuming: Boolean isResuming: Boolean
) = ) =
@ -126,7 +124,31 @@ fun getRecentMangasLimitQuery(
AND max_last_read.${History.COL_LAST_READ} > 0 AND max_last_read.${History.COL_LAST_READ} > 0
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
${limitAndOffset(endless, isResuming, offset)} ${limitAndOffset(true, isResuming, offset)}
"""
/**
* Query to get the recently read chapters of manga from the library up to a date.
* 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 getRecentHistoryUngrouped(
search: String = "",
offset: Int = 0,
isResuming: Boolean
) =
"""
SELECT ${Manga.TABLE}.${Manga.COL_URL} as mangaUrl, ${Manga.TABLE}.*, ${Chapter.TABLE}.*, ${History.TABLE}.*
FROM ${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}
AND ${History.TABLE}.${History.COL_LAST_READ} > 0
AND lower(${Manga.TABLE}.${Manga.COL_TITLE}) LIKE '%$search%'
ORDER BY ${History.TABLE}.${History.COL_LAST_READ} DESC
${limitAndOffset(true, isResuming, offset)}
""" """
/** /**

View File

@ -187,6 +187,11 @@ object PreferenceKeys {
const val showReadInAllRecents = "show_read_in_all_recents" const val showReadInAllRecents = "show_read_in_all_recents"
const val showTitleFirstInRecents = "show_title_first_in_recents" const val showTitleFirstInRecents = "show_title_first_in_recents"
const val groupChaptersHistory = "group_chapters_history"
const val showUpdatedTime = "show_updated_time"
const val groupChaptersUpdates = "group_chapters_updates"
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

@ -335,6 +335,12 @@ class PreferencesHelper(val context: Context) {
fun showReadInAllRecents() = flowPrefs.getBoolean(Keys.showReadInAllRecents, false) fun showReadInAllRecents() = flowPrefs.getBoolean(Keys.showReadInAllRecents, false)
fun showUpdatedTime() = flowPrefs.getBoolean(Keys.showUpdatedTime, false)
fun groupChaptersUpdates() = flowPrefs.getBoolean(Keys.groupChaptersUpdates, true)
fun groupChaptersHistory() = flowPrefs.getBoolean(Keys.groupChaptersHistory, false)
fun showTitleFirstInRecents() = flowPrefs.getBoolean(Keys.showTitleFirstInRecents, false) fun showTitleFirstInRecents() = flowPrefs.getBoolean(Keys.showTitleFirstInRecents, false)
fun lastExtCheck() = rxPrefs.getLong("last_ext_check", 0) fun lastExtCheck() = rxPrefs.getLong("last_ext_check", 0)

View File

@ -6,6 +6,7 @@ import eu.davidea.flexibleadapter.items.IFlexible
import eu.kanade.tachiyomi.data.preference.PreferencesHelper 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.CoroutineScope
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
@ -20,6 +21,7 @@ class RecentMangaAdapter(val delegate: RecentsInterface) :
var showDownloads = preferences.showRecentsDownloads().get() var showDownloads = preferences.showRecentsDownloads().get()
var showRemoveHistory = preferences.showRecentsRemHistory().get() var showRemoveHistory = preferences.showRecentsRemHistory().get()
var showTitleFirst = preferences.showTitleFirstInRecents().get() var showTitleFirst = preferences.showTitleFirstInRecents().get()
var showUpdatedTime = preferences.showUpdatedTime().get()
val viewType: Int val viewType: Int
get() = delegate.getViewType() get() = delegate.getViewType()
@ -39,10 +41,12 @@ class RecentMangaAdapter(val delegate: RecentsInterface) :
preferences.showRecentsDownloads().register { showDownloads = it } preferences.showRecentsDownloads().register { showDownloads = it }
preferences.showRecentsRemHistory().register { showRemoveHistory = it } preferences.showRecentsRemHistory().register { showRemoveHistory = it }
preferences.showTitleFirstInRecents().register { showTitleFirst = it } preferences.showTitleFirstInRecents().register { showTitleFirst = it }
preferences.showUpdatedTime().register { showUpdatedTime = it }
} }
private fun <T> Preference<T>.register(onChanged: (T) -> Unit) { private fun <T> Preference<T>.register(onChanged: (T) -> Unit) {
asFlow() asFlow()
.drop(1)
.onEach { .onEach {
onChanged(it) onChanged(it)
notifyDataSetChanged() notifyDataSetChanged()

View File

@ -29,7 +29,10 @@ class RecentMangaHolder(
binding.removeHistory.setOnClickListener { adapter.delegate.onRemoveHistoryClicked(flexibleAdapterPosition) } binding.removeHistory.setOnClickListener { adapter.delegate.onRemoveHistoryClicked(flexibleAdapterPosition) }
} }
fun bind(item: RecentMangaItem, showDLs: RecentMangaAdapter.ShowRecentsDLs, showRemoveHistory: Boolean, showTitleFirst: Boolean) { fun bind(item: RecentMangaItem) {
val showDLs = adapter.showDownloads
val showRemoveHistory = adapter.showRemoveHistory
val showTitleFirst = adapter.showTitleFirst
binding.downloadButton.downloadButton.isVisible = when (showDLs) { binding.downloadButton.downloadButton.isVisible = when (showDLs) {
RecentMangaAdapter.ShowRecentsDLs.None -> false RecentMangaAdapter.ShowRecentsDLs.None -> false
RecentMangaAdapter.ShowRecentsDLs.OnlyUnread, RecentMangaAdapter.ShowRecentsDLs.UnreadOrDownloaded -> !item.chapter.read RecentMangaAdapter.ShowRecentsDLs.OnlyUnread, RecentMangaAdapter.ShowRecentsDLs.UnreadOrDownloaded -> !item.chapter.read
@ -37,7 +40,8 @@ class RecentMangaHolder(
RecentMangaAdapter.ShowRecentsDLs.All -> true RecentMangaAdapter.ShowRecentsDLs.All -> true
} && !item.mch.manga.isLocal() } && !item.mch.manga.isLocal()
val isUpdates = adapter.viewType == RecentsPresenter.VIEW_TYPE_ONLY_UPDATES val isUpdates = adapter.viewType == RecentsPresenter.VIEW_TYPE_ONLY_UPDATES &&
!adapter.showUpdatedTime
binding.cardLayout.updateLayoutParams<ConstraintLayout.LayoutParams> { binding.cardLayout.updateLayoutParams<ConstraintLayout.LayoutParams> {
height = (if (isUpdates) 40 else 80).dpToPx height = (if (isUpdates) 40 else 80).dpToPx
width = (if (isUpdates) 40 else 60).dpToPx width = (if (isUpdates) 40 else 60).dpToPx
@ -101,7 +105,7 @@ class RecentMangaHolder(
R.string.added_, R.string.added_,
item.mch.manga.date_added.timeSpanFromNow(itemView.context) item.mch.manga.date_added.timeSpanFromNow(itemView.context)
) )
adapter.viewType == RecentsPresenter.VIEW_TYPE_ONLY_UPDATES -> "" isUpdates -> ""
item.mch.history.id == null -> binding.body.context.getString( item.mch.history.id == null -> binding.body.context.getString(
R.string.updated_, R.string.updated_,
item.chapter.date_upload.timeSpanFromNow(itemView.context) item.chapter.date_upload.timeSpanFromNow(itemView.context)

View File

@ -57,10 +57,7 @@ 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 if (chapter.id != null) (holder as? RecentMangaHolder)?.bind(this, showDLs, showRemoveHistory, showTitleFirst) else if (chapter.id != null) (holder as? RecentMangaHolder)?.bind(this)
} }
} }

View File

@ -36,6 +36,7 @@ import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.ui.main.RootSearchInterface import eu.kanade.tachiyomi.ui.main.RootSearchInterface
import eu.kanade.tachiyomi.ui.manga.MangaDetailsController import eu.kanade.tachiyomi.ui.manga.MangaDetailsController
import eu.kanade.tachiyomi.ui.reader.ReaderActivity import eu.kanade.tachiyomi.ui.reader.ReaderActivity
import eu.kanade.tachiyomi.ui.recents.options.TabbedRecentsOptionsSheet
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
@ -91,6 +92,7 @@ class RecentsController(bundle: Bundle? = null) :
* Adapter containing the recent manga. * Adapter containing the recent manga.
*/ */
private var adapter = RecentMangaAdapter(this) private var adapter = RecentMangaAdapter(this)
var displaySheet: TabbedRecentsOptionsSheet? = null
private var progressItem: ProgressItem? = null private var progressItem: ProgressItem? = null
private var presenter = RecentsPresenter(this) private var presenter = RecentsPresenter(this)
@ -364,6 +366,12 @@ class RecentsController(bundle: Bundle? = null) :
presenter.cancelScope() presenter.cancelScope()
} }
override fun onDestroyView(view: View) {
super.onDestroyView(view)
displaySheet?.dismiss()
displaySheet = null
}
fun refresh() = presenter.getRecents() fun refresh() = presenter.getRecents()
fun showLists( fun showLists(
@ -653,7 +661,13 @@ 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.display_options -> RecentsOptionsSheet(activity!!).show() R.id.display_options -> {
displaySheet = TabbedRecentsOptionsSheet(
this,
(presenter.viewType - 1).coerceIn(0, 2)
)
displaySheet?.show()
}
} }
return super.onOptionsItemSelected(item) return super.onOptionsItemSelected(item)
} }

View File

@ -1,45 +0,0 @@
package eu.kanade.tachiyomi.ui.recents
import android.app.Activity
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.lang.withSubtitle
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)
binding.showRemoveHistory.text = titleText
.withSubtitle(binding.showRemoveHistory.context, R.string.press_and_hold_to_also_reset)
}
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

@ -73,14 +73,19 @@ class RecentsPresenter(
get() = pageOffset == 0 get() = pageOffset == 0
init { init {
preferences.showReadInAllRecents() listOf(
.asFlow() preferences.groupChaptersHistory(),
.drop(1) preferences.showReadInAllRecents(),
.onEach { preferences.groupChaptersUpdates()
resetOffsets() ).forEach {
getRecents() it.asFlow()
} .drop(1)
.launchIn(scope) .onEach {
resetOffsets()
getRecents()
}
.launchIn(scope)
}
} }
fun onCreate() { fun onCreate() {
@ -126,6 +131,8 @@ class RecentsPresenter(
val showRead = preferences.showReadInAllRecents().get() && !limit val showRead = preferences.showReadInAllRecents().get() && !limit
val isUngrouped = viewType > VIEW_TYPE_GROUP_ALL || query.isNotEmpty() val isUngrouped = viewType > VIEW_TYPE_GROUP_ALL || query.isNotEmpty()
val groupChaptersUpdates = preferences.groupChaptersUpdates().get()
val groupChaptersHistory = preferences.groupChaptersHistory().get()
val isCustom = customViewType != null val isCustom = customViewType != null
val isEndless = isUngrouped && !limit val isEndless = isUngrouped && !limit
@ -140,27 +147,43 @@ class RecentsPresenter(
).executeOnIO() ).executeOnIO()
} }
viewType == VIEW_TYPE_ONLY_HISTORY -> { viewType == VIEW_TYPE_ONLY_HISTORY -> {
db.getRecentMangaLimit( if (groupChaptersHistory) {
query, db.getRecentMangaLimit(
isEndless, query,
if (isCustom) ENDLESS_LIMIT else pageOffset, if (isCustom) ENDLESS_LIMIT else pageOffset,
!updatePageCount && !isOnFirstPage !updatePageCount && !isOnFirstPage
).executeOnIO() )
} else {
db.getHistoryUngrouped(
query,
if (isCustom) ENDLESS_LIMIT else pageOffset,
!updatePageCount && !isOnFirstPage
)
}.executeOnIO()
} }
viewType == VIEW_TYPE_ONLY_UPDATES -> { viewType == VIEW_TYPE_ONLY_UPDATES -> {
db.getRecentChapters( if (groupChaptersUpdates) {
query, db.getUpdatedChaptersDistinct(
if (isCustom) ENDLESS_LIMIT else pageOffset, query,
!updatePageCount && !isOnFirstPage if (isCustom) ENDLESS_LIMIT else pageOffset,
).executeOnIO().map { !updatePageCount && !isOnFirstPage
MangaChapterHistory(
it.manga,
it.chapter,
HistoryImpl().apply {
last_read = it.chapter.date_fetch
}
) )
} } else {
db.getRecentChapters(
query,
if (isCustom) ENDLESS_LIMIT else pageOffset,
!updatePageCount && !isOnFirstPage
)
}.executeOnIO()
.map {
MangaChapterHistory(
it.manga,
it.chapter,
HistoryImpl().apply {
last_read = it.chapter.date_fetch
}
)
}
} }
else -> emptyList() else -> emptyList()
} }
@ -185,12 +208,21 @@ class RecentsPresenter(
} }
val pairs = mangaList.mapNotNull { val pairs = mangaList.mapNotNull {
val chapter = when { val chapter = when {
viewType == VIEW_TYPE_ONLY_UPDATES -> it.chapter (viewType == VIEW_TYPE_ONLY_UPDATES && !groupChaptersUpdates) ||
it.chapter.read || it.chapter.id == null -> getNextChapter(it.manga) (viewType == VIEW_TYPE_ONLY_HISTORY && !groupChaptersHistory) -> {
?: if (showRead && it.chapter.id != null) it.chapter else null it.chapter
it.history.id == null -> getFirstUpdatedChapter(it.manga, it.chapter) }
?: if (showRead && it.chapter.id != null) it.chapter else null (it.chapter.read && viewType != VIEW_TYPE_ONLY_UPDATES) || it.chapter.id == null -> {
else -> it.chapter getNextChapter(it.manga)
?: if (showRead && it.chapter.id != null) it.chapter else null
}
it.history.id == null -> {
getFirstUpdatedChapter(it.manga, it.chapter)
?: if ((showRead && it.chapter.id != null) || viewType == VIEW_TYPE_ONLY_UPDATES) it.chapter else null
}
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) &&
it.chapter.id != null it.chapter.id != null
@ -248,9 +280,9 @@ class RecentsPresenter(
pairs.groupByTo(map, { getMapKey(it.first.history.last_read) }) pairs.groupByTo(map, { getMapKey(it.first.history.last_read) })
byDay.flatMap { byDay.flatMap {
val dateItem = DateItem(it.key, true) val dateItem = DateItem(it.key, true)
it.value.map { item -> it.value
RecentMangaItem(item.first, item.second, dateItem) .map { item -> RecentMangaItem(item.first, item.second, dateItem) }
} .sortedByDescending { item -> item.chapter.date_upload }
} }
} else pairs.map { RecentMangaItem(it.first, it.second, null) } } else pairs.map { RecentMangaItem(it.first, it.second, null) }
} }

View File

@ -0,0 +1,24 @@
package eu.kanade.tachiyomi.ui.recents.options
import android.content.Context
import android.util.AttributeSet
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.databinding.RecentsGeneralViewBinding
import eu.kanade.tachiyomi.util.bindToPreference
import eu.kanade.tachiyomi.util.lang.withSubtitle
import eu.kanade.tachiyomi.widget.BaseRecentsDisplayView
class RecentsGeneralView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
BaseRecentsDisplayView<RecentsGeneralViewBinding>(context, attrs) {
override fun inflateBinding() = RecentsGeneralViewBinding.bind(this)
override fun initGeneralPreferences() {
val titleText = context.getString(R.string.show_reset_history_button)
binding.showRemoveHistory.text = titleText
.withSubtitle(binding.showRemoveHistory.context, R.string.press_and_hold_to_also_reset)
binding.showRecentsDownload.bindToPreference(preferences.showRecentsDownloads())
binding.showRemoveHistory.bindToPreference(preferences.showRecentsRemHistory())
binding.showReadInAll.bindToPreference(preferences.showReadInAllRecents())
binding.showTitleFirst.bindToPreference(preferences.showTitleFirstInRecents())
}
}

View File

@ -0,0 +1,16 @@
package eu.kanade.tachiyomi.ui.recents.options
import android.content.Context
import android.util.AttributeSet
import eu.kanade.tachiyomi.databinding.RecentsHistoryViewBinding
import eu.kanade.tachiyomi.util.bindToPreference
import eu.kanade.tachiyomi.widget.BaseRecentsDisplayView
class RecentsHistoryView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
BaseRecentsDisplayView<RecentsHistoryViewBinding>(context, attrs) {
override fun inflateBinding() = RecentsHistoryViewBinding.bind(this)
override fun initGeneralPreferences() {
binding.groupChapters.bindToPreference(preferences.groupChaptersHistory())
}
}

View File

@ -0,0 +1,17 @@
package eu.kanade.tachiyomi.ui.recents.options
import android.content.Context
import android.util.AttributeSet
import eu.kanade.tachiyomi.databinding.RecentsUpdatesViewBinding
import eu.kanade.tachiyomi.util.bindToPreference
import eu.kanade.tachiyomi.widget.BaseRecentsDisplayView
class RecentsUpdatesView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
BaseRecentsDisplayView<RecentsUpdatesViewBinding>(context, attrs) {
override fun inflateBinding() = RecentsUpdatesViewBinding.bind(this)
override fun initGeneralPreferences() {
binding.showUpdatedTime.bindToPreference(preferences.showUpdatedTime())
binding.groupChapters.bindToPreference(preferences.groupChaptersUpdates())
}
}

View File

@ -0,0 +1,43 @@
package eu.kanade.tachiyomi.ui.recents.options
import android.view.View
import android.view.View.inflate
import androidx.annotation.IntRange
import androidx.core.view.isVisible
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.ui.recents.RecentsController
import eu.kanade.tachiyomi.widget.TabbedBottomSheetDialog
class TabbedRecentsOptionsSheet(val controller: RecentsController, @IntRange(from = 0, to = 2) startingTab: Int) :
TabbedBottomSheetDialog(controller.activity!!) {
private val generalView = inflate(controller.activity!!, R.layout.recents_general_view, null) as RecentsGeneralView
private val historyView = inflate(controller.activity!!, R.layout.recents_history_view, null) as RecentsHistoryView
private val updatesView = inflate(controller.activity!!, R.layout.recents_updates_view, null) as RecentsUpdatesView
init {
binding.menu.isVisible = false
generalView.controller = controller
historyView.controller = controller
updatesView.controller = controller
binding.tabs.getTabAt(startingTab)?.select()
}
override fun dismiss() {
super.dismiss()
controller.displaySheet = null
}
override fun getTabViews(): List<View> = listOf(
generalView,
historyView,
updatesView
)
override fun getTabTitles(): List<Int> = listOf(
R.string.general,
R.string.history,
R.string.updates
)
}

View File

@ -7,6 +7,7 @@ import androidx.viewbinding.ViewBinding
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.ui.library.LibraryController import eu.kanade.tachiyomi.ui.library.LibraryController
import eu.kanade.tachiyomi.ui.reader.ReaderActivity import eu.kanade.tachiyomi.ui.reader.ReaderActivity
import eu.kanade.tachiyomi.ui.recents.RecentsController
import eu.kanade.tachiyomi.util.view.RecyclerWindowInsetsListener import eu.kanade.tachiyomi.util.view.RecyclerWindowInsetsListener
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
@ -31,6 +32,11 @@ abstract class BaseTabbedScrollView<VB : ViewBinding> @JvmOverloads constructor(
} }
} }
abstract class BaseRecentsDisplayView<VB : ViewBinding> @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
BaseTabbedScrollView<VB>(context, attrs) {
var controller: RecentsController? = null
}
abstract class BaseLibraryDisplayView<VB : ViewBinding> @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : abstract class BaseLibraryDisplayView<VB : ViewBinding> @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
BaseTabbedScrollView<VB>(context, attrs) { BaseTabbedScrollView<VB>(context, attrs) {
var controller: LibraryController? = null var controller: LibraryController? = null

View File

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<eu.kanade.tachiyomi.ui.recents.options.RecentsGeneralView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<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">
<eu.kanade.tachiyomi.widget.MaterialSpinnerView
android:id="@+id/show_recents_download"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
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="8dp"
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="8dp"
android:text="@string/show_read_chapters_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="8dp" />
</LinearLayout>
</eu.kanade.tachiyomi.ui.recents.options.RecentsGeneralView>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<eu.kanade.tachiyomi.ui.recents.options.RecentsHistoryView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<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">
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/group_chapters"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/group_chapters_together"
android:textColor="?android:attr/textColorPrimary" />
</LinearLayout>
</eu.kanade.tachiyomi.ui.recents.options.RecentsHistoryView>

View File

@ -1,64 +0,0 @@
<?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="8dp"
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="8dp"
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="8dp"
android:text="@string/show_read_chapters_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="8dp" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<eu.kanade.tachiyomi.ui.recents.options.RecentsUpdatesView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<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">
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/show_updated_time"
android:layout_width="match_parent"
android:layout_marginTop="8dp"
android:layout_height="wrap_content"
android:text="@string/show_updated_time"
android:textColor="?android:attr/textColorPrimary"
app:layout_constraintBottom_toTopOf="@+id/show_read_in_all" />
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/group_chapters"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/group_chapters_together"
android:textColor="?android:attr/textColorPrimary" />
</LinearLayout>
</eu.kanade.tachiyomi.ui.recents.options.RecentsUpdatesView>

View File

@ -241,6 +241,8 @@
<string name="show_read_chapters_all">Show read chapters in Grouped and All</string> <string name="show_read_chapters_all">Show read chapters in Grouped and All</string>
<string name="show_title_first">Show title first</string> <string name="show_title_first">Show title first</string>
<string name="a_while_ago">A while ago</string> <string name="a_while_ago">A while ago</string>
<string name="show_updated_time">Show updated time</string>
<string name="group_chapters_together">Group chapters together</string>
<!-- Browse --> <!-- Browse -->
<string name="search_filters">Search filters</string> <string name="search_filters">Search filters</string>