Database queries are now separated by table. Improve how the app creates downloads

This commit is contained in:
len
2016-05-02 22:33:36 +02:00
parent af2b886599
commit 5e24054a0b
20 changed files with 657 additions and 532 deletions
@@ -1,14 +1,12 @@
package eu.kanade.tachiyomi.ui.recent
import android.os.Bundle
import android.support.v4.app.DialogFragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
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.data.database.models.MangaChapter
import eu.kanade.tachiyomi.data.download.DownloadService
import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.ui.base.adapter.FlexibleViewHolder
import eu.kanade.tachiyomi.ui.base.decoration.DividerItemDecoration
@@ -16,12 +14,11 @@ import eu.kanade.tachiyomi.ui.base.fragment.BaseRxFragment
import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
import eu.kanade.tachiyomi.util.getResourceDrawable
import eu.kanade.tachiyomi.widget.DeletingChaptersDialog
import eu.kanade.tachiyomi.widget.NpaLinearLayoutManager
import kotlinx.android.synthetic.main.fragment_recent_chapters.*
import nucleus.factory.RequiresPresenter
import rx.Observable
import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers
import timber.log.Timber
/**
* Fragment that shows recent chapters.
@@ -143,78 +140,57 @@ class RecentChaptersFragment : BaseRxFragment<RecentChaptersPresenter>(), Flexib
}
/**
* Start downloading chapter
* @param chapters selected chapters
* @param manga manga that belongs to chapter
* @return true
* Mark chapter as read
*
* @param item selected chapter with manga
*/
fun onDownload(chapters: Observable<Chapter>, manga: Manga): Boolean {
// Start the download service.
DownloadService.start(activity)
fun markAsRead(item: MangaChapter) {
presenter.markChapterRead(item.chapter, true)
if (presenter.preferences.removeAfterMarkedAsRead()) {
deleteChapter(item)
}
}
// Refresh data on download competition.
val observable = chapters
.doOnCompleted({
adapter.notifyDataSetChanged()
presenter.start(presenter.CHAPTER_STATUS_CHANGES)
})
/**
* Mark chapter as unread
*
* @param item selected chapter with manga
*/
fun markAsUnread(item: MangaChapter) {
presenter.markChapterRead(item.chapter, false)
}
// Download chapter.
presenter.downloadChapter(observable, manga)
return true
/**
* Start downloading chapter
*
* @param item selected chapter with manga
*/
fun downloadChapter(item: MangaChapter) {
presenter.downloadChapter(item)
}
/**
* Start deleting chapter
*
* @param chapters selected chapters
* @param manga manga that belongs to chapter
* @return success of deletion.
* @param item selected chapter with manga
*/
fun onDelete(chapters: Observable<Chapter>, manga: Manga): Boolean {
//Create observable
val observable = chapters
.concatMap { chapter ->
presenter.deleteChapter(chapter, manga)
Observable.just(chapter)
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnNext { chapter ->
chapter.status = Download.NOT_DOWNLOADED
}
.doOnCompleted { adapter.notifyDataSetChanged() }
// Delete chapters with observable
presenter.deleteChapters(observable)
return true
fun deleteChapter(item: MangaChapter) {
DeletingChaptersDialog().show(childFragmentManager, DeletingChaptersDialog.TAG)
presenter.deleteChapter(item)
}
/**
* Mark chapter as read
* @param chapters selected chapter
* @return true
*/
fun onMarkAsRead(chapters: Observable<Chapter>, manga : Manga): Boolean {
// Set marked as read
presenter.markChaptersRead(chapters, manga, true)
return true
fun onChaptersDeleted() {
dismissDeletingDialog()
adapter.notifyDataSetChanged()
}
/**
* Mark chapter as unread
* @param chapters selected chapter
* @return true
*/
fun onMarkAsUnread(chapters: Observable<Chapter> , manga : Manga): Boolean {
// Set marked as unread
presenter.markChaptersRead(chapters, manga, false)
return true
fun onChaptersDeletedError(error: Throwable) {
dismissDeletingDialog()
Timber.e(error, error.message)
}
fun dismissDeletingDialog() {
(childFragmentManager.findFragmentByTag(DeletingChaptersDialog.TAG) as? DialogFragment)?.dismiss()
}
}
@@ -1,16 +1,13 @@
package eu.kanade.tachiyomi.ui.recent
import android.content.Context
import android.view.View
import android.widget.PopupMenu
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.MangaChapter
import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.ui.base.adapter.FlexibleViewHolder
import eu.kanade.tachiyomi.util.getResourceColor
import kotlinx.android.synthetic.main.item_recent_chapter.view.*
import rx.Observable
/**
* Holder that contains chapter item
@@ -32,7 +29,7 @@ class RecentChaptersHolder(view: View, private val adapter: RecentChaptersAdapte
/**
* Color of unread chapter
*/
private var unreadColor = view.context.theme.getResourceColor(android.R.attr.textColorPrimary)
private var unreadColor = view.context.theme.getResourceColor(android.R.attr.textColorPrimary)
/**
* Object containing chapter information
@@ -40,9 +37,10 @@ class RecentChaptersHolder(view: View, private val adapter: RecentChaptersAdapte
private var mangaChapter: MangaChapter? = null
init {
//Set OnClickListener for download menu
itemView.chapterMenu.setOnClickListener { v -> v.post({ showPopupMenu(v) }) }
// We need to post a Runnable to show the popup to make sure that the PopupMenu is
// correctly positioned. The reason being that the view may change position before the
// PopupMenu is shown.
itemView.chapterMenu.setOnClickListener { it.post({ showPopupMenu(it) }) }
}
/**
@@ -120,15 +118,14 @@ class RecentChaptersHolder(view: View, private val adapter: RecentChaptersAdapte
// Set a listener so we are notified if a menu item is clicked
popup.setOnMenuItemClickListener { menuItem ->
val chapterObservable = Observable.just<Chapter>(it.chapter)
when (menuItem.itemId) {
R.id.action_download -> adapter.fragment.onDownload(chapterObservable, it.manga)
R.id.action_delete -> adapter.fragment.onDelete(chapterObservable, it.manga)
R.id.action_mark_as_read -> adapter.fragment.onMarkAsRead(chapterObservable, it.manga);
R.id.action_mark_as_unread -> adapter.fragment.onMarkAsUnread(chapterObservable, it.manga);
R.id.action_download -> adapter.fragment.downloadChapter(it)
R.id.action_delete -> adapter.fragment.deleteChapter(it)
R.id.action_mark_as_read -> adapter.fragment.markAsRead(it)
R.id.action_mark_as_unread -> adapter.fragment.markAsUnread(it)
}
false
true
}
}
@@ -6,10 +6,10 @@ import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.models.MangaChapter
import eu.kanade.tachiyomi.data.download.DownloadManager
import eu.kanade.tachiyomi.data.download.DownloadService
import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.source.SourceManager
import eu.kanade.tachiyomi.event.DownloadChaptersEvent
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
import rx.Observable
import rx.android.schedulers.AndroidSchedulers
@@ -250,59 +250,69 @@ class RecentChaptersPresenter : BasePresenter<RecentChaptersFragment>() {
}
/**
* Download selected chapter
* @param selectedChapter chapter that is selected
* *
* @param manga manga that belongs to chapter
* Mark selected chapter as read
*
* @param chapter selected chapter
* @param read read status
*/
fun downloadChapter(selectedChapter: Observable<Chapter>, manga: Manga) {
add(selectedChapter.toList()
.observeOn(AndroidSchedulers.mainThread())
.subscribe { downloadManager.onDownloadChaptersEvent(DownloadChaptersEvent(manga, it)) })
fun markChapterRead(chapter: Chapter, read: Boolean) {
Observable.just(chapter)
.doOnNext { chapter ->
chapter.read = read
if (!read) {
chapter.last_page_read = 0
}
}
.flatMap { db.updateChapterProgress(it).asRxObservable() }
.subscribeOn(Schedulers.io())
.subscribe()
}
/**
* Download selected chapter
*
* @param item chapter that is selected
*/
fun downloadChapter(item: MangaChapter) {
DownloadService.start(context)
downloadManager.downloadChapters(item.manga, listOf(item.chapter))
}
/**
* Delete selected chapter
*
* @param item chapter that are selected
*/
fun deleteChapter(item: MangaChapter) {
val wasRunning = downloadManager.isRunning
if (wasRunning) {
DownloadService.stop(context)
}
Observable.just(item)
.doOnNext { deleteChapter(it.chapter, it.manga) }
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeFirst({ view, result ->
view.onChaptersDeleted()
if (wasRunning) {
DownloadService.start(context)
}
}, { view, error ->
view.onChaptersDeletedError(error)
})
}
/**
* Delete selected chapter
*
* @param chapter chapter that is selected
* *
* @param manga manga that belongs to chapter
*/
fun deleteChapter(chapter: Chapter, manga: Manga) {
val source = sourceManager.get(manga.source)!!
private fun deleteChapter(chapter: Chapter, manga: Manga) {
val source = sourceManager.get(manga.source) ?: return
downloadManager.queue.del(chapter)
downloadManager.deleteChapter(source, manga, chapter)
chapter.status = Download.NOT_DOWNLOADED
}
/**
* Delete selected chapter observable
* @param selectedChapters chapter that are selected
*/
fun deleteChapters(selectedChapters: Observable<Chapter>) {
add(selectedChapters
.subscribe(
{ chapter -> downloadManager.queue.del(chapter) })
{ error -> Timber.e(error.message) })
}
/**
* Mark selected chapter as read
* @param selectedChapters chapter that is selected
* *
* @param read read status
*/
fun markChaptersRead(selectedChapters: Observable<Chapter>, manga: Manga, read: Boolean) {
add(selectedChapters.subscribeOn(Schedulers.io())
.doOnNext { chapter ->
chapter.read = read
if (!read) chapter.last_page_read = 0
// Delete chapter when marked as read if desired by user.
if (preferences.removeAfterMarkedAsRead() && read) {
deleteChapter(chapter,manga)
}
}
.toList()
.flatMap { chapters -> db.insertChapters(chapters).asRxObservable() }
.observeOn(AndroidSchedulers.mainThread())
.subscribe())
}
}