Introduce coroutines. Fix #1027. Lower notification channels' importance

This commit is contained in:
len 2017-10-13 00:12:29 +02:00
parent d97aff85b3
commit 4abd2d709f
6 changed files with 70 additions and 56 deletions

View File

@ -218,10 +218,14 @@ dependencies {
testCompile "org.robolectric:shadows-play-services:$robolectric_version"
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
final coroutines_version = '0.19.1'
compile "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
compile "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
}
buildscript {
ext.kotlin_version = '1.1.50'
ext.kotlin_version = '1.1.51'
repositories {
mavenCentral()
}
@ -234,6 +238,12 @@ repositories {
mavenCentral()
}
kotlin {
experimental {
coroutines 'enable'
}
}
// add support for placeholders in resource files
//https://code.google.com/p/android/issues/detail?id=69224
def replacePlaceholdersInFile(basePath, fileName, placeholders) {

View File

@ -16,6 +16,7 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.source.online.fetchAllImageUrlsFromPageList
import eu.kanade.tachiyomi.util.*
import kotlinx.coroutines.experimental.async
import okhttp3.Response
import rx.Observable
import rx.android.schedulers.AndroidSchedulers
@ -90,11 +91,10 @@ class Downloader(private val context: Context, private val provider: DownloadPro
@Volatile private var isRunning: Boolean = false
init {
Observable.fromCallable { store.restore() }
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ downloads -> queue.addAll(downloads)
}, { error -> Timber.e(error) })
launchNow {
val chapters = async { store.restore() }
queue.addAll(chapters.await())
}
}
/**
@ -217,51 +217,49 @@ class Downloader(private val context: Context, private val provider: DownloadPro
* @param manga the manga of the chapters to download.
* @param chapters the list of chapters to download.
*/
fun queueChapters(manga: Manga, chapters: List<Chapter>) {
val source = sourceManager.get(manga.source) as? HttpSource ?: return
fun queueChapters(manga: Manga, chapters: List<Chapter>) = launchUI {
val source = sourceManager.get(manga.source) as? HttpSource ?: return@launchUI
Observable
// Background, long running checks
.fromCallable {
val mangaDir = provider.findMangaDir(source, manga)
// Called in background thread, the operation can be slow with SAF.
val chaptersWithoutDir = async {
val mangaDir = provider.findMangaDir(source, manga)
chapters
// Avoid downloading chapters with the same name.
.distinctBy { it.name }
// Filter out those already downloaded.
.filter { mangaDir?.findFile(provider.getChapterDirName(it)) == null }
// Add chapters to queue from the start.
.sortedByDescending { it.source_order }
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
// Main thread, quick checks
.map { chaptersToQueue ->
chaptersToQueue
// Filter out those already enqueued.
.filter { chapter -> queue.none { it.chapter.id == chapter.id } }
// Create a download for each one.
.map { Download(source, manga, it) }
}
.subscribe { chaptersToQueue ->
if (chaptersToQueue.isNotEmpty()) {
queue.addAll(chaptersToQueue)
chapters
// Avoid downloading chapters with the same name.
.distinctBy { it.name }
// Filter out those already downloaded.
.filter { mangaDir?.findFile(provider.getChapterDirName(it)) == null }
// Add chapters to queue from the start.
.sortedByDescending { it.source_order }
}
// Initialize queue size.
notifier.initialQueueSize = queue.size
// Runs in main thread (synchronization needed).
val chaptersToQueue = chaptersWithoutDir.await()
// Filter out those already enqueued.
.filter { chapter -> queue.none { it.chapter.id == chapter.id } }
// Create a download for each one.
.map { Download(source, manga, it) }
// Initial multi-thread
notifier.multipleDownloadThreads = preferences.downloadThreads().getOrDefault() > 1
if (chaptersToQueue.isNotEmpty()) {
queue.addAll(chaptersToQueue)
if (isRunning) {
// Send the list of downloads to the downloader.
downloadsRelay.call(chaptersToQueue)
} else {
// Show initial notification.
notifier.onProgressChange(queue)
}
}
}
// Initialize queue size.
notifier.initialQueueSize = queue.size
// Initial multi-thread
notifier.multipleDownloadThreads = preferences.downloadThreads().getOrDefault() > 1
if (isRunning) {
// Send the list of downloads to the downloader.
downloadsRelay.call(chaptersToQueue)
} else {
// Show initial notification.
notifier.onProgressChange(queue)
}
// Start downloader if needed
DownloadService.start(this@Downloader.context)
}
}
/**

View File

@ -43,11 +43,11 @@ object Notifications {
val channels = listOf(
NotificationChannel(CHANNEL_COMMON, context.getString(R.string.channel_common),
NotificationManager.IMPORTANCE_DEFAULT),
NotificationManager.IMPORTANCE_LOW),
NotificationChannel(CHANNEL_LIBRARY, context.getString(R.string.channel_library),
NotificationManager.IMPORTANCE_DEFAULT),
NotificationManager.IMPORTANCE_LOW),
NotificationChannel(CHANNEL_DOWNLOADER, context.getString(R.string.channel_downloader),
NotificationManager.IMPORTANCE_DEFAULT)
NotificationManager.IMPORTANCE_LOW)
)
context.notificationManager.createNotificationChannels(channels)
}

View File

@ -7,7 +7,6 @@ import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.Manga
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.source.Source
@ -35,8 +34,6 @@ class ChaptersPresenter(
private val downloadManager: DownloadManager = Injekt.get()
) : BasePresenter<ChaptersController>() {
private val context = preferences.context
/**
* List of chapters of the manga. It's always unfiltered and unsorted.
*/
@ -246,7 +243,6 @@ class ChaptersPresenter(
* @param chapters the list of chapters to download.
*/
fun downloadChapters(chapters: List<ChapterItem>) {
DownloadService.start(context)
downloadManager.downloadChapters(manga, chapters)
}

View File

@ -25,8 +25,6 @@ class RecentChaptersPresenter(
private val sourceManager: SourceManager = Injekt.get()
) : BasePresenter<RecentChaptersController>() {
private val context = preferences.context
/**
* List containing chapter and manga information
*/
@ -207,7 +205,6 @@ class RecentChaptersPresenter(
*/
fun downloadChapters(items: List<RecentChapterItem>) {
items.forEach { downloadManager.downloadChapters(it.manga, listOf(it.chapter)) }
DownloadService.start(context)
}
/**

View File

@ -0,0 +1,13 @@
package eu.kanade.tachiyomi.util
import kotlinx.coroutines.experimental.CoroutineScope
import kotlinx.coroutines.experimental.CoroutineStart
import kotlinx.coroutines.experimental.Job
import kotlinx.coroutines.experimental.android.UI
import kotlinx.coroutines.experimental.launch
fun launchUI(block: suspend CoroutineScope.() -> Unit): Job =
launch(UI, CoroutineStart.DEFAULT, block)
fun launchNow(block: suspend CoroutineScope.() -> Unit): Job =
launch(UI, CoroutineStart.UNDISPATCHED, block)