Recents can now be filtered for only history or updates

This commit is contained in:
Jay 2020-04-13 00:46:01 -04:00
parent cb6de21804
commit 6533689539
11 changed files with 231 additions and 66 deletions

View File

@ -245,7 +245,7 @@ class PreferencesHelper(val context: Context) {
fun extensionUpdatesCount() = rxPrefs.getInteger("ext_updates_count", 0) fun extensionUpdatesCount() = rxPrefs.getInteger("ext_updates_count", 0)
fun groupRecents() = rxPrefs.getBoolean("group_recents", true) fun recentsViewType() = rxPrefs.getInteger("recents_view_type", 0)
fun lastExtCheck() = rxPrefs.getLong("last_ext_check", 0) fun lastExtCheck() = rxPrefs.getLong("last_ext_check", 0)

View File

@ -145,7 +145,8 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
}) return@setOnNavigationItemSelectedListener false }) return@setOnNavigationItemSelectedListener false
} }
continueSwitchingTabs = false continueSwitchingTabs = false
preferences.lastTab().set(item.itemId) if (item.itemId != R.id.nav_browse)
preferences.lastTab().set(item.itemId)
val currentRoot = router.backstack.firstOrNull() val currentRoot = router.backstack.firstOrNull()
if (currentRoot?.tag()?.toIntOrNull() != id) { if (currentRoot?.tag()?.toIntOrNull() != id) {
setRoot(when (id) { setRoot(when (id) {
@ -311,12 +312,12 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
private fun setExtensionsBadge() { private fun setExtensionsBadge() {
val updates = preferences.extensionUpdatesCount().getOrDefault() val updates = preferences.extensionUpdatesCount().getOrDefault()
if (updates > 0) { if (updates > 0) {
val badge = bottom_nav.getOrCreateBadge(R.id.nav_catalogues) val badge = bottom_nav.getOrCreateBadge(R.id.nav_browse)
badge.number = updates badge.number = updates
badge.backgroundColor = getResourceColor(R.attr.badgeColor) badge.backgroundColor = getResourceColor(R.attr.badgeColor)
badge.badgeTextColor = Color.WHITE badge.badgeTextColor = Color.WHITE
} else { } else {
bottom_nav.removeBadge(R.id.nav_catalogues) bottom_nav.removeBadge(R.id.nav_browse)
} }
} }
@ -367,9 +368,9 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
} }
router.pushController(controller.withFadeTransaction()) router.pushController(controller.withFadeTransaction())
} }
SHORTCUT_CATALOGUES -> bottom_nav.selectedItemId = R.id.nav_catalogues SHORTCUT_CATALOGUES -> bottom_nav.selectedItemId = R.id.nav_browse
SHORTCUT_EXTENSIONS -> { SHORTCUT_EXTENSIONS -> {
bottom_nav.selectedItemId = R.id.nav_catalogues bottom_nav.selectedItemId = R.id.nav_browse
router.popToRoot() router.popToRoot()
bottom_nav.post { bottom_nav.post {
val controller = val controller =

View File

@ -11,7 +11,8 @@ import eu.davidea.viewholders.FlexibleViewHolder
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import java.util.Date import java.util.Date
class DateItem(val date: Date) : AbstractHeaderItem<DateItem.Holder>() { class DateItem(val date: Date, val addedString: Boolean = false) : AbstractHeaderItem<DateItem
.Holder>() {
override fun getLayoutRes(): Int { override fun getLayoutRes(): Int {
return R.layout.recent_chapters_section_item return R.layout.recent_chapters_section_item
@ -44,7 +45,9 @@ class DateItem(val date: Date) : AbstractHeaderItem<DateItem.Holder>() {
val section_text: TextView = view.findViewById(R.id.section_text) val section_text: TextView = view.findViewById(R.id.section_text)
fun bind(item: DateItem) { fun bind(item: DateItem) {
section_text.text = DateUtils.getRelativeTimeSpanString(item.date.time, now, DateUtils.DAY_IN_MILLIS) val dateString = DateUtils.getRelativeTimeSpanString(item.date.time, now, DateUtils.DAY_IN_MILLIS)
section_text.text =
if (item.addedString) itemView.context.getString(R.string.added_, dateString) else dateString
} }
} }
} }

View File

@ -7,6 +7,7 @@ import com.afollestad.materialdialogs.checkbox.checkBoxPrompt
import com.afollestad.materialdialogs.checkbox.isCheckPromptChecked import com.afollestad.materialdialogs.checkbox.isCheckPromptChecked
import com.bluelinelabs.conductor.Controller import com.bluelinelabs.conductor.Controller
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.History import eu.kanade.tachiyomi.data.database.models.History
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.ui.base.controller.DialogController import eu.kanade.tachiyomi.ui.base.controller.DialogController
@ -18,21 +19,28 @@ class RemoveHistoryDialog<T>(bundle: Bundle? = null) : DialogController(bundle)
private var history: History? = null private var history: History? = null
constructor(target: T, manga: Manga, history: History) : this() { private var chapter: Chapter? = null
constructor(target: T, manga: Manga, history: History, chapter: Chapter? = null) : this() {
this.manga = manga this.manga = manga
this.history = history this.history = history
this.chapter = chapter
targetController = target targetController = target
} }
override fun onCreateDialog(savedViewState: Bundle?): Dialog { override fun onCreateDialog(savedViewState: Bundle?): Dialog {
val activity = activity!! val activity = activity!!
return MaterialDialog(activity).title(R.string.remove) return MaterialDialog(activity).title(R.string.reset_chapter_question).message(
.message(R.string.this_will_remove_the_read_date_question).checkBoxPrompt( text = if (chapter?.name != null) activity.getString(
R.string.this_will_remove_the_read_date_for_x_question, chapter?.name ?: ""
)
else activity.getString(R.string.this_will_remove_the_read_date_question)
).checkBoxPrompt(
text = activity.getString( text = activity.getString(
R.string.reset_all_chapters_for_this_, manga!!.mangaType(activity) R.string.reset_all_chapters_for_this_, manga!!.mangaType(activity)
) )
) {}.negativeButton(android.R.string.cancel).positiveButton(R.string.remove) { ) {}.negativeButton(android.R.string.cancel).positiveButton(R.string.reset) {
onPositive(it.isCheckPromptChecked()) onPositive(it.isCheckPromptChecked())
} }
} }

View File

@ -10,6 +10,7 @@ import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.data.glide.GlideApp import eu.kanade.tachiyomi.data.glide.GlideApp
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.system.getResourceColor
import eu.kanade.tachiyomi.util.view.visibleIf import eu.kanade.tachiyomi.util.view.visibleIf
import kotlinx.android.synthetic.main.download_button.* import kotlinx.android.synthetic.main.download_button.*
import kotlinx.android.synthetic.main.recent_manga_item.* import kotlinx.android.synthetic.main.recent_manga_item.*
@ -37,9 +38,21 @@ class RecentMangaHolder(
fun bind(item: RecentMangaItem) { fun bind(item: RecentMangaItem) {
download_button.visibleIf(item.mch.manga.source != LocalSource.ID) download_button.visibleIf(item.mch.manga.source != LocalSource.ID)
subtitle.text = item.mch.manga.title title.apply {
val isSearch = adapter.delegate.isSearching() text = item.chapter.name
title.text = item.chapter.name setTextColor(when {
item.chapter.bookmark -> context.getResourceColor(R.attr.colorAccent)
item.chapter.read -> context.getResourceColor(android.R.attr.textColorHint)
else -> context.getResourceColor(android.R.attr.textColorPrimary)
})
}
subtitle.apply {
text = item.mch.manga.title
setTextColor(when {
item.chapter.read -> context.getResourceColor(android.R.attr.textColorHint)
else -> context.getResourceColor(android.R.attr.textColorPrimary)
})
}
val notValidNum = item.mch.chapter.chapter_number <= 0 val notValidNum = item.mch.chapter.chapter_number <= 0
body.text = when { body.text = when {
item.mch.chapter.id == null -> body.context.getString( item.mch.chapter.id == null -> body.context.getString(
@ -77,13 +90,18 @@ class RecentMangaHolder(
GlideApp.with(itemView.context).load(item.mch.manga).diskCacheStrategy(DiskCacheStrategy GlideApp.with(itemView.context).load(item.mch.manga).diskCacheStrategy(DiskCacheStrategy
.AUTOMATIC) .AUTOMATIC)
.signature(ObjectKey(MangaImpl.getLastCoverFetch(item.mch.manga.id!!).toString())).into(cover_thumbnail) .signature(ObjectKey(MangaImpl.getLastCoverFetch(item.mch.manga.id!!).toString())).into(cover_thumbnail)
// adapter.delegate.setCover(item.mch.manga, cover_thumbnail)
notifyStatus( notifyStatus(
if (adapter.isSelected(adapterPosition)) Download.CHECKED else item.status, if (adapter.isSelected(adapterPosition)) Download.CHECKED else item.status,
item.progress item.progress
) )
} }
override fun onLongClick(view: View?): Boolean {
super.onLongClick(view)
val item = adapter.getItem(adapterPosition) as? RecentMangaItem ?: return false
return item.mch.history.id != null
}
fun notifyStatus(status: Int, progress: Int) = fun notifyStatus(status: Int, progress: Int) =
download_button.setDownloadStatus(status, progress) download_button.setDownloadStatus(status, progress)

View File

@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.ui.recents
import android.view.View import android.view.View
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.items.AbstractHeaderItem
import eu.davidea.flexibleadapter.items.IFlexible import eu.davidea.flexibleadapter.items.IFlexible
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Chapter import eu.kanade.tachiyomi.data.database.models.Chapter
@ -13,10 +14,9 @@ import eu.kanade.tachiyomi.ui.manga.chapter.BaseChapterItem
class RecentMangaItem( class RecentMangaItem(
val mch: MangaChapterHistory = MangaChapterHistory.createBlank(), val mch: MangaChapterHistory = MangaChapterHistory.createBlank(),
chapter: Chapter = ChapterImpl(), chapter: Chapter = ChapterImpl(),
header: header: AbstractHeaderItem<*>?
RecentMangaHeaderItem?
) : ) :
BaseChapterItem<RecentMangaHolder, RecentMangaHeaderItem>(chapter, header) { BaseChapterItem<RecentMangaHolder, AbstractHeaderItem<*>>(chapter, header) {
override fun getLayoutRes(): Int { override fun getLayoutRes(): Int {
return if (mch.manga.id == null) R.layout.recents_footer_item return if (mch.manga.id == null) R.layout.recents_footer_item
@ -37,14 +37,15 @@ class RecentMangaItem(
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
if (this === other) return true if (this === other) return true
if (other is RecentMangaItem) { if (other is RecentMangaItem) {
return if (mch.manga.id == null) header?.recentsType == other.header?.recentsType return if (mch.manga.id == null) (header as? RecentMangaHeaderItem)?.recentsType ==
(other.header as? RecentMangaHeaderItem)?.recentsType
else chapter.id == other.chapter.id else chapter.id == other.chapter.id
} }
return false return false
} }
override fun hashCode(): Int { override fun hashCode(): Int {
return if (mch.manga.id == null) -(header?.recentsType ?: 0).hashCode() return if (mch.manga.id == null) -((header as? RecentMangaHeaderItem)?.recentsType ?: 0).hashCode()
else (chapter.id ?: 0L).hashCode() else (chapter.id ?: 0L).hashCode()
} }
@ -54,7 +55,7 @@ class RecentMangaItem(
position: Int, position: Int,
payloads: MutableList<Any?>? payloads: MutableList<Any?>?
) { ) {
if (mch.manga.id == null) holder.bind(header?.recentsType ?: 0) if (mch.manga.id == null) holder.bind((header as? RecentMangaHeaderItem)?.recentsType ?: 0)
else holder.bind(this) else holder.bind(this)
} }
} }

View File

@ -8,6 +8,7 @@ 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
@ -20,6 +21,8 @@ import com.google.android.material.snackbar.BaseTransientBottomBar
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.History
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.download.DownloadService import eu.kanade.tachiyomi.data.download.DownloadService
import eu.kanade.tachiyomi.data.download.model.Download import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.data.library.LibraryUpdateService import eu.kanade.tachiyomi.data.library.LibraryUpdateService
@ -32,7 +35,9 @@ 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.recent_updates.RecentChaptersController import eu.kanade.tachiyomi.ui.recent_updates.RecentChaptersController
import eu.kanade.tachiyomi.ui.recently_read.RecentlyReadController import eu.kanade.tachiyomi.ui.recently_read.RecentlyReadController
import eu.kanade.tachiyomi.ui.recently_read.RemoveHistoryDialog
import eu.kanade.tachiyomi.util.system.dpToPx import eu.kanade.tachiyomi.util.system.dpToPx
import eu.kanade.tachiyomi.util.system.toast
import eu.kanade.tachiyomi.util.view.applyWindowInsetsForRootController import eu.kanade.tachiyomi.util.view.applyWindowInsetsForRootController
import eu.kanade.tachiyomi.util.view.scrollViewWith import eu.kanade.tachiyomi.util.view.scrollViewWith
import eu.kanade.tachiyomi.util.view.setOnQueryTextChangeListener import eu.kanade.tachiyomi.util.view.setOnQueryTextChangeListener
@ -54,9 +59,11 @@ import kotlin.math.max
class RecentsController(bundle: Bundle? = null) : BaseController(bundle), class RecentsController(bundle: Bundle? = null) : BaseController(bundle),
RecentMangaAdapter.RecentsInterface, RecentMangaAdapter.RecentsInterface,
FlexibleAdapter.OnItemClickListener, FlexibleAdapter.OnItemClickListener,
FlexibleAdapter.OnItemLongClickListener,
FlexibleAdapter.OnItemMoveListener, FlexibleAdapter.OnItemMoveListener,
RootSearchInterface, RootSearchInterface,
BottomSheetController { BottomSheetController,
RemoveHistoryDialog.Listener {
init { init {
setHasOptionsMenu(true) setHasOptionsMenu(true)
@ -112,7 +119,10 @@ class RecentsController(bundle: Bundle? = null) : BaseController(bundle),
} }
presenter.onCreate() presenter.onCreate()
if (presenter.recentItems.isNotEmpty()) adapter.updateDataSet(presenter.recentItems) if (presenter.recentItems.isNotEmpty()) {
adapter.updateDataSet(presenter.recentItems)
adapter.addScrollableHeader(presenter.generalHeader)
}
dl_bottom_sheet.onCreate(this) dl_bottom_sheet.onCreate(this)
@ -173,6 +183,7 @@ class RecentsController(bundle: Bundle? = null) : BaseController(bundle),
fun reEnableSwipe() { fun reEnableSwipe() {
swipe_refresh.isRefreshing = false swipe_refresh.isRefreshing = false
} }
override fun onItemMove(fromPosition: Int, toPosition: Int) { } override fun onItemMove(fromPosition: Int, toPosition: Int) { }
override fun shouldMoveItem(fromPosition: Int, toPosition: Int) = true override fun shouldMoveItem(fromPosition: Int, toPosition: Int) = true
@ -217,6 +228,9 @@ class RecentsController(bundle: Bundle? = null) : BaseController(bundle),
fun showLists(recents: List<RecentMangaItem>) { fun showLists(recents: List<RecentMangaItem>) {
swipe_refresh.isRefreshing = LibraryUpdateService.isRunning() swipe_refresh.isRefreshing = LibraryUpdateService.isRunning()
adapter.updateDataSet(recents) adapter.updateDataSet(recents)
adapter.removeAllScrollableHeaders()
if (presenter.viewType > 0)
adapter.addScrollableHeader(presenter.generalHeader)
if (lastChapterId != null) { if (lastChapterId != null) {
refreshItem(lastChapterId ?: 0L) refreshItem(lastChapterId ?: 0L)
lastChapterId = null lastChapterId = null
@ -286,6 +300,25 @@ class RecentsController(bundle: Bundle? = null) : BaseController(bundle),
return true return true
} }
override fun onItemLongClick(position: Int) {
val item = adapter.getItem(position) as? RecentMangaItem ?: return
val manga = item.mch.manga
val history = item.mch.history
val chapter = item.mch.chapter
if (history.id != null)
RemoveHistoryDialog(this, manga, history, chapter).showDialog(router)
}
override fun removeHistory(manga: Manga, history: History, all: Boolean) {
if (all) {
// Reset last read of chapter to 0L
presenter.removeAllFromHistory(manga.id!!)
} else {
// Remove all chapters belonging to manga from library
presenter.removeFromHistory(history)
}
}
override fun markAsRead(position: Int) { override fun markAsRead(position: Int) {
val item = adapter.getItem(position) as? RecentMangaItem ?: return val item = adapter.getItem(position) as? RecentMangaItem ?: return
val chapter = item.chapter val chapter = item.chapter
@ -323,10 +356,13 @@ class RecentsController(bundle: Bundle? = null) : BaseController(bundle),
} else { } else {
inflater.inflate(R.menu.recents, menu) inflater.inflate(R.menu.recents, menu)
val viewItem = menu.findItem(R.id.action_view) when (presenter.viewType) {
val endless = presenter.groupRecents 0 -> menu.findItem(R.id.action_group_all)
viewItem.setTitle(if (endless) R.string.group_recents else R.string.ungroup_recents) 1 -> menu.findItem(R.id.action_ungroup_all)
viewItem.setIcon(if (endless) R.drawable.ic_view_stream_24dp else R.drawable.ic_view_headline_24dp) 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
@ -385,8 +421,16 @@ class RecentsController(bundle: Bundle? = null) : BaseController(bundle),
if (showingDownloads) if (showingDownloads)
return dl_bottom_sheet.onOptionsItemSelected(item) return dl_bottom_sheet.onOptionsItemSelected(item)
when (item.itemId) { when (item.itemId) {
R.id.action_view -> { R.id.action_group_all, R.id.action_ungroup_all, R.id.action_only_history,
presenter.toggleGroupRecents() 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() activity?.invalidateOptionsMenu()
} }
} }

View File

@ -2,6 +2,8 @@ package eu.kanade.tachiyomi.ui.recents
import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Chapter import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.History
import eu.kanade.tachiyomi.data.database.models.HistoryImpl
import eu.kanade.tachiyomi.data.database.models.LibraryManga import eu.kanade.tachiyomi.data.database.models.LibraryManga
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.models.MangaChapterHistory import eu.kanade.tachiyomi.data.database.models.MangaChapterHistory
@ -13,6 +15,7 @@ import eu.kanade.tachiyomi.data.library.LibraryUpdateService
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.getOrDefault import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.ui.recent_updates.DateItem
import eu.kanade.tachiyomi.util.system.executeOnIO import eu.kanade.tachiyomi.util.system.executeOnIO
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -24,6 +27,7 @@ import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.util.Calendar import java.util.Calendar
import java.util.Date import java.util.Date
import java.util.TreeMap
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import kotlin.math.abs import kotlin.math.abs
@ -41,10 +45,10 @@ class RecentsPresenter(
var query = "" var query = ""
private val newAdditionsHeader = RecentMangaHeaderItem(RecentMangaHeaderItem.NEWLY_ADDED) private val newAdditionsHeader = RecentMangaHeaderItem(RecentMangaHeaderItem.NEWLY_ADDED)
private val newChaptersHeader = RecentMangaHeaderItem(RecentMangaHeaderItem.NEW_CHAPTERS) private val newChaptersHeader = RecentMangaHeaderItem(RecentMangaHeaderItem.NEW_CHAPTERS)
private val endlessHeader = RecentMangaHeaderItem(-1) val generalHeader = RecentMangaHeaderItem(-1)
private val continueReadingHeader = RecentMangaHeaderItem(RecentMangaHeaderItem private val continueReadingHeader = RecentMangaHeaderItem(RecentMangaHeaderItem
.CONTINUE_READING) .CONTINUE_READING)
var groupRecents = preferences.groupRecents().getOrDefault() var viewType: Int = preferences.recentsViewType().getOrDefault()
fun onCreate() { fun onCreate() {
downloadManager.addListener(this) downloadManager.addListener(this)
@ -60,12 +64,13 @@ class RecentsPresenter(
fun getRecents() { fun getRecents() {
val oldQuery = query val oldQuery = query
scope.launch { scope.launch {
val isEndless = groupRecents && query.isEmpty() val isUngrouped = viewType > 0 && query.isEmpty()
// groupRecents && query.isEmpty()
val cal = Calendar.getInstance().apply { val cal = Calendar.getInstance().apply {
time = Date() time = Date()
when { when {
query.isNotEmpty() -> add(Calendar.YEAR, -50) query.isNotEmpty() -> add(Calendar.YEAR, -50)
isEndless -> add(Calendar.MONTH, -1) isUngrouped -> add(Calendar.MONTH, -1)
else -> add(Calendar.MONTH, -1) else -> add(Calendar.MONTH, -1)
} }
} }
@ -74,7 +79,7 @@ class RecentsPresenter(
time = Date() time = Date()
when { when {
query.isNotEmpty() -> add(Calendar.YEAR, -50) query.isNotEmpty() -> add(Calendar.YEAR, -50)
isEndless -> add(Calendar.MONTH, -1) isUngrouped -> add(Calendar.MONTH, -1)
else -> add(Calendar.WEEK_OF_YEAR, -1) else -> add(Calendar.WEEK_OF_YEAR, -1)
} }
} }
@ -83,19 +88,30 @@ class RecentsPresenter(
time = Date() time = Date()
when { when {
query.isNotEmpty() -> add(Calendar.YEAR, -50) query.isNotEmpty() -> add(Calendar.YEAR, -50)
isEndless -> add(Calendar.MONTH, -1) isUngrouped -> add(Calendar.MONTH, -1)
else -> add(Calendar.DAY_OF_YEAR, -1) else -> add(Calendar.DAY_OF_YEAR, -1)
} }
} }
val cReading = val cReading = if (viewType != 3)
if (query.isEmpty()) db.getRecentsWithUnread(cal.time, query, isEndless).executeOnIO() if (query.isEmpty() && viewType != 2)
else db.getRecentMangaLimit(cal.time, 8, query).executeOnIO() db.getRecentsWithUnread(cal.time, query, isUngrouped).executeOnIO()
val rUpdates = db.getUpdatedManga(calWeek.time, query, isEndless).executeOnIO() else db.getRecentMangaLimit(
cal.time,
if (viewType == 2) 200 else 8,
query).executeOnIO() else emptyList()
val rUpdates = when {
viewType == 3 -> db.getRecentChapters(calWeek.time).executeOnIO().map {
MangaChapterHistory(it.manga, it.chapter, HistoryImpl())
}
viewType != 2 -> db.getUpdatedManga(calWeek.time, query, isUngrouped).executeOnIO()
else -> emptyList()
}
rUpdates.forEach { rUpdates.forEach {
it.history.last_read = it.chapter.date_fetch it.history.last_read = it.chapter.date_fetch
} }
val nAdditions = db.getRecentlyAdded(calDay.time, query, isEndless).executeOnIO() val nAdditions = if (viewType < 2)
db.getRecentlyAdded(calDay.time, query, isUngrouped).executeOnIO() else emptyList()
nAdditions.forEach { nAdditions.forEach {
it.history.last_read = it.manga.date_added it.history.last_read = it.manga.date_added
} }
@ -103,19 +119,21 @@ class RecentsPresenter(
val mangaList = (cReading + rUpdates + nAdditions).sortedByDescending { val mangaList = (cReading + rUpdates + nAdditions).sortedByDescending {
it.history.last_read it.history.last_read
}.distinctBy { }.distinctBy {
if (query.isEmpty()) it.manga.id else it.chapter.id if (query.isEmpty() && viewType != 3) it.manga.id else it.chapter.id
} }
val pairs = mangaList.mapNotNull { val pairs = mangaList.mapNotNull {
val chapter = if (it.chapter.read || it.chapter.id == null) getNextChapter(it.manga) val chapter = when {
else if (it.history.id == null) getFirstUpdatedChapter(it.manga, it.chapter) viewType == 3 -> it.chapter
else it.chapter it.chapter.read || it.chapter.id == null -> getNextChapter(it.manga)
if (chapter == null) if (query.isNotEmpty() && it.chapter.id != null) Pair( it.history.id == null -> getFirstUpdatedChapter(it.manga, it.chapter)
it, it.chapter else -> it.chapter
) }
if (chapter == null) if ((query.isNotEmpty() || viewType > 1) &&
it.chapter.id != null) Pair(it, it.chapter)
else null else null
else Pair(it, chapter) else Pair(it, chapter)
} }
if (query.isEmpty() && !groupRecents) { if (query.isEmpty() && !isUngrouped) {
val nChaptersItems = val nChaptersItems =
pairs.filter { it.first.history.id == null && it.first.chapter.id != null } pairs.filter { it.first.history.id == null && it.first.chapter.id != null }
.sortedWith(Comparator<Pair<MangaChapterHistory, Chapter>> { f1, f2 -> .sortedWith(Comparator<Pair<MangaChapterHistory, Chapter>> { f1, f2 ->
@ -148,9 +166,20 @@ class RecentsPresenter(
it.firstOrNull()?.mch?.history?.last_read ?: 0L it.firstOrNull()?.mch?.history?.last_read ?: 0L
}.flatten() }.flatten()
} else { } else {
val header = if (isEndless) endlessHeader else null recentItems =
recentItems = pairs.map { RecentMangaItem(it.first, it.second, header) } if (viewType == 3) {
if (isEndless && recentItems.isEmpty()) { val map = TreeMap<Date, MutableList<Pair<MangaChapterHistory, Chapter>>> {
d1, d2 -> d2
.compareTo(d1) }
val byDay =
pairs.groupByTo(map, { getMapKey(it.first.history.last_read) })
byDay.flatMap {
val dateItem = DateItem(it.key, true)
it.value.map { item ->
RecentMangaItem(item.first, item.second, dateItem) }
}
} else pairs.map { RecentMangaItem(it.first, it.second, null) }
if (isUngrouped && recentItems.isEmpty()) {
recentItems = listOf( recentItems = listOf(
RecentMangaItem(header = newChaptersHeader), RecentMangaItem(header = newChaptersHeader),
RecentMangaItem(header = continueReadingHeader)) RecentMangaItem(header = continueReadingHeader))
@ -183,9 +212,9 @@ class RecentsPresenter(
scope.cancel() scope.cancel()
} }
fun toggleGroupRecents() { fun toggleGroupRecents(pref: Int) {
preferences.groupRecents().set(!groupRecents) preferences.recentsViewType().set(pref)
groupRecents = !groupRecents viewType = pref
getRecents() getRecents()
} }
@ -236,6 +265,22 @@ class RecentsPresenter(
} }
} }
/**
* Get date as time key
*
* @param date desired date
* @return date as time key
*/
private fun getMapKey(date: Long): Date {
val cal = Calendar.getInstance()
cal.time = Date(date)
cal[Calendar.HOUR_OF_DAY] = 0
cal[Calendar.MINUTE] = 0
cal[Calendar.SECOND] = 0
cal[Calendar.MILLISECOND] = 0
return cal.time
}
/** /**
* Downloads the given list of chapters with the manager. * Downloads the given list of chapters with the manager.
* @param chapter the chapter to download. * @param chapter the chapter to download.
@ -272,7 +317,29 @@ class RecentsPresenter(
} }
} }
private companion object { // History
/**
* Reset last read of chapter to 0L
* @param history history belonging to chapter
*/
fun removeFromHistory(history: History) {
history.last_read = 0L
db.updateHistoryLastRead(history).executeAsBlocking()
getRecents()
}
/**
* Removes all chapters belonging to manga from history.
* @param mangaId id of manga
*/
fun removeAllFromHistory(mangaId: Long) {
val history = db.getHistoryByMangaId(mangaId).executeAsBlocking()
history.forEach { it.last_read = 0L }
db.updateHistoryLastRead(history).executeAsBlocking()
getRecents()
}
companion object {
var lastRecents: List<RecentMangaItem>? = null var lastRecents: List<RecentMangaItem>? = null
} }
} }

View File

@ -11,7 +11,7 @@
android:icon="@drawable/recent_read_selector_24dp" android:icon="@drawable/recent_read_selector_24dp"
android:title="@string/recents" /> android:title="@string/recents" />
<item <item
android:id="@+id/nav_catalogues" android:id="@+id/nav_browse"
android:icon="@drawable/browse_selector_24dp" android:icon="@drawable/browse_selector_24dp"
android:title="@string/browse" /> android:title="@string/browse" />
</group> </group>

View File

@ -6,15 +6,31 @@
android:id="@+id/action_search" android:id="@+id/action_search"
android:icon="@drawable/ic_search_white_24dp" android:icon="@drawable/ic_search_white_24dp"
android:title="@string/search" android:title="@string/search"
app:actionViewClass="androidx.appcompat.widget.SearchView"
android:visible="false" android:visible="false"
app:actionViewClass="androidx.appcompat.widget.SearchView"
app:showAsAction="ifRoom|collapseActionView" /> app:showAsAction="ifRoom|collapseActionView" />
<item <item
android:id="@+id/action_view" android:id="@+id/action_filter"
android:icon="@drawable/ic_view_stream_24dp" android:icon="@drawable/ic_filter_list_white_24dp"
android:title="@string/group_recents" android:title="@string/group_all"
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_white_24dp" android:icon="@drawable/ic_settings_white_24dp"

View File

@ -177,7 +177,10 @@
<string name="history">History</string> <string name="history">History</string>
<string name="recently_read">Recently read</string> <string name="recently_read">Recently read</string>
<string name="recent_updates">Recent updates</string> <string name="recent_updates">Recent updates</string>
<string name="this_will_remove_the_read_date_question">This will remove the read date of this chapter. Are you sure?</string> <string name="this_will_remove_the_read_date_for_x_question">This will remove the read date of
\"%1$s\". Are you sure?</string>
<string name="this_will_remove_the_read_date_question">This will remove the read date of this
chapter. Are you sure?</string>
<string name="reset_all_chapters_for_this_">Reset all chapters for this %1$s</string> <string name="reset_all_chapters_for_this_">Reset all chapters for this %1$s</string>
<string name="source_dash_chapter_">%1$s - Ch.%2$s</string> <string name="source_dash_chapter_">%1$s - Ch.%2$s</string>
<string name="last_read_">Last read %1$s</string> <string name="last_read_">Last read %1$s</string>
@ -190,8 +193,12 @@
<string name="search_recents">Search recents…</string> <string name="search_recents">Search recents…</string>
<string name="no_recent_chapters">No recent chapters</string> <string name="no_recent_chapters">No recent chapters</string>
<string name="no_recently_read_manga">No recently read manga</string> <string name="no_recently_read_manga">No recently read manga</string>
<string name="group_recents">Group recents</string> <string name="group_all">Group all</string>
<string name="ungroup_recents">Ungroup recents</string> <string name="ungroup_all">Ungroup all</string>
<string name="only_history">Only history</string>
<string name="only_updates">Only updates</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>
<!-- Browse --> <!-- Browse -->
<string name="search_filters">Search filters</string> <string name="search_filters">Search filters</string>