|
|
|
@ -41,7 +41,7 @@ class RecentChaptersPresenter : BasePresenter<RecentChaptersFragment>() {
|
|
|
|
|
/**
|
|
|
|
|
* List containing chapter and manga information
|
|
|
|
|
*/
|
|
|
|
|
private var chapters: List<RecentChapter>? = null
|
|
|
|
|
private var chapters: List<RecentChapterItem> = emptyList()
|
|
|
|
|
|
|
|
|
|
override fun onCreate(savedState: Bundle?) {
|
|
|
|
|
super.onCreate(savedState)
|
|
|
|
@ -53,15 +53,15 @@ class RecentChaptersPresenter : BasePresenter<RecentChaptersFragment>() {
|
|
|
|
|
getChapterStatusObservable()
|
|
|
|
|
.subscribeLatestCache(RecentChaptersFragment::onChapterStatusChange,
|
|
|
|
|
{ view, error -> Timber.e(error) })
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get observable containing recent chapters and date
|
|
|
|
|
*
|
|
|
|
|
* @return observable containing recent chapters and date
|
|
|
|
|
*/
|
|
|
|
|
fun getRecentChaptersObservable(): Observable<ArrayList<Any>> {
|
|
|
|
|
// Set date for recent chapters
|
|
|
|
|
fun getRecentChaptersObservable(): Observable<List<RecentChapterItem>> {
|
|
|
|
|
// Set date limit for recent chapters
|
|
|
|
|
val cal = Calendar.getInstance().apply {
|
|
|
|
|
time = Date()
|
|
|
|
|
add(Calendar.MONTH, -1)
|
|
|
|
@ -70,33 +70,48 @@ class RecentChaptersPresenter : BasePresenter<RecentChaptersFragment>() {
|
|
|
|
|
return db.getRecentChapters(cal.time).asRxObservable()
|
|
|
|
|
// Convert to a list of recent chapters.
|
|
|
|
|
.map { mangaChapters ->
|
|
|
|
|
mangaChapters.map { it.toModel() }
|
|
|
|
|
val map = TreeMap<Date, MutableList<MangaChapter>> { d1, d2 -> d2.compareTo(d1) }
|
|
|
|
|
val byDay = mangaChapters.groupByTo(map, { getMapKey(it.chapter.date_fetch) })
|
|
|
|
|
byDay.flatMap {
|
|
|
|
|
val dateItem = DateItem(it.key)
|
|
|
|
|
it.value.map { RecentChapterItem(it.chapter, it.manga, dateItem) }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
.doOnNext {
|
|
|
|
|
setDownloadedChapters(it)
|
|
|
|
|
chapters = it
|
|
|
|
|
}
|
|
|
|
|
// Group chapters by the date they were fetched on a ordered map.
|
|
|
|
|
.flatMap { recentItems ->
|
|
|
|
|
Observable.from(recentItems)
|
|
|
|
|
.toMultimap(
|
|
|
|
|
{ getMapKey(it.date_fetch) },
|
|
|
|
|
{ it },
|
|
|
|
|
{ TreeMap { d1, d2 -> d2.compareTo(d1) } })
|
|
|
|
|
}
|
|
|
|
|
// Add every day and all its chapters to a single list.
|
|
|
|
|
.map { recentItems ->
|
|
|
|
|
ArrayList<Any>().apply {
|
|
|
|
|
for ((key, value) in recentItems) {
|
|
|
|
|
add(key)
|
|
|
|
|
addAll(value)
|
|
|
|
|
it.forEach { item ->
|
|
|
|
|
// Find an active download for this chapter.
|
|
|
|
|
val download = downloadManager.queue.find { it.chapter.id == item.chapter.id }
|
|
|
|
|
|
|
|
|
|
// If there's an active download, assign it, otherwise ask the manager if the chapter is
|
|
|
|
|
// downloaded and assign it to the status.
|
|
|
|
|
if (download != null) {
|
|
|
|
|
item.download = download
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
setDownloadedChapters(it)
|
|
|
|
|
chapters = it
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 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
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns observable containing chapter status.
|
|
|
|
|
*
|
|
|
|
|
* @return download object containing download progress.
|
|
|
|
|
*/
|
|
|
|
|
private fun getChapterStatusObservable(): Observable<Download> {
|
|
|
|
@ -105,38 +120,21 @@ class RecentChaptersPresenter : BasePresenter<RecentChaptersFragment>() {
|
|
|
|
|
.doOnNext { download -> onDownloadStatusChange(download) }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Converts a chapter from the database to an extended model, allowing to store new fields.
|
|
|
|
|
*/
|
|
|
|
|
private fun MangaChapter.toModel(): RecentChapter {
|
|
|
|
|
// Create the model object.
|
|
|
|
|
val model = RecentChapter(this)
|
|
|
|
|
|
|
|
|
|
// Find an active download for this chapter.
|
|
|
|
|
val download = downloadManager.queue.find { it.chapter.id == chapter.id }
|
|
|
|
|
|
|
|
|
|
// If there's an active download, assign it, otherwise ask the manager if the chapter is
|
|
|
|
|
// downloaded and assign it to the status.
|
|
|
|
|
if (download != null) {
|
|
|
|
|
model.download = download
|
|
|
|
|
}
|
|
|
|
|
return model
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Finds and assigns the list of downloaded chapters.
|
|
|
|
|
*
|
|
|
|
|
* @param chapters the list of chapter from the database.
|
|
|
|
|
* @param items the list of chapter from the database.
|
|
|
|
|
*/
|
|
|
|
|
private fun setDownloadedChapters(chapters: List<RecentChapter>) {
|
|
|
|
|
private fun setDownloadedChapters(items: List<RecentChapterItem>) {
|
|
|
|
|
// Cached list of downloaded manga directories.
|
|
|
|
|
val mangaDirectories = mutableMapOf<Long, Array<UniFile>>()
|
|
|
|
|
|
|
|
|
|
// Cached list of downloaded chapter directories for a manga.
|
|
|
|
|
val chapterDirectories = mutableMapOf<Long, Array<UniFile>>()
|
|
|
|
|
|
|
|
|
|
for (chapter in chapters) {
|
|
|
|
|
val manga = chapter.manga
|
|
|
|
|
for (item in items) {
|
|
|
|
|
val manga = item.manga
|
|
|
|
|
val chapter = item.chapter
|
|
|
|
|
val source = sourceManager.get(manga.source) ?: continue
|
|
|
|
|
|
|
|
|
|
val mangaDirs = mangaDirectories.getOrPut(source.id) {
|
|
|
|
@ -152,64 +150,52 @@ class RecentChaptersPresenter : BasePresenter<RecentChaptersFragment>() {
|
|
|
|
|
|
|
|
|
|
val chapterDirName = downloadManager.getChapterDirName(chapter)
|
|
|
|
|
if (chapterDirs.any { it.name == chapterDirName }) {
|
|
|
|
|
chapter.status = Download.DOWNLOADED
|
|
|
|
|
item.status = Download.DOWNLOADED
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Update status of chapters.
|
|
|
|
|
*
|
|
|
|
|
* @param download download object containing progress.
|
|
|
|
|
*/
|
|
|
|
|
private fun onDownloadStatusChange(download: Download) {
|
|
|
|
|
// Assign the download to the model object.
|
|
|
|
|
if (download.status == Download.QUEUE) {
|
|
|
|
|
val chapter = chapters?.find { it.id == download.chapter.id }
|
|
|
|
|
val chapter = chapters.find { it.chapter.id == download.chapter.id }
|
|
|
|
|
if (chapter != null && chapter.download == null) {
|
|
|
|
|
chapter.download = download
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 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
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Mark selected chapter as read
|
|
|
|
|
* @param chapters list of selected chapters
|
|
|
|
|
*
|
|
|
|
|
* @param items list of selected chapters
|
|
|
|
|
* @param read read status
|
|
|
|
|
*/
|
|
|
|
|
fun markChapterRead(chapters: List<RecentChapter>, read: Boolean) {
|
|
|
|
|
Observable.from(chapters)
|
|
|
|
|
.doOnNext { chapter ->
|
|
|
|
|
chapter.read = read
|
|
|
|
|
if (!read) {
|
|
|
|
|
chapter.last_page_read = 0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
.toList()
|
|
|
|
|
.flatMap { db.updateChaptersProgress(it).asRxObservable() }
|
|
|
|
|
fun markChapterRead(items: List<RecentChapterItem>, read: Boolean) {
|
|
|
|
|
val chapters = items.map { it.chapter }
|
|
|
|
|
chapters.forEach {
|
|
|
|
|
it.read = read
|
|
|
|
|
if (!read) {
|
|
|
|
|
it.last_page_read = 0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Observable.fromCallable { db.updateChaptersProgress(chapters).executeAsBlocking() }
|
|
|
|
|
.subscribeOn(Schedulers.io())
|
|
|
|
|
.subscribe()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Delete selected chapters
|
|
|
|
|
*
|
|
|
|
|
* @param chapters list of chapters
|
|
|
|
|
*/
|
|
|
|
|
fun deleteChapters(chapters: List<RecentChapter>) {
|
|
|
|
|
fun deleteChapters(chapters: List<RecentChapterItem>) {
|
|
|
|
|
Observable.from(chapters)
|
|
|
|
|
.doOnNext { deleteChapter(it) }
|
|
|
|
|
.toList()
|
|
|
|
@ -217,42 +203,29 @@ class RecentChaptersPresenter : BasePresenter<RecentChaptersFragment>() {
|
|
|
|
|
.observeOn(AndroidSchedulers.mainThread())
|
|
|
|
|
.subscribeFirst({ view, result ->
|
|
|
|
|
view.onChaptersDeleted()
|
|
|
|
|
}, { view, error ->
|
|
|
|
|
view.onChaptersDeletedError(error)
|
|
|
|
|
})
|
|
|
|
|
}, RecentChaptersFragment::onChaptersDeletedError)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Download selected chapters
|
|
|
|
|
* @param chapters list of recent chapters seleted.
|
|
|
|
|
*/
|
|
|
|
|
fun downloadChapters(chapters: List<RecentChapter>) {
|
|
|
|
|
DownloadService.start(context)
|
|
|
|
|
Observable.from(chapters)
|
|
|
|
|
.doOnNext { downloadChapter(it) }
|
|
|
|
|
.subscribeOn(AndroidSchedulers.mainThread())
|
|
|
|
|
.subscribe()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Download selected chapter
|
|
|
|
|
* @param chapter chapter that is selected
|
|
|
|
|
* @param items list of recent chapters seleted.
|
|
|
|
|
*/
|
|
|
|
|
fun downloadChapter(chapter: RecentChapter) {
|
|
|
|
|
fun downloadChapters(items: List<RecentChapterItem>) {
|
|
|
|
|
items.forEach { downloadManager.downloadChapters(it.manga, listOf(it.chapter)) }
|
|
|
|
|
DownloadService.start(context)
|
|
|
|
|
downloadManager.downloadChapters(chapter.manga, listOf(chapter))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Delete selected chapter
|
|
|
|
|
* @param chapter chapter that is selected
|
|
|
|
|
*/
|
|
|
|
|
private fun deleteChapter(chapter: RecentChapter) {
|
|
|
|
|
val source = sourceManager.get(chapter.manga.source) ?: return
|
|
|
|
|
downloadManager.queue.remove(chapter)
|
|
|
|
|
downloadManager.deleteChapter(source, chapter.manga, chapter)
|
|
|
|
|
chapter.status = Download.NOT_DOWNLOADED
|
|
|
|
|
chapter.download = null
|
|
|
|
|
*
|
|
|
|
|
* @param item chapter that is selected
|
|
|
|
|
*/
|
|
|
|
|
private fun deleteChapter(item: RecentChapterItem) {
|
|
|
|
|
val source = sourceManager.get(item.manga.source) ?: return
|
|
|
|
|
downloadManager.queue.remove(item.chapter)
|
|
|
|
|
downloadManager.deleteChapter(source, item.manga, item.chapter)
|
|
|
|
|
item.status = Download.NOT_DOWNLOADED
|
|
|
|
|
item.download = null
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|