Updates to Date Added

On upgrade, assign date added to the earliest chapter fetch
Added "Newly Added" section to recents
Reformated Recents to use a single recyclerview
pull/3117/head
Jay 5 years ago
parent 0154653a2f
commit 5963c09691

@ -65,7 +65,7 @@ object Migrations {
if (oldVersion < 54)
DownloadProvider(context).renameChaapters()
if (oldVersion < 62)
LibraryPresenter.resetCustomManga()
LibraryPresenter.updateDB()
return true
}
return false

@ -7,4 +7,8 @@ package eu.kanade.tachiyomi.data.database.models
* @param chapter object containing chater
* @param history object containing history
*/
data class MangaChapterHistory(val manga: Manga, val chapter: Chapter, val history: History)
data class MangaChapterHistory(val manga: Manga, val chapter: Chapter, val history: History) {
companion object {
fun createBlank() = MangaChapterHistory(MangaImpl(), ChapterImpl(), HistoryImpl())
}
}

@ -8,6 +8,7 @@ import eu.kanade.tachiyomi.data.database.models.MangaChapterHistory
import eu.kanade.tachiyomi.data.database.resolvers.HistoryLastReadPutResolver
import eu.kanade.tachiyomi.data.database.resolvers.MangaChapterHistoryGetResolver
import eu.kanade.tachiyomi.data.database.tables.HistoryTable
import eu.kanade.tachiyomi.data.database.tables.MangaTable
import java.util.Date
interface HistoryQueries : DbProvider {
@ -33,6 +34,21 @@ interface HistoryQueries : DbProvider {
.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 getRecentlyAdded(date: Date, search: String = "") = db.get()
.listOfObjects(MangaChapterHistory::class.java)
.withQuery(RawQuery.builder()
.query(getRecentAdditionsQuery(search))
.args(date.time)
.observesTables(MangaTable.TABLE)
.build())
.withGetResolver(MangaChapterHistoryGetResolver.INSTANCE)
.prepare()
/**
* Returns history of recent manga containing last read chapter in 25s
* @param date recent date range

@ -61,6 +61,18 @@ fun getRecentsQuery() = """
ORDER BY ${Chapter.COL_DATE_UPLOAD} DESC
"""
/**
* Query to get the recent chapters of manga from the library up to a date.
*/
fun getRecentAdditionsQuery(search: String) = """
SELECT ${Manga.TABLE}.${Manga.COL_URL} as mangaUrl, * FROM ${Manga.TABLE}
WHERE ${Manga.COL_FAVORITE} = 1
AND ${Manga.COL_DATE_ADDED} > ?
AND lower(${Manga.COL_TITLE}) LIKE '%$search%'
ORDER BY ${Manga.COL_DATE_ADDED} DESC
LIMIT 8
"""
/**
* Query to get the recent chapters of manga from the library up to a date.
*/
@ -73,7 +85,7 @@ fun getRecentsQueryDistinct(search: String) = """
SELECT ${Chapter.TABLE}.${Chapter.COL_MANGA_ID},${Chapter.TABLE}.${Chapter.COL_ID} as ${History.COL_CHAPTER_ID},MAX(${Chapter.TABLE}.${Chapter.COL_DATE_UPLOAD})
FROM ${Chapter.TABLE} JOIN ${Manga.TABLE}
ON ${Manga.TABLE}.${Manga.COL_ID} = ${Chapter.TABLE}.${Chapter.COL_MANGA_ID}
WHERE ${Chapter.COL_DATE_FETCH} > ?
WHERE ${Chapter.COL_DATE_UPLOAD} > ?
AND ${Chapter.COL_READ} = 0
GROUP BY ${Chapter.TABLE}.${Chapter.COL_MANGA_ID}) AS newest_chapter
ON ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} = newest_chapter.${Chapter.COL_MANGA_ID}

@ -5,6 +5,7 @@ import com.pushtorefresh.storio.sqlite.operations.get.DefaultGetResolver
import eu.kanade.tachiyomi.data.database.mappers.ChapterGetResolver
import eu.kanade.tachiyomi.data.database.mappers.HistoryGetResolver
import eu.kanade.tachiyomi.data.database.mappers.MangaGetResolver
import eu.kanade.tachiyomi.data.database.models.ChapterImpl
import eu.kanade.tachiyomi.data.database.models.HistoryImpl
import eu.kanade.tachiyomi.data.database.models.MangaChapterHistory
@ -36,14 +37,17 @@ class MangaChapterHistoryGetResolver : DefaultGetResolver<MangaChapterHistory>()
val manga = mangaGetResolver.mapFromCursor(cursor)
// Get chapter object
val chapter = chapterResolver.mapFromCursor(cursor)
val chapter = try { chapterResolver.mapFromCursor(cursor) } catch (e: Exception) {
ChapterImpl() }
// Get history object
val history = try { historyGetResolver.mapFromCursor(cursor) } catch (e: Exception) { HistoryImpl() }
// Make certain column conflicts are dealt with
manga.id = chapter.manga_id
manga.url = cursor.getString(cursor.getColumnIndex("mangaUrl"))
if (chapter.id != null) {
manga.id = chapter.manga_id
manga.url = cursor.getString(cursor.getColumnIndex("mangaUrl"))
}
if (history.id != null)
chapter.id = history.chapter_id

@ -55,7 +55,8 @@ import kotlin.math.pow
import kotlin.math.roundToInt
import kotlin.math.sign
class LibraryListController(bundle: Bundle? = null) : LibraryController(bundle),
class
LibraryListController(bundle: Bundle? = null) : LibraryController(bundle),
FlexibleAdapter.OnItemClickListener, FlexibleAdapter.OnItemLongClickListener,
FlexibleAdapter.OnItemMoveListener, LibraryCategoryAdapter.LibraryListener,
SpinnerTitleInterface, OnTouchEventInterface, SwipeGestureInterface {

@ -927,11 +927,16 @@ class LibraryPresenter(
companion object {
private var currentLibrary: Library? = null
fun resetCustomManga() {
fun updateDB() {
val db: DatabaseHelper = Injekt.get()
db.inTransaction {
val libraryManga = db.getLibraryMangas().executeAsBlocking()
libraryManga.forEach { manga ->
if (manga.date_added == 0L) {
val chapters = db.getChapters(manga).executeAsBlocking()
manga.date_added = chapters.minBy { it.date_fetch }?.date_fetch ?: 0L
db.insertManga(manga).executeAsBlocking()
}
db.resetMangaInfo(manga).executeAsBlocking()
}
}

@ -7,6 +7,6 @@ object LibrarySort {
const val LATEST_CHAPTER = 2
const val UNREAD = 3
const val TOTAL = 4
const val DATE_ADDED = 5
const val DRAG_AND_DROP = 6
const val DATE_ADDED = 7
}

@ -13,11 +13,11 @@ open class BaseChapterHolder(
) : BaseFlexibleViewHolder(view, adapter) {
init {
download_button.setOnClickListener { downloadOrRemoveMenu() }
download_button?.setOnClickListener { downloadOrRemoveMenu() }
}
private fun downloadOrRemoveMenu() {
val chapter = adapter.getItem(adapterPosition) as? BaseChapterItem ?: return
val chapter = adapter.getItem(adapterPosition) as? BaseChapterItem<*, *> ?: return
if (chapter.status == Download.NOT_DOWNLOADED || chapter.status == Download.ERROR) {
adapter.baseDelegate.downloadChapter(adapterPosition)
} else {

@ -1,12 +1,17 @@
package eu.kanade.tachiyomi.ui.manga.chapter
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
import eu.davidea.flexibleadapter.items.AbstractHeaderItem
import eu.davidea.flexibleadapter.items.AbstractSectionableItem
import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.source.model.Page
abstract class BaseChapterItem<T : BaseChapterHolder>(val chapter: Chapter) :
AbstractFlexibleItem<T>(),
abstract class BaseChapterItem<T : BaseChapterHolder, H : AbstractHeaderItem<*>>(
val chapter:
Chapter,
header: H? = null
) :
AbstractSectionableItem<T, H?>(header),
Chapter by chapter {
private var _status: Int = 0
@ -28,13 +33,13 @@ abstract class BaseChapterItem<T : BaseChapterHolder>(val chapter: Chapter) :
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other is BaseChapterItem<*>) {
return chapter.id!! == other.chapter.id!!
if (other is BaseChapterItem<*, *>) {
return chapter.id == other.chapter.id
}
return false
}
override fun hashCode(): Int {
return chapter.id!!.hashCode()
return (chapter.id ?: 0L).hashCode()
}
}

@ -3,14 +3,16 @@ package eu.kanade.tachiyomi.ui.manga.chapter
import android.view.View
import androidx.recyclerview.widget.RecyclerView
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.items.AbstractHeaderItem
import eu.davidea.flexibleadapter.items.IFlexible
import eu.davidea.viewholders.FlexibleViewHolder
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.ui.manga.MangaDetailsAdapter
class ChapterItem(chapter: Chapter, val manga: Manga) :
BaseChapterItem<ChapterHolder>(chapter) {
BaseChapterItem<ChapterHolder, AbstractHeaderItem<FlexibleViewHolder>>(chapter) {
var isLocked = false

@ -9,7 +9,11 @@ import java.text.DecimalFormat
import java.text.DecimalFormatSymbols
class RecentMangaAdapter(val delegate: RecentsInterface) :
BaseChapterAdapter<IFlexible<RecentMangaHolder>>(delegate) {
BaseChapterAdapter<IFlexible<*>>(delegate) {
init {
setDisplayHeadersAtStartUp(true)
}
val decimalFormat = DecimalFormat("#.###", DecimalFormatSymbols()
.apply { decimalSeparator = '.' })
@ -17,9 +21,11 @@ class RecentMangaAdapter(val delegate: RecentsInterface) :
interface RecentsInterface : RecentMangaInterface, DownloadInterface
interface RecentMangaInterface {
fun onHeaderClick(position: Int)
fun onCoverClick(position: Int)
fun markAsRead(position: Int)
fun setCover(manga: Manga, view: ImageView)
fun isSearching(): Boolean
}
override fun onItemSwiped(position: Int, direction: Int) {

@ -0,0 +1,68 @@
package eu.kanade.tachiyomi.ui.recents
import android.view.View
import androidx.recyclerview.widget.RecyclerView
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.items.AbstractHeaderItem
import eu.davidea.flexibleadapter.items.IFlexible
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
import eu.kanade.tachiyomi.ui.library.LibraryHeaderItem
import kotlinx.android.synthetic.main.recents_header_item.*
class RecentMangaHeaderItem(val recentsType: Int) :
AbstractHeaderItem<RecentMangaHeaderItem.Holder>() {
override fun getLayoutRes(): Int {
return R.layout.recents_header_item
}
override fun createViewHolder(
view: View,
adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>
): Holder {
return Holder(view, adapter as RecentMangaAdapter)
}
override fun bindViewHolder(
adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>,
holder: Holder,
position: Int,
payloads: MutableList<Any?>?
) {
holder.bind(recentsType)
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other is LibraryHeaderItem) {
return recentsType == recentsType
}
return false
}
override fun isDraggable(): Boolean {
return false
}
override fun isSwipeable(): Boolean {
return false
}
override fun hashCode(): Int {
return recentsType.hashCode()
}
class Holder(val view: View, adapter: RecentMangaAdapter) : BaseFlexibleViewHolder(view, adapter,
true) {
fun bind(recentsType: Int) {
title.setText(when (recentsType) {
RecentsItem.CONTINUE_READING -> R.string.continue_reading
RecentsItem.NEW_CHAPTERS -> R.string.new_chapters
RecentsItem.NEWLY_ADDED -> R.string.new_additions
else -> R.string.continue_reading
})
}
}
}

@ -17,46 +17,55 @@ class RecentMangaHolder(
) : BaseChapterHolder(view, adapter) {
init {
cover_thumbnail.setOnClickListener { adapter.delegate.onCoverClick(adapterPosition) }
cover_thumbnail?.setOnClickListener { adapter.delegate.onCoverClick(adapterPosition) }
}
fun bind(recentsType: Int) {
when (recentsType) {
RecentsItem.CONTINUE_READING -> {
title.setText(R.string.view_history)
}
RecentsItem.NEW_CHAPTERS -> {
title.setText(R.string.view_all_updates)
}
}
}
fun bind(item: RecentMangaItem) {
download_button.visibleIf(item.mch.manga.source != LocalSource.ID)
title.text = item.mch.manga.title
val holder = (adapter.delegate as RecentsHolder)
val isSearch =
(holder.adapter.getItem(holder.adapterPosition) as RecentsItem).recentType == RecentsItem.SEARCH
val isSearch = adapter.delegate.isSearching()
subtitle.text = item.chapter.name
body.text = if (isSearch) when {
val notValidNum = item.mch.chapter.chapter_number <= 0
body.text = when {
item.mch.chapter.id == null -> body.context.getString(
R.string.added_x, DateUtils.getRelativeTimeSpanString(
item.mch.manga.date_added, Date().time, DateUtils.MINUTE_IN_MILLIS
).toString()
)
item.chapter.id != item.mch.chapter.id -> body.context.getString(
R.string.last_read_chapter_x, adapter.decimalFormat.format(
item.mch.chapter.chapter_number
) + " (${DateUtils.getRelativeTimeSpanString(
if (notValidNum) R.string.last_read_x else R.string.last_read_chapter_x,
if (notValidNum) item.mch.chapter.name else adapter.decimalFormat.format(item.mch.chapter.chapter_number) +
" (${DateUtils.getRelativeTimeSpanString(
item.mch.history.last_read, Date().time, DateUtils.MINUTE_IN_MILLIS
)})"
)
item.mch.history.id == null -> body.context.getString(
R.string.uploaded_x, DateUtils.getRelativeTimeSpanString(
R.string.updated_x, DateUtils.getRelativeTimeSpanString(
item.chapter.date_upload, Date().time, DateUtils.HOUR_IN_MILLIS
).toString()
)
else -> body.context.getString(
R.string.last_read_x, DateUtils.getRelativeTimeSpanString(
!isSearch && item.chapter.pages_left > 0 -> itemView.resources.getQuantityString(
R.plurals.pages_left, item.chapter.pages_left, item.chapter.pages_left
) +
" (${DateUtils.getRelativeTimeSpanString(
item.mch.history.last_read, Date().time, DateUtils.MINUTE_IN_MILLIS
)})"
isSearch -> body.context.getString(
R.string.read_x, DateUtils.getRelativeTimeSpanString(
item.mch.history.last_read, Date().time, DateUtils.MINUTE_IN_MILLIS
).toString()
)
} else when {
item.chapter.id != item.mch.chapter.id -> body.context.getString(
R.string.last_read_chapter_x, adapter.decimalFormat.format(
item.mch.chapter.chapter_number
)
)
item.mch.history.id == null -> DateUtils.getRelativeTimeSpanString(
item.chapter.date_upload, Date().time, DateUtils.HOUR_IN_MILLIS
).toString()
item.chapter.pages_left > 0 -> itemView.resources.getQuantityString(
R.plurals.pages_left, item.chapter.pages_left, item.chapter.pages_left
)
else -> ""
}
adapter.delegate.setCover(item.mch.manga, cover_thumbnail)

@ -6,14 +6,21 @@ import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.items.IFlexible
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.ChapterImpl
import eu.kanade.tachiyomi.data.database.models.MangaChapterHistory
import eu.kanade.tachiyomi.ui.manga.chapter.BaseChapterItem
class RecentMangaItem(val mch: MangaChapterHistory, chapter: Chapter) :
BaseChapterItem<RecentMangaHolder>(chapter) {
class RecentMangaItem(
val mch: MangaChapterHistory = MangaChapterHistory.createBlank(),
chapter: Chapter = ChapterImpl(),
header:
RecentMangaHeaderItem?
) :
BaseChapterItem<RecentMangaHolder, RecentMangaHeaderItem>(chapter, header) {
override fun getLayoutRes(): Int {
return R.layout.recent_manga_item
return if (mch.manga.id == null) R.layout.recents_footer_item
else R.layout.recent_manga_item
}
override fun createViewHolder(
@ -23,12 +30,31 @@ class RecentMangaItem(val mch: MangaChapterHistory, chapter: Chapter) :
return RecentMangaHolder(view, adapter as RecentMangaAdapter)
}
override fun isSwipeable(): Boolean {
return mch.manga.id != null
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other is RecentMangaItem) {
return if (mch.manga.id == null) header?.recentsType == other.header?.recentsType
else chapter.id == other.chapter.id
}
return false
}
override fun hashCode(): Int {
return if (mch.manga.id == null) -(header?.recentsType ?: 0).hashCode()
else (chapter.id ?: 0L).hashCode()
}
override fun bindViewHolder(
adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>,
holder: RecentMangaHolder,
position: Int,
payloads: MutableList<Any?>?
) {
holder.bind(this)
if (mch.manga.id == null) holder.bind(header?.recentsType ?: 0)
else holder.bind(this)
}
}

@ -10,6 +10,7 @@ import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import androidx.appcompat.widget.SearchView
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import com.bluelinelabs.conductor.Controller
import com.bluelinelabs.conductor.ControllerChangeHandler
@ -48,8 +49,9 @@ import kotlinx.android.synthetic.main.recently_read_controller.*
* UI related actions should be called from here.
*/
class RecentsController(bundle: Bundle? = null) : BaseController(bundle),
FlexibleAdapter.OnUpdateListener,
RecentMangaAdapter.RecentsInterface,
RecentsAdapter.RecentsInterface,
FlexibleAdapter.OnItemClickListener,
RootSearchInterface {
init {
@ -59,10 +61,11 @@ class RecentsController(bundle: Bundle? = null) : BaseController(bundle),
/**
* Adapter containing the recent manga.
*/
private val adapter = RecentsAdapter(this)
// private val adapter = RecentsAdapter(this)
private var adapter = RecentMangaAdapter(this)
private var presenter = RecentsPresenter(this)
private var recentItems: List<RecentsItem>? = null
private var recentItems: List<RecentMangaItem>? = null
private var snack: Snackbar? = null
private var lastChapterId: Long? = null
@ -83,10 +86,20 @@ class RecentsController(bundle: Bundle? = null) : BaseController(bundle),
super.onViewCreated(view)
view.applyWindowInsetsForRootController(activity!!.bottom_nav)
// Initialize adapter
adapter = RecentMangaAdapter(this)
recycler.adapter = adapter
recycler.layoutManager = LinearLayoutManager(view.context)
recycler.setHasFixedSize(true)
recycler.recycledViewPool.setMaxRecycledViews(0, 0)
adapter.isSwipeEnabled = true
/*recycler.addItemDecoration(
DividerItemDecoration(
recycler.context, DividerItemDecoration.VERTICAL
)
)*/
adapter.itemTouchHelperCallback.setSwipeFlags(
ItemTouchHelper.LEFT
)
scrollViewWith(recycler, skipFirstSnap = true)
if (recentItems != null) adapter.updateDataSet(recentItems!!.toList())
@ -108,37 +121,42 @@ class RecentsController(bundle: Bundle? = null) : BaseController(bundle),
fun refresh() = presenter.getRecents()
fun showLists(recents: List<RecentsItem>) {
fun showLists(recents: List<RecentMangaItem>) {
recentItems = recents
adapter.updateDataSet(recents)
if (lastChapterId != null) {
refreshItem(lastChapterId ?: 0L)
lastChapterId = null
}
}
override fun onUpdateEmptyView(size: Int) {
if (size > 0) {
empty_view?.hide()
} else {
empty_view?.show(R.drawable.ic_history_white_128dp, R.string
.information_no_recent_manga)
}
// recycler.removeItemDecorationAt(0)
}
fun updateChapterDownload(download: Download) {
if (view == null) return
for (i in 0 until adapter.itemCount) {
val id = download.chapter.id ?: return
val holder = recycler.findViewHolderForItemId(id) as? RecentMangaHolder ?: return
holder.notifyStatus(download.status, download.progress)
/* (i in 0 until adapter.itemCount) {
val holder = recycler.findViewHolderForAdapterPosition(i) as? RecentsHolder ?: continue
if (holder.updateChapterDownload(download)) break
}
}*/
}
private fun refreshItem(chapterId: Long) {
val recentItemPos = adapter.currentItems.indexOfFirst {
it is RecentMangaItem &&
it.mch.chapter.id == chapterId }
if (recentItemPos > -1) adapter.notifyItemChanged(recentItemPos)
/*holder.notifyStatus(download.status, download.progress)
for (i in 0 until adapter.itemCount) {
val holder = recycler.findViewHolderForAdapterPosition(i) as? RecentsHolder ?: continue
holder.refreshChapter(chapterId)
}
}*/
}
override fun downloadChapter(position: Int) {
val item = adapter.getItem(position) as? RecentMangaItem ?: return
downloadChapter(item)
}
override fun downloadChapter(item: RecentMangaItem) {
@ -153,18 +171,49 @@ class RecentsController(bundle: Bundle? = null) : BaseController(bundle),
}
}
override fun startDownloadNow(position: Int) {
val chapter = (adapter.getItem(position) as? RecentMangaItem)?.chapter ?: return
presenter.startDownloadChapterNow(chapter)
}
override fun downloadChapterNow(chapter: Chapter) {
presenter.startDownloadChapterNow(chapter)
}
override fun onCoverClick(position: Int) {
val manga = (adapter.getItem(position) as? RecentMangaItem)?.mch?.manga ?: return
router.pushController(MangaDetailsController(manga).withFadeTransaction())
}
override fun showManga(manga: Manga) = router.pushController(MangaDetailsController(manga).withFadeTransaction())
override fun onItemClick(view: View?, position: Int): Boolean {
val item = adapter.getItem(position) ?: return false
if (item is RecentMangaItem) {
if (item.mch.manga.id == null) {
val headerItem = adapter.getHeaderOf(item) as? RecentMangaHeaderItem
val controller: Controller = when (headerItem?.recentsType) {
RecentsItem.NEW_CHAPTERS -> RecentChaptersController()
RecentsItem.CONTINUE_READING -> RecentlyReadController()
else -> return false
}
router.pushController(controller.withFadeTransaction())
} else resumeManga(item.mch.manga, item.chapter)
} else if (item is RecentMangaHeaderItem) return false // onHeaderClick(position)
return true
}
override fun resumeManga(manga: Manga, chapter: Chapter) {
val activity = activity ?: return
val intent = ReaderActivity.newIntent(activity, manga, chapter)
startActivity(intent)
}
override fun markAsRead(position: Int) {
val item = adapter.getItem(position) as? RecentMangaItem ?: return
markAsRead(item.mch.manga, item.chapter)
}
override fun markAsRead(manga: Manga, chapter: Chapter) {
val lastRead = chapter.last_page_read
val pagesLeft = chapter.pages_left
@ -191,6 +240,8 @@ class RecentsController(bundle: Bundle? = null) : BaseController(bundle),
(activity as? MainActivity)?.setUndoSnackBar(snack)
}
override fun isSearching() = presenter.query.isNotEmpty()
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.recents, menu)
val searchItem = menu.findItem(R.id.action_search)
@ -229,8 +280,9 @@ class RecentsController(bundle: Bundle? = null) : BaseController(bundle),
.signature(ObjectKey(MangaImpl.getLastCoverFetch(manga.id!!).toString())).into(view)
}
override fun viewAll(position: Int) {
val recentsType = (adapter.getItem(position) as? RecentsItem)?.recentType ?: return
override fun onHeaderClick(position: Int) {
val recentsType = (adapter.getItem(position) as? RecentMangaHeaderItem)?.recentsType
?: return
val controller: Controller = when (recentsType) {
RecentsItem.NEW_CHAPTERS -> RecentChaptersController()
RecentsItem.CONTINUE_READING -> RecentlyReadController()
@ -239,6 +291,16 @@ class RecentsController(bundle: Bundle? = null) : BaseController(bundle),
router.pushController(controller.withFadeTransaction())
}
override fun viewAll(position: Int) {
/*val recentsType = (adapter.getItem(position) as? RecentsItem)?.recentType ?: return
val controller: Controller = when (recentsType) {
RecentsItem.NEW_CHAPTERS -> RecentChaptersController()
RecentsItem.CONTINUE_READING -> RecentlyReadController()
else -> return
}
router.pushController(controller.withFadeTransaction())*/
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.action_refresh -> {

@ -129,4 +129,8 @@ class RecentsHolder(
val item = (subAdapter.getItem(position) as RecentMangaItem)
adapter.delegate.markAsRead(item.mch.manga, item.chapter)
}
override fun onHeaderClick(position: Int) {
}
override fun isSearching() = false
}

@ -32,9 +32,12 @@ class RecentsPresenter(
private var scope = CoroutineScope(Job() + Dispatchers.Default)
private var recentItems = listOf<RecentMangaItem>()
var groupedRecentItems = listOf<RecentsItem>()
var recentItems = listOf<RecentMangaItem>()
// var groupedRecentItems = listOf<RecentsItem>()
var query = ""
var newAdditionsHeader = RecentMangaHeaderItem(RecentsItem.NEWLY_ADDED)
var newChaptersHeader = RecentMangaHeaderItem(RecentsItem.NEW_CHAPTERS)
var continueReadingHeader = RecentMangaHeaderItem(RecentsItem.CONTINUE_READING)
fun onCreate() {
downloadManager.addListener(this)
@ -43,51 +46,75 @@ class RecentsPresenter(
}
fun getRecents() {
val oldQuery = query
scope.launch {
val cal = Calendar.getInstance()
cal.time = Date()
if (query.isNotEmpty()) cal.add(Calendar.YEAR, -50)
else cal.add(Calendar.MONTH, -1)
val calWeek = Calendar.getInstance()
calWeek.time = Date()
if (query.isNotEmpty()) calWeek.add(Calendar.YEAR, -50)
else calWeek.add(Calendar.DAY_OF_YEAR, -1)
val cReading =
if (query.isEmpty())
db.getRecentsWithUnread(cal.time, query).executeOnIO()
else
db.getRecentMangaLimit(cal.time, 8, query).executeOnIO()
if (query.isEmpty()) db.getRecentsWithUnread(cal.time, query).executeOnIO()
else db.getRecentMangaLimit(cal.time, 8, query).executeOnIO()
val rUpdates = db.getUpdatedManga(cal.time, query).executeOnIO()
rUpdates.forEach {
it.history.last_read = it.chapter.date_upload
it.history.last_read = it.chapter.date_fetch
}
val nAdditions = db.getRecentlyAdded(calWeek.time, query).executeOnIO()
nAdditions.forEach {
it.history.last_read = it.manga.date_added
}
val mangaList = (cReading + rUpdates).sortedByDescending {
if (query != oldQuery) return@launch
val mangaList = (cReading + rUpdates + nAdditions).sortedByDescending {
it.history.last_read
}.distinctBy {
if (query.isEmpty()) it.manga.id else it.chapter.id }
recentItems = mangaList.mapNotNull {
val chapter = if (it.chapter.read) getNextChapter(it.manga)
if (query.isEmpty()) it.manga.id else it.chapter.id
}
val pairs = mangaList.mapNotNull {
val chapter = if (it.chapter.read || it.chapter.id == null) getNextChapter(it.manga)
else it.chapter
if (chapter == null) if (query.isNotEmpty()) RecentMangaItem(it, it.chapter)
if (chapter == null) if (query.isNotEmpty() && it.chapter.id != null) Pair(
it, it.chapter
)
else null
else RecentMangaItem(it, chapter)
else Pair(it, chapter)
}
setDownloadedChapters(recentItems)
if (query.isEmpty()) {
val nChaptersItems = RecentsItem(
RecentsItem.NEW_CHAPTERS,
recentItems.filter { it.mch.history.id == null }.take(4)
)
val cReadingItems = RecentsItem(
RecentsItem.CONTINUE_READING,
recentItems.filter { it.mch.history.id != null }.take(
8 - nChaptersItems.mangaList.size
)
)
// TODO: Add Date Added
groupedRecentItems = listOf(cReadingItems, nChaptersItems).sortedByDescending {
it.mangaList.firstOrNull()?.mch?.history?.last_read ?: 0
}
val nChaptersItems =
pairs.filter { it.first.history.id == null && it.first.chapter.id != null }
.sortedByDescending { it.second.date_upload }
.take(4).map {
RecentMangaItem(
it.first,
it.second,
newChaptersHeader
)
} +
RecentMangaItem(header = newChaptersHeader)
val cReadingItems =
pairs.filter { it.first.history.id != null }.take(9 - nChaptersItems.size).map {
RecentMangaItem(
it.first,
it.second,
continueReadingHeader
)
} + RecentMangaItem(header = continueReadingHeader)
val nAdditionsItems = pairs.filter { it.first.chapter.id == null }.take(4)
.map { RecentMangaItem(it.first, it.second, newAdditionsHeader) }
recentItems =
listOf(nChaptersItems, cReadingItems, nAdditionsItems).sortedByDescending {
it.firstOrNull()?.mch?.history?.last_read ?: 0L
}.flatten()
} else {
groupedRecentItems = listOf(RecentsItem(RecentsItem.SEARCH, recentItems))
recentItems = pairs.map { RecentMangaItem(it.first, it.second, null) }
}
withContext(Dispatchers.Main) { controller.showLists(groupedRecentItems) }
setDownloadedChapters(recentItems)
withContext(Dispatchers.Main) { controller.showLists(recentItems) }
}
}
@ -147,7 +174,7 @@ class RecentsPresenter(
download = null
}
controller.showLists(groupedRecentItems)
controller.showLists(recentItems)
}
}

@ -173,5 +173,14 @@
android:layout_height="6dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/bottom_line" />
<View
android:layout_width="0dp"
android:layout_height="1dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginStart="10dp"
android:background="?android:attr/divider"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>

@ -0,0 +1,34 @@
<?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/recent_item"
android:background="?selectable_list_drawable"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="6dp"
android:layout_marginBottom="12dp"
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
app:layout_constraintStart_toEndOf="@id/arrow"
app:layout_constraintTop_toTopOf="parent"
android:textColor="?colorAccent"
app:layout_constraintBottom_toBottomOf="parent"
tools:text="@string/view_all_updates" />
<ImageView
android:id="@+id/arrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_arrow_forward_white_24dp"
android:tint="?colorAccent"
android:layout_marginStart="12dp"
app:layout_constraintTop_toTopOf="@id/title"
app:layout_constraintBottom_toBottomOf="@id/title"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -0,0 +1,23 @@
<?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/recent_item"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="8dp"
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline6"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
tools:text="@string/label_recent_updates" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -21,7 +21,7 @@
<string name="label_catalogues">Catalogues</string>
<string name="label_recent_updates">Recent updates</string>
<string name="new_chapters">New chapters</string>
<string name="new_additions">New additions</string>
<string name="new_additions">Newly added</string>
<string name="label_selected">Selected: %1$d</string>
<string name="label_migration">Source migration</string>
<string name="label_extensions">Extensions</string>
@ -761,7 +761,9 @@
<string name="previously_read_chapter">Previously read Chapter %1$s</string>
<string name="last_read_chapter_x">Last read Chapter %1$s</string>
<string name="last_read_x">Last read %1$s</string>
<string name="uploaded_x">Uploaded %1$s</string>
<string name="read_x">Read %1$s</string>
<string name="updated_x">Updated %1$s</string>
<string name="added_x">Added %1$s</string>
<string name="view_history">View history</string>
<string name="view_all_updates">View all updates</string>
<string name="marked_as_read">Marked as read</string>

Loading…
Cancel
Save